[K2/N] Add ObjCExport test for kdoc strings
^KT-56090 Merge-request: KT-MR-9926 Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
d24eaf13b5
commit
79599ab69e
@@ -0,0 +1 @@
|
||||
EXPORT_KDOC
|
||||
@@ -0,0 +1,14 @@
|
||||
* `Summary class` [KDocExport]. // EXPORT_KDOC
|
||||
* @property xyzzy Doc for property xyzzy // EXPORT_KDOC
|
||||
* @property zzz See below. // EXPORT_KDOC
|
||||
/** Non-primary ctor KDoc: // EXPORT_KDOC */
|
||||
/** @property xyzzy KDoc for foo? // EXPORT_KDOC */
|
||||
* @param xyzzy is documented. // EXPORT_KDOC
|
||||
* This is multi-line KDoc. See a blank line above. // EXPORT_KDOC
|
||||
/** @property foo KDoc for yxxyz? // EXPORT_KDOC */
|
||||
* Kdoc for a property // EXPORT_KDOC
|
||||
* Useless function [whatever] // EXPORT_KDOC
|
||||
* This kdoc has some additional formatting. // EXPORT_KDOC
|
||||
* @param a keep intact and return // EXPORT_KDOC
|
||||
* @return value of [a] // EXPORT_KDOC
|
||||
* Check for additional comment (note) below // EXPORT_KDOC
|
||||
@@ -0,0 +1,54 @@
|
||||
// KT-56090: [K2/N] Emit DocString klib extensions for ObjCExport
|
||||
// MUTED_WHEN: K2
|
||||
/*
|
||||
* Copyright 2010-2023 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 kdocExport
|
||||
|
||||
/**
|
||||
* `Summary class` [KDocExport]. // EXPORT_KDOC
|
||||
*
|
||||
* @property xyzzy Doc for property xyzzy // EXPORT_KDOC
|
||||
* @property zzz See below. // EXPORT_KDOC
|
||||
*/
|
||||
|
||||
// Expected: this comment shall not affect KDoc (i.e. kdoc above is still OK)
|
||||
class KDocExport() {
|
||||
/**
|
||||
* @param xyzzy is documented. // EXPORT_KDOC
|
||||
*
|
||||
* This is multi-line KDoc. See a blank line above. // EXPORT_KDOC
|
||||
*/
|
||||
val xyzzy: String = "String example"
|
||||
|
||||
/** Non-primary ctor KDoc: // EXPORT_KDOC */
|
||||
constructor(name: String) : this() {
|
||||
println(name)
|
||||
}
|
||||
|
||||
/** @property xyzzy KDoc for foo? // EXPORT_KDOC */
|
||||
val foo = "foo"
|
||||
/** @property foo KDoc for yxxyz? // EXPORT_KDOC */
|
||||
var yxxyz = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Useless function [whatever] // EXPORT_KDOC
|
||||
*
|
||||
* This kdoc has some additional formatting. // EXPORT_KDOC
|
||||
* @param a keep intact and return // EXPORT_KDOC
|
||||
* @return value of [a] // EXPORT_KDOC
|
||||
* Check for additional comment (note) below // EXPORT_KDOC
|
||||
*/
|
||||
fun whatever(a:String) = a
|
||||
|
||||
public abstract class SomeClassWithProperty
|
||||
{
|
||||
/**
|
||||
* Kdoc for a property // EXPORT_KDOC
|
||||
*/
|
||||
public abstract val heavyFormattedKDocFoo: SomeClassWithProperty
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.group.FirPipeline;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("native/native.tests/testData/ObjCExport")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@Tag("frontend-fir")
|
||||
@FirPipeline()
|
||||
public class FirObjCExportTestGenerated extends AbstractNativeObjCExportTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInObjCExport() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/ObjCExport"), Pattern.compile("^([^_](.+))$"), null, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kdocExport")
|
||||
public void testKdocExport() throws Exception {
|
||||
runTest("native/native.tests/testData/ObjCExport/kdocExport/");
|
||||
}
|
||||
}
|
||||
Generated
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2010-2023 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;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.util.KtTestUtil;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("native/native.tests/testData/ObjCExport")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class ObjCExportTestGenerated extends AbstractNativeObjCExportTest {
|
||||
@Test
|
||||
public void testAllFilesPresentInObjCExport() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("native/native.tests/testData/ObjCExport"), Pattern.compile("^([^_](.+))$"), null, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("kdocExport")
|
||||
public void testKdocExport() throws Exception {
|
||||
runTest("native/native.tests/testData/ObjCExport/kdocExport/");
|
||||
}
|
||||
}
|
||||
+17
@@ -165,6 +165,23 @@ fun main() {
|
||||
}
|
||||
}
|
||||
|
||||
// ObjCExport tests.
|
||||
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
|
||||
testClass<AbstractNativeObjCExportTest>(
|
||||
suiteTestClassName = "ObjCExportTestGenerated"
|
||||
) {
|
||||
model("ObjCExport", pattern = "^([^_](.+))$", recursive = false)
|
||||
}
|
||||
testClass<AbstractNativeObjCExportTest>(
|
||||
suiteTestClassName = "FirObjCExportTestGenerated",
|
||||
annotations = listOf(
|
||||
*frontendFir()
|
||||
),
|
||||
) {
|
||||
model("ObjCExport", pattern = "^([^_](.+))$", recursive = false)
|
||||
}
|
||||
}
|
||||
|
||||
// Klib contents tests
|
||||
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
|
||||
testClass<AbstractNativeKlibContentsTest>(
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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
|
||||
|
||||
import com.intellij.testFramework.TestDataFile
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.getAbsoluteFile
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions
|
||||
import org.junit.jupiter.api.Assumptions
|
||||
import org.junit.jupiter.api.Tag
|
||||
import java.io.File
|
||||
|
||||
@Tag("objcexport")
|
||||
abstract class AbstractNativeObjCExportTest : AbstractNativeSimpleTest() {
|
||||
private val targets: KotlinNativeTargets get() = testRunSettings.get<KotlinNativeTargets>()
|
||||
private val testCompilationFactory = TestCompilationFactory()
|
||||
|
||||
protected fun runTest(@TestDataFile testDir: String) {
|
||||
Assumptions.assumeTrue(targets.testTarget.family.isAppleFamily)
|
||||
val testPathFull = getAbsoluteFile(testDir)
|
||||
val ktSources = testPathFull.list()!!
|
||||
.filter { it.endsWith(".kt")}
|
||||
.map { testPathFull.resolve(it) }
|
||||
ktSources.forEach { muteTestIfNecessary(it) }
|
||||
|
||||
val testCase: TestCase = generateObjCFrameworkTestCase(testPathFull, ktSources)
|
||||
val objCFramework: ObjCFramework = testCase.toObjCFramework().assertSuccess().resultingArtifact
|
||||
|
||||
val mainHeaderContents = objCFramework.mainHeader.readText()
|
||||
val regexFilter = testPathFull.resolve("${testPathFull.name}.filter.txt").readText()
|
||||
val actualFilteredOutput = filterContentsOutput(mainHeaderContents, regexFilter)
|
||||
val expectedFilteredOutput = testPathFull.resolve("${testPathFull.name}.gold.txt").readText()
|
||||
|
||||
// Compare to goldfile, ignoring lines order. This is needed to be stable against possible declaration order fluctuations.
|
||||
// TODO Investigate why ObjCExport declarations order may vary
|
||||
JUnit5Assertions.assertEquals(
|
||||
expectedFilteredOutput.lines().sorted().joinToString("\n"),
|
||||
actualFilteredOutput.lines().sorted().joinToString("\n")
|
||||
)
|
||||
}
|
||||
|
||||
private fun filterContentsOutput(contents: String, pattern: String) =
|
||||
contents.split("\n").filter {
|
||||
it.contains(Regex(pattern))
|
||||
}.joinToString(separator = "\n")
|
||||
|
||||
private fun TestCase.toObjCFramework(): TestCompilationResult<out ObjCFramework> {
|
||||
return testCompilationFactory.testCaseToObjCFrameworkCompilation(this, testRunSettings).result
|
||||
}
|
||||
|
||||
private fun generateObjCFrameworkTestCase(testPathFull: File, sources: List<File>): TestCase {
|
||||
val moduleName: String = testPathFull.name
|
||||
val module = TestModule.Exclusive(moduleName, emptySet(), emptySet(), emptySet())
|
||||
sources.forEach { module.files += TestFile.createCommitted(it, module) }
|
||||
|
||||
return TestCase(
|
||||
id = TestCaseId.Named(moduleName),
|
||||
kind = TestKind.STANDALONE,
|
||||
modules = setOf(module),
|
||||
freeCompilerArgs = TestCompilerArgs(listOf("-Xexport-kdoc")),
|
||||
nominalPackageName = PackageName(moduleName),
|
||||
checks = TestRunChecks.Default(testRunSettings.get<Timeouts>().executionTimeout),
|
||||
extras = TestCase.WithTestRunnerExtras(TestRunnerType.DEFAULT)
|
||||
).apply {
|
||||
initialize(null, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -207,6 +207,7 @@ private object NativeTestSupport {
|
||||
output += computePipelineType(testClass.get())
|
||||
output += computeUsedPartialLinkageConfig(enclosingTestClass)
|
||||
output += computeCompilerOutputInterceptor(enforcedProperties)
|
||||
output += computeBinariesDirs(getOrCreateTestProcessSettings().get(), nativeTargets, enclosingTestClass)
|
||||
|
||||
return nativeTargets
|
||||
}
|
||||
@@ -337,7 +338,6 @@ private object NativeTestSupport {
|
||||
|
||||
// Put settings that are always required:
|
||||
this += computedTestConfiguration
|
||||
this += computeBinariesDirs(testProcessSettings.get(), nativeTargets, enclosingTestClass)
|
||||
|
||||
// Add custom settings:
|
||||
computedTestConfiguration.configuration.requiredSettings.forEach { clazz ->
|
||||
|
||||
+34
@@ -213,6 +213,40 @@ internal class LibraryCompilation(
|
||||
}
|
||||
}
|
||||
|
||||
internal class ObjCFrameworkCompilation(
|
||||
settings: Settings,
|
||||
freeCompilerArgs: TestCompilerArgs,
|
||||
sourceModules: Collection<TestModule>,
|
||||
dependencies: Iterable<TestCompilationDependency<*>>,
|
||||
expectedArtifact: ObjCFramework
|
||||
) : SourceBasedCompilation<ObjCFramework>(
|
||||
targets = settings.get(),
|
||||
home = settings.get(),
|
||||
classLoader = settings.get(),
|
||||
optimizationMode = settings.get(),
|
||||
compilerOutputInterceptor = settings.get(),
|
||||
memoryModel = settings.get(),
|
||||
threadStateChecker = settings.get(),
|
||||
sanitizer = settings.get(),
|
||||
gcType = settings.get(),
|
||||
gcScheduler = settings.get(),
|
||||
pipelineType = settings.get(),
|
||||
freeCompilerArgs = freeCompilerArgs,
|
||||
sourceModules = sourceModules,
|
||||
dependencies = CategorizedDependencies(dependencies),
|
||||
expectedArtifact = expectedArtifact
|
||||
) {
|
||||
override val binaryOptions get() = BinaryOptions.RuntimeAssertionsMode.defaultForTesting
|
||||
|
||||
override fun applySpecificArgs(argsBuilder: ArgsBuilder) = with(argsBuilder) {
|
||||
add(
|
||||
"-produce", "framework",
|
||||
"-output", expectedArtifact.frameworkDir.absolutePath
|
||||
)
|
||||
super.applySpecificArgs(argsBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
internal class GivenLibraryCompilation(givenArtifact: KLIB) : TestCompilation<KLIB>() {
|
||||
override val result = TestCompilationResult.Success(givenArtifact, LoggedData.NoopCompilerCall(givenArtifact.klibFile))
|
||||
}
|
||||
|
||||
+7
@@ -24,4 +24,11 @@ internal sealed interface TestCompilationArtifact {
|
||||
override val logFile: File get() = executableFile.resolveSibling("${executableFile.name}.log")
|
||||
val testDumpFile: File get() = executableFile.resolveSibling("${executableFile.name}.dump")
|
||||
}
|
||||
|
||||
data class ObjCFramework(private val buildDir: File, val frameworkName: String) : TestCompilationArtifact {
|
||||
override val logFile: File get() = buildDir.resolve("$frameworkName.log")
|
||||
val frameworkDir = buildDir.resolve("$frameworkName.framework")
|
||||
val headersDir: File = frameworkDir.resolve("Headers")
|
||||
val mainHeader: File = headersDir.resolve("$frameworkName.h")
|
||||
}
|
||||
}
|
||||
|
||||
+61
-22
@@ -25,9 +25,11 @@ import java.io.File
|
||||
internal class TestCompilationFactory {
|
||||
private val cachedKlibCompilations = ThreadSafeCache<KlibCacheKey, KlibCompilations>()
|
||||
private val cachedExecutableCompilations = ThreadSafeCache<ExecutableCacheKey, TestCompilation<Executable>>()
|
||||
private val cachedObjCFrameworkCompilations = ThreadSafeCache<ObjCFrameworkCacheKey, ObjCFrameworkCompilation>()
|
||||
|
||||
private data class KlibCacheKey(val sourceModules: Set<TestModule>, val freeCompilerArgs: TestCompilerArgs)
|
||||
private data class ExecutableCacheKey(val sourceModules: Set<TestModule>)
|
||||
private data class ObjCFrameworkCacheKey(val sourceModules: Set<TestModule>)
|
||||
|
||||
// A pair of compilations for a KLIB itself and for its static cache that are created together.
|
||||
private data class KlibCompilations(val klib: TestCompilation<KLIB>, val staticCache: TestCompilation<KLIBStaticCache>?)
|
||||
@@ -80,6 +82,31 @@ internal class TestCompilationFactory {
|
||||
}
|
||||
}
|
||||
|
||||
fun testCaseToObjCFrameworkCompilation(testCase: TestCase, settings: Settings): ObjCFrameworkCompilation {
|
||||
val cacheKey = ObjCFrameworkCacheKey(testCase.rootModules)
|
||||
cachedObjCFrameworkCompilations[cacheKey]?.let { return it }
|
||||
|
||||
val (
|
||||
dependencies: Iterable<CompiledDependency<*>>,
|
||||
sourceModules: Set<TestModule.Exclusive>
|
||||
) = getDependenciesAndSourceModules(settings, testCase.rootModules, testCase.freeCompilerArgs) {
|
||||
ProduceStaticCache.No
|
||||
}
|
||||
|
||||
return cachedObjCFrameworkCompilations.computeIfAbsent(cacheKey) {
|
||||
ObjCFrameworkCompilation(
|
||||
settings = settings,
|
||||
freeCompilerArgs = testCase.freeCompilerArgs,
|
||||
sourceModules = sourceModules,
|
||||
dependencies = dependencies,
|
||||
expectedArtifact = ObjCFramework(
|
||||
settings.artifactDirForPackageName(testCase.nominalPackageName),
|
||||
testCase.nominalPackageName.compressedPackageName
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun testCasesToExecutable(testCases: Collection<TestCase>, settings: Settings): TestCompilation<Executable> {
|
||||
val rootModules = testCases.flatMapToSet { testCase -> testCase.rootModules }
|
||||
val cacheKey = ExecutableCacheKey(rootModules)
|
||||
@@ -92,28 +119,11 @@ internal class TestCompilationFactory {
|
||||
val extras = testCases.first().extras // Should be identical inside the same test case group.
|
||||
val executableArtifact = Executable(settings.artifactFileForExecutable(rootModules))
|
||||
|
||||
val sourceModulesToCompileExecutable: Set<TestModule.Exclusive>
|
||||
val dependenciesToCompileExecutable: Iterable<CompiledDependency<*>>
|
||||
|
||||
when (settings.get<TestMode>()) {
|
||||
TestMode.ONE_STAGE_MULTI_MODULE -> {
|
||||
// Collect dependencies of root modules. Compile root modules directly to executable.
|
||||
sourceModulesToCompileExecutable = rootModules
|
||||
dependenciesToCompileExecutable = collectDependencies(rootModules, freeCompilerArgs, settings).forOneStageExecutable()
|
||||
}
|
||||
TestMode.TWO_STAGE_MULTI_MODULE -> {
|
||||
// Compile root modules to KLIB. Pass this KLIB as included dependency to executable compilation.
|
||||
val produceStaticCache = ProduceStaticCache.decideForIncludedKlib(settings, executableArtifact, extras)
|
||||
val klibCompilations = modulesToKlib(rootModules, freeCompilerArgs, produceStaticCache, settings)
|
||||
|
||||
sourceModulesToCompileExecutable = emptySet() // No sources.
|
||||
|
||||
// Include just compiled KLIB as -Xinclude dependency.
|
||||
dependenciesToCompileExecutable = collectDependencies(rootModules, freeCompilerArgs, settings).forTwoStageExecutable(
|
||||
includedKlib = klibCompilations.klib.asKlibDependency(IncludedLibrary),
|
||||
includedKlibStaticCache = klibCompilations.staticCache?.asStaticCacheDependency()
|
||||
)
|
||||
}
|
||||
val (
|
||||
dependenciesToCompileExecutable: Iterable<CompiledDependency<*>>,
|
||||
sourceModulesToCompileExecutable: Set<TestModule.Exclusive>
|
||||
) = getDependenciesAndSourceModules(settings, rootModules, freeCompilerArgs) {
|
||||
ProduceStaticCache.decideForIncludedKlib(settings, executableArtifact, extras)
|
||||
}
|
||||
|
||||
return cachedExecutableCompilations.computeIfAbsent(cacheKey) {
|
||||
@@ -128,6 +138,35 @@ internal class TestCompilationFactory {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getDependenciesAndSourceModules(
|
||||
settings: Settings,
|
||||
rootModules: Set<TestModule.Exclusive>,
|
||||
freeCompilerArgs: TestCompilerArgs,
|
||||
produceStaticCache: () -> ProduceStaticCache,
|
||||
): Pair<Iterable<CompiledDependency<*>>, Set<TestModule.Exclusive>> =
|
||||
when (settings.get<TestMode>()) {
|
||||
TestMode.ONE_STAGE_MULTI_MODULE -> {
|
||||
Pair(
|
||||
// Collect dependencies of root modules. Compile root modules directly to executable.
|
||||
collectDependencies(rootModules, freeCompilerArgs, settings).forOneStageExecutable(),
|
||||
rootModules
|
||||
)
|
||||
}
|
||||
TestMode.TWO_STAGE_MULTI_MODULE -> {
|
||||
// Compile root modules to KLIB. Pass this KLIB as included dependency to executable compilation.
|
||||
val klibCompilations = modulesToKlib(rootModules, freeCompilerArgs, produceStaticCache(), settings)
|
||||
|
||||
Pair(
|
||||
// Include just compiled KLIB as -Xinclude dependency.
|
||||
collectDependencies(rootModules, freeCompilerArgs, settings).forTwoStageExecutable(
|
||||
includedKlib = klibCompilations.klib.asKlibDependency(IncludedLibrary),
|
||||
includedKlibStaticCache = klibCompilations.staticCache?.asStaticCacheDependency()
|
||||
),
|
||||
emptySet() // No sources.
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun modulesToKlib(
|
||||
sourceModules: Set<TestModule>,
|
||||
freeCompilerArgs: TestCompilerArgs,
|
||||
|
||||
Reference in New Issue
Block a user