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.
 
 
 
 

212 lines
6.6 KiB

import org.jetbrains.compose.gradle.standardConf
plugins {
kotlin("multiplatform")
id("org.jetbrains.compose")
}
kotlin {
js(IR) {
browser() {
testTask {
useKarma {
standardConf()
}
}
}
binaries.executable()
}
sourceSets {
val jsMain by getting {
dependencies {
implementation(project(":compose-compiler-integration-lib"))
implementation(kotlin("stdlib-js"))
implementation(compose.runtime)
implementation(project(":html-core"))
implementation(libs.kotlinx.coroutines.core)
}
}
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
}
}
fun cloneTemplate(templateName: String, contentMain: String, contentLib: String): File {
val tempDir = file("${project.buildDir.absolutePath}/temp/cloned-$templateName")
tempDir.deleteRecursively()
tempDir.mkdirs()
file("${projectDir.absolutePath}/main-template").copyRecursively(tempDir)
// tempDir.deleteOnExit()
File("$tempDir/src/commonMain/kotlin/Main.kt").printWriter().use { out ->
out.println(contentMain)
}
File("$tempDir/lib/src/commonMain/kotlin/Lib.kt").printWriter().use { out ->
out.println(contentLib)
}
return tempDir
}
fun build(
caseName: String,
directory: File,
failureExpected: Boolean = false,
composeVersion: String,
kotlinVersion: String,
vararg buildCmd: String = arrayOf("build", "jsNodeRun")
) {
val isWin = System.getProperty("os.name").startsWith("Win")
val arguments = buildCmd.toMutableList().also {
it.add("-Pcompose.version=$composeVersion")
it.add("-Pkotlin.version=$kotlinVersion")
}.toTypedArray()
val procBuilder = if (isWin) {
ProcessBuilder("gradlew.bat", *arguments)
} else {
ProcessBuilder("bash", "./gradlew", *arguments)
}
val proc = procBuilder
.directory(directory)
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
proc.waitFor(5, TimeUnit.MINUTES)
"(COMPOSE_INTEGRATION_VERSION=\\[.*\\])".toRegex().find(
proc.inputStream.bufferedReader().readText()
)?.also {
println(it.groupValues[1])
}
println(proc.errorStream.bufferedReader().readText())
if (proc.exitValue() != 0 && !failureExpected) {
throw GradleException("Error compiling $caseName")
}
if (failureExpected && proc.exitValue() == 0) {
throw AssertionError("$caseName compilation did not fail!!!")
}
}
data class RunChecksResult(
val cases: Map<String, Throwable?>
) {
val totalCount = cases.size
val failedCount = cases.filter { it.value != null }.size
val hasFailed = failedCount > 0
fun printResults() {
cases.forEach { (name, throwable) ->
println(name + " : " + (throwable ?: "OK"))
}
}
fun reportToTeamCity() {
cases.forEach { (caseName, error) ->
println("##teamcity[testStarted name='compileTestCase_$caseName']")
if (error != null) {
println("##teamcity[testFailed name='compileTestCase_$caseName']")
}
println("##teamcity[testFinished name='compileTestCase_$caseName']")
}
}
}
fun runCasesInDirectory(
dir: File,
filterPath: String,
expectCompilationError: Boolean,
composeVersion: String,
kotlinVersion: String
): RunChecksResult {
return dir.listFiles()!!.filter { it.absolutePath.contains(filterPath) }.mapIndexed { _, file ->
println("Running check for ${file.name}, expectCompilationError = $expectCompilationError, composeVersion = $composeVersion")
val contentLines = file.readLines()
val startMainLineIx = contentLines.indexOf("// @Module:Main").let { ix ->
if (ix == -1) 0 else ix + 1
}
val startLibLineIx = contentLines.indexOf("// @Module:Lib").let { ix ->
if (ix == -1) contentLines.size else ix - 1
}
require(startMainLineIx < startLibLineIx) {
"The convention is that @Module:Lib should go after @Module:Main"
}
val mainContent = contentLines.let { lines ->
val endLineIx = if (startLibLineIx < lines.size) startLibLineIx - 1 else lines.lastIndex
lines.slice(startMainLineIx..endLineIx).joinToString(separator = "\n")
}
val libContent = contentLines.let { lines ->
if (startLibLineIx < lines.size) {
lines.slice(startLibLineIx..lines.lastIndex)
} else {
emptyList()
}.joinToString(separator = "\n")
}
val caseName = file.name
val tmpDir = cloneTemplate(caseName, contentMain = mainContent, contentLib = libContent)
caseName to kotlin.runCatching {
build(
caseName = caseName,
directory = tmpDir,
failureExpected = expectCompilationError,
composeVersion = composeVersion,
kotlinVersion = kotlinVersion
)
}.exceptionOrNull()
}.let {
RunChecksResult(it.toMap())
}
}
tasks.register("checkComposeCases") {
doLast {
val filterCases = project.findProperty("FILTER_CASES")?.toString() ?: ""
val composeVersion = project.findProperty("compose.version")?.toString() ?: "0.0.0-SNASPHOT"
val kotlinVersion = kotlin.coreLibrariesVersion
val expectedFailingCasesDir = File("${projectDir.absolutePath}/testcases/failing")
val expectedFailingResult = runCasesInDirectory(
dir = expectedFailingCasesDir,
expectCompilationError = true,
filterPath = filterCases,
composeVersion = composeVersion,
kotlinVersion = kotlinVersion
)
val passingCasesDir = File("${projectDir.absolutePath}/testcases/passing")
val passingResult = runCasesInDirectory(
dir = passingCasesDir,
expectCompilationError = false,
filterPath = filterCases,
composeVersion = composeVersion,
kotlinVersion = kotlinVersion
)
expectedFailingResult.printResults()
expectedFailingResult.reportToTeamCity()
passingResult.printResults()
passingResult.reportToTeamCity()
if (expectedFailingResult.hasFailed || passingResult.hasFailed) {
error("There were failed cases. Check the logs above")
}
}
}