You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Over-fulfilling XCTestExpectation records test failure even when assertForOverFulfill is disabled
This fixes an issue where calling `XCTestExpectation.fulfill()` more times than expected will still
record a test failure, even if its `assertForOverFulfill` property is set to `false` (the default).
In this Corelibs version of XCTest, `assertForOverFulfill` is only guarding a `fatalError`, but we
still unconditionally record a test failure which causes this symptom. This means the behavior is
different than in the Xcode copy of XCTest, where if `assertForOverFulfill` is false, neither an
NSAssert exception nor a test failure occurs. Swift doesn't support exceptions, so I believe the
unconditional test failure was added here in the past in an attempt to emulate that behavior.
The fix here removes the `fatalError()` entirely, and leaves the test failure-recording logic but
makes it conditional on `assertForOverFulfill` being true. The behavior will still differ from Xcode's
copy of XCTest, but I think it's justifiable and closer to what users expect. The use of NSAssert in
the (ObjC) Xcode copy of XCTest was largely an attempt to get better diagnostics when an over-fulfill
occurred by capturing the backtrace of that fulfillment. This is especially important with
XCTestExpectations, since they are meant for testing async conditions, and an over-fulfillment could
occur after their test has completed, so without a backtrace or some better state tracking the test
failure could be misattributed to a subsequent test once it becomes "current". Corelibs XCTest doesn't
suffer from this diagnostics problem as much since it already captures `file:line:` in `fulfill()`.
Moreover, there have been requests to change that behavior in ObjC XCTest and use a "plain" test failure
everywhere instead of NSAssert.
So this PR gets us closer to that goal, starting here in Corelibs, by removing the fatalError and only
leaving the existing test failure-recording behavior. To fully realize it and ensure these test
failures are attributed to the correct test, we'll need to make further internal state tracking
enhancements (63874139), but for now this seems like a good incremental step, considering that Corelibs
already performed this test failure recording. I've also added a new test and modified an existing one.
rdar://problem/62202297
Copy file name to clipboardExpand all lines: Tests/Functional/Asynchronous/Expectations/main.swift
+40-3Lines changed: 40 additions & 3 deletions
Original file line number
Diff line number
Diff line change
@@ -338,6 +338,39 @@ class ExpectationsTestCase: XCTestCase {
338
338
waitForExpectations(timeout:0.2)
339
339
}
340
340
341
+
// PRAGMA MARK: - assertForOverFulfill
342
+
343
+
// CHECK: Test Case 'ExpectationsTestCase.test_assertForOverfulfill_disabled' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
344
+
// CHECK: Test Case 'ExpectationsTestCase.test_assertForOverfulfill_disabled' passed \(\d+\.\d+ seconds\)
345
+
func test_assertForOverfulfill_disabled(){
346
+
letfoo=XCTestExpectation(description:"foo")
347
+
XCTAssertFalse(foo.assertForOverFulfill,"assertForOverFulfill should be disabled by default")
348
+
foo.fulfill()
349
+
foo.fulfill()
350
+
}
351
+
352
+
// CHECK: Test Case 'ExpectationsTestCase.test_assertForOverfulfill_failure' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
353
+
// CHECK: .*[/\\]Tests[/\\]Functional[/\\]Asynchronous[/\\]Expectations[/\\]main.swift:[[@LINE+7]]: error: ExpectationsTestCase.test_assertForOverfulfill_failure : API violation - multiple calls made to XCTestExpectation.fulfill\(\) for rob.
354
+
// CHECK: .*[/\\]Tests[/\\]Functional[/\\]Asynchronous[/\\]Expectations[/\\]main.swift:[[@LINE+16]]: error: ExpectationsTestCase.test_assertForOverfulfill_failure : API violation - multiple calls made to XCTestExpectation.fulfill\(\) for rob.
355
+
// CHECK: Test Case 'ExpectationsTestCase.test_assertForOverfulfill_failure' failed \(\d+\.\d+ seconds\)
Copy file name to clipboardExpand all lines: Tests/Functional/Asynchronous/Misuse/main.swift
+3-25Lines changed: 3 additions & 25 deletions
Original file line number
Diff line number
Diff line change
@@ -28,41 +28,19 @@ class MisuseTestCase: XCTestCase {
28
28
self.waitForExpectations(timeout:0.1)
29
29
}
30
30
31
-
// CHECK: Test Case 'MisuseTestCase.test_whenExpectationIsFulfilledMultipleTimes_fails' started at \d+-\d+-\d+ \d+:\d+:\d+\.\d+
32
-
// CHECK: .*[/\\]Tests[/\\]Functional[/\\]Asynchronous[/\\]Misuse[/\\]main.swift:[[@LINE+6]]: error: MisuseTestCase.test_whenExpectationIsFulfilledMultipleTimes_fails : API violation - multiple calls made to XCTestExpectation.fulfill\(\) for rob.
33
-
// CHECK: .*[/\\]Tests[/\\]Functional[/\\]Asynchronous[/\\]Misuse[/\\]main.swift:[[@LINE+15]]: error: MisuseTestCase.test_whenExpectationIsFulfilledMultipleTimes_fails : API violation - multiple calls made to XCTestExpectation.fulfill\(\) for rob.
34
-
// CHECK: Test Case 'MisuseTestCase.test_whenExpectationIsFulfilledMultipleTimes_fails' failed \(\d+\.\d+ seconds\)
0 commit comments