You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

171 lines
6.3 KiB

/*
* Copyright 2020-2022 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/
package org.jetbrains.compose.test.utils
import org.gradle.testkit.runner.BuildResult
import org.gradle.testkit.runner.GradleRunner
import org.gradle.util.GradleVersion
import org.jetbrains.compose.desktop.application.internal.ComposeProperties
import java.io.File
import java.util.Properties
data class TestEnvironment(
val workingDir: File,
val kotlinVersion: String = TestKotlinVersions.Default,
val agpVersion: String = "7.3.1",
val composeGradlePluginVersion: String = TestProperties.composeGradlePluginVersion,
val mokoResourcesPluginVersion: String = "0.23.0",
val composeCompilerPlugin: String? = null,
val composeCompilerArgs: String? = null,
val composeVerbose: Boolean = true,
val useGradleConfigurationCache: Boolean = TestProperties.gradleConfigurationCache,
val additionalEnvVars: Map<String, String> = mapOf()
) {
private val placeholders = linkedMapOf(
"COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER" to composeGradlePluginVersion,
"KOTLIN_VERSION_PLACEHOLDER" to kotlinVersion,
"AGP_VERSION_PLACEHOLDER" to agpVersion,
"COMPOSE_COMPILER_PLUGIN_PLACEHOLDER" to composeCompilerPlugin,
"COMPOSE_COMPILER_PLUGIN_ARGS_PLACEHOLDER" to composeCompilerArgs,
"MOKO_RESOURCES_PLUGIN_VERSION_PLACEHOLDER" to mokoResourcesPluginVersion,
)
fun replacePlaceholdersInFile(file: File) {
var content = file.readText()
for ((placeholder, value) in placeholders.entries) {
if (value != null) {
content = content.replace(placeholder, value)
}
}
file.writeText(content)
}
}
private val testJdks = TestProperties
.testJdksRoot?.let { listTestJdks(it) }.orEmpty()
class TestProject(
private val name: String,
private val testEnvironment: TestEnvironment
) {
private val testProjectsRootDir = File("src/test/test-projects")
private val additionalArgs = listOfNotNull(
"--stacktrace",
"--init-script", testProjectsRootDir.resolve("init.gradle").absolutePath,
"-P${ComposeProperties.VERBOSE}=${testEnvironment.composeVerbose}",
if (GradleVersion.version(TestProperties.gradleVersionForTests).baseVersion < GradleVersion.version("8.0")) {
null
} else {
"-Porg.gradle.java.installations.paths=${testJdks.joinToString(",")}"
}
)
init {
val originalTestRoot = testProjectsRootDir.resolve(name).also {
check(it.exists()) { "Test project is not found: ${it.absolutePath}" }
}
for (orig in originalTestRoot.walk()) {
if (!orig.isFile) continue
val target = testEnvironment.workingDir.resolve(orig.relativeTo(originalTestRoot))
target.parentFile.mkdirs()
orig.copyTo(target)
if (orig.name.endsWith(".gradle") || orig.name.endsWith(".gradle.kts")) {
testEnvironment.replacePlaceholdersInFile(target)
}
}
}
internal fun gradle(vararg args: String): BuildResult =
withGradleRunner(args) { build() }
internal fun gradleFailure(vararg args: String): BuildResult =
withGradleRunner(args) { buildAndFail() }
private inline fun withGradleRunner(args: Array<out String>, runnerFn: GradleRunner.() -> BuildResult): BuildResult {
if (testEnvironment.useGradleConfigurationCache) {
if (TestProperties.gradleBaseVersionForTests < GradleVersion.version("8.0")) {
// Gradle 7.* does not use the configuration cache in the same build.
// In other words, if cache misses, Gradle performs configuration,
// but does not, use the serialized task graph.
// So in order to test the cache, we need to perform dry-run before the actual run.
// This should be fixed in https://github.com/gradle/gradle/issues/21985 (which is planned for 8.0 RC 1)
gradleRunner(args.withDryRun()).runnerFn()
}
}
return gradleRunner(args).runnerFn()
}
private fun Array<out String>.withDryRun(): Array<String> {
var sawDryRun = false
val dryRunArgs = ArrayList<String>(size)
for (arg in this) {
sawDryRun = sawDryRun || arg.trim() in listOf("-m", "--dry-run")
dryRunArgs.add(arg)
}
if (!sawDryRun) {
dryRunArgs.add("--dry-run")
}
return dryRunArgs.toTypedArray()
}
private fun gradleRunner(args: Array<out String>): GradleRunner {
val allArgs = args.toMutableList()
allArgs.addAll(additionalArgs)
if (testEnvironment.useGradleConfigurationCache) {
allArgs.add("--configuration-cache")
}
return GradleRunner.create().apply {
withGradleVersion(TestProperties.gradleVersionForTests)
withProjectDir(testEnvironment.workingDir)
withArguments(allArgs)
if (testEnvironment.additionalEnvVars.isNotEmpty()) {
val newEnv = HashMap(System.getenv() + testEnvironment.additionalEnvVars)
withEnvironment(newEnv)
}
forwardOutput()
}
}
fun file(path: String): File =
testEnvironment.workingDir.resolve(path)
fun modifyText(path: String, fn: (String) -> String) {
val file = file(path)
val oldContent = file.readText()
val newContent = fn(oldContent)
file.writeText(newContent)
}
fun appendText(path: String, fn: () -> String) {
val file = file(path)
val oldContent = file.readText()
val newContent = oldContent + "\n" + fn()
file.writeText(newContent)
}
fun modifyGradleProperties(fn: Properties.() -> Unit) {
val propertiesFile = file("gradle.properties")
val properties = Properties()
if (propertiesFile.exists()) {
propertiesFile.bufferedReader().use { reader ->
properties.load(reader)
}
}
fn(properties)
propertiesFile.delete()
if (properties.isNotEmpty()) {
propertiesFile.bufferedWriter().use { writer ->
properties.store(writer, null)
}
}
}
}