• 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 
14 @ExperimentalTime
15 class WithTimeoutOrNullDurationTest : TestBase() {
16     /**
17      * Tests a case of no timeout and no suspension inside.
18      */
19     @Test
<lambda>null20     fun testBasicNoSuspend() = runTest {
21         expect(1)
22         val result = withTimeoutOrNull(10.seconds) {
23             expect(2)
24             "OK"
25         }
26         assertEquals("OK", result)
27         finish(3)
28     }
29 
30     /**
31      * Tests a case of no timeout and one suspension inside.
32      */
33     @Test
<lambda>null34     fun testBasicSuspend() = runTest {
35         expect(1)
36         val result = withTimeoutOrNull(10.seconds) {
37             expect(2)
38             yield()
39             expect(3)
40             "OK"
41         }
42         assertEquals("OK", result)
43         finish(4)
44     }
45 
46     /**
47      * Tests property dispatching of `withTimeoutOrNull` blocks
48      */
49     @Test
<lambda>null50     fun testDispatch() = runTest {
51         expect(1)
52         launch {
53             expect(4)
54             yield() // back to main
55             expect(7)
56         }
57         expect(2)
58         // test that it does not yield to the above job when started
59         val result = withTimeoutOrNull(1.seconds) {
60             expect(3)
61             yield() // yield only now
62             expect(5)
63             "OK"
64         }
65         assertEquals("OK", result)
66         expect(6)
67         yield() // back to launch
68         finish(8)
69     }
70 
71     /**
72      * Tests that a 100% CPU-consuming loop will react on timeout if it has yields.
73      */
74     @Test
<lambda>null75     fun testYieldBlockingWithTimeout() = runTest {
76         expect(1)
77         val result = withTimeoutOrNull(100.milliseconds) {
78             while (true) {
79                 yield()
80             }
81         }
82         assertNull(result)
83         finish(2)
84     }
85 
86     @Test
testSmallTimeoutnull87     fun testSmallTimeout() = runTest {
88         val channel = Channel<Int>(1)
89         val value = withTimeoutOrNull(1.milliseconds) {
90             channel.receive()
91         }
92         assertNull(value)
93     }
94 
95     @Test
<lambda>null96     fun testThrowException() = runTest(expected = {it is AssertionError}) {
<lambda>null97         withTimeoutOrNull(Duration.INFINITE) {
98             throw AssertionError()
99         }
100     }
101 
102     @Test
testInnerTimeoutnull103     fun testInnerTimeout() = runTest(
104         expected = { it is CancellationException }
<lambda>null105     ) {
106         withTimeoutOrNull(1000.milliseconds) {
107             withTimeout(10.milliseconds) {
108                 while (true) {
109                     yield()
110                 }
111             }
112             expectUnreached() // will timeout
113         }
114         expectUnreached() // will timeout
115     }
116 
117     @Test
testNestedTimeoutnull118     fun testNestedTimeout() = runTest(expected = { it is TimeoutCancellationException }) {
<lambda>null119         withTimeoutOrNull(Duration.INFINITE) {
120             // Exception from this withTimeout is not suppressed by withTimeoutOrNull
121             withTimeout(10.milliseconds) {
122                 delay(Duration.INFINITE)
123                 1
124             }
125         }
126 
127         expectUnreached()
128     }
129 
130     @Test
<lambda>null131     fun testOuterTimeout() = runTest {
132         var counter = 0
133         val result = withTimeoutOrNull(250.milliseconds) {
134             while (true) {
135                 val inner = withTimeoutOrNull(100.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(1000.milliseconds) {
235                 expect(3)
236                 throw TestException()
237             }
238             expectUnreached()
239         } catch (e: TestException) {
240             finish(4)
241         }
242     }
243 }
244