Gradle, native: Introduce separate binary type for tests
Earlier native tests were represented by the same binary type as product
executables. We also used to create test tasks in the same manner as run
tasks for product executables. Such tasks could be obtained used a property
of an executable binary with type Exec.
But now we have a separate class for test tasks. Also we probably will want
to create several tasks for the same test. So we cannot use the same run task
property for both test and product executables. Also representing test and
product executables by the same binary type leads to the fact that assemble
task execution causes building not only product binaries but also the test
ones.
This patch solves the issues described above by introducing a separate binary
type for tests. Such a test binary can be created in the same manner as other
binaries:
kotlin.macosX64 {
binaries {
test("integration") { ... }
}
}
One test binary and a task executing it is created by the plugin out of the box.
This test binary replaces a test executable used to be created earlier.
Issue #KT-31609 Fixed
This commit is contained in:
+21
-5
@@ -17,17 +17,25 @@ internal data class BinaryType(
|
||||
val nativeOutputKind: TypeName,
|
||||
val factoryMethod: String,
|
||||
val getMethod: String,
|
||||
val findMethod: String
|
||||
val findMethod: String,
|
||||
val defaultBaseName: String
|
||||
)
|
||||
|
||||
private fun binaryType(description: String, className: String, outputKind: String, baseMethodName: String) =
|
||||
private fun binaryType(
|
||||
description: String,
|
||||
className: String,
|
||||
outputKind: String,
|
||||
baseMethodName: String,
|
||||
defaultBaseName: String = "project.name"
|
||||
) =
|
||||
BinaryType(
|
||||
description,
|
||||
typeName("$MPP_PACKAGE.$className"),
|
||||
typeName("${nativeOutputKindClass.fqName}.$outputKind"),
|
||||
baseMethodName,
|
||||
"get${baseMethodName.capitalize()}",
|
||||
"find${baseMethodName.capitalize()}"
|
||||
"find${baseMethodName.capitalize()}",
|
||||
defaultBaseName
|
||||
)
|
||||
|
||||
private val nativeBuildTypeClass = typeName("$MPP_PACKAGE.NativeBuildType")
|
||||
@@ -41,6 +49,7 @@ private fun generateFactoryMethods(binaryType: BinaryType): String {
|
||||
val nativeBuildType = nativeBuildTypeClass.renderShort()
|
||||
val methodName = binaryType.factoryMethod
|
||||
val binaryDescription = binaryType.description
|
||||
val defaultBaseName = binaryType.defaultBaseName
|
||||
|
||||
return """
|
||||
/** Creates $binaryDescription with the given [namePrefix] for each build type and configures it. */
|
||||
@@ -56,7 +65,7 @@ private fun generateFactoryMethods(binaryType: BinaryType): String {
|
||||
fun $methodName(
|
||||
buildTypes: Collection<$nativeBuildType> = $nativeBuildType.DEFAULT_BUILD_TYPES,
|
||||
configure: $className.() -> Unit = {}
|
||||
) = createBinaries("", project.name, $outputKindClass.$outputKind, buildTypes, ::$className, configure)
|
||||
) = createBinaries("", $defaultBaseName, $outputKindClass.$outputKind, buildTypes, ::$className, configure)
|
||||
|
||||
/** Creates $binaryDescription with the given [namePrefix] for each build type and configures it. */
|
||||
@JvmOverloads
|
||||
@@ -115,7 +124,14 @@ fun generateAbstractKotlinNativeBinaryContainer() {
|
||||
binaryType("an executable","Executable", "EXECUTABLE", "executable"),
|
||||
binaryType("a static library","StaticLibrary", "STATIC", "staticLib"),
|
||||
binaryType("a shared library","SharedLibrary", "DYNAMIC", "sharedLib"),
|
||||
binaryType("an Objective-C framework","Framework", "FRAMEWORK", "framework")
|
||||
binaryType("an Objective-C framework","Framework", "FRAMEWORK", "framework"),
|
||||
binaryType(
|
||||
"a test executable",
|
||||
"Test",
|
||||
"TEST",
|
||||
"test",
|
||||
defaultBaseName = "\"test\""
|
||||
)
|
||||
)
|
||||
|
||||
val className = typeName("org.jetbrains.kotlin.gradle.dsl.AbstractKotlinNativeBinaryContainer")
|
||||
|
||||
+55
-2
@@ -942,7 +942,6 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
"fooReleaseExecutable" to "foo",
|
||||
"barReleaseExecutable" to "bar",
|
||||
"bazReleaseExecutable" to "my-baz",
|
||||
"testDebugExecutable" to "test",
|
||||
"test2ReleaseExecutable" to "test2",
|
||||
"releaseStatic" to "native_binary",
|
||||
"releaseShared" to "native_binary"
|
||||
@@ -1136,19 +1135,73 @@ class NewMultiplatformIT : BaseGradleIT() {
|
||||
fun testNativeTests() = with(Project("new-mpp-native-tests", gradleVersion)) {
|
||||
val testTasks = listOf("macos64Test", "linux64Test", "mingw64Test")
|
||||
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"
|
||||
|
||||
build("tasks") {
|
||||
assertSuccessful()
|
||||
println(output)
|
||||
testTasks.forEach {
|
||||
// We need to create tasks for all hosts
|
||||
assertTrue(output.contains("$it - "), "There is no test task '$it' in the task list.")
|
||||
}
|
||||
}
|
||||
|
||||
// Check that tests are not built during the ":assemble" execution
|
||||
build("assemble") {
|
||||
assertSuccessful()
|
||||
assertNoSuchFile(defaultOutputFile)
|
||||
assertNoSuchFile(anotherOutputFile)
|
||||
}
|
||||
|
||||
build("check") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(":$hostTestTask")
|
||||
assertFileExists(defaultOutputFile)
|
||||
assertTestResults("testProject/new-mpp-native-tests/TEST-TestKt.xml", hostTestTask)
|
||||
}
|
||||
|
||||
build("linkAnotherDebugTest${nativeHostTargetName}") {
|
||||
assertSuccessful()
|
||||
assertFileExists(anotherOutputFile)
|
||||
}
|
||||
|
||||
// Check that test binaries can be accessed in a buildscript.
|
||||
build("checkNewGetters") {
|
||||
assertSuccessful()
|
||||
listOf("test.$suffix", "another.$suffix").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
|
||||
|
||||
+1
@@ -53,6 +53,7 @@ kotlin {
|
||||
|
||||
executable("test2", [RELEASE]) {
|
||||
compilation = compilations["test"]
|
||||
freeCompilerArgs.add("-tr")
|
||||
}
|
||||
|
||||
sharedLib([RELEASE])
|
||||
|
||||
+1
@@ -44,6 +44,7 @@ kotlin {
|
||||
|
||||
executable("test2") {
|
||||
compilation = compilations["test"]
|
||||
freeCompilerArgs.add("-tr")
|
||||
}
|
||||
|
||||
sharedLib(listOf(RELEASE))
|
||||
|
||||
+51
@@ -24,5 +24,56 @@ kotlin {
|
||||
fromPreset(presets.macosX64, 'macos64')
|
||||
fromPreset(presets.linuxX64, 'linux64')
|
||||
fromPreset(presets.mingwX64, 'mingw64')
|
||||
|
||||
configure([macos64, linux64, mingw64]) {
|
||||
compilations.create("anotherTest")
|
||||
binaries {
|
||||
test("another", [DEBUG]) {
|
||||
compilation = compilations.anotherTest
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
anotherTest
|
||||
macos64AnotherTest.dependsOn(anotherTest)
|
||||
linux64AnotherTest.dependsOn(anotherTest)
|
||||
mingw64AnotherTest.dependsOn(anotherTest)
|
||||
}
|
||||
}
|
||||
|
||||
// Check that getting a test binary in an old way fails showing the corresponding warning
|
||||
task checkOldGet {
|
||||
doLast {
|
||||
kotlin.targets {
|
||||
configure([macos64, linux64, mingw64]) {
|
||||
println("Get test: ${binaries.getExecutable("test", DEBUG)}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that finding a test binary in an old way returns null showing the corresponding warning.
|
||||
task checkOldFind {
|
||||
doLast {
|
||||
kotlin.targets {
|
||||
configure([macos64, linux64, mingw64]) {
|
||||
println("Find test: ${binaries.findExecutable("test", DEBUG)}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
task checkNewGetters {
|
||||
doLast {
|
||||
kotlin.targets {
|
||||
configure([macos64, linux64, mingw64]) {
|
||||
println("Get test: ${binaries.getTest(DEBUG).outputFile.name}")
|
||||
println("Find test: ${binaries.findTest(DEBUG).outputFile.name}")
|
||||
println("Get test: ${binaries.getTest("another", DEBUG).outputFile.name}")
|
||||
println("Find test: ${binaries.findTest("another", DEBUG).outputFile.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
kotlin.tests.individualTaskReports=true
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* 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.foo.test
|
||||
|
||||
import kotlin.test.*
|
||||
|
||||
@Test
|
||||
fun anotherTest() {
|
||||
println("Another test")
|
||||
}
|
||||
+56
@@ -142,6 +142,32 @@ abstract class AbstractKotlinNativeBinaryContainer : DomainObjectSet<NativeBinar
|
||||
/** Returns an Objective-C framework with the empty name prefix and the given build type. Returns null if there is no such binary. */
|
||||
fun findFramework(buildType: String): Framework? = findFramework("", buildType)
|
||||
|
||||
/** Returns a test executable with the given [namePrefix] and the given build type. Throws an exception if there is no such binary.*/
|
||||
abstract fun getTest(namePrefix: String, buildType: NativeBuildType): Test
|
||||
|
||||
/** Returns a test executable with the given [namePrefix] and the given build type. Throws an exception if there is no such binary.*/
|
||||
fun getTest(namePrefix: String, buildType: String): Test =
|
||||
getTest(namePrefix, NativeBuildType.valueOf(buildType.toUpperCase()))
|
||||
|
||||
/** Returns a test executable with the empty name prefix and the given build type. Throws an exception if there is no such binary.*/
|
||||
fun getTest(buildType: NativeBuildType): Test = getTest("", buildType)
|
||||
|
||||
/** Returns a test executable with the empty name prefix and the given build type. Throws an exception if there is no such binary.*/
|
||||
fun getTest(buildType: String): Test = getTest("", buildType)
|
||||
|
||||
/** Returns a test executable with the given [namePrefix] and the given build type. Returns null if there is no such binary. */
|
||||
abstract fun findTest(namePrefix: String, buildType: NativeBuildType): Test?
|
||||
|
||||
/** Returns a test executable with the given [namePrefix] and the given build type. Returns null if there is no such binary. */
|
||||
fun findTest(namePrefix: String, buildType: String): Test? =
|
||||
findTest(namePrefix, NativeBuildType.valueOf(buildType.toUpperCase()))
|
||||
|
||||
/** Returns a test executable with the empty name prefix and the given build type. Returns null if there is no such binary. */
|
||||
fun findTest(buildType: NativeBuildType): Test? = findTest("", buildType)
|
||||
|
||||
/** Returns a test executable with the empty name prefix and the given build type. Returns null if there is no such binary. */
|
||||
fun findTest(buildType: String): Test? = findTest("", buildType)
|
||||
|
||||
/** Creates an executable with the given [namePrefix] for each build type and configures it. */
|
||||
@JvmOverloads
|
||||
fun executable(
|
||||
@@ -262,4 +288,34 @@ abstract class AbstractKotlinNativeBinaryContainer : DomainObjectSet<NativeBinar
|
||||
configureClosure: Closure<*>
|
||||
) = framework(buildTypes) { ConfigureUtil.configure(configureClosure, this) }
|
||||
|
||||
/** Creates a test executable with the given [namePrefix] for each build type and configures it. */
|
||||
@JvmOverloads
|
||||
fun test(
|
||||
namePrefix: String,
|
||||
buildTypes: Collection<NativeBuildType> = NativeBuildType.DEFAULT_BUILD_TYPES,
|
||||
configure: Test.() -> Unit = {}
|
||||
) = createBinaries(namePrefix, namePrefix, NativeOutputKind.TEST, buildTypes, ::Test, configure)
|
||||
|
||||
/** Creates a test executable with the empty name prefix for each build type and configures it. */
|
||||
@JvmOverloads
|
||||
fun test(
|
||||
buildTypes: Collection<NativeBuildType> = NativeBuildType.DEFAULT_BUILD_TYPES,
|
||||
configure: Test.() -> Unit = {}
|
||||
) = createBinaries("", "test", NativeOutputKind.TEST, buildTypes, ::Test, configure)
|
||||
|
||||
/** Creates a test executable with the given [namePrefix] for each build type and configures it. */
|
||||
@JvmOverloads
|
||||
fun test(
|
||||
namePrefix: String,
|
||||
buildTypes: Collection<NativeBuildType> = NativeBuildType.DEFAULT_BUILD_TYPES,
|
||||
configureClosure: Closure<*>
|
||||
) = test(namePrefix, buildTypes) { ConfigureUtil.configure(configureClosure, this) }
|
||||
|
||||
/** Creates a test executable with the default name prefix for each build type and configures it. */
|
||||
@JvmOverloads
|
||||
fun test(
|
||||
buildTypes: Collection<NativeBuildType> = NativeBuildType.DEFAULT_BUILD_TYPES,
|
||||
configureClosure: Closure<*>
|
||||
) = test(buildTypes) { ConfigureUtil.configure(configureClosure, this) }
|
||||
|
||||
}
|
||||
+43
-21
@@ -32,6 +32,9 @@ open class KotlinNativeBinaryContainer @Inject constructor(
|
||||
private val defaultCompilation: KotlinNativeCompilation
|
||||
get() = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
|
||||
private val defaultTestCompilation: KotlinNativeCompilation
|
||||
get() = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
|
||||
|
||||
private val nameToBinary = mutableMapOf<String, NativeBinary>()
|
||||
internal val prefixGroups: NamedDomainObjectSet<PrefixGroup> = project.container(PrefixGroup::class.java)
|
||||
|
||||
@@ -69,8 +72,16 @@ open class KotlinNativeBinaryContainer @Inject constructor(
|
||||
override fun getByName(name: String): NativeBinary = nameToBinary.getValue(name)
|
||||
override fun findByName(name: String): NativeBinary? = nameToBinary[name]
|
||||
|
||||
override fun getExecutable(namePrefix: String, buildType: NativeBuildType): Executable =
|
||||
getBinary(namePrefix, buildType, NativeOutputKind.EXECUTABLE)
|
||||
private fun checkDeprecatedTestAccess(namePrefix: String, buildType: NativeBuildType, warning: String) {
|
||||
if (namePrefix == DEFAULT_TEST_NAME_PREFIX && buildType == DEFAULT_TEST_BUILD_TYPE) {
|
||||
project.logger.warn(warning)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getExecutable(namePrefix: String, buildType: NativeBuildType): Executable {
|
||||
checkDeprecatedTestAccess(namePrefix, buildType, GET_TEST_DEPRECATION_WARNING)
|
||||
return getBinary(namePrefix, buildType, NativeOutputKind.EXECUTABLE)
|
||||
}
|
||||
|
||||
override fun getStaticLib(namePrefix: String, buildType: NativeBuildType): StaticLibrary =
|
||||
getBinary(namePrefix, buildType, NativeOutputKind.STATIC)
|
||||
@@ -81,9 +92,13 @@ open class KotlinNativeBinaryContainer @Inject constructor(
|
||||
override fun getFramework(namePrefix: String, buildType: NativeBuildType): Framework =
|
||||
getBinary(namePrefix, buildType, NativeOutputKind.FRAMEWORK)
|
||||
|
||||
override fun getTest(namePrefix: String, buildType: NativeBuildType): Test =
|
||||
getBinary(namePrefix, buildType, NativeOutputKind.TEST)
|
||||
|
||||
override fun findExecutable(namePrefix: String, buildType: NativeBuildType): Executable? =
|
||||
findBinary(namePrefix, buildType, NativeOutputKind.EXECUTABLE)
|
||||
override fun findExecutable(namePrefix: String, buildType: NativeBuildType): Executable? {
|
||||
checkDeprecatedTestAccess(namePrefix, buildType, FIND_TEST_DEPRECATED_WARNING)
|
||||
return findBinary(namePrefix, buildType, NativeOutputKind.EXECUTABLE)
|
||||
}
|
||||
|
||||
override fun findStaticLib(namePrefix: String, buildType: NativeBuildType): StaticLibrary? =
|
||||
findBinary(namePrefix, buildType, NativeOutputKind.STATIC)
|
||||
@@ -93,6 +108,9 @@ open class KotlinNativeBinaryContainer @Inject constructor(
|
||||
|
||||
override fun findFramework(namePrefix: String, buildType: NativeBuildType): Framework? =
|
||||
findBinary(namePrefix, buildType, NativeOutputKind.FRAMEWORK)
|
||||
|
||||
override fun findTest(namePrefix: String, buildType: NativeBuildType): Test? =
|
||||
findBinary(namePrefix, buildType, NativeOutputKind.TEST)
|
||||
// endregion.
|
||||
|
||||
// region Factories
|
||||
@@ -119,7 +137,8 @@ open class KotlinNativeBinaryContainer @Inject constructor(
|
||||
"Cannot create ${outputKind.description}: $name. Binaries of this kind are not available for target ${target.name}"
|
||||
}
|
||||
|
||||
val binary = create(name, baseName, buildType, defaultCompilation)
|
||||
val compilation = if (outputKind == NativeOutputKind.TEST) defaultTestCompilation else defaultCompilation
|
||||
val binary = create(name, baseName, buildType, compilation)
|
||||
add(binary)
|
||||
prefixGroup.binaries.add(binary)
|
||||
nameToBinary[binary.name] = binary
|
||||
@@ -131,28 +150,31 @@ open class KotlinNativeBinaryContainer @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
internal fun defaultTestExecutable(
|
||||
configure: Executable.() -> Unit
|
||||
) = createBinaries(
|
||||
DEFAULT_TEST_NAME_PREFIX,
|
||||
"test",
|
||||
NativeOutputKind.EXECUTABLE,
|
||||
listOf(DEFAULT_TEST_BUILD_TYPE),
|
||||
{ name, baseName, buildType, compilation ->
|
||||
Executable(name, baseName, buildType, compilation, true)
|
||||
},
|
||||
configure
|
||||
)
|
||||
|
||||
internal fun getDefaultTestExecutable(): Executable =
|
||||
getExecutable(DEFAULT_TEST_NAME_PREFIX, DEFAULT_TEST_BUILD_TYPE)
|
||||
|
||||
companion object {
|
||||
internal val DEFAULT_TEST_BUILD_TYPE = NativeBuildType.DEBUG
|
||||
internal val DEFAULT_TEST_NAME_PREFIX = "test"
|
||||
|
||||
internal fun generateBinaryName(prefix: String, buildType: NativeBuildType, outputKindClassifier: String) =
|
||||
lowerCamelCaseName(prefix, buildType.getName(), outputKindClassifier)
|
||||
|
||||
// TODO: Remove in 1.3.50.
|
||||
private val GET_TEST_DEPRECATION_WARNING = """
|
||||
|
|
||||
|Probably you are accessing the default test binary using the 'binaries.getExecutable("$DEFAULT_TEST_NAME_PREFIX", ${DEFAULT_TEST_BUILD_TYPE.name})' method.
|
||||
|Since 1.3.40 tests are represented by a separate binary type. To get the default test binary, use:
|
||||
|
|
||||
| binaries.getTest(DEBUG)
|
||||
|
|
||||
""".trimMargin()
|
||||
|
||||
private val FIND_TEST_DEPRECATED_WARNING = """
|
||||
|
|
||||
|Probably you are accessing the default test binary using the 'binaries.findExecutable("$DEFAULT_TEST_NAME_PREFIX", ${DEFAULT_TEST_BUILD_TYPE.name})' method.
|
||||
|Since 1.3.40 tests are represented by a separate binary type. To get the default test binary, use:
|
||||
|
|
||||
| binaries.findTest(DEBUG)
|
||||
|
|
||||
""".trimMargin()
|
||||
}
|
||||
// endregion.
|
||||
|
||||
|
||||
-2
@@ -42,8 +42,6 @@ class KotlinNativeCompilation(
|
||||
// TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
|
||||
internal val commonSources: MutableSet<SourceDirectorySet> = mutableSetOf()
|
||||
|
||||
var isTestCompilation = false
|
||||
|
||||
var friendCompilationName: String? = null
|
||||
|
||||
internal val friendCompilation: KotlinNativeCompilation?
|
||||
|
||||
-1
@@ -21,7 +21,6 @@ class KotlinNativeCompilationFactory(
|
||||
KotlinNativeCompilation(target, name).apply {
|
||||
if (name == KotlinCompilation.TEST_COMPILATION_NAME) {
|
||||
friendCompilationName = KotlinCompilation.MAIN_COMPILATION_NAME
|
||||
isTestCompilation = true
|
||||
}
|
||||
}
|
||||
}
|
||||
+40
-35
@@ -25,6 +25,8 @@ import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.testing.internal.configureConventions
|
||||
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
@@ -119,45 +121,26 @@ open class KotlinNativeTargetConfigurator(
|
||||
destinationDir = binary.outputDirectory
|
||||
addCompilerPlugins()
|
||||
|
||||
tasks.maybeCreate(target.artifactsTaskName).dependsOn(this)
|
||||
tasks.maybeCreate(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(this)
|
||||
if (binary !is Test) {
|
||||
tasks.maybeCreate(target.artifactsTaskName).dependsOn(this)
|
||||
tasks.maybeCreate(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.createRunTask(binary: Executable) {
|
||||
val taskName = binary.runTaskName ?: return
|
||||
tasks.create(taskName, Exec::class.java).apply {
|
||||
group = RUN_GROUP
|
||||
description = "Executes Kotlin/Native executable ${binary.name} for target ${binary.target.name}"
|
||||
|
||||
if (binary.isDefaultTestExecutable) {
|
||||
val testTask = createOrRegisterTask<KotlinNativeTest>(taskName) { testTask ->
|
||||
testTask.group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
testTask.description = "Executes Kotlin/Native unit tests for target ${binary.target.name}."
|
||||
testTask.targetName = binary.compilation.target.targetName
|
||||
enabled = binary.target.konanTarget.isCurrentHost
|
||||
|
||||
testTask.enabled = binary.target.konanTarget.isCurrentHost
|
||||
executable = binary.outputFile.absolutePath
|
||||
workingDir = project.projectDir
|
||||
|
||||
testTask.executable = binary.outputFile
|
||||
testTask.workingDir = project.projectDir.absolutePath
|
||||
|
||||
testTask.onlyIf { binary.outputFile.exists() }
|
||||
testTask.dependsOn(binary.linkTaskName)
|
||||
|
||||
testTask.configureConventions()
|
||||
}
|
||||
|
||||
kotlinTestRegistry.registerTestTask(testTask)
|
||||
} else {
|
||||
tasks.create(taskName, Exec::class.java).apply {
|
||||
group = RUN_GROUP
|
||||
description = "Executes Kotlin/Native executable ${binary.name} for target ${binary.target.name}"
|
||||
|
||||
enabled = binary.target.konanTarget.isCurrentHost
|
||||
|
||||
executable = binary.outputFile.absolutePath
|
||||
workingDir = project.projectDir
|
||||
|
||||
onlyIf { binary.outputFile.exists() }
|
||||
dependsOn(binary.linkTaskName)
|
||||
}
|
||||
onlyIf { binary.outputFile.exists() }
|
||||
dependsOn(binary.linkTaskName)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +164,7 @@ open class KotlinNativeTargetConfigurator(
|
||||
|
||||
project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTask)
|
||||
|
||||
if (compilation.compilationName == KotlinCompilation.MAIN_COMPILATION_NAME) {
|
||||
if (compilation.compilationName == MAIN_COMPILATION_NAME) {
|
||||
project.tasks.getByName(compilation.target.artifactsTaskName).apply {
|
||||
dependsOn(compileTask)
|
||||
}
|
||||
@@ -248,9 +231,31 @@ open class KotlinNativeTargetConfigurator(
|
||||
}
|
||||
}
|
||||
|
||||
override fun configureTest(target: KotlinNativeTarget) {
|
||||
target.binaries.defaultTestExecutable {
|
||||
compilation = target.compilations.maybeCreate(TEST_COMPILATION_NAME)
|
||||
override fun configureTest(target: KotlinNativeTarget): Unit = with(target.project) {
|
||||
// We don't create test tasks for non-host platforms.
|
||||
if (target.konanTarget !in listOf(KonanTarget.MACOS_X64, KonanTarget.MINGW_X64, KonanTarget.LINUX_X64)) {
|
||||
return
|
||||
}
|
||||
|
||||
val taskName = lowerCamelCaseName(target.disambiguationClassifier, testTaskNameSuffix)
|
||||
target.binaries.test(listOf(NativeBuildType.DEBUG)) {
|
||||
val testTask = createOrRegisterTask<KotlinNativeTest>(taskName) { testTask ->
|
||||
testTask.group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
testTask.description = "Executes Kotlin/Native unit tests for target ${target.name}."
|
||||
testTask.targetName = compilation.target.targetName
|
||||
|
||||
testTask.enabled = target.konanTarget.isCurrentHost
|
||||
|
||||
testTask.executable { outputFile }
|
||||
testTask.workingDir = project.projectDir.absolutePath
|
||||
|
||||
testTask.onlyIf { outputFile.exists() }
|
||||
testTask.dependsOn(linkTaskName)
|
||||
|
||||
testTask.configureConventions()
|
||||
}
|
||||
|
||||
kotlinTestRegistry.registerTestTask(testTask)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+25
-22
@@ -12,10 +12,8 @@ import org.gradle.api.Named
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.tasks.AbstractExecTask
|
||||
import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinTargetConfigurator
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
|
||||
@@ -83,19 +81,19 @@ sealed class NativeBinary(
|
||||
override fun getName(): String = name
|
||||
}
|
||||
|
||||
abstract class AbstractExecutable(
|
||||
name: String,
|
||||
baseName: String,
|
||||
buildType: NativeBuildType,
|
||||
compilation: KotlinNativeCompilation
|
||||
) : NativeBinary(name, baseName, buildType, compilation)
|
||||
|
||||
class Executable constructor(
|
||||
name: String,
|
||||
baseName: String,
|
||||
buildType: NativeBuildType,
|
||||
compilation: KotlinNativeCompilation,
|
||||
internal val isDefaultTestExecutable: Boolean
|
||||
) : NativeBinary(name, baseName, buildType, compilation) {
|
||||
|
||||
constructor(
|
||||
name: String,
|
||||
baseName: String,
|
||||
buildType: NativeBuildType,
|
||||
compilation: KotlinNativeCompilation) : this(name, baseName, buildType, compilation, false)
|
||||
compilation: KotlinNativeCompilation
|
||||
) : AbstractExecutable(name, baseName, buildType, compilation) {
|
||||
|
||||
override val outputKind: NativeOutputKind
|
||||
get() = NativeOutputKind.EXECUTABLE
|
||||
@@ -114,20 +112,14 @@ class Executable constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* A name of task running this executable.
|
||||
* A name of a task running this executable.
|
||||
* Returns null if the executables's target is not a host one (macosX64, linuxX64 or mingw64).
|
||||
*/
|
||||
val runTaskName: String?
|
||||
get() {
|
||||
if (target.konanTarget !in listOf(KonanTarget.MACOS_X64, KonanTarget.LINUX_X64, KonanTarget.MINGW_X64)) {
|
||||
return null
|
||||
}
|
||||
|
||||
return if (isDefaultTestExecutable) {
|
||||
lowerCamelCaseName(compilation.target.targetName, AbstractKotlinTargetConfigurator.testTaskNameSuffix)
|
||||
} else {
|
||||
lowerCamelCaseName("run", name, compilation.target.targetName)
|
||||
}
|
||||
get() = if (target.konanTarget in listOf(KonanTarget.MACOS_X64, KonanTarget.LINUX_X64, KonanTarget.MINGW_X64)) {
|
||||
lowerCamelCaseName("run", name, compilation.target.targetName)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,6 +130,17 @@ class Executable constructor(
|
||||
get() = runTaskName?.let { project.tasks.getByName(it) as AbstractExecTask<*> }
|
||||
}
|
||||
|
||||
class Test(
|
||||
name: String,
|
||||
baseName: String,
|
||||
buildType: NativeBuildType,
|
||||
compilation: KotlinNativeCompilation
|
||||
) : AbstractExecutable(name, baseName, buildType, compilation) {
|
||||
|
||||
override val outputKind: NativeOutputKind
|
||||
get() = NativeOutputKind.TEST
|
||||
}
|
||||
|
||||
class StaticLibrary(
|
||||
name: String,
|
||||
baseName: String,
|
||||
|
||||
+5
@@ -32,6 +32,11 @@ enum class NativeOutputKind(
|
||||
"executable",
|
||||
description = "an executable"
|
||||
),
|
||||
TEST(
|
||||
CompilerOutputKind.PROGRAM,
|
||||
"test",
|
||||
description = "a test executable"
|
||||
),
|
||||
DYNAMIC(
|
||||
CompilerOutputKind.DYNAMIC,
|
||||
"shared",
|
||||
|
||||
+5
-4
@@ -126,9 +126,6 @@ abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile<Ko
|
||||
throw UnsupportedOperationException("Setting classpath directly is unsupported.")
|
||||
}
|
||||
|
||||
val processTests
|
||||
@Input get() = compilation.isTestCompilation
|
||||
|
||||
val target: String
|
||||
@Input get() = compilation.target.konanTarget.name
|
||||
|
||||
@@ -273,7 +270,6 @@ abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile<Ko
|
||||
addKey("-opt", optimized)
|
||||
addKey("-g", debuggable)
|
||||
addKey("-ea", debuggable)
|
||||
addKey("-tr", processTests)
|
||||
|
||||
addArg("-target", target)
|
||||
addArg("-p", outputKind.name.toLowerCase())
|
||||
@@ -366,6 +362,10 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile() {
|
||||
val linkerOpts: List<String>
|
||||
get() = binary.linkerOpts
|
||||
|
||||
@get:Input
|
||||
val processTests: Boolean
|
||||
get() = binary is Test
|
||||
|
||||
@get:InputFiles
|
||||
val exportLibraries: FileCollection
|
||||
get() = binary.let {
|
||||
@@ -392,6 +392,7 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile() {
|
||||
val superArgs = super.buildArgs(defaultsOnly)
|
||||
return mutableListOf<String>().apply {
|
||||
addAll(superArgs)
|
||||
addKey("-tr", processTests)
|
||||
addArgIfNotNull("-entry", entryPoint)
|
||||
when (embedBitcode) {
|
||||
Framework.BitcodeEmbeddingMode.MARKER -> add("-Xembed-bitcode-marker")
|
||||
|
||||
+49
-12
@@ -5,6 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.native.tasks
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFile
|
||||
import org.gradle.api.tasks.Internal
|
||||
@@ -19,31 +21,63 @@ import java.io.File
|
||||
|
||||
open class KotlinNativeTest : KotlinTest() {
|
||||
@Suppress("LeakingThis")
|
||||
@Internal
|
||||
val processOptions: ProcessForkOptions = DefaultProcessForkOptions(fileResolver)
|
||||
private val processOptions: ProcessForkOptions = DefaultProcessForkOptions(fileResolver)
|
||||
|
||||
@InputFile
|
||||
@SkipWhenEmpty
|
||||
val executableProperty: Property<File> = project.objects.property(File::class.java)
|
||||
|
||||
@Input
|
||||
var args: List<String> = emptyList()
|
||||
|
||||
// Already taken into account in the executableProperty.
|
||||
@get:Internal
|
||||
var executable: File
|
||||
@InputFile
|
||||
@SkipWhenEmpty
|
||||
get() = File(processOptions.executable)
|
||||
get() = executableProperty.get()
|
||||
set(value) {
|
||||
processOptions.executable = value.absolutePath
|
||||
executableProperty.set(value)
|
||||
}
|
||||
|
||||
@get:Input
|
||||
var workingDir: String
|
||||
@Input get() = processOptions.workingDir.canonicalPath
|
||||
get() = processOptions.workingDir.canonicalPath
|
||||
set(value) {
|
||||
processOptions.workingDir = File(value)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun processOptions(options: ProcessForkOptions.() -> Unit) {
|
||||
options(processOptions)
|
||||
@get:Input
|
||||
var environment: Map<String, Any>
|
||||
get() = processOptions.environment
|
||||
set(value) {
|
||||
processOptions.environment = value
|
||||
}
|
||||
|
||||
private fun <T> Property<T>.set(providerLambda: () -> T) = set(project.provider { providerLambda() })
|
||||
|
||||
fun executable(file: File) {
|
||||
executableProperty.set(file)
|
||||
}
|
||||
|
||||
fun executable(path: String) {
|
||||
executableProperty.set { project.file(path) }
|
||||
}
|
||||
|
||||
fun executable(provider: () -> File) {
|
||||
executableProperty.set(provider)
|
||||
}
|
||||
|
||||
fun executable(provider: Closure<File>) {
|
||||
executableProperty.set(project.provider(provider))
|
||||
}
|
||||
|
||||
fun environment(name: String, value: Any) {
|
||||
processOptions.environment(name, value)
|
||||
}
|
||||
|
||||
override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
|
||||
val extendedForkOptions = DefaultProcessForkOptions(fileResolver)
|
||||
processOptions.copyTo(extendedForkOptions)
|
||||
extendedForkOptions.executable = executable.absolutePath
|
||||
|
||||
val clientSettings = TCServiceMessagesClientSettings(
|
||||
name,
|
||||
@@ -53,7 +87,7 @@ open class KotlinNativeTest : KotlinTest() {
|
||||
stackTraceParser = ::parseKotlinNativeStackTraceAsJvm
|
||||
)
|
||||
|
||||
val cliArgs = CliArgs("TEAMCITY", includePatterns, excludePatterns)
|
||||
val cliArgs = CliArgs("TEAMCITY", includePatterns, excludePatterns, args)
|
||||
|
||||
return TCServiceMessagesTestExecutionSpec(
|
||||
extendedForkOptions,
|
||||
@@ -66,7 +100,8 @@ open class KotlinNativeTest : KotlinTest() {
|
||||
private class CliArgs(
|
||||
val testLogger: String? = null,
|
||||
val testGradleFilter: Set<String> = setOf(),
|
||||
val testNegativeGradleFilter: Set<String> = setOf()
|
||||
val testNegativeGradleFilter: Set<String> = setOf(),
|
||||
val userArgs: List<String> = emptyList()
|
||||
) {
|
||||
fun toList() = mutableListOf<String>().also {
|
||||
if (testLogger != null) {
|
||||
@@ -80,6 +115,8 @@ open class KotlinNativeTest : KotlinTest() {
|
||||
if (testNegativeGradleFilter.isNotEmpty()) {
|
||||
it.add("--ktest_negative_gradle_filter=${testNegativeGradleFilter.joinToString(",")}")
|
||||
}
|
||||
|
||||
it.addAll(userArgs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user