@@ -125,6 +125,41 @@ class TestRunLoop : XCTestCase {
125
125
XCTAssertTrue ( didDeallocate)
126
126
}
127
127
128
+ func test_mainDispatchQueueCallout( ) {
129
+ let runLoop = RunLoop . current
130
+
131
+ var asyncExecuted = false
132
+ DispatchQueue . main. async {
133
+ asyncExecuted = true
134
+ }
135
+
136
+ // RunLoop should service main queue
137
+ _ = runLoop. run ( mode: . default, before: Date ( timeIntervalSinceNow: 2 ) )
138
+ XCTAssertTrue ( asyncExecuted, " Main queue async code should be executed " )
139
+
140
+ asyncExecuted = false
141
+ DispatchQueue . main. async {
142
+ asyncExecuted = true
143
+ }
144
+
145
+ // Second run to be sure RunLoop will not stuck
146
+ _ = runLoop. run ( mode: . default, before: Date ( timeIntervalSinceNow: 2 ) )
147
+ XCTAssertTrue ( asyncExecuted, " Main queue async code should be executed " )
148
+
149
+ var timerFired = false
150
+ let dummyTimer = Timer . scheduledTimer ( withTimeInterval: 0.5 , repeats: false ) { _ in
151
+ timerFired = true
152
+ }
153
+ runLoop. add ( dummyTimer, forMode: . default)
154
+
155
+ // At this moment RunLoop has no work to do except waiting for timer.
156
+ // But RunLoop will exit prematurely if event from previous async calls
157
+ // got stuck in wrong state.
158
+ _ = runLoop. run ( mode: . default, before: Date ( timeIntervalSinceNow: 2 ) )
159
+
160
+ XCTAssertTrue ( timerFired, " Time should fire already " )
161
+ }
162
+
128
163
static var allTests : [ ( String , ( TestRunLoop ) -> ( ) throws -> Void ) ] {
129
164
return [
130
165
( " test_constants " , test_constants) ,
@@ -134,6 +169,7 @@ class TestRunLoop : XCTestCase {
134
169
( " test_runLoopLimitDate " , test_runLoopLimitDate) ,
135
170
( " test_runLoopPoll " , test_runLoopPoll) ,
136
171
( " test_addingRemovingPorts " , test_addingRemovingPorts) ,
172
+ ( " test_mainDispatchQueueCallout " , test_mainDispatchQueueCallout)
137
173
]
138
174
}
139
175
}
0 commit comments