[Wasm] Wasi kotlin.test implementation

This commit is contained in:
Igor Yakovlev
2023-07-31 14:28:54 +02:00
committed by Zalim Bashorov
parent 8cc0660693
commit 18a9c1916e
7 changed files with 193 additions and 77 deletions
@@ -0,0 +1,70 @@
/*
* 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.test.FrameworkAdapter
import kotlin.js.Promise
// Need to wrap into additional lambdas so that js launcher will work without Mocha or any other testing framework
private fun describe(name: String, fn: () -> Unit): Unit =
js("describe(name, fn)")
private fun xdescribe(name: String, fn: () -> Unit): Unit =
js("xdescribe(name, fn)")
private fun it(name: String, fn: () -> JsAny?): Unit =
js("it(name, fn)")
private fun xit(name: String, fn: () -> JsAny?): Unit =
js("xit(name, fn)")
private fun jsThrow(jsException: JsAny): Nothing =
js("{ throw jsException; }")
private fun throwableToJsError(message: String, stack: String): JsAny =
js("{ const e = new Error(); e.message = message; e.stack = stack; return e; }")
private fun Throwable.toJsError(): JsAny =
throwableToJsError(message ?: "", stackTraceToString())
/**
* [Jasmine](https://github.com/jasmine/jasmine) adapter.
* Also used for [Mocha](https://mochajs.org/) and [Jest](https://facebook.github.io/jest/).
*/
internal class JasmineLikeAdapter : FrameworkAdapter {
override fun suite(name: String, ignored: Boolean, suiteFn: () -> Unit) {
if (ignored) {
xdescribe(name, suiteFn)
} else {
describe(name, suiteFn)
}
}
private fun callTest(testFn: () -> Any?): JsAny? =
try {
(testFn() as? Promise<*>)?.catch { exception ->
val jsException = exception
.toThrowableOrNull()
?.toJsError()
?: exception
Promise.reject(jsException)
}
} catch (exception: Throwable) {
jsThrow(exception.toJsError())
}
override fun test(name: String, ignored: Boolean, testFn: () -> Any?) {
if (ignored) {
xit(name) {
callTest(testFn)
}
} else {
it(name) {
callTest(testFn)
}
}
}
}
@@ -0,0 +1,63 @@
/*
* Copyright 2010-2022 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.math.abs
import kotlin.js.*
// Using 'globalThis.arguments' because 'arguments' can refer to current JS function arguments
@JsFun("() => globalThis.arguments?.join?.(' ') ?? ''")
private external fun d8Arguments(): String
@JsFun("() => (typeof process != 'undefined' && typeof process.argv != 'undefined') ? process.argv.slice(2).join(' ') : ''")
private external fun nodeArguments(): String
internal fun getArguments(): List<String> = (d8Arguments().ifEmpty { nodeArguments() }).split(' ')
internal class TeamcityAdapterWithPromiseSupport : TeamcityAdapter() {
private var scheduleNextTaskAfter: Promise<JsAny?>? = null
override fun runOrScheduleNext(block: () -> Unit) {
if (scheduleNextTaskAfter == null) {
block()
} else {
scheduleNextTaskAfter = scheduleNextTaskAfter!!.finally(block)
}
}
override fun runOrScheduleNextWithResult(block: () -> Any?) {
val nextTask = scheduleNextTaskAfter
if (nextTask == null) {
val result = block()
if (result is Promise<JsAny?>)
scheduleNextTaskAfter = result
} else {
scheduleNextTaskAfter = nextTask.then {
block() as? Promise<JsAny?>
}
}
}
override fun tryProcessResult(result: Any?, name: String): Any? {
if (result == null) return null
if (result !is Promise<*>) return null
return result.then(
onFulfilled = { value ->
MessageType.Finished.report(name)
value
},
onRejected = { e ->
val throwable = e.toThrowableOrNull()
if (throwable != null) {
MessageType.Failed.report(name, throwable)
} else {
MessageType.Failed.report(name, e.toString())
}
MessageType.Finished.report(name)
null
}
)
}
}
@@ -0,0 +1,27 @@
/*
* 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
/**
* 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
}
internal var currentAdapter: FrameworkAdapter? = null
private fun isJasmine(): Boolean =
js("typeof describe === 'function' && typeof it === 'function'")
internal fun adapter(): FrameworkAdapter {
val result = currentAdapter ?: if (isJasmine()) JasmineLikeAdapter() else TeamcityAdapterWithPromiseSupport()
currentAdapter = result
return result
}