MPP: Add tests for new MPP model import

This commit is contained in:
Alexey Sedunov
2018-08-08 12:51:00 +03:00
committed by Mikhail Glukhikh
parent ded652382b
commit 7ae740dd91
2 changed files with 535 additions and 0 deletions
@@ -0,0 +1,330 @@
/*
* 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.gradle
import com.intellij.openapi.roots.*
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.config.KotlinResourceRootType
import org.jetbrains.kotlin.config.KotlinSourceRootType
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.codeInsight.gradle.GradleImportingTestCase
import org.junit.Test
import org.junit.runners.Parameterized
class NewMultiplatformProjectImportingTest : GradleImportingTestCase() {
private val kotlinVersion = "1.2.70-dev-1648"
@Test
fun testProjectDependency() {
createProjectSubFile(
"settings.gradle",
"include 'lib', 'app'"
)
createProjectSubFile(
"build.gradle",
"""
buildscript {
repositories {
mavenLocal()
jcenter()
maven { url 'https://dl.bintray.com/kotlin/kotlin-dev' }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}
allprojects {
repositories {
mavenLocal()
jcenter()
maven { url 'https://dl.bintray.com/kotlin/kotlin-dev' }
}
}
""".trimIndent()
)
createProjectSubFile(
"app/build.gradle",
"""
apply plugin: 'kotlin-multiplatform'
kotlin {
sourceSets {
commonMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
implementation project(':lib')
}
}
main {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib'
}
}
jsMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-js'
}
}
}
targets {
fromPreset(presets.jvmWithJava, 'jvm')
fromPreset(presets.js, 'js')
}
}
apply plugin: 'application'
mainClassName = 'com.example.app.JvmGreeterKt'
""".trimIndent()
)
createProjectSubFile(
"lib/build.gradle",
"""
apply plugin: 'kotlin-multiplatform'
kotlin {
sourceSets {
commonMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
}
}
jvmMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib'
}
}
jsMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-js'
}
}
}
targets {
fromPreset(presets.jvm, 'jvm')
fromPreset(presets.js, 'js')
}
}
""".trimIndent()
)
importProject()
checkProjectStructure() {
allModules {
languageVersion("1.2")
apiVersion("1.2")
}
module("project")
module("app")
// TODO: Delete metadata modules (after KT-26253 fixed)
module("app_metadataMain") {
platform(TargetPlatformKind.Common)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("app_commonMain", DependencyScope.COMPILE)
moduleDependency("lib_metadataMain", DependencyScope.COMPILE)
sourceFolder("app/src/metadataMain/kotlin", KotlinSourceRootType.Source)
sourceFolder("app/src/metadataMain/resources", KotlinResourceRootType.Resource)
outputPath("app/build/classes/kotlin/metadata/main", true)
}
module("app_metadataTest") {
platform(TargetPlatformKind.Common)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("app_commonMain", DependencyScope.COMPILE)
moduleDependency("app_commonTest", DependencyScope.COMPILE)
moduleDependency("app_metadataMain", DependencyScope.COMPILE)
moduleDependency("lib_metadataMain", DependencyScope.COMPILE)
sourceFolder("app/src/metadataTest/kotlin", KotlinSourceRootType.TestSource)
sourceFolder("app/src/metadataTest/resources", KotlinResourceRootType.TestResource)
outputPath("app/build/classes/kotlin/metadata/test", false)
}
module("app_commonMain") {
platform(TargetPlatformKind.Common)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
sourceFolder("app/src/commonMain/kotlin", KotlinSourceRootType.Source)
sourceFolder("app/src/commonMain/resources", KotlinResourceRootType.Resource)
inheritProjectOutput()
}
module("app_commonTest") {
platform(TargetPlatformKind.Common)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("app_commonMain", DependencyScope.COMPILE)
sourceFolder("app/src/commonTest/kotlin", KotlinSourceRootType.TestSource)
sourceFolder("app/src/commonTest/resources", KotlinResourceRootType.TestResource)
inheritProjectOutput()
}
module("app_jsMain") {
platform(TargetPlatformKind.JavaScript)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("lib_jsMain", DependencyScope.COMPILE)
moduleDependency("app_commonMain", DependencyScope.COMPILE)
sourceFolder("app/src/jsMain/kotlin", KotlinSourceRootType.Source)
sourceFolder("app/src/jsMain/resources", KotlinResourceRootType.Resource)
outputPath("app/build/classes/kotlin/js/main", true)
}
module("app_jsTest") {
platform(TargetPlatformKind.JavaScript)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("lib_jsMain", DependencyScope.COMPILE)
moduleDependency("app_commonMain", DependencyScope.COMPILE)
moduleDependency("app_commonTest", DependencyScope.COMPILE)
moduleDependency("app_jsMain", DependencyScope.COMPILE)
sourceFolder("app/src/jsTest/kotlin", KotlinSourceRootType.TestSource)
sourceFolder("app/src/jsTest/resources", KotlinResourceRootType.TestResource)
outputPath("app/build/classes/kotlin/js/test", false)
}
module("app_jvmMain") {
platform(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains:annotations:13.0", DependencyScope.COMPILE)
moduleDependency("lib_jvmMain", DependencyScope.COMPILE)
moduleDependency("app_main", DependencyScope.COMPILE)
moduleDependency("app_commonMain", DependencyScope.COMPILE)
sourceFolder("app/src/jvmMain/kotlin", JavaSourceRootType.SOURCE)
sourceFolder("app/src/jvmMain/resources", JavaResourceRootType.RESOURCE)
outputPath("app/build/classes/kotlin/jvm/main", true)
}
module("app_jvmTest") {
platform(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains:annotations:13.0", DependencyScope.COMPILE)
moduleDependency("lib_jvmMain", DependencyScope.COMPILE)
moduleDependency("app_test", DependencyScope.COMPILE)
moduleDependency("app_jvmMain", DependencyScope.COMPILE)
moduleDependency("app_commonMain", DependencyScope.COMPILE)
moduleDependency("app_commonTest", DependencyScope.COMPILE)
sourceFolder("app/src/jvmTest/kotlin", JavaSourceRootType.TEST_SOURCE)
sourceFolder("app/src/jvmTest/resources", JavaResourceRootType.TEST_RESOURCE)
outputPath("app/build/classes/kotlin/jvm/test", false)
}
module("app_main") {
platform(TargetPlatformKind.Jvm[JvmTarget.JVM_1_8])
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains:annotations:13.0", DependencyScope.COMPILE)
sourceFolder("app/src/main/java", JavaSourceRootType.SOURCE)
sourceFolder("app/src/main/kotlin", JavaSourceRootType.SOURCE)
sourceFolder("app/src/main/resources", JavaResourceRootType.RESOURCE)
inheritProjectOutput()
}
module("app_test") {
platform(TargetPlatformKind.Jvm[JvmTarget.JVM_1_8])
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains:annotations:13.0", DependencyScope.COMPILE)
moduleDependency("app_main", DependencyScope.COMPILE)
sourceFolder("app/src/test/java", JavaSourceRootType.TEST_SOURCE)
sourceFolder("app/src/test/kotlin", JavaSourceRootType.TEST_SOURCE)
sourceFolder("app/src/test/resources", JavaResourceRootType.TEST_RESOURCE)
inheritProjectOutput()
}
module("lib")
module("lib_metadataMain") {
platform(TargetPlatformKind.Common)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("lib_commonMain", DependencyScope.COMPILE)
sourceFolder("lib/src/metadataMain/kotlin", KotlinSourceRootType.Source)
sourceFolder("lib/src/metadataMain/resources", KotlinResourceRootType.Resource)
outputPath("lib/build/classes/kotlin/metadata/main", true)
}
module("lib_metadataTest") {
platform(TargetPlatformKind.Common)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("lib_commonMain", DependencyScope.COMPILE)
moduleDependency("lib_commonTest", DependencyScope.COMPILE)
moduleDependency("lib_metadataMain", DependencyScope.COMPILE)
sourceFolder("lib/src/metadataTest/kotlin", KotlinSourceRootType.TestSource)
sourceFolder("lib/src/metadataTest/resources", KotlinResourceRootType.TestResource)
outputPath("lib/build/classes/kotlin/metadata/test", false)
}
module("lib_commonMain") {
platform(TargetPlatformKind.Common)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
sourceFolder("lib/src/commonMain/kotlin", KotlinSourceRootType.Source)
sourceFolder("lib/src/commonMain/resources", KotlinResourceRootType.Resource)
inheritProjectOutput()
}
module("lib_commonTest") {
platform(TargetPlatformKind.Common)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("lib_commonMain", DependencyScope.COMPILE)
sourceFolder("lib/src/commonTest/kotlin", KotlinSourceRootType.TestSource)
sourceFolder("lib/src/commonTest/resources", KotlinResourceRootType.TestResource)
inheritProjectOutput()
}
module("lib_jsMain") {
platform(TargetPlatformKind.JavaScript)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("lib_commonMain", DependencyScope.COMPILE)
sourceFolder("lib/src/jsMain/kotlin", KotlinSourceRootType.Source)
sourceFolder("lib/src/jsMain/resources", KotlinResourceRootType.Resource)
outputPath("lib/build/classes/kotlin/js/main", true)
}
module("lib_jsTest") {
platform(TargetPlatformKind.JavaScript)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-js:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
moduleDependency("lib_commonMain", DependencyScope.COMPILE)
moduleDependency("lib_commonTest", DependencyScope.COMPILE)
moduleDependency("lib_jsMain", DependencyScope.COMPILE)
sourceFolder("lib/src/jsTest/kotlin", KotlinSourceRootType.TestSource)
sourceFolder("lib/src/jsTest/resources", KotlinResourceRootType.TestResource)
outputPath("lib/build/classes/kotlin/js/test", false)
}
module("lib_jvmMain") {
platform(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains:annotations:13.0", DependencyScope.COMPILE)
moduleDependency("lib_commonMain", DependencyScope.COMPILE)
sourceFolder("lib/src/jvmMain/kotlin", JavaSourceRootType.SOURCE)
sourceFolder("lib/src/jvmMain/resources", JavaResourceRootType.RESOURCE)
outputPath("lib/build/classes/kotlin/jvm/main", true)
}
module("lib_jvmTest") {
platform(TargetPlatformKind.Jvm[JvmTarget.JVM_1_6])
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains.kotlin:kotlin-stdlib-common:$kotlinVersion", DependencyScope.COMPILE)
libraryDependency("Gradle: org.jetbrains:annotations:13.0", DependencyScope.COMPILE)
moduleDependency("lib_commonTest", DependencyScope.COMPILE)
moduleDependency("lib_commonMain", DependencyScope.COMPILE)
moduleDependency("lib_jvmMain", DependencyScope.COMPILE)
sourceFolder("lib/src/jvmTest/kotlin", JavaSourceRootType.TEST_SOURCE)
sourceFolder("lib/src/jvmTest/resources", JavaResourceRootType.TEST_RESOURCE)
outputPath("lib/build/classes/kotlin/jvm/test", false)
}
}
}
private fun checkProjectStructure(body: ProjectInfo.() -> Unit = {}) {
checkProjectStructure(myProject, projectPath, body)
}
override fun importProject() {
val isCreateEmptyContentRootDirectories = currentExternalProjectSettings.isCreateEmptyContentRootDirectories
currentExternalProjectSettings.isCreateEmptyContentRootDirectories = true
try {
super.importProject()
} finally {
currentExternalProjectSettings.isCreateEmptyContentRootDirectories = isCreateEmptyContentRootDirectories
}
}
companion object {
@Parameterized.Parameters(name = "{index}: with Gradle-{0}")
@Throws(Throwable::class)
@JvmStatic
fun data() = listOf(arrayOf("4.7"))
}
}
@@ -0,0 +1,205 @@
/*
* 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.gradle
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleManager
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.rootManager
import com.intellij.openapi.roots.*
import com.intellij.openapi.util.io.FileUtil
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.jps.util.JpsPathUtil
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.idea.project.targetPlatform
class MessageCollector {
private val builder = StringBuilder()
fun report(message: String) {
builder.append(message).append('\n')
}
fun check() {
val message = builder.toString()
if (message.isNotEmpty()) {
assert(false) { message }
}
}
}
class ProjectInfo(project: Project, private val projectPath: String) {
private val messageCollector = MessageCollector()
private val moduleManager = ModuleManager.getInstance(project)
private val expectedModuleNames = HashSet<String>()
private var allModulesAsserter: (ModuleInfo.() -> Unit)? = null
fun allModules(body: ModuleInfo.() -> Unit) {
assert(allModulesAsserter == null)
allModulesAsserter = body
}
fun module(name: String, body: ModuleInfo.() -> Unit = {}) {
val module = moduleManager.findModuleByName(name)
if (module == null) {
messageCollector.report("No module found: '$name'")
return
}
val moduleInfo = ModuleInfo(module, messageCollector, projectPath)
allModulesAsserter?.let { moduleInfo.it() }
moduleInfo.run(body)
expectedModuleNames += name
}
fun run(body: ProjectInfo.() -> Unit = {}) {
body()
val actualNames = moduleManager.modules.map { it.name }.sorted()
val expectedNames = expectedModuleNames.sorted()
if (actualNames != expectedNames) {
messageCollector.report("Expected module list $expectedNames doesn't match the actual one: $actualNames")
}
messageCollector.check()
}
}
class ModuleInfo(
private val module: Module,
private val messageCollector: MessageCollector,
private val projectPath: String
) {
private val rootModel = module.rootManager
private val expectedDependencyNames = HashSet<String>()
private val expectedSourceRoots = HashSet<String>()
private val sourceFolderByPath by lazy {
rootModel.contentEntries.asSequence()
.flatMap { it.sourceFolders.asSequence() }
.mapNotNull {
val path = it.file?.path ?: return@mapNotNull null
FileUtil.getRelativePath(projectPath, path, '/')!! to it
}
.toMap()
}
fun languageVersion(version: String) {
val actualVersion = module.languageVersionSettings.languageVersion.versionString
if (actualVersion != version) {
messageCollector.report("Module '${module.name}': expected language version '$version' but found '$actualVersion'")
}
}
fun apiVersion(version: String) {
val actualVersion = module.languageVersionSettings.apiVersion.versionString
if (actualVersion != version) {
messageCollector.report("Module '${module.name}': expected API version '$version' but found '$actualVersion'")
}
}
fun platform(platform: TargetPlatformKind<*>) {
val actualPlatform = module.targetPlatform
if (actualPlatform != platform) {
messageCollector.report(
"Module '${module.name}': expected platform '${platform.description}' but found '${actualPlatform?.description}'"
)
}
}
fun libraryDependency(libraryName: String, scope: DependencyScope) {
val libraryEntry = rootModel.orderEntries.filterIsInstance<LibraryOrderEntry>().singleOrNull { it.libraryName == libraryName }
if (libraryEntry == null) {
messageCollector.report("Module '${module.name}': No library dependency found: '$libraryName'")
return
}
checkDependencyScope(libraryEntry, scope)
expectedDependencyNames += libraryEntry.presentableName
}
fun moduleDependency(moduleName: String, scope: DependencyScope) {
val moduleEntry = rootModel.orderEntries.filterIsInstance<ModuleOrderEntry>().singleOrNull { it.moduleName == moduleName }
if (moduleEntry == null) {
messageCollector.report("Module '${module.name}': No module dependency found: '$moduleName'")
return
}
checkDependencyScope(moduleEntry, scope)
expectedDependencyNames += moduleEntry.presentableName
}
fun sourceFolder(pathInProject: String, rootType: JpsModuleSourceRootType<*>) {
val sourceFolder = sourceFolderByPath[pathInProject]
if (sourceFolder == null) {
messageCollector.report("Module '${module.name}': No source folder found: '$pathInProject'")
return
}
expectedSourceRoots += pathInProject
val actualRootType = sourceFolder.rootType
if (actualRootType != rootType) {
messageCollector.report(
"Module '${module.name}', source root '$pathInProject': Expected root type $rootType doesn't match the actual one: $actualRootType"
)
return
}
}
fun inheritProjectOutput() {
val isInherited = CompilerModuleExtension.getInstance(module)?.isCompilerOutputPathInherited ?: true
if (!isInherited) {
messageCollector.report("Module '${module.name}': project output is not inherited")
}
}
fun outputPath(pathInProject: String, isProduction: Boolean) {
val compilerModuleExtension = CompilerModuleExtension.getInstance(module)
val url = if (isProduction) compilerModuleExtension?.compilerOutputUrl else compilerModuleExtension?.compilerOutputUrlForTests
val actualPathInProject = url?.let {
FileUtil.getRelativePath(
projectPath,
JpsPathUtil.urlToPath(
it
),
'/'
)
}
if (actualPathInProject != pathInProject) {
messageCollector.report(
"Module '${module.name}': Expected output path $pathInProject doesn't match the actual one: $actualPathInProject"
)
return
}
}
fun run(body: ModuleInfo.() -> Unit = {}) {
body()
val actualDependencyNames = rootModel
.orderEntries
.filter { it is ModuleOrderEntry || it is LibraryOrderEntry }
.map { it.presentableName }
.sorted()
val expectedDependencyNames = expectedDependencyNames.sorted()
if (actualDependencyNames != expectedDependencyNames) {
messageCollector.report("Module '${module.name}': Expected dependency list $expectedDependencyNames doesn't match the actual one: $actualDependencyNames")
}
val actualSourceRoots = sourceFolderByPath.keys.sorted()
val expectedSourceRoots = expectedSourceRoots.sorted()
if (actualSourceRoots != expectedSourceRoots) {
messageCollector.report("Module '${module.name}': Expected source root list $expectedSourceRoots doesn't match the actual one: $actualSourceRoots")
}
}
private fun checkDependencyScope(library: ExportableOrderEntry, scope: DependencyScope) {
val actualScope = library.scope
if (actualScope != scope) {
messageCollector.report("Module '${module.name}': Dependency '${library.presentableName}': expected scope '$scope' but found '$actualScope'")
}
}
}
fun checkProjectStructure(project: Project, projectPath: String, body: ProjectInfo.() -> Unit = {}) {
ProjectInfo(project, projectPath).run(body)
}