Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Windows Support #1088

Merged
merged 6 commits into from
Sep 27, 2023
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
13 changes: 13 additions & 0 deletions .github/workflows/ci-swiftpm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,16 @@ jobs:
- uses: actions/checkout@v4
- run: swift build -Xswiftc -suppress-warnings
- run: swift test -Xswiftc -suppress-warnings --enable-test-discovery

swiftpm_windows:
name: SwiftPM, Windows
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Install Swift
uses: compnerd/gha-setup-swift@main
with:
branch: swift-5.9-release
tag: 5.9-RELEASE
- name: Test Windows
run: swift test -Xswiftc -suppress-warnings
4 changes: 4 additions & 0 deletions Sources/Nimble/Matchers/PostNotification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ internal class NotificationCollector {
}
}

#if !os(Windows)
private let mainThread = pthread_self()
#else
private let mainThread = Thread.mainThread
#endif

private func _postNotifications<Out>(
_ predicate: Predicate<[Notification]>,
Expand Down
3 changes: 3 additions & 0 deletions Sources/Nimble/Utils/AsyncAwait.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#if !os(WASI)

#if canImport(CoreFoundation)
import CoreFoundation
#endif

import Dispatch
import Foundation

Expand Down
2 changes: 2 additions & 0 deletions Sources/Nimble/Utils/AsyncTimerSequence.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#if !os(WASI)

#if canImport(CoreFoundation)
import CoreFoundation
#endif
import Dispatch
import Foundation

Expand Down
33 changes: 33 additions & 0 deletions Sources/Nimble/Utils/PollAwait.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#if !os(WASI)

#if canImport(CoreFoundation)
import CoreFoundation
#endif
import Dispatch
import Foundation

Expand Down Expand Up @@ -153,7 +155,7 @@
self.trigger = trigger
}

func timeout(_ timeoutInterval: NimbleTimeInterval, forcefullyAbortTimeout: NimbleTimeInterval) -> Self {

Check warning on line 158 in Sources/Nimble/Utils/PollAwait.swift

View workflow job for this annotation

GitHub Actions / lint

Function Body Length Violation: Function body should span 50 lines or less excluding comments and whitespace: currently spans 54 lines (function_body_length)
/// = Discussion =
///
/// There's a lot of technical decisions here that is useful to elaborate on. This is
Expand Down Expand Up @@ -192,6 +194,7 @@
let timedOutSem = DispatchSemaphore(value: 0)
let semTimedOutOrBlocked = DispatchSemaphore(value: 0)
semTimedOutOrBlocked.signal()
#if canImport(CoreFoundation)
let runLoop = CFRunLoopGetMain()
#if canImport(Darwin)
let runLoopMode = CFRunLoopMode.defaultMode.rawValue
Expand All @@ -209,12 +212,30 @@
}
// potentially interrupt blocking code on run loop to let timeout code run
CFRunLoopStop(runLoop)
#else
let runLoop = RunLoop.main
runLoop.perform(inModes: [.default], block: {
if semTimedOutOrBlocked.wait(timeout: .now()) == .success {
timedOutSem.signal()
semTimedOutOrBlocked.signal()
if self.promise.resolveResult(.timedOut) {
RunLoop.main._stop()
}
}
})
// potentially interrupt blocking code on run loop to let timeout code run
runLoop._stop()
#endif
let now = DispatchTime.now() + forcefullyAbortTimeout.dispatchTimeInterval
let didNotTimeOut = timedOutSem.wait(timeout: now) != .success
let timeoutWasNotTriggered = semTimedOutOrBlocked.wait(timeout: .now()) == .success
if didNotTimeOut && timeoutWasNotTriggered {
if self.promise.resolveResult(.blockedRunLoop) {
#if canImport(CoreFoundation)
CFRunLoopStop(CFRunLoopGetMain())
#else
RunLoop.main._stop()
#endif
}
}
}
Expand Down Expand Up @@ -302,7 +323,11 @@
if completionCount < 2 {
func completeBlock() {
if promise.resolveResult(.completed(result)) {
#if canImport(CoreFoundation)
CFRunLoopStop(CFRunLoopGetMain())
#else
RunLoop.main._stop()
#endif
}
}

Expand Down Expand Up @@ -340,12 +365,20 @@
do {
if let result = try closure() {
if promise.resolveResult(.completed(result)) {
#if canImport(CoreFoundation)
CFRunLoopStop(CFRunLoopGetCurrent())
#else
RunLoop.current._stop()
#endif
}
}
} catch let error {
if promise.resolveResult(.errorThrown(error)) {
#if canImport(CoreFoundation)
CFRunLoopStop(CFRunLoopGetCurrent())
#else
RunLoop.current._stop()
#endif
}
}
}
Expand Down Expand Up @@ -380,4 +413,4 @@
return result
}

#endif // #if !os(WASI)

Check warning on line 416 in Sources/Nimble/Utils/PollAwait.swift

View workflow job for this annotation

GitHub Actions / lint

File Length Violation: File should contain 400 lines or less: currently contains 416 (file_length)
2 changes: 1 addition & 1 deletion Tests/NimbleTests/AsyncAwaitTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ final class AsyncAwaitTest: XCTestCase { // swiftlint:disable:this type_body_len
@MainActor
func testToEventuallyOnMain() async {
await expect(1).toEventually(equal(1), timeout: .seconds(300))
await expect { usleep(10); return 1 }.toEventually(equal(1))
await expect { try? await Task.sleep(nanoseconds: 10_000); return 1 }.toEventually(equal(1))
}

@MainActor
Expand Down
16 changes: 8 additions & 8 deletions Tests/NimbleTests/Matchers/ThrowAssertionTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@ private let error: Error = NSError(domain: "test", code: 0, userInfo: nil)

final class ThrowAssertionTest: XCTestCase {
func testPositiveMatch() {
#if arch(x86_64) || arch(arm64)
#if (arch(x86_64) || arch(arm64)) && !os(Windows)
expect { () -> Void in fatalError() }.to(throwAssertion())
#endif
}

func testErrorThrown() {
#if arch(x86_64) || arch(arm64)
#if (arch(x86_64) || arch(arm64)) && !os(Windows)
expect { throw error }.toNot(throwAssertion())
#endif
}

func testPostAssertionCodeNotRun() {
#if arch(x86_64) || arch(arm64)
#if (arch(x86_64) || arch(arm64)) && !os(Windows)
var reachedPoint1 = false
var reachedPoint2 = false

Expand All @@ -37,7 +37,7 @@ final class ThrowAssertionTest: XCTestCase {
}

func testNegativeMatch() {
#if arch(x86_64) || arch(arm64)
#if (arch(x86_64) || arch(arm64)) && !os(Windows)
var reachedPoint1 = false

expect { reachedPoint1 = true }.toNot(throwAssertion())
Expand All @@ -47,7 +47,7 @@ final class ThrowAssertionTest: XCTestCase {
}

func testPositiveMessage() {
#if arch(x86_64) || arch(arm64)
#if (arch(x86_64) || arch(arm64)) && !os(Windows)
failsWithErrorMessage("expected to throw an assertion") {
expect { () -> Void? in return }.to(throwAssertion())
}
Expand All @@ -59,21 +59,21 @@ final class ThrowAssertionTest: XCTestCase {
}

func testNegativeMessage() {
#if arch(x86_64) || arch(arm64)
#if (arch(x86_64) || arch(arm64)) && !os(Windows)
failsWithErrorMessage("expected to not throw an assertion") {
expect { () -> Void in fatalError() }.toNot(throwAssertion())
}
#endif
}

func testNonVoidClosure() {
#if arch(x86_64) || arch(arm64)
#if (arch(x86_64) || arch(arm64)) && !os(Windows)
expect { () -> Int in fatalError() }.to(throwAssertion())
#endif
}

func testChainOnThrowAssertion() {
#if arch(x86_64) || arch(arm64)
#if (arch(x86_64) || arch(arm64)) && !os(Windows)
expect { () -> Int in return 5 }.toNot(throwAssertion()).to(equal(5))
#endif
}
Expand Down
2 changes: 2 additions & 0 deletions Tests/NimbleTests/PollingTest.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#if !os(WASI)

import Dispatch
#if canImport(CoreFoundation)
import CoreFoundation
#endif
import Foundation
import XCTest
import Nimble
Expand Down