• 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         if (isJavaAndWindows) return@runTest
135         var counter = 0
136         val result = withTimeoutOrNull(320.milliseconds) {
137             while (true) {
138                 val inner = withTimeoutOrNull(150.milliseconds) {
139                     while (true) {
140                         yield()
141                     }
142                 }
143                 assertNull(inner)
144                 counter++
145             }
146         }
147         assertNull(result)
148         check(counter in 1..2) {"Executed: $counter times"}
149     }
150 
151     @Test
<lambda>null152     fun testBadClass() = runTest {
153         val bad = BadClass()
154         val result = withTimeoutOrNull(100.milliseconds) {
155             bad
156         }
157         assertSame(bad, result)
158     }
159 
160     class BadClass {
equalsnull161         override fun equals(other: Any?): Boolean = error("Should not be called")
162         override fun hashCode(): Int = error("Should not be called")
163         override fun toString(): String = error("Should not be called")
164     }
165 
166     @Test
167     fun testNullOnTimeout() = runTest {
168         expect(1)
169         val result = withTimeoutOrNull(100.milliseconds) {
170             expect(2)
171             delay(1000.milliseconds)
172             expectUnreached()
173             "OK"
174         }
175         assertNull(result)
176         finish(3)
177     }
178 
179     @Test
<lambda>null180     fun testSuppressExceptionWithResult() = runTest {
181         expect(1)
182         val result = withTimeoutOrNull(100.milliseconds) {
183             expect(2)
184             try {
185                 delay(1000.milliseconds)
186             } catch (e: CancellationException) {
187                 expect(3)
188             }
189             "OK"
190         }
191         assertNull(result)
192         finish(4)
193     }
194 
195     @Test
<lambda>null196     fun testSuppressExceptionWithAnotherException() = runTest {
197         expect(1)
198         try {
199             withTimeoutOrNull(100.milliseconds) {
200                 expect(2)
201                 try {
202                     delay(1000.milliseconds)
203                 } catch (e: CancellationException) {
204                     expect(3)
205                     throw TestException()
206                 }
207                 expectUnreached()
208                 "OK"
209             }
210             expectUnreached()
211         } catch (e: TestException) {
212             // catches TestException
213             finish(4)
214 
215         }
216     }
217 
218     @Test
<lambda>null219     fun testNegativeTimeout() = runTest {
220         expect(1)
221         var result = withTimeoutOrNull(-1.milliseconds) {
222             expectUnreached()
223         }
224         assertNull(result)
225         result = withTimeoutOrNull(0.milliseconds) {
226             expectUnreached()
227         }
228         assertNull(result)
229         finish(2)
230     }
231 
232     @Test
<lambda>null233     fun testExceptionFromWithinTimeout() = runTest {
234         expect(1)
235         try {
236             expect(2)
237             withTimeoutOrNull<Unit>(1000.milliseconds) {
238                 expect(3)
239                 throw TestException()
240             }
241             expectUnreached()
242         } catch (e: TestException) {
243             finish(4)
244         }
245     }
246 }
247