[Gradle, K/N] Move native-specific tests to a separate class from MPP
This patch just copies the tests without any refactoring.
This commit is contained in:
committed by
Alexander.Likhachev
parent
4d28463f1a
commit
d971817c32
+780
-1
@@ -5,11 +5,60 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.jdom.input.SAXBuilder
|
||||
import org.jetbrains.kotlin.gradle.internals.DISABLED_NATIVE_TARGETS_REPORTER_DISABLE_WARNING_PROPERTY_NAME
|
||||
import org.jetbrains.kotlin.gradle.internals.DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX
|
||||
import org.jetbrains.kotlin.gradle.internals.NO_NATIVE_STDLIB_PROPERTY_WARNING
|
||||
import org.jetbrains.kotlin.gradle.internals.NO_NATIVE_STDLIB_WARNING
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
|
||||
import org.jetbrains.kotlin.gradle.util.checkedReplace
|
||||
import org.jetbrains.kotlin.gradle.util.isWindows
|
||||
import org.jetbrains.kotlin.gradle.util.modify
|
||||
import org.jetbrains.kotlin.gradle.util.runProcess
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.library.KLIB_PROPERTY_SHORT_NAME
|
||||
import org.jetbrains.kotlin.library.KLIB_PROPERTY_UNIQUE_NAME
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
data class NativeTargets(val current: String, val supported: List<String>, val unsupported: List<String>)
|
||||
|
||||
fun configure(): NativeTargets {
|
||||
val all = listOf("linux64", "macos64", "mingw64", "wasm32")
|
||||
|
||||
val current = when {
|
||||
HostManager.hostIsMingw -> "mingw64"
|
||||
HostManager.hostIsLinux -> "linux64"
|
||||
HostManager.hostIsMac -> "macos64"
|
||||
else -> error("Unknown host")
|
||||
}
|
||||
|
||||
val unsupported = when {
|
||||
HostManager.hostIsMingw -> listOf("macos64")
|
||||
HostManager.hostIsLinux -> listOf("macos64", "mingw64")
|
||||
HostManager.hostIsMac -> listOf("mingw64")
|
||||
else -> error("Unknown host")
|
||||
}
|
||||
|
||||
val supported = all.filter { !unsupported.contains(it) }
|
||||
|
||||
return NativeTargets(current, supported, unsupported)
|
||||
}
|
||||
|
||||
class GeneralNativeIT : BaseGradleIT() {
|
||||
|
||||
val nativeHostTargetName = configure().current
|
||||
|
||||
private fun Project.targetClassesDir(targetName: String, sourceSetName: String = "main") =
|
||||
classesDir(sourceSet = "$targetName/$sourceSetName")
|
||||
|
||||
override val defaultGradleVersion: GradleVersionRequired
|
||||
get() = GradleVersionRequired.FOR_MPP_SUPPORT
|
||||
|
||||
@@ -41,5 +90,735 @@ class GeneralNativeIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move native specific tests from NewMultiplatformIT here.
|
||||
@Test
|
||||
fun testEndorsedLibsController() {
|
||||
with(
|
||||
transformProjectWithPluginsDsl("new-mpp-native-endorsed")
|
||||
) {
|
||||
setupWorkingDir()
|
||||
|
||||
build("build") {
|
||||
assertSuccessful()
|
||||
}
|
||||
gradleBuildScript().modify {
|
||||
it.replace("enableEndorsedLibs = true", "")
|
||||
}
|
||||
build("build") {
|
||||
assertFailed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun testCanProduceNativeLibraries() = with(Project("new-mpp-native-libraries")) {
|
||||
val baseName = "main"
|
||||
|
||||
val sharedPrefix = CompilerOutputKind.DYNAMIC.prefix(HostManager.host)
|
||||
val sharedSuffix = CompilerOutputKind.DYNAMIC.suffix(HostManager.host)
|
||||
val sharedPaths = listOf(
|
||||
"build/bin/$nativeHostTargetName/mainDebugShared/$sharedPrefix$baseName$sharedSuffix",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseShared/$sharedPrefix$baseName$sharedSuffix"
|
||||
)
|
||||
|
||||
val staticPrefix = CompilerOutputKind.STATIC.prefix(HostManager.host)
|
||||
val staticSuffix = CompilerOutputKind.STATIC.suffix(HostManager.host)
|
||||
val staticPaths = listOf(
|
||||
"build/bin/$nativeHostTargetName/mainDebugStatic/$staticPrefix$baseName$staticSuffix",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseStatic/$staticPrefix$baseName$staticSuffix"
|
||||
)
|
||||
|
||||
val headerPaths = listOf(
|
||||
"build/bin/$nativeHostTargetName/mainDebugShared/$sharedPrefix${baseName}_api.h",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseShared/$sharedPrefix${baseName}_api.h",
|
||||
"build/bin/$nativeHostTargetName/mainDebugStatic/$staticPrefix${baseName}_api.h",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseStatic/$staticPrefix${baseName}_api.h"
|
||||
)
|
||||
|
||||
val klibPrefix = CompilerOutputKind.LIBRARY.prefix(HostManager.host)
|
||||
val klibSuffix = CompilerOutputKind.LIBRARY.suffix(HostManager.host)
|
||||
val klibPath = "${targetClassesDir(nativeHostTargetName)}${klibPrefix}native-lib$klibSuffix"
|
||||
|
||||
val frameworkPrefix = CompilerOutputKind.FRAMEWORK.prefix(HostManager.host)
|
||||
val frameworkSuffix = CompilerOutputKind.FRAMEWORK.suffix(HostManager.host)
|
||||
val frameworkPaths = listOf(
|
||||
"build/bin/$nativeHostTargetName/mainDebugFramework/$frameworkPrefix$baseName$frameworkSuffix.dSYM",
|
||||
"build/bin/$nativeHostTargetName/mainDebugFramework/$frameworkPrefix$baseName$frameworkSuffix",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseFramework/$frameworkPrefix$baseName$frameworkSuffix"
|
||||
)
|
||||
.takeIf { HostManager.hostIsMac }
|
||||
.orEmpty()
|
||||
|
||||
val taskSuffix = nativeHostTargetName.capitalize()
|
||||
val linkTasks = listOf(
|
||||
":linkMainDebugShared$taskSuffix",
|
||||
":linkMainReleaseShared$taskSuffix",
|
||||
":linkMainDebugStatic$taskSuffix",
|
||||
":linkMainReleaseStatic$taskSuffix"
|
||||
)
|
||||
|
||||
val klibTask = ":compileKotlin$taskSuffix"
|
||||
|
||||
val frameworkTasks = listOf(":linkMainDebugFramework$taskSuffix", ":linkMainReleaseFramework$taskSuffix")
|
||||
.takeIf { HostManager.hostIsMac }
|
||||
.orEmpty()
|
||||
|
||||
// Building
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
|
||||
sharedPaths.forEach { assertFileExists(it) }
|
||||
staticPaths.forEach { assertFileExists(it) }
|
||||
headerPaths.forEach { assertFileExists(it) }
|
||||
frameworkPaths.forEach { assertFileExists(it) }
|
||||
assertFileExists(klibPath)
|
||||
}
|
||||
|
||||
// Test that all up-to date checks are correct
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
assertTasksUpToDate(linkTasks)
|
||||
assertTasksUpToDate(frameworkTasks)
|
||||
assertTasksUpToDate(klibTask)
|
||||
}
|
||||
|
||||
// Remove outputs and check that they are rebuilt.
|
||||
assertTrue(projectDir.resolve(headerPaths[0]).delete())
|
||||
if (HostManager.hostIsMac) {
|
||||
assertTrue(projectDir.resolve(frameworkPaths[0]).deleteRecursively())
|
||||
}
|
||||
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
assertTasksUpToDate(linkTasks.drop(1))
|
||||
assertTasksUpToDate(klibTask)
|
||||
assertTasksExecuted(linkTasks[0])
|
||||
|
||||
if (HostManager.hostIsMac) {
|
||||
assertTasksUpToDate(frameworkTasks.drop(1))
|
||||
assertTasksExecuted(frameworkTasks[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeBinaryGroovyDSL() {
|
||||
// Building K/N binaries is very time-consuming. So we check building only for Kotlin DSL.
|
||||
// For Groovy DSl we just check that a project can be configured.
|
||||
val project = transformProjectWithPluginsDsl(
|
||||
"groovy-dsl", directoryPrefix = "new-mpp-native-binaries"
|
||||
)
|
||||
project.build("tasks") {
|
||||
assertSuccessful()
|
||||
|
||||
// Check that getters work fine.
|
||||
val hostSuffix = nativeHostTargetName.capitalize()
|
||||
assertTrue(output.contains("Check link task: linkReleaseShared$hostSuffix"))
|
||||
assertTrue(output.contains("Check run task: runFooReleaseExecutable$hostSuffix"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun CompiledProject.checkNativeCommandLineFor(vararg taskPaths: String, check: (String) -> Unit) =
|
||||
taskPaths.forEach { taskPath ->
|
||||
val commandLine = output.lineSequence().dropWhile {
|
||||
!it.contains("Executing actions for task '$taskPath'")
|
||||
}.first {
|
||||
it.contains("Run tool: \"konanc\"")
|
||||
}
|
||||
check(commandLine)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeBinaryKotlinDSL() = with(
|
||||
transformProjectWithPluginsDsl("kotlin-dsl", directoryPrefix = "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",
|
||||
"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"
|
||||
name to "build/bin/$nativeHostTargetName/$name/$fileName"
|
||||
}.toMap()
|
||||
|
||||
val runTasks = listOf(
|
||||
"runDebugExecutable",
|
||||
"runReleaseExecutable",
|
||||
"runFooDebugExecutable",
|
||||
"runFooReleaseExecutable",
|
||||
"runBarReleaseExecutable",
|
||||
"runBazReleaseExecutable",
|
||||
"runTest2ReleaseExecutable"
|
||||
).map { "$it$hostSuffix" }.toMutableList()
|
||||
|
||||
val binariesTasks = arrayOf("${nativeHostTargetName}MainBinaries", "${nativeHostTargetName}TestBinaries")
|
||||
|
||||
val compileTask = "compileKotlin$hostSuffix"
|
||||
val compileTestTask = "compileTestKotlin$hostSuffix"
|
||||
|
||||
// Check that all link and run tasks are generated.
|
||||
build(*binariesTasks) {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(linkTasks.map { ":$it" })
|
||||
assertTasksExecuted(":$compileTask", ":$compileTestTask")
|
||||
outputFiles.forEach { (_, file) ->
|
||||
assertFileExists(file)
|
||||
}
|
||||
// Check that getters work fine.
|
||||
assertTrue(output.contains("Check link task: linkReleaseShared$hostSuffix"))
|
||||
assertTrue(output.contains("Check run task: runFooReleaseExecutable$hostSuffix"))
|
||||
|
||||
// Check that dependency export works for static and shared libs.
|
||||
val staticSuffix = CompilerOutputKind.STATIC.suffix(HostManager.host)
|
||||
val sharedSuffix = CompilerOutputKind.DYNAMIC.suffix(HostManager.host)
|
||||
val staticPrefix = CompilerOutputKind.STATIC.prefix(HostManager.host)
|
||||
val sharedPrefix = CompilerOutputKind.DYNAMIC.prefix(HostManager.host)
|
||||
val staticHeader = outputFiles.getValue("releaseStatic").removeSuffix(staticSuffix) + "_api.h"
|
||||
val sharedHeader = outputFiles.getValue("releaseShared").removeSuffix(sharedSuffix) + "_api.h"
|
||||
assertTrue(fileInWorkingDir(staticHeader).readText().contains("${staticPrefix}native_binary_KInt (*exported)();"))
|
||||
assertTrue(fileInWorkingDir(sharedHeader).readText().contains("${sharedPrefix}native_binary_KInt (*exported)();"))
|
||||
}
|
||||
|
||||
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 kotlinOptions work fine for a compilation.
|
||||
build(compileTask) {
|
||||
assertSuccessful()
|
||||
checkNativeCommandLineFor(":$compileTask") {
|
||||
assertTrue(it.contains("-verbose"))
|
||||
}
|
||||
}
|
||||
|
||||
// Check that run tasks work fine 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()
|
||||
assertTasksExecuted(":$compileTestTask")
|
||||
checkNativeCommandLineFor(":linkTest2ReleaseExecutable$hostSuffix") {
|
||||
assertTrue(it.contains("-tr"))
|
||||
assertTrue(it.contains("-Xtime"))
|
||||
// Check that kotlinOptions of the compilation don't affect the binary.
|
||||
assertFalse(it.contains("-verbose"))
|
||||
// Check that free args are still propagated to the binary (unlike other kotlinOptions, see KT-33717).
|
||||
// TODO: Reverse this check when the args are fully separated.
|
||||
assertTrue(it.contains("-nowarn"))
|
||||
}
|
||||
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"))
|
||||
}
|
||||
|
||||
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.
|
||||
checkNativeCommandLineFor(":linkReleaseFrameworkIos") {
|
||||
assertTrue(it.contains("-Xembed-bitcode"))
|
||||
assertTrue(it.contains("-opt"))
|
||||
}
|
||||
}
|
||||
|
||||
// For debug builds.
|
||||
build("linkDebugFrameworkIos") {
|
||||
assertSuccessful()
|
||||
assertFileExists("build/bin/ios/debugFramework/native_binary.framework")
|
||||
assertTrue(
|
||||
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.
|
||||
checkNativeCommandLineFor(":linkDebugFrameworkIos") {
|
||||
assertTrue(it.contains("-Xembed-bitcode-marker"))
|
||||
assertTrue(it.contains("-g"))
|
||||
}
|
||||
}
|
||||
|
||||
// Check manual disabling bitcode embedding, custom command line args and building a static framework.
|
||||
build("linkCustomReleaseFrameworkIos") {
|
||||
assertSuccessful()
|
||||
checkNativeCommandLineFor(":linkCustomReleaseFrameworkIos") {
|
||||
assertTrue(it.contains("-linker-option -L."))
|
||||
assertTrue(it.contains("-Xtime"))
|
||||
assertTrue(it.contains("-Xstatic-framework"))
|
||||
assertFalse(it.contains("-Xembed-bitcode-marker"))
|
||||
assertFalse(it.contains("-Xembed-bitcode"))
|
||||
}
|
||||
}
|
||||
|
||||
// Check that bitcode is disabled for iOS simulator.
|
||||
build("linkReleaseFrameworkIosSim", "linkDebugFrameworkIosSim") {
|
||||
assertSuccessful()
|
||||
assertFileExists("build/bin/iosSim/releaseFramework/native_binary.framework")
|
||||
assertFileExists("build/bin/iosSim/debugFramework/native_binary.framework")
|
||||
checkNativeCommandLineFor(":linkReleaseFrameworkIosSim", ":linkDebugFrameworkIosSim") {
|
||||
assertFalse(it.contains("-Xembed-bitcode"))
|
||||
assertFalse(it.contains("-Xembed-bitcode-marker"))
|
||||
}
|
||||
}
|
||||
|
||||
// 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\"))", "")
|
||||
}
|
||||
projectDir.resolve("src/commonMain/kotlin/PackageMain.kt").modify {
|
||||
// Remove usages of the ":exported" dependency to be able to compile the sources.
|
||||
it.checkedReplace("import com.example.exported", "").checkedReplace("val exp = exported()", "val exp = 42")
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We propagate compilation args to link tasks for now (see KT-33717).
|
||||
// TODO: Reenable the test when the args are separated.
|
||||
@Ignore
|
||||
@Test
|
||||
fun testNativeFreeArgsWarning() = with(transformProjectWithPluginsDsl("kotlin-dsl", directoryPrefix = "new-mpp-native-binaries")) {
|
||||
gradleBuildScript().appendText(
|
||||
"""kotlin.targets["macos64"].compilations["main"].kotlinOptions.freeCompilerArgs += "-opt""""
|
||||
)
|
||||
gradleBuildScript("exported").appendText(
|
||||
"""
|
||||
kotlin.targets["macos64"].compilations["main"].kotlinOptions.freeCompilerArgs += "-opt"
|
||||
kotlin.targets["macos64"].compilations["test"].kotlinOptions.freeCompilerArgs += "-g"
|
||||
kotlin.targets["linux64"].compilations["main"].kotlinOptions.freeCompilerArgs +=
|
||||
listOf("-g", "-Xdisable-phases=Devirtualization,BuildDFG")
|
||||
""".trimIndent()
|
||||
)
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
assertContains(
|
||||
"""
|
||||
The following free compiler arguments must be specified for a binary instead of a compilation:
|
||||
* In project ':':
|
||||
* In target 'macos64':
|
||||
* Compilation: 'main', arguments: [-opt]
|
||||
* In project ':exported':
|
||||
* In target 'linux64':
|
||||
* Compilation: 'main', arguments: [-g, -Xdisable-phases=Devirtualization,BuildDFG]
|
||||
* In target 'macos64':
|
||||
* Compilation: 'main', arguments: [-opt]
|
||||
* Compilation: 'test', arguments: [-g]
|
||||
|
||||
Please move them into final binary declarations. E.g. binaries.executable { freeCompilerArgs += "..." }
|
||||
See more about final binaries: https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#building-final-native-binaries.
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBootedSimulators(workingDirectory: File): Set<String>? =
|
||||
if (HostManager.hostIsMac) {
|
||||
val simulators = runProcess(listOf("xcrun", "simctl", "list"), workingDirectory, System.getenv()).also {
|
||||
assertTrue(it.isSuccessful, "xcrun exection failed")
|
||||
}.output
|
||||
|
||||
simulators.split('\n').filter { it.contains("(Booted)") }.map { it.trim() }.toSet()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeTests() = with(Project("new-mpp-native-tests")) {
|
||||
val testTasks = listOf("macos64Test", "linux64Test", "mingw64Test", "iosTest")
|
||||
val hostTestTask = "${nativeHostTargetName}Test"
|
||||
|
||||
val suffix = if (isWindows) "exe" else "kexe"
|
||||
|
||||
val defaultOutputFile = "build/bin/$nativeHostTargetName/debugTest/test.$suffix"
|
||||
val anotherOutputFile = "build/bin/$nativeHostTargetName/anotherDebugTest/another.$suffix"
|
||||
|
||||
val hostIsMac = HostManager.hostIsMac
|
||||
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
testTasks.forEach {
|
||||
// We need to create tasks for all hosts
|
||||
assertTrue(output.contains("$it - "), "There is no test task '$it' in the task list.")
|
||||
}
|
||||
}
|
||||
|
||||
// Perform all following checks in a single test to avoid running the K/N compiler several times.
|
||||
// Check that tests are not built during the ":assemble" execution
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
assertNoSuchFile(defaultOutputFile)
|
||||
assertNoSuchFile(anotherOutputFile)
|
||||
}
|
||||
|
||||
val testsToExecute = mutableListOf(":$hostTestTask")
|
||||
if (hostIsMac) {
|
||||
testsToExecute.add(":iosTest")
|
||||
}
|
||||
val testsToSkip = testTasks.map { ":$it" } - testsToExecute
|
||||
|
||||
// Store currently booted simulators to check that they don't leak (MacOS only).
|
||||
val bootedSimulatorsBefore = getBootedSimulators(projectDir)
|
||||
|
||||
// Check the case when all tests pass.
|
||||
build("check") {
|
||||
assertSuccessful()
|
||||
|
||||
assertTasksExecuted(*testsToExecute.toTypedArray())
|
||||
assertTasksSkipped(*testsToSkip.toTypedArray())
|
||||
|
||||
assertContainsRegex("org\\.foo\\.test\\.TestKt\\.fooTest\\s+PASSED".toRegex())
|
||||
assertContainsRegex("org\\.foo\\.test\\.TestKt\\.barTest\\s+PASSED".toRegex())
|
||||
|
||||
assertFileExists(defaultOutputFile)
|
||||
}
|
||||
|
||||
// Check simulator process leaking.
|
||||
val bootedSimulatorsAfter = getBootedSimulators(projectDir)
|
||||
assertEquals(bootedSimulatorsBefore, bootedSimulatorsAfter)
|
||||
|
||||
// Check the case with failed tests.
|
||||
projectDir.resolve("src/commonTest/kotlin/test.kt").appendText(
|
||||
"""
|
||||
@Test
|
||||
fun fail() {
|
||||
throw IllegalStateException("FAILURE!")
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
build("check") {
|
||||
assertFailed()
|
||||
|
||||
assertTasksFailed(":allTests")
|
||||
// In the aggregation report mode platform-specific tasks
|
||||
// are executed successfully even if there are failing tests.
|
||||
assertTasksExecuted(*testsToExecute.toTypedArray())
|
||||
assertTasksSkipped(*testsToSkip.toTypedArray())
|
||||
|
||||
assertContainsRegex("org\\.foo\\.test\\.TestKt\\.fail\\s+FAILED".toRegex())
|
||||
}
|
||||
|
||||
// Check that individual test reports are created correctly.
|
||||
build("check", "-Pkotlin.tests.individualTaskReports=true", "--continue") {
|
||||
assertFailed()
|
||||
|
||||
// In the individual report mode platform-specific tasks
|
||||
// fail if there are failing tests.
|
||||
assertTasksFailed(*testsToExecute.toTypedArray())
|
||||
assertTasksSkipped(*testsToSkip.toTypedArray())
|
||||
|
||||
|
||||
fun assertStacktrace(taskName: String) {
|
||||
val testReport = projectDir.resolve("build/test-results/$taskName/TEST-org.foo.test.TestKt.xml")
|
||||
val stacktrace = SAXBuilder().build(testReport).rootElement
|
||||
.getChildren("testcase")
|
||||
.single { it.getAttribute("name").value == "fail" }
|
||||
.getChild("failure")
|
||||
.text
|
||||
assertTrue(stacktrace.contains("""at org\.foo\.test#fail\(.*test\.kt:24\)""".toRegex()))
|
||||
}
|
||||
|
||||
assertTestResults("testProject/new-mpp-native-tests/TEST-TestKt.xml", hostTestTask)
|
||||
// K/N doesn't report line numbers correctly on Linux (see KT-35408).
|
||||
// TODO: Uncomment when this is fixed.
|
||||
//assertStacktrace(hostTestTask)
|
||||
if (hostIsMac) {
|
||||
assertTestResults("testProject/new-mpp-native-tests/TEST-TestKt.xml", "iosTest")
|
||||
assertStacktrace("iosTest")
|
||||
}
|
||||
}
|
||||
|
||||
build("linkAnotherDebugTest${nativeHostTargetName}") {
|
||||
assertSuccessful()
|
||||
assertFileExists(anotherOutputFile)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeTestGetters() = with(Project("new-mpp-native-tests")) {
|
||||
// Check that test binaries can be accessed in a buildscript.
|
||||
build("checkNewGetters") {
|
||||
assertSuccessful()
|
||||
val suffixes = listOf("exe", "kexe", "wasm")
|
||||
val names = listOf("test", "another")
|
||||
val files = names.flatMap { name ->
|
||||
suffixes.map { suffix ->
|
||||
"$name.$suffix"
|
||||
}
|
||||
}
|
||||
|
||||
files.forEach {
|
||||
assertContains("Get test: $it")
|
||||
assertContains("Find test: $it")
|
||||
}
|
||||
}
|
||||
|
||||
// Check that accessing a test as an executable fails or returns null and shows the corresponding warning.
|
||||
build("checkOldGet") {
|
||||
assertFailed()
|
||||
assertContains(
|
||||
"""
|
||||
|Probably you are accessing the default test binary using the 'binaries.getExecutable("test", DEBUG)' method.
|
||||
|Since 1.3.40 tests are represented by a separate binary type. To get the default test binary, use:
|
||||
|
|
||||
| binaries.getTest("DEBUG")
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
build("checkOldFind") {
|
||||
assertSuccessful()
|
||||
assertContains(
|
||||
"""
|
||||
|Probably you are accessing the default test binary using the 'binaries.findExecutable("test", DEBUG)' method.
|
||||
|Since 1.3.40 tests are represented by a separate binary type. To get the default test binary, use:
|
||||
|
|
||||
| binaries.findTest("DEBUG")
|
||||
""".trimMargin()
|
||||
)
|
||||
assertContains("Find test: null")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun kt33750() {
|
||||
// Check that build fails if a test executable crashes.
|
||||
with(Project("new-mpp-native-tests")) {
|
||||
setupWorkingDir()
|
||||
projectDir.resolve("src/commonTest/kotlin/test.kt").appendText("\nval fail: Int = error(\"\")\n")
|
||||
build("check") {
|
||||
assertFailed()
|
||||
output.contains("exited with errors \\(exit code: \\d+\\)".toRegex())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCinterop() {
|
||||
val libProject = Project("sample-lib", directoryPrefix = "new-mpp-lib-and-app")
|
||||
libProject.build("publish") {
|
||||
assertSuccessful()
|
||||
}
|
||||
val repo = libProject.projectDir.resolve("repo").absolutePath.replace('\\', '/')
|
||||
|
||||
with(Project("new-mpp-native-cinterop")) {
|
||||
|
||||
setupWorkingDir()
|
||||
listOf(gradleBuildScript(), gradleBuildScript("publishedLibrary")).forEach {
|
||||
it.appendText(
|
||||
"""
|
||||
repositories {
|
||||
maven { url '$repo' }
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
val targetsToBuild = if (HostManager.hostIsMingw) {
|
||||
listOf(nativeHostTargetName, "mingw86")
|
||||
} else {
|
||||
listOf(nativeHostTargetName)
|
||||
}
|
||||
|
||||
val libraryCinteropTasks = targetsToBuild.map { ":projectLibrary:cinteropStdio${it.capitalize()}" }
|
||||
val libraryCompileTasks = targetsToBuild.map { ":projectLibrary:compileKotlin${it.capitalize()}" }
|
||||
|
||||
build(":projectLibrary:build") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(libraryCinteropTasks)
|
||||
assertTrue(output.contains("Project test"), "No test output found")
|
||||
targetsToBuild.forEach {
|
||||
assertFileExists("projectLibrary/build/classes/kotlin/$it/main/projectLibrary-cinterop-stdio.klib")
|
||||
}
|
||||
}
|
||||
|
||||
build(":publishedLibrary:build", ":publishedLibrary:publish") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(
|
||||
targetsToBuild.map { ":publishedLibrary:cinteropStdio${it.capitalize()}" }
|
||||
)
|
||||
assertTrue(output.contains("Published test"), "No test output found")
|
||||
targetsToBuild.forEach {
|
||||
assertFileExists("publishedLibrary/build/classes/kotlin/$it/main/publishedLibrary-cinterop-stdio.klib")
|
||||
assertFileExists("publishedLibrary/build/classes/kotlin/$it/test/test-cinterop-stdio.klib")
|
||||
assertFileExists("repo/org/example/publishedLibrary-$it/1.0/publishedLibrary-$it-1.0-cinterop-stdio.klib")
|
||||
}
|
||||
}
|
||||
|
||||
build(":build") {
|
||||
assertSuccessful()
|
||||
assertTrue(output.contains("Dependent: Project print"), "No test output found")
|
||||
assertTrue(output.contains("Dependent: Published print"), "No test output found")
|
||||
}
|
||||
|
||||
// Check that changing the compiler version in properties causes interop reprocessing and source recompilation.
|
||||
val hostLibraryTasks = listOf(
|
||||
":projectLibrary:cinteropStdio${nativeHostTargetName.capitalize()}",
|
||||
":projectLibrary:compileKotlin${nativeHostTargetName.capitalize()}"
|
||||
)
|
||||
build(":projectLibrary:build") {
|
||||
assertSuccessful()
|
||||
assertTasksUpToDate(hostLibraryTasks)
|
||||
}
|
||||
|
||||
build(*hostLibraryTasks.toTypedArray(), "-Porg.jetbrains.kotlin.native.version=1.3.70-dev-13258") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(hostLibraryTasks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeCompilerDownloading() {
|
||||
// The plugin shouldn't download the K/N compiler if there are no corresponding targets in the project.
|
||||
with(Project("sample-old-style-app", directoryPrefix = "new-mpp-lib-and-app")) {
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
assertFalse(output.contains("Kotlin/Native distribution: "))
|
||||
}
|
||||
}
|
||||
with(Project("new-mpp-native-libraries")) {
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
assertTrue(output.contains("Kotlin/Native distribution: "))
|
||||
// Check for KT-30258.
|
||||
assertFalse(output.contains("Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0."))
|
||||
}
|
||||
|
||||
// This directory actually doesn't contain a K/N distribution
|
||||
// but we still can run a project configuration and check logs.
|
||||
val currentDir = projectDir.absolutePath
|
||||
build("tasks", "-Pkotlin.native.home=$currentDir") {
|
||||
assertSuccessful()
|
||||
assertContains("User-provided Kotlin/Native distribution: $currentDir")
|
||||
assertNotContains("Project property 'org.jetbrains.kotlin.native.home' is deprecated")
|
||||
assertContains(NO_NATIVE_STDLIB_WARNING)
|
||||
assertContains(NO_NATIVE_STDLIB_PROPERTY_WARNING)
|
||||
}
|
||||
|
||||
// Deprecated property.
|
||||
build("tasks", "-Porg.jetbrains.kotlin.native.home=$currentDir", "-Pkotlin.native.nostdlib=true") {
|
||||
assertSuccessful()
|
||||
assertContains("User-provided Kotlin/Native distribution: $currentDir")
|
||||
assertContains("Project property 'org.jetbrains.kotlin.native.home' is deprecated")
|
||||
assertNotContains(NO_NATIVE_STDLIB_WARNING)
|
||||
assertNotContains(NO_NATIVE_STDLIB_PROPERTY_WARNING)
|
||||
}
|
||||
|
||||
build("tasks", "-Pkotlin.native.version=1.3-eap-10779") {
|
||||
assertSuccessful()
|
||||
assertContainsRegex("Kotlin/Native distribution: .*kotlin-native-(macos|linux|windows)-1\\.3-eap-10779".toRegex())
|
||||
assertNotContains("Project property 'org.jetbrains.kotlin.native.version' is deprecated")
|
||||
}
|
||||
|
||||
// Deprecated property
|
||||
build("tasks", "-Porg.jetbrains.kotlin.native.version=1.3-eap-10779") {
|
||||
assertSuccessful()
|
||||
assertContainsRegex("Kotlin/Native distribution: .*kotlin-native-(macos|linux|windows)-1\\.3-eap-10779".toRegex())
|
||||
assertContains("Project property 'org.jetbrains.kotlin.native.version' is deprecated")
|
||||
}
|
||||
}
|
||||
|
||||
// Gradle 5.0 introduced a new API for Ivy repository layouts.
|
||||
// MPP plugin uses this API to download K/N if Gradle version is >= 5.0.
|
||||
// Check this too (see KT-30258).
|
||||
with(Project("new-mpp-native-libraries")) {
|
||||
build("tasks", "-Pkotlin.native.version=1.3.50-eap-11606") {
|
||||
assertSuccessful()
|
||||
assertTrue(output.contains("Kotlin/Native distribution: "))
|
||||
assertFalse(output.contains("Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKt29725() {
|
||||
with(Project("new-mpp-native-libraries")) {
|
||||
// Assert that a project with a native target can be configured with Gradle 5.2
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIgnoreDisabledNativeTargets() = with(Project("sample-lib", directoryPrefix = "new-mpp-lib-and-app")) {
|
||||
build {
|
||||
assertSuccessful()
|
||||
assertEquals(1, output.lines().count { DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX in it })
|
||||
}
|
||||
build("-P$DISABLED_NATIVE_TARGETS_REPORTER_DISABLE_WARNING_PROPERTY_NAME=true") {
|
||||
assertSuccessful()
|
||||
assertNotContains(DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeArgsWithSpaces() = with(Project("sample-lib", directoryPrefix = "new-mpp-lib-and-app")) {
|
||||
setupWorkingDir()
|
||||
val compilcatedDirectoryName = if (HostManager.hostIsMingw) {
|
||||
// Windows doesn't allow creating a file with " in its name.
|
||||
"path with spaces"
|
||||
} else {
|
||||
"path with spaces and \""
|
||||
}
|
||||
|
||||
val fileWithSpacesInPath = projectDir.resolve("src/commonMain/kotlin/$compilcatedDirectoryName")
|
||||
.apply { mkdirs() }
|
||||
.resolve("B.kt")
|
||||
fileWithSpacesInPath.writeText("fun foo() = 42")
|
||||
|
||||
build("compileKotlin${nativeHostTargetName.capitalize()}") {
|
||||
assertSuccessful()
|
||||
checkNativeCommandLineFor(":compileKotlin${nativeHostTargetName.capitalize()}") {
|
||||
it.contains(fileWithSpacesInPath.absolutePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-763
@@ -4,32 +4,23 @@
|
||||
*/
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.jdom.input.SAXBuilder
|
||||
import org.jetbrains.kotlin.gradle.internals.DISABLED_NATIVE_TARGETS_REPORTER_DISABLE_WARNING_PROPERTY_NAME
|
||||
import org.jetbrains.kotlin.gradle.internals.DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX
|
||||
import org.jetbrains.kotlin.gradle.internals.NO_NATIVE_STDLIB_PROPERTY_WARNING
|
||||
import org.jetbrains.kotlin.gradle.internals.NO_NATIVE_STDLIB_WARNING
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations
|
||||
import org.jetbrains.kotlin.gradle.plugin.lowerName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmWithJavaTargetPreset
|
||||
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.plugin.sources.UnsatisfiedSourceSetVisibilityException
|
||||
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.library.KLIB_PROPERTY_SHORT_NAME
|
||||
import org.jetbrains.kotlin.library.KLIB_PROPERTY_UNIQUE_NAME
|
||||
import org.junit.Assert
|
||||
import org.junit.Ignore
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.jar.JarFile
|
||||
import java.util.zip.ZipFile
|
||||
@@ -37,30 +28,6 @@ import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
data class NativeTargets(val current: String, val supported: List<String>, val unsupported: List<String>)
|
||||
|
||||
fun configure(): NativeTargets {
|
||||
val all = listOf("linux64", "macos64", "mingw64", "wasm32")
|
||||
|
||||
val current = when {
|
||||
HostManager.hostIsMingw -> "mingw64"
|
||||
HostManager.hostIsLinux -> "linux64"
|
||||
HostManager.hostIsMac -> "macos64"
|
||||
else -> error("Unknown host")
|
||||
}
|
||||
|
||||
val unsupported = when {
|
||||
HostManager.hostIsMingw -> listOf("macos64")
|
||||
HostManager.hostIsLinux -> listOf("macos64", "mingw64")
|
||||
HostManager.hostIsMac -> listOf("mingw64")
|
||||
else -> error("Unknown host")
|
||||
}
|
||||
|
||||
val supported = all.filter { !unsupported.contains(it) }
|
||||
|
||||
return NativeTargets(current, supported, unsupported)
|
||||
}
|
||||
|
||||
class NewMultiplatformIT : BaseGradleIT() {
|
||||
val gradleVersion = GradleVersionRequired.FOR_MPP_SUPPORT
|
||||
|
||||
@@ -946,25 +913,6 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEndorsedLibsController() {
|
||||
with(
|
||||
transformProjectWithPluginsDsl("new-mpp-native-endorsed", gradleVersion)
|
||||
) {
|
||||
setupWorkingDir()
|
||||
|
||||
build("build") {
|
||||
assertSuccessful()
|
||||
}
|
||||
gradleBuildScript().modify {
|
||||
it.replace("enableEndorsedLibs = true", "")
|
||||
}
|
||||
build("build") {
|
||||
assertFailed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPublishingOnlySupportedNativeTargets() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
|
||||
val publishedVariant = nativeHostTargetName
|
||||
@@ -1080,353 +1028,6 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCanProduceNativeLibraries() = with(Project("new-mpp-native-libraries", gradleVersion)) {
|
||||
val baseName = "main"
|
||||
|
||||
val sharedPrefix = CompilerOutputKind.DYNAMIC.prefix(HostManager.host)
|
||||
val sharedSuffix = CompilerOutputKind.DYNAMIC.suffix(HostManager.host)
|
||||
val sharedPaths = listOf(
|
||||
"build/bin/$nativeHostTargetName/mainDebugShared/$sharedPrefix$baseName$sharedSuffix",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseShared/$sharedPrefix$baseName$sharedSuffix"
|
||||
)
|
||||
|
||||
val staticPrefix = CompilerOutputKind.STATIC.prefix(HostManager.host)
|
||||
val staticSuffix = CompilerOutputKind.STATIC.suffix(HostManager.host)
|
||||
val staticPaths = listOf(
|
||||
"build/bin/$nativeHostTargetName/mainDebugStatic/$staticPrefix$baseName$staticSuffix",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseStatic/$staticPrefix$baseName$staticSuffix"
|
||||
)
|
||||
|
||||
val headerPaths = listOf(
|
||||
"build/bin/$nativeHostTargetName/mainDebugShared/$sharedPrefix${baseName}_api.h",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseShared/$sharedPrefix${baseName}_api.h",
|
||||
"build/bin/$nativeHostTargetName/mainDebugStatic/$staticPrefix${baseName}_api.h",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseStatic/$staticPrefix${baseName}_api.h"
|
||||
)
|
||||
|
||||
val klibPrefix = CompilerOutputKind.LIBRARY.prefix(HostManager.host)
|
||||
val klibSuffix = CompilerOutputKind.LIBRARY.suffix(HostManager.host)
|
||||
val klibPath = "${targetClassesDir(nativeHostTargetName)}${klibPrefix}native-lib$klibSuffix"
|
||||
|
||||
val frameworkPrefix = CompilerOutputKind.FRAMEWORK.prefix(HostManager.host)
|
||||
val frameworkSuffix = CompilerOutputKind.FRAMEWORK.suffix(HostManager.host)
|
||||
val frameworkPaths = listOf(
|
||||
"build/bin/$nativeHostTargetName/mainDebugFramework/$frameworkPrefix$baseName$frameworkSuffix.dSYM",
|
||||
"build/bin/$nativeHostTargetName/mainDebugFramework/$frameworkPrefix$baseName$frameworkSuffix",
|
||||
"build/bin/$nativeHostTargetName/mainReleaseFramework/$frameworkPrefix$baseName$frameworkSuffix"
|
||||
)
|
||||
.takeIf { HostManager.hostIsMac }
|
||||
.orEmpty()
|
||||
|
||||
val taskSuffix = nativeHostTargetName.capitalize()
|
||||
val linkTasks = listOf(
|
||||
":linkMainDebugShared$taskSuffix",
|
||||
":linkMainReleaseShared$taskSuffix",
|
||||
":linkMainDebugStatic$taskSuffix",
|
||||
":linkMainReleaseStatic$taskSuffix"
|
||||
)
|
||||
|
||||
val klibTask = ":compileKotlin$taskSuffix"
|
||||
|
||||
val frameworkTasks = listOf(":linkMainDebugFramework$taskSuffix", ":linkMainReleaseFramework$taskSuffix")
|
||||
.takeIf { HostManager.hostIsMac }
|
||||
.orEmpty()
|
||||
|
||||
// Building
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
|
||||
sharedPaths.forEach { assertFileExists(it) }
|
||||
staticPaths.forEach { assertFileExists(it) }
|
||||
headerPaths.forEach { assertFileExists(it) }
|
||||
frameworkPaths.forEach { assertFileExists(it) }
|
||||
assertFileExists(klibPath)
|
||||
}
|
||||
|
||||
// Test that all up-to date checks are correct
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
assertTasksUpToDate(linkTasks)
|
||||
assertTasksUpToDate(frameworkTasks)
|
||||
assertTasksUpToDate(klibTask)
|
||||
}
|
||||
|
||||
// Remove outputs and check that they are rebuilt.
|
||||
assertTrue(projectDir.resolve(headerPaths[0]).delete())
|
||||
if (HostManager.hostIsMac) {
|
||||
assertTrue(projectDir.resolve(frameworkPaths[0]).deleteRecursively())
|
||||
}
|
||||
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
assertTasksUpToDate(linkTasks.drop(1))
|
||||
assertTasksUpToDate(klibTask)
|
||||
assertTasksExecuted(linkTasks[0])
|
||||
|
||||
if (HostManager.hostIsMac) {
|
||||
assertTasksUpToDate(frameworkTasks.drop(1))
|
||||
assertTasksExecuted(frameworkTasks[0])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeBinaryGroovyDSL() {
|
||||
// Building K/N binaries is very time-consuming. So we check building only for Kotlin DSL.
|
||||
// For Groovy DSl we just check that a project can be configured.
|
||||
val project = transformProjectWithPluginsDsl(
|
||||
"groovy-dsl", gradleVersion, "new-mpp-native-binaries"
|
||||
)
|
||||
project.build("tasks") {
|
||||
assertSuccessful()
|
||||
|
||||
// Check that getters work fine.
|
||||
val hostSuffix = nativeHostTargetName.capitalize()
|
||||
assertTrue(output.contains("Check link task: linkReleaseShared$hostSuffix"))
|
||||
assertTrue(output.contains("Check run task: runFooReleaseExecutable$hostSuffix"))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun CompiledProject.checkNativeCommandLineFor(vararg taskPaths: String, check: (String) -> Unit) =
|
||||
taskPaths.forEach { taskPath ->
|
||||
val commandLine = output.lineSequence().dropWhile {
|
||||
!it.contains("Executing actions for task '$taskPath'")
|
||||
}.first {
|
||||
it.contains("Run tool: \"konanc\"")
|
||||
}
|
||||
check(commandLine)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeBinaryKotlinDSL() = with(
|
||||
transformProjectWithPluginsDsl("kotlin-dsl", gradleVersion, "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",
|
||||
"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"
|
||||
name to "build/bin/$nativeHostTargetName/$name/$fileName"
|
||||
}.toMap()
|
||||
|
||||
val runTasks = listOf(
|
||||
"runDebugExecutable",
|
||||
"runReleaseExecutable",
|
||||
"runFooDebugExecutable",
|
||||
"runFooReleaseExecutable",
|
||||
"runBarReleaseExecutable",
|
||||
"runBazReleaseExecutable",
|
||||
"runTest2ReleaseExecutable"
|
||||
).map { "$it$hostSuffix" }.toMutableList()
|
||||
|
||||
val binariesTasks = arrayOf("${nativeHostTargetName}MainBinaries", "${nativeHostTargetName}TestBinaries")
|
||||
|
||||
val compileTask = "compileKotlin$hostSuffix"
|
||||
val compileTestTask = "compileTestKotlin$hostSuffix"
|
||||
|
||||
// Check that all link and run tasks are generated.
|
||||
build(*binariesTasks) {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(linkTasks.map { ":$it" })
|
||||
assertTasksExecuted(":$compileTask", ":$compileTestTask")
|
||||
outputFiles.forEach { (_, file) ->
|
||||
assertFileExists(file)
|
||||
}
|
||||
// Check that getters work fine.
|
||||
assertTrue(output.contains("Check link task: linkReleaseShared$hostSuffix"))
|
||||
assertTrue(output.contains("Check run task: runFooReleaseExecutable$hostSuffix"))
|
||||
|
||||
// Check that dependency export works for static and shared libs.
|
||||
val staticSuffix = CompilerOutputKind.STATIC.suffix(HostManager.host)
|
||||
val sharedSuffix = CompilerOutputKind.DYNAMIC.suffix(HostManager.host)
|
||||
val staticPrefix = CompilerOutputKind.STATIC.prefix(HostManager.host)
|
||||
val sharedPrefix = CompilerOutputKind.DYNAMIC.prefix(HostManager.host)
|
||||
val staticHeader = outputFiles.getValue("releaseStatic").removeSuffix(staticSuffix) + "_api.h"
|
||||
val sharedHeader = outputFiles.getValue("releaseShared").removeSuffix(sharedSuffix) + "_api.h"
|
||||
assertTrue(fileInWorkingDir(staticHeader).readText().contains("${staticPrefix}native_binary_KInt (*exported)();"))
|
||||
assertTrue(fileInWorkingDir(sharedHeader).readText().contains("${sharedPrefix}native_binary_KInt (*exported)();"))
|
||||
}
|
||||
|
||||
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 kotlinOptions work fine for a compilation.
|
||||
build(compileTask) {
|
||||
assertSuccessful()
|
||||
checkNativeCommandLineFor(":$compileTask") {
|
||||
assertTrue(it.contains("-verbose"))
|
||||
}
|
||||
}
|
||||
|
||||
// Check that run tasks work fine 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()
|
||||
assertTasksExecuted(":$compileTestTask")
|
||||
checkNativeCommandLineFor(":linkTest2ReleaseExecutable$hostSuffix") {
|
||||
assertTrue(it.contains("-tr"))
|
||||
assertTrue(it.contains("-Xtime"))
|
||||
// Check that kotlinOptions of the compilation don't affect the binary.
|
||||
assertFalse(it.contains("-verbose"))
|
||||
// Check that free args are still propagated to the binary (unlike other kotlinOptions, see KT-33717).
|
||||
// TODO: Reverse this check when the args are fully separated.
|
||||
assertTrue(it.contains("-nowarn"))
|
||||
}
|
||||
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"))
|
||||
}
|
||||
|
||||
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.
|
||||
checkNativeCommandLineFor(":linkReleaseFrameworkIos") {
|
||||
assertTrue(it.contains("-Xembed-bitcode"))
|
||||
assertTrue(it.contains("-opt"))
|
||||
}
|
||||
}
|
||||
|
||||
// For debug builds.
|
||||
build("linkDebugFrameworkIos") {
|
||||
assertSuccessful()
|
||||
assertFileExists("build/bin/ios/debugFramework/native_binary.framework")
|
||||
assertTrue(
|
||||
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.
|
||||
checkNativeCommandLineFor(":linkDebugFrameworkIos") {
|
||||
assertTrue(it.contains("-Xembed-bitcode-marker"))
|
||||
assertTrue(it.contains("-g"))
|
||||
}
|
||||
}
|
||||
|
||||
// Check manual disabling bitcode embedding, custom command line args and building a static framework.
|
||||
build("linkCustomReleaseFrameworkIos") {
|
||||
assertSuccessful()
|
||||
checkNativeCommandLineFor(":linkCustomReleaseFrameworkIos") {
|
||||
assertTrue(it.contains("-linker-option -L."))
|
||||
assertTrue(it.contains("-Xtime"))
|
||||
assertTrue(it.contains("-Xstatic-framework"))
|
||||
assertFalse(it.contains("-Xembed-bitcode-marker"))
|
||||
assertFalse(it.contains("-Xembed-bitcode"))
|
||||
}
|
||||
}
|
||||
|
||||
// Check that bitcode is disabled for iOS simulator.
|
||||
build("linkReleaseFrameworkIosSim", "linkDebugFrameworkIosSim") {
|
||||
assertSuccessful()
|
||||
assertFileExists("build/bin/iosSim/releaseFramework/native_binary.framework")
|
||||
assertFileExists("build/bin/iosSim/debugFramework/native_binary.framework")
|
||||
checkNativeCommandLineFor(":linkReleaseFrameworkIosSim", ":linkDebugFrameworkIosSim") {
|
||||
assertFalse(it.contains("-Xembed-bitcode"))
|
||||
assertFalse(it.contains("-Xembed-bitcode-marker"))
|
||||
}
|
||||
}
|
||||
|
||||
// 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\"))", "")
|
||||
}
|
||||
projectDir.resolve("src/commonMain/kotlin/PackageMain.kt").modify {
|
||||
// Remove usages of the ":exported" dependency to be able to compile the sources.
|
||||
it.checkedReplace("import com.example.exported", "").checkedReplace("val exp = exported()", "val exp = 42")
|
||||
}
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We propagate compilation args to link tasks for now (see KT-33717).
|
||||
// TODO: Reenable the test when the args are separated.
|
||||
@Ignore
|
||||
@Test
|
||||
fun testNativeFreeArgsWarning() = with(transformProjectWithPluginsDsl("kotlin-dsl", gradleVersion, "new-mpp-native-binaries")) {
|
||||
gradleBuildScript().appendText(
|
||||
"""kotlin.targets["macos64"].compilations["main"].kotlinOptions.freeCompilerArgs += "-opt""""
|
||||
)
|
||||
gradleBuildScript("exported").appendText(
|
||||
"""
|
||||
kotlin.targets["macos64"].compilations["main"].kotlinOptions.freeCompilerArgs += "-opt"
|
||||
kotlin.targets["macos64"].compilations["test"].kotlinOptions.freeCompilerArgs += "-g"
|
||||
kotlin.targets["linux64"].compilations["main"].kotlinOptions.freeCompilerArgs +=
|
||||
listOf("-g", "-Xdisable-phases=Devirtualization,BuildDFG")
|
||||
""".trimIndent()
|
||||
)
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
assertContains(
|
||||
"""
|
||||
The following free compiler arguments must be specified for a binary instead of a compilation:
|
||||
* In project ':':
|
||||
* In target 'macos64':
|
||||
* Compilation: 'main', arguments: [-opt]
|
||||
* In project ':exported':
|
||||
* In target 'linux64':
|
||||
* Compilation: 'main', arguments: [-g, -Xdisable-phases=Devirtualization,BuildDFG]
|
||||
* In target 'macos64':
|
||||
* Compilation: 'main', arguments: [-opt]
|
||||
* Compilation: 'test', arguments: [-g]
|
||||
|
||||
Please move them into final binary declarations. E.g. binaries.executable { freeCompilerArgs += "..." }
|
||||
See more about final binaries: https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#building-final-native-binaries.
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSourceJars() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
|
||||
setupWorkingDir()
|
||||
@@ -1470,325 +1071,6 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBootedSimulators(workingDirectory: File): Set<String>? =
|
||||
if (HostManager.hostIsMac) {
|
||||
val simulators = runProcess(listOf("xcrun", "simctl", "list"), workingDirectory, System.getenv()).also {
|
||||
assertTrue(it.isSuccessful, "xcrun exection failed")
|
||||
}.output
|
||||
|
||||
simulators.split('\n').filter { it.contains("(Booted)") }.map { it.trim() }.toSet()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeTests() = with(Project("new-mpp-native-tests", gradleVersion)) {
|
||||
val testTasks = listOf("macos64Test", "linux64Test", "mingw64Test", "iosTest")
|
||||
val hostTestTask = "${nativeHostTargetName}Test"
|
||||
|
||||
val suffix = if (isWindows) "exe" else "kexe"
|
||||
|
||||
val defaultOutputFile = "build/bin/$nativeHostTargetName/debugTest/test.$suffix"
|
||||
val anotherOutputFile = "build/bin/$nativeHostTargetName/anotherDebugTest/another.$suffix"
|
||||
|
||||
val hostIsMac = HostManager.hostIsMac
|
||||
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
testTasks.forEach {
|
||||
// We need to create tasks for all hosts
|
||||
assertTrue(output.contains("$it - "), "There is no test task '$it' in the task list.")
|
||||
}
|
||||
}
|
||||
|
||||
// Perform all following checks in a single test to avoid running the K/N compiler several times.
|
||||
// Check that tests are not built during the ":assemble" execution
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
assertNoSuchFile(defaultOutputFile)
|
||||
assertNoSuchFile(anotherOutputFile)
|
||||
}
|
||||
|
||||
val testsToExecute = mutableListOf(":$hostTestTask")
|
||||
if (hostIsMac) {
|
||||
testsToExecute.add(":iosTest")
|
||||
}
|
||||
val testsToSkip = testTasks.map { ":$it" } - testsToExecute
|
||||
|
||||
// Store currently booted simulators to check that they don't leak (MacOS only).
|
||||
val bootedSimulatorsBefore = getBootedSimulators(projectDir)
|
||||
|
||||
// Check the case when all tests pass.
|
||||
build("check") {
|
||||
assertSuccessful()
|
||||
|
||||
assertTasksExecuted(*testsToExecute.toTypedArray())
|
||||
assertTasksSkipped(*testsToSkip.toTypedArray())
|
||||
|
||||
assertContainsRegex("org\\.foo\\.test\\.TestKt\\.fooTest\\s+PASSED".toRegex())
|
||||
assertContainsRegex("org\\.foo\\.test\\.TestKt\\.barTest\\s+PASSED".toRegex())
|
||||
|
||||
assertFileExists(defaultOutputFile)
|
||||
}
|
||||
|
||||
// Check simulator process leaking.
|
||||
val bootedSimulatorsAfter = getBootedSimulators(projectDir)
|
||||
assertEquals(bootedSimulatorsBefore, bootedSimulatorsAfter)
|
||||
|
||||
// Check the case with failed tests.
|
||||
projectDir.resolve("src/commonTest/kotlin/test.kt").appendText(
|
||||
"""
|
||||
@Test
|
||||
fun fail() {
|
||||
throw IllegalStateException("FAILURE!")
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
build("check") {
|
||||
assertFailed()
|
||||
|
||||
assertTasksFailed(":allTests")
|
||||
// In the aggregation report mode platform-specific tasks
|
||||
// are executed successfully even if there are failing tests.
|
||||
assertTasksExecuted(*testsToExecute.toTypedArray())
|
||||
assertTasksSkipped(*testsToSkip.toTypedArray())
|
||||
|
||||
assertContainsRegex("org\\.foo\\.test\\.TestKt\\.fail\\s+FAILED".toRegex())
|
||||
}
|
||||
|
||||
// Check that individual test reports are created correctly.
|
||||
build("check", "-Pkotlin.tests.individualTaskReports=true", "--continue") {
|
||||
assertFailed()
|
||||
|
||||
// In the individual report mode platform-specific tasks
|
||||
// fail if there are failing tests.
|
||||
assertTasksFailed(*testsToExecute.toTypedArray())
|
||||
assertTasksSkipped(*testsToSkip.toTypedArray())
|
||||
|
||||
|
||||
fun assertStacktrace(taskName: String) {
|
||||
val testReport = projectDir.resolve("build/test-results/$taskName/TEST-org.foo.test.TestKt.xml")
|
||||
val stacktrace = SAXBuilder().build(testReport).rootElement
|
||||
.getChildren("testcase")
|
||||
.single { it.getAttribute("name").value == "fail" }
|
||||
.getChild("failure")
|
||||
.text
|
||||
assertTrue(stacktrace.contains("""at org\.foo\.test#fail\(.*test\.kt:24\)""".toRegex()))
|
||||
}
|
||||
|
||||
assertTestResults("testProject/new-mpp-native-tests/TEST-TestKt.xml", hostTestTask)
|
||||
// K/N doesn't report line numbers correctly on Linux (see KT-35408).
|
||||
// TODO: Uncomment when this is fixed.
|
||||
//assertStacktrace(hostTestTask)
|
||||
if (hostIsMac) {
|
||||
assertTestResults("testProject/new-mpp-native-tests/TEST-TestKt.xml", "iosTest")
|
||||
assertStacktrace("iosTest")
|
||||
}
|
||||
}
|
||||
|
||||
build("linkAnotherDebugTest${nativeHostTargetName}") {
|
||||
assertSuccessful()
|
||||
assertFileExists(anotherOutputFile)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeTestGetters() = with(Project("new-mpp-native-tests", gradleVersion)) {
|
||||
// Check that test binaries can be accessed in a buildscript.
|
||||
build("checkNewGetters") {
|
||||
assertSuccessful()
|
||||
val suffixes = listOf("exe", "kexe", "wasm")
|
||||
val names = listOf("test", "another")
|
||||
val files = names.flatMap { name ->
|
||||
suffixes.map { suffix ->
|
||||
"$name.$suffix"
|
||||
}
|
||||
}
|
||||
|
||||
files.forEach {
|
||||
assertContains("Get test: $it")
|
||||
assertContains("Find test: $it")
|
||||
}
|
||||
}
|
||||
|
||||
// Check that accessing a test as an executable fails or returns null and shows the corresponding warning.
|
||||
build("checkOldGet") {
|
||||
assertFailed()
|
||||
assertContains(
|
||||
"""
|
||||
|Probably you are accessing the default test binary using the 'binaries.getExecutable("test", DEBUG)' method.
|
||||
|Since 1.3.40 tests are represented by a separate binary type. To get the default test binary, use:
|
||||
|
|
||||
| binaries.getTest("DEBUG")
|
||||
""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
build("checkOldFind") {
|
||||
assertSuccessful()
|
||||
assertContains(
|
||||
"""
|
||||
|Probably you are accessing the default test binary using the 'binaries.findExecutable("test", DEBUG)' method.
|
||||
|Since 1.3.40 tests are represented by a separate binary type. To get the default test binary, use:
|
||||
|
|
||||
| binaries.findTest("DEBUG")
|
||||
""".trimMargin()
|
||||
)
|
||||
assertContains("Find test: null")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun kt33750() {
|
||||
// Check that build fails if a test executable crashes.
|
||||
with(Project("new-mpp-native-tests", gradleVersion)) {
|
||||
setupWorkingDir()
|
||||
projectDir.resolve("src/commonTest/kotlin/test.kt").appendText("\nval fail: Int = error(\"\")\n")
|
||||
build("check") {
|
||||
assertFailed()
|
||||
output.contains("exited with errors \\(exit code: \\d+\\)".toRegex())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testCinterop() {
|
||||
val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")
|
||||
libProject.build("publish") {
|
||||
assertSuccessful()
|
||||
}
|
||||
val repo = libProject.projectDir.resolve("repo").absolutePath.replace('\\', '/')
|
||||
|
||||
with(Project("new-mpp-native-cinterop", gradleVersion)) {
|
||||
|
||||
setupWorkingDir()
|
||||
listOf(gradleBuildScript(), gradleBuildScript("publishedLibrary")).forEach {
|
||||
it.appendText(
|
||||
"""
|
||||
repositories {
|
||||
maven { url '$repo' }
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
val targetsToBuild = if (HostManager.hostIsMingw) {
|
||||
listOf(nativeHostTargetName, "mingw86")
|
||||
} else {
|
||||
listOf(nativeHostTargetName)
|
||||
}
|
||||
|
||||
val libraryCinteropTasks = targetsToBuild.map { ":projectLibrary:cinteropStdio${it.capitalize()}" }
|
||||
val libraryCompileTasks = targetsToBuild.map { ":projectLibrary:compileKotlin${it.capitalize()}" }
|
||||
|
||||
build(":projectLibrary:build") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(libraryCinteropTasks)
|
||||
assertTrue(output.contains("Project test"), "No test output found")
|
||||
targetsToBuild.forEach {
|
||||
assertFileExists("projectLibrary/build/classes/kotlin/$it/main/projectLibrary-cinterop-stdio.klib")
|
||||
}
|
||||
}
|
||||
|
||||
build(":publishedLibrary:build", ":publishedLibrary:publish") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(
|
||||
targetsToBuild.map { ":publishedLibrary:cinteropStdio${it.capitalize()}" }
|
||||
)
|
||||
assertTrue(output.contains("Published test"), "No test output found")
|
||||
targetsToBuild.forEach {
|
||||
assertFileExists("publishedLibrary/build/classes/kotlin/$it/main/publishedLibrary-cinterop-stdio.klib")
|
||||
assertFileExists("publishedLibrary/build/classes/kotlin/$it/test/test-cinterop-stdio.klib")
|
||||
assertFileExists("repo/org/example/publishedLibrary-$it/1.0/publishedLibrary-$it-1.0-cinterop-stdio.klib")
|
||||
}
|
||||
}
|
||||
|
||||
build(":build") {
|
||||
assertSuccessful()
|
||||
assertTrue(output.contains("Dependent: Project print"), "No test output found")
|
||||
assertTrue(output.contains("Dependent: Published print"), "No test output found")
|
||||
}
|
||||
|
||||
// Check that changing the compiler version in properties causes interop reprocessing and source recompilation.
|
||||
val hostLibraryTasks = listOf(
|
||||
":projectLibrary:cinteropStdio${nativeHostTargetName.capitalize()}",
|
||||
":projectLibrary:compileKotlin${nativeHostTargetName.capitalize()}"
|
||||
)
|
||||
build(":projectLibrary:build") {
|
||||
assertSuccessful()
|
||||
assertTasksUpToDate(hostLibraryTasks)
|
||||
}
|
||||
|
||||
build(*hostLibraryTasks.toTypedArray(), "-Porg.jetbrains.kotlin.native.version=1.3.70-dev-13258") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(hostLibraryTasks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeCompilerDownloading() {
|
||||
// The plugin shouldn't download the K/N compiler if there are no corresponding targets in the project.
|
||||
with(Project("sample-old-style-app", gradleVersion, "new-mpp-lib-and-app")) {
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
assertFalse(output.contains("Kotlin/Native distribution: "))
|
||||
}
|
||||
}
|
||||
with(Project("new-mpp-native-libraries", gradleVersion)) {
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
assertTrue(output.contains("Kotlin/Native distribution: "))
|
||||
// Check for KT-30258.
|
||||
assertFalse(output.contains("Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0."))
|
||||
}
|
||||
|
||||
// This directory actually doesn't contain a K/N distribution
|
||||
// but we still can run a project configuration and check logs.
|
||||
val currentDir = projectDir.absolutePath
|
||||
build("tasks", "-Pkotlin.native.home=$currentDir") {
|
||||
assertSuccessful()
|
||||
assertContains("User-provided Kotlin/Native distribution: $currentDir")
|
||||
assertNotContains("Project property 'org.jetbrains.kotlin.native.home' is deprecated")
|
||||
assertContains(NO_NATIVE_STDLIB_WARNING)
|
||||
assertContains(NO_NATIVE_STDLIB_PROPERTY_WARNING)
|
||||
}
|
||||
|
||||
// Deprecated property.
|
||||
build("tasks", "-Porg.jetbrains.kotlin.native.home=$currentDir", "-Pkotlin.native.nostdlib=true") {
|
||||
assertSuccessful()
|
||||
assertContains("User-provided Kotlin/Native distribution: $currentDir")
|
||||
assertContains("Project property 'org.jetbrains.kotlin.native.home' is deprecated")
|
||||
assertNotContains(NO_NATIVE_STDLIB_WARNING)
|
||||
assertNotContains(NO_NATIVE_STDLIB_PROPERTY_WARNING)
|
||||
}
|
||||
|
||||
build("tasks", "-Pkotlin.native.version=1.3-eap-10779") {
|
||||
assertSuccessful()
|
||||
assertContainsRegex("Kotlin/Native distribution: .*kotlin-native-(macos|linux|windows)-1\\.3-eap-10779".toRegex())
|
||||
assertNotContains("Project property 'org.jetbrains.kotlin.native.version' is deprecated")
|
||||
}
|
||||
|
||||
// Deprecated property
|
||||
build("tasks", "-Porg.jetbrains.kotlin.native.version=1.3-eap-10779") {
|
||||
assertSuccessful()
|
||||
assertContainsRegex("Kotlin/Native distribution: .*kotlin-native-(macos|linux|windows)-1\\.3-eap-10779".toRegex())
|
||||
assertContains("Project property 'org.jetbrains.kotlin.native.version' is deprecated")
|
||||
}
|
||||
}
|
||||
|
||||
// Gradle 5.0 introduced a new API for Ivy repository layouts.
|
||||
// MPP plugin uses this API to download K/N if Gradle version is >= 5.0.
|
||||
// Check this too (see KT-30258).
|
||||
with(Project("new-mpp-native-libraries")) {
|
||||
build("tasks", "-Pkotlin.native.version=1.3.50-eap-11606") {
|
||||
assertSuccessful()
|
||||
assertTrue(output.contains("Kotlin/Native distribution: "))
|
||||
assertFalse(output.contains("Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0."))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPublishMultimoduleProjectWithMetadata() {
|
||||
val libProject = Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")
|
||||
@@ -2182,16 +1464,6 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKt29725() {
|
||||
with(Project("new-mpp-native-libraries")) {
|
||||
// Assert that a project with a native target can be configured with Gradle 5.2
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIncrementalCompilation() = with(Project("new-mpp-jvm-js-ic", gradleVersion)) {
|
||||
build("build") {
|
||||
@@ -2307,18 +1579,6 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
doTestPomRewriting(mppProjectDependency = false, legacyPublishing = true, keepPomIntact = true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testIgnoreDisabledNativeTargets() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
|
||||
build {
|
||||
assertSuccessful()
|
||||
assertEquals(1, output.lines().count { DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX in it })
|
||||
}
|
||||
build("-P$DISABLED_NATIVE_TARGETS_REPORTER_DISABLE_WARNING_PROPERTY_NAME=true") {
|
||||
assertSuccessful()
|
||||
assertNotContains(DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testAssociateCompilations() {
|
||||
testAssociateCompilationsImpl()
|
||||
@@ -2408,29 +1668,6 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testNativeArgsWithSpaces() = with(Project("sample-lib", directoryPrefix = "new-mpp-lib-and-app")) {
|
||||
setupWorkingDir()
|
||||
val compilcatedDirectoryName = if (HostManager.hostIsMingw) {
|
||||
// Windows doesn't allow creating a file with " in its name.
|
||||
"path with spaces"
|
||||
} else {
|
||||
"path with spaces and \""
|
||||
}
|
||||
|
||||
val fileWithSpacesInPath = projectDir.resolve("src/commonMain/kotlin/$compilcatedDirectoryName")
|
||||
.apply { mkdirs() }
|
||||
.resolve("B.kt")
|
||||
fileWithSpacesInPath.writeText("fun foo() = 42")
|
||||
|
||||
build("compileKotlin${nativeHostTargetName.capitalize()}") {
|
||||
assertSuccessful()
|
||||
checkNativeCommandLineFor(":compileKotlin${nativeHostTargetName.capitalize()}") {
|
||||
it.contains(fileWithSpacesInPath.absolutePath)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testKlibsWithTheSameProjectName() = with(transformProjectWithPluginsDsl("new-mpp-klibs-with-same-name")) {
|
||||
// KT-36721.
|
||||
|
||||
Reference in New Issue
Block a user