Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5c8c83f914 | |||
| ef2d9f5a90 | |||
| 08ebb473f2 | |||
| d32a041159 | |||
| 1057a7fca6 | |||
| cee2be50e2 | |||
| 8161c3cf02 | |||
| bb0f301383 | |||
| 9da1347d12 |
@@ -0,0 +1,32 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
If needed, include code examples for the problem or steps to reproduce.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Version [e.g. 0.7.0]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6, Simulator iPhone6 ...]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Version [e.g. 0.7.0]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution or feature you would like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
+2
-2
@@ -7,8 +7,8 @@ target 'SwiftAudio_Example' do
|
||||
target 'SwiftAudio_Tests' do
|
||||
inherit! :search_paths
|
||||
|
||||
pod 'Quick', '~> 1.3.0'
|
||||
pod 'Nimble' , '~> 7.3.0'
|
||||
pod 'Quick', '~> 2.0.0'
|
||||
pod 'Nimble' , '~> 8.0.0'
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
PODS:
|
||||
- Nimble (7.3.1)
|
||||
- Quick (1.3.2)
|
||||
- SwiftAudio (0.3.3)
|
||||
- Nimble (8.0.1)
|
||||
- Quick (2.0.0)
|
||||
- SwiftAudio (0.7.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Nimble (~> 7.3.0)
|
||||
- Quick (~> 1.3.0)
|
||||
- Nimble (~> 8.0.0)
|
||||
- Quick (~> 2.0.0)
|
||||
- SwiftAudio (from `../`)
|
||||
|
||||
SPEC REPOS:
|
||||
@@ -18,10 +18,10 @@ EXTERNAL SOURCES:
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Nimble: 04f732da099ea4d153122aec8c2a88fd0c7219ae
|
||||
Quick: 2623cb30d7a7f41ca62f684f679586558f483d46
|
||||
SwiftAudio: 2e712c3e04cf172d05639d7bb1516db7afd195da
|
||||
Nimble: 45f786ae66faa9a709624227fae502db55a8bdd0
|
||||
Quick: ce1276c7c27ba2da3cb2fd0cde053c3648b3b22d
|
||||
SwiftAudio: a7bb22e98fd48fd908f7ffca992166e0057ce8ea
|
||||
|
||||
PODFILE CHECKSUM: 8a75946cbc65d8d98176f80a88d8363a28d118ce
|
||||
PODFILE CHECKSUM: 08ea4075437f8ff3c4f84ed70827a8132461373f
|
||||
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "SwiftAudio",
|
||||
"version": "0.3.3",
|
||||
"version": "0.7.2",
|
||||
"summary": "Easy audio streaming for iOS",
|
||||
"description": "SwiftAudio is an audio player written in Swift, making it simpler to work with audio playback from streams and files.",
|
||||
"homepage": "https://github.com/jorgenhenrichsen/SwiftAudio",
|
||||
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"source": {
|
||||
"git": "https://github.com/jorgenhenrichsen/SwiftAudio.git",
|
||||
"tag": "0.3.3"
|
||||
"tag": "0.7.2"
|
||||
},
|
||||
"platforms": {
|
||||
"ios": "10.0"
|
||||
|
||||
Generated
+9
-9
@@ -1,11 +1,11 @@
|
||||
PODS:
|
||||
- Nimble (7.3.1)
|
||||
- Quick (1.3.2)
|
||||
- SwiftAudio (0.3.3)
|
||||
- Nimble (8.0.1)
|
||||
- Quick (2.0.0)
|
||||
- SwiftAudio (0.7.2)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Nimble (~> 7.3.0)
|
||||
- Quick (~> 1.3.0)
|
||||
- Nimble (~> 8.0.0)
|
||||
- Quick (~> 2.0.0)
|
||||
- SwiftAudio (from `../`)
|
||||
|
||||
SPEC REPOS:
|
||||
@@ -18,10 +18,10 @@ EXTERNAL SOURCES:
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Nimble: 04f732da099ea4d153122aec8c2a88fd0c7219ae
|
||||
Quick: 2623cb30d7a7f41ca62f684f679586558f483d46
|
||||
SwiftAudio: 2e712c3e04cf172d05639d7bb1516db7afd195da
|
||||
Nimble: 45f786ae66faa9a709624227fae502db55a8bdd0
|
||||
Quick: ce1276c7c27ba2da3cb2fd0cde053c3648b3b22d
|
||||
SwiftAudio: a7bb22e98fd48fd908f7ffca992166e0057ce8ea
|
||||
|
||||
PODFILE CHECKSUM: 8a75946cbc65d8d98176f80a88d8363a28d118ce
|
||||
PODFILE CHECKSUM: 08ea4075437f8ff3c4f84ed70827a8132461373f
|
||||
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
Generated
+7
-22
@@ -4,6 +4,7 @@
|
||||
[](https://cocoapods.org/pods/Nimble)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](https://cocoapods.org/pods/Nimble)
|
||||
[](https://houndci.com)
|
||||
|
||||
Use Nimble to express the expected outcomes of Swift
|
||||
or Objective-C expressions. Inspired by
|
||||
@@ -306,8 +307,7 @@ In Nimble, it's easy to make expectations on values that are updated
|
||||
asynchronously. Just use `toEventually` or `toEventuallyNot`:
|
||||
|
||||
```swift
|
||||
// Swift 3.0 and later
|
||||
|
||||
// Swift
|
||||
DispatchQueue.main.async {
|
||||
ocean.add("dolphins")
|
||||
ocean.add("whales")
|
||||
@@ -316,17 +316,6 @@ expect(ocean).toEventually(contain("dolphins", "whales"))
|
||||
```
|
||||
|
||||
|
||||
```swift
|
||||
// Swift 2.3 and earlier
|
||||
|
||||
dispatch_async(dispatch_get_main_queue()) {
|
||||
ocean.add("dolphins")
|
||||
ocean.add("whales")
|
||||
}
|
||||
expect(ocean).toEventually(contain("dolphins", "whales"))
|
||||
```
|
||||
|
||||
|
||||
```objc
|
||||
// Objective-C
|
||||
|
||||
@@ -857,11 +846,7 @@ Notes:
|
||||
|
||||
## Swift Error Handling
|
||||
|
||||
If you're using Swift 2.0 or newer, you can use the `throwError` matcher to check if an error is thrown.
|
||||
|
||||
Note:
|
||||
The following code sample references the `Swift.Error` protocol.
|
||||
This is `Swift.ErrorProtocol` in versions of Swift prior to version 3.0.
|
||||
You can use the `throwError` matcher to check if an error is thrown.
|
||||
|
||||
```swift
|
||||
// Swift
|
||||
@@ -1277,7 +1262,7 @@ public func equal<T: Equatable>(expectedValue: T?) -> Predicate<T> {
|
||||
// Predicate { actual in ... }
|
||||
//
|
||||
// But shown with types here for clarity.
|
||||
return Predicate { (actual: Expression<T>) throws -> PredicateResult in
|
||||
return Predicate { (actualExpression: Expression<T>) throws -> PredicateResult in
|
||||
let msg = ExpectationMessage.expectedActualValueTo("equal <\(expectedValue)>")
|
||||
if let actualValue = try actualExpression.evaluate() {
|
||||
return PredicateResult(
|
||||
@@ -1673,11 +1658,11 @@ backported.
|
||||
The deprecating plan is a 3 major versions removal. Which is as follows:
|
||||
|
||||
1. Introduce new `Predicate` API, deprecation warning for old matcher APIs.
|
||||
(Nimble `v7.x.x`)
|
||||
(Nimble `v7.x.x` and `v8.x.x`)
|
||||
2. Introduce warnings on migration-path features (`.predicate`,
|
||||
`Predicate`-constructors with similar arguments to old API). (Nimble
|
||||
`v8.x.x`)
|
||||
3. Remove old API. (Nimble `v9.x.x`)
|
||||
`v9.x.x`)
|
||||
3. Remove old API. (Nimble `v10.x.x`)
|
||||
|
||||
|
||||
# Installing Nimble
|
||||
|
||||
@@ -13,5 +13,6 @@ public protocol AssertionHandler {
|
||||
///
|
||||
/// @see AssertionHandler
|
||||
public var NimbleAssertionHandler: AssertionHandler = { () -> AssertionHandler in
|
||||
// swiftlint:disable:previous identifier_name
|
||||
return isXCTestAvailable() ? NimbleXCTestHandler() : NimbleXCTestUnavailableHandler()
|
||||
}()
|
||||
|
||||
@@ -37,21 +37,48 @@ public class AssertionRecorder: AssertionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
extension NMBExceptionCapture {
|
||||
internal func tryBlockThrows(_ unsafeBlock: () throws -> Void) throws {
|
||||
var catchedError: Error?
|
||||
tryBlock {
|
||||
do {
|
||||
try unsafeBlock()
|
||||
} catch {
|
||||
catchedError = error
|
||||
}
|
||||
}
|
||||
if let error = catchedError {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 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: () throws -> Void) {
|
||||
public func withAssertionHandler(_ tempAssertionHandler: AssertionHandler,
|
||||
file: FileString = #file,
|
||||
line: UInt = #line,
|
||||
closure: () throws -> Void) {
|
||||
let environment = NimbleEnvironment.activeInstance
|
||||
let oldRecorder = environment.assertionHandler
|
||||
let capturer = NMBExceptionCapture(handler: nil, finally: ({
|
||||
environment.assertionHandler = oldRecorder
|
||||
}))
|
||||
environment.assertionHandler = tempAssertionHandler
|
||||
capturer.tryBlock {
|
||||
try! closure()
|
||||
|
||||
do {
|
||||
try capturer.tryBlockThrows {
|
||||
try closure()
|
||||
}
|
||||
} catch {
|
||||
let failureMessage = FailureMessage()
|
||||
failureMessage.stringValue = "unexpected error thrown: <\(error)>"
|
||||
let location = SourceLocation(file: file, line: line)
|
||||
tempAssertionHandler.assert(false, message: failureMessage, location: location)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
|
||||
private func from(objcPredicate: NMBPredicate) -> Predicate<NSObject> {
|
||||
return Predicate { actualExpression in
|
||||
@@ -15,6 +15,7 @@ internal struct ObjCMatcherWrapper: Matcher {
|
||||
|
||||
func matches(_ actualExpression: Expression<NSObject>, failureMessage: FailureMessage) -> Bool {
|
||||
return matcher.matches(
|
||||
// swiftlint:disable:next force_try
|
||||
({ try! actualExpression.evaluate() }),
|
||||
failureMessage: failureMessage,
|
||||
location: actualExpression.location)
|
||||
@@ -22,6 +23,7 @@ internal struct ObjCMatcherWrapper: Matcher {
|
||||
|
||||
func doesNotMatch(_ actualExpression: Expression<NSObject>, failureMessage: FailureMessage) -> Bool {
|
||||
return matcher.doesNotMatch(
|
||||
// swiftlint:disable:next force_try
|
||||
({ try! actualExpression.evaluate() }),
|
||||
failureMessage: failureMessage,
|
||||
location: actualExpression.location)
|
||||
@@ -30,11 +32,13 @@ internal struct ObjCMatcherWrapper: Matcher {
|
||||
|
||||
// Equivalent to Expectation, but for Nimble's Objective-C interface
|
||||
public class NMBExpectation: NSObject {
|
||||
// swiftlint:disable identifier_name
|
||||
internal let _actualBlock: () -> NSObject?
|
||||
internal var _negative: Bool
|
||||
internal let _file: FileString
|
||||
internal let _line: UInt
|
||||
internal var _timeout: TimeInterval = 1.0
|
||||
// swiftlint:enable identifier_name
|
||||
|
||||
@objc public init(actualBlock: @escaping () -> NSObject?, negative: Bool, file: FileString, line: UInt) {
|
||||
self._actualBlock = actualBlock
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
|
||||
// swiftlint:disable line_length
|
||||
public typealias MatcherBlock = (_ actualExpression: Expression<NSObject>, _ failureMessage: FailureMessage) throws -> Bool
|
||||
@@ -8,8 +8,10 @@ public typealias FullMatcherBlock = (_ actualExpression: Expression<NSObject>, _
|
||||
// swiftlint:enable line_length
|
||||
|
||||
public class NMBObjCMatcher: NSObject, NMBMatcher {
|
||||
// swiftlint:disable identifier_name
|
||||
let _match: MatcherBlock
|
||||
let _doesNotMatch: MatcherBlock
|
||||
// swiftlint:enable identifier_name
|
||||
let canMatchNil: Bool
|
||||
|
||||
public init(canMatchNil: Bool, matcher: @escaping MatcherBlock, notMatcher: @escaping MatcherBlock) {
|
||||
|
||||
@@ -3,7 +3,7 @@ import Foundation
|
||||
|
||||
/// "Global" state of Nimble is stored here. Only DSL functions should access / be aware of this
|
||||
/// class' existence
|
||||
internal class NimbleEnvironment {
|
||||
internal class NimbleEnvironment: NSObject {
|
||||
static var activeInstance: NimbleEnvironment {
|
||||
get {
|
||||
let env = Thread.current.threadDictionary["NimbleEnvironment"]
|
||||
@@ -20,6 +20,7 @@ internal class NimbleEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next todo
|
||||
// TODO: eventually migrate the global to this environment value
|
||||
var assertionHandler: AssertionHandler {
|
||||
get { return NimbleAssertionHandler }
|
||||
@@ -29,17 +30,14 @@ internal class NimbleEnvironment {
|
||||
var suppressTVOSAssertionWarning: Bool = false
|
||||
var awaiter: Awaiter
|
||||
|
||||
init() {
|
||||
let timeoutQueue: DispatchQueue
|
||||
if #available(OSX 10.10, *) {
|
||||
timeoutQueue = DispatchQueue.global(qos: .userInitiated)
|
||||
} else {
|
||||
timeoutQueue = DispatchQueue.global(priority: .high)
|
||||
}
|
||||
|
||||
override init() {
|
||||
let timeoutQueue = DispatchQueue.global(qos: .userInitiated)
|
||||
awaiter = Awaiter(
|
||||
waitLock: AssertionWaitLock(),
|
||||
asyncQueue: .main,
|
||||
timeoutQueue: timeoutQueue)
|
||||
timeoutQueue: timeoutQueue
|
||||
)
|
||||
|
||||
super.init()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class NimbleXCTestUnavailableHandler: AssertionHandler {
|
||||
#endif
|
||||
|
||||
func isXCTestAvailable() -> Bool {
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
// XCTest is weakly linked and so may not be present
|
||||
return NSClassFromString("XCTestCase") != nil
|
||||
#else
|
||||
@@ -77,15 +77,14 @@ public func recordFailure(_ message: String, location: SourceLocation) {
|
||||
XCTFail("\(message)", file: location.file, line: location.line)
|
||||
#else
|
||||
if let testCase = CurrentTestCaseTracker.sharedInstance.currentTestCase {
|
||||
#if swift(>=4)
|
||||
let line = Int(location.line)
|
||||
#else
|
||||
let line = location.line
|
||||
#endif
|
||||
testCase.recordFailure(withDescription: message, inFile: location.file, atLine: line, expected: true)
|
||||
} else {
|
||||
let msg = "Attempted to report a test failure to XCTest while no test case was running. " +
|
||||
"The failure was:\n\"\(message)\"\nIt occurred at: \(location.file):\(location.line)"
|
||||
let msg = """
|
||||
Attempted to report a test failure to XCTest while no test case was running. The failure was:
|
||||
\"\(message)\"
|
||||
It occurred at: \(location.file):\(location.line)
|
||||
"""
|
||||
NSException(name: .internalInconsistencyException, reason: msg, userInfo: nil).raise()
|
||||
}
|
||||
#endif
|
||||
|
||||
+10
-4
@@ -14,7 +14,7 @@ internal class NMBWait: NSObject {
|
||||
// About these kind of lines, `@objc` attributes are only required for Objective-C
|
||||
// support, so that should be conditional on Darwin platforms and normal Xcode builds
|
||||
// (non-SwiftPM builds).
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objc
|
||||
internal class func until(
|
||||
timeout: TimeInterval,
|
||||
@@ -87,13 +87,19 @@ internal class NMBWait: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objc(untilFile:line:action:)
|
||||
internal class func until(_ file: FileString = #file, line: UInt = #line, action: @escaping (() -> Void) -> Void) {
|
||||
internal class func until(
|
||||
_ file: FileString = #file,
|
||||
line: UInt = #line,
|
||||
action: @escaping (@escaping () -> Void) -> Void) {
|
||||
until(timeout: 1, file: file, line: line, action: action)
|
||||
}
|
||||
#else
|
||||
internal class func until(_ file: FileString = #file, line: UInt = #line, action: @escaping (() -> Void) -> Void) {
|
||||
internal class func until(
|
||||
_ file: FileString = #file,
|
||||
line: UInt = #line,
|
||||
action: @escaping (@escaping () -> Void) -> Void) {
|
||||
until(timeout: 1, file: file, line: line, action: action)
|
||||
}
|
||||
#endif
|
||||
|
||||
+11
-7
@@ -43,12 +43,13 @@ internal func nimblePrecondition(
|
||||
line: UInt = #line) {
|
||||
let result = expr()
|
||||
if !result {
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
let e = NSException(
|
||||
#if canImport(Darwin)
|
||||
let exception = NSException(
|
||||
name: NSExceptionName(name()),
|
||||
reason: message(),
|
||||
userInfo: nil)
|
||||
e.raise()
|
||||
userInfo: nil
|
||||
)
|
||||
exception.raise()
|
||||
#else
|
||||
preconditionFailure("\(name()) - \(message())", file: file, line: line)
|
||||
#endif
|
||||
@@ -56,9 +57,12 @@ internal func nimblePrecondition(
|
||||
}
|
||||
|
||||
internal func internalError(_ msg: String, file: FileString = #file, line: UInt = #line) -> Never {
|
||||
// swiftlint:disable line_length
|
||||
fatalError(
|
||||
"Nimble Bug Found: \(msg) at \(file):\(line).\n" +
|
||||
"Please file a bug to Nimble: https://github.com/Quick/Nimble/issues with the " +
|
||||
"code snippet that caused this error."
|
||||
"""
|
||||
Nimble Bug Found: \(msg) at \(file):\(line).
|
||||
Please file a bug to Nimble: https://github.com/Quick/Nimble/issues with the code snippet that caused this error.
|
||||
"""
|
||||
)
|
||||
// swiftlint:enable line_length
|
||||
}
|
||||
|
||||
+16
-13
@@ -75,6 +75,7 @@ public indirect enum ExpectationMessage {
|
||||
}
|
||||
|
||||
internal func visitLeafs(_ f: (ExpectationMessage) -> ExpectationMessage) -> ExpectationMessage {
|
||||
// swiftlint:disable:previous identifier_name
|
||||
switch self {
|
||||
case .fail, .expectedTo, .expectedActualValueTo, .expectedCustomValueTo:
|
||||
return f(self)
|
||||
@@ -90,6 +91,7 @@ public indirect enum ExpectationMessage {
|
||||
/// Replaces a primary expectation with one returned by f. Preserves all composite expectations
|
||||
/// that were built upon it (aka - all appended(message:) and appended(details:).
|
||||
public func replacedExpectation(_ f: @escaping (ExpectationMessage) -> ExpectationMessage) -> ExpectationMessage {
|
||||
// swiftlint:disable:previous identifier_name
|
||||
func walk(_ msg: ExpectationMessage) -> ExpectationMessage {
|
||||
switch msg {
|
||||
case .fail, .expectedTo, .expectedActualValueTo, .expectedCustomValueTo:
|
||||
@@ -124,6 +126,7 @@ public indirect enum ExpectationMessage {
|
||||
return visitLeafs(walk)
|
||||
}
|
||||
|
||||
// swiftlint:disable:next todo
|
||||
// TODO: test & verify correct behavior
|
||||
internal func prepended(message: String) -> ExpectationMessage {
|
||||
return .prepends(message, self)
|
||||
@@ -183,32 +186,32 @@ public indirect enum ExpectationMessage {
|
||||
|
||||
extension FailureMessage {
|
||||
internal func toExpectationMessage() -> ExpectationMessage {
|
||||
let defaultMsg = FailureMessage()
|
||||
if expected != defaultMsg.expected || _stringValueOverride != nil {
|
||||
let defaultMessage = FailureMessage()
|
||||
if expected != defaultMessage.expected || _stringValueOverride != nil {
|
||||
return .fail(stringValue)
|
||||
}
|
||||
|
||||
var msg: ExpectationMessage = .fail(userDescription ?? "")
|
||||
var message: ExpectationMessage = .fail(userDescription ?? "")
|
||||
if actualValue != "" && actualValue != nil {
|
||||
msg = .expectedCustomValueTo(postfixMessage, actualValue ?? "")
|
||||
} else if postfixMessage != defaultMsg.postfixMessage {
|
||||
message = .expectedCustomValueTo(postfixMessage, actualValue ?? "")
|
||||
} else if postfixMessage != defaultMessage.postfixMessage {
|
||||
if actualValue == nil {
|
||||
msg = .expectedTo(postfixMessage)
|
||||
message = .expectedTo(postfixMessage)
|
||||
} else {
|
||||
msg = .expectedActualValueTo(postfixMessage)
|
||||
message = .expectedActualValueTo(postfixMessage)
|
||||
}
|
||||
}
|
||||
if postfixActual != defaultMsg.postfixActual {
|
||||
msg = .appends(msg, postfixActual)
|
||||
if postfixActual != defaultMessage.postfixActual {
|
||||
message = .appends(message, postfixActual)
|
||||
}
|
||||
if let m = extendedMessage {
|
||||
msg = .details(msg, m)
|
||||
if let extended = extendedMessage {
|
||||
message = .details(message, extended)
|
||||
}
|
||||
return msg
|
||||
return message
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
|
||||
public class NMBExpectationMessage: NSObject {
|
||||
private let msg: ExpectationMessage
|
||||
|
||||
@@ -24,8 +24,10 @@ internal func memoizedClosure<T>(_ closure: @escaping () throws -> T) -> (Bool)
|
||||
/// This provides a common consumable API for matchers to utilize to allow
|
||||
/// Nimble to change internals to how the captured closure is managed.
|
||||
public struct Expression<T> {
|
||||
// swiftlint:disable identifier_name
|
||||
internal let _expression: (Bool) throws -> T?
|
||||
internal let _withoutCaching: Bool
|
||||
// swiftlint:enable identifier_name
|
||||
public let location: SourceLocation
|
||||
public let isClosure: Bool
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ public class FailureMessage: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
// swiftlint:disable:next identifier_name
|
||||
internal var _stringValueOverride: String?
|
||||
internal var hasOverriddenStringValue: Bool {
|
||||
return _stringValueOverride != nil
|
||||
|
||||
+2
-1
@@ -63,7 +63,7 @@ private func createPredicate<S>(_ elementMatcher: Predicate<S.Iterator.Element>)
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func allPassMatcher(_ matcher: NMBMatcher) -> NMBPredicate {
|
||||
return NMBPredicate { actualExpression in
|
||||
@@ -103,6 +103,7 @@ extension NMBObjCMatcher {
|
||||
} else {
|
||||
let failureMessage = FailureMessage()
|
||||
let result = matcher.matches(
|
||||
// swiftlint:disable:next force_try
|
||||
({ try! expr.evaluate() }),
|
||||
failureMessage: failureMessage,
|
||||
location: expr.location
|
||||
|
||||
+10
-4
@@ -23,14 +23,18 @@ private func async<T>(style: ExpectationStyle, predicate: Predicate<T>, timeout:
|
||||
}
|
||||
switch result {
|
||||
case .completed: return lastPredicateResult!
|
||||
case .timedOut: return PredicateResult(status: .fail, message: lastPredicateResult!.message)
|
||||
case .timedOut:
|
||||
let message = lastPredicateResult?.message ?? .fail("timed out before returning a value")
|
||||
return PredicateResult(status: .fail, message: message)
|
||||
case let .errorThrown(error):
|
||||
return PredicateResult(status: .fail, message: .fail("unexpected error thrown: <\(error)>"))
|
||||
case let .raisedException(exception):
|
||||
return PredicateResult(status: .fail, message: .fail("unexpected exception raised: \(exception)"))
|
||||
case .blockedRunLoop:
|
||||
// swiftlint:disable:next line_length
|
||||
return PredicateResult(status: .fail, message: lastPredicateResult!.message.appended(message: " (timed out, but main thread was unresponsive)."))
|
||||
let message = lastPredicateResult?.message.appended(message: " (timed out, but main run loop was unresponsive).") ??
|
||||
.fail("main run loop was unresponsive")
|
||||
return PredicateResult(status: .fail, message: message)
|
||||
case .incomplete:
|
||||
internalError("Reached .incomplete state for \(fnName)(...).")
|
||||
}
|
||||
@@ -38,8 +42,10 @@ private func async<T>(style: ExpectationStyle, predicate: Predicate<T>, timeout:
|
||||
}
|
||||
|
||||
private let toEventuallyRequiresClosureError = FailureMessage(
|
||||
// swiftlint:disable:next line_length
|
||||
stringValue: "expect(...).toEventually(...) requires an explicit closure (eg - expect { ... }.toEventually(...) )\nSwift 1.2 @autoclosure behavior has changed in an incompatible way for Nimble to function"
|
||||
stringValue: """
|
||||
expect(...).toEventually(...) requires an explicit closure (eg - expect { ... }.toEventually(...) )
|
||||
Swift 1.2 @autoclosure behavior has changed in an incompatible way for Nimble to function
|
||||
"""
|
||||
)
|
||||
|
||||
extension Expectation {
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ public func beAKindOf<T>(_ expectedType: T.Type) -> Predicate<Any> {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
|
||||
/// 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
|
||||
|
||||
@@ -33,7 +33,7 @@ public func beAnInstanceOf(_ expectedClass: AnyClass) -> Predicate<NSObject> {
|
||||
} else {
|
||||
actualString = "<nil>"
|
||||
}
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
let matches = instance != nil && instance!.isMember(of: expectedClass)
|
||||
#else
|
||||
let matches = instance != nil && type(of: instance!) == expectedClass
|
||||
@@ -45,7 +45,7 @@ public func beAnInstanceOf(_ expectedClass: AnyClass) -> Predicate<NSObject> {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beAnInstanceOfMatcher(_ expected: AnyClass) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
|
||||
+8
-1
@@ -1,5 +1,6 @@
|
||||
import Foundation
|
||||
|
||||
// swiftlint:disable:next identifier_name
|
||||
public let DefaultDelta = 0.0001
|
||||
|
||||
internal func isCloseTo(_ actualValue: NMBDoubleConvertible?,
|
||||
@@ -34,10 +35,12 @@ public func beCloseTo(_ expectedValue: NMBDoubleConvertible, within delta: Doubl
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
public class NMBObjCBeCloseToMatcher: NSObject, NMBMatcher {
|
||||
// swiftlint:disable identifier_name
|
||||
var _expected: NSNumber
|
||||
var _delta: CDouble
|
||||
// swiftlint:enable identifier_name
|
||||
init(expected: NSNumber, within: CDouble) {
|
||||
_expected = expected
|
||||
_delta = within
|
||||
@@ -110,14 +113,17 @@ public func beCloseTo(_ expectedValues: [Double], within delta: Double = Default
|
||||
|
||||
infix operator ≈ : ComparisonPrecedence
|
||||
|
||||
// swiftlint:disable:next identifier_name
|
||||
public func ≈(lhs: Expectation<[Double]>, rhs: [Double]) {
|
||||
lhs.to(beCloseTo(rhs))
|
||||
}
|
||||
|
||||
// swiftlint:disable:next identifier_name
|
||||
public func ≈(lhs: Expectation<NMBDoubleConvertible>, rhs: NMBDoubleConvertible) {
|
||||
lhs.to(beCloseTo(rhs))
|
||||
}
|
||||
|
||||
// swiftlint:disable:next identifier_name
|
||||
public func ≈(lhs: Expectation<NMBDoubleConvertible>, rhs: (expected: NMBDoubleConvertible, delta: Double)) {
|
||||
lhs.to(beCloseTo(rhs.expected, within: rhs.delta))
|
||||
}
|
||||
@@ -133,6 +139,7 @@ precedencegroup PlusMinusOperatorPrecedence {
|
||||
}
|
||||
|
||||
infix operator ± : PlusMinusOperatorPrecedence
|
||||
// swiftlint:disable:next identifier_name
|
||||
public func ±(lhs: NMBDoubleConvertible, rhs: Double) -> (expected: NMBDoubleConvertible, delta: Double) {
|
||||
return (expected: lhs, delta: rhs)
|
||||
}
|
||||
|
||||
+25
-4
@@ -4,15 +4,36 @@ import Foundation
|
||||
/// means the are no items in that collection. For strings, it is an empty string.
|
||||
public func beEmpty<S: Sequence>() -> Predicate<S> {
|
||||
return Predicate.simple("be empty") { actualExpression in
|
||||
let actualSeq = try actualExpression.evaluate()
|
||||
if actualSeq == nil {
|
||||
guard let actual = try actualExpression.evaluate() else {
|
||||
return .fail
|
||||
}
|
||||
var generator = actualSeq!.makeIterator()
|
||||
var generator = actual.makeIterator()
|
||||
return PredicateStatus(bool: 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<S: SetAlgebra>() -> Predicate<S> {
|
||||
return Predicate.simple("be empty") { actualExpression in
|
||||
guard let actual = try actualExpression.evaluate() else {
|
||||
return .fail
|
||||
}
|
||||
return PredicateStatus(bool: actual.isEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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: Sequence & SetAlgebra>() -> Predicate<S> {
|
||||
return Predicate.simple("be empty") { actualExpression in
|
||||
guard let actual = try actualExpression.evaluate() else {
|
||||
return .fail
|
||||
}
|
||||
return PredicateStatus(bool: actual.isEmpty)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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() -> Predicate<String> {
|
||||
@@ -61,7 +82,7 @@ public func beEmpty() -> Predicate<NMBCollection> {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beEmptyMatcher() -> NMBPredicate {
|
||||
return NMBPredicate { actualExpression in
|
||||
|
||||
@@ -30,12 +30,12 @@ public func > (lhs: Expectation<NMBComparable>, rhs: NMBComparable?) {
|
||||
lhs.to(beGreaterThan(rhs))
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beGreaterThanMatcher(_ expected: NMBComparable?) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func beGreaterThanMatcher(_ expected: NMBComparable?) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let expr = actualExpression.cast { $0 as? NMBComparable }
|
||||
return try beGreaterThan(expected).matches(expr, failureMessage: failureMessage)
|
||||
return try beGreaterThan(expected).satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ public func >=<T: NMBComparable>(lhs: Expectation<T>, rhs: T) {
|
||||
lhs.to(beGreaterThanOrEqualTo(rhs))
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beGreaterThanOrEqualToMatcher(_ expected: NMBComparable?) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func beGreaterThanOrEqualToMatcher(_ expected: NMBComparable?) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let expr = actualExpression.cast { $0 as? NMBComparable }
|
||||
return try beGreaterThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage)
|
||||
return try beGreaterThanOrEqualTo(expected).satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,14 @@ import Foundation
|
||||
/// as the expected instance.
|
||||
public func beIdenticalTo(_ expected: Any?) -> Predicate<Any> {
|
||||
return Predicate.define { actualExpression in
|
||||
#if os(Linux)
|
||||
#if os(Linux) && !swift(>=4.1.50)
|
||||
let actual = try actualExpression.evaluate() as? AnyObject
|
||||
#else
|
||||
let actual = try actualExpression.evaluate() as AnyObject?
|
||||
#endif
|
||||
|
||||
let bool: Bool
|
||||
#if os(Linux)
|
||||
#if os(Linux) && !swift(>=4.1.50)
|
||||
bool = actual === (expected as? AnyObject) && actual !== nil
|
||||
#else
|
||||
bool = actual === (expected as AnyObject?) && actual !== nil
|
||||
@@ -41,12 +41,12 @@ public func be(_ expected: Any?) -> Predicate<Any> {
|
||||
return beIdenticalTo(expected)
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beIdenticalToMatcher(_ expected: NSObject?) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func beIdenticalToMatcher(_ expected: NSObject?) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let aExpr = actualExpression.cast { $0 as Any? }
|
||||
return try beIdenticalTo(expected).matches(aExpr, failureMessage: failureMessage)
|
||||
return try beIdenticalTo(expected).satisfies(aExpr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ public func < (lhs: Expectation<NMBComparable>, rhs: NMBComparable?) {
|
||||
lhs.to(beLessThan(rhs))
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beLessThanMatcher(_ expected: NMBComparable?) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func beLessThanMatcher(_ expected: NMBComparable?) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let expr = actualExpression.cast { $0 as? NMBComparable }
|
||||
return try beLessThan(expected).matches(expr, failureMessage: failureMessage)
|
||||
return try beLessThan(expected).satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,12 +29,12 @@ public func <=<T: NMBComparable>(lhs: Expectation<T>, rhs: T) {
|
||||
lhs.to(beLessThanOrEqualTo(rhs))
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beLessThanOrEqualToMatcher(_ expected: NMBComparable?) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func beLessThanOrEqualToMatcher(_ expected: NMBComparable?) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let expr = actualExpression.cast { $0 as? NMBComparable }
|
||||
return try beLessThanOrEqualTo(expected).matches(expr, failureMessage: failureMessage)
|
||||
return try beLessThanOrEqualTo(expected).satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-30
@@ -100,14 +100,6 @@ public func beTruthy<T: ExpressibleByBooleanLiteral & Equatable>() -> Predicate<
|
||||
return Predicate.simpleNilable("be truthy") { actualExpression in
|
||||
let actualValue = try actualExpression.evaluate()
|
||||
if let actualValue = actualValue {
|
||||
// FIXME: This is a workaround to SR-2290.
|
||||
// See:
|
||||
// - https://bugs.swift.org/browse/SR-2290
|
||||
// - https://github.com/norio-nomura/Nimble/pull/5#issuecomment-237835873
|
||||
if let number = actualValue as? NSNumber {
|
||||
return PredicateStatus(bool: number.boolValue == true)
|
||||
}
|
||||
|
||||
return PredicateStatus(bool: actualValue == (true as T))
|
||||
}
|
||||
return PredicateStatus(bool: actualValue != nil)
|
||||
@@ -120,47 +112,42 @@ public func beFalsy<T: ExpressibleByBooleanLiteral & Equatable>() -> Predicate<T
|
||||
return Predicate.simpleNilable("be falsy") { actualExpression in
|
||||
let actualValue = try actualExpression.evaluate()
|
||||
if let actualValue = actualValue {
|
||||
// FIXME: This is a workaround to SR-2290.
|
||||
// See:
|
||||
// - https://bugs.swift.org/browse/SR-2290
|
||||
// - https://github.com/norio-nomura/Nimble/pull/5#issuecomment-237835873
|
||||
if let number = actualValue as? NSNumber {
|
||||
return PredicateStatus(bool: number.boolValue == false)
|
||||
}
|
||||
|
||||
return PredicateStatus(bool: actualValue == (false as T))
|
||||
}
|
||||
return PredicateStatus(bool: actualValue == nil)
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beTruthyMatcher() -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher { actualExpression, failureMessage in
|
||||
@objc public class func beTruthyMatcher() -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false }
|
||||
return try beTruthy().matches(expr, failureMessage: failureMessage)
|
||||
return try beTruthy().satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
|
||||
@objc public class func beFalsyMatcher() -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher { actualExpression, failureMessage in
|
||||
@objc public class func beFalsyMatcher() -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false }
|
||||
return try beFalsy().matches(expr, failureMessage: failureMessage)
|
||||
return try beFalsy().satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
|
||||
@objc public class func beTrueMatcher() -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher { actualExpression, failureMessage in
|
||||
@objc public class func beTrueMatcher() -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false }
|
||||
return try beTrue().matches(expr, failureMessage: failureMessage)
|
||||
return try beTrue().satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
|
||||
@objc public class func beFalseMatcher() -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
let expr = actualExpression.cast { ($0 as? NSNumber)?.boolValue ?? false }
|
||||
return try beFalse().matches(expr, failureMessage: failureMessage)
|
||||
@objc public class func beFalseMatcher() -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let expr = actualExpression.cast { value -> Bool? in
|
||||
guard let value = value else { return nil }
|
||||
return (value as? NSNumber)?.boolValue ?? false
|
||||
}
|
||||
return try beFalse().satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -8,11 +8,11 @@ public func beNil<T>() -> Predicate<T> {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beNilMatcher() -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher { actualExpression, failureMessage in
|
||||
return try beNil().matches(actualExpression, failureMessage: failureMessage)
|
||||
@objc public class func beNilMatcher() -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
return try beNil().satisfies(actualExpression).toObjectiveC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+7
-5
@@ -8,10 +8,12 @@ public func beVoid() -> Predicate<()> {
|
||||
}
|
||||
}
|
||||
|
||||
public func == (lhs: Expectation<()>, rhs: ()) {
|
||||
lhs.to(beVoid())
|
||||
}
|
||||
extension Expectation where T == () {
|
||||
public static func == (lhs: Expectation<()>, rhs: ()) {
|
||||
lhs.to(beVoid())
|
||||
}
|
||||
|
||||
public func != (lhs: Expectation<()>, rhs: ()) {
|
||||
lhs.toNot(beVoid())
|
||||
public static func != (lhs: Expectation<()>, rhs: ()) {
|
||||
lhs.toNot(beVoid())
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -35,24 +35,24 @@ public func beginWith(_ startingElement: Any) -> Predicate<NMBOrderedCollection>
|
||||
public func beginWith(_ startingSubstring: String) -> Predicate<String> {
|
||||
return Predicate.simple("begin with <\(startingSubstring)>") { actualExpression in
|
||||
if let actual = try actualExpression.evaluate() {
|
||||
let range = actual.range(of: startingSubstring)
|
||||
return PredicateStatus(bool: range != nil && range!.lowerBound == actual.startIndex)
|
||||
return PredicateStatus(bool: actual.hasPrefix(startingSubstring))
|
||||
}
|
||||
return .fail
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func beginWithMatcher(_ expected: Any) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func beginWithMatcher(_ expected: Any) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let actual = try actualExpression.evaluate()
|
||||
if (actual as? String) != nil {
|
||||
if actual is String {
|
||||
let expr = actualExpression.cast { $0 as? String }
|
||||
return try beginWith(expected as! String).matches(expr, failureMessage: failureMessage)
|
||||
// swiftlint:disable:next force_cast
|
||||
return try beginWith(expected as! String).satisfies(expr).toObjectiveC()
|
||||
} else {
|
||||
let expr = actualExpression.cast { $0 as? NMBOrderedCollection }
|
||||
return try beginWith(expected).matches(expr, failureMessage: failureMessage)
|
||||
return try beginWith(expected).satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+67
-18
@@ -1,16 +1,17 @@
|
||||
import Foundation
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual sequence contains the expected value.
|
||||
/// A Nimble matcher that succeeds when the actual sequence contains the expected values.
|
||||
public func contain<S: Sequence, T: Equatable>(_ items: T...) -> Predicate<S>
|
||||
where S.Iterator.Element == T {
|
||||
where S.Element == T {
|
||||
return contain(items)
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual sequence contains the expected values.
|
||||
public func contain<S: Sequence, T: Equatable>(_ items: [T]) -> Predicate<S>
|
||||
where S.Iterator.Element == T {
|
||||
where S.Element == T {
|
||||
return Predicate.simple("contain <\(arrayAsString(items))>") { actualExpression in
|
||||
if let actual = try actualExpression.evaluate() {
|
||||
let matches = items.all {
|
||||
let matches = items.allSatisfy {
|
||||
return actual.contains($0)
|
||||
}
|
||||
return PredicateStatus(bool: matches)
|
||||
@@ -19,6 +20,46 @@ public func contain<S: Sequence, T: Equatable>(_ items: [T]) -> Predicate<S>
|
||||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual set contains the expected values.
|
||||
public func contain<S: SetAlgebra, T: Equatable>(_ items: T...) -> Predicate<S>
|
||||
where S.Element == T {
|
||||
return contain(items)
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual set contains the expected values.
|
||||
public func contain<S: SetAlgebra, T: Equatable>(_ items: [T]) -> Predicate<S>
|
||||
where S.Element == T {
|
||||
return Predicate.simple("contain <\(arrayAsString(items))>") { actualExpression in
|
||||
if let actual = try actualExpression.evaluate() {
|
||||
let matches = items.allSatisfy {
|
||||
return actual.contains($0)
|
||||
}
|
||||
return PredicateStatus(bool: matches)
|
||||
}
|
||||
return .fail
|
||||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual set contains the expected values.
|
||||
public func contain<S: Sequence & SetAlgebra, T: Equatable>(_ items: T...) -> Predicate<S>
|
||||
where S.Element == T {
|
||||
return contain(items)
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual set contains the expected values.
|
||||
public func contain<S: Sequence & SetAlgebra, T: Equatable>(_ items: [T]) -> Predicate<S>
|
||||
where S.Element == T {
|
||||
return Predicate.simple("contain <\(arrayAsString(items))>") { actualExpression in
|
||||
if let actual = try actualExpression.evaluate() {
|
||||
let matches = items.allSatisfy {
|
||||
return actual.contains($0)
|
||||
}
|
||||
return PredicateStatus(bool: matches)
|
||||
}
|
||||
return .fail
|
||||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual string contains the expected substring.
|
||||
public func contain(_ substrings: String...) -> Predicate<String> {
|
||||
return contain(substrings)
|
||||
@@ -27,7 +68,7 @@ public func contain(_ substrings: String...) -> Predicate<String> {
|
||||
public func contain(_ substrings: [String]) -> Predicate<String> {
|
||||
return Predicate.simple("contain <\(arrayAsString(substrings))>") { actualExpression in
|
||||
if let actual = try actualExpression.evaluate() {
|
||||
let matches = substrings.all {
|
||||
let matches = substrings.allSatisfy {
|
||||
let range = actual.range(of: $0)
|
||||
return range != nil && !range!.isEmpty
|
||||
}
|
||||
@@ -45,7 +86,7 @@ public func contain(_ substrings: NSString...) -> Predicate<NSString> {
|
||||
public func contain(_ substrings: [NSString]) -> Predicate<NSString> {
|
||||
return Predicate.simple("contain <\(arrayAsString(substrings))>") { actualExpression in
|
||||
if let actual = try actualExpression.evaluate() {
|
||||
let matches = substrings.all { actual.range(of: $0.description).length != 0 }
|
||||
let matches = substrings.allSatisfy { actual.range(of: $0.description).length != 0 }
|
||||
return PredicateStatus(bool: matches)
|
||||
}
|
||||
return .fail
|
||||
@@ -60,17 +101,17 @@ public func contain(_ items: Any?...) -> Predicate<NMBContainer> {
|
||||
public func contain(_ items: [Any?]) -> Predicate<NMBContainer> {
|
||||
return Predicate.simple("contain <\(arrayAsString(items))>") { actualExpression in
|
||||
guard let actual = try actualExpression.evaluate() else { return .fail }
|
||||
let matches = items.all { item in
|
||||
let matches = items.allSatisfy { item in
|
||||
return item.map { actual.contains($0) } ?? false
|
||||
}
|
||||
return PredicateStatus(bool: matches)
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func containMatcher(_ expected: [NSObject]) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func containMatcher(_ expected: [NSObject]) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let location = actualExpression.location
|
||||
let actualValue = try actualExpression.evaluate()
|
||||
if let value = actualValue as? NMBContainer {
|
||||
@@ -78,17 +119,25 @@ extension NMBObjCMatcher {
|
||||
|
||||
// A straightforward cast on the array causes this to crash, so we have to cast the individual items
|
||||
let expectedOptionals: [Any?] = expected.map({ $0 as Any? })
|
||||
return try contain(expectedOptionals).matches(expr, failureMessage: failureMessage)
|
||||
return try contain(expectedOptionals).satisfies(expr).toObjectiveC()
|
||||
} else if let value = actualValue as? NSString {
|
||||
let expr = Expression(expression: ({ value as String }), location: location)
|
||||
return try contain(expected as! [String]).matches(expr, failureMessage: failureMessage)
|
||||
} else if actualValue != nil {
|
||||
// swiftlint:disable:next line_length
|
||||
failureMessage.postfixMessage = "contain <\(arrayAsString(expected))> (only works for NSArrays, NSSets, NSHashTables, and NSStrings)"
|
||||
} else {
|
||||
failureMessage.postfixMessage = "contain <\(arrayAsString(expected))>"
|
||||
// swiftlint:disable:next force_cast
|
||||
return try contain(expected as! [String]).satisfies(expr).toObjectiveC()
|
||||
}
|
||||
return false
|
||||
|
||||
let message: ExpectationMessage
|
||||
if actualValue != nil {
|
||||
message = ExpectationMessage.expectedActualValueTo(
|
||||
// swiftlint:disable:next line_length
|
||||
"contain <\(arrayAsString(expected))> (only works for NSArrays, NSSets, NSHashTables, and NSStrings)"
|
||||
)
|
||||
} else {
|
||||
message = ExpectationMessage
|
||||
.expectedActualValueTo("contain <\(arrayAsString(expected))>")
|
||||
.appendedBeNilHint()
|
||||
}
|
||||
return NMBPredicateResult(status: .fail, message: message.toObjectiveC())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-13
@@ -24,20 +24,22 @@ public func containElementSatisfying<S: Sequence, T>(_ predicate: @escaping ((T)
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func containElementSatisfyingMatcher(_ predicate: @escaping ((NSObject) -> Bool)) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func containElementSatisfyingMatcher(_ predicate: @escaping ((NSObject) -> Bool)) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let value = try actualExpression.evaluate()
|
||||
guard let enumeration = value as? NSFastEnumeration else {
|
||||
// swiftlint:disable:next line_length
|
||||
failureMessage.postfixMessage = "containElementSatisfying must be provided an NSFastEnumeration object"
|
||||
failureMessage.actualValue = nil
|
||||
failureMessage.expected = ""
|
||||
failureMessage.to = ""
|
||||
return false
|
||||
let message = ExpectationMessage.fail(
|
||||
"containElementSatisfying must be provided an NSFastEnumeration object"
|
||||
)
|
||||
return NMBPredicateResult(status: .fail, message: message.toObjectiveC())
|
||||
}
|
||||
|
||||
let message = ExpectationMessage
|
||||
.expectedTo("find object in collection that satisfies predicate")
|
||||
.toObjectiveC()
|
||||
|
||||
var iterator = NSFastEnumerationIterator(enumeration)
|
||||
while let item = iterator.next() {
|
||||
guard let object = item as? NSObject else {
|
||||
@@ -45,13 +47,11 @@ public func containElementSatisfying<S: Sequence, T>(_ predicate: @escaping ((T)
|
||||
}
|
||||
|
||||
if predicate(object) {
|
||||
return true
|
||||
return NMBPredicateResult(status: .matches, message: message)
|
||||
}
|
||||
}
|
||||
|
||||
failureMessage.actualValue = nil
|
||||
failureMessage.postfixMessage = "find object in collection that satisfies predicate"
|
||||
return false
|
||||
return NMBPredicateResult(status: .doesNotMatch, message: message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/// A Nimble matcher that succeeds when the actual sequence contain the same elements in the same order to the exepected sequence.
|
||||
public func elementsEqual<S: Sequence>(_ expectedValue: S?) -> Predicate<S> where S.Element: Equatable {
|
||||
// A matcher abstraction for https://developer.apple.com/documentation/swift/sequence/2949668-elementsequal
|
||||
return Predicate.define("elementsEqual <\(stringify(expectedValue))>") { (actualExpression, msg) in
|
||||
let actualValue = try actualExpression.evaluate()
|
||||
switch (expectedValue, actualValue) {
|
||||
case (nil, _?):
|
||||
return PredicateResult(status: .fail, message: msg.appendedBeNilHint())
|
||||
case (nil, nil), (_, nil):
|
||||
return PredicateResult(status: .fail, message: msg)
|
||||
case (let expected?, let actual?):
|
||||
let matches = expected.elementsEqual(actual)
|
||||
return PredicateResult(bool: matches, message: msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
+7
-6
@@ -50,17 +50,18 @@ public func endWith(_ endingSubstring: String) -> Predicate<String> {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func endWithMatcher(_ expected: Any) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func endWithMatcher(_ expected: Any) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let actual = try actualExpression.evaluate()
|
||||
if (actual as? String) != nil {
|
||||
if actual is String {
|
||||
let expr = actualExpression.cast { $0 as? String }
|
||||
return try endWith(expected as! String).matches(expr, failureMessage: failureMessage)
|
||||
// swiftlint:disable:next force_cast
|
||||
return try endWith(expected as! String).satisfies(expr).toObjectiveC()
|
||||
} else {
|
||||
let expr = actualExpression.cast { $0 as? NMBOrderedCollection }
|
||||
return try endWith(expected).matches(expr, failureMessage: failureMessage)
|
||||
return try endWith(expected).satisfies(expr).toObjectiveC()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+46
-118
@@ -7,103 +7,30 @@ import Foundation
|
||||
public func equal<T: Equatable>(_ expectedValue: T?) -> Predicate<T> {
|
||||
return Predicate.define("equal <\(stringify(expectedValue))>") { actualExpression, msg in
|
||||
let actualValue = try actualExpression.evaluate()
|
||||
let matches = actualValue == expectedValue && expectedValue != nil
|
||||
if expectedValue == nil || actualValue == nil {
|
||||
if expectedValue == nil && actualValue != nil {
|
||||
return PredicateResult(
|
||||
status: .fail,
|
||||
message: msg.appendedBeNilHint()
|
||||
)
|
||||
}
|
||||
switch (expectedValue, actualValue) {
|
||||
case (nil, _?):
|
||||
return PredicateResult(status: .fail, message: msg.appendedBeNilHint())
|
||||
case (nil, nil), (_, nil):
|
||||
return PredicateResult(status: .fail, message: msg)
|
||||
case (let expected?, let actual?):
|
||||
let matches = expected == actual
|
||||
return PredicateResult(bool: matches, message: msg)
|
||||
}
|
||||
return PredicateResult(status: PredicateStatus(bool: matches), message: msg)
|
||||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual value is equal to the expected value.
|
||||
/// Values can support equal by supporting the Equatable protocol.
|
||||
///
|
||||
/// @see beCloseTo if you want to match imprecise types (eg - floats, doubles).
|
||||
public func equal<T, C: Equatable>(_ expectedValue: [T: C]?) -> Predicate<[T: C]> {
|
||||
return Predicate.define("equal <\(stringify(expectedValue))>") { actualExpression, msg in
|
||||
let actualValue = try actualExpression.evaluate()
|
||||
if expectedValue == nil || actualValue == nil {
|
||||
if expectedValue == nil && actualValue != nil {
|
||||
return PredicateResult(
|
||||
status: .fail,
|
||||
message: msg.appendedBeNilHint()
|
||||
)
|
||||
}
|
||||
return PredicateResult(status: .fail, message: msg)
|
||||
}
|
||||
return PredicateResult(
|
||||
status: PredicateStatus(bool: expectedValue! == actualValue!),
|
||||
message: msg
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual collection is equal to the expected collection.
|
||||
/// Items must implement the Equatable protocol.
|
||||
public func equal<T: Equatable>(_ expectedValue: [T]?) -> Predicate<[T]> {
|
||||
return Predicate.define("equal <\(stringify(expectedValue))>") { actualExpression, msg in
|
||||
let actualValue = try actualExpression.evaluate()
|
||||
if expectedValue == nil || actualValue == nil {
|
||||
if expectedValue == nil && actualValue != nil {
|
||||
return PredicateResult(
|
||||
status: .fail,
|
||||
message: msg.appendedBeNilHint()
|
||||
)
|
||||
}
|
||||
return PredicateResult(
|
||||
status: .fail,
|
||||
message: msg
|
||||
)
|
||||
}
|
||||
return PredicateResult(
|
||||
bool: expectedValue! == actualValue!,
|
||||
message: msg
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// A Nimble matcher allowing comparison of collection with optional type
|
||||
public func equal<T: Equatable>(_ expectedValue: [T?]) -> Predicate<[T?]> {
|
||||
return Predicate.define("equal <\(stringify(expectedValue))>") { actualExpression, msg in
|
||||
if let actualValue = try actualExpression.evaluate() {
|
||||
let doesNotMatch = PredicateResult(
|
||||
status: .doesNotMatch,
|
||||
message: msg
|
||||
)
|
||||
|
||||
if expectedValue.count != actualValue.count {
|
||||
return doesNotMatch
|
||||
}
|
||||
|
||||
for (index, item) in actualValue.enumerated() {
|
||||
let otherItem = expectedValue[index]
|
||||
if item == nil && otherItem == nil {
|
||||
continue
|
||||
} else if item == nil && otherItem != nil {
|
||||
return doesNotMatch
|
||||
} else if item != nil && otherItem == nil {
|
||||
return doesNotMatch
|
||||
} else if item! != otherItem! {
|
||||
return doesNotMatch
|
||||
}
|
||||
}
|
||||
|
||||
return PredicateResult(
|
||||
status: .matches,
|
||||
message: msg
|
||||
)
|
||||
} else {
|
||||
guard let actualValue = try actualExpression.evaluate() else {
|
||||
return PredicateResult(
|
||||
status: .fail,
|
||||
message: msg.appendedBeNilHint()
|
||||
)
|
||||
}
|
||||
|
||||
let matches = expectedValue == actualValue
|
||||
return PredicateResult(bool: matches, message: msg)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,44 +55,45 @@ private func equal<T>(_ expectedValue: Set<T>?, stringify: @escaping (Set<T>?) -
|
||||
var errorMessage: ExpectationMessage =
|
||||
.expectedActualValueTo("equal <\(stringify(expectedValue))>")
|
||||
|
||||
if let expectedValue = expectedValue {
|
||||
if let actualValue = try actualExpression.evaluate() {
|
||||
errorMessage = .expectedCustomValueTo(
|
||||
"equal <\(stringify(expectedValue))>",
|
||||
"<\(stringify(actualValue))>"
|
||||
)
|
||||
|
||||
if expectedValue == actualValue {
|
||||
return PredicateResult(
|
||||
status: .matches,
|
||||
message: errorMessage
|
||||
)
|
||||
}
|
||||
|
||||
let missing = expectedValue.subtracting(actualValue)
|
||||
if missing.count > 0 {
|
||||
errorMessage = errorMessage.appended(message: ", missing <\(stringify(missing))>")
|
||||
}
|
||||
|
||||
let extra = actualValue.subtracting(expectedValue)
|
||||
if extra.count > 0 {
|
||||
errorMessage = errorMessage.appended(message: ", extra <\(stringify(extra))>")
|
||||
}
|
||||
return PredicateResult(
|
||||
status: .doesNotMatch,
|
||||
message: errorMessage
|
||||
)
|
||||
}
|
||||
return PredicateResult(
|
||||
status: .fail,
|
||||
message: errorMessage.appendedBeNilHint()
|
||||
)
|
||||
} else {
|
||||
guard let expectedValue = expectedValue else {
|
||||
return PredicateResult(
|
||||
status: .fail,
|
||||
message: errorMessage.appendedBeNilHint()
|
||||
)
|
||||
}
|
||||
|
||||
guard let actualValue = try actualExpression.evaluate() else {
|
||||
return PredicateResult(
|
||||
status: .fail,
|
||||
message: errorMessage.appendedBeNilHint()
|
||||
)
|
||||
}
|
||||
|
||||
errorMessage = .expectedCustomValueTo(
|
||||
"equal <\(stringify(expectedValue))>",
|
||||
"<\(stringify(actualValue))>"
|
||||
)
|
||||
|
||||
if expectedValue == actualValue {
|
||||
return PredicateResult(
|
||||
status: .matches,
|
||||
message: errorMessage
|
||||
)
|
||||
}
|
||||
|
||||
let missing = expectedValue.subtracting(actualValue)
|
||||
if missing.count > 0 {
|
||||
errorMessage = errorMessage.appended(message: ", missing <\(stringify(missing))>")
|
||||
}
|
||||
|
||||
let extra = actualValue.subtracting(expectedValue)
|
||||
if extra.count > 0 {
|
||||
errorMessage = errorMessage.appended(message: ", extra <\(stringify(extra))>")
|
||||
}
|
||||
return PredicateResult(
|
||||
status: .doesNotMatch,
|
||||
message: errorMessage
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -209,7 +137,7 @@ public func !=<T, C: Equatable>(lhs: Expectation<[T: C]>, rhs: [T: C]?) {
|
||||
lhs.toNot(equal(rhs))
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func equalMatcher(_ expected: NSObject) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
|
||||
+18
-9
@@ -7,7 +7,7 @@ import Foundation
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual Collection's count equals
|
||||
/// the expected value
|
||||
public func haveCount<T: Collection>(_ expectedValue: T.IndexDistance) -> Predicate<T> {
|
||||
public func haveCount<T: Collection>(_ expectedValue: Int) -> Predicate<T> {
|
||||
return Predicate.define { actualExpression in
|
||||
if let actualValue = try actualExpression.evaluate() {
|
||||
let message = ExpectationMessage
|
||||
@@ -45,20 +45,29 @@ public func haveCount(_ expectedValue: Int) -> Predicate<NMBCollection> {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func haveCountMatcher(_ expected: NSNumber) -> NMBObjCMatcher {
|
||||
return NMBObjCMatcher(canMatchNil: false) { actualExpression, failureMessage in
|
||||
@objc public class func haveCountMatcher(_ expected: NSNumber) -> NMBMatcher {
|
||||
return NMBPredicate { actualExpression in
|
||||
let location = actualExpression.location
|
||||
let actualValue = try actualExpression.evaluate()
|
||||
if let value = actualValue as? NMBCollection {
|
||||
let expr = Expression(expression: ({ value as NMBCollection}), location: location)
|
||||
return try haveCount(expected.intValue).matches(expr, failureMessage: failureMessage)
|
||||
} else if let actualValue = actualValue {
|
||||
failureMessage.postfixMessage = "get type of NSArray, NSSet, NSDictionary, or NSHashTable"
|
||||
failureMessage.actualValue = "\(String(describing: type(of: actualValue)))"
|
||||
return try haveCount(expected.intValue).satisfies(expr).toObjectiveC()
|
||||
}
|
||||
return false
|
||||
|
||||
let message: ExpectationMessage
|
||||
if let actualValue = actualValue {
|
||||
message = ExpectationMessage.expectedCustomValueTo(
|
||||
"get type of NSArray, NSSet, NSDictionary, or NSHashTable",
|
||||
"\(String(describing: type(of: actualValue)))"
|
||||
)
|
||||
} else {
|
||||
message = ExpectationMessage
|
||||
.expectedActualValueTo("have a collection with count \(stringify(expected.intValue))")
|
||||
.appendedBeNilHint()
|
||||
}
|
||||
return NMBPredicateResult(status: .fail, message: message.toObjectiveC())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ public func match(_ expectedValue: String?) -> Predicate<String> {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func matchMatcher(_ expected: NSString) -> NMBMatcher {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
// `CGFloat` is in Foundation (swift-corelibs-foundation) on Linux.
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
import CoreGraphics
|
||||
#endif
|
||||
|
||||
@@ -28,7 +28,7 @@ extension Matcher {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
/// Objective-C interface to the Swift variant of Matcher.
|
||||
@objc public protocol NMBMatcher {
|
||||
func matches(_ actualBlock: @escaping () -> NSObject?, failureMessage: FailureMessage, location: SourceLocation) -> Bool
|
||||
@@ -41,7 +41,8 @@ public protocol NMBContainer {
|
||||
func contains(_ anObject: Any) -> Bool
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
// swiftlint:disable:next todo
|
||||
// FIXME: NSHashTable can not conform to NMBContainer since swift-DEVELOPMENT-SNAPSHOT-2016-04-25-a
|
||||
//extension NSHashTable : NMBContainer {} // Corelibs Foundation does not include this class yet
|
||||
#endif
|
||||
@@ -54,7 +55,7 @@ public protocol NMBCollection {
|
||||
var count: Int { get }
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NSHashTable: NMBCollection {} // Corelibs Foundation does not include these classes yet
|
||||
extension NSMapTable: NMBCollection {}
|
||||
#endif
|
||||
@@ -131,7 +132,7 @@ extension NSDate: TestOutputStringConvertible {
|
||||
/// beGreaterThan(), beGreaterThanOrEqualTo(), and equal() matchers.
|
||||
///
|
||||
/// Types that conform to Swift's Comparable protocol will work implicitly too
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
@objc public protocol NMBComparable {
|
||||
func NMB_compare(_ otherObject: NMBComparable!) -> ComparisonResult
|
||||
}
|
||||
@@ -144,11 +145,13 @@ public protocol NMBComparable {
|
||||
|
||||
extension NSNumber: NMBComparable {
|
||||
public func NMB_compare(_ otherObject: NMBComparable!) -> ComparisonResult {
|
||||
// swiftlint:disable:next force_cast
|
||||
return compare(otherObject as! NSNumber)
|
||||
}
|
||||
}
|
||||
extension NSString: NMBComparable {
|
||||
public func NMB_compare(_ otherObject: NMBComparable!) -> ComparisonResult {
|
||||
// swiftlint:disable:next force_cast
|
||||
return compare(otherObject as! String)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,9 @@
|
||||
import Foundation
|
||||
|
||||
// A workaround to SR-6419.
|
||||
extension NotificationCenter {
|
||||
#if !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
|
||||
#if swift(>=4.0)
|
||||
#if swift(>=4.0.2)
|
||||
#else
|
||||
func addObserver(forName name: Notification.Name?, object obj: Any?, queue: OperationQueue?, using block: @escaping (Notification) -> Void) -> NSObjectProtocol {
|
||||
return addObserver(forName: name, object: obj, queue: queue, usingBlock: block)
|
||||
}
|
||||
#endif
|
||||
#elseif swift(>=3.2)
|
||||
#if swift(>=3.2.2)
|
||||
#else
|
||||
// swiftlint:disable:next line_length
|
||||
func addObserver(forName name: Notification.Name?, object obj: Any?, queue: OperationQueue?, using block: @escaping (Notification) -> Void) -> NSObjectProtocol {
|
||||
return addObserver(forName: name, object: obj, queue: queue, usingBlock: block)
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
// swiftlint:disable:next line_length
|
||||
func addObserver(forName name: Notification.Name?, object obj: Any?, queue: OperationQueue?, using block: @escaping (Notification) -> Void) -> NSObjectProtocol {
|
||||
return addObserver(forName: name, object: obj, queue: queue, usingBlock: block)
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
internal class NotificationCollector {
|
||||
private(set) var observedNotifications: [Notification]
|
||||
private let notificationCenter: NotificationCenter
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
private var token: AnyObject?
|
||||
#else
|
||||
private var token: NSObjectProtocol?
|
||||
@@ -43,14 +16,14 @@ internal class NotificationCollector {
|
||||
|
||||
func startObserving() {
|
||||
// swiftlint:disable:next line_length
|
||||
self.token = self.notificationCenter.addObserver(forName: nil, object: nil, queue: nil, using: { [weak self] n in
|
||||
self.token = self.notificationCenter.addObserver(forName: nil, object: nil, queue: nil) { [weak self] notification in
|
||||
// linux-swift gets confused by .append(n)
|
||||
self?.observedNotifications.append(n)
|
||||
})
|
||||
self?.observedNotifications.append(notification)
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
if let token = self.token {
|
||||
self.notificationCenter.removeObserver(token)
|
||||
}
|
||||
|
||||
+3
-2
@@ -218,6 +218,7 @@ extension Predicate: Matcher {
|
||||
extension Predicate {
|
||||
// Someday, make this public? Needs documentation
|
||||
internal func after(f: @escaping (Expression<T>, PredicateResult) throws -> PredicateResult) -> Predicate<T> {
|
||||
// swiftlint:disable:previous identifier_name
|
||||
return Predicate { actual -> PredicateResult in
|
||||
let result = try self.satisfies(actual)
|
||||
return try f(actual, result)
|
||||
@@ -241,7 +242,7 @@ extension Predicate {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
public typealias PredicateBlock = (_ actualExpression: Expression<NSObject>) throws -> NMBPredicateResult
|
||||
|
||||
public class NMBPredicate: NSObject {
|
||||
@@ -311,7 +312,7 @@ final public class NMBPredicateStatus: NSObject {
|
||||
public static let doesNotMatch: NMBPredicateStatus = NMBPredicateStatus(status: 1)
|
||||
public static let fail: NMBPredicateStatus = NMBPredicateStatus(status: 2)
|
||||
|
||||
public override var hashValue: Int { return self.status.hashValue }
|
||||
public override var hash: Int { return self.status.hashValue }
|
||||
|
||||
public override func isEqual(_ object: Any?) -> Bool {
|
||||
guard let otherPredicate = object as? NMBPredicateStatus else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
// This matcher requires the Objective-C, and being built by Xcode rather than the Swift Package Manager
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
|
||||
/// A Nimble matcher that succeeds when the actual expression raises an
|
||||
/// exception with the specified name, reason, and/or userInfo.
|
||||
@@ -23,8 +23,12 @@ public func raiseException(
|
||||
exception = e
|
||||
}), finally: nil)
|
||||
|
||||
capture.tryBlock {
|
||||
_ = try! actualExpression.evaluate()
|
||||
do {
|
||||
try capture.tryBlockThrows {
|
||||
_ = try actualExpression.evaluate()
|
||||
}
|
||||
} catch {
|
||||
return PredicateResult(status: .fail, message: .fail("unexpected error thrown: <\(error)>"))
|
||||
}
|
||||
|
||||
let failureMessage = FailureMessage()
|
||||
@@ -118,10 +122,12 @@ internal func exceptionMatchesNonNilFieldsOrClosure(
|
||||
}
|
||||
|
||||
public class NMBObjCRaiseExceptionMatcher: NSObject, NMBMatcher {
|
||||
// swiftlint:disable identifier_name
|
||||
internal var _name: String?
|
||||
internal var _reason: String?
|
||||
internal var _userInfo: NSDictionary?
|
||||
internal var _block: ((NSException) -> Void)?
|
||||
// swiftlint:enable identifier_name
|
||||
|
||||
internal init(name: String?, reason: String?, userInfo: NSDictionary?, block: ((NSException) -> Void)?) {
|
||||
_name = name
|
||||
|
||||
@@ -39,7 +39,7 @@ public func && <T>(left: Predicate<T>, right: Predicate<T>) -> Predicate<T> {
|
||||
return satisfyAllOf(left, right)
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func satisfyAllOfMatcher(_ matchers: [NMBMatcher]) -> NMBPredicate {
|
||||
return NMBPredicate { actualExpression in
|
||||
@@ -60,8 +60,12 @@ extension NMBObjCMatcher {
|
||||
return predicate.satisfies({ try expression.evaluate() }, location: actualExpression.location).toSwift()
|
||||
} else {
|
||||
let failureMessage = FailureMessage()
|
||||
// swiftlint:disable:next line_length
|
||||
let success = matcher.matches({ try! expression.evaluate() }, failureMessage: failureMessage, location: actualExpression.location)
|
||||
let success = matcher.matches(
|
||||
// swiftlint:disable:next force_try
|
||||
{ try! expression.evaluate() },
|
||||
failureMessage: failureMessage,
|
||||
location: actualExpression.location
|
||||
)
|
||||
return PredicateResult(bool: success, message: failureMessage.toExpectationMessage())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public func || <T>(left: MatcherFunc<T>, right: MatcherFunc<T>) -> Predicate<T>
|
||||
return satisfyAnyOf(left, right)
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
extension NMBObjCMatcher {
|
||||
@objc public class func satisfyAnyOfMatcher(_ matchers: [NMBMatcher]) -> NMBPredicate {
|
||||
return NMBPredicate { actualExpression in
|
||||
@@ -68,8 +68,12 @@ extension NMBObjCMatcher {
|
||||
return predicate.satisfies({ try expression.evaluate() }, location: actualExpression.location).toSwift()
|
||||
} else {
|
||||
let failureMessage = FailureMessage()
|
||||
// swiftlint:disable:next line_length
|
||||
let success = matcher.matches({ try! expression.evaluate() }, failureMessage: failureMessage, location: actualExpression.location)
|
||||
let success = matcher.matches(
|
||||
// swiftlint:disable:next force_try
|
||||
{ try! expression.evaluate() },
|
||||
failureMessage: failureMessage,
|
||||
location: actualExpression.location
|
||||
)
|
||||
return PredicateResult(bool: success, message: failureMessage.toExpectationMessage())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import Foundation
|
||||
|
||||
public func throwAssertion() -> Predicate<Void> {
|
||||
return Predicate { actualExpression in
|
||||
#if arch(x86_64) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
#if arch(x86_64) && canImport(Darwin) && !SWIFT_PACKAGE
|
||||
let message = ExpectationMessage.expectedTo("throw an assertion")
|
||||
|
||||
var actualError: Error?
|
||||
@@ -44,9 +44,8 @@ public func throwAssertion() -> Predicate<Void> {
|
||||
" conditional statement")
|
||||
#else
|
||||
fatalError("The throwAssertion Nimble matcher can only run on x86_64 platforms with " +
|
||||
"Objective-C (e.g. Mac, iPhone 5s or later simulators). You can silence this error " +
|
||||
"by placing the test case inside an #if arch(x86_64) or (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) conditional statement")
|
||||
// swiftlint:disable:previous line_length
|
||||
"Objective-C (e.g. macOS, iPhone 5s or later simulators). You can silence this error " +
|
||||
"by placing the test case inside an #if arch(x86_64) or canImport(Darwin) conditional statement")
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
+13
-19
@@ -2,7 +2,7 @@ import CoreFoundation
|
||||
import Dispatch
|
||||
import Foundation
|
||||
|
||||
#if !(os(macOS) || os(iOS) || os(tvOS) || os(watchOS))
|
||||
#if canImport(CDispatch)
|
||||
import CDispatch
|
||||
#endif
|
||||
|
||||
@@ -32,7 +32,7 @@ internal class AssertionWaitLock: WaitLock {
|
||||
|
||||
func acquireWaitingLock(_ fnName: String, file: FileString, line: UInt) {
|
||||
let info = WaitingInfo(name: fnName, file: file, lineNumber: line)
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
let isMainThread = Thread.isMainThread
|
||||
#else
|
||||
let isMainThread = _CFIsMainThread()
|
||||
@@ -45,10 +45,15 @@ internal class AssertionWaitLock: WaitLock {
|
||||
nimblePrecondition(
|
||||
currentWaiter == nil,
|
||||
"InvalidNimbleAPIUsage",
|
||||
"Nested async expectations are not allowed to avoid creating flaky tests.\n\n" +
|
||||
"The call to\n\t\(info)\n" +
|
||||
"triggered this exception because\n\t\(currentWaiter!)\n" +
|
||||
"is currently managing the main run loop."
|
||||
"""
|
||||
Nested async expectations are not allowed to avoid creating flaky tests.
|
||||
|
||||
The call to
|
||||
\t\(info)
|
||||
triggered this exception because
|
||||
\t\(currentWaiter!)
|
||||
is currently managing the main run loop.
|
||||
"""
|
||||
)
|
||||
currentWaiter = info
|
||||
}
|
||||
@@ -180,25 +185,18 @@ internal class AwaitPromiseBuilder<T> {
|
||||
// checked.
|
||||
//
|
||||
// In addition, stopping the run loop is used to halt code executed on the main run loop.
|
||||
#if swift(>=4.0)
|
||||
trigger.timeoutSource.schedule(
|
||||
deadline: DispatchTime.now() + timeoutInterval,
|
||||
repeating: .never,
|
||||
leeway: timeoutLeeway
|
||||
)
|
||||
#else
|
||||
trigger.timeoutSource.scheduleOneshot(
|
||||
deadline: DispatchTime.now() + timeoutInterval,
|
||||
leeway: timeoutLeeway
|
||||
)
|
||||
#endif
|
||||
trigger.timeoutSource.setEventHandler {
|
||||
guard self.promise.asyncResult.isIncomplete() else { return }
|
||||
let timedOutSem = DispatchSemaphore(value: 0)
|
||||
let semTimedOutOrBlocked = DispatchSemaphore(value: 0)
|
||||
semTimedOutOrBlocked.signal()
|
||||
let runLoop = CFRunLoopGetMain()
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
let runLoopMode = CFRunLoopMode.defaultMode.rawValue
|
||||
#else
|
||||
let runLoopMode = kCFRunLoopDefaultMode
|
||||
@@ -263,7 +261,7 @@ internal class AwaitPromiseBuilder<T> {
|
||||
self.trigger.timeoutSource.resume()
|
||||
while self.promise.asyncResult.isIncomplete() {
|
||||
// Stopping the run loop does not work unless we run only 1 mode
|
||||
#if swift(>=4.2)
|
||||
#if (swift(>=4.2) && canImport(Darwin)) || compiler(>=5.0)
|
||||
_ = RunLoop.current.run(mode: .default, before: .distantFuture)
|
||||
#else
|
||||
_ = RunLoop.current.run(mode: .defaultRunLoopMode, before: .distantFuture)
|
||||
@@ -333,11 +331,7 @@ internal class Awaiter {
|
||||
let asyncSource = createTimerSource(asyncQueue)
|
||||
let trigger = AwaitTrigger(timeoutSource: timeoutSource, actionSource: asyncSource) {
|
||||
let interval = DispatchTimeInterval.nanoseconds(Int(pollInterval * TimeInterval(NSEC_PER_SEC)))
|
||||
#if swift(>=4.0)
|
||||
asyncSource.schedule(deadline: .now(), repeating: interval, leeway: pollLeeway)
|
||||
#else
|
||||
asyncSource.scheduleRepeating(deadline: .now(), interval: interval, leeway: pollLeeway)
|
||||
#endif
|
||||
asyncSource.setEventHandler {
|
||||
do {
|
||||
if let result = try closure() {
|
||||
|
||||
+4
-2
@@ -1,12 +1,14 @@
|
||||
import Foundation
|
||||
|
||||
#if !swift(>=4.2)
|
||||
extension Sequence {
|
||||
internal func all(_ fn: (Iterator.Element) -> Bool) -> Bool {
|
||||
internal func allSatisfy(_ predicate: (Element) throws -> Bool) rethrows -> Bool {
|
||||
for item in self {
|
||||
if !fn(item) {
|
||||
if try !predicate(item) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
+3
-2
@@ -2,7 +2,7 @@ import Foundation
|
||||
|
||||
internal func identityAsString(_ value: Any?) -> String {
|
||||
let anyObject: AnyObject?
|
||||
#if os(Linux)
|
||||
#if os(Linux) && !swift(>=4.1.50)
|
||||
anyObject = value as? AnyObject
|
||||
#else
|
||||
anyObject = value as AnyObject?
|
||||
@@ -122,6 +122,7 @@ extension String: TestOutputStringConvertible {
|
||||
extension Data: TestOutputStringConvertible {
|
||||
public var testDescription: String {
|
||||
#if os(Linux)
|
||||
// swiftlint:disable:next todo
|
||||
// FIXME: Swift on Linux triggers a segfault when calling NSData's hash() (last checked on 03-11-16)
|
||||
return "Data<length=\(count)>"
|
||||
#else
|
||||
@@ -158,7 +159,7 @@ public func stringify<T>(_ value: T?) -> String {
|
||||
return String(describing: value)
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
@objc public class NMBStringer: NSObject {
|
||||
@objc public class func stringify(_ obj: Any?) -> String {
|
||||
return Nimble.stringify(obj)
|
||||
|
||||
+993
-943
File diff suppressed because it is too large
Load Diff
Generated
+3
-1
@@ -4,6 +4,7 @@
|
||||
[](https://cocoapods.org/pods/Quick)
|
||||
[](https://github.com/Carthage/Carthage)
|
||||
[](https://cocoapods.org/pods/Quick)
|
||||
[](https://houndci.com)
|
||||
|
||||
Quick is a behavior-driven development framework for Swift and Objective-C.
|
||||
Inspired by [RSpec](https://github.com/rspec/rspec), [Specta](https://github.com/specta/specta), and [Ginkgo](https://github.com/onsi/ginkgo).
|
||||
@@ -44,7 +45,8 @@ Certain versions of Quick and Nimble only support certain versions of Swift. Dep
|
||||
|
||||
|Swift version |Quick version |Nimble version |
|
||||
|:--------------------|:---------------|:--------------|
|
||||
|Swift 3 |v1.0.0 or later |v5.0.0 or later|
|
||||
|Swift 4.2 |v1.3.2 or later |v7.3.2 or later|
|
||||
|Swift 3 / Swift 4 |v1.0.0 or later |v5.0.0 or later|
|
||||
|Swift 2.2 / Swift 2.3|v0.9.3 |v4.1.0 |
|
||||
|
||||
## Documentation
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
|
||||
open class Behavior<Context> {
|
||||
|
||||
open static var name: String { return String(describing: self) }
|
||||
public static var name: String { return String(describing: self) }
|
||||
/**
|
||||
override this method in your behavior to define a set of reusable examples.
|
||||
|
||||
|
||||
+3
-9
@@ -1,14 +1,8 @@
|
||||
import Foundation
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _CallsiteBase: NSObject {}
|
||||
#else
|
||||
public class _CallsiteBase: NSObject {}
|
||||
#endif
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _CallsiteBase: NSObject {}
|
||||
#else
|
||||
public class _CallsiteBase: NSObject {}
|
||||
#endif
|
||||
|
||||
@@ -72,7 +72,7 @@ final public class Configuration: NSObject {
|
||||
provided with metadata on the example that the closure is being run
|
||||
prior to.
|
||||
*/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
@objc(beforeEachWithMetadata:)
|
||||
public func beforeEach(_ closure: @escaping BeforeExampleWithMetadataClosure) {
|
||||
exampleHooks.appendBefore(closure)
|
||||
@@ -109,7 +109,7 @@ final public class Configuration: NSObject {
|
||||
is provided with metadata on the example that the closure is being
|
||||
run after.
|
||||
*/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
@objc(afterEachWithMetadata:)
|
||||
public func afterEach(_ closure: @escaping AfterExampleWithMetadataClosure) {
|
||||
exampleHooks.appendAfter(closure)
|
||||
|
||||
+3
-3
@@ -56,7 +56,7 @@ extension World {
|
||||
currentExampleGroup.hooks.appendBefore(closure)
|
||||
}
|
||||
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objc(beforeEachWithMetadata:)
|
||||
internal func beforeEach(closure: @escaping BeforeExampleWithMetadataClosure) {
|
||||
currentExampleGroup.hooks.appendBefore(closure)
|
||||
@@ -74,7 +74,7 @@ extension World {
|
||||
currentExampleGroup.hooks.appendAfter(closure)
|
||||
}
|
||||
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objc(afterEachWithMetadata:)
|
||||
internal func afterEach(closure: @escaping AfterExampleWithMetadataClosure) {
|
||||
currentExampleGroup.hooks.appendAfter(closure)
|
||||
@@ -172,7 +172,7 @@ extension World {
|
||||
self.itBehavesLike(behavior, context: context, flags: pendingFlags, file: file, line: line)
|
||||
}
|
||||
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objc(itWithDescription:flags:file:line:closure:)
|
||||
internal func objc_it(_ description: String, flags: FilterFlags, file: String, line: UInt, closure: @escaping () -> Void) {
|
||||
it(description, flags: flags, file: file, line: line, closure: closure)
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import Foundation
|
||||
|
||||
internal func raiseError(_ message: String) -> Never {
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
NSException(name: .internalInconsistencyException, reason: message, userInfo: nil).raise()
|
||||
#endif
|
||||
|
||||
|
||||
+3
-9
@@ -3,15 +3,9 @@ import Foundation
|
||||
private var numberOfExamplesRun = 0
|
||||
private var numberOfIncludedExamples = 0
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _ExampleBase: NSObject {}
|
||||
#else
|
||||
public class _ExampleBase: NSObject {}
|
||||
#endif
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _ExampleBase: NSObject {}
|
||||
#else
|
||||
public class _ExampleBase: NSObject {}
|
||||
#endif
|
||||
|
||||
+3
-9
@@ -1,14 +1,8 @@
|
||||
import Foundation
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _ExampleMetadataBase: NSObject {}
|
||||
#else
|
||||
public class _ExampleMetadataBase: NSObject {}
|
||||
#endif
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _ExampleMetadataBase: NSObject {}
|
||||
#else
|
||||
public class _ExampleMetadataBase: NSObject {}
|
||||
#endif
|
||||
|
||||
+3
-9
@@ -1,14 +1,8 @@
|
||||
import Foundation
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _FilterBase: NSObject {}
|
||||
#else
|
||||
public class _FilterBase: NSObject {}
|
||||
#endif
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
public class _FilterBase: NSObject {}
|
||||
#else
|
||||
public class _FilterBase: NSObject {}
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
#if canImport(Darwin)
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
#if canImport(Darwin)
|
||||
import Foundation
|
||||
|
||||
extension NSString {
|
||||
@@ -21,7 +21,7 @@ extension NSString {
|
||||
return invalidCharacters
|
||||
}()
|
||||
|
||||
/// This API is not meant to be used outside Quick, so will be unavaialbe in
|
||||
/// This API is not meant to be used outside Quick, so will be unavailable in
|
||||
/// a next major version.
|
||||
@objc(qck_c99ExtendedIdentifier)
|
||||
public var c99ExtendedIdentifier: String {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
#if canImport(Darwin)
|
||||
import Foundation
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
|
||||
#if canImport(Darwin)
|
||||
|
||||
import XCTest
|
||||
|
||||
|
||||
+5
-11
@@ -12,15 +12,9 @@ public typealias SharedExampleContext = () -> [String: Any]
|
||||
*/
|
||||
public typealias SharedExampleClosure = (@escaping SharedExampleContext) -> Void
|
||||
|
||||
// `#if swift(>=3.2) && (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE`
|
||||
// does not work as expected.
|
||||
#if swift(>=3.2)
|
||||
#if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
internal class _WorldBase: NSObject {}
|
||||
#else
|
||||
internal class _WorldBase: NSObject {}
|
||||
#endif
|
||||
#if canImport(Darwin) && !SWIFT_PACKAGE
|
||||
@objcMembers
|
||||
internal class _WorldBase: NSObject {}
|
||||
#else
|
||||
internal class _WorldBase: NSObject {}
|
||||
#endif
|
||||
@@ -57,7 +51,7 @@ final internal class World: _WorldBase {
|
||||
within this test suite. This is only true within the context of Quick
|
||||
functional tests.
|
||||
*/
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
// Convention of generating Objective-C selector has been changed on Swift 3
|
||||
@objc(isRunningAdditionalSuites)
|
||||
internal var isRunningAdditionalSuites = false
|
||||
@@ -158,7 +152,7 @@ final internal class World: _WorldBase {
|
||||
}
|
||||
}
|
||||
|
||||
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
|
||||
#if canImport(Darwin)
|
||||
@objc(examplesForSpecClass:)
|
||||
internal func objc_examples(_ specClass: AnyClass) -> [Example] {
|
||||
return examples(specClass)
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>7.3.1</string>
|
||||
<string>8.0.1</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.3.2</string>
|
||||
<string>2.0.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.3.3</string>
|
||||
<string>0.7.2</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@@ -307,7 +307,7 @@
|
||||
607FACCF1AFB9204008FA782 = {
|
||||
CreatedOnToolsVersion = 6.3.1;
|
||||
DevelopmentTeam = HPNZWPB9JK;
|
||||
LastSwiftMigration = 1010;
|
||||
LastSwiftMigration = 1020;
|
||||
SystemCapabilities = {
|
||||
com.apple.BackgroundModes = {
|
||||
enabled = 1;
|
||||
@@ -317,14 +317,14 @@
|
||||
607FACE41AFB9204008FA782 = {
|
||||
CreatedOnToolsVersion = 6.3.1;
|
||||
DevelopmentTeam = HPNZWPB9JK;
|
||||
LastSwiftMigration = 1010;
|
||||
LastSwiftMigration = 1020;
|
||||
TestTargetID = 607FACCF1AFB9204008FA782;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 607FACCB1AFB9204008FA782 /* Build configuration list for PBXProject "SwiftAudio" */;
|
||||
compatibilityVersion = "Xcode 3.2";
|
||||
developmentRegion = English;
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
@@ -630,7 +630,7 @@
|
||||
MODULE_NAME = ExampleApp;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
name = Debug;
|
||||
@@ -647,7 +647,7 @@
|
||||
MODULE_NAME = ExampleApp;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
};
|
||||
name = Release;
|
||||
@@ -669,7 +669,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftAudio_Example.app/SwiftAudio_Example";
|
||||
};
|
||||
name = Debug;
|
||||
@@ -687,7 +687,7 @@
|
||||
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
|
||||
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.$(PRODUCT_NAME:rfc1034identifier)";
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 4.2;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SwiftAudio_Example.app/SwiftAudio_Example";
|
||||
};
|
||||
name = Release;
|
||||
|
||||
@@ -23,13 +23,13 @@ SwiftAudio is available through [CocoaPods](http://cocoapods.org). To install
|
||||
it, simply add the following line to your Podfile:
|
||||
|
||||
```ruby
|
||||
pod 'SwiftAudio', '~> 0.7.2'
|
||||
pod 'SwiftAudio', '~> 0.8.0'
|
||||
```
|
||||
|
||||
### Carthage
|
||||
SwiftAudio supports [Carthage](https://github.com/Carthage/Carthage). Add this to your Cartfile:
|
||||
```ruby
|
||||
github "jorgenhenrichsen/SwiftAudio" ~> 0.7.2
|
||||
github "jorgenhenrichsen/SwiftAudio" ~> 0.8.0
|
||||
```
|
||||
Then follow the rest of Carthage instructions on [adding a framework](https://github.com/Carthage/Carthage#adding-frameworks-to-an-application).
|
||||
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'SwiftAudio'
|
||||
s.version = '0.7.2'
|
||||
s.version = '0.8.0'
|
||||
s.summary = 'Easy audio streaming for iOS'
|
||||
|
||||
# This description is used to generate tags and improve search results.
|
||||
|
||||
@@ -142,6 +142,8 @@ class AVPlayerWrapper: AVPlayerWrapperProtocol {
|
||||
pause()
|
||||
case .paused:
|
||||
play()
|
||||
@unknown default:
|
||||
fatalError("Unknown AVPlayer.timeControlStatus")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,6 +218,8 @@ extension AVPlayerWrapper: AVPlayerObserverDelegate {
|
||||
self._state = .loading
|
||||
case .playing:
|
||||
self._state = .playing
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -240,6 +244,8 @@ extension AVPlayerWrapper: AVPlayerObserverDelegate {
|
||||
|
||||
case .unknown:
|
||||
break
|
||||
@unknown default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,23 +10,6 @@ import MediaPlayer
|
||||
|
||||
public typealias AudioPlayerState = AVPlayerWrapperState
|
||||
|
||||
@available(*, deprecated, message: "Delegates will be removed in future versions of SwiftAudio. Use event handlers instead.")
|
||||
public protocol AudioPlayerDelegate: class {
|
||||
|
||||
func audioPlayer(playerDidChangeState state: AudioPlayerState)
|
||||
|
||||
func audioPlayer(itemPlaybackEndedWithReason reason: PlaybackEndedReason)
|
||||
|
||||
func audioPlayer(secondsElapsed seconds: Double)
|
||||
|
||||
func audioPlayer(failedWithError error: Error?)
|
||||
|
||||
func audioPlayer(seekTo seconds: Int, didFinish: Bool)
|
||||
|
||||
func audioPlayer(didUpdateDuration duration: Double)
|
||||
|
||||
}
|
||||
|
||||
public class AudioPlayer: AVPlayerWrapperDelegate {
|
||||
|
||||
private var _wrapper: AVPlayerWrapperProtocol
|
||||
@@ -38,9 +21,7 @@ public class AudioPlayer: AVPlayerWrapperDelegate {
|
||||
|
||||
public let nowPlayingInfoController: NowPlayingInfoControllerProtocol
|
||||
public let remoteCommandController: RemoteCommandController
|
||||
|
||||
public let event = EventHolder()
|
||||
public weak var delegate: AudioPlayerDelegate?
|
||||
|
||||
var _currentItem: AudioItem?
|
||||
public var currentItem: AudioItem? {
|
||||
@@ -226,7 +207,6 @@ public class AudioPlayer: AVPlayerWrapperDelegate {
|
||||
self.reset()
|
||||
self.wrapper.stop()
|
||||
self.event.playbackEnd.emit(data: .playerStopped)
|
||||
self.delegate?.audioPlayer(itemPlaybackEndedWithReason: .playerStopped)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -336,17 +316,14 @@ public class AudioPlayer: AVPlayerWrapperDelegate {
|
||||
default: break
|
||||
}
|
||||
self.event.stateChange.emit(data: state)
|
||||
self.delegate?.audioPlayer(playerDidChangeState: state)
|
||||
}
|
||||
|
||||
func AVWrapper(secondsElapsed seconds: Double) {
|
||||
self.event.secondElapse.emit(data: seconds)
|
||||
self.delegate?.audioPlayer(secondsElapsed: seconds)
|
||||
}
|
||||
|
||||
func AVWrapper(failedWithError error: Error?) {
|
||||
self.event.fail.emit(data: error)
|
||||
self.delegate?.audioPlayer(failedWithError: error)
|
||||
}
|
||||
|
||||
func AVWrapper(seekTo seconds: Int, didFinish: Bool) {
|
||||
@@ -354,17 +331,14 @@ public class AudioPlayer: AVPlayerWrapperDelegate {
|
||||
updateNowPlayingCurrentTime(currentTime)
|
||||
}
|
||||
self.event.seek.emit(data: (seconds, didFinish))
|
||||
self.delegate?.audioPlayer(seekTo: seconds, didFinish: didFinish)
|
||||
}
|
||||
|
||||
func AVWrapper(didUpdateDuration duration: Double) {
|
||||
self.event.updateDuration.emit(data: duration)
|
||||
self.delegate?.audioPlayer(didUpdateDuration: duration)
|
||||
}
|
||||
|
||||
func AVWrapperItemDidPlayToEndTime() {
|
||||
self.event.playbackEnd.emit(data: .playedUntilEnd)
|
||||
self.delegate?.audioPlayer(itemPlaybackEndedWithReason: .playedUntilEnd)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -120,7 +120,6 @@ public class QueuedAudioPlayer: AudioPlayer {
|
||||
*/
|
||||
public func next() throws {
|
||||
event.playbackEnd.emit(data: .skippedToNext)
|
||||
delegate?.audioPlayer(itemPlaybackEndedWithReason: .skippedToNext)
|
||||
let nextItem = try queueManager.next()
|
||||
try self.load(item: nextItem, playWhenReady: true)
|
||||
}
|
||||
@@ -130,7 +129,6 @@ public class QueuedAudioPlayer: AudioPlayer {
|
||||
*/
|
||||
public func previous() throws {
|
||||
event.playbackEnd.emit(data: .skippedToPrevious)
|
||||
delegate?.audioPlayer(itemPlaybackEndedWithReason: .skippedToPrevious)
|
||||
let previousItem = try queueManager.previous()
|
||||
try self.load(item: previousItem, playWhenReady: true)
|
||||
}
|
||||
@@ -154,7 +152,6 @@ public class QueuedAudioPlayer: AudioPlayer {
|
||||
*/
|
||||
public func jumpToItem(atIndex index: Int, playWhenReady: Bool = true) throws {
|
||||
event.playbackEnd.emit(data: .jumpedToIndex)
|
||||
delegate?.audioPlayer(itemPlaybackEndedWithReason: .jumpedToIndex)
|
||||
let item = try queueManager.jump(to: index)
|
||||
try self.load(item: item, playWhenReady: playWhenReady)
|
||||
}
|
||||
|
||||
@@ -13,12 +13,14 @@ public enum TimeEventFrequency {
|
||||
case everySecond
|
||||
case everyHalfSecond
|
||||
case everyQuarterSecond
|
||||
case custom(time: CMTime)
|
||||
|
||||
func getTime() -> CMTime {
|
||||
switch self {
|
||||
case .everySecond: return CMTime(value: 1, timescale: 1)
|
||||
case .everyHalfSecond: return CMTime(value: 1, timescale: 2)
|
||||
case .everyQuarterSecond: return CMTime(value: 1, timescale: 4)
|
||||
case .custom(let time): return time
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user