From 969bd1a563eacac79f6ef719b8fc1f0bb5a31bfd Mon Sep 17 00:00:00 2001 From: Nikita Konopelko Date: Thu, 30 Mar 2023 16:01:38 +0300 Subject: [PATCH] 1.2.0 --- Package.resolved | 26 +- Package.swift | 26 +- ...+NQueue.swift => DispatchTime+Queue.swift} | 7 + Source/Queue.swift | 14 +- Tests/DelayedQueueSpec.swift | 223 ------------------ Tests/DelayedQueueTests.swift | 153 ++++++++++++ Tests/DispatchTime+QueueTests.swift | 43 ++++ Tests/DispatchTimeInterval+NQueueSpec.swift | 24 -- Tests/QueueSpec.swift | 80 ------- Tests/QueueTests.swift | 36 +++ 10 files changed, 263 insertions(+), 369 deletions(-) rename Source/{DispatchTimeInterval+NQueue.swift => DispatchTime+Queue.swift} (54%) delete mode 100644 Tests/DelayedQueueSpec.swift create mode 100644 Tests/DelayedQueueTests.swift create mode 100644 Tests/DispatchTime+QueueTests.swift delete mode 100644 Tests/DispatchTimeInterval+NQueueSpec.swift delete mode 100644 Tests/QueueSpec.swift create mode 100644 Tests/QueueTests.swift diff --git a/Package.resolved b/Package.resolved index 6300fc1..f23e66b 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/mattgallagher/CwlCatchException.git", "state" : { - "revision" : "f809deb30dc5c9d9b78c872e553261a61177721a", - "version" : "2.0.0" + "revision" : "35f9e770f54ce62dd8526470f14c6e137cef3eea", + "version" : "2.1.1" } }, { @@ -18,31 +18,13 @@ "version" : "2.1.0" } }, - { - "identity" : "nimble", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Quick/Nimble.git", - "state" : { - "revision" : "b7f6c49acdb247e3158198c5448b38c3cc595533", - "version" : "11.2.1" - } - }, { "identity" : "nspry", "kind" : "remoteSourceControl", "location" : "https://github.com/NikSativa/NSpry.git", "state" : { - "revision" : "ac81bc9c46e2e79905b8b066d9f19964584f4dce", - "version" : "1.3.3" - } - }, - { - "identity" : "quick", - "kind" : "remoteSourceControl", - "location" : "https://github.com/Quick/Quick.git", - "state" : { - "revision" : "16910e406be96e08923918315388c3e989deac9e", - "version" : "6.1.0" + "revision" : "eb1afc57f1c6a425f19a00dd7d06f3f681821e40", + "version" : "2.0.0" } } ], diff --git a/Package.swift b/Package.swift index e33a450..5e9072c 100644 --- a/Package.swift +++ b/Package.swift @@ -6,32 +6,32 @@ let package = Package( name: "NQueue", platforms: [ .iOS(.v13), - .macOS(.v10_15) + .macOS(.v11) ], products: [ .library(name: "NQueue", targets: ["NQueue"]), .library(name: "NQueueTestHelpers", targets: ["NQueueTestHelpers"]) ], dependencies: [ - .package(url: "https://github.com/NikSativa/NSpry.git", .upToNextMajor(from: "1.2.9")), - .package(url: "https://github.com/Quick/Quick.git", .upToNextMajor(from: "6.1.0")), - .package(url: "https://github.com/Quick/Nimble.git", .upToNextMajor(from: "11.2.1")) + .package(url: "https://github.com/NikSativa/NSpry.git", .upToNextMajor(from: "2.0.0")) ], targets: [ .target(name: "NQueue", - dependencies: [], + dependencies: [ + ], path: "Source"), .target(name: "NQueueTestHelpers", - dependencies: ["NQueue", - "NSpry"], + dependencies: [ + "NQueue", + "NSpry" + ], path: "TestHelpers"), .testTarget(name: "NQueueTests", - dependencies: ["NQueue", - "NQueueTestHelpers", - "NSpry", - .product(name: "NSpry_Nimble", package: "NSpry"), - "Nimble", - "Quick"], + dependencies: [ + "NQueue", + "NQueueTestHelpers", + "NSpry" + ], path: "Tests") ] ) diff --git a/Source/DispatchTimeInterval+NQueue.swift b/Source/DispatchTime+Queue.swift similarity index 54% rename from Source/DispatchTimeInterval+NQueue.swift rename to Source/DispatchTime+Queue.swift index bad233c..f31795e 100644 --- a/Source/DispatchTimeInterval+NQueue.swift +++ b/Source/DispatchTime+Queue.swift @@ -1,3 +1,4 @@ +import Dispatch import Foundation public extension DispatchTimeInterval { @@ -6,3 +7,9 @@ public extension DispatchTimeInterval { return .nanoseconds(nano) } } + +public extension DispatchTime { + static func delayInSeconds(_ seconds: Double) -> Self { + return .now() + .seconds(seconds) + } +} diff --git a/Source/Queue.swift b/Source/Queue.swift index 2bd504a..58bc226 100644 --- a/Source/Queue.swift +++ b/Source/Queue.swift @@ -24,39 +24,39 @@ public struct Queue: Equatable { case userInteractive } - public static var main: Queueable { + public static var main: Self { return Queue(kind: .main, sdk: .main) } - public static var background: Queueable { + public static var background: Self { return Queue(kind: .background, sdk: .global(qos: .background)) } - public static var utility: Queueable { + public static var utility: Self { return Queue(kind: .utility, sdk: .global(qos: .utility)) } - public static var `default`: Queueable { + public static var `default`: Self { return Queue(kind: .default, sdk: .global(qos: .default)) } - public static var userInitiated: Queueable { + public static var userInitiated: Self { return Queue(kind: .userInitiated, sdk: .global(qos: .userInitiated)) } - public static var userInteractive: Queueable { + public static var userInteractive: Self { return Queue(kind: .userInteractive, sdk: .global(qos: .userInteractive)) } public static func custom(label: String, qos: DispatchQoS = .default, - attributes: Attributes = .concurrent) -> Queueable { + attributes: Attributes = .concurrent) -> Self { return Queue(kind: .custom(label: label, qos: qos, attributes: attributes), diff --git a/Tests/DelayedQueueSpec.swift b/Tests/DelayedQueueSpec.swift deleted file mode 100644 index 9060ffc..0000000 --- a/Tests/DelayedQueueSpec.swift +++ /dev/null @@ -1,223 +0,0 @@ -import Foundation -import Nimble -import NSpry -import NSpry_Nimble -import Quick -@testable import NQueue -@testable import NQueueTestHelpers - -final class DelayedQueueSpec: QuickSpec { - override func spec() { - describe("DelayedQueue") { - var subject: DelayedQueue! - - describe("fake queue") { - describe("absent") { - beforeEach { - subject = .absent - } - - it("should not be nil") { - expect(subject).toNot(beNil()) - } - - context("when calling async") { - it("should call task immediately") { - var didCall = false - subject.fire { - didCall = true - } - expect(didCall).to(beTrue()) - } - } - - context("when calling sync") { - it("should call task immediately") { - var didCall = false - subject.fire { - didCall = true - } - expect(didCall).to(beTrue()) - } - } - } - - describe("sync") { - var queue: FakeQueueable! - - beforeEach { - queue = .init() - subject = .sync(queue) - } - - it("should not be nil") { - expect(subject).toNot(beNil()) - } - - context("when calling async") { - var didCall: Bool! - - beforeEach { - didCall = false - queue.shouldFireSyncClosures = true - queue.stub(.sync).andReturn() - subject.fire { - didCall = true - } - } - - it("should schedule task") { - expect(queue).to(haveReceived(.sync, countSpecifier: .exactly(1))) - } - - it("should call task immediately") { - expect(didCall).to(beTrue()) - } - } - } - - describe("async") { - var queue: FakeQueueable! - - beforeEach { - queue = .init() - subject = .async(queue) - } - - it("should not be nil") { - expect(subject).toNot(beNil()) - } - - context("when calling async") { - var didCall: Bool! - - beforeEach { - didCall = false - queue.stub(.async).andReturn() - subject.fire { - didCall = true - } - } - - it("should schedule task") { - expect(didCall).to(beFalse()) - expect(queue).to(haveReceived(.async, with: Argument.anything, countSpecifier: .exactly(1))) - } - - context("when the task is executed") { - beforeEach { - queue.asyncWorkItem?() - } - - it("should call task immediately") { - expect(didCall).to(beTrue()) - } - } - } - } - - describe("async after") { - var queue: FakeQueueable! - var deadline: DispatchTime! - - beforeEach { - deadline = .now() + .seconds(1) - queue = .init() - subject = .asyncAfter(deadline: deadline, queue: queue) - } - - it("should not be nil") { - expect(subject).toNot(beNil()) - } - - context("when calling async") { - var didCall: Bool! - - beforeEach { - didCall = false - queue.stub(.asyncAfter).andReturn() - subject.fire { - didCall = true - } - } - - it("should schedule task") { - expect(didCall).to(beFalse()) - expect(queue).to(haveReceived(.asyncAfter, with: deadline, Argument.anything, countSpecifier: .exactly(1))) - } - - context("when the task is executed") { - beforeEach { - queue.asyncWorkItem?() - } - - it("should call task immediately") { - expect(didCall).to(beTrue()) - } - } - } - } - } - - describe("real queue") { - describe("absent") { - beforeEach { - subject = .absent - } - - it("should not be nil") { - expect(subject).toNot(beNil()) - } - - it("should execute task immediately") { - var didCall = false - subject.fire { - sleep(1) - didCall = true - } - expect(didCall).to(beTrue()) - } - } - - describe("sync") { - beforeEach { - subject = .sync(Queue.default) - } - - it("should not be nil") { - expect(subject).toNot(beNil()) - } - - it("should execute task immediately") { - var didCall = false - subject.fire { - sleep(1) - didCall = true - } - expect(didCall).to(beTrue()) - } - } - - describe("async") { - beforeEach { - subject = .async(Queue.default) - } - - it("should not be nil") { - expect(subject).toNot(beNil()) - } - - it("should schedule task") { - var didCall = false - subject.fire { - sleep(1) - didCall = true - } - expect(didCall).to(beFalse()) - expect(didCall).toEventually(beTrue(), timeout: .seconds(2)) - } - } - } - } - } -} diff --git a/Tests/DelayedQueueTests.swift b/Tests/DelayedQueueTests.swift new file mode 100644 index 0000000..a42560a --- /dev/null +++ b/Tests/DelayedQueueTests.swift @@ -0,0 +1,153 @@ +import Dispatch +import Foundation +import NSpry +import XCTest + +@testable import NQueue +@testable import NQueueTestHelpers + +final class DelayedQueueTests: XCTestCase { + // MARK: - fake + + func test_fake_queue_absent() { + let subject: DelayedQueue = .absent + var didCall = false + subject.fire { + didCall = true + } + XCTAssertTrue(didCall) + } + + func test_fake_queue_sync() { + let queue: FakeQueueable = .init() + queue.shouldFireSyncClosures = true + queue.stub(.sync).andReturn() + + let subject: DelayedQueue = .sync(queue) + var didCall = false + subject.fire { + didCall = true + } + XCTAssertTrue(didCall) + XCTAssertHaveReceived(queue, .sync) + } + + func test_fake_queue_async() { + let queue: FakeQueueable = .init() + queue.shouldFireSyncClosures = true + queue.stub(.async).andReturn() + + let subject: DelayedQueue = .async(queue) + var didCall = false + subject.fire { + didCall = true + } + XCTAssertFalse(didCall) + XCTAssertHaveReceived(queue, .async) + + queue.asyncWorkItem?() + XCTAssertTrue(didCall) + } + + func test_fake_queue_async_after() { + let dispatchTime = DispatchTime.delayInSeconds(1) + + let queue: FakeQueueable = .init() + queue.shouldFireSyncClosures = true + queue.stub(.asyncAfter).andReturn() + + let subject: DelayedQueue = .asyncAfter(deadline: dispatchTime, queue: queue) + var didCall = false + subject.fire { + didCall = true + } + XCTAssertFalse(didCall) + XCTAssertHaveReceived(queue, .asyncAfter, with: dispatchTime, Argument.anything) + + queue.asyncWorkItem?() + XCTAssertTrue(didCall) + } + + func test_fake_queue_async_after_with_flags() { + let dispatchTime = DispatchTime.delayInSeconds(1) + + let queue: FakeQueueable = .init() + queue.shouldFireSyncClosures = true + queue.stub(.asyncAfterWithFlags).andReturn() + + let subject: DelayedQueue = .asyncAfterWithFlags(deadline: dispatchTime, flags: .barrier, queue: queue) + var didCall = false + subject.fire { + didCall = true + } + XCTAssertFalse(didCall) + XCTAssertHaveReceived(queue, .asyncAfterWithFlags, with: dispatchTime, Queue.Flags.barrier, Argument.anything) + + queue.asyncWorkItem?() + XCTAssertTrue(didCall) + } + + // MARK: - real + + func test_real_queue_absent() { + let subject: DelayedQueue = .absent + var didCall = false + subject.fire { + didCall = true + } + XCTAssertTrue(didCall) + } + + func test_real_queue_sync() { + let queue = Queue.main + let subject: DelayedQueue = .sync(queue) + var didCall = false + subject.fire { + didCall = true + } + XCTAssertTrue(didCall) + } + + func test_real_queue_async() { + let queue = Queue.main + let subject: DelayedQueue = .async(queue) + let didCall = expectation(description: "should be called") + subject.fire { + didCall.fulfill() + } + wait(for: [didCall], timeout: 0.1) + } + + func test_real_queue_async_after() { + let queue = Queue.main + let dispatchTime = DispatchTime.delayInSeconds(0.1) + let subject: DelayedQueue = .asyncAfter(deadline: dispatchTime, queue: queue) + let didCall = expectation(description: "should be called") + subject.fire { + didCall.fulfill() + } + wait(for: [didCall], timeout: 0.2) + } + + func test_real_queue_async_after_with_flags_barrier() { + let queue = Queue.main + let dispatchTime = DispatchTime.delayInSeconds(0.1) + let subject: DelayedQueue = .asyncAfterWithFlags(deadline: dispatchTime, flags: .barrier, queue: queue) + let didCall = expectation(description: "should be called") + subject.fire { + didCall.fulfill() + } + wait(for: [didCall], timeout: 0.2) + } + + func test_real_queue_async_after_with_flags() { + let queue = Queue.main + let dispatchTime = DispatchTime.delayInSeconds(0.1) + let subject: DelayedQueue = .asyncAfterWithFlags(deadline: dispatchTime, flags: .absent, queue: queue) + let didCall = expectation(description: "should be called") + subject.fire { + didCall.fulfill() + } + wait(for: [didCall], timeout: 0.2) + } +} diff --git a/Tests/DispatchTime+QueueTests.swift b/Tests/DispatchTime+QueueTests.swift new file mode 100644 index 0000000..66a6f16 --- /dev/null +++ b/Tests/DispatchTime+QueueTests.swift @@ -0,0 +1,43 @@ +import Dispatch +import Foundation +import NSpry +import XCTest + +@testable import NQueue +@testable import NQueueTestHelpers + +final class DispatchTime_QueueTests: XCTestCase { + func test_seconds() { + XCTAssertEqual(DispatchTimeInterval.seconds(2.2), .nanoseconds(22 * Int(1E+8))) + XCTAssertEqual(DispatchTimeInterval.seconds(0.2), .nanoseconds(2 * Int(1E+8))) + XCTAssertEqual(DispatchTimeInterval.seconds(2), .nanoseconds(2 * Int(1E+9))) + XCTAssertEqual(DispatchTimeInterval.seconds(0.222222222), .nanoseconds(222222222)) + XCTAssertEqual(DispatchTimeInterval.seconds(0.2222222223), .nanoseconds(222222222)) + XCTAssertEqual(DispatchTimeInterval.seconds(0.2222222225), .nanoseconds(222222222)) + XCTAssertEqual(DispatchTimeInterval.seconds(0.2222222228), .nanoseconds(222222222)) + XCTAssertEqual(DispatchTimeInterval.seconds(0.222222222822), .nanoseconds(222222222)) + XCTAssertEqual(DispatchTimeInterval.seconds(0.222222222822), .nanoseconds(222222222)) + } + + func test_delayInSeconds() { + XCTAssertEqual(DispatchTime.delayInSeconds(2.2), .now() + .nanoseconds(22 * Int(1E+8))) + XCTAssertEqual(DispatchTime.delayInSeconds(0.2), .now() + .nanoseconds(2 * Int(1E+8))) + XCTAssertEqual(DispatchTime.delayInSeconds(2), .now() + .nanoseconds(2 * Int(1E+9))) + XCTAssertEqual(DispatchTime.delayInSeconds(0.222222222), .now() + .nanoseconds(222222222)) + XCTAssertEqual(DispatchTime.delayInSeconds(0.2222222223), .now() + .nanoseconds(222222222)) + XCTAssertEqual(DispatchTime.delayInSeconds(0.2222222225), .now() + .nanoseconds(222222222)) + XCTAssertEqual(DispatchTime.delayInSeconds(0.2222222228), .now() + .nanoseconds(222222222)) + XCTAssertEqual(DispatchTime.delayInSeconds(0.222222222822), .now() + .nanoseconds(222222222)) + XCTAssertEqual(DispatchTime.delayInSeconds(0.222222222822), .now() + .nanoseconds(222222222)) + } +} + +private func XCTAssertEqual(_ expression1: @autoclosure () -> DispatchTime, + _ expression2: @autoclosure () -> DispatchTime, + _ message: @autoclosure () -> String = "", + file: StaticString = #filePath, + line: UInt = #line) { + let lhs = Float(expression1().uptimeNanoseconds) / 1000 + let rhs = Float(expression2().uptimeNanoseconds) / 1000 + XCTAssertEqual(lhs, rhs, accuracy: 0.1, message(), file: file, line: line) +} diff --git a/Tests/DispatchTimeInterval+NQueueSpec.swift b/Tests/DispatchTimeInterval+NQueueSpec.swift deleted file mode 100644 index 35ac6ed..0000000 --- a/Tests/DispatchTimeInterval+NQueueSpec.swift +++ /dev/null @@ -1,24 +0,0 @@ -import Foundation -import Nimble -import NQueue -import NQueueTestHelpers -import NSpry -import Quick - -final class DispatchTimeInterval_NQueueSpec: QuickSpec { - override func spec() { - describe("DispatchTimeInterval+NQueue") { - it("should convert correctly") { - expect(DispatchTimeInterval.seconds(2.2)) == .nanoseconds(22 * Int(1E+8)) - expect(DispatchTimeInterval.seconds(0.2)) == .nanoseconds(2 * Int(1E+8)) - expect(DispatchTimeInterval.seconds(2)) == .nanoseconds(2 * Int(1E+9)) - expect(DispatchTimeInterval.seconds(0.222222222)) == .nanoseconds(222222222) - expect(DispatchTimeInterval.seconds(0.2222222223)) == .nanoseconds(222222222) - expect(DispatchTimeInterval.seconds(0.2222222225)) == .nanoseconds(222222222) - expect(DispatchTimeInterval.seconds(0.2222222228)) == .nanoseconds(222222222) - expect(DispatchTimeInterval.seconds(0.222222222822)) == .nanoseconds(222222222) - expect(DispatchTimeInterval.seconds(0.222222222822)) == .nanoseconds(222222222) - } - } - } -} diff --git a/Tests/QueueSpec.swift b/Tests/QueueSpec.swift deleted file mode 100644 index af02a00..0000000 --- a/Tests/QueueSpec.swift +++ /dev/null @@ -1,80 +0,0 @@ -import Foundation -import Nimble -import NQueue -import NQueueTestHelpers -import NSpry -import Quick - -final class QueueSpec: QuickSpec { - override func spec() { - describe("Queue") { - var subject: Queueable! - - beforeEach { - subject = Queue.main - } - - it("should not be nil") { - expect(subject).toNot(beNil()) - } - - describe("async") { - var didCall = false - - beforeEach { - subject.async { - didCall = true - } - } - - afterEach { - didCall = false - } - - it("should not call task") { - expect(didCall).toNot(beTrue()) - } - - it("should call task") { - expect(didCall).toEventually(beTrue()) - } - } - - describe("asyncAfter") { - var didCall = false - - beforeEach { - subject.asyncAfter(deadline: .now() + .seconds(1)) { - didCall = true - } - } - - afterEach { - didCall = false - } - - it("should not call task") { - expect(didCall).toNot(beTrue()) - } - - it("should call task") { - expect(didCall).toEventually(beTrue(), timeout: .seconds(2)) - } - } - - describe("sync") { - var didCall = false - - beforeEach { - subject.sync { - didCall = true - } - } - - it("should call task") { - expect(didCall).to(beTrue()) - } - } - } - } -} diff --git a/Tests/QueueTests.swift b/Tests/QueueTests.swift new file mode 100644 index 0000000..fc9eb06 --- /dev/null +++ b/Tests/QueueTests.swift @@ -0,0 +1,36 @@ +import Dispatch +import Foundation +import NSpry +import XCTest + +@testable import NQueue +@testable import NQueueTestHelpers + +final class QueueTests: XCTestCase { + func test_async() { + let callExpectation = expectation(description: "should be called") + let subject = Queue.main + subject.async { + callExpectation.fulfill() + } + wait(for: [callExpectation], timeout: 0.1) + } + + func test_asyncAfter() { + let callExpectation = expectation(description: "should be called") + let subject = Queue.main + subject.asyncAfter(deadline: .delayInSeconds(0.1)) { + callExpectation.fulfill() + } + wait(for: [callExpectation], timeout: 0.2) + } + + func test_sync() { + var didCall = false + let subject = Queue.main + subject.sync { + didCall = true + } + XCTAssertTrue(didCall) + } +}