Removed quick.
This commit is contained in:
parent
296be1bdb3
commit
c579d2b87b
5
Podfile
5
Podfile
|
|
@ -4,6 +4,7 @@ platform :ios, '8.0'
|
|||
|
||||
target 'cameraTests' do
|
||||
use_frameworks!
|
||||
pod 'Quick', :git => 'https://github.com/Quick/Quick.git', :commit => 'f8c9ff9f499fc5ea72ff55c1c5eed32e1ff303ea'
|
||||
pod 'Nimble', :git => 'https://github.com/Quick/Nimble.git', :commit => '9538a301d5320fd607f01c931dc282868b0e827a'
|
||||
|
||||
pod 'Nimble'
|
||||
|
||||
end
|
||||
|
|
|
|||
27
Podfile.lock
27
Podfile.lock
|
|
@ -1,29 +1,10 @@
|
|||
PODS:
|
||||
- Nimble (0.3.0)
|
||||
- Quick (0.2.2)
|
||||
- Nimble (0.4.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Nimble (from `https://github.com/Quick/Nimble.git`, commit `9538a301d5320fd607f01c931dc282868b0e827a`)
|
||||
- Quick (from `https://github.com/Quick/Quick.git`, commit `f8c9ff9f499fc5ea72ff55c1c5eed32e1ff303ea`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Nimble:
|
||||
:commit: 9538a301d5320fd607f01c931dc282868b0e827a
|
||||
:git: https://github.com/Quick/Nimble.git
|
||||
Quick:
|
||||
:commit: f8c9ff9f499fc5ea72ff55c1c5eed32e1ff303ea
|
||||
:git: https://github.com/Quick/Quick.git
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
Nimble:
|
||||
:commit: 9538a301d5320fd607f01c931dc282868b0e827a
|
||||
:git: https://github.com/Quick/Nimble.git
|
||||
Quick:
|
||||
:commit: f8c9ff9f499fc5ea72ff55c1c5eed32e1ff303ea
|
||||
:git: https://github.com/Quick/Quick.git
|
||||
- Nimble
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Nimble: 55fef248ef3703024ce431db817160ad24d89ba3
|
||||
Quick: 1bda8b4c8d43f6b4dd69ca001918b1767b3c9c93
|
||||
Nimble: 49b7a7da8919f42823d37c6d68cc6d15a7009f32
|
||||
|
||||
COCOAPODS: 0.36.0
|
||||
COCOAPODS: 0.37.1
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/NSString+QCKSelectorName.h
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/DSL/QCKDSL.h
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/Quick.h
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/Configuration/QuickConfiguration.h
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/QuickSpec.h
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/NSString+QCKSelectorName.h
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/DSL/QCKDSL.h
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/Quick.h
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/Configuration/QuickConfiguration.h
|
||||
|
|
@ -1 +0,0 @@
|
|||
../../../Quick/Quick/QuickSpec.h
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
{
|
||||
"name": "Quick",
|
||||
"version": "0.2.2",
|
||||
"summary": "The Swift (and Objective-C) testing framework.",
|
||||
"description": " Quick is a behavior-driven development framework for Swift and Objective-C. Inspired by RSpec, Specta, and Ginkgo.\n",
|
||||
"homepage": "https://github.com/Quick/Quick",
|
||||
"license": {
|
||||
"type": "Apache 2.0",
|
||||
"file": "LICENSE"
|
||||
},
|
||||
"authors": "Quick Contributors",
|
||||
"platforms": {
|
||||
"ios": "8.0",
|
||||
"osx": "10.10"
|
||||
},
|
||||
"source": {
|
||||
"git": "https://github.com/Quick/Quick.git",
|
||||
"tag": "v0.2.2"
|
||||
},
|
||||
"source_files": [
|
||||
"Quick",
|
||||
"Quick/**/*.{swift,h,m}"
|
||||
],
|
||||
"frameworks": "XCTest",
|
||||
"requires_arc": true
|
||||
}
|
||||
|
|
@ -1,29 +1,10 @@
|
|||
PODS:
|
||||
- Nimble (0.3.0)
|
||||
- Quick (0.2.2)
|
||||
- Nimble (0.4.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Nimble (from `https://github.com/Quick/Nimble.git`, commit `9538a301d5320fd607f01c931dc282868b0e827a`)
|
||||
- Quick (from `https://github.com/Quick/Quick.git`, commit `f8c9ff9f499fc5ea72ff55c1c5eed32e1ff303ea`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Nimble:
|
||||
:commit: 9538a301d5320fd607f01c931dc282868b0e827a
|
||||
:git: https://github.com/Quick/Nimble.git
|
||||
Quick:
|
||||
:commit: f8c9ff9f499fc5ea72ff55c1c5eed32e1ff303ea
|
||||
:git: https://github.com/Quick/Quick.git
|
||||
|
||||
CHECKOUT OPTIONS:
|
||||
Nimble:
|
||||
:commit: 9538a301d5320fd607f01c931dc282868b0e827a
|
||||
:git: https://github.com/Quick/Nimble.git
|
||||
Quick:
|
||||
:commit: f8c9ff9f499fc5ea72ff55c1c5eed32e1ff303ea
|
||||
:git: https://github.com/Quick/Quick.git
|
||||
- Nimble
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Nimble: 55fef248ef3703024ce431db817160ad24d89ba3
|
||||
Quick: 1bda8b4c8d43f6b4dd69ca001918b1767b3c9c93
|
||||
Nimble: 49b7a7da8919f42823d37c6d68cc6d15a7009f32
|
||||
|
||||
COCOAPODS: 0.36.0
|
||||
COCOAPODS: 0.37.1
|
||||
|
|
|
|||
|
|
@ -9,5 +9,4 @@ public protocol AssertionHandler {
|
|||
/// Defaults to a private test handler that passes through to XCTest.
|
||||
///
|
||||
/// @see AssertionHandler
|
||||
var CurrentAssertionHandler: AssertionHandler = XCTestHandler()
|
||||
|
||||
public var NimbleAssertionHandler: AssertionHandler = NimbleXCTestHandler()
|
||||
|
|
|
|||
|
|
@ -40,11 +40,11 @@ public class AssertionRecorder : AssertionHandler {
|
|||
///
|
||||
/// @see AssertionHandler
|
||||
public func withAssertionHandler(tempAssertionHandler: AssertionHandler, closure: () -> Void) {
|
||||
let oldRecorder = CurrentAssertionHandler
|
||||
let oldRecorder = NimbleAssertionHandler
|
||||
let capturer = NMBExceptionCapture(handler: nil, finally: ({
|
||||
CurrentAssertionHandler = oldRecorder
|
||||
NimbleAssertionHandler = oldRecorder
|
||||
}))
|
||||
CurrentAssertionHandler = tempAssertionHandler
|
||||
NimbleAssertionHandler = tempAssertionHandler
|
||||
capturer.tryBlock {
|
||||
closure()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
import Foundation
|
||||
import XCTest
|
||||
|
||||
/// Default handler for Nimble. This assertion handler passes failures along to
|
||||
/// XCTest.
|
||||
public class NimbleXCTestHandler : AssertionHandler {
|
||||
public func assert(assertion: Bool, message: String, location: SourceLocation) {
|
||||
if !assertion {
|
||||
XCTFail(message, file: location.file, line: location.line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
import Foundation
|
||||
import XCTest
|
||||
|
||||
class XCTestHandler : AssertionHandler {
|
||||
func assert(assertion: Bool, message: String, location: SourceLocation) {
|
||||
if !assertion {
|
||||
XCTFail(message, file: location.file, line: location.line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@ import Foundation
|
|||
/// bridges to Objective-C via the @objc keyword. This class encapsulates callback-style
|
||||
/// asynchronous waiting logic so that it may be called from Objective-C and Swift.
|
||||
@objc public class NMBWait {
|
||||
public class func until(#timeout: NSTimeInterval, action: (() -> Void) -> Void, file: String = __FILE__, line: UInt = __LINE__) -> Void {
|
||||
public class func until(#timeout: NSTimeInterval, file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void {
|
||||
var completed = false
|
||||
var token: dispatch_once_t = 0
|
||||
let result = pollBlock(pollInterval: 0.01, timeoutInterval: timeout) {
|
||||
|
|
@ -23,21 +23,21 @@ import Foundation
|
|||
}
|
||||
}
|
||||
|
||||
public class func until(action: (() -> Void) -> Void, file: String = __FILE__, line: UInt = __LINE__) -> Void {
|
||||
until(timeout: 1, action: action, file: file, line: line)
|
||||
public class func until(file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void {
|
||||
until(timeout: 1, file: file, line: line, action: action)
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait asynchronously until the done closure is called.
|
||||
///
|
||||
/// This will advance the run loop.
|
||||
public func waitUntil(#timeout: NSTimeInterval, action: (() -> Void) -> Void, file: String = __FILE__, line: UInt = __LINE__) -> Void {
|
||||
NMBWait.until(timeout: timeout, action: action, file: file, line: line)
|
||||
public func waitUntil(#timeout: NSTimeInterval, file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void {
|
||||
NMBWait.until(timeout: timeout, file: file, line: line, action: action)
|
||||
}
|
||||
|
||||
/// Wait asynchronously until the done closure is called.
|
||||
///
|
||||
/// This will advance the run loop.
|
||||
public func waitUntil(action: (() -> Void) -> Void, file: String = __FILE__, line: UInt = __LINE__) -> Void {
|
||||
NMBWait.until(action, file: file, line: line)
|
||||
public func waitUntil(file: String = __FILE__, line: UInt = __LINE__, action: (() -> Void) -> Void) -> Void {
|
||||
NMBWait.until(file: file, line: line, action: action)
|
||||
}
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
/// Make an expectation on a given actual value. The value given is lazily evaluated.
|
||||
public func expect<T>(expression: @autoclosure () -> T?, file: String = __FILE__, line: UInt = __LINE__) -> Expectation<T> {
|
||||
public func expect<T>(@autoclosure(escaping) expression: () -> T?, file: String = __FILE__, line: UInt = __LINE__) -> Expectation<T> {
|
||||
return Expectation(
|
||||
expression: Expression(
|
||||
expression: expression,
|
||||
location: SourceLocation(file: file, line: line)))
|
||||
location: SourceLocation(file: file, line: line),
|
||||
isClosure: true))
|
||||
}
|
||||
|
||||
/// Make an expectation on a given actual value. The closure is lazily invoked.
|
||||
|
|
@ -11,12 +12,13 @@ public func expect<T>(file: String = __FILE__, line: UInt = __LINE__, expression
|
|||
return Expectation(
|
||||
expression: Expression(
|
||||
expression: expression,
|
||||
location: SourceLocation(file: file, line: line)))
|
||||
location: SourceLocation(file: file, line: line),
|
||||
isClosure: true))
|
||||
}
|
||||
|
||||
/// Always fails the test with a message and a specified location.
|
||||
public func fail(message: String, #location: SourceLocation) {
|
||||
CurrentAssertionHandler.assert(false, message: message, location: location)
|
||||
NimbleAssertionHandler.assert(false, message: message, location: location)
|
||||
}
|
||||
|
||||
/// Always fails the test with a message.
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ public struct Expectation<T> {
|
|||
let expression: Expression<T>
|
||||
|
||||
public func verify(pass: Bool, _ message: String) {
|
||||
CurrentAssertionHandler.assert(pass, message: message, location: expression.location)
|
||||
NimbleAssertionHandler.assert(pass, message: message, location: expression.location)
|
||||
}
|
||||
|
||||
public func to<U where U: Matcher, U.ValueType == T>(matcher: U) {
|
||||
|
|
|
|||
|
|
@ -16,21 +16,24 @@ public struct Expression<T> {
|
|||
internal let _expression: (Bool) -> T?
|
||||
internal let _withoutCaching: Bool
|
||||
public let location: SourceLocation
|
||||
public let isClosure: Bool
|
||||
|
||||
public init(expression: () -> T?, location: SourceLocation) {
|
||||
public init(expression: () -> T?, location: SourceLocation, isClosure: Bool = false) {
|
||||
self._expression = memoizedClosure(expression)
|
||||
self.location = location
|
||||
self._withoutCaching = false
|
||||
self.isClosure = isClosure
|
||||
}
|
||||
|
||||
public init(memoizedExpression: (Bool) -> T?, location: SourceLocation, withoutCaching: Bool) {
|
||||
public init(memoizedExpression: (Bool) -> T?, location: SourceLocation, withoutCaching: Bool, isClosure: Bool = false) {
|
||||
self._expression = memoizedExpression
|
||||
self.location = location
|
||||
self._withoutCaching = withoutCaching
|
||||
self.isClosure = isClosure
|
||||
}
|
||||
|
||||
public func cast<U>(block: (T?) -> U?) -> Expression<U> {
|
||||
return Expression<U>(expression: ({ block(self.evaluate()) }), location: self.location)
|
||||
return Expression<U>(expression: ({ block(self.evaluate()) }), location: self.location, isClosure: self.isClosure)
|
||||
}
|
||||
|
||||
public func evaluate() -> T? {
|
||||
|
|
@ -38,6 +41,6 @@ public struct Expression<T> {
|
|||
}
|
||||
|
||||
public func withoutCaching() -> Expression<T> {
|
||||
return Expression(memoizedExpression: self._expression, location: location, withoutCaching: true)
|
||||
return Expression(memoizedExpression: self._expression, location: location, withoutCaching: true, isClosure: isClosure)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ public class FailureMessage {
|
|||
if let actualValue = actualValue {
|
||||
value = "\(expected) \(to) \(postfixMessage), got \(actualValue)\(postfixActual)"
|
||||
}
|
||||
var lines: [String] = (value as NSString).componentsSeparatedByString("\n") as [String]
|
||||
var lines: [String] = (value as NSString).componentsSeparatedByString("\n") as! [String]
|
||||
let whitespace = NSCharacterSet.whitespaceAndNewlineCharacterSet()
|
||||
lines = lines.map { line in line.stringByTrimmingCharactersInSet(whitespace) }
|
||||
return "".join(lines)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
import Foundation
|
||||
|
||||
public func allPass<T,U where U: SequenceType, U.Generator.Element == T>
|
||||
(passFunc: (T?) -> Bool) -> NonNilMatcherFunc<U> {
|
||||
return allPass("pass a condition", passFunc)
|
||||
}
|
||||
|
||||
public func allPass<T,U where U: SequenceType, U.Generator.Element == T>
|
||||
(passName:String, passFunc: (T?) -> Bool) -> NonNilMatcherFunc<U> {
|
||||
return createAllPassMatcher() {
|
||||
expression, failureMessage in
|
||||
failureMessage.postfixMessage = passName
|
||||
return passFunc(expression.evaluate())
|
||||
}
|
||||
}
|
||||
|
||||
public func allPass<U,V where U: SequenceType, V: NonNilBasicMatcher, U.Generator.Element == V.ValueType>
|
||||
(matcher: V) -> NonNilMatcherFunc<U> {
|
||||
let wrapper = NonNilMatcherWrapper(NonNilBasicMatcherWrapper(matcher))
|
||||
return createAllPassMatcher() {wrapper.matches($0, failureMessage: $1)}
|
||||
}
|
||||
|
||||
public func allPass<U,V where U: SequenceType, V: BasicMatcher, U.Generator.Element == V.ValueType>
|
||||
(matcher: V) -> NonNilMatcherFunc<U> {
|
||||
let wrapper = BasicMatcherWrapper(matcher: matcher)
|
||||
return createAllPassMatcher() {wrapper.matches($0, failureMessage: $1)}
|
||||
}
|
||||
|
||||
public func allPass<U,V where U: SequenceType, V: Matcher, U.Generator.Element == V.ValueType>
|
||||
(matcher: V) -> NonNilMatcherFunc<U> {
|
||||
return createAllPassMatcher() {matcher.matches($0, failureMessage: $1)}
|
||||
}
|
||||
|
||||
private func createAllPassMatcher<T,U where U: SequenceType, U.Generator.Element == T>
|
||||
(elementEvaluator:(Expression<T>, FailureMessage) -> Bool) -> NonNilMatcherFunc<U> {
|
||||
return NonNilMatcherFunc { actualExpression, failureMessage in
|
||||
failureMessage.actualValue = nil
|
||||
if let actualValue = actualExpression.evaluate() {
|
||||
for currentElement in actualValue {
|
||||
let exp = Expression(
|
||||
expression: {currentElement}, location: actualExpression.location)
|
||||
if !elementEvaluator(exp, failureMessage) {
|
||||
failureMessage.postfixMessage =
|
||||
"all \(failureMessage.postfixMessage),"
|
||||
+ " but failed first at element <\(stringify(currentElement))>"
|
||||
+ " in <\(stringify(actualValue))>"
|
||||
return false
|
||||
}
|
||||
}
|
||||
failureMessage.postfixMessage = "all \(failureMessage.postfixMessage)"
|
||||
} else {
|
||||
failureMessage.postfixMessage = "all pass (use beNil() to match nils)"
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension NMBObjCMatcher {
|
||||
public class func allPassMatcher(matcher: NMBObjCMatcher) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage, location in
|
||||
let actualValue = actualExpression.evaluate()
|
||||
var nsObjects = [NSObject]()
|
||||
|
||||
var collectionIsUsable = true
|
||||
if let value = actualValue as? NSFastEnumeration {
|
||||
let generator = NSFastGenerator(value)
|
||||
while let obj:AnyObject = generator.next() {
|
||||
if let nsObject = obj as? NSObject {
|
||||
nsObjects.append(nsObject)
|
||||
} else {
|
||||
collectionIsUsable = false
|
||||
break
|
||||
}
|
||||
}
|
||||
} else {
|
||||
collectionIsUsable = false
|
||||
}
|
||||
|
||||
if !collectionIsUsable {
|
||||
failureMessage.postfixMessage =
|
||||
"allPass only works with NSFastEnumeration (NSArray, NSSet, ...) of NSObjects"
|
||||
failureMessage.expected = ""
|
||||
failureMessage.to = ""
|
||||
return false
|
||||
}
|
||||
|
||||
let expr = Expression(expression: ({ nsObjects }), location: location)
|
||||
let elementEvaluator: (Expression<NSObject>, FailureMessage) -> Bool = {
|
||||
expression, failureMessage in
|
||||
return matcher.matches(
|
||||
{expression.evaluate()}, failureMessage: failureMessage, location: expr.location)
|
||||
}
|
||||
return createAllPassMatcher(elementEvaluator).matches(
|
||||
expr, failureMessage: failureMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ public func >(lhs: Expectation<NMBComparable>, rhs: NMBComparable?) {
|
|||
extension NMBObjCMatcher {
|
||||
public class func beGreaterThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage, location in
|
||||
let expr = actualExpression.cast { $0 as NMBComparable? }
|
||||
let expr = actualExpression.cast { $0 as? NMBComparable }
|
||||
return beGreaterThan(expected).matches(expr, failureMessage: failureMessage)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public func >=<T: NMBComparable>(lhs: Expectation<T>, rhs: T) {
|
|||
extension NMBObjCMatcher {
|
||||
public class func beGreaterThanOrEqualToMatcher(expected: NMBComparable?) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage, location in
|
||||
let expr = actualExpression.cast { $0 as NMBComparable? }
|
||||
let expr = actualExpression.cast { $0 as? NMBComparable }
|
||||
return beGreaterThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public func <(lhs: Expectation<NMBComparable>, rhs: NMBComparable?) {
|
|||
extension NMBObjCMatcher {
|
||||
public class func beLessThanMatcher(expected: NMBComparable?) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage, location in
|
||||
let expr = actualExpression.cast { $0 as NMBComparable? }
|
||||
let expr = actualExpression.cast { $0 as! NMBComparable? }
|
||||
return beLessThan(expected).matches(expr, failureMessage: failureMessage)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ extension NMBObjCMatcher {
|
|||
let actual = actualExpression.evaluate()
|
||||
if let actualString = actual as? String {
|
||||
let expr = actualExpression.cast { $0 as? String }
|
||||
return beginWith(expected as String).matches(expr, failureMessage: failureMessage)
|
||||
return beginWith(expected as! String).matches(expr, failureMessage: failureMessage)
|
||||
} else {
|
||||
let expr = actualExpression.cast { $0 as? NMBOrderedCollection }
|
||||
return beginWith(expected).matches(expr, failureMessage: failureMessage)
|
||||
|
|
|
|||
|
|
@ -28,6 +28,19 @@ public func contain(substrings: String...) -> NonNilMatcherFunc<String> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual string contains the expected substring.
|
||||
public func contain(substrings: NSString...) -> NonNilMatcherFunc<NSString> {
|
||||
return NonNilMatcherFunc { actualExpression, failureMessage in
|
||||
failureMessage.postfixMessage = "contain <\(arrayAsString(substrings))>"
|
||||
if let actual = actualExpression.evaluate() {
|
||||
return all(substrings) {
|
||||
return actual.containsString($0.description)
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual collection contains the expected object.
|
||||
public func contain(items: AnyObject?...) -> NonNilMatcherFunc<NMBContainer> {
|
||||
return NonNilMatcherFunc { actualExpression, failureMessage in
|
||||
|
|
@ -48,7 +61,7 @@ extension NMBObjCMatcher {
|
|||
return contain(expected).matches(expr, failureMessage: failureMessage)
|
||||
} else if let value = actualValue as? NSString {
|
||||
let expr = Expression(expression: ({ value as String }), location: location)
|
||||
return contain(expected as String).matches(expr, failureMessage: failureMessage)
|
||||
return contain(expected as! String).matches(expr, failureMessage: failureMessage)
|
||||
} else if actualValue != nil {
|
||||
failureMessage.postfixMessage = "contain <\(stringify(expected))> (only works for NSArrays, NSSets, NSHashTables, and NSStrings)"
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ extension NMBObjCMatcher {
|
|||
let actual = actualExpression.evaluate()
|
||||
if let actualString = actual as? String {
|
||||
let expr = Expression(expression: ({ actualString }), location: location)
|
||||
return endWith(expected as String).matches(expr, failureMessage: failureMessage)
|
||||
return endWith(expected as! String).matches(expr, failureMessage: failureMessage)
|
||||
} else {
|
||||
let expr = Expression(expression: ({ actual as? NMBOrderedCollection }), location: location)
|
||||
return endWith(expected).matches(expr, failureMessage: failureMessage)
|
||||
|
|
|
|||
|
|
@ -50,6 +50,52 @@ public func equal<T: Equatable>(expectedValue: [T]?) -> NonNilMatcherFunc<[T]> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual set is equal to the expected set.
|
||||
public func equal<T>(expectedValue: Set<T>?) -> NonNilMatcherFunc<Set<T>> {
|
||||
return equal(expectedValue, stringify: stringify)
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual set is equal to the expected set.
|
||||
public func equal<T: Comparable>(expectedValue: Set<T>?) -> NonNilMatcherFunc<Set<T>> {
|
||||
return equal(expectedValue, stringify: {
|
||||
if let set = $0 {
|
||||
return stringify(Array(set).sorted { $0 < $1 })
|
||||
} else {
|
||||
return "nil"
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func equal<T>(expectedValue: Set<T>?, #stringify: Set<T>? -> String) -> NonNilMatcherFunc<Set<T>> {
|
||||
return NonNilMatcherFunc { actualExpression, failureMessage in
|
||||
failureMessage.postfixMessage = "equal <\(stringify(expectedValue))>"
|
||||
|
||||
if let expectedValue = expectedValue {
|
||||
if let actualValue = actualExpression.evaluate() {
|
||||
failureMessage.actualValue = "<\(stringify(actualValue))>"
|
||||
|
||||
if expectedValue == actualValue {
|
||||
return true
|
||||
}
|
||||
|
||||
let missing = expectedValue.subtract(actualValue)
|
||||
if missing.count > 0 {
|
||||
failureMessage.postfixActual += ", missing <\(stringify(missing))>"
|
||||
}
|
||||
|
||||
let extra = actualValue.subtract(expectedValue)
|
||||
if extra.count > 0 {
|
||||
failureMessage.postfixActual += ", extra <\(stringify(extra))>"
|
||||
}
|
||||
}
|
||||
} else {
|
||||
failureMessage.postfixActual = " (use beNil() to match nils)"
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
public func ==<T: Equatable>(lhs: Expectation<T>, rhs: T?) {
|
||||
lhs.to(equal(rhs))
|
||||
}
|
||||
|
|
@ -66,6 +112,22 @@ public func !=<T: Equatable>(lhs: Expectation<[T]>, rhs: [T]?) {
|
|||
lhs.toNot(equal(rhs))
|
||||
}
|
||||
|
||||
public func ==<T>(lhs: Expectation<Set<T>>, rhs: Set<T>?) {
|
||||
lhs.to(equal(rhs))
|
||||
}
|
||||
|
||||
public func !=<T>(lhs: Expectation<Set<T>>, rhs: Set<T>?) {
|
||||
lhs.toNot(equal(rhs))
|
||||
}
|
||||
|
||||
public func ==<T: Comparable>(lhs: Expectation<Set<T>>, rhs: Set<T>?) {
|
||||
lhs.to(equal(rhs))
|
||||
}
|
||||
|
||||
public func !=<T: Comparable>(lhs: Expectation<Set<T>>, rhs: Set<T>?) {
|
||||
lhs.toNot(equal(rhs))
|
||||
}
|
||||
|
||||
public func ==<T: Equatable, C: Equatable>(lhs: Expectation<[T: C]>, rhs: [T: C]?) {
|
||||
lhs.to(equal(rhs))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ extension NMBObjCMatcher {
|
|||
public class func matchMatcher(expected: NSString) -> NMBMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage, location in
|
||||
let actual = actualExpression.cast { $0 as? String }
|
||||
return match(expected).matches(actual, failureMessage: failureMessage)
|
||||
return match(expected.description).matches(actual, failureMessage: failureMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,11 +82,11 @@ extension NSDecimalNumber : NMBDoubleConvertible { } // TODO: not the best to do
|
|||
}
|
||||
extension NSNumber : NMBComparable {
|
||||
public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult {
|
||||
return compare(otherObject as NSNumber)
|
||||
return compare(otherObject as! NSNumber)
|
||||
}
|
||||
}
|
||||
extension NSString : NMBComparable {
|
||||
public func NMB_compare(otherObject: NMBComparable!) -> NSComparisonResult {
|
||||
return compare(otherObject as NSString)
|
||||
return compare(otherObject as! String)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,81 +1,185 @@
|
|||
import Foundation
|
||||
|
||||
internal func raiseExceptionMatcher<T>(message: String, matches: (NSException?) -> Bool) -> MatcherFunc<T> {
|
||||
internal struct RaiseExceptionMatchResult {
|
||||
var success: Bool
|
||||
var nameFailureMessage: FailureMessage?
|
||||
var reasonFailureMessage: FailureMessage?
|
||||
var userInfoFailureMessage: FailureMessage?
|
||||
}
|
||||
|
||||
internal func raiseExceptionMatcher(matches: (NSException?, SourceLocation) -> RaiseExceptionMatchResult) -> MatcherFunc<Any> {
|
||||
return MatcherFunc { actualExpression, failureMessage in
|
||||
failureMessage.actualValue = nil
|
||||
failureMessage.postfixMessage = message
|
||||
|
||||
// It would be better if this was part of Expression, but
|
||||
// Swift compiler crashes when expect() is inside a closure.
|
||||
var exception: NSException?
|
||||
var result: T?
|
||||
var capture = NMBExceptionCapture(handler: ({ e in
|
||||
exception = e
|
||||
}), finally: nil)
|
||||
}), finally: nil)
|
||||
|
||||
capture.tryBlock {
|
||||
actualExpression.evaluate()
|
||||
return
|
||||
}
|
||||
return matches(exception)
|
||||
|
||||
let result = matches(exception, actualExpression.location)
|
||||
|
||||
failureMessage.postfixMessage = "raise exception"
|
||||
|
||||
if let nameFailureMessage = result.nameFailureMessage {
|
||||
failureMessage.postfixMessage += " with name \(nameFailureMessage.postfixMessage)"
|
||||
}
|
||||
if let reasonFailureMessage = result.reasonFailureMessage {
|
||||
failureMessage.postfixMessage += " with reason \(reasonFailureMessage.postfixMessage)"
|
||||
}
|
||||
if let userInfoFailureMessage = result.userInfoFailureMessage {
|
||||
failureMessage.postfixMessage += " with userInfo \(userInfoFailureMessage.postfixMessage)"
|
||||
}
|
||||
if result.nameFailureMessage == nil && result.reasonFailureMessage == nil
|
||||
&& result.userInfoFailureMessage == nil {
|
||||
failureMessage.postfixMessage = "raise any exception"
|
||||
}
|
||||
|
||||
return result.success
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// A Nimble matcher that succeeds when the actual expression raises an exception, which name,
|
||||
// reason and userInfo match successfully with the provided matchers
|
||||
public func raiseException(
|
||||
named: NonNilMatcherFunc<String>? = nil,
|
||||
reason: NonNilMatcherFunc<String>? = nil,
|
||||
userInfo: NonNilMatcherFunc<NSDictionary>? = nil) -> MatcherFunc<Any> {
|
||||
return raiseExceptionMatcher() { exception, location in
|
||||
|
||||
var matches = exception != nil
|
||||
|
||||
var nameFailureMessage: FailureMessage?
|
||||
if let nameMatcher = named {
|
||||
let wrapper = NonNilMatcherWrapper(NonNilBasicMatcherWrapper(nameMatcher))
|
||||
nameFailureMessage = FailureMessage()
|
||||
matches = wrapper.matches(
|
||||
Expression(expression: { exception?.name },
|
||||
location: location,
|
||||
isClosure: false),
|
||||
failureMessage: nameFailureMessage!) && matches
|
||||
}
|
||||
|
||||
var reasonFailureMessage: FailureMessage?
|
||||
if let reasonMatcher = reason {
|
||||
let wrapper = NonNilMatcherWrapper(NonNilBasicMatcherWrapper(reasonMatcher))
|
||||
reasonFailureMessage = FailureMessage()
|
||||
matches = wrapper.matches(
|
||||
Expression(expression: { exception?.reason },
|
||||
location: location,
|
||||
isClosure: false),
|
||||
failureMessage: reasonFailureMessage!) && matches
|
||||
}
|
||||
|
||||
var userInfoFailureMessage: FailureMessage?
|
||||
if let userInfoMatcher = userInfo {
|
||||
let wrapper = NonNilMatcherWrapper(NonNilBasicMatcherWrapper(userInfoMatcher))
|
||||
userInfoFailureMessage = FailureMessage()
|
||||
matches = wrapper.matches(
|
||||
Expression(expression: { exception?.userInfo },
|
||||
location: location,
|
||||
isClosure: false),
|
||||
failureMessage: userInfoFailureMessage!) && matches
|
||||
}
|
||||
|
||||
return RaiseExceptionMatchResult(
|
||||
success: matches,
|
||||
nameFailureMessage: nameFailureMessage,
|
||||
reasonFailureMessage: reasonFailureMessage,
|
||||
userInfoFailureMessage: userInfoFailureMessage)
|
||||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual expression raises an exception with
|
||||
/// the specified name, reason, and userInfo.
|
||||
public func raiseException(#named: String, #reason: String, #userInfo: NSDictionary) -> MatcherFunc<Any> {
|
||||
return raiseExceptionMatcher("raise exception named <\(named)> with reason <\(reason)> and userInfo <\(userInfo)>") {
|
||||
exception in
|
||||
return exception?.name == named
|
||||
&& exception?.reason == reason
|
||||
&& exception?.userInfo == userInfo
|
||||
}
|
||||
return raiseException(named: equal(named), reason: equal(reason), userInfo: equal(userInfo))
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual expression raises an exception with
|
||||
/// the specified name and reason.
|
||||
public func raiseException(#named: String, #reason: String) -> MatcherFunc<Any> {
|
||||
return raiseExceptionMatcher("raise exception named <\(named)> with reason <\(reason)>") {
|
||||
exception in return exception?.name == named && exception?.reason == reason
|
||||
}
|
||||
return raiseException(named: equal(named), reason: equal(reason))
|
||||
}
|
||||
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual expression raises an exception with
|
||||
/// the specified name.
|
||||
public func raiseException(#named: String) -> MatcherFunc<Any> {
|
||||
return raiseExceptionMatcher("raise exception named <\(named)>") {
|
||||
exception in return exception?.name == named
|
||||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual expression raises any exception.
|
||||
/// Please use a more specific raiseException() matcher when possible.
|
||||
public func raiseException() -> MatcherFunc<Any> {
|
||||
return raiseExceptionMatcher("raise any exception") {
|
||||
exception in return exception != nil
|
||||
}
|
||||
return raiseException(named: equal(named))
|
||||
}
|
||||
|
||||
@objc public class NMBObjCRaiseExceptionMatcher : NMBMatcher {
|
||||
var _name: String?
|
||||
var _reason: String?
|
||||
var _userInfo: NSDictionary?
|
||||
var _nameMatcher: NMBMatcher?
|
||||
var _reasonMatcher: NMBMatcher?
|
||||
var _userInfoMatcher: NMBMatcher?
|
||||
|
||||
init(name: String?, reason: String?, userInfo: NSDictionary?) {
|
||||
_name = name
|
||||
_reason = reason
|
||||
_userInfo = userInfo
|
||||
}
|
||||
|
||||
init(nameMatcher: NMBMatcher?, reasonMatcher: NMBMatcher?, userInfoMatcher: NMBMatcher?) {
|
||||
_nameMatcher = nameMatcher
|
||||
_reasonMatcher = reasonMatcher
|
||||
_userInfoMatcher = userInfoMatcher
|
||||
}
|
||||
|
||||
public func matches(actualBlock: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool {
|
||||
let block: () -> Any? = ({ actualBlock(); return nil })
|
||||
let expr = Expression(expression: block, location: location)
|
||||
if _name != nil && _reason != nil && _userInfo != nil {
|
||||
return raiseException(named: _name!, reason: _reason!, userInfo: _userInfo!).matches(expr, failureMessage: failureMessage)
|
||||
} else if _name != nil && _reason != nil {
|
||||
return raiseException(named: _name!, reason: _reason!).matches(expr, failureMessage: failureMessage)
|
||||
} else if _name != nil {
|
||||
return raiseException(named: _name!).matches(expr, failureMessage: failureMessage)
|
||||
if _nameMatcher != nil || _reasonMatcher != nil || _userInfoMatcher != nil {
|
||||
return raiseExceptionMatcher() {
|
||||
exception, location in
|
||||
|
||||
var matches = exception != nil
|
||||
|
||||
var nameFailureMessage: FailureMessage?
|
||||
if let nameMatcher = self._nameMatcher {
|
||||
nameFailureMessage = FailureMessage()
|
||||
matches = nameMatcher.matches({ exception?.name },
|
||||
failureMessage: nameFailureMessage!,
|
||||
location: location) && matches
|
||||
}
|
||||
|
||||
var reasonFailureMessage: FailureMessage?
|
||||
if let reasonMatcher = self._reasonMatcher {
|
||||
reasonFailureMessage = FailureMessage()
|
||||
matches = reasonMatcher.matches({ exception?.reason },
|
||||
failureMessage: reasonFailureMessage!,
|
||||
location: location) && matches
|
||||
}
|
||||
|
||||
var userInfoFailureMessage: FailureMessage?
|
||||
if let userInfoMatcher = self._userInfoMatcher {
|
||||
userInfoFailureMessage = FailureMessage()
|
||||
matches = userInfoMatcher.matches({ exception?.userInfo },
|
||||
failureMessage: userInfoFailureMessage!,
|
||||
location: location) && matches
|
||||
}
|
||||
|
||||
return RaiseExceptionMatchResult(
|
||||
success: matches,
|
||||
nameFailureMessage: nameFailureMessage,
|
||||
reasonFailureMessage: reasonFailureMessage,
|
||||
userInfoFailureMessage: userInfoFailureMessage)
|
||||
|
||||
}.matches(expr, failureMessage: failureMessage)
|
||||
} else if let name = _name, reason = _reason, userInfo = _userInfo {
|
||||
return raiseException(named: name, reason: reason, userInfo: userInfo).matches(expr, failureMessage: failureMessage)
|
||||
} else if let name = _name, reason = _reason {
|
||||
return raiseException(named: name, reason: reason).matches(expr, failureMessage: failureMessage)
|
||||
} else if let name = _name {
|
||||
return raiseException(named: name).matches(expr, failureMessage: failureMessage)
|
||||
} else {
|
||||
return raiseException().matches(expr, failureMessage: failureMessage)
|
||||
}
|
||||
|
|
@ -102,6 +206,27 @@ public func raiseException() -> MatcherFunc<Any> {
|
|||
return NMBObjCRaiseExceptionMatcher(name: self._name, reason: self._reason, userInfo: userInfo)
|
||||
})
|
||||
}
|
||||
|
||||
public var withName: (nameMatcher: NMBMatcher) -> NMBObjCRaiseExceptionMatcher {
|
||||
return ({ nameMatcher in
|
||||
return NMBObjCRaiseExceptionMatcher(nameMatcher: nameMatcher,
|
||||
reasonMatcher: self._reasonMatcher, userInfoMatcher: self._userInfoMatcher)
|
||||
})
|
||||
}
|
||||
|
||||
public var withReason: (reasonMatcher: NMBMatcher) -> NMBObjCRaiseExceptionMatcher {
|
||||
return ({ reasonMatcher in
|
||||
return NMBObjCRaiseExceptionMatcher(nameMatcher: self._nameMatcher,
|
||||
reasonMatcher: reasonMatcher, userInfoMatcher: self._userInfoMatcher)
|
||||
})
|
||||
}
|
||||
|
||||
public var withUserInfo: (userInfoMatcher: NMBMatcher) -> NMBObjCRaiseExceptionMatcher {
|
||||
return ({ userInfoMatcher in
|
||||
return NMBObjCRaiseExceptionMatcher(nameMatcher: self._nameMatcher,
|
||||
reasonMatcher: self._reasonMatcher, userInfoMatcher: userInfoMatcher)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
extension NMBObjCMatcher {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ internal func identityAsString(value: AnyObject?) -> String {
|
|||
if value == nil {
|
||||
return "nil"
|
||||
}
|
||||
return NSString(format: "<%p>", unsafeBitCast(value!, Int.self))
|
||||
return NSString(format: "<%p>", unsafeBitCast(value!, Int.self)).description
|
||||
}
|
||||
|
||||
internal func arrayAsString<T>(items: [T], joiner: String = ", ") -> String {
|
||||
|
|
@ -41,8 +41,8 @@ extension NSArray : NMBStringer {
|
|||
}
|
||||
|
||||
internal func stringify<T>(value: T) -> String {
|
||||
if value is Double {
|
||||
return NSString(format: "%.4f", (value as Double))
|
||||
if let value = value as? Double {
|
||||
return NSString(format: "%.4f", (value)).description
|
||||
}
|
||||
return toString(value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,8 +2,14 @@ import Foundation
|
|||
|
||||
struct AsyncMatcherWrapper<T, U where U: Matcher, U.ValueType == T>: Matcher {
|
||||
let fullMatcher: U
|
||||
let timeoutInterval: NSTimeInterval = 1
|
||||
let pollInterval: NSTimeInterval = 0.01
|
||||
let timeoutInterval: NSTimeInterval
|
||||
let pollInterval: NSTimeInterval
|
||||
|
||||
init(fullMatcher: U, timeoutInterval: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
|
||||
self.fullMatcher = fullMatcher
|
||||
self.timeoutInterval = timeoutInterval
|
||||
self.pollInterval = pollInterval
|
||||
}
|
||||
|
||||
func matches(actualExpression: Expression<T>, failureMessage: FailureMessage) -> Bool {
|
||||
let uncachedExpression = actualExpression.withoutCaching()
|
||||
|
|
@ -34,25 +40,36 @@ struct AsyncMatcherWrapper<T, U where U: Matcher, U.ValueType == T>: Matcher {
|
|||
}
|
||||
}
|
||||
|
||||
private let toEventuallyRequiresClosureError = "expect(...).toEventually(...) requires an explicit closure (eg - expect { ... }.toEventually(...) )\nSwift 1.2 @autoclosure behavior has changed in an incompatible way for Nimble to function"
|
||||
|
||||
|
||||
extension Expectation {
|
||||
public func toEventually<U where U: Matcher, U.ValueType == T>(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
|
||||
to(AsyncMatcherWrapper(
|
||||
fullMatcher: FullMatcherWrapper(
|
||||
matcher: matcher,
|
||||
to: "to eventually",
|
||||
toNot: "to eventually not"),
|
||||
timeoutInterval: timeout,
|
||||
pollInterval: pollInterval))
|
||||
if expression.isClosure {
|
||||
to(AsyncMatcherWrapper(
|
||||
fullMatcher: FullMatcherWrapper(
|
||||
matcher: matcher,
|
||||
to: "to eventually",
|
||||
toNot: "to eventually not"),
|
||||
timeoutInterval: timeout,
|
||||
pollInterval: pollInterval))
|
||||
} else {
|
||||
verify(false, toEventuallyRequiresClosureError)
|
||||
}
|
||||
}
|
||||
|
||||
public func toEventuallyNot<U where U: Matcher, U.ValueType == T>(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
|
||||
toNot(AsyncMatcherWrapper(
|
||||
fullMatcher: FullMatcherWrapper(
|
||||
matcher: matcher,
|
||||
to: "to eventually",
|
||||
toNot: "to eventually not"),
|
||||
timeoutInterval: timeout,
|
||||
pollInterval: pollInterval))
|
||||
if expression.isClosure {
|
||||
toNot(AsyncMatcherWrapper(
|
||||
fullMatcher: FullMatcherWrapper(
|
||||
matcher: matcher,
|
||||
to: "to eventually",
|
||||
toNot: "to eventually not"),
|
||||
timeoutInterval: timeout,
|
||||
pollInterval: pollInterval))
|
||||
} else {
|
||||
verify(false, toEventuallyRequiresClosureError)
|
||||
}
|
||||
}
|
||||
|
||||
public func toEventually<U where U: BasicMatcher, U.ValueType == T>(matcher: U, timeout: NSTimeInterval = 1, pollInterval: NSTimeInterval = 0.01) {
|
||||
|
|
|
|||
|
|
@ -96,6 +96,10 @@ NIMBLE_EXPORT id<NMBMatcher> NMB_match(id expectedValue);
|
|||
NIMBLE_SHORT(id<NMBMatcher> match(id expectedValue),
|
||||
NMB_match(expectedValue));
|
||||
|
||||
NIMBLE_EXPORT id<NMBMatcher> NMB_allPass(id matcher);
|
||||
NIMBLE_SHORT(id<NMBMatcher> allPass(id matcher),
|
||||
NMB_allPass(matcher));
|
||||
|
||||
// In order to preserve breakpoint behavior despite using macros to fill in __FILE__ and __LINE__,
|
||||
// define a builder that populates __FILE__ and __LINE__, and returns a block that takes timeout
|
||||
// and action arguments. See https://github.com/Quick/Quick/pull/185 for details.
|
||||
|
|
|
|||
|
|
@ -84,18 +84,22 @@ NIMBLE_EXPORT id<NMBMatcher> NMB_match(id expectedValue) {
|
|||
return [NMBObjCMatcher matchMatcher:expectedValue];
|
||||
}
|
||||
|
||||
NIMBLE_EXPORT id<NMBMatcher> NMB_allPass(id expectedValue) {
|
||||
return [NMBObjCMatcher allPassMatcher:expectedValue];
|
||||
}
|
||||
|
||||
NIMBLE_EXPORT NMBObjCRaiseExceptionMatcher *NMB_raiseException() {
|
||||
return [NMBObjCMatcher raiseExceptionMatcher];
|
||||
}
|
||||
|
||||
NIMBLE_EXPORT NMBWaitUntilTimeoutBlock nmb_wait_until_timeout_builder(NSString *file, NSUInteger line) {
|
||||
return ^(NSTimeInterval timeout, void (^action)(void (^)(void))) {
|
||||
[NMBWait untilTimeout:timeout action:action file:file line:line];
|
||||
[NMBWait untilTimeout:timeout file:file line:line action:action];
|
||||
};
|
||||
}
|
||||
|
||||
NIMBLE_EXPORT NMBWaitUntilBlock nmb_wait_until_builder(NSString *file, NSUInteger line) {
|
||||
return ^(void (^action)(void (^)(void))) {
|
||||
[NMBWait until:action file:file line:line];
|
||||
[NMBWait untilFile:file line:line action:action];
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Nimble
|
||||
|
||||
[](https://travis-ci.org/Quick/Nimble)
|
||||
[](https://travis-ci.org/Quick/Nimble)
|
||||
|
||||
Use Nimble to express the expected outcomes of Swift
|
||||
or Objective-C expressions. Inspired by
|
||||
|
|
@ -40,6 +40,7 @@ expect(ocean.isClean).toEventually(beTruthy())
|
|||
- [Exceptions](#exceptions)
|
||||
- [Collection Membership](#collection-membership)
|
||||
- [Strings](#strings)
|
||||
- [Checking if all elements of a collection pass a condition](#checking-if-all-elements-of-a-collection-pass-a-condition)
|
||||
- [Writing Your Own Matchers](#writing-your-own-matchers)
|
||||
- [Lazy Evaluation](#lazy-evaluation)
|
||||
- [Type Checking via Swift Generics](#type-checking-via-swift-generics)
|
||||
|
|
@ -177,14 +178,14 @@ let exception = NSException(
|
|||
name: NSInternalInconsistencyException,
|
||||
reason: "Not enough fish in the sea.",
|
||||
userInfo: ["something": "is fishy"])
|
||||
expect(exception.raise()).to(raiseException())
|
||||
expect { exception.raise() }.to(raiseException())
|
||||
|
||||
// Also, you can customize raiseException to be more specific
|
||||
expect(exception.raise()).to(raiseException(named: NSInternalInconsistencyException))
|
||||
expect(exception.raise()).to(raiseException(
|
||||
expect { exception.raise() }.to(raiseException(named: NSInternalInconsistencyException))
|
||||
expect { exception.raise() }.to(raiseException(
|
||||
named: NSInternalInconsistencyException,
|
||||
reason: "Not enough fish in the sea"))
|
||||
expect(exception.raise()).to(raiseException(
|
||||
expect { exception.raise() }.to(raiseException(
|
||||
named: NSInternalInconsistencyException,
|
||||
reason: "Not enough fish in the sea",
|
||||
userInfo: ["something": "is fishy"]))
|
||||
|
|
@ -213,16 +214,6 @@ expectAction([exception raise]).to(raiseException().
|
|||
userInfo(@{@"something": @"is fishy"}));
|
||||
```
|
||||
|
||||
In Swift, the `expect` function can also take a trailing closure:
|
||||
|
||||
```swift
|
||||
// Swift
|
||||
|
||||
expect {
|
||||
exception.raise()
|
||||
}.to(raiseException(named: NSInternalInconsistencyException))
|
||||
```
|
||||
|
||||
## C Primitives
|
||||
|
||||
Some testing frameworks make it hard to test primitive C values.
|
||||
|
|
@ -639,6 +630,16 @@ expect(actual).to(raiseException(named: name))
|
|||
|
||||
// Passes if actual raises an exception with the given name and reason:
|
||||
expect(actual).to(raiseException(named: name, reason: reason))
|
||||
|
||||
// Passes if actual raises an exception with a name equal "a name"
|
||||
expect(actual).to(raiseException(named: equal("a name")))
|
||||
|
||||
// Passes if actual raises an exception with a reason that begins with "a r"
|
||||
expect(actual).to(raiseException(reason: beginWith("a r")))
|
||||
|
||||
// Passes if actual raises an exception with a name equal "a name"
|
||||
// and a reason that begins with "a r"
|
||||
expect(actual).to(raiseException(named: equal("a name"), reason: beginWith("a r")))
|
||||
```
|
||||
|
||||
```objc
|
||||
|
|
@ -646,13 +647,27 @@ expect(actual).to(raiseException(named: name, reason: reason))
|
|||
|
||||
// Passes if actual, when evaluated, raises an exception:
|
||||
expect(actual).to(raiseException())
|
||||
|
||||
// Passes if actual raises an exception with the given name
|
||||
expect(actual).to(raiseException().named(name))
|
||||
|
||||
// Passes if actual raises an exception with the given name and reason:
|
||||
expect(actual).to(raiseException().named(name).reason(reason))
|
||||
|
||||
// Passes if actual raises an exception with a name equal "a name"
|
||||
expect(actual).to(raiseException().withName(equal("a name")))
|
||||
|
||||
// Passes if actual raises an exception with a reason that begins with "a r"
|
||||
expect(actual).to(raiseException().withName(withReason(beginWith(@"a r")))
|
||||
|
||||
// Passes if actual raises an exception with a name equal "a name"
|
||||
// and a reason that begins with "a r"
|
||||
expect(actual).to(raiseException().withName(equal("a name")).withReason(beginWith(@"a r")))
|
||||
```
|
||||
|
||||
Note: Swift currently doesn't have exceptions. Only Objective-C code can raise
|
||||
exceptions that Nimble will catch.
|
||||
|
||||
> Sorry, [Nimble doesn't support matching on exception `name`, `reason`, or `userInfo` yet](https://github.com/Quick/Nimble/issues/26).
|
||||
|
||||
## Collection Membership
|
||||
|
||||
```swift
|
||||
|
|
@ -768,6 +783,29 @@ expect(actual).to(beEmpty());
|
|||
expect(actual).to(match(expected))
|
||||
```
|
||||
|
||||
## Checking if all elements of a collection pass a condition
|
||||
|
||||
```swift
|
||||
// Swift
|
||||
|
||||
// with a custom function:
|
||||
expect([1,2,3,4]).to(allPass({$0 < 5}))
|
||||
|
||||
// with another matcher:
|
||||
expect([1,2,3,4]).to(allPass(beLessThan(5)))
|
||||
```
|
||||
|
||||
```objc
|
||||
// Objective-C
|
||||
|
||||
expect(@[@1, @2, @3,@4]).to(allPass(beLessThan(@5)));
|
||||
```
|
||||
|
||||
For Swift the actual value has to be a SequenceType, e.g. an array, a set or a custom seqence type.
|
||||
|
||||
For Objective-C the actual value has to be a NSFastEnumeration, e.g. NSArray and NSSet, of NSObjects and only the variant which
|
||||
uses another matcher is available here.
|
||||
|
||||
# Writing Your Own Matchers
|
||||
|
||||
In Nimble, matchers are Swift functions that take an expected
|
||||
|
|
@ -807,9 +845,10 @@ also check out the tips below.
|
|||
|
||||
## Lazy Evaluation
|
||||
|
||||
`actualExpression` is a lazy, memoized closure around the value provided to
|
||||
the `expect` function. In order to determine whether that value matches,
|
||||
custom matchers should call `actualExpression.evalaute()`:
|
||||
`actualExpression` is a lazy, memoized closure around the value provided to the
|
||||
`expect` function. The expression can either be a closure or a value directly
|
||||
passed to `expect(...)`. In order to determine whether that value matches,
|
||||
custom matchers should call `actualExpression.evaluate()`:
|
||||
|
||||
```swift
|
||||
// Swift
|
||||
|
|
@ -827,6 +866,9 @@ that returns a value. The value it returns, which is accessed via the
|
|||
`evaluate()` method, may be `nil`. If that value is `nil`, the `beNil`
|
||||
matcher function returns `true`, indicating that the expectation passed.
|
||||
|
||||
Use `expression.isClosure` to determine if the expression will be invoking
|
||||
a closure to produce its value.
|
||||
|
||||
## Type Checking via Swift Generics
|
||||
|
||||
Using Swift's generics, matchers can constrain the type of the actual value
|
||||
|
|
@ -971,8 +1013,9 @@ extension NMBObjCMatcher {
|
|||
Quick and Nimble, follow [the installation instructions in the Quick
|
||||
README](https://github.com/Quick/Quick#how-to-install-quick).
|
||||
|
||||
Nimble can currently be installed in one of two ways: using a pre-release
|
||||
version of CocoaPods, or with git submodules.
|
||||
Nimble can currently be installed in one of two ways: using CocoaPods, or with git submodules. The master branch of
|
||||
Nimble supports Swift 1.2. For Swift 1.1 support, use the `swift-1.1`
|
||||
branch.
|
||||
|
||||
## Installing Nimble as a Submodule
|
||||
|
||||
|
|
@ -980,7 +1023,7 @@ To use Nimble as a submodule to test your iOS or OS X applications, follow these
|
|||
4 easy steps:
|
||||
|
||||
1. Clone the Nimble repository
|
||||
2. Add Nimble.xcodeproj to your test target
|
||||
2. Add Nimble.xcodeproj to the Xcode workspace for your project
|
||||
3. Link Nimble.framework to your test target
|
||||
4. Start writing expectations!
|
||||
|
||||
|
|
@ -991,9 +1034,8 @@ install just Nimble.
|
|||
|
||||
## Installing Nimble via CocoaPods
|
||||
|
||||
To use Nimble in CocoaPods to test your iOS or OS X applications, we'll need to
|
||||
install 0.36 Beta 1 of CocoaPods. Do so using the command `[sudo] gem install cocoapods --pre`.
|
||||
Then just add Nimble to your podfile.
|
||||
To use Nimble in CocoaPods to test your iOS or OS X applications, update CocoaPods to Version 0.36.0.
|
||||
Then add Nimble to your podfile and add the ```use_frameworks!``` line to enable Swift support for Cocoapods.
|
||||
|
||||
```ruby
|
||||
platform :ios, '8.0'
|
||||
|
|
@ -1003,8 +1045,12 @@ source 'https://github.com/CocoaPods/Specs.git'
|
|||
# Whatever pods you need for your app go here
|
||||
|
||||
target 'YOUR_APP_NAME_HERE_Tests', :exclusive => true do
|
||||
pod 'Nimble'
|
||||
use_frameworks!
|
||||
# If you're using Swift 1.2 (Xcode 6.3 beta), use this:
|
||||
pod 'Nimble', '~> 0.4.0'
|
||||
# Otherwise, use this commented out line for Swift 1.1 (Xcode 6.2):
|
||||
# pod 'Nimble', '~> 0.3.0'
|
||||
end
|
||||
```
|
||||
|
||||
Finally run `bundle exec pod install`.
|
||||
Finally run `pod install`.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0510"
|
||||
LastUpgradeVersion = "0640"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "03098993B86EADB31B473BE6"
|
||||
BlueprintIdentifier = "F31DCF4BC1F75A477673D8D8"
|
||||
BuildableName = "Nimble.framework"
|
||||
BlueprintName = "Pods-cameraTests-Nimble"
|
||||
ReferencedContainer = "container:Pods.xcodeproj">
|
||||
|
|
|
|||
|
|
@ -1,59 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0510"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "63EE31CFA4335E182795B62C"
|
||||
BuildableName = "Quick.framework"
|
||||
BlueprintName = "Pods-cameraTests-Quick"
|
||||
ReferencedContainer = "container:Pods.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
buildConfiguration = "Debug">
|
||||
<Testables>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Debug"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
allowLocationSimulation = "YES">
|
||||
<AdditionalOptions>
|
||||
</AdditionalOptions>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
buildConfiguration = "Release"
|
||||
debugDocumentVersioning = "YES">
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "0510"
|
||||
LastUpgradeVersion = "0640"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "13DE2AA1E6F090FB14C78F4F"
|
||||
BlueprintIdentifier = "5450F12D18236260DBDC1426"
|
||||
BuildableName = "Pods_cameraTests.framework"
|
||||
BlueprintName = "Pods-cameraTests"
|
||||
ReferencedContainer = "container:Pods.xcodeproj">
|
||||
|
|
|
|||
|
|
@ -9,11 +9,6 @@
|
|||
<key>isShown</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Pods-cameraTests-Quick.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
<false/>
|
||||
</dict>
|
||||
<key>Pods-cameraTests.xcscheme</key>
|
||||
<dict>
|
||||
<key>isShown</key>
|
||||
|
|
@ -22,17 +17,12 @@
|
|||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
<dict>
|
||||
<key>03098993B86EADB31B473BE6</key>
|
||||
<key>5450F12D18236260DBDC1426</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>13DE2AA1E6F090FB14C78F4F</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>63EE31CFA4335E182795B62C</key>
|
||||
<key>F31DCF4BC1F75A477673D8D8</key>
|
||||
<dict>
|
||||
<key>primary</key>
|
||||
<true/>
|
||||
|
|
|
|||
|
|
@ -1,201 +0,0 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014, Quick Team
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
/**
|
||||
An object encapsulating the file and line number at which
|
||||
a particular example is defined.
|
||||
*/
|
||||
@objc final public class Callsite: Equatable {
|
||||
/**
|
||||
The absolute path of the file in which an example is defined.
|
||||
*/
|
||||
public let file: String
|
||||
|
||||
/**
|
||||
The line number on which an example is defined.
|
||||
*/
|
||||
public let line: Int
|
||||
|
||||
internal init(file: String, line: Int) {
|
||||
self.file = file
|
||||
self.line = line
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a boolean indicating whether two Callsite objects are equal.
|
||||
If two callsites are in the same file and on the same line, they must be equal.
|
||||
*/
|
||||
public func ==(lhs: Callsite, rhs: Callsite) -> Bool {
|
||||
return lhs.file == rhs.file && lhs.line == rhs.line
|
||||
}
|
||||
|
|
@ -1,147 +0,0 @@
|
|||
/**
|
||||
A closure that temporarily exposes a Configuration object within
|
||||
the scope of the closure.
|
||||
*/
|
||||
public typealias QuickConfigurer = (configuration: Configuration) -> ()
|
||||
|
||||
/**
|
||||
A closure that, given metadata about an example, returns a boolean value
|
||||
indicating whether that example should be run.
|
||||
*/
|
||||
public typealias ExampleFilter = (example: Example) -> Bool
|
||||
|
||||
/**
|
||||
A configuration encapsulates various options you can use
|
||||
to configure Quick's behavior.
|
||||
*/
|
||||
@objc final public class Configuration {
|
||||
internal let exampleHooks = ExampleHooks()
|
||||
internal let suiteHooks = SuiteHooks()
|
||||
internal var exclusionFilters: [ExampleFilter] = [{ example in
|
||||
if let pending = example.filterFlags[Filter.pending] {
|
||||
return pending
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}]
|
||||
internal var inclusionFilters: [ExampleFilter] = [{ example in
|
||||
if let focused = example.filterFlags[Filter.focused] {
|
||||
return focused
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}]
|
||||
|
||||
/**
|
||||
Run all examples if none match the configured filters. True by default.
|
||||
*/
|
||||
public var runAllWhenEverythingFiltered = true
|
||||
|
||||
/**
|
||||
Registers an inclusion filter.
|
||||
|
||||
All examples are filtered using all inclusion filters.
|
||||
The remaining examples are run. If no examples remain, all examples are run.
|
||||
|
||||
:param: filter A filter that, given an example, returns a value indicating
|
||||
whether that example should be included in the examples
|
||||
that are run.
|
||||
*/
|
||||
public func include(filter: ExampleFilter) {
|
||||
inclusionFilters.append(filter)
|
||||
}
|
||||
|
||||
/**
|
||||
Registers an exclusion filter.
|
||||
|
||||
All examples that remain after being filtered by the inclusion filters are
|
||||
then filtered via all exclusion filters.
|
||||
|
||||
:param: filter A filter that, given an example, returns a value indicating
|
||||
whether that example should be excluded from the examples
|
||||
that are run.
|
||||
*/
|
||||
public func exclude(filter: ExampleFilter) {
|
||||
exclusionFilters.append(filter)
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to Quick.Configuration.beforeEach, except the closure is
|
||||
provided with metadata on the example that the closure is being run
|
||||
prior to.
|
||||
*/
|
||||
@objc(beforeEachWithMetadata:)
|
||||
public func beforeEach(closure: BeforeExampleWithMetadataClosure) {
|
||||
exampleHooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Like Quick.DSL.beforeEach, this configures Quick to execute the
|
||||
given closure before each example that is run. The closure
|
||||
passed to this method is executed before each example Quick runs,
|
||||
globally across the test suite. You may call this method multiple
|
||||
times across mulitple +[QuickConfigure configure:] methods in order
|
||||
to define several closures to run before each example.
|
||||
|
||||
Note that, since Quick makes no guarantee as to the order in which
|
||||
+[QuickConfiguration configure:] methods are evaluated, there is no
|
||||
guarantee as to the order in which beforeEach closures are evaluated
|
||||
either. Mulitple beforeEach defined on a single configuration, however,
|
||||
will be executed in the order they're defined.
|
||||
|
||||
:param: closure The closure to be executed before each example
|
||||
in the test suite.
|
||||
*/
|
||||
public func beforeEach(closure: BeforeExampleClosure) {
|
||||
exampleHooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to Quick.Configuration.afterEach, except the closure
|
||||
is provided with metadata on the example that the closure is being
|
||||
run after.
|
||||
*/
|
||||
@objc(afterEachWithMetadata:)
|
||||
public func afterEach(closure: AfterExampleWithMetadataClosure) {
|
||||
exampleHooks.appendAfter(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Like Quick.DSL.afterEach, this configures Quick to execute the
|
||||
given closure after each example that is run. The closure
|
||||
passed to this method is executed after each example Quick runs,
|
||||
globally across the test suite. You may call this method multiple
|
||||
times across mulitple +[QuickConfigure configure:] methods in order
|
||||
to define several closures to run after each example.
|
||||
|
||||
Note that, since Quick makes no guarantee as to the order in which
|
||||
+[QuickConfiguration configure:] methods are evaluated, there is no
|
||||
guarantee as to the order in which afterEach closures are evaluated
|
||||
either. Mulitple afterEach defined on a single configuration, however,
|
||||
will be executed in the order they're defined.
|
||||
|
||||
:param: closure The closure to be executed before each example
|
||||
in the test suite.
|
||||
*/
|
||||
public func afterEach(closure: AfterExampleClosure) {
|
||||
exampleHooks.appendAfter(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Like Quick.DSL.beforeSuite, this configures Quick to execute
|
||||
the given closure prior to any and all examples that are run.
|
||||
The two methods are functionally equivalent.
|
||||
*/
|
||||
public func beforeSuite(closure: BeforeSuiteClosure) {
|
||||
suiteHooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Like Quick.DSL.afterSuite, this configures Quick to execute
|
||||
the given closure after all examples have been run.
|
||||
The two methods are functionally equivalent.
|
||||
*/
|
||||
public func afterSuite(closure: AfterSuiteClosure) {
|
||||
suiteHooks.appendAfter(closure)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class Configuration;
|
||||
|
||||
/**
|
||||
Subclass QuickConfiguration and override the +[QuickConfiguration configure:]
|
||||
method in order to configure how Quick behaves when running specs, or to define
|
||||
shared examples that are used across spec files.
|
||||
*/
|
||||
@interface QuickConfiguration : NSObject
|
||||
|
||||
/**
|
||||
This method is executed on each subclass of this class before Quick runs
|
||||
any examples. You may override this method on as many subclasses as you like, but
|
||||
there is no guarantee as to the order in which these methods are executed.
|
||||
|
||||
You can override this method in order to:
|
||||
|
||||
1. Configure how Quick behaves, by modifying properties on the Configuration object.
|
||||
Setting the same properties in several methods has undefined behavior.
|
||||
|
||||
2. Define shared examples using `sharedExamples`.
|
||||
|
||||
@param configuration A mutable object that is used to configure how Quick behaves on
|
||||
a framework level. For details on all the options, see the
|
||||
documentation in Configuration.swift.
|
||||
*/
|
||||
+ (void)configure:(Configuration *)configuration;
|
||||
|
||||
@end
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
#import "QuickConfiguration.h"
|
||||
#import <Quick/Quick-Swift.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
typedef void (^QCKClassEnumerationBlock)(Class klass);
|
||||
|
||||
/**
|
||||
Finds all direct subclasses of the given class and passes them to the block provided.
|
||||
The classes are iterated over in the order that objc_getClassList returns them.
|
||||
|
||||
@param klass The base class to find subclasses of.
|
||||
@param block A block that takes a Class. This block will be executed once for each subclass of klass.
|
||||
*/
|
||||
void qck_enumerateSubclasses(Class klass, QCKClassEnumerationBlock block) {
|
||||
Class *classes = NULL;
|
||||
int classesCount = objc_getClassList(NULL, 0);
|
||||
|
||||
if (classesCount > 0) {
|
||||
classes = (Class *)calloc(sizeof(Class), classesCount);
|
||||
classesCount = objc_getClassList(classes, classesCount);
|
||||
|
||||
Class subclass, superclass;
|
||||
for(int i = 0; i < classesCount; i++) {
|
||||
subclass = classes[i];
|
||||
superclass = class_getSuperclass(subclass);
|
||||
if (superclass == klass && block) {
|
||||
block(subclass);
|
||||
}
|
||||
}
|
||||
|
||||
free(classes);
|
||||
}
|
||||
}
|
||||
|
||||
@implementation QuickConfiguration
|
||||
|
||||
#pragma mark - Object Lifecycle
|
||||
|
||||
/**
|
||||
QuickConfiguration is not meant to be instantiated; it merely provides a hook
|
||||
for users to configure how Quick behaves. Raise an exception if an instance of
|
||||
QuickConfiguration is created.
|
||||
*/
|
||||
- (instancetype)init {
|
||||
NSString *className = NSStringFromClass([self class]);
|
||||
NSString *selectorName = NSStringFromSelector(@selector(configure:));
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"%@ is not meant to be instantiated; "
|
||||
@"subclass %@ and override %@ to configure Quick.",
|
||||
className, className, selectorName];
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark - NSObject Overrides
|
||||
|
||||
/**
|
||||
Hook into when QuickConfiguration is initialized in the runtime in order to
|
||||
call +[QuickConfiguration configure:] on each of its subclasses.
|
||||
*/
|
||||
+ (void)initialize {
|
||||
// Only enumerate over the subclasses of QuickConfiguration, not any of its subclasses.
|
||||
if ([self class] == [QuickConfiguration class]) {
|
||||
|
||||
// Only enumerate over subclasses once, even if +[QuickConfiguration initialize]
|
||||
// were to be called several times. This is necessary because +[QuickSpec initialize]
|
||||
// manually calls +[QuickConfiguration initialize].
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
qck_enumerateSubclasses([QuickConfiguration class], ^(__unsafe_unretained Class klass) {
|
||||
[[World sharedWorld] configure:^(Configuration *configuration) {
|
||||
[klass configure:configuration];
|
||||
}];
|
||||
});
|
||||
[[World sharedWorld] finalizeConfiguration];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Public Interface
|
||||
|
||||
+ (void)configure:(Configuration *)configuration { }
|
||||
|
||||
@end
|
||||
|
|
@ -1,227 +0,0 @@
|
|||
/**
|
||||
Defines a closure to be run prior to any examples in the test suite.
|
||||
You may define an unlimited number of these closures, but there is no
|
||||
guarantee as to the order in which they're run.
|
||||
|
||||
If the test suite crashes before the first example is run, this closure
|
||||
will not be executed.
|
||||
|
||||
:param: closure The closure to be run prior to any examples in the test suite.
|
||||
*/
|
||||
public func beforeSuite(closure: BeforeSuiteClosure) {
|
||||
World.sharedWorld().beforeSuite(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a closure to be run after all of the examples in the test suite.
|
||||
You may define an unlimited number of these closures, but there is no
|
||||
guarantee as to the order in which they're run.
|
||||
|
||||
If the test suite crashes before all examples are run, this closure
|
||||
will not be executed.
|
||||
|
||||
:param: closure The closure to be run after all of the examples in the test suite.
|
||||
*/
|
||||
public func afterSuite(closure: AfterSuiteClosure) {
|
||||
World.sharedWorld().afterSuite(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a group of shared examples. These examples can be re-used in several locations
|
||||
by using the `itBehavesLike` function.
|
||||
|
||||
:param: name The name of the shared example group. This must be unique across all shared example
|
||||
groups defined in a test suite.
|
||||
:param: closure A closure containing the examples. This behaves just like an example group defined
|
||||
using `describe` or `context`--the closure may contain any number of `beforeEach`
|
||||
and `afterEach` closures, as well as any number of examples (defined using `it`).
|
||||
*/
|
||||
public func sharedExamples(name: String, closure: () -> ()) {
|
||||
World.sharedWorld().sharedExamples(name, closure: { (NSDictionary) in closure() })
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a group of shared examples. These examples can be re-used in several locations
|
||||
by using the `itBehavesLike` function.
|
||||
|
||||
:param: name The name of the shared example group. This must be unique across all shared example
|
||||
groups defined in a test suite.
|
||||
:param: closure A closure containing the examples. This behaves just like an example group defined
|
||||
using `describe` or `context`--the closure may contain any number of `beforeEach`
|
||||
and `afterEach` closures, as well as any number of examples (defined using `it`).
|
||||
|
||||
The closure takes a SharedExampleContext as an argument. This context is a function
|
||||
that can be executed to retrieve parameters passed in via an `itBehavesLike` function.
|
||||
*/
|
||||
public func sharedExamples(name: String, closure: SharedExampleClosure) {
|
||||
World.sharedWorld().sharedExamples(name, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example group. Example groups are logical groupings of examples.
|
||||
Example groups can share setup and teardown code.
|
||||
|
||||
:param: description An arbitrary string describing the example group.
|
||||
:param: closure A closure that can contain other examples.
|
||||
:param: flags A mapping of string keys to booleans that can be used to filter examples or example groups.
|
||||
*/
|
||||
public func describe(description: String, closure: () -> (), flags: FilterFlags = [:]) {
|
||||
World.sharedWorld().describe(description, closure: closure, flags: flags)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example group. Equivalent to `describe`.
|
||||
*/
|
||||
public func context(description: String, closure: () -> (), flags: FilterFlags = [:]) {
|
||||
describe(description, closure, flags: flags)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a closure to be run prior to each example in the current example
|
||||
group. This closure is not run for pending or otherwise disabled examples.
|
||||
An example group may contain an unlimited number of beforeEach. They'll be
|
||||
run in the order they're defined, but you shouldn't rely on that behavior.
|
||||
|
||||
:param: closure The closure to be run prior to each example.
|
||||
*/
|
||||
public func beforeEach(closure: BeforeExampleClosure) {
|
||||
World.sharedWorld().beforeEach(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to Quick.DSL.beforeEach, except the closure is provided with
|
||||
metadata on the example that the closure is being run prior to.
|
||||
*/
|
||||
public func beforeEach(#closure: BeforeExampleWithMetadataClosure) {
|
||||
World.sharedWorld().beforeEach(closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a closure to be run after each example in the current example
|
||||
group. This closure is not run for pending or otherwise disabled examples.
|
||||
An example group may contain an unlimited number of afterEach. They'll be
|
||||
run in the order they're defined, but you shouldn't rely on that behavior.
|
||||
|
||||
:param: closure The closure to be run after each example.
|
||||
*/
|
||||
public func afterEach(closure: AfterExampleClosure) {
|
||||
World.sharedWorld().afterEach(closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Identical to Quick.DSL.afterEach, except the closure is provided with
|
||||
metadata on the example that the closure is being run after.
|
||||
*/
|
||||
public func afterEach(#closure: AfterExampleWithMetadataClosure) {
|
||||
World.sharedWorld().afterEach(closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example. Examples use assertions to demonstrate how code should
|
||||
behave. These are like "tests" in XCTest.
|
||||
|
||||
:param: description An arbitrary string describing what the example is meant to specify.
|
||||
:param: closure A closure that can contain assertions.
|
||||
:param: flags A mapping of string keys to booleans that can be used to filter examples or example groups.
|
||||
Empty by default.
|
||||
:param: file The absolute path to the file containing the example. A sensible default is provided.
|
||||
:param: line The line containing the example. A sensible default is provided.
|
||||
*/
|
||||
public func it(description: String, closure: () -> (), flags: FilterFlags = [:], file: String = __FILE__, line: Int = __LINE__) {
|
||||
World.sharedWorld().it(description, flags: flags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Inserts the examples defined using a `sharedExamples` function into the current example group.
|
||||
The shared examples are executed at this location, as if they were written out manually.
|
||||
|
||||
:param: name The name of the shared examples group to be executed. This must be identical to the
|
||||
name of a shared examples group defined using `sharedExamples`. If there are no shared
|
||||
examples that match the name given, an exception is thrown and the test suite will crash.
|
||||
:param: flags A mapping of string keys to booleans that can be used to filter examples or example groups.
|
||||
Empty by default.
|
||||
:param: file The absolute path to the file containing the current example group. A sensible default is provided.
|
||||
:param: line The line containing the current example group. A sensible default is provided.
|
||||
*/
|
||||
public func itBehavesLike(name: String, flags: FilterFlags = [:], file: String = __FILE__, line: Int = __LINE__) {
|
||||
itBehavesLike(name, { return [:] }, flags: flags, file: file, line: line)
|
||||
}
|
||||
|
||||
/**
|
||||
Inserts the examples defined using a `sharedExamples` function into the current example group.
|
||||
The shared examples are executed at this location, as if they were written out manually.
|
||||
This function also passes those shared examples a context that can be evaluated to give the shared
|
||||
examples extra information on the subject of the example.
|
||||
|
||||
:param: name The name of the shared examples group to be executed. This must be identical to the
|
||||
name of a shared examples group defined using `sharedExamples`. If there are no shared
|
||||
examples that match the name given, an exception is thrown and the test suite will crash.
|
||||
:param: sharedExampleContext A closure that, when evaluated, returns key-value pairs that provide the
|
||||
shared examples with extra information on the subject of the example.
|
||||
:param: flags A mapping of string keys to booleans that can be used to filter examples or example groups.
|
||||
Empty by default.
|
||||
:param: file The absolute path to the file containing the current example group. A sensible default is provided.
|
||||
:param: line The line containing the current example group. A sensible default is provided.
|
||||
*/
|
||||
public func itBehavesLike(name: String, sharedExampleContext: SharedExampleContext, flags: FilterFlags = [:], file: String = __FILE__, line: Int = __LINE__) {
|
||||
World.sharedWorld().itBehavesLike(name, sharedExampleContext: sharedExampleContext, flags: flags, file: file, line: line)
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example or example group that should not be executed. Use `pending` to temporarily disable
|
||||
examples or groups that should not be run yet.
|
||||
|
||||
:param: description An arbitrary string describing the example or example group.
|
||||
:param: closure A closure that will not be evaluated.
|
||||
*/
|
||||
public func pending(description: String, closure: () -> ()) {
|
||||
World.sharedWorld().pending(description, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark a `describe` closure as pending.
|
||||
This disables all examples within the closure.
|
||||
*/
|
||||
public func xdescribe(description: String, closure: () -> (), flags: FilterFlags) {
|
||||
World.sharedWorld().xdescribe(description, closure: closure, flags: flags)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark a `context` closure as pending.
|
||||
This disables all examples within the closure.
|
||||
*/
|
||||
public func xcontext(description: String, closure: () -> (), flags: FilterFlags) {
|
||||
xdescribe(description, closure, flags)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark an `it` closure as pending.
|
||||
This disables the example and ensures the code within the closure is never run.
|
||||
*/
|
||||
public func xit(description: String, closure: () -> (), flags: FilterFlags = [:], file: String = __FILE__, line: Int = __LINE__) {
|
||||
World.sharedWorld().xit(description, flags: flags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus a `describe` closure, focusing the examples in the closure.
|
||||
If any examples in the test suite are focused, only those examples are executed.
|
||||
This trumps any explicitly focused or unfocused examples within the closure--they are all treated as focused.
|
||||
*/
|
||||
public func fdescribe(description: String, closure: () -> (), flags: FilterFlags = [:]) {
|
||||
World.sharedWorld().fdescribe(description, closure: closure, flags: flags)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus a `context` closure. Equivalent to `fdescribe`.
|
||||
*/
|
||||
public func fcontext(description: String, closure: () -> (), flags: FilterFlags = [:]) {
|
||||
fdescribe(description, closure, flags: flags)
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus an `it` closure, focusing the example.
|
||||
If any examples in the test suite are focused, only those examples are executed.
|
||||
*/
|
||||
public func fit(description: String, closure: () -> (), flags: FilterFlags = [:], file: String = __FILE__, line: Int = __LINE__) {
|
||||
World.sharedWorld().fit(description, flags: flags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
|
@ -1,211 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
Provides a hook for Quick to be configured before any examples are run.
|
||||
Within this scope, override the +[QuickConfiguration configure:] method
|
||||
to set properties on a configuration object to customize Quick behavior.
|
||||
For details, see the documentation for Configuraiton.swift.
|
||||
|
||||
@param name The name of the configuration class. Like any Objective-C
|
||||
class name, this must be unique to the current runtime
|
||||
environment.
|
||||
*/
|
||||
#define QuickConfigurationBegin(name) \
|
||||
@interface name : QuickConfiguration; @end \
|
||||
@implementation name \
|
||||
|
||||
|
||||
/**
|
||||
Marks the end of a Quick configuration.
|
||||
Make sure you put this after `QuickConfigurationBegin`.
|
||||
*/
|
||||
#define QuickConfigurationEnd \
|
||||
@end \
|
||||
|
||||
|
||||
/**
|
||||
Defines a new QuickSpec. Define examples and example groups within the space
|
||||
between this and `QuickSpecEnd`.
|
||||
|
||||
@param name The name of the spec class. Like any Objective-C class name, this
|
||||
must be unique to the current runtime environment.
|
||||
*/
|
||||
#define QuickSpecBegin(name) \
|
||||
@interface name : QuickSpec; @end \
|
||||
@implementation name \
|
||||
- (void)spec { \
|
||||
|
||||
|
||||
/**
|
||||
Marks the end of a QuickSpec. Make sure you put this after `QuickSpecBegin`.
|
||||
*/
|
||||
#define QuickSpecEnd \
|
||||
} \
|
||||
@end \
|
||||
|
||||
typedef NSDictionary *(^QCKDSLSharedExampleContext)(void);
|
||||
typedef void (^QCKDSLSharedExampleBlock)(QCKDSLSharedExampleContext);
|
||||
typedef void (^QCKDSLEmptyBlock)(void);
|
||||
|
||||
extern void qck_beforeSuite(QCKDSLEmptyBlock closure);
|
||||
extern void qck_afterSuite(QCKDSLEmptyBlock closure);
|
||||
extern void qck_sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure);
|
||||
extern void qck_describe(NSString *description, QCKDSLEmptyBlock closure);
|
||||
extern void qck_context(NSString *description, QCKDSLEmptyBlock closure);
|
||||
extern void qck_beforeEach(QCKDSLEmptyBlock closure);
|
||||
extern void qck_afterEach(QCKDSLEmptyBlock closure);
|
||||
extern void qck_pending(NSString *description, QCKDSLEmptyBlock closure);
|
||||
extern void qck_xdescribe(NSString *description, QCKDSLEmptyBlock closure);
|
||||
extern void qck_xcontext(NSString *description, QCKDSLEmptyBlock closure);
|
||||
extern void qck_fdescribe(NSString *description, QCKDSLEmptyBlock closure);
|
||||
extern void qck_fcontext(NSString *description, QCKDSLEmptyBlock closure);
|
||||
|
||||
#ifndef QUICK_DISABLE_SHORT_SYNTAX
|
||||
/**
|
||||
Defines a closure to be run prior to any examples in the test suite.
|
||||
You may define an unlimited number of these closures, but there is no
|
||||
guarantee as to the order in which they're run.
|
||||
|
||||
If the test suite crashes before the first example is run, this closure
|
||||
will not be executed.
|
||||
|
||||
@param closure The closure to be run prior to any examples in the test suite.
|
||||
*/
|
||||
static inline void beforeSuite(QCKDSLEmptyBlock closure) {
|
||||
qck_beforeSuite(closure);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Defines a closure to be run after all of the examples in the test suite.
|
||||
You may define an unlimited number of these closures, but there is no
|
||||
guarantee as to the order in which they're run.
|
||||
|
||||
If the test suite crashes before all examples are run, this closure
|
||||
will not be executed.
|
||||
|
||||
@param closure The closure to be run after all of the examples in the test suite.
|
||||
*/
|
||||
static inline void afterSuite(QCKDSLEmptyBlock closure) {
|
||||
qck_afterSuite(closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a group of shared examples. These examples can be re-used in several locations
|
||||
by using the `itBehavesLike` function.
|
||||
|
||||
@param name The name of the shared example group. This must be unique across all shared example
|
||||
groups defined in a test suite.
|
||||
@param closure A closure containing the examples. This behaves just like an example group defined
|
||||
using `describe` or `context`--the closure may contain any number of `beforeEach`
|
||||
and `afterEach` closures, as well as any number of examples (defined using `it`).
|
||||
*/
|
||||
static inline void sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure) {
|
||||
qck_sharedExamples(name, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example group. Example groups are logical groupings of examples.
|
||||
Example groups can share setup and teardown code.
|
||||
|
||||
@param description An arbitrary string describing the example group.
|
||||
@param closure A closure that can contain other examples.
|
||||
*/
|
||||
static inline void describe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_describe(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example group. Equivalent to `describe`.
|
||||
*/
|
||||
static inline void context(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_context(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a closure to be run prior to each example in the current example
|
||||
group. This closure is not run for pending or otherwise disabled examples.
|
||||
An example group may contain an unlimited number of beforeEach. They'll be
|
||||
run in the order they're defined, but you shouldn't rely on that behavior.
|
||||
|
||||
@param closure The closure to be run prior to each example.
|
||||
*/
|
||||
static inline void beforeEach(QCKDSLEmptyBlock closure) {
|
||||
qck_beforeEach(closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines a closure to be run after each example in the current example
|
||||
group. This closure is not run for pending or otherwise disabled examples.
|
||||
An example group may contain an unlimited number of afterEach. They'll be
|
||||
run in the order they're defined, but you shouldn't rely on that behavior.
|
||||
|
||||
@param closure The closure to be run after each example.
|
||||
*/
|
||||
static inline void afterEach(QCKDSLEmptyBlock closure) {
|
||||
qck_afterEach(closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Defines an example or example group that should not be executed. Use `pending` to temporarily disable
|
||||
examples or groups that should not be run yet.
|
||||
|
||||
@param description An arbitrary string describing the example or example group.
|
||||
@param closure A closure that will not be evaluated.
|
||||
*/
|
||||
static inline void pending(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_pending(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark a `describe` block as pending.
|
||||
This disables all examples within the block.
|
||||
*/
|
||||
static inline void xdescribe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_xdescribe(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly mark a `context` block as pending.
|
||||
This disables all examples within the block.
|
||||
*/
|
||||
static inline void xcontext(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_xcontext(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus a `describe` block, focusing the examples in the block.
|
||||
If any examples in the test suite are focused, only those examples are executed.
|
||||
This trumps any explicitly focused or unfocused examples within the block--they are all treated as focused.
|
||||
*/
|
||||
static inline void fdescribe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_fdescribe(description, closure);
|
||||
}
|
||||
|
||||
/**
|
||||
Use this to quickly focus a `context` block. Equivalent to `fdescribe`.
|
||||
*/
|
||||
static inline void fcontext(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_fcontext(description, closure);
|
||||
}
|
||||
|
||||
#define it qck_it
|
||||
#define xit qck_xit
|
||||
#define fit qck_fit
|
||||
#define itBehavesLike qck_itBehavesLike
|
||||
#define xitBehavesLike qck_xitBehavesLike
|
||||
#define fitBehavesLike qck_fitBehavesLike
|
||||
#endif
|
||||
|
||||
#define qck_it qck_it_builder(@{}, @(__FILE__), __LINE__)
|
||||
#define qck_xit qck_it_builder(@{Filter.pending: @YES}, @(__FILE__), __LINE__)
|
||||
#define qck_fit qck_it_builder(@{Filter.focused: @YES}, @(__FILE__), __LINE__)
|
||||
#define qck_itBehavesLike qck_itBehavesLike_builder(@{}, @(__FILE__), __LINE__)
|
||||
#define qck_xitBehavesLike qck_itBehavesLike_builder(@{Filter.pending: @YES}, @(__FILE__), __LINE__)
|
||||
#define qck_fitBehavesLike qck_itBehavesLike_builder(@{Filter.focused: @YES}, @(__FILE__), __LINE__)
|
||||
|
||||
typedef void (^QCKItBlock)(NSString *description, QCKDSLEmptyBlock closure);
|
||||
typedef void (^QCKItBehavesLikeBlock)(NSString *description, QCKDSLSharedExampleContext context);
|
||||
|
||||
extern QCKItBlock qck_it_builder(NSDictionary *flags, NSString *file, NSUInteger line);
|
||||
extern QCKItBehavesLikeBlock qck_itBehavesLike_builder(NSDictionary *flags, NSString *file, NSUInteger line);
|
||||
|
|
@ -1,70 +0,0 @@
|
|||
#import "QCKDSL.h"
|
||||
#import <Quick/Quick-Swift.h>
|
||||
|
||||
void qck_beforeSuite(QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] beforeSuite:closure];
|
||||
}
|
||||
|
||||
void qck_afterSuite(QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] afterSuite:closure];
|
||||
}
|
||||
|
||||
void qck_sharedExamples(NSString *name, QCKDSLSharedExampleBlock closure) {
|
||||
[[World sharedWorld] sharedExamples:name closure:closure];
|
||||
}
|
||||
|
||||
void qck_describe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] describe:description closure:closure flags:@{}];
|
||||
}
|
||||
|
||||
void qck_context(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_describe(description, closure);
|
||||
}
|
||||
|
||||
void qck_beforeEach(QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] beforeEach:closure];
|
||||
}
|
||||
|
||||
void qck_afterEach(QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] afterEach:closure];
|
||||
}
|
||||
|
||||
QCKItBlock qck_it_builder(NSDictionary *flags, NSString *file, NSUInteger line) {
|
||||
return ^(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] itWithDescription:description
|
||||
flags:flags
|
||||
file:file
|
||||
line:line
|
||||
closure:closure];
|
||||
};
|
||||
}
|
||||
|
||||
QCKItBehavesLikeBlock qck_itBehavesLike_builder(NSDictionary *flags, NSString *file, NSUInteger line) {
|
||||
return ^(NSString *name, QCKDSLSharedExampleContext context) {
|
||||
[[World sharedWorld] itBehavesLikeSharedExampleNamed:name
|
||||
sharedExampleContext:context
|
||||
flags:flags
|
||||
file:file
|
||||
line:line];
|
||||
};
|
||||
}
|
||||
|
||||
void qck_pending(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] pending:description closure:closure];
|
||||
}
|
||||
|
||||
void qck_xdescribe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] xdescribe:description closure:closure flags:@{}];
|
||||
}
|
||||
|
||||
void qck_xcontext(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_xdescribe(description, closure);
|
||||
}
|
||||
|
||||
void qck_fdescribe(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
[[World sharedWorld] fdescribe:description closure:closure flags:@{}];
|
||||
}
|
||||
|
||||
void qck_fcontext(NSString *description, QCKDSLEmptyBlock closure) {
|
||||
qck_fdescribe(description, closure);
|
||||
}
|
||||
|
|
@ -1,100 +0,0 @@
|
|||
/**
|
||||
Adds methods to World to support top-level DSL functions (Swift) and
|
||||
macros (Objective-C). These functions map directly to the DSL that test
|
||||
writers use in their specs.
|
||||
*/
|
||||
extension World {
|
||||
public func beforeSuite(closure: BeforeSuiteClosure) {
|
||||
suiteHooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
public func afterSuite(closure: AfterSuiteClosure) {
|
||||
suiteHooks.appendAfter(closure)
|
||||
}
|
||||
|
||||
public func sharedExamples(name: String, closure: SharedExampleClosure) {
|
||||
registerSharedExample(name, closure: closure)
|
||||
}
|
||||
|
||||
public func describe(description: String, closure: () -> (), flags: FilterFlags) {
|
||||
var group = ExampleGroup(description: description, flags: flags)
|
||||
currentExampleGroup!.appendExampleGroup(group)
|
||||
currentExampleGroup = group
|
||||
closure()
|
||||
currentExampleGroup = group.parent
|
||||
}
|
||||
|
||||
public func context(description: String, closure: () -> (), flags: FilterFlags) {
|
||||
self.describe(description, closure: closure, flags: flags)
|
||||
}
|
||||
|
||||
public func fdescribe(description: String, closure: () -> (), flags: FilterFlags) {
|
||||
var focusedFlags = flags
|
||||
focusedFlags[Filter.focused] = true
|
||||
self.describe(description, closure: closure, flags: focusedFlags)
|
||||
}
|
||||
|
||||
public func xdescribe(description: String, closure: () -> (), flags: FilterFlags) {
|
||||
var pendingFlags = flags
|
||||
pendingFlags[Filter.pending] = true
|
||||
self.describe(description, closure: closure, flags: pendingFlags)
|
||||
}
|
||||
|
||||
public func beforeEach(closure: BeforeExampleClosure) {
|
||||
currentExampleGroup!.hooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
public func beforeEach(#closure: BeforeExampleWithMetadataClosure) {
|
||||
currentExampleGroup!.hooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
public func afterEach(closure: AfterExampleClosure) {
|
||||
currentExampleGroup!.hooks.appendAfter(closure)
|
||||
}
|
||||
|
||||
public func afterEach(#closure: AfterExampleWithMetadataClosure) {
|
||||
currentExampleGroup!.hooks.appendAfter(closure)
|
||||
}
|
||||
|
||||
@objc(itWithDescription:flags:file:line:closure:)
|
||||
public func it(description: String, flags: FilterFlags, file: String, line: Int, closure: () -> ()) {
|
||||
let callsite = Callsite(file: file, line: line)
|
||||
let example = Example(description: description, callsite: callsite, flags: flags, closure)
|
||||
currentExampleGroup!.appendExample(example)
|
||||
}
|
||||
|
||||
@objc(fitWithDescription:flags:file:line:closure:)
|
||||
public func fit(description: String, flags: FilterFlags, file: String, line: Int, closure: () -> ()) {
|
||||
var focusedFlags = flags
|
||||
focusedFlags[Filter.focused] = true
|
||||
self.it(description, flags: focusedFlags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
@objc(xitWithDescription:flags:file:line:closure:)
|
||||
public func xit(description: String, flags: FilterFlags, file: String, line: Int, closure: () -> ()) {
|
||||
var pendingFlags = flags
|
||||
pendingFlags[Filter.pending] = true
|
||||
self.it(description, flags: pendingFlags, file: file, line: line, closure: closure)
|
||||
}
|
||||
|
||||
@objc(itBehavesLikeSharedExampleNamed:sharedExampleContext:flags:file:line:)
|
||||
public func itBehavesLike(name: String, sharedExampleContext: SharedExampleContext, flags: FilterFlags, file: String, line: Int) {
|
||||
let callsite = Callsite(file: file, line: line)
|
||||
let closure = World.sharedWorld().sharedExample(name)
|
||||
|
||||
var group = ExampleGroup(description: name, flags: flags)
|
||||
currentExampleGroup!.appendExampleGroup(group)
|
||||
currentExampleGroup = group
|
||||
closure(sharedExampleContext)
|
||||
currentExampleGroup!.walkDownExamples { (example: Example) in
|
||||
example.isSharedExample = true
|
||||
example.callsite = callsite
|
||||
}
|
||||
|
||||
currentExampleGroup = group.parent
|
||||
}
|
||||
|
||||
public func pending(description: String, closure: () -> ()) {
|
||||
println("Pending: \(description)")
|
||||
}
|
||||
}
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
private var numberOfExamplesRun = 0
|
||||
|
||||
/**
|
||||
Examples, defined with the `it` function, use assertions to
|
||||
demonstrate how code should behave. These are like "tests" in XCTest.
|
||||
*/
|
||||
@objc final public class Example: Equatable {
|
||||
/**
|
||||
A boolean indicating whether the example is a shared example;
|
||||
i.e.: whether it is an example defined with `itBehavesLike`.
|
||||
*/
|
||||
public var isSharedExample = false
|
||||
|
||||
/**
|
||||
The site at which the example is defined.
|
||||
This must be set correctly in order for Xcode to highlight
|
||||
the correct line in red when reporting a failure.
|
||||
*/
|
||||
public var callsite: Callsite
|
||||
|
||||
weak internal var group: ExampleGroup?
|
||||
|
||||
private let description: String
|
||||
private let closure: () -> ()
|
||||
private let flags: FilterFlags
|
||||
|
||||
internal init(description: String, callsite: Callsite, flags: FilterFlags, closure: () -> ()) {
|
||||
self.description = description
|
||||
self.closure = closure
|
||||
self.callsite = callsite
|
||||
self.flags = flags
|
||||
}
|
||||
|
||||
/**
|
||||
The example name. A name is a concatenation of the name of
|
||||
the example group the example belongs to, followed by the
|
||||
description of the example itself.
|
||||
|
||||
The example name is used to generate a test method selector
|
||||
to be displayed in Xcode's test navigator.
|
||||
*/
|
||||
public var name: String {
|
||||
switch group!.name {
|
||||
case .Some(let groupName): return "\(groupName), \(description)"
|
||||
case .None: return description
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Executes the example closure, as well as all before and after
|
||||
closures defined in the its surrounding example groups.
|
||||
*/
|
||||
public func run() {
|
||||
let world = World.sharedWorld()
|
||||
|
||||
if numberOfExamplesRun == 0 {
|
||||
world.suiteHooks.executeBefores()
|
||||
}
|
||||
|
||||
let exampleMetadata = ExampleMetadata(example: self, exampleIndex: numberOfExamplesRun)
|
||||
world.currentExampleMetadata = exampleMetadata
|
||||
|
||||
world.exampleHooks.executeBefores(exampleMetadata)
|
||||
for before in group!.befores {
|
||||
before(exampleMetadata: exampleMetadata)
|
||||
}
|
||||
|
||||
closure()
|
||||
|
||||
for after in group!.afters {
|
||||
after(exampleMetadata: exampleMetadata)
|
||||
}
|
||||
world.exampleHooks.executeAfters(exampleMetadata)
|
||||
|
||||
++numberOfExamplesRun
|
||||
|
||||
if !world.isRunningAdditionalSuites && numberOfExamplesRun >= world.exampleCount {
|
||||
world.suiteHooks.executeAfters()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Evaluates the filter flags set on this example and on the example groups
|
||||
this example belongs to. Flags set on the example are trumped by flags on
|
||||
the example group it belongs to. Flags on inner example groups are trumped
|
||||
by flags on outer example groups.
|
||||
*/
|
||||
internal var filterFlags: FilterFlags {
|
||||
var aggregateFlags = flags
|
||||
for (key, value) in group!.filterFlags {
|
||||
aggregateFlags[key] = value
|
||||
}
|
||||
return aggregateFlags
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a boolean indicating whether two Example objects are equal.
|
||||
If two examples are defined at the exact same callsite, they must be equal.
|
||||
*/
|
||||
public func ==(lhs: Example, rhs: Example) -> Bool {
|
||||
return lhs.callsite == rhs.callsite
|
||||
}
|
||||
|
|
@ -1,97 +0,0 @@
|
|||
/**
|
||||
Example groups are logical groupings of examples, defined with
|
||||
the `describe` and `context` functions. Example groups can share
|
||||
setup and teardown code.
|
||||
*/
|
||||
@objc final public class ExampleGroup {
|
||||
weak internal var parent: ExampleGroup?
|
||||
internal let hooks = ExampleHooks()
|
||||
|
||||
private let description: String
|
||||
private let flags: FilterFlags
|
||||
private let isInternalRootExampleGroup: Bool
|
||||
private var childGroups = [ExampleGroup]()
|
||||
private var childExamples = [Example]()
|
||||
|
||||
internal init(description: String, flags: FilterFlags, isInternalRootExampleGroup: Bool = false) {
|
||||
self.description = description
|
||||
self.flags = flags
|
||||
self.isInternalRootExampleGroup = isInternalRootExampleGroup
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a list of examples that belong to this example group,
|
||||
or to any of its descendant example groups.
|
||||
*/
|
||||
public var examples: [Example] {
|
||||
var examples = childExamples
|
||||
for group in childGroups {
|
||||
examples.extend(group.examples)
|
||||
}
|
||||
return examples
|
||||
}
|
||||
|
||||
internal var name: String? {
|
||||
if let parent = parent {
|
||||
switch(parent.name) {
|
||||
case .Some(let name): return "\(name), \(description)"
|
||||
case .None: return description
|
||||
}
|
||||
} else {
|
||||
return isInternalRootExampleGroup ? nil : description
|
||||
}
|
||||
}
|
||||
|
||||
internal var filterFlags: FilterFlags {
|
||||
var aggregateFlags = flags
|
||||
walkUp() { (group: ExampleGroup) -> () in
|
||||
for (key, value) in group.flags {
|
||||
aggregateFlags[key] = value
|
||||
}
|
||||
}
|
||||
return aggregateFlags
|
||||
}
|
||||
|
||||
internal var befores: [BeforeExampleWithMetadataClosure] {
|
||||
var closures = hooks.befores.reverse()
|
||||
walkUp() { (group: ExampleGroup) -> () in
|
||||
closures.extend(group.hooks.befores.reverse())
|
||||
}
|
||||
return closures.reverse()
|
||||
}
|
||||
|
||||
internal var afters: [AfterExampleWithMetadataClosure] {
|
||||
var closures = hooks.afters
|
||||
walkUp() { (group: ExampleGroup) -> () in
|
||||
closures.extend(group.hooks.afters)
|
||||
}
|
||||
return closures
|
||||
}
|
||||
|
||||
internal func walkDownExamples(callback: (example: Example) -> ()) {
|
||||
for example in childExamples {
|
||||
callback(example: example)
|
||||
}
|
||||
for group in childGroups {
|
||||
group.walkDownExamples(callback)
|
||||
}
|
||||
}
|
||||
|
||||
internal func appendExampleGroup(group: ExampleGroup) {
|
||||
group.parent = self
|
||||
childGroups.append(group)
|
||||
}
|
||||
|
||||
internal func appendExample(example: Example) {
|
||||
example.group = self
|
||||
childExamples.append(example)
|
||||
}
|
||||
|
||||
private func walkUp(callback: (group: ExampleGroup) -> ()) {
|
||||
var group = self
|
||||
while let parent = group.parent {
|
||||
callback(group: parent)
|
||||
group = parent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
/**
|
||||
A class that encapsulates information about an example,
|
||||
including the index at which the example was executed, as
|
||||
well as the example itself.
|
||||
*/
|
||||
@objc final public class ExampleMetadata {
|
||||
/**
|
||||
The example for which this metadata was collected.
|
||||
*/
|
||||
public let example: Example
|
||||
|
||||
/**
|
||||
The index at which this example was executed in the
|
||||
test suite.
|
||||
*/
|
||||
public let exampleIndex: Int
|
||||
|
||||
internal init(example: Example, exampleIndex: Int) {
|
||||
self.example = example
|
||||
self.exampleIndex = exampleIndex
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
import Foundation
|
||||
|
||||
@objc final class Failure {
|
||||
let callsite: Callsite
|
||||
let exception: NSException
|
||||
|
||||
init(exception: NSException, callsite: Callsite) {
|
||||
self.exception = exception
|
||||
self.callsite = callsite
|
||||
}
|
||||
|
||||
@objc(failureWithException:callsite:)
|
||||
class func failure(exception: NSException, callsite: Callsite) -> Failure {
|
||||
return Failure(exception: exception, callsite: callsite)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
/**
|
||||
A mapping of string keys to booleans that can be used to
|
||||
filter examples or example groups. For example, a "focused"
|
||||
example would have the flags [Focused: true].
|
||||
*/
|
||||
public typealias FilterFlags = [String: Bool]
|
||||
|
||||
/**
|
||||
A namespace for filter flag keys, defined primarily to make the
|
||||
keys available in Objective-C.
|
||||
*/
|
||||
@objc(QCKFilter) final public class Filter {
|
||||
/**
|
||||
Example and example groups with [Focused: true] are included in test runs,
|
||||
excluding all other examples without this flag. Use this to only run one or
|
||||
two tests that you're currently focusing on.
|
||||
*/
|
||||
public class var focused: String {
|
||||
return "focused"
|
||||
}
|
||||
|
||||
/**
|
||||
Example and example groups with [Pending: true] are excluded from test runs.
|
||||
Use this to temporarily suspend examples that you know do not pass yet.
|
||||
*/
|
||||
public class var pending: String {
|
||||
return "pending"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
// MARK: Example Hooks
|
||||
|
||||
/**
|
||||
A closure executed before an example is run.
|
||||
*/
|
||||
public typealias BeforeExampleClosure = () -> ()
|
||||
|
||||
/**
|
||||
A closure executed before an example is run. The closure is given example metadata,
|
||||
which contains information about the example that is about to be run.
|
||||
*/
|
||||
public typealias BeforeExampleWithMetadataClosure = (exampleMetadata: ExampleMetadata) -> ()
|
||||
|
||||
/**
|
||||
A closure executed after an example is run.
|
||||
*/
|
||||
public typealias AfterExampleClosure = BeforeExampleClosure
|
||||
|
||||
/**
|
||||
A closure executed after an example is run. The closure is given example metadata,
|
||||
which contains information about the example that has just finished running.
|
||||
*/
|
||||
public typealias AfterExampleWithMetadataClosure = BeforeExampleWithMetadataClosure
|
||||
|
||||
// MARK: Suite Hooks
|
||||
|
||||
/**
|
||||
A closure executed before any examples are run.
|
||||
*/
|
||||
public typealias BeforeSuiteClosure = () -> ()
|
||||
|
||||
/**
|
||||
A closure executed after all examples have finished running.
|
||||
*/
|
||||
public typealias AfterSuiteClosure = BeforeSuiteClosure
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/**
|
||||
A container for closures to be executed before and after each example.
|
||||
*/
|
||||
final internal class ExampleHooks {
|
||||
|
||||
internal var befores: [BeforeExampleWithMetadataClosure] = []
|
||||
internal var afters: [AfterExampleWithMetadataClosure] = []
|
||||
|
||||
internal func appendBefore(closure: BeforeExampleWithMetadataClosure) {
|
||||
befores.append(closure)
|
||||
}
|
||||
|
||||
internal func appendBefore(closure: BeforeExampleClosure) {
|
||||
befores.append { (exampleMetadata: ExampleMetadata) in closure() }
|
||||
}
|
||||
|
||||
internal func appendAfter(closure: AfterExampleWithMetadataClosure) {
|
||||
afters.append(closure)
|
||||
}
|
||||
|
||||
internal func appendAfter(closure: AfterExampleClosure) {
|
||||
afters.append { (exampleMetadata: ExampleMetadata) in closure() }
|
||||
}
|
||||
|
||||
internal func executeBefores(exampleMetadata: ExampleMetadata) {
|
||||
for before in befores {
|
||||
before(exampleMetadata: exampleMetadata)
|
||||
}
|
||||
}
|
||||
|
||||
internal func executeAfters(exampleMetadata: ExampleMetadata) {
|
||||
for after in afters {
|
||||
after(exampleMetadata: exampleMetadata)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/**
|
||||
A container for closures to be executed before and after all examples.
|
||||
*/
|
||||
final internal class SuiteHooks {
|
||||
internal var befores: [BeforeSuiteClosure] = []
|
||||
internal var beforesAlreadyExecuted = false
|
||||
|
||||
internal var afters: [AfterSuiteClosure] = []
|
||||
internal var aftersAlreadyExecuted = false
|
||||
|
||||
internal func appendBefore(closure: BeforeSuiteClosure) {
|
||||
befores.append(closure)
|
||||
}
|
||||
|
||||
internal func appendAfter(closure: AfterSuiteClosure) {
|
||||
afters.append(closure)
|
||||
}
|
||||
|
||||
internal func executeBefores() {
|
||||
assert(!beforesAlreadyExecuted)
|
||||
for before in befores {
|
||||
before()
|
||||
}
|
||||
beforesAlreadyExecuted = true
|
||||
}
|
||||
|
||||
internal func executeAfters() {
|
||||
assert(!aftersAlreadyExecuted)
|
||||
for after in afters {
|
||||
after()
|
||||
}
|
||||
aftersAlreadyExecuted = true
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
/**
|
||||
QuickSpec converts example names into test methods.
|
||||
Those test methods need valid selector names, which means no whitespace,
|
||||
control characters, etc. This category gives NSString objects an easy way
|
||||
to replace those illegal characters with underscores.
|
||||
*/
|
||||
@interface NSString (QCKSelectorName)
|
||||
|
||||
/**
|
||||
Returns a string with underscores in place of all characters that cannot
|
||||
be included in a selector (SEL) name.
|
||||
*/
|
||||
@property (nonatomic, readonly) NSString *qck_selectorName;
|
||||
|
||||
@end
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#import "NSString+QCKSelectorName.h"
|
||||
|
||||
@implementation NSString (QCKSelectorName)
|
||||
|
||||
- (NSString *)qck_selectorName {
|
||||
static NSMutableCharacterSet *invalidCharacters = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
invalidCharacters = [NSMutableCharacterSet new];
|
||||
|
||||
NSCharacterSet *whitespaceCharacterSet = [NSCharacterSet whitespaceCharacterSet];
|
||||
NSCharacterSet *newlineCharacterSet = [NSCharacterSet newlineCharacterSet];
|
||||
NSCharacterSet *illegalCharacterSet = [NSCharacterSet illegalCharacterSet];
|
||||
NSCharacterSet *controlCharacterSet = [NSCharacterSet controlCharacterSet];
|
||||
NSCharacterSet *punctuationCharacterSet = [NSCharacterSet punctuationCharacterSet];
|
||||
NSCharacterSet *nonBaseCharacterSet = [NSCharacterSet nonBaseCharacterSet];
|
||||
NSCharacterSet *symbolCharacterSet = [NSCharacterSet symbolCharacterSet];
|
||||
|
||||
[invalidCharacters formUnionWithCharacterSet:whitespaceCharacterSet];
|
||||
[invalidCharacters formUnionWithCharacterSet:newlineCharacterSet];
|
||||
[invalidCharacters formUnionWithCharacterSet:illegalCharacterSet];
|
||||
[invalidCharacters formUnionWithCharacterSet:controlCharacterSet];
|
||||
[invalidCharacters formUnionWithCharacterSet:punctuationCharacterSet];
|
||||
[invalidCharacters formUnionWithCharacterSet:nonBaseCharacterSet];
|
||||
[invalidCharacters formUnionWithCharacterSet:symbolCharacterSet];
|
||||
});
|
||||
|
||||
NSArray *validComponents = [self componentsSeparatedByCharactersInSet:invalidCharacters];
|
||||
|
||||
return [validComponents componentsJoinedByString:@"_"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
|
||||
//! Project version number for Quick.
|
||||
FOUNDATION_EXPORT double QuickVersionNumber;
|
||||
|
||||
//! Project version string for Quick.
|
||||
FOUNDATION_EXPORT const unsigned char QuickVersionString[];
|
||||
|
||||
// In this header, you should import all the public headers of your framework using statements like #import <Quick/PublicHeader.h>
|
||||
|
||||
#import <Quick/QuickSpec.h>
|
||||
#import <Quick/QCKDSL.h>
|
||||
#import <Quick/QuickConfiguration.h>
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
#import <XCTest/XCTest.h>
|
||||
|
||||
/**
|
||||
QuickSpec is a base class all specs written in Quick inherit from.
|
||||
They need to inherit from QuickSpec, a subclass of XCTestCase, in
|
||||
order to be discovered by the XCTest framework.
|
||||
|
||||
XCTest automatically compiles a list of XCTestCase subclasses included
|
||||
in the test target. It iterates over each class in that list, and creates
|
||||
a new instance of that class for each test method. It then creates an
|
||||
"invocation" to execute that test method. The invocation is an instance of
|
||||
NSInvocation, which represents a single message send in Objective-C.
|
||||
The invocation is set on the XCTestCase instance, and the test is run.
|
||||
|
||||
Most of the code in QuickSpec is dedicated to hooking into XCTest events.
|
||||
First, when the spec is first loaded and before it is sent any messages,
|
||||
the +[NSObject initialize] method is called. QuickSpec overrides this method
|
||||
to call +[QuickSpec spec]. This builds the example group stacks and
|
||||
registers them with Quick.World, a global register of examples.
|
||||
|
||||
Then, XCTest queries QuickSpec for a list of test methods. Normally, XCTest
|
||||
automatically finds all methods whose selectors begin with the string "test".
|
||||
However, QuickSpec overrides this default behavior by implementing the
|
||||
+[XCTestCase testInvocations] method. This method iterates over each example
|
||||
registered in Quick.World, defines a new method for that example, and
|
||||
returns an invocation to call that method to XCTest. Those invocations are
|
||||
the tests that are run by XCTest. Their selector names are displayed in
|
||||
the Xcode test navigation bar.
|
||||
*/
|
||||
@interface QuickSpec : XCTestCase
|
||||
|
||||
/**
|
||||
Override this method in your spec to define a set of example groups
|
||||
and examples.
|
||||
|
||||
override class func spec() {
|
||||
describe("winter") {
|
||||
it("is coming") {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
See DSL.swift for more information on what syntax is available.
|
||||
*/
|
||||
- (void)spec;
|
||||
|
||||
@end
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
#import "QuickSpec.h"
|
||||
#import "QuickConfiguration.h"
|
||||
#import "NSString+QCKSelectorName.h"
|
||||
#import <Quick/Quick-Swift.h>
|
||||
#import <objc/runtime.h>
|
||||
|
||||
const void * const QCKExampleKey = &QCKExampleKey;
|
||||
|
||||
@interface QuickSpec ()
|
||||
@property (nonatomic, strong) Example *example;
|
||||
@end
|
||||
|
||||
@implementation QuickSpec
|
||||
|
||||
#pragma mark - XCTestCase Overrides
|
||||
|
||||
/**
|
||||
The runtime sends initialize to each class in a program just before the class, or any class
|
||||
that inherits from it, is sent its first message from within the program. QuickSpec hooks into
|
||||
this event to compile the example groups for this spec subclass.
|
||||
|
||||
If an exception occurs when compiling the examples, report it to the user. Chances are they
|
||||
included an expectation outside of a "it", "describe", or "context" block.
|
||||
*/
|
||||
+ (void)initialize {
|
||||
[QuickConfiguration initialize];
|
||||
|
||||
World *world = [World sharedWorld];
|
||||
world.currentExampleGroup = [world rootExampleGroupForSpecClass:[self class]];
|
||||
QuickSpec *spec = [self new];
|
||||
|
||||
@try {
|
||||
[spec spec];
|
||||
}
|
||||
@catch (NSException *exception) {
|
||||
[NSException raise:NSInternalInconsistencyException
|
||||
format:@"An exception occurred when building Quick's example groups.\n"
|
||||
@"Some possible reasons this might happen include:\n\n"
|
||||
@"- An 'expect(...).to' expectation was evaluated outside of "
|
||||
@"an 'it', 'context', or 'describe' block\n"
|
||||
@"- 'sharedExamples' was called twice with the same name\n"
|
||||
@"- 'itBehavesLike' was called with a name that is not registered as a shared example\n\n"
|
||||
@"Here's the original exception: '%@', reason: '%@', userInfo: '%@'",
|
||||
exception.name, exception.reason, exception.userInfo];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Invocations for each test method in the test case. QuickSpec overrides this method to define a
|
||||
new method for each example defined in +[QuickSpec spec].
|
||||
|
||||
@return An array of invocations that execute the newly defined example methods.
|
||||
*/
|
||||
+ (NSArray *)testInvocations {
|
||||
NSArray *examples = [[World sharedWorld] examplesForSpecClass:[self class]];
|
||||
NSMutableArray *invocations = [NSMutableArray arrayWithCapacity:[examples count]];
|
||||
for (Example *example in examples) {
|
||||
SEL selector = [self addInstanceMethodForExample:example];
|
||||
NSInvocation *invocation = [self invocationForInstanceMethodWithSelector:selector
|
||||
example:example];
|
||||
[invocations addObject:invocation];
|
||||
}
|
||||
|
||||
return invocations;
|
||||
}
|
||||
|
||||
/**
|
||||
XCTest sets the invocation for the current test case instance using this setter.
|
||||
QuickSpec hooks into this event to give the test case a reference to the current example.
|
||||
It will need this reference to correctly report its name to XCTest.
|
||||
*/
|
||||
- (void)setInvocation:(NSInvocation *)invocation {
|
||||
self.example = objc_getAssociatedObject(invocation, QCKExampleKey);
|
||||
[super setInvocation:invocation];
|
||||
}
|
||||
|
||||
#pragma mark - Public Interface
|
||||
|
||||
- (void)spec { }
|
||||
|
||||
#pragma mark - Internal Methods
|
||||
|
||||
/**
|
||||
QuickSpec uses this method to dynamically define a new instance method for the
|
||||
given example. The instance method runs the example, catching any exceptions.
|
||||
The exceptions are then reported as test failures.
|
||||
|
||||
In order to report the correct file and line number, examples must raise exceptions
|
||||
containing following keys in their userInfo:
|
||||
|
||||
- "SenTestFilenameKey": A String representing the file name
|
||||
- "SenTestLineNumberKey": An Int representing the line number
|
||||
|
||||
These keys used to be used by SenTestingKit, and are still used by some testing tools
|
||||
in the wild. See: https://github.com/Quick/Quick/pull/41
|
||||
|
||||
@return The selector of the newly defined instance method.
|
||||
*/
|
||||
+ (SEL)addInstanceMethodForExample:(Example *)example {
|
||||
IMP implementation = imp_implementationWithBlock(^(id self){
|
||||
[example run];
|
||||
});
|
||||
const char *types = [[NSString stringWithFormat:@"%s%s%s", @encode(id), @encode(id), @encode(SEL)] UTF8String];
|
||||
SEL selector = NSSelectorFromString(example.name.qck_selectorName);
|
||||
class_addMethod(self, selector, implementation, types);
|
||||
|
||||
return selector;
|
||||
}
|
||||
|
||||
+ (NSInvocation *)invocationForInstanceMethodWithSelector:(SEL)selector
|
||||
example:(Example *)example {
|
||||
NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector];
|
||||
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
|
||||
invocation.selector = selector;
|
||||
objc_setAssociatedObject(invocation,
|
||||
QCKExampleKey,
|
||||
example,
|
||||
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
return invocation;
|
||||
}
|
||||
|
||||
/**
|
||||
This method is used to record failures, whether they represent example
|
||||
expectations that were not met, or exceptions raised during test setup
|
||||
and teardown. By default, the failure will be reported as an
|
||||
XCTest failure, and the example will be highlighted in Xcode.
|
||||
*/
|
||||
- (void)recordFailureWithDescription:(NSString *)description
|
||||
inFile:(NSString *)filePath
|
||||
atLine:(NSUInteger)lineNumber
|
||||
expected:(BOOL)expected {
|
||||
if (self.example.isSharedExample) {
|
||||
filePath = self.example.callsite.file;
|
||||
lineNumber = self.example.callsite.line;
|
||||
}
|
||||
[super recordFailureWithDescription:description
|
||||
inFile:filePath
|
||||
atLine:lineNumber
|
||||
expected:expected];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -1,197 +0,0 @@
|
|||
import Foundation
|
||||
|
||||
/**
|
||||
A closure that, when evaluated, returns a dictionary of key-value
|
||||
pairs that can be accessed from within a group of shared examples.
|
||||
*/
|
||||
public typealias SharedExampleContext = () -> (NSDictionary)
|
||||
|
||||
/**
|
||||
A closure that is used to define a group of shared examples. This
|
||||
closure may contain any number of example and example groups.
|
||||
*/
|
||||
public typealias SharedExampleClosure = (SharedExampleContext) -> ()
|
||||
|
||||
/**
|
||||
A collection of state Quick builds up in order to work its magic.
|
||||
World is primarily responsible for maintaining a mapping of QuickSpec
|
||||
classes to root example groups for those classes.
|
||||
|
||||
It also maintains a mapping of shared example names to shared
|
||||
example closures.
|
||||
|
||||
You may configure how Quick behaves by calling the -[World configure:]
|
||||
method from within an overridden +[QuickConfiguration configure:] method.
|
||||
*/
|
||||
@objc final public class World {
|
||||
/**
|
||||
The example group that is currently being run.
|
||||
The DSL requires that this group is correctly set in order to build a
|
||||
correct hierarchy of example groups and their examples.
|
||||
*/
|
||||
public var currentExampleGroup: ExampleGroup?
|
||||
|
||||
/**
|
||||
The example metadata of the test that is currently being run.
|
||||
This is useful for using the Quick test metadata (like its name) at
|
||||
runtime.
|
||||
*/
|
||||
|
||||
public var currentExampleMetadata: ExampleMetadata?
|
||||
|
||||
/**
|
||||
A flag that indicates whether additional test suites are being run
|
||||
within this test suite. This is only true within the context of Quick
|
||||
functional tests.
|
||||
*/
|
||||
public var isRunningAdditionalSuites = false
|
||||
|
||||
private var specs: Dictionary<String, ExampleGroup> = [:]
|
||||
private var sharedExamples: [String: SharedExampleClosure] = [:]
|
||||
private let configuration = Configuration()
|
||||
private var isConfigurationFinalized = false
|
||||
|
||||
internal var exampleHooks: ExampleHooks {return configuration.exampleHooks }
|
||||
internal var suiteHooks: SuiteHooks { return configuration.suiteHooks }
|
||||
|
||||
// MARK: Singleton Constructor
|
||||
|
||||
private init() {}
|
||||
private struct Shared {
|
||||
static let instance = World()
|
||||
}
|
||||
public class func sharedWorld() -> World {
|
||||
return Shared.instance
|
||||
}
|
||||
|
||||
// MARK: Public Interface
|
||||
|
||||
/**
|
||||
Exposes the World's Configuration object within the scope of the closure
|
||||
so that it may be configured. This method must not be called outside of
|
||||
an overridden +[QuickConfiguration configure:] method.
|
||||
|
||||
:param: closure A closure that takes a Configuration object that can
|
||||
be mutated to change Quick's behavior.
|
||||
*/
|
||||
public func configure(closure: QuickConfigurer) {
|
||||
assert(!isConfigurationFinalized,
|
||||
"Quick cannot be configured outside of a +[QuickConfiguration configure:] method. You should not call -[World configure:] directly. Instead, subclass QuickConfiguration and override the +[QuickConfiguration configure:] method.")
|
||||
closure(configuration: configuration)
|
||||
}
|
||||
|
||||
/**
|
||||
Finalizes the World's configuration.
|
||||
Any subsequent calls to World.configure() will raise.
|
||||
*/
|
||||
public func finalizeConfiguration() {
|
||||
isConfigurationFinalized = true
|
||||
}
|
||||
|
||||
/**
|
||||
Returns an internally constructed root example group for the given
|
||||
QuickSpec class.
|
||||
|
||||
A root example group with the description "root example group" is lazily
|
||||
initialized for each QuickSpec class. This root example group wraps the
|
||||
top level of a -[QuickSpec spec] method--it's thanks to this group that
|
||||
users can define beforeEach and it closures at the top level, like so:
|
||||
|
||||
override func spec() {
|
||||
// These belong to the root example group
|
||||
beforeEach {}
|
||||
it("is at the top level") {}
|
||||
}
|
||||
|
||||
:param: cls The QuickSpec class for which to retrieve the root example group.
|
||||
:returns: The root example group for the class.
|
||||
*/
|
||||
public func rootExampleGroupForSpecClass(cls: AnyClass) -> ExampleGroup {
|
||||
let name = NSStringFromClass(cls)
|
||||
if let group = specs[name] {
|
||||
return group
|
||||
} else {
|
||||
let group = ExampleGroup(
|
||||
description: "root example group",
|
||||
flags: [:],
|
||||
isInternalRootExampleGroup: true
|
||||
)
|
||||
specs[name] = group
|
||||
return group
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Returns all examples that should be run for a given spec class.
|
||||
There are two filtering passes that occur when determining which examples should be run.
|
||||
That is, these examples are the ones that are included by inclusion filters, and are
|
||||
not excluded by exclusion filters.
|
||||
|
||||
:param: specClass The QuickSpec subclass for which examples are to be returned.
|
||||
:returns: A list of examples to be run as test invocations.
|
||||
*/
|
||||
@objc(examplesForSpecClass:)
|
||||
public func examples(specClass: AnyClass) -> [Example] {
|
||||
// 1. Grab all included examples.
|
||||
let included = includedExamples
|
||||
// 2. Grab the intersection of (a) examples for this spec, and (b) included examples.
|
||||
let spec = rootExampleGroupForSpecClass(specClass).examples.filter { contains(included, $0) }
|
||||
// 3. Remove all excluded examples.
|
||||
return spec.filter { example in
|
||||
!self.configuration.exclusionFilters.reduce(false) { $0 || $1(example: example) }
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
internal func registerSharedExample(name: String, closure: SharedExampleClosure) {
|
||||
raiseIfSharedExampleAlreadyRegistered(name)
|
||||
sharedExamples[name] = closure
|
||||
}
|
||||
|
||||
internal func sharedExample(name: String) -> SharedExampleClosure {
|
||||
raiseIfSharedExampleNotRegistered(name)
|
||||
return sharedExamples[name]!
|
||||
}
|
||||
|
||||
internal var exampleCount: Int {
|
||||
return allExamples.count
|
||||
}
|
||||
|
||||
private var allExamples: [Example] {
|
||||
var all: [Example] = []
|
||||
for (_, group) in specs {
|
||||
group.walkDownExamples { all.append($0) }
|
||||
}
|
||||
return all
|
||||
}
|
||||
|
||||
private var includedExamples: [Example] {
|
||||
let all = allExamples
|
||||
let included = all.filter { example in
|
||||
return self.configuration.inclusionFilters.reduce(false) { $0 || $1(example: example) }
|
||||
}
|
||||
|
||||
if included.isEmpty && configuration.runAllWhenEverythingFiltered {
|
||||
return all
|
||||
} else {
|
||||
return included
|
||||
}
|
||||
}
|
||||
|
||||
private func raiseIfSharedExampleAlreadyRegistered(name: String) {
|
||||
if sharedExamples[name] != nil {
|
||||
NSException(name: NSInternalInconsistencyException,
|
||||
reason: "A shared example named '\(name)' has already been registered.",
|
||||
userInfo: nil).raise()
|
||||
}
|
||||
}
|
||||
|
||||
private func raiseIfSharedExampleNotRegistered(name: String) {
|
||||
if sharedExamples[name] == nil {
|
||||
NSException(name: NSInternalInconsistencyException,
|
||||
reason: "No shared example named '\(name)' has been registered. Registered shared examples: '\(Array(sharedExamples.keys))'",
|
||||
userInfo: nil).raise()
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -15,7 +15,7 @@
|
|||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.3.0</string>
|
||||
<string>0.4.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
CONFIGURATION_BUILD_DIR = $PODS_FRAMEWORK_BUILD_PATH
|
||||
FRAMEWORK_SEARCH_PATHS = "$PODS_FRAMEWORK_BUILD_PATH" ${PODS_CAMERATESTS_NIMBLE_FRAMEWORK_SEARCH_PATHS}
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Nimble" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Nimble" "${PODS_ROOT}/Headers/Public/Quick"
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Nimble" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Nimble"
|
||||
OTHER_LDFLAGS = ${PODS_CAMERATESTS_NIMBLE_OTHER_LDFLAGS} -ObjC
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-cameraTests
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>org.cocoapods.${PRODUCT_NAME:rfc1034identifier}</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.2.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>${CURRENT_PROJECT_VERSION}</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#include "Pods-cameraTests-Quick.xcconfig"
|
||||
CONFIGURATION_BUILD_DIR = $PODS_FRAMEWORK_BUILD_PATH
|
||||
FRAMEWORK_SEARCH_PATHS = "$PODS_FRAMEWORK_BUILD_PATH" ${PODS_CAMERATESTS_QUICK_FRAMEWORK_SEARCH_PATHS}
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Quick" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/Nimble" "${PODS_ROOT}/Headers/Public/Quick"
|
||||
OTHER_LDFLAGS = ${PODS_CAMERATESTS_QUICK_OTHER_LDFLAGS} -ObjC
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-cameraTests
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
SKIP_INSTALL = YES
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#import <Foundation/Foundation.h>
|
||||
@interface PodsDummy_Pods_cameraTests_Quick : NSObject
|
||||
@end
|
||||
@implementation PodsDummy_Pods_cameraTests_Quick
|
||||
@end
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#ifdef __OBJC__
|
||||
#import <UIKit/UIKit.h>
|
||||
#endif
|
||||
|
||||
#import "Pods-cameraTests-environment.h"
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "NSString+QCKSelectorName.h"
|
||||
#import "Quick.h"
|
||||
#import "QuickSpec.h"
|
||||
#import "QuickConfiguration.h"
|
||||
#import "QCKDSL.h"
|
||||
|
||||
FOUNDATION_EXPORT double QuickVersionNumber;
|
||||
FOUNDATION_EXPORT const unsigned char QuickVersionString[];
|
||||
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
framework module Quick {
|
||||
umbrella header "Pods-cameraTests-Quick-umbrella.h"
|
||||
|
||||
export *
|
||||
module * { export * }
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
PODS_CAMERATESTS_QUICK_FRAMEWORK_SEARCH_PATHS = $(inherited) "$(SDKROOT)/Developer/Library/Frameworks" "$(PLATFORM_DIR)/Developer/Library/Frameworks"
|
||||
PODS_CAMERATESTS_QUICK_OTHER_LDFLAGS = -framework "XCTest"
|
||||
|
|
@ -205,209 +205,4 @@ Apache License
|
|||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
## Quick
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014, Quick Team
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Generated by CocoaPods - http://cocoapods.org
|
||||
|
|
|
|||
|
|
@ -221,215 +221,6 @@
|
|||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2014, Quick Team
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
</string>
|
||||
<key>Title</key>
|
||||
<string>Quick</string>
|
||||
<key>Type</key>
|
||||
<string>PSGroupSpecifier</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>FooterText</key>
|
||||
<string>Generated by CocoaPods - http://cocoapods.org</string>
|
||||
|
|
|
|||
|
|
@ -9,12 +9,6 @@
|
|||
// Nimble
|
||||
#define COCOAPODS_POD_AVAILABLE_Nimble
|
||||
#define COCOAPODS_VERSION_MAJOR_Nimble 0
|
||||
#define COCOAPODS_VERSION_MINOR_Nimble 3
|
||||
#define COCOAPODS_VERSION_PATCH_Nimble 0
|
||||
|
||||
// Quick
|
||||
#define COCOAPODS_POD_AVAILABLE_Quick
|
||||
#define COCOAPODS_VERSION_MAJOR_Quick 0
|
||||
#define COCOAPODS_VERSION_MINOR_Quick 2
|
||||
#define COCOAPODS_VERSION_PATCH_Quick 2
|
||||
#define COCOAPODS_VERSION_MINOR_Nimble 4
|
||||
#define COCOAPODS_VERSION_PATCH_Nimble 2
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@ install_framework()
|
|||
fi
|
||||
|
||||
# use filter instead of exclude so missing patterns dont' throw errors
|
||||
echo "rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers/" --filter "- PrivateHeaders/" ${source} ${destination}"
|
||||
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers/" --filter "- PrivateHeaders/" "${source}" "${destination}"
|
||||
echo "rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers/" --filter "- PrivateHeaders/" --filter "- Modules/" ${source} ${destination}"
|
||||
rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers/" --filter "- PrivateHeaders/" --filter "- Modules/" "${source}" "${destination}"
|
||||
# Resign the code if required by the build settings to avoid unstable apps
|
||||
if [ "${CODE_SIGNING_REQUIRED}" == "YES" ]; then
|
||||
code_sign "${destination}/$1"
|
||||
|
|
@ -49,9 +49,7 @@ code_sign() {
|
|||
|
||||
if [[ "$CONFIGURATION" == "Debug" ]]; then
|
||||
install_framework 'Nimble.framework'
|
||||
install_framework 'Quick.framework'
|
||||
fi
|
||||
if [[ "$CONFIGURATION" == "Release" ]]; then
|
||||
install_framework 'Nimble.framework'
|
||||
install_framework 'Quick.framework'
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -6,7 +6,13 @@ mkdir -p "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
|||
RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
|
||||
> "$RESOURCES_TO_COPY"
|
||||
|
||||
XCASSET_FILES=""
|
||||
XCASSET_FILES=()
|
||||
|
||||
realpath() {
|
||||
DIRECTORY=$(cd "${1%/*}" && pwd)
|
||||
FILENAME="${1##*/}"
|
||||
echo "$DIRECTORY/$FILENAME"
|
||||
}
|
||||
|
||||
install_resource()
|
||||
{
|
||||
|
|
@ -38,7 +44,8 @@ install_resource()
|
|||
xcrun mapc "${PODS_ROOT}/$1" "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$1" .xcmappingmodel`.cdm"
|
||||
;;
|
||||
*.xcassets)
|
||||
XCASSET_FILES="$XCASSET_FILES '$1'"
|
||||
ABSOLUTE_XCASSET_FILE=$(realpath "${PODS_ROOT}/$1")
|
||||
XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
|
||||
;;
|
||||
/*)
|
||||
echo "$1"
|
||||
|
|
@ -57,7 +64,7 @@ if [[ "${ACTION}" == "install" ]]; then
|
|||
fi
|
||||
rm -f "$RESOURCES_TO_COPY"
|
||||
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n $XCASSET_FILES ]
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
|
||||
then
|
||||
case "${TARGETED_DEVICE_FAMILY}" in
|
||||
1,2)
|
||||
|
|
@ -73,5 +80,14 @@ then
|
|||
TARGET_DEVICE_ARGS="--target-device mac"
|
||||
;;
|
||||
esac
|
||||
echo $XCASSET_FILES | xargs 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}"
|
||||
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
while read line; do
|
||||
if [[ $line != "`realpath $PODS_ROOT`*" ]]; then
|
||||
XCASSET_FILES+=("$line")
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
||||
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}"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
FRAMEWORK_SEARCH_PATHS = "$PODS_FRAMEWORK_BUILD_PATH"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_FRAMEWORK_BUILD_PATH"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_FRAMEWORK_BUILD_PATH/Nimble.framework/Headers" -iquote "$PODS_FRAMEWORK_BUILD_PATH/Quick.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -ObjC -framework "Nimble" -framework "Quick"
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_FRAMEWORK_BUILD_PATH/Nimble.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -ObjC -framework "Nimble"
|
||||
OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-cameraTests
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
FRAMEWORK_SEARCH_PATHS = "$PODS_FRAMEWORK_BUILD_PATH"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_FRAMEWORK_BUILD_PATH"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_FRAMEWORK_BUILD_PATH/Nimble.framework/Headers" -iquote "$PODS_FRAMEWORK_BUILD_PATH/Quick.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -ObjC -framework "Nimble" -framework "Quick"
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_FRAMEWORK_BUILD_PATH/Nimble.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -ObjC -framework "Nimble"
|
||||
OTHER_LIBTOOLFLAGS = $(OTHER_LDFLAGS)
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_FRAMEWORK_BUILD_PATH = $(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)/Pods-cameraTests
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1,16 +1,7 @@
|
|||
//
|
||||
// cameraTests.swift
|
||||
// cameraTests
|
||||
//
|
||||
// Created by Natalia Terlecka on 25/03/15.
|
||||
// Copyright (c) 2015 imaginaryCloud. All rights reserved.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import XCTest
|
||||
|
||||
import Quick
|
||||
|
||||
class cameraTests: XCTestCase {
|
||||
|
||||
override func setUp() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue