[Native][tests] Rework PackageName entity
This commit is contained in:
+7
-6
@@ -7,10 +7,11 @@ package org.jetbrains.kotlin.konan.blackboxtest
|
|||||||
|
|
||||||
import com.intellij.testFramework.TestDataFile
|
import com.intellij.testFramework.TestDataFile
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.*
|
import org.jetbrains.kotlin.konan.blackboxtest.support.*
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TreeNode
|
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.getAbsoluteFile
|
import org.jetbrains.kotlin.konan.blackboxtest.support.TestCaseId
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.joinPackageNames
|
import org.jetbrains.kotlin.konan.blackboxtest.support.TestRun
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.prependPackageName
|
import org.jetbrains.kotlin.konan.blackboxtest.support.TestRunProvider
|
||||||
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
|
||||||
import org.junit.jupiter.api.DynamicNode
|
import org.junit.jupiter.api.DynamicNode
|
||||||
import org.junit.jupiter.api.DynamicTest.dynamicTest
|
import org.junit.jupiter.api.DynamicTest.dynamicTest
|
||||||
import org.junit.jupiter.api.extension.ExtendWith
|
import org.junit.jupiter.api.extension.ExtendWith
|
||||||
@@ -89,7 +90,7 @@ abstract class AbstractNativeBlackBoxTest {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
buildList {
|
buildList {
|
||||||
fun TreeNode<TestRun>.processItems(parentPackageSegment: String) {
|
fun TreeNode<TestRun>.processItems(parentPackageSegment: PackageName) {
|
||||||
val ownPackageSegment = joinPackageNames(parentPackageSegment, packageSegment)
|
val ownPackageSegment = joinPackageNames(parentPackageSegment, packageSegment)
|
||||||
items.mapTo(this@buildList) { testRun ->
|
items.mapTo(this@buildList) { testRun ->
|
||||||
val displayName = testRun.displayName.prependPackageName(ownPackageSegment)
|
val displayName = testRun.displayName.prependPackageName(ownPackageSegment)
|
||||||
@@ -99,7 +100,7 @@ abstract class AbstractNativeBlackBoxTest {
|
|||||||
children.forEach { it.processItems(ownPackageSegment) }
|
children.forEach { it.processItems(ownPackageSegment) }
|
||||||
}
|
}
|
||||||
|
|
||||||
testRunNodes.forEach { testRunNode -> testRunNode.processItems("") }
|
testRunNodes.forEach { testRunNode -> testRunNode.processItems(PackageName.EMPTY) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun performTestRun(testRun: TestRun) {
|
private fun performTestRun(testRun: TestRun) {
|
||||||
|
|||||||
+6
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.konan.blackboxtest
|
package org.jetbrains.kotlin.konan.blackboxtest
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.compressedName
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.compressedName
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.compressedPackageName
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.compressedPackageName
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.compressedSimpleName
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.compressedSimpleName
|
||||||
@@ -90,4 +91,9 @@ class TestInfra_CompressedNamesTest {
|
|||||||
"foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz".compressedPackageName
|
"foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz.foo.bar.baz".compressedPackageName
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val String.compressedPackageName
|
||||||
|
get() = PackageName(this).compressedPackageName
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.konan.blackboxtest.support
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a package name.
|
||||||
|
*/
|
||||||
|
internal class PackageName private constructor(private val fqn: String, val segments: List<String>) {
|
||||||
|
constructor(segments: List<String>) : this(segments.joinToString("."), segments)
|
||||||
|
constructor(fqn: String) : this(fqn, if (fqn.isNotEmpty()) fqn.split('.') else emptyList())
|
||||||
|
|
||||||
|
fun isEmpty(): Boolean = segments.isEmpty()
|
||||||
|
|
||||||
|
override fun toString() = fqn
|
||||||
|
override fun equals(other: Any?) = fqn == (other as? PackageName)?.fqn
|
||||||
|
override fun hashCode() = fqn.hashCode()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val EMPTY = PackageName("", emptyList())
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
-3
@@ -15,13 +15,12 @@ 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 PackageFQN = String
|
|
||||||
internal typealias FunctionName = String
|
internal typealias FunctionName = String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a single test function (i.e. a function annotated with [kotlin.test.Test]) inside of a [TestFile].
|
* Represents a single test function (i.e. a function annotated with [kotlin.test.Test]) inside of a [TestFile].
|
||||||
*/
|
*/
|
||||||
internal data class TestFunction(val packageName: PackageFQN, val functionName: FunctionName)
|
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.
|
||||||
@@ -179,7 +178,7 @@ internal class TestCase(
|
|||||||
val kind: TestKind,
|
val kind: TestKind,
|
||||||
val modules: Set<TestModule.Exclusive>,
|
val modules: Set<TestModule.Exclusive>,
|
||||||
val freeCompilerArgs: TestCompilerArgs,
|
val freeCompilerArgs: TestCompilerArgs,
|
||||||
val nominalPackageName: PackageFQN,
|
val nominalPackageName: PackageName,
|
||||||
val expectedOutputDataFile: File?,
|
val expectedOutputDataFile: File?,
|
||||||
val extras: Extras
|
val extras: Extras
|
||||||
) {
|
) {
|
||||||
|
|||||||
+3
-3
@@ -113,7 +113,7 @@ internal class TestCompilationFactory(private val settings: Settings) {
|
|||||||
private fun multiModuleArtifactFile(modules: Collection<TestModule>, extension: String): File {
|
private fun multiModuleArtifactFile(modules: Collection<TestModule>, extension: String): File {
|
||||||
var filesCount = 0
|
var filesCount = 0
|
||||||
var hash = 0
|
var hash = 0
|
||||||
val uniquePackageNames = hashSetOf<PackageFQN>()
|
val uniquePackageNames = hashSetOf<PackageName>()
|
||||||
|
|
||||||
modules.forEach { module ->
|
modules.forEach { module ->
|
||||||
module.files.forEach { file ->
|
module.files.forEach { file ->
|
||||||
@@ -132,7 +132,7 @@ internal class TestCompilationFactory(private val settings: Settings) {
|
|||||||
repeat(4 - prefix.length) { append('0') }
|
repeat(4 - prefix.length) { append('0') }
|
||||||
append(prefix).append('-')
|
append(prefix).append('-')
|
||||||
|
|
||||||
if (commonPackageName != null)
|
if (!commonPackageName.isEmpty())
|
||||||
append(commonPackageName.compressedPackageName).append('-')
|
append(commonPackageName.compressedPackageName).append('-')
|
||||||
|
|
||||||
append(prettyHash(hash))
|
append(prettyHash(hash))
|
||||||
@@ -143,7 +143,7 @@ internal class TestCompilationFactory(private val settings: Settings) {
|
|||||||
return artifactDirForPackageName(commonPackageName).resolve(artifactFileName)
|
return artifactDirForPackageName(commonPackageName).resolve(artifactFileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun artifactDirForPackageName(packageName: PackageFQN?): File {
|
private fun artifactDirForPackageName(packageName: PackageName?): File {
|
||||||
val baseDir = settings.get<Binaries>().testBinariesDir
|
val baseDir = settings.get<Binaries>().testBinariesDir
|
||||||
val outputDir = if (packageName != null) baseDir.resolve(packageName.compressedPackageName) else baseDir
|
val outputDir = if (packageName != null) baseDir.resolve(packageName.compressedPackageName) else baseDir
|
||||||
|
|
||||||
|
|||||||
+6
-5
@@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.konan.blackboxtest.support
|
package org.jetbrains.kotlin.konan.blackboxtest.support
|
||||||
|
|
||||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TestName
|
||||||
|
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
|
||||||
|
|
||||||
@@ -28,9 +29,9 @@ internal sealed interface TestRunParameter {
|
|||||||
abstract fun testMatches(testName: String): Boolean
|
abstract fun testMatches(testName: String): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
class WithPackageFilter(packageName: PackageFQN) : WithFilter() {
|
class WithPackageFilter(packageName: PackageName) : WithFilter() {
|
||||||
init {
|
init {
|
||||||
assertTrue(packageName.isNotEmpty())
|
assertFalse(packageName.isEmpty())
|
||||||
}
|
}
|
||||||
|
|
||||||
private val packagePrefix = "$packageName."
|
private val packagePrefix = "$packageName."
|
||||||
@@ -39,11 +40,11 @@ internal sealed interface TestRunParameter {
|
|||||||
programArgs += "--ktest_filter=$packagePrefix*"
|
programArgs += "--ktest_filter=$packagePrefix*"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun testMatches(testName: String) = testName.startsWith(packagePrefix)
|
override fun testMatches(testName: TestName) = testName.startsWith(packagePrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
class WithFunctionFilter(val testFunction: TestFunction) : WithFilter() {
|
class WithFunctionFilter(val testFunction: TestFunction) : WithFilter() {
|
||||||
private val packagePrefix = if (testFunction.packageName.isNotEmpty()) "${testFunction.packageName}." else ""
|
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_regex_filter=${packagePrefix.replace(".", "\\.")}([^\\.]+)\\.${testFunction.functionName}"
|
||||||
|
|||||||
+2
-2
@@ -16,10 +16,10 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.runner.LocalTestFunctionE
|
|||||||
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
|
||||||
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.ThreadSafeCache
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.ThreadSafeCache
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TreeNode
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.TreeNode
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.buildTree
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.buildTree
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.isSameOrSubpackageOf
|
|
||||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
|
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 org.junit.jupiter.api.Assumptions.assumeTrue
|
import org.junit.jupiter.api.Assumptions.assumeTrue
|
||||||
@@ -199,7 +199,7 @@ internal class TestRunProvider(
|
|||||||
|
|
||||||
private fun Collection<TestFunction>.filterIrrelevant(testCase: TestCase) =
|
private fun Collection<TestFunction>.filterIrrelevant(testCase: TestCase) =
|
||||||
if (testCase.kind == TestKind.REGULAR)
|
if (testCase.kind == TestKind.REGULAR)
|
||||||
filter { testFunction -> testFunction.packageName.isSameOrSubpackageOf(testCase.nominalPackageName) }
|
filter { testFunction -> testFunction.packageName.startsWith(testCase.nominalPackageName) }
|
||||||
else
|
else
|
||||||
this
|
this
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -279,7 +279,7 @@ private class ExtTestDataFile(
|
|||||||
private fun patchPackageNames(isStandaloneTest: Boolean) = with(structure) {
|
private fun patchPackageNames(isStandaloneTest: Boolean) = with(structure) {
|
||||||
if (isStandaloneTest) return // Don't patch packages for standalone tests.
|
if (isStandaloneTest) return // Don't patch packages for standalone tests.
|
||||||
|
|
||||||
val basePackageName = FqName(testDataFileSettings.nominalPackageName)
|
val basePackageName = FqName(testDataFileSettings.nominalPackageName.toString())
|
||||||
|
|
||||||
val oldPackageNames: Set<FqName> = filesToTransform.mapToSet { it.packageFqName }
|
val oldPackageNames: Set<FqName> = filesToTransform.mapToSet { it.packageFqName }
|
||||||
val oldToNewPackageNameMapping: Map<FqName, FqName> = oldPackageNames.associateWith { oldPackageName ->
|
val oldToNewPackageNameMapping: Map<FqName, FqName> = oldPackageNames.associateWith { oldPackageName ->
|
||||||
@@ -650,7 +650,7 @@ private class ExtTestDataFileSettings(
|
|||||||
val optInsForCompiler: Set<String>,
|
val optInsForCompiler: Set<String>,
|
||||||
val expectActualLinker: Boolean,
|
val expectActualLinker: Boolean,
|
||||||
val generatedSourcesDir: File,
|
val generatedSourcesDir: File,
|
||||||
val nominalPackageName: PackageFQN
|
val nominalPackageName: PackageName
|
||||||
)
|
)
|
||||||
|
|
||||||
private typealias SharedModuleGenerator = (sharedModulesDir: File) -> TestModule.Shared?
|
private typealias SharedModuleGenerator = (sharedModulesDir: File) -> TestModule.Shared?
|
||||||
|
|||||||
+1
-1
@@ -58,7 +58,7 @@ internal class PredefinedTestCaseGroupProvider(annotation: PredefinedTestCases)
|
|||||||
modules = setOf(module),
|
modules = setOf(module),
|
||||||
freeCompilerArgs = predefinedTestCase.freeCompilerArgs
|
freeCompilerArgs = predefinedTestCase.freeCompilerArgs
|
||||||
.parseCompilerArgs { "Failed to parse free compiler arguments for test case $testCaseId" },
|
.parseCompilerArgs { "Failed to parse free compiler arguments for test case $testCaseId" },
|
||||||
nominalPackageName = testCaseId.uniqueName,
|
nominalPackageName = PackageName(testCaseId.uniqueName),
|
||||||
expectedOutputDataFile = null,
|
expectedOutputDataFile = null,
|
||||||
extras = WithTestRunnerExtras
|
extras = WithTestRunnerExtras
|
||||||
)
|
)
|
||||||
|
|||||||
+2
-2
@@ -221,7 +221,7 @@ internal class StandardTestCaseGroupProvider(private val settings: Settings) : T
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun fixPackageNames(testModules: Collection<TestModule.Exclusive>, basePackageName: PackageFQN, testDataFile: File) {
|
private fun fixPackageNames(testModules: Collection<TestModule.Exclusive>, basePackageName: PackageName, testDataFile: File) {
|
||||||
testModules.forEach { testModule ->
|
testModules.forEach { testModule ->
|
||||||
testModule.files.forEach { testFile ->
|
testModule.files.forEach { testFile ->
|
||||||
val firstMeaningfulLine = testFile.text.dropNonMeaningfulLines().firstOrNull()
|
val firstMeaningfulLine = testFile.text.dropNonMeaningfulLines().firstOrNull()
|
||||||
@@ -230,7 +230,7 @@ internal class StandardTestCaseGroupProvider(private val settings: Settings) : T
|
|||||||
val existingPackageName = firstMeaningfulLine?.getExistingPackageName()
|
val existingPackageName = firstMeaningfulLine?.getExistingPackageName()
|
||||||
if (existingPackageName != null) {
|
if (existingPackageName != null) {
|
||||||
// Validate it.
|
// Validate it.
|
||||||
assertTrue(existingPackageName.isSameOrSubpackageOf(basePackageName)) {
|
assertTrue(existingPackageName.startsWith(basePackageName)) {
|
||||||
val location = Location(testDataFile, firstMeaningfulLine.number)
|
val location = Location(testDataFile, firstMeaningfulLine.number)
|
||||||
"""
|
"""
|
||||||
$location: Invalid package name declaration found: $firstMeaningfulLine
|
$location: Invalid package name declaration found: $firstMeaningfulLine
|
||||||
|
|||||||
+3
-3
@@ -6,7 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
||||||
|
|
||||||
import org.apache.commons.lang.StringUtils.splitByCharacterTypeCamelCase
|
import org.apache.commons.lang.StringUtils.splitByCharacterTypeCamelCase
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageFQN
|
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName
|
||||||
import org.jetbrains.kotlin.konan.target.Architecture
|
import org.jetbrains.kotlin.konan.target.Architecture
|
||||||
import org.jetbrains.kotlin.konan.target.Family
|
import org.jetbrains.kotlin.konan.target.Family
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
@@ -48,9 +48,9 @@ internal val Architecture.compressedName: String
|
|||||||
internal val Class<*>.compressedSimpleName: String
|
internal val Class<*>.compressedSimpleName: String
|
||||||
get() = splitByCharacterTypeCamelCase(simpleName).joinToString("") { it.take(3) }
|
get() = splitByCharacterTypeCamelCase(simpleName).joinToString("") { it.take(3) }
|
||||||
|
|
||||||
internal val PackageFQN.compressedPackageName: String
|
internal val PackageName.compressedPackageName: String
|
||||||
get() {
|
get() {
|
||||||
val sanitizedName = replace('.', '_')
|
val sanitizedName = segments.joinToString("_")
|
||||||
return if (sanitizedName.length > COMPRESSED_PACKAGE_FQN_MAX_LENGTH) {
|
return if (sanitizedName.length > COMPRESSED_PACKAGE_FQN_MAX_LENGTH) {
|
||||||
val suffix = "-" + prettyHash(sanitizedName.hashCode())
|
val suffix = "-" + prettyHash(sanitizedName.hashCode())
|
||||||
sanitizedName.substring(0, COMPRESSED_PACKAGE_FQN_MAX_LENGTH - suffix.length) + suffix
|
sanitizedName.substring(0, COMPRESSED_PACKAGE_FQN_MAX_LENGTH - suffix.length) + suffix
|
||||||
|
|||||||
+32
-27
@@ -5,15 +5,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
||||||
|
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageFQN
|
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName
|
||||||
import org.jetbrains.kotlin.renderer.KeywordStringsGenerated.KEYWORDS
|
import org.jetbrains.kotlin.renderer.KeywordStringsGenerated.KEYWORDS
|
||||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
|
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertTrue
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.file.Path
|
|
||||||
import kotlin.io.path.name
|
import kotlin.io.path.name
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
internal fun computePackageName(testDataBaseDir: File, testDataFile: File): PackageFQN {
|
internal fun computePackageName(testDataBaseDir: File, testDataFile: File): PackageName {
|
||||||
assertTrue(testDataFile.startsWith(testDataBaseDir)) {
|
assertTrue(testDataFile.startsWith(testDataBaseDir)) {
|
||||||
"""
|
"""
|
||||||
The file is outside of the directory.
|
The file is outside of the directory.
|
||||||
@@ -26,13 +25,13 @@ internal fun computePackageName(testDataBaseDir: File, testDataFile: File): Pack
|
|||||||
.relativeTo(testDataBaseDir)
|
.relativeTo(testDataBaseDir)
|
||||||
.resolve(testDataFile.nameWithoutExtension)
|
.resolve(testDataFile.nameWithoutExtension)
|
||||||
.toPath()
|
.toPath()
|
||||||
.map(Path::name)
|
.map { pathSegment ->
|
||||||
.joinToString(".") { packagePart ->
|
val packageSegment = pathSegment.name
|
||||||
if (packagePart in KEYWORDS)
|
if (packageSegment in KEYWORDS)
|
||||||
"_${packagePart}_"
|
"_${packageSegment}_"
|
||||||
else
|
else
|
||||||
buildString {
|
buildString {
|
||||||
packagePart.forEachIndexed { index, ch ->
|
packageSegment.forEachIndexed { index, ch ->
|
||||||
if (ch.isJavaIdentifierPart()) {
|
if (ch.isJavaIdentifierPart()) {
|
||||||
if (index == 0 && !ch.isJavaIdentifierStart()) {
|
if (index == 0 && !ch.isJavaIdentifierStart()) {
|
||||||
// If the first character is not suitable for start, escape it with '_'.
|
// If the first character is not suitable for start, escape it with '_'.
|
||||||
@@ -46,36 +45,42 @@ internal fun computePackageName(testDataBaseDir: File, testDataFile: File): Pack
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.let(::PackageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun Set<PackageFQN>.findCommonPackageName(): PackageFQN? = when (size) {
|
internal fun Set<PackageName>.findCommonPackageName(): PackageName = when (size) {
|
||||||
0 -> null
|
0 -> PackageName.EMPTY
|
||||||
1 -> first()
|
1 -> first()
|
||||||
else -> map { packageName: PackageFQN ->
|
else -> map { packageName -> packageName.segments }
|
||||||
packageName.split('.')
|
.reduce { commonSegments: List<String>, segments: List<String> ->
|
||||||
}.reduce { commonPackageNameParts: List<String>, packageNameParts: List<String> ->
|
buildList(min(commonSegments.size, segments.size)) {
|
||||||
ArrayList<String>(min(commonPackageNameParts.size, packageNameParts.size)).apply {
|
val i = commonSegments.iterator()
|
||||||
val i = commonPackageNameParts.iterator()
|
val j = segments.iterator()
|
||||||
val j = packageNameParts.iterator()
|
|
||||||
|
|
||||||
while (i.hasNext() && j.hasNext()) {
|
while (i.hasNext() && j.hasNext()) {
|
||||||
val packageNamePart = i.next()
|
val segment = i.next()
|
||||||
if (packageNamePart == j.next()) add(packageNamePart) else break
|
if (segment == j.next()) add(segment) else break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}.takeIf { it.isNotEmpty() }?.joinToString(".")
|
.let(::PackageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun joinPackageNames(a: PackageFQN, b: PackageFQN): PackageFQN = when {
|
internal fun joinPackageNames(a: PackageName, b: PackageName): PackageName = when {
|
||||||
a.isEmpty() -> b
|
a.isEmpty() -> b
|
||||||
b.isEmpty() -> a
|
b.isEmpty() -> a
|
||||||
else -> "$a.$b"
|
else -> PackageName(a.segments + b.segments)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun String.prependPackageName(packageName: PackageFQN): String =
|
internal fun String.prependPackageName(packageName: PackageName): String =
|
||||||
if (packageName.isEmpty()) this else "$packageName.$this"
|
if (packageName.isEmpty()) this else "$packageName.$this"
|
||||||
|
|
||||||
internal fun PackageFQN.isSameOrSubpackageOf(parentPackageName: PackageFQN): Boolean =
|
internal fun PackageName.startsWith(other: PackageName): Boolean {
|
||||||
parentPackageName.isEmpty()
|
if (segments.size < other.segments.size) return false
|
||||||
|| this == parentPackageName
|
|
||||||
|| (length > parentPackageName.length && startsWith(parentPackageName) && this[parentPackageName.length] == '.')
|
for (i in other.segments.indices) {
|
||||||
|
if (segments[i] != other.segments[i]) return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
+3
-2
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
||||||
|
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageFQN
|
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName
|
||||||
|
|
||||||
internal typealias SourceText = CharSequence
|
internal typealias SourceText = CharSequence
|
||||||
internal typealias SourceLine = String
|
internal typealias SourceLine = String
|
||||||
@@ -17,10 +17,11 @@ internal data class NumberedSourceLine(val number: Int, val text: SourceLine) :
|
|||||||
internal fun SourceText.hasAnythingButComments(): Boolean =
|
internal fun SourceText.hasAnythingButComments(): Boolean =
|
||||||
dropNonMeaningfulLines().firstOrNull() != null
|
dropNonMeaningfulLines().firstOrNull() != null
|
||||||
|
|
||||||
internal fun NumberedSourceLine.getExistingPackageName(): PackageFQN? =
|
internal fun NumberedSourceLine.getExistingPackageName(): PackageName? =
|
||||||
text.substringAfter("package ", missingDelimiterValue = "")
|
text.substringAfter("package ", missingDelimiterValue = "")
|
||||||
.trimStart()
|
.trimStart()
|
||||||
.takeIf(String::isNotEmpty)
|
.takeIf(String::isNotEmpty)
|
||||||
|
?.let(::PackageName)
|
||||||
|
|
||||||
internal fun SourceText.dropNonMeaningfulLines(): Sequence<NumberedSourceLine> {
|
internal fun SourceText.dropNonMeaningfulLines(): Sequence<NumberedSourceLine> {
|
||||||
var inMultilineComment = false
|
var inMultilineComment = false
|
||||||
|
|||||||
+7
-9
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
||||||
|
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageFQN
|
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.TestFunction
|
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.konan.blackboxtest.support.util.GTestListingParseState as State
|
import org.jetbrains.kotlin.konan.blackboxtest.support.util.GTestListingParseState as State
|
||||||
@@ -48,14 +48,12 @@ internal fun parseGTestListing(rawGTestListing: String): Collection<TestFunction
|
|||||||
}
|
}
|
||||||
else -> when (state) {
|
else -> when (state) {
|
||||||
is State.Begin, is State.NewTest -> {
|
is State.Begin, is State.NewTest -> {
|
||||||
val packageParts = line.trimEnd().removeSuffix(".").split('.')
|
val packageSegments = line.trimEnd().removeSuffix(".").split('.')
|
||||||
if (packageParts.isEmpty()) parseError("Malformed test suite name")
|
if (packageSegments.isEmpty()) parseError("Malformed test suite name")
|
||||||
|
|
||||||
// Drop the last part because it is related to class name (or file-class name).
|
// Drop the last part because it is related to class name (or file-class name).
|
||||||
// TODO: How to handle nested classes?
|
// TODO: How to handle nested classes?
|
||||||
val packageName = packageParts.dropLast(1).joinToString(".")
|
State.NewTestSuite(PackageName(packageSegments.dropLast(1)))
|
||||||
|
|
||||||
State.NewTestSuite(packageName)
|
|
||||||
}
|
}
|
||||||
else -> parseError("Unexpected test suite name")
|
else -> parseError("Unexpected test suite name")
|
||||||
}
|
}
|
||||||
@@ -66,11 +64,11 @@ 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: PackageFQN) : State, HasPackageName
|
class NewTestSuite(override val packageName: PackageName) : State, HasPackageName
|
||||||
class NewTest(override val packageName: PackageFQN) : State, HasPackageName
|
class NewTest(override val packageName: PackageName) : State, HasPackageName
|
||||||
|
|
||||||
interface HasPackageName {
|
interface HasPackageName {
|
||||||
val packageName: PackageFQN
|
val packageName: PackageName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-11
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
||||||
|
|
||||||
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageFQN
|
import org.jetbrains.kotlin.konan.blackboxtest.support.PackageName
|
||||||
|
|
||||||
internal interface TreeNode<T> {
|
internal interface TreeNode<T> {
|
||||||
val packageSegment: String
|
val packageSegment: PackageName
|
||||||
val items: Collection<T>
|
val items: Collection<T>
|
||||||
val children: Collection<TreeNode<T>>
|
val children: Collection<TreeNode<T>>
|
||||||
|
|
||||||
@@ -16,15 +16,15 @@ internal interface TreeNode<T> {
|
|||||||
fun <T> oneLevel(vararg items: T) = oneLevel(listOf(*items))
|
fun <T> oneLevel(vararg items: T) = oneLevel(listOf(*items))
|
||||||
|
|
||||||
fun <T> oneLevel(items: Iterable<T>): List<TreeNode<T>> = listOf(object : TreeNode<T> {
|
fun <T> oneLevel(items: Iterable<T>): List<TreeNode<T>> = listOf(object : TreeNode<T> {
|
||||||
override val packageSegment get() = ""
|
override val packageSegment get() = PackageName.EMPTY
|
||||||
override val items = items.toList()
|
override val items = items.toList()
|
||||||
override val children get() = emptyList<TreeNode<T>>()
|
override val children get() = emptyList<TreeNode<T>>()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <T, R> Collection<T>.buildTree(extractPackageName: (T) -> PackageFQN, transform: (T) -> R): Collection<TreeNode<R>> {
|
internal fun <T, R> Collection<T>.buildTree(extractPackageName: (T) -> PackageName, transform: (T) -> R): Collection<TreeNode<R>> {
|
||||||
val groupedItems: Map<PackageFQN, List<R>> = groupBy(extractPackageName).mapValues { (_, items) -> items.map(transform) }
|
val groupedItems: Map<PackageName, List<R>> = groupBy(extractPackageName).mapValues { (_, items) -> items.map(transform) }
|
||||||
|
|
||||||
// Fast pass.
|
// Fast pass.
|
||||||
when (groupedItems.size) {
|
when (groupedItems.size) {
|
||||||
@@ -33,13 +33,14 @@ internal fun <T, R> Collection<T>.buildTree(extractPackageName: (T) -> PackageFQ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Long pass.
|
// Long pass.
|
||||||
val root = TreeBuilder<R>("")
|
val root = TreeBuilder<R>(PackageName.EMPTY)
|
||||||
|
|
||||||
// Populate the tree.
|
// Populate the tree.
|
||||||
groupedItems.forEach { (packageFQN, items) ->
|
groupedItems.forEach { (packageName, items) ->
|
||||||
var node = root
|
var node = root
|
||||||
packageFQN.split('.').forEach { packageSegment ->
|
packageName.segments.forEach { packageSegment ->
|
||||||
node = node.childrenMap.computeIfAbsent(packageSegment) { TreeBuilder(packageSegment) }
|
val packageSegmentAsName = PackageName(listOf(packageSegment))
|
||||||
|
node = node.childrenMap.computeIfAbsent(packageSegmentAsName) { TreeBuilder(packageSegmentAsName) }
|
||||||
}
|
}
|
||||||
node.items += items
|
node.items += items
|
||||||
}
|
}
|
||||||
@@ -54,9 +55,9 @@ internal fun <T, R> Collection<T>.buildTree(extractPackageName: (T) -> PackageFQ
|
|||||||
meaningfulNode.childrenMap.values
|
meaningfulNode.childrenMap.values
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TreeBuilder<T>(override var packageSegment: String) : TreeNode<T> {
|
private class TreeBuilder<T>(override var packageSegment: PackageName) : TreeNode<T> {
|
||||||
override val items = mutableListOf<T>()
|
override val items = mutableListOf<T>()
|
||||||
val childrenMap = hashMapOf<String, TreeBuilder<T>>()
|
val childrenMap = hashMapOf<PackageName, TreeBuilder<T>>()
|
||||||
override val children: Collection<TreeBuilder<T>> get() = childrenMap.values
|
override val children: Collection<TreeBuilder<T>> get() = childrenMap.values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user