blob: dd94dd8d05bc0a7c4f0b5afb23bc80dac24399ff [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
case noThrow
var name: String? {
switch(self) {
case .equal: return "XCTAssertEqual"
case .equalWithAccuracy: return "XCTAssertEqual"
case .greaterThan: return "XCTAssertGreaterThan"
case .greaterThanOrEqual: return "XCTAssertGreaterThanOrEqual"
case .lessThan: return "XCTAssertLessThan"
case .lessThanOrEqual: return "XCTAssertLessThanOrEqual"
case .notEqual: return "XCTAssertNotEqual"
case .notEqualWithAccuracy: return "XCTAssertNotEqual"
case .`nil`: return "XCTAssertNil"
case .notNil: return "XCTAssertNotNil"
case .`true`: return "XCTAssertTrue"
case .`false`: return "XCTAssertFalse"
case .throwsError: return "XCTAssertThrowsError"
case .noThrow: return "XCTAssertNoThrow"
case .fail: return nil
}
}
}
private enum _XCTAssertionResult {
case success
case expectedFailure(String?)
case unexpectedFailure(Swift.Error)
var isExpected: 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, message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line, expression: () throws -> _XCTAssertionResult) {
let result: _XCTAssertionResult
do {
result = try expression()
} catch {
result = .unexpectedFailure(error)
}
switch result {
case .success:
return
default:
if let currentTestCase = XCTCurrentTestCase {
currentTestCase.recordFailure(
withDescription: "\(result.failureDescription(assertion)) - \(message())",
inFile: String(describing: file),
atLine: Int(line),
expected: result.isExpected)
}
}
}
/// This function emits a test failure if the general `Boolean` expression passed
/// to it evaluates to `false`.
///
/// - Requires: This and all other XCTAssert* functions must be called from
/// within a test method, as passed to `XCTMain`.
/// 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 occurred
/// 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(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
XCTAssertTrue(expression, message, file: file, line: line)
}
public func XCTAssertEqual<T: Equatable>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> T?, _ expression2: @autoclosure () throws -> T?, _ message: @autoclosure () -> 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("(\"\(String(describing: value1))\") is not equal to (\"\(String(describing: value2))\")")
}
}
}
public func XCTAssertEqual<T: Equatable>(_ expression1: @autoclosure () throws -> ArraySlice<T>, _ expression2: @autoclosure () throws -> ArraySlice<T>, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> ContiguousArray<T>, _ expression2: @autoclosure () throws -> ContiguousArray<T>, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> [T], _ expression2: @autoclosure () throws -> [T], _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> [T: U], _ expression2: @autoclosure () throws -> [T: U], _ message: @autoclosure () -> 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: FloatingPoint>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, accuracy: T, _ message: @autoclosure () -> 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.distance(to: value2)) <= abs(accuracy.distance(to: T(0))) {
return .success
} else {
return .expectedFailure("(\"\(value1)\") is not equal to (\"\(value2)\") +/- (\"\(accuracy)\")")
}
}
}
@available(*, deprecated, renamed: "XCTAssertEqual(_:_:accuracy:file:line:)")
public func XCTAssertEqualWithAccuracy<T: FloatingPoint>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
XCTAssertEqual(expression1, expression2, accuracy: accuracy, message, file: file, line: line)
}
public func XCTAssertFalse(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
_XCTEvaluateAssertion(.`false`, message: message, file: file, line: line) {
let value = try expression()
if !value {
return .success
} else {
return .expectedFailure(nil)
}
}
}
public func XCTAssertGreaterThan<T: Comparable>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> 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(_ expression: @autoclosure () throws -> Any?, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> T?, _ expression2: @autoclosure () throws -> T?, _ message: @autoclosure () -> 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("(\"\(String(describing: value1))\") is equal to (\"\(String(describing: value2))\")")
}
}
}
public func XCTAssertNotEqual<T: Equatable>(_ expression1: @autoclosure () throws -> ContiguousArray<T>, _ expression2: @autoclosure () throws -> ContiguousArray<T>, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> ArraySlice<T>, _ expression2: @autoclosure () throws -> ArraySlice<T>, _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> [T], _ expression2: @autoclosure () throws -> [T], _ message: @autoclosure () -> 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>(_ expression1: @autoclosure () throws -> [T: U], _ expression2: @autoclosure () throws -> [T: U], _ message: @autoclosure () -> 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: FloatingPoint>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, accuracy: T, _ message: @autoclosure () -> 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.distance(to: value2)) > abs(accuracy.distance(to: T(0))) {
return .success
} else {
return .expectedFailure("(\"\(value1)\") is equal to (\"\(value2)\") +/- (\"\(accuracy)\")")
}
}
}
@available(*, deprecated, renamed: "XCTAssertNotEqual(_:_:accuracy:file:line:)")
public func XCTAssertNotEqualWithAccuracy<T: FloatingPoint>(_ expression1: @autoclosure () throws -> T, _ expression2: @autoclosure () throws -> T, _ accuracy: T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
XCTAssertNotEqual(expression1, expression2, accuracy: accuracy, message, file: file, line: line)
}
public func XCTAssertNotNil(_ expression: @autoclosure () throws -> Any?, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
_XCTEvaluateAssertion(.notNil, message: message, file: file, line: line) {
let value = try expression()
if value != nil {
return .success
} else {
return .expectedFailure(nil)
}
}
}
public func XCTAssertTrue(_ expression: @autoclosure () throws -> Bool, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
_XCTEvaluateAssertion(.`true`, message: message, file: file, line: line) {
let value = try expression()
if value {
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>(_ expression: @autoclosure () throws -> T, _ message: String = "", file: StaticString = #file, line: UInt = #line, _ errorHandler: (_ error: Swift.Error) -> Void = { _ in }) {
_XCTEvaluateAssertion(.throwsError, message: message, file: file, line: line) {
var caughtErrorOptional: Swift.Error?
do {
_ = try expression()
} catch {
caughtErrorOptional = error
}
if let caughtError = caughtErrorOptional {
errorHandler(caughtError)
return .success
} else {
return .expectedFailure("did not throw error")
}
}
}
public func XCTAssertNoThrow<T>(_ expression: @autoclosure () throws -> T, _ message: @autoclosure () -> String = "", file: StaticString = #file, line: UInt = #line) {
_XCTEvaluateAssertion(.noThrow, message: message, file: file, line: line) {
do {
_ = try expression()
return .success
} catch let error {
return .expectedFailure("threw error \"\(error)\"")
}
}
}