blob: 6eb499a61693b4f817b87a43c0e15e7ce9a33698 [file] [log] [blame]
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//
// XCTAssert.swift
//
private enum _XCTAssertion {
case Equal
case EqualWithAccuracy
case GreaterThan
case GreaterThanOrEqual
case LessThan
case LessThanOrEqual
case NotEqual
case NotEqualWithAccuracy
case Nil
case NotNil
case True
case False
case Fail
case ThrowsError
var name: String? {
switch(self) {
case .Equal: return "XCTAssertEqual"
case .EqualWithAccuracy: return "XCTAssertEqualWithAccuracy"
case .GreaterThan: return "XCTAssertGreaterThan"
case .GreaterThanOrEqual: return "XCTAssertGreaterThanOrEqual"
case .LessThan: return "XCTAssertLessThan"
case .LessThanOrEqual: return "XCTAssertLessThanOrEqual"
case .NotEqual: return "XCTAssertNotEqual"
case .NotEqualWithAccuracy: return "XCTAssertNotEqualWithAccuracy"
case .Nil: return "XCTAssertNil"
case .NotNil: return "XCTAssertNotNil"
case .True: return "XCTAssertTrue"
case .False: return "XCTAssertFalse"
case .ThrowsError: return "XCTAssertThrowsError"
case .Fail: return nil
}
}
}
private enum _XCTAssertionResult {
case Success
case ExpectedFailure(String?)
case UnexpectedFailure(ErrorType)
var expected: Bool {
switch (self) {
case .UnexpectedFailure(_):
return false
default:
return true
}
}
func failureDescription(assertion: _XCTAssertion) -> String {
let explanation: String
switch (self) {
case .Success:
explanation = "passed"
case .ExpectedFailure(let details?):
explanation = "failed: \(details)"
case .ExpectedFailure(_):
explanation = "failed"
case .UnexpectedFailure(let error):
explanation = "threw error \"\(error)\""
}
if let name = assertion.name {
return "\(name) \(explanation)"
} else {
return explanation
}
}
}
private func _XCTEvaluateAssertion(assertion: _XCTAssertion, @autoclosure message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__, @noescape expression: () throws -> _XCTAssertionResult) {
let result: _XCTAssertionResult
do {
result = try expression()
} catch {
result = .UnexpectedFailure(error)
}
switch result {
case .Success:
return
default:
if let handler = XCTFailureHandler {
handler(XCTFailure(message: message(), failureDescription: result.failureDescription(assertion), expected: result.expected, file: file, line: line))
}
}
}
/// This function emits a test failure if the general Bool expression passed
/// to it evaluates to false.
///
/// - Requires: This and all other XCTAssert* functions must be called from
/// within a test method, as indicated by `XCTestCaseProvider.allTests`.
/// Assertion failures that occur outside of a test method will *not* be
/// reported as failures.
///
/// - Parameter expression: A boolean test. If it evaluates to false, the
/// assertion fails and emits a test failure.
/// - Parameter message: An optional message to use in the failure if the
/// assertion fails. If no message is supplied a default message is used.
/// - Parameter file: The file name to use in the error message if the assertion
/// fails. Default is the file containing the call to this function. It is
/// rare to provide this parameter when calling this function.
/// - Parameter line: The line number to use in the error message if the
/// assertion fails. Default is the line number of the call to this function
/// in the calling file. It is rare to provide this parameter when calling
/// this function.
///
/// - Note: It is rare to provide the `file` and `line` parameters when calling
/// this function, although you may consider doing so when creating your own
/// assertion functions. For example, consider the following custom assertion:
///
/// ```
/// // AssertEmpty.swift
///
/// func AssertEmpty<T>(elements: [T]) {
/// XCTAssertEqual(elements.count, 0, "Array is not empty")
/// }
/// ```
///
/// Calling this assertion will cause XCTest to report the failure occured
/// in the file where `AssertEmpty()` is defined, and on the line where
/// `XCTAssertEqual` is called from within that function:
///
/// ```
/// // MyFile.swift
///
/// AssertEmpty([1, 2, 3]) // Emits "AssertEmpty.swift:3: error: ..."
/// ```
///
/// To have XCTest properly report the file and line where the assertion
/// failed, you may specify the file and line yourself:
///
/// ```
/// // AssertEmpty.swift
///
/// func AssertEmpty<T>(elements: [T], file: StaticString = __FILE__, line: UInt = __LINE__) {
/// XCTAssertEqual(elements.count, 0, "Array is not empty", file: file, line: line)
/// }
/// ```
///
/// Now calling failures in `AssertEmpty` will be reported in the file and on
/// the line that the assert function is *called*, not where it is defined.
public func XCTAssert(@autoclosure expression: () throws -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
XCTAssertTrue(expression, message, file: file, line: line)
}
public func XCTAssertEqual<T: Equatable>(@autoclosure expression1: () throws -> T?, @autoclosure _ expression2: () throws -> T?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 == value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is not equal to (\"\(value2)\")")
}
}
}
public func XCTAssertEqual<T: Equatable>(@autoclosure expression1: () throws -> ArraySlice<T>, @autoclosure _ expression2: () throws -> ArraySlice<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 == value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is not equal to (\"\(value2)\")")
}
}
}
public func XCTAssertEqual<T: Equatable>(@autoclosure expression1: () throws -> ContiguousArray<T>, @autoclosure _ expression2: () throws -> ContiguousArray<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 == value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is not equal to (\"\(value2)\")")
}
}
}
public func XCTAssertEqual<T: Equatable>(@autoclosure expression1: () throws -> [T], @autoclosure _ expression2: () throws -> [T], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 == value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is not equal to (\"\(value2)\")")
}
}
}
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__) {
_XCTEvaluateAssertion(.Equal, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 == value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is not equal to (\"\(value2)\")")
}
}
}
public func XCTAssertEqualWithAccuracy<T: FloatingPointType>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, accuracy: T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.EqualWithAccuracy, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if abs(value1.distanceTo(value2)) <= abs(accuracy.distanceTo(T(0))) {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is not equal to (\"\(value2)\") +/- (\"\(accuracy)\")")
}
}
}
public func XCTAssertFalse(@autoclosure expression: () throws -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.False, message: message, file: file, line: line) {
let value = try expression()
if !value.boolValue {
return .Success
} else {
return .ExpectedFailure(nil)
}
}
}
public func XCTAssertGreaterThan<T: Comparable>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.GreaterThan, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 > value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is not greater than (\"\(value2)\")")
}
}
}
public func XCTAssertGreaterThanOrEqual<T: Comparable>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.GreaterThanOrEqual, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 >= value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is less than (\"\(value2)\")")
}
}
}
public func XCTAssertLessThan<T: Comparable>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.LessThan, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 < value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is not less than (\"\(value2)\")")
}
}
}
public func XCTAssertLessThanOrEqual<T: Comparable>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.LessThanOrEqual, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 <= value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is greater than (\"\(value2)\")")
}
}
}
public func XCTAssertNil(@autoclosure expression: () throws -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.Nil, message: message, file: file, line: line) {
let value = try expression()
if value == nil {
return .Success
} else {
return .ExpectedFailure("\"\(value!)\"")
}
}
}
public func XCTAssertNotEqual<T: Equatable>(@autoclosure expression1: () throws -> T?, @autoclosure _ expression2: () throws -> T?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 != value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is equal to (\"\(value2)\")")
}
}
}
public func XCTAssertNotEqual<T: Equatable>(@autoclosure expression1: () throws -> ContiguousArray<T>, @autoclosure _ expression2: () throws -> ContiguousArray<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 != value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is equal to (\"\(value2)\")")
}
}
}
public func XCTAssertNotEqual<T: Equatable>(@autoclosure expression1: () throws -> ArraySlice<T>, @autoclosure _ expression2: () throws -> ArraySlice<T>, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 != value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is equal to (\"\(value2)\")")
}
}
}
public func XCTAssertNotEqual<T: Equatable>(@autoclosure expression1: () throws -> [T], @autoclosure _ expression2: () throws -> [T], @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 != value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is equal to (\"\(value2)\")")
}
}
}
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__) {
_XCTEvaluateAssertion(.NotEqual, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if value1 != value2 {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is equal to (\"\(value2)\")")
}
}
}
public func XCTAssertNotEqualWithAccuracy<T: FloatingPointType>(@autoclosure expression1: () throws -> T, @autoclosure _ expression2: () throws -> T, _ accuracy: T, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.NotEqualWithAccuracy, message: message, file: file, line: line) {
let (value1, value2) = (try expression1(), try expression2())
if abs(value1.distanceTo(value2)) > abs(accuracy.distanceTo(T(0))) {
return .Success
} else {
return .ExpectedFailure("(\"\(value1)\") is equal to (\"\(value2)\") +/- (\"\(accuracy)\")")
}
}
}
public func XCTAssertNotNil(@autoclosure expression: () throws -> Any?, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.Nil, message: message, file: file, line: line) {
let value = try expression()
if value != nil {
return .Success
} else {
return .ExpectedFailure(nil)
}
}
}
public func XCTAssertTrue(@autoclosure expression: () throws -> BooleanType, @autoclosure _ message: () -> String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.True, message: message, file: file, line: line) {
let value = try expression()
if value.boolValue {
return .Success
} else {
return .ExpectedFailure(nil)
}
}
}
public func XCTFail(message: String = "", file: StaticString = __FILE__, line: UInt = __LINE__) {
_XCTEvaluateAssertion(.Fail, message: message, file: file, line: line) {
return .ExpectedFailure(nil)
}
}
public func XCTAssertThrowsError<T>(@autoclosure expression: () throws -> T, _ message: String = "", file: StaticString = __FILE__, line: UInt = __LINE__, _ errorHandler: (error: ErrorType) -> Void = { _ in }) {
_XCTEvaluateAssertion(.ThrowsError, message: message, file: file, line: line) {
var caughtErrorOptional: ErrorType?
do {
_ = try expression()
} catch {
caughtErrorOptional = error
}
if let caughtError = caughtErrorOptional {
errorHandler(error: caughtError)
return .Success
} else {
return .ExpectedFailure("did not throw error")
}
}
}