Skip to content

Commit e5cf2f4

Browse files
committed
Add throwing assertion expressions.
Allow assertion expressions themselves to throw errors, which will then be treated as unexpected test failures. This reduces the need to write do...catch boilerplate in test code that is intended to test function results rather than error conditions. Addresses rdar://problem/23778444.
1 parent e5c0cb3 commit e5cf2f4

File tree

2 files changed

+77
-46
lines changed

2 files changed

+77
-46
lines changed

Sources/XCTest/XCTAssert.swift

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ private enum _XCTAssertion {
4949
private enum _XCTAssertionResult {
5050
case Success
5151
case ExpectedFailure(String?)
52+
case UnexpectedFailure(ErrorType)
53+
54+
var expected: Bool {
55+
switch (self) {
56+
case .UnexpectedFailure(_):
57+
return false
58+
default:
59+
return true
60+
}
61+
}
5262

5363
func failureDescription(assertion: _XCTAssertion) -> String {
5464
let explanation: String
@@ -59,6 +69,8 @@ private enum _XCTAssertionResult {
5969
explanation = "failed: \(details)"
6070
case .ExpectedFailure(_):
6171
explanation = "failed"
72+
case .UnexpectedFailure(let error):
73+
explanation = "threw error \"\(error)\""
6274
}
6375

6476
if let name = assertion.name {
@@ -69,16 +81,21 @@ private enum _XCTAssertionResult {
6981
}
7082
}
7183

72-
private func _XCTEvaluateAssertion(assertion: _XCTAssertion, @autoclosure message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__, @noescape expression: () -> _XCTAssertionResult) {
73-
let result = expression()
84+
private func _XCTEvaluateAssertion(assertion: _XCTAssertion, @autoclosure message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__, @noescape expression: () throws -> _XCTAssertionResult) {
85+
let result: _XCTAssertionResult
86+
do {
87+
result = try expression()
88+
} catch {
89+
result = .UnexpectedFailure(error)
90+
}
7491

7592
switch result {
7693
case .Success:
7794
return
7895

7996
default:
8097
if let handler = XCTFailureHandler {
81-
handler(XCTFailure(message: message(), failureDescription: result.failureDescription(assertion), expected: true, file: file, line: line))
98+
handler(XCTFailure(message: message(), failureDescription: result.failureDescription(assertion), expected: result.expected, file: file, line: line))
8299
}
83100
}
84101
}
@@ -138,13 +155,13 @@ private func _XCTEvaluateAssertion(assertion: _XCTAssertion, @autoclosure messag
138155
///
139156
/// Now calling failures in `AssertEmpty` will be reported in the file and on
140157
/// the line that the assert function is *called*, not where it is defined.
141-
public func XCTAssert(@autoclosure expression: () -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
158+
public func XCTAssert(@autoclosure expression: () throws -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
142159
XCTAssertTrue(expression, message, file: file, line: line)
143160
}
144161

145-
public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () -> T?, @autoclosure _ expression2: () -> T?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
162+
public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () throws -> T?, @autoclosure _ expression2: () throws -> T?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
146163
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
147-
let (value1, value2) = (expression1(), expression2())
164+
let (value1, value2) = (try expression1(), try expression2())
148165
if value1 == value2 {
149166
return .Success
150167
} else {
@@ -153,9 +170,9 @@ public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () -> T?, @a
153170
}
154171
}
155172

156-
public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () -> ArraySlice<T>, @autoclosure _ expression2: () -> ArraySlice<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
173+
public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () throws -> ArraySlice<T>, @autoclosure _ expression2: () throws -> ArraySlice<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
157174
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
158-
let (value1, value2) = (expression1(), expression2())
175+
let (value1, value2) = (try expression1(), try expression2())
159176
if value1 == value2 {
160177
return .Success
161178
} else {
@@ -164,9 +181,9 @@ public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () -> ArrayS
164181
}
165182
}
166183

167-
public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () -> ContiguousArray<T>, @autoclosure _ expression2: () -> ContiguousArray<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
184+
public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () throws -> ContiguousArray<T>, @autoclosure _ expression2: () throws -> ContiguousArray<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
168185
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
169-
let (value1, value2) = (expression1(), expression2())
186+
let (value1, value2) = (try expression1(), try expression2())
170187
if value1 == value2 {
171188
return .Success
172189
} else {
@@ -175,9 +192,9 @@ public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () -> Contig
175192
}
176193
}
177194

178-
public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () -> [T], @autoclosure _ expression2: () -> [T], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
195+
public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () throws -> [T], @autoclosure _ expression2: () throws -> [T], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
179196
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
180-
let (value1, value2) = (expression1(), expression2())
197+
let (value1, value2) = (try expression1(), try expression2())
181198
if value1 == value2 {
182199
return .Success
183200
} else {
@@ -186,9 +203,9 @@ public func XCTAssertEqual<T : Equatable>(@autoclosure expression1: () -> [T], @
186203
}
187204
}
188205

189-
public func XCTAssertEqual<T, U : Equatable>(@autoclosure expression1: () -> [T : U], @autoclosure _ expression2: () -> [T : U], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
206+
public func XCTAssertEqual<T, U : Equatable>(@autoclosure expression1: () throws -> [T : U], @autoclosure _ expression2: () throws -> [T : U], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
190207
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
191-
let (value1, value2) = (expression1(), expression2())
208+
let (value1, value2) = (try expression1(), try expression2())
192209
if value1 == value2 {
193210
return .Success
194211
} else {
@@ -197,9 +214,9 @@ public func XCTAssertEqual<T, U : Equatable>(@autoclosure expression1: () -> [T
197214
}
198215
}
199216

200-
public func XCTAssertEqualWithAccuracy<T : FloatingPointType>(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, accuracy: T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
217+
public func XCTAssertEqualWithAccuracy<T : FloatingPointType>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, accuracy: T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
201218
_XCTEvaluateAssertion(.EqualWithAccuracy, message: message, file: file, line: line) {
202-
let (value1, value2) = (expression1(), expression2())
219+
let (value1, value2) = (try expression1(), try expression2())
203220
if abs(value1.distanceTo(value2)) <= abs(accuracy.distanceTo(T(0))) {
204221
return .Success
205222
} else {
@@ -208,9 +225,9 @@ public func XCTAssertEqualWithAccuracy<T : FloatingPointType>(@autoclosure expre
208225
}
209226
}
210227

211-
public func XCTAssertFalse(@autoclosure expression: () -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
228+
public func XCTAssertFalse(@autoclosure expression: () throws -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
212229
_XCTEvaluateAssertion(.False, message: message, file: file, line: line) {
213-
let value = expression()
230+
let value = try expression()
214231
if !value.boolValue {
215232
return .Success
216233
} else {
@@ -219,9 +236,9 @@ public func XCTAssertFalse(@autoclosure expression: () -> BooleanType, @autoclos
219236
}
220237
}
221238

222-
public func XCTAssertGreaterThan<T : Comparable>(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
239+
public func XCTAssertGreaterThan<T : Comparable>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
223240
_XCTEvaluateAssertion(.GreaterThan, message: message, file: file, line: line) {
224-
let (value1, value2) = (expression1(), expression2())
241+
let (value1, value2) = (try expression1(), try expression2())
225242
if value1 > value2 {
226243
return .Success
227244
} else {
@@ -230,9 +247,9 @@ public func XCTAssertGreaterThan<T : Comparable>(@autoclosure expression1: () ->
230247
}
231248
}
232249

233-
public func XCTAssertGreaterThanOrEqual<T : Comparable>(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
250+
public func XCTAssertGreaterThanOrEqual<T : Comparable>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
234251
_XCTEvaluateAssertion(.GreaterThanOrEqual, message: message, file: file, line: line) {
235-
let (value1, value2) = (expression1(), expression2())
252+
let (value1, value2) = (try expression1(), try expression2())
236253
if value1 >= value2 {
237254
return .Success
238255
} else {
@@ -241,9 +258,9 @@ public func XCTAssertGreaterThanOrEqual<T : Comparable>(@autoclosure expression1
241258
}
242259
}
243260

244-
public func XCTAssertLessThan<T : Comparable>(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
261+
public func XCTAssertLessThan<T : Comparable>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
245262
_XCTEvaluateAssertion(.LessThan, message: message, file: file, line: line) {
246-
let (value1, value2) = (expression1(), expression2())
263+
let (value1, value2) = (try expression1(), try expression2())
247264
if value1 < value2 {
248265
return .Success
249266
} else {
@@ -252,9 +269,9 @@ public func XCTAssertLessThan<T : Comparable>(@autoclosure expression1: () -> T,
252269
}
253270
}
254271

255-
public func XCTAssertLessThanOrEqual<T : Comparable>(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
272+
public func XCTAssertLessThanOrEqual<T : Comparable>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
256273
_XCTEvaluateAssertion(.LessThanOrEqual, message: message, file: file, line: line) {
257-
let (value1, value2) = (expression1(), expression2())
274+
let (value1, value2) = (try expression1(), try expression2())
258275
if value1 <= value2 {
259276
return .Success
260277
} else {
@@ -263,9 +280,9 @@ public func XCTAssertLessThanOrEqual<T : Comparable>(@autoclosure expression1: (
263280
}
264281
}
265282

266-
public func XCTAssertNil(@autoclosure expression: () -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
283+
public func XCTAssertNil(@autoclosure expression: () throws -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
267284
_XCTEvaluateAssertion(.Nil, message: message, file: file, line: line) {
268-
let value = expression()
285+
let value = try expression()
269286
if value == nil {
270287
return .Success
271288
} else {
@@ -274,9 +291,9 @@ public func XCTAssertNil(@autoclosure expression: () -> Any?, @autoclosure _ mes
274291
}
275292
}
276293

277-
public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () -> T?, @autoclosure _ expression2: () -> T?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
294+
public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () throws -> T?, @autoclosure _ expression2: () throws -> T?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
278295
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
279-
let (value1, value2) = (expression1(), expression2())
296+
let (value1, value2) = (try expression1(), try expression2())
280297
if value1 != value2 {
281298
return .Success
282299
} else {
@@ -285,9 +302,9 @@ public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () -> T?,
285302
}
286303
}
287304

288-
public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () -> ContiguousArray<T>, @autoclosure _ expression2: () -> ContiguousArray<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
305+
public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () throws -> ContiguousArray<T>, @autoclosure _ expression2: () throws -> ContiguousArray<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
289306
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
290-
let (value1, value2) = (expression1(), expression2())
307+
let (value1, value2) = (try expression1(), try expression2())
291308
if value1 != value2 {
292309
return .Success
293310
} else {
@@ -296,9 +313,9 @@ public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () -> Con
296313
}
297314
}
298315

299-
public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () -> ArraySlice<T>, @autoclosure _ expression2: () -> ArraySlice<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
316+
public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () throws -> ArraySlice<T>, @autoclosure _ expression2: () throws -> ArraySlice<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
300317
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
301-
let (value1, value2) = (expression1(), expression2())
318+
let (value1, value2) = (try expression1(), try expression2())
302319
if value1 != value2 {
303320
return .Success
304321
} else {
@@ -307,9 +324,9 @@ public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () -> Arr
307324
}
308325
}
309326

310-
public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () -> [T], @autoclosure _ expression2: () -> [T], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
327+
public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () throws -> [T], @autoclosure _ expression2: () throws -> [T], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
311328
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
312-
let (value1, value2) = (expression1(), expression2())
329+
let (value1, value2) = (try expression1(), try expression2())
313330
if value1 != value2 {
314331
return .Success
315332
} else {
@@ -318,9 +335,9 @@ public func XCTAssertNotEqual<T : Equatable>(@autoclosure expression1: () -> [T]
318335
}
319336
}
320337

321-
public func XCTAssertNotEqual<T, U : Equatable>(@autoclosure expression1: () -> [T : U], @autoclosure _ expression2: () -> [T : U], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
338+
public func XCTAssertNotEqual<T, U : Equatable>(@autoclosure expression1: () throws -> [T : U], @autoclosure _ expression2: () throws -> [T : U], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
322339
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
323-
let (value1, value2) = (expression1(), expression2())
340+
let (value1, value2) = (try expression1(), try expression2())
324341
if value1 != value2 {
325342
return .Success
326343
} else {
@@ -329,9 +346,9 @@ public func XCTAssertNotEqual<T, U : Equatable>(@autoclosure expression1: () ->
329346
}
330347
}
331348

332-
public func XCTAssertNotEqualWithAccuracy<T : FloatingPointType>(@autoclosure expression1: () -> T, @autoclosure _ expression2: () -> T, _ accuracy: T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
349+
public func XCTAssertNotEqualWithAccuracy<T : FloatingPointType>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, _ accuracy: T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
333350
_XCTEvaluateAssertion(.NotEqualWithAccuracy, message: message, file: file, line: line) {
334-
let (value1, value2) = (expression1(), expression2())
351+
let (value1, value2) = (try expression1(), try expression2())
335352
if abs(value1.distanceTo(value2)) > abs(accuracy.distanceTo(T(0))) {
336353
return .Success
337354
} else {
@@ -340,9 +357,9 @@ public func XCTAssertNotEqualWithAccuracy<T : FloatingPointType>(@autoclosure ex
340357
}
341358
}
342359

343-
public func XCTAssertNotNil(@autoclosure expression: () -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
360+
public func XCTAssertNotNil(@autoclosure expression: () throws -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
344361
_XCTEvaluateAssertion(.Nil, message: message, file: file, line: line) {
345-
let value = expression()
362+
let value = try expression()
346363
if value != nil {
347364
return .Success
348365
} else {
@@ -351,9 +368,9 @@ public func XCTAssertNotNil(@autoclosure expression: () -> Any?, @autoclosure _
351368
}
352369
}
353370

354-
public func XCTAssertTrue(@autoclosure expression: () -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
371+
public func XCTAssertTrue(@autoclosure expression: () throws -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
355372
_XCTEvaluateAssertion(.True, message: message, file: file, line: line) {
356-
let value = expression()
373+
let value = try expression()
357374
if value.boolValue {
358375
return .Success
359376
} else {

0 commit comments

Comments
 (0)