[Native][tests] Drop TestFunction/FunctionName, introduce TestName instead

This commit is contained in:
Dmitriy Dolovov
2021-12-03 12:19:20 +03:00
parent 7abfe4d47b
commit cdbbc70116
8 changed files with 103 additions and 97 deletions
@@ -22,3 +22,38 @@ internal class PackageName private constructor(private val fqn: String, val segm
val EMPTY = PackageName("", emptyList()) val EMPTY = PackageName("", emptyList())
} }
} }
/**
* Represents a single test name (i.e. a function annotated with [kotlin.test.Test]) inside of a [TestFile].
*
* [packageName] - containing package name. For the sake of simplification [packageName] may also include top-level and nested class names,
* but it does not include package-part class name (i.e. "SomethingKt").
* [packagePartClassName] - package-part class name (if there is any)
* [functionName] - name of test function
*/
internal data class TestName(private val fqn: String) {
val packageName: PackageName
val packagePartClassName: String?
val functionName: String
init {
val segments = fqn.split('.').toMutableList()
functionName = segments.removeLast()
val maybePackagePartClassSegment = segments.lastOrNull()
packagePartClassName = if (maybePackagePartClassSegment?.firstOrNull()?.isEffectivelyUpperCase() == true
&& maybePackagePartClassSegment.endsWith("Kt")
) {
segments.removeLast()
} else
null
packageName = PackageName(segments)
}
override fun toString() = fqn
companion object {
private fun Char.isEffectivelyUpperCase() = if (isUpperCase()) true else !isLowerCase()
}
}
@@ -15,13 +15,6 @@ import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
import java.io.File import java.io.File
internal typealias FunctionName = String
/**
* Represents a single test function (i.e. a function annotated with [kotlin.test.Test]) inside of a [TestFile].
*/
internal data class TestFunction(val packageName: PackageName, val functionName: FunctionName)
/** /**
* Represents a single file that will be supplied to the compiler. * Represents a single file that will be supplied to the compiler.
*/ */
@@ -5,7 +5,7 @@
package org.jetbrains.kotlin.konan.blackboxtest.support package org.jetbrains.kotlin.konan.blackboxtest.support
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestName import org.jetbrains.kotlin.konan.blackboxtest.support.util.startsWith
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertFalse import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertFalse
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.io.File import java.io.File
@@ -26,45 +26,27 @@ internal sealed interface TestRunParameter {
fun applyTo(programArgs: MutableList<String>) fun applyTo(programArgs: MutableList<String>)
sealed class WithFilter : TestRunParameter { sealed class WithFilter : TestRunParameter {
abstract fun testMatches(testName: String): Boolean abstract fun testMatches(testName: TestName): Boolean
} }
class WithPackageFilter(packageName: PackageName) : WithFilter() { class WithPackageFilter(private val packageName: PackageName) : WithFilter() {
init { init {
assertFalse(packageName.isEmpty()) assertFalse(packageName.isEmpty())
} }
private val packagePrefix = "$packageName."
override fun applyTo(programArgs: MutableList<String>) { override fun applyTo(programArgs: MutableList<String>) {
programArgs += "--ktest_filter=$packagePrefix*" programArgs += "--ktest_filter=$packageName.*"
} }
override fun testMatches(testName: TestName) = testName.startsWith(packagePrefix) override fun testMatches(testName: TestName) = testName.packageName.startsWith(packageName)
} }
class WithFunctionFilter(val testFunction: TestFunction) : WithFilter() { class WithTestFilter(val testName: TestName) : WithFilter() {
private val packagePrefix = if (testFunction.packageName.isEmpty()) "" else "${testFunction.packageName}."
override fun applyTo(programArgs: MutableList<String>) { override fun applyTo(programArgs: MutableList<String>) {
programArgs += "--ktest_regex_filter=${packagePrefix.replace(".", "\\.")}([^\\.]+)\\.${testFunction.functionName}" programArgs += "--ktest_filter=$testName"
} }
override fun testMatches(testName: String): Boolean { override fun testMatches(testName: TestName) = this.testName == testName
val remainder = if (packagePrefix.isNotEmpty()) {
if (!testName.startsWith(packagePrefix)) return false
testName.substringAfter(packagePrefix)
} else
testName
val suffix = remainder
.split('.')
.takeIf { it.size == 2 }
?.last()
?: return false
return suffix == testFunction.functionName
}
} }
object WithTCTestLogger : TestRunParameter { object WithTCTestLogger : TestRunParameter {
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.NoTestRunnerExtr
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilationResult.Companion.assertSuccess 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.group.TestCaseGroupProvider
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.AbstractRunner import org.jetbrains.kotlin.konan.blackboxtest.support.runner.AbstractRunner
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.LocalTestFunctionExtractor import org.jetbrains.kotlin.konan.blackboxtest.support.runner.LocalTestNameExtractor
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.LocalTestRunner import org.jetbrains.kotlin.konan.blackboxtest.support.runner.LocalTestRunner
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.GlobalSettings import org.jetbrains.kotlin.konan.blackboxtest.support.settings.GlobalSettings
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings
@@ -32,7 +32,7 @@ internal class TestRunProvider(
) : ExtensionContext.Store.CloseableResource { ) : ExtensionContext.Store.CloseableResource {
private val compilationFactory = TestCompilationFactory(settings) private val compilationFactory = TestCompilationFactory(settings)
private val cachedCompilations = ThreadSafeCache<TestCompilationCacheKey, TestCompilation>() private val cachedCompilations = ThreadSafeCache<TestCompilationCacheKey, TestCompilation>()
private val cachedTestFunctions = ThreadSafeCache<TestCompilationCacheKey, Collection<TestFunction>>() private val cachedTestNames = ThreadSafeCache<TestCompilationCacheKey, Collection<TestName>>()
fun setProcessors(testDataFile: File, sourceTransformers: List<(String) -> String>) { fun setProcessors(testDataFile: File, sourceTransformers: List<(String) -> String>) {
testCaseGroupProvider.setPreprocessors(testDataFile, sourceTransformers) testCaseGroupProvider.setPreprocessors(testDataFile, sourceTransformers)
@@ -64,7 +64,7 @@ internal class TestRunProvider(
* } * }
*/ */
fun getSingleTestRun(testCaseId: TestCaseId): TestRun = withTestExecutable(testCaseId) { testCase, executable, _ -> fun getSingleTestRun(testCaseId: TestCaseId): TestRun = withTestExecutable(testCaseId) { testCase, executable, _ ->
val runParameters = getRunParameters(testCase, testFunction = null) val runParameters = getRunParameters(testCase, testName = null)
TestRun(displayName = /* Unimportant. Used only in dynamic tests. */ "", executable, runParameters, testCase.id) TestRun(displayName = /* Unimportant. Used only in dynamic tests. */ "", executable, runParameters, testCase.id)
} }
@@ -101,24 +101,24 @@ internal class TestRunProvider(
fun getTestRuns( fun getTestRuns(
testCaseId: TestCaseId testCaseId: TestCaseId
): Collection<TreeNode<TestRun>> = withTestExecutable(testCaseId) { testCase, executable, cacheKey -> ): Collection<TreeNode<TestRun>> = withTestExecutable(testCaseId) { testCase, executable, cacheKey ->
fun createTestRun(testRunName: String, testFunction: TestFunction?): TestRun { fun createTestRun(testRunName: String, testName: TestName?): TestRun {
val runParameters = getRunParameters(testCase, testFunction) val runParameters = getRunParameters(testCase, testName)
return TestRun(testRunName, executable, runParameters, testCase.id) return TestRun(testRunName, executable, runParameters, testCase.id)
} }
when (testCase.kind) { when (testCase.kind) {
TestKind.STANDALONE_NO_TR -> { TestKind.STANDALONE_NO_TR -> {
val testRunName = testCase.extras<NoTestRunnerExtras>().entryPoint.substringAfterLast('.') val testRunName = testCase.extras<NoTestRunnerExtras>().entryPoint.substringAfterLast('.')
val testRun = createTestRun(testRunName, testFunction = null) val testRun = createTestRun(testRunName, testName = null)
TreeNode.oneLevel(testRun) TreeNode.oneLevel(testRun)
} }
TestKind.REGULAR, TestKind.STANDALONE -> { TestKind.REGULAR, TestKind.STANDALONE -> {
val testFunctions = cachedTestFunctions.computeIfAbsent(cacheKey) { val testNames = cachedTestNames.computeIfAbsent(cacheKey) {
extractTestFunctions(executable) extractTestNames(executable)
}.filterIrrelevant(testCase) }.filterIrrelevant(testCase)
testFunctions.buildTree(TestFunction::packageName) { testFunction -> testNames.buildTree(TestName::packageName) { testName ->
createTestRun(testFunction.functionName, testFunction) createTestRun(testName.functionName, testName)
} }
} }
} }
@@ -159,10 +159,10 @@ internal class TestRunProvider(
return action(testCase, executable, cacheKey) return action(testCase, executable, cacheKey)
} }
private fun getRunParameters(testCase: TestCase, testFunction: TestFunction?): List<TestRunParameter> = with(testCase) { private fun getRunParameters(testCase: TestCase, testName: TestName?): List<TestRunParameter> = with(testCase) {
when (kind) { when (kind) {
TestKind.STANDALONE_NO_TR -> { TestKind.STANDALONE_NO_TR -> {
assertTrue(testFunction == null) assertTrue(testName == null)
listOfNotNull( listOfNotNull(
extras<NoTestRunnerExtras>().inputDataFile?.let(TestRunParameter::WithInputData), extras<NoTestRunnerExtras>().inputDataFile?.let(TestRunParameter::WithInputData),
expectedOutputDataFile?.let(TestRunParameter::WithExpectedOutputData) expectedOutputDataFile?.let(TestRunParameter::WithExpectedOutputData)
@@ -170,12 +170,12 @@ internal class TestRunProvider(
} }
TestKind.STANDALONE -> listOfNotNull( TestKind.STANDALONE -> listOfNotNull(
TestRunParameter.WithTCTestLogger, TestRunParameter.WithTCTestLogger,
testFunction?.let(TestRunParameter::WithFunctionFilter), testName?.let(TestRunParameter::WithTestFilter),
expectedOutputDataFile?.let(TestRunParameter::WithExpectedOutputData) expectedOutputDataFile?.let(TestRunParameter::WithExpectedOutputData)
) )
TestKind.REGULAR -> listOfNotNull( TestKind.REGULAR -> listOfNotNull(
TestRunParameter.WithTCTestLogger, TestRunParameter.WithTCTestLogger,
testFunction?.let(TestRunParameter::WithFunctionFilter) ?: TestRunParameter.WithPackageFilter(nominalPackageName), testName?.let(TestRunParameter::WithTestFilter) ?: TestRunParameter.WithPackageFilter(nominalPackageName),
expectedOutputDataFile?.let(TestRunParameter::WithExpectedOutputData) expectedOutputDataFile?.let(TestRunParameter::WithExpectedOutputData)
) )
} }
@@ -189,17 +189,17 @@ internal class TestRunProvider(
runningAtNonHostTarget() runningAtNonHostTarget()
} }
// Currently, only local test function extractor is supported. // Currently, only local test name extractor is supported.
private fun extractTestFunctions(executable: TestExecutable): Collection<TestFunction> = with(settings.get<GlobalSettings>()) { private fun extractTestNames(executable: TestExecutable): Collection<TestName> = with(settings.get<GlobalSettings>()) {
if (target == hostTarget) if (target == hostTarget)
LocalTestFunctionExtractor(executable, executionTimeout).run() LocalTestNameExtractor(executable, executionTimeout).run()
else else
runningAtNonHostTarget() runningAtNonHostTarget()
} }
private fun Collection<TestFunction>.filterIrrelevant(testCase: TestCase) = private fun Collection<TestName>.filterIrrelevant(testCase: TestCase) =
if (testCase.kind == TestKind.REGULAR) if (testCase.kind == TestKind.REGULAR)
filter { testFunction -> testFunction.packageName.startsWith(testCase.nominalPackageName) } filter { testName -> testName.packageName.startsWith(testCase.nominalPackageName) }
else else
this this
@@ -7,17 +7,17 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.runner
import org.jetbrains.kotlin.konan.blackboxtest.support.LoggedData import org.jetbrains.kotlin.konan.blackboxtest.support.LoggedData
import org.jetbrains.kotlin.konan.blackboxtest.support.TestExecutable import org.jetbrains.kotlin.konan.blackboxtest.support.TestExecutable
import org.jetbrains.kotlin.konan.blackboxtest.support.TestFunction import org.jetbrains.kotlin.konan.blackboxtest.support.TestName
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestOutputFilter import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestOutputFilter
import org.jetbrains.kotlin.konan.blackboxtest.support.util.parseGTestListing import org.jetbrains.kotlin.konan.blackboxtest.support.util.parseGTestListing
import org.jetbrains.kotlin.test.services.JUnit5Assertions import org.jetbrains.kotlin.test.services.JUnit5Assertions
import kotlin.time.Duration import kotlin.time.Duration
internal class LocalTestFunctionExtractor( internal class LocalTestNameExtractor(
override val executable: TestExecutable, override val executable: TestExecutable,
executionTimeout: Duration executionTimeout: Duration
) : AbstractLocalProcessRunner<Collection<TestFunction>>(executionTimeout) { ) : AbstractLocalProcessRunner<Collection<TestName>>(executionTimeout) {
override val visibleProcessName get() = "Test function extractor" override val visibleProcessName get() = "Test name extractor"
override val programArgs = listOf(executable.executableFile.path, "--ktest_list_tests") override val programArgs = listOf(executable.executableFile.path, "--ktest_list_tests")
override val outputFilter get() = TestOutputFilter.NO_FILTERING override val outputFilter get() = TestOutputFilter.NO_FILTERING
@@ -32,12 +32,12 @@ internal class LocalTestFunctionExtractor(
override fun handleUnexpectedFailure(t: Throwable) = JUnit5Assertions.fail { override fun handleUnexpectedFailure(t: Throwable) = JUnit5Assertions.fail {
LoggedData.TestRunUnexpectedFailure(getLoggedParameters(), t) LoggedData.TestRunUnexpectedFailure(getLoggedParameters(), t)
.withErrorMessage("Test function extraction failed with unexpected exception.") .withErrorMessage("Test name extraction failed with unexpected exception.")
} }
inner class ResultHandler( inner class ResultHandler(
runResult: RunResult.Completed runResult: RunResult.Completed
) : AbstractLocalProcessRunner<Collection<TestFunction>>.ResultHandler(runResult) { ) : AbstractLocalProcessRunner<Collection<TestName>>.ResultHandler(runResult) {
override fun getLoggedRun() = LoggedData.TestRun(getLoggedParameters(), runResult) override fun getLoggedRun() = LoggedData.TestRun(getLoggedParameters(), runResult)
override fun doHandle() = parseGTestListing(runResult.processOutput.stdOut.filteredOutput) override fun doHandle() = parseGTestListing(runResult.processOutput.stdOut.filteredOutput)
} }
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.runner
import com.intellij.openapi.util.text.StringUtilRt.convertLineSeparators import com.intellij.openapi.util.text.StringUtilRt.convertLineSeparators
import org.jetbrains.kotlin.konan.blackboxtest.support.* import org.jetbrains.kotlin.konan.blackboxtest.support.*
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TCTestOutputFilter import org.jetbrains.kotlin.konan.blackboxtest.support.util.TCTestOutputFilter
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestName
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestOutputFilter import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestOutputFilter
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestReport import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestReport
import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
@@ -5,31 +5,33 @@
package org.jetbrains.kotlin.konan.blackboxtest.support.util package org.jetbrains.kotlin.konan.blackboxtest.support.util
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName import org.jetbrains.kotlin.konan.blackboxtest.support.TestName
import org.jetbrains.kotlin.konan.blackboxtest.support.TestFunction
import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail
import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.konan.blackboxtest.support.util.GTestListingParseState as State import org.jetbrains.kotlin.konan.blackboxtest.support.util.GTestListingParseState as State
/** /**
* Extracts [TestFunction]s from GTest listing. * Extracts [TestName]s from GTest listing.
* *
* Example: * Example:
* sample.test.SampleTestKt. * sample.test.SampleTestKt.
* one * one
* two * two
* *
* yields TestFunction(sample.test, one) and TestFunction(sample.test, two). * yields TestName(packageName = "sample.test", packagePartClassName = "SampleTestKt", functionName = "one")
* and TestName(packageName = "sample.test", packagePartClassName = "SampleTestKt", functionName = "two")
*/ */
internal fun parseGTestListing(rawGTestListing: String): Collection<TestFunction> = buildList { internal fun parseGTestListing(listing: String): Collection<TestName> = buildList {
var state: State = State.Begin var state: State = State.Begin
rawGTestListing.lineSequence().forEachIndexed { index, line -> listing.lineSequence().forEachIndexed { index, line ->
fun parseError(message: String): Nothing = fail { fun parseError(message: String): Nothing = fail {
buildString { buildString {
appendLine("$message at line #$index: \"$line\"") appendLine("$message at line #$index: \"$line\"")
appendLine() appendLine()
appendLine("Full listing:") appendLine("Full listing:")
appendLine(rawGTestListing) appendLine(listing)
} }
} }
@@ -39,21 +41,18 @@ internal fun parseGTestListing(rawGTestListing: String): Collection<TestFunction
is State.NewTest, is State.End -> State.End is State.NewTest, is State.End -> State.End
else -> parseError("Unexpected empty line") else -> parseError("Unexpected empty line")
} }
line[0].isWhitespace() -> when (val s = state) { line[0].isWhitespace() -> when (state) {
is State.HasPackageName -> { is State.NewTestSuite,
this += TestFunction(s.packageName, line.trim()) is State.NewTest -> {
State.NewTest(s.packageName) val testSuite = state.testSuite
this += TestName(testSuite.testSuiteNameWithDotSuffix + line.trim())
State.NewTest(testSuite)
} }
else -> parseError("Test name encountered before test suite name") else -> parseError("Test name encountered before test suite name")
} }
else -> when (state) { else -> when (state) {
is State.Begin, is State.NewTest -> { is State.Begin, is State.NewTest -> {
val packageSegments = line.trimEnd().removeSuffix(".").split('.') State.NewTestSuite(line.trimEnd())
if (packageSegments.isEmpty()) parseError("Malformed test suite name")
// Drop the last part because it is related to class name (or file-class name).
// TODO: How to handle nested classes?
State.NewTestSuite(PackageName(packageSegments.dropLast(1)))
} }
else -> parseError("Unexpected test suite name") else -> parseError("Unexpected test suite name")
} }
@@ -64,13 +63,13 @@ internal fun parseGTestListing(rawGTestListing: String): Collection<TestFunction
private sealed interface GTestListingParseState { private sealed interface GTestListingParseState {
object Begin : State object Begin : State
object End : State object End : State
class NewTestSuite(override val packageName: PackageName) : State, HasPackageName
class NewTest(override val packageName: PackageName) : State, HasPackageName
interface HasPackageName { class NewTestSuite(val testSuiteNameWithDotSuffix: String) : State
val packageName: PackageName class NewTest(val testSuite: NewTestSuite) : State
}
} }
private inline val State.testSuite: State.NewTestSuite
get() = safeAs<State.NewTestSuite>() ?: cast<State.NewTest>().testSuite
// The very first line of stdlib test output may contain seed of Random. Such line should be ignored. // The very first line of stdlib test output may contain seed of Random. Such line should be ignored.
private const val STDLIB_TESTS_IGNORED_LINE_PREFIX = "Seed: " private const val STDLIB_TESTS_IGNORED_LINE_PREFIX = "Seed: "
@@ -6,15 +6,13 @@
package org.jetbrains.kotlin.konan.blackboxtest.support.util package org.jetbrains.kotlin.konan.blackboxtest.support.util
import jetbrains.buildServer.messages.serviceMessages.* import jetbrains.buildServer.messages.serviceMessages.*
import org.jetbrains.kotlin.konan.blackboxtest.support.FunctionName import org.jetbrains.kotlin.konan.blackboxtest.support.TestName
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
import org.jetbrains.kotlin.utils.addToStdlib.cast import org.jetbrains.kotlin.utils.addToStdlib.cast
import org.jetbrains.kotlin.utils.addToStdlib.safeAs import org.jetbrains.kotlin.utils.addToStdlib.safeAs
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TCTestReportParseState as State import org.jetbrains.kotlin.konan.blackboxtest.support.util.TCTestReportParseState as State
import java.text.ParseException import java.text.ParseException
internal typealias TestName = String
internal class TestReport( internal class TestReport(
val passedTests: Collection<TestName>, val passedTests: Collection<TestName>,
val failedTests: Collection<TestName>, val failedTests: Collection<TestName>,
@@ -120,25 +118,25 @@ private class TCTestMessageParserCallback : ServiceMessageParserCallback {
is TestIgnored -> when (state) { is TestIgnored -> when (state) {
is State.TestSuiteStarted, is State.TestSuiteStarted,
is State.TestIgnored, is State.TestIgnored,
is State.TestFinished -> State.TestIgnored(state.testSuite, message.functionName).also { ignoredTests += it.testName } is State.TestFinished -> State.TestIgnored(state.testSuite, message.simpleTestName).also { ignoredTests += it.testName }
else -> unexpectedMessage() else -> unexpectedMessage()
} }
is TestStarted -> when (state) { is TestStarted -> when (state) {
is State.TestSuiteStarted, is State.TestSuiteStarted,
is State.TestIgnored, is State.TestIgnored,
is State.TestFinished -> State.TestStarted(state.testSuite, message.testName) is State.TestFinished -> State.TestStarted(state.testSuite, message.simpleTestName)
else -> unexpectedMessage() else -> unexpectedMessage()
} }
is TestFailed -> when (val s = state) { is TestFailed -> when (val s = state) {
is State.TestStarted -> { is State.TestStarted -> {
nonTestOutput.append(message.stacktrace) nonTestOutput.append(message.stacktrace)
State.TestFailed(s.testSuite, message.testName).also { failedTests += it.testName } State.TestFailed(s.testSuite, message.simpleTestName).also { failedTests += it.testName }
} }
else -> unexpectedMessage() else -> unexpectedMessage()
} }
is TestFinished -> when (state) { is TestFinished -> when (state) {
is State.TestStarted -> State.TestFinished(state.testSuite, message.testName).also { passedTests += it.testName } is State.TestStarted -> State.TestFinished(state.testSuite, message.simpleTestName).also { passedTests += it.testName }
is State.TestFailed -> State.TestFinished(state.testSuite, message.testName) is State.TestFailed -> State.TestFinished(state.testSuite, message.simpleTestName)
else -> unexpectedMessage() else -> unexpectedMessage()
} }
else -> { else -> {
@@ -172,17 +170,17 @@ private sealed interface TCTestReportParseState {
class TestSuiteStarted(val testSuiteName: String) : State class TestSuiteStarted(val testSuiteName: String) : State
object TestSuiteFinished : State object TestSuiteFinished : State
sealed class TestState(val testSuite: TestSuiteStarted, val functionName: FunctionName) : State { sealed class TestState(val testSuite: TestSuiteStarted, val simpleTestName: String) : State {
val testName: TestName get() = "${testSuite.testSuiteName}.$functionName" val testName: TestName get() = TestName("${testSuite.testSuiteName}.$simpleTestName")
} }
class TestIgnored(testSuite: TestSuiteStarted, functionName: FunctionName) : TestState(testSuite, functionName) class TestIgnored(testSuite: TestSuiteStarted, simpleTestName: String) : TestState(testSuite, simpleTestName)
class TestStarted(testSuite: TestSuiteStarted, functionName: FunctionName) : TestState(testSuite, functionName) class TestStarted(testSuite: TestSuiteStarted, simpleTestName: String) : TestState(testSuite, simpleTestName)
class TestFailed(testSuite: TestSuiteStarted, functionName: FunctionName) : TestState(testSuite, functionName) class TestFailed(testSuite: TestSuiteStarted, simpleTestName: String) : TestState(testSuite, simpleTestName)
class TestFinished(testSuite: TestSuiteStarted, functionName: FunctionName) : TestState(testSuite, functionName) class TestFinished(testSuite: TestSuiteStarted, simpleTestName: String) : TestState(testSuite, simpleTestName)
} }
private val State.testSuite: State.TestSuiteStarted private inline val State.testSuite: State.TestSuiteStarted
get() = if (this is State.TestSuiteStarted) this else cast<State.TestState>().testSuite get() = if (this is State.TestSuiteStarted) this else cast<State.TestState>().testSuite
private val BaseTestMessage.functionName: FunctionName get() = testName private inline val BaseTestMessage.simpleTestName get() = testName