diff --git a/Example/Podfile.lock b/Example/Podfile.lock index 3e4516a..1ef200f 100644 --- a/Example/Podfile.lock +++ b/Example/Podfile.lock @@ -7,9 +7,9 @@ PODS: - URITemplate (~> 2.0) - Mockingjay/XCTest (2.0.1): - Mockingjay/Core - - Nimble (7.3.1) - - Quick (1.3.2) - - SwiftLint (0.29.0) + - Nimble (7.3.4) + - Quick (1.3.4) + - SwiftLint (0.31.0) - URITemplate (2.0.3) DEPENDENCIES: @@ -34,9 +34,9 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Cara: 7bd0fc988ccc33954be01e8b2a61ffd213f4dd81 Mockingjay: 11a621880d2887f1775bdcf824341eb68f218450 - Nimble: 04f732da099ea4d153122aec8c2a88fd0c7219ae - Quick: 2623cb30d7a7f41ca62f684f679586558f483d46 - SwiftLint: d4e7443d93e2bbe868dc302e6c7ac30b469d6a14 + Nimble: 051e3d8912d40138fa5591c78594f95fb172af37 + Quick: f4f7f063c524394c73ed93ac70983c609805d481 + SwiftLint: 7a0227733d786395817373b2d0ca799fd0093ff3 URITemplate: ace0c4c46dcf8afe6e89b4060621852886b15c3b PODFILE CHECKSUM: ad86ce978961012c0d4241a21e19bc6aa2f5ce17 diff --git a/Example/Pods/Manifest.lock b/Example/Pods/Manifest.lock index 3e4516a..1ef200f 100644 --- a/Example/Pods/Manifest.lock +++ b/Example/Pods/Manifest.lock @@ -7,9 +7,9 @@ PODS: - URITemplate (~> 2.0) - Mockingjay/XCTest (2.0.1): - Mockingjay/Core - - Nimble (7.3.1) - - Quick (1.3.2) - - SwiftLint (0.29.0) + - Nimble (7.3.4) + - Quick (1.3.4) + - SwiftLint (0.31.0) - URITemplate (2.0.3) DEPENDENCIES: @@ -34,9 +34,9 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Cara: 7bd0fc988ccc33954be01e8b2a61ffd213f4dd81 Mockingjay: 11a621880d2887f1775bdcf824341eb68f218450 - Nimble: 04f732da099ea4d153122aec8c2a88fd0c7219ae - Quick: 2623cb30d7a7f41ca62f684f679586558f483d46 - SwiftLint: d4e7443d93e2bbe868dc302e6c7ac30b469d6a14 + Nimble: 051e3d8912d40138fa5591c78594f95fb172af37 + Quick: f4f7f063c524394c73ed93ac70983c609805d481 + SwiftLint: 7a0227733d786395817373b2d0ca799fd0093ff3 URITemplate: ace0c4c46dcf8afe6e89b4060621852886b15c3b PODFILE CHECKSUM: ad86ce978961012c0d4241a21e19bc6aa2f5ce17 diff --git a/Example/Pods/Nimble/README.md b/Example/Pods/Nimble/README.md index 19c562f..647028c 100644 --- a/Example/Pods/Nimble/README.md +++ b/Example/Pods/Nimble/README.md @@ -1277,7 +1277,7 @@ public func equal(expectedValue: T?) -> Predicate { // Predicate { actual in ... } // // But shown with types here for clarity. - return Predicate { (actual: Expression) throws -> PredicateResult in + return Predicate { (actualExpression: Expression) throws -> PredicateResult in let msg = ExpectationMessage.expectedActualValueTo("equal <\(expectedValue)>") if let actualValue = try actualExpression.evaluate() { return PredicateResult( diff --git a/Example/Pods/Nimble/Sources/Nimble/Adapters/NimbleEnvironment.swift b/Example/Pods/Nimble/Sources/Nimble/Adapters/NimbleEnvironment.swift index e1b5432..818e478 100644 --- a/Example/Pods/Nimble/Sources/Nimble/Adapters/NimbleEnvironment.swift +++ b/Example/Pods/Nimble/Sources/Nimble/Adapters/NimbleEnvironment.swift @@ -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"] @@ -29,7 +29,7 @@ internal class NimbleEnvironment { var suppressTVOSAssertionWarning: Bool = false var awaiter: Awaiter - init() { + override init() { let timeoutQueue: DispatchQueue if #available(OSX 10.10, *) { timeoutQueue = DispatchQueue.global(qos: .userInitiated) @@ -40,6 +40,9 @@ internal class NimbleEnvironment { awaiter = Awaiter( waitLock: AssertionWaitLock(), asyncQueue: .main, - timeoutQueue: timeoutQueue) + timeoutQueue: timeoutQueue + ) + + super.init() } } diff --git a/Example/Pods/Nimble/Sources/Nimble/DSL+Wait.swift b/Example/Pods/Nimble/Sources/Nimble/DSL+Wait.swift index e874136..ee281ed 100644 --- a/Example/Pods/Nimble/Sources/Nimble/DSL+Wait.swift +++ b/Example/Pods/Nimble/Sources/Nimble/DSL+Wait.swift @@ -89,11 +89,17 @@ internal class NMBWait: NSObject { #if (os(macOS) || os(iOS) || os(tvOS) || os(watchOS)) && !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 diff --git a/Example/Pods/Nimble/Sources/Nimble/Matchers/Async.swift b/Example/Pods/Nimble/Sources/Nimble/Matchers/Async.swift index 63e863e..c70b65e 100644 --- a/Example/Pods/Nimble/Sources/Nimble/Matchers/Async.swift +++ b/Example/Pods/Nimble/Sources/Nimble/Matchers/Async.swift @@ -23,14 +23,18 @@ private func async(style: ExpectationStyle, predicate: Predicate, 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)(...).") } diff --git a/Example/Pods/Nimble/Sources/Nimble/Matchers/BeIdenticalTo.swift b/Example/Pods/Nimble/Sources/Nimble/Matchers/BeIdenticalTo.swift index 94758c2..dfbcb9e 100644 --- a/Example/Pods/Nimble/Sources/Nimble/Matchers/BeIdenticalTo.swift +++ b/Example/Pods/Nimble/Sources/Nimble/Matchers/BeIdenticalTo.swift @@ -5,14 +5,38 @@ import Foundation public func beIdenticalTo(_ expected: Any?) -> Predicate { return Predicate.define { actualExpression in #if os(Linux) - let actual = try actualExpression.evaluate() as? AnyObject + #if swift(>=4.0) + #if !swift(>=4.1.50) + let actual = try actualExpression.evaluate() as? AnyObject + #else + let actual = try actualExpression.evaluate() as AnyObject? + #endif + #else + #if !swift(>=3.4) + let actual = try actualExpression.evaluate() as? AnyObject + #else + let actual = try actualExpression.evaluate() as AnyObject? + #endif + #endif #else let actual = try actualExpression.evaluate() as AnyObject? #endif let bool: Bool #if os(Linux) - bool = actual === (expected as? AnyObject) && actual !== nil + #if swift(>=4.0) + #if !swift(>=4.1.50) + bool = actual === (expected as? AnyObject) && actual !== nil + #else + bool = actual === (expected as AnyObject?) && actual !== nil + #endif + #else + #if !swift(>=3.4) + bool = actual === (expected as? AnyObject) && actual !== nil + #else + bool = actual === (expected as AnyObject?) && actual !== nil + #endif + #endif #else bool = actual === (expected as AnyObject?) && actual !== nil #endif diff --git a/Example/Pods/Nimble/Sources/Nimble/Matchers/BeginWith.swift b/Example/Pods/Nimble/Sources/Nimble/Matchers/BeginWith.swift index a013f9f..cb3efe3 100644 --- a/Example/Pods/Nimble/Sources/Nimble/Matchers/BeginWith.swift +++ b/Example/Pods/Nimble/Sources/Nimble/Matchers/BeginWith.swift @@ -35,8 +35,7 @@ public func beginWith(_ startingElement: Any) -> Predicate public func beginWith(_ startingSubstring: String) -> Predicate { 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 } diff --git a/Example/Pods/Nimble/Sources/Nimble/Matchers/Equal.swift b/Example/Pods/Nimble/Sources/Nimble/Matchers/Equal.swift index 5f26f49..b8ac2c9 100644 --- a/Example/Pods/Nimble/Sources/Nimble/Matchers/Equal.swift +++ b/Example/Pods/Nimble/Sources/Nimble/Matchers/Equal.swift @@ -7,17 +7,15 @@ import Foundation public func equal(_ expectedValue: T?) -> Predicate { 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) } } @@ -28,19 +26,15 @@ public func equal(_ expectedValue: T?) -> Predicate { public func equal(_ 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() - ) - } + 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: expectedValue! == actualValue!), - message: msg - ) } } @@ -49,61 +43,54 @@ public func equal(_ expectedValue: [T: C]?) -> Predicate<[T: C] public func equal(_ 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 - ) + 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( - bool: expectedValue! == actualValue!, - message: msg - ) } } /// A Nimble matcher allowing comparison of collection with optional type public func equal(_ 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 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 + ) } } @@ -128,44 +115,45 @@ private func equal(_ expectedValue: Set?, stringify: @escaping (Set?) - 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 - ) - } + guard let expectedValue = expectedValue else { return PredicateResult( status: .fail, message: errorMessage.appendedBeNilHint() ) - } else { + } + + 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 + ) } } diff --git a/Example/Pods/Nimble/Sources/Nimble/Matchers/Predicate.swift b/Example/Pods/Nimble/Sources/Nimble/Matchers/Predicate.swift index 19fd322..4810b9b 100644 --- a/Example/Pods/Nimble/Sources/Nimble/Matchers/Predicate.swift +++ b/Example/Pods/Nimble/Sources/Nimble/Matchers/Predicate.swift @@ -311,7 +311,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 { diff --git a/Example/Pods/Nimble/Sources/Nimble/Utils/Await.swift b/Example/Pods/Nimble/Sources/Nimble/Utils/Await.swift index cb672ad..ad7a6eb 100644 --- a/Example/Pods/Nimble/Sources/Nimble/Utils/Await.swift +++ b/Example/Pods/Nimble/Sources/Nimble/Utils/Await.swift @@ -263,7 +263,7 @@ internal class AwaitPromiseBuilder { 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) && (os(macOS) || os(iOS) || os(tvOS)) _ = RunLoop.current.run(mode: .default, before: .distantFuture) #else _ = RunLoop.current.run(mode: .defaultRunLoopMode, before: .distantFuture) diff --git a/Example/Pods/Nimble/Sources/Nimble/Utils/Stringers.swift b/Example/Pods/Nimble/Sources/Nimble/Utils/Stringers.swift index 7c4d273..ce21eea 100644 --- a/Example/Pods/Nimble/Sources/Nimble/Utils/Stringers.swift +++ b/Example/Pods/Nimble/Sources/Nimble/Utils/Stringers.swift @@ -3,7 +3,19 @@ import Foundation internal func identityAsString(_ value: Any?) -> String { let anyObject: AnyObject? #if os(Linux) - anyObject = value as? AnyObject + #if swift(>=4.0) + #if !swift(>=4.1.50) + anyObject = value as? AnyObject + #else + anyObject = value as AnyObject? + #endif + #else + #if !swift(>=3.4) + anyObject = value as? AnyObject + #else + anyObject = value as AnyObject? + #endif + #endif #else anyObject = value as AnyObject? #endif diff --git a/Example/Pods/Quick/Sources/Quick/Behavior.swift b/Example/Pods/Quick/Sources/Quick/Behavior.swift index 1d98702..7dfefac 100644 --- a/Example/Pods/Quick/Sources/Quick/Behavior.swift +++ b/Example/Pods/Quick/Sources/Quick/Behavior.swift @@ -4,7 +4,7 @@ open class Behavior { - 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. diff --git a/Example/Pods/SwiftLint/swiftlint b/Example/Pods/SwiftLint/swiftlint index e24da34..4d2eb4f 100755 Binary files a/Example/Pods/SwiftLint/swiftlint and b/Example/Pods/SwiftLint/swiftlint differ diff --git a/Example/Pods/Target Support Files/Nimble/Nimble-Info.plist b/Example/Pods/Target Support Files/Nimble/Nimble-Info.plist index 6971fd4..5e150f8 100644 --- a/Example/Pods/Target Support Files/Nimble/Nimble-Info.plist +++ b/Example/Pods/Target Support Files/Nimble/Nimble-Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 7.3.1 + 7.3.4 CFBundleSignature ???? CFBundleVersion diff --git a/Example/Pods/Target Support Files/Quick/Quick-Info.plist b/Example/Pods/Target Support Files/Quick/Quick-Info.plist index 6c1d64f..ff96127 100644 --- a/Example/Pods/Target Support Files/Quick/Quick-Info.plist +++ b/Example/Pods/Target Support Files/Quick/Quick-Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.3.2 + 1.3.4 CFBundleSignature ???? CFBundleVersion diff --git a/Example/Tests/Specs/Service/NetworkServiceSpec.swift b/Example/Tests/Specs/Service/NetworkServiceSpec.swift index 1c65fe1..f7f4062 100644 --- a/Example/Tests/Specs/Service/NetworkServiceSpec.swift +++ b/Example/Tests/Specs/Service/NetworkServiceSpec.swift @@ -9,6 +9,7 @@ import Quick import Nimble import Mockingjay +import Foundation @testable import Cara @@ -42,6 +43,7 @@ class NetworkServiceSpec: QuickSpec { with: MockedSerializer(), isInterceptable: true, retryCount: 0, + executionQueue: nil, retry: {}, completion: { _ in }) expect(loggerOne.didTriggerStartRequest).toNot(beNil()) @@ -57,6 +59,7 @@ class NetworkServiceSpec: QuickSpec { with: MockedSerializer(), isInterceptable: true, retryCount: 0, + executionQueue: nil, retry: {}, completion: { _ in done() @@ -84,6 +87,7 @@ class NetworkServiceSpec: QuickSpec { with: MockedSerializer(), isInterceptable: true, retryCount: 0, + executionQueue: nil, retry: {}, completion: { _ in done() @@ -103,7 +107,12 @@ class NetworkServiceSpec: QuickSpec { service.interceptor = interceptor waitUntil { done in - service.execute(one, with: MockedSerializer(), isInterceptable: true, retryCount: 0, retry: { + service.execute(one, + with: MockedSerializer(), + isInterceptable: true, + retryCount: 0, + executionQueue: nil, + retry: { done() }, completion: { _ in }) } @@ -125,6 +134,7 @@ class NetworkServiceSpec: QuickSpec { with: MockedSerializer(), isInterceptable: false, retryCount: 0, + executionQueue: nil, retry: {}, completion: { _ in done() @@ -139,35 +149,35 @@ class NetworkServiceSpec: QuickSpec { let request = URLRequest(url: URL(string: "https://relative.com/request")!) waitUntil { done in - DispatchQueue.main.async { - service.execute(request, - with: MockedSerializer(), - isInterceptable: true, - retryCount: 0, - retry: {}, completion: { _ in - expect(Thread.isMainThread) == true - done() - }) - } + service.execute(request, + with: MockedSerializer(), + isInterceptable: true, + retryCount: 0, + executionQueue: DispatchQueue.main, + retry: {}, completion: { _ in + expect(Thread.isMainThread) == true + expect(Thread.current.qualityOfService) == .default + done() + }) } } - it("should not return on the global queue") { + it("should return on the global queue") { self.stub(http(.get, uri: "https://relative.com/request"), http(200)) let request = URLRequest(url: URL(string: "https://relative.com/request")!) waitUntil { done in - DispatchQueue.global(qos: .utility).async { - service.execute(request, - with: MockedSerializer(), - isInterceptable: true, - retryCount: 0, - retry: {}, - completion: { _ in - expect(Thread.isMainThread) == false - done() - }) - } + service.execute(request, + with: MockedSerializer(), + isInterceptable: true, + retryCount: 0, + executionQueue: DispatchQueue.global(qos: .utility), + retry: {}, + completion: { _ in + expect(Thread.isMainThread) == false + expect(Thread.current.qualityOfService) == .utility + done() + }) } } } diff --git a/Example/Tests/Specs/Service/ResponseErrorSpec.swift b/Example/Tests/Specs/Service/ResponseErrorSpec.swift index f5489a5..f259ea9 100644 --- a/Example/Tests/Specs/Service/ResponseErrorSpec.swift +++ b/Example/Tests/Specs/Service/ResponseErrorSpec.swift @@ -12,7 +12,7 @@ import Nimble @testable import Cara class ResponseErrorSpec: QuickSpec { - // swiftlint:disable lines function_body_length + // swiftlint:disable function_body_length override func spec() { describe("ResponseError") { context("handling") { diff --git a/Example/Tests/Specs/Service/ServiceSpec.swift b/Example/Tests/Specs/Service/ServiceSpec.swift index 8a8a6d6..82b6ec9 100644 --- a/Example/Tests/Specs/Service/ServiceSpec.swift +++ b/Example/Tests/Specs/Service/ServiceSpec.swift @@ -158,6 +158,36 @@ class ServiceSpec: QuickSpec { } } + context("threading") { + it("should return on the main queue") { + self.stub(http(.get, uri: "https://relative.com/request"), http(200)) + let request = MockedRequest(url: URL(string: "request")) + + waitUntil { done in + DispatchQueue.main.async { + service.execute(request, with: MockedSerializer()) { _ in + expect(Thread.isMainThread) == true + done() + } + } + } + } + + it("should not return on the main queue") { + self.stub(http(.get, uri: "https://relative.com/request"), http(200)) + let request = MockedRequest(url: URL(string: "request")) + + waitUntil { done in + DispatchQueue.global(qos: .utility).async { + service.execute(request, with: MockedSerializer()) { _ in + expect(Thread.isMainThread) == false + done() + } + } + } + } + } + context("serializer") { it("should fail to execute a request because of an invalid url") { self.stub(http(.get, uri: "https://relative.com/"), http(200)) diff --git a/Sources/Service/NetworkService.swift b/Sources/Service/NetworkService.swift index fe1e269..b1488ff 100644 --- a/Sources/Service/NetworkService.swift +++ b/Sources/Service/NetworkService.swift @@ -29,10 +29,9 @@ class NetworkService: NSObject { with serializer: S, isInterceptable: Bool, retryCount: UInt, + executionQueue: DispatchQueue?, retry: @escaping () -> Void, completion: @escaping (_ response: S.Response) -> Void) -> URLSessionDataTask { - // Get the originating queue. - let executionQueue: DispatchQueue? = OperationQueue.current?.underlyingQueue // Trigger the loggers before the request is done. configuration.start(urlRequest: urlRequest) // Prepare the session. diff --git a/Sources/Service/Service.swift b/Sources/Service/Service.swift index 5d0f74e..a7cc619 100644 --- a/Sources/Service/Service.swift +++ b/Sources/Service/Service.swift @@ -5,6 +5,8 @@ // Created by Jelle Vandebeeck on 01/12/2018. // +import Foundation + /// This it the main executor of requests. open class Service { @@ -45,13 +47,16 @@ open class Service { public func execute(_ request: Request, with serializer: S, completion: @escaping (_ response: S.Response) -> Void) -> URLSessionDataTask? { - return execute(request, with: serializer, retryCount: 0, completion: completion) + // Get the originating queue. + let executionQueue: DispatchQueue? = OperationQueue.current?.underlyingQueue + return execute(request, with: serializer, retryCount: 0, executionQueue: executionQueue, completion: completion) } /// This private function is used just to keep track of the retry count of the current request. private func execute(_ request: Request, with serializer: S, retryCount: UInt, + executionQueue: DispatchQueue?, completion: @escaping (_ response: S.Response) -> Void) -> URLSessionDataTask? { do { // Create the request. @@ -60,8 +65,13 @@ open class Service { with: serializer, isInterceptable: request.isInterceptable, retryCount: retryCount, + executionQueue: executionQueue, retry: { [weak self] in - self?.execute(request, with: serializer, retryCount: retryCount + 1, completion: completion) + self?.execute(request, + with: serializer, + retryCount: retryCount + 1, + executionQueue: executionQueue, + completion: completion) }, completion: completion) } catch { let response = serializer.serialize(data: nil, error: error, response: nil)