1 /*
2 * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
3 */
4
5 package kotlinx.coroutines.test
6
7 import kotlinx.atomicfu.*
8 import kotlin.test.*
9 import kotlin.time.*
10 import kotlin.time.Duration.Companion.seconds
11
12 /**
13 * The number of milliseconds that is sure not to pass [assertRunsFast].
14 */
15 const val SLOW = 100_000L
16
17 /**
18 * Asserts that a block completed within [timeout].
19 */
20 @OptIn(ExperimentalTime::class)
assertRunsFastnull21 inline fun <T> assertRunsFast(timeout: Duration, block: () -> T): T {
22 val result: T
23 val elapsed = TimeSource.Monotonic.measureTime { result = block() }
24 assertTrue("Should complete in $timeout, but took $elapsed") { elapsed < timeout }
25 return result
26 }
27
28 /**
29 * Asserts that a block completed within two seconds.
30 */
assertRunsFastnull31 inline fun <T> assertRunsFast(block: () -> T): T = assertRunsFast(2.seconds, block)
32
33 /**
34 * Runs [test], and then invokes [block], passing to it the lambda that functionally behaves
35 * the same way [test] does.
36 */
37 fun testResultMap(block: (() -> Unit) -> Unit, test: () -> TestResult): TestResult = testResultChain(
38 block = test,
39 after = {
40 block { it.getOrThrow() }
41 createTestResult { }
42 }
43 )
44
45 /**
46 * Chains together [block] and [after], passing the result of [block] to [after].
47 */
testResultChainnull48 expect fun testResultChain(block: () -> TestResult, after: (Result<Unit>) -> TestResult): TestResult
49
50 fun testResultChain(vararg chained: (Result<Unit>) -> TestResult): TestResult =
51 if (chained.isEmpty()) {
52 createTestResult { }
53 } else {
<lambda>null54 testResultChain(block = {
55 chained[0](Result.success(Unit))
56 }) {
57 testResultChain(*chained.drop(1).toTypedArray())
58 }
59 }
60
61 class TestException(message: String? = null): Exception(message)
62
63 /**
64 * A class inheriting from which allows to check the execution order inside tests.
65 *
66 * @see TestBase
67 */
68 open class OrderedExecutionTestBase {
69 private val actionIndex = atomic(0)
70 private val finished = atomic(false)
71
72 /** Expect the next action to be [index] in order. */
expectnull73 protected fun expect(index: Int) {
74 val wasIndex = actionIndex.incrementAndGet()
75 check(index == wasIndex) { "Expecting action index $index but it is actually $wasIndex" }
76 }
77
78 /** Expect this action to be final, with the given [index]. */
finishnull79 protected fun finish(index: Int) {
80 expect(index)
81 check(!finished.getAndSet(true)) { "Should call 'finish(...)' at most once" }
82 }
83
84 @AfterTest
ensureFinishCallsnull85 fun ensureFinishCalls() {
86 assertTrue(finished.value || actionIndex.value == 0, "Expected `finish` to be called")
87 }
88 }
89
voidnull90 internal fun <T> T.void() { }
91
92 @OptionalExpectation
93 expect annotation class NoJs()
94
95 @OptionalExpectation
96 expect annotation class NoNative()
97