[Wasm] Add kotlin-test-wasm library

This commit is contained in:
Igor Laevsky
2021-10-01 21:36:36 +03:00
committed by TeamCityServer
parent 6ba65065ee
commit 14eee7c539
11 changed files with 414 additions and 12 deletions
-10
View File
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
</set>
</option>
</component>
</project>
+59
View File
@@ -55,6 +55,24 @@ val jsRuntimeVariant by configurations.creating {
extendsFrom(jsApiVariant)
}
val wasmApiVariant by configurations.creating {
isCanBeConsumed = true
isCanBeResolved = false
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-api"))
attribute(KotlinPlatformType.attribute, KotlinPlatformType.wasm)
}
}
val wasmRuntimeVariant by configurations.creating {
isCanBeConsumed = true
isCanBeResolved = false
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-runtime"))
attribute(KotlinPlatformType.attribute, KotlinPlatformType.wasm)
}
extendsFrom(wasmApiVariant)
}
val nativeApiVariant by configurations.creating {
isCanBeConsumed = true
isCanBeResolved = false
@@ -76,6 +94,7 @@ val commonVariant by configurations.creating {
dependencies {
jvmApi(project(":kotlin-stdlib"))
jsApiVariant("$group:kotlin-test-js:$version")
wasmApiVariant("$group:kotlin-test-wasm:$version")
commonVariant("$group:kotlin-test-common:$version")
commonVariant("$group:kotlin-test-annotations-common:$version")
}
@@ -114,6 +133,8 @@ val rootComponent = componentFactory.adhoc("root").apply {
}
addVariantsFromConfiguration(jsApiVariant) { mapToOptional() }
addVariantsFromConfiguration(jsRuntimeVariant) { mapToOptional() }
addVariantsFromConfiguration(wasmApiVariant) { mapToOptional() }
addVariantsFromConfiguration(wasmRuntimeVariant) { mapToOptional() }
addVariantsFromConfiguration(nativeApiVariant) { mapToOptional() }
addVariantsFromConfiguration(commonVariant) { mapToOptional() }
}
@@ -236,6 +257,38 @@ val jsComponent = componentFactory.adhoc("js").apply {
}
}
val (wasmApi, wasmRuntime) = listOf("api", "runtime").map { usage ->
configurations.create("wasm${usage.capitalize()}") {
isCanBeConsumed = true
isCanBeResolved = false
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named("kotlin-$usage"))
attribute(KotlinPlatformType.attribute, KotlinPlatformType.js)
}
}
}
wasmRuntime.extendsFrom(wasmApi)
dependencies {
wasmApi(project(":kotlin-stdlib-wasm"))
}
artifacts {
val wasmJar = tasks.getByPath(":kotlin-test:kotlin-test-wasm:jsJar")
add(wasmApi.name, wasmJar)
add(wasmRuntime.name, wasmJar)
}
val wasmComponent = componentFactory.adhoc("wasm").apply {
addVariantsFromConfiguration(wasmApi) {
mapToMavenScope("compile")
}
addVariantsFromConfiguration(wasmRuntime) {
mapToMavenScope("runtime")
}
}
val commonMetadata by configurations.creating {
isCanBeConsumed = true
isCanBeResolved = false
@@ -306,6 +359,12 @@ publishing {
artifact(tasks.getByPath(":kotlin-test:kotlin-test-js:sourcesJar") as Jar)
configureKotlinPomAttributes(project, "Kotlin Test for JS")
}
create("wasm", MavenPublication::class) {
artifactId = "kotlin-test-wasm"
from(wasmComponent)
// TODO: artifact(tasks.getByPath(":kotlin-test:kotlin-test-wasm:jsSourcesJar"))
configureKotlinPomAttributes(project, "Kotlin Test for WASM")
}
create("common", MavenPublication::class) {
artifactId = "kotlin-test-common"
from(commonMetadataComponent)
@@ -0,0 +1,64 @@
/*
* Copyright 2010-2021 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.
*/
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
plugins {
kotlin("multiplatform")
}
val commonMainSources by task<Sync> {
from(
"$rootDir/libraries/kotlin.test/common/src",
"$rootDir/libraries/kotlin.test/annotations-common/src"
)
into("$buildDir/commonMainSources")
}
//val commonTestSources by task<Sync> {
// from("$rootDir/libraries/kotlin.test/common/src/test/kotlin")
// into("$buildDir/commonTestSources")
//}
kotlin {
js(IR) {
nodejs()
}
sourceSets {
val commonMain by getting {
dependencies {
api(project(":kotlin-stdlib-wasm"))
}
kotlin.srcDir(commonMainSources.get().destinationDir)
}
// val commonTest by getting {
// kotlin.srcDir(commonTestSources.get().destinationDir)
// }
val jsMain by getting {
dependencies {
api(project(":kotlin-stdlib-wasm"))
}
kotlin.srcDir("$rootDir/libraries/kotlin.test/wasm/src")
}
}
}
tasks.withType<KotlinCompile<*>>().configureEach {
kotlinOptions.freeCompilerArgs += listOf(
"-Xallow-kotlin-package",
"-opt-in=kotlin.ExperimentalMultiplatform",
"-opt-in=kotlin.contracts.ExperimentalContracts"
)
}
tasks.named("compileKotlinJs") {
(this as KotlinCompile<*>).kotlinOptions.freeCompilerArgs += "-Xir-module-name=kotlin-test"
dependsOn(commonMainSources)
}
//tasks.named("compileTestKotlinJs") {
// dependsOn(commonTestSources)
//}
@@ -0,0 +1,30 @@
/*
* Copyright 2010-2021 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 kotlin.test
/**
* Marks a function as a test.
*/
@Target(AnnotationTarget.FUNCTION)
public actual annotation class Test
/**
* Marks a test or a suite as ignored.
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
public actual annotation class Ignore
/**
* Marks a function to be invoked before each test.
*/
@Target(AnnotationTarget.FUNCTION)
public actual annotation class BeforeTest
/**
* Marks a function to be invoked after each test.
*/
@Target(AnnotationTarget.FUNCTION)
public actual annotation class AfterTest
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2021 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 kotlin.test
/**
* A fallback adapter for the case when no framework is detected.
*/
internal open class BareAdapter : FrameworkAdapter {
override fun suite(name: String, ignored: Boolean, suiteFn: () -> Unit) {
if (!ignored) {
suiteFn()
}
}
override fun test(name: String, ignored: Boolean, testFn: () -> Any?) {
if (!ignored) {
testFn()
}
}
}
@@ -0,0 +1,98 @@
/*
* Copyright 2010-2021 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 kotlin.test
/**
* Describes the result of an assertion execution.
*/
public interface AssertionResult {
val result: Boolean
val expected: Any?
val actual: Any?
val lazyMessage: () -> String?
}
internal var assertHook: (AssertionResult) -> Unit = { _ -> }
internal object DefaultWasmAsserter : Asserter {
private var e: Any? = null
private var a: Any? = null
override fun assertEquals(message: String?, expected: Any?, actual: Any?) {
e = expected
a = actual
super.assertEquals(message, expected, actual)
}
override fun assertNotEquals(message: String?, illegal: Any?, actual: Any?) {
e = illegal
a = actual
super.assertNotEquals(message, illegal, actual)
}
override fun assertSame(message: String?, expected: Any?, actual: Any?) {
e = expected
a = actual
super.assertSame(message, expected, actual)
}
override fun assertNotSame(message: String?, illegal: Any?, actual: Any?) {
e = illegal
a = actual
super.assertNotSame(message, illegal, actual)
}
override fun assertNull(message: String?, actual: Any?) {
a = actual
super.assertNull(message, actual)
}
override fun assertNotNull(message: String?, actual: Any?) {
a = actual
super.assertNotNull(message, actual)
}
override fun assertTrue(lazyMessage: () -> String?, actual: Boolean) {
if (!actual) {
failWithMessage(lazyMessage, null)
} else {
invokeHook(true, lazyMessage)
}
}
override fun assertTrue(message: String?, actual: Boolean) {
assertTrue({ message }, actual)
}
override fun fail(message: String?): Nothing {
fail(message, null)
}
@SinceKotlin("1.4")
override fun fail(message: String?, cause: Throwable?): Nothing {
failWithMessage({ message }, cause)
}
private inline fun failWithMessage(lazyMessage: () -> String?, cause: Throwable?): Nothing {
val message = lazyMessage()
invokeHook(false) { message }
throw AssertionErrorWithCause(message, cause)
}
private fun invokeHook(result: Boolean, lazyMessage: () -> String?) {
try {
assertHook(object : AssertionResult {
override val result: Boolean = result
override val expected: Any? = e
override val actual: Any? = a
override val lazyMessage: () -> String? = lazyMessage
})
} finally {
e = null
a = null
}
}
}
@@ -0,0 +1,44 @@
/*
* Copyright 2010-2021 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 kotlin.test
/**
* Serves as a bridge to a testing framework.
*
* The tests structure is defined using internal functions suite and test, which delegate to corresponding functions of a [FrameworkAdapter].
* Sample test layout:
*
* ```
* suite('a suite', false, function() {
* suite('a subsuite', false, function() {
* test('a test', false, function() {...});
* test('an ignored/pending test', true, function() {...});
* });
* suite('an ignored/pending test', true, function() {...});
* });
* ```
*
*/
public interface FrameworkAdapter {
/**
* Declares a test suite.
*
* @param name the name of the test suite, e.g. a class name
* @param ignored whether the test suite is ignored, e.g. marked with [Ignore] annotation
* @param suiteFn defines nested suites by calling [kotlin.test.suite] and tests by calling [kotlin.test.test]
*/
fun suite(name: String, ignored: Boolean, suiteFn: () -> Unit)
/**
* Declares a test.
*
* @param name the test name.
* @param ignored whether the test is ignored
* @param testFn contains test body invocation
*/
fun test(name: String, ignored: Boolean, testFn: () -> Any?)
}
@@ -0,0 +1,46 @@
/*
* Copyright 2010-2021 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 kotlin.test
import kotlin.js.JsExport
/**
* Overrides current framework adapter with a provided instance of [FrameworkAdapter]. Use in order to support custom test frameworks.
*
* If this function is not called, the test framework will be detected automatically.
*
*/
internal fun setAdapter(adapter: FrameworkAdapter) {
currentAdapter = adapter
}
/**
* The functions below are used by the compiler to describe the tests structure, e.g.
*
* suite('a suite', false, function() {
* suite('a subsuite', false, function() {
* test('a test', false, function() {...});
* test('an ignored/pending test', true, function() {...});
* });
* suite('an ignored/pending test', true, function() {...});
* });
*/
internal fun suite(name: String, ignored: Boolean, suiteFn: () -> Unit) {
currentAdapter.suite(name, ignored, suiteFn)
}
internal fun test(name: String, ignored: Boolean, testFn: () -> Any?) {
currentAdapter.test(name, ignored, testFn)
}
internal var currentAdapter: FrameworkAdapter = BareAdapter()
// This is called from the js-launcher alongside wasm start function
@JsExport
internal fun startUnitTests() {
// This will be filled with the corresponding code during lowering
}
@@ -0,0 +1,45 @@
/*
* Copyright 2010-2021 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 kotlin.test
import kotlin.reflect.KClass
/**
* Takes the given [block] of test code and _doesn't_ execute it.
*
* This keeps the code under test referenced, but doesn't actually test it until it is implemented.
*/
actual fun todo(block: () -> Unit) {
println("TODO at " + block)
}
/** Platform-specific construction of AssertionError with cause */
@Suppress("NOTHING_TO_INLINE")
internal actual inline fun AssertionErrorWithCause(message: String?, cause: Throwable?): AssertionError =
AssertionError(message, cause)
@PublishedApi
internal actual fun <T : Throwable> checkResultIsFailure(exceptionClass: KClass<T>, message: String?, blockResult: Result<Unit>): T {
blockResult.fold(
onSuccess = {
asserter.fail(messagePrefix(message) + "Expected an exception of $exceptionClass to be thrown, but was completed successfully.")
},
onFailure = { e ->
if (exceptionClass.isInstance(e)) {
@Suppress("UNCHECKED_CAST")
return e as T
}
asserter.fail(messagePrefix(message) + "Expected an exception of $exceptionClass to be thrown, but was $e", e)
}
)
}
/**
* Provides the JS implementation of asserter
*/
internal actual fun lookupAsserter(): Asserter = DefaultWasmAsserter
@@ -66,7 +66,7 @@ public actual open class ClassCastException actual constructor(message: String?)
actual constructor() : this(null)
}
public actual open class AssertionError private constructor(message: String?, cause: Throwable?) : Error(message, cause) {
public actual open class AssertionError constructor(message: String?, cause: Throwable?) : Error(message, cause) {
actual constructor() : this(null)
constructor(message: String?) : this(message, null)
actual constructor(message: Any?) : this(message.toString(), message as? Throwable)
+3 -1
View File
@@ -500,7 +500,8 @@ if (buildProperties.inJpsBuildIdeaSync) {
":kotlin-test",
":kotlin-test:kotlin-test-js",
":kotlin-test:kotlin-test-js-ir",
":kotlin-test:kotlin-test-js:kotlin-test-js-it"
":kotlin-test:kotlin-test-js:kotlin-test-js-it",
":kotlin-test:kotlin-test-wasm"
project(':kotlin-stdlib-common').projectDir = "$rootDir/libraries/stdlib/common" as File
project(':kotlin-stdlib').projectDir = "$rootDir/libraries/stdlib/jvm" as File
@@ -520,6 +521,7 @@ if (buildProperties.inJpsBuildIdeaSync) {
project(':kotlin-test:kotlin-test-js').projectDir = "$rootDir/libraries/kotlin.test/js" as File
project(':kotlin-test:kotlin-test-js-ir').projectDir = "$rootDir/libraries/kotlin.test/js-ir" as File
project(':kotlin-test:kotlin-test-js:kotlin-test-js-it').projectDir = "$rootDir/libraries/kotlin.test/js/it" as File
project(':kotlin-test:kotlin-test-wasm').projectDir = "$rootDir/libraries/kotlin.test/wasm" as File
}
include ":compiler:android-tests"