1 
2 /*
3  * Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
4  */
5 
6 @file:Suppress("NAMED_ARGUMENTS_NOT_ALLOWED") // KT-21913
7 
8 package kotlinx.coroutines
9 
10 import kotlinx.coroutines.channels.*
11 import kotlin.test.*
12 
13 class WithTimeoutOrNullTest : 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_000) {
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_000) {
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(1000) {
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) {
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) {
88             channel.receive()
89         }
90         assertNull(value)
91     }
92 
93     @Test
<lambda>null94     fun testThrowException() = runTest(expected = {it is AssertionError}) {
<lambda>null95         withTimeoutOrNull(Long.MAX_VALUE) {
96             throw AssertionError()
97         }
98     }
99 
100     @Test
testInnerTimeoutnull101     fun testInnerTimeout() = runTest(
102         expected = { it is CancellationException }
<lambda>null103     ) {
104         withTimeoutOrNull(1000) {
105             withTimeout(10) {
106                 while (true) {
107                     yield()
108                 }
109             }
110             expectUnreached() // will timeout
111         }
112         expectUnreached() // will timeout
113     }
114 
115     @Test
testNestedTimeoutnull116     fun testNestedTimeout() = runTest(expected = { it is TimeoutCancellationException }) {
<lambda>null117         withTimeoutOrNull(Long.MAX_VALUE) {
118             // Exception from this withTimeout is not suppressed by withTimeoutOrNull
119             withTimeout(10) {
120                 delay(Long.MAX_VALUE)
121                 1
122             }
123         }
124 
125         expectUnreached()
126     }
127 
128     @Test
<lambda>null129     fun testOuterTimeout() = runTest {
130         var counter = 0
131         val result = withTimeoutOrNull(250) {
132             while (true) {
133                 val inner = withTimeoutOrNull(100) {
134                     while (true) {
135                         yield()
136                     }
137                 }
138                 assertNull(inner)
139                 counter++
140             }
141         }
142         assertNull(result)
143         check(counter in 1..2) {"Executed: $counter times"}
144     }
145 
146     @Test
<lambda>null147     fun testBadClass() = runTest {
148         val bad = BadClass()
149         val result = withTimeoutOrNull(100) {
150             bad
151         }
152         assertSame(bad, result)
153     }
154 
155     @Test
<lambda>null156     fun testNullOnTimeout() = runTest {
157         expect(1)
158         val result = withTimeoutOrNull(100) {
159             expect(2)
160             delay(1000)
161             expectUnreached()
162             "OK"
163         }
164         assertNull(result)
165         finish(3)
166     }
167 
168     @Test
<lambda>null169     fun testSuppressExceptionWithResult() = runTest {
170         expect(1)
171         val result = withTimeoutOrNull(100) {
172             expect(2)
173             try {
174                 delay(1000)
175             } catch (e: CancellationException) {
176                 expect(3)
177             }
178             "OK"
179         }
180         assertNull(result)
181         finish(4)
182     }
183 
184     @Test
<lambda>null185     fun testSuppressExceptionWithAnotherException() = runTest {
186         expect(1)
187         try {
188             withTimeoutOrNull(100) {
189                 expect(2)
190                 try {
191                     delay(1000)
192                 } catch (e: CancellationException) {
193                     expect(3)
194                     throw TestException()
195                 }
196                 expectUnreached()
197                 "OK"
198             }
199             expectUnreached()
200         } catch (e: TestException) {
201             // catches TestException
202             finish(4)
203 
204         }
205     }
206 
207     @Test
<lambda>null208     fun testNegativeTimeout() = runTest {
209         expect(1)
210         var result = withTimeoutOrNull(-1) {
211             expectUnreached()
212         }
213         assertNull(result)
214         result = withTimeoutOrNull(0) {
215             expectUnreached()
216         }
217         assertNull(result)
218         finish(2)
219     }
220 
221     @Test
<lambda>null222     fun testExceptionFromWithinTimeout() = runTest {
223         expect(1)
224         try {
225             expect(2)
226             withTimeoutOrNull(1000) {
227                 expect(3)
228                 throw TestException()
229             }
230             expectUnreached()
231         } catch (e: TestException) {
232             finish(4)
233         }
234     }
235 }
236