Commit 2f7d293d authored by Dapperstout's avatar Dapperstout

Added 'Quick' and 'Nimble' testing frameworks using CocoaPods.

parent 2bb86286
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
link_with 'Pulse', 'PulseTests', 'PulseIntegrationTests'
link_with 'Pulse'
use_frameworks!
pod 'SwiftBytes', '~> 0.1.0'
......@@ -10,3 +10,13 @@ pod 'lz4', '~> 123', :inhibit_warnings => true
pod 'Base32', '~> 1.0.2'
pod 'IGDigest', '~> 1.1.0'
pod 'OpenSSL-Framework', '~> 1.0.2'
target 'PulseTests' do
pod 'Quick', '~> 0.2.2'
pod 'Nimble', '~> 0.3.0'
end
target 'PulseIntegrationTests' do
pod 'Quick', '~> 0.2.2'
pod 'Nimble', '~> 0.3.0'
end
\ No newline at end of file
......@@ -3,7 +3,9 @@ PODS:
- CocoaAsyncSocket (7.4.1)
- IGDigest (1.1.2)
- lz4 (123)
- Nimble (0.3.0)
- OpenSSL-Framework (1.0.2)
- Quick (0.2.2)
- SwiftBytes (0.1.0)
DEPENDENCIES:
......@@ -11,7 +13,9 @@ DEPENDENCIES:
- CocoaAsyncSocket (~> 7.4)
- IGDigest (~> 1.1.0)
- lz4 (~> 123)
- Nimble (~> 0.3.0)
- OpenSSL-Framework (~> 1.0.2)
- Quick (~> 0.2.2)
- SwiftBytes (~> 0.1.0)
SPEC CHECKSUMS:
......@@ -19,7 +23,9 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: b0a1a89e7ea4c1c0ea4ec83f57d55117d3cdae06
IGDigest: b9ff1800bf1f0bdc3714fb4f0f63904464b2ddb4
lz4: 316468bb1b748b046e7d4452e46ffc5c7fddccf0
Nimble: a4d9d978129e83d73e33b7d8bce57443bd556068
OpenSSL-Framework: b1654dc18ef9a08ee7670c690a5e9795b44ce28d
Quick: 7b89ff625e72ef931c2a9ef2f25ac3a9d2457763
SwiftBytes: 2f33be5dd47e9cee01aae1ccd54c126ea1ab5a6e
COCOAPODS: 0.36.0.rc.1
../../../Nimble/Nimble/objc/DSL.h
\ No newline at end of file
../../../Nimble/Nimble/objc/NMBExceptionCapture.h
\ No newline at end of file
../../../Nimble/Nimble/Nimble.h
\ No newline at end of file
../../../Quick/Quick/NSString+QCKSelectorName.h
\ No newline at end of file
../../../Quick/Quick/DSL/QCKDSL.h
\ No newline at end of file
../../../Quick/Quick/Quick.h
\ No newline at end of file
../../../Quick/Quick/Configuration/QuickConfiguration.h
\ No newline at end of file
../../../Quick/Quick/QuickSpec.h
\ No newline at end of file
../../../Nimble/Nimble/objc/DSL.h
\ No newline at end of file
../../../Nimble/Nimble/objc/NMBExceptionCapture.h
\ No newline at end of file
../../../Nimble/Nimble/Nimble.h
\ No newline at end of file
../../../Quick/Quick/NSString+QCKSelectorName.h
\ No newline at end of file
../../../Quick/Quick/DSL/QCKDSL.h
\ No newline at end of file
../../../Quick/Quick/Quick.h
\ No newline at end of file
../../../Quick/Quick/Configuration/QuickConfiguration.h
\ No newline at end of file
../../../Quick/Quick/QuickSpec.h
\ No newline at end of file
......@@ -3,7 +3,9 @@ PODS:
- CocoaAsyncSocket (7.4.1)
- IGDigest (1.1.2)
- lz4 (123)
- Nimble (0.3.0)
- OpenSSL-Framework (1.0.2)
- Quick (0.2.2)
- SwiftBytes (0.1.0)
DEPENDENCIES:
......@@ -11,7 +13,9 @@ DEPENDENCIES:
- CocoaAsyncSocket (~> 7.4)
- IGDigest (~> 1.1.0)
- lz4 (~> 123)
- Nimble (~> 0.3.0)
- OpenSSL-Framework (~> 1.0.2)
- Quick (~> 0.2.2)
- SwiftBytes (~> 0.1.0)
SPEC CHECKSUMS:
......@@ -19,7 +23,9 @@ SPEC CHECKSUMS:
CocoaAsyncSocket: b0a1a89e7ea4c1c0ea4ec83f57d55117d3cdae06
IGDigest: b9ff1800bf1f0bdc3714fb4f0f63904464b2ddb4
lz4: 316468bb1b748b046e7d4452e46ffc5c7fddccf0
Nimble: a4d9d978129e83d73e33b7d8bce57443bd556068
OpenSSL-Framework: b1654dc18ef9a08ee7670c690a5e9795b44ce28d
Quick: 7b89ff625e72ef931c2a9ef2f25ac3a9d2457763
SwiftBytes: 2f33be5dd47e9cee01aae1ccd54c126ea1ab5a6e
COCOAPODS: 0.36.0.rc.1
This diff is collapsed.
import Foundation
/// Protocol for the assertion handler that Nimble uses for all expectations.
public protocol AssertionHandler {
func assert(assertion: Bool, message: String, location: SourceLocation)
}
/// Global backing interface for assertions that Nimble creates.
/// Defaults to a private test handler that passes through to XCTest.
///
/// @see AssertionHandler
var CurrentAssertionHandler: AssertionHandler = XCTestHandler()
import Foundation
/// A data structure that stores information about an assertion when
/// AssertionRecorder is set as the Nimble assertion handler.
///
/// @see AssertionRecorder
/// @see AssertionHandler
public struct AssertionRecord {
/// Whether the assertion succeeded or failed
public let success: Bool
/// The failure message the assertion would display on failure.
public let message: String
/// The source location the expectation occurred on.
public let location: SourceLocation
}
/// An AssertionHandler that silently records assertions that Nimble makes.
/// This is useful for testing failure messages for matchers.
///
/// @see AssertionHandler
public class AssertionRecorder : AssertionHandler {
/// All the assertions that were captured by this recorder
public var assertions = [AssertionRecord]()
public init() {}
public func assert(assertion: Bool, message: String, location: SourceLocation) {
assertions.append(
AssertionRecord(
success: assertion,
message: message,
location: location))
}
}
/// Allows you to temporarily replace the current Nimble assertion handler with
/// the one provided for the scope of the closure.
///
/// Once the closure finishes, then the original Nimble assertion handler is restored.
///
/// @see AssertionHandler
public func withAssertionHandler(tempAssertionHandler: AssertionHandler, closure: () -> Void) {
let oldRecorder = CurrentAssertionHandler
let capturer = NMBExceptionCapture(handler: nil, finally: ({
CurrentAssertionHandler = oldRecorder
}))
CurrentAssertionHandler = tempAssertionHandler
capturer.tryBlock {
closure()
}
}
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)
}
}
}
import Foundation
/// Only classes, protocols, methods, properties, and subscript declarations can be
/// 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 {
var completed = false
var token: dispatch_once_t = 0
let result = pollBlock(pollInterval: 0.01, timeoutInterval: timeout) {
dispatch_once(&token) {
dispatch_async(dispatch_get_main_queue()) {
action() { completed = true }
}
}
return completed
}
if result == PollResult.Failure {
let pluralize = (timeout == 1 ? "" : "s")
fail("Waited more than \(timeout) second\(pluralize)", file: file, line: line)
} else if result == PollResult.Timeout {
fail("Stall on main thread - too much enqueued on main run loop before waitUntil executes.", file: file, line: line)
}
}
public class func until(action: (() -> Void) -> Void, file: String = __FILE__, line: UInt = __LINE__) -> Void {
until(timeout: 1, action: action, file: file, line: line)
}
}
/// 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)
}
/// 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)
}
\ No newline at end of file
/// 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> {
return Expectation(
expression: Expression(
expression: expression,
location: SourceLocation(file: file, line: line)))
}
/// Make an expectation on a given actual value. The closure is lazily invoked.
public func expect<T>(file: String = __FILE__, line: UInt = __LINE__, expression: () -> T?) -> Expectation<T> {
return Expectation(
expression: Expression(
expression: expression,
location: SourceLocation(file: file, line: line)))
}
/// 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)
}
/// Always fails the test with a message.
public func fail(message: String, file: String = __FILE__, line: UInt = __LINE__) {
fail(message, location: SourceLocation(file: file, line: line))
}
/// Always fails the test.
public func fail(file: String = __FILE__, line: UInt = __LINE__) {
fail("fail() always fails")
}
\ No newline at end of file
import Foundation
public struct Expectation<T> {
let expression: Expression<T>
public func verify(pass: Bool, _ message: String) {
CurrentAssertionHandler.assert(pass, message: message, location: expression.location)
}
public func to<U where U: Matcher, U.ValueType == T>(matcher: U) {
var msg = FailureMessage()
let pass = matcher.matches(expression, failureMessage: msg)
if msg.actualValue == "" {
msg.actualValue = "<\(stringify(expression.evaluate()))>"
}
verify(pass, msg.stringValue())
}
public func toNot<U where U: Matcher, U.ValueType == T>(matcher: U) {
var msg = FailureMessage()
let pass = matcher.doesNotMatch(expression, failureMessage: msg)
if msg.actualValue == "" {
msg.actualValue = "<\(stringify(expression.evaluate()))>"
}
verify(pass, msg.stringValue())
}
public func notTo<U where U: Matcher, U.ValueType == T>(matcher: U) {
toNot(matcher)
}
// see:
// - BasicMatcherWrapper for extension
// - AsyncMatcherWrapper for extension
// - NonNilMatcherWrapper for extension
//
// - NMBExpectation for Objective-C interface
}
import Foundation
// Memoizes the given closure, only calling the passed
// closure once; even if repeat calls to the returned closure
internal func memoizedClosure<T>(closure: () -> T) -> (Bool) -> T {
var cache: T?
return ({ withoutCaching in
if (withoutCaching || cache == nil) {
cache = closure()
}
return cache!
})
}
public struct Expression<T> {
internal let _expression: (Bool) -> T?
internal let _withoutCaching: Bool
public let location: SourceLocation
public var cache: T?
public init(expression: () -> T?, location: SourceLocation) {
self._expression = memoizedClosure(expression)
self.location = location
self._withoutCaching = false
}
public init(memoizedExpression: (Bool) -> T?, location: SourceLocation, withoutCaching: Bool) {
self._expression = memoizedExpression
self.location = location
self._withoutCaching = withoutCaching
}
public func cast<U>(block: (T?) -> U?) -> Expression<U> {
return Expression<U>(expression: ({ block(self.evaluate()) }), location: self.location)
}
public func evaluate() -> T? {
return self._expression(_withoutCaching)
}
public func withoutCaching() -> Expression<T> {
return Expression(memoizedExpression: self._expression, location: location, withoutCaching: true)
}
}
import Foundation
@objc
public class FailureMessage {
public var expected: String = "expected"
public var actualValue: String? = "" // empty string -> use default; nil -> exclude
public var to: String = "to"
public var postfixMessage: String = "match"
public var postfixActual: String = ""
public init() {
}
public func stringValue() -> String {
var value = "\(expected) \(to) \(postfixMessage)"
if let actualValue = actualValue {
value = "\(expected) \(to) \(postfixMessage), got \(actualValue)\(postfixActual)"
}
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)
}
}
\ No newline at end of file
import Foundation
/// A Nimble matcher that succeeds when the actual value is an instance of the given class.
/// @see beAnInstanceOf if you want to match against the exact class
public func beAKindOf(expectedClass: AnyClass) -> NonNilMatcherFunc<NSObject> {
return NonNilMatcherFunc { actualExpression, failureMessage in
let instance = actualExpression.evaluate()
if let validInstance = instance {
failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>"
} else {
failureMessage.actualValue = "<nil>"
}
failureMessage.postfixMessage = "be a kind of \(NSStringFromClass(expectedClass))"
return instance != nil && instance!.isKindOfClass(expectedClass)
}
}
extension NMBObjCMatcher {
public class func beAKindOfMatcher(expected: AnyClass) -> NMBMatcher {
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage, location in
return beAKindOf(expected).matches(actualExpression, failureMessage: failureMessage)
}
}
}
import Foundation
/// A Nimble matcher that succeeds when the actual value is an instance of the given class.
/// @see beAKindOf if you want to match against subclasses
public func beAnInstanceOf(expectedClass: AnyClass) -> NonNilMatcherFunc<NSObject> {
return NonNilMatcherFunc { actualExpression, failureMessage in
let instance = actualExpression.evaluate()
if let validInstance = instance {
failureMessage.actualValue = "<\(NSStringFromClass(validInstance.dynamicType)) instance>"
} else {
failureMessage.actualValue = "<nil>"
}
failureMessage.postfixMessage = "be an instance of \(NSStringFromClass(expectedClass))"
return instance != nil && instance!.isMemberOfClass(expectedClass)
}
}
extension NMBObjCMatcher {
public class func beAnInstanceOfMatcher(expected: AnyClass) -> NMBMatcher {
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage, location in
return beAnInstanceOf(expected).matches(actualExpression, failureMessage: failureMessage)
}
}
}
import Foundation
let DefaultDelta = 0.0001
internal func isCloseTo(actualValue: Double?, expectedValue: Double, delta: Double, failureMessage: FailureMessage) -> Bool {
failureMessage.postfixMessage = "be close to <\(stringify(expectedValue))> (within \(stringify(delta)))"
if actualValue != nil {
failureMessage.actualValue = "<\(stringify(actualValue!))>"
} else {
failureMessage.actualValue = "<nil>"
}
return actualValue != nil && abs(actualValue! - expectedValue) < delta
}
/// A Nimble matcher that succeeds when a value is close to another. This is used for floating
/// point values which can have imprecise results when doing arithmetic on them.
///
/// @see equal
public func beCloseTo(expectedValue: Double, within delta: Double = DefaultDelta) -> NonNilMatcherFunc<Double> {
return NonNilMatcherFunc { actualExpression, failureMessage in
return isCloseTo(actualExpression.evaluate(), expectedValue, delta, failureMessage)
}
}
/// A Nimble matcher that succeeds when a value is close to another. This is used for floating
/// point values which can have imprecise results when doing arithmetic on them.
///
/// @see equal
public func beCloseTo(expectedValue: NMBDoubleConvertible, within delta: Double = DefaultDelta) -> NonNilMatcherFunc<NMBDoubleConvertible> {
return NonNilMatcherFunc { actualExpression, failureMessage in
return isCloseTo(actualExpression.evaluate()?.doubleValue, expectedValue.doubleValue, delta, failureMessage)
}
}
@objc public class NMBObjCBeCloseToMatcher : NMBMatcher {
var _expected: NSNumber
var _delta: CDouble
init(expected: NSNumber, within: CDouble) {
_expected = expected
_delta = within
}
public func matches(actualExpression: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool {
let actualBlock: () -> NMBDoubleConvertible? = ({
return actualExpression() as? NMBDoubleConvertible
})
let expr = Expression(expression: actualBlock, location: location)
let matcher = NonNilMatcherWrapper(NonNilBasicMatcherWrapper(beCloseTo(self._expected, within: self._delta)))
return matcher.matches(expr, failureMessage: failureMessage)
}
public func doesNotMatch(actualExpression: () -> NSObject!, failureMessage: FailureMessage, location: SourceLocation) -> Bool {
let actualBlock: () -> NMBDoubleConvertible? = ({
return actualExpression() as? NMBDoubleConvertible
})
let expr = Expression(expression: actualBlock, location: location)
let matcher = NonNilMatcherWrapper(NonNilBasicMatcherWrapper(beCloseTo(self._expected, within: self._delta)))
return matcher.doesNotMatch(expr, failureMessage: failureMessage)
}
public var within: (CDouble) -> NMBObjCBeCloseToMatcher {
return ({ delta in
return NMBObjCBeCloseToMatcher(expected: self._expected, within: delta)
})
}
}
extension NMBObjCMatcher {
public class func beCloseToMatcher(expected: NSNumber, within: CDouble) -> NMBObjCBeCloseToMatcher {
return NMBObjCBeCloseToMatcher(expected: expected, within: within)
}
}
public func beCloseTo(expectedValues: [Double], within delta: Double = DefaultDelta) -> NonNilMatcherFunc <[Double]> {
return NonNilMatcherFunc { actualExpression, failureMessage in
failureMessage.postfixMessage = "be close to <\(stringify(expectedValues))> (each within \(stringify(delta)))"
if let actual = actualExpression.evaluate() {
if actual.count != expectedValues.count {
return false
} else {
for (index, actualItem) in enumerate(actual) {
if fabs(actualItem - expectedValues[index]) > delta {
return false
}
}
return true
}
}
return false
}
}
// MARK: - Operators
infix operator {}
public func (lhs: Expectation<[Double]>, rhs: [Double]) {
lhs.to(beCloseTo(rhs))
}
public func (lhs: Expectation<Double>, rhs: Double) {
lhs.to(beCloseTo(rhs))
}
public func (lhs: Expectation<Double>, rhs: (expected: Double, delta: Double)) {
lhs.to(beCloseTo(rhs.expected, within: rhs.delta))
}
public func ==(lhs: Expectation<Double>, rhs: (expected: Double, delta: Double)) {
lhs.to(beCloseTo(rhs.expected, within: rhs.delta))
}
// make this higher precedence than exponents so the Doubles either end aren't pulled in
// unexpectantly
infix operator ± { precedence 170 }
public func ±(lhs: Double, rhs: Double) -> (expected: Double, delta: Double) {
return (expected: lhs, delta: rhs)
}
import Foundation
/// A Nimble matcher that succeeds when a value is "empty". For collections, this
/// means the are no items in that collection. For strings, it is an empty string.
public func beEmpty<S: SequenceType>() -> NonNilMatcherFunc<S> {
return NonNilMatcherFunc { actualExpression, failureMessage in
failureMessage.postfixMessage = "be empty"
let actualSeq = actualExpression.evaluate()
if actualSeq == nil {
return true
}
var generator = actualSeq!.generate()
return generator.next() == nil
}
}
/// A Nimble matcher that succeeds when a value is "empty". For collections, this
/// means the are no items in that collection. For strings, it is an empty string.
public func beEmpty() -> NonNilMatcherFunc<NSString> {
return NonNilMatcherFunc { actualExpression, failureMessage in
failureMessage.postfixMessage = "be empty"
let actualString = actualExpression.evaluate()
return actualString == nil || actualString!.length == 0
}
}
// Without specific overrides, beEmpty() is ambiguous for NSDictionary, NSArray,
// etc, since they conform to SequenceType as well as NMBCollection.
/// A Nimble matcher that succeeds when a value is "empty". For collections, this
/// means the are no items in that collection. For strings, it is an empty string.
public func beEmpty() -> NonNilMatcherFunc<NSDictionary> {
return NonNilMatcherFunc { actualExpression, failureMessage in
failureMessage.postfixMessage = "be empty"
let actualDictionary = actualExpression.evaluate()
return actualDictionary == nil || actualDictionary!.count == 0
}
}
/// A Nimble matcher that succeeds when a value is "empty". For collections, this