diff --git a/Sources/Nimble/Matchers/Predicate.swift b/Sources/Nimble/Matchers/Predicate.swift deleted file mode 100644 index 715d69e2..00000000 --- a/Sources/Nimble/Matchers/Predicate.swift +++ /dev/null @@ -1,289 +0,0 @@ -// New Matcher API -// - -/// A Predicate is part of the new matcher API that provides assertions to expectations. -/// -/// Given a code snippet: -/// -/// expect(1).to(equal(2)) -/// ^^^^^^^^ -/// Called a "matcher" -/// -/// A matcher consists of two parts a constructor function and the Predicate. The term Predicate -/// is used as a separate name from Matcher to help transition custom matchers to the new Nimble -/// matcher API. -/// -/// The Predicate provide the heavy lifting on how to assert against a given value. Internally, -/// predicates are simple wrappers around closures to provide static type information and -/// allow composition and wrapping of existing behaviors. -public struct Predicate { - fileprivate var matcher: (Expression) throws -> PredicateResult - - /// Constructs a predicate that knows how take a given value - public init(_ matcher: @escaping (Expression) throws -> PredicateResult) { - self.matcher = matcher - } - - /// Uses a predicate on a given value to see if it passes the predicate. - /// - /// @param expression The value to run the predicate's logic against - /// @returns A predicate result indicate passing or failing and an associated error message. - public func satisfies(_ expression: Expression) throws -> PredicateResult { - return try matcher(expression) - } -} - -/// Provides convenience helpers to defining predicates -extension Predicate { - /// Like Predicate() constructor, but automatically guard against nil (actual) values - public static func define(matcher: @escaping (Expression) throws -> PredicateResult) -> Predicate { - return Predicate { actual in - return try matcher(actual) - }.requireNonNil - } - - /// Defines a predicate with a default message that can be returned in the closure - /// Also ensures the predicate's actual value cannot pass with `nil` given. - public static func define(_ message: String = "match", matcher: @escaping (Expression, ExpectationMessage) throws -> PredicateResult) -> Predicate { - return Predicate { actual in - return try matcher(actual, .expectedActualValueTo(message)) - }.requireNonNil - } - - /// Defines a predicate with a default message that can be returned in the closure - /// Unlike `define`, this allows nil values to succeed if the given closure chooses to. - public static func defineNilable(_ message: String = "match", matcher: @escaping (Expression, ExpectationMessage) throws -> PredicateResult) -> Predicate { - return Predicate { actual in - return try matcher(actual, .expectedActualValueTo(message)) - } - } -} - -extension Predicate { - /// Provides a simple predicate definition that provides no control over the predefined - /// error message. - /// - /// Also ensures the predicate's actual value cannot pass with `nil` given. - public static func simple(_ message: String = "match", matcher: @escaping (Expression) throws -> PredicateStatus) -> Predicate { - return Predicate { actual in - return PredicateResult(status: try matcher(actual), message: .expectedActualValueTo(message)) - }.requireNonNil - } - - /// Provides a simple predicate definition that provides no control over the predefined - /// error message. - /// - /// Unlike `simple`, this allows nil values to succeed if the given closure chooses to. - public static func simpleNilable(_ message: String = "match", matcher: @escaping (Expression) throws -> PredicateStatus) -> Predicate { - return Predicate { actual in - return PredicateResult(status: try matcher(actual), message: .expectedActualValueTo(message)) - } - } -} - -// The Expectation style intended for comparison to a PredicateStatus. -public enum ExpectationStyle { - case toMatch, toNotMatch -} - -/// The value that a Predicates return to describe if the given (actual) value matches the -/// predicate. -public struct PredicateResult { - /// Status indicates if the predicate matches, does not match, or fails. - public var status: PredicateStatus - /// The error message that can be displayed if it does not match - public var message: ExpectationMessage - - /// Constructs a new PredicateResult with a given status and error message - public init(status: PredicateStatus, message: ExpectationMessage) { - self.status = status - self.message = message - } - - /// Shorthand to PredicateResult(status: PredicateStatus(bool: bool), message: message) - public init(bool: Bool, message: ExpectationMessage) { - self.status = PredicateStatus(bool: bool) - self.message = message - } - - /// Converts the result to a boolean based on what the expectation intended - public func toBoolean(expectation style: ExpectationStyle) -> Bool { - return status.toBoolean(expectation: style) - } -} - -/// PredicateStatus is a trinary that indicates if a Predicate matches a given value or not -public enum PredicateStatus { - /// Matches indicates if the predicate / matcher passes with the given value - /// - /// For example, `equals(1)` returns `.matches` for `expect(1).to(equal(1))`. - case matches - /// DoesNotMatch indicates if the predicate / matcher fails with the given value, but *would* - /// succeed if the expectation was inverted. - /// - /// For example, `equals(2)` returns `.doesNotMatch` for `expect(1).toNot(equal(2))`. - case doesNotMatch - /// Fail indicates the predicate will never satisfy with the given value in any case. - /// A perfect example is that most matchers fail whenever given `nil`. - /// - /// Using `equal(1)` fails both `expect(nil).to(equal(1))` and `expect(nil).toNot(equal(1))`. - /// Note: Predicate's `requireNonNil` property will also provide this feature mostly for free. - /// Your predicate will still need to guard against nils, but error messaging will be - /// handled for you. - case fail - - /// Converts a boolean to either .matches (if true) or .doesNotMatch (if false). - public init(bool matches: Bool) { - if matches { - self = .matches - } else { - self = .doesNotMatch - } - } - - private func shouldMatch() -> Bool { - switch self { - case .matches: return true - case .doesNotMatch, .fail: return false - } - } - - private func shouldNotMatch() -> Bool { - switch self { - case .doesNotMatch: return true - case .matches, .fail: return false - } - } - - /// Converts the PredicateStatus result to a boolean based on what the expectation intended - internal func toBoolean(expectation style: ExpectationStyle) -> Bool { - if style == .toMatch { - return shouldMatch() - } else { - return shouldNotMatch() - } - } -} - -extension Predicate { - // Someday, make this public? Needs documentation - internal func after(f: @escaping (Expression, PredicateResult) throws -> PredicateResult) -> Predicate { - // swiftlint:disable:previous identifier_name - return Predicate { actual -> PredicateResult in - let result = try self.satisfies(actual) - return try f(actual, result) - } - } - - /// Returns a new Predicate based on the current one that always fails if nil is given as - /// the actual value. - public var requireNonNil: Predicate { - return after { actual, result in - if try actual.evaluate() == nil { - return PredicateResult( - status: .fail, - message: result.message.appendedBeNilHint() - ) - } - return result - } - } -} - -#if canImport(Darwin) -import Foundation - -public typealias PredicateBlock = (_ actualExpression: Expression) throws -> NMBPredicateResult - -public class NMBPredicate: NSObject { - private let predicate: PredicateBlock - - public init(predicate: @escaping PredicateBlock) { - self.predicate = predicate - } - - func satisfies(_ expression: @escaping () throws -> NSObject?, location: SourceLocation) -> NMBPredicateResult { - let expr = Expression(expression: expression, location: location) - do { - return try self.predicate(expr) - } catch let error { - return PredicateResult(status: .fail, message: .fail("unexpected error thrown: <\(error)>")).toObjectiveC() - } - } -} - -final public class NMBPredicateResult: NSObject { - public var status: NMBPredicateStatus - public var message: NMBExpectationMessage - - public init(status: NMBPredicateStatus, message: NMBExpectationMessage) { - self.status = status - self.message = message - } - - public init(bool success: Bool, message: NMBExpectationMessage) { - self.status = NMBPredicateStatus.from(bool: success) - self.message = message - } - - public func toSwift() -> PredicateResult { - return PredicateResult(status: status.toSwift(), - message: message.toSwift()) - } -} - -extension PredicateResult { - public func toObjectiveC() -> NMBPredicateResult { - return NMBPredicateResult(status: status.toObjectiveC(), message: message.toObjectiveC()) - } -} - -final public class NMBPredicateStatus: NSObject { - private let status: Int - private init(status: Int) { - self.status = status - } - - public static let matches: NMBPredicateStatus = NMBPredicateStatus(status: 0) - public static let doesNotMatch: NMBPredicateStatus = NMBPredicateStatus(status: 1) - public static let fail: NMBPredicateStatus = NMBPredicateStatus(status: 2) - - public override var hash: Int { return self.status.hashValue } - - public override func isEqual(_ object: Any?) -> Bool { - guard let otherPredicate = object as? NMBPredicateStatus else { - return false - } - return self.status == otherPredicate.status - } - - public static func from(status: PredicateStatus) -> NMBPredicateStatus { - switch status { - case .matches: return self.matches - case .doesNotMatch: return self.doesNotMatch - case .fail: return self.fail - } - } - - public static func from(bool success: Bool) -> NMBPredicateStatus { - return self.from(status: PredicateStatus(bool: success)) - } - - public func toSwift() -> PredicateStatus { - switch status { - case NMBPredicateStatus.matches.status: return .matches - case NMBPredicateStatus.doesNotMatch.status: return .doesNotMatch - case NMBPredicateStatus.fail.status: return .fail - default: - internalError("Unhandle status for NMBPredicateStatus") - } - } -} - -extension PredicateStatus { - public func toObjectiveC() -> NMBPredicateStatus { - return NMBPredicateStatus.from(status: self) - } -} - -#endif