@@ -113,6 +113,113 @@ final class JavaScriptEventLoopTests: XCTestCase {
113113 XCTAssertEqual ( context . completed , [ " t4 " , " t3 " , " t5 " ] )
114114 }
115115
116+ final class OrderContext : @unchecked Sendable {
117+ var completed : [ String ] = [ ]
118+ var expectedCount = 0
119+ var continuation : CheckedContinuation < Void , Never > ?
120+
121+ func record ( _ name : String ) {
122+ completed . append ( name )
123+ if completed . count == expectedCount {
124+ continuation ? . resume ( )
125+ continuation = nil
126+ }
127+ }
128+ }
129+
130+ /// Starts tasks without awaiting them, so no await raises the priority of a queued task.
131+ func runUnawaited ( expectedCount : Int , _ start : ( OrderContext ) -> Void ) async -> [ String ] {
132+ let context = OrderContext ( )
133+ context . expectedCount = expectedCount
134+ await withCheckedContinuation { continuation in
135+ context . continuation = continuation
136+ start ( context )
137+ }
138+ return context . completed
139+ }
140+
141+ func testTaskPriorityOrderWithMixedPriorities ( ) async throws {
142+ let burst : [ ( String , TaskPriority ) ] = [
143+ ( " low1 " , . low ) , ( " medium1 " , . medium ) , ( " low2 " , . low ) , ( " high1 " , . high ) ,
144+ ( " medium2 " , . medium ) , ( " low3 " , . low ) , ( " high2 " , . high ) , ( " medium3 " , . medium ) ,
145+ ]
146+ let burstOrder = await runUnawaited ( expectedCount : burst . count ) { context in
147+ for ( name , priority ) in burst {
148+ Task ( priority : priority ) { context . record ( name ) }
149+ }
150+ }
151+ XCTAssertEqual ( burstOrder , [ " high1 " , " high2 " , " medium1 " , " medium2 " , " medium3 " , " low1 " , " low2 " , " low3 " ] )
152+
153+ let nestedOrder = await runUnawaited ( expectedCount : 7 ) { context in
154+ Task ( priority : . medium ) {
155+ context . record ( " outer " )
156+ let nested : [ ( String , TaskPriority ) ] = [
157+ ( " nestedLow1 " , . low ) , ( " nestedHigh " , . high ) , ( " nestedMedium " , . medium ) , ( " nestedLow2 " , . low ) ,
158+ ]
159+ for ( name , priority ) in nested {
160+ Task ( priority : priority ) { context . record ( name ) }
161+ }
162+ }
163+ Task ( priority : . medium ) { context . record ( " medium " ) }
164+ Task ( priority : . low ) { context . record ( " low " ) }
165+ }
166+ XCTAssertEqual (
167+ nestedOrder ,
168+ [ " outer " , " nestedHigh " , " medium " , " nestedMedium " , " low " , " nestedLow1 " , " nestedLow2 " ]
169+ )
170+
171+ let priorities : [ TaskPriority ] = [
172+ . low , . high , . background , . medium , TaskPriority ( rawValue : 22 ) , TaskPriority ( rawValue : 5 ) ,
173+ ]
174+ let many = ( 0 ..< 600 ) . map { index in ( " \( index ) " , priorities [ index % priorities . count ] ) }
175+ let manyOrder = await runUnawaited ( expectedCount : many . count ) { context in
176+ for ( name , priority ) in many {
177+ Task ( priority : priority ) { context . record ( name ) }
178+ }
179+ }
180+ let expectedManyOrder = many . enumerated ( )
181+ . sorted { lhs , rhs in
182+ lhs . element . 1 . rawValue != rhs . element . 1 . rawValue
183+ ? lhs . element . 1 . rawValue > rhs . element . 1 . rawValue
184+ : lhs . offset < rhs . offset
185+ }
186+ . map ( \. element . 0 )
187+ XCTAssertEqual ( manyOrder , expectedManyOrder )
188+ }
189+
190+ func testTaskPriorityOrderAfterQueueEmpties ( ) async throws {
191+ let rounds : [ [ ( String , TaskPriority ) ] ] = [
192+ [ ( " low1 " , . low ) , ( " low2 " , . low ) , ( " high1 " , . high ) , ( " low3 " , . low ) ] ,
193+ [ ( " high1 " , . high ) , ( " medium1 " , . medium ) , ( " high2 " , . high ) , ( " low1 " , . low ) ] ,
194+ [ ( " medium1 " , . medium ) , ( " medium2 " , . medium ) , ( " medium3 " , . medium ) ] ,
195+ ]
196+ let expectedOrders = [
197+ [ " high1 " , " low1 " , " low2 " , " low3 " ] ,
198+ [ " high1 " , " high2 " , " medium1 " , " low1 " ] ,
199+ [ " medium1 " , " medium2 " , " medium3 " ] ,
200+ ]
201+ for ( round , expectedOrder ) in zip ( rounds , expectedOrders ) {
202+ let order = await runUnawaited ( expectedCount : round . count ) { context in
203+ for ( name , priority ) in round {
204+ Task ( priority : priority ) { context . record ( name ) }
205+ }
206+ }
207+ XCTAssertEqual ( order , expectedOrder )
208+ }
209+ }
210+
211+ func testTaskPriorityOrderAfterSingleJobRunIsClaimed ( ) async throws {
212+ let order = await runUnawaited ( expectedCount : 4 ) { context in
213+ Task ( priority : . low ) { context . record ( " low1 " ) }
214+ Task ( priority : . low ) { context . record ( " low2 " ) }
215+ Task ( priority : . high ) {
216+ context . record ( " high " )
217+ Task ( priority : . low ) { context . record ( " low3 " ) }
218+ }
219+ }
220+ XCTAssertEqual ( order , [ " high " , " low1 " , " low2 " , " low3 " ] )
221+ }
222+
116223 // MARK: - Promise Tests
117224
118225 func testPromiseResolution ( ) async throws {
0 commit comments