Skip to content

Commit

Permalink
Added custom user description to all Swift expectation methods (Issue Q…
Browse files Browse the repository at this point in the history
  • Loading branch information
abbeycode committed Jul 24, 2015
1 parent a804949 commit 0651cfa
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 19 deletions.
18 changes: 10 additions & 8 deletions Nimble/Expectation.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import Foundation

internal func expressionMatches<T, U where U: Matcher, U.ValueType == T>(expression: Expression<T>, matcher: U, to: String) -> (Bool, FailureMessage) {
internal func expressionMatches<T, U where U: Matcher, U.ValueType == T>(expression: Expression<T>, matcher: U, to: String, description: String?) -> (Bool, FailureMessage) {
let msg = FailureMessage()
msg.userDescription = description
msg.to = to
let pass = matcher.matches(expression, failureMessage: msg)
if msg.actualValue == "" {
Expand All @@ -10,8 +11,9 @@ internal func expressionMatches<T, U where U: Matcher, U.ValueType == T>(express
return (pass, msg)
}

internal func expressionDoesNotMatch<T, U where U: Matcher, U.ValueType == T>(expression: Expression<T>, matcher: U, toNot: String) -> (Bool, FailureMessage) {
internal func expressionDoesNotMatch<T, U where U: Matcher, U.ValueType == T>(expression: Expression<T>, matcher: U, toNot: String, description: String?) -> (Bool, FailureMessage) {
let msg = FailureMessage()
msg.userDescription = description
msg.to = toNot
let pass = matcher.doesNotMatch(expression, failureMessage: msg)
if msg.actualValue == "" {
Expand All @@ -28,22 +30,22 @@ public struct Expectation<T> {
}

/// Tests the actual value using a matcher to match.
public func to<U where U: Matcher, U.ValueType == T>(matcher: U) {
let (pass, msg) = expressionMatches(expression, matcher: matcher, to: "to")
public func to<U where U: Matcher, U.ValueType == T>(matcher: U, description: String? = nil) {
let (pass, msg) = expressionMatches(expression, matcher: matcher, to: "to", description: description)
verify(pass, msg)
}

/// Tests the actual value using a matcher to not match.
public func toNot<U where U: Matcher, U.ValueType == T>(matcher: U) {
let (pass, msg) = expressionDoesNotMatch(expression, matcher: matcher, toNot: "to not")
public func toNot<U where U: Matcher, U.ValueType == T>(matcher: U, description: String? = nil) {
let (pass, msg) = expressionDoesNotMatch(expression, matcher: matcher, toNot: "to not", description: description)
verify(pass, msg)
}

/// Tests the actual value using a matcher to not match.
///
/// Alias to toNot().
public func notTo<U where U: Matcher, U.ValueType == T>(matcher: U) {
toNot(matcher)
public func notTo<U where U: Matcher, U.ValueType == T>(matcher: U, description: String? = nil) {
toNot(matcher, description: description)
}

// see:
Expand Down
9 changes: 8 additions & 1 deletion Nimble/FailureMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class FailureMessage: NSObject {
public var to: String = "to"
public var postfixMessage: String = "match"
public var postfixActual: String = ""
public var userDescription: String? = nil

public var stringValue: String {
get {
Expand Down Expand Up @@ -44,6 +45,12 @@ public class FailureMessage: NSObject {
if let actualValue = actualValue {
value = "\(expected) \(to) \(postfixMessage), got \(actualValue)\(postfixActual)"
}
return stripNewlines(value)
value = stripNewlines(value)

if let userDescription = userDescription {
return "\(userDescription)\n\(value)"
}

return value
}
}
6 changes: 4 additions & 2 deletions Nimble/ObjCExpectation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ public class NMBExpectation : NSObject {
return ({ matcher in
self.expectValue.toEventually(
ObjCMatcherWrapper(matcher: matcher),
timeout: self._timeout
timeout: self._timeout,
description: nil
)
})
}
Expand All @@ -72,7 +73,8 @@ public class NMBExpectation : NSObject {
return ({ matcher in
self.expectValue.toEventuallyNot(
ObjCMatcherWrapper(matcher: matcher),
timeout: self._timeout
timeout: self._timeout,
description: nil
)
})
}
Expand Down
14 changes: 8 additions & 6 deletions Nimble/Wrappers/AsyncMatcherWrapper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,16 @@ private let toEventuallyRequiresClosureError = FailureMessage(stringValue: "expe
extension Expectation {
/// Tests the actual value using a matcher to match by checking continuously
/// at each pollInterval until the timeout is reached.
public func toEventually<U where U: Matcher, U.ValueType == T>(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
public func toEventually<U where U: Matcher, U.ValueType == T>(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) {
if expression.isClosure {
let (pass, msg) = expressionMatches(
expression,
matcher: AsyncMatcherWrapper(
fullMatcher: matcher,
timeoutInterval: timeout,
pollInterval: pollInterval),
to: "to eventually"
to: "to eventually",
description: description
)
verify(pass, msg)
} else {
Expand All @@ -64,15 +65,16 @@ extension Expectation {

/// Tests the actual value using a matcher to not match by checking
/// continuously at each pollInterval until the timeout is reached.
public func toEventuallyNot<U where U: Matcher, U.ValueType == T>(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
public func toEventuallyNot<U where U: Matcher, U.ValueType == T>(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) {
if expression.isClosure {
let (pass, msg) = expressionDoesNotMatch(
expression,
matcher: AsyncMatcherWrapper(
fullMatcher: matcher,
timeoutInterval: timeout,
pollInterval: pollInterval),
toNot: "to eventually not"
toNot: "to eventually not",
description: description
)
verify(pass, msg)
} else {
Expand All @@ -84,7 +86,7 @@ extension Expectation {
/// continuously at each pollInterval until the timeout is reached.
///
/// Alias of toEventuallyNot()
public func toNotEventually<U where U: Matcher, U.ValueType == T>(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
return toEventuallyNot(matcher, timeout: timeout, pollInterval: pollInterval)
public func toNotEventually<U where U: Matcher, U.ValueType == T>(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) {
return toEventuallyNot(matcher, timeout: timeout, pollInterval: pollInterval, description: description)
}
}
24 changes: 24 additions & 0 deletions NimbleTests/AsynchronousTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,28 @@ class AsyncTest: XCTestCase {
}
}
}

func testToEventuallyMatch_CustomFailureMessage() {
failsWithErrorMessage(
"These aren't eventually equal!\n" +
"expected to eventually equal <1>, got <0>") {
expect { 0 }.toEventually(equal(1), description: "These aren't eventually equal!")
}
}

func testToEventuallyNotMatch_CustomFailureMessage() {
failsWithErrorMessage(
"These are eventually equal!\n" +
"expected to eventually not equal <1>, got <1>") {
expect { 1 }.toEventuallyNot(equal(1), description: "These are eventually equal!")
}
}

func testToNotEventuallyMatch_CustomFailureMessage() {
failsWithErrorMessage(
"These are eventually equal!\n" +
"expected to eventually not equal <1>, got <1>") {
expect { 1 }.toEventuallyNot(equal(1), description: "These are eventually equal!")
}
}
}
25 changes: 24 additions & 1 deletion NimbleTests/SynchronousTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,31 @@ class SynchronousTest: XCTestCase {
}
}


func testNotToMatchesLikeToNot() {
expect(1).notTo(MatcherFunc { expr, failure in false })
}

func testToMatcher_CustomFailureMessage() {
failsWithErrorMessage(
"These aren't equal!\n" +
"expected to match, got <1>") {
expect(1).to(MatcherFunc { expr, failure in false }, description: "These aren't equal!")
}
}

func testNotToMatcher_CustomFailureMessage() {
failsWithErrorMessage(
"These aren't equal!\n" +
"expected to not match, got <1>") {
expect(1).notTo(MatcherFunc { expr, failure in true }, description: "These aren't equal!")
}
}

func testToNotMatcher_CustomFailureMessage() {
failsWithErrorMessage(
"These aren't equal!\n" +
"expected to not match, got <1>") {
expect(1).toNot(MatcherFunc { expr, failure in true }, description: "These aren't equal!")
}
}
}
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,21 @@ expect(seagull.squawk).toNot(equal(@"Oh, hello there!"));
expect(seagull.squawk).notTo(equal(@"Oh, hello there!"));
```
## Custom Failure Messages
Would you like to add more information to the test's failure messages? Use the `description` optional argument to add your own text:
```swift
// Swift
expect(1 + 1).to(equal(3))
// failed - expected to equal <3>, got <2>
expect(1 + 1).to(equal(3), description: "Make sure libKindergartenMath is loaded")
// failed - Make sure libKindergartenMath is loaded
// expected to equal <3>, got <2>
```

## Type Checking

Nimble makes sure you don't compare two types that don't match:
Expand Down Expand Up @@ -1048,4 +1063,4 @@ target 'YOUR_APP_NAME_HERE_Tests', :exclusive => true do
end
```

Finally run `pod install`.
Finally run `pod install`.

0 comments on commit 0651cfa

Please sign in to comment.