Giter VIP home page Giter VIP logo

swift-clocks's Introduction

Swift 5.7 CI @pointfreeco

This repo contains the full source code for the Point-Free website, a video series exploring advanced programming topics in Swift. The codebase is split into 3 pieces:

  • PointFree: This is the core application, and is responsible for routing requests, loading data and rendering HTML and CSS.
  • Styleguide: This library contains functions and data types for creating a consistent style across the entire website.
  • Server: This is the actual executable server. It uses NIO to handle the low-level server responsibilities, and hands everything else over to the PointFree package.

Point-Free Homepage

Getting Started

Interested in a video tour of the code base?

video poster image

The repo contains an extensive test suite and some playgrounds to explore. To get things running:

  • Open up a terminal window and grab the code:

    git clone https://github.com/pointfreeco/pointfreeco.git
    cd pointfreeco
  • Make sure cmark is installed. You can install it with Homebrew:

    brew install cmark # or your preferred installation method
  • Make sure Postgres is installed and running. It's our database of choice. You can install it with Homebrew:

    brew install postgres # or your preferred installation method
    brew services start postgresql # or your preferred launch method
    make db

    (If you use Postgres.app, EnterpriseDB, or another installation method, please follow some additional instructions in the CPostgreSQL README.)

With the project open in Xcode, you can:

  • Run the server locally
    • Select the Server target
    • Run: Command+R
    • Visit http://localhost:8080
  • Explore our playgrounds
    • Select the PointFree target
    • Build: Command+B
    • Open a playground!

Some fun things to explore

There're a lot of fun things to explore in this repo. For example:

  • We develop web pages in playgrounds for a continuous feedback loop. This is made possible by the fact that the entire server stack is composed of pure functions with side-effects pushed to the boundaries of the application. It allows us to load up any request in isolation, including POST requests, all without ever worrying about doing a side-effect. Server side Swift in a playground

  • We use snapshot testing to capture full data structures in order to verify their correctness. Not only do we do this in the traditional way of taking screenshots of web pages at various break points (e.g. on iPhone and desktop), but we can also snapshot any entire request-to-response lifecycle (e.g. the POST to a signup page does the correct redirect).

▿ Step
  ResponseEnded

▿ Request
  POST http://localhost:8080/launch-signup

  [email protected]

▿ Response
  Status 302 FOUND
  Location: /?success=true

Xcode Color Theme

Like the color theme we use in our episodes? Run make colortheme to install locally!

Related projects

Point-Free uses a bunch of interesting open-source software:

  • 🗺 swift-html: A Swift DSL for type-safe, extensible, and transformable HTML documents.
  • 🕸 swift-web: A collection of types and functions for dealing with common web server concerns, such as HTML render, CSS preprocessing, middleware and more.
  • 🎶 swift-prelude: Offers a standard library for experimental functional programming in Swift.
  • 🏷 swift-tagged: Helps us create strong contracts with our data boundaries, like JSON from GitHub and Stripe, and our PostgreSQL data.
  • 📸 swift-snapshot-testing: Powers our testing infrastructure by taking snapshots of various data structures to guarantee the correctness of their output. We use this on everything from middleware to ensure requests are correctly transformed into responses, and even entire web pages to make sure the site looks correct at a variety of sizes (e.g. on iPhone and desktop).

Explore more of our open-source on the Point-Free organization.

Learn More

Brandon gave a talk about most of the core ideas that went into this project at Swift Summit 2017.

The two sides of writing testable code

Find this interesting?

Then check out Point-Free!

License

The content of this project itself is licensed under the CC BY-NC-SA 4.0 license, and the underlying source code used to format and display that content is licensed under the MIT license.

swift-clocks's People

Contributors

andrewsb avatar b1ackturtle avatar bobergj avatar brzzdev avatar matejkob avatar mbrandonw avatar rspoon3 avatar sanghun0724 avatar stephencelis avatar tgrapperon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swift-clocks's Issues

TestClock.sleep(until deadline:) suspends when called with a deadline that is equal to TestClock.now

Description

TestClock.sleep(until deadline:) suspends when called with a deadline that is equal to TestClock.now

Checklist

  • If possible, I've reproduced the issue using the main branch of this package.
  • This issue hasn't been addressed in an existing GitHub issue or discussion.

Expected behavior

TestClock.sleep(until deadline:) immediately returns when TestClock.now is already equal to deadline

Actual behavior

TestClock.sleep(until:) suspends if TestClock.now == deadline at the time of the call, clock must be advanced past the deadline for wake up

Steps to reproduce

PR with test case and fix: #22

swift-clocks version information

main

Destination operating system

iOS 16

Xcode version information

Version 14.3.1 (14E300c)

Swift Compiler version information

xcrun swiftc --version
swift-driver version: 1.75.2 Apple Swift version 5.8.1 (swiftlang-5.8.0.124.5 clang-1403.0.22.11.100)
Target: x86_64-apple-macosx13.0

Unit Tests Run Incredibly Slow

Description

I noticed in a project of mine that using the TestClock was causing tests to become incredibly slow. I made a very simple demo app and was able to reproduce the problem. After that I thought I would try running the tests that came with the library. The same thing occurs. Tests are taking seconds to run (sometimes close to a minute) as well as failing.

I am testing on Xcode 15.4 (15F31d) with an iPhone 14 (17.4) simulator. I can also reproduce on the 17.5 and 16.4 simulators.

Logging Error: Failed to initialize logging system. Log messages may be missing. If this issue persists, try setting IDEPreferLogStreaming=YES in the active scheme actions environment variables.
Test Suite 'All tests' started at 2024-05-16 08:14:49.643.
Test Suite 'ClocksTests.xctest' started at 2024-05-16 08:14:49.643.
Test Suite 'ImmediateClockTests' started at 2024-05-16 08:14:49.644.
Test Case '-[ClocksTests.ImmediateClockTests testCooperativeCancellation]' started.
Test Case '-[ClocksTests.ImmediateClockTests testCooperativeCancellation]' passed (0.001 seconds).
Test Case '-[ClocksTests.ImmediateClockTests testNow]' started.
Test Case '-[ClocksTests.ImmediateClockTests testNow]' passed (0.113 seconds).
Test Case '-[ClocksTests.ImmediateClockTests testTimer]' started.
Test Case '-[ClocksTests.ImmediateClockTests testTimer]' passed (36.022 seconds).
Test Suite 'ImmediateClockTests' passed at 2024-05-16 08:15:25.782.
	 Executed 3 tests, with 0 failures (0 unexpected) in 36.136 (36.139) seconds
Test Suite 'TestClockTests' started at 2024-05-16 08:15:25.783.
Test Case '-[ClocksTests.TestClockTests testAdvance]' started.
Test Case '-[ClocksTests.TestClockTests testAdvance]' passed (6.591 seconds).
Test Case '-[ClocksTests.TestClockTests testAdvanceWithReentrantUnitsOfWork]' started.
Test Case '-[ClocksTests.TestClockTests testAdvanceWithReentrantUnitsOfWork]' passed (12.760 seconds).
Test Case '-[ClocksTests.TestClockTests testCancellationRemovesScheduledItem]' started.
Test Case '-[ClocksTests.TestClockTests testCancellationRemovesScheduledItem]' passed (1.260 seconds).
Test Case '-[ClocksTests.TestClockTests testCheckScheduledWork]' started.
Test Case '-[ClocksTests.TestClockTests testCheckScheduledWork]' passed (6.489 seconds).
Test Case '-[ClocksTests.TestClockTests testCooperativeCancellation]' started.
/Users/richardwitherspoon/Documents/swift-clocks/Tests/ClocksTests/TestClocksTests.swift:164: error: -[ClocksTests.TestClockTests testCooperativeCancellation] : Expected all sleeps to finish, but some are still suspending after 0.5 seconds.

There are sleeps suspending. This could mean you are not advancing the test clock far enough for your feature to execute its logic, or there could be a bug in your feature's logic.

You can also increase the timeout of 'run' to be greater than 0.5 seconds.
Test Case '-[ClocksTests.TestClockTests testCooperativeCancellation]' failed (4.361 seconds).
Test Case '-[ClocksTests.TestClockTests testNow]' started.
Test Case '-[ClocksTests.TestClockTests testNow]' passed (0.635 seconds).
Test Case '-[ClocksTests.TestClockTests testRunMultipleUnitsOfWork]' started.
/Users/richardwitherspoon/Documents/swift-clocks/Tests/ClocksTests/TestClocksTests.swift:106: error: -[ClocksTests.TestClockTests testRunMultipleUnitsOfWork] : Expected all sleeps to finish, but some are still suspending after 1.0 seconds.

There are sleeps suspending. This could mean you are not advancing the test clock far enough for your feature to execute its logic, or there could be a bug in your feature's logic.

You can also increase the timeout of 'run' to be greater than 1.0 seconds.
/Users/richardwitherspoon/Documents/swift-clocks/Tests/ClocksTests/TestClocksTests.swift:108: error: -[ClocksTests.TestClockTests testRunMultipleUnitsOfWork] : XCTAssertEqual failed: ("1") is not equal to ("10")
Test Case '-[ClocksTests.TestClockTests testRunMultipleUnitsOfWork]' failed (1.599 seconds).
Test Case '-[ClocksTests.TestClockTests testRunSorting]' started.
/Users/richardwitherspoon/Documents/swift-clocks/Tests/ClocksTests/TestClocksTests.swift:212: error: -[ClocksTests.TestClockTests testRunSorting] : Expected all sleeps to finish, but some are still suspending after 0.5 seconds.

There are sleeps suspending. This could mean you are not advancing the test clock far enough for your feature to execute its logic, or there could be a bug in your feature's logic.

You can also increase the timeout of 'run' to be greater than 0.5 seconds.
/Users/richardwitherspoon/Documents/swift-clocks/Sources/Clocks/TestClock.swift:232: error: -[ClocksTests.TestClockTests testRunSorting] : failed: caught error: "CancellationError()"
Test Case '-[ClocksTests.TestClockTests testRunSorting]' failed (6.458 seconds).
Test Case '-[ClocksTests.TestClockTests testRun]' started.
/Users/richardwitherspoon/Documents/swift-clocks/Tests/ClocksTests/TestClocksTests.swift:59: error: -[ClocksTests.TestClockTests testRun] : Expected all sleeps to finish, but some are still suspending after 0.5 seconds.

There are sleeps suspending. This could mean you are not advancing the test clock far enough for your feature to execute its logic, or there could be a bug in your feature's logic.

You can also increase the timeout of 'run' to be greater than 0.5 seconds.
/Users/richardwitherspoon/Documents/swift-clocks/Tests/ClocksTests/TestClocksTests.swift:61: error: -[ClocksTests.TestClockTests testRun] : XCTAssertEqual failed: ("false") is not equal to ("true")
Test Case '-[ClocksTests.TestClockTests testRun]' failed (5.838 seconds).
Test Case '-[ClocksTests.TestClockTests testRunWithReentrantUnitsOfWork]' started.
/Users/richardwitherspoon/Documents/swift-clocks/Tests/ClocksTests/TestClocksTests.swift:127: error: -[ClocksTests.TestClockTests testRunWithReentrantUnitsOfWork] : Expected all sleeps to finish, but some are still suspending after 0.5 seconds.

There are sleeps suspending. This could mean you are not advancing the test clock far enough for your feature to execute its logic, or there could be a bug in your feature's logic.

You can also increase the timeout of 'run' to be greater than 0.5 seconds.
/Users/richardwitherspoon/Documents/swift-clocks/Sources/Clocks/TestClock.swift:232: error: -[ClocksTests.TestClockTests testRunWithReentrantUnitsOfWork] : failed: caught error: "CancellationError()"
Test Case '-[ClocksTests.TestClockTests testRunWithReentrantUnitsOfWork]' failed (3.619 seconds).
Test Case '-[ClocksTests.TestClockTests testRunWithTimeout]' started.
XCTExpectFailure: matcher accepted Assertion Failure at TestClocksTests.swift:88: Expected all sleeps to finish, but some are still suspending after 1.0 seconds.

There are sleeps suspending. This could mean you are not advancing the test clock far enough for your feature to execute its logic, or there could be a bug in your feature's logic.

You can also increase the timeout of 'run' to be greater than 1.0 seconds.
TestClocksTests.swift:88: Expected failure in -[ClocksTests.TestClockTests testRunWithTimeout]: Expected all sleeps to finish, but some are still suspending after 1.0 seconds.

There are sleeps suspending. This could mean you are not advancing the test clock far enough for your feature to execute its logic, or there could be a bug in your feature's logic.

You can also increase the timeout of 'run' to be greater than 1.0 seconds.
XCTExpectFailure: matcher accepted Assertion Failure at TestClocksTests.swift:90: Expected all sleeps to finish, but some are still suspending after 1.0 seconds.

There are sleeps suspending. This could mean you are not advancing the test clock far enough for your feature to execute its logic, or there could be a bug in your feature's logic.

You can also increase the timeout of 'run' to be greater than 1.0 seconds.
TestClocksTests.swift:90: Expected failure in -[ClocksTests.TestClockTests testRunWithTimeout]: Expected all sleeps to finish, but some are still suspending after 1.0 seconds.

There are sleeps suspending. This could mean you are not advancing the test clock far enough for your feature to execute its logic, or there could be a bug in your feature's logic.

You can also increase the timeout of 'run' to be greater than 1.0 seconds.
Test Case '-[ClocksTests.TestClockTests testRunWithTimeout]' passed (8.530 seconds).
Test Case '-[ClocksTests.TestClockTests testSleepUntilExactlyNow]' started.
Test Case '-[ClocksTests.TestClockTests testSleepUntilExactlyNow]' passed (1.695 seconds).
Test Suite 'TestClockTests' failed at 2024-05-16 08:16:25.643.
	 Executed 12 tests, with 9 failures (2 unexpected) in 59.836 (59.859) seconds
Test Suite 'UnimplementedClockTests' started at 2024-05-16 08:16:25.644.
Test Case '-[ClocksTests.UnimplementedClockTests testCooperativeCancellation]' started.
XCTExpectFailure: matcher accepted Assertion Failure at UnimplementedClockTests.swift:62: Unimplemented: Clock.now
XCTExpectFailure: matcher accepted Assertion Failure at UnimplementedClockTests.swift:62: Unimplemented: Clock.sleep
UnimplementedClockTests.swift:62: Expected failure in -[ClocksTests.UnimplementedClockTests testCooperativeCancellation]: Unimplemented: Clock.now
UnimplementedClockTests.swift:62: Expected failure in -[ClocksTests.UnimplementedClockTests testCooperativeCancellation]: Unimplemented: Clock.sleep
Test Case '-[ClocksTests.UnimplementedClockTests testCooperativeCancellation]' passed (0.015 seconds).
Test Case '-[ClocksTests.UnimplementedClockTests testNow]' started.
XCTExpectFailure: matcher accepted Assertion Failure at UnimplementedClockTests.swift:46: Unimplemented: Clock.now
XCTExpectFailure: matcher accepted Assertion Failure at UnimplementedClockTests.swift:46: Unimplemented: Clock.sleep
UnimplementedClockTests.swift:46: Expected failure in -[ClocksTests.UnimplementedClockTests testNow]: Unimplemented: Clock.now
UnimplementedClockTests.swift:46: Expected failure in -[ClocksTests.UnimplementedClockTests testNow]: Unimplemented: Clock.sleep
Test Case '-[ClocksTests.UnimplementedClockTests testNow]' passed (0.210 seconds).
Test Case '-[ClocksTests.UnimplementedClockTests testUnimplementedClock_WithName]' started.
XCTExpectFailure: matcher accepted Assertion Failure at UnimplementedClockTests.swift:32: Unimplemented: ContinuousClock.now
XCTExpectFailure: matcher accepted Assertion Failure at UnimplementedClockTests.swift:32: Unimplemented: ContinuousClock.sleep
UnimplementedClockTests.swift:32: Expected failure in -[ClocksTests.UnimplementedClockTests testUnimplementedClock_WithName]: Unimplemented: ContinuousClock.now
UnimplementedClockTests.swift:32: Expected failure in -[ClocksTests.UnimplementedClockTests testUnimplementedClock_WithName]: Unimplemented: ContinuousClock.sleep
Test Case '-[ClocksTests.UnimplementedClockTests testUnimplementedClock_WithName]' passed (9.477 seconds).
Test Case '-[ClocksTests.UnimplementedClockTests testUnimplementedClock]' started.
XCTExpectFailure: matcher accepted Assertion Failure at UnimplementedClockTests.swift:18: Unimplemented: Clock.now
XCTExpectFailure: matcher accepted Assertion Failure at UnimplementedClockTests.swift:18: Unimplemented: Clock.sleep
UnimplementedClockTests.swift:18: Expected failure in -[ClocksTests.UnimplementedClockTests testUnimplementedClock]: Unimplemented: Clock.now
UnimplementedClockTests.swift:18: Expected failure in -[ClocksTests.UnimplementedClockTests testUnimplementedClock]: Unimplemented: Clock.sleep
Test Case '-[ClocksTests.UnimplementedClockTests testUnimplementedClock]' passed (0.423 seconds).
Test Suite 'UnimplementedClockTests' passed at 2024-05-16 08:16:35.773.
	 Executed 4 tests, with 0 failures (0 unexpected) in 10.125 (10.129) seconds
Test Suite 'ClocksTests.xctest' failed at 2024-05-16 08:16:35.774.
	 Executed 19 tests, with 9 failures (2 unexpected) in 106.096 (106.131) seconds
Test Suite 'All tests' failed at 2024-05-16 08:16:35.775.
	 Executed 19 tests, with 9 failures (2 unexpected) in 106.096 (106.132) seconds
Program ended with exit code: 1

Checklist

  • If possible, I've reproduced the issue using the main branch of this package.
  • This issue hasn't been addressed in an existing GitHub issue or discussion.

Expected behavior

Tests should run in a fraction of a second.

Actual behavior

Tests are taking seconds to run (sometimes close to a minute) as well as failing.

Steps to reproduce

  1. Download Xcode 15.4
  2. Select an iPhone 16.4, 17.4 or 17.5 simulator
  3. Run the libraries unit tests

swift-clocks version information

2c74776

Destination operating system

iOS 16 and 17

Xcode version information

Xcode 15.4 (15F31d)

Swift Compiler version information

Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)

Store with TestClock not awaiting when using SnapshotTesting

Description

There seems to be an issue with the Store when using a TestClock, the view doesn't react to timer ticks unless we assert for state mutation and recreate the view and the store.

Current versions:
swift-clocks 1.0.2
swift-composable-architecture 1.10.4
swift-snapshot-testing 1.16.0

Checklist

  • If possible, I've reproduced the issue using the main branch of this package.
  • This issue hasn't been addressed in an existing GitHub issue or discussion.

Expected behavior

These tests should pass

@MainActor // ❌
  func testExampleFailing() async {

    let clock = TestClock()
    let store = Store(initialState: .init(), reducer: { ContentViewFeature()}, withDependencies: { $0.continuousClock = clock })
    let sut = ContentView(store: store)

    await store.send(.startTimer).finish()

    await clock.advance(by: .seconds(1))
    // Test ends with unexpected result, timer doesn't advance
    assertSnapshot(matching: UIHostingController(rootView: sut), as: .image)

    // Same here
    await clock.advance(by: .seconds(4))
    assertSnapshot(matching: UIHostingController(rootView: sut), as: .image)
  }

  @MainActor // ❌
  func testExampleFailing2() async {

    let clock = TestClock()
    let store = TestStore(initialState: .init(), reducer: { ContentViewFeature()}, withDependencies: { $0.continuousClock = clock })
    store.exhaustivity = .off
    let sut = ContentView(store: store.snapshotStore)

    let task = await store.send(.startTimer)

    // Test ends with unexpected result, timer doesn't advance
    await clock.advance(by: .seconds(1))
    assertSnapshot(matching: UIHostingController(rootView: sut), as: .image)

    // Test ends with unexpected result, timer doesn't advance
    await clock.advance(by: .seconds(4))
    assertSnapshot(matching: UIHostingController(rootView: sut), as: .image)

    await task.cancel()
  }

Actual behavior

These tests are the only ones that I'm able to make work

  @MainActor // ✅
  func testExampleMutatingState() async {
    let clock = TestClock()
    let store = Store(initialState: .init(), reducer: { ContentViewFeature()}, withDependencies: { $0.continuousClock = clock })

    await store.send(.startTimer).finish()

    // State does get mutated
    await clock.advance(by: .seconds(1))
    XCTAssertEqual(store.secondsElapsed, 1)

    await clock.advance(by: .seconds(4))
    XCTAssertEqual(store.secondsElapsed, 5)
  }

  @MainActor // ✅
  func testExampleWithUISnapshot() async {
    let clock = TestClock()
    let store = TestStore(
      initialState: ContentViewFeature.State(),
      reducer: { ContentViewFeature() },
      withDependencies: { $0.continuousClock = clock }
    )
    let task = await store.send(.startTimer)

    let sut1 = ContentView(store: store.snapshotStore)
    assertSnapshot(matching: UIHostingController(rootView: sut1), as: .image)

    await clock.advance(by: .seconds(1))
    // By asserting the state mutation we mamage to await
    await store.receive(\.timerTicked) { $0.secondsElapsed = 1 }

    // If we recreate the view and the store with the current state then we get the desired result
    let sut2 = ContentView(store: store.snapshotStore)
    assertSnapshot(matching: UIHostingController(rootView: sut2), as: .image)

    // Same concept here
    await clock.advance(by: .seconds(4))
    for second in 2...5 {
      await store.receive(\.timerTicked) { $0.secondsElapsed = Double(second) }
    }
    let sut3 = ContentView(store: store.snapshotStore)
    assertSnapshot(matching: UIHostingController(rootView: sut3), as: .image)

    await task.cancel()
  }

Steps to reproduce

  1. Create a view with a timer
  2. A store that uses a ContinuousClock
  3. Create a test for a view that injects a TestClock
  4. Use assertSnapshot to assert changes in the view

Find here the project:
clockTests.zip

Thanks in advance

swift-clocks version information

1.0.2

Destination operating system

iOS 17.4

Xcode version information

15.3

Swift Compiler version information

swift-driver version: 1.90.11.1 Apple Swift version 5.10 (swiftlang-5.10.0.13 clang-1500.3.9.4)
Target: arm64-apple-macosx14.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.