Skip to content

Commit 60961ce

Browse files
committed
Migrate BSMDelegate in BuildSystemManagerTests` to an actor
1 parent 32af558 commit 60961ce

File tree

1 file changed

+68
-54
lines changed

1 file changed

+68
-54
lines changed

Tests/SKCoreTests/BuildSystemManagerTests.swift

Lines changed: 68 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,13 @@ final class BuildSystemManagerTests: XCTestCase {
103103

104104
bs.map[a] = FileBuildSettings(compilerArguments: ["x"])
105105
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)])
107107
await bsm.registerForChangeNotifications(for: a, language: .swift)
108108
try await fulfillmentOfOrThrow([initial])
109109

110110
bs.map[a] = nil
111111
let changed = expectation(description: "changed settings")
112-
del.expected = [(a, nil, changed, #file, #line)]
112+
await del.setExpected([(a, nil, changed, #file, #line)])
113113
bsm.fileBuildSettingsChanged([a: .removedOrUnavailable])
114114
try await fulfillmentOfOrThrow([changed])
115115
}
@@ -126,13 +126,13 @@ final class BuildSystemManagerTests: XCTestCase {
126126
defer { withExtendedLifetime(bsm) {} } // Keep BSM alive for callbacks.
127127
let del = await BSMDelegate(bsm)
128128
let initial = expectation(description: "initial settings")
129-
del.expected = [(a, nil, initial, #file, #line)]
129+
await del.setExpected([(a, nil, initial, #file, #line)])
130130
await bsm.registerForChangeNotifications(for: a, language: .swift)
131131
try await fulfillmentOfOrThrow([initial])
132132

133133
bs.map[a] = FileBuildSettings(compilerArguments: ["x"])
134134
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)])
136136
bsm.fileBuildSettingsChanged([a: .modified(bs.map[a]!)])
137137
try await fulfillmentOfOrThrow([changed])
138138
}
@@ -151,19 +151,19 @@ final class BuildSystemManagerTests: XCTestCase {
151151
let del = await BSMDelegate(bsm)
152152
let fallbackSettings = fallback.buildSettings(for: a, language: .swift)
153153
let initial = expectation(description: "initial fallback settings")
154-
del.expected = [(a, fallbackSettings, initial, #file, #line)]
154+
await del.setExpected([(a, fallbackSettings, initial, #file, #line)])
155155
await bsm.registerForChangeNotifications(for: a, language: .swift)
156156
try await fulfillmentOfOrThrow([initial])
157157

158158
bs.map[a] = FileBuildSettings(compilerArguments: ["non-fallback", "args"])
159159
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)])
161161
bsm.fileBuildSettingsChanged([a: .modified(bs.map[a]!)])
162162
try await fulfillmentOfOrThrow([changed])
163163

164164
bs.map[a] = nil
165165
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)])
167167
bsm.fileBuildSettingsChanged([a: .removedOrUnavailable])
168168
try await fulfillmentOfOrThrow([revert])
169169
}
@@ -184,18 +184,18 @@ final class BuildSystemManagerTests: XCTestCase {
184184
bs.map[a] = FileBuildSettings(compilerArguments: ["x"])
185185
bs.map[b] = FileBuildSettings(compilerArguments: ["y"])
186186
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)])
188188
await bsm.registerForChangeNotifications(for: a, language: .swift)
189189
try await fulfillmentOfOrThrow([initial])
190190
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)])
192192
await bsm.registerForChangeNotifications(for: b, language: .swift)
193193
try await fulfillmentOfOrThrow([initialB])
194194

195195
bs.map[a] = FileBuildSettings(compilerArguments: ["xx"])
196196
bs.map[b] = FileBuildSettings(compilerArguments: ["yy"])
197197
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)])
199199
bsm.fileBuildSettingsChanged([a: .modified(bs.map[a]!)])
200200
try await fulfillmentOfOrThrow([changed])
201201

@@ -204,10 +204,10 @@ final class BuildSystemManagerTests: XCTestCase {
204204
bs.map[b] = FileBuildSettings(compilerArguments: ["yyy"])
205205
let changedBothA = expectation(description: "changed setting a")
206206
let changedBothB = expectation(description: "changed setting b")
207-
del.expected = [
207+
await del.setExpected([
208208
(a, bs.map[a]!, changedBothA, #file, #line),
209209
(b, bs.map[b]!, changedBothB, #file, #line),
210-
]
210+
])
211211
bsm.fileBuildSettingsChanged([
212212
a:. modified(bs.map[a]!),
213213
b: .modified(bs.map[b]!)
@@ -232,19 +232,19 @@ final class BuildSystemManagerTests: XCTestCase {
232232
bs.map[b] = FileBuildSettings(compilerArguments: ["b"])
233233

234234
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)])
236236
await bsm.registerForChangeNotifications(for: a, language: .swift)
237237
try await fulfillmentOfOrThrow([initialA])
238238

239239
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)])
241241
await bsm.registerForChangeNotifications(for: b, language: .swift)
242242
try await fulfillmentOfOrThrow([initialB])
243243

244244
bs.map[a] = nil
245245
bs.map[b] = nil
246246
let changed = expectation(description: "changed settings")
247-
del.expected = [(b, nil, changed, #file, #line)]
247+
await del.setExpected([(b, nil, changed, #file, #line)])
248248
bsm.fileBuildSettingsChanged([
249249
b: .removedOrUnavailable
250250
])
@@ -274,35 +274,35 @@ final class BuildSystemManagerTests: XCTestCase {
274274
bs.map[cpp2] = FileBuildSettings(compilerArguments: ["C++ 2"])
275275

276276
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)])
278278
await bsm.registerForChangeNotifications(for: h, language: .c)
279279
try await fulfillmentOfOrThrow([initial])
280280

281281
mainFiles.mainFiles[h] = Set([cpp2])
282282

283283
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)])
285285
await bsm.mainFilesChangedImpl()
286286
try await fulfillmentOfOrThrow([changed])
287287

288288
let changed2 = expectation(description: "still cpp2, no update")
289289
changed2.isInverted = true
290-
del.expected = [(h, nil, changed2, #file, #line)]
290+
await del.setExpected([(h, nil, changed2, #file, #line)])
291291
await bsm.mainFilesChangedImpl()
292292
try await fulfillmentOfOrThrow([changed2], timeout: 1)
293293

294294
mainFiles.mainFiles[h] = Set([cpp1, cpp2])
295295

296296
let changed3 = expectation(description: "added main file, no update")
297297
changed3.isInverted = true
298-
del.expected = [(h, nil, changed3, #file, #line)]
298+
await del.setExpected([(h, nil, changed3, #file, #line)])
299299
await bsm.mainFilesChangedImpl()
300300
try await fulfillmentOfOrThrow([changed3], timeout: 1)
301301

302302
mainFiles.mainFiles[h] = Set([])
303303

304304
let changed4 = expectation(description: "changed settings to []")
305-
del.expected = [(h, nil, changed4, #file, #line)]
305+
await del.setExpected([(h, nil, changed4, #file, #line)])
306306
await bsm.mainFilesChangedImpl()
307307
try await fulfillmentOfOrThrow([changed4])
308308
}
@@ -332,10 +332,10 @@ final class BuildSystemManagerTests: XCTestCase {
332332
let initial2 = expectation(description: "initial settings h2 via cpp")
333333
let expectedArgsH1 = FileBuildSettings(compilerArguments: ["-xc++", cppArg, h1.pseudoPath])
334334
let expectedArgsH2 = FileBuildSettings(compilerArguments: ["-xc++", cppArg, h2.pseudoPath])
335-
del.expected = [
335+
await del.setExpected([
336336
(h1, expectedArgsH1, initial1, #file, #line),
337337
(h2, expectedArgsH2, initial2, #file, #line),
338-
]
338+
])
339339

340340
await bsm.registerForChangeNotifications(for: h1, language: .c)
341341
await bsm.registerForChangeNotifications(for: h2, language: .c)
@@ -350,10 +350,10 @@ final class BuildSystemManagerTests: XCTestCase {
350350
let changed2 = expectation(description: "initial settings h2 via cpp")
351351
let newArgsH1 = FileBuildSettings(compilerArguments: ["-xc++", newCppArg, h1.pseudoPath])
352352
let newArgsH2 = FileBuildSettings(compilerArguments: ["-xc++", newCppArg, h2.pseudoPath])
353-
del.expected = [
353+
await del.setExpected([
354354
(h1, newArgsH1, changed1, #file, #line),
355355
(h2, newArgsH2, changed2, #file, #line),
356-
]
356+
])
357357
bsm.fileBuildSettingsChanged([cpp: .modified(bs.map[cpp]!)])
358358

359359
try await fulfillmentOfOrThrow([changed1, changed2])
@@ -380,11 +380,11 @@ final class BuildSystemManagerTests: XCTestCase {
380380
let initialA = expectation(description: "initial settings a")
381381
let initialB = expectation(description: "initial settings b")
382382
let initialC = expectation(description: "initial settings c")
383-
del.expected = [
383+
await del.setExpected([
384384
(a, bs.map[a]!, initialA, #file, #line),
385385
(b, bs.map[b]!, initialB, #file, #line),
386386
(c, bs.map[c]!, initialC, #file, #line),
387-
]
387+
])
388388
await bsm.registerForChangeNotifications(for: a, language: .swift)
389389
await bsm.registerForChangeNotifications(for: b, language: .swift)
390390
await bsm.registerForChangeNotifications(for: c, language: .swift)
@@ -395,9 +395,9 @@ final class BuildSystemManagerTests: XCTestCase {
395395
bs.map[c] = FileBuildSettings(compilerArguments: ["new-c"])
396396

397397
let changedB = expectation(description: "changed settings b")
398-
del.expected = [
398+
await del.setExpected([
399399
(b, bs.map[b]!, changedB, #file, #line),
400-
]
400+
])
401401

402402
await bsm.unregisterForChangeNotifications(for: a)
403403
await bsm.unregisterForChangeNotifications(for: c)
@@ -434,16 +434,16 @@ final class BuildSystemManagerTests: XCTestCase {
434434

435435
bs.map[a] = FileBuildSettings(compilerArguments: ["x"])
436436
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)])
438438

439439
let depUpdate1 = expectation(description: "dependencies update during registration")
440-
del.expectedDependenciesUpdate = [(a, depUpdate1, #file, #line)]
440+
await del.setExpectedDependenciesUpdate([(a, depUpdate1, #file, #line)])
441441

442442
await bsm.registerForChangeNotifications(for: a, language: .swift)
443443
try await fulfillmentOfOrThrow([initial, depUpdate1])
444444

445445
let depUpdate2 = expectation(description: "dependencies update 2")
446-
del.expectedDependenciesUpdate = [(a, depUpdate2, #file, #line)]
446+
await del.setExpectedDependenciesUpdate([(a, depUpdate2, #file, #line)])
447447

448448
bsm.filesDependenciesUpdated([a])
449449
try await fulfillmentOfOrThrow([depUpdate2])
@@ -507,45 +507,59 @@ class ManualBuildSystem: BuildSystem {
507507
}
508508

509509
/// 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+
511514
let queue: DispatchQueue = DispatchQueue(label: "\(BSMDelegate.self)")
512515
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+
514523
var expectedDependenciesUpdate: [(uri: DocumentURI, expectation: XCTestExpectation, file: StaticString, line: UInt)] = []
515524

525+
/// - Note: Needed to set `expected` outside of the actor's isolation context.
526+
func setExpectedDependenciesUpdate(_ expectedDependenciesUpdated: [ExpectedDependenciesUpdatedCall]) {
527+
self.expectedDependenciesUpdate = expectedDependenciesUpdated
528+
}
529+
516530
init(_ bsm: BuildSystemManager) async {
517531
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+
}()
519537
}
520538

521539
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
533544
}
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()
534550
}
535551
}
536552

537553
func buildTargetsChanged(_ changes: [BuildTargetEvent]) {}
538554
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
548559
}
560+
561+
XCTAssertEqual(uri, expected.uri, file: expected.file, line: expected.line)
562+
expected.expectation.fulfill()
549563
}
550564
}
551565

0 commit comments

Comments
 (0)