• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2016-2020 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 import kotlin.time.*
13 import kotlin.time.Duration.Companion.milliseconds
14 import kotlin.time.Duration.Companion.seconds
15 
16 class WithTimeoutOrNullDurationTest : TestBase() {
17     /**
18      * Tests a case of no timeout and no suspension inside.
19      */
20     @Test
<lambda>null21     fun testBasicNoSuspend() = runTest {
22         expect(1)
23         val result = withTimeoutOrNull(10.seconds) {
24             expect(2)
25             "OK"
26         }
27         assertEquals("OK", result)
28         finish(3)
29     }
30 
31     /**
32      * Tests a case of no timeout and one suspension inside.
33      */
34     @Test
<lambda>null35     fun testBasicSuspend() = runTest {
36         expect(1)
37         val result = withTimeoutOrNull(10.seconds) {
38             expect(2)
39             yield()
40             expect(3)
41             "OK"
42         }
43         assertEquals("OK", result)
44         finish(4)
45     }
46 
47     /**
48      * Tests property dispatching of `withTimeoutOrNull` blocks
49      */
50     @Test
<lambda>null51     fun testDispatch() = runTest {
52         expect(1)
53         launch {
54             expect(4)
55             yield() // back to main
56             expect(7)
57         }
58         expect(2)
59         // test that it does not yield to the above job when started
60         val result = withTimeoutOrNull(1.seconds) {
61             expect(3)
62             yield() // yield only now
63             expect(5)
64             "OK"
65         }
66         assertEquals("OK", result)
67         expect(6)
68         yield() // back to launch
69         finish(8)
70     }
71 
72     /**
73      * Tests that a 100% CPU-consuming loop will react on timeout if it has yields.
74      */
75     @Test
<lambda>null76     fun testYieldBlockingWithTimeout() = runTest {
77         expect(1)
78         val result = withTimeoutOrNull(100.milliseconds) {
79             while (true) {
80                 yield()
81             }
82         }
83         assertNull(result)
84         finish(2)
85     }
86 
87     @Test
testSmallTimeoutnull88     fun testSmallTimeout() = runTest {
89         val channel = Channel<Int>(1)
90         val value = withTimeoutOrNull(1.milliseconds) {
91             channel.receive()
92         }
93         assertNull(value)
94     }
95 
96     @Test
<lambda>null97     fun testThrowException() = runTest(expected = {it is AssertionError}) {
<lambda>null98         withTimeoutOrNull<Unit>(Duration.INFINITE) {
99             throw AssertionError()
100         }
101     }
102 
103     @Test
testInnerTimeoutnull104     fun testInnerTimeout() = runTest(
105         expected = { it is CancellationException }
<lambda>null106     ) {
107         withTimeoutOrNull(1000.milliseconds) {
108             withTimeout(10.milliseconds) {
109                 while (true) {
110                     yield()
111                 }
112             }
113             @Suppress("UNREACHABLE_CODE")
114             expectUnreached() // will timeout
115         }
116         expectUnreached() // will timeout
117     }
118 
119     @Test
testNestedTimeoutnull120     fun testNestedTimeout() = runTest(expected = { it is TimeoutCancellationException }) {
<lambda>null121         withTimeoutOrNull(Duration.INFINITE) {
122             // Exception from this withTimeout is not suppressed by withTimeoutOrNull
123             withTimeout(10.milliseconds) {
124                 delay(Duration.INFINITE)
125                 1
126             }
127         }
128 
129         expectUnreached()
130     }
131 
132     @Test
<lambda>null133     fun testOuterTimeout() = runTest {
134         var counter = 0
135         val result = withTimeoutOrNull(320.milliseconds) {
136             while (true) {
137                 val inner = withTimeoutOrNull(150.milliseconds) {
138                     while (true) {
139                         yield()
140                     }
141                 }
142                 assertNull(inner)
143                 counter++
144             }
145         }
146         assertNull(result)
147         check(counter in 1..2) {"Executed: $counter times"}
148     }
149 
150     @Test
<lambda>null151     fun testBadClass() = runTest {
152         val bad = BadClass()
153         val result = withTimeoutOrNull(100.milliseconds) {
154             bad
155         }
156         assertSame(bad, result)
157     }
158 
159     class BadClass {
equalsnull160         override fun equals(other: Any?): Boolean = error("Should not be called")
161         override fun hashCode(): Int = error("Should not be called")
162         override fun toString(): String = error("Should not be called")
163     }
164 
165     @Test
166     fun testNullOnTimeout() = runTest {
167         expect(1)
168         val result = withTimeoutOrNull(100.milliseconds) {
169             expect(2)
170             delay(1000.milliseconds)
171             expectUnreached()
172             "OK"
173         }
174         assertNull(result)
175         finish(3)
176     }
177 
178     @Test
<lambda>null179     fun testSuppressExceptionWithResult() = runTest {
180         expect(1)
181         val result = withTimeoutOrNull(100.milliseconds) {
182             expect(2)
183             try {
184                 delay(1000.milliseconds)
185             } catch (e: CancellationException) {
186                 expect(3)
187             }
188             "OK"
189         }
190         assertNull(result)
191         finish(4)
192     }
193 
194     @Test
<lambda>null195     fun testSuppressExceptionWithAnotherException() = runTest {
196         expect(1)
197         try {
198             withTimeoutOrNull(100.milliseconds) {
199                 expect(2)
200                 try {
201                     delay(1000.milliseconds)
202                 } catch (e: CancellationException) {
203                     expect(3)
204                     throw TestException()
205                 }
206                 expectUnreached()
207                 "OK"
208             }
209             expectUnreached()
210         } catch (e: TestException) {
211             // catches TestException
212             finish(4)
213 
214         }
215     }
216 
217     @Test
<lambda>null218     fun testNegativeTimeout() = runTest {
219         expect(1)
220         var result = withTimeoutOrNull(-1.milliseconds) {
221             expectUnreached()
222         }
223         assertNull(result)
224         result = withTimeoutOrNull(0.milliseconds) {
225             expectUnreached()
226         }
227         assertNull(result)
228         finish(2)
229     }
230 
231     @Test
<lambda>null232     fun testExceptionFromWithinTimeout() = runTest {
233         expect(1)
234         try {
235             expect(2)
236             withTimeoutOrNull<Unit>(1000.milliseconds) {
237                 expect(3)
238                 throw TestException()
239             }
240             expectUnreached()
241         } catch (e: TestException) {
242             finish(4)
243         }
244     }
245 }
246