blob: 5cde77af7241d9346c1cc01ab86a9dfb354b5356 [file] [log] [blame] [edit]
import com.github.gradle.node.npm.task.NpmTask
import com.github.gradle.node.variant.computeNodeExec
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.ideaExt.idea
import org.apache.tools.ant.filters.FixCrLfFilter
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import java.util.Properties
plugins {
kotlin("jvm")
kotlin("plugin.serialization")
id("jps-compatible")
id("com.github.node-gradle.node") version "5.0.0"
}
val nodeDir = buildDir.resolve("node")
val cacheRedirectorEnabled = findProperty("cacheRedirectorEnabled")?.toString()?.toBoolean() == true
node {
download.set(true)
version.set(nodejsVersion)
nodeProjectDir.set(nodeDir)
if (cacheRedirectorEnabled) {
distBaseUrl.set("https://cache-redirector.jetbrains.com/nodejs.org/dist")
}
}
val antLauncherJar by configurations.creating
val testJsRuntime by configurations.creating {
attributes {
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.LIBRARY))
attribute(Usage.USAGE_ATTRIBUTE, objects.named(KotlinUsages.KOTLIN_RUNTIME))
attribute(KotlinPlatformType.attribute, KotlinPlatformType.js)
attribute(KotlinJsCompilerAttribute.jsCompilerAttribute, KotlinJsCompilerAttribute.ir)
}
}
dependencies {
testApi(platform(libs.junit.bom))
testImplementation(libs.junit.jupiter.api)
testRuntimeOnly(libs.junit.jupiter.engine)
testRuntimeOnly(libs.junit.vintage.engine)
testApi(protobufFull())
testApi(projectTests(":compiler:tests-common"))
testApi(projectTests(":compiler:test-infrastructure"))
testApi(projectTests(":compiler:test-infrastructure-utils"))
testApi(projectTests(":compiler:tests-compiler-utils"))
testApi(projectTests(":compiler:tests-common-new"))
testImplementation(projectTests(":compiler:fir:analysis-tests"))
testCompileOnly(project(":compiler:frontend"))
testCompileOnly(project(":compiler:cli"))
testCompileOnly(project(":compiler:cli-js"))
testCompileOnly(project(":compiler:util"))
testCompileOnly(intellijCore())
testApi(project(":compiler:backend.js"))
testApi(project(":js:js.translator"))
testApi(project(":js:js.serializer"))
testApi(project(":js:js.dce"))
testApi(project(":js:js.engines"))
testApi(project(":compiler:incremental-compilation-impl"))
testImplementation(libs.junit4)
testApi(projectTests(":kotlin-build-common"))
testApi(projectTests(":generators:test-generator"))
testApi(intellijCore())
testApi(project(":compiler:frontend"))
testApi(project(":compiler:cli"))
testApi(project(":compiler:util"))
testRuntimeOnly(commonDependency("org.jetbrains.intellij.deps:trove4j"))
testRuntimeOnly(libs.guava)
testRuntimeOnly(commonDependency("org.jetbrains.intellij.deps:jdom"))
testRuntimeOnly(kotlinStdlib())
testJsRuntime(kotlinStdlib())
if (!kotlinBuildProperties.isInJpsBuildIdeaSync) {
testJsRuntime(project(":kotlin-test:kotlin-test-js-ir")) // to be sure that kotlin-test-js built before tests run
}
testRuntimeOnly(project(":kotlin-preloader")) // it's required for ant tests
testRuntimeOnly(project(":compiler:backend-common"))
testRuntimeOnly(commonDependency("org.fusesource.jansi", "jansi"))
antLauncherJar(commonDependency("org.apache.ant", "ant"))
antLauncherJar(toolsJar())
testRuntimeOnly(libs.junit.vintage.engine)
testImplementation(commonDependency("org.jetbrains.kotlinx", "kotlinx-serialization-json"))
testImplementation(libs.ktor.client.cio)
testImplementation(libs.ktor.client.core)
testImplementation(libs.ktor.client.websockets)
}
val generationRoot = projectDir.resolve("tests-gen")
useD8Plugin()
optInToExperimentalCompilerApi()
sourceSets {
"main" { }
"test" {
projectDefault()
this.java.srcDir(generationRoot.name)
}
}
if (kotlinBuildProperties.isInJpsBuildIdeaSync) {
apply(plugin = "idea")
idea {
this.module.generatedSourceDirs.add(generationRoot)
}
}
abstract class MochaTestTask : NpmTask(), VerificationTask
val testDataDir = project(":js:js.translator").projectDir.resolve("testData")
val typescriptTestsDir = testDataDir.resolve("typescript-export")
val installTsDependencies by task<NpmTask> {
val packageLockFile = testDataDir.resolve("package-lock.json")
inputs.file(testDataDir.resolve("package.json"))
outputs.file(packageLockFile)
outputs.upToDateWhen { testDataDir.resolve("node_modules").exists() }
workingDir.set(testDataDir)
args.set(listOf("install"))
}
fun parallel(tasksToRun: List<TaskProvider<*>>, beforeAll: TaskProvider<*>? = null, afterAll: TaskProvider<*>? = null): RegisteringDomainObjectDelegateProviderWithAction<out TaskContainer, Task> {
return tasks.registering {
tasksToRun.forEach { dependsOn(it) }
if (afterAll != null) {
finalizedBy(afterAll)
}
}.apply {
if (beforeAll != null) {
tasksToRun.forEach {
it.configure {
dependsOn(beforeAll)
}
}
}
}
}
val exportFileDirPostfix = "-in-exported-file"
fun generateJsExportOnFileTestFor(dir: String): TaskProvider<Copy> = tasks.register<Copy>("generate-js-export-on-file-for-$dir") {
val dirPostfix = exportFileDirPostfix
val inputDir = fileTree(typescriptTestsDir.resolve(dir))
val outputDir = typescriptTestsDir.resolve("$dir$dirPostfix")
inputs.files(inputDir.matching {
include("**/*.kt")
include("**/*.ts")
include("**/tsconfig.json")
})
outputs.dir(outputDir)
from(inputDir) {
include("**/*.kt")
include("**/*.ts")
include("**/tsconfig.json")
}
eachFile {
var isFirstLine = true
filter {
when {
isFirstLine && name.endsWith(".kt") -> "/** This file is generated by {@link :js:js.test:generateTypeScriptJsExportOnFileTests} task. DO NOT MODIFY MANUALLY */\n\n$it"
.also { isFirstLine = false }
it.contains("// FILE") -> "$it\n\n@file:JsExport"
else -> it.replace("@JsExport(?!.)".toRegex(), "")
}
}
filter(
FixCrLfFilter::class,
"eol" to FixCrLfFilter.CrLf.newInstance("lf"),
"fixlast" to false
)
}
into(outputDir)
}
fun generateTypeScriptTestFor(dir: String): TaskProvider<NpmTask> = tasks.register<NpmTask>("generate-ts-for-$dir") {
val baseDir = typescriptTestsDir.resolve(dir)
val mainTsFile = fileTree(baseDir).files.find { it.name.endsWith("__main.ts") } ?: return@register
val mainJsFile = baseDir.resolve("${mainTsFile.nameWithoutExtension}.js")
workingDir.set(testDataDir)
inputs.file(mainTsFile)
outputs.file(mainJsFile)
outputs.upToDateWhen { mainJsFile.exists() }
args.set(listOf("run", "generateTypeScriptTests", "--", "./typescript-export/$dir/tsconfig.json"))
}
val generateTypeScriptTests by parallel(
beforeAll = installTsDependencies,
tasksToRun = typescriptTestsDir.listFiles { it: File ->
it.isDirectory &&
!it.path.endsWith("module-systems") &&
!it.path.endsWith("module-systems-in-exported-file")
}
.map { generateTypeScriptTestFor(it.name) }
)
val generateTypeScriptJsExportOnFileTests by parallel(
typescriptTestsDir
.listFiles { it: File ->
it.isDirectory &&
!it.path.endsWith("selective-export") &&
!it.path.endsWith("implicit-export") &&
!it.path.endsWith("inheritance") &&
!it.path.endsWith("strict-implicit-export") &&
!it.path.endsWith("private-primary-constructor") &&
!it.path.endsWith(exportFileDirPostfix)
}
.map { generateJsExportOnFileTestFor(it.name) }
)
fun Test.setupNodeJs() {
systemProperty("javascript.engine.path.NodeJs", com.github.gradle.node.variant.VariantComputer()
.let { variantComputer ->
computeNodeExec(node, variantComputer.computeNodeBinDir(node.computedNodeDir)).get()
}
)
}
fun Test.setUpJsBoxTests(jsEnabled: Boolean, jsIrEnabled: Boolean, firEnabled: Boolean, es6Enabled: Boolean) {
setupV8()
if (jsIrEnabled) {
setupNodeJs()
dependsOn(npmInstall)
}
inputs.files(rootDir.resolve("js/js.engines/src/org/jetbrains/kotlin/js/engine/repl.js"))
dependsOn(":dist")
dependsOn(generateTypeScriptTests)
if (jsEnabled) {
dependsOn(testJsRuntime)
inputs.files(testJsRuntime)
}
if (jsIrEnabled) {
dependsOn(":kotlin-stdlib:jsJar")
systemProperty("kotlin.js.full.stdlib.path", "libraries/stdlib/build/classes/kotlin/js/main")
inputs.dir(rootDir.resolve("libraries/stdlib/build/classes/kotlin/js/main"))
systemProperty("kotlin.js.stdlib.klib.path", "libraries/stdlib/build/libs/kotlin-stdlib-js-$version.klib")
inputs.file(rootDir.resolve("libraries/stdlib/build/libs/kotlin-stdlib-js-$version.klib"))
dependsOn(":kotlin-stdlib-js-ir-minimal-for-test:compileKotlinJs")
systemProperty("kotlin.js.reduced.stdlib.path", "libraries/stdlib/js-ir-minimal-for-test/build/classes/kotlin/js/main")
inputs.dir(rootDir.resolve("libraries/stdlib/js-ir-minimal-for-test/build/classes/kotlin/js/main"))
dependsOn(":kotlin-test:kotlin-test-js-ir:compileKotlinJs")
systemProperty("kotlin.js.kotlin.test.path", "libraries/kotlin.test/js-ir/build/classes/kotlin/js/main")
inputs.dir(rootDir.resolve("libraries/kotlin.test/js-ir/build/classes/kotlin/js/main"))
systemProperty("kotlin.js.kotlin.test.klib.path", "libraries/kotlin.test/js-ir/build/libs/kotlin-test-js-$version.klib")
inputs.file(rootDir.resolve("libraries/kotlin.test/js-ir/build/libs/kotlin-test-js-$version.klib"))
}
exclude("org/jetbrains/kotlin/js/testOld/api/*")
if (jsEnabled && !jsIrEnabled) {
include("org/jetbrains/kotlin/integration/AntTaskJsTest.class")
include("org/jetbrains/kotlin/js/testOld/*")
include("org/jetbrains/kotlin/js/testOld/ast/*")
include("org/jetbrains/kotlin/js/testOld/optimizer/*")
include("org/jetbrains/kotlin/js/test/*")
}
if (!jsEnabled) {
when {
firEnabled && !es6Enabled -> {
include("org/jetbrains/kotlin/js/test/fir/*")
exclude("org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.class")
exclude("org/jetbrains/kotlin/js/test/fir/FirJsES6CodegenBoxTestGenerated.class")
exclude("org/jetbrains/kotlin/js/test/fir/FirJsES6CodegenInlineTestGenerated.class")
exclude("org/jetbrains/kotlin/js/test/fir/FirJsES6CodegenBoxErrorTestGenerated.class")
exclude("org/jetbrains/kotlin/js/test/fir/FirJsES6CodegenWasmJsInteropTestGenerated.class")
}
es6Enabled -> {
if (firEnabled) {
include("org/jetbrains/kotlin/js/test/fir/FirJsES6BoxTestGenerated.class")
include("org/jetbrains/kotlin/js/test/fir/FirJsES6CodegenBoxTestGenerated.class")
include("org/jetbrains/kotlin/js/test/fir/FirJsES6CodegenInlineTestGenerated.class")
include("org/jetbrains/kotlin/js/test/fir/FirJsES6CodegenBoxErrorTestGenerated.class")
include("org/jetbrains/kotlin/js/test/fir/FirJsES6CodegenWasmJsInteropTestGenerated.class")
} else {
include("org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.class")
include("org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.class")
include("org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenInlineTestGenerated.class")
include("org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxErrorTestGenerated.class")
include("org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.class")
}
}
else -> {
include("org/jetbrains/kotlin/js/test/ir/*")
include("org/jetbrains/kotlin/incremental/*")
include("org/jetbrains/kotlin/js/testOld/compatibility/binary/JsKlibBinaryCompatibilityTestGenerated.class")
include("org/jetbrains/kotlin/benchmarks/GenerateIrRuntime.class")
include("org/jetbrains/kotlin/integration/JsIrAnalysisHandlerExtensionTest.class")
exclude("org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.class")
exclude("org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxTestGenerated.class")
exclude("org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenInlineTestGenerated.class")
exclude("org/jetbrains/kotlin/js/test/ir/IrJsES6CodegenBoxErrorTestGenerated.class")
exclude("org/jetbrains/kotlin/incremental/JsIrES6InvalidationTestGenerated.class")
}
}
}
jvmArgs("-da:jdk.nashorn.internal.runtime.RecompilableScriptFunctionData") // Disable assertion which fails due to a bug in nashorn (KT-23637)
setUpBoxTests()
}
fun Test.forwardProperties() {
val rootLocalProperties = Properties().apply {
rootProject.file("local.properties").takeIf { it.isFile }?.inputStream()?.use {
load(it)
}
}
val allProperties = properties + rootLocalProperties
val prefixForPropertiesToForward = "fd."
for ((key, value) in allProperties) {
if (key is String && key.startsWith(prefixForPropertiesToForward)) {
systemProperty(key.substring(prefixForPropertiesToForward.length), value!!)
}
}
}
fun Test.setUpBoxTests() {
workingDir = rootDir
dependsOn(antLauncherJar)
inputs.files(antLauncherJar)
val antLauncherJarPath = antLauncherJar.asPath
doFirst {
systemProperty("kotlin.ant.classpath", antLauncherJarPath)
systemProperty("kotlin.ant.launcher.class", "org.apache.tools.ant.Main")
}
systemProperty("kotlin.js.test.root.out.dir", "$nodeDir/")
systemProperty(
"overwrite.output", project.providers.gradleProperty("overwrite.output").orNull ?: "false"
)
forwardProperties()
}
val test = projectTest(jUnitMode = JUnitMode.JUnit5) {
setUpJsBoxTests(jsEnabled = true, jsIrEnabled = true, firEnabled = true, es6Enabled = true)
inputs.dir(rootDir.resolve("compiler/cli/cli-common/resources")) // compiler.xml
inputs.dir(testDataDir)
inputs.dir(rootDir.resolve("dist"))
inputs.dir(rootDir.resolve("compiler/testData"))
outputs.dir("$buildDir/out")
outputs.dir("$buildDir/out-min")
configureTestDistribution()
}
val jsTest = projectTest("jsTest", jUnitMode = JUnitMode.JUnit5) {
setUpJsBoxTests(jsEnabled = true, jsIrEnabled = false, firEnabled = false, es6Enabled = false)
useJUnitPlatform()
}
projectTest("jsIrTest", jUnitMode = JUnitMode.JUnit5) {
setUpJsBoxTests(jsEnabled = false, jsIrEnabled = true, firEnabled = false, es6Enabled = false)
useJUnitPlatform()
}
projectTest("jsIrES6Test", jUnitMode = JUnitMode.JUnit5) {
setUpJsBoxTests(jsEnabled = false, jsIrEnabled = true, firEnabled = false, es6Enabled = true)
useJUnitPlatform()
}
projectTest("jsFirTest", jUnitMode = JUnitMode.JUnit5) {
setUpJsBoxTests(jsEnabled = false, jsIrEnabled = true, firEnabled = true, es6Enabled = false)
useJUnitPlatform()
}
projectTest("jsFirES6Test", jUnitMode = JUnitMode.JUnit5) {
setUpJsBoxTests(jsEnabled = false, jsIrEnabled = true, firEnabled = true, es6Enabled = true)
useJUnitPlatform()
}
projectTest("quickTest", jUnitMode = JUnitMode.JUnit5) {
setUpJsBoxTests(jsEnabled = true, jsIrEnabled = false, firEnabled = false, es6Enabled = false)
systemProperty("kotlin.js.skipMinificationTest", "true")
useJUnitPlatform()
}
projectTest("jsStdlibApiTest", parallel = true, maxHeapSizeMb = 4096) {
setupV8()
setupNodeJs()
dependsOn(npmInstall)
dependsOn(":dist")
inputs.dir(rootDir.resolve("dist"))
include("org/jetbrains/kotlin/js/testOld/api/*")
inputs.dir(rootDir.resolve("libraries/stdlib/api/js"))
dependsOn(":kotlin-stdlib:jsJar")
systemProperty("kotlin.js.full.stdlib.path", "libraries/stdlib/build/classes/kotlin/js/main")
inputs.dir(rootDir.resolve("libraries/stdlib/build/classes/kotlin/js/main"))
setTestNameIncludePatterns(listOf("org.jetbrains.kotlin.js.testOld.api.ApiTest.*"))
setUpBoxTests()
}
testsJar {}
val generateTests by generator("org.jetbrains.kotlin.generators.tests.GenerateJsTestsKt") {
dependsOn(":compiler:generateTestData")
dependsOn(generateTypeScriptJsExportOnFileTests)
}
val testJsFile = testDataDir.resolve("test.js")
val packageJsonFile = testDataDir.resolve("package.json")
val prepareNpmTestData by task<Copy> {
inputs.files(testJsFile, packageJsonFile)
outputs.dir(nodeDir)
from(testJsFile)
from(packageJsonFile)
into(nodeDir)
}
val npmInstall by tasks.getting(NpmTask::class) {
val packageLockFile = testDataDir.resolve("package-lock.json")
inputs.file(nodeDir.resolve("package.json"))
outputs.file(packageLockFile)
outputs.upToDateWhen { packageLockFile.exists() }
workingDir.set(nodeDir)
dependsOn(prepareNpmTestData)
}
val mochaTest by task<MochaTestTask> {
workingDir.set(nodeDir)
val target = if (project.hasProperty("teamcity")) "runOnTeamcity" else "test"
args.set(listOf("run", target))
ignoreExitValue.set(kotlinBuildProperties.ignoreTestFailures)
dependsOn(npmInstall)
environment.set(
mapOf(
"KOTLIN_JS_LOCATION" to rootDir.resolve("dist/js/kotlin.js").toString(),
"KOTLIN_JS_TEST_LOCATION" to rootDir.resolve("dist/js/kotlin-test.js").toString(),
"BOX_FLAG_LOCATION" to rootDir.resolve("compiler/testData/jsBoxFlag.js").toString()
)
)
}
val runMocha by tasks.registering {
dependsOn(jsTest)
finalizedBy(mochaTest)
}
projectTest("invalidationTest", jUnitMode = JUnitMode.JUnit5) {
workingDir = rootDir
useJsIrBoxTests(version = version, buildDir = "$buildDir/")
include("org/jetbrains/kotlin/incremental/*")
dependsOn(":dist")
forwardProperties()
useJUnitPlatform()
}
tasks.named("check") {
dependsOn(runMocha)
}