diff --git a/Sources/Nimble/Expectation.swift b/Sources/Nimble/Expectation.swift index e3f616a92..827594fdc 100644 --- a/Sources/Nimble/Expectation.swift +++ b/Sources/Nimble/Expectation.swift @@ -108,22 +108,27 @@ public struct Expectation { ////////////////// NEW API ///////////////////// /// Tests the actual value using a matcher to match. - public func to(_ predicate: Predicate, description: String? = nil) { + @discardableResult + public func to(_ predicate: Predicate, description: String? = nil) -> Expectation { let (pass, msg) = execute(expression, .toMatch, predicate, to: "to", description: description) verify(pass, msg) + return self } /// Tests the actual value using a matcher to not match. - public func toNot(_ predicate: Predicate, description: String? = nil) { + @discardableResult + public func toNot(_ predicate: Predicate, description: String? = nil) -> Expectation { let (pass, msg) = execute(expression, .toNotMatch, predicate, to: "to not", description: description) verify(pass, msg) + return self } /// Tests the actual value using a matcher to not match. /// /// Alias to toNot(). - public func notTo(_ predicate: Predicate, description: String? = nil) { - toNot(predicate, description: description) + @discardableResult + public func notTo(_ predicate: Predicate, description: String? = nil) -> Expectation { + return toNot(predicate, description: description) } // see: diff --git a/Sources/Nimble/Matchers/ThrowAssertion.swift b/Sources/Nimble/Matchers/ThrowAssertion.swift index a530c60f8..0e031ea19 100644 --- a/Sources/Nimble/Matchers/ThrowAssertion.swift +++ b/Sources/Nimble/Matchers/ThrowAssertion.swift @@ -1,6 +1,6 @@ import Foundation -public func throwAssertion() -> Predicate { +public func throwAssertion() -> Predicate { return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in #if arch(x86_64) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE failureMessage.postfixMessage = "throw an assertion" diff --git a/Sources/Nimble/Matchers/ThrowError.swift b/Sources/Nimble/Matchers/ThrowError.swift index 872ca5c2e..1f4737a43 100644 --- a/Sources/Nimble/Matchers/ThrowError.swift +++ b/Sources/Nimble/Matchers/ThrowError.swift @@ -11,7 +11,7 @@ import Foundation /// /// nil arguments indicates that the matcher should not attempt to match against /// that parameter. -public func throwError() -> Predicate { +public func throwError() -> Predicate { return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in var actualError: Error? @@ -42,7 +42,7 @@ public func throwError() -> Predicate { /// /// nil arguments indicates that the matcher should not attempt to match against /// that parameter. -public func throwError(_ error: T, closure: ((Error) -> Void)? = nil) -> Predicate { +public func throwError(_ error: T, closure: ((Error) -> Void)? = nil) -> Predicate { return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in var actualError: Error? @@ -87,7 +87,7 @@ public func throwError(_ error: T, closure: ((Error) -> Void)? = nil) /// /// nil arguments indicates that the matcher should not attempt to match against /// that parameter. -public func throwError(_ error: T, closure: ((T) -> Void)? = nil) -> Predicate { +public func throwError(_ error: T, closure: ((T) -> Void)? = nil) -> Predicate { return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in var actualError: Error? @@ -133,9 +133,9 @@ public func throwError(_ error: T, closure: ((T) -> Void)? /// /// nil arguments indicates that the matcher should not attempt to match against /// that parameter. -public func throwError( +public func throwError( errorType: T.Type, - closure: ((T) -> Void)? = nil) -> Predicate { + closure: ((T) -> Void)? = nil) -> Predicate { return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in var actualError: Error? @@ -194,7 +194,7 @@ public func throwError( /// values of the existential type `Error` in the closure. /// /// The closure only gets called when an error was thrown. -public func throwError(closure: @escaping ((Error) -> Void)) -> Predicate { +public func throwError(closure: @escaping ((Error) -> Void)) -> Predicate { return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in var actualError: Error? @@ -229,7 +229,7 @@ public func throwError(closure: @escaping ((Error) -> Void)) -> Predicate { /// values of the existential type `Error` in the closure. /// /// The closure only gets called when an error was thrown. -public func throwError(closure: @escaping ((T) -> Void)) -> Predicate { +public func throwError(closure: @escaping ((T) -> Void)) -> Predicate { return Predicate.fromDeprecatedClosure { actualExpression, failureMessage in var actualError: Error? diff --git a/Tests/NimbleTests/Matchers/ThrowAssertionTest.swift b/Tests/NimbleTests/Matchers/ThrowAssertionTest.swift index 68086e003..733eafd53 100644 --- a/Tests/NimbleTests/Matchers/ThrowAssertionTest.swift +++ b/Tests/NimbleTests/Matchers/ThrowAssertionTest.swift @@ -13,6 +13,7 @@ final class ThrowAssertionTest: XCTestCase, XCTestCaseProvider { ("testNegativeMatch", testNegativeMatch), ("testPositiveMessage", testPositiveMessage), ("testNegativeMessage", testNegativeMessage), + ("testChainOnThrowAssertion", testChainOnThrowAssertion), ] } @@ -57,6 +58,10 @@ final class ThrowAssertionTest: XCTestCase, XCTestCaseProvider { expect { () -> Void in fatalError() }.toNot(throwAssertion()) } } + + func testChainOnThrowAssertion() { + expect { () -> Int in return 5 }.toNot(throwAssertion()).to(equal(5)) + } } #endif diff --git a/Tests/NimbleTests/Matchers/ThrowErrorTest.swift b/Tests/NimbleTests/Matchers/ThrowErrorTest.swift index f11c8c56e..c3499646c 100644 --- a/Tests/NimbleTests/Matchers/ThrowErrorTest.swift +++ b/Tests/NimbleTests/Matchers/ThrowErrorTest.swift @@ -41,6 +41,7 @@ final class ThrowErrorTest: XCTestCase, XCTestCaseProvider { ("testNegativeNegatedMatches", testNegativeNegatedMatches), ("testNegativeMatchesDoNotCallClosureWithoutError", testNegativeMatchesDoNotCallClosureWithoutError), ("testNegativeMatchesWithClosure", testNegativeMatchesWithClosure), + ("testChainOnThrowError", testChainOnThrowError), ] } @@ -136,7 +137,7 @@ final class ThrowErrorTest: XCTestCase, XCTestCaseProvider { func testNegativeMatchesWithClosure() { let moduleName = "NimbleTests" let innerFailureMessage = "expected to equal , got <\(moduleName).NimbleError>" - let closure = { (error: Error) in + let closure = { (error: Error) -> Void in expect(error._domain).to(equal("foo")) } @@ -152,4 +153,12 @@ final class ThrowErrorTest: XCTestCase, XCTestCaseProvider { expect { throw NimbleError.laugh }.to(throwError(NimbleError.laugh, closure: closure)) } } + + func testChainOnThrowError() { + let closure = { () throws -> Int in + return 5 + } + + expect(try closure()).toNot(throwError()).to(equal(5)) + } } diff --git a/Tests/NimbleTests/SynchronousTests.swift b/Tests/NimbleTests/SynchronousTests.swift index ce8181b04..53917d93a 100644 --- a/Tests/NimbleTests/SynchronousTests.swift +++ b/Tests/NimbleTests/SynchronousTests.swift @@ -18,6 +18,8 @@ final class SynchronousTest: XCTestCase, XCTestCaseProvider { ("testToNotProvidesAMemoizedActualValueExpressionIsEvaluatedAtMatcherControl", testToNotProvidesAMemoizedActualValueExpressionIsEvaluatedAtMatcherControl), ("testToNotNegativeMatches", testToNotNegativeMatches), ("testNotToMatchesLikeToNot", testNotToMatchesLikeToNot), + ("testChainExpectation", testChainExpectation), + ("testChainFailOnFirstError", testChainFailOnFirstError), ] } @@ -125,4 +127,15 @@ final class SynchronousTest: XCTestCase, XCTestCaseProvider { func testNotToMatchesLikeToNot() { expect(1).notTo(MatcherFunc { _, _ in false }) } + + func testChainExpectation() { + expect(2).toNot(equal(1)).to(equal(2)).notTo(equal(3)) + } + + func testChainFailOnFirstError() { + failsWithErrorMessage("expected to not equal <2>, got <2>") { + expect(2).toNot(equal(1)).toNot(equal(2)).to(equal(3)) + } + } + }