Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,16 @@ jobs:
- name: Run ${{ matrix.config }} tests
run: CONFIG=${{ matrix.config }} make test

# TODO: test on linux
ubuntu_tests:
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-20.04]

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v2
- name: Build
run: swift build
- name: Run tests
run: swift test
13 changes: 13 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@ test:
-scheme swift-clocks \
-destination platform="$(PLATFORM)"

test-linux:
docker run \
--rm \
-v "$(PWD):$(PWD)" \
-w "$(PWD)" \
swift:5.3 \
bash -c 'make test-swift'

test-swift:
swift test \
--enable-test-discovery \
--parallel

format:
swift format \
--ignore-unparsable-files \
Expand Down
2 changes: 1 addition & 1 deletion Sources/Clocks/SwiftUI.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if canImport(RoomPlan) || (!canImport(Darwin) && swift(>=5.7))
#if canImport(SwiftUI) && (canImport(RoomPlan) || (!canImport(Darwin) && swift(>=5.7)))
import SwiftUI

@available(macOS 13, iOS 16, watchOS 9, tvOS 16, *)
Expand Down
18 changes: 13 additions & 5 deletions Sources/Clocks/TestClock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@
public private(set) var now: Instant

private let lock = NSRecursiveLock()
private var suspensions:
[(id: UUID, deadline: Instant, continuation: AsyncStream<Never>.Continuation)] = []
private var suspensions: [(
id: UUID,
deadline: Instant,
continuation: AsyncThrowingStream<Never, Error>.Continuation
)] = []

public init(now: Instant = .init()) {
self.now = .init()
Expand All @@ -99,18 +102,18 @@
try Task.checkCancellation()
let id = UUID()
do {
let stream: AsyncStream<Never>? = self.lock.sync {
let stream: AsyncThrowingStream<Never, Error>? = self.lock.sync {
guard deadline >= self.now
else {
return nil
}
return AsyncStream<Never> { continuation in
return AsyncThrowingStream<Never, Error> { continuation in
self.suspensions.append((id: id, deadline: deadline, continuation: continuation))
}
}
guard let stream = stream
else { return }
for await _ in stream {}
for try await _ in stream {}
try Task.checkCancellation()
} catch is CancellationError {
self.lock.sync { self.suspensions.removeAll(where: { $0.id == id }) }
Expand Down Expand Up @@ -184,9 +187,11 @@
}()

if `return` {
await Task.megaYield()
return
}
}
await Task.megaYield()
}

/// Runs the clock until it has no scheduled sleeps left.
Expand Down Expand Up @@ -225,6 +230,9 @@
try await withThrowingTaskGroup(of: Void.self) { group in
group.addTask {
try await Task.sleep(until: .now.advanced(by: duration), clock: .continuous)
for suspension in self.suspensions {
suspension.continuation.finish(throwing: CancellationError())
}
throw CancellationError()
}
group.addTask {
Expand Down
1 change: 0 additions & 1 deletion Tests/ClocksTests/AsyncAlgorithmsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Clocks
import XCTest

@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
@MainActor
final class AsyncAlgorithmsTests: XCTestCase, @unchecked Sendable {
let clock = TestClock()

Expand Down
3 changes: 1 addition & 2 deletions Tests/ClocksTests/ImmediateClockTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Clocks
import XCTest

@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
@MainActor
final class ImmediateClockTests: XCTestCase {
func testTimer() async throws {
let clock = ImmediateClock()
Expand Down Expand Up @@ -30,7 +29,7 @@ final class ImmediateClockTests: XCTestCase {
func testCooperativeCancellation() async throws {
let clock = ImmediateClock()
let task = Task {
try? await Task.sleep(nanoseconds: NSEC_PER_SEC / 3)
try? await Task.sleep(nanoseconds: 1_000_000_000 / 3)
try await clock.sleep(for: .seconds(1))
}
task.cancel()
Expand Down
1 change: 0 additions & 1 deletion Tests/ClocksTests/ShimTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import Clocks
import XCTest

@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
@MainActor
final class ShimTests: XCTestCase {
func testClockSleepFor() async {
let testClock = TestClock()
Expand Down
4 changes: 2 additions & 2 deletions Tests/ClocksTests/TestClocksTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import Clocks
import XCTest

@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
@MainActor
final class TestClockTests: XCTestCase, @unchecked Sendable {
let clock = TestClock()

Expand Down Expand Up @@ -63,7 +62,8 @@ final class TestClockTests: XCTestCase, @unchecked Sendable {
XCTAssertEqual(checkIsFinished, true)
}

#if DEBUG
#if DEBUG && canImport(Darwin)
@MainActor
func testRunWithTimeout() async throws {
XCTExpectFailure {
$0.compactDescription == """
Expand Down
9 changes: 6 additions & 3 deletions Tests/ClocksTests/UnimplementedClockTests.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#if DEBUG
#if DEBUG && canImport(Darwin)
import AsyncAlgorithms
import Clocks
import XCTest

@available(iOS 16, macOS 13, tvOS 16, watchOS 9, *)
@MainActor
final class UnimplementedClockTests: XCTestCase {
@MainActor
func testUnimplementedClock() async throws {
XCTExpectFailure {
[
Expand All @@ -19,6 +19,7 @@
try await clock.sleep(for: .seconds(1))
}

@MainActor
func testUnimplementedClock_WithName() async throws {
XCTExpectFailure {
[
Expand All @@ -32,6 +33,7 @@
try await clock.sleep(for: .seconds(1))
}

@MainActor
func testNow() async throws {
XCTExpectFailure {
[
Expand All @@ -46,6 +48,7 @@
XCTAssertEqual(clock.now.offset, .seconds(5))
}

@MainActor
func testCooperativeCancellation() async throws {
XCTExpectFailure {
[
Expand All @@ -57,7 +60,7 @@

let clock = UnimplementedClock()
let task = Task {
try? await Task.sleep(nanoseconds: NSEC_PER_SEC / 3)
try? await Task.sleep(nanoseconds: 1_000_000_000 / 3)
try await clock.sleep(for: .seconds(1))
}
task.cancel()
Expand Down