Add tests for new binaries DSL

This commit is contained in:
Ilya Matveev
2018-12-16 19:11:02 +07:00
parent 833e9a90a2
commit 7b1552f3d6
18 changed files with 465 additions and 10 deletions
@@ -6,13 +6,11 @@ package org.jetbrains.kotlin.gradle
import org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
import org.jetbrains.kotlin.gradle.plugin.mpp.UnusedSourceSetsChecker
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetConsistencyChecks
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.testResolveAllConfigurations
import org.jetbrains.kotlin.gradle.util.*
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.HostManager
import org.junit.Assert
@@ -152,6 +150,15 @@ class NewMultiplatformIT : BaseGradleIT() {
val nativeExeName = if (isWindows) "main.exe" else "main.kexe"
assertFileExists("build/bin/$nativeHostTargetName/mainReleaseExecutable/$nativeExeName")
assertFileExists("build/bin/$nativeHostTargetName/mainDebugExecutable/$nativeExeName")
// Check that linker options was correctly passed to the K/N compiler.
output.lineSequence().filter {
it.contains("Run tool: konanc") && it.contains("-p program")
}.toList().also {
assertTrue(it.isNotEmpty())
}.forEach {
assertTrue(it.contains("-linker-options -L."))
}
}
build("assemble", "resolveRuntimeDependencies") {
@@ -171,6 +178,12 @@ class NewMultiplatformIT : BaseGradleIT() {
build("clean", "assemble", "--rerun-tasks") {
checkAppBuild()
}
// Check that binary getters initially introduced in 1.3 work.
build("checkBinaryGetters") {
assertTrue(output.contains("Wasm binary file: main.wasm"))
assertTrue(output.contains("Wasm link task: linkMainReleaseExecutableWasm32"))
}
}
with(oldStyleAppProject) {
@@ -835,6 +848,158 @@ class NewMultiplatformIT : BaseGradleIT() {
}
}
@Test
fun testNativeBinaryKotlinDSL() = doTestNativeBinaryDSL("kotlin-dsl")
@Test
fun testNativeBinaryGroovyDSL() = doTestNativeBinaryDSL("groovy-dsl")
private fun doTestNativeBinaryDSL(
projectName: String,
gradleVersionRequired: GradleVersionRequired = gradleVersion
) = with(transformProjectWithPluginsDsl(projectName, gradleVersionRequired, "new-mpp-native-binaries")) {
val hostSuffix = nativeHostTargetName.capitalize()
val binaries = mutableListOf(
"debugExecutable" to "native-binary",
"releaseExecutable" to "native-binary",
"fooDebugExecutable" to "foo",
"fooReleaseExecutable" to "foo",
"barReleaseExecutable" to "bar",
"bazReleaseExecutable" to "my-baz",
"testDebugExecutable" to "test",
"test2ReleaseExecutable" to "test2",
"releaseStatic" to "native_binary",
"releaseShared" to "native_binary"
)
val linkTasks = binaries.map { (name, _) -> "link${name.capitalize()}$hostSuffix" }
val outputFiles = binaries.map { (name, fileBaseName) ->
val outputKind = NativeOutputKind.values().single { name.endsWith(it.taskNameClassifier, true) }.compilerOutputKind
val prefix = outputKind.prefix(HostManager.host)
val suffix = outputKind.suffix(HostManager.host)
val fileName = "$prefix$fileBaseName$suffix"
"build/bin/$nativeHostTargetName/$name/$fileName"
}
val runTasks = listOf(
"runDebugExecutable",
"runReleaseExecutable",
"runFooDebugExecutable",
"runFooReleaseExecutable",
"runBarReleaseExecutable",
"runBazReleaseExecutable",
"runTest2ReleaseExecutable"
).map { "$it$hostSuffix" }.toMutableList()
val binariesTasks = arrayOf("${nativeHostTargetName}MainBinaries", "${nativeHostTargetName}TestBinaries")
// Check that all link and run tasks are generated.
build(*binariesTasks) {
assertSuccessful()
assertTasksExecuted(linkTasks.map { ":$it" })
outputFiles.forEach {
assertFileExists(it)
}
// Check that getters work fine.
assertTrue(output.contains("Check link task: linkReleaseShared$hostSuffix"))
assertTrue(output.contains("Check run task: runFooReleaseExecutable$hostSuffix"))
}
build("tasks") {
assertSuccessful()
runTasks.forEach {
assertTrue(output.contains(it), "The 'tasks' output doesn't contain a task ${it}")
}
}
// Clean the build to check that run tasks build corresponding binaries.
build("clean") {
assertSuccessful()
}
// Check that run tasks work find and an entry point can be specified.
build("runDebugExecutable$hostSuffix") {
assertSuccessful()
assertTrue(output.contains("<root>.main"))
}
build("runBazReleaseExecutable$hostSuffix") {
assertSuccessful()
assertTrue(output.contains("foo.main"))
}
build("runTest2ReleaseExecutable$hostSuffix") {
assertSuccessful()
assertTrue(output.contains("tests.foo"))
}
// Check that we still have a default test task and it can be executed properly.
build("${nativeHostTargetName}Test") {
assertSuccessful()
assertTrue(output.contains("tests.foo"))
}
fun CompiledProject.checkFrameworkCompilationCommandLine(check: (String) -> Unit) {
output.lineSequence().filter {
it.contains("Run tool: konanc") && it.contains("-p framework")
}.toList().also {
assertTrue(it.isNotEmpty())
}.forEach(check)
}
if (HostManager.hostIsMac) {
// Check dependency exporting and bitcode embedding in frameworks.
// For release builds
build("linkReleaseFrameworkIos") {
assertSuccessful()
assertFileExists("build/bin/ios/releaseFramework/native_binary.framework")
fileInWorkingDir("build/bin/ios/releaseFramework/native_binary.framework/Headers/native_binary.h")
.readText().contains("+ (int32_t)exported")
// Check that by default release frameworks have bitcode embedded.
checkFrameworkCompilationCommandLine {
assertTrue(it.contains("-Xembed-bitcode"))
assertTrue(it.contains("-opt"))
}
}
// For debug builds
build("linkDebugFrameworkIos") {
assertSuccessful()
assertFileExists("build/bin/ios/debugFramework/native_binary.framework")
fileInWorkingDir("build/bin/ios/debugFramework/native_binary.framework/Headers/native_binary.h")
.readText().contains("+ (int32_t)exported")
// Check that by default debug frameworks have bitcode marker embedded.
checkFrameworkCompilationCommandLine {
assertTrue(it.contains("-Xembed-bitcode-marker"))
assertTrue(it.contains("-g"))
}
}
// Check manual disabling bitcode embedding and custom command line args.
build("linkCustomReleaseFrameworkIos") {
assertSuccessful()
checkFrameworkCompilationCommandLine {
assertTrue(it.contains("-linker-options -L."))
assertTrue(it.contains("-Xtime"))
assertFalse(it.contains("-Xembed-bitcode-marker"))
assertFalse(it.contains("-Xembed-bitcode"))
}
}
// Check that plugin doesn't allow exporting dependencies not added in the API configuration.
val buildFile = listOf("build.gradle", "build.gradle.kts").map { projectDir.resolve(it) }.single { it.exists() }
buildFile.modify {
it.replace("api(project(\":exported\"))", "")
}
build("linkReleaseFrameworkIos") {
assertFailed()
val failureMsg = "Following dependencies exported in the releaseFramework binary " +
"are not specified as API-dependencies of a corresponding source set"
assertTrue(output.contains(failureMsg))
}
}
}
@Test
fun testSourceJars() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
setupWorkingDir()
@@ -1,5 +1,3 @@
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind.EXECUTABLE
plugins {
id("org.jetbrains.kotlin.multiplatform").version("<pluginMarkerVersion>")
id("maven-publish")
@@ -29,6 +27,8 @@ kotlin {
compilations.getByName("main") {
outputKinds.add(EXECUTABLE)
entryPoint = "com.example.app.native.main"
// Check that linker options are correctly passed to the compiler.
linkerOpts = mutableListOf("-L.")
}
}
@@ -59,6 +59,13 @@ kotlin {
}
}
}
tasks.create("checkBinaryGetters") {
doLast {
println("Wasm binary file: ${wasm32.compilations.getByName("main").getBinary("EXECUTABLE", "RELEASE").name}")
println("Wasm link task: ${wasm32.compilations.getByName("main").getLinkTask("EXECUTABLE", "RELEASE").name}")
}
}
}
tasks.create("resolveRuntimeDependencies", DefaultTask::class.java) {
@@ -67,4 +74,4 @@ tasks.create("resolveRuntimeDependencies", DefaultTask::class.java) {
val configName = kotlin.jvm("jvm6").compilations["main"].runtimeDependencyConfigurationName
configurations[configName].resolve()
}
}
}
@@ -66,6 +66,8 @@ kotlin {
configure([wasm32, linux64, mingw64, macos64]) {
compilations.main.outputKinds += org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind.EXECUTABLE
compilations.main.entryPoint = "com.example.app.native.main"
// Check that linker options are correctly passed to the compiler.
compilations.main.linkerOpts = ['-L.']
}
}
}
@@ -76,4 +78,11 @@ task resolveRuntimeDependencies(type: DefaultTask) {
def configName = kotlin.targets.jvm6.compilations.main.runtimeDependencyConfigurationName
configurations[configName].resolve()
}
}
task checkBinaryGetters {
doLast {
println("Wasm binary file: ${kotlin.targets.wasm32.compilations.main.getBinary("EXECUTABLE", "RELEASE").name}")
println("Wasm link task: ${kotlin.targets.wasm32.compilations.main.getLinkTask("EXECUTABLE", "RELEASE").name}")
}
}
@@ -0,0 +1,85 @@
buildscript {
repositories {
mavenLocal()
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'kotlin-multiplatform'
repositories {
mavenLocal()
jcenter()
}
kotlin {
sourceSets {
commonMain {
dependencies {
api "org.jetbrains.kotlin:kotlin-stdlib-common"
}
}
iosMain {
dependencies {
api(project(":exported"))
}
}
commonTest {
dependencies {
api "org.jetbrains.kotlin:kotlin-test-annotations-common"
}
}
}
targets {
macosX64("macos64")
linuxX64("linux64")
mingwX64("windows64")
configure([macos64, linux64, windows64]) {
binaries {
executable() // Executable with default name.
executable("foo") // Custom binary name.
executable("bar", [RELEASE]) // Custom build types.
// Configure a binary.
executable("baz", [RELEASE]) {
// Rename an output binary: baz.kexe -> my-baz.kexe.
baseName = "my-baz"
// Use a custom entry point.
entryPoint = "foo.main"
}
executable("test2", [RELEASE]) {
compilation = compilations["test"]
}
sharedLib([RELEASE])
staticLib([RELEASE])
}
// Check that we can access binaries/tasks:
// Just by name:
println("Check link task: ${binaries.releaseShared.linkTask.name}")
// Using a typed getter:
println("Check run task: ${binaries.getExecutable("foo", RELEASE).runTask.name}")
}
iosArm64("ios") {
binaries {
framework {
export project(':exported')
}
framework('custom', [RELEASE]) {
embedBitcode = 'DISABLE'
linkerOpts = ['-L.']
freeCompilerArgs = ["-Xtime"]
}
}
}
}
}
@@ -0,0 +1,19 @@
plugins {
id("org.jetbrains.kotlin.multiplatform")
}
repositories {
mavenLocal()
jcenter()
maven { setUrl("http://dl.bintray.com/kotlin/kotlinx.html/") }
}
kotlin {
sourceSets.commonMain {
dependencies {
api("org.jetbrains.kotlin:kotlin-stdlib-common")
}
}
iosArm64("ios")
}
@@ -0,0 +1,5 @@
enableFeaturePreview('GRADLE_METADATA')
rootProject.name = "native-binary"
include ':exported'
@@ -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 kotlin.test.*
@Test
fun foo() {
println("tests.foo")
}
@@ -0,0 +1,96 @@
plugins {
id("org.jetbrains.kotlin.multiplatform").version("<pluginMarkerVersion>")
}
repositories {
mavenLocal()
jcenter()
maven { setUrl("http://dl.bintray.com/kotlin/kotlinx.html/") }
}
kotlin {
sourceSets["commonMain"].apply {
dependencies {
api("org.jetbrains.kotlin:kotlin-stdlib-common")
}
}
sourceSets.create("iosMain").apply {
dependencies {
api(project(":exported"))
}
}
sourceSets["commonTest"].apply {
dependencies {
api("org.jetbrains.kotlin:kotlin-test-annotations-common")
}
}
val macos = macosX64("macos64")
val linux = linuxX64("linux64")
val windows = mingwX64("windows64")
configure(listOf(macos, linux, windows)) {
binaries {
executable() // Executable with default name.
executable("foo") // Custom binary name.
executable("bar", listOf(RELEASE)) // Custom build types.
// Configure a binary.
executable("baz") {
// Rename an output binary: baz.kexe -> my-baz.kexe.
baseName = "my-baz"
// Use a custom entry point.
entryPoint = "foo.main"
}
executable("test2") {
compilation = compilations["test"]
}
sharedLib(listOf(RELEASE))
staticLib(listOf(RELEASE))
}
// Check that we can access binaries/tasks:
// Just by name:
println("Check link task: ${binaries["releaseShared"].linkTask.name}")
// Using a typed getter:
println("Check run task: ${binaries.getExecutable("foo", RELEASE).runTask?.name}")
}
iosArm64("ios") {
binaries {
framework {
export(project(":exported"))
}
framework("custom", listOf(RELEASE)) {
embedBitcode("disable")
linkerOpts = mutableListOf("-L.")
freeCompilerArgs = mutableListOf("-Xtime")
}
}
}
}
@@ -0,0 +1,19 @@
plugins {
id("org.jetbrains.kotlin.multiplatform")
}
repositories {
mavenLocal()
jcenter()
maven { setUrl("http://dl.bintray.com/kotlin/kotlinx.html/") }
}
kotlin {
sourceSets["commonMain"].apply {
dependencies {
api("org.jetbrains.kotlin:kotlin-stdlib-common")
}
}
iosArm64("ios")
}
@@ -0,0 +1,13 @@
pluginManagement {
repositories {
mavenLocal()
jcenter()
gradlePluginPortal()
}
}
enableFeaturePreview('GRADLE_METADATA')
rootProject.name = "native-binary"
include ':exported'
@@ -0,0 +1,6 @@
import kotlin.test.*
@Test
fun foo() {
println("tests.foo")
}
@@ -199,11 +199,13 @@ class Framework(
/**
* Enable or disable embedding bitcode for the framework.
* The parameter [mode] is one of the following string constants:
*
* @param mode - one of the following string constants:
* disable - Don't embed LLVM IR bitcode.
* bitcode - Embed LLVM IR bitcode as data. Has the same effect as the -Xembed-bitcode command line option.
* marker - Embed placeholder LLVM IR data as a marker. Has the same effect as the -Xembed-bitcode-marker command line option.
* bitcode - Embed LLVM IR bitcode as data.
* Has the same effect as the -Xembed-bitcode command line option.
* marker - Embed placeholder LLVM IR data as a marker.
* Has the same effect as the -Xembed-bitcode-marker command line option.
*/
fun embedBitcode(mode: String) = embedBitcode(BitcodeEmbeddingMode.valueOf(mode.toUpperCase()))