Add tests for Kotlin/Native in new MPP

* Add K/N variants to the general MPP tests
* Also check the separated publishing
This commit is contained in:
Sergey Igushkin
2018-08-23 19:12:37 +03:00
committed by Ilya Matveev
parent 67bd659390
commit 577bae763c
9 changed files with 130 additions and 21 deletions
@@ -9,10 +9,12 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetConsistencyChecks import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetConsistencyChecks
import org.jetbrains.kotlin.gradle.util.checkBytecodeContains import org.jetbrains.kotlin.gradle.util.checkBytecodeContains
import org.jetbrains.kotlin.gradle.util.isWindows
import org.jetbrains.kotlin.gradle.util.modify import org.jetbrains.kotlin.gradle.util.modify
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
import java.util.zip.ZipFile import java.util.zip.ZipFile
import kotlin.test.assertTrue
class NewMultiplatformIT : BaseGradleIT() { class NewMultiplatformIT : BaseGradleIT() {
val gradleVersion = GradleVersionRequired.AtLeast("4.8") val gradleVersion = GradleVersionRequired.AtLeast("4.8")
@@ -26,35 +28,43 @@ class NewMultiplatformIT : BaseGradleIT() {
val appProject = Project("sample-app", gradleVersion, "new-mpp-lib-and-app") val appProject = Project("sample-app", gradleVersion, "new-mpp-lib-and-app")
val oldStyleAppProject = Project("sample-old-style-app", gradleVersion, "new-mpp-lib-and-app") val oldStyleAppProject = Project("sample-old-style-app", gradleVersion, "new-mpp-lib-and-app")
val hostTargetName = if (isWindows) "mingw64" else "linux64"
val compileTasksNames =
listOf("Jvm6", "NodeJs", "Metadata", "Wasm32", hostTargetName.capitalize()).map { ":compileKotlin$it" }
with(libProject) { with(libProject) {
build("publish") { build("publish") {
assertSuccessful() assertSuccessful()
assertTasksExecuted( assertTasksExecuted(*compileTasksNames.toTypedArray(), ":jvm6Jar", ":nodeJsJar", ":metadataJar")
":compileKotlinJvm6", ":compileKotlinNodeJs", ":compileKotlinMetadata",
":jvm6Jar", ":nodeJsJar", ":metadataJar"
)
val moduleDir = projectDir.resolve("repo/com/example/sample-lib/1.0")
val jvmJarName = "sample-lib-1.0-jvm6.jar"
val jsJarName = "sample-lib-1.0-nodeJs.jar"
val metadataJarName = "sample-lib-1.0-metadata.jar"
listOf(jvmJarName, jsJarName, metadataJarName, "sample-lib-1.0.module").forEach { val groupDir = projectDir.resolve("repo/com/example")
Assert.assertTrue(moduleDir.resolve(it).exists()) val jvmJarName = "sample-lib-jvm6/1.0/sample-lib-jvm6-1.0-jvm6.jar"
val jsJarName = "sample-lib-nodejs/1.0/sample-lib-nodejs-1.0-nodeJs.jar"
val metadataJarName = "sample-lib-metadata/1.0/sample-lib-metadata-1.0-metadata.jar"
val wasmKlibName = "sample-lib-wasm32/1.0/sample-lib-wasm32-1.0.klib"
val nativeKlibName = "sample-lib-$hostTargetName/1.0/sample-lib-$hostTargetName-1.0.klib"
listOf(jvmJarName, jsJarName, metadataJarName, "sample-lib/1.0/sample-lib-1.0.module").forEach {
Assert.assertTrue("$it should exist", groupDir.resolve(it).exists())
} }
val jvmJarEntries = ZipFile(moduleDir.resolve(jvmJarName)).entries().asSequence().map { it.name }.toSet() val jvmJarEntries = ZipFile(groupDir.resolve(jvmJarName)).entries().asSequence().map { it.name }.toSet()
Assert.assertTrue("com/example/lib/CommonKt.class" in jvmJarEntries) Assert.assertTrue("com/example/lib/CommonKt.class" in jvmJarEntries)
Assert.assertTrue("com/example/lib/MainKt.class" in jvmJarEntries) Assert.assertTrue("com/example/lib/MainKt.class" in jvmJarEntries)
val jsJar = ZipFile(moduleDir.resolve(jsJarName)) val jsJar = ZipFile(groupDir.resolve(jsJarName))
val compiledJs = jsJar.getInputStream(jsJar.getEntry("sample-lib.js")).reader().readText() val compiledJs = jsJar.getInputStream(jsJar.getEntry("sample-lib.js")).reader().readText()
Assert.assertTrue("function id(" in compiledJs) Assert.assertTrue("function id(" in compiledJs)
Assert.assertTrue("function idUsage(" in compiledJs) Assert.assertTrue("function idUsage(" in compiledJs)
Assert.assertTrue("function expectedFun(" in compiledJs) Assert.assertTrue("function expectedFun(" in compiledJs)
Assert.assertTrue("function main(" in compiledJs) Assert.assertTrue("function main(" in compiledJs)
val metadataJarEntries = ZipFile(moduleDir.resolve(metadataJarName)).entries().asSequence().map { it.name }.toSet() val metadataJarEntries = ZipFile(groupDir.resolve(metadataJarName)).entries().asSequence().map { it.name }.toSet()
Assert.assertTrue("com/example/lib/CommonKt.kotlin_metadata" in metadataJarEntries) Assert.assertTrue("com/example/lib/CommonKt.kotlin_metadata" in metadataJarEntries)
Assert.assertTrue(groupDir.resolve(wasmKlibName).exists())
Assert.assertTrue(groupDir.resolve(nativeKlibName).exists())
} }
} }
@@ -66,7 +76,7 @@ class NewMultiplatformIT : BaseGradleIT() {
fun CompiledProject.checkAppBuild() { fun CompiledProject.checkAppBuild() {
assertSuccessful() assertSuccessful()
assertTasksExecuted(":compileKotlinJvm6", ":compileKotlinJvm8", ":compileKotlinNodeJs", ":compileKotlinMetadata") assertTasksExecuted(*compileTasksNames.toTypedArray())
projectDir.resolve(targetClassesDir("jvm6")).run { projectDir.resolve(targetClassesDir("jvm6")).run {
Assert.assertTrue(resolve("com/example/app/AKt.class").exists()) Assert.assertTrue(resolve("com/example/app/AKt.class").exists())
@@ -87,6 +97,19 @@ class NewMultiplatformIT : BaseGradleIT() {
Assert.assertTrue(contains("console.info")) Assert.assertTrue(contains("console.info"))
Assert.assertTrue(contains("function nodeJsMain(")) Assert.assertTrue(contains("function nodeJsMain("))
} }
projectDir.resolve(targetClassesDir("wasm32")).run {
Assert.assertTrue(resolve("sample-app.klib").exists())
}
assertFileExists("build/bin/wasm32/main/debug/main.wasm.js")
assertFileExists("build/bin/wasm32/main/debug/main.wasm")
assertFileExists("build/bin/wasm32/main/release/main.wasm.js")
assertFileExists("build/bin/wasm32/main/release/main.wasm")
val nativeExeName = if (isWindows) "main.exe" else "main.kexe"
assertFileExists("build/bin/$hostTargetName/main/release/$nativeExeName")
assertFileExists("build/bin/$hostTargetName/main/debug/$nativeExeName")
} }
build("assemble", "resolveRuntimeDependencies") { build("assemble", "resolveRuntimeDependencies") {
@@ -99,7 +122,7 @@ class NewMultiplatformIT : BaseGradleIT() {
projectDir.resolve("settings.gradle").appendText("\ninclude '${libProject.projectDir.name}'") projectDir.resolve("settings.gradle").appendText("\ninclude '${libProject.projectDir.name}'")
gradleBuildScript().modify { it.replace("'com.example:sample-lib:1.0'", "project(':${libProject.projectDir.name}')") } gradleBuildScript().modify { it.replace("'com.example:sample-lib:1.0'", "project(':${libProject.projectDir.name}')") }
build("assemble", "--rerun-tasks") { build("clean", "assemble", "--rerun-tasks") {
checkAppBuild() checkAppBuild()
} }
} }
@@ -342,7 +365,7 @@ class NewMultiplatformIT : BaseGradleIT() {
doFirst { doFirst {
['Api', 'Implementation', 'CompileOnly', 'RuntimeOnly'].each { kind -> ['Api', 'Implementation', 'CompileOnly', 'RuntimeOnly'].each { kind ->
def configuration = configurations.getByName("commonMain${'$'}kind" + '$METADATA_CONFIGURATION_NAME_SUFFIX') def configuration = configurations.getByName("commonMain${'$'}kind" + '$METADATA_CONFIGURATION_NAME_SUFFIX')
configuration.files.each { println '$pathPrefix' + configuration.name + '->' + it.absolutePath } configuration.files.each { println '$pathPrefix' + configuration.name + '->' + it.name }
} }
} }
} }
@@ -353,16 +376,13 @@ class NewMultiplatformIT : BaseGradleIT() {
build("printMetadataFiles") { build("printMetadataFiles") {
assertSuccessful() assertSuccessful()
val expectedPath = val expectedFileName = "sample-lib-1.0-${KotlinMultiplatformPlugin.METADATA_TARGET_NAME}.jar"
localRepo.resolve(
"com/example/sample-lib/1.0/sample-lib-1.0-${KotlinMultiplatformPlugin.METADATA_TARGET_NAME}.jar"
).absolutePath
val paths = metadataDependencyRegex.findAll(output).map { it.groupValues[1] to it.groupValues[2] }.toSet() val paths = metadataDependencyRegex.findAll(output).map { it.groupValues[1] to it.groupValues[2] }.toSet()
Assert.assertEquals( Assert.assertEquals(
listOf("Api", "Implementation", "CompileOnly", "RuntimeOnly").map { listOf("Api", "Implementation", "CompileOnly", "RuntimeOnly").map {
"commonMain$it$METADATA_CONFIGURATION_NAME_SUFFIX" to expectedPath "commonMain$it$METADATA_CONFIGURATION_NAME_SUFFIX" to expectedFileName
}.toSet(), }.toSet(),
paths paths
) )
@@ -370,6 +390,22 @@ class NewMultiplatformIT : BaseGradleIT() {
} }
} }
@Test
fun testPublishingOnlySupportedNativeTargets() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
val (publishedVariant, nonPublishedVariant) = listOf("mingw64", "linux64").let { if (!isWindows) it.reversed() else it }
build("publish") {
assertSuccessful()
assertFileExists("repo/com/example/sample-lib-$publishedVariant/1.0/sample-lib-$publishedVariant-1.0.klib")
assertNoSuchFile("repo/com/example/sample-lib-$nonPublishedVariant") // check that no artifacts are published for that variant
// but check that the module metadata contains both variants:
val gradleModuleMetadata = projectDir.resolve("repo/com/example/sample-lib/1.0/sample-lib-1.0.module").readText()
assertTrue(""""name": "linux64-api"""" in gradleModuleMetadata)
assertTrue(""""name": "mingw64-api"""" in gradleModuleMetadata)
}
}
@Test @Test
fun testOptionalExpectations() = with(Project("new-mpp-lib-with-tests", gradleVersion)) { fun testOptionalExpectations() = with(Project("new-mpp-lib-with-tests", gradleVersion)) {
@@ -58,6 +58,13 @@ kotlin {
} }
} }
fromPreset(presets.js, 'nodeJs') fromPreset(presets.js, 'nodeJs')
fromPreset(presets.wasm32, 'wasm32')
fromPreset(presets.linuxX64, 'linux64')
fromPreset(presets.mingwX64, 'mingw64')
configure([wasm32, linux64, mingw64]) {
compilations.main.outputKinds += org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind.EXECUTABLE
}
} }
} }
@@ -0,0 +1,11 @@
/*
* 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.
*/
import com.example.lib.*
fun main(args: Array<String>) {
id(id(123))
expectedFun()
}
@@ -0,0 +1,11 @@
/*
* 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.
*/
import com.example.lib.*
fun main(args: Array<String>) {
id(id(123))
expectedFun()
}
@@ -0,0 +1,11 @@
/*
* 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.
*/
import com.example.lib.*
fun main(args: Array<String>) {
id(id(123))
expectedFun()
}
@@ -23,6 +23,9 @@ kotlin {
targets { targets {
fromPreset(presets.jvm, 'jvm6') fromPreset(presets.jvm, 'jvm6')
fromPreset(presets.js, 'nodeJs') fromPreset(presets.js, 'nodeJs')
fromPreset(presets.wasm32, 'wasm32')
fromPreset(presets.linuxX64, 'linux64')
fromPreset(presets.mingwX64, 'mingw64')
} }
sourceSets { sourceSets {
jvm6Main { jvm6Main {
@@ -0,0 +1,10 @@
/*
* 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 com.example.lib
actual fun expectedFun(): Unit {
id(123)
}
@@ -0,0 +1,10 @@
/*
* 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 com.example.lib
actual fun expectedFun(): Unit {
id(123)
}
@@ -0,0 +1,10 @@
/*
* 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 com.example.lib
actual fun expectedFun(): Unit {
id(123)
}