Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Draft] Introduce junit test runner #533

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions save-common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,11 @@ kotlin {
implementation(libs.okio.fakefilesystem)
}
}

val jvmTest by getting {
dependencies {
implementation("junit:junit:4.13.2")
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.saveourtool.save.core.annotations

enum class CheckedLanguage {
foo,
bar,
}

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class AnnotationForClass(
val databaseSuffix: String,
val ruleSuffix: String = "txt",
val codeBasePath: String,
val databasePath: String,
val ruleBasePath: String,
val checkedLanguage: CheckedLanguage,
val needParseSourceFile: Boolean = true
)

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.saveourtool.save.core.annotations

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class AnnotationForMethods(
val sourcePackage: String,
val headerPackage: String = "",
val jarPackage: String = "",
val databaseName: String,
val ruleName: String,
val resultSize: Int = 1,
val valid: Boolean = true
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
package com.saveourtool.save.core.runners

import com.saveourtool.save.core.annotations.CheckedLanguage
import com.saveourtool.save.core.annotations.AnnotationForClass
import com.saveourtool.save.core.annotations.AnnotationForMethods
import org.junit.AssumptionViolatedException
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.Description
import org.junit.runner.notification.Failure
import org.junit.runner.notification.RunNotifier
import org.junit.runners.BlockJUnit4ClassRunner
import org.junit.runners.model.FrameworkMethod
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method


/**
* Runner, which provide interface for running tests, by setting configuration via annotations
*/
class CommonTestRunner(private val testClass: Class<*>) : BlockJUnit4ClassRunner(testClass) {
/**
* Run test cases in [testClass], annotated with [AnnotationForClass]
*
*
* If individual test is annotated with [AnnotationForMethods], run doTest()
* otherwise, invoke test as is
*
* @param frameworkMethod running method
* @param notifier notifier, which fires about actual status of test
*/
override fun runChild(
frameworkMethod: FrameworkMethod,
notifier: RunNotifier
) {
val method = frameworkMethod.method
val methodDescription = Description.createTestDescription(
testClass, method.name
)
notifier.fireTestStarted(methodDescription)
try {
if (testClass.isAnnotationPresent(Ignore::class.java) ||
method.isAnnotationPresent(Ignore::class.java)
) {
notifier.fireTestIgnored(methodDescription)
return
}
val testObject = testClass.getDeclaredConstructor().newInstance()
doRunChild(testObject, method, methodDescription, notifier)
notifier.fireTestFinished(methodDescription)
} catch (e: AssumptionViolatedException) {
val failure = Failure(methodDescription, e)
notifier.fireTestAssumptionFailed(failure)
} catch (e: Exception) {
val failure = Failure(methodDescription, e)
notifier.fireTestFailure(failure)
}
}

private fun doRunChild(
testObject: Any,
method: Method,
methodDescription: Description,
notifier: RunNotifier
) {
try {
if (testClass.isAnnotationPresent(Ignore::class.java) || method.isAnnotationPresent(Ignore::class.java)) {
notifier.fireTestIgnored(methodDescription)
return
}
if (testClass.isAnnotationPresent(AnnotationForClass::class.java) &&
method.isAnnotationPresent(Test::class.java) &&
method.isAnnotationPresent(AnnotationForMethods::class.java)
) {
// TODO:
// here you can collect configuration from annotations and do test
// doTest()

// if needed, invoke test itself
method.invoke(testObject)
} else if (testClass.isAnnotationPresent(AnnotationForClass::class.java) &&
method.isAnnotationPresent(Test::class.java)
) {
// support the case, when test is not annotated for some reasons,
// simply run the test
method.invoke(testObject)
}
} catch (e: InvocationTargetException) {
val targetException = e.targetException
// we need to distinguish AssumptionViolatedException separately
if (targetException is AssumptionViolatedException) {
throw targetException
} else {
throw e
}
}
}

// ==================== TestConfigParams Getters ====================== //

private fun databaseSuffix(): String {
return testClass.getAnnotation(AnnotationForClass::class.java).databaseSuffix
}

private fun ruleSuffix(): String {
return testClass.getAnnotation(AnnotationForClass::class.java).ruleSuffix
}

private fun codeBasePath(): String {
return testClass.getAnnotation(AnnotationForClass::class.java).codeBasePath
}

private fun databasePath(): String {
return testClass.getAnnotation(AnnotationForClass::class.java).databasePath
}

private fun ruleBasePath(): String {
return testClass.getAnnotation(AnnotationForClass::class.java).ruleBasePath
}

private fun checkedLanguage(): CheckedLanguage {
return testClass.getAnnotation(AnnotationForClass::class.java).checkedLanguage
}

private fun needParseSourceFile(): Boolean {
return testClass.getAnnotation(AnnotationForClass::class.java).needParseSourceFile
}

// ==================== TestcaseConfigParams Getters ====================== //

private fun sourcePackage(method: Method): String {
return method.getAnnotation(AnnotationForMethods::class.java).sourcePackage
}

private fun headerPackage(method: Method): String {
return method.getAnnotation(AnnotationForMethods::class.java).headerPackage
}

private fun jarPackage(method: Method): String {
return method.getAnnotation(AnnotationForMethods::class.java).jarPackage
}

private fun databaseName(method: Method): String {
return method.getAnnotation(AnnotationForMethods::class.java).databaseName
}

private fun ruleName(method: Method): String {
return method.getAnnotation(AnnotationForMethods::class.java).ruleName
}

private fun resultSize(method: Method): Int {
return method.getAnnotation(AnnotationForMethods::class.java).resultSize
}

private fun valid(method: Method): Boolean {
return method.getAnnotation(AnnotationForMethods::class.java).valid
}
}