@@ -103,6 +103,22 @@ public struct SourceLocStack {
103
103
}
104
104
}
105
105
106
+ fileprivate struct AtomicBool {
107
+
108
+ private var _value : _stdlib_AtomicInt
109
+
110
+ init ( _ b: Bool ) { self . _value = _stdlib_AtomicInt ( b ? 1 : 0 ) }
111
+
112
+ func store( _ b: Bool ) { _value. store ( b ? 1 : 0 ) }
113
+
114
+ func load( ) -> Bool { return _value. load ( ) != 0 }
115
+
116
+ @discardableResult
117
+ func orAndFetch( _ b: Bool ) -> Bool {
118
+ return _value. orAndFetch ( b ? 1 : 0 ) != 0
119
+ }
120
+ }
121
+
106
122
func _printStackTrace( _ stackTrace: SourceLocStack ? ) {
107
123
guard let s = stackTrace, !s. locs. isEmpty else { return }
108
124
print ( " stacktrace: " )
@@ -112,10 +128,8 @@ func _printStackTrace(_ stackTrace: SourceLocStack?) {
112
128
}
113
129
}
114
130
115
- // FIXME: these variables should be atomic, since multiple threads can call
116
- // `expect*()` functions.
117
- var _anyExpectFailed = false
118
- var _seenExpectCrash = false
131
+ fileprivate var _anyExpectFailed = AtomicBool ( false )
132
+ fileprivate var _seenExpectCrash = AtomicBool ( false )
119
133
120
134
/// Run `body` and expect a failure to happen.
121
135
///
@@ -125,16 +139,16 @@ public func expectFailure(
125
139
stackTrace: SourceLocStack = SourceLocStack ( ) ,
126
140
showFrame: Bool = true ,
127
141
file: String = #file, line: UInt = #line, invoking body: ( ) -> Void ) {
128
- let startAnyExpectFailed = _anyExpectFailed
129
- _anyExpectFailed = false
142
+ let startAnyExpectFailed = _anyExpectFailed. load ( )
143
+ _anyExpectFailed. store ( false )
130
144
body ( )
131
- let endAnyExpectFailed = _anyExpectFailed
132
- _anyExpectFailed = false
145
+ let endAnyExpectFailed = _anyExpectFailed. load ( )
146
+ _anyExpectFailed. store ( false )
133
147
expectTrue (
134
148
endAnyExpectFailed, " running `body` should produce an expected failure " ,
135
149
stackTrace: stackTrace. pushIf ( showFrame, file: file, line: line)
136
150
)
137
- _anyExpectFailed = _anyExpectFailed || startAnyExpectFailed
151
+ _anyExpectFailed. orAndFetch ( startAnyExpectFailed)
138
152
}
139
153
140
154
public func identity( _ element: OpaqueValue < Int > ) -> OpaqueValue < Int > {
@@ -257,7 +271,7 @@ public func expectationFailure(
257
271
_ reason: String ,
258
272
trace message: String ,
259
273
stackTrace: SourceLocStack ) {
260
- _anyExpectFailed = true
274
+ _anyExpectFailed. store ( true )
261
275
stackTrace. print ( )
262
276
print ( reason, terminator: reason == " " ? " " : " \n " )
263
277
print ( message, terminator: message == " " ? " " : " \n " )
@@ -681,12 +695,12 @@ public func expectNotNil<T>(_ value: T?,
681
695
}
682
696
683
697
public func expectCrashLater( withMessage message: String = " " ) {
684
- print ( " \( _stdlibUnittestStreamPrefix) ;expectCrash; \( _anyExpectFailed) " )
698
+ print ( " \( _stdlibUnittestStreamPrefix) ;expectCrash; \( _anyExpectFailed. load ( ) ) " )
685
699
686
700
var stderr = _Stderr ( )
687
701
print ( " \( _stdlibUnittestStreamPrefix) ;expectCrash; \( message) " , to: & stderr)
688
702
689
- _seenExpectCrash = true
703
+ _seenExpectCrash. store ( true )
690
704
}
691
705
692
706
public func expectCrash( withMessage message: String = " " , executing: ( ) -> Void ) -> Never {
@@ -831,10 +845,10 @@ func _childProcess() {
831
845
}
832
846
833
847
let testSuite = _allTestSuites [ _testSuiteNameToIndex [ testSuiteName] !]
834
- _anyExpectFailed = false
848
+ _anyExpectFailed. store ( false )
835
849
testSuite. _runTest ( name: testName, parameter: testParameter)
836
850
837
- print ( " \( _stdlibUnittestStreamPrefix) ;end; \( _anyExpectFailed) " )
851
+ print ( " \( _stdlibUnittestStreamPrefix) ;end; \( _anyExpectFailed. load ( ) ) " )
838
852
839
853
var stderr = _Stderr ( )
840
854
print ( " \( _stdlibUnittestStreamPrefix) ;end " , to: & stderr)
@@ -1212,25 +1226,27 @@ class _ParentProcess {
1212
1226
if _runTestsInProcess {
1213
1227
if t. stdinText != nil {
1214
1228
print ( " The test \( fullTestName) requires stdin input and can't be run in-process, marking as failed " )
1215
- _anyExpectFailed = true
1229
+ _anyExpectFailed. store ( true )
1216
1230
} else if t. requiresOwnProcess {
1217
1231
print ( " The test \( fullTestName) requires running in a child process and can't be run in-process, marking as failed. " )
1218
- _anyExpectFailed = true
1232
+ _anyExpectFailed. store ( true )
1219
1233
} else {
1220
- _anyExpectFailed = false
1234
+ _anyExpectFailed. store ( false )
1221
1235
testSuite. _runTest ( name: t. name, parameter: testParameter)
1222
1236
}
1223
1237
} else {
1224
- ( _anyExpectFailed, expectCrash, childTerminationStatus, crashStdout,
1238
+ var anyExpectFailed = false
1239
+ ( anyExpectFailed, expectCrash, childTerminationStatus, crashStdout,
1225
1240
crashStderr) =
1226
1241
_runTestInChild ( testSuite, t. name, parameter: testParameter)
1242
+ _anyExpectFailed. store ( anyExpectFailed)
1227
1243
}
1228
1244
1229
1245
// Determine if the test passed, not taking XFAILs into account.
1230
1246
var testPassed = false
1231
1247
switch ( childTerminationStatus, expectCrash) {
1232
1248
case ( . none, false ) :
1233
- testPassed = !_anyExpectFailed
1249
+ testPassed = !_anyExpectFailed. load ( )
1234
1250
1235
1251
case ( . none, true ) :
1236
1252
testPassed = false
@@ -1241,7 +1257,7 @@ class _ParentProcess {
1241
1257
print ( " the test crashed unexpectedly " )
1242
1258
1243
1259
case ( . some, true ) :
1244
- testPassed = !_anyExpectFailed
1260
+ testPassed = !_anyExpectFailed. load ( )
1245
1261
}
1246
1262
if testPassed && t. crashOutputMatches. count > 0 {
1247
1263
// If we still think that the test passed, check if the crash
0 commit comments