├── .travis.yml ├── LICENSE.md ├── Package.swift ├── Podfile ├── Podfile.lock ├── Pods ├── Headers │ └── Private │ │ ├── Nimble │ │ ├── DSL.h │ │ ├── NMBExceptionCapture.h │ │ └── Nimble.h │ │ └── Quick │ │ ├── NSString+QCKSelectorName.h │ │ ├── QCKDSL.h │ │ ├── Quick.h │ │ ├── QuickConfiguration.h │ │ ├── QuickSpec.h │ │ ├── World+DSL.h │ │ └── World.h ├── Manifest.lock ├── Nimble │ ├── LICENSE.md │ ├── Nimble │ │ ├── Adapters │ │ │ ├── AdapterProtocols.swift │ │ │ ├── AssertionDispatcher.swift │ │ │ ├── AssertionRecorder.swift │ │ │ └── NimbleXCTestHandler.swift │ │ ├── DSL+Wait.swift │ │ ├── DSL.swift │ │ ├── Expectation.swift │ │ ├── Expression.swift │ │ ├── FailureMessage.swift │ │ ├── Matchers │ │ │ ├── AllPass.swift │ │ │ ├── BeAKindOf.swift │ │ │ ├── BeAnInstanceOf.swift │ │ │ ├── BeCloseTo.swift │ │ │ ├── BeEmpty.swift │ │ │ ├── BeGreaterThan.swift │ │ │ ├── BeGreaterThanOrEqualTo.swift │ │ │ ├── BeIdenticalTo.swift │ │ │ ├── BeLessThan.swift │ │ │ ├── BeLessThanOrEqual.swift │ │ │ ├── BeLogical.swift │ │ │ ├── BeNil.swift │ │ │ ├── BeginWith.swift │ │ │ ├── Contain.swift │ │ │ ├── EndWith.swift │ │ │ ├── Equal.swift │ │ │ ├── HaveCount.swift │ │ │ ├── Match.swift │ │ │ ├── MatcherProtocols.swift │ │ │ ├── RaisesException.swift │ │ │ └── ThrowError.swift │ │ ├── Nimble.h │ │ ├── ObjCExpectation.swift │ │ ├── Utils │ │ │ ├── Functional.swift │ │ │ ├── Poll.swift │ │ │ ├── SourceLocation.swift │ │ │ └── Stringers.swift │ │ ├── Wrappers │ │ │ ├── AsyncMatcherWrapper.swift │ │ │ ├── MatcherFunc.swift │ │ │ └── ObjCMatcher.swift │ │ └── objc │ │ │ ├── DSL.h │ │ │ ├── DSL.m │ │ │ ├── NMBExceptionCapture.h │ │ │ └── NMBExceptionCapture.m │ └── README.md ├── Pods.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── Matthew.xcuserdatad │ │ └── xcschemes │ │ ├── Nimble.xcscheme │ │ ├── Pods-PrompterTests.xcscheme │ │ ├── Quick.xcscheme │ │ └── xcschememanagement.plist ├── Quick │ ├── LICENSE │ ├── Quick │ │ ├── Callsite.swift │ │ ├── Configuration │ │ │ ├── Configuration.swift │ │ │ ├── QuickConfiguration.h │ │ │ └── QuickConfiguration.m │ │ ├── DSL │ │ │ ├── DSL.swift │ │ │ ├── QCKDSL.h │ │ │ ├── QCKDSL.m │ │ │ ├── World+DSL.h │ │ │ └── World+DSL.swift │ │ ├── Example.swift │ │ ├── ExampleGroup.swift │ │ ├── ExampleMetadata.swift │ │ ├── Filter.swift │ │ ├── Hooks │ │ │ ├── Closures.swift │ │ │ ├── ExampleHooks.swift │ │ │ └── SuiteHooks.swift │ │ ├── NSString+QCKSelectorName.h │ │ ├── NSString+QCKSelectorName.m │ │ ├── Quick.h │ │ ├── QuickSpec.h │ │ ├── QuickSpec.m │ │ ├── World.h │ │ └── World.swift │ └── README.md └── Target Support Files │ ├── Nimble │ ├── Info.plist │ ├── Nimble-dummy.m │ ├── Nimble-prefix.pch │ ├── Nimble-umbrella.h │ ├── Nimble.modulemap │ └── Nimble.xcconfig │ ├── Pods-PrompterTests │ ├── Info.plist │ ├── Pods-PrompterTests-acknowledgements.markdown │ ├── Pods-PrompterTests-acknowledgements.plist │ ├── Pods-PrompterTests-dummy.m │ ├── Pods-PrompterTests-frameworks.sh │ ├── Pods-PrompterTests-resources.sh │ ├── Pods-PrompterTests-umbrella.h │ ├── Pods-PrompterTests.debug.xcconfig │ ├── Pods-PrompterTests.modulemap │ └── Pods-PrompterTests.release.xcconfig │ └── Quick │ ├── Info.plist │ ├── Quick-dummy.m │ ├── Quick-prefix.pch │ ├── Quick-umbrella.h │ ├── Quick.modulemap │ └── Quick.xcconfig ├── Prompter.podspec ├── Prompter.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── Matthew.xcuserdatad │ └── xcschemes │ ├── Prompter.xcscheme │ └── xcschememanagement.plist ├── Prompter.xcworkspace └── contents.xcworkspacedata ├── README.md ├── Resources └── scripts │ └── docs.sh ├── Source ├── Extensions.swift ├── Info.plist ├── Prompter.h └── Prompter.swift └── Tests ├── Info.plist └── Tests.swift /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | podfile: Podfile 3 | osx_image: xcode7.2 4 | rvm: 2.2.3 5 | xcode_project: Prompter.xcworkspace 6 | xcode_scheme: Sources 7 | before_install: 8 | - gem install cocoapods -v '0.39' 9 | - pod install 10 | only: 11 | - master 12 | script: 13 | - pod lib lint 14 | after_success: 15 | - chmod +x ./Resources/scripts/docs.sh 16 | - ./Resources/scripts/docs.sh 17 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) Matthew Clarkson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | import PackageDescription 2 | 3 | let package = Package( 4 | name: "Prompter" 5 | ) 6 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | source 'https://github.com/CocoaPods/Specs.git' 2 | use_frameworks! 3 | 4 | target 'PrompterTests' do 5 | pod 'Quick', '~> 0.8.0' 6 | pod 'Nimble', '3.0.0' 7 | end 8 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Nimble (3.0.0) 3 | - Quick (0.8.0) 4 | 5 | DEPENDENCIES: 6 | - Nimble (= 3.0.0) 7 | - Quick (~> 0.8.0) 8 | 9 | SPEC CHECKSUMS: 10 | Nimble: 4c353d43735b38b545cbb4cb91504588eb5de926 11 | Quick: 563d0f6ec5f72e394645adb377708639b7dd38ab 12 | 13 | COCOAPODS: 0.39.0 14 | -------------------------------------------------------------------------------- /Pods/Headers/Private/Nimble/DSL.h: -------------------------------------------------------------------------------- 1 | ../../../Nimble/Nimble/objc/DSL.h -------------------------------------------------------------------------------- /Pods/Headers/Private/Nimble/NMBExceptionCapture.h: -------------------------------------------------------------------------------- 1 | ../../../Nimble/Nimble/objc/NMBExceptionCapture.h -------------------------------------------------------------------------------- /Pods/Headers/Private/Nimble/Nimble.h: -------------------------------------------------------------------------------- 1 | ../../../Nimble/Nimble/Nimble.h -------------------------------------------------------------------------------- /Pods/Headers/Private/Quick/NSString+QCKSelectorName.h: -------------------------------------------------------------------------------- 1 | ../../../Quick/Quick/NSString+QCKSelectorName.h -------------------------------------------------------------------------------- /Pods/Headers/Private/Quick/QCKDSL.h: -------------------------------------------------------------------------------- 1 | ../../../Quick/Quick/DSL/QCKDSL.h -------------------------------------------------------------------------------- /Pods/Headers/Private/Quick/Quick.h: -------------------------------------------------------------------------------- 1 | ../../../Quick/Quick/Quick.h -------------------------------------------------------------------------------- /Pods/Headers/Private/Quick/QuickConfiguration.h: -------------------------------------------------------------------------------- 1 | ../../../Quick/Quick/Configuration/QuickConfiguration.h -------------------------------------------------------------------------------- /Pods/Headers/Private/Quick/QuickSpec.h: -------------------------------------------------------------------------------- 1 | ../../../Quick/Quick/QuickSpec.h -------------------------------------------------------------------------------- /Pods/Headers/Private/Quick/World+DSL.h: -------------------------------------------------------------------------------- 1 | ../../../Quick/Quick/DSL/World+DSL.h -------------------------------------------------------------------------------- /Pods/Headers/Private/Quick/World.h: -------------------------------------------------------------------------------- 1 | ../../../Quick/Quick/World.h -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - Nimble (3.0.0) 3 | - Quick (0.8.0) 4 | 5 | DEPENDENCIES: 6 | - Nimble (= 3.0.0) 7 | - Quick (~> 0.8.0) 8 | 9 | SPEC CHECKSUMS: 10 | Nimble: 4c353d43735b38b545cbb4cb91504588eb5de926 11 | Quick: 563d0f6ec5f72e394645adb377708639b7dd38ab 12 | 13 | COCOAPODS: 0.39.0 14 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Adapters/AdapterProtocols.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Protocol for the assertion handler that Nimble uses for all expectations. 4 | public protocol AssertionHandler { 5 | func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) 6 | } 7 | 8 | /// Global backing interface for assertions that Nimble creates. 9 | /// Defaults to a private test handler that passes through to XCTest. 10 | /// 11 | /// If XCTest is not available, you must assign your own assertion handler 12 | /// before using any matchers, otherwise Nimble will abort the program. 13 | /// 14 | /// @see AssertionHandler 15 | public var NimbleAssertionHandler: AssertionHandler = { () -> AssertionHandler in 16 | return isXCTestAvailable() ? NimbleXCTestHandler() : NimbleXCTestUnavailableHandler() 17 | }() 18 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Adapters/AssertionDispatcher.swift: -------------------------------------------------------------------------------- 1 | 2 | /// AssertionDispatcher allows multiple AssertionHandlers to receive 3 | /// assertion messages. 4 | /// 5 | /// @warning Does not fully dispatch if one of the handlers raises an exception. 6 | /// This is possible with XCTest-based assertion handlers. 7 | /// 8 | public class AssertionDispatcher: AssertionHandler { 9 | let handlers: [AssertionHandler] 10 | 11 | public init(handlers: [AssertionHandler]) { 12 | self.handlers = handlers 13 | } 14 | 15 | public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { 16 | for handler in handlers { 17 | handler.assert(assertion, message: message, location: location) 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Adapters/AssertionRecorder.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A data structure that stores information about an assertion when 4 | /// AssertionRecorder is set as the Nimble assertion handler. 5 | /// 6 | /// @see AssertionRecorder 7 | /// @see AssertionHandler 8 | public struct AssertionRecord: CustomStringConvertible { 9 | /// Whether the assertion succeeded or failed 10 | public let success: Bool 11 | /// The failure message the assertion would display on failure. 12 | public let message: FailureMessage 13 | /// The source location the expectation occurred on. 14 | public let location: SourceLocation 15 | 16 | public var description: String { 17 | return "AssertionRecord { success=\(success), message='\(message.stringValue)', location=\(location) }" 18 | } 19 | } 20 | 21 | /// An AssertionHandler that silently records assertions that Nimble makes. 22 | /// This is useful for testing failure messages for matchers. 23 | /// 24 | /// @see AssertionHandler 25 | public class AssertionRecorder : AssertionHandler { 26 | /// All the assertions that were captured by this recorder 27 | public var assertions = [AssertionRecord]() 28 | 29 | public init() {} 30 | 31 | public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { 32 | assertions.append( 33 | AssertionRecord( 34 | success: assertion, 35 | message: message, 36 | location: location)) 37 | } 38 | } 39 | 40 | /// Allows you to temporarily replace the current Nimble assertion handler with 41 | /// the one provided for the scope of the closure. 42 | /// 43 | /// Once the closure finishes, then the original Nimble assertion handler is restored. 44 | /// 45 | /// @see AssertionHandler 46 | public func withAssertionHandler(tempAssertionHandler: AssertionHandler, closure: () throws -> Void) { 47 | let oldRecorder = NimbleAssertionHandler 48 | let capturer = NMBExceptionCapture(handler: nil, finally: ({ 49 | NimbleAssertionHandler = oldRecorder 50 | })) 51 | NimbleAssertionHandler = tempAssertionHandler 52 | capturer.tryBlock { 53 | try! closure() 54 | } 55 | } 56 | 57 | /// Captures expectations that occur in the given closure. Note that all 58 | /// expectations will still go through to the default Nimble handler. 59 | /// 60 | /// This can be useful if you want to gather information about expectations 61 | /// that occur within a closure. 62 | /// 63 | /// @param silently expectations are no longer send to the default Nimble 64 | /// assertion handler when this is true. Defaults to false. 65 | /// 66 | /// @see gatherFailingExpectations 67 | public func gatherExpectations(silently silently: Bool = false, closure: () -> Void) -> [AssertionRecord] { 68 | let previousRecorder = NimbleAssertionHandler 69 | let recorder = AssertionRecorder() 70 | let handlers: [AssertionHandler] 71 | 72 | if silently { 73 | handlers = [recorder] 74 | } else { 75 | handlers = [recorder, previousRecorder] 76 | } 77 | 78 | let dispatcher = AssertionDispatcher(handlers: handlers) 79 | withAssertionHandler(dispatcher, closure: closure) 80 | return recorder.assertions 81 | } 82 | 83 | /// Captures failed expectations that occur in the given closure. Note that all 84 | /// expectations will still go through to the default Nimble handler. 85 | /// 86 | /// This can be useful if you want to gather information about failed 87 | /// expectations that occur within a closure. 88 | /// 89 | /// @param silently expectations are no longer send to the default Nimble 90 | /// assertion handler when this is true. Defaults to false. 91 | /// 92 | /// @see gatherExpectations 93 | /// @see raiseException source for an example use case. 94 | public func gatherFailingExpectations(silently silently: Bool = false, closure: () -> Void) -> [AssertionRecord] { 95 | let assertions = gatherExpectations(silently: silently, closure: closure) 96 | return assertions.filter { assertion in 97 | !assertion.success 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Adapters/NimbleXCTestHandler.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | import XCTest 3 | 4 | /// Default handler for Nimble. This assertion handler passes failures along to 5 | /// XCTest. 6 | public class NimbleXCTestHandler : AssertionHandler { 7 | public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { 8 | if !assertion { 9 | XCTFail("\(message.stringValue)\n", file: location.file, line: location.line) 10 | } 11 | } 12 | } 13 | 14 | /// Alternative handler for Nimble. This assertion handler passes failures along 15 | /// to XCTest by attempting to reduce the failure message size. 16 | public class NimbleShortXCTestHandler: AssertionHandler { 17 | public func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { 18 | if !assertion { 19 | let msg: String 20 | if let actual = message.actualValue { 21 | msg = "got: \(actual) \(message.postfixActual)" 22 | } else { 23 | msg = "expected \(message.to) \(message.postfixMessage)" 24 | } 25 | XCTFail("\(msg)\n", file: location.file, line: location.line) 26 | } 27 | } 28 | } 29 | 30 | /// Fallback handler in case XCTest is unavailable. This assertion handler will abort 31 | /// the program if it is invoked. 32 | class NimbleXCTestUnavailableHandler : AssertionHandler { 33 | func assert(assertion: Bool, message: FailureMessage, location: SourceLocation) { 34 | fatalError("XCTest is not available and no custom assertion handler was configured. Aborting.") 35 | } 36 | } 37 | 38 | func isXCTestAvailable() -> Bool { 39 | return NSClassFromString("XCTestCase") != nil 40 | } 41 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/DSL+Wait.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Only classes, protocols, methods, properties, and subscript declarations can be 4 | /// bridges to Objective-C via the @objc keyword. This class encapsulates callback-style 5 | /// asynchronous waiting logic so that it may be called from Objective-C and Swift. 6 | internal class NMBWait: NSObject { 7 | internal class func until(timeout timeout: NSTimeInterval, file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void { 8 | var completed = false 9 | var token: dispatch_once_t = 0 10 | let result = pollBlock(pollInterval: 0.01, timeoutInterval: timeout) { 11 | dispatch_once(&token) { 12 | dispatch_async(dispatch_get_main_queue()) { 13 | action() { completed = true } 14 | } 15 | } 16 | return completed 17 | } 18 | switch (result) { 19 | case .Failure: 20 | let pluralize = (timeout == 1 ? "" : "s") 21 | fail("Waited more than \(timeout) second\(pluralize)", file: file, line: line) 22 | case .Timeout: 23 | fail("Stall on main thread - too much enqueued on main run loop before waitUntil executes.", file: file, line: line) 24 | case let .ErrorThrown(error): 25 | // Technically, we can never reach this via a public API call 26 | fail("Unexpected error thrown: \(error)", file: file, line: line) 27 | case .Success: 28 | break 29 | } 30 | } 31 | 32 | @objc(untilFile:line:action:) 33 | internal class func until(file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void { 34 | until(timeout: 1, file: file, line: line, action: action) 35 | } 36 | } 37 | 38 | /// Wait asynchronously until the done closure is called. 39 | /// 40 | /// This will advance the run loop. 41 | public func waitUntil(timeout timeout: NSTimeInterval = 1, file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void { 42 | NMBWait.until(timeout: timeout, file: file, line: line, action: action) 43 | } -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/DSL.swift: -------------------------------------------------------------------------------- 1 | /// Make an expectation on a given actual value. The value given is lazily evaluated. 2 | public func expect(@autoclosure(escaping) expression: () throws -> T?, file: String = __FILE__, line: UInt = __LINE__) -> Expectation { 3 | return Expectation( 4 | expression: Expression( 5 | expression: expression, 6 | location: SourceLocation(file: file, line: line), 7 | isClosure: true)) 8 | } 9 | 10 | /// Make an expectation on a given actual value. The closure is lazily invoked. 11 | public func expect(file: String = __FILE__, line: UInt = __LINE__, expression: () throws -> T?) -> Expectation { 12 | return Expectation( 13 | expression: Expression( 14 | expression: expression, 15 | location: SourceLocation(file: file, line: line), 16 | isClosure: true)) 17 | } 18 | 19 | /// Always fails the test with a message and a specified location. 20 | public func fail(message: String, location: SourceLocation) { 21 | NimbleAssertionHandler.assert(false, message: FailureMessage(stringValue: message), location: location) 22 | } 23 | 24 | /// Always fails the test with a message. 25 | public func fail(message: String, file: String = __FILE__, line: UInt = __LINE__) { 26 | fail(message, location: SourceLocation(file: file, line: line)) 27 | } 28 | 29 | /// Always fails the test. 30 | public func fail(file: String = __FILE__, line: UInt = __LINE__) { 31 | fail("fail() always fails", file: file, line: line) 32 | } 33 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Expectation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal func expressionMatches(expression: Expression, matcher: U, to: String, description: String?) -> (Bool, FailureMessage) { 4 | let msg = FailureMessage() 5 | msg.userDescription = description 6 | msg.to = to 7 | do { 8 | let pass = try matcher.matches(expression, failureMessage: msg) 9 | if msg.actualValue == "" { 10 | msg.actualValue = "<\(stringify(try expression.evaluate()))>" 11 | } 12 | return (pass, msg) 13 | } catch let error { 14 | msg.actualValue = "an unexpected error thrown: <\(error)>" 15 | return (false, msg) 16 | } 17 | } 18 | 19 | internal func expressionDoesNotMatch(expression: Expression, matcher: U, toNot: String, description: String?) -> (Bool, FailureMessage) { 20 | let msg = FailureMessage() 21 | msg.userDescription = description 22 | msg.to = toNot 23 | do { 24 | let pass = try matcher.doesNotMatch(expression, failureMessage: msg) 25 | if msg.actualValue == "" { 26 | msg.actualValue = "<\(stringify(try expression.evaluate()))>" 27 | } 28 | return (pass, msg) 29 | } catch let error { 30 | msg.actualValue = "an unexpected error thrown: <\(error)>" 31 | return (false, msg) 32 | } 33 | } 34 | 35 | public struct Expectation { 36 | let expression: Expression 37 | 38 | public func verify(pass: Bool, _ message: FailureMessage) { 39 | NimbleAssertionHandler.assert(pass, message: message, location: expression.location) 40 | } 41 | 42 | /// Tests the actual value using a matcher to match. 43 | public func to(matcher: U, description: String? = nil) { 44 | let (pass, msg) = expressionMatches(expression, matcher: matcher, to: "to", description: description) 45 | verify(pass, msg) 46 | } 47 | 48 | /// Tests the actual value using a matcher to not match. 49 | public func toNot(matcher: U, description: String? = nil) { 50 | let (pass, msg) = expressionDoesNotMatch(expression, matcher: matcher, toNot: "to not", description: description) 51 | verify(pass, msg) 52 | } 53 | 54 | /// Tests the actual value using a matcher to not match. 55 | /// 56 | /// Alias to toNot(). 57 | public func notTo(matcher: U, description: String? = nil) { 58 | toNot(matcher, description: description) 59 | } 60 | 61 | // see: 62 | // - AsyncMatcherWrapper for extension 63 | // - NMBExpectation for Objective-C interface 64 | } 65 | -------------------------------------------------------------------------------- /Pods/Nimble/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 | internal func memoizedClosure(closure: () throws -> T) -> (Bool) throws -> T { 6 | var cache: T? 7 | return ({ withoutCaching in 8 | if (withoutCaching || cache == nil) { 9 | cache = try closure() 10 | } 11 | return cache! 12 | }) 13 | } 14 | 15 | /// Expression represents the closure of the value inside expect(...). 16 | /// Expressions are memoized by default. This makes them safe to call 17 | /// evaluate() multiple times without causing a re-evaluation of the underlying 18 | /// closure. 19 | /// 20 | /// @warning Since the closure can be any code, Objective-C code may choose 21 | /// to raise an exception. Currently, Expression does not memoize 22 | /// exception raising. 23 | /// 24 | /// This provides a common consumable API for matchers to utilize to allow 25 | /// Nimble to change internals to how the captured closure is managed. 26 | public struct Expression { 27 | internal let _expression: (Bool) throws -> T? 28 | internal let _withoutCaching: Bool 29 | public let location: SourceLocation 30 | public let isClosure: Bool 31 | 32 | /// Creates a new expression struct. Normally, expect(...) will manage this 33 | /// creation process. The expression is memoized. 34 | /// 35 | /// @param expression The closure that produces a given value. 36 | /// @param location The source location that this closure originates from. 37 | /// @param isClosure A bool indicating if the captured expression is a 38 | /// closure or internally produced closure. Some matchers 39 | /// may require closures. For example, toEventually() 40 | /// requires an explicit closure. This gives Nimble 41 | /// flexibility if @autoclosure behavior changes between 42 | /// Swift versions. Nimble internals always sets this true. 43 | public init(expression: () throws -> T?, location: SourceLocation, isClosure: Bool = true) { 44 | self._expression = memoizedClosure(expression) 45 | self.location = location 46 | self._withoutCaching = false 47 | self.isClosure = isClosure 48 | } 49 | 50 | /// Creates a new expression struct. Normally, expect(...) will manage this 51 | /// creation process. 52 | /// 53 | /// @param expression The closure that produces a given value. 54 | /// @param location The source location that this closure originates from. 55 | /// @param withoutCaching Indicates if the struct should memoize the given 56 | /// closure's result. Subsequent evaluate() calls will 57 | /// not call the given closure if this is true. 58 | /// @param isClosure A bool indicating if the captured expression is a 59 | /// closure or internally produced closure. Some matchers 60 | /// may require closures. For example, toEventually() 61 | /// requires an explicit closure. This gives Nimble 62 | /// flexibility if @autoclosure behavior changes between 63 | /// Swift versions. Nimble internals always sets this true. 64 | public init(memoizedExpression: (Bool) throws -> T?, location: SourceLocation, withoutCaching: Bool, isClosure: Bool = true) { 65 | self._expression = memoizedExpression 66 | self.location = location 67 | self._withoutCaching = withoutCaching 68 | self.isClosure = isClosure 69 | } 70 | 71 | /// Returns a new Expression from the given expression. Identical to a map() 72 | /// on this type. This should be used only to typecast the Expression's 73 | /// closure value. 74 | /// 75 | /// The returned expression will preserve location and isClosure. 76 | /// 77 | /// @param block The block that can cast the current Expression value to a 78 | /// new type. 79 | public func cast(block: (T?) throws -> U?) -> Expression { 80 | return Expression(expression: ({ try block(self.evaluate()) }), location: self.location, isClosure: self.isClosure) 81 | } 82 | 83 | public func evaluate() throws -> T? { 84 | return try self._expression(_withoutCaching) 85 | } 86 | 87 | public func withoutCaching() -> Expression { 88 | return Expression(memoizedExpression: self._expression, location: location, withoutCaching: true, isClosure: isClosure) 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/FailureMessage.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Encapsulates the failure message that matchers can report to the end user. 4 | /// 5 | /// This is shared state between Nimble and matchers that mutate this value. 6 | public class FailureMessage: NSObject { 7 | public var expected: String = "expected" 8 | public var actualValue: String? = "" // empty string -> use default; nil -> exclude 9 | public var to: String = "to" 10 | public var postfixMessage: String = "match" 11 | public var postfixActual: String = "" 12 | public var userDescription: String? = nil 13 | 14 | public var stringValue: String { 15 | get { 16 | if let value = _stringValueOverride { 17 | return value 18 | } else { 19 | return computeStringValue() 20 | } 21 | } 22 | set { 23 | _stringValueOverride = newValue 24 | } 25 | } 26 | 27 | internal var _stringValueOverride: String? 28 | 29 | public override init() { 30 | } 31 | 32 | public init(stringValue: String) { 33 | _stringValueOverride = stringValue 34 | } 35 | 36 | internal func stripNewlines(str: String) -> String { 37 | var lines: [String] = (str as NSString).componentsSeparatedByString("\n") as [String] 38 | let whitespace = NSCharacterSet.whitespaceAndNewlineCharacterSet() 39 | lines = lines.map { line in line.stringByTrimmingCharactersInSet(whitespace) } 40 | return lines.joinWithSeparator("") 41 | } 42 | 43 | internal func computeStringValue() -> String { 44 | var value = "\(expected) \(to) \(postfixMessage)" 45 | if let actualValue = actualValue { 46 | value = "\(expected) \(to) \(postfixMessage), got \(actualValue)\(postfixActual)" 47 | } 48 | value = stripNewlines(value) 49 | 50 | if let userDescription = userDescription { 51 | return "\(userDescription)\n\(value)" 52 | } 53 | 54 | return value 55 | } 56 | } -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/AllPass.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public func allPass 4 | (passFunc: (T?) -> Bool) -> NonNilMatcherFunc { 5 | return allPass("pass a condition", passFunc) 6 | } 7 | 8 | public func allPass 9 | (passName: String, _ passFunc: (T?) -> Bool) -> NonNilMatcherFunc { 10 | return createAllPassMatcher() { 11 | expression, failureMessage in 12 | failureMessage.postfixMessage = passName 13 | return passFunc(try expression.evaluate()) 14 | } 15 | } 16 | 17 | public func allPass 18 | (matcher: V) -> NonNilMatcherFunc { 19 | return createAllPassMatcher() { 20 | try matcher.matches($0, failureMessage: $1) 21 | } 22 | } 23 | 24 | private func createAllPassMatcher 25 | (elementEvaluator:(Expression, FailureMessage) throws -> Bool) -> NonNilMatcherFunc { 26 | return NonNilMatcherFunc { actualExpression, failureMessage in 27 | failureMessage.actualValue = nil 28 | if let actualValue = try actualExpression.evaluate() { 29 | for currentElement in actualValue { 30 | let exp = Expression( 31 | expression: {currentElement}, location: actualExpression.location) 32 | if try !elementEvaluator(exp, failureMessage) { 33 | failureMessage.postfixMessage = 34 | "all \(failureMessage.postfixMessage)," 35 | + " but failed first at element <\(stringify(currentElement))>" 36 | + " in <\(stringify(actualValue))>" 37 | return false 38 | } 39 | } 40 | failureMessage.postfixMessage = "all \(failureMessage.postfixMessage)" 41 | } else { 42 | failureMessage.postfixMessage = "all pass (use beNil() to match nils)" 43 | return false 44 | } 45 | 46 | return true 47 | } 48 | } 49 | 50 | extension NMBObjCMatcher { 51 | public class func allPassMatcher(matcher: NMBObjCMatcher) -> NMBObjCMatcher { 52 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 53 | let location = actualExpression.location 54 | let actualValue = try! actualExpression.evaluate() 55 | var nsObjects = [NSObject]() 56 | 57 | var collectionIsUsable = true 58 | if let value = actualValue as? NSFastEnumeration { 59 | let generator = NSFastGenerator(value) 60 | while let obj:AnyObject = generator.next() { 61 | if let nsObject = obj as? NSObject { 62 | nsObjects.append(nsObject) 63 | } else { 64 | collectionIsUsable = false 65 | break 66 | } 67 | } 68 | } else { 69 | collectionIsUsable = false 70 | } 71 | 72 | if !collectionIsUsable { 73 | failureMessage.postfixMessage = 74 | "allPass only works with NSFastEnumeration (NSArray, NSSet, ...) of NSObjects" 75 | failureMessage.expected = "" 76 | failureMessage.to = "" 77 | return false 78 | } 79 | 80 | let expr = Expression(expression: ({ nsObjects }), location: location) 81 | let elementEvaluator: (Expression, FailureMessage) -> Bool = { 82 | expression, failureMessage in 83 | return matcher.matches( 84 | {try! expression.evaluate()}, failureMessage: failureMessage, location: expr.location) 85 | } 86 | return try! createAllPassMatcher(elementEvaluator).matches( 87 | expr, failureMessage: failureMessage) 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeAKindOf.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // A Nimble matcher that catches attempts to use beAKindOf with non Objective-C types 4 | public func beAKindOf(expectedClass: Any) -> NonNilMatcherFunc { 5 | return NonNilMatcherFunc {actualExpression, failureMessage in 6 | failureMessage.stringValue = "beAKindOf only works on Objective-C types since" 7 | + " the Swift compiler will automatically type check Swift-only types." 8 | + " This expectation is redundant." 9 | return false 10 | } 11 | } 12 | 13 | /// A Nimble matcher that succeeds when the actual value is an instance of the given class. 14 | /// @see beAnInstanceOf if you want to match against the exact class 15 | public func beAKindOf(expectedClass: AnyClass) -> NonNilMatcherFunc { 16 | return NonNilMatcherFunc { actualExpression, failureMessage in 17 | let instance = try actualExpression.evaluate() 18 | if let validInstance = instance { 19 | failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>" 20 | } else { 21 | failureMessage.actualValue = "" 22 | } 23 | failureMessage.postfixMessage = "be a kind of \(NSStringFromClass(expectedClass))" 24 | return instance != nil && instance!.isKindOfClass(expectedClass) 25 | } 26 | } 27 | 28 | extension NMBObjCMatcher { 29 | public class func beAKindOfMatcher(expected: AnyClass) -> NMBMatcher { 30 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 31 | return try! beAKindOf(expected).matches(actualExpression, failureMessage: failureMessage) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeAnInstanceOf.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | // A Nimble matcher that catches attempts to use beAnInstanceOf with non Objective-C types 4 | public func beAnInstanceOf(expectedClass: Any) -> NonNilMatcherFunc { 5 | return NonNilMatcherFunc {actualExpression, failureMessage in 6 | failureMessage.stringValue = "beAnInstanceOf only works on Objective-C types since" 7 | + " the Swift compiler will automatically type check Swift-only types." 8 | + " This expectation is redundant." 9 | return false 10 | } 11 | } 12 | 13 | /// A Nimble matcher that succeeds when the actual value is an instance of the given class. 14 | /// @see beAKindOf if you want to match against subclasses 15 | public func beAnInstanceOf(expectedClass: AnyClass) -> NonNilMatcherFunc { 16 | return NonNilMatcherFunc { actualExpression, failureMessage in 17 | let instance = try actualExpression.evaluate() 18 | if let validInstance = instance { 19 | failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>" 20 | } else { 21 | failureMessage.actualValue = "" 22 | } 23 | failureMessage.postfixMessage = "be an instance of \(NSStringFromClass(expectedClass))" 24 | return instance != nil && instance!.isMemberOfClass(expectedClass) 25 | } 26 | } 27 | 28 | extension NMBObjCMatcher { 29 | public class func beAnInstanceOfMatcher(expected: AnyClass) -> NMBMatcher { 30 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 31 | return try! beAnInstanceOf(expected).matches(actualExpression, failureMessage: failureMessage) 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeCloseTo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal let DefaultDelta = 0.0001 4 | 5 | internal func isCloseTo(actualValue: NMBDoubleConvertible?, expectedValue: NMBDoubleConvertible, delta: Double, failureMessage: FailureMessage) -> Bool { 6 | failureMessage.postfixMessage = "be close to <\(stringify(expectedValue))> (within \(stringify(delta)))" 7 | if actualValue != nil { 8 | failureMessage.actualValue = "<\(stringify(actualValue!))>" 9 | } else { 10 | failureMessage.actualValue = "" 11 | } 12 | return actualValue != nil && abs(actualValue!.doubleValue - expectedValue.doubleValue) < delta 13 | } 14 | 15 | /// A Nimble matcher that succeeds when a value is close to another. This is used for floating 16 | /// point values which can have imprecise results when doing arithmetic on them. 17 | /// 18 | /// @see equal 19 | public func beCloseTo(expectedValue: Double, within delta: Double = DefaultDelta) -> NonNilMatcherFunc { 20 | return NonNilMatcherFunc { actualExpression, failureMessage in 21 | return isCloseTo(try actualExpression.evaluate(), expectedValue: expectedValue, delta: delta, failureMessage: failureMessage) 22 | } 23 | } 24 | 25 | /// A Nimble matcher that succeeds when a value is close to another. This is used for floating 26 | /// point values which can have imprecise results when doing arithmetic on them. 27 | /// 28 | /// @see equal 29 | public func beCloseTo(expectedValue: NMBDoubleConvertible, within delta: Double = DefaultDelta) -> NonNilMatcherFunc { 30 | return NonNilMatcherFunc { actualExpression, failureMessage in 31 | return isCloseTo(try actualExpression.evaluate(), expectedValue: expectedValue, delta: delta, failureMessage: failureMessage) 32 | } 33 | } 34 | 35 | public class NMBObjCBeCloseToMatcher : NSObject, NMBMatcher { 36 | var _expected: NSNumber 37 | var _delta: CDouble 38 | init(expected: NSNumber, within: CDouble) { 39 | _expected = expected 40 | _delta = within 41 | } 42 | 43 | public func matches(actualExpression: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { 44 | let actualBlock: () -> NMBDoubleConvertible? = ({ 45 | return actualExpression() as? NMBDoubleConvertible 46 | }) 47 | let expr = Expression(expression: actualBlock, location: location) 48 | let matcher = beCloseTo(self._expected, within: self._delta) 49 | return try! matcher.matches(expr, failureMessage: failureMessage) 50 | } 51 | 52 | public func doesNotMatch(actualExpression: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { 53 | let actualBlock: () -> NMBDoubleConvertible? = ({ 54 | return actualExpression() as? NMBDoubleConvertible 55 | }) 56 | let expr = Expression(expression: actualBlock, location: location) 57 | let matcher = beCloseTo(self._expected, within: self._delta) 58 | return try! matcher.doesNotMatch(expr, failureMessage: failureMessage) 59 | } 60 | 61 | public var within: (CDouble) -> NMBObjCBeCloseToMatcher { 62 | return ({ delta in 63 | return NMBObjCBeCloseToMatcher(expected: self._expected, within: delta) 64 | }) 65 | } 66 | } 67 | 68 | extension NMBObjCMatcher { 69 | public class func beCloseToMatcher(expected: NSNumber, within: CDouble) -> NMBObjCBeCloseToMatcher { 70 | return NMBObjCBeCloseToMatcher(expected: expected, within: within) 71 | } 72 | } 73 | 74 | public func beCloseTo(expectedValues: [Double], within delta: Double = DefaultDelta) -> NonNilMatcherFunc <[Double]> { 75 | return NonNilMatcherFunc { actualExpression, failureMessage in 76 | failureMessage.postfixMessage = "be close to <\(stringify(expectedValues))> (each within \(stringify(delta)))" 77 | if let actual = try actualExpression.evaluate() { 78 | if actual.count != expectedValues.count { 79 | return false 80 | } else { 81 | for (index, actualItem) in actual.enumerate() { 82 | if fabs(actualItem - expectedValues[index]) > delta { 83 | return false 84 | } 85 | } 86 | return true 87 | } 88 | } 89 | return false 90 | } 91 | } 92 | 93 | // MARK: - Operators 94 | 95 | infix operator ≈ { 96 | associativity none 97 | precedence 130 98 | } 99 | 100 | public func ≈(lhs: Expectation<[Double]>, rhs: [Double]) { 101 | lhs.to(beCloseTo(rhs)) 102 | } 103 | 104 | public func ≈(lhs: Expectation, rhs: Double) { 105 | lhs.to(beCloseTo(rhs)) 106 | } 107 | 108 | public func ≈(lhs: Expectation, rhs: (expected: Double, delta: Double)) { 109 | lhs.to(beCloseTo(rhs.expected, within: rhs.delta)) 110 | } 111 | 112 | public func ==(lhs: Expectation, rhs: (expected: Double, delta: Double)) { 113 | lhs.to(beCloseTo(rhs.expected, within: rhs.delta)) 114 | } 115 | 116 | // make this higher precedence than exponents so the Doubles either end aren't pulled in 117 | // unexpectantly 118 | infix operator ± { precedence 170 } 119 | public func ±(lhs: Double, rhs: Double) -> (expected: Double, delta: Double) { 120 | return (expected: lhs, delta: rhs) 121 | } 122 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeEmpty.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | /// A Nimble matcher that succeeds when a value is "empty". For collections, this 5 | /// means the are no items in that collection. For strings, it is an empty string. 6 | public func beEmpty() -> NonNilMatcherFunc { 7 | return NonNilMatcherFunc { actualExpression, failureMessage in 8 | failureMessage.postfixMessage = "be empty" 9 | let actualSeq = try actualExpression.evaluate() 10 | if actualSeq == nil { 11 | return true 12 | } 13 | var generator = actualSeq!.generate() 14 | return generator.next() == nil 15 | } 16 | } 17 | 18 | /// A Nimble matcher that succeeds when a value is "empty". For collections, this 19 | /// means the are no items in that collection. For strings, it is an empty string. 20 | public func beEmpty() -> NonNilMatcherFunc { 21 | return NonNilMatcherFunc { actualExpression, failureMessage in 22 | failureMessage.postfixMessage = "be empty" 23 | let actualString = try actualExpression.evaluate() 24 | return actualString == nil || (actualString! as NSString).length == 0 25 | } 26 | } 27 | 28 | /// A Nimble matcher that succeeds when a value is "empty". For collections, this 29 | /// means the are no items in that collection. For NSString instances, it is an empty string. 30 | public func beEmpty() -> NonNilMatcherFunc { 31 | return NonNilMatcherFunc { actualExpression, failureMessage in 32 | failureMessage.postfixMessage = "be empty" 33 | let actualString = try actualExpression.evaluate() 34 | return actualString == nil || actualString!.length == 0 35 | } 36 | } 37 | 38 | // Without specific overrides, beEmpty() is ambiguous for NSDictionary, NSArray, 39 | // etc, since they conform to SequenceType as well as NMBCollection. 40 | 41 | /// A Nimble matcher that succeeds when a value is "empty". For collections, this 42 | /// means the are no items in that collection. For strings, it is an empty string. 43 | public func beEmpty() -> NonNilMatcherFunc { 44 | return NonNilMatcherFunc { actualExpression, failureMessage in 45 | failureMessage.postfixMessage = "be empty" 46 | let actualDictionary = try actualExpression.evaluate() 47 | return actualDictionary == nil || actualDictionary!.count == 0 48 | } 49 | } 50 | 51 | /// A Nimble matcher that succeeds when a value is "empty". For collections, this 52 | /// means the are no items in that collection. For strings, it is an empty string. 53 | public func beEmpty() -> NonNilMatcherFunc { 54 | return NonNilMatcherFunc { actualExpression, failureMessage in 55 | failureMessage.postfixMessage = "be empty" 56 | let actualArray = try actualExpression.evaluate() 57 | return actualArray == nil || actualArray!.count == 0 58 | } 59 | } 60 | 61 | /// A Nimble matcher that succeeds when a value is "empty". For collections, this 62 | /// means the are no items in that collection. For strings, it is an empty string. 63 | public func beEmpty() -> NonNilMatcherFunc { 64 | return NonNilMatcherFunc { actualExpression, failureMessage in 65 | failureMessage.postfixMessage = "be empty" 66 | let actual = try actualExpression.evaluate() 67 | return actual == nil || actual!.count == 0 68 | } 69 | } 70 | 71 | extension NMBObjCMatcher { 72 | public class func beEmptyMatcher() -> NMBObjCMatcher { 73 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 74 | let location = actualExpression.location 75 | let actualValue = try! actualExpression.evaluate() 76 | failureMessage.postfixMessage = "be empty" 77 | if let value = actualValue as? NMBCollection { 78 | let expr = Expression(expression: ({ value as NMBCollection }), location: location) 79 | return try! beEmpty().matches(expr, failureMessage: failureMessage) 80 | } else if let value = actualValue as? NSString { 81 | let expr = Expression(expression: ({ value as String }), location: location) 82 | return try! beEmpty().matches(expr, failureMessage: failureMessage) 83 | } else if let actualValue = actualValue { 84 | failureMessage.postfixMessage = "be empty (only works for NSArrays, NSSets, NSDictionaries, NSHashTables, and NSStrings)" 85 | failureMessage.actualValue = "\(NSStringFromClass(actualValue.dynamicType)) type" 86 | } 87 | return false 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeGreaterThan.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | /// A Nimble matcher that succeeds when the actual value is greater than the expected value. 5 | public func beGreaterThan(expectedValue: T?) -> NonNilMatcherFunc { 6 | return NonNilMatcherFunc { actualExpression, failureMessage in 7 | failureMessage.postfixMessage = "be greater than <\(stringify(expectedValue))>" 8 | return try actualExpression.evaluate() > expectedValue 9 | } 10 | } 11 | 12 | /// A Nimble matcher that succeeds when the actual value is greater than the expected value. 13 | public func beGreaterThan(expectedValue: NMBComparable?) -> NonNilMatcherFunc { 14 | return NonNilMatcherFunc { actualExpression, failureMessage in 15 | failureMessage.postfixMessage = "be greater than <\(stringify(expectedValue))>" 16 | let actualValue = try actualExpression.evaluate() 17 | let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) == NSComparisonResult.OrderedDescending 18 | return matches 19 | } 20 | } 21 | 22 | public func >(lhs: Expectation, rhs: T) { 23 | lhs.to(beGreaterThan(rhs)) 24 | } 25 | 26 | public func >(lhs: Expectation, rhs: NMBComparable?) { 27 | lhs.to(beGreaterThan(rhs)) 28 | } 29 | 30 | extension NMBObjCMatcher { 31 | public class func beGreaterThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher { 32 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 33 | let expr = actualExpression.cast { $0 as? NMBComparable } 34 | return try! beGreaterThan(expected).matches(expr, failureMessage: failureMessage) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeGreaterThanOrEqualTo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is greater than 4 | /// or equal to the expected value. 5 | public func beGreaterThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { 6 | return NonNilMatcherFunc { actualExpression, failureMessage in 7 | failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>" 8 | let actualValue = try actualExpression.evaluate() 9 | return actualValue >= expectedValue 10 | } 11 | } 12 | 13 | /// A Nimble matcher that succeeds when the actual value is greater than 14 | /// or equal to the expected value. 15 | public func beGreaterThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { 16 | return NonNilMatcherFunc { actualExpression, failureMessage in 17 | failureMessage.postfixMessage = "be greater than or equal to <\(stringify(expectedValue))>" 18 | let actualValue = try actualExpression.evaluate() 19 | let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) != NSComparisonResult.OrderedAscending 20 | return matches 21 | } 22 | } 23 | 24 | public func >=(lhs: Expectation, rhs: T) { 25 | lhs.to(beGreaterThanOrEqualTo(rhs)) 26 | } 27 | 28 | public func >=(lhs: Expectation, rhs: T) { 29 | lhs.to(beGreaterThanOrEqualTo(rhs)) 30 | } 31 | 32 | extension NMBObjCMatcher { 33 | public class func beGreaterThanOrEqualToMatcher(expected: NMBComparable?) -> NMBObjCMatcher { 34 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 35 | let expr = actualExpression.cast { $0 as? NMBComparable } 36 | return try! beGreaterThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeIdenticalTo.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | /// A Nimble matcher that succeeds when the actual value is the same instance 5 | /// as the expected instance. 6 | public func beIdenticalTo(expected: T?) -> NonNilMatcherFunc { 7 | return NonNilMatcherFunc { actualExpression, failureMessage in 8 | let actual = try actualExpression.evaluate() 9 | failureMessage.actualValue = "\(identityAsString(actual))" 10 | failureMessage.postfixMessage = "be identical to \(identityAsString(expected))" 11 | return actual === expected && actual !== nil 12 | } 13 | } 14 | 15 | public func ===(lhs: Expectation, rhs: T?) { 16 | lhs.to(beIdenticalTo(rhs)) 17 | } 18 | public func !==(lhs: Expectation, rhs: T?) { 19 | lhs.toNot(beIdenticalTo(rhs)) 20 | } 21 | 22 | extension NMBObjCMatcher { 23 | public class func beIdenticalToMatcher(expected: NSObject?) -> NMBObjCMatcher { 24 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 25 | return try! beIdenticalTo(expected).matches(actualExpression, failureMessage: failureMessage) 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeLessThan.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is less than the expected value. 4 | public func beLessThan(expectedValue: T?) -> NonNilMatcherFunc { 5 | return NonNilMatcherFunc { actualExpression, failureMessage in 6 | failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>" 7 | return try actualExpression.evaluate() < expectedValue 8 | } 9 | } 10 | 11 | /// A Nimble matcher that succeeds when the actual value is less than the expected value. 12 | public func beLessThan(expectedValue: NMBComparable?) -> NonNilMatcherFunc { 13 | return NonNilMatcherFunc { actualExpression, failureMessage in 14 | failureMessage.postfixMessage = "be less than <\(stringify(expectedValue))>" 15 | let actualValue = try actualExpression.evaluate() 16 | let matches = actualValue != nil && actualValue!.NMB_compare(expectedValue) == NSComparisonResult.OrderedAscending 17 | return matches 18 | } 19 | } 20 | 21 | public func <(lhs: Expectation, rhs: T) { 22 | lhs.to(beLessThan(rhs)) 23 | } 24 | 25 | public func <(lhs: Expectation, rhs: NMBComparable?) { 26 | lhs.to(beLessThan(rhs)) 27 | } 28 | 29 | extension NMBObjCMatcher { 30 | public class func beLessThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher { 31 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 32 | let expr = actualExpression.cast { $0 as! NMBComparable? } 33 | return try! beLessThan(expected).matches(expr, failureMessage: failureMessage) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeLessThanOrEqual.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is less than 4 | /// or equal to the expected value. 5 | public func beLessThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { 6 | return NonNilMatcherFunc { actualExpression, failureMessage in 7 | failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>" 8 | return try actualExpression.evaluate() <= expectedValue 9 | } 10 | } 11 | 12 | /// A Nimble matcher that succeeds when the actual value is less than 13 | /// or equal to the expected value. 14 | public func beLessThanOrEqualTo(expectedValue: T?) -> NonNilMatcherFunc { 15 | return NonNilMatcherFunc { actualExpression, failureMessage in 16 | failureMessage.postfixMessage = "be less than or equal to <\(stringify(expectedValue))>" 17 | let actualValue = try actualExpression.evaluate() 18 | return actualValue != nil && actualValue!.NMB_compare(expectedValue) != NSComparisonResult.OrderedDescending 19 | } 20 | } 21 | 22 | public func <=(lhs: Expectation, rhs: T) { 23 | lhs.to(beLessThanOrEqualTo(rhs)) 24 | } 25 | 26 | public func <=(lhs: Expectation, rhs: T) { 27 | lhs.to(beLessThanOrEqualTo(rhs)) 28 | } 29 | 30 | extension NMBObjCMatcher { 31 | public class func beLessThanOrEqualToMatcher(expected: NMBComparable?) -> NMBObjCMatcher { 32 | return NMBObjCMatcher(canMatchNil:false) { actualExpression, failureMessage in 33 | let expr = actualExpression.cast { $0 as? NMBComparable } 34 | return try! beLessThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage) 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeLogical.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal func matcherWithFailureMessage(matcher: M, postprocessor: (FailureMessage) -> Void) -> FullMatcherFunc { 4 | return FullMatcherFunc { actualExpression, failureMessage, isNegation in 5 | let pass: Bool 6 | if isNegation { 7 | pass = try matcher.doesNotMatch(actualExpression, failureMessage: failureMessage) 8 | } else { 9 | pass = try matcher.matches(actualExpression, failureMessage: failureMessage) 10 | } 11 | postprocessor(failureMessage) 12 | return pass 13 | } 14 | } 15 | 16 | // MARK: beTrue() / beFalse() 17 | 18 | /// A Nimble matcher that succeeds when the actual value is exactly true. 19 | /// This matcher will not match against nils. 20 | public func beTrue() -> FullMatcherFunc { 21 | return matcherWithFailureMessage(equal(true)) { failureMessage in 22 | failureMessage.postfixMessage = "be true" 23 | } 24 | } 25 | 26 | /// A Nimble matcher that succeeds when the actual value is exactly false. 27 | /// This matcher will not match against nils. 28 | public func beFalse() -> FullMatcherFunc { 29 | return matcherWithFailureMessage(equal(false)) { failureMessage in 30 | failureMessage.postfixMessage = "be false" 31 | } 32 | } 33 | 34 | // MARK: beTruthy() / beFalsy() 35 | 36 | /// A Nimble matcher that succeeds when the actual value is not logically false. 37 | public func beTruthy() -> MatcherFunc { 38 | return MatcherFunc { actualExpression, failureMessage in 39 | failureMessage.postfixMessage = "be truthy" 40 | let actualValue = try actualExpression.evaluate() 41 | if let actualValue = actualValue { 42 | if let actualValue = actualValue as? BooleanType { 43 | return actualValue.boolValue == true 44 | } 45 | } 46 | return actualValue != nil 47 | } 48 | } 49 | 50 | /// A Nimble matcher that succeeds when the actual value is logically false. 51 | /// This matcher will match against nils. 52 | public func beFalsy() -> MatcherFunc { 53 | return MatcherFunc { actualExpression, failureMessage in 54 | failureMessage.postfixMessage = "be falsy" 55 | let actualValue = try actualExpression.evaluate() 56 | if let actualValue = actualValue { 57 | if let actualValue = actualValue as? BooleanType { 58 | return actualValue.boolValue != true 59 | } 60 | } 61 | return actualValue == nil 62 | } 63 | } 64 | 65 | extension NMBObjCMatcher { 66 | public class func beTruthyMatcher() -> NMBObjCMatcher { 67 | return NMBObjCMatcher { actualExpression, failureMessage in 68 | let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as BooleanType? } 69 | return try! beTruthy().matches(expr, failureMessage: failureMessage) 70 | } 71 | } 72 | 73 | public class func beFalsyMatcher() -> NMBObjCMatcher { 74 | return NMBObjCMatcher { actualExpression, failureMessage in 75 | let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as BooleanType? } 76 | return try! beFalsy().matches(expr, failureMessage: failureMessage) 77 | } 78 | } 79 | 80 | public class func beTrueMatcher() -> NMBObjCMatcher { 81 | return NMBObjCMatcher { actualExpression, failureMessage in 82 | let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as Bool? } 83 | return try! beTrue().matches(expr, failureMessage: failureMessage) 84 | } 85 | } 86 | 87 | public class func beFalseMatcher() -> NMBObjCMatcher { 88 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 89 | let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false as Bool? } 90 | return try! beFalse().matches(expr, failureMessage: failureMessage) 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeNil.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is nil. 4 | public func beNil() -> MatcherFunc { 5 | return MatcherFunc { actualExpression, failureMessage in 6 | failureMessage.postfixMessage = "be nil" 7 | let actualValue = try actualExpression.evaluate() 8 | return actualValue == nil 9 | } 10 | } 11 | 12 | extension NMBObjCMatcher { 13 | public class func beNilMatcher() -> NMBObjCMatcher { 14 | return NMBObjCMatcher { actualExpression, failureMessage in 15 | return try! beNil().matches(actualExpression, failureMessage: failureMessage) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/BeginWith.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | /// A Nimble matcher that succeeds when the actual sequence's first element 5 | /// is equal to the expected value. 6 | public func beginWith(startingElement: T) -> NonNilMatcherFunc { 7 | return NonNilMatcherFunc { actualExpression, failureMessage in 8 | failureMessage.postfixMessage = "begin with <\(startingElement)>" 9 | if let actualValue = try actualExpression.evaluate() { 10 | var actualGenerator = actualValue.generate() 11 | return actualGenerator.next() == startingElement 12 | } 13 | return false 14 | } 15 | } 16 | 17 | /// A Nimble matcher that succeeds when the actual collection's first element 18 | /// is equal to the expected object. 19 | public func beginWith(startingElement: AnyObject) -> NonNilMatcherFunc { 20 | return NonNilMatcherFunc { actualExpression, failureMessage in 21 | failureMessage.postfixMessage = "begin with <\(startingElement)>" 22 | let collection = try actualExpression.evaluate() 23 | return collection != nil && collection!.indexOfObject(startingElement) == 0 24 | } 25 | } 26 | 27 | /// A Nimble matcher that succeeds when the actual string contains expected substring 28 | /// where the expected substring's location is zero. 29 | public func beginWith(startingSubstring: String) -> NonNilMatcherFunc { 30 | return NonNilMatcherFunc { actualExpression, failureMessage in 31 | failureMessage.postfixMessage = "begin with <\(startingSubstring)>" 32 | if let actual = try actualExpression.evaluate() { 33 | let range = actual.rangeOfString(startingSubstring) 34 | return range != nil && range!.startIndex == actual.startIndex 35 | } 36 | return false 37 | } 38 | } 39 | 40 | extension NMBObjCMatcher { 41 | public class func beginWithMatcher(expected: AnyObject) -> NMBObjCMatcher { 42 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 43 | let actual = try! actualExpression.evaluate() 44 | if let _ = actual as? String { 45 | let expr = actualExpression.cast { $0 as? String } 46 | return try! beginWith(expected as! String).matches(expr, failureMessage: failureMessage) 47 | } else { 48 | let expr = actualExpression.cast { $0 as? NMBOrderedCollection } 49 | return try! beginWith(expected).matches(expr, failureMessage: failureMessage) 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/Contain.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual sequence contains the expected value. 4 | public func contain(items: T...) -> NonNilMatcherFunc { 5 | return contain(items) 6 | } 7 | 8 | private func contain(items: [T]) -> NonNilMatcherFunc { 9 | return NonNilMatcherFunc { actualExpression, failureMessage in 10 | failureMessage.postfixMessage = "contain <\(arrayAsString(items))>" 11 | if let actual = try actualExpression.evaluate() { 12 | return all(items) { 13 | return actual.contains($0) 14 | } 15 | } 16 | return false 17 | } 18 | } 19 | 20 | /// A Nimble matcher that succeeds when the actual string contains the expected substring. 21 | public func contain(substrings: String...) -> NonNilMatcherFunc { 22 | return contain(substrings) 23 | } 24 | 25 | private func contain(substrings: [String]) -> NonNilMatcherFunc { 26 | return NonNilMatcherFunc { actualExpression, failureMessage in 27 | failureMessage.postfixMessage = "contain <\(arrayAsString(substrings))>" 28 | if let actual = try actualExpression.evaluate() { 29 | return all(substrings) { 30 | let scanRange = Range(start: actual.startIndex, end: actual.endIndex) 31 | let range = actual.rangeOfString($0, options: [], range: scanRange, locale: nil) 32 | return range != nil && !range!.isEmpty 33 | } 34 | } 35 | return false 36 | } 37 | } 38 | 39 | /// A Nimble matcher that succeeds when the actual string contains the expected substring. 40 | public func contain(substrings: NSString...) -> NonNilMatcherFunc { 41 | return contain(substrings) 42 | } 43 | 44 | private func contain(substrings: [NSString]) -> NonNilMatcherFunc { 45 | return NonNilMatcherFunc { actualExpression, failureMessage in 46 | failureMessage.postfixMessage = "contain <\(arrayAsString(substrings))>" 47 | if let actual = try actualExpression.evaluate() { 48 | return all(substrings) { actual.rangeOfString($0.description).length != 0 } 49 | } 50 | return false 51 | } 52 | } 53 | 54 | /// A Nimble matcher that succeeds when the actual collection contains the expected object. 55 | public func contain(items: AnyObject?...) -> NonNilMatcherFunc { 56 | return contain(items) 57 | } 58 | 59 | private func contain(items: [AnyObject?]) -> NonNilMatcherFunc { 60 | return NonNilMatcherFunc { actualExpression, failureMessage in 61 | failureMessage.postfixMessage = "contain <\(arrayAsString(items))>" 62 | let actual = try actualExpression.evaluate() 63 | return all(items) { item in 64 | return actual != nil && actual!.containsObject(item) 65 | } 66 | } 67 | } 68 | 69 | extension NMBObjCMatcher { 70 | public class func containMatcher(expected: [NSObject]) -> NMBObjCMatcher { 71 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 72 | let location = actualExpression.location 73 | let actualValue = try! actualExpression.evaluate() 74 | if let value = actualValue as? NMBContainer { 75 | let expr = Expression(expression: ({ value as NMBContainer }), location: location) 76 | 77 | // A straightforward cast on the array causes this to crash, so we have to cast the individual items 78 | let expectedOptionals: [AnyObject?] = expected.map({ $0 as AnyObject? }) 79 | return try! contain(expectedOptionals).matches(expr, failureMessage: failureMessage) 80 | } else if let value = actualValue as? NSString { 81 | let expr = Expression(expression: ({ value as String }), location: location) 82 | return try! contain(expected as! [String]).matches(expr, failureMessage: failureMessage) 83 | } else if actualValue != nil { 84 | failureMessage.postfixMessage = "contain <\(arrayAsString(expected))> (only works for NSArrays, NSSets, NSHashTables, and NSStrings)" 85 | } else { 86 | failureMessage.postfixMessage = "contain <\(arrayAsString(expected))>" 87 | } 88 | return false 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/EndWith.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | /// A Nimble matcher that succeeds when the actual sequence's last element 5 | /// is equal to the expected value. 6 | public func endWith(endingElement: T) -> NonNilMatcherFunc { 7 | return NonNilMatcherFunc { actualExpression, failureMessage in 8 | failureMessage.postfixMessage = "end with <\(endingElement)>" 9 | 10 | if let actualValue = try actualExpression.evaluate() { 11 | var actualGenerator = actualValue.generate() 12 | var lastItem: T? 13 | var item: T? 14 | repeat { 15 | lastItem = item 16 | item = actualGenerator.next() 17 | } while(item != nil) 18 | 19 | return lastItem == endingElement 20 | } 21 | return false 22 | } 23 | } 24 | 25 | /// A Nimble matcher that succeeds when the actual collection's last element 26 | /// is equal to the expected object. 27 | public func endWith(endingElement: AnyObject) -> NonNilMatcherFunc { 28 | return NonNilMatcherFunc { actualExpression, failureMessage in 29 | failureMessage.postfixMessage = "end with <\(endingElement)>" 30 | let collection = try actualExpression.evaluate() 31 | return collection != nil && collection!.indexOfObject(endingElement) == collection!.count - 1 32 | } 33 | } 34 | 35 | 36 | /// A Nimble matcher that succeeds when the actual string contains the expected substring 37 | /// where the expected substring's location is the actual string's length minus the 38 | /// expected substring's length. 39 | public func endWith(endingSubstring: String) -> NonNilMatcherFunc { 40 | return NonNilMatcherFunc { actualExpression, failureMessage in 41 | failureMessage.postfixMessage = "end with <\(endingSubstring)>" 42 | if let collection = try actualExpression.evaluate() { 43 | let range = collection.rangeOfString(endingSubstring) 44 | return range != nil && range!.endIndex == collection.endIndex 45 | } 46 | return false 47 | } 48 | } 49 | 50 | extension NMBObjCMatcher { 51 | public class func endWithMatcher(expected: AnyObject) -> NMBObjCMatcher { 52 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 53 | let actual = try! actualExpression.evaluate() 54 | if let _ = actual as? String { 55 | let expr = actualExpression.cast { $0 as? String } 56 | return try! endWith(expected as! String).matches(expr, failureMessage: failureMessage) 57 | } else { 58 | let expr = actualExpression.cast { $0 as? NMBOrderedCollection } 59 | return try! endWith(expected).matches(expr, failureMessage: failureMessage) 60 | } 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/Equal.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual value is equal to the expected value. 4 | /// Values can support equal by supporting the Equatable protocol. 5 | /// 6 | /// @see beCloseTo if you want to match imprecise types (eg - floats, doubles). 7 | public func equal(expectedValue: T?) -> NonNilMatcherFunc { 8 | return NonNilMatcherFunc { actualExpression, failureMessage in 9 | failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" 10 | let actualValue = try actualExpression.evaluate() 11 | let matches = actualValue == expectedValue && expectedValue != nil 12 | if expectedValue == nil || actualValue == nil { 13 | if expectedValue == nil { 14 | failureMessage.postfixActual = " (use beNil() to match nils)" 15 | } 16 | return false 17 | } 18 | return matches 19 | } 20 | } 21 | 22 | /// A Nimble matcher that succeeds when the actual value is equal to the expected value. 23 | /// Values can support equal by supporting the Equatable protocol. 24 | /// 25 | /// @see beCloseTo if you want to match imprecise types (eg - floats, doubles). 26 | public func equal(expectedValue: [T: C]?) -> NonNilMatcherFunc<[T: C]> { 27 | return NonNilMatcherFunc { actualExpression, failureMessage in 28 | failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" 29 | let actualValue = try actualExpression.evaluate() 30 | if expectedValue == nil || actualValue == nil { 31 | if expectedValue == nil { 32 | failureMessage.postfixActual = " (use beNil() to match nils)" 33 | } 34 | return false 35 | } 36 | return expectedValue! == actualValue! 37 | } 38 | } 39 | 40 | /// A Nimble matcher that succeeds when the actual collection is equal to the expected collection. 41 | /// Items must implement the Equatable protocol. 42 | public func equal(expectedValue: [T]?) -> NonNilMatcherFunc<[T]> { 43 | return NonNilMatcherFunc { actualExpression, failureMessage in 44 | failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" 45 | let actualValue = try actualExpression.evaluate() 46 | if expectedValue == nil || actualValue == nil { 47 | if expectedValue == nil { 48 | failureMessage.postfixActual = " (use beNil() to match nils)" 49 | } 50 | return false 51 | } 52 | return expectedValue! == actualValue! 53 | } 54 | } 55 | 56 | /// A Nimble matcher that succeeds when the actual set is equal to the expected set. 57 | public func equal(expectedValue: Set?) -> NonNilMatcherFunc> { 58 | return equal(expectedValue, stringify: stringify) 59 | } 60 | 61 | /// A Nimble matcher that succeeds when the actual set is equal to the expected set. 62 | public func equal(expectedValue: Set?) -> NonNilMatcherFunc> { 63 | return equal(expectedValue, stringify: { 64 | if let set = $0 { 65 | return stringify(Array(set).sort { $0 < $1 }) 66 | } else { 67 | return "nil" 68 | } 69 | }) 70 | } 71 | 72 | private func equal(expectedValue: Set?, stringify: Set? -> String) -> NonNilMatcherFunc> { 73 | return NonNilMatcherFunc { actualExpression, failureMessage in 74 | failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>" 75 | 76 | if let expectedValue = expectedValue { 77 | if let actualValue = try actualExpression.evaluate() { 78 | failureMessage.actualValue = "<\(stringify(actualValue))>" 79 | 80 | if expectedValue == actualValue { 81 | return true 82 | } 83 | 84 | let missing = expectedValue.subtract(actualValue) 85 | if missing.count > 0 { 86 | failureMessage.postfixActual += ", missing <\(stringify(missing))>" 87 | } 88 | 89 | let extra = actualValue.subtract(expectedValue) 90 | if extra.count > 0 { 91 | failureMessage.postfixActual += ", extra <\(stringify(extra))>" 92 | } 93 | } 94 | } else { 95 | failureMessage.postfixActual = " (use beNil() to match nils)" 96 | } 97 | 98 | return false 99 | } 100 | } 101 | 102 | public func ==(lhs: Expectation, rhs: T?) { 103 | lhs.to(equal(rhs)) 104 | } 105 | 106 | public func !=(lhs: Expectation, rhs: T?) { 107 | lhs.toNot(equal(rhs)) 108 | } 109 | 110 | public func ==(lhs: Expectation<[T]>, rhs: [T]?) { 111 | lhs.to(equal(rhs)) 112 | } 113 | 114 | public func !=(lhs: Expectation<[T]>, rhs: [T]?) { 115 | lhs.toNot(equal(rhs)) 116 | } 117 | 118 | public func ==(lhs: Expectation>, rhs: Set?) { 119 | lhs.to(equal(rhs)) 120 | } 121 | 122 | public func !=(lhs: Expectation>, rhs: Set?) { 123 | lhs.toNot(equal(rhs)) 124 | } 125 | 126 | public func ==(lhs: Expectation>, rhs: Set?) { 127 | lhs.to(equal(rhs)) 128 | } 129 | 130 | public func !=(lhs: Expectation>, rhs: Set?) { 131 | lhs.toNot(equal(rhs)) 132 | } 133 | 134 | public func ==(lhs: Expectation<[T: C]>, rhs: [T: C]?) { 135 | lhs.to(equal(rhs)) 136 | } 137 | 138 | public func !=(lhs: Expectation<[T: C]>, rhs: [T: C]?) { 139 | lhs.toNot(equal(rhs)) 140 | } 141 | 142 | extension NMBObjCMatcher { 143 | public class func equalMatcher(expected: NSObject) -> NMBMatcher { 144 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 145 | return try! equal(expected).matches(actualExpression, failureMessage: failureMessage) 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/HaveCount.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual CollectionType's count equals 4 | /// the expected value 5 | public func haveCount(expectedValue: T.Index.Distance) -> NonNilMatcherFunc { 6 | return NonNilMatcherFunc { actualExpression, failureMessage in 7 | if let actualValue = try actualExpression.evaluate() { 8 | failureMessage.postfixMessage = "have \(actualValue) with count \(expectedValue)" 9 | let result = expectedValue == actualValue.count 10 | failureMessage.actualValue = "\(actualValue.count)" 11 | return result 12 | } else { 13 | return false 14 | } 15 | } 16 | } 17 | 18 | /// A Nimble matcher that succeeds when the actual collection's count equals 19 | /// the expected value 20 | public func haveCount(expectedValue: Int) -> MatcherFunc { 21 | return MatcherFunc { actualExpression, failureMessage in 22 | if let actualValue = try actualExpression.evaluate() { 23 | failureMessage.postfixMessage = "have \(actualValue) with count \(expectedValue)" 24 | let result = expectedValue == actualValue.count 25 | failureMessage.actualValue = "\(actualValue.count)" 26 | return result 27 | } else { 28 | return false 29 | } 30 | } 31 | } 32 | 33 | extension NMBObjCMatcher { 34 | public class func haveCountMatcher(expected: NSNumber) -> NMBObjCMatcher { 35 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 36 | let location = actualExpression.location 37 | let actualValue = try! actualExpression.evaluate() 38 | if let value = actualValue as? NMBCollection { 39 | let expr = Expression(expression: ({ value as NMBCollection}), location: location) 40 | return try! haveCount(expected.integerValue).matches(expr, failureMessage: failureMessage) 41 | } else if let actualValue = actualValue { 42 | failureMessage.postfixMessage = "get type of NSArray, NSSet, NSDictionary, or NSHashTable" 43 | failureMessage.actualValue = "\(NSStringFromClass(actualValue.dynamicType))" 44 | } 45 | return false 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/Match.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual string satisfies the regular expression 4 | /// described by the expected string. 5 | public func match(expectedValue: String?) -> NonNilMatcherFunc { 6 | return NonNilMatcherFunc { actualExpression, failureMessage in 7 | failureMessage.postfixMessage = "match <\(stringify(expectedValue))>" 8 | 9 | if let actual = try actualExpression.evaluate() { 10 | if let regexp = expectedValue { 11 | return actual.rangeOfString(regexp, options: .RegularExpressionSearch) != nil 12 | } 13 | } 14 | 15 | return false 16 | } 17 | } 18 | 19 | extension NMBObjCMatcher { 20 | public class func matchMatcher(expected: NSString) -> NMBMatcher { 21 | return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in 22 | let actual = actualExpression.cast { $0 as? String } 23 | return try! match(expected.description).matches(actual, failureMessage: failureMessage) 24 | } 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/MatcherProtocols.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Implement this protocol to implement a custom matcher for Swift 4 | public protocol Matcher { 5 | typealias ValueType 6 | func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool 7 | func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool 8 | } 9 | 10 | /// Objective-C interface to the Swift variant of Matcher. 11 | @objc public protocol NMBMatcher { 12 | func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool 13 | func doesNotMatch(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool 14 | } 15 | 16 | /// Protocol for types that support contain() matcher. 17 | @objc public protocol NMBContainer { 18 | func containsObject(object: AnyObject!) -> Bool 19 | } 20 | extension NSArray : NMBContainer {} 21 | extension NSSet : NMBContainer {} 22 | extension NSHashTable : NMBContainer {} 23 | 24 | /// Protocol for types that support only beEmpty(), haveCount() matchers 25 | @objc public protocol NMBCollection { 26 | var count: Int { get } 27 | } 28 | extension NSSet : NMBCollection {} 29 | extension NSDictionary : NMBCollection {} 30 | extension NSHashTable : NMBCollection {} 31 | extension NSMapTable : NMBCollection {} 32 | 33 | /// Protocol for types that support beginWith(), endWith(), beEmpty() matchers 34 | @objc public protocol NMBOrderedCollection : NMBCollection { 35 | func indexOfObject(object: AnyObject!) -> Int 36 | } 37 | extension NSArray : NMBOrderedCollection {} 38 | 39 | /// Protocol for types to support beCloseTo() matcher 40 | @objc public protocol NMBDoubleConvertible { 41 | var doubleValue: CDouble { get } 42 | } 43 | extension NSNumber : NMBDoubleConvertible { 44 | } 45 | 46 | private let dateFormatter: NSDateFormatter = { 47 | let formatter = NSDateFormatter() 48 | formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSSS" 49 | formatter.locale = NSLocale(localeIdentifier: "en_US_POSIX") 50 | 51 | return formatter 52 | }() 53 | 54 | extension NSDate: NMBDoubleConvertible { 55 | public var doubleValue: CDouble { 56 | get { 57 | return self.timeIntervalSinceReferenceDate 58 | } 59 | } 60 | } 61 | 62 | 63 | extension NMBDoubleConvertible { 64 | public var stringRepresentation: String { 65 | get { 66 | if let date = self as? NSDate { 67 | return dateFormatter.stringFromDate(date) 68 | } 69 | 70 | if let debugStringConvertible = self as? CustomDebugStringConvertible { 71 | return debugStringConvertible.debugDescription 72 | } 73 | 74 | if let stringConvertible = self as? CustomStringConvertible { 75 | return stringConvertible.description 76 | } 77 | 78 | return "" 79 | } 80 | } 81 | } 82 | 83 | /// Protocol for types to support beLessThan(), beLessThanOrEqualTo(), 84 | /// beGreaterThan(), beGreaterThanOrEqualTo(), and equal() matchers. 85 | /// 86 | /// Types that conform to Swift's Comparable protocol will work implicitly too 87 | @objc public protocol NMBComparable { 88 | func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult 89 | } 90 | extension NSNumber : NMBComparable { 91 | public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult { 92 | return compare(otherObject as! NSNumber) 93 | } 94 | } 95 | extension NSString : NMBComparable { 96 | public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult { 97 | return compare(otherObject as! String) 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/RaisesException.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual expression raises an 4 | /// exception with the specified name, reason, and/or userInfo. 5 | /// 6 | /// Alternatively, you can pass a closure to do any arbitrary custom matching 7 | /// to the raised exception. The closure only gets called when an exception 8 | /// is raised. 9 | /// 10 | /// nil arguments indicates that the matcher should not attempt to match against 11 | /// that parameter. 12 | public func raiseException( 13 | named named: String? = nil, 14 | reason: String? = nil, 15 | userInfo: NSDictionary? = nil, 16 | closure: ((NSException) -> Void)? = nil) -> MatcherFunc { 17 | return MatcherFunc { actualExpression, failureMessage in 18 | 19 | var exception: NSException? 20 | let capture = NMBExceptionCapture(handler: ({ e in 21 | exception = e 22 | }), finally: nil) 23 | 24 | capture.tryBlock { 25 | try! actualExpression.evaluate() 26 | return 27 | } 28 | 29 | setFailureMessageForException(failureMessage, exception: exception, named: named, reason: reason, userInfo: userInfo, closure: closure) 30 | return exceptionMatchesNonNilFieldsOrClosure(exception, named: named, reason: reason, userInfo: userInfo, closure: closure) 31 | } 32 | } 33 | 34 | internal func setFailureMessageForException( 35 | failureMessage: FailureMessage, 36 | exception: NSException?, 37 | named: String?, 38 | reason: String?, 39 | userInfo: NSDictionary?, 40 | closure: ((NSException) -> Void)?) { 41 | failureMessage.postfixMessage = "raise exception" 42 | 43 | if let named = named { 44 | failureMessage.postfixMessage += " with name <\(named)>" 45 | } 46 | if let reason = reason { 47 | failureMessage.postfixMessage += " with reason <\(reason)>" 48 | } 49 | if let userInfo = userInfo { 50 | failureMessage.postfixMessage += " with userInfo <\(userInfo)>" 51 | } 52 | if let _ = closure { 53 | failureMessage.postfixMessage += " that satisfies block" 54 | } 55 | if named == nil && reason == nil && userInfo == nil && closure == nil { 56 | failureMessage.postfixMessage = "raise any exception" 57 | } 58 | 59 | if let exception = exception { 60 | failureMessage.actualValue = "\(NSStringFromClass(exception.dynamicType)) { name=\(exception.name), reason='\(stringify(exception.reason))', userInfo=\(stringify(exception.userInfo)) }" 61 | } else { 62 | failureMessage.actualValue = "no exception" 63 | } 64 | } 65 | 66 | internal func exceptionMatchesNonNilFieldsOrClosure( 67 | exception: NSException?, 68 | named: String?, 69 | reason: String?, 70 | userInfo: NSDictionary?, 71 | closure: ((NSException) -> Void)?) -> Bool { 72 | var matches = false 73 | 74 | if let exception = exception { 75 | matches = true 76 | 77 | if named != nil && exception.name != named { 78 | matches = false 79 | } 80 | if reason != nil && exception.reason != reason { 81 | matches = false 82 | } 83 | if userInfo != nil && exception.userInfo != userInfo { 84 | matches = false 85 | } 86 | if let closure = closure { 87 | let assertions = gatherFailingExpectations { 88 | closure(exception) 89 | } 90 | let messages = assertions.map { $0.message } 91 | if messages.count > 0 { 92 | matches = false 93 | } 94 | } 95 | } 96 | 97 | return matches 98 | } 99 | 100 | public class NMBObjCRaiseExceptionMatcher : NSObject, NMBMatcher { 101 | internal var _name: String? 102 | internal var _reason: String? 103 | internal var _userInfo: NSDictionary? 104 | internal var _block: ((NSException) -> Void)? 105 | 106 | internal init(name: String?, reason: String?, userInfo: NSDictionary?, block: ((NSException) -> Void)?) { 107 | _name = name 108 | _reason = reason 109 | _userInfo = userInfo 110 | _block = block 111 | } 112 | 113 | public func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { 114 | let block: () -> Any? = ({ actualBlock(); return nil }) 115 | let expr = Expression(expression: block, location: location) 116 | 117 | return try! raiseException( 118 | named: _name, 119 | reason: _reason, 120 | userInfo: _userInfo, 121 | closure: _block 122 | ).matches(expr, failureMessage: failureMessage) 123 | } 124 | 125 | public func doesNotMatch(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { 126 | return !matches(actualBlock, failureMessage: failureMessage, location: location) 127 | } 128 | 129 | public var named: (name: String) -> NMBObjCRaiseExceptionMatcher { 130 | return ({ name in 131 | return NMBObjCRaiseExceptionMatcher( 132 | name: name, 133 | reason: self._reason, 134 | userInfo: self._userInfo, 135 | block: self._block 136 | ) 137 | }) 138 | } 139 | 140 | public var reason: (reason: String?) -> NMBObjCRaiseExceptionMatcher { 141 | return ({ reason in 142 | return NMBObjCRaiseExceptionMatcher( 143 | name: self._name, 144 | reason: reason, 145 | userInfo: self._userInfo, 146 | block: self._block 147 | ) 148 | }) 149 | } 150 | 151 | public var userInfo: (userInfo: NSDictionary?) -> NMBObjCRaiseExceptionMatcher { 152 | return ({ userInfo in 153 | return NMBObjCRaiseExceptionMatcher( 154 | name: self._name, 155 | reason: self._reason, 156 | userInfo: userInfo, 157 | block: self._block 158 | ) 159 | }) 160 | } 161 | 162 | public var satisfyingBlock: (block: ((NSException) -> Void)?) -> NMBObjCRaiseExceptionMatcher { 163 | return ({ block in 164 | return NMBObjCRaiseExceptionMatcher( 165 | name: self._name, 166 | reason: self._reason, 167 | userInfo: self._userInfo, 168 | block: block 169 | ) 170 | }) 171 | } 172 | } 173 | 174 | extension NMBObjCMatcher { 175 | public class func raiseExceptionMatcher() -> NMBObjCRaiseExceptionMatcher { 176 | return NMBObjCRaiseExceptionMatcher(name: nil, reason: nil, userInfo: nil, block: nil) 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Matchers/ThrowError.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// A Nimble matcher that succeeds when the actual expression throws an 4 | /// error of the specified type or from the specified case. 5 | /// 6 | /// Errors are tried to be compared by their implementation of Equatable, 7 | /// otherwise they fallback to comparision by _domain and _code. 8 | /// 9 | /// Alternatively, you can pass a closure to do any arbitrary custom matching 10 | /// to the thrown error. The closure only gets called when an error was thrown. 11 | /// 12 | /// nil arguments indicates that the matcher should not attempt to match against 13 | /// that parameter. 14 | public func throwError( 15 | error: T? = nil, 16 | errorType: T.Type? = nil, 17 | closure: ((T) -> Void)? = nil) -> MatcherFunc { 18 | return MatcherFunc { actualExpression, failureMessage in 19 | 20 | var actualError: ErrorType? 21 | do { 22 | try actualExpression.evaluate() 23 | } catch let catchedError { 24 | actualError = catchedError 25 | } 26 | 27 | setFailureMessageForError(failureMessage, actualError: actualError, error: error, errorType: errorType, closure: closure) 28 | return errorMatchesNonNilFieldsOrClosure(actualError, error: error, errorType: errorType, closure: closure) 29 | } 30 | } 31 | 32 | internal func setFailureMessageForError( 33 | failureMessage: FailureMessage, 34 | actualError: ErrorType?, 35 | error: T?, 36 | errorType: T.Type? = nil, 37 | closure: ((T) -> Void)?) { 38 | failureMessage.postfixMessage = "throw error" 39 | 40 | if let error = error { 41 | if let error = error as? CustomDebugStringConvertible { 42 | failureMessage.postfixMessage += " <\(error.debugDescription)>" 43 | } else { 44 | failureMessage.postfixMessage += " <\(error)>" 45 | } 46 | } else if errorType != nil || closure != nil { 47 | failureMessage.postfixMessage += " from type <\(T.self)>" 48 | } 49 | if let _ = closure { 50 | failureMessage.postfixMessage += " that satisfies block" 51 | } 52 | if error == nil && errorType == nil && closure == nil { 53 | failureMessage.postfixMessage = "throw any error" 54 | } 55 | 56 | if let actualError = actualError { 57 | failureMessage.actualValue = "<\(actualError)>" 58 | } else { 59 | failureMessage.actualValue = "no error" 60 | } 61 | } 62 | 63 | internal func errorMatchesExpectedError( 64 | actualError: ErrorType, 65 | expectedError: T) -> Bool { 66 | return actualError._domain == expectedError._domain 67 | && actualError._code == expectedError._code 68 | } 69 | 70 | internal func errorMatchesExpectedError( 71 | actualError: ErrorType, 72 | expectedError: T) -> Bool { 73 | if let actualError = actualError as? T { 74 | return actualError == expectedError 75 | } 76 | return false 77 | } 78 | 79 | internal func errorMatchesNonNilFieldsOrClosure( 80 | actualError: ErrorType?, 81 | error: T?, 82 | errorType: T.Type?, 83 | closure: ((T) -> Void)?) -> Bool { 84 | var matches = false 85 | 86 | if let actualError = actualError { 87 | matches = true 88 | 89 | if let error = error { 90 | if !errorMatchesExpectedError(actualError, expectedError: error) { 91 | matches = false 92 | } 93 | } 94 | if let actualError = actualError as? T { 95 | if let closure = closure { 96 | let assertions = gatherFailingExpectations { 97 | closure(actualError as T) 98 | } 99 | let messages = assertions.map { $0.message } 100 | if messages.count > 0 { 101 | matches = false 102 | } 103 | } 104 | } else if errorType != nil && closure != nil { 105 | // The closure expects another ErrorType as argument, so this 106 | // is _supposed_ to fail, so that it becomes more obvious. 107 | let assertions = gatherExpectations { 108 | expect(actualError is T).to(equal(true)) 109 | } 110 | precondition(assertions.map { $0.message }.count > 0) 111 | matches = false 112 | } 113 | } 114 | 115 | return matches 116 | } 117 | 118 | 119 | /// A Nimble matcher that succeeds when the actual expression throws any 120 | /// error or when the passed closures' arbitrary custom matching succeeds. 121 | /// 122 | /// This duplication to it's generic adequate is required to allow to receive 123 | /// values of the existential type ErrorType in the closure. 124 | /// 125 | /// The closure only gets called when an error was thrown. 126 | public func throwError( 127 | closure closure: ((ErrorType) -> Void)? = nil) -> MatcherFunc { 128 | return MatcherFunc { actualExpression, failureMessage in 129 | 130 | var actualError: ErrorType? 131 | do { 132 | try actualExpression.evaluate() 133 | } catch let catchedError { 134 | actualError = catchedError 135 | } 136 | 137 | setFailureMessageForError(failureMessage, actualError: actualError, closure: closure) 138 | return errorMatchesNonNilFieldsOrClosure(actualError, closure: closure) 139 | } 140 | } 141 | 142 | internal func setFailureMessageForError( 143 | failureMessage: FailureMessage, 144 | actualError: ErrorType?, 145 | closure: ((ErrorType) -> Void)?) { 146 | failureMessage.postfixMessage = "throw error" 147 | 148 | if let _ = closure { 149 | failureMessage.postfixMessage += " that satisfies block" 150 | } else { 151 | failureMessage.postfixMessage = "throw any error" 152 | } 153 | 154 | if let actualError = actualError { 155 | failureMessage.actualValue = "<\(actualError)>" 156 | } else { 157 | failureMessage.actualValue = "no error" 158 | } 159 | } 160 | 161 | internal func errorMatchesNonNilFieldsOrClosure( 162 | actualError: ErrorType?, 163 | closure: ((ErrorType) -> Void)?) -> Bool { 164 | var matches = false 165 | 166 | if let actualError = actualError { 167 | matches = true 168 | 169 | if let closure = closure { 170 | let assertions = gatherFailingExpectations { 171 | closure(actualError) 172 | } 173 | let messages = assertions.map { $0.message } 174 | if messages.count > 0 { 175 | matches = false 176 | } 177 | } 178 | } 179 | 180 | return matches 181 | } 182 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Nimble.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import "NMBExceptionCapture.h" 3 | #import "DSL.h" 4 | 5 | FOUNDATION_EXPORT double NimbleVersionNumber; 6 | FOUNDATION_EXPORT const unsigned char NimbleVersionString[]; -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/ObjCExpectation.swift: -------------------------------------------------------------------------------- 1 | internal struct ObjCMatcherWrapper : Matcher { 2 | let matcher: NMBMatcher 3 | 4 | func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { 5 | return matcher.matches( 6 | ({ try! actualExpression.evaluate() }), 7 | failureMessage: failureMessage, 8 | location: actualExpression.location) 9 | } 10 | 11 | func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { 12 | return matcher.doesNotMatch( 13 | ({ try! actualExpression.evaluate() }), 14 | failureMessage: failureMessage, 15 | location: actualExpression.location) 16 | } 17 | } 18 | 19 | // Equivalent to Expectation, but for Nimble's Objective-C interface 20 | public class NMBExpectation : NSObject { 21 | internal let _actualBlock: () -> NSObject! 22 | internal var _negative: Bool 23 | internal let _file: String 24 | internal let _line: UInt 25 | internal var _timeout: NSTimeInterval = 1.0 26 | 27 | public init(actualBlock: () -> NSObject!, negative: Bool, file: String, line: UInt) { 28 | self._actualBlock = actualBlock 29 | self._negative = negative 30 | self._file = file 31 | self._line = line 32 | } 33 | 34 | private var expectValue: Expectation { 35 | return expect(_file, line: _line){ 36 | self._actualBlock() as NSObject? 37 | } 38 | } 39 | 40 | public var withTimeout: (NSTimeInterval) -> NMBExpectation { 41 | return ({ timeout in self._timeout = timeout 42 | return self 43 | }) 44 | } 45 | 46 | public var to: (NMBMatcher) -> Void { 47 | return ({ matcher in 48 | self.expectValue.to(ObjCMatcherWrapper(matcher: matcher)) 49 | }) 50 | } 51 | 52 | public var toWithDescription: (NMBMatcher, String) -> Void { 53 | return ({ matcher, description in 54 | self.expectValue.to(ObjCMatcherWrapper(matcher: matcher), description: description) 55 | }) 56 | } 57 | 58 | public var toNot: (NMBMatcher) -> Void { 59 | return ({ matcher in 60 | self.expectValue.toNot( 61 | ObjCMatcherWrapper(matcher: matcher) 62 | ) 63 | }) 64 | } 65 | 66 | public var toNotWithDescription: (NMBMatcher, String) -> Void { 67 | return ({ matcher, description in 68 | self.expectValue.toNot( 69 | ObjCMatcherWrapper(matcher: matcher), description: description 70 | ) 71 | }) 72 | } 73 | 74 | public var notTo: (NMBMatcher) -> Void { return toNot } 75 | 76 | public var notToWithDescription: (NMBMatcher, String) -> Void { return toNotWithDescription } 77 | 78 | public var toEventually: (NMBMatcher) -> Void { 79 | return ({ matcher in 80 | self.expectValue.toEventually( 81 | ObjCMatcherWrapper(matcher: matcher), 82 | timeout: self._timeout, 83 | description: nil 84 | ) 85 | }) 86 | } 87 | 88 | public var toEventuallyWithDescription: (NMBMatcher, String) -> Void { 89 | return ({ matcher, description in 90 | self.expectValue.toEventually( 91 | ObjCMatcherWrapper(matcher: matcher), 92 | timeout: self._timeout, 93 | description: description 94 | ) 95 | }) 96 | } 97 | 98 | public var toEventuallyNot: (NMBMatcher) -> Void { 99 | return ({ matcher in 100 | self.expectValue.toEventuallyNot( 101 | ObjCMatcherWrapper(matcher: matcher), 102 | timeout: self._timeout, 103 | description: nil 104 | ) 105 | }) 106 | } 107 | 108 | public var toEventuallyNotWithDescription: (NMBMatcher, String) -> Void { 109 | return ({ matcher, description in 110 | self.expectValue.toEventuallyNot( 111 | ObjCMatcherWrapper(matcher: matcher), 112 | timeout: self._timeout, 113 | description: description 114 | ) 115 | }) 116 | } 117 | 118 | public var toNotEventually: (NMBMatcher) -> Void { return toEventuallyNot } 119 | 120 | public var toNotEventuallyWithDescription: (NMBMatcher, String) -> Void { return toEventuallyNotWithDescription } 121 | 122 | public class func failWithMessage(message: String, file: String, line: UInt) { 123 | fail(message, location: SourceLocation(file: file, line: line)) 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Utils/Functional.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal 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 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Utils/Poll.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal enum PollResult : BooleanType { 4 | case Success, Failure, Timeout 5 | case ErrorThrown(ErrorType) 6 | 7 | var boolValue : Bool { 8 | switch (self) { 9 | case .Success: 10 | return true 11 | default: 12 | return false 13 | } 14 | } 15 | } 16 | 17 | internal class RunPromise { 18 | var token: dispatch_once_t = 0 19 | var didFinish = false 20 | var didFail = false 21 | 22 | init() {} 23 | 24 | func succeed() { 25 | dispatch_once(&self.token) { 26 | self.didFinish = false 27 | } 28 | } 29 | 30 | func fail(block: () -> Void) { 31 | dispatch_once(&self.token) { 32 | self.didFail = true 33 | block() 34 | } 35 | } 36 | } 37 | 38 | let killQueue = dispatch_queue_create("nimble.waitUntil.queue", DISPATCH_QUEUE_SERIAL) 39 | 40 | internal func stopRunLoop(runLoop: NSRunLoop, delay: NSTimeInterval) -> RunPromise { 41 | let promise = RunPromise() 42 | let killTimeOffset = Int64(CDouble(delay) * CDouble(NSEC_PER_SEC)) 43 | let killTime = dispatch_time(DISPATCH_TIME_NOW, killTimeOffset) 44 | dispatch_after(killTime, killQueue) { 45 | promise.fail { 46 | CFRunLoopStop(runLoop.getCFRunLoop()) 47 | } 48 | } 49 | return promise 50 | } 51 | 52 | internal func pollBlock(pollInterval pollInterval: NSTimeInterval, timeoutInterval: NSTimeInterval, expression: () throws -> Bool) -> PollResult { 53 | let runLoop = NSRunLoop.mainRunLoop() 54 | 55 | let promise = stopRunLoop(runLoop, delay: min(timeoutInterval, 0.2)) 56 | 57 | let startDate = NSDate() 58 | 59 | // trigger run loop to make sure enqueued tasks don't block our assertion polling 60 | // the stop run loop task above will abort us if necessary 61 | runLoop.runUntilDate(startDate) 62 | dispatch_sync(killQueue) { 63 | promise.succeed() 64 | } 65 | 66 | if promise.didFail { 67 | return .Timeout 68 | } 69 | 70 | var pass = false 71 | do { 72 | repeat { 73 | pass = try expression() 74 | if pass { 75 | break 76 | } 77 | 78 | let runDate = NSDate().dateByAddingTimeInterval(pollInterval) 79 | runLoop.runUntilDate(runDate) 80 | } while(NSDate().timeIntervalSinceDate(startDate) < timeoutInterval) 81 | } catch let error { 82 | return .ErrorThrown(error) 83 | } 84 | 85 | return pass ? .Success : .Failure 86 | } 87 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Utils/SourceLocation.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | public class SourceLocation : NSObject { 5 | public let file: String 6 | public let line: UInt 7 | 8 | override 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 | override public var description: String { 19 | return "\(file):\(line)" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Utils/Stringers.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | 4 | internal func identityAsString(value: AnyObject?) -> String { 5 | if value == nil { 6 | return "nil" 7 | } 8 | return NSString(format: "<%p>", unsafeBitCast(value!, Int.self)).description 9 | } 10 | 11 | internal func arrayAsString(items: [T], joiner: String = ", ") -> String { 12 | return items.reduce("") { accum, item in 13 | let prefix = (accum.isEmpty ? "" : joiner) 14 | return accum + prefix + "\(stringify(item))" 15 | } 16 | } 17 | 18 | @objc internal protocol NMBStringer { 19 | func NMB_stringify() -> String 20 | } 21 | 22 | internal func stringify(value: S) -> String { 23 | var generator = value.generate() 24 | var strings = [String]() 25 | var value: S.Generator.Element? 26 | repeat { 27 | value = generator.next() 28 | if value != nil { 29 | strings.append(stringify(value)) 30 | } 31 | } while value != nil 32 | let str = strings.joinWithSeparator(", ") 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 | internal func stringify(value: T) -> String { 44 | if let value = value as? Double { 45 | return NSString(format: "%.4f", (value)).description 46 | } 47 | return String(value) 48 | } 49 | 50 | internal func stringify(value: NMBDoubleConvertible) -> String { 51 | if let value = value as? Double { 52 | return NSString(format: "%.4f", (value)).description 53 | } 54 | return value.stringRepresentation 55 | } 56 | 57 | internal func stringify(value: T?) -> String { 58 | if let unboxed = value { 59 | return stringify(unboxed) 60 | } 61 | return "nil" 62 | } 63 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Wrappers/AsyncMatcherWrapper.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | internal struct AsyncMatcherWrapper: Matcher { 4 | let fullMatcher: U 5 | let timeoutInterval: NSTimeInterval 6 | let pollInterval: NSTimeInterval 7 | 8 | init(fullMatcher: U, timeoutInterval: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) { 9 | self.fullMatcher = fullMatcher 10 | self.timeoutInterval = timeoutInterval 11 | self.pollInterval = pollInterval 12 | } 13 | 14 | func matches(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { 15 | let uncachedExpression = actualExpression.withoutCaching() 16 | let result = pollBlock(pollInterval: pollInterval, timeoutInterval: timeoutInterval) { 17 | try self.fullMatcher.matches(uncachedExpression, failureMessage: failureMessage) 18 | } 19 | switch (result) { 20 | case .Success: return true 21 | case .Failure: return false 22 | case let .ErrorThrown(error): 23 | failureMessage.actualValue = "an unexpected error thrown: <\(error)>" 24 | return false 25 | case .Timeout: 26 | failureMessage.postfixMessage += " (Stall on main thread)." 27 | return false 28 | } 29 | } 30 | 31 | func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { 32 | let uncachedExpression = actualExpression.withoutCaching() 33 | let result = pollBlock(pollInterval: pollInterval, timeoutInterval: timeoutInterval) { 34 | try self.fullMatcher.doesNotMatch(uncachedExpression, failureMessage: failureMessage) 35 | } 36 | switch (result) { 37 | case .Success: return true 38 | case .Failure: return false 39 | case let .ErrorThrown(error): 40 | failureMessage.actualValue = "an unexpected error thrown: <\(error)>" 41 | return false 42 | case .Timeout: 43 | failureMessage.postfixMessage += " (Stall on main thread)." 44 | return false 45 | } 46 | } 47 | } 48 | 49 | private let toEventuallyRequiresClosureError = FailureMessage(stringValue: "expect(...).toEventually(...) requires an explicit closure (eg - expect { ... }.toEventually(...) )\nSwift 1.2 @autoclosure behavior has changed in an incompatible way for Nimble to function") 50 | 51 | 52 | extension Expectation { 53 | /// Tests the actual value using a matcher to match by checking continuously 54 | /// at each pollInterval until the timeout is reached. 55 | public func toEventually(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) { 56 | if expression.isClosure { 57 | let (pass, msg) = expressionMatches( 58 | expression, 59 | matcher: AsyncMatcherWrapper( 60 | fullMatcher: matcher, 61 | timeoutInterval: timeout, 62 | pollInterval: pollInterval), 63 | to: "to eventually", 64 | description: description 65 | ) 66 | verify(pass, msg) 67 | } else { 68 | verify(false, toEventuallyRequiresClosureError) 69 | } 70 | } 71 | 72 | /// Tests the actual value using a matcher to not match by checking 73 | /// continuously at each pollInterval until the timeout is reached. 74 | public func toEventuallyNot(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) { 75 | if expression.isClosure { 76 | let (pass, msg) = expressionDoesNotMatch( 77 | expression, 78 | matcher: AsyncMatcherWrapper( 79 | fullMatcher: matcher, 80 | timeoutInterval: timeout, 81 | pollInterval: pollInterval), 82 | toNot: "to eventually not", 83 | description: description 84 | ) 85 | verify(pass, msg) 86 | } else { 87 | verify(false, toEventuallyRequiresClosureError) 88 | } 89 | } 90 | 91 | /// Tests the actual value using a matcher to not match by checking 92 | /// continuously at each pollInterval until the timeout is reached. 93 | /// 94 | /// Alias of toEventuallyNot() 95 | public func toNotEventually(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01, description: String? = nil) { 96 | return toEventuallyNot(matcher, timeout: timeout, pollInterval: pollInterval, description: description) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Wrappers/MatcherFunc.swift: -------------------------------------------------------------------------------- 1 | /// A convenience API to build matchers that allow full control over 2 | /// to() and toNot() match cases. 3 | /// 4 | /// The final bool argument in the closure is if the match is for negation. 5 | /// 6 | /// You may use this when implementing your own custom matchers. 7 | /// 8 | /// Use the Matcher protocol instead of this type to accept custom matchers as 9 | /// input parameters. 10 | /// @see allPass for an example that uses accepts other matchers as input. 11 | public struct FullMatcherFunc: Matcher { 12 | public let matcher: (Expression, FailureMessage, Bool) throws -> Bool 13 | 14 | public init(_ matcher: (Expression, FailureMessage, Bool) throws -> Bool) { 15 | self.matcher = matcher 16 | } 17 | 18 | public func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { 19 | return try matcher(actualExpression, failureMessage, false) 20 | } 21 | 22 | public func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { 23 | return try matcher(actualExpression, failureMessage, true) 24 | } 25 | } 26 | 27 | /// A convenience API to build matchers that don't need special negation 28 | /// behavior. The toNot() behavior is the negation of to(). 29 | /// 30 | /// @see NonNilMatcherFunc if you prefer to have this matcher fail when nil 31 | /// values are recieved in an expectation. 32 | /// 33 | /// You may use this when implementing your own custom matchers. 34 | /// 35 | /// Use the Matcher protocol instead of this type to accept custom matchers as 36 | /// input parameters. 37 | /// @see allPass for an example that uses accepts other matchers as input. 38 | public struct MatcherFunc: Matcher { 39 | public let matcher: (Expression, FailureMessage) throws -> Bool 40 | 41 | public init(_ matcher: (Expression, FailureMessage) throws -> Bool) { 42 | self.matcher = matcher 43 | } 44 | 45 | public func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { 46 | return try matcher(actualExpression, failureMessage) 47 | } 48 | 49 | public func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { 50 | return try !matcher(actualExpression, failureMessage) 51 | } 52 | } 53 | 54 | /// A convenience API to build matchers that don't need special negation 55 | /// behavior. The toNot() behavior is the negation of to(). 56 | /// 57 | /// Unlike MatcherFunc, this will always fail if an expectation contains nil. 58 | /// This applies regardless of using to() or toNot(). 59 | /// 60 | /// You may use this when implementing your own custom matchers. 61 | /// 62 | /// Use the Matcher protocol instead of this type to accept custom matchers as 63 | /// input parameters. 64 | /// @see allPass for an example that uses accepts other matchers as input. 65 | public struct NonNilMatcherFunc: Matcher { 66 | public let matcher: (Expression, FailureMessage) throws -> Bool 67 | 68 | public init(_ matcher: (Expression, FailureMessage) throws -> Bool) { 69 | self.matcher = matcher 70 | } 71 | 72 | public func matches(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { 73 | let pass = try matcher(actualExpression, failureMessage) 74 | if try attachNilErrorIfNeeded(actualExpression, failureMessage: failureMessage) { 75 | return false 76 | } 77 | return pass 78 | } 79 | 80 | public func doesNotMatch(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { 81 | let pass = try !matcher(actualExpression, failureMessage) 82 | if try attachNilErrorIfNeeded(actualExpression, failureMessage: failureMessage) { 83 | return false 84 | } 85 | return pass 86 | } 87 | 88 | internal func attachNilErrorIfNeeded(actualExpression: Expression, failureMessage: FailureMessage) throws -> Bool { 89 | if try actualExpression.evaluate() == nil { 90 | failureMessage.postfixActual = " (use beNil() to match nils)" 91 | return true 92 | } 93 | return false 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/Wrappers/ObjCMatcher.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public typealias MatcherBlock = (actualExpression: Expression, failureMessage: FailureMessage) -> Bool 4 | public typealias FullMatcherBlock = (actualExpression: Expression, failureMessage: FailureMessage, shouldNotMatch: Bool) -> Bool 5 | 6 | public class NMBObjCMatcher : NSObject, NMBMatcher { 7 | let _match: MatcherBlock 8 | let _doesNotMatch: MatcherBlock 9 | let canMatchNil: Bool 10 | 11 | public init(canMatchNil: Bool, matcher: MatcherBlock, notMatcher: MatcherBlock) { 12 | self.canMatchNil = canMatchNil 13 | self._match = matcher 14 | self._doesNotMatch = notMatcher 15 | } 16 | 17 | public convenience init(matcher: MatcherBlock) { 18 | self.init(canMatchNil: true, matcher: matcher) 19 | } 20 | 21 | public convenience init(canMatchNil: Bool, matcher: MatcherBlock) { 22 | self.init(canMatchNil: canMatchNil, matcher: matcher, notMatcher: ({ actualExpression, failureMessage in 23 | return !matcher(actualExpression: actualExpression, failureMessage: failureMessage) 24 | })) 25 | } 26 | 27 | public convenience init(matcher: FullMatcherBlock) { 28 | self.init(canMatchNil: true, matcher: matcher) 29 | } 30 | 31 | public convenience init(canMatchNil: Bool, matcher: FullMatcherBlock) { 32 | self.init(canMatchNil: canMatchNil, matcher: ({ actualExpression, failureMessage in 33 | return matcher(actualExpression: actualExpression, failureMessage: failureMessage, shouldNotMatch: false) 34 | }), notMatcher: ({ actualExpression, failureMessage in 35 | return matcher(actualExpression: actualExpression, failureMessage: failureMessage, shouldNotMatch: true) 36 | })) 37 | } 38 | 39 | private func canMatch(actualExpression: Expression, failureMessage: FailureMessage) -> Bool { 40 | do { 41 | if !canMatchNil { 42 | if try actualExpression.evaluate() == nil { 43 | failureMessage.postfixActual = " (use beNil() to match nils)" 44 | return false 45 | } 46 | } 47 | } catch let error { 48 | failureMessage.actualValue = "an unexpected error thrown: \(error)" 49 | return false 50 | } 51 | return true 52 | } 53 | 54 | public func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { 55 | let expr = Expression(expression: actualBlock, location: location) 56 | let result = _match( 57 | actualExpression: expr, 58 | failureMessage: failureMessage) 59 | if self.canMatch(Expression(expression: actualBlock, location: location), failureMessage: failureMessage) { 60 | return result 61 | } else { 62 | return false 63 | } 64 | } 65 | 66 | public func doesNotMatch(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool { 67 | let expr = Expression(expression: actualBlock, location: location) 68 | let result = _doesNotMatch( 69 | actualExpression: expr, 70 | failureMessage: failureMessage) 71 | if self.canMatch(Expression(expression: actualBlock, location: location), failureMessage: failureMessage) { 72 | return result 73 | } else { 74 | return false 75 | } 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /Pods/Nimble/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)(), NSString *file, NSUInteger line); 18 | NIMBLE_EXPORT NMBExpectation *NMB_expectAction(void(^actualBlock)(), NSString *file, NSUInteger line); 19 | 20 | NIMBLE_EXPORT id NMB_equal(id expectedValue); 21 | NIMBLE_SHORT(id equal(id expectedValue), 22 | NMB_equal(expectedValue)); 23 | 24 | NIMBLE_EXPORT id NMB_haveCount(id expectedValue); 25 | NIMBLE_SHORT(id haveCount(id expectedValue), 26 | NMB_haveCount(expectedValue)); 27 | 28 | NIMBLE_EXPORT NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue); 29 | NIMBLE_SHORT(NMBObjCBeCloseToMatcher *beCloseTo(id expectedValue), 30 | NMB_beCloseTo(expectedValue)); 31 | 32 | NIMBLE_EXPORT id NMB_beAnInstanceOf(Class expectedClass); 33 | NIMBLE_SHORT(id beAnInstanceOf(Class expectedClass), 34 | NMB_beAnInstanceOf(expectedClass)); 35 | 36 | NIMBLE_EXPORT id NMB_beAKindOf(Class expectedClass); 37 | NIMBLE_SHORT(id beAKindOf(Class expectedClass), 38 | NMB_beAKindOf(expectedClass)); 39 | 40 | NIMBLE_EXPORT id NMB_beginWith(id itemElementOrSubstring); 41 | NIMBLE_SHORT(id beginWith(id itemElementOrSubstring), 42 | NMB_beginWith(itemElementOrSubstring)); 43 | 44 | NIMBLE_EXPORT id NMB_beGreaterThan(NSNumber *expectedValue); 45 | NIMBLE_SHORT(id beGreaterThan(NSNumber *expectedValue), 46 | NMB_beGreaterThan(expectedValue)); 47 | 48 | NIMBLE_EXPORT id NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue); 49 | NIMBLE_SHORT(id beGreaterThanOrEqualTo(NSNumber *expectedValue), 50 | NMB_beGreaterThanOrEqualTo(expectedValue)); 51 | 52 | NIMBLE_EXPORT id NMB_beIdenticalTo(id expectedInstance); 53 | NIMBLE_SHORT(id beIdenticalTo(id expectedInstance), 54 | NMB_beIdenticalTo(expectedInstance)); 55 | 56 | NIMBLE_EXPORT id NMB_beLessThan(NSNumber *expectedValue); 57 | NIMBLE_SHORT(id beLessThan(NSNumber *expectedValue), 58 | NMB_beLessThan(expectedValue)); 59 | 60 | NIMBLE_EXPORT id NMB_beLessThanOrEqualTo(NSNumber *expectedValue); 61 | NIMBLE_SHORT(id beLessThanOrEqualTo(NSNumber *expectedValue), 62 | NMB_beLessThanOrEqualTo(expectedValue)); 63 | 64 | NIMBLE_EXPORT id NMB_beTruthy(void); 65 | NIMBLE_SHORT(id beTruthy(void), 66 | NMB_beTruthy()); 67 | 68 | NIMBLE_EXPORT id NMB_beFalsy(void); 69 | NIMBLE_SHORT(id beFalsy(void), 70 | NMB_beFalsy()); 71 | 72 | NIMBLE_EXPORT id NMB_beTrue(void); 73 | NIMBLE_SHORT(id beTrue(void), 74 | NMB_beTrue()); 75 | 76 | NIMBLE_EXPORT id NMB_beFalse(void); 77 | NIMBLE_SHORT(id beFalse(void), 78 | NMB_beFalse()); 79 | 80 | NIMBLE_EXPORT id NMB_beNil(void); 81 | NIMBLE_SHORT(id beNil(void), 82 | NMB_beNil()); 83 | 84 | NIMBLE_EXPORT id NMB_beEmpty(void); 85 | NIMBLE_SHORT(id beEmpty(void), 86 | NMB_beEmpty()); 87 | 88 | NIMBLE_EXPORT id NMB_containWithNilTermination(id itemOrSubstring, ...) NS_REQUIRES_NIL_TERMINATION; 89 | #define NMB_contain(...) NMB_containWithNilTermination(__VA_ARGS__, nil) 90 | #ifndef NIMBLE_DISABLE_SHORT_SYNTAX 91 | #define contain(...) NMB_contain(__VA_ARGS__) 92 | #endif 93 | 94 | NIMBLE_EXPORT id NMB_endWith(id itemElementOrSubstring); 95 | NIMBLE_SHORT(id endWith(id itemElementOrSubstring), 96 | NMB_endWith(itemElementOrSubstring)); 97 | 98 | NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException(void); 99 | NIMBLE_SHORT(NMBObjCRaiseExceptionMatcher *raiseException(void), 100 | NMB_raiseException()); 101 | 102 | NIMBLE_EXPORT id NMB_match(id expectedValue); 103 | NIMBLE_SHORT(id match(id expectedValue), 104 | NMB_match(expectedValue)); 105 | 106 | NIMBLE_EXPORT id NMB_allPass(id matcher); 107 | NIMBLE_SHORT(id allPass(id matcher), 108 | NMB_allPass(matcher)); 109 | 110 | // In order to preserve breakpoint behavior despite using macros to fill in __FILE__ and __LINE__, 111 | // define a builder that populates __FILE__ and __LINE__, and returns a block that takes timeout 112 | // and action arguments. See https://github.com/Quick/Quick/pull/185 for details. 113 | typedef void (^NMBWaitUntilTimeoutBlock)(NSTimeInterval timeout, void (^action)(void (^)(void))); 114 | typedef void (^NMBWaitUntilBlock)(void (^action)(void (^)(void))); 115 | 116 | NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line); 117 | 118 | NIMBLE_EXPORT NMBWaitUntilTimeoutBlock NMB_waitUntilTimeoutBuilder(NSString *file, NSUInteger line); 119 | NIMBLE_EXPORT NMBWaitUntilBlock NMB_waitUntilBuilder(NSString *file, NSUInteger line); 120 | 121 | NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line); 122 | 123 | #define NMB_waitUntilTimeout NMB_waitUntilTimeoutBuilder(@(__FILE__), __LINE__) 124 | #define NMB_waitUntil NMB_waitUntilBuilder(@(__FILE__), __LINE__) 125 | 126 | #ifndef NIMBLE_DISABLE_SHORT_SYNTAX 127 | #define expect(...) NMB_expect(^id{ return (__VA_ARGS__); }, @(__FILE__), __LINE__) 128 | #define expectAction(BLOCK) NMB_expectAction((BLOCK), @(__FILE__), __LINE__) 129 | #define failWithMessage(msg) NMB_failWithMessage(msg, @(__FILE__), __LINE__) 130 | #define fail() failWithMessage(@"fail() always fails") 131 | 132 | 133 | #define waitUntilTimeout NMB_waitUntilTimeout 134 | #define waitUntil NMB_waitUntil 135 | #endif 136 | -------------------------------------------------------------------------------- /Pods/Nimble/Nimble/objc/DSL.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | SWIFT_CLASS("_TtC6Nimble7NMBWait") 5 | @interface NMBWait : NSObject 6 | 7 | + (void)untilTimeout:(NSTimeInterval)timeout file:(NSString *)file line:(NSUInteger)line action:(void(^)())action; 8 | + (void)untilFile:(NSString *)file line:(NSUInteger)line action:(void(^)())action; 9 | 10 | @end 11 | 12 | NIMBLE_EXPORT NMBExpectation *NMB_expect(id(^actualBlock)(), NSString *file, NSUInteger line) { 13 | return [[NMBExpectation alloc] initWithActualBlock:actualBlock 14 | negative:NO 15 | file:file 16 | line:line]; 17 | } 18 | 19 | NIMBLE_EXPORT NMBExpectation *NMB_expectAction(void(^actualBlock)(), NSString *file, NSUInteger line) { 20 | return NMB_expect(^id{ 21 | actualBlock(); 22 | return nil; 23 | }, file, line); 24 | } 25 | 26 | NIMBLE_EXPORT void NMB_failWithMessage(NSString *msg, NSString *file, NSUInteger line) { 27 | return [NMBExpectation failWithMessage:msg file:file line:line]; 28 | } 29 | 30 | NIMBLE_EXPORT id NMB_beAnInstanceOf(Class expectedClass) { 31 | return [NMBObjCMatcher beAnInstanceOfMatcher:expectedClass]; 32 | } 33 | 34 | NIMBLE_EXPORT id NMB_beAKindOf(Class expectedClass) { 35 | return [NMBObjCMatcher beAKindOfMatcher:expectedClass]; 36 | } 37 | 38 | NIMBLE_EXPORT NMBObjCBeCloseToMatcher *NMB_beCloseTo(NSNumber *expectedValue) { 39 | return [NMBObjCMatcher beCloseToMatcher:expectedValue within:0.001]; 40 | } 41 | 42 | NIMBLE_EXPORT id NMB_beginWith(id itemElementOrSubstring) { 43 | return [NMBObjCMatcher beginWithMatcher:itemElementOrSubstring]; 44 | } 45 | 46 | NIMBLE_EXPORT id NMB_beGreaterThan(NSNumber *expectedValue) { 47 | return [NMBObjCMatcher beGreaterThanMatcher:expectedValue]; 48 | } 49 | 50 | NIMBLE_EXPORT id NMB_beGreaterThanOrEqualTo(NSNumber *expectedValue) { 51 | return [NMBObjCMatcher beGreaterThanOrEqualToMatcher:expectedValue]; 52 | } 53 | 54 | NIMBLE_EXPORT id NMB_beIdenticalTo(id expectedInstance) { 55 | return [NMBObjCMatcher beIdenticalToMatcher:expectedInstance]; 56 | } 57 | 58 | NIMBLE_EXPORT id NMB_beLessThan(NSNumber *expectedValue) { 59 | return [NMBObjCMatcher beLessThanMatcher:expectedValue]; 60 | } 61 | 62 | NIMBLE_EXPORT id NMB_beLessThanOrEqualTo(NSNumber *expectedValue) { 63 | return [NMBObjCMatcher beLessThanOrEqualToMatcher:expectedValue]; 64 | } 65 | 66 | NIMBLE_EXPORT id NMB_beTruthy() { 67 | return [NMBObjCMatcher beTruthyMatcher]; 68 | } 69 | 70 | NIMBLE_EXPORT id NMB_beFalsy() { 71 | return [NMBObjCMatcher beFalsyMatcher]; 72 | } 73 | 74 | NIMBLE_EXPORT id NMB_beTrue() { 75 | return [NMBObjCMatcher beTrueMatcher]; 76 | } 77 | 78 | NIMBLE_EXPORT id NMB_beFalse() { 79 | return [NMBObjCMatcher beFalseMatcher]; 80 | } 81 | 82 | NIMBLE_EXPORT id NMB_beNil() { 83 | return [NMBObjCMatcher beNilMatcher]; 84 | } 85 | 86 | NIMBLE_EXPORT id NMB_beEmpty() { 87 | return [NMBObjCMatcher beEmptyMatcher]; 88 | } 89 | 90 | NIMBLE_EXPORT id NMB_containWithNilTermination(id itemOrSubstring, ...) { 91 | NSMutableArray *itemOrSubstringArray = [NSMutableArray array]; 92 | 93 | if (itemOrSubstring) { 94 | [itemOrSubstringArray addObject:itemOrSubstring]; 95 | 96 | va_list args; 97 | va_start(args, itemOrSubstring); 98 | id next; 99 | while ((next = va_arg(args, id))) { 100 | [itemOrSubstringArray addObject:next]; 101 | } 102 | va_end(args); 103 | } 104 | 105 | return [NMBObjCMatcher containMatcher:itemOrSubstringArray]; 106 | } 107 | 108 | NIMBLE_EXPORT id NMB_endWith(id itemElementOrSubstring) { 109 | return [NMBObjCMatcher endWithMatcher:itemElementOrSubstring]; 110 | } 111 | 112 | NIMBLE_EXPORT id NMB_equal(id expectedValue) { 113 | return [NMBObjCMatcher equalMatcher:expectedValue]; 114 | } 115 | 116 | NIMBLE_EXPORT id NMB_haveCount(id expectedValue) { 117 | return [NMBObjCMatcher haveCountMatcher:expectedValue]; 118 | } 119 | 120 | NIMBLE_EXPORT id NMB_match(id expectedValue) { 121 | return [NMBObjCMatcher matchMatcher:expectedValue]; 122 | } 123 | 124 | NIMBLE_EXPORT id NMB_allPass(id expectedValue) { 125 | return [NMBObjCMatcher allPassMatcher:expectedValue]; 126 | } 127 | 128 | NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException() { 129 | return [NMBObjCMatcher raiseExceptionMatcher]; 130 | } 131 | 132 | NIMBLE_EXPORT NMBWaitUntilTimeoutBlock NMB_waitUntilTimeoutBuilder(NSString *file, NSUInteger line) { 133 | return ^(NSTimeInterval timeout, void (^action)(void (^)(void))) { 134 | [NMBWait untilTimeout:timeout file:file line:line action:action]; 135 | }; 136 | } 137 | 138 | NIMBLE_EXPORT NMBWaitUntilBlock NMB_waitUntilBuilder(NSString *file, NSUInteger line) { 139 | return ^(void (^action)(void (^)(void))) { 140 | [NMBWait untilFile:file line:line action:action]; 141 | }; 142 | } 143 | -------------------------------------------------------------------------------- /Pods/Nimble/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 9 | -------------------------------------------------------------------------------- /Pods/Nimble/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 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/Matthew.xcuserdatad/xcschemes/Nimble.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/Matthew.xcuserdatad/xcschemes/Pods-PrompterTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/Matthew.xcuserdatad/xcschemes/Quick.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 45 | 46 | 52 | 53 | 55 | 56 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Pods/Pods.xcodeproj/xcuserdata/Matthew.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Nimble.xcscheme 8 | 9 | isShown 10 | 11 | 12 | Pods-PrompterTests.xcscheme 13 | 14 | isShown 15 | 16 | 17 | Quick.xcscheme 18 | 19 | isShown 20 | 21 | 22 | 23 | SuppressBuildableAutocreation 24 | 25 | 020EBAB7DD661FE681BA334658EDA264 26 | 27 | primary 28 | 29 | 30 | B64A28649026D96850754695E9F7F50F 31 | 32 | primary 33 | 34 | 35 | C5DB5104FED3C10F78978AFC810982B9 36 | 37 | primary 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Callsite.swift: -------------------------------------------------------------------------------- 1 | /** 2 | An object encapsulating the file and line number at which 3 | a particular example is defined. 4 | */ 5 | final public class Callsite: NSObject { 6 | /** 7 | The absolute path of the file in which an example is defined. 8 | */ 9 | public let file: String 10 | 11 | /** 12 | The line number on which an example is defined. 13 | */ 14 | public let line: UInt 15 | 16 | internal init(file: String, line: UInt) { 17 | self.file = file 18 | self.line = line 19 | } 20 | } 21 | 22 | /** 23 | Returns a boolean indicating whether two Callsite objects are equal. 24 | If two callsites are in the same file and on the same line, they must be equal. 25 | */ 26 | public func ==(lhs: Callsite, rhs: Callsite) -> Bool { 27 | return lhs.file == rhs.file && lhs.line == rhs.line 28 | } 29 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Configuration/Configuration.swift: -------------------------------------------------------------------------------- 1 | /** 2 | A closure that temporarily exposes a Configuration object within 3 | the scope of the closure. 4 | */ 5 | public typealias QuickConfigurer = (configuration: Configuration) -> () 6 | 7 | /** 8 | A closure that, given metadata about an example, returns a boolean value 9 | indicating whether that example should be run. 10 | */ 11 | public typealias ExampleFilter = (example: Example) -> Bool 12 | 13 | /** 14 | A configuration encapsulates various options you can use 15 | to configure Quick's behavior. 16 | */ 17 | final public class Configuration: NSObject { 18 | internal let exampleHooks = ExampleHooks() 19 | internal let suiteHooks = SuiteHooks() 20 | internal var exclusionFilters: [ExampleFilter] = [{ example in 21 | if let pending = example.filterFlags[Filter.pending] { 22 | return pending 23 | } else { 24 | return false 25 | } 26 | }] 27 | internal var inclusionFilters: [ExampleFilter] = [{ example in 28 | if let focused = example.filterFlags[Filter.focused] { 29 | return focused 30 | } else { 31 | return false 32 | } 33 | }] 34 | 35 | /** 36 | Run all examples if none match the configured filters. True by default. 37 | */ 38 | public var runAllWhenEverythingFiltered = true 39 | 40 | /** 41 | Registers an inclusion filter. 42 | 43 | All examples are filtered using all inclusion filters. 44 | The remaining examples are run. If no examples remain, all examples are run. 45 | 46 | - parameter filter: A filter that, given an example, returns a value indicating 47 | whether that example should be included in the examples 48 | that are run. 49 | */ 50 | public func include(filter: ExampleFilter) { 51 | inclusionFilters.append(filter) 52 | } 53 | 54 | /** 55 | Registers an exclusion filter. 56 | 57 | All examples that remain after being filtered by the inclusion filters are 58 | then filtered via all exclusion filters. 59 | 60 | - parameter filter: A filter that, given an example, returns a value indicating 61 | whether that example should be excluded from the examples 62 | that are run. 63 | */ 64 | public func exclude(filter: ExampleFilter) { 65 | exclusionFilters.append(filter) 66 | } 67 | 68 | /** 69 | Identical to Quick.Configuration.beforeEach, except the closure is 70 | provided with metadata on the example that the closure is being run 71 | prior to. 72 | */ 73 | @objc(beforeEachWithMetadata:) 74 | public func beforeEach(closure: BeforeExampleWithMetadataClosure) { 75 | exampleHooks.appendBefore(closure) 76 | } 77 | 78 | /** 79 | Like Quick.DSL.beforeEach, this configures Quick to execute the 80 | given closure before each example that is run. The closure 81 | passed to this method is executed before each example Quick runs, 82 | globally across the test suite. You may call this method multiple 83 | times across mulitple +[QuickConfigure configure:] methods in order 84 | to define several closures to run before each example. 85 | 86 | Note that, since Quick makes no guarantee as to the order in which 87 | +[QuickConfiguration configure:] methods are evaluated, there is no 88 | guarantee as to the order in which beforeEach closures are evaluated 89 | either. Mulitple beforeEach defined on a single configuration, however, 90 | will be executed in the order they're defined. 91 | 92 | - parameter closure: The closure to be executed before each example 93 | in the test suite. 94 | */ 95 | public func beforeEach(closure: BeforeExampleClosure) { 96 | exampleHooks.appendBefore(closure) 97 | } 98 | 99 | /** 100 | Identical to Quick.Configuration.afterEach, except the closure 101 | is provided with metadata on the example that the closure is being 102 | run after. 103 | */ 104 | @objc(afterEachWithMetadata:) 105 | public func afterEach(closure: AfterExampleWithMetadataClosure) { 106 | exampleHooks.appendAfter(closure) 107 | } 108 | 109 | /** 110 | Like Quick.DSL.afterEach, this configures Quick to execute the 111 | given closure after each example that is run. The closure 112 | passed to this method is executed after each example Quick runs, 113 | globally across the test suite. You may call this method multiple 114 | times across mulitple +[QuickConfigure configure:] methods in order 115 | to define several closures to run after each example. 116 | 117 | Note that, since Quick makes no guarantee as to the order in which 118 | +[QuickConfiguration configure:] methods are evaluated, there is no 119 | guarantee as to the order in which afterEach closures are evaluated 120 | either. Mulitple afterEach defined on a single configuration, however, 121 | will be executed in the order they're defined. 122 | 123 | - parameter closure: The closure to be executed before each example 124 | in the test suite. 125 | */ 126 | public func afterEach(closure: AfterExampleClosure) { 127 | exampleHooks.appendAfter(closure) 128 | } 129 | 130 | /** 131 | Like Quick.DSL.beforeSuite, this configures Quick to execute 132 | the given closure prior to any and all examples that are run. 133 | The two methods are functionally equivalent. 134 | */ 135 | public func beforeSuite(closure: BeforeSuiteClosure) { 136 | suiteHooks.appendBefore(closure) 137 | } 138 | 139 | /** 140 | Like Quick.DSL.afterSuite, this configures Quick to execute 141 | the given closure after all examples have been run. 142 | The two methods are functionally equivalent. 143 | */ 144 | public func afterSuite(closure: AfterSuiteClosure) { 145 | suiteHooks.appendAfter(closure) 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Configuration/QuickConfiguration.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class Configuration; 4 | 5 | /** 6 | Subclass QuickConfiguration and override the +[QuickConfiguration configure:] 7 | method in order to configure how Quick behaves when running specs, or to define 8 | shared examples that are used across spec files. 9 | */ 10 | @interface QuickConfiguration : NSObject 11 | 12 | /** 13 | This method is executed on each subclass of this class before Quick runs 14 | any examples. You may override this method on as many subclasses as you like, but 15 | there is no guarantee as to the order in which these methods are executed. 16 | 17 | You can override this method in order to: 18 | 19 | 1. Configure how Quick behaves, by modifying properties on the Configuration object. 20 | Setting the same properties in several methods has undefined behavior. 21 | 22 | 2. Define shared examples using `sharedExamples`. 23 | 24 | @param configuration A mutable object that is used to configure how Quick behaves on 25 | a framework level. For details on all the options, see the 26 | documentation in Configuration.swift. 27 | */ 28 | + (void)configure:(Configuration *)configuration; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Configuration/QuickConfiguration.m: -------------------------------------------------------------------------------- 1 | #import "QuickConfiguration.h" 2 | #import "World.h" 3 | #import 4 | 5 | typedef void (^QCKClassEnumerationBlock)(Class klass); 6 | 7 | /** 8 | Finds all direct subclasses of the given class and passes them to the block provided. 9 | The classes are iterated over in the order that objc_getClassList returns them. 10 | 11 | @param klass The base class to find subclasses of. 12 | @param block A block that takes a Class. This block will be executed once for each subclass of klass. 13 | */ 14 | void qck_enumerateSubclasses(Class klass, QCKClassEnumerationBlock block) { 15 | Class *classes = NULL; 16 | int classesCount = objc_getClassList(NULL, 0); 17 | 18 | if (classesCount > 0) { 19 | classes = (Class *)calloc(sizeof(Class), classesCount); 20 | classesCount = objc_getClassList(classes, classesCount); 21 | 22 | Class subclass, superclass; 23 | for(int i = 0; i < classesCount; i++) { 24 | subclass = classes[i]; 25 | superclass = class_getSuperclass(subclass); 26 | if (superclass == klass && block) { 27 | block(subclass); 28 | } 29 | } 30 | 31 | free(classes); 32 | } 33 | } 34 | 35 | @implementation QuickConfiguration 36 | 37 | #pragma mark - Object Lifecycle 38 | 39 | /** 40 | QuickConfiguration is not meant to be instantiated; it merely provides a hook 41 | for users to configure how Quick behaves. Raise an exception if an instance of 42 | QuickConfiguration is created. 43 | */ 44 | - (instancetype)init { 45 | NSString *className = NSStringFromClass([self class]); 46 | NSString *selectorName = NSStringFromSelector(@selector(configure:)); 47 | [NSException raise:NSInternalInconsistencyException 48 | format:@"%@ is not meant to be instantiated; " 49 | @"subclass %@ and override %@ to configure Quick.", 50 | className, className, selectorName]; 51 | return nil; 52 | } 53 | 54 | #pragma mark - NSObject Overrides 55 | 56 | /** 57 | Hook into when QuickConfiguration is initialized in the runtime in order to 58 | call +[QuickConfiguration configure:] on each of its subclasses. 59 | */ 60 | + (void)initialize { 61 | // Only enumerate over the subclasses of QuickConfiguration, not any of its subclasses. 62 | if ([self class] == [QuickConfiguration class]) { 63 | 64 | // Only enumerate over subclasses once, even if +[QuickConfiguration initialize] 65 | // were to be called several times. This is necessary because +[QuickSpec initialize] 66 | // manually calls +[QuickConfiguration initialize]. 67 | static dispatch_once_t onceToken; 68 | dispatch_once(&onceToken, ^{ 69 | qck_enumerateSubclasses([QuickConfiguration class], ^(__unsafe_unretained Class klass) { 70 | [[World sharedWorld] configure:^(Configuration *configuration) { 71 | [klass configure:configuration]; 72 | }]; 73 | }); 74 | [[World sharedWorld] finalizeConfiguration]; 75 | }); 76 | } 77 | } 78 | 79 | #pragma mark - Public Interface 80 | 81 | + (void)configure:(Configuration *)configuration { } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/DSL/QCKDSL.m: -------------------------------------------------------------------------------- 1 | #import "QCKDSL.h" 2 | #import "World.h" 3 | #import "World+DSL.h" 4 | 5 | void qck_beforeSuite(QCKDSLEmptyBlock closure) { 6 | [[World sharedWorld] beforeSuite:closure]; 7 | } 8 | 9 | void qck_afterSuite(QCKDSLEmptyBlock closure) { 10 | [[World sharedWorld] afterSuite:closure]; 11 | } 12 | 13 | void qck_sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure) { 14 | [[World sharedWorld] sharedExamples:name closure:closure]; 15 | } 16 | 17 | void qck_describe(NSString *description, QCKDSLEmptyBlock closure) { 18 | [[World sharedWorld] describe:description flags:@{} closure:closure]; 19 | } 20 | 21 | void qck_context(NSString *description, QCKDSLEmptyBlock closure) { 22 | qck_describe(description, closure); 23 | } 24 | 25 | void qck_beforeEach(QCKDSLEmptyBlock closure) { 26 | [[World sharedWorld] beforeEach:closure]; 27 | } 28 | 29 | void qck_beforeEachWithMetadata(QCKDSLExampleMetadataBlock closure) { 30 | [[World sharedWorld] beforeEachWithMetadata:closure]; 31 | } 32 | 33 | void qck_afterEach(QCKDSLEmptyBlock closure) { 34 | [[World sharedWorld] afterEach:closure]; 35 | } 36 | 37 | void qck_afterEachWithMetadata(QCKDSLExampleMetadataBlock closure) { 38 | [[World sharedWorld] afterEachWithMetadata:closure]; 39 | } 40 | 41 | QCKItBlock qck_it_builder(NSDictionary *flags, NSString *file, NSUInteger line) { 42 | return ^(NSString *description, QCKDSLEmptyBlock closure) { 43 | [[World sharedWorld] itWithDescription:description 44 | flags:flags 45 | file:file 46 | line:line 47 | closure:closure]; 48 | }; 49 | } 50 | 51 | QCKItBehavesLikeBlock qck_itBehavesLike_builder(NSDictionary *flags, NSString *file, NSUInteger line) { 52 | return ^(NSString *name, QCKDSLSharedExampleContext context) { 53 | [[World sharedWorld] itBehavesLikeSharedExampleNamed:name 54 | sharedExampleContext:context 55 | flags:flags 56 | file:file 57 | line:line]; 58 | }; 59 | } 60 | 61 | void qck_pending(NSString *description, QCKDSLEmptyBlock closure) { 62 | [[World sharedWorld] pending:description closure:closure]; 63 | } 64 | 65 | void qck_xdescribe(NSString *description, QCKDSLEmptyBlock closure) { 66 | [[World sharedWorld] xdescribe:description flags:@{} closure:closure]; 67 | } 68 | 69 | void qck_xcontext(NSString *description, QCKDSLEmptyBlock closure) { 70 | qck_xdescribe(description, closure); 71 | } 72 | 73 | void qck_fdescribe(NSString *description, QCKDSLEmptyBlock closure) { 74 | [[World sharedWorld] fdescribe:description flags:@{} closure:closure]; 75 | } 76 | 77 | void qck_fcontext(NSString *description, QCKDSLEmptyBlock closure) { 78 | qck_fdescribe(description, closure); 79 | } 80 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/DSL/World+DSL.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface World (SWIFT_EXTENSION(Quick)) 4 | - (void)beforeSuite:(void (^ __nonnull)(void))closure; 5 | - (void)afterSuite:(void (^ __nonnull)(void))closure; 6 | - (void)sharedExamples:(NSString * __nonnull)name closure:(void (^ __nonnull)(NSDictionary * __nonnull (^ __nonnull)(void)))closure; 7 | - (void)describe:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure; 8 | - (void)context:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure; 9 | - (void)fdescribe:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure; 10 | - (void)xdescribe:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags closure:(void (^ __nonnull)(void))closure; 11 | - (void)beforeEach:(void (^ __nonnull)(void))closure; 12 | - (void)beforeEachWithMetadata:(void (^ __nonnull)(ExampleMetadata * __nonnull))closure; 13 | - (void)afterEach:(void (^ __nonnull)(void))closure; 14 | - (void)afterEachWithMetadata:(void (^ __nonnull)(ExampleMetadata * __nonnull))closure; 15 | - (void)itWithDescription:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line closure:(void (^ __nonnull)(void))closure; 16 | - (void)fitWithDescription:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line closure:(void (^ __nonnull)(void))closure; 17 | - (void)xitWithDescription:(NSString * __nonnull)description flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line closure:(void (^ __nonnull)(void))closure; 18 | - (void)itBehavesLikeSharedExampleNamed:(NSString * __nonnull)name sharedExampleContext:(NSDictionary * __nonnull (^ __nonnull)(void))sharedExampleContext flags:(NSDictionary * __nonnull)flags file:(NSString * __nonnull)file line:(NSUInteger)line; 19 | - (void)pending:(NSString * __nonnull)description closure:(void (^ __nonnull)(void))closure; 20 | @end 21 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/DSL/World+DSL.swift: -------------------------------------------------------------------------------- 1 | /** 2 | Adds methods to World to support top-level DSL functions (Swift) and 3 | macros (Objective-C). These functions map directly to the DSL that test 4 | writers use in their specs. 5 | */ 6 | extension World { 7 | internal func beforeSuite(closure: BeforeSuiteClosure) { 8 | suiteHooks.appendBefore(closure) 9 | } 10 | 11 | internal func afterSuite(closure: AfterSuiteClosure) { 12 | suiteHooks.appendAfter(closure) 13 | } 14 | 15 | internal func sharedExamples(name: String, closure: SharedExampleClosure) { 16 | registerSharedExample(name, closure: closure) 17 | } 18 | 19 | internal func describe(description: String, flags: FilterFlags, closure: () -> ()) { 20 | let group = ExampleGroup(description: description, flags: flags) 21 | currentExampleGroup!.appendExampleGroup(group) 22 | currentExampleGroup = group 23 | closure() 24 | currentExampleGroup = group.parent 25 | } 26 | 27 | internal func context(description: String, flags: FilterFlags, closure: () -> ()) { 28 | self.describe(description, flags: flags, closure: closure) 29 | } 30 | 31 | internal func fdescribe(description: String, flags: FilterFlags, closure: () -> ()) { 32 | var focusedFlags = flags 33 | focusedFlags[Filter.focused] = true 34 | self.describe(description, flags: focusedFlags, closure: closure) 35 | } 36 | 37 | internal func xdescribe(description: String, flags: FilterFlags, closure: () -> ()) { 38 | var pendingFlags = flags 39 | pendingFlags[Filter.pending] = true 40 | self.describe(description, flags: pendingFlags, closure: closure) 41 | } 42 | 43 | internal func beforeEach(closure: BeforeExampleClosure) { 44 | currentExampleGroup!.hooks.appendBefore(closure) 45 | } 46 | 47 | @objc(beforeEachWithMetadata:) 48 | internal func beforeEach(closure closure: BeforeExampleWithMetadataClosure) { 49 | currentExampleGroup!.hooks.appendBefore(closure) 50 | } 51 | 52 | internal func afterEach(closure: AfterExampleClosure) { 53 | currentExampleGroup!.hooks.appendAfter(closure) 54 | } 55 | 56 | @objc(afterEachWithMetadata:) 57 | internal func afterEach(closure closure: AfterExampleWithMetadataClosure) { 58 | currentExampleGroup!.hooks.appendAfter(closure) 59 | } 60 | 61 | @objc(itWithDescription:flags:file:line:closure:) 62 | internal func it(description: String, flags: FilterFlags, file: String, line: UInt, closure: () -> ()) { 63 | let callsite = Callsite(file: file, line: line) 64 | let example = Example(description: description, callsite: callsite, flags: flags, closure: closure) 65 | currentExampleGroup!.appendExample(example) 66 | } 67 | 68 | @objc(fitWithDescription:flags:file:line:closure:) 69 | internal func fit(description: String, flags: FilterFlags, file: String, line: UInt, closure: () -> ()) { 70 | var focusedFlags = flags 71 | focusedFlags[Filter.focused] = true 72 | self.it(description, flags: focusedFlags, file: file, line: line, closure: closure) 73 | } 74 | 75 | @objc(xitWithDescription:flags:file:line:closure:) 76 | internal func xit(description: String, flags: FilterFlags, file: String, line: UInt, closure: () -> ()) { 77 | var pendingFlags = flags 78 | pendingFlags[Filter.pending] = true 79 | self.it(description, flags: pendingFlags, file: file, line: line, closure: closure) 80 | } 81 | 82 | @objc(itBehavesLikeSharedExampleNamed:sharedExampleContext:flags:file:line:) 83 | internal func itBehavesLike(name: String, sharedExampleContext: SharedExampleContext, flags: FilterFlags, file: String, line: UInt) { 84 | let callsite = Callsite(file: file, line: line) 85 | let closure = World.sharedWorld().sharedExample(name) 86 | 87 | let group = ExampleGroup(description: name, flags: flags) 88 | currentExampleGroup!.appendExampleGroup(group) 89 | currentExampleGroup = group 90 | closure(sharedExampleContext) 91 | currentExampleGroup!.walkDownExamples { (example: Example) in 92 | example.isSharedExample = true 93 | example.callsite = callsite 94 | } 95 | 96 | currentExampleGroup = group.parent 97 | } 98 | 99 | internal func pending(description: String, closure: () -> ()) { 100 | print("Pending: \(description)") 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Example.swift: -------------------------------------------------------------------------------- 1 | private var numberOfExamplesRun = 0 2 | 3 | /** 4 | Examples, defined with the `it` function, use assertions to 5 | demonstrate how code should behave. These are like "tests" in XCTest. 6 | */ 7 | final public class Example: NSObject { 8 | /** 9 | A boolean indicating whether the example is a shared example; 10 | i.e.: whether it is an example defined with `itBehavesLike`. 11 | */ 12 | public var isSharedExample = false 13 | 14 | /** 15 | The site at which the example is defined. 16 | This must be set correctly in order for Xcode to highlight 17 | the correct line in red when reporting a failure. 18 | */ 19 | public var callsite: Callsite 20 | 21 | weak internal var group: ExampleGroup? 22 | 23 | private let internalDescription: String 24 | private let closure: () -> () 25 | private let flags: FilterFlags 26 | 27 | internal init(description: String, callsite: Callsite, flags: FilterFlags, closure: () -> ()) { 28 | self.internalDescription = description 29 | self.closure = closure 30 | self.callsite = callsite 31 | self.flags = flags 32 | } 33 | 34 | public override var description: String { 35 | return internalDescription 36 | } 37 | 38 | /** 39 | The example name. A name is a concatenation of the name of 40 | the example group the example belongs to, followed by the 41 | description of the example itself. 42 | 43 | The example name is used to generate a test method selector 44 | to be displayed in Xcode's test navigator. 45 | */ 46 | public var name: String { 47 | switch group!.name { 48 | case .Some(let groupName): return "\(groupName), \(description)" 49 | case .None: return description 50 | } 51 | } 52 | 53 | /** 54 | Executes the example closure, as well as all before and after 55 | closures defined in the its surrounding example groups. 56 | */ 57 | public func run() { 58 | let world = World.sharedWorld() 59 | 60 | if numberOfExamplesRun == 0 { 61 | world.suiteHooks.executeBefores() 62 | } 63 | 64 | let exampleMetadata = ExampleMetadata(example: self, exampleIndex: numberOfExamplesRun) 65 | world.currentExampleMetadata = exampleMetadata 66 | 67 | world.exampleHooks.executeBefores(exampleMetadata) 68 | for before in group!.befores { 69 | before(exampleMetadata: exampleMetadata) 70 | } 71 | 72 | closure() 73 | 74 | for after in group!.afters { 75 | after(exampleMetadata: exampleMetadata) 76 | } 77 | world.exampleHooks.executeAfters(exampleMetadata) 78 | 79 | ++numberOfExamplesRun 80 | 81 | if !world.isRunningAdditionalSuites && numberOfExamplesRun >= world.exampleCount { 82 | world.suiteHooks.executeAfters() 83 | } 84 | } 85 | 86 | /** 87 | Evaluates the filter flags set on this example and on the example groups 88 | this example belongs to. Flags set on the example are trumped by flags on 89 | the example group it belongs to. Flags on inner example groups are trumped 90 | by flags on outer example groups. 91 | */ 92 | internal var filterFlags: FilterFlags { 93 | var aggregateFlags = flags 94 | for (key, value) in group!.filterFlags { 95 | aggregateFlags[key] = value 96 | } 97 | return aggregateFlags 98 | } 99 | } 100 | 101 | /** 102 | Returns a boolean indicating whether two Example objects are equal. 103 | If two examples are defined at the exact same callsite, they must be equal. 104 | */ 105 | public func ==(lhs: Example, rhs: Example) -> Bool { 106 | return lhs.callsite == rhs.callsite 107 | } 108 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/ExampleGroup.swift: -------------------------------------------------------------------------------- 1 | /** 2 | Example groups are logical groupings of examples, defined with 3 | the `describe` and `context` functions. Example groups can share 4 | setup and teardown code. 5 | */ 6 | final public class ExampleGroup: NSObject { 7 | weak internal var parent: ExampleGroup? 8 | internal let hooks = ExampleHooks() 9 | 10 | private let internalDescription: String 11 | private let flags: FilterFlags 12 | private let isInternalRootExampleGroup: Bool 13 | private var childGroups = [ExampleGroup]() 14 | private var childExamples = [Example]() 15 | 16 | internal init(description: String, flags: FilterFlags, isInternalRootExampleGroup: Bool = false) { 17 | self.internalDescription = description 18 | self.flags = flags 19 | self.isInternalRootExampleGroup = isInternalRootExampleGroup 20 | } 21 | 22 | public override var description: String { 23 | return internalDescription 24 | } 25 | 26 | /** 27 | Returns a list of examples that belong to this example group, 28 | or to any of its descendant example groups. 29 | */ 30 | public var examples: [Example] { 31 | var examples = childExamples 32 | for group in childGroups { 33 | examples.appendContentsOf(group.examples) 34 | } 35 | return examples 36 | } 37 | 38 | internal var name: String? { 39 | if let parent = parent { 40 | switch(parent.name) { 41 | case .Some(let name): return "\(name), \(description)" 42 | case .None: return description 43 | } 44 | } else { 45 | return isInternalRootExampleGroup ? nil : description 46 | } 47 | } 48 | 49 | internal var filterFlags: FilterFlags { 50 | var aggregateFlags = flags 51 | walkUp() { (group: ExampleGroup) -> () in 52 | for (key, value) in group.flags { 53 | aggregateFlags[key] = value 54 | } 55 | } 56 | return aggregateFlags 57 | } 58 | 59 | internal var befores: [BeforeExampleWithMetadataClosure] { 60 | var closures = Array(hooks.befores.reverse()) 61 | walkUp() { (group: ExampleGroup) -> () in 62 | closures.appendContentsOf(Array(group.hooks.befores.reverse())) 63 | } 64 | return Array(closures.reverse()) 65 | } 66 | 67 | internal var afters: [AfterExampleWithMetadataClosure] { 68 | var closures = hooks.afters 69 | walkUp() { (group: ExampleGroup) -> () in 70 | closures.appendContentsOf(group.hooks.afters) 71 | } 72 | return closures 73 | } 74 | 75 | internal func walkDownExamples(callback: (example: Example) -> ()) { 76 | for example in childExamples { 77 | callback(example: example) 78 | } 79 | for group in childGroups { 80 | group.walkDownExamples(callback) 81 | } 82 | } 83 | 84 | internal func appendExampleGroup(group: ExampleGroup) { 85 | group.parent = self 86 | childGroups.append(group) 87 | } 88 | 89 | internal func appendExample(example: Example) { 90 | example.group = self 91 | childExamples.append(example) 92 | } 93 | 94 | private func walkUp(callback: (group: ExampleGroup) -> ()) { 95 | var group = self 96 | while let parent = group.parent { 97 | callback(group: parent) 98 | group = parent 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/ExampleMetadata.swift: -------------------------------------------------------------------------------- 1 | /** 2 | A class that encapsulates information about an example, 3 | including the index at which the example was executed, as 4 | well as the example itself. 5 | */ 6 | final public class ExampleMetadata: NSObject { 7 | /** 8 | The example for which this metadata was collected. 9 | */ 10 | public let example: Example 11 | 12 | /** 13 | The index at which this example was executed in the 14 | test suite. 15 | */ 16 | public let exampleIndex: Int 17 | 18 | internal init(example: Example, exampleIndex: Int) { 19 | self.example = example 20 | self.exampleIndex = exampleIndex 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Filter.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /** 4 | A mapping of string keys to booleans that can be used to 5 | filter examples or example groups. For example, a "focused" 6 | example would have the flags [Focused: true]. 7 | */ 8 | public typealias FilterFlags = [String: Bool] 9 | 10 | /** 11 | A namespace for filter flag keys, defined primarily to make the 12 | keys available in Objective-C. 13 | */ 14 | final public class Filter: NSObject { 15 | /** 16 | Example and example groups with [Focused: true] are included in test runs, 17 | excluding all other examples without this flag. Use this to only run one or 18 | two tests that you're currently focusing on. 19 | */ 20 | public class var focused: String { 21 | return "focused" 22 | } 23 | 24 | /** 25 | Example and example groups with [Pending: true] are excluded from test runs. 26 | Use this to temporarily suspend examples that you know do not pass yet. 27 | */ 28 | public class var pending: String { 29 | return "pending" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Hooks/Closures.swift: -------------------------------------------------------------------------------- 1 | // MARK: Example Hooks 2 | 3 | /** 4 | A closure executed before an example is run. 5 | */ 6 | public typealias BeforeExampleClosure = () -> () 7 | 8 | /** 9 | A closure executed before an example is run. The closure is given example metadata, 10 | which contains information about the example that is about to be run. 11 | */ 12 | public typealias BeforeExampleWithMetadataClosure = (exampleMetadata: ExampleMetadata) -> () 13 | 14 | /** 15 | A closure executed after an example is run. 16 | */ 17 | public typealias AfterExampleClosure = BeforeExampleClosure 18 | 19 | /** 20 | A closure executed after an example is run. The closure is given example metadata, 21 | which contains information about the example that has just finished running. 22 | */ 23 | public typealias AfterExampleWithMetadataClosure = BeforeExampleWithMetadataClosure 24 | 25 | // MARK: Suite Hooks 26 | 27 | /** 28 | A closure executed before any examples are run. 29 | */ 30 | public typealias BeforeSuiteClosure = () -> () 31 | 32 | /** 33 | A closure executed after all examples have finished running. 34 | */ 35 | public typealias AfterSuiteClosure = BeforeSuiteClosure 36 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Hooks/ExampleHooks.swift: -------------------------------------------------------------------------------- 1 | /** 2 | A container for closures to be executed before and after each example. 3 | */ 4 | final internal class ExampleHooks { 5 | 6 | internal var befores: [BeforeExampleWithMetadataClosure] = [] 7 | internal var afters: [AfterExampleWithMetadataClosure] = [] 8 | 9 | internal func appendBefore(closure: BeforeExampleWithMetadataClosure) { 10 | befores.append(closure) 11 | } 12 | 13 | internal func appendBefore(closure: BeforeExampleClosure) { 14 | befores.append { (exampleMetadata: ExampleMetadata) in closure() } 15 | } 16 | 17 | internal func appendAfter(closure: AfterExampleWithMetadataClosure) { 18 | afters.append(closure) 19 | } 20 | 21 | internal func appendAfter(closure: AfterExampleClosure) { 22 | afters.append { (exampleMetadata: ExampleMetadata) in closure() } 23 | } 24 | 25 | internal func executeBefores(exampleMetadata: ExampleMetadata) { 26 | for before in befores { 27 | before(exampleMetadata: exampleMetadata) 28 | } 29 | } 30 | 31 | internal func executeAfters(exampleMetadata: ExampleMetadata) { 32 | for after in afters { 33 | after(exampleMetadata: exampleMetadata) 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Hooks/SuiteHooks.swift: -------------------------------------------------------------------------------- 1 | /** 2 | A container for closures to be executed before and after all examples. 3 | */ 4 | final internal class SuiteHooks { 5 | internal var befores: [BeforeSuiteClosure] = [] 6 | internal var beforesAlreadyExecuted = false 7 | 8 | internal var afters: [AfterSuiteClosure] = [] 9 | internal var aftersAlreadyExecuted = false 10 | 11 | internal func appendBefore(closure: BeforeSuiteClosure) { 12 | befores.append(closure) 13 | } 14 | 15 | internal func appendAfter(closure: AfterSuiteClosure) { 16 | afters.append(closure) 17 | } 18 | 19 | internal func executeBefores() { 20 | assert(!beforesAlreadyExecuted) 21 | for before in befores { 22 | before() 23 | } 24 | beforesAlreadyExecuted = true 25 | } 26 | 27 | internal func executeAfters() { 28 | assert(!aftersAlreadyExecuted) 29 | for after in afters { 30 | after() 31 | } 32 | aftersAlreadyExecuted = true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/NSString+QCKSelectorName.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | QuickSpec converts example names into test methods. 5 | Those test methods need valid selector names, which means no whitespace, 6 | control characters, etc. This category gives NSString objects an easy way 7 | to replace those illegal characters with underscores. 8 | */ 9 | @interface NSString (QCKSelectorName) 10 | 11 | /** 12 | Returns a string with underscores in place of all characters that cannot 13 | be included in a selector (SEL) name. 14 | */ 15 | @property (nonatomic, readonly) NSString *qck_selectorName; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/NSString+QCKSelectorName.m: -------------------------------------------------------------------------------- 1 | #import "NSString+QCKSelectorName.h" 2 | 3 | @implementation NSString (QCKSelectorName) 4 | 5 | - (NSString *)qck_selectorName { 6 | static NSMutableCharacterSet *invalidCharacters = nil; 7 | static dispatch_once_t onceToken; 8 | dispatch_once(&onceToken, ^{ 9 | invalidCharacters = [NSMutableCharacterSet new]; 10 | 11 | NSCharacterSet *whitespaceCharacterSet = [NSCharacterSet whitespaceCharacterSet]; 12 | NSCharacterSet *newlineCharacterSet = [NSCharacterSet newlineCharacterSet]; 13 | NSCharacterSet *illegalCharacterSet = [NSCharacterSet illegalCharacterSet]; 14 | NSCharacterSet *controlCharacterSet = [NSCharacterSet controlCharacterSet]; 15 | NSCharacterSet *punctuationCharacterSet = [NSCharacterSet punctuationCharacterSet]; 16 | NSCharacterSet *nonBaseCharacterSet = [NSCharacterSet nonBaseCharacterSet]; 17 | NSCharacterSet *symbolCharacterSet = [NSCharacterSet symbolCharacterSet]; 18 | 19 | [invalidCharacters formUnionWithCharacterSet:whitespaceCharacterSet]; 20 | [invalidCharacters formUnionWithCharacterSet:newlineCharacterSet]; 21 | [invalidCharacters formUnionWithCharacterSet:illegalCharacterSet]; 22 | [invalidCharacters formUnionWithCharacterSet:controlCharacterSet]; 23 | [invalidCharacters formUnionWithCharacterSet:punctuationCharacterSet]; 24 | [invalidCharacters formUnionWithCharacterSet:nonBaseCharacterSet]; 25 | [invalidCharacters formUnionWithCharacterSet:symbolCharacterSet]; 26 | }); 27 | 28 | NSArray *validComponents = [self componentsSeparatedByCharactersInSet:invalidCharacters]; 29 | 30 | return [validComponents componentsJoinedByString:@"_"]; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/Quick.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | //! Project version number for Quick. 4 | FOUNDATION_EXPORT double QuickVersionNumber; 5 | 6 | //! Project version string for Quick. 7 | FOUNDATION_EXPORT const unsigned char QuickVersionString[]; 8 | 9 | #import "QuickSpec.h" 10 | #import "QCKDSL.h" 11 | #import "QuickConfiguration.h" 12 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/QuickSpec.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | /** 4 | QuickSpec is a base class all specs written in Quick inherit from. 5 | They need to inherit from QuickSpec, a subclass of XCTestCase, in 6 | order to be discovered by the XCTest framework. 7 | 8 | XCTest automatically compiles a list of XCTestCase subclasses included 9 | in the test target. It iterates over each class in that list, and creates 10 | a new instance of that class for each test method. It then creates an 11 | "invocation" to execute that test method. The invocation is an instance of 12 | NSInvocation, which represents a single message send in Objective-C. 13 | The invocation is set on the XCTestCase instance, and the test is run. 14 | 15 | Most of the code in QuickSpec is dedicated to hooking into XCTest events. 16 | First, when the spec is first loaded and before it is sent any messages, 17 | the +[NSObject initialize] method is called. QuickSpec overrides this method 18 | to call +[QuickSpec spec]. This builds the example group stacks and 19 | registers them with Quick.World, a global register of examples. 20 | 21 | Then, XCTest queries QuickSpec for a list of test methods. Normally, XCTest 22 | automatically finds all methods whose selectors begin with the string "test". 23 | However, QuickSpec overrides this default behavior by implementing the 24 | +[XCTestCase testInvocations] method. This method iterates over each example 25 | registered in Quick.World, defines a new method for that example, and 26 | returns an invocation to call that method to XCTest. Those invocations are 27 | the tests that are run by XCTest. Their selector names are displayed in 28 | the Xcode test navigation bar. 29 | */ 30 | @interface QuickSpec : XCTestCase 31 | 32 | /** 33 | Override this method in your spec to define a set of example groups 34 | and examples. 35 | 36 | override class func spec() { 37 | describe("winter") { 38 | it("is coming") { 39 | // ... 40 | } 41 | } 42 | } 43 | 44 | See DSL.swift for more information on what syntax is available. 45 | */ 46 | - (void)spec; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /Pods/Quick/Quick/World.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @class ExampleGroup; 4 | @class ExampleMetadata; 5 | 6 | SWIFT_CLASS("_TtC5Quick5World") 7 | @interface World 8 | 9 | @property (nonatomic) ExampleGroup * __nullable currentExampleGroup; 10 | @property (nonatomic) ExampleMetadata * __nullable currentExampleMetadata; 11 | @property (nonatomic) BOOL isRunningAdditionalSuites; 12 | + (World * __nonnull)sharedWorld; 13 | - (void)configure:(void (^ __nonnull)(Configuration * __nonnull))closure; 14 | - (void)finalizeConfiguration; 15 | - (ExampleGroup * __nonnull)rootExampleGroupForSpecClass:(Class __nonnull)cls; 16 | - (NSArray * __nonnull)examplesForSpecClass:(Class __nonnull)specClass; 17 | @end 18 | -------------------------------------------------------------------------------- /Pods/Quick/README.md: -------------------------------------------------------------------------------- 1 | ![](http://f.cl.ly/items/0r1E192C1R0b2g2Q3h2w/QuickLogo_Color.png) 2 | 3 | Quick is a behavior-driven development framework for Swift and Objective-C. 4 | Inspired by [RSpec](https://github.com/rspec/rspec), [Specta](https://github.com/specta/specta), and [Ginkgo](https://github.com/onsi/ginkgo). 5 | 6 | ![](https://raw.githubusercontent.com/Quick/Assets/master/Screenshots/QuickSpec%20screenshot.png) 7 | 8 | ```swift 9 | // Swift 10 | 11 | import Quick 12 | import Nimble 13 | 14 | class TableOfContentsSpec: QuickSpec { 15 | override func spec() { 16 | describe("the 'Documentation' directory") { 17 | it("has everything you need to get started") { 18 | let sections = Directory("Documentation").sections 19 | expect(sections).to(contain("Organized Tests with Quick Examples and Example Groups")) 20 | expect(sections).to(contain("Installing Quick")) 21 | } 22 | 23 | context("if it doesn't have what you're looking for") { 24 | it("needs to be updated") { 25 | let you = You(awesome: true) 26 | expect{you.submittedAnIssue}.toEventually(beTruthy()) 27 | } 28 | } 29 | } 30 | } 31 | } 32 | ``` 33 | #### Nimble 34 | Quick comes together with [Nimble](https://github.com/Quick/Nimble) — a matcher framework for your tests. You can learn why `XCTAssert()` statements make your expectations unclear and how to fix that using Nimble assertions [here](./Documentation/NimbleAssertions.md). 35 | 36 | ## Documentation 37 | 38 | All documentation can be found in the [Documentation folder](./Documentation), including [detailed installation instructions](./Documentation/InstallingQuick.md) for CocoaPods, Carthage, Git submodules, and more. For example, you can install Quick and [Nimble](https://github.com/Quick/Nimble) using CocoaPods by adding the following to your Podfile: 39 | 40 | ```rb 41 | # Podfile 42 | 43 | use_frameworks! 44 | 45 | def testing_pods 46 | # If you're using Xcode 7 / Swift 2 47 | pod 'Quick', '~> 0.6.0' 48 | pod 'Nimble', '2.0.0-rc.3' 49 | 50 | # If you're using Xcode 6 / Swift 1.2 51 | pod 'Quick', '~> 0.3.0' 52 | pod 'Nimble', '~> 1.0.0' 53 | end 54 | 55 | target 'MyTests' do 56 | testing_pods 57 | end 58 | 59 | target 'MyUITests' do 60 | testing_pods 61 | end 62 | ``` 63 | 64 | ## License 65 | 66 | Apache 2.0 license. See the `LICENSE` file for details. 67 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Nimble/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 3.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Nimble/Nimble-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Nimble : NSObject 3 | @end 4 | @implementation PodsDummy_Nimble 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Nimble/Nimble-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Nimble/Nimble-umbrella.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "Nimble.h" 4 | #import "DSL.h" 5 | #import "NMBExceptionCapture.h" 6 | 7 | FOUNDATION_EXPORT double NimbleVersionNumber; 8 | FOUNDATION_EXPORT const unsigned char NimbleVersionString[]; 9 | 10 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Nimble/Nimble.modulemap: -------------------------------------------------------------------------------- 1 | framework module Nimble { 2 | umbrella header "Nimble-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Nimble/Nimble.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | ENABLE_BITCODE = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Nimble" "${PODS_ROOT}/Headers/Public" 6 | OTHER_LDFLAGS = -weak-lswiftXCTest -weak_framework "XCTest" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_ROOT = ${SRCROOT} 9 | SKIP_INSTALL = YES -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PrompterTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PrompterTests/Pods-PrompterTests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_PrompterTests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_PrompterTests 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PrompterTests/Pods-PrompterTests-frameworks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 6 | 7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" 8 | 9 | install_framework() 10 | { 11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then 12 | local source="${BUILT_PRODUCTS_DIR}/$1" 13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then 14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")" 15 | elif [ -r "$1" ]; then 16 | local source="$1" 17 | fi 18 | 19 | local destination="${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 20 | 21 | if [ -L "${source}" ]; then 22 | echo "Symlinked..." 23 | source="$(readlink "${source}")" 24 | fi 25 | 26 | # use filter instead of exclude so missing patterns dont' throw errors 27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\"" 28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}" 29 | 30 | local basename 31 | basename="$(basename -s .framework "$1")" 32 | binary="${destination}/${basename}.framework/${basename}" 33 | if ! [ -r "$binary" ]; then 34 | binary="${destination}/${basename}" 35 | fi 36 | 37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device 38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then 39 | strip_invalid_archs "$binary" 40 | fi 41 | 42 | # Resign the code if required by the build settings to avoid unstable apps 43 | code_sign_if_enabled "${destination}/$(basename "$1")" 44 | 45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7. 46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then 47 | local swift_runtime_libs 48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]}) 49 | for lib in $swift_runtime_libs; do 50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\"" 51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}" 52 | code_sign_if_enabled "${destination}/${lib}" 53 | done 54 | fi 55 | } 56 | 57 | # Signs a framework with the provided identity 58 | code_sign_if_enabled() { 59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then 60 | # Use the current code_sign_identitiy 61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}" 62 | echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \"$1\"" 63 | /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1" 64 | fi 65 | } 66 | 67 | # Strip invalid architectures 68 | strip_invalid_archs() { 69 | binary="$1" 70 | # Get architectures for current file 71 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)" 72 | stripped="" 73 | for arch in $archs; do 74 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then 75 | # Strip non-valid architectures in-place 76 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1 77 | stripped="$stripped $arch" 78 | fi 79 | done 80 | if [[ "$stripped" ]]; then 81 | echo "Stripped $binary of architectures:$stripped" 82 | fi 83 | } 84 | 85 | 86 | if [[ "$CONFIGURATION" == "Debug" ]]; then 87 | install_framework "Pods-PrompterTests/Nimble.framework" 88 | install_framework "Pods-PrompterTests/Quick.framework" 89 | fi 90 | if [[ "$CONFIGURATION" == "Release" ]]; then 91 | install_framework "Pods-PrompterTests/Nimble.framework" 92 | install_framework "Pods-PrompterTests/Quick.framework" 93 | fi 94 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PrompterTests/Pods-PrompterTests-resources.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 5 | 6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt 7 | > "$RESOURCES_TO_COPY" 8 | 9 | XCASSET_FILES=() 10 | 11 | realpath() { 12 | DIRECTORY="$(cd "${1%/*}" && pwd)" 13 | FILENAME="${1##*/}" 14 | echo "$DIRECTORY/$FILENAME" 15 | } 16 | 17 | install_resource() 18 | { 19 | case $1 in 20 | *.storyboard) 21 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 22 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .storyboard`.storyboardc" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 23 | ;; 24 | *.xib) 25 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib ${PODS_ROOT}/$1 --sdk ${SDKROOT}" 26 | ibtool --reference-external-strings-file --errors --warnings --notices --output-format human-readable-text --compile "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$1\" .xib`.nib" "${PODS_ROOT}/$1" --sdk "${SDKROOT}" 27 | ;; 28 | *.framework) 29 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 30 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 31 | echo "rsync -av ${PODS_ROOT}/$1 ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 32 | rsync -av "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" 33 | ;; 34 | *.xcdatamodel) 35 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1"`.mom\"" 36 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodel`.mom" 37 | ;; 38 | *.xcdatamodeld) 39 | echo "xcrun momc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd\"" 40 | xcrun momc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcdatamodeld`.momd" 41 | ;; 42 | *.xcmappingmodel) 43 | echo "xcrun mapc \"${PODS_ROOT}/$1\" \"${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm\"" 44 | xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm" 45 | ;; 46 | *.xcassets) 47 | ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1") 48 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE") 49 | ;; 50 | /*) 51 | echo "$1" 52 | echo "$1" >> "$RESOURCES_TO_COPY" 53 | ;; 54 | *) 55 | echo "${PODS_ROOT}/$1" 56 | echo "${PODS_ROOT}/$1" >> "$RESOURCES_TO_COPY" 57 | ;; 58 | esac 59 | } 60 | 61 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 62 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 63 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then 64 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 65 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 66 | fi 67 | rm -f "$RESOURCES_TO_COPY" 68 | 69 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ] 70 | then 71 | case "${TARGETED_DEVICE_FAMILY}" in 72 | 1,2) 73 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone" 74 | ;; 75 | 1) 76 | TARGET_DEVICE_ARGS="--target-device iphone" 77 | ;; 78 | 2) 79 | TARGET_DEVICE_ARGS="--target-device ipad" 80 | ;; 81 | *) 82 | TARGET_DEVICE_ARGS="--target-device mac" 83 | ;; 84 | esac 85 | 86 | # Find all other xcassets (this unfortunately includes those of path pods and other targets). 87 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d) 88 | while read line; do 89 | if [[ $line != "`realpath $PODS_ROOT`*" ]]; then 90 | XCASSET_FILES+=("$line") 91 | fi 92 | done <<<"$OTHER_XCASSETS" 93 | 94 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${IPHONEOS_DEPLOYMENT_TARGET}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" 95 | fi 96 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PrompterTests/Pods-PrompterTests-umbrella.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | 4 | FOUNDATION_EXPORT double Pods_PrompterTestsVersionNumber; 5 | FOUNDATION_EXPORT const unsigned char Pods_PrompterTestsVersionString[]; 6 | 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PrompterTests/Pods-PrompterTests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Nimble.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Quick.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "Nimble" -framework "Quick" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-PrompterTests 9 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PrompterTests/Pods-PrompterTests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_PrompterTests { 2 | umbrella header "Pods-PrompterTests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-PrompterTests/Pods-PrompterTests.release.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | EMBEDDED_CONTENT_CONTAINS_SWIFT = YES 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 5 | OTHER_CFLAGS = $(inherited) -iquote "$CONFIGURATION_BUILD_DIR/Nimble.framework/Headers" -iquote "$CONFIGURATION_BUILD_DIR/Quick.framework/Headers" 6 | OTHER_LDFLAGS = $(inherited) -framework "Nimble" -framework "Quick" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-PrompterTests 9 | PODS_ROOT = ${SRCROOT}/Pods -------------------------------------------------------------------------------- /Pods/Target Support Files/Quick/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.8.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Quick/Quick-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Quick : NSObject 3 | @end 4 | @implementation PodsDummy_Quick 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Quick/Quick-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #endif 4 | 5 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Quick/Quick-umbrella.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | #import "QuickConfiguration.h" 4 | #import "QCKDSL.h" 5 | #import "Quick.h" 6 | #import "QuickSpec.h" 7 | 8 | FOUNDATION_EXPORT double QuickVersionNumber; 9 | FOUNDATION_EXPORT const unsigned char QuickVersionString[]; 10 | 11 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Quick/Quick.modulemap: -------------------------------------------------------------------------------- 1 | framework module Quick { 2 | umbrella header "Quick-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Quick/Quick.xcconfig: -------------------------------------------------------------------------------- 1 | CODE_SIGN_IDENTITY = 2 | ENABLE_BITCODE = NO 3 | FRAMEWORK_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Quick" "${PODS_ROOT}/Headers/Public" 6 | OTHER_LDFLAGS = -framework "XCTest" 7 | OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS" 8 | PODS_ROOT = ${SRCROOT} 9 | SKIP_INSTALL = YES -------------------------------------------------------------------------------- /Prompter.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "Prompter" 4 | s.version = "0.1.2" 5 | s.summary = "Light weight helpers for developing interactive command line (cli) scripts in Swift." 6 | s.license = { :type => "MIT", :file => "LICENSE.md" } 7 | s.author = { "Matthew Clarkson" => "mpclarkson@gmail.com" } 8 | s.social_media_url = "http://twitter.com/matt_clarkson" 9 | s.platform = :osx, "10.11" 10 | s.requires_arc = true 11 | s.source = { :git => "https://github.com/mpclarkson/Prompter.git", :tag => s.version.to_s } 12 | s.homepage = 'https://github.com/mpclarkson/Prompter' 13 | s.source_files = 'Source/*.{swift}' 14 | s.documentation_url = 'http://mpclarkson.github.io/Prompter/' 15 | 16 | end 17 | -------------------------------------------------------------------------------- /Prompter.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Prompter.xcodeproj/xcuserdata/Matthew.xcuserdatad/xcschemes/Prompter.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 64 | 65 | 71 | 72 | 73 | 74 | 75 | 76 | 82 | 83 | 89 | 90 | 91 | 92 | 94 | 95 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Prompter.xcodeproj/xcuserdata/Matthew.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Prompter.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 34B78D7A1C44A60F009E364E 16 | 17 | primary 18 | 19 | 20 | 34B78D841C44A610009E364E 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Prompter.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Prompter - Capture Command Line Input with Swift 2 | 3 | [![CI Status](http://img.shields.io/travis/mpclarkson/Prompter.svg?style=flat)](https://travis-ci.org/hilenium/Prompter) 4 | [![Version](https://img.shields.io/cocoapods/v/Prompter.svg?style=flat)](http://cocoapods.org/pods/Prompter) 5 | [![License](https://img.shields.io/cocoapods/l/Prompter.svg?style=flat)](http://cocoapods.org/pods/Prompter) 6 | [![Platform](https://img.shields.io/cocoapods/p/Prompter.svg?style=flat)](http://cocoapods.org/pods/Prompter) 7 | 8 | Prompter is lightweight Swift 2+ library that greatly simplifies capturing user input for command line (cli) applications on OSX and Linux. 9 | 10 | Specifically, it allows you to prompt the user for input and validate that responses are (currently) `String`, `Int`, `Bool`, or a valid single choice from a given list. 11 | 12 | ## Installation 13 | 14 | ### Swift Package Manager 15 | 16 | To add Prompter via the SPM, add the following to your `Package.swift` file: 17 | 18 | ```swift 19 | let package = Package( 20 | name: "YourPackageName" 21 | dependencies: [ 22 | .Package(url: "https://github.com/mpclarkson/Prompter.git", majorVersion: 1), 23 | ] 24 | ) 25 | ``` 26 | 27 | ### CocoaPods 28 | 29 | Prompter is available through [CocoaPods](http://cocoapods.org). 30 | 31 | To install it, simply add the following line to your Podfile: 32 | 33 | ```ruby 34 | pod "Prompter" 35 | ``` 36 | 37 | ## Instructions 38 | 39 | ### Documentation 40 | This library is well documented. View the [documentation](https://mpclarkson.github.io/Prompter/). 41 | 42 | ### Overview 43 | 44 | Each `ask` method includes the following arguments: 45 | - `question` - required 46 | - `message` - optional string to override the default validation message 47 | - `block` - an optional closure that is called on success 48 | 49 | ```swift 50 | 51 | import Prompter 52 | 53 | let prompt = Prompt() 54 | 55 | //Prompt the user for a string input 56 | let name = prompt.askString("What is your name?", 57 | message: "This is an optional validation message!") { string in 58 | //this is an optional block 59 | } 60 | 61 | //Prompt the user for a string input 62 | let age = prompt.askInt("How old are you?") 63 | 64 | //Prompt the user for a Boolean response 65 | //y, Y, Yes, yes, t, True, 1 are all true etc 66 | let age = prompt.askBool("Do you like beans") 67 | 68 | //Ask the user to select from a list of choices 69 | let choices = ["beans", "apples"] 70 | let age = prompt.askChoice("Which of these do you prefer", 71 | choices: choices) { (index, string) in 72 | print(index, string) 73 | //0, beans 74 | } 75 | 76 | ``` 77 | 78 | ## Todo 79 | 80 | - askDate 81 | - askMultiple 82 | - initWithStyle 83 | 84 | ##Tests 85 | 86 | Run the tests using xctool: 87 | 88 | ```bash 89 | xctool -workspace Prompter.xcworkspace -scheme Prompter test 90 | ``` 91 | 92 | ## Author 93 | 94 | Matthew Clarkson from [Hilenium](http://hilenium.com) [@matt_clarkson](https://twitter.com/matt_clarkson) 95 | 96 | ## License 97 | 98 | Prompter is available under the MIT license. See the LICENSE file for more info. 99 | -------------------------------------------------------------------------------- /Resources/scripts/docs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$TRAVIS_PULL_REQUEST" == "false" ] && [ "$TRAVIS_BRANCH" == "master" ]; then 4 | echo -e "*** Generating docs ***\n" 5 | echo -e "*** Installing Jazzy ***\n" 6 | gem install jazzy 7 | echo -e "*** Creating documentation folder ***\n" 8 | rm -rf out || exit 0; 9 | mkdir out; 10 | cd out 11 | echo -e "*** Setting up git ***\n" 12 | git init 13 | git config user.email "travis@travis-ci.org" 14 | git config user.name "travis-ci" 15 | echo -e "*** Generating documentation ***\n" 16 | jazzy --swift-version 2.1.1 --source-directory ../ --output . --podspec ../Prompter.podspec 17 | echo -e "*** Adding docs to git ***\n" 18 | git add . 19 | git commit -m "Updated docs from travis build $TRAVIS_BUILD_NUMBER" 20 | git push --force --quiet "https://${GH_TOKEN}@github.com/mpclarkson/Prompter" master:gh-pages > /dev/null 2>&1 21 | echo -e "*** Published latest docs ***\n" 22 | fi 23 | -------------------------------------------------------------------------------- /Source/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // swift-cli 4 | // 5 | // Created by Matthew on 11/01/2016. 6 | // Copyright © 2016 Matthew Clarkson. All rights reserved. 7 | // 8 | 9 | extension String { 10 | 11 | var bool: Bool? { 12 | 13 | switch self.lowercaseString { 14 | case "true", "t", "y", "yes", "1": 15 | return true 16 | case "false", "f", "n", "no", "0": 17 | return false 18 | default: 19 | return nil 20 | } 21 | } 22 | 23 | var int: Int? { 24 | return Int(self) 25 | } 26 | } 27 | 28 | extension Array { 29 | 30 | func getAtIndex(index: Int?) -> Element? { 31 | guard let index = index where index >= 0 else { return nil } 32 | return index <= self.count - 1 ? self[index] : nil 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /Source/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 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 | NSHumanReadableCopyright 24 | Copyright © 2016 Matthew Clarkson. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Source/Prompter.h: -------------------------------------------------------------------------------- 1 | // 2 | // Prompter.h 3 | // Prompter 4 | // 5 | // Created by Matthew on 12/01/2016. 6 | // Copyright © 2016 Matthew Clarkson. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //! Project version number for Prompter. 12 | FOUNDATION_EXPORT double PrompterVersionNumber; 13 | 14 | //! Project version string for Prompter. 15 | FOUNDATION_EXPORT const unsigned char PrompterVersionString[]; 16 | 17 | // In this header, you should import all the public headers of your framework using statements like #import 18 | -------------------------------------------------------------------------------- /Source/Prompter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Prompter 3 | // 4 | // Created by Matthew on 11/01/2016. 5 | // Copyright © 2016 Matthew Clarkson. All rights reserved. 6 | // 7 | 8 | public typealias Choice = String 9 | public typealias Choices = [Choice] 10 | public typealias Index = Int 11 | public typealias ChoiceInfo = (Index, Choice) 12 | public typealias Block = (AnyObject) -> () 13 | 14 | /** 15 | Protocol for preconfiguring the prompt display style. 16 | Not really implemented (only default message) 17 | **/ 18 | public protocol PrompterStyle { 19 | var defaultMessage: String { get } 20 | } 21 | 22 | /** 23 | Prompt class 24 | 25 | **/ 26 | public class Prompter { 27 | 28 | public private(set) var defaultMessage: String = "Invalid response. Please try again." 29 | 30 | /** 31 | Initialize the prompt with a display style 32 | 33 | - parameter withStyle: PromptStyle 34 | 35 | **/ 36 | convenience public init(withStyle style: PrompterStyle) { 37 | self.init() 38 | defaultMessage = style.defaultMessage 39 | } 40 | 41 | /** 42 | Asks a question that requires a `String` response. A valid response must be provided before the user can proceed. 43 | 44 | - parameter question: The question to ask the user to respond to. 45 | - parameter message: Optional message to override the default message if the response is invalid. 46 | - parameter block: Optional block 47 | - returns: String 48 | 49 | **/ 50 | public func askString(question: String, message: String? = nil, block: Block? = nil) -> String { 51 | return ask(question, type: .String, message: message, block: block).value 52 | } 53 | 54 | /** 55 | Asks a question that requires an `Int` response. A valid response (i.e. an integer) must be provided before the user can proceed. 56 | 57 | - parameter question: The question to ask the user to respond to. 58 | - parameter message: Optional message to override the default message if the response is invalid. 59 | - parameter block: Optional block 60 | - returns: Integer 61 | 62 | **/ 63 | public func askInt(question: String, message: String? = nil, block: Block? = nil) -> Int { 64 | return ask(question, type: .Int, message: message, block: block).value 65 | } 66 | 67 | /** 68 | Asks a question that requires a `Bool` response. A valid response that can be converted to a boolean must be provided before the user can proceed. 69 | 70 | - parameter question: The question to ask the user to respond to. 71 | - parameter message: Optional message to override the default message if the response is invalid. 72 | - parameter block: Optional block 73 | - returns: Boolean 74 | 75 | **/ 76 | public func askBool(question: String, message: String? = nil, block: Block? = nil) -> Bool? { 77 | return ask(question, type: .Bool, message: message, block: block).value 78 | } 79 | 80 | /** 81 | Asks a multiple choice question that requires a single response (via entering an integer). A valid response must be provided. 82 | 83 | - parameter question: The question to ask the user to respond to. 84 | - parameter choices: An array of choices to present to the user. 85 | - parameter message: Optional message to override the default message if the response is invalid. 86 | - parameter block: Optional block 87 | - returns: (Index, String) - The index of the selected choice and the choice as a string 88 | 89 | **/ 90 | public func askSingleChoice(text: String, choices: Choices, message: String? = nil, block: Block? = nil) -> ChoiceInfo? { 91 | return ask(text, type: .SingleChoice(choices), message: message, block: block).value 92 | } 93 | } 94 | 95 | //MARK: - Private methods 96 | 97 | extension Prompter { 98 | 99 | private func ask(text: String, type: QuestionType, message: String?, block: Block?) -> Result { 100 | display(text, type: type) 101 | return input(type, message: message, block: block) 102 | } 103 | 104 | private func input(type: QuestionType, message: String?, block: Block?) -> Result { 105 | let msg = message != nil ? message! : defaultMessage 106 | 107 | guard let data = readLine(stripNewline: true) else { 108 | return invalidResponse(type, message: msg, block: block) 109 | } 110 | 111 | if let result = type.result(data) { 112 | block?(result.value as! AnyObject) 113 | return result 114 | } 115 | 116 | return invalidResponse(type, message: msg, block: block) 117 | } 118 | 119 | private func invalidResponse(type: QuestionType, message: String, block: Block?) -> Result { 120 | showMessage(message) 121 | return input(type, message: message, block: block) 122 | } 123 | 124 | private func display(text: String, type: QuestionType) { 125 | print(text) 126 | 127 | if let options = type.options { 128 | displayOptions(options) 129 | } 130 | } 131 | 132 | private func displayOptions(list: [String]) { 133 | list.enumerate().forEach { print("[\($0+1)] \($1) ") } 134 | } 135 | 136 | private func showMessage(text: String) { 137 | print("*** \(text) ***") 138 | } 139 | } 140 | 141 | //MARK: - Supporting 142 | 143 | private struct Result { 144 | let value: T 145 | 146 | init(value: T) { 147 | self.value = value 148 | } 149 | } 150 | 151 | private enum QuestionType { 152 | case String, Int, Bool, SingleChoice(Choices) 153 | 154 | var options: Choices? { 155 | switch self { 156 | case .SingleChoice(let choices): return choices 157 | default: return nil 158 | } 159 | } 160 | 161 | func result(input: Choice) -> Result? { 162 | 163 | var result: T? 164 | 165 | switch self { 166 | case .String: result = input as? T 167 | case .Int: result = input.int as? T 168 | case .Bool: result = input.bool as? T 169 | case .SingleChoice: 170 | if let int = input.int, options = self.options, item = options.getAtIndex(int - 1) { 171 | result = (int - 1, item) as? T 172 | } 173 | } 174 | 175 | return result != nil ? Result(value: result!) : nil 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 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 | -------------------------------------------------------------------------------- /Tests/Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SwiftPromptTests.swift 3 | // SwiftPromptTests 4 | // 5 | // Created by Matthew on 12/01/2016. 6 | // Copyright © 2016 Matthew Clarkson. All rights reserved. 7 | // 8 | 9 | import Nimble 10 | import Quick 11 | 12 | class PromptSpec: QuickSpec { 13 | 14 | override func spec() { 15 | 16 | describe("init withStyle") { 17 | 18 | struct Style: PrompterStyle { 19 | var defaultMessage = "foo" 20 | } 21 | 22 | let styledPrompter = Prompter(withStyle: Style()) 23 | 24 | it("default message") { 25 | expect(styledPrompter.defaultMessage) == "foo" 26 | } 27 | } 28 | } 29 | } 30 | 31 | class ExtensionsSpec: QuickSpec { 32 | 33 | override func spec() { 34 | describe("string extension") { 35 | 36 | it("bool true") { 37 | let trues = ["y", "Y", "yes", "YES", "t", "T", "TRUE", "true", "1"] 38 | 39 | trues.forEach { 40 | expect($0.bool) == true 41 | } 42 | } 43 | 44 | it("does not contain") { 45 | let falses = ["n", "N", "no", "NO", "f", "F", "False", "f", "0"] 46 | falses.forEach { 47 | expect($0.bool) == false 48 | } 49 | } 50 | } 51 | 52 | describe("array extension") { 53 | 54 | let array = ["a", "b", "c"] 55 | 56 | it("getAtIndex successfulluy") { 57 | expect(array.getAtIndex(0)) == "a" 58 | } 59 | 60 | it("getAtIndex negative index") { 61 | expect(array.getAtIndex(-1)).to(beNil()) 62 | } 63 | 64 | it("getAtIndex non existent index") { 65 | expect(array.getAtIndex(-3)).to(beNil()) 66 | } 67 | 68 | } 69 | } 70 | } 71 | 72 | 73 | --------------------------------------------------------------------------------