jps: support multiplatform incremental compilation for jvm and js
- support common modules metadata compilation under flag (it is not required since all common source roots are included transitively for now)
- introduce expect actual tracker in jps: move implementation from gradle to build-common
- support js incremental compilation: move implementation from gradle to build-common
Original commit: 0eee2729cd
This commit is contained in:
+187
-98
@@ -40,29 +40,34 @@ import org.jetbrains.jps.cmdline.ProjectDescriptor
|
||||
import org.jetbrains.jps.incremental.*
|
||||
import org.jetbrains.jps.incremental.messages.BuildMessage
|
||||
import org.jetbrains.jps.model.JpsModuleRootModificationUtil
|
||||
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
|
||||
import org.jetbrains.jps.model.java.JpsJavaExtensionService
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
|
||||
import org.jetbrains.kotlin.config.IncrementalCompilation
|
||||
import org.jetbrains.kotlin.incremental.CacheVersion
|
||||
import org.jetbrains.kotlin.incremental.LookupSymbol
|
||||
import org.jetbrains.kotlin.incremental.isJavaFile
|
||||
import org.jetbrains.kotlin.incremental.testingUtils.*
|
||||
import org.jetbrains.kotlin.jps.build.dependeciestxt.DependenciesTxt
|
||||
import org.jetbrains.kotlin.jps.build.dependeciestxt.DependenciesTxtBuilder
|
||||
import org.jetbrains.kotlin.jps.incremental.getKotlinCache
|
||||
import org.jetbrains.kotlin.jps.incremental.withLookupStorage
|
||||
import org.jetbrains.kotlin.jps.model.JpsKotlinFacetModuleExtension
|
||||
import org.jetbrains.kotlin.jps.platforms.kotlinBuildTargets
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import org.jetbrains.kotlin.utils.keysToMap
|
||||
import java.io.*
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import java.util.*
|
||||
import java.util.concurrent.Future
|
||||
import kotlin.reflect.jvm.javaField
|
||||
|
||||
abstract class AbstractIncrementalJpsTest(
|
||||
private val allowNoFilesWithSuffixInTestData: Boolean = false,
|
||||
private val checkDumpsCaseInsensitively: Boolean = false,
|
||||
private val allowNoBuildLogFileInTestData: Boolean = false
|
||||
private val allowNoFilesWithSuffixInTestData: Boolean = false,
|
||||
private val checkDumpsCaseInsensitively: Boolean = false,
|
||||
private val allowNoBuildLogFileInTestData: Boolean = false
|
||||
) : BaseKotlinJpsBuildTestCase() {
|
||||
companion object {
|
||||
private val COMPILATION_FAILED = "COMPILATION FAILED"
|
||||
@@ -79,6 +84,7 @@ abstract class AbstractIncrementalJpsTest(
|
||||
// is used to compare lookup dumps in a human readable way (lookup symbols are hashed in an actual lookup storage)
|
||||
protected lateinit var lookupsDuringTest: MutableSet<LookupSymbol>
|
||||
private var isICEnabledBackup: Boolean = false
|
||||
private var isJSICEnabledBackup: Boolean = false
|
||||
|
||||
protected var mapWorkingToOriginalFile: MutableMap<File, File> = hashMapOf()
|
||||
|
||||
@@ -115,7 +121,10 @@ abstract class AbstractIncrementalJpsTest(
|
||||
super.setUp()
|
||||
lookupsDuringTest = hashSetOf()
|
||||
isICEnabledBackup = IncrementalCompilation.isEnabled()
|
||||
isJSICEnabledBackup = IncrementalCompilation.isEnabledForJs()
|
||||
|
||||
IncrementalCompilation.setIsEnabled(true)
|
||||
IncrementalCompilation.setIsEnabledForJs(true)
|
||||
|
||||
if (DEBUG_LOGGING_ENABLED) {
|
||||
enableDebugLogging()
|
||||
@@ -129,6 +138,7 @@ abstract class AbstractIncrementalJpsTest(
|
||||
(AbstractIncrementalJpsTest::systemPropertiesBackup).javaField!![this] = null
|
||||
lookupsDuringTest.clear()
|
||||
IncrementalCompilation.setIsEnabled(isICEnabledBackup)
|
||||
IncrementalCompilation.setIsEnabledForJs(isJSICEnabledBackup)
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
@@ -138,7 +148,7 @@ abstract class AbstractIncrementalJpsTest(
|
||||
private val mockConstantSearch: Callbacks.ConstantAffectionResolver?
|
||||
get() = MockJavaConstantSearch(workDir)
|
||||
|
||||
private fun build(scope: CompileScopeTestBuilder = CompileScopeTestBuilder.make().allModules()): MakeResult {
|
||||
private fun build(scope: CompileScopeTestBuilder = CompileScopeTestBuilder.make().allModules(), name: String? = null): MakeResult {
|
||||
val workDirPath = FileUtil.toSystemIndependentName(workDir.absolutePath)
|
||||
|
||||
val logger = MyLogger(workDirPath)
|
||||
@@ -148,48 +158,67 @@ abstract class AbstractIncrementalJpsTest(
|
||||
projectDescriptor.project.setTestingContext(TestingContext(lookupTracker, logger))
|
||||
|
||||
try {
|
||||
val builder = IncProjectBuilder(projectDescriptor, BuilderRegistry.getInstance(), myBuildParams, CanceledStatus.NULL, mockConstantSearch, true)
|
||||
val builder = IncProjectBuilder(
|
||||
projectDescriptor,
|
||||
BuilderRegistry.getInstance(),
|
||||
myBuildParams,
|
||||
CanceledStatus.NULL,
|
||||
mockConstantSearch,
|
||||
true
|
||||
)
|
||||
val buildResult = BuildResult()
|
||||
builder.addMessageHandler(buildResult)
|
||||
builder.build(scope.build(), false)
|
||||
|
||||
val finalScope = scope.build()
|
||||
builder.build(finalScope, false)
|
||||
|
||||
lookupTracker.lookups.mapTo(lookupsDuringTest) { LookupSymbol(it.name, it.scopeFqName) }
|
||||
|
||||
// for getting kotlin platform only
|
||||
val dummyCompileContext = CompileContextImpl.createContextForTests(finalScope, projectDescriptor)
|
||||
|
||||
if (!buildResult.isSuccessful) {
|
||||
val errorMessages =
|
||||
buildResult
|
||||
.getMessages(BuildMessage.Kind.ERROR)
|
||||
.map { it.messageText }
|
||||
.map { it.replace("^.+:\\d+:\\s+".toRegex(), "").trim() }
|
||||
.joinToString("\n")
|
||||
return MakeResult(logger.log + "$COMPILATION_FAILED\n" + errorMessages + "\n", true, null)
|
||||
buildResult
|
||||
.getMessages(BuildMessage.Kind.ERROR)
|
||||
.map { it.messageText }
|
||||
.map { it.replace("^.+:\\d+:\\s+".toRegex(), "").trim() }
|
||||
.joinToString("\n")
|
||||
return MakeResult(
|
||||
logger.log + "$COMPILATION_FAILED\n" + errorMessages + "\n",
|
||||
true,
|
||||
null,
|
||||
name
|
||||
)
|
||||
} else {
|
||||
return MakeResult(
|
||||
logger.log,
|
||||
false,
|
||||
createMappingsDump(projectDescriptor, dummyCompileContext),
|
||||
name
|
||||
)
|
||||
}
|
||||
else {
|
||||
return MakeResult(logger.log, false, createMappingsDump(projectDescriptor))
|
||||
}
|
||||
}
|
||||
finally {
|
||||
} finally {
|
||||
projectDescriptor.dataManager.flush(false)
|
||||
projectDescriptor.release()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initialMake(): MakeResult {
|
||||
val makeResult = build()
|
||||
protected fun initialMake(): MakeResult {
|
||||
val makeResult = build(name = "initial")
|
||||
|
||||
val initBuildLogFile = File(testDataDir, "init-build.log")
|
||||
if (initBuildLogFile.exists()) {
|
||||
UsefulTestCase.assertSameLinesWithFile(initBuildLogFile.absolutePath, makeResult.log)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assertFalse("Initial make failed:\n$makeResult", makeResult.makeFailed)
|
||||
}
|
||||
|
||||
return makeResult
|
||||
}
|
||||
|
||||
private fun make(): MakeResult {
|
||||
return build()
|
||||
private fun make(name: String?): MakeResult {
|
||||
return build(name = name)
|
||||
}
|
||||
|
||||
private fun rebuild(): MakeResult {
|
||||
@@ -205,21 +234,21 @@ abstract class AbstractIncrementalJpsTest(
|
||||
}
|
||||
|
||||
val rebuildResult = rebuild()
|
||||
assertEquals("Rebuild failed: ${rebuildResult.makeFailed}, last make failed: ${makeOverallResult.makeFailed}. Rebuild result: $rebuildResult",
|
||||
rebuildResult.makeFailed, makeOverallResult.makeFailed)
|
||||
assertEquals(
|
||||
"Rebuild failed: ${rebuildResult.makeFailed}, last make failed: ${makeOverallResult.makeFailed}. Rebuild result: $rebuildResult",
|
||||
rebuildResult.makeFailed, makeOverallResult.makeFailed
|
||||
)
|
||||
|
||||
if (!outAfterMake.exists()) {
|
||||
assertFalse(outDir.exists())
|
||||
}
|
||||
else {
|
||||
assertEqualDirectories(outDir, outAfterMake, makeOverallResult.makeFailed)
|
||||
} else {
|
||||
assertEqualDirectories(outAfterMake, outDir, makeOverallResult.makeFailed)
|
||||
}
|
||||
|
||||
if (!makeOverallResult.makeFailed) {
|
||||
if (checkDumpsCaseInsensitively && rebuildResult.mappingsDump?.toLowerCase() == makeOverallResult.mappingsDump?.toLowerCase()) {
|
||||
// do nothing
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
TestCase.assertEquals(rebuildResult.mappingsDump, makeOverallResult.mappingsDump)
|
||||
}
|
||||
}
|
||||
@@ -233,30 +262,27 @@ abstract class AbstractIncrementalJpsTest(
|
||||
rebuildAndCheckOutput(makeOverallResult)
|
||||
}
|
||||
|
||||
private fun readModuleDependencies(): Map<String, List<DependencyDescriptor>>? {
|
||||
val dependenciesTxt = File(testDataDir, "dependencies.txt")
|
||||
if (!dependenciesTxt.exists()) return null
|
||||
open protected val dependenciesTxtFile get() = File(testDataDir, "dependencies.txt")
|
||||
|
||||
val result = HashMap<String, List<DependencyDescriptor>>()
|
||||
for (line in dependenciesTxt.readLines()) {
|
||||
val split = line.split("->")
|
||||
val module = split[0]
|
||||
val dependencies = if (split.size > 1) split[1] else ""
|
||||
val dependencyList = dependencies.split(",").filterNot { it.isEmpty() }
|
||||
result[module] = dependencyList.map(::parseDependency)
|
||||
}
|
||||
private fun readModuleDependencies(): DependenciesTxt? {
|
||||
val dependenciesTxtFile = dependenciesTxtFile
|
||||
if (!dependenciesTxtFile.exists()) return null
|
||||
|
||||
return result
|
||||
return DependenciesTxtBuilder().readFile(dependenciesTxtFile)
|
||||
}
|
||||
|
||||
protected open fun createBuildLog(incrementalMakeResults: List<AbstractIncrementalJpsTest.MakeResult>): String =
|
||||
buildString {
|
||||
incrementalMakeResults.forEachIndexed { i, makeResult ->
|
||||
if (i > 0) append("\n")
|
||||
buildString {
|
||||
incrementalMakeResults.forEachIndexed { i, makeResult ->
|
||||
if (i > 0) append("\n")
|
||||
if (makeResult.name != null) {
|
||||
append("================ Step #${i + 1} ${makeResult.name} =================\n\n")
|
||||
} else {
|
||||
append("================ Step #${i + 1} =================\n\n")
|
||||
append(makeResult.log)
|
||||
}
|
||||
append(makeResult.log)
|
||||
}
|
||||
}
|
||||
|
||||
protected open fun doTest(testDataPath: String) {
|
||||
testDataDir = File(testDataPath)
|
||||
@@ -272,8 +298,7 @@ abstract class AbstractIncrementalJpsTest(
|
||||
|
||||
if (buildLogFile != null && buildLogFile.exists()) {
|
||||
UsefulTestCase.assertSameLinesWithFile(buildLogFile.absolutePath, logs)
|
||||
}
|
||||
else if (!allowNoBuildLogFileInTestData) {
|
||||
} else if (!allowNoBuildLogFileInTestData) {
|
||||
throw IllegalStateException("No build log file in $testDataDir")
|
||||
}
|
||||
|
||||
@@ -282,17 +307,38 @@ abstract class AbstractIncrementalJpsTest(
|
||||
clearCachesRebuildAndCheckOutput(lastMakeResult)
|
||||
}
|
||||
|
||||
private fun createMappingsDump(project: ProjectDescriptor) =
|
||||
createKotlinIncrementalCacheDump(project) + "\n\n\n" +
|
||||
createLookupCacheDump(project) + "\n\n\n" +
|
||||
createCommonMappingsDump(project) + "\n\n\n" +
|
||||
createJavaMappingsDump(project)
|
||||
protected open fun doInitialMakeTest(testDataPath: String) {
|
||||
testDataDir = File(testDataPath)
|
||||
workDir = FileUtilRt.createTempDirectory(TEMP_DIRECTORY_TO_USE, "jps-build", null)
|
||||
Disposer.register(testRootDisposable, Disposable { FileUtilRt.delete(workDir) })
|
||||
|
||||
private fun createKotlinIncrementalCacheDump(project: ProjectDescriptor): String {
|
||||
configureModules()
|
||||
val results = initialMake()
|
||||
|
||||
val buildLogFile = buildLogFinder.findBuildLog(testDataDir)
|
||||
|
||||
if (buildLogFile != null && buildLogFile.exists()) {
|
||||
UsefulTestCase.assertSameLinesWithFile(buildLogFile.absolutePath, results.log)
|
||||
} else throw IllegalStateException("No build log file in $testDataDir")
|
||||
}
|
||||
|
||||
private fun createMappingsDump(
|
||||
project: ProjectDescriptor,
|
||||
dummyCompileContext: CompileContext
|
||||
) =
|
||||
createKotlinIncrementalCacheDump(project, dummyCompileContext) + "\n\n\n" +
|
||||
createLookupCacheDump(project) + "\n\n\n" +
|
||||
createCommonMappingsDump(project) + "\n\n\n" +
|
||||
createJavaMappingsDump(project)
|
||||
|
||||
private fun createKotlinIncrementalCacheDump(
|
||||
project: ProjectDescriptor,
|
||||
dummyCompileContext: CompileContext
|
||||
): String {
|
||||
return buildString {
|
||||
for (target in project.allModuleTargets.sortedBy { it.presentableName }) {
|
||||
append("<target $target>\n")
|
||||
append(project.dataManager.getKotlinCache(target).dump())
|
||||
append(project.dataManager.getKotlinCache(dummyCompileContext.kotlinBuildTargets[target]!!).dump())
|
||||
append("</target $target>\n\n\n")
|
||||
}
|
||||
}
|
||||
@@ -350,23 +396,35 @@ abstract class AbstractIncrementalJpsTest(
|
||||
return byteArrayOutputStream.toString()
|
||||
}
|
||||
|
||||
protected data class MakeResult(val log: String, val makeFailed: Boolean, val mappingsDump: String?)
|
||||
protected data class MakeResult(
|
||||
val log: String,
|
||||
val makeFailed: Boolean,
|
||||
val mappingsDump: String?,
|
||||
val name: String?
|
||||
)
|
||||
|
||||
open val testDataSrc: File
|
||||
get() = testDataDir
|
||||
|
||||
private fun performModificationsAndMake(moduleNames: Set<String>?): List<MakeResult> {
|
||||
val results = arrayListOf<MakeResult>()
|
||||
val modifications = getModificationsToPerform(testDataDir, moduleNames, allowNoFilesWithSuffixInTestData, TouchPolicy.TIMESTAMP)
|
||||
val modifications = getModificationsToPerform(testDataSrc, moduleNames, allowNoFilesWithSuffixInTestData, TouchPolicy.TIMESTAMP)
|
||||
|
||||
for (step in modifications) {
|
||||
val stepsTxt = File(testDataSrc, "steps.txt")
|
||||
val modificationNames = if (stepsTxt.exists()) stepsTxt.readLines() else null
|
||||
|
||||
modifications.forEachIndexed { index, step ->
|
||||
step.forEach { it.perform(workDir, mapWorkingToOriginalFile) }
|
||||
performAdditionalModifications(step)
|
||||
if (moduleNames == null) {
|
||||
preProcessSources(File(workDir, "src"))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
moduleNames.forEach { preProcessSources(File(workDir, "$it/src")) }
|
||||
}
|
||||
|
||||
results.add(make())
|
||||
val name = modificationNames?.getOrNull(index)
|
||||
val makeResult = make(name)
|
||||
results.add(makeResult)
|
||||
}
|
||||
return results
|
||||
}
|
||||
@@ -374,54 +432,92 @@ abstract class AbstractIncrementalJpsTest(
|
||||
protected open fun performAdditionalModifications(modifications: List<Modification>) {
|
||||
}
|
||||
|
||||
// null means one module
|
||||
private fun configureModules(): Set<String>? {
|
||||
fun prepareModuleSources(moduleName: String?) {
|
||||
val sourceDirName = moduleName?.let { "$it/src" } ?: "src"
|
||||
val filePrefix = moduleName?.let { "${it}_" } ?: ""
|
||||
val sourceDestinationDir = File(workDir, sourceDirName)
|
||||
val sourcesMapping = copyTestSources(testDataDir, sourceDestinationDir, filePrefix)
|
||||
mapWorkingToOriginalFile.putAll(sourcesMapping)
|
||||
preProcessSources(sourceDestinationDir)
|
||||
}
|
||||
protected open fun generateModuleSources(dependenciesTxt: DependenciesTxt) {
|
||||
|
||||
JpsJavaExtensionService.getInstance().getOrCreateProjectExtension(myProject).outputUrl = JpsPathUtil.pathToUrl(getAbsolutePath("out"))
|
||||
}
|
||||
|
||||
protected open fun prepareModuleSources(module: DependenciesTxt.Module? = null) {
|
||||
if (module != null) {
|
||||
prepareModuleSourcesByName("${module.name}/src", "${module.name}_")
|
||||
} else {
|
||||
prepareModuleSourcesByName("src", "")
|
||||
}
|
||||
}
|
||||
|
||||
protected fun prepareIndexedModuleSources(module: DependenciesTxt.Module) {
|
||||
prepareModuleSourcesByName("${module.name}/src", "${module.indexedName}_")
|
||||
}
|
||||
|
||||
private fun prepareModuleSourcesByName(sourceDirName: String, filePrefix: String) {
|
||||
val sourceDestinationDir = File(workDir, sourceDirName)
|
||||
val sourcesMapping = copyTestSources(testDataSrc, sourceDestinationDir, filePrefix)
|
||||
mapWorkingToOriginalFile.putAll(sourcesMapping)
|
||||
preProcessSources(sourceDestinationDir)
|
||||
}
|
||||
|
||||
// null means one module
|
||||
protected fun configureModules(): Set<String>? {
|
||||
val outputUrl = JpsPathUtil.pathToUrl(getAbsolutePath("out"))
|
||||
JpsJavaExtensionService.getInstance().getOrCreateProjectExtension(myProject).outputUrl = outputUrl
|
||||
|
||||
val jdk = addJdk("my jdk")
|
||||
val moduleDependencies = readModuleDependencies()
|
||||
val dependenciesTxt = readModuleDependencies()
|
||||
mapWorkingToOriginalFile = hashMapOf()
|
||||
|
||||
val moduleNames: Set<String>?
|
||||
if (moduleDependencies == null) {
|
||||
if (dependenciesTxt == null) {
|
||||
addModule("module", arrayOf(getAbsolutePath("src")), null, null, jdk)
|
||||
prepareModuleSources(moduleName = null)
|
||||
prepareModuleSources(module = null)
|
||||
moduleNames = null
|
||||
}
|
||||
else {
|
||||
val nameToModule = moduleDependencies.keys
|
||||
.keysToMap { addModule(it, arrayOf(getAbsolutePath("$it/src")), null, null, jdk)!! }
|
||||
} else {
|
||||
dependenciesTxt.modules.forEach {
|
||||
val module = addModule(
|
||||
it.name,
|
||||
arrayOf(getAbsolutePath("${it.name}/src")),
|
||||
null,
|
||||
null,
|
||||
jdk
|
||||
)!!
|
||||
|
||||
for ((moduleName, dependencies) in moduleDependencies) {
|
||||
val module = nameToModule[moduleName]!!
|
||||
val kotlinFacetSettings = it.kotlinFacetSettings
|
||||
if (kotlinFacetSettings != null) {
|
||||
val compilerArguments = kotlinFacetSettings.compilerArguments
|
||||
if (compilerArguments is K2MetadataCompilerArguments) {
|
||||
val out = getAbsolutePath("${it.name}/out")
|
||||
File(out).mkdirs()
|
||||
compilerArguments.destination = out
|
||||
}
|
||||
|
||||
for (dependency in dependencies) {
|
||||
JpsModuleRootModificationUtil.addDependency(module, nameToModule[dependency.name],
|
||||
JpsJavaDependencyScope.COMPILE, dependency.exported)
|
||||
module.container.setChild(
|
||||
JpsKotlinFacetModuleExtension.KIND,
|
||||
JpsKotlinFacetModuleExtension(kotlinFacetSettings)
|
||||
)
|
||||
}
|
||||
|
||||
it.jpsModule = module
|
||||
}
|
||||
|
||||
for (module in nameToModule.values) {
|
||||
prepareModuleSources(module.name)
|
||||
dependenciesTxt.dependencies.forEach {
|
||||
JpsModuleRootModificationUtil.addDependency(
|
||||
it.from.jpsModule,
|
||||
it.to.jpsModule,
|
||||
it.scope,
|
||||
it.exported
|
||||
)
|
||||
}
|
||||
|
||||
moduleNames = nameToModule.keys
|
||||
generateModuleSources(dependenciesTxt)
|
||||
dependenciesTxt.modules.forEach {
|
||||
prepareModuleSources(it)
|
||||
}
|
||||
|
||||
moduleNames = dependenciesTxt.modules.map { it.name }.toSet()
|
||||
}
|
||||
AbstractKotlinJpsBuildTestCase.addKotlinStdlibDependency(myProject)
|
||||
AbstractKotlinJpsBuildTestCase.addKotlinTestDependency(myProject)
|
||||
return moduleNames
|
||||
}
|
||||
|
||||
|
||||
protected open fun preProcessSources(srcDir: File) {
|
||||
}
|
||||
|
||||
@@ -530,10 +626,3 @@ private class MockJavaConstantSearch(private val workDir: File) : Callbacks.Cons
|
||||
|
||||
internal val ProjectDescriptor.allModuleTargets: Collection<ModuleBuildTarget>
|
||||
get() = buildTargetIndex.allTargets.filterIsInstance<ModuleBuildTarget>()
|
||||
|
||||
private class DependencyDescriptor(val name: String, val exported: Boolean)
|
||||
|
||||
private fun parseDependency(dependency: String): DependencyDescriptor =
|
||||
DependencyDescriptor(dependency.removeSuffix(EXPORTED_SUFFIX), dependency.endsWith(EXPORTED_SUFFIX))
|
||||
|
||||
private val EXPORTED_SUFFIX = "[exported]"
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.jps.build
|
||||
|
||||
import org.jetbrains.kotlin.jps.build.dependeciestxt.DependenciesTxt
|
||||
import org.jetbrains.kotlin.jps.build.dependeciestxt.MppJpsIncTestsGenerator
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractMultiplatformJpsTest : AbstractIncrementalJpsTest() {
|
||||
override val dependenciesTxtFile: File
|
||||
get() = File(testDataDir.parent, "dependencies.txt").also {
|
||||
check(it.exists()) {
|
||||
"`dependencies.txt` should be in parent dir. " +
|
||||
"See jps-plugin/testData/incremental/multiplatform/multiModule/README.md for details"
|
||||
}
|
||||
}
|
||||
|
||||
override val testDataSrc: File
|
||||
get() = File(workDir, "generatedTestDataSources")
|
||||
|
||||
override fun generateModuleSources(dependenciesTxt: DependenciesTxt) {
|
||||
testDataSrc.mkdirs()
|
||||
|
||||
val testCaseName = testDataDir.name
|
||||
|
||||
val generator = MppJpsIncTestsGenerator(dependenciesTxt) { testDataSrc }
|
||||
val testCase = generator.testCases.find { it.name == testCaseName } ?: error("Unsupported test case name: $testCaseName")
|
||||
testCase.generate()
|
||||
}
|
||||
|
||||
override fun prepareModuleSources(module: DependenciesTxt.Module?) {
|
||||
prepareIndexedModuleSources(module!!)
|
||||
}
|
||||
}
|
||||
+358
@@ -0,0 +1,358 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.jps.build;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TargetBackend;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class MultiplatformJpsTestGenerated extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInMultiplatformMultiModule() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/simple")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Simple extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSimple() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/simple"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("editingCExpectActual")
|
||||
public void testEditingCExpectActual() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingCExpectActual/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingCKotlin")
|
||||
public void testEditingCKotlin() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingCKotlin/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingPJsKotlin")
|
||||
public void testEditingPJsKotlin() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingPJsKotlin/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingPJvmJava")
|
||||
public void testEditingPJvmJava() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingPJvmJava/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingPJvmKotlin")
|
||||
public void testEditingPJvmKotlin() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingPJvmKotlin/");
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingCExpectActual")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingCExpectActual extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingCExpectActual() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingCExpectActual"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingCKotlin")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingCKotlin extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingCKotlin() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingCKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingPJsKotlin")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingPJsKotlin extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingPJsKotlin() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingPJsKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingPJvmJava")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingPJvmJava extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingPJvmJava() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingPJvmJava"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingPJvmKotlin")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingPJvmKotlin extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingPJvmKotlin() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/simple/editingPJvmKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/simpleJsJvmProjectWithTests")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class SimpleJsJvmProjectWithTests extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInSimpleJsJvmProjectWithTests() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/simpleJsJvmProjectWithTests"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("editingCMainExpectActual")
|
||||
public void testEditingCMainExpectActual() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/simpleJsJvmProjectWithTests/editingCMainExpectActual/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingCTestsExpectActual")
|
||||
public void testEditingCTestsExpectActual() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/simpleJsJvmProjectWithTests/editingCTestsExpectActual/");
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/simpleJsJvmProjectWithTests/editingCMainExpectActual")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingCMainExpectActual extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingCMainExpectActual() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/simpleJsJvmProjectWithTests/editingCMainExpectActual"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/simpleJsJvmProjectWithTests/editingCTestsExpectActual")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingCTestsExpectActual extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingCTestsExpectActual() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/simpleJsJvmProjectWithTests/editingCTestsExpectActual"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class Ultimate extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInUltimate() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
|
||||
@TestMetadata("editingACommonExpectActual")
|
||||
public void testEditingACommonExpectActual() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingACommonExpectActual/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingAJsClientKotlin")
|
||||
public void testEditingAJsClientKotlin() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingAJsClientKotlin/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingAJvmClientJava")
|
||||
public void testEditingAJvmClientJava() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingAJvmClientJava/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingAJvmClientKotlin")
|
||||
public void testEditingAJvmClientKotlin() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingAJvmClientKotlin/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingBCommonExpectActual")
|
||||
public void testEditingBCommonExpectActual() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingBCommonExpectActual/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingRJsKotlin")
|
||||
public void testEditingRJsKotlin() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRJsKotlin/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingRJvmKotlin")
|
||||
public void testEditingRJvmKotlin() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRJvmKotlin/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingRaJsKotlin")
|
||||
public void testEditingRaJsKotlin() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRaJsKotlin/");
|
||||
}
|
||||
|
||||
@TestMetadata("editingRaJvmKotlin")
|
||||
public void testEditingRaJvmKotlin() throws Exception {
|
||||
runTest("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRaJvmKotlin/");
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingACommonExpectActual")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingACommonExpectActual extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingACommonExpectActual() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingACommonExpectActual"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingAJsClientKotlin")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingAJsClientKotlin extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingAJsClientKotlin() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingAJsClientKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingAJvmClientJava")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingAJvmClientJava extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingAJvmClientJava() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingAJvmClientJava"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingAJvmClientKotlin")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingAJvmClientKotlin extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingAJvmClientKotlin() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingAJvmClientKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingBCommonExpectActual")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingBCommonExpectActual extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingBCommonExpectActual() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingBCommonExpectActual"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRJsKotlin")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingRJsKotlin extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingRJsKotlin() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRJsKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRJvmKotlin")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingRJvmKotlin extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingRJvmKotlin() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRJvmKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRaJsKotlin")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingRaJsKotlin extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingRaJsKotlin() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRaJsKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRaJvmKotlin")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class EditingRaJvmKotlin extends AbstractMultiplatformJpsTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.ANY, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInEditingRaJvmKotlin() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("jps-plugin/testData/incremental/multiplatform/multiModule/ultimate/editingRaJvmKotlin"), Pattern.compile("^([^\\.]+)$"), TargetBackend.ANY, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+267
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.jps.build.dependeciestxt
|
||||
|
||||
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
|
||||
import org.jetbrains.jps.model.module.JpsModule
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
|
||||
import org.jetbrains.kotlin.config.CompilerSettings
|
||||
import org.jetbrains.kotlin.config.KotlinFacetSettings
|
||||
import org.jetbrains.kotlin.config.TargetPlatformKind
|
||||
import java.io.File
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.full.findAnnotation
|
||||
import kotlin.reflect.full.memberProperties
|
||||
|
||||
/**
|
||||
* Dependencies description file.
|
||||
* See [README.md] for more details.
|
||||
*/
|
||||
data class DependenciesTxt(
|
||||
val file: File,
|
||||
val fileName: String,
|
||||
val modules: List<Module>,
|
||||
val dependencies: List<Dependency>
|
||||
) {
|
||||
override fun toString() = fileName
|
||||
|
||||
data class Module(val name: String) {
|
||||
var index: Int = -1
|
||||
|
||||
val indexedName
|
||||
get() = "${index / 10}${index % 10}_$name"
|
||||
|
||||
/**
|
||||
* Facet should not be created for old tests
|
||||
*/
|
||||
var kotlinFacetSettings: KotlinFacetSettings? = null
|
||||
|
||||
lateinit var jpsModule: JpsModule
|
||||
|
||||
val dependencies = mutableListOf<Dependency>()
|
||||
val usages = mutableListOf<Dependency>()
|
||||
|
||||
val isCommonModule
|
||||
get() = kotlinFacetSettings?.targetPlatformKind == TargetPlatformKind.Common
|
||||
|
||||
val isJvmModule
|
||||
get() = kotlinFacetSettings?.targetPlatformKind is TargetPlatformKind.Jvm
|
||||
|
||||
val expectedBy
|
||||
get() = dependencies.filter { it.expectedBy }
|
||||
|
||||
@Flag
|
||||
var edit: Boolean = false
|
||||
|
||||
@Flag
|
||||
var editJvm: Boolean = false
|
||||
|
||||
@Flag
|
||||
var editExpectActual: Boolean = false
|
||||
|
||||
companion object {
|
||||
val flags: Map<String, KMutableProperty1<Module, Boolean>> = Module::class.memberProperties
|
||||
.filter { it.findAnnotation<Flag>() != null }
|
||||
.filterIsInstance<KMutableProperty1<Module, Boolean>>()
|
||||
.associateBy { it.name }
|
||||
}
|
||||
}
|
||||
|
||||
annotation class Flag
|
||||
|
||||
data class Dependency(
|
||||
val from: Module,
|
||||
val to: Module,
|
||||
val scope: JpsJavaDependencyScope,
|
||||
val expectedBy: Boolean,
|
||||
val exported: Boolean
|
||||
) {
|
||||
val effectivelyExported
|
||||
get() = expectedBy || exported
|
||||
|
||||
init {
|
||||
from.dependencies.add(this)
|
||||
to.usages.add(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DependenciesTxtBuilder {
|
||||
val modules = mutableMapOf<String, ModuleRef>()
|
||||
private val dependencies = mutableListOf<DependencyBuilder>()
|
||||
|
||||
/**
|
||||
* Reference to module which can be defined later
|
||||
*/
|
||||
class ModuleRef(name: String) {
|
||||
var defined: Boolean = false
|
||||
var actual: DependenciesTxt.Module = DependenciesTxt.Module(name)
|
||||
|
||||
override fun toString() = actual.name
|
||||
|
||||
fun build(index: Int): DependenciesTxt.Module {
|
||||
val result = actual
|
||||
result.index = index
|
||||
val kotlinFacetSettings = result.kotlinFacetSettings
|
||||
if (kotlinFacetSettings != null) {
|
||||
kotlinFacetSettings.implementedModuleNames =
|
||||
result.dependencies.filter { it.expectedBy }.map { it.to.name }
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary object for resolving references to modules.
|
||||
*/
|
||||
data class DependencyBuilder(
|
||||
val from: ModuleRef,
|
||||
val to: ModuleRef,
|
||||
val scope: JpsJavaDependencyScope,
|
||||
val expectedBy: Boolean,
|
||||
val exported: Boolean
|
||||
) {
|
||||
fun build(): DependenciesTxt.Dependency {
|
||||
if (expectedBy) check(to.actual.isCommonModule) { "$this: ${to.actual} is not common module" }
|
||||
return DependenciesTxt.Dependency(from.actual, to.actual, scope, expectedBy, exported)
|
||||
}
|
||||
}
|
||||
|
||||
fun readFile(file: File, fileTitle: String = file.toString()): DependenciesTxt {
|
||||
file.forEachLine { line ->
|
||||
parseDeclaration(line)
|
||||
}
|
||||
|
||||
// module.build() requires built dependencies
|
||||
val dependencies = dependencies.map { it.build() }
|
||||
return DependenciesTxt(
|
||||
file,
|
||||
fileTitle,
|
||||
modules.values.mapIndexed { index, moduleRef -> moduleRef.build(index) },
|
||||
dependencies
|
||||
)
|
||||
}
|
||||
|
||||
private fun parseDeclaration(line: String) = doParseDeclaration(removeComments(line))
|
||||
|
||||
private fun removeComments(line: String) = line.split("//", limit = 2)[0].trim()
|
||||
|
||||
private fun doParseDeclaration(line: String) {
|
||||
when {
|
||||
line.isEmpty() -> Unit // skip empty lines
|
||||
line.contains("->") -> {
|
||||
val (from, rest) = line.split("->", limit = 2)
|
||||
if (rest.isBlank()) {
|
||||
// `name -> ` - module
|
||||
newModule(ValueWithFlags(from))
|
||||
} else {
|
||||
val (to, flags) = parseValueWithFlags(rest.trim())
|
||||
newDependency(from.trim(), to.trim(), flags) // `from -> to [flag1, flag2, ...]` - dependency
|
||||
}
|
||||
}
|
||||
else -> newModule(parseValueWithFlags(line)) // `name [flag1, flag2, ...]` - module
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* `value [flag1, flag2, ...]`
|
||||
*/
|
||||
private fun parseValueWithFlags(str: String): ValueWithFlags {
|
||||
val parts = str.split("[", limit = 2)
|
||||
return if (parts.size > 1) {
|
||||
val (value, flags) = parts
|
||||
ValueWithFlags(
|
||||
value = value.trim(),
|
||||
flags = flags.trim()
|
||||
.removeSuffix("]")
|
||||
.split(",")
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.toSet()
|
||||
)
|
||||
} else ValueWithFlags(str)
|
||||
}
|
||||
|
||||
data class ValueWithFlags(val value: String, val flags: Set<String> = setOf())
|
||||
|
||||
private fun moduleRef(name: String) =
|
||||
modules.getOrPut(name) { ModuleRef(name) }
|
||||
|
||||
private fun newModule(def: ValueWithFlags): DependenciesTxt.Module {
|
||||
val name = def.value.trim()
|
||||
|
||||
val module = DependenciesTxt.Module(name)
|
||||
val kotlinFacetSettings = KotlinFacetSettings()
|
||||
module.kotlinFacetSettings = kotlinFacetSettings
|
||||
|
||||
kotlinFacetSettings.useProjectSettings = false
|
||||
kotlinFacetSettings.compilerSettings = CompilerSettings().also {
|
||||
it.additionalArguments = "-version -Xmulti-platform"
|
||||
}
|
||||
|
||||
val moduleRef = moduleRef(name)
|
||||
check(!moduleRef.defined) { "Module `$name` already defined" }
|
||||
moduleRef.defined = true
|
||||
moduleRef.actual = module
|
||||
|
||||
def.flags.forEach { flag ->
|
||||
when (flag) {
|
||||
"common" -> kotlinFacetSettings.compilerArguments = K2MetadataCompilerArguments()
|
||||
"jvm" -> kotlinFacetSettings.compilerArguments = K2JVMCompilerArguments()
|
||||
"js" -> kotlinFacetSettings.compilerArguments = K2JSCompilerArguments()
|
||||
else -> {
|
||||
val flagProperty = DependenciesTxt.Module.flags[flag]
|
||||
if (flagProperty != null) flagProperty.set(module, true)
|
||||
else error("Unknown module flag `$flag`")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return module
|
||||
}
|
||||
|
||||
private fun newDependency(from: String, to: String, flags: Set<String>): DependencyBuilder? {
|
||||
if (to.isEmpty()) {
|
||||
// `x -> ` should just create undefined module `x`
|
||||
moduleRef(from)
|
||||
|
||||
check(flags.isEmpty()) {
|
||||
"`name -> [flag1, flag2, ...]` - not allowed due to the ambiguity of belonging to modules/dependencies. " +
|
||||
"Please use `x [attrs...]` syntax for module attributes."
|
||||
}
|
||||
|
||||
return null
|
||||
} else {
|
||||
var exported = false
|
||||
var scope = JpsJavaDependencyScope.COMPILE
|
||||
var expectedBy = false
|
||||
|
||||
flags.forEach { flag ->
|
||||
when (flag) {
|
||||
"exported" -> exported = true
|
||||
"compile" -> scope = JpsJavaDependencyScope.COMPILE
|
||||
"test" -> scope = JpsJavaDependencyScope.TEST
|
||||
"runtime" -> scope = JpsJavaDependencyScope.RUNTIME
|
||||
"provided" -> scope = JpsJavaDependencyScope.PROVIDED
|
||||
"expectedBy" -> expectedBy = true
|
||||
else -> error("Unknown dependency flag `$flag`")
|
||||
}
|
||||
}
|
||||
|
||||
return DependencyBuilder(
|
||||
from = moduleRef(from),
|
||||
to = moduleRef(to),
|
||||
scope = scope,
|
||||
expectedBy = expectedBy,
|
||||
exported = exported
|
||||
).also {
|
||||
dependencies.add(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+432
@@ -0,0 +1,432 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.jps.build.dependeciestxt
|
||||
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Utility for generating common/platform module stub contents based on it's dependencies.
|
||||
*/
|
||||
fun actualizeMppJpsIncTestCaseDirs(rootDir: String, dir: String) {
|
||||
File("$rootDir/$dir").listFiles { it: File -> it.isDirectory }.forEach { dirFile ->
|
||||
val dependenciesTxtFile = File(dirFile, "dependencies.txt")
|
||||
if (dependenciesTxtFile.exists()) {
|
||||
val fileTitle = "$dir/${dirFile.name}/dependencies.txt"
|
||||
val dependenciesTxt = DependenciesTxtBuilder().readFile(dependenciesTxtFile, fileTitle)
|
||||
|
||||
MppJpsIncTestsGenerator(dependenciesTxt) { File(dirFile, it.name) }
|
||||
.actualizeTestCasesDirs(dirFile)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
class MppJpsIncTestsGenerator(val txt: DependenciesTxt, val testCaseDirProvider: (TestCase) -> File) {
|
||||
val DependenciesTxt.Module.capitalName get() = name.capitalize()
|
||||
|
||||
val testCases: List<TestCase>
|
||||
|
||||
init {
|
||||
val testCases = mutableListOf<TestCase>()
|
||||
|
||||
txt.modules.forEach {
|
||||
if (it.edit)
|
||||
testCases.add(EditingTestCase(it, changeJavaClass = false))
|
||||
|
||||
if (it.editJvm && it.isJvmModule)
|
||||
testCases.add(EditingTestCase(it, changeJavaClass = true))
|
||||
|
||||
if (it.editExpectActual && it.isCommonModule)
|
||||
testCases.add(EditingExpectActualTestCase(it))
|
||||
}
|
||||
|
||||
this.testCases = testCases
|
||||
}
|
||||
|
||||
fun actualizeTestCasesDirs(rootDir: File) {
|
||||
val requiredDirs = mutableSetOf<File>()
|
||||
testCases.forEach {
|
||||
val dir = it.dir
|
||||
check(requiredDirs.add(dir)) { "TestCase dir clash $dir" }
|
||||
|
||||
if (!dir.exists()) {
|
||||
File(dir, "build.log").setFileContent("")
|
||||
}
|
||||
}
|
||||
|
||||
rootDir.listFiles().forEach {
|
||||
if (it.isDirectory && it !in requiredDirs) {
|
||||
it.deleteRecursively()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set required content for [this] [File].
|
||||
*/
|
||||
fun File.setFileContent(content: String) {
|
||||
check(!exists()) {
|
||||
"File `$this` already exists," +
|
||||
"\n\n============= contents ============\n" +
|
||||
readText() +
|
||||
"\n===================================\n" +
|
||||
"\n============ new content ==========\n" +
|
||||
content +
|
||||
"\n===================================\n"
|
||||
}
|
||||
|
||||
parentFile.mkdirs()
|
||||
writeText(content)
|
||||
}
|
||||
|
||||
data class ModuleContentSettings(
|
||||
val module: DependenciesTxt.Module,
|
||||
val serviceNameSuffix: String = "",
|
||||
val generateActualDeclarationsFor: List<DependenciesTxt.Module> = module.expectedBy.map { it.to },
|
||||
val generatePlatformDependent: Boolean = true,
|
||||
var generateKtFile: Boolean = true,
|
||||
var generateJavaFile: Boolean = true
|
||||
)
|
||||
|
||||
inner class EditingTestCase(val module: DependenciesTxt.Module, val changeJavaClass: Boolean) : TestCase() {
|
||||
override val name: String =
|
||||
if (changeJavaClass) "editing${module.capitalName}Java"
|
||||
else "editing${module.capitalName}Kotlin"
|
||||
|
||||
override val dir: File = testCaseDirProvider(this)
|
||||
|
||||
override fun generate() {
|
||||
generateBaseContent()
|
||||
|
||||
// create new file with service implementation
|
||||
// don't create expect/actual functions (generatePlatformDependent = false)
|
||||
module.contentsSettings = ModuleContentSettings(
|
||||
module,
|
||||
serviceNameSuffix = "New",
|
||||
generatePlatformDependent = false,
|
||||
generateKtFile = !changeJavaClass,
|
||||
generateJavaFile = changeJavaClass
|
||||
)
|
||||
|
||||
when {
|
||||
module.isCommonModule -> {
|
||||
step("create new service") {
|
||||
generateCommonFile(
|
||||
module,
|
||||
fileNameSuffix = ".new.$step"
|
||||
)
|
||||
}
|
||||
|
||||
step("edit new service") {
|
||||
generateCommonFile(
|
||||
module,
|
||||
fileNameSuffix = ".touch.$step"
|
||||
)
|
||||
}
|
||||
|
||||
step("delete new service") {
|
||||
serviceKtFile(
|
||||
module,
|
||||
fileNameSuffix = ".delete.$step"
|
||||
).setFileContent("")
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
step("create new service") {
|
||||
// generateKtFile event if changeJavaClass requested (for test calling java from kotlin)
|
||||
val prevModuleContentsSettings = module.contentsSettings
|
||||
module.contentsSettings = module.contentsSettings.copy(generateKtFile = true)
|
||||
|
||||
|
||||
generatePlatformFile(
|
||||
module,
|
||||
fileNameSuffix = ".new.$step"
|
||||
)
|
||||
|
||||
module.contentsSettings = prevModuleContentsSettings
|
||||
}
|
||||
|
||||
step("edit new service") {
|
||||
generatePlatformFile(
|
||||
module,
|
||||
fileNameSuffix = ".touch.$step"
|
||||
)
|
||||
}
|
||||
|
||||
step("delete new service") {
|
||||
if (changeJavaClass) serviceJavaFile(module, fileNameSuffix = ".delete.$step").setFileContent("")
|
||||
|
||||
// kotlin file also created for testing java class
|
||||
serviceKtFile(module, fileNameSuffix = ".delete.$step").setFileContent("")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generateStepsTxt()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
inner class EditingExpectActualTestCase(val commonModule: DependenciesTxt.Module) : TestCase() {
|
||||
override val name: String = "editing${commonModule.capitalName}ExpectActual"
|
||||
override val dir: File = testCaseDirProvider(this)
|
||||
|
||||
override fun generate() {
|
||||
generateBaseContent()
|
||||
check(commonModule.isCommonModule)
|
||||
val implModules = commonModule.usages.filter { it.expectedBy }.map { it.from }
|
||||
|
||||
commonModule.contentsSettings = ModuleContentSettings(commonModule, serviceNameSuffix = "New")
|
||||
implModules.forEach { implModule ->
|
||||
implModule.contentsSettings = ModuleContentSettings(
|
||||
implModule,
|
||||
serviceNameSuffix = "New",
|
||||
generateActualDeclarationsFor = listOf(commonModule)
|
||||
)
|
||||
}
|
||||
|
||||
step("create new service in ${commonModule.name}") {
|
||||
generateCommonFile(commonModule, fileNameSuffix = ".new.$step")
|
||||
}
|
||||
|
||||
implModules.forEach { implModule ->
|
||||
step("create new service in ${implModule.name}") {
|
||||
generatePlatformFile(implModule, fileNameSuffix = ".new.$step")
|
||||
}
|
||||
}
|
||||
|
||||
step("change new service in ${commonModule.name}") {
|
||||
generateCommonFile(commonModule, fileNameSuffix = ".touch.$step")
|
||||
}
|
||||
|
||||
implModules.forEach { implModule ->
|
||||
if (implModule.isJvmModule) {
|
||||
implModule.contentsSettings.generateKtFile = false
|
||||
implModule.contentsSettings.generateJavaFile = true
|
||||
step("change new service in ${implModule.name}: java") {
|
||||
generatePlatformFile(implModule, fileNameSuffix = ".touch.$step")
|
||||
}
|
||||
|
||||
implModule.contentsSettings.generateKtFile = true
|
||||
implModule.contentsSettings.generateJavaFile = false
|
||||
step("change new service in ${implModule.name}: kotlin") {
|
||||
generatePlatformFile(implModule, fileNameSuffix = ".touch.$step")
|
||||
}
|
||||
} else {
|
||||
step("change new service in ${implModule.name}") {
|
||||
generatePlatformFile(implModule, fileNameSuffix = ".touch.$step")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
implModules.forEach { implModule ->
|
||||
step("delete new service in ${implModule.name}") {
|
||||
serviceKtFile(implModule, fileNameSuffix = ".delete.$step").setFileContent("")
|
||||
}
|
||||
}
|
||||
|
||||
step("delete new service in ${commonModule.name}") {
|
||||
serviceKtFile(commonModule, fileNameSuffix = ".delete.$step").setFileContent("")
|
||||
}
|
||||
|
||||
generateStepsTxt()
|
||||
}
|
||||
}
|
||||
|
||||
abstract inner class TestCase() {
|
||||
abstract val name: String
|
||||
|
||||
abstract fun generate()
|
||||
|
||||
abstract val dir: File
|
||||
|
||||
private val modules = mutableMapOf<DependenciesTxt.Module, ModuleContentSettings>()
|
||||
|
||||
var step = 1
|
||||
val steps = mutableListOf<String>()
|
||||
|
||||
protected inline fun step(name: String, body: () -> Unit) {
|
||||
body()
|
||||
steps.add(name)
|
||||
step++
|
||||
}
|
||||
|
||||
var DependenciesTxt.Module.contentsSettings: ModuleContentSettings
|
||||
get() = modules.getOrPut(this) { ModuleContentSettings(this) }
|
||||
set(value) {
|
||||
modules[this] = value
|
||||
}
|
||||
|
||||
protected fun generateStepsTxt() {
|
||||
File(dir, "steps.txt").setFileContent(steps.joinToString("\n"))
|
||||
}
|
||||
|
||||
fun generateBaseContent() {
|
||||
dir.mkdir()
|
||||
|
||||
txt.modules.forEach {
|
||||
generateModuleContents(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateModuleContents(module: DependenciesTxt.Module) {
|
||||
when {
|
||||
module.isCommonModule -> {
|
||||
// common module
|
||||
generateCommonFile(module)
|
||||
}
|
||||
module.expectedBy.isEmpty() -> {
|
||||
// regular module
|
||||
generatePlatformFile(module)
|
||||
}
|
||||
else -> {
|
||||
// common module platform implementation
|
||||
generatePlatformFile(module)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val DependenciesTxt.Module.serviceName
|
||||
get() = "$capitalName${contentsSettings.serviceNameSuffix}"
|
||||
|
||||
private val DependenciesTxt.Module.javaClassName
|
||||
get() = "${serviceName}JavaClass"
|
||||
|
||||
protected fun serviceKtFile(module: DependenciesTxt.Module, fileNameSuffix: String = ""): File {
|
||||
val suffix =
|
||||
if (module.isCommonModule) "${module.serviceName}Header"
|
||||
else "${module.name.capitalize()}${module.contentsSettings.serviceNameSuffix}Impl"
|
||||
|
||||
return File(dir, "${module.indexedName}_service$suffix.kt$fileNameSuffix")
|
||||
}
|
||||
|
||||
fun serviceJavaFile(module: DependenciesTxt.Module, fileNameSuffix: String = ""): File {
|
||||
return File(dir, "${module.indexedName}_${module.javaClassName}.java$fileNameSuffix")
|
||||
}
|
||||
|
||||
private val DependenciesTxt.Module.platformDependentFunName: String
|
||||
get() {
|
||||
check(isCommonModule)
|
||||
return "${name}_platformDependent$serviceName"
|
||||
}
|
||||
|
||||
private val DependenciesTxt.Module.platformIndependentFunName: String
|
||||
get() {
|
||||
check(isCommonModule)
|
||||
return "${name}_platformIndependent$serviceName"
|
||||
}
|
||||
|
||||
private val DependenciesTxt.Module.platformOnlyFunName: String
|
||||
get() {
|
||||
// platformOnly fun names already unique, so no module name prefix required
|
||||
return "${name}_platformOnly${contentsSettings.serviceNameSuffix}"
|
||||
}
|
||||
|
||||
protected fun generateCommonFile(
|
||||
module: DependenciesTxt.Module,
|
||||
fileNameSuffix: String = ""
|
||||
) {
|
||||
val settings = module.contentsSettings
|
||||
|
||||
serviceKtFile(module, fileNameSuffix).setFileContent(buildString {
|
||||
if (settings.generatePlatformDependent)
|
||||
appendln("expect fun ${module.platformDependentFunName}(): String")
|
||||
|
||||
appendln("fun ${module.platformIndependentFunName}() = \"common$fileNameSuffix\"")
|
||||
|
||||
appendTestFun(module, settings)
|
||||
})
|
||||
}
|
||||
|
||||
protected fun generatePlatformFile(
|
||||
module: DependenciesTxt.Module,
|
||||
fileNameSuffix: String = ""
|
||||
) {
|
||||
val isJvm = module.isJvmModule
|
||||
val settings = module.contentsSettings
|
||||
|
||||
val javaClassName = module.javaClassName
|
||||
|
||||
if (settings.generateKtFile) {
|
||||
serviceKtFile(module, fileNameSuffix).setFileContent(buildString {
|
||||
if (settings.generatePlatformDependent) {
|
||||
for (expectedBy in settings.generateActualDeclarationsFor) {
|
||||
appendln(
|
||||
"actual fun ${expectedBy.platformDependentFunName}(): String" +
|
||||
" = \"${module.name}$fileNameSuffix\""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
appendln(
|
||||
"fun ${module.platformOnlyFunName}()" +
|
||||
" = \"${module.name}$fileNameSuffix\""
|
||||
)
|
||||
|
||||
appendTestFun(module, settings)
|
||||
})
|
||||
}
|
||||
|
||||
if (isJvm && settings.generateJavaFile) {
|
||||
serviceJavaFile(module, fileNameSuffix).setFileContent(
|
||||
"""
|
||||
|public class $javaClassName {
|
||||
| public String doStuff() {
|
||||
| return "${module.name}$fileNameSuffix";
|
||||
| }
|
||||
|}
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// call all functions declared in this module and all of its dependencies recursively
|
||||
private fun StringBuilder.appendTestFun(
|
||||
module: DependenciesTxt.Module,
|
||||
settings: ModuleContentSettings
|
||||
) {
|
||||
appendln()
|
||||
appendln("fun Test${module.serviceName}() {")
|
||||
|
||||
val thisAndDependencies = mutableSetOf(module)
|
||||
module.collectDependenciesRecursivelyTo(thisAndDependencies)
|
||||
thisAndDependencies.forEach { thisOrDependent ->
|
||||
if (thisOrDependent.isCommonModule) {
|
||||
appendln(" ${thisOrDependent.platformIndependentFunName}()")
|
||||
|
||||
if (settings.generatePlatformDependent) {
|
||||
appendln(" ${thisOrDependent.platformDependentFunName}()")
|
||||
}
|
||||
} else {
|
||||
// platform module
|
||||
appendln(" ${thisOrDependent.platformOnlyFunName}()")
|
||||
|
||||
if (thisOrDependent.isJvmModule && thisOrDependent.contentsSettings.generateJavaFile) {
|
||||
appendln(" ${thisOrDependent.javaClassName}().doStuff()")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
appendln("}")
|
||||
}
|
||||
|
||||
private fun DependenciesTxt.Module.collectDependenciesRecursivelyTo(
|
||||
collection: MutableCollection<DependenciesTxt.Module>,
|
||||
exportedOnly: Boolean = false
|
||||
) {
|
||||
dependencies.forEach {
|
||||
if (!exportedOnly || it.effectivelyExported) {
|
||||
val dependentModule = it.to
|
||||
collection.add(dependentModule)
|
||||
dependentModule.collectDependenciesRecursivelyTo(collection, exportedOnly = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString() = name
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
Useful micro-language for concise description of project structure.
|
||||
Mostly like the [DOT language](https://www.graphviz.org/doc/info/attrs.html).
|
||||
|
||||
## Example
|
||||
|
||||
```
|
||||
c [common]
|
||||
p1 [jvm]
|
||||
p2 [jvm]
|
||||
|
||||
p1 -> c [expectedBy]
|
||||
p2 -> c [expectedBy]
|
||||
```
|
||||
|
||||
## Format
|
||||
|
||||
File contains declarations of modules and dependencies:
|
||||
- Module: `module_name [flag1, key1=value1, ...]`
|
||||
- Dependency: `source_module_name -> target_module_name [flag1, key1=value1, ...]`
|
||||
|
||||
Referring to undefined module is allowed (`jvm` module will be created at this case).
|
||||
This modules can be defined after reference. Several declarations for same module is not allowed.
|
||||
|
||||
Supported module flags:
|
||||
- `common`
|
||||
- `jvm` (default)
|
||||
- `js`
|
||||
- `edit`, `editJvm`, `editExcpetActual` - see jps-plugin/testData/incremental/multiplatform/multiModule/README.md
|
||||
|
||||
Supported dependency flags:
|
||||
- `compile` (default)
|
||||
- `test`
|
||||
- `runtime`
|
||||
- `provided`
|
||||
- `expectedBy`
|
||||
- `exproted`
|
||||
Reference in New Issue
Block a user