@@ -103,13 +103,13 @@ final class BuildSystemManagerTests: XCTestCase {
103
103
104
104
bs. map [ a] = FileBuildSettings ( compilerArguments: [ " x " ] )
105
105
let initial = expectation ( description: " initial settings " )
106
- del. expected = [ ( a, bs. map [ a] !, initial, #file, #line) ]
106
+ await del. setExpected ( [ ( a, bs. map [ a] !, initial, #file, #line) ] )
107
107
await bsm. registerForChangeNotifications ( for: a, language: . swift)
108
108
try await fulfillmentOfOrThrow ( [ initial] )
109
109
110
110
bs. map [ a] = nil
111
111
let changed = expectation ( description: " changed settings " )
112
- del. expected = [ ( a, nil , changed, #file, #line) ]
112
+ await del. setExpected ( [ ( a, nil , changed, #file, #line) ] )
113
113
bsm. fileBuildSettingsChanged ( [ a: . removedOrUnavailable] )
114
114
try await fulfillmentOfOrThrow ( [ changed] )
115
115
}
@@ -126,13 +126,13 @@ final class BuildSystemManagerTests: XCTestCase {
126
126
defer { withExtendedLifetime ( bsm) { } } // Keep BSM alive for callbacks.
127
127
let del = await BSMDelegate ( bsm)
128
128
let initial = expectation ( description: " initial settings " )
129
- del. expected = [ ( a, nil , initial, #file, #line) ]
129
+ await del. setExpected ( [ ( a, nil , initial, #file, #line) ] )
130
130
await bsm. registerForChangeNotifications ( for: a, language: . swift)
131
131
try await fulfillmentOfOrThrow ( [ initial] )
132
132
133
133
bs. map [ a] = FileBuildSettings ( compilerArguments: [ " x " ] )
134
134
let changed = expectation ( description: " changed settings " )
135
- del. expected = [ ( a, bs. map [ a] !, changed, #file, #line) ]
135
+ await del. setExpected ( [ ( a, bs. map [ a] !, changed, #file, #line) ] )
136
136
bsm. fileBuildSettingsChanged ( [ a: . modified( bs. map [ a] !) ] )
137
137
try await fulfillmentOfOrThrow ( [ changed] )
138
138
}
@@ -151,19 +151,19 @@ final class BuildSystemManagerTests: XCTestCase {
151
151
let del = await BSMDelegate ( bsm)
152
152
let fallbackSettings = fallback. buildSettings ( for: a, language: . swift)
153
153
let initial = expectation ( description: " initial fallback settings " )
154
- del. expected = [ ( a, fallbackSettings, initial, #file, #line) ]
154
+ await del. setExpected ( [ ( a, fallbackSettings, initial, #file, #line) ] )
155
155
await bsm. registerForChangeNotifications ( for: a, language: . swift)
156
156
try await fulfillmentOfOrThrow ( [ initial] )
157
157
158
158
bs. map [ a] = FileBuildSettings ( compilerArguments: [ " non-fallback " , " args " ] )
159
159
let changed = expectation ( description: " changed settings " )
160
- del. expected = [ ( a, bs. map [ a] !, changed, #file, #line) ]
160
+ await del. setExpected ( [ ( a, bs. map [ a] !, changed, #file, #line) ] )
161
161
bsm. fileBuildSettingsChanged ( [ a: . modified( bs. map [ a] !) ] )
162
162
try await fulfillmentOfOrThrow ( [ changed] )
163
163
164
164
bs. map [ a] = nil
165
165
let revert = expectation ( description: " revert to fallback settings " )
166
- del. expected = [ ( a, fallbackSettings, revert, #file, #line) ]
166
+ await del. setExpected ( [ ( a, fallbackSettings, revert, #file, #line) ] )
167
167
bsm. fileBuildSettingsChanged ( [ a: . removedOrUnavailable] )
168
168
try await fulfillmentOfOrThrow ( [ revert] )
169
169
}
@@ -184,18 +184,18 @@ final class BuildSystemManagerTests: XCTestCase {
184
184
bs. map [ a] = FileBuildSettings ( compilerArguments: [ " x " ] )
185
185
bs. map [ b] = FileBuildSettings ( compilerArguments: [ " y " ] )
186
186
let initial = expectation ( description: " initial settings " )
187
- del. expected = [ ( a, bs. map [ a] !, initial, #file, #line) ]
187
+ await del. setExpected ( [ ( a, bs. map [ a] !, initial, #file, #line) ] )
188
188
await bsm. registerForChangeNotifications ( for: a, language: . swift)
189
189
try await fulfillmentOfOrThrow ( [ initial] )
190
190
let initialB = expectation ( description: " initial settings " )
191
- del. expected = [ ( b, bs. map [ b] !, initialB, #file, #line) ]
191
+ await del. setExpected ( [ ( b, bs. map [ b] !, initialB, #file, #line) ] )
192
192
await bsm. registerForChangeNotifications ( for: b, language: . swift)
193
193
try await fulfillmentOfOrThrow ( [ initialB] )
194
194
195
195
bs. map [ a] = FileBuildSettings ( compilerArguments: [ " xx " ] )
196
196
bs. map [ b] = FileBuildSettings ( compilerArguments: [ " yy " ] )
197
197
let changed = expectation ( description: " changed settings " )
198
- del. expected = [ ( a, bs. map [ a] !, changed, #file, #line) ]
198
+ await del. setExpected ( [ ( a, bs. map [ a] !, changed, #file, #line) ] )
199
199
bsm. fileBuildSettingsChanged ( [ a: . modified( bs. map [ a] !) ] )
200
200
try await fulfillmentOfOrThrow ( [ changed] )
201
201
@@ -204,10 +204,10 @@ final class BuildSystemManagerTests: XCTestCase {
204
204
bs. map [ b] = FileBuildSettings ( compilerArguments: [ " yyy " ] )
205
205
let changedBothA = expectation ( description: " changed setting a " )
206
206
let changedBothB = expectation ( description: " changed setting b " )
207
- del. expected = [
207
+ await del. setExpected ( [
208
208
( a, bs. map [ a] !, changedBothA, #file, #line) ,
209
209
( b, bs. map [ b] !, changedBothB, #file, #line) ,
210
- ]
210
+ ] )
211
211
bsm. fileBuildSettingsChanged ( [
212
212
a: . modified( bs. map [ a] !) ,
213
213
b: . modified( bs. map [ b] !)
@@ -232,19 +232,19 @@ final class BuildSystemManagerTests: XCTestCase {
232
232
bs. map [ b] = FileBuildSettings ( compilerArguments: [ " b " ] )
233
233
234
234
let initialA = expectation ( description: " initial settings a " )
235
- del. expected = [ ( a, bs. map [ a] !, initialA, #file, #line) ]
235
+ await del. setExpected ( [ ( a, bs. map [ a] !, initialA, #file, #line) ] )
236
236
await bsm. registerForChangeNotifications ( for: a, language: . swift)
237
237
try await fulfillmentOfOrThrow ( [ initialA] )
238
238
239
239
let initialB = expectation ( description: " initial settings b " )
240
- del. expected = [ ( b, bs. map [ b] !, initialB, #file, #line) ]
240
+ await del. setExpected ( [ ( b, bs. map [ b] !, initialB, #file, #line) ] )
241
241
await bsm. registerForChangeNotifications ( for: b, language: . swift)
242
242
try await fulfillmentOfOrThrow ( [ initialB] )
243
243
244
244
bs. map [ a] = nil
245
245
bs. map [ b] = nil
246
246
let changed = expectation ( description: " changed settings " )
247
- del. expected = [ ( b, nil , changed, #file, #line) ]
247
+ await del. setExpected ( [ ( b, nil , changed, #file, #line) ] )
248
248
bsm. fileBuildSettingsChanged ( [
249
249
b: . removedOrUnavailable
250
250
] )
@@ -274,35 +274,35 @@ final class BuildSystemManagerTests: XCTestCase {
274
274
bs. map [ cpp2] = FileBuildSettings ( compilerArguments: [ " C++ 2 " ] )
275
275
276
276
let initial = expectation ( description: " initial settings via cpp1 " )
277
- del. expected = [ ( h, bs. map [ cpp1] !, initial, #file, #line) ]
277
+ await del. setExpected ( [ ( h, bs. map [ cpp1] !, initial, #file, #line) ] )
278
278
await bsm. registerForChangeNotifications ( for: h, language: . c)
279
279
try await fulfillmentOfOrThrow ( [ initial] )
280
280
281
281
mainFiles. mainFiles [ h] = Set ( [ cpp2] )
282
282
283
283
let changed = expectation ( description: " changed settings to cpp2 " )
284
- del. expected = [ ( h, bs. map [ cpp2] !, changed, #file, #line) ]
284
+ await del. setExpected ( [ ( h, bs. map [ cpp2] !, changed, #file, #line) ] )
285
285
await bsm. mainFilesChangedImpl ( )
286
286
try await fulfillmentOfOrThrow ( [ changed] )
287
287
288
288
let changed2 = expectation ( description: " still cpp2, no update " )
289
289
changed2. isInverted = true
290
- del. expected = [ ( h, nil , changed2, #file, #line) ]
290
+ await del. setExpected ( [ ( h, nil , changed2, #file, #line) ] )
291
291
await bsm. mainFilesChangedImpl ( )
292
292
try await fulfillmentOfOrThrow ( [ changed2] , timeout: 1 )
293
293
294
294
mainFiles. mainFiles [ h] = Set ( [ cpp1, cpp2] )
295
295
296
296
let changed3 = expectation ( description: " added main file, no update " )
297
297
changed3. isInverted = true
298
- del. expected = [ ( h, nil , changed3, #file, #line) ]
298
+ await del. setExpected ( [ ( h, nil , changed3, #file, #line) ] )
299
299
await bsm. mainFilesChangedImpl ( )
300
300
try await fulfillmentOfOrThrow ( [ changed3] , timeout: 1 )
301
301
302
302
mainFiles. mainFiles [ h] = Set ( [ ] )
303
303
304
304
let changed4 = expectation ( description: " changed settings to [] " )
305
- del. expected = [ ( h, nil , changed4, #file, #line) ]
305
+ await del. setExpected ( [ ( h, nil , changed4, #file, #line) ] )
306
306
await bsm. mainFilesChangedImpl ( )
307
307
try await fulfillmentOfOrThrow ( [ changed4] )
308
308
}
@@ -332,10 +332,10 @@ final class BuildSystemManagerTests: XCTestCase {
332
332
let initial2 = expectation ( description: " initial settings h2 via cpp " )
333
333
let expectedArgsH1 = FileBuildSettings ( compilerArguments: [ " -xc++ " , cppArg, h1. pseudoPath] )
334
334
let expectedArgsH2 = FileBuildSettings ( compilerArguments: [ " -xc++ " , cppArg, h2. pseudoPath] )
335
- del. expected = [
335
+ await del. setExpected ( [
336
336
( h1, expectedArgsH1, initial1, #file, #line) ,
337
337
( h2, expectedArgsH2, initial2, #file, #line) ,
338
- ]
338
+ ] )
339
339
340
340
await bsm. registerForChangeNotifications ( for: h1, language: . c)
341
341
await bsm. registerForChangeNotifications ( for: h2, language: . c)
@@ -350,10 +350,10 @@ final class BuildSystemManagerTests: XCTestCase {
350
350
let changed2 = expectation ( description: " initial settings h2 via cpp " )
351
351
let newArgsH1 = FileBuildSettings ( compilerArguments: [ " -xc++ " , newCppArg, h1. pseudoPath] )
352
352
let newArgsH2 = FileBuildSettings ( compilerArguments: [ " -xc++ " , newCppArg, h2. pseudoPath] )
353
- del. expected = [
353
+ await del. setExpected ( [
354
354
( h1, newArgsH1, changed1, #file, #line) ,
355
355
( h2, newArgsH2, changed2, #file, #line) ,
356
- ]
356
+ ] )
357
357
bsm. fileBuildSettingsChanged ( [ cpp: . modified( bs. map [ cpp] !) ] )
358
358
359
359
try await fulfillmentOfOrThrow ( [ changed1, changed2] )
@@ -380,11 +380,11 @@ final class BuildSystemManagerTests: XCTestCase {
380
380
let initialA = expectation ( description: " initial settings a " )
381
381
let initialB = expectation ( description: " initial settings b " )
382
382
let initialC = expectation ( description: " initial settings c " )
383
- del. expected = [
383
+ await del. setExpected ( [
384
384
( a, bs. map [ a] !, initialA, #file, #line) ,
385
385
( b, bs. map [ b] !, initialB, #file, #line) ,
386
386
( c, bs. map [ c] !, initialC, #file, #line) ,
387
- ]
387
+ ] )
388
388
await bsm. registerForChangeNotifications ( for: a, language: . swift)
389
389
await bsm. registerForChangeNotifications ( for: b, language: . swift)
390
390
await bsm. registerForChangeNotifications ( for: c, language: . swift)
@@ -395,9 +395,9 @@ final class BuildSystemManagerTests: XCTestCase {
395
395
bs. map [ c] = FileBuildSettings ( compilerArguments: [ " new-c " ] )
396
396
397
397
let changedB = expectation ( description: " changed settings b " )
398
- del. expected = [
398
+ await del. setExpected ( [
399
399
( b, bs. map [ b] !, changedB, #file, #line) ,
400
- ]
400
+ ] )
401
401
402
402
await bsm. unregisterForChangeNotifications ( for: a)
403
403
await bsm. unregisterForChangeNotifications ( for: c)
@@ -434,16 +434,16 @@ final class BuildSystemManagerTests: XCTestCase {
434
434
435
435
bs. map [ a] = FileBuildSettings ( compilerArguments: [ " x " ] )
436
436
let initial = expectation ( description: " initial settings " )
437
- del. expected = [ ( a, bs. map [ a] !, initial, #file, #line) ]
437
+ await del. setExpected ( [ ( a, bs. map [ a] !, initial, #file, #line) ] )
438
438
439
439
let depUpdate1 = expectation ( description: " dependencies update during registration " )
440
- del. expectedDependenciesUpdate = [ ( a, depUpdate1, #file, #line) ]
440
+ await del. setExpectedDependenciesUpdate ( [ ( a, depUpdate1, #file, #line) ] )
441
441
442
442
await bsm. registerForChangeNotifications ( for: a, language: . swift)
443
443
try await fulfillmentOfOrThrow ( [ initial, depUpdate1] )
444
444
445
445
let depUpdate2 = expectation ( description: " dependencies update 2 " )
446
- del. expectedDependenciesUpdate = [ ( a, depUpdate2, #file, #line) ]
446
+ await del. setExpectedDependenciesUpdate ( [ ( a, depUpdate2, #file, #line) ] )
447
447
448
448
bsm. filesDependenciesUpdated ( [ a] )
449
449
try await fulfillmentOfOrThrow ( [ depUpdate2] )
@@ -507,45 +507,59 @@ class ManualBuildSystem: BuildSystem {
507
507
}
508
508
509
509
/// A `BuildSystemDelegate` setup for testing.
510
- private final class BSMDelegate : BuildSystemDelegate {
510
+ private actor BSMDelegate : BuildSystemDelegate {
511
+ fileprivate typealias ExpectedBuildSettingChangedCall = ( uri: DocumentURI , settings: FileBuildSettings ? , expectation: XCTestExpectation , file: StaticString , line: UInt )
512
+ fileprivate typealias ExpectedDependenciesUpdatedCall = ( uri: DocumentURI , expectation: XCTestExpectation , file: StaticString , line: UInt )
513
+
511
514
let queue : DispatchQueue = DispatchQueue ( label: " \( BSMDelegate . self) " )
512
515
unowned let bsm : BuildSystemManager
513
- var expected : [ ( uri: DocumentURI , settings: FileBuildSettings ? , expectation: XCTestExpectation , file: StaticString , line: UInt ) ] = [ ]
516
+ var expected : [ ExpectedBuildSettingChangedCall ] = [ ]
517
+
518
+ /// - Note: Needed to set `expected` outside of the actor's isolation context.
519
+ func setExpected( _ expected: [ ExpectedBuildSettingChangedCall ] ) {
520
+ self . expected = expected
521
+ }
522
+
514
523
var expectedDependenciesUpdate : [ ( uri: DocumentURI , expectation: XCTestExpectation , file: StaticString , line: UInt ) ] = [ ]
515
524
525
+ /// - Note: Needed to set `expected` outside of the actor's isolation context.
526
+ func setExpectedDependenciesUpdate( _ expectedDependenciesUpdated: [ ExpectedDependenciesUpdatedCall ] ) {
527
+ self . expectedDependenciesUpdate = expectedDependenciesUpdated
528
+ }
529
+
516
530
init ( _ bsm: BuildSystemManager ) async {
517
531
self . bsm = bsm
518
- await bsm. setDelegate ( self )
532
+ // Actor initializers can't directly leave their executor. Moving the call
533
+ // of `bsm.setDelegate` into a closure works around that limitation. rdar://116221716
534
+ await {
535
+ await bsm. setDelegate ( self )
536
+ } ( )
519
537
}
520
538
521
539
func fileBuildSettingsChanged( _ changes: [ DocumentURI : FileBuildSettingsChange ] ) {
522
- queue. sync {
523
- for (uri, change) in changes {
524
- guard let expected = expected. first ( where: { $0. uri == uri } ) else {
525
- XCTFail ( " unexpected settings change for \( uri) " )
526
- continue
527
- }
528
-
529
- XCTAssertEqual ( uri, expected. uri, file: expected. file, line: expected. line)
530
- let settings = change. newSettings
531
- XCTAssertEqual ( settings, expected. settings, file: expected. file, line: expected. line)
532
- expected. expectation. fulfill ( )
540
+ for (uri, change) in changes {
541
+ guard let expected = expected. first ( where: { $0. uri == uri } ) else {
542
+ XCTFail ( " unexpected settings change for \( uri) " )
543
+ continue
533
544
}
545
+
546
+ XCTAssertEqual ( uri, expected. uri, file: expected. file, line: expected. line)
547
+ let settings = change. newSettings
548
+ XCTAssertEqual ( settings, expected. settings, file: expected. file, line: expected. line)
549
+ expected. expectation. fulfill ( )
534
550
}
535
551
}
536
552
537
553
func buildTargetsChanged( _ changes: [ BuildTargetEvent ] ) { }
538
554
func filesDependenciesUpdated( _ changedFiles: Set < DocumentURI > ) {
539
- queue. sync {
540
- for uri in changedFiles {
541
- guard let expected = expectedDependenciesUpdate. first ( where: { $0. uri == uri } ) else {
542
- XCTFail ( " unexpected filesDependenciesUpdated for \( uri) " )
543
- continue
544
- }
545
-
546
- XCTAssertEqual ( uri, expected. uri, file: expected. file, line: expected. line)
547
- expected. expectation. fulfill ( )
555
+ for uri in changedFiles {
556
+ guard let expected = expectedDependenciesUpdate. first ( where: { $0. uri == uri } ) else {
557
+ XCTFail ( " unexpected filesDependenciesUpdated for \( uri) " )
558
+ continue
548
559
}
560
+
561
+ XCTAssertEqual ( uri, expected. uri, file: expected. file, line: expected. line)
562
+ expected. expectation. fulfill ( )
549
563
}
550
564
}
551
565
0 commit comments