• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 @file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED") // KT-21913
3 
4 package kotlinx.coroutines
5 
6 import kotlinx.coroutines.testing.*
7 import kotlinx.coroutines.channels.*
8 import kotlin.test.*
9 import kotlin.time.*
10 import kotlin.time.Duration.Companion.milliseconds
11 import kotlin.time.Duration.Companion.seconds
12 
13 class WithTimeoutOrNullDurationTest : TestBase() {
14     /**
15      * Tests a case of no timeout and no suspension inside.
16      */
17     @Test
<lambda>null18     fun testBasicNoSuspend() = runTest {
19         expect(1)
20         val result = withTimeoutOrNull(10.seconds) {
21             expect(2)
22             "OK"
23         }
24         assertEquals("OK", result)
25         finish(3)
26     }
27 
28     /**
29      * Tests a case of no timeout and one suspension inside.
30      */
31     @Test
<lambda>null32     fun testBasicSuspend() = runTest {
33         expect(1)
34         val result = withTimeoutOrNull(10.seconds) {
35             expect(2)
36             yield()
37             expect(3)
38             "OK"
39         }
40         assertEquals("OK", result)
41         finish(4)
42     }
43 
44     /**
45      * Tests property dispatching of `withTimeoutOrNull` blocks
46      */
47     @Test
<lambda>null48     fun testDispatch() = runTest {
49         expect(1)
50         launch {
51             expect(4)
52             yield() // back to main
53             expect(7)
54         }
55         expect(2)
56         // test that it does not yield to the above job when started
57         val result = withTimeoutOrNull(1.seconds) {
58             expect(3)
59             yield() // yield only now
60             expect(5)
61             "OK"
62         }
63         assertEquals("OK", result)
64         expect(6)
65         yield() // back to launch
66         finish(8)
67     }
68 
69     /**
70      * Tests that a 100% CPU-consuming loop will react on timeout if it has yields.
71      */
72     @Test
<lambda>null73     fun testYieldBlockingWithTimeout() = runTest {
74         expect(1)
75         val result = withTimeoutOrNull(100.milliseconds) {
76             while (true) {
77                 yield()
78             }
79         }
80         assertNull(result)
81         finish(2)
82     }
83 
84     @Test
testSmallTimeoutnull85     fun testSmallTimeout() = runTest {
86         val channel = Channel<Int>(1)
87         val value = withTimeoutOrNull(1.milliseconds) {
88             channel.receive()
89         }
90         assertNull(value)
91     }
92 
93     @Test
<lambda>null94     fun testThrowException() = runTest(expected = {it is AssertionError}) {
<lambda>null95         withTimeoutOrNull<Unit>(Duration.INFINITE) {
96             throw AssertionError()
97         }
98     }
99 
100     @Test
testInnerTimeoutnull101     fun testInnerTimeout() = runTest(
102         expected = { it is CancellationException }
<lambda>null103     ) {
104         withTimeoutOrNull(1000.milliseconds) {
105             withTimeout(10.milliseconds) {
106                 while (true) {
107                     yield()
108                 }
109             }
110             @Suppress("UNREACHABLE_CODE")
111             expectUnreached() // will timeout
112         }
113         expectUnreached() // will timeout
114     }
115 
116     @Test
testNestedTimeoutnull117     fun testNestedTimeout() = runTest(expected = { it is TimeoutCancellationException }) {
<lambda>null118         withTimeoutOrNull(Duration.INFINITE) {
119             // Exception from this withTimeout is not suppressed by withTimeoutOrNull
120             withTimeout(10.milliseconds) {
121                 delay(Duration.INFINITE)
122                 1
123             }
124         }
125 
126         expectUnreached()
127     }
128 
129     @Test
<lambda>null130     fun testOuterTimeout() = runTest {
131         if (isJavaAndWindows) return@runTest
132         var counter = 0
133         val result = withTimeoutOrNull(320.milliseconds) {
134             while (true) {
135                 val inner = withTimeoutOrNull(150.milliseconds) {
136                     while (true) {
137                         yield()
138                     }
139                 }
140                 assertNull(inner)
141                 counter++
142             }
143         }
144         assertNull(result)
145         check(counter in 1..2) {"Executed: $counter times"}
146     }
147 
148     @Test
<lambda>null149     fun testBadClass() = runTest {
150         val bad = BadClass()
151         val result = withTimeoutOrNull(100.milliseconds) {
152             bad
153         }
154         assertSame(bad, result)
155     }
156 
157     class BadClass {
equalsnull158         override fun equals(other: Any?): Boolean = error("Should not be called")
159         override fun hashCode(): Int = error("Should not be called")
160         override fun toString(): String = error("Should not be called")
161     }
162 
163     @Test
164     fun testNullOnTimeout() = runTest {
165         expect(1)
166         val result = withTimeoutOrNull(100.milliseconds) {
167             expect(2)
168             delay(1000.milliseconds)
169             expectUnreached()
170             "OK"
171         }
172         assertNull(result)
173         finish(3)
174     }
175 
176     @Test
<lambda>null177     fun testSuppressExceptionWithResult() = runTest {
178         expect(1)
179         val result = withTimeoutOrNull(100.milliseconds) {
180             expect(2)
181             try {
182                 delay(1000.milliseconds)
183             } catch (e: CancellationException) {
184                 expect(3)
185             }
186             "OK"
187         }
188         assertNull(result)
189         finish(4)
190     }
191 
192     @Test
<lambda>null193     fun testSuppressExceptionWithAnotherException() = runTest {
194         expect(1)
195         try {
196             withTimeoutOrNull(100.milliseconds) {
197                 expect(2)
198                 try {
199                     delay(1000.milliseconds)
200                 } catch (e: CancellationException) {
201                     expect(3)
202                     throw TestException()
203                 }
204                 expectUnreached()
205                 "OK"
206             }
207             expectUnreached()
208         } catch (e: TestException) {
209             // catches TestException
210             finish(4)
211 
212         }
213     }
214 
215     @Test
<lambda>null216     fun testNegativeTimeout() = runTest {
217         expect(1)
218         var result = withTimeoutOrNull(-1.milliseconds) {
219             expectUnreached()
220         }
221         assertNull(result)
222         result = withTimeoutOrNull(0.milliseconds) {
223             expectUnreached()
224         }
225         assertNull(result)
226         finish(2)
227     }
228 
229     @Test
<lambda>null230     fun testExceptionFromWithinTimeout() = runTest {
231         expect(1)
232         try {
233             expect(2)
234             withTimeoutOrNull<Unit>(1000.milliseconds) {
235                 expect(3)
236                 throw TestException()
237             }
238             expectUnreached()
239         } catch (e: TestException) {
240             finish(4)
241         }
242     }
243 }
244