All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest.kt Maven / Gradle / Ivy
/*
* Copyright 2010-2020 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.jetbrains.kotlin.gradle.targets.native.tasks
import groovy.lang.Closure
import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.gradle.api.tasks.options.Option
import org.gradle.process.ProcessForkOptions
import org.gradle.process.internal.DefaultProcessForkOptions
import org.jetbrains.kotlin.compilerRunner.konanVersion
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesClientSettings
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutionSpec
import org.jetbrains.kotlin.gradle.internal.testing.TCServiceMessagesTestExecutor.Companion.TC_PROJECT_PROPERTY
import org.jetbrains.kotlin.gradle.plugin.mpp.isAtLeast
import org.jetbrains.kotlin.gradle.targets.native.internal.parseKotlinNativeStackTraceAsJvm
import org.jetbrains.kotlin.gradle.tasks.KotlinTest
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
import java.io.File
import java.util.concurrent.Callable
abstract class KotlinNativeTest : KotlinTest() {
@Suppress("LeakingThis")
private val processOptions: ProcessForkOptions = DefaultProcessForkOptions(fileResolver)
@get:Internal
val executableProperty: Property = project.objects.property(FileCollection::class.java)
@get:PathSensitive(PathSensitivity.ABSOLUTE)
@get:IgnoreEmptyDirectories
@get:InputFiles // use FileCollection & @InputFiles rather than @InputFile to allow for task dependencies built-into this FileCollection
@get:SkipWhenEmpty
@Suppress("UNUSED") // Gradle input
internal val executableFiles: FileCollection // Gradle < 5.0 seems to not work properly with @InputFiles Property
get() = executableProperty.get()
private val executableFile
get() = executableProperty.get().singleFile
init {
onlyIf { executableFile.exists() }
}
@Input
var args: List = emptyList()
// Already taken into account in the executableProperty.
@get:Internal
var executable: File
get() = executableProperty.get().singleFile
set(value) {
executableProperty.set(project.files(value))
}
@get:Input
var workingDir: String
get() = processOptions.workingDir.canonicalPath
set(value) {
processOptions.workingDir = File(value)
}
@get:Internal
var environment: Map
get() = processOptions.environment
set(value) {
processOptions.environment = value
}
private val trackedEnvironmentVariablesKeys = mutableSetOf()
@Suppress("unused")
@get:Input
val trackedEnvironment
get() = environment.filterKeys(trackedEnvironmentVariablesKeys::contains)
private fun Property.set(providerLambda: () -> T) = set(project.provider { providerLambda() })
fun executable(file: File) {
executableProperty.set(project.files(file))
}
fun executable(path: String) {
executableProperty.set { project.files(path) }
}
fun executable(provider: () -> File) {
executableProperty.set(project.files(Callable { provider() }))
}
fun executable(builtByTask: Task, provider: () -> File) {
executableProperty.set(project.files(Callable { provider() }).builtBy(builtByTask))
}
fun executable(provider: Provider) {
executableProperty.set(provider.map { project.files(it) })
}
fun executable(provider: Closure) {
executableProperty.set(project.provider(provider).map { project.files(it) })
}
@JvmOverloads
fun environment(name: String, value: Any, tracked: Boolean = true) {
processOptions.environment(name, value)
if (tracked) {
trackedEnvironmentVariablesKeys.add(name)
}
}
@JvmOverloads
fun trackEnvironment(name: String, tracked: Boolean = true) {
if (tracked) {
trackedEnvironmentVariablesKeys.add(name)
} else {
trackedEnvironmentVariablesKeys.remove(name)
}
}
@get:Internal
protected abstract val testCommand: TestCommand
override fun createTestExecutionSpec(): TCServiceMessagesTestExecutionSpec {
val extendedForkOptions = DefaultProcessForkOptions(fileResolver)
processOptions.copyTo(extendedForkOptions)
extendedForkOptions.executable = testCommand.executable
val clientSettings = TCServiceMessagesClientSettings(
name,
testNameSuffix = targetName,
prependSuiteName = targetName != null,
treatFailedTestOutputAsStacktrace = false,
stackTraceParser = ::parseKotlinNativeStackTraceAsJvm,
escapeTCMessagesInLog = if (isConfigurationCacheAvailable(project.gradle)) {
project.providers.gradleProperty(TC_PROJECT_PROPERTY).forUseAtConfigurationTime().isPresent
} else {
project.hasProperty(TC_PROJECT_PROPERTY)
}
)
// The KotlinTest expects that the exit code is zero even if some tests failed.
// In this case it can check exit code and distinguish test failures from crashes.
// But K/N allows forcing a zero exit code only since 1.3 (which was included in Kotlin 1.3.40).
// Thus we check the exit code only for newer versions.
val checkExitCode = project.konanVersion.isAtLeast(1, 3, 0)
val cliArgs = testCommand.cliArgs("TEAMCITY", checkExitCode, includePatterns, excludePatterns, args)
return TCServiceMessagesTestExecutionSpec(extendedForkOptions, cliArgs, checkExitCode, clientSettings)
}
protected abstract class TestCommand() {
abstract val executable: String
abstract fun cliArgs(
testLogger: String?,
checkExitCode: Boolean,
testGradleFilter: Set,
testNegativeGradleFilter: Set,
userArgs: List
): List
protected fun testArgs(
testLogger: String?,
checkExitCode: Boolean,
testGradleFilter: Set,
testNegativeGradleFilter: Set,
userArgs: List
): List = mutableListOf().also {
// during debug from IDE executable is switched and special arguments are added
// via Gradle task manipulation; these arguments are expected to precede test settings
it.addAll(userArgs)
if (checkExitCode) {
// Avoid returning a non-zero exit code in case of failed tests.
it.add("--ktest_no_exit_code")
}
if (testLogger != null) {
it.add("--ktest_logger=$testLogger")
}
if (testGradleFilter.isNotEmpty()) {
it.add("--ktest_gradle_filter=${testGradleFilter.joinToString(",")}")
}
if (testNegativeGradleFilter.isNotEmpty()) {
it.add("--ktest_negative_gradle_filter=${testNegativeGradleFilter.joinToString(",")}")
}
}
}
}
/**
* A task running Kotlin/Native tests on a host machine.
*/
open class KotlinNativeHostTest : KotlinNativeTest() {
@get:Internal
override val testCommand: TestCommand = object : TestCommand() {
override val executable: String
get() = [email protected]
override fun cliArgs(
testLogger: String?,
checkExitCode: Boolean,
testGradleFilter: Set,
testNegativeGradleFilter: Set,
userArgs: List
): List = testArgs(testLogger, checkExitCode, testGradleFilter, testNegativeGradleFilter, userArgs)
}
}
/**
* A task running Kotlin/Native tests on a simulator (iOS/watchOS/tvOS).
*/
open class KotlinNativeSimulatorTest : KotlinNativeTest() {
@Input
@Option(option = "device", description = "Sets a simulated device used to execute tests.")
lateinit var deviceId: String
@Internal
var debugMode = false
@get:Internal
override val testCommand: TestCommand = object : TestCommand() {
override val executable: String
get() = "/usr/bin/xcrun"
override fun cliArgs(
testLogger: String?,
checkExitCode: Boolean,
testGradleFilter: Set,
testNegativeGradleFilter: Set,
userArgs: List
): List =
listOfNotNull(
"simctl",
"spawn",
"--wait-for-debugger".takeIf { debugMode },
"--standalone",
deviceId,
[email protected] ,
"--"
) +
testArgs(testLogger, checkExitCode, testGradleFilter, testNegativeGradleFilter, userArgs)
}
}