[Native][tests] Add a directive to specify test runner type

This commit is contained in:
Dmitriy Dolovov
2021-12-06 19:13:50 +03:00
parent 580328ece7
commit 3e54bb06ee
13 changed files with 202 additions and 16 deletions
@@ -0,0 +1,23 @@
// TEST_RUNNER: DEFAULT
import kotlin.test.*
@Test
fun addition() {
assertEquals(42, 40 + 2)
}
@Test
fun multiplication () {
assertEquals(42, 21 * 2)
}
@Test
fun subtraction () {
assertEquals(42, 50 - 8)
}
@Test
fun division () {
assertEquals(42, 126 / 3)
}
@@ -0,0 +1,23 @@
// TEST_RUNNER: NO_EXIT
import kotlin.test.*
@Test
fun addition() {
assertEquals(42, 40 + 2)
}
@Test
fun multiplication () {
assertEquals(42, 21 * 2)
}
@Test
fun subtraction () {
assertEquals(42, 50 - 8)
}
@Test
fun division () {
assertEquals(42, 126 / 3)
}
@@ -0,0 +1,23 @@
// TEST_RUNNER: WORKER
import kotlin.test.*
@Test
fun addition() {
assertEquals(42, 40 + 2)
}
@Test
fun multiplication () {
assertEquals(42, 21 * 2)
}
@Test
fun subtraction () {
assertEquals(42, 50 - 8)
}
@Test
fun division () {
assertEquals(42, 126 / 3)
}
@@ -0,0 +1,24 @@
// KIND: STANDALONE
// TEST_RUNNER: DEFAULT
import kotlin.test.*
@Test
fun addition() {
assertEquals(42, 40 + 2)
}
@Test
fun multiplication () {
assertEquals(42, 21 * 2)
}
@Test
fun subtraction () {
assertEquals(42, 50 - 8)
}
@Test
fun division () {
assertEquals(42, 126 / 3)
}
@@ -0,0 +1,24 @@
// KIND: STANDALONE
// TEST_RUNNER: NO_EXIT
import kotlin.test.*
@Test
fun addition() {
assertEquals(42, 40 + 2)
}
@Test
fun multiplication () {
assertEquals(42, 21 * 2)
}
@Test
fun subtraction () {
assertEquals(42, 50 - 8)
}
@Test
fun division () {
assertEquals(42, 126 / 3)
}
@@ -0,0 +1,24 @@
// KIND: STANDALONE
// TEST_RUNNER: WORKER
import kotlin.test.*
@Test
fun addition() {
assertEquals(42, 40 + 2)
}
@Test
fun multiplication () {
assertEquals(42, 21 * 2)
}
@Test
fun subtraction () {
assertEquals(42, 50 - 8)
}
@Test
fun division () {
assertEquals(42, 126 / 3)
}
@@ -7,6 +7,7 @@
package org.jetbrains.kotlin.konan.blackboxtest.support
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.WithTestRunnerExtras
import org.jetbrains.kotlin.konan.blackboxtest.support.TestModule.Companion.allDependencies
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.TestMode
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
@@ -177,7 +178,7 @@ internal class TestCase(
) {
sealed interface Extras
class NoTestRunnerExtras(val entryPoint: String, val inputDataFile: File?) : Extras
object WithTestRunnerExtras : Extras
class WithTestRunnerExtras(val runnerType: TestRunnerType) : Extras
init {
when (kind) {
@@ -256,7 +257,7 @@ internal interface TestCaseGroupId {
internal interface TestCaseGroup {
fun isEnabled(testCaseId: TestCaseId): Boolean
fun getByName(testCaseId: TestCaseId): TestCase?
fun getRegularOnlyByCompilerArgs(freeCompilerArgs: TestCompilerArgs): Collection<TestCase>
fun getRegularOnly(freeCompilerArgs: TestCompilerArgs, runnerType: TestRunnerType): Collection<TestCase>
class Default(
private val disabledTestCaseIds: Set<TestCaseId>,
@@ -267,15 +268,20 @@ internal interface TestCaseGroup {
override fun isEnabled(testCaseId: TestCaseId) = testCaseId !in disabledTestCaseIds
override fun getByName(testCaseId: TestCaseId) = testCasesById[testCaseId]
override fun getRegularOnlyByCompilerArgs(freeCompilerArgs: TestCompilerArgs) =
testCasesById.values.filter { it.kind == TestKind.REGULAR && it.freeCompilerArgs == freeCompilerArgs }
override fun getRegularOnly(freeCompilerArgs: TestCompilerArgs, runnerType: TestRunnerType) =
testCasesById.values.filter { testCase ->
testCase.kind == TestKind.REGULAR
&& testCase.extras<WithTestRunnerExtras>().runnerType == runnerType
&& testCase.freeCompilerArgs == freeCompilerArgs
}
}
companion object {
val ALL_DISABLED = object : TestCaseGroup {
override fun isEnabled(testCaseId: TestCaseId) = false
override fun getByName(testCaseId: TestCaseId) = fail { "This function should not be called" }
override fun getRegularOnlyByCompilerArgs(freeCompilerArgs: TestCompilerArgs) = fail { "This function should not be called" }
override fun getByName(testCaseId: TestCaseId) = unsupported()
override fun getRegularOnly(freeCompilerArgs: TestCompilerArgs, runnerType: TestRunnerType) = unsupported()
private fun unsupported(): Nothing = fail { "This function should not be called" }
}
}
}
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.compilerRunner.processCompilerOutput
import org.jetbrains.kotlin.config.Services
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.NoTestRunnerExtras
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.WithTestRunnerExtras
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilation.Companion.resultingArtifactPath
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilationResult.Companion.assertSuccess
import org.jetbrains.kotlin.konan.blackboxtest.support.TestModule.Companion.allDependencies
@@ -41,13 +42,12 @@ internal class TestCompilationFactory(private val settings: Settings) {
cachedCompilations[cacheKey]?.let { return it }
// Long pass.
val freeCompilerArgs = rootModules.first().testCase.freeCompilerArgs
val freeCompilerArgs = rootModules.first().testCase.freeCompilerArgs // Should be identical inside the same test case group.
val extras = testCases.first().extras // Should be identical inside the same test case group.
val libraries = rootModules.flatMapToSet { it.allDependencies }.map { moduleToKlib(it, freeCompilerArgs) }
val friends = rootModules.flatMapToSet { it.allFriends }.map { moduleToKlib(it, freeCompilerArgs) }
return cachedCompilations.computeIfAbsent(cacheKey) {
val entryPoint = testCases.singleOrNull()?.safeExtras<NoTestRunnerExtras>()?.entryPoint
TestCompilationImpl(
settings = settings,
freeCompilerArgs = freeCompilerArgs,
@@ -56,7 +56,17 @@ internal class TestCompilationFactory(private val settings: Settings) {
expectedArtifactFile = artifactFileForExecutable(rootModules),
specificCompilerArgs = {
add("-produce", "program")
if (entryPoint != null) add("-entry", entryPoint) else add("-generate-test-runner")
when (extras) {
is NoTestRunnerExtras -> add("-entry", extras.entryPoint)
is WithTestRunnerExtras -> {
val testRunnerArg = when (extras.runnerType) {
TestRunnerType.DEFAULT -> "-generate-test-runner"
TestRunnerType.WORKER -> "-generate-worker-test-runner"
TestRunnerType.NO_EXIT -> "-generate-no-exit-test-runner"
}
add(testRunnerArg)
}
}
settings.get<GlobalSettings>().getRootCacheDirectory(debuggable = true)?.let { rootCacheDir ->
add("-Xcache-directory=$rootCacheDir")
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.TestDirectives.FREE_COMPI
import org.jetbrains.kotlin.konan.blackboxtest.support.TestDirectives.INPUT_DATA_FILE
import org.jetbrains.kotlin.konan.blackboxtest.support.TestDirectives.KIND
import org.jetbrains.kotlin.konan.blackboxtest.support.TestDirectives.OUTPUT_DATA_FILE
import org.jetbrains.kotlin.konan.blackboxtest.support.TestDirectives.TEST_RUNNER
import org.jetbrains.kotlin.test.directives.model.RegisteredDirectives
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
import org.jetbrains.kotlin.test.directives.model.StringDirective
@@ -35,6 +36,14 @@ internal object TestDirectives : SimpleDirectivesContainer() {
""".trimIndent()
)
val TEST_RUNNER by enumDirective<TestRunnerType>(
description = """
Usage: // TEST_RUNNER: [DEFAULT, WORKER, NO_EXIT]
Specify test runner type.
Note that this directive makes sense only in combination with // KIND: REGULAR or // KIND: STANDALONE
""".trimIndent()
)
val ENTRY_POINT by stringDirective(
description = """
Specify custom program entry point. The default entry point is `main` function in the root package.
@@ -81,6 +90,12 @@ internal enum class TestKind {
STANDALONE_NO_TR;
}
internal enum class TestRunnerType {
DEFAULT,
WORKER,
NO_EXIT
}
internal class TestCompilerArgs(val compilerArgs: List<String>) {
private val uniqueCompilerArgs = compilerArgs.toSet()
override fun hashCode() = uniqueCompilerArgs.hashCode()
@@ -115,6 +130,14 @@ internal fun parseTestKind(registeredDirectives: RegisteredDirectives, location:
return values.singleOrNull() ?: fail { "$location: Exactly one test kind expected in $KIND directive: $values" }
}
internal fun parseTestRunner(registeredDirectives: RegisteredDirectives, location: Location): TestRunnerType {
if (TEST_RUNNER !in registeredDirectives)
return TestRunnerType.DEFAULT // The default one.
val values = registeredDirectives[TEST_RUNNER]
return values.singleOrNull() ?: fail { "$location: Exactly one test runner type expected in $TEST_RUNNER directive: $values" }
}
internal fun parseEntryPoint(registeredDirectives: RegisteredDirectives, location: Location): String {
if (ENTRY_POINT !in registeredDirectives)
return "main" // The default one.
@@ -9,6 +9,7 @@ package org.jetbrains.kotlin.konan.blackboxtest.support
import com.intellij.openapi.util.Disposer
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.NoTestRunnerExtras
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.WithTestRunnerExtras
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilationResult.Companion.assertSuccess
import org.jetbrains.kotlin.konan.blackboxtest.support.group.TestCaseGroupProvider
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.AbstractRunner
@@ -143,9 +144,10 @@ internal class TestRunProvider(
}
TestKind.REGULAR -> {
// Group regular test cases by compiler arguments.
val cacheKey = TestCompilationCacheKey.Grouped(testCaseId.testCaseGroupId, testCase.freeCompilerArgs)
val testRunnerType = testCase.extras<WithTestRunnerExtras>().runnerType
val cacheKey = TestCompilationCacheKey.Grouped(testCaseId.testCaseGroupId, testCase.freeCompilerArgs, testRunnerType)
val testCompilation = cachedCompilations.computeIfAbsent(cacheKey) {
val testCases = testCaseGroup.getRegularOnlyByCompilerArgs(testCase.freeCompilerArgs)
val testCases = testCaseGroup.getRegularOnly(testCase.freeCompilerArgs, testRunnerType)
assertTrue(testCases.isNotEmpty())
compilationFactory.testCasesToExecutable(testCases)
}
@@ -217,6 +219,10 @@ internal class TestRunProvider(
private sealed class TestCompilationCacheKey {
data class Standalone(val testCaseId: TestCaseId) : TestCompilationCacheKey()
data class Grouped(val testCaseGroupId: TestCaseGroupId, val freeCompilerArgs: TestCompilerArgs) : TestCompilationCacheKey()
data class Grouped(
val testCaseGroupId: TestCaseGroupId,
val freeCompilerArgs: TestCompilerArgs,
val runnerType: TestRunnerType
) : TestCompilationCacheKey()
}
}
@@ -594,7 +594,7 @@ private class ExtTestDataFile(
freeCompilerArgs = assembleFreeCompilerArgs(),
nominalPackageName = testDataFileSettings.nominalPackageName,
expectedOutputDataFile = null,
extras = WithTestRunnerExtras
extras = WithTestRunnerExtras(runnerType = TestRunnerType.DEFAULT)
)
testCase.initialize(sharedModules::get)
@@ -58,7 +58,7 @@ internal class PredefinedTestCaseGroupProvider(private val settings: Settings, a
.parseCompilerArgs { "Failed to parse free compiler arguments for test case $testCaseId" },
nominalPackageName = PackageName(testCaseId.uniqueName),
expectedOutputDataFile = null,
extras = WithTestRunnerExtras
extras = WithTestRunnerExtras(runnerType = TestRunnerType.DEFAULT) // TODO: pass TR from the predefined configuration here
)
testCase.initialize(null)
@@ -213,7 +213,7 @@ internal class StandardTestCaseGroupProvider(private val settings: Settings) : T
inputDataFile = parseInputDataFile(baseDir = testDataFile.parentFile, registeredDirectives, location)
)
else
WithTestRunnerExtras
WithTestRunnerExtras(runnerType = parseTestRunner(registeredDirectives, location))
)
testCase.initialize(findSharedModule = null)