-
-
Notifications
You must be signed in to change notification settings - Fork 595
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #95 from rbeeger/allPassMatcher
All pass matcher
- Loading branch information
Showing
7 changed files
with
261 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import Foundation | ||
|
||
public func allPass<T,U where U: SequenceType, U.Generator.Element == T> | ||
(passFunc: (T?) -> Bool) -> NonNilMatcherFunc<U> { | ||
return allPass("pass a condition", passFunc) | ||
} | ||
|
||
public func allPass<T,U where U: SequenceType, U.Generator.Element == T> | ||
(passName:String, passFunc: (T?) -> Bool) -> NonNilMatcherFunc<U> { | ||
return createAllPassMatcher() { | ||
expression, failureMessage in | ||
failureMessage.postfixMessage = passName | ||
return passFunc(expression.evaluate()) | ||
} | ||
} | ||
|
||
public func allPass<U,V where U: SequenceType, V: NonNilBasicMatcher, U.Generator.Element == V.ValueType> | ||
(matcher: V) -> NonNilMatcherFunc<U> { | ||
let wrapper = NonNilMatcherWrapper(NonNilBasicMatcherWrapper(matcher)) | ||
return createAllPassMatcher() {wrapper.matches($0, failureMessage: $1)} | ||
} | ||
|
||
public func allPass<U,V where U: SequenceType, V: BasicMatcher, U.Generator.Element == V.ValueType> | ||
(matcher: V) -> NonNilMatcherFunc<U> { | ||
let wrapper = BasicMatcherWrapper(matcher: matcher) | ||
return createAllPassMatcher() {wrapper.matches($0, failureMessage: $1)} | ||
} | ||
|
||
public func allPass<U,V where U: SequenceType, V: Matcher, U.Generator.Element == V.ValueType> | ||
(matcher: V) -> NonNilMatcherFunc<U> { | ||
return createAllPassMatcher() {matcher.matches($0, failureMessage: $1)} | ||
} | ||
|
||
private func createAllPassMatcher<T,U where U: SequenceType, U.Generator.Element == T> | ||
(elementEvaluator:(Expression<T>, FailureMessage) -> Bool) -> NonNilMatcherFunc<U> { | ||
return NonNilMatcherFunc { actualExpression, failureMessage in | ||
failureMessage.actualValue = nil | ||
if let actualValue = actualExpression.evaluate() { | ||
for currentElement in actualValue { | ||
let exp = Expression( | ||
expression: {currentElement}, location: actualExpression.location) | ||
if !elementEvaluator(exp, failureMessage) { | ||
failureMessage.postfixMessage = | ||
"all \(failureMessage.postfixMessage)," | ||
+ " but failed first at element <\(stringify(currentElement))>" | ||
+ " in <\(stringify(actualValue))>" | ||
return false | ||
} | ||
} | ||
failureMessage.postfixMessage = "all \(failureMessage.postfixMessage)" | ||
} else { | ||
failureMessage.postfixMessage = "all pass (use beNil() to match nils)" | ||
return false | ||
} | ||
|
||
return true | ||
} | ||
} | ||
|
||
extension NMBObjCMatcher { | ||
public class func allPassMatcher(matcher: NMBObjCMatcher) -> NMBObjCMatcher { | ||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage, location in | ||
let actualValue = actualExpression.evaluate() | ||
var nsObjects = [NSObject]() | ||
|
||
var collectionIsUsable = true | ||
if let value = actualValue as? NSFastEnumeration { | ||
let generator = NSFastGenerator(value) | ||
while let obj:AnyObject = generator.next() { | ||
if let nsObject = obj as? NSObject { | ||
nsObjects.append(nsObject) | ||
} else { | ||
collectionIsUsable = false | ||
break | ||
} | ||
} | ||
} else { | ||
collectionIsUsable = false | ||
} | ||
|
||
if !collectionIsUsable { | ||
failureMessage.postfixMessage = | ||
"allPass only works with NSFastEnumeration (NSArray, NSSet, ...) of NSObjects" | ||
failureMessage.expected = "" | ||
failureMessage.to = "" | ||
return false | ||
} | ||
|
||
let expr = Expression(expression: ({ nsObjects }), location: location) | ||
let elementEvaluator: (Expression<NSObject>, FailureMessage) -> Bool = { | ||
expression, failureMessage in | ||
return matcher.matches( | ||
{expression.evaluate()}, failureMessage: failureMessage, location: expr.location) | ||
} | ||
return createAllPassMatcher(elementEvaluator).matches( | ||
expr, failureMessage: failureMessage) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import XCTest | ||
import Nimble | ||
|
||
class AllPassTest: XCTestCase { | ||
func testAllPassArray() { | ||
expect([1,2,3,4]).to(allPass({$0 < 5})) | ||
expect([1,2,3,4]).toNot(allPass({$0 > 5})) | ||
|
||
failsWithErrorMessage( | ||
"expected to all pass a condition, but failed first at element <3> in <[1, 2, 3, 4]>") { | ||
expect([1,2,3,4]).to(allPass({$0 < 3})) | ||
} | ||
failsWithErrorMessage("expected to not all pass a condition") { | ||
expect([1,2,3,4]).toNot(allPass({$0 < 5})) | ||
} | ||
failsWithErrorMessage( | ||
"expected to all be something, but failed first at element <3> in <[1, 2, 3, 4]>") { | ||
expect([1,2,3,4]).to(allPass("be something", {$0 < 3})) | ||
} | ||
failsWithErrorMessage("expected to not all be something") { | ||
expect([1,2,3,4]).toNot(allPass("be something", {$0 < 5})) | ||
} | ||
} | ||
|
||
func testAllPassMatcher() { | ||
expect([1,2,3,4]).to(allPass(beLessThan(5))) | ||
expect([1,2,3,4]).toNot(allPass(beGreaterThan(5))) | ||
|
||
failsWithErrorMessage( | ||
"expected to all be less than <3>, but failed first at element <3> in <[1, 2, 3, 4]>") { | ||
expect([1,2,3,4]).to(allPass(beLessThan(3))) | ||
} | ||
failsWithErrorMessage("expected to not all be less than <5>") { | ||
expect([1,2,3,4]).toNot(allPass(beLessThan(5))) | ||
} | ||
} | ||
|
||
func testAllPassCollectionsWithOptionalsDontWork() { | ||
failsWithErrorMessage("expected to all be nil, but failed first at element <nil> in <[nil, nil, nil]>") { | ||
expect([nil, nil, nil] as [Int?]).to(allPass(beNil())) | ||
} | ||
failsWithErrorMessage("expected to all pass a condition, but failed first at element <nil> in <[nil, nil, nil]>") { | ||
expect([nil, nil, nil] as [Int?]).to(allPass({$0 == nil})) | ||
} | ||
} | ||
|
||
func testAllPassCollectionsWithOptionalsUnwrappingOneOptionalLayer() { | ||
expect([nil, nil, nil] as [Int?]).to(allPass({$0! == nil})) | ||
expect([nil, 1, nil] as [Int?]).toNot(allPass({$0! == nil})) | ||
expect([1, 1, 1] as [Int?]).to(allPass({$0! == 1})) | ||
expect([1, 1, nil] as [Int?]).toNot(allPass({$0! == 1})) | ||
expect([1, 2, 3] as [Int?]).to(allPass({$0! < 4})) | ||
expect([1, 2, 3] as [Int?]).toNot(allPass({$0! < 3})) | ||
expect([1, 2, nil] as [Int?]).to(allPass({$0! < 3})) | ||
} | ||
|
||
func testAllPassSet() { | ||
expect(Set([1,2,3,4])).to(allPass({$0 < 5})) | ||
expect(Set([1,2,3,4])).toNot(allPass({$0 > 5})) | ||
|
||
failsWithErrorMessage("expected to not all pass a condition") { | ||
expect(Set([1,2,3,4])).toNot(allPass({$0 < 5})) | ||
} | ||
failsWithErrorMessage("expected to not all be something") { | ||
expect(Set([1,2,3,4])).toNot(allPass("be something", {$0 < 5})) | ||
} | ||
} | ||
|
||
func testAllPassWithNilAsExpectedValue() { | ||
failsWithErrorMessageForNil("expected to all pass") { | ||
expect(nil as [Int]?).to(allPass(beLessThan(5))) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#import <XCTest/XCTest.h> | ||
#import "NimbleSpecHelper.h" | ||
|
||
@interface ObjCAllPassTest : XCTestCase | ||
|
||
@end | ||
|
||
@implementation ObjCAllPassTest | ||
|
||
- (void)testPositiveMatches { | ||
expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@5))); | ||
expect(@[@1, @2, @3,@4]).toNot(allPass(beGreaterThan(@5))); | ||
|
||
expect([NSSet setWithArray:@[@1, @2, @3,@4]]).to(allPass(beLessThan(@5))); | ||
expect([NSSet setWithArray:@[@1, @2, @3,@4]]).toNot(allPass(beGreaterThan(@5))); | ||
} | ||
|
||
- (void)testNegativeMatches { | ||
expectFailureMessage(@"expected to all be less than <3.0000>, but failed first at element" | ||
" <3.0000> in <[1.0000, 2.0000, 3.0000, 4.0000]>", ^{ | ||
expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@3))); | ||
}); | ||
expectFailureMessage(@"expected to not all be less than <5.0000>", ^{ | ||
expect(@[@1, @2, @3,@4]).toNot(allPass(beLessThan(@5))); | ||
}); | ||
expectFailureMessage(@"expected to not all be less than <5.0000>", ^{ | ||
expect([NSSet setWithArray:@[@1, @2, @3,@4]]).toNot(allPass(beLessThan(@5))); | ||
}); | ||
expectFailureMessage(@"allPass only works with NSFastEnumeration" | ||
" (NSArray, NSSet, ...) of NSObjects, got <3.0000>", ^{ | ||
expect(@3).to(allPass(beLessThan(@5))); | ||
}); | ||
expectFailureMessage(@"allPass only works with NSFastEnumeration" | ||
" (NSArray, NSSet, ...) of NSObjects, got <3.0000>", ^{ | ||
expect(@3).toNot(allPass(beLessThan(@5))); | ||
}); | ||
} | ||
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters