Skip to content

Commit 3bab9bd

Browse files
committed
Add support for unexpected failures
An “unexpected failure” is a failure that wasn’t accounted for by an assertion.
1 parent 2f785e1 commit 3bab9bd

File tree

3 files changed

+15
-7
lines changed

3 files changed

+15
-7
lines changed

XCTest/XCTAssert.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The primitive assertion function for XCTest. All other XCTAssert* functions are
2020
public func XCTAssert(@autoclosure expression: () -> BooleanType, _ message: String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
2121
if !expression().boolValue {
2222
if let test = XCTCurrentTestCase {
23-
test.testFailure(message, file: file, line: line)
23+
test.testFailure(message, expected: true, file: file, line: line)
2424
}
2525
}
2626
}

XCTest/XCTest.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,12 @@ import Darwin
2020

2121
struct XCTFailure {
2222
var message: String
23+
var expected: Bool
2324
var file: StaticString
2425
var line: UInt
2526

2627
func emit(method: String) {
27-
print("\(file):\(line): error: \(method) : \(message)")
28+
print("\(file):\(line): \(expected ? "" : "unexpected ")error: \(method) : \(message)")
2829
}
2930
}
3031

@@ -33,6 +34,9 @@ internal struct XCTRun {
3334
var method: String
3435
var passed: Bool
3536
var failures: [XCTFailure]
37+
var unexpectedFailures: [XCTFailure] {
38+
get { return failures.filter({ failure -> Bool in failure.expected == false }) }
39+
}
3640
}
3741

3842
/// Starts a test run for the specified test cases.
@@ -43,7 +47,7 @@ internal struct XCTRun {
4347
for testCase in testCases {
4448
testCase.invokeTest()
4549
}
46-
let (totalDuration, totalFailures) = XCTAllRuns.reduce((0.0, 0)) { ($0.0 + $1.duration, $0.1 + $1.failures.count) }
50+
let (totalDuration, totalFailures, totalUnexpectedFailures) = XCTAllRuns.reduce((0.0, 0, 0)) { totals, run in (totals.0 + run.duration, totals.1 + run.failures.count, totals.2 + run.unexpectedFailures.count) }
4751

4852
var testCountSuffix = "s"
4953
if XCTAllRuns.count == 1 {
@@ -54,7 +58,7 @@ internal struct XCTRun {
5458
failureSuffix = ""
5559
}
5660
let averageDuration = totalDuration / Double(XCTAllRuns.count)
57-
print("Total executed \(XCTAllRuns.count) test\(testCountSuffix), with \(totalFailures) failure\(failureSuffix) (0 unexpected) in \(round(averageDuration * 1000.0) / 1000.0) (\(round(totalDuration * 1000.0) / 1000.0)) seconds")
61+
print("Total executed \(XCTAllRuns.count) test\(testCountSuffix), with \(totalFailures) failure\(failureSuffix) (\(totalUnexpectedFailures) unexpected) in \(round(averageDuration * 1000.0) / 1000.0) (\(round(totalDuration * 1000.0) / 1000.0)) seconds")
5862
exit(totalFailures > 0 ? 1 : 0)
5963
}
6064

XCTest/XCTestCase.swift

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ extension XCTestCase {
3636
let tests = self.allTests
3737
var totalDuration = 0.0
3838
var totalFailures = 0
39+
var unexpectedFailures = 0
3940
for (name, test) in tests {
4041
XCTCurrentTestCase = self
4142
let method = "\(self.dynamicType).\(name)"
@@ -57,6 +58,9 @@ extension XCTestCase {
5758
for failure in XCTCurrentFailures {
5859
failure.emit(method)
5960
totalFailures++
61+
if failure.expected == false {
62+
unexpectedFailures++
63+
}
6064
}
6165
var result = "passed"
6266
if XCTCurrentFailures.count > 0 {
@@ -78,15 +82,15 @@ extension XCTestCase {
7882
let averageDuration = totalDuration / Double(tests.count)
7983

8084

81-
print("Executed \(tests.count) test\(testCountSuffix), with \(totalFailures) failure\(failureSuffix) (0 unexpected) in \(round(averageDuration * 1000.0) / 1000.0) (\(round(totalDuration * 1000.0) / 1000.0)) seconds")
85+
print("Executed \(tests.count) test\(testCountSuffix), with \(totalFailures) failure\(failureSuffix) \(unexpectedFailures) unexpected) in \(round(averageDuration * 1000.0) / 1000.0) (\(round(totalDuration * 1000.0) / 1000.0)) seconds")
8286
}
8387

8488
// This function is for the use of XCTestCase only, but we must make it public or clients will get a link failure when using XCTest (23476006)
85-
public func testFailure(message: String, file: StaticString , line: UInt) {
89+
public func testFailure(message: String, expected: Bool, file: StaticString , line: UInt) {
8690
if !continueAfterFailure {
8791
assert(false, message, file: file, line: line)
8892
} else {
89-
XCTCurrentFailures.append(XCTFailure(message: message, file: file, line: line))
93+
XCTCurrentFailures.append(XCTFailure(message: message, expected: expected, file: file, line: line))
9094
}
9195
}
9296

0 commit comments

Comments
 (0)