[Native][tests] Drop TestFunction/FunctionName, introduce TestName instead
This commit is contained in:
+35
@@ -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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+8
-26
@@ -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 {
|
||||||
|
|||||||
+19
-19
@@ -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
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -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)
|
||||||
}
|
}
|
||||||
-1
@@ -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
|
||||||
|
|||||||
+21
-22
@@ -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: "
|
||||||
|
|||||||
+14
-16
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user