├── .gitignore
├── NimbleTests
├── objc
│ ├── NimbleTests-Bridging-Header.h
│ ├── Nimble-OSXTests-Bridging-Header.h
│ └── CompatibilityTest.m
├── Helpers
│ ├── ObjectWithLazyProperty.swift
│ └── utils.swift
├── Matchers
│ ├── BeNilTest.swift
│ ├── MatchTest.swift
│ ├── beOneOfTest.swift
│ ├── BeAnInstanceOfTest.swift
│ ├── BeAKindOfTest.swift
│ ├── BeGreaterThanTest.swift
│ ├── BeLessThanTest.swift
│ ├── BeLessThanOrEqualToTest.swift
│ ├── BeCloseToTest.swift
│ ├── BeGreaterThanOrEqualToTest.swift
│ ├── EndWithTest.swift
│ ├── BeIdenticalToTest.swift
│ ├── BeginWithTest.swift
│ ├── BeIdenticalToObjectTest.swift
│ ├── BeEmptyTest.swift
│ ├── RaisesExceptionTest.swift
│ ├── ContainTest.swift
│ ├── BeLogicalTest.swift
│ └── EqualTest.swift
├── Info.plist
├── AsynchronousTest.swift
└── SynchronousTests.swift
├── Nimble.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── Nimble.xccheckout
└── xcshareddata
│ └── xcschemes
│ ├── Nimble-OSX.xcscheme
│ └── Nimble-iOS.xcscheme
├── Nimble
├── Nimble.h
├── Utils
│ ├── Functional.swift
│ ├── SourceLocation.swift
│ ├── Poll.swift
│ └── Stringers.swift
├── Adapters
│ ├── AdapterProtocols.swift
│ ├── XCTestHandler.swift
│ └── AssertionRecorder.swift
├── objc
│ ├── NMBExceptionCapture.h
│ ├── NMBExceptionCapture.m
│ ├── DSL.m
│ └── DSL.h
├── Matchers
│ ├── BeOneOf.swift
│ ├── BeNil.swift
│ ├── BeAKindOf.swift
│ ├── BeAnInstanceOf.swift
│ ├── Match.swift
│ ├── BeIdenticalTo.swift
│ ├── BeLessThan.swift
│ ├── BeGreaterThan.swift
│ ├── BeLessThanOrEqual.swift
│ ├── BeGreaterThanOrEqualTo.swift
│ ├── Contain.swift
│ ├── BeginWith.swift
│ ├── BeEmpty.swift
│ ├── BeCloseTo.swift
│ ├── EndWith.swift
│ ├── MatcherProtocols.swift
│ ├── BeLogical.swift
│ ├── RaisesException.swift
│ └── Equal.swift
├── Info.plist
├── Wrappers
│ ├── MatcherFunc.swift
│ ├── FullMatcherWrapper.swift
│ ├── AsyncMatcherWrapper.swift
│ └── ObjCMatcher.swift
├── Expectation.swift
├── Expression.swift
├── FailureMessage.swift
└── DSL.swift
├── .travis.yml
├── test
├── CONTRIBUTING.md
├── LICENSE.md
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | xcuserdata/
3 | build/
4 | .idea
5 | DerivedData/
6 |
--------------------------------------------------------------------------------
/NimbleTests/objc/NimbleTests-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/NimbleTests/objc/Nimble-OSXTests-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // Use this file to import your target's public headers that you would like to expose to Swift.
3 | //
4 |
5 |
--------------------------------------------------------------------------------
/NimbleTests/Helpers/ObjectWithLazyProperty.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | class ObjectWithLazyProperty {
4 | init() {}
5 | lazy var value: String = "hello"
6 | lazy var anotherValue: String = { return "world" }()
7 | }
8 |
--------------------------------------------------------------------------------
/Nimble.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Nimble/Nimble.h:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 | #import
4 |
5 | FOUNDATION_EXPORT double NimbleVersionNumber;
6 | FOUNDATION_EXPORT const unsigned char NimbleVersionString[];
7 |
--------------------------------------------------------------------------------
/Nimble/Utils/Functional.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | func _all(array: [T], fn: (T) -> Bool) -> Bool {
4 | for item in array {
5 | if !fn(item) {
6 | return false
7 | }
8 | }
9 | return true
10 | }
11 |
12 |
--------------------------------------------------------------------------------
/Nimble/Adapters/AdapterProtocols.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public protocol AssertionHandler {
4 | func assert(assertion: Bool, message: String, location: SourceLocation)
5 | }
6 |
7 | var CurrentAssertionHandler: AssertionHandler = XCTestHandler()
8 |
9 |
--------------------------------------------------------------------------------
/Nimble/objc/NMBExceptionCapture.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @interface NMBExceptionCapture : NSObject
4 |
5 | - (id)initWithHandler:(void(^)(NSException *))handler finally:(void(^)())finally;
6 | - (void)tryBlock:(void(^)())unsafeBlock;
7 |
8 | @end
--------------------------------------------------------------------------------
/Nimble/Adapters/XCTestHandler.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import XCTest
3 |
4 | class XCTestHandler : AssertionHandler {
5 | func assert(assertion: Bool, message: String, location: SourceLocation) {
6 | if !assertion {
7 | XCTFail(message, file: location.file, line: location.line)
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 |
3 | env:
4 | matrix:
5 | - NIMBLE_BUILD_SDK_VERSION=8.0 NIMBLE_RUNTIME_SDK_VERSION=8.0 TYPE=ios
6 | # Until travis-ci supports these, we can't run this.
7 | # - NIMBLE_BUILD_SDK_VERSION=8.1 NIMBLE_RUNTIME_SDK_VERSION=8.1 TYPE=ios
8 | # - NIMBLE_BUILD_SDK_VERSION=8.1 NIMBLE_RUNTIME_SDK_VERSION=8.1 TYPE=osx
9 |
10 | script: ./test $TYPE
11 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeOneOf.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Nimble
3 |
4 | public func beOneOf(allowedValues: [T]) -> MatcherFunc {
5 | return MatcherFunc { actualExpression, failureMessage in
6 | failureMessage.postfixMessage = "be one of: \(stringify(allowedValues))"
7 | if let actualValue = actualExpression.evaluate() {
8 | return contains(allowedValues, actualValue)
9 | }
10 | return false
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Nimble/Utils/SourceLocation.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 |
4 | @objc public class SourceLocation : Printable {
5 | public let file: String
6 | public let line: UInt
7 |
8 | init() {
9 | file = "Unknown File"
10 | line = 0
11 | }
12 |
13 | init(file: String, line: UInt) {
14 | self.file = file
15 | self.line = line
16 | }
17 |
18 | public var description: String {
19 | return "\(file):\(line)"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Nimble/Utils/Poll.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | func _pollBlock(#pollInterval: NSTimeInterval, #timeoutInterval: NSTimeInterval, expression: () -> Bool) -> Bool {
4 | let startDate = NSDate()
5 | var pass: Bool
6 | do {
7 | pass = expression()
8 | if pass {
9 | break
10 | }
11 |
12 | let runDate = NSDate().dateByAddingTimeInterval(pollInterval) as NSDate
13 | NSRunLoop.mainRunLoop().runUntilDate(runDate)
14 | } while(NSDate().timeIntervalSinceDate(startDate) < timeoutInterval);
15 |
16 | return pass
17 | }
18 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeNilTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeNilTest: XCTestCase {
5 | func producesNil() -> Array? {
6 | return nil
7 | }
8 |
9 | func testBeNil() {
10 | expect(nil as Int?).to(beNil())
11 | expect(1 as Int?).toNot(beNil())
12 | expect(producesNil()).to(beNil())
13 |
14 | failsWithErrorMessage("expected to not be nil, got ") {
15 | expect(nil as Int?).toNot(beNil())
16 | }
17 |
18 | failsWithErrorMessage("expected to be nil, got <1>") {
19 | expect(1 as Int?).to(beNil())
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeNil.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func beNil() -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "be nil"
6 | let actualValue = actualExpression.evaluate()
7 | return actualValue == nil
8 | }
9 | }
10 |
11 | extension NMBObjCMatcher {
12 | public class func beNilMatcher() -> NMBObjCMatcher {
13 | return NMBObjCMatcher { actualBlock, failureMessage, location in
14 | let block = ({ actualBlock() as NSObject? })
15 | let expr = Expression(expression: block, location: location)
16 | return beNil().matches(expr, failureMessage: failureMessage)
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/MatchTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class MatchTest:XCTestCase {
5 | func testMatchPositive() {
6 | expect("11:14").to(match("\\d{2}:\\d{2}"))
7 | }
8 |
9 | func testMatchNegative() {
10 | expect("hello").toNot(match("\\d{2}:\\d{2}"))
11 | }
12 |
13 | func testMatchPositiveMessage() {
14 | let message = "expected to match <\\d{2}:\\d{2}>, got "
15 | failsWithErrorMessage(message) {
16 | expect("hello").to(match("\\d{2}:\\d{2}"))
17 | }
18 | }
19 |
20 | func testMatchNegativeMessage() {
21 | let message = "expected to not match <\\d{2}:\\d{2}>, got <11:14>"
22 | failsWithErrorMessage(message) {
23 | expect("11:14").toNot(match("\\d{2}:\\d{2}"))
24 | }
25 | }
26 |
27 | }
--------------------------------------------------------------------------------
/NimbleTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | net.jeffhui.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/beOneOfTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class beOneOfTest: XCTestCase {
5 | func testPositiveMatches() {
6 | expect(1).to(beOneOf([1, 2, 3]))
7 | expect(4).toNot(beOneOf([1, 2, 3]))
8 |
9 | expect(1 as CInt).to(beOneOf([1, 2, 3]))
10 | expect(4 as CInt).toNot(beOneOf([1, 2, 3]))
11 |
12 | expect(NSString(string: "a")).to(beOneOf(["a", "b", "c"]))
13 | expect(NSString(string: "d")).toNot(beOneOf(["a", "b", "c"]))
14 | }
15 |
16 | func testNegativeMatches() {
17 | failsWithErrorMessage("expected to not be one of: [1, 2, 3], got <1>") {
18 | expect(1).toNot(beOneOf([1, 2, 3]))
19 | }
20 | failsWithErrorMessage("expected to be one of: [1, 2, 3], got <4>") {
21 | expect(4).to(beOneOf([1, 2, 3]))
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Nimble/objc/NMBExceptionCapture.m:
--------------------------------------------------------------------------------
1 | #import "NMBExceptionCapture.h"
2 |
3 | @interface NMBExceptionCapture ()
4 | @property (nonatomic, copy) void(^handler)(NSException *exception);
5 | @property (nonatomic, copy) void(^finally)();
6 | @end
7 |
8 | @implementation NMBExceptionCapture
9 |
10 | - (id)initWithHandler:(void(^)(NSException *))handler finally:(void(^)())finally {
11 | self = [super init];
12 | if (self) {
13 | self.handler = handler;
14 | self.finally = finally;
15 | }
16 | return self;
17 | }
18 |
19 | - (void)tryBlock:(void(^)())unsafeBlock {
20 | @try {
21 | unsafeBlock();
22 | }
23 | @catch (NSException *exception) {
24 | if (self.handler) {
25 | self.handler(exception);
26 | }
27 | }
28 | @finally {
29 | if (self.finally) {
30 | self.finally();
31 | }
32 | }
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeAnInstanceOfTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeAnInstanceOfTest: XCTestCase {
5 | func testPositiveMatch() {
6 | expect(nil as NSNull?).toNot(beAnInstanceOf(NSNull))
7 |
8 | expect(NSNull()).to(beAnInstanceOf(NSNull))
9 | expect(NSNumber(integer:1)).toNot(beAnInstanceOf(NSDate))
10 | }
11 |
12 | func testFailureMessages() {
13 | failsWithErrorMessage("expected to be an instance of NSString, got ") {
14 | expect(nil as NSString?).to(beAnInstanceOf(NSString))
15 | }
16 | failsWithErrorMessage("expected to be an instance of NSString, got <__NSCFNumber instance>") {
17 | expect(NSNumber(integer:1)).to(beAnInstanceOf(NSString))
18 | }
19 | failsWithErrorMessage("expected to not be an instance of NSNumber, got <__NSCFNumber instance>") {
20 | expect(NSNumber(integer:1)).toNot(beAnInstanceOf(NSNumber))
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeAKindOfTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class TestNull : NSNull {}
5 |
6 | class BeAKindOfTest: XCTestCase {
7 | func testPositiveMatch() {
8 | expect(nil as NSNull?).toNot(beAKindOf(NSNull))
9 |
10 | expect(TestNull()).to(beAKindOf(NSNull))
11 | expect(NSObject()).to(beAKindOf(NSObject))
12 | expect(NSNumber(integer:1)).toNot(beAKindOf(NSDate))
13 | }
14 |
15 | func testFailureMessages() {
16 | failsWithErrorMessage("expected to be a kind of NSString, got ") {
17 | expect(nil as NSString?).to(beAKindOf(NSString))
18 | }
19 | failsWithErrorMessage("expected to be a kind of NSString, got <__NSCFNumber instance>") {
20 | expect(NSNumber(integer:1)).to(beAKindOf(NSString))
21 | }
22 | failsWithErrorMessage("expected to not be a kind of NSNumber, got <__NSCFNumber instance>") {
23 | expect(NSNumber(integer:1)).toNot(beAKindOf(NSNumber))
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Nimble/Adapters/AssertionRecorder.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct AssertionRecord {
4 | public let success: Bool
5 | public let message: String
6 | public let location: SourceLocation
7 | }
8 |
9 | public class AssertionRecorder : AssertionHandler {
10 | public var assertions = [AssertionRecord]()
11 |
12 | public init() {}
13 |
14 | public func assert(assertion: Bool, message: String, location: SourceLocation) {
15 | assertions.append(
16 | AssertionRecord(
17 | success: assertion,
18 | message: message,
19 | location: location))
20 | }
21 | }
22 |
23 | public func withAssertionHandler(recorder: AssertionHandler, closure: () -> Void) {
24 | let oldRecorder = CurrentAssertionHandler
25 | let capturer = NMBExceptionCapture(handler: nil, finally: ({
26 | CurrentAssertionHandler = oldRecorder
27 | }))
28 | CurrentAssertionHandler = recorder
29 | capturer.tryBlock {
30 | closure()
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Nimble/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | net.jeffhui.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | ${CURRENT_PROJECT_VERSION}
23 | NSPrincipalClass
24 |
25 | NSHumanReadableCopyright
26 | Copyright © 2014 Jeff Hui. All rights reserved.
27 |
28 |
29 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeGreaterThanTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeGreaterThanTest: XCTestCase {
5 | func testGreaterThan() {
6 | expect(10).to(beGreaterThan(2))
7 | expect(1).toNot(beGreaterThan(2))
8 | expect(NSNumber(int:3)).to(beGreaterThan(2))
9 | expect(NSNumber(int:1)).toNot(beGreaterThan(NSNumber(int:2)))
10 |
11 | failsWithErrorMessage("expected to be greater than <2>, got <0>") {
12 | expect(0).to(beGreaterThan(2))
13 | return
14 | }
15 | failsWithErrorMessage("expected to not be greater than <0>, got <1>") {
16 | expect(1).toNot(beGreaterThan(0))
17 | return
18 | }
19 | }
20 |
21 | func testGreaterThanOperator() {
22 | expect(1) > 0
23 | expect(NSNumber(int:1)) > NSNumber(int:0)
24 | expect(NSNumber(int:1)) > 0
25 |
26 | failsWithErrorMessage("expected to be greater than <2.0000>, got <1.0000>") {
27 | expect(1) > 2
28 | return
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeAKindOf.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func beAKindOf(expectedClass: AnyClass) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | let instance = actualExpression.evaluate()
6 | if let validInstance = instance {
7 | failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>"
8 | } else {
9 | failureMessage.actualValue = ""
10 | }
11 | failureMessage.postfixMessage = "be a kind of \(NSStringFromClass(expectedClass))"
12 | return instance != nil && instance!.isKindOfClass(expectedClass)
13 | }
14 | }
15 |
16 | extension NMBObjCMatcher {
17 | public class func beAKindOfMatcher(expected: AnyClass) -> NMBMatcher {
18 | return NMBObjCMatcher { actualExpression, failureMessage, location in
19 | let expr = Expression(expression: actualExpression, location: location)
20 | return beAKindOf(expected).matches(expr, failureMessage: failureMessage)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/NimbleTests/Helpers/utils.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 | import Nimble
3 | import XCTest
4 |
5 | func failsWithErrorMessage(message: String, closure: () -> Void, file: String = __FILE__, line: Int = __LINE__) {
6 | let recorder = AssertionRecorder()
7 | withAssertionHandler(recorder, closure)
8 |
9 | var lastFailureMessage: String?
10 | if recorder.assertions.count > 0 {
11 | lastFailureMessage = recorder.assertions[recorder.assertions.endIndex - 1].message
12 | if lastFailureMessage == message {
13 | return
14 | }
15 | }
16 | if lastFailureMessage != nil {
17 | let msg = "Got failure message: \"\(lastFailureMessage!)\", but expected \"\(message)\""
18 | XCTFail(msg, file: file, line: UInt(line))
19 | } else {
20 | XCTFail("expected failure message, but got none", file: file, line: UInt(line))
21 | }
22 | }
23 |
24 | func deferToMainQueue(action: () -> Void) {
25 | dispatch_async(dispatch_get_main_queue()) {
26 | NSThread.sleepForTimeInterval(0.01)
27 | action()
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeAnInstanceOf.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func beAnInstanceOf(expectedClass: AnyClass) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | let instance = actualExpression.evaluate()
6 | if let validInstance = instance {
7 | failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>"
8 | } else {
9 | failureMessage.actualValue = ""
10 | }
11 | failureMessage.postfixMessage = "be an instance of \(NSStringFromClass(expectedClass))"
12 | return instance != nil && instance!.isMemberOfClass(expectedClass)
13 | }
14 | }
15 |
16 | extension NMBObjCMatcher {
17 | public class func beAnInstanceOfMatcher(expected: AnyClass) -> NMBMatcher {
18 | return NMBObjCMatcher { actualExpression, failureMessage, location in
19 | let expr = Expression(expression: actualExpression, location: location)
20 | return beAnInstanceOf(expected).matches(expr, failureMessage: failureMessage)
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeLessThanTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeLessThanTest: XCTestCase {
5 |
6 | func testLessThan() {
7 | expect(2).to(beLessThan(10))
8 | expect(2).toNot(beLessThan(1))
9 | expect(NSNumber(integer:2)).to(beLessThan(10))
10 | expect(NSNumber(integer:2)).toNot(beLessThan(1))
11 |
12 | expect(2).to(beLessThan(NSNumber(integer:10)))
13 | expect(2).toNot(beLessThan(NSNumber(integer:1)))
14 |
15 | failsWithErrorMessage("expected to be less than <0>, got <2>") {
16 | expect(2).to(beLessThan(0))
17 | return
18 | }
19 | failsWithErrorMessage("expected to not be less than <1>, got <0>") {
20 | expect(0).toNot(beLessThan(1))
21 | return
22 | }
23 | }
24 |
25 | func testLessThanOperator() {
26 | expect(0) < 1
27 | expect(NSNumber(int:0)) < 1
28 |
29 | failsWithErrorMessage("expected to be less than <1.0000>, got <2.0000>") {
30 | expect(2) < 1
31 | return
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Nimble/Matchers/Match.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func match(expectedValue:String?) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "match <\(stringify(expectedValue))>"
6 |
7 | if let actual = actualExpression.evaluate() {
8 | if let regexp = expectedValue {
9 | return actual.rangeOfString(regexp, options: .RegularExpressionSearch) != nil
10 | }
11 | }
12 |
13 | return false
14 | }
15 | }
16 |
17 | extension NMBObjCMatcher {
18 | public class func matchMatcher(expected: NSString) -> NMBMatcher {
19 | return NMBObjCMatcher { actualBlock, failureMessage, location in
20 | let actual = actualBlock()
21 | if let actualString = actual as? String {
22 | let expr = Expression(expression: ({ actualString }), location: location)
23 | return match(expected).matches(expr, failureMessage: failureMessage)
24 | }
25 | return false
26 | }
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/Nimble/Wrappers/MatcherFunc.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct MatcherFunc: BasicMatcher {
4 | public let matcher: (Expression, FailureMessage) -> Bool
5 |
6 | public init(_ matcher: (Expression, FailureMessage) -> Bool) {
7 | self.matcher = matcher
8 | }
9 |
10 | public func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool {
11 | return matcher(actualExpression, failureMessage)
12 | }
13 |
14 | public func withFailureMessage(postprocessor: (FailureMessage) -> Void) -> MatcherFunc {
15 | return MatcherFunc { actualExpression, failureMessage in
16 | let result = self.matches(actualExpression, failureMessage: failureMessage)
17 | postprocessor(failureMessage)
18 | return result
19 | }
20 | }
21 | }
22 |
23 | func _objc(matcher: MatcherFunc) -> NMBObjCMatcher {
24 | return NMBObjCMatcher { actualExpression, failureMessage, location in
25 | let expr = Expression(expression: actualExpression, location: location)
26 | return matcher.matches(expr, failureMessage: failureMessage)
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeLessThanOrEqualToTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeLessThanOrEqualToTest: XCTestCase {
5 | func testLessThanOrEqualTo() {
6 | expect(10).to(beLessThanOrEqualTo(10))
7 | expect(2).to(beLessThanOrEqualTo(10))
8 | expect(2).toNot(beLessThanOrEqualTo(1))
9 |
10 | expect(NSNumber(int:2)).to(beLessThanOrEqualTo(10))
11 | expect(NSNumber(int:2)).toNot(beLessThanOrEqualTo(1))
12 | expect(2).to(beLessThanOrEqualTo(NSNumber(int:10)))
13 | expect(2).toNot(beLessThanOrEqualTo(NSNumber(int:1)))
14 |
15 | failsWithErrorMessage("expected to be less than or equal to <0>, got <2>") {
16 | expect(2).to(beLessThanOrEqualTo(0))
17 | return
18 | }
19 | failsWithErrorMessage("expected to not be less than or equal to <0>, got <0>") {
20 | expect(0).toNot(beLessThanOrEqualTo(0))
21 | return
22 | }
23 | }
24 |
25 | func testLessThanOrEqualToOperator() {
26 | expect(0) <= 1
27 | expect(1) <= 1
28 |
29 | failsWithErrorMessage("expected to be less than or equal to <1>, got <2>") {
30 | expect(2) <= 1
31 | return
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Nimble/Wrappers/FullMatcherWrapper.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 |
4 | struct FullMatcherWrapper: Matcher {
5 | let matcher: M
6 | let to: String
7 | let toNot: String
8 |
9 | func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool {
10 | failureMessage.to = to
11 | let pass = matcher.matches(actualExpression, failureMessage: failureMessage)
12 | return pass
13 | }
14 |
15 | func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool {
16 | failureMessage.to = toNot
17 | let pass = matcher.matches(actualExpression, failureMessage: failureMessage)
18 | return !pass
19 | }
20 | }
21 |
22 | extension Expectation {
23 | public func to(matcher: U) {
24 | to(FullMatcherWrapper(matcher: matcher, to: "to", toNot: "to not"))
25 | }
26 |
27 | public func toNot(matcher: U) {
28 | toNot(FullMatcherWrapper(matcher: matcher, to: "to", toNot: "to not"))
29 | }
30 |
31 | public func notTo(matcher: U) {
32 | toNot(matcher)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeCloseToTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeCloseToTest: XCTestCase {
5 | func testBeCloseTo() {
6 | expect(1.2).to(beCloseTo(1.2001))
7 | expect(1.2 as CDouble).to(beCloseTo(1.2001))
8 | expect(1.2 as Float).to(beCloseTo(1.2001))
9 |
10 | failsWithErrorMessage("expected to not be close to <1.2001> (within 0.0001), got <1.2000>") {
11 | expect(1.2).toNot(beCloseTo(1.2001))
12 | }
13 | }
14 |
15 | func testBeCloseToWithin() {
16 | expect(1.2).to(beCloseTo(9.300, within: 10))
17 |
18 | failsWithErrorMessage("expected to not be close to <1.2001> (within 1.0000), got <1.2000>") {
19 | expect(1.2).toNot(beCloseTo(1.2001, within: 1.0))
20 | }
21 | }
22 |
23 | func testBeCloseToWithNSNumber() {
24 | expect(NSNumber(double:1.2)).to(beCloseTo(9.300, within: 10))
25 | expect(NSNumber(double:1.2)).to(beCloseTo(NSNumber(double:9.300), within: 10))
26 | expect(1.2).to(beCloseTo(NSNumber(double:9.300), within: 10))
27 |
28 | failsWithErrorMessage("expected to not be close to <1.2001> (within 1.0000), got <1.2000>") {
29 | expect(NSNumber(double:1.2)).toNot(beCloseTo(1.2001, within: 1.0))
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Nimble/Expectation.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct Expectation {
4 | let expression: Expression
5 |
6 | public func verify(pass: Bool, _ message: String) {
7 | CurrentAssertionHandler.assert(pass, message: message, location: expression.location)
8 | }
9 |
10 | public func to(matcher: U) {
11 | var msg = FailureMessage()
12 | let pass = matcher.matches(expression, failureMessage: msg)
13 | if msg.actualValue == "" {
14 | msg.actualValue = "<\(stringify(expression.evaluate()))>"
15 | }
16 | verify(pass, msg.stringValue())
17 | }
18 |
19 | public func toNot(matcher: U) {
20 | var msg = FailureMessage()
21 | let pass = matcher.doesNotMatch(expression, failureMessage: msg)
22 | if msg.actualValue == "" {
23 | msg.actualValue = "<\(stringify(expression.evaluate()))>"
24 | }
25 | verify(pass, msg.stringValue())
26 | }
27 |
28 | public func notTo(matcher: U) {
29 | toNot(matcher)
30 | }
31 |
32 | // see FullMatcherWrapper and AsyncMatcherWrapper for extensions
33 | // see NMBExpectation for Objective-C interface
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeGreaterThanOrEqualToTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeGreaterThanOrEqualToTest: XCTestCase {
5 |
6 | func testGreaterThanOrEqualTo() {
7 | expect(10).to(beGreaterThanOrEqualTo(10))
8 | expect(10).to(beGreaterThanOrEqualTo(2))
9 | expect(1).toNot(beGreaterThanOrEqualTo(2))
10 | expect(NSNumber(int:1)).toNot(beGreaterThanOrEqualTo(2))
11 | expect(NSNumber(int:2)).to(beGreaterThanOrEqualTo(NSNumber(int:2)))
12 | expect(1).to(beGreaterThanOrEqualTo(NSNumber(int:0)))
13 |
14 | failsWithErrorMessage("expected to be greater than or equal to <2>, got <0>") {
15 | expect(0).to(beGreaterThanOrEqualTo(2))
16 | return
17 | }
18 | failsWithErrorMessage("expected to not be greater than or equal to <1>, got <1>") {
19 | expect(1).toNot(beGreaterThanOrEqualTo(1))
20 | return
21 | }
22 | }
23 |
24 | func testGreaterThanOrEqualToOperator() {
25 | expect(0) >= 0
26 | expect(1) >= 0
27 | expect(NSNumber(int:1)) >= 1
28 | expect(NSNumber(int:1)) >= NSNumber(int:1)
29 |
30 | failsWithErrorMessage("expected to be greater than or equal to <2>, got <1>") {
31 | expect(1) >= 2
32 | return
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/EndWithTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class EndWithTest: XCTestCase {
5 |
6 | func testEndWithPositives() {
7 | expect([1, 2, 3]).to(endWith(3))
8 | expect([1, 2, 3]).toNot(endWith(2))
9 |
10 | expect("foobar").to(endWith("bar"))
11 | expect("foobar").toNot(endWith("oo"))
12 |
13 | expect(NSString(string: "foobar")).to(endWith("bar"))
14 | expect(NSString(string: "foobar")).toNot(endWith("oo"))
15 |
16 | expect(NSArray(array: ["a", "b"])).to(endWith("b"))
17 | expect(NSArray(array: ["a", "b"])).toNot(endWith("a"))
18 | expect(nil as NSArray?).toNot(endWith("a"))
19 | }
20 |
21 | func testEndWithNegatives() {
22 | failsWithErrorMessage("expected to end with <2>, got <[1, 2, 3]>") {
23 | expect([1, 2, 3]).to(endWith(2))
24 | }
25 | failsWithErrorMessage("expected to not end with <3>, got <[1, 2, 3]>") {
26 | expect([1, 2, 3]).toNot(endWith(3))
27 | }
28 | failsWithErrorMessage("expected to end with , got ") {
29 | expect("batman").to(endWith("atm"))
30 | }
31 | failsWithErrorMessage("expected to not end with , got ") {
32 | expect("batman").toNot(endWith("man"))
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeIdenticalToTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeIdenticalToTest: XCTestCase {
5 | func testBeIdenticalToPositive() {
6 | expect(NSNumber(integer:1)).to(beIdenticalTo(NSNumber(integer:1)))
7 | }
8 |
9 | func testBeIdenticalToNegative() {
10 | expect(NSNumber(integer:1)).toNot(beIdenticalTo("yo"))
11 | expect([1]).toNot(beIdenticalTo([1]))
12 | }
13 |
14 | func testBeIdenticalToPositiveMessage() {
15 | let num1 = NSNumber(integer:1)
16 | let num2 = NSNumber(integer:2)
17 | let message = NSString(format: "expected to be identical to <%p>, got <%p>", num2, num1)
18 | failsWithErrorMessage(message) {
19 | expect(num1).to(beIdenticalTo(num2))
20 | }
21 | }
22 |
23 | func testBeIdenticalToNegativeMessage() {
24 | let value1 = NSArray(array: [])
25 | let value2 = NSArray(array: [])
26 | let message = NSString(format: "expected to not be identical to <%p>, got <%p>", value2, value1)
27 | failsWithErrorMessage(message) {
28 | expect(value1).toNot(beIdenticalTo(value2))
29 | }
30 | }
31 |
32 | func testOperators() {
33 | expect(NSNumber(integer:1)) === NSNumber(integer:1)
34 | expect(NSNumber(integer:1)) !== NSNumber(integer:2)
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeIdenticalTo.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 |
4 | public func beIdenticalTo(expected: T?) -> MatcherFunc {
5 | return MatcherFunc { actualExpression, failureMessage in
6 | let actual = actualExpression.evaluate()
7 | failureMessage.actualValue = "\(_identityAsString(actual))"
8 | failureMessage.postfixMessage = "be identical to \(_identityAsString(expected))"
9 | let matches = actual === expected && actual !== nil
10 | if !matches && actual === nil {
11 | failureMessage.postfixMessage += " (will not compare nils, use beNil() instead)"
12 | }
13 | return matches
14 | }
15 | }
16 |
17 | public func ===(lhs: Expectation, rhs: T?) {
18 | lhs.to(beIdenticalTo(rhs))
19 | }
20 | public func !==(lhs: Expectation, rhs: T?) {
21 | lhs.toNot(beIdenticalTo(rhs))
22 | }
23 |
24 | extension NMBObjCMatcher {
25 | public class func beIdenticalToMatcher(expected: NSObject?) -> NMBObjCMatcher {
26 | return NMBObjCMatcher { actualBlock, failureMessage, location in
27 | let block = ({ actualBlock() as NSObject? })
28 | let expr = Expression(expression: block, location: location)
29 | return beIdenticalTo(expected).matches(expr, failureMessage: failureMessage)
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeginWithTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeginWithTest: XCTestCase {
5 |
6 | func testPositiveMatches() {
7 | expect([1, 2, 3]).to(beginWith(1))
8 | expect([1, 2, 3]).toNot(beginWith(2))
9 |
10 | expect("foobar").to(beginWith("foo"))
11 | expect("foobar").toNot(beginWith("oo"))
12 |
13 | expect(NSString(string: "foobar")).to(beginWith("foo"))
14 | expect(NSString(string: "foobar")).toNot(beginWith("oo"))
15 |
16 | expect(NSArray(array: ["a", "b"])).to(beginWith("a"))
17 | expect(NSArray(array: ["a", "b"])).toNot(beginWith("b"))
18 | expect(nil as NSArray?).toNot(beginWith("b"))
19 | }
20 |
21 | func testNegativeMatches() {
22 | failsWithErrorMessage("expected to begin with <2>, got <[1, 2, 3]>") {
23 | expect([1, 2, 3]).to(beginWith(2))
24 | }
25 | failsWithErrorMessage("expected to not begin with <1>, got <[1, 2, 3]>") {
26 | expect([1, 2, 3]).toNot(beginWith(1))
27 | }
28 | failsWithErrorMessage("expected to begin with , got ") {
29 | expect("batman").to(beginWith("atm"))
30 | }
31 | failsWithErrorMessage("expected to not begin with , got ") {
32 | expect("batman").toNot(beginWith("bat"))
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/Nimble/Expression.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | // Memoizes the given closure, only calling the passed
4 | // closure once; even if repeat calls to the returned closure
5 | func _memoizedClosure(closure: () -> T) -> (Bool) -> T {
6 | var cache: T?
7 | return ({ withoutCaching in
8 | if (withoutCaching || cache == nil) {
9 | cache = closure()
10 | }
11 | return cache!
12 | })
13 | }
14 |
15 | public struct Expression {
16 | public let _expression: (Bool) -> T?
17 | public let location: SourceLocation
18 | public let _withoutCaching: Bool
19 | public var cache: T?
20 |
21 | public init(expression: () -> T?, location: SourceLocation) {
22 | self._expression = _memoizedClosure(expression)
23 | self.location = location
24 | self._withoutCaching = false
25 | }
26 |
27 | public init(memoizedExpression: (Bool) -> T?, location: SourceLocation, withoutCaching: Bool) {
28 | self._expression = memoizedExpression
29 | self.location = location
30 | self._withoutCaching = withoutCaching
31 | }
32 |
33 | public func evaluate() -> T? {
34 | return self._expression(_withoutCaching)
35 | }
36 |
37 | public func withoutCaching() -> Expression {
38 | return Expression(memoizedExpression: self._expression, location: location, withoutCaching: true)
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Nimble/FailureMessage.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | @objc
4 | public class FailureMessage {
5 | public var expected: String = "expected"
6 | public var actualValue: String? = "" // empty string -> use default; nil -> exclude
7 | public var to: String = "to"
8 | public var postfixMessage: String = "match"
9 |
10 | public init() {
11 | }
12 |
13 | var description : String {
14 | var value = "\(expected) \(to) \(postfixMessage)"
15 | if let actualValue = actualValue {
16 | value = "\(expected) \(actualValue) \(to) \(postfixMessage)"
17 | }
18 | var lines: [String] = (value as NSString).componentsSeparatedByString("\n") as [String]
19 | let whitespace = NSCharacterSet.whitespaceAndNewlineCharacterSet()
20 | lines = lines.map { line in line.stringByTrimmingCharactersInSet(whitespace) }
21 | return "".join(lines)
22 | }
23 |
24 | public func stringValue() -> String {
25 | var value = "\(expected) \(to) \(postfixMessage)"
26 | if let actualValue = actualValue {
27 | value = "\(expected) \(to) \(postfixMessage), got \(actualValue)"
28 | }
29 | var lines: [String] = (value as NSString).componentsSeparatedByString("\n") as [String]
30 | let whitespace = NSCharacterSet.whitespaceAndNewlineCharacterSet()
31 | lines = lines.map { line in line.stringByTrimmingCharactersInSet(whitespace) }
32 | return "".join(lines)
33 | }
34 | }
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeIdenticalToObjectTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeIdenticalToObjectTest:XCTestCase {
5 | private class BeIdenticalToObjectTester {}
6 | private let testObjectA = BeIdenticalToObjectTester()
7 | private let testObjectB = BeIdenticalToObjectTester()
8 |
9 | func testBeIdenticalToPositive() {
10 | expect(testObjectA).to(beIdenticalTo(testObjectA))
11 | }
12 |
13 | func testBeIdenticalToNegative() {
14 | expect(testObjectA).toNot(beIdenticalTo(testObjectB))
15 | }
16 |
17 | func testBeIdenticalToPositiveMessage() {
18 | let message = NSString(format: "expected to be identical to <%p>, got <%p>",
19 | unsafeBitCast(testObjectB, Int.self), unsafeBitCast(testObjectA, Int.self))
20 | failsWithErrorMessage(message) {
21 | expect(self.testObjectA).to(beIdenticalTo(self.testObjectB))
22 | }
23 | }
24 |
25 | func testBeIdenticalToNegativeMessage() {
26 | let message = NSString(format: "expected to not be identical to <%p>, got <%p>",
27 | unsafeBitCast(testObjectA, Int.self), unsafeBitCast(testObjectA, Int.self))
28 | failsWithErrorMessage(message) {
29 | expect(self.testObjectA).toNot(beIdenticalTo(self.testObjectA))
30 | }
31 | }
32 |
33 | func testOperators() {
34 | expect(testObjectA) === testObjectA
35 | expect(testObjectA) !== testObjectB
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeLessThan.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func beLessThan(expectedValue: T?) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>"
6 | return actualExpression.evaluate() < expectedValue
7 | }
8 | }
9 |
10 | public func beLessThan(expectedValue: NMBComparable?) -> MatcherFunc {
11 | return MatcherFunc { actualExpression, failureMessage in
12 | failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>"
13 | let actualValue = actualExpression.evaluate()
14 | let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) == NSComparisonResult.OrderedAscending
15 | return matches
16 | }
17 | }
18 |
19 | public func <(lhs: Expectation, rhs: T) {
20 | lhs.to(beLessThan(rhs))
21 | }
22 |
23 | public func <(lhs: Expectation, rhs: NMBComparable?) {
24 | lhs.to(beLessThan(rhs))
25 | }
26 |
27 | extension NMBObjCMatcher {
28 | public class func beLessThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher {
29 | return NMBObjCMatcher { actualBlock, failureMessage, location in
30 | let block = ({ actualBlock() as NMBComparable? })
31 | let expr = Expression(expression: block, location: location)
32 | return beLessThan(expected).matches(expr, failureMessage: failureMessage)
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Nimble/Utils/Stringers.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 |
4 | func _identityAsString(value: AnyObject?) -> String {
5 | if value == nil {
6 | return "nil"
7 | }
8 | return NSString(format: "<%p>", unsafeBitCast(value!, Int.self))
9 | }
10 |
11 | func _arrayAsString(items: [T], joiner: String = ", ") -> String {
12 | return items.reduce("") { accum, item in
13 | let prefix = (accum.isEmpty ? "" : joiner)
14 | return accum + prefix + "\(item)"
15 | }
16 | }
17 |
18 | @objc protocol NMBStringer {
19 | func NMB_stringify() -> String
20 | }
21 |
22 | func stringify(value: S) -> String {
23 | var generator = value.generate()
24 | var strings = [String]()
25 | var value: S.Generator.Element?
26 | do {
27 | value = generator.next()
28 | if value != nil {
29 | strings.append(stringify(value))
30 | }
31 | } while value != nil
32 | let str = ", ".join(strings)
33 | return "[\(str)]"
34 | }
35 |
36 | extension NSArray : NMBStringer {
37 | func NMB_stringify() -> String {
38 | let str = self.componentsJoinedByString(", ")
39 | return "[\(str)]"
40 | }
41 | }
42 |
43 | func stringify(value: T) -> String {
44 | if value is Double {
45 | return NSString(format: "%.4f", (value as Double))
46 | }
47 | return toString(value)
48 | }
49 |
50 | func stringify(value: T?) -> String {
51 | if let unboxed = value {
52 | return stringify(unboxed)
53 | }
54 | return "nil"
55 | }
56 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeGreaterThan.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func beGreaterThan(expectedValue: T?) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "be greater than <\(stringify(expectedValue))>"
6 | return actualExpression.evaluate() > expectedValue
7 | }
8 | }
9 |
10 | public func beGreaterThan(expectedValue: NMBComparable?) -> MatcherFunc {
11 | return MatcherFunc { actualExpression, failureMessage in
12 | failureMessage.postfixMessage = "be greater than <\(stringify(expectedValue))>"
13 | let actualValue = actualExpression.evaluate()
14 | let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) == NSComparisonResult.OrderedDescending
15 | return matches
16 | }
17 | }
18 |
19 | public func >(lhs: Expectation, rhs: T) {
20 | lhs.to(beGreaterThan(rhs))
21 | }
22 |
23 | public func >(lhs: Expectation, rhs: NMBComparable?) {
24 | lhs.to(beGreaterThan(rhs))
25 | }
26 |
27 | extension NMBObjCMatcher {
28 | public class func beGreaterThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher {
29 | return NMBObjCMatcher { actualBlock, failureMessage, location in
30 | let block = ({ actualBlock() as NMBComparable? })
31 | let expr = Expression(expression: block, location: location)
32 | return beGreaterThan(expected).matches(expr, failureMessage: failureMessage)
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeLessThanOrEqual.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func beLessThanOrEqualTo(expectedValue: T?) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>"
6 | return actualExpression.evaluate() <= expectedValue
7 | }
8 | }
9 |
10 | public func beLessThanOrEqualTo(expectedValue: T?) -> MatcherFunc {
11 | return MatcherFunc { actualExpression, failureMessage in
12 | failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>"
13 | let actualValue = actualExpression.evaluate()
14 | return actualValue != nil && actualValue!.NMB_compare(expectedValue) != NSComparisonResult.OrderedDescending
15 | }
16 | }
17 |
18 | public func <=(lhs: Expectation, rhs: T) {
19 | lhs.to(beLessThanOrEqualTo(rhs))
20 | }
21 |
22 | public func <=(lhs: Expectation, rhs: T) {
23 | lhs.to(beLessThanOrEqualTo(rhs))
24 | }
25 |
26 | extension NMBObjCMatcher {
27 | public class func beLessThanOrEqualToMatcher(expected: NMBComparable?) -> NMBObjCMatcher {
28 | return NMBObjCMatcher { actualBlock, failureMessage, location in
29 | let block = ({ actualBlock() as NMBComparable? })
30 | let expr = Expression(expression: block, location: location)
31 | return beLessThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage)
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/NimbleTests/AsynchronousTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class AsyncTest: XCTestCase {
5 |
6 | func testAsyncPolling() {
7 | var value = 0
8 | deferToMainQueue { value = 1 }
9 | expect(value).toEventually(equal(1))
10 |
11 | deferToMainQueue { value = 0 }
12 | expect(value).toEventuallyNot(equal(1))
13 |
14 | failsWithErrorMessage("expected to eventually not equal <0>, got <0>") {
15 | expect(value).toEventuallyNot(equal(0))
16 | }
17 | failsWithErrorMessage("expected to eventually equal <1>, got <0>") {
18 | expect(value).toEventually(equal(1))
19 | }
20 | }
21 |
22 | func testAsyncCallback() {
23 | waitUntil { done in
24 | done()
25 | }
26 | waitUntil { done in
27 | deferToMainQueue {
28 | done()
29 | }
30 | }
31 | failsWithErrorMessage("Waited more than 1.0 second") {
32 | waitUntil(timeout: 1) { done in return }
33 | }
34 | failsWithErrorMessage("Waited more than 0.01 seconds") {
35 | waitUntil(timeout: 0.01) { done in
36 | NSThread.sleepForTimeInterval(0.1)
37 | done()
38 | }
39 | }
40 |
41 | failsWithErrorMessage("expected to equal <2>, got <1>") {
42 | waitUntil { done in
43 | NSThread.sleepForTimeInterval(0.1)
44 | expect(1).to(equal(2))
45 | done()
46 | }
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Nimble.xcodeproj/project.xcworkspace/xcshareddata/Nimble.xccheckout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDESourceControlProjectFavoriteDictionaryKey
6 |
7 | IDESourceControlProjectIdentifier
8 | 3C7A95C5-450E-4971-8DC4-2613B2BA4376
9 | IDESourceControlProjectName
10 | Nimble
11 | IDESourceControlProjectOriginsDictionary
12 |
13 | 95438028B10BBB846574013D29F154A00556A9D1
14 | github.com:quick/Nimble.git
15 |
16 | IDESourceControlProjectPath
17 | Nimble.xcodeproj
18 | IDESourceControlProjectRelativeInstallPathDictionary
19 |
20 | 95438028B10BBB846574013D29F154A00556A9D1
21 | ../..
22 |
23 | IDESourceControlProjectURL
24 | github.com:quick/Nimble.git
25 | IDESourceControlProjectVersion
26 | 111
27 | IDESourceControlProjectWCCIdentifier
28 | 95438028B10BBB846574013D29F154A00556A9D1
29 | IDESourceControlProjectWCConfigurations
30 |
31 |
32 | IDESourceControlRepositoryExtensionIdentifierKey
33 | public.vcs.git
34 | IDESourceControlWCCIdentifierKey
35 | 95438028B10BBB846574013D29F154A00556A9D1
36 | IDESourceControlWCCName
37 | Nimble
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeGreaterThanOrEqualTo.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func beGreaterThanOrEqualTo(expectedValue: T?) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>"
6 | let actualValue = actualExpression.evaluate()
7 | return actualValue >= expectedValue
8 | }
9 | }
10 |
11 | public func beGreaterThanOrEqualTo(expectedValue: T?) -> MatcherFunc {
12 | return MatcherFunc { actualExpression, failureMessage in
13 | failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>"
14 | let actualValue = actualExpression.evaluate()
15 | let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) != NSComparisonResult.OrderedAscending
16 | return matches
17 | }
18 | }
19 |
20 | public func >=(lhs: Expectation, rhs: T) {
21 | lhs.to(beGreaterThanOrEqualTo(rhs))
22 | }
23 |
24 | public func >=(lhs: Expectation, rhs: T) {
25 | lhs.to(beGreaterThanOrEqualTo(rhs))
26 | }
27 |
28 | extension NMBObjCMatcher {
29 | public class func beGreaterThanOrEqualToMatcher(expected: NMBComparable?) -> NMBObjCMatcher {
30 | return NMBObjCMatcher { actualBlock, failureMessage, location in
31 | let block = ({ actualBlock() as NMBComparable? })
32 | let expr = Expression(expression: block, location: location)
33 | return beGreaterThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage)
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeEmptyTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class BeEmptyTest: XCTestCase {
5 | func testBeEmptyPositive() {
6 | expect(nil as NSString?).to(beEmpty())
7 | expect(nil as [CInt]?).to(beEmpty())
8 |
9 | expect([]).to(beEmpty())
10 | expect([1]).toNot(beEmpty())
11 |
12 | expect([] as [CInt]).to(beEmpty())
13 | expect([1] as [CInt]).toNot(beEmpty())
14 |
15 | expect(NSDictionary()).to(beEmpty())
16 | expect(NSDictionary(object: 1, forKey: 1)).toNot(beEmpty())
17 |
18 | expect(Dictionary()).to(beEmpty())
19 | expect(["hi": 1]).toNot(beEmpty())
20 |
21 | expect(NSArray()).to(beEmpty())
22 | expect(NSArray(array: [1])).toNot(beEmpty())
23 |
24 | expect(NSSet()).to(beEmpty())
25 | expect(NSSet(array: [1])).toNot(beEmpty())
26 |
27 | expect(NSString()).to(beEmpty())
28 | expect(NSString(string: "hello")).toNot(beEmpty())
29 |
30 | expect("").to(beEmpty())
31 | expect("foo").toNot(beEmpty())
32 | }
33 |
34 | func testBeEmptyNegative() {
35 | failsWithErrorMessage("expected to not be empty, got <()>") {
36 | expect([]).toNot(beEmpty())
37 | }
38 | failsWithErrorMessage("expected to be empty, got <[1]>") {
39 | expect([1]).to(beEmpty())
40 | }
41 |
42 | failsWithErrorMessage("expected to not be empty, got <>") {
43 | expect("").toNot(beEmpty())
44 | }
45 | failsWithErrorMessage("expected to be empty, got ") {
46 | expect("foo").to(beEmpty())
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/test:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | BUILD_DIR=`pwd`/build
4 | BUILD_SDK_VERSION=${NIMBLE_BUILD_SDK_VERSION:-8.1}
5 | RUNTIME_SDK_VERSION=${NIMBLE_RUNTIME_SDK_VERSION:-8.1}
6 |
7 | set -e
8 |
9 | function run {
10 | echo "\x1B[01;92m==>\x1B[0m $@"
11 | "$@"
12 | }
13 |
14 | function test_ios {
15 | run osascript -e 'tell app "iOS Simulator" to quit'
16 | run xcodebuild -project Nimble.xcodeproj -scheme "Nimble-iOS" -configuration "Debug" -sdk "iphonesimulator$BUILD_SDK_VERSION" -destination "name=iPad Air,OS=$RUNTIME_SDK_VERSION" -destination-timeout 5 build test
17 |
18 | run osascript -e 'tell app "iOS Simulator" to quit'
19 | run xcodebuild -project Nimble.xcodeproj -scheme "Nimble-iOS" -configuration "Debug" -sdk "iphonesimulator$BUILD_SDK_VERSION" -destination "name=iPhone 5s,OS=$RUNTIME_SDK_VERSION" -destination-timeout 5 build test
20 | }
21 |
22 | function test_osx {
23 | run xcodebuild -project Nimble.xcodeproj -scheme "Nimble-OSX" -configuration "Debug" -sdk "macosx" -destination-timeout 5 build test
24 | }
25 |
26 | function test() {
27 | test_ios
28 | test_osx
29 | }
30 |
31 | function clean {
32 | run rm -rf ~/Library/Developer/Xcode/DerivedData
33 | }
34 |
35 | function help {
36 | echo "Usage: $0 COMMANDS"
37 | echo
38 | echo "COMMANDS:"
39 | echo " clean - Cleans the derived data directory of Xcode. Assumes default location"
40 | echo " ios - Runs the tests as an iOS device"
41 | echo " osx - Runs the tests on Mac OS X 10.10 (Yosemite and newer only)"
42 | echo " help - Displays this help"
43 | echo
44 | exit 1
45 | }
46 |
47 | function main {
48 | for arg in $@
49 | do
50 | case "$arg" in
51 | clean) clean ;;
52 | ios) test_ios ;;
53 | osx) test_osx ;;
54 | test) test ;;
55 | all) test ;;
56 | help) help ;;
57 | esac
58 | done
59 |
60 | if [ $# -eq 0 ]; then
61 | clean
62 | test
63 | fi
64 | }
65 |
66 | main $@
67 |
68 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/RaisesExceptionTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class RaisesExceptionTest: XCTestCase {
5 | var exception = NSException(name: "laugh", reason: "Lulz", userInfo: nil)
6 |
7 | func testCapturingInAutoClosure() {
8 | expect(exception.raise()).to(raiseException(named: "laugh"))
9 | expect(exception.raise()).to(raiseException())
10 |
11 | failsWithErrorMessage("expected to raise exception named ") {
12 | expect(self.exception.raise()).to(raiseException(named: "foo"))
13 | }
14 | }
15 |
16 | func testCapturingInExplicitClosure() {
17 | expect {
18 | self.exception.raise()
19 | }.to(raiseException(named: "laugh"))
20 |
21 | expect {
22 | self.exception.raise()
23 | }.to(raiseException())
24 | }
25 |
26 | func testCapturingWithReason() {
27 | expect(exception.raise()).to(raiseException(named: "laugh", reason: "Lulz"))
28 |
29 | failsWithErrorMessage("expected to raise any exception") {
30 | expect(self.exception).to(raiseException())
31 | }
32 | failsWithErrorMessage("expected to not raise any exception") {
33 | expect(self.exception.raise()).toNot(raiseException())
34 | }
35 | failsWithErrorMessage("expected to raise exception named and reason ") {
36 | expect(self.exception).to(raiseException(named: "laugh", reason: "Lulz"))
37 | }
38 |
39 | failsWithErrorMessage("expected to raise exception named and reason ") {
40 | expect(self.exception.raise()).to(raiseException(named: "bar", reason: "Lulz"))
41 | }
42 | failsWithErrorMessage("expected to not raise exception named ") {
43 | expect(self.exception.raise()).toNot(raiseException(named: "laugh"))
44 | }
45 | failsWithErrorMessage("expected to not raise exception named and reason ") {
46 | expect(self.exception.raise()).toNot(raiseException(named: "laugh", reason: "Lulz"))
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Nimble/Matchers/Contain.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func contain(items: T...) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "contain <\(_arrayAsString(items))>"
6 | if let actual = actualExpression.evaluate() {
7 | return _all(items) {
8 | return contains(actual, $0)
9 | }
10 | }
11 | return false
12 | }
13 | }
14 |
15 | public func contain(substrings: String...) -> MatcherFunc {
16 | return MatcherFunc { actualExpression, failureMessage in
17 | failureMessage.postfixMessage = "contain <\(_arrayAsString(substrings))>"
18 | if let actual = actualExpression.evaluate() {
19 | return _all(substrings) {
20 | let scanRange = Range(start: actual.startIndex, end: actual.endIndex)
21 | let range = actual.rangeOfString($0, options: nil, range: scanRange, locale: nil)
22 | return range != nil && !range!.isEmpty
23 | }
24 | }
25 | return false
26 | }
27 | }
28 |
29 | public func contain(items: AnyObject?...) -> MatcherFunc {
30 | return MatcherFunc { actualExpression, failureMessage in
31 | failureMessage.postfixMessage = "contain <\(_arrayAsString(items))>"
32 | let actual = actualExpression.evaluate()
33 | return _all(items) { item in
34 | return actual != nil && actual!.containsObject(item)
35 | }
36 | }
37 | }
38 |
39 | extension NMBObjCMatcher {
40 | public class func containMatcher(expected: NSObject?) -> NMBObjCMatcher {
41 | return NMBObjCMatcher { actualBlock, failureMessage, location in
42 | let block: () -> NMBContainer? = ({
43 | if let value = actualBlock() as? NMBContainer {
44 | return value
45 | }
46 | return nil
47 | })
48 | let expr = Expression(expression: block, location: location)
49 | return contain(expected).matches(expr, failureMessage: failureMessage)
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeginWith.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func beginWith(startingElement: T) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "begin with <\(startingElement)>"
6 | if let actualValue = actualExpression.evaluate() {
7 | var actualGenerator = actualValue.generate()
8 | return actualGenerator.next() == startingElement
9 | }
10 | return false
11 | }
12 | }
13 |
14 | public func beginWith(startingElement: AnyObject) -> MatcherFunc {
15 | return MatcherFunc { actualExpression, failureMessage in
16 | failureMessage.postfixMessage = "begin with <\(startingElement)>"
17 | let collection = actualExpression.evaluate()
18 | return collection != nil && collection!.indexOfObject(startingElement) == 0
19 | }
20 | }
21 |
22 | public func beginWith(startingSubstring: String) -> MatcherFunc {
23 | return MatcherFunc { actualExpression, failureMessage in
24 | failureMessage.postfixMessage = "begin with <\(startingSubstring)>"
25 | if let actual = actualExpression.evaluate() {
26 | let range = actual.rangeOfString(startingSubstring)
27 | return range != nil && range!.startIndex == actual.startIndex
28 | }
29 | return false
30 | }
31 | }
32 |
33 | extension NMBObjCMatcher {
34 | public class func beginWithMatcher(expected: AnyObject) -> NMBObjCMatcher {
35 | return NMBObjCMatcher { actualBlock, failureMessage, location in
36 | let actual = actualBlock()
37 | if let actualString = actual as? String {
38 | let expr = Expression(expression: ({ actualString }), location: location)
39 | return beginWith(expected as NSString).matches(expr, failureMessage: failureMessage)
40 | } else {
41 | let expr = Expression(expression: ({ actual as? NMBOrderedCollection }), location: location)
42 | return beginWith(expected).matches(expr, failureMessage: failureMessage)
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeEmpty.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func beEmpty() -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "be empty"
6 | let actualSeq = actualExpression.evaluate()
7 | if actualSeq == nil {
8 | return true
9 | }
10 | var generator = actualSeq!.generate()
11 | return generator.next() == nil
12 | }
13 | }
14 |
15 | public func beEmpty() -> MatcherFunc {
16 | return MatcherFunc { actualExpression, failureMessage in
17 | failureMessage.postfixMessage = "be empty"
18 | let actualString = actualExpression.evaluate()
19 | return actualString == nil || actualString!.length == 0
20 | }
21 | }
22 |
23 | // Without specific overrides, beEmpty() is ambiguous for NSDictionary, NSArray,
24 | // etc, since they conform to SequenceType as well as NMBCollection.
25 | public func beEmpty() -> MatcherFunc {
26 | return MatcherFunc { actualExpression, failureMessage in
27 | failureMessage.postfixMessage = "be empty"
28 | let actualDictionary = actualExpression.evaluate()
29 | return actualDictionary == nil || actualDictionary!.count == 0
30 | }
31 | }
32 |
33 | public func beEmpty() -> MatcherFunc {
34 | return MatcherFunc { actualExpression, failureMessage in
35 | failureMessage.postfixMessage = "be empty"
36 | let actualArray = actualExpression.evaluate()
37 | return actualArray == nil || actualArray!.count == 0
38 | }
39 | }
40 |
41 | public func beEmpty() -> MatcherFunc {
42 | return MatcherFunc { actualExpression, failureMessage in
43 | failureMessage.postfixMessage = "be empty"
44 | let actual = actualExpression.evaluate()
45 | return actual == nil || actual!.count == 0
46 | }
47 | }
48 |
49 | extension NMBObjCMatcher {
50 | class func beEmptyMatcher() -> NMBObjCMatcher {
51 | return NMBObjCMatcher { actualBlock, failureMessage, location in
52 | let block = ({ actualBlock() as? NMBCollection })
53 | let expr = Expression(expression: block, location: location)
54 | return beEmpty().matches(expr, failureMessage: failureMessage)
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeCloseTo.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | func _isCloseTo(actualValue: Double?, expectedValue: Double, delta: Double, failureMessage: FailureMessage) -> Bool {
4 | failureMessage.postfixMessage = "be close to <\(stringify(expectedValue))> (within \(stringify(delta)))"
5 | if actualValue != nil {
6 | failureMessage.actualValue = "<\(stringify(actualValue!))>"
7 | } else {
8 | failureMessage.actualValue = ""
9 | }
10 | return actualValue != nil && abs(actualValue! - expectedValue) < delta
11 | }
12 |
13 | public func beCloseTo(expectedValue: Double, within delta: Double = 0.0001) -> MatcherFunc {
14 | return MatcherFunc { actualExpression, failureMessage in
15 | return _isCloseTo(actualExpression.evaluate(), expectedValue, delta, failureMessage)
16 | }
17 | }
18 |
19 | public func beCloseTo(expectedValue: NMBDoubleConvertible, within delta: Double = 0.0001) -> MatcherFunc {
20 | return MatcherFunc { actualExpression, failureMessage in
21 | return _isCloseTo(actualExpression.evaluate()?.doubleValue, expectedValue.doubleValue, delta, failureMessage)
22 | }
23 | }
24 |
25 | @objc public class NMBObjCBeCloseToMatcher : NMBMatcher {
26 | var _expected: NSNumber
27 | var _delta: CDouble
28 | init(expected: NSNumber, within: CDouble) {
29 | _expected = expected
30 | _delta = within
31 | }
32 |
33 | public func matches(actualExpression: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool {
34 | let actualBlock: () -> NMBDoubleConvertible? = ({
35 | return actualExpression() as? NMBDoubleConvertible
36 | })
37 | let expr = Expression(expression: actualBlock, location: location)
38 | return beCloseTo(self._expected, within: self._delta).matches(expr, failureMessage: failureMessage)
39 | }
40 |
41 | public var within: (CDouble) -> NMBObjCBeCloseToMatcher {
42 | return ({ delta in
43 | return NMBObjCBeCloseToMatcher(expected: self._expected, within: delta)
44 | })
45 | }
46 | }
47 |
48 | extension NMBObjCMatcher {
49 | public class func beCloseToMatcher(expected: NSNumber, within: CDouble) -> NMBObjCBeCloseToMatcher {
50 | return NMBObjCBeCloseToMatcher(expected: expected, within: within)
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Nimble/DSL.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | // Begins an assertion on a given value.
4 | // file: and line: can be omitted to default to the current line this function is called on.
5 | public func expect(expression: @autoclosure () -> T?, file: String = __FILE__, line: UInt = __LINE__) -> Expectation {
6 | return Expectation(
7 | expression: Expression(
8 | expression: expression,
9 | location: SourceLocation(file: file, line: line)))
10 | }
11 |
12 | // Begins an assertion on a given value.
13 | // file: and line: can be omitted to default to the current line this function is called on.
14 | public func expect(file: String = __FILE__, line: UInt = __LINE__, expression: () -> T?) -> Expectation {
15 | return Expectation(
16 | expression: Expression(
17 | expression: expression,
18 | location: SourceLocation(file: file, line: line)))
19 | }
20 |
21 | // Begins an assertion on a given value.
22 | // file: and line: can be omitted to default to the current line this function is called on.
23 | public func waitUntil(#timeout: NSTimeInterval, action: (() -> Void) -> Void, file: String = __FILE__, line: UInt = __LINE__) -> Void {
24 | var completed = false
25 | dispatch_async(dispatch_get_main_queue()) {
26 | action() { completed = true }
27 | }
28 | let passed = _pollBlock(pollInterval: 0.01, timeoutInterval: timeout) {
29 | return completed
30 | }
31 | if !passed {
32 | let pluralize = (timeout == 1 ? "" : "s")
33 | fail("Waited more than \(timeout) second\(pluralize)", file: file, line: line)
34 | }
35 | }
36 |
37 | // Begins an assertion on a given value.
38 | // file: and line: can be omitted to default to the current line this function is called on.
39 | public func waitUntil(action: (() -> Void) -> Void, file: String = __FILE__, line: UInt = __LINE__) -> Void {
40 | waitUntil(timeout: 1, action, file: file, line: line)
41 | }
42 |
43 | public func fail(message: String, #location: SourceLocation) {
44 | CurrentAssertionHandler.assert(false, message: message, location: location)
45 | }
46 |
47 | public func fail(message: String, file: String = __FILE__, line: UInt = __LINE__) {
48 | fail(message, location: SourceLocation(file: file, line: line))
49 | }
50 |
51 | public func fail(file: String = __FILE__, line: UInt = __LINE__) {
52 | fail("fail() always fails")
53 | }
--------------------------------------------------------------------------------
/NimbleTests/Matchers/ContainTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class ContainTest: XCTestCase {
5 | func testContain() {
6 | expect([1, 2, 3]).to(contain(1))
7 | expect([1, 2, 3] as [CInt]).to(contain(1 as CInt))
8 | expect([1, 2, 3] as Array).to(contain(1 as CInt))
9 | expect(["foo", "bar", "baz"]).to(contain("baz"))
10 | expect([1, 2, 3]).toNot(contain(4))
11 | expect(["foo", "bar", "baz"]).toNot(contain("ba"))
12 | expect(NSArray(array: ["a"])).to(contain("a"))
13 | expect(NSArray(array: ["a"])).toNot(contain("b"))
14 | expect(NSArray(object: 1) as NSArray?).to(contain(1))
15 | expect(nil as NSArray?).toNot(contain(1))
16 |
17 | failsWithErrorMessage("expected to contain , got <[a, b, c]>") {
18 | expect(["a", "b", "c"]).to(contain("bar"))
19 | }
20 | failsWithErrorMessage("expected to not contain , got <[a, b, c]>") {
21 | expect(["a", "b", "c"]).toNot(contain("b"))
22 | }
23 | }
24 |
25 | func testContainSubstring() {
26 | expect("foo").to(contain("o"))
27 | expect("foo").to(contain("oo"))
28 | expect("foo").toNot(contain("z"))
29 | expect("foo").toNot(contain("zz"))
30 |
31 | failsWithErrorMessage("expected to contain , got ") {
32 | expect("foo").to(contain("bar"))
33 | }
34 | failsWithErrorMessage("expected to not contain , got ") {
35 | expect("foo").toNot(contain("oo"))
36 | }
37 | }
38 |
39 | func testContainObjCSubstring() {
40 | let str = NSString(string: "foo")
41 | expect(str).to(contain(NSString(string: "o")))
42 | expect(str).to(contain(NSString(string: "oo")))
43 | expect(str).toNot(contain(NSString(string: "z")))
44 | expect(str).toNot(contain(NSString(string: "zz")))
45 | }
46 |
47 | func testVariadicArguments() {
48 | expect([1, 2, 3]).to(contain(1, 2))
49 | expect([1, 2, 3]).toNot(contain(1, 4))
50 |
51 | failsWithErrorMessage("expected to contain , got <[a, b, c]>") {
52 | expect(["a", "b", "c"]).to(contain("a", "bar"))
53 | }
54 |
55 | failsWithErrorMessage("expected to not contain , got <[a, b, c]>") {
56 | expect(["a", "b", "c"]).toNot(contain("bar", "b"))
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Nimble/Matchers/EndWith.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public func endWith(endingElement: T) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "end with <\(endingElement)>"
6 |
7 | if let actualValue = actualExpression.evaluate() {
8 | var actualGenerator = actualValue.generate()
9 | var lastItem: T?
10 | var item: T?
11 | do {
12 | lastItem = item
13 | item = actualGenerator.next()
14 | } while(item != nil)
15 |
16 | return lastItem == endingElement
17 | }
18 | return false
19 | }
20 | }
21 |
22 | public func endWith(endingElement: AnyObject) -> MatcherFunc {
23 | return MatcherFunc { actualExpression, failureMessage in
24 | failureMessage.postfixMessage = "end with <\(endingElement)>"
25 | let collection = actualExpression.evaluate()
26 | return collection != nil && collection!.indexOfObject(endingElement) == collection!.count - 1
27 | }
28 | }
29 |
30 | public func endWith(endingSubstring: String) -> MatcherFunc {
31 | return MatcherFunc { actualExpression, failureMessage in
32 | failureMessage.postfixMessage = "end with <\(endingSubstring)>"
33 | if let collection = actualExpression.evaluate() {
34 | let range = collection.rangeOfString(endingSubstring)
35 | return range != nil && range!.endIndex == collection.endIndex
36 | }
37 | return false
38 | }
39 | }
40 |
41 | extension NMBObjCMatcher {
42 | public class func endWithMatcher(expected: AnyObject) -> NMBObjCMatcher {
43 | return NMBObjCMatcher { actualBlock, failureMessage, location in
44 | let actual = actualBlock()
45 | if let actualString = actual as? String {
46 | let expr = Expression(expression: ({ actualString }), location: location)
47 | return endWith(expected as NSString).matches(expr, failureMessage: failureMessage)
48 | } else {
49 | let expr = Expression(expression: ({ actual as? NMBOrderedCollection }), location: location)
50 | return endWith(expected).matches(expr, failureMessage: failureMessage)
51 | }
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Nimble/Wrappers/AsyncMatcherWrapper.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct AsyncMatcherWrapper: Matcher {
4 | let fullMatcher: U
5 | let timeoutInterval: NSTimeInterval = 1
6 | let pollInterval: NSTimeInterval = 0.01
7 |
8 | func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool {
9 | let uncachedExpression = actualExpression.withoutCaching()
10 | return _pollBlock(pollInterval: pollInterval, timeoutInterval: timeoutInterval) {
11 | self.fullMatcher.matches(uncachedExpression, failureMessage: failureMessage)
12 | }
13 | }
14 |
15 | func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool {
16 | let uncachedExpression = actualExpression.withoutCaching()
17 | return _pollBlock(pollInterval: pollInterval, timeoutInterval: timeoutInterval) {
18 | self.fullMatcher.doesNotMatch(uncachedExpression, failureMessage: failureMessage)
19 | }
20 | }
21 | }
22 |
23 | extension Expectation {
24 | public func toEventually(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
25 | to(AsyncMatcherWrapper(
26 | fullMatcher: matcher,
27 | timeoutInterval: timeout,
28 | pollInterval: pollInterval))
29 | }
30 |
31 | public func toEventuallyNot(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
32 | toNot(AsyncMatcherWrapper(
33 | fullMatcher: matcher,
34 | timeoutInterval: timeout,
35 | pollInterval: pollInterval))
36 | }
37 |
38 | public func toEventually(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
39 | toEventually(
40 | FullMatcherWrapper(
41 | matcher: matcher,
42 | to: "to eventually",
43 | toNot: "to eventually not"),
44 | timeout: timeout,
45 | pollInterval: pollInterval)
46 | }
47 |
48 | public func toEventuallyNot(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
49 | toEventuallyNot(
50 | FullMatcherWrapper(
51 | matcher: matcher,
52 | to: "to eventually",
53 | toNot: "to eventually not"),
54 | timeout: timeout,
55 | pollInterval: pollInterval)
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Nimble/Matchers/MatcherProtocols.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 |
4 | // Implement this protocol if you want full control over to() and toNot() behaviors
5 | public protocol Matcher {
6 | typealias ValueType
7 | func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool
8 | func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool
9 | }
10 |
11 | // Implement this protocol if you just want a simplier matcher. The negation
12 | // is provided for you automatically.
13 | //
14 | // If you just want a very simplified usage of BasicMatcher,
15 | // @see MatcherFunc.
16 | public protocol BasicMatcher {
17 | typealias ValueType
18 | func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool
19 | }
20 |
21 | // Objective-C interface to a similar interface
22 | @objc public protocol NMBMatcher {
23 | func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool
24 | }
25 |
26 | // Protocol for types that support contain() matcher
27 | @objc public protocol NMBContainer {
28 | func containsObject(object: AnyObject!) -> Bool
29 | }
30 | extension NSArray : NMBContainer {}
31 | extension NSSet : NMBContainer {}
32 | extension NSHashTable : NMBContainer {}
33 |
34 | // Protocol for types that support only beEmpty()
35 | @objc public protocol NMBCollection {
36 | var count: Int { get }
37 | }
38 | extension NSSet : NMBCollection {}
39 | extension NSDictionary : NMBCollection {}
40 | extension NSHashTable : NMBCollection {}
41 |
42 | // Protocol for types that support beginWith(), endWith(), beEmpty() matchers
43 | @objc public protocol NMBOrderedCollection : NMBCollection {
44 | func indexOfObject(object: AnyObject!) -> Int
45 | }
46 | extension NSArray : NMBOrderedCollection {}
47 |
48 | // Protocol for types to support beCloseTo() matcher
49 | @objc public protocol NMBDoubleConvertible {
50 | var doubleValue: CDouble { get }
51 | }
52 | extension NSNumber : NMBDoubleConvertible { }
53 | extension NSDecimalNumber : NMBDoubleConvertible { } // TODO: not the best to downsize
54 |
55 | // Protocol for types to support beLessThan(), beLessThanOrEqualTo(),
56 | // beGreaterThan(), beGreaterThanOrEqualTo(), and equal() matchers.
57 | //
58 | // Types that conform to Swift's Comparable protocol will work implicitly too
59 | @objc public protocol NMBComparable {
60 | func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult
61 | }
62 | extension NSNumber : NMBComparable {
63 | public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult {
64 | return compare(otherObject as NSNumber)
65 | }
66 | }
67 | extension NSString : NMBComparable {
68 | public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult {
69 | return compare(otherObject as NSString)
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/Nimble/Matchers/BeLogical.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | func _beBool(#expectedValue: BooleanType, #stringValue: String, #falseMatchesNil: Bool) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.postfixMessage = "be \(stringValue)"
6 | let actual = actualExpression.evaluate()
7 | if expectedValue {
8 | return actual?.boolValue == expectedValue.boolValue
9 | } else if !falseMatchesNil {
10 | return actual != nil && actual!.boolValue != !expectedValue.boolValue
11 | } else {
12 | return actual?.boolValue != !expectedValue.boolValue
13 | }
14 | }
15 | }
16 |
17 | // mark: beTrue() / beFalse()
18 |
19 | public func beTrue() -> MatcherFunc {
20 | return equal(true).withFailureMessage { failureMessage in
21 | failureMessage.postfixMessage = "be true"
22 | }
23 | }
24 |
25 | public func beFalse() -> MatcherFunc {
26 | return equal(false).withFailureMessage { failureMessage in
27 | failureMessage.postfixMessage = "be false"
28 | }
29 | }
30 |
31 | // mark: beTruthy() / beFalsy()
32 |
33 | public func beTruthy() -> MatcherFunc {
34 | return _beBool(expectedValue: true, stringValue: "truthy", falseMatchesNil: true)
35 | }
36 |
37 | public func beFalsy() -> MatcherFunc {
38 | return _beBool(expectedValue: false, stringValue: "falsy", falseMatchesNil: true)
39 | }
40 |
41 | extension NMBObjCMatcher {
42 | public class func beTruthyMatcher() -> NMBObjCMatcher {
43 | return NMBObjCMatcher { actualBlock, failureMessage, location in
44 | let block = ({ (actualBlock() as? NSNumber)?.boolValue ?? false as BooleanType? })
45 | let expr = Expression(expression: block, location: location)
46 | return beTruthy().matches(expr, failureMessage: failureMessage)
47 | }
48 | }
49 |
50 | public class func beFalsyMatcher() -> NMBObjCMatcher {
51 | return NMBObjCMatcher { actualBlock, failureMessage, location in
52 | let block = ({ (actualBlock() as? NSNumber)?.boolValue ?? false as BooleanType? })
53 | let expr = Expression(expression: block, location: location)
54 | return beFalsy().matches(expr, failureMessage: failureMessage)
55 | }
56 | }
57 |
58 | public class func beTrueMatcher() -> NMBObjCMatcher {
59 | return NMBObjCMatcher { actualBlock, failureMessage, location in
60 | let block = ({ (actualBlock() as? NSNumber)?.boolValue as Bool? })
61 | let expr = Expression(expression: block, location: location)
62 | return beTrue().matches(expr, failureMessage: failureMessage)
63 | }
64 | }
65 |
66 | public class func beFalseMatcher() -> NMBObjCMatcher {
67 | return NMBObjCMatcher { actualBlock, failureMessage, location in
68 | let block = ({ (actualBlock() as? NSNumber)?.boolValue as Bool? })
69 | let expr = Expression(expression: block, location: location)
70 | return beFalse().matches(expr, failureMessage: failureMessage)
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Nimble/objc/DSL.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 | NIMBLE_EXPORT NMBExpectation *NMB_expect(id(^actualBlock)(), const char *file, unsigned int line) {
5 | return [[NMBExpectation alloc] initWithActualBlock:actualBlock
6 | negative:NO
7 | file:[[NSString alloc] initWithFormat:@"%s", file]
8 | line:line];
9 | }
10 |
11 | NIMBLE_EXPORT id NMB_beAnInstanceOf(Class expectedClass) {
12 | return [NMBObjCMatcher beAnInstanceOfMatcher:expectedClass];
13 | }
14 |
15 | NIMBLE_EXPORT id NMB_beAKindOf(Class expectedClass) {
16 | return [NMBObjCMatcher beAKindOfMatcher:expectedClass];
17 | }
18 |
19 | NIMBLE_EXPORT NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue) {
20 | return [NMBObjCMatcher beCloseToMatcher:expectedValue within:0.001];
21 | }
22 |
23 | NIMBLE_EXPORT id NMB_beginWith(id itemElementOrSubstring) {
24 | return [NMBObjCMatcher beginWithMatcher:itemElementOrSubstring];
25 | }
26 |
27 | NIMBLE_EXPORT id NMB_beGreaterThan(NSNumber *expectedValue) {
28 | return [NMBObjCMatcher beGreaterThanMatcher:expectedValue];
29 | }
30 |
31 | NIMBLE_EXPORT id NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue) {
32 | return [NMBObjCMatcher beGreaterThanOrEqualToMatcher:expectedValue];
33 | }
34 |
35 | NIMBLE_EXPORT id NMB_beIdenticalTo(id expectedInstance) {
36 | return [NMBObjCMatcher beIdenticalToMatcher:expectedInstance];
37 | }
38 |
39 | NIMBLE_EXPORT id NMB_beLessThan(NSNumber *expectedValue) {
40 | return [NMBObjCMatcher beLessThanMatcher:expectedValue];
41 | }
42 |
43 | NIMBLE_EXPORT id NMB_beLessThanOrEqualTo(NSNumber *expectedValue) {
44 | return [NMBObjCMatcher beLessThanOrEqualToMatcher:expectedValue];
45 | }
46 |
47 | NIMBLE_EXPORT id NMB_beTruthy() {
48 | return [NMBObjCMatcher beTruthyMatcher];
49 | }
50 |
51 | NIMBLE_EXPORT id NMB_beFalsy() {
52 | return [NMBObjCMatcher beFalsyMatcher];
53 | }
54 |
55 | NIMBLE_EXPORT id NMB_beTrue() {
56 | return [NMBObjCMatcher beTrueMatcher];
57 | }
58 |
59 | NIMBLE_EXPORT id NMB_beFalse() {
60 | return [NMBObjCMatcher beFalseMatcher];
61 | }
62 |
63 | NIMBLE_EXPORT id NMB_beNil() {
64 | return [NMBObjCMatcher beNilMatcher];
65 | }
66 |
67 | NIMBLE_EXPORT id NMB_contain(id itemOrSubstring) {
68 | return [NMBObjCMatcher containMatcher:itemOrSubstring];
69 | }
70 |
71 | NIMBLE_EXPORT id NMB_endWith(id itemElementOrSubstring) {
72 | return [NMBObjCMatcher endWithMatcher:itemElementOrSubstring];
73 | }
74 |
75 | NIMBLE_EXPORT id NMB_equal(id expectedValue) {
76 | return [NMBObjCMatcher equalMatcher:expectedValue];
77 | }
78 |
79 | NIMBLE_EXPORT id NMB_match(id expectedValue) {
80 | return [NMBObjCMatcher matchMatcher:expectedValue];
81 | }
82 |
83 | NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException() {
84 | return [NMBObjCMatcher raiseExceptionMatcher];
85 | }
86 |
87 |
--------------------------------------------------------------------------------
/Nimble.xcodeproj/xcshareddata/xcschemes/Nimble-OSX.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
71 |
72 |
74 |
75 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/Nimble.xcodeproj/xcshareddata/xcschemes/Nimble-iOS.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
53 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
71 |
72 |
74 |
75 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/Nimble/Matchers/RaisesException.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | func _raiseExceptionMatcher(message: String, matches: (NSException?) -> Bool) -> MatcherFunc {
4 | return MatcherFunc { actualExpression, failureMessage in
5 | failureMessage.actualValue = nil
6 | failureMessage.postfixMessage = message
7 |
8 | // It would be better if this was part of Expression, but
9 | // Swift compiler crashes when expect() is inside a closure.
10 | var exception: NSException?
11 | var result: T?
12 | var capture = NMBExceptionCapture(handler: ({ e in
13 | exception = e
14 | }), finally: nil)
15 |
16 | capture.tryBlock {
17 | actualExpression.evaluate()
18 | return
19 | }
20 | return matches(exception)
21 | }
22 | }
23 |
24 | public func raiseException(#named: String, #reason: String?) -> MatcherFunc {
25 | var theReason = ""
26 | if let reason = reason {
27 | theReason = reason
28 | }
29 | return _raiseExceptionMatcher("raise exception named <\(named)> and reason <\(theReason)>") {
30 | exception in return exception?.name == named && exception?.reason == reason
31 | }
32 | }
33 |
34 | public func raiseException(#named: String) -> MatcherFunc {
35 | return _raiseExceptionMatcher("raise exception named <\(named)>") {
36 | exception in return exception?.name == named
37 | }
38 | }
39 |
40 | public func raiseException() -> MatcherFunc {
41 | return _raiseExceptionMatcher("raise any exception") {
42 | exception in return exception != nil
43 | }
44 | }
45 |
46 | @objc public class NMBObjCRaiseExceptionMatcher : NMBMatcher {
47 | var _name: String?
48 | var _reason: String?
49 | init(name: String?, reason: String?) {
50 | _name = name
51 | _reason = reason
52 | }
53 |
54 | public func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool {
55 | let block: () -> Any? = ({ actualBlock(); return nil })
56 | let expr = Expression(expression: block, location: location)
57 | if _name != nil && _reason != nil {
58 | return raiseException(named: _name!, reason: _reason).matches(expr, failureMessage: failureMessage)
59 | } else if _name != nil {
60 | return raiseException(named: _name!).matches(expr, failureMessage: failureMessage)
61 | } else {
62 | return raiseException().matches(expr, failureMessage: failureMessage)
63 | }
64 | }
65 |
66 | var named: (name: String) -> NMBObjCRaiseExceptionMatcher {
67 | return ({ name in
68 | return NMBObjCRaiseExceptionMatcher(name: name, reason: self._reason)
69 | })
70 | }
71 |
72 | var reason: (reason: String?) -> NMBObjCRaiseExceptionMatcher {
73 | return ({ reason in
74 | return NMBObjCRaiseExceptionMatcher(name: self._name, reason: reason)
75 | })
76 | }
77 | }
78 |
79 | extension NMBObjCMatcher {
80 | public class func raiseExceptionMatcher() -> NMBObjCRaiseExceptionMatcher {
81 | return NMBObjCRaiseExceptionMatcher(name: nil, reason: nil)
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/NimbleTests/SynchronousTests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class SynchronousTest: XCTestCase {
5 | func testFailAlwaysFails() {
6 | failsWithErrorMessage("My error message") {
7 | fail("My error message")
8 | }
9 | failsWithErrorMessage("fail() always fails") {
10 | fail()
11 | }
12 | }
13 |
14 | func testToMatchesIfMatcherReturnsTrue() {
15 | expect(1).to(MatcherFunc { expr, failure in true })
16 | expect{1}.to(MatcherFunc { expr, failure in true })
17 | }
18 |
19 | func testToProvidesActualValueExpression() {
20 | var value: Int?
21 | expect(1).to(MatcherFunc { expr, failure in value = expr.evaluate(); return true })
22 | expect(value).to(equal(1))
23 | }
24 |
25 | func testToProvidesAMemoizedActualValueExpression() {
26 | var callCount = 0
27 | expect{ callCount++ }.to(MatcherFunc { expr, failure in
28 | expr.evaluate()
29 | expr.evaluate()
30 | return true
31 | })
32 | expect(callCount).to(equal(1))
33 | }
34 |
35 | func testToProvidesAMemoizedActualValueExpressionIsEvaluatedAtMatcherControl() {
36 | var callCount = 0
37 | expect{ callCount++ }.to(MatcherFunc { expr, failure in
38 | expect(callCount).to(equal(0))
39 | expr.evaluate()
40 | return true
41 | })
42 | expect(callCount).to(equal(1))
43 | }
44 |
45 | func testToMatchAgainstLazyProperties() {
46 | expect(ObjectWithLazyProperty().value).to(equal("hello"))
47 | expect(ObjectWithLazyProperty().value).toNot(equal("world"))
48 | expect(ObjectWithLazyProperty().anotherValue).to(equal("world"))
49 | expect(ObjectWithLazyProperty().anotherValue).toNot(equal("hello"))
50 | }
51 |
52 | // repeated tests from to() for toNot()
53 | func testToNotMatchesIfMatcherReturnsTrue() {
54 | expect(1).toNot(MatcherFunc { expr, failure in false })
55 | expect{1}.toNot(MatcherFunc { expr, failure in false })
56 | }
57 |
58 | func testToNotProvidesActualValueExpression() {
59 | var value: Int?
60 | expect(1).toNot(MatcherFunc { expr, failure in value = expr.evaluate(); return false })
61 | expect(value).to(equal(1))
62 | }
63 |
64 | func testToNotProvidesAMemoizedActualValueExpression() {
65 | var callCount = 0
66 | expect{ callCount++ }.toNot(MatcherFunc { expr, failure in
67 | expr.evaluate()
68 | expr.evaluate()
69 | return false
70 | })
71 | expect(callCount).to(equal(1))
72 | }
73 |
74 | func testToNotProvidesAMemoizedActualValueExpressionIsEvaluatedAtMatcherControl() {
75 | var callCount = 0
76 | expect{ callCount++ }.toNot(MatcherFunc { expr, failure in
77 | expect(callCount).to(equal(0))
78 | expr.evaluate()
79 | return false
80 | })
81 | expect(callCount).to(equal(1))
82 | }
83 |
84 | func testToNotNegativeMatches() {
85 | failsWithErrorMessage("expected to not match, got <1>") {
86 | expect(1).toNot(MatcherFunc { expr, failure in true })
87 | }
88 | }
89 |
90 |
91 | func testNotToMatchesLikeToNot() {
92 | expect(1).notTo(MatcherFunc { expr, failure in false })
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - [Welcome to Nimble!](#welcome-to-nimble!)
5 | - [Reporting Bugs](#reporting-bugs)
6 | - [Building the Project](#building-the-project)
7 | - [Pull Requests](#pull-requests)
8 | - [Style Conventions](#style-conventions)
9 | - [Core Members](#core-members)
10 | - [Code of Conduct](#code-of-conduct)
11 |
12 |
13 |
14 | # Welcome to Nimble!
15 |
16 | We're building a BDD framework for a new generation of Swift and
17 | Objective-C developers.
18 |
19 | Nimble should be easy to use and easy to maintain. Let's keep things
20 | simple and well-tested.
21 |
22 | **tl;dr:** If you've added a file to the project, make sure it's
23 | included in both the OS X and iOS targets.
24 |
25 | ## Reporting Bugs
26 |
27 | Nothing is off-limits. If you're having a problem, we want to hear about
28 | it.
29 |
30 | - See a crash? File an issue.
31 | - Code isn't compiling, but you don't know why? Sounds like you should
32 | submit a new issue, bud.
33 | - Went to the kitchen, only to forget why you went in the first place?
34 | Better submit an issue.
35 |
36 | ## Building the Project
37 |
38 | - Use `Nimble.xcproj` to work on Nimble.
39 |
40 | ## Pull Requests
41 |
42 | - Nothing is trivial. Submit pull requests for anything: typos,
43 | whitespace, you name it.
44 | - Not all pull requests will be merged, but all will be acknowledged. If
45 | no one has provided feedback on your request, ping one of the owners
46 | by name.
47 | - Make sure your pull request includes any necessary updates to the
48 | README or other documentation.
49 | - Be sure the unit tests for both the OS X and iOS targets of Nimble
50 | before submitting your pull request. You can run all the OS X unit tests
51 | using `./test.sh full`. Use `./test.sh` without `full` to run against only
52 | the latest of OS X and iOS.
53 | - If you've added a file to the project, make sure it's included in both
54 | the OS X and iOS targets.
55 |
56 | ### Style Conventions
57 |
58 | - Indent using 4 spaces.
59 | - Keep lines 100 characters or shorter. Break long statements into
60 | shorter ones over multiple lines.
61 | - In Objective-C, use `#pragma mark -` to mark public, internal,
62 | protocol, and superclass methods.
63 |
64 | ## Core Members
65 |
66 | If a few of your pull requests have been merged, and you'd like a
67 | controlling stake in the project, file an issue asking for write access
68 | to the repository.
69 |
70 | ### Code of Conduct
71 |
72 | Your conduct as a core member is your own responsibility, but here are
73 | some "ground rules":
74 |
75 | - Feel free to push whatever you want to master, and (if you have
76 | ownership permissions) to create any repositories you'd like.
77 |
78 | Ideally, however, all changes should be submitted as GitHub pull
79 | requests. No one should merge their own pull request, unless no
80 | other core members respond for at least a few days.
81 |
82 | If you'd like to create a new repository, it'd be nice if you created
83 | a GitHub issue and gathered some feedback first.
84 |
85 | - It'd be awesome if you could review, provide feedback on, and close
86 | issues or pull requests submitted to the project. Please provide kind,
87 | constructive feedback. Please don't be sarcastic or snarky.
88 |
89 |
--------------------------------------------------------------------------------
/Nimble/Wrappers/ObjCMatcher.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | struct ObjCMatcherWrapper : Matcher {
4 | let matcher: NMBMatcher
5 | let to: String
6 | let toNot: String
7 |
8 | func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool {
9 | failureMessage.to = to
10 | let pass = matcher.matches(({ actualExpression.evaluate() }), failureMessage: failureMessage, location: actualExpression.location)
11 | return pass
12 | }
13 |
14 | func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool {
15 | failureMessage.to = toNot
16 | let pass = matcher.matches(({ actualExpression.evaluate() }), failureMessage: failureMessage, location: actualExpression.location)
17 | return !pass
18 | }
19 | }
20 |
21 | // Equivalent to Expectation, but simplified for ObjC objects only
22 | public class NMBExpectation : NSObject {
23 | let _actualBlock: () -> NSObject!
24 | var _negative: Bool
25 | let _file: String
26 | let _line: UInt
27 | var _timeout: NSTimeInterval = 1.0
28 |
29 | public init(actualBlock: () -> NSObject!, negative: Bool, file: String, line: UInt) {
30 | self._actualBlock = actualBlock
31 | self._negative = negative
32 | self._file = file
33 | self._line = line
34 | }
35 |
36 | public var withTimeout: (NSTimeInterval) -> NMBExpectation {
37 | return ({ timeout in self._timeout = timeout
38 | return self
39 | })
40 | }
41 |
42 | public var to: (matcher: NMBMatcher) -> Void {
43 | return ({ matcher in
44 | expect(file: self._file, line: self._line){ self._actualBlock() as NSObject? }.to(
45 | ObjCMatcherWrapper(matcher: matcher, to: "to", toNot: "to not")
46 | )
47 | })
48 | }
49 |
50 | public var toNot: (matcher: NMBMatcher) -> Void {
51 | return ({ matcher in
52 | expect(file: self._file, line: self._line){ self._actualBlock() as NSObject? }.toNot(
53 | ObjCMatcherWrapper(matcher: matcher, to: "to", toNot: "to not")
54 | )
55 | })
56 | }
57 |
58 | public var notTo: (matcher: NMBMatcher) -> Void { return toNot }
59 |
60 | public var toEventually: (matcher: NMBMatcher) -> Void {
61 | return ({ matcher in
62 | expect(file: self._file, line: self._line){ self._actualBlock() as NSObject? }.toEventually(
63 | ObjCMatcherWrapper(matcher: matcher, to: "to", toNot: "to not"),
64 | timeout: self._timeout
65 | )
66 | })
67 | }
68 |
69 | public var toEventuallyNot: (matcher: NMBMatcher) -> Void {
70 | return ({ matcher in
71 | expect(file: self._file, line: self._line){ self._actualBlock() as NSObject? }.toEventuallyNot(
72 | ObjCMatcherWrapper(matcher: matcher, to: "to", toNot: "to not"),
73 | timeout: self._timeout
74 | )
75 | })
76 | }
77 | }
78 |
79 | @objc public class NMBObjCMatcher : NMBMatcher {
80 | let _matcher: (actualExpression: () -> NSObject?, failureMessage: FailureMessage, location: SourceLocation) -> Bool
81 | init(matcher: (actualExpression: () -> NSObject?, failureMessage: FailureMessage, location: SourceLocation) -> Bool) {
82 | self._matcher = matcher
83 | }
84 |
85 | public func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool {
86 | return _matcher(
87 | actualExpression: ({ actualBlock() as NSObject? }),
88 | failureMessage: failureMessage,
89 | location: location)
90 | }
91 | }
92 |
93 |
--------------------------------------------------------------------------------
/Nimble/objc/DSL.h:
--------------------------------------------------------------------------------
1 | #import
2 |
3 | @class NMBExpectation;
4 | @class NMBObjCBeCloseToMatcher;
5 | @class NMBObjCRaiseExceptionMatcher;
6 | @protocol NMBMatcher;
7 |
8 |
9 | #define NIMBLE_EXPORT FOUNDATION_EXPORT
10 |
11 | #ifdef NIMBLE_DISABLE_SHORT_SYNTAX
12 | #define NIMBLE_SHORT(PROTO, ORIGINAL)
13 | #else
14 | #define NIMBLE_SHORT(PROTO, ORIGINAL) FOUNDATION_STATIC_INLINE PROTO { return (ORIGINAL); }
15 | #endif
16 |
17 | NIMBLE_EXPORT NMBExpectation *NMB_expect(id(^actualBlock)(), const char *file, unsigned int line);
18 |
19 | NIMBLE_EXPORT id NMB_equal(id expectedValue);
20 | NIMBLE_SHORT(id equal(id expectedValue),
21 | NMB_equal(expectedValue));
22 |
23 | NIMBLE_EXPORT NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue);
24 | NIMBLE_SHORT(NMBObjCBeCloseToMatcher *beCloseTo(id expectedValue),
25 | NMB_beCloseTo(expectedValue));
26 |
27 | NIMBLE_EXPORT id NMB_beAnInstanceOf(Class expectedClass);
28 | NIMBLE_SHORT(id beAnInstanceOf(Class expectedClass),
29 | NMB_beAnInstanceOf(expectedClass));
30 |
31 | NIMBLE_EXPORT id NMB_beAKindOf(Class expectedClass);
32 | NIMBLE_SHORT(id beAKindOf(Class expectedClass),
33 | NMB_beAKindOf(expectedClass));
34 |
35 | NIMBLE_EXPORT id NMB_beginWith(id itemElementOrSubstring);
36 | NIMBLE_SHORT(id beginWith(id itemElementOrSubstring),
37 | NMB_beginWith(itemElementOrSubstring));
38 |
39 | NIMBLE_EXPORT id NMB_beGreaterThan(NSNumber *expectedValue);
40 | NIMBLE_SHORT(id beGreaterThan(NSNumber *expectedValue),
41 | NMB_beGreaterThan(expectedValue));
42 |
43 | NIMBLE_EXPORT id NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue);
44 | NIMBLE_SHORT(id beGreaterThanOrEqualTo(NSNumber *expectedValue),
45 | NMB_beGreaterThanOrEqualTo(expectedValue));
46 |
47 | NIMBLE_EXPORT id NMB_beIdenticalTo(id expectedInstance);
48 | NIMBLE_SHORT(id beIdenticalTo(id expectedInstance),
49 | NMB_beIdenticalTo(expectedInstance));
50 |
51 | NIMBLE_EXPORT id NMB_beLessThan(NSNumber *expectedValue);
52 | NIMBLE_SHORT(id beLessThan(NSNumber *expectedValue),
53 | NMB_beLessThan(expectedValue));
54 |
55 | NIMBLE_EXPORT id NMB_beLessThanOrEqualTo(NSNumber *expectedValue);
56 | NIMBLE_SHORT(id beLessThanOrEqualTo(NSNumber *expectedValue),
57 | NMB_beLessThanOrEqualTo(expectedValue));
58 |
59 | NIMBLE_EXPORT id NMB_beTruthy();
60 | NIMBLE_SHORT(id beTruthy(),
61 | NMB_beTruthy());
62 |
63 | NIMBLE_EXPORT id NMB_beFalsy();
64 | NIMBLE_SHORT(id beFalsy(),
65 | NMB_beFalsy());
66 |
67 | NIMBLE_EXPORT id NMB_beTrue();
68 | NIMBLE_SHORT(id beTrue(),
69 | NMB_beTrue());
70 |
71 | NIMBLE_EXPORT id NMB_beFalse();
72 | NIMBLE_SHORT(id beFalse(),
73 | NMB_beFalse());
74 |
75 | NIMBLE_EXPORT id NMB_beNil();
76 | NIMBLE_SHORT(id beNil(),
77 | NMB_beNil());
78 |
79 | NIMBLE_EXPORT id NMB_contain(id itemOrSubstring);
80 | NIMBLE_SHORT(id contain(id itemOrSubstring),
81 | NMB_contain(itemOrSubstring));
82 |
83 | NIMBLE_EXPORT id NMB_endWith(id itemElementOrSubstring);
84 | NIMBLE_SHORT(id endWith(id itemElementOrSubstring),
85 | NMB_endWith(itemElementOrSubstring));
86 |
87 | NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException();
88 | NIMBLE_SHORT(NMBObjCRaiseExceptionMatcher *raiseException(),
89 | NMB_raiseException());
90 |
91 | NIMBLE_EXPORT id NMB_match(id expectedValue);
92 | NIMBLE_SHORT(id match(id expectedValue),
93 | NMB_match(expectedValue));
94 |
95 |
96 | #ifndef NIMBLE_DISABLE_SHORT_SYNTAX
97 | #define expect(EXPR) NMB_expect(^id{ return (EXPR); }, __FILE__, __LINE__)
98 | #define expectAction(EXPR) NMB_expect(^id{ (EXPR); return nil; }, __FILE__, __LINE__)
99 | #endif
100 |
--------------------------------------------------------------------------------
/NimbleTests/objc/CompatibilityTest.m:
--------------------------------------------------------------------------------
1 | #import
2 | #import
3 |
4 |
5 | @interface CompatibilityTest : XCTestCase
6 |
7 | @end
8 |
9 | @implementation CompatibilityTest
10 |
11 | - (void)testBeAnInstanceOf {
12 | NSNull *obj = [NSNull null];
13 | expect(obj).to(beAnInstanceOf([NSNull class]));
14 | expect(@1).toNot(beAnInstanceOf([NSNull class]));
15 | expect(nil).toNot(beAnInstanceOf([NSNull class]));
16 | }
17 | - (void)testBeAKindOf {
18 | NSMutableArray *array = [NSMutableArray array];
19 | expect(array).to(beAKindOf([NSArray class]));
20 | expect(@1).toNot(beAKindOf([NSNull class]));
21 | expect(nil).toNot(beAKindOf([NSNull class]));
22 | }
23 |
24 | - (void)testBeCloseTo {
25 | expect(@1.2).to(beCloseTo(@1.2001));
26 | expect(@1.2).to(beCloseTo(@2).within(10));
27 | expect(nil).toNot(beCloseTo(@0));
28 | }
29 |
30 | - (void)testBeginWith {
31 | expect(@"hello world!").to(beginWith(@"hello"));
32 | expect(@"hello world!").toNot(beginWith(@"world"));
33 |
34 | NSArray *array = @[@1, @2];
35 | expect(array).to(beginWith(@1));
36 | expect(array).toNot(beginWith(@2));
37 | expect(nil).toNot(beginWith(@1));
38 | }
39 |
40 | - (void)testBeGreaterThan {
41 | expect(@2).to(beGreaterThan(@1));
42 | expect(@2).toNot(beGreaterThan(@2));
43 | expect(nil).toNot(beGreaterThan(@(-1)));
44 | }
45 |
46 | - (void)testBeGreaterThanOrEqualTo {
47 | expect(@2).to(beGreaterThanOrEqualTo(@2));
48 | expect(@2).toNot(beGreaterThanOrEqualTo(@3));
49 | expect(nil).toNot(beGreaterThanOrEqualTo(@(-1)));
50 | }
51 |
52 | - (void)testBeIdenticalTo {
53 | NSNull *obj = [NSNull null];
54 | expect(obj).to(beIdenticalTo([NSNull null]));
55 | expect(@2).toNot(beIdenticalTo(@3));
56 | expect(nil).toNot(beIdenticalTo(nil));
57 | expect(nil).toNot(beIdenticalTo(@1));
58 | }
59 |
60 | - (void)testBeLessThan {
61 | expect(@2).to(beLessThan(@3));
62 | expect(@2).toNot(beLessThan(@2));
63 | expect(nil).toNot(beLessThan(@1));
64 | }
65 |
66 | - (void)testBeLessThanOrEqualTo {
67 | expect(@2).to(beLessThanOrEqualTo(@2));
68 | expect(@2).toNot(beLessThanOrEqualTo(@1));
69 | expect(nil).toNot(beLessThan(@2));
70 | }
71 |
72 | - (void)testBeTruthy {
73 | expect(@YES).to(beTruthy());
74 | expect(@NO).toNot(beTruthy());
75 | expect(nil).toNot(beTruthy());
76 | }
77 |
78 | - (void)testBeFalsy {
79 | expect(@NO).to(beFalsy());
80 | expect(@YES).toNot(beFalsy());
81 | expect(nil).to(beFalsy());
82 | }
83 |
84 | - (void)testBeTrue {
85 | expect(@YES).to(beTrue());
86 | expect(@NO).toNot(beTrue());
87 | expect(nil).toNot(beTrue());
88 | }
89 |
90 | - (void)testBeFalse {
91 | expect(@NO).to(beFalse());
92 | expect(@YES).toNot(beFalse());
93 | expect(nil).toNot(beFalse());
94 | }
95 |
96 | - (void)testBeNil {
97 | expect(nil).to(beNil());
98 | expect(@NO).toNot(beNil());
99 | }
100 |
101 | - (void)testContain {
102 | NSArray *array = @[@1, @2];
103 | expect(array).to(contain(@1));
104 | expect(array).toNot(contain(@"HI"));
105 | expect(nil).toNot(contain(@"hi"));
106 | }
107 |
108 | - (void)testEndWith {
109 | NSArray *array = @[@1, @2];
110 | expect(@"hello world!").to(endWith(@"world!"));
111 | expect(@"hello world!").toNot(endWith(@"hello"));
112 | expect(array).to(endWith(@2));
113 | expect(array).toNot(endWith(@1));
114 | expect(nil).toNot(endWith(@1));
115 | }
116 |
117 | - (void)testEqual {
118 | expect(@1).to(equal(@1));
119 | expect(@1).toNot(equal(@2));
120 | expect(@1).notTo(equal(@2));
121 | expect(@"hello").to(equal(@"hello"));
122 | expect(nil).toNot(equal(nil));
123 | }
124 |
125 | - (void)testMatch {
126 | expect(@"11:14").to(match(@"\\d{2}:\\d{2}"));
127 | expect(@"hello").toNot(match(@"\\d{2}:\\d{2}"));
128 | }
129 |
130 | - (void)testRaiseException {
131 | __block NSException *exception = [NSException exceptionWithName:NSInvalidArgumentException reason:@"No food" userInfo:nil];
132 | expectAction([exception raise]).to(raiseException());
133 | expectAction(exception).toNot(raiseException());
134 | }
135 |
136 | @end
137 |
--------------------------------------------------------------------------------
/Nimble/Matchers/Equal.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 |
4 | public func equal(expectedValue: T?) -> MatcherFunc {
5 | return MatcherFunc { actualExpression, failureMessage in
6 | failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>"
7 | let matches = actualExpression.evaluate() == expectedValue && expectedValue != nil
8 | if expectedValue == nil || actualExpression.evaluate() == nil {
9 | failureMessage.postfixMessage += " (will not match nils, use beNil() instead)"
10 | return false
11 | }
12 | return matches
13 | }
14 | }
15 |
16 | // perhaps try to extend to SequenceOf or Sequence types instead of dictionaries
17 | public func equal(expectedValue: [T: C]?) -> MatcherFunc<[T: C]> {
18 | return MatcherFunc { actualExpression, failureMessage in
19 | failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>"
20 | if expectedValue == nil || actualExpression.evaluate() == nil {
21 | failureMessage.postfixMessage += " (will not match nils, use beNil() instead)"
22 | return false
23 | }
24 | var expectedGen = expectedValue!.generate()
25 | var actualGen = actualExpression.evaluate()!.generate()
26 |
27 | var expectedItem = expectedGen.next()
28 | var actualItem = actualGen.next()
29 | var matches = elementsAreEqual(expectedItem, actualItem)
30 | while (matches && (actualItem != nil || expectedItem != nil)) {
31 | actualItem = actualGen.next()
32 | expectedItem = expectedGen.next()
33 | matches = elementsAreEqual(expectedItem, actualItem)
34 | }
35 | return matches
36 | }
37 | }
38 |
39 | // perhaps try to extend to SequenceOf or Sequence types instead of arrays
40 | public func equal(expectedValue: [T]?) -> MatcherFunc<[T]> {
41 | return MatcherFunc { actualExpression, failureMessage in
42 | failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>"
43 | if expectedValue == nil || actualExpression.evaluate() == nil {
44 | failureMessage.postfixMessage += " (will not match nils, use beNil() instead)"
45 | return false
46 | }
47 | var expectedGen = expectedValue!.generate()
48 | var actualGen = actualExpression.evaluate()!.generate()
49 | var expectedItem = expectedGen.next()
50 | var actualItem = actualGen.next()
51 | var matches = actualItem == expectedItem
52 | while (matches && (actualItem != nil || expectedItem != nil)) {
53 | actualItem = actualGen.next()
54 | expectedItem = expectedGen.next()
55 | matches = actualItem == expectedItem
56 | }
57 | return matches
58 | }
59 | }
60 |
61 | public func ==(lhs: Expectation, rhs: T?) {
62 | lhs.to(equal(rhs))
63 | }
64 |
65 | public func !=(lhs: Expectation, rhs: T?) {
66 | lhs.toNot(equal(rhs))
67 | }
68 |
69 | public func ==(lhs: Expectation<[T]>, rhs: [T]?) {
70 | lhs.to(equal(rhs))
71 | }
72 |
73 | public func !=(lhs: Expectation<[T]>, rhs: [T]?) {
74 | lhs.toNot(equal(rhs))
75 | }
76 |
77 | public func ==(lhs: Expectation<[T: C]>, rhs: [T: C]?) {
78 | lhs.to(equal(rhs))
79 | }
80 |
81 | public func !=(lhs: Expectation<[T: C]>, rhs: [T: C]?) {
82 | lhs.toNot(equal(rhs))
83 | }
84 |
85 | extension NMBObjCMatcher {
86 | public class func equalMatcher(expected: NSObject) -> NMBMatcher {
87 | return NMBObjCMatcher { actualExpression, failureMessage, location in
88 | let expr = Expression(expression: actualExpression, location: location)
89 | return equal(expected).matches(expr, failureMessage: failureMessage)
90 | }
91 | }
92 | }
93 |
94 |
95 | internal func elementsAreEqual(a: (T, C)?, b: (T, C)?) -> Bool {
96 | if a == nil || b == nil {
97 | return a == nil && b == nil
98 | } else {
99 | let (aKey, aValue) = a!
100 | let (bKey, bValue) = b!
101 | return (aKey == bKey && aValue == bValue)
102 | }
103 | }
104 |
105 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/BeLogicalTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | enum ConvertsToBool : BooleanType, Printable {
5 | case TrueLike, FalseLike
6 |
7 | var boolValue : Bool {
8 | switch self {
9 | case .TrueLike: return true
10 | case .FalseLike: return false
11 | }
12 | }
13 |
14 | var description : String {
15 | switch self {
16 | case .TrueLike: return "TrueLike"
17 | case .FalseLike: return "FalseLike"
18 | }
19 | }
20 | }
21 |
22 | class BeTruthyTest : XCTestCase {
23 | func testShouldMatchTrue() {
24 | expect(true).to(beTruthy())
25 |
26 | failsWithErrorMessage("expected to not be truthy, got ") {
27 | expect(true).toNot(beTruthy())
28 | }
29 | }
30 |
31 | func testShouldNotMatchFalse() {
32 | expect(false).toNot(beTruthy())
33 |
34 | failsWithErrorMessage("expected to be truthy, got ") {
35 | expect(false).to(beTruthy())
36 | }
37 | }
38 |
39 | func testShouldNotMatchNilBools() {
40 | expect(nil as Bool?).toNot(beTruthy())
41 |
42 | failsWithErrorMessage("expected to be truthy, got ") {
43 | expect(nil as Bool?).to(beTruthy())
44 | }
45 | }
46 |
47 | func testShouldMatchBoolConvertibleTypesThatConvertToTrue() {
48 | expect(ConvertsToBool.TrueLike).to(beTruthy())
49 |
50 | failsWithErrorMessage("expected to not be truthy, got ") {
51 | expect(ConvertsToBool.TrueLike).toNot(beTruthy())
52 | }
53 | }
54 |
55 | func testShouldNotMatchBoolConvertibleTypesThatConvertToFalse() {
56 | expect(ConvertsToBool.FalseLike).toNot(beTruthy())
57 |
58 | failsWithErrorMessage("expected to be truthy, got ") {
59 | expect(ConvertsToBool.FalseLike).to(beTruthy())
60 | }
61 | }
62 | }
63 |
64 | class BeTrueTest : XCTestCase {
65 | func testShouldMatchTrue() {
66 | expect(true).to(beTrue())
67 |
68 | failsWithErrorMessage("expected to not be true, got ") {
69 | expect(true).toNot(beTrue())
70 | }
71 | }
72 |
73 | func testShouldNotMatchFalse() {
74 | expect(false).toNot(beTrue())
75 |
76 | failsWithErrorMessage("expected to be true, got ") {
77 | expect(false).to(beTrue())
78 | }
79 | }
80 |
81 | func testShouldNotMatchNilBools() {
82 | expect(nil as Bool?).toNot(beTrue())
83 |
84 | failsWithErrorMessage("expected to be true, got ") {
85 | expect(nil as Bool?).to(beTrue())
86 | }
87 | }
88 | }
89 |
90 | class BeFalsyTest : XCTestCase {
91 | func testShouldNotMatchTrue() {
92 | expect(true).toNot(beFalsy())
93 |
94 | failsWithErrorMessage("expected to be falsy, got ") {
95 | expect(true).to(beFalsy())
96 | }
97 | }
98 |
99 | func testShouldMatchFalse() {
100 | expect(false).to(beFalsy())
101 |
102 | failsWithErrorMessage("expected to not be falsy, got ") {
103 | expect(false).toNot(beFalsy())
104 | }
105 | }
106 |
107 | func testShouldMatchNilBools() {
108 | expect(nil as Bool?).to(beFalsy())
109 |
110 | failsWithErrorMessage("expected to not be falsy, got ") {
111 | expect(nil as Bool?).toNot(beFalsy())
112 | }
113 | }
114 | }
115 |
116 | class BeFalseTest : XCTestCase {
117 | func testShouldNotMatchTrue() {
118 | expect(true).toNot(beFalse())
119 |
120 | failsWithErrorMessage("expected to be false, got ") {
121 | expect(true).to(beFalse())
122 | }
123 | }
124 |
125 | func testShouldMatchFalse() {
126 | expect(false).to(beFalse())
127 |
128 | failsWithErrorMessage("expected to not be false, got ") {
129 | expect(false).toNot(beFalse())
130 | }
131 | }
132 |
133 | func testShouldNotMatchNilBools() {
134 | failsWithErrorMessage("expected to be false, got ") {
135 | expect(nil as Bool?).to(beFalse())
136 | }
137 |
138 | failsWithErrorMessage("expected to not be false, got ") {
139 | expect(nil as Bool?).toNot(beFalse())
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/NimbleTests/Matchers/EqualTest.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 | import Nimble
3 |
4 | class EqualTest: XCTestCase {
5 | func testEquality() {
6 | expect(1 as CInt).to(equal(1 as CInt))
7 | expect(1 as CInt).to(equal(1))
8 | expect(1).to(equal(1))
9 | expect("hello").to(equal("hello"))
10 | expect("hello").toNot(equal("world"))
11 |
12 | expect {
13 | 1
14 | }.to(equal(1))
15 |
16 | failsWithErrorMessage("expected to equal , got ") {
17 | expect("hello").to(equal("world"))
18 | }
19 | failsWithErrorMessage("expected to not equal , got ") {
20 | expect("hello").toNot(equal("hello"))
21 | }
22 | }
23 |
24 | func testArrayEquality() {
25 | expect([1, 2, 3]).to(equal([1, 2, 3]))
26 | expect([1, 2, 3]).toNot(equal([1, 2]))
27 | expect([1, 2, 3]).toNot(equal([1, 2, 4]))
28 |
29 | let array1: Array = [1, 2, 3]
30 | let array2: Array = [1, 2, 3]
31 | expect(array1).to(equal(array2))
32 | expect(array1).to(equal([1, 2, 3]))
33 | expect(array1).toNot(equal([1, 2] as Array))
34 |
35 | expect(NSArray(array: [1, 2, 3])).to(equal(NSArray(array: [1, 2, 3])))
36 |
37 | failsWithErrorMessage("expected to equal <[1, 2]>, got <[1, 2, 3]>") {
38 | expect([1, 2, 3]).to(equal([1, 2]))
39 | }
40 | }
41 |
42 | func testDoesNotMatchNils() {
43 | failsWithErrorMessage("expected to equal (will not match nils, use beNil() instead), got ") {
44 | expect(nil as String?).to(equal(nil as String?))
45 | }
46 | failsWithErrorMessage("expected to not equal (will not match nils, use beNil() instead), got ") {
47 | expect("foo").toNot(equal(nil as String?))
48 | }
49 | failsWithErrorMessage("expected to not equal (will not match nils, use beNil() instead), got ") {
50 | expect(nil as String?).toNot(equal("bar"))
51 | }
52 |
53 | failsWithErrorMessage("expected to equal (will not match nils, use beNil() instead), got ") {
54 | expect(nil as [Int]?).to(equal(nil as [Int]?))
55 | }
56 | failsWithErrorMessage("expected to not equal <[1]> (will not match nils, use beNil() instead), got ") {
57 | expect(nil as [Int]?).toNot(equal([1]))
58 | }
59 | failsWithErrorMessage("expected to not equal (will not match nils, use beNil() instead), got <[1]>") {
60 | expect([1]).toNot(equal(nil as [Int]?))
61 | }
62 |
63 | failsWithErrorMessage("expected to equal (will not match nils, use beNil() instead), got ") {
64 | expect(nil as [Int: Int]?).to(equal(nil as [Int: Int]?))
65 | }
66 | failsWithErrorMessage("expected to not equal <[1: 1]> (will not match nils, use beNil() instead), got