Add a few integration tests for the new MPP plugin

This commit is contained in:
Sergey Igushkin
2018-07-25 11:23:45 +03:00
parent 1e95e4d427
commit 209d0cf6a1
24 changed files with 537 additions and 0 deletions
@@ -0,0 +1,211 @@
/*
* 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 org.jetbrains.kotlin.gradle.util.modify
import org.junit.Assert
import org.junit.Test
import java.util.zip.ZipFile
class NewMultiplatformIT : BaseGradleIT() {
val gradleVersion = GradleVersionRequired.AtLeast("4.8")
private fun Project.targetClassesDir(targetName: String, sourceSetName: String = "main") =
classesDir(sourceSet = "$targetName/$sourceSetName")
@Test
fun testLibAndApp() {
val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")
val appProject = Project("sample-app", gradleVersion, "new-mpp-lib-and-app")
with(libProject) {
build("publish") {
assertSuccessful()
assertTasksExecuted(":compileKotlinJvm6", ":compileKotlinNodeJs", ":jvm6Jar", ":nodeJsJar")
val repoDir = projectDir.resolve("repo")
val moduleDir = repoDir.resolve("com/example/sample-lib/1.0")
val jvmJarName = "sample-lib-1.0-jvm6.jar"
val jsJarName = "sample-lib-1.0-nodeJs.jar"
listOf(jvmJarName, jsJarName, "sample-lib-1.0.module").forEach {
Assert.assertTrue(moduleDir.resolve(it).exists())
}
val jvmJarEntries = ZipFile(moduleDir.resolve(jvmJarName)).entries().asSequence().map { it.name }.toSet()
Assert.assertTrue("com/example/lib/CommonKt.class" in jvmJarEntries)
Assert.assertTrue("com/example/lib/MainKt.class" in jvmJarEntries)
val jsJar = ZipFile(moduleDir.resolve(jsJarName))
val compiledJs = jsJar.getInputStream(jsJar.getEntry("sample-lib.js")).reader().readText()
Assert.assertTrue("function id(" in compiledJs)
Assert.assertTrue("function idUsage(" in compiledJs)
Assert.assertTrue("function expectedFun(" in compiledJs)
Assert.assertTrue("function main(" in compiledJs)
}
}
val libLocalRepoUri = libProject.projectDir.resolve("repo").toURI()
with(appProject) {
setupWorkingDir()
gradleBuildScript().appendText("\nrepositories { maven { url '$libLocalRepoUri' } }")
fun CompiledProject.checkAppBuild() {
assertSuccessful()
assertTasksExecuted(":compileKotlinJvm6", ":compileKotlinJvm8", ":compileKotlinNodeJs")
projectDir.resolve(targetClassesDir("jvm6")).run {
Assert.assertTrue(resolve("com/example/app/AKt.class").exists())
Assert.assertTrue(this.resolve("com/example/app/UseBothIdsKt.class").exists())
}
projectDir.resolve(targetClassesDir("jvm8")).run {
Assert.assertTrue(resolve("com/example/app/AKt.class").exists())
Assert.assertTrue(resolve("com/example/app/UseBothIdsKt.class").exists())
Assert.assertTrue(resolve("com/example/app/Jdk8ApiUsageKt.class").exists())
}
projectDir.resolve(targetClassesDir("nodeJs")).resolve("sample-app.js").readText().run {
Assert.assertTrue(contains("console.info"))
Assert.assertTrue(contains("function nodeJsMain("))
}
}
build("assemble") {
checkAppBuild()
}
// Now run again with a project dependency instead of a module one:
libProject.projectDir.copyRecursively(projectDir.resolve(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}')") }
build("assemble", "--rerun-tasks") {
checkAppBuild()
}
}
}
@Test
fun testSourceSetCyclicDependencyDetection() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
setupWorkingDir()
gradleBuildScript().appendText("\n" + """
kotlin.sourceSets {
a
b { dependsOn a }
c { dependsOn b }
a.dependsOn(c)
}
""".trimIndent())
build("assemble") {
assertFailed()
assertContains("a -> c -> b -> a")
}
}
@Test
fun testJvmWithJavaEquivalence() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
lateinit var classesWithoutJava: Set<String>
fun getFilePathsSet(inDirectory: String): Set<String> {
val dir = projectDir.resolve(inDirectory)
return dir.walk().filter { it.isFile }.map { it.relativeTo(dir).path.replace('\\', '/') }.toSet()
}
build("assemble") {
assertSuccessful()
classesWithoutJava = getFilePathsSet("build/classes")
}
gradleBuildScript().modify { it.replace("presets.jvm", "presets.jvmWithJava") }
projectDir.resolve("src/main/java").apply {
mkdirs()
mkdir()
// Check that Java can access the dependencies (kotlin-stdlib):
resolve("JavaClassInJava.java").writeText("""
package com.example.lib;
import kotlin.sequences.Sequence;
class JavaClassInJava {
Sequence<String> makeSequence() { throw new UnsupportedOperationException(); }
}
""".trimIndent())
// Add a Kotlin source file in the Java source root and check that it is compiled:
resolve("KotlinClassInJava.kt").writeText("""
package com.example.lib
class KotlinClassInJava
""".trimIndent())
}
build("clean", "assemble") {
assertSuccessful()
val expectedClasses =
classesWithoutJava +
"kotlin/jvm6/main/com/example/lib/KotlinClassInJava.class" +
"java/main/com/example/lib/JavaClassInJava.class"
val actualClasses = getFilePathsSet("build/classes")
Assert.assertEquals(expectedClasses, actualClasses)
}
}
@Test
fun testLibWithTests() = with(Project("new-mpp-lib-with-tests", gradleVersion)) {
build("check") {
assertSuccessful()
assertTasksExecuted(
// compilation tasks:
":compileKotlinJs",
":compileTestKotlinJs",
":compileKotlinJvmWithoutJava",
":compileTestKotlinJvmWithoutJava",
":compileKotlinJvmWithJava",
":compileJava",
":compileTestKotlinJvmWithJava",
":compileTestJava",
// test tasks:
":jsTest", // does not run any actual tests for now
":jvmWithoutJavaTest",
":test"
)
val expectedKotlinOutputFiles = listOf(
kotlinClassesDir(sourceSet = "js/main") + "new-mpp-lib-with-tests.js",
kotlinClassesDir(sourceSet = "js/test") + "new-mpp-lib-with-tests_test.js",
*kotlinClassesDir(sourceSet = "jvmWithJava/main").let {
arrayOf(
it + "com/example/lib/JavaClassUsageKt.class",
it + "com/example/lib/CommonKt.class",
it + "META-INF/new-mpp-lib-with-tests.kotlin_module"
)
},
*kotlinClassesDir(sourceSet = "jvmWithJava/test").let {
arrayOf(
it + "com/example/lib/TestCommonCode.class",
it + "com/example/lib/TestWithJava.class",
it + "META-INF/new-mpp-lib-with-tests.kotlin_module" // Note: same name as in main
)
},
*kotlinClassesDir(sourceSet = "jvmWithoutJava/main").let {
arrayOf(
it + "com/example/lib/CommonKt.class",
it + "com/example/lib/MainKt.class",
it + "META-INF/new-mpp-lib-with-tests.kotlin_module"
)
},
*kotlinClassesDir(sourceSet = "jvmWithoutJava/test").let {
arrayOf(
it + "com/example/lib/TestCommonCode.class",
it + "com/example/lib/TestWithoutJava.class",
it + "META-INF/new-mpp-lib-with-tests.kotlin_module" // Note: same name as in main
)
}
)
expectedKotlinOutputFiles.forEach { assertFileExists(it) }
}
}
}
@@ -0,0 +1,62 @@
buildscript {
repositories {
mavenLocal()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin-multiplatform'
repositories {
mavenLocal()
jcenter()
// NB: Build of this module depends on 'sample-lib' publication. You need to add the local
// repository where 'sample-lib' artifacts are published.
}
kotlin {
sourceSets {
commonMain {
dependencies {
implementation 'com.example:sample-lib:1.0'
}
}
allJvm {
dependsOn commonMain
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib'
}
}
jvm6Main {
dependsOn allJvm
}
jvm8Main {
dependsOn allJvm
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
}
}
nodeJsMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-js'
}
}
}
targets {
fromPreset(presets.jvm, 'jvm6')
fromPreset(presets.jvm, 'jvm8') {
compilations.main {
tasks.getByName(compileKotlinTaskName) {
kotlinOptions {
jvmTarget = '1.8'
}
}
}
}
fromPreset(presets.js, 'nodeJs')
}
}
@@ -0,0 +1,9 @@
package com.example.app
import com.example.lib.*
fun main(args: Array<String>) {
println(id(123))
println(idUsage(456))
println(x())
}
@@ -0,0 +1,10 @@
package com.example.app
import com.example.lib.id
import com.example.lib.expectedFun
fun idUsage(x: Int): Int = id(x)
fun main(args: Array<String>) {
expectedFun()
}
@@ -0,0 +1,5 @@
package com.example.app
import kotlin.streams.asStream
fun useJdk8Api() = listOf(1, 2, 3).asSequence().asStream()
@@ -0,0 +1,9 @@
import kotlin.js.Console
import com.example.lib.*
external val console: Console
fun nodeJsMain(args: Array<String>) {
console.info(id(123), idUsage(), expectedFun())
}
@@ -0,0 +1,49 @@
group 'com.example'
version '1.0'
buildscript {
repositories {
mavenLocal()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin-multiplatform'
repositories {
mavenLocal()
jcenter()
maven { url "http://dl.bintray.com/kotlin/kotlinx.html/" }
}
kotlin {
targets {
fromPreset(presets.jvm, 'jvm6')
fromPreset(presets.js, 'nodeJs')
}
sourceSets {
jvm6Main {
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.23.4'
}
}
nodeJsMain {
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-html-js:0.6.11'
}
}
}
}
kotlin.sourceSets.each { println it.kotlin.srcDirs }
apply plugin: 'maven-publish'
publishing {
repositories {
maven { url "file://${projectDir.absolutePath.replace('\\', '/')}/repo" }
}
}
@@ -0,0 +1,5 @@
package com.example.lib
fun <T> id(t: T): T = t
expect fun expectedFun(): Unit
@@ -0,0 +1,7 @@
package com.example.lib
fun x(): String = "x"
actual fun expectedFun() {
println(id(x()))
}
@@ -0,0 +1,12 @@
package com.example.lib
import com.example.lib.id
import com.example.lib.expectedFun
fun idUsage() = id("123")
actual fun expectedFun() = Unit
fun main(args: Array<String>) {
expectedFun()
}
@@ -0,0 +1,52 @@
group 'com.example'
version '1.0'
buildscript {
repositories {
mavenLocal()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin-multiplatform'
repositories {
mavenLocal()
jcenter()
maven { url "http://dl.bintray.com/kotlin/kotlinx.html/" }
}
kotlin {
targets {
fromPreset(presets.jvm, 'jvmWithoutJava')
fromPreset(presets.jvmWithJava, 'jvmWithJava')
fromPreset(presets.js, 'js')
}
sourceSets {
commonTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test-common'
implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
}
}
configure([main, jvmWithoutJavaMain]) {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib'
}
}
configure([test, jvmWithoutJavaTest]) {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
}
}
jsTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test-js'
}
}
}
}
@@ -0,0 +1,5 @@
package com.example.lib
fun <T> id(t: T): T = t
expect fun expectedFun(): Unit
@@ -0,0 +1,18 @@
package com.example.lib
import kotlin.test.Test
import kotlin.test.assertEquals
class TestCommonCode {
@Test
fun testId() {
val x = 1
val idX = id(x)
assertEquals(x, idX)
}
@Test
fun testExpectedFun() {
expectedFun()
}
}
@@ -0,0 +1,14 @@
package com.example.lib
import com.example.lib.id
import com.example.lib.expectedFun
fun idUsage() = id("123")
actual fun expectedFun() = Unit
fun main(args: Array<String>) {
expectedFun()
}
fun jsSpecificFun() { expectedFun() }
@@ -0,0 +1,10 @@
package com.example.lib
import kotlin.test.Test
class TestJs {
@Test
fun testJsSpecificCode() {
jsSpecificFun()
}
}
@@ -0,0 +1,9 @@
package com.example.lib
fun x(): String = "x"
actual fun expectedFun() {
println(id(x()))
}
fun isJavaThere(): Boolean = false
@@ -0,0 +1,11 @@
package com.example.lib
import org.junit.Test
import org.junit.Assert.*
class TestWithoutJava {
@Test
fun test() {
assertFalse(isJavaThere())
}
}
@@ -0,0 +1,5 @@
package com.example.lib
actual fun expectedFun() { println(id(1)) }
fun f() = JavaClass()
@@ -0,0 +1,11 @@
package com.example.lib;
import org.junit.Test;
public class TestJava {
@Test
public void testJava() {
new JavaClass();
JavaClassUsageKt.f();
}
}
@@ -0,0 +1,15 @@
package com.example.lib
import org.junit.Test
class TestWithJava {
@Test
fun testJavaClass() {
JavaClass()
f()
}
companion object {
val seesJavaTestClass = TestJava::class
}
}