xref: /aosp_15_r20/external/kotlinx.coroutines/test-utils/wasmJs/src/TestBase.kt (revision 7a7160fed73afa6648ef8aa100d4a336fe921d9a)

<lambda>null1 package kotlinx.coroutines.testing
2 
3 import kotlin.test.*
4 import kotlin.js.*
5 import kotlinx.coroutines.*
6 
7 actual val VERBOSE = false
8 
9 actual typealias NoJs = Ignore
10 
11 actual val isStressTest: Boolean = false
12 actual val stressTestMultiplier: Int = 1
13 actual val stressTestMultiplierSqrt: Int = 1
14 
15 @Suppress("ACTUAL_WITHOUT_EXPECT", "ACTUAL_TYPE_ALIAS_TO_CLASS_WITH_DECLARATION_SITE_VARIANCE")
16 actual typealias TestResult = Promise<JsAny?>
17 
18 internal actual fun lastResortReportException(error: Throwable) {
19     println(error)
20 }
21 
22 actual open class TestBase(
23     private val errorCatching: ErrorCatching.Impl
24 ): OrderedExecutionTestBase(), ErrorCatching by errorCatching {
25     private var lastTestPromise: Promise<JsAny?>? = null
26 
27     actual constructor(): this(errorCatching = ErrorCatching.Impl())
28 
printlnnull29     actual fun println(message: Any?) {
30         kotlin.io.println(message)
31     }
32 
runTestnull33     actual fun runTest(
34         expected: ((Throwable) -> Boolean)?,
35         unhandled: List<(Throwable) -> Boolean>,
36         block: suspend CoroutineScope.() -> Unit
37     ): TestResult {
38         var exCount = 0
39         var ex: Throwable? = null
40         /*
41          * This is an additional sanity check against `runTest` mis-usage on JS.
42          * The only way to write an async test on JS is to return Promise from the test function.
43          * _Just_ launching promise and returning `Unit` won't suffice as the underlying test framework
44          * won't be able to detect an asynchronous failure in a timely manner.
45          * We cannot detect such situations, but we can detect the most common erroneous pattern
46          * in our code base, an attempt to use multiple `runTest` in the same `@Test` method,
47          * which typically is a premise to the same error:
48          * ```
49          * @Test
50          * fun incorrectTestForJs() { // <- promise is not returned
51          *     for (parameter in parameters) {
52          *         runTest {
53          *             runTestForParameter(parameter)
54          *         }
55          *     }
56          * }
57          * ```
58          */
59         if (lastTestPromise != null) {
60             error("Attempt to run multiple asynchronous test within one @Test method")
61         }
62         val result = GlobalScope.promise(block = block, context = CoroutineExceptionHandler { _, e ->
63             if (e is CancellationException) return@CoroutineExceptionHandler // are ignored
64             exCount++
65             when {
66                 exCount > unhandled.size ->
67                     error("Too many unhandled exceptions $exCount, expected ${unhandled.size}, got: $e", e)
68                 !unhandled[exCount - 1](e) ->
69                     error("Unhandled exception was unexpected: $e", e)
70             }
71         }).catch { jsE ->
72             val e = jsE.toThrowableOrNull() ?: error("Unexpected non-Kotlin exception $jsE")
73             ex = e
74             if (expected != null) {
75                 if (!expected(e)) {
76                     println(e)
77                     error("Unexpected exception $e", e)
78                 }
79             } else
80                 throw e
81             null
82         }.finally {
83             if (ex == null && expected != null) error("Exception was expected but none produced")
84             if (exCount < unhandled.size)
85                 error("Too few unhandled exceptions $exCount, expected ${unhandled.size}")
86             errorCatching.close()
87             checkFinishCall()
88         }
89         lastTestPromise = result
90         return result
91     }
92 }
93 
94 actual val isNative = false
95 
96 actual val isBoundByJsTestTimeout = true
97 
98 actual val isJavaAndWindows: Boolean get() = false
99