From 252891f07a2f6e5e89ca2eeaf70b87d3f02fd4db Mon Sep 17 00:00:00 2001 From: iamsyc Date: Sun, 10 May 2026 12:54:43 +0800 Subject: [PATCH] =?UTF-8?q?refactor(testing):=20=E6=B8=85=E7=90=86?= =?UTF-8?q?=E4=BD=8E=E9=A3=8E=E9=99=A9=E9=87=8D=E5=A4=8D=E6=94=AF=E6=92=91?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 删除 resolution 旧兼容 shim 和重复测试 helper - 新增 Sharing 与 VirtualDisplay 测试支撑 target - 更新测试依赖和 imports 并保持产品行为不变 --- Package.swift | 33 ++- .../Resolution/Resolution.swift | 15 -- .../Resolution/ResolutionSelection.swift | 2 +- .../Resolution/ResolutionsList.swift | 2 - .../Services/SharingState.swift | 2 +- .../CaptureControllerTests.swift | 1 + .../CaptureSharingIsolationTests.swift | 1 + .../ObservabilitySnapshotProviderTests.swift | 1 + .../ScreenCatalogOrchestratorTests.swift | 1 + .../SharingControllerTests.swift | 1 + .../TestSupport/TestSignalSessionHub.swift | 195 ------------------ .../TestSupport/TestVirtualDisplayClock.swift | 37 ---- .../MockWebServiceController.swift | 51 ++--- .../TestSignalSessionHub.swift | 30 +-- .../SharingEndToEndIntegrationTests.swift | 16 +- .../SharingWorkflowSmokeTests.swift | 2 + .../Integration/SocketTestSupport.swift | 1 + .../WebServerSocketIntegrationTests.swift | 1 + .../DisplaySharingCoordinatorTests.swift | 2 + .../Services/SharingServiceTests.swift | 2 + .../Services/WebServiceControllerTests.swift | 2 + .../TestSupport/AsyncTestHelpers.swift | 60 ------ .../MockWebServiceController.swift | 76 ------- .../TestSupport/TestPortAllocator.swift | 29 --- .../Web/RelaySessionHubTests.swift | 15 +- .../AppSettingsFeedbackControllerTests.swift | 1 + .../SupportHistoryStoreTests.swift | 1 + .../TestSupport/TemporaryDirectory.swift | 11 - .../AsyncTestHelpers.swift | 15 +- .../TestPortAllocator.swift | 7 +- .../TestVirtualDisplayClock.swift | 14 +- .../TestVirtualDisplayRuntimeDriver.swift | 0 ...ngDisplayReconfigurationMonitorTests.swift | 1 + .../DisplayRebuildCoordinatorTests.swift | 1 + ...yTeardownCoordinatorOfflineWaitTests.swift | 1 + .../DisplayTeardownCoordinatorTests.swift | 1 + ...imaryDisplayFallbackCoordinatorTests.swift | 1 + .../TestSupport/AsyncTestHelpers.swift | 60 ------ .../TestVirtualDisplayRuntimeDriver.swift | 13 -- .../VirtualDisplayAndResolutionTests.swift | 2 +- .../VirtualDisplayControllerTests.swift | 1 + .../VirtualDisplayListViewModelTests.swift | 1 + ...VirtualDisplayOrchestratorLightTests.swift | 1 + .../VirtualDisplayTopologyRecoveryTests.swift | 1 + 44 files changed, 121 insertions(+), 590 deletions(-) delete mode 100644 Sources/VoidDisplayFoundation/Resolution/Resolution.swift delete mode 100644 Tests/VoidDisplayAppTests/TestSupport/TestSignalSessionHub.swift delete mode 100644 Tests/VoidDisplayAppTests/TestSupport/TestVirtualDisplayClock.swift rename Tests/{VoidDisplayAppTests/TestSupport => VoidDisplaySharingTestingSupport}/MockWebServiceController.swift (54%) rename Tests/{VoidDisplaySharingTests/TestSupport => VoidDisplaySharingTestingSupport}/TestSignalSessionHub.swift (87%) delete mode 100644 Tests/VoidDisplaySharingTests/TestSupport/AsyncTestHelpers.swift delete mode 100644 Tests/VoidDisplaySharingTests/TestSupport/MockWebServiceController.swift delete mode 100644 Tests/VoidDisplaySharingTests/TestSupport/TestPortAllocator.swift delete mode 100644 Tests/VoidDisplaySupportTests/TestSupport/TemporaryDirectory.swift rename Tests/{VoidDisplayVirtualDisplayTests/TestSupport => VoidDisplayVirtualDisplayTestingSupport}/TestVirtualDisplayClock.swift (64%) rename Tests/{VoidDisplayAppTests/TestSupport => VoidDisplayVirtualDisplayTestingSupport}/TestVirtualDisplayRuntimeDriver.swift (100%) delete mode 100644 Tests/VoidDisplayVirtualDisplayTests/TestSupport/AsyncTestHelpers.swift delete mode 100644 Tests/VoidDisplayVirtualDisplayTests/TestSupport/TestVirtualDisplayRuntimeDriver.swift diff --git a/Package.swift b/Package.swift index e20f818..029c802 100644 --- a/Package.swift +++ b/Package.swift @@ -124,14 +124,18 @@ let package = Package( "VoidDisplaySupport", "VoidDisplayObservability", "VoidDisplayFoundation", - "VoidDisplayTestingSupport" + "VoidDisplayTestingSupport", + "VoidDisplaySharingTestingSupport", + "VoidDisplayVirtualDisplayTestingSupport" ], swiftSettings: sharedSwiftSettings ), .testTarget( name: "VoidDisplayVirtualDisplayTests", dependencies: [ - "VoidDisplayVirtualDisplay" + "VoidDisplayVirtualDisplay", + "VoidDisplayTestingSupport", + "VoidDisplayVirtualDisplayTestingSupport" ], swiftSettings: sharedSwiftSettings ), @@ -152,7 +156,9 @@ let package = Package( .testTarget( name: "VoidDisplaySharingTests", dependencies: [ - "VoidDisplaySharing" + "VoidDisplaySharing", + "VoidDisplayTestingSupport", + "VoidDisplaySharingTestingSupport" ], swiftSettings: sharedSwiftSettings ), @@ -168,7 +174,8 @@ let package = Package( dependencies: [ "VoidDisplaySupport", "VoidDisplayObservability", - "VoidDisplayFoundation" + "VoidDisplayFoundation", + "VoidDisplayTestingSupport" ], swiftSettings: sharedSwiftSettings ), @@ -194,6 +201,24 @@ let package = Package( ], path: "Tests/VoidDisplayTestingSupport", swiftSettings: sharedSwiftSettings + ), + .target( + name: "VoidDisplaySharingTestingSupport", + dependencies: [ + "VoidDisplaySharing", + "VoidDisplayFoundation" + ], + path: "Tests/VoidDisplaySharingTestingSupport", + swiftSettings: sharedSwiftSettings + ), + .target( + name: "VoidDisplayVirtualDisplayTestingSupport", + dependencies: [ + "VoidDisplayVirtualDisplay", + "VoidDisplayFoundation" + ], + path: "Tests/VoidDisplayVirtualDisplayTestingSupport", + swiftSettings: sharedSwiftSettings ) ] ) diff --git a/Sources/VoidDisplayFoundation/Resolution/Resolution.swift b/Sources/VoidDisplayFoundation/Resolution/Resolution.swift deleted file mode 100644 index c6a3af6..0000000 --- a/Sources/VoidDisplayFoundation/Resolution/Resolution.swift +++ /dev/null @@ -1,15 +0,0 @@ -// -// Resolution.swift -// VoidDisplay -// -// - -import Foundation - -package extension DisplayResolutionPreset { - // Compatibility shim for existing callers. - var resolutions: (Int, Int) { - let size = logicalSize - return (size.width, size.height) - } -} diff --git a/Sources/VoidDisplayFoundation/Resolution/ResolutionSelection.swift b/Sources/VoidDisplayFoundation/Resolution/ResolutionSelection.swift index d71f5b4..9a69214 100644 --- a/Sources/VoidDisplayFoundation/Resolution/ResolutionSelection.swift +++ b/Sources/VoidDisplayFoundation/Resolution/ResolutionSelection.swift @@ -21,7 +21,7 @@ package struct ResolutionSelection: Identifiable, Hashable { /// - refreshRate: Refresh rate in Hz (default: 60.0) /// - enableHiDPI: Whether to enable HiDPI for this resolution (default: true) package init(preset: DisplayResolutionPreset, refreshRate: Double = 60.0, enableHiDPI: Bool = true) { - let (w, h) = preset.resolutions + let (w, h) = preset.logicalSize self.width = w self.height = h self.refreshRate = refreshRate diff --git a/Sources/VoidDisplayFoundation/Resolution/ResolutionsList.swift b/Sources/VoidDisplayFoundation/Resolution/ResolutionsList.swift index 9a1455c..eaf0b05 100644 --- a/Sources/VoidDisplayFoundation/Resolution/ResolutionsList.swift +++ b/Sources/VoidDisplayFoundation/Resolution/ResolutionsList.swift @@ -43,5 +43,3 @@ package enum DisplayResolutionPreset: String, CaseIterable, Identifiable { return "\(size.width) × \(size.height)" } } - -package typealias Resolutions = DisplayResolutionPreset diff --git a/Sources/VoidDisplaySharing/Services/SharingState.swift b/Sources/VoidDisplaySharing/Services/SharingState.swift index 574f11e..5da9313 100644 --- a/Sources/VoidDisplaySharing/Services/SharingState.swift +++ b/Sources/VoidDisplaySharing/Services/SharingState.swift @@ -35,7 +35,7 @@ package struct SharingSessionEvent: Sendable, Equatable { sessionEpoch } - nonisolated init( + package nonisolated init( target: ShareTarget, clientID: String, sessionEpoch: UInt64 = 0, diff --git a/Tests/VoidDisplayAppTests/CaptureControllerTests.swift b/Tests/VoidDisplayAppTests/CaptureControllerTests.swift index 6ab89d5..106c384 100644 --- a/Tests/VoidDisplayAppTests/CaptureControllerTests.swift +++ b/Tests/VoidDisplayAppTests/CaptureControllerTests.swift @@ -3,6 +3,7 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation @testable import VoidDisplayTestingSupport +@testable import VoidDisplaySharingTestingSupport import CoreGraphics import CoreMedia import Foundation diff --git a/Tests/VoidDisplayAppTests/CaptureSharingIsolationTests.swift b/Tests/VoidDisplayAppTests/CaptureSharingIsolationTests.swift index f387568..d730a2a 100644 --- a/Tests/VoidDisplayAppTests/CaptureSharingIsolationTests.swift +++ b/Tests/VoidDisplayAppTests/CaptureSharingIsolationTests.swift @@ -3,6 +3,7 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation @testable import VoidDisplayTestingSupport +@testable import VoidDisplaySharingTestingSupport import CoreGraphics import Foundation import Testing diff --git a/Tests/VoidDisplayAppTests/ObservabilitySnapshotProviderTests.swift b/Tests/VoidDisplayAppTests/ObservabilitySnapshotProviderTests.swift index 01b4f37..af4440e 100644 --- a/Tests/VoidDisplayAppTests/ObservabilitySnapshotProviderTests.swift +++ b/Tests/VoidDisplayAppTests/ObservabilitySnapshotProviderTests.swift @@ -5,6 +5,7 @@ @testable import VoidDisplayObservability @testable import VoidDisplayFoundation @testable import VoidDisplayTestingSupport +@testable import VoidDisplaySharingTestingSupport import Foundation import Testing diff --git a/Tests/VoidDisplayAppTests/ScreenCatalogOrchestratorTests.swift b/Tests/VoidDisplayAppTests/ScreenCatalogOrchestratorTests.swift index 3bf47f8..c8b7ffc 100644 --- a/Tests/VoidDisplayAppTests/ScreenCatalogOrchestratorTests.swift +++ b/Tests/VoidDisplayAppTests/ScreenCatalogOrchestratorTests.swift @@ -4,6 +4,7 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation @testable import VoidDisplayTestingSupport +@testable import VoidDisplaySharingTestingSupport import CoreGraphics import Foundation import ScreenCaptureKit diff --git a/Tests/VoidDisplayAppTests/SharingControllerTests.swift b/Tests/VoidDisplayAppTests/SharingControllerTests.swift index 33bd291..602a246 100644 --- a/Tests/VoidDisplayAppTests/SharingControllerTests.swift +++ b/Tests/VoidDisplayAppTests/SharingControllerTests.swift @@ -2,6 +2,7 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation @testable import VoidDisplayTestingSupport +@testable import VoidDisplaySharingTestingSupport import Foundation import CoreGraphics import ScreenCaptureKit diff --git a/Tests/VoidDisplayAppTests/TestSupport/TestSignalSessionHub.swift b/Tests/VoidDisplayAppTests/TestSupport/TestSignalSessionHub.swift deleted file mode 100644 index 5e8787f..0000000 --- a/Tests/VoidDisplayAppTests/TestSupport/TestSignalSessionHub.swift +++ /dev/null @@ -1,195 +0,0 @@ -@testable import VoidDisplaySharing -import CoreVideo -import Foundation -import Synchronization -import VoidDisplayFoundation - -final class TestSignalSessionHub: SignalSessionHub, @unchecked Sendable { - private struct ClientState { - nonisolated(unsafe) let connection: any SignalSocketConnection - let clientID: String - let sessionEpoch: UInt64 - let target: ShareTarget - let eventSink: @Sendable (SharingSessionEvent) -> Void - var nextEventSequence: UInt64 = 0 - } - - private struct State: ~Copyable { - var clients: [ObjectIdentifier: ClientState] = [:] - var nextSessionEpoch: UInt64 = 0 - var onDemandChanged: @Sendable (Bool) -> Void = { _ in } - } - - private let state = Mutex(State()) - - nonisolated var activeClientCount: Int { - state.withLock { $0.clients.count } - } - - nonisolated var hasDemand: Bool { - activeClientCount > 0 - } - - nonisolated func updateDemandHandler(_ onDemandChanged: @escaping @Sendable (Bool) -> Void) { - state.withLock { $0.onDemandChanged = onDemandChanged } - } - - nonisolated func addClient( - _ connection: any SignalSocketConnection, - target: ShareTarget, - makeClientID: @escaping @Sendable () -> String = { UUID().uuidString }, - eventSink: @escaping @Sendable (SharingSessionEvent) -> Void - ) -> SignalSessionClientAddResult { - let key = ObjectIdentifier(connection as AnyObject) - let clientID = makeClientID() - let demandCallback = state.withLock { state -> (@Sendable (Bool) -> Void)? in - let wasEmpty = state.clients.isEmpty - state.nextSessionEpoch &+= 1 - state.clients[key] = ClientState( - connection: connection, - clientID: clientID, - sessionEpoch: state.nextSessionEpoch, - target: target, - eventSink: eventSink - ) - return wasEmpty ? state.onDemandChanged : nil - } - demandCallback?(true) - emitEvent(phase: .signalingConnected, source: .webSocket, for: key) - send(message: SignalingOutboundMessage(type: .ready), to: connection) - return .accepted(clientID: clientID) - } - - nonisolated func removeClient(_ connection: any SignalSocketConnection) { - removeClient(for: ObjectIdentifier(connection as AnyObject), cancelConnection: false) - } - - nonisolated func sendRejection(reason: String, to connection: any SignalSocketConnection) { - send(message: SignalingOutboundMessage(type: .error, reason: reason), to: connection) - } - - nonisolated func disconnectAllClients() { - for key in state.withLock({ Array($0.clients.keys) }) { - removeClient(for: key, cancelConnection: true) - } - } - - nonisolated func stopSharing() { - for key in state.withLock({ Array($0.clients.keys) }) { - if let connection = state.withLock({ $0.clients[key]?.connection }) { - send(message: SignalingOutboundMessage(type: .stopped), to: connection) - } - removeClient(for: key, cancelConnection: true) - } - } - - nonisolated func updateSourceVideoSpec(_: SourceVideoSpec) {} - - nonisolated func updatePerformanceMode(_: CapturePerformanceMode) {} - - nonisolated func receiveSignalText(_ text: String, from connection: any SignalSocketConnection) { - let key = ObjectIdentifier(connection as AnyObject) - guard let message = parseMessage(text) else { - send(message: SignalingOutboundMessage(type: .error, reason: "invalid_signal_payload"), to: connection) - return - } - guard let typeRawValue = message.type else { - send(message: SignalingOutboundMessage(type: .error, reason: "missing_signal_type"), to: connection) - return - } - guard let type = SignalingMessageType(rawValue: typeRawValue) else { - send(message: SignalingOutboundMessage(type: .error, reason: "unsupported_signal_type"), to: connection) - return - } - - switch type { - case .viewerReady, .iceComplete: - return - case .offer: - guard message.sdp != nil else { - send(message: SignalingOutboundMessage(type: .error, reason: "missing_offer_sdp"), to: connection) - return - } - emitEvent(phase: .offerReceived, source: .peerConnection, for: key) - send(message: SignalingOutboundMessage(type: .answer, sdp: "test-answer"), to: connection) - emitEvent(phase: .peerConnected, source: .peerConnection, for: key) - case .iceCandidate: - guard message.candidate != nil else { - send(message: SignalingOutboundMessage(type: .error, reason: "missing_ice_candidate"), to: connection) - return - } - default: - send(message: SignalingOutboundMessage(type: .error, reason: "unsupported_signal_type"), to: connection) - } - } - - nonisolated func submitFrame(pixelBuffer _: CVPixelBuffer, ptsUs _: UInt64) {} - - private nonisolated func removeClient(for key: ObjectIdentifier, cancelConnection: Bool) { - let result = state.withLock { state -> ( - connection: (any SignalSocketConnection)?, - event: SharingSessionEvent?, - sink: (@Sendable (SharingSessionEvent) -> Void)?, - demandCallback: (@Sendable (Bool) -> Void)? - ) in - guard var client = state.clients.removeValue(forKey: key) else { - return (nil, nil, nil, nil) - } - client.nextEventSequence += 1 - let event = SharingSessionEvent( - target: client.target, - clientID: client.clientID, - sessionEpoch: client.sessionEpoch, - sequence: client.nextEventSequence, - phase: .closed, - source: .webSocket - ) - let demandCallback = state.clients.isEmpty ? state.onDemandChanged : nil - return (client.connection, event, client.eventSink, demandCallback) - } - if let event = result.event, let sink = result.sink { - sink(event) - } - result.demandCallback?(false) - if cancelConnection { - result.connection?.cancelSocket() - } - } - - private nonisolated func emitEvent( - phase: SharingPeerPhase, - source: SharingSessionEventSource, - for key: ObjectIdentifier - ) { - let payload = state.withLock { - state -> (event: SharingSessionEvent, sink: @Sendable (SharingSessionEvent) -> Void)? in - guard var client = state.clients[key] else { return nil } - client.nextEventSequence += 1 - let event = SharingSessionEvent( - target: client.target, - clientID: client.clientID, - sessionEpoch: client.sessionEpoch, - sequence: client.nextEventSequence, - phase: phase, - source: source - ) - state.clients[key] = client - return (event, client.eventSink) - } - guard let payload else { return } - payload.sink(payload.event) - } - - private nonisolated func parseMessage(_ text: String) -> SignalingInboundMessage? { - guard let data = text.data(using: .utf8) else { return nil } - return try? JSONDecoder().decode(SignalingInboundMessage.self, from: data) - } - - private nonisolated func send(message: SignalingOutboundMessage, to connection: any SignalSocketConnection) { - guard let data = try? JSONEncoder().encode(message), - let text = String(data: data, encoding: .utf8) else { - return - } - connection.sendSocketFrame(encodeWebSocketTextFrame(text)) { _ in } - } -} diff --git a/Tests/VoidDisplayAppTests/TestSupport/TestVirtualDisplayClock.swift b/Tests/VoidDisplayAppTests/TestSupport/TestVirtualDisplayClock.swift deleted file mode 100644 index 48617fa..0000000 --- a/Tests/VoidDisplayAppTests/TestSupport/TestVirtualDisplayClock.swift +++ /dev/null @@ -1,37 +0,0 @@ -@testable import VoidDisplayApp -@testable import VoidDisplayVirtualDisplay -@testable import VoidDisplayCapture -@testable import VoidDisplaySharing -@testable import VoidDisplayFoundation -import Foundation - -@MainActor -final class TestVirtualDisplayClock: VirtualDisplayClocking { - private(set) var currentTime: TimeInterval - - init(startTime: TimeInterval = 0) { - self.currentTime = startTime - } - - func now() -> TimeInterval { - currentTime - } - - func sleep(for duration: Duration) async { - let components = duration.components - let seconds = - Double(components.seconds) + - (Double(components.attoseconds) / 1_000_000_000_000_000_000) - var remaining = max(seconds, 0) - if remaining == 0 { - await Task.yield() - return - } - while remaining > 0 { - let step = min(0.05, remaining) - currentTime += step - remaining -= step - await Task.yield() - } - } -} diff --git a/Tests/VoidDisplayAppTests/TestSupport/MockWebServiceController.swift b/Tests/VoidDisplaySharingTestingSupport/MockWebServiceController.swift similarity index 54% rename from Tests/VoidDisplayAppTests/TestSupport/MockWebServiceController.swift rename to Tests/VoidDisplaySharingTestingSupport/MockWebServiceController.swift index d49595b..6c6ae7d 100644 --- a/Tests/VoidDisplayAppTests/TestSupport/MockWebServiceController.swift +++ b/Tests/VoidDisplaySharingTestingSupport/MockWebServiceController.swift @@ -1,33 +1,34 @@ import VoidDisplaySharing -import VoidDisplayCapture import VoidDisplayFoundation import Foundation @MainActor -final class MockWebServiceController: WebServiceControllerProtocol { - var portValue: UInt16 = 9090 - var lifecycleState: WebServiceLifecycleState = .stopped - var isRunning = false - var activeStreamClientCount = 0 - var streamClientCountByTarget: [ShareTarget: Int] = [:] - var onRunningStateChanged: (@MainActor @Sendable (Bool) -> Void)? - var onLifecycleStateChanged: (@MainActor @Sendable (WebServiceLifecycleState) -> Void)? +package final class MockWebServiceController: WebServiceControllerProtocol { + package var portValue: UInt16 = 9090 + package var lifecycleState: WebServiceLifecycleState = .stopped + package var isRunning = false + package var activeStreamClientCount = 0 + package var streamClientCountByTarget: [ShareTarget: Int] = [:] + package var onRunningStateChanged: (@MainActor @Sendable (Bool) -> Void)? + package var onLifecycleStateChanged: (@MainActor @Sendable (WebServiceLifecycleState) -> Void)? - var startResult: WebServiceStartResult = .started( + package var startResult: WebServiceStartResult = .started( WebServiceBinding(requestedPort: 9090, boundPort: 9090) ) - var lastRequestedPort: UInt16? - var startCallCount = 0 - var stopCallCount = 0 - var disconnectCallCount = 0 - var disconnectTargetCallCount = 0 - var disconnectedTargetsHistory: [Set] = [] - var capturedTargetStateProvider: (@MainActor @Sendable (ShareTarget) -> ShareTargetState)? - var capturedConcreteTargetResolver: (@MainActor @Sendable (ShareTarget) -> ShareTarget?)? - var capturedSessionHubProvider: (@MainActor @Sendable (ShareTarget) -> (any SignalSessionHub)?)? - var capturedSharingEventSink: (@Sendable (SharingSessionEvent) -> Void)? + package var lastRequestedPort: UInt16? + package var startCallCount = 0 + package var stopCallCount = 0 + package var disconnectCallCount = 0 + package var disconnectTargetCallCount = 0 + package var disconnectedTargetsHistory: [Set] = [] + package var capturedTargetStateProvider: (@MainActor @Sendable (ShareTarget) -> ShareTargetState)? + package var capturedConcreteTargetResolver: (@MainActor @Sendable (ShareTarget) -> ShareTarget?)? + package var capturedSessionHubProvider: (@MainActor @Sendable (ShareTarget) -> (any SignalSessionHub)?)? + package var capturedSharingEventSink: (@Sendable (SharingSessionEvent) -> Void)? - func start( + package init() {} + + package func start( requestedPort: UInt16, targetStateProvider: @escaping @MainActor @Sendable (ShareTarget) -> ShareTargetState, concreteTargetResolver: @escaping @MainActor @Sendable (ShareTarget) -> ShareTarget?, @@ -54,7 +55,7 @@ final class MockWebServiceController: WebServiceControllerProtocol { return startResult } - func stop() { + package func stop() { stopCallCount += 1 isRunning = false lifecycleState = .stopped @@ -62,16 +63,16 @@ final class MockWebServiceController: WebServiceControllerProtocol { onLifecycleStateChanged?(lifecycleState) } - func disconnectAllStreamClients() { + package func disconnectAllStreamClients() { disconnectCallCount += 1 } - func disconnectStreamClients(for targets: Set) { + package func disconnectStreamClients(for targets: Set) { disconnectTargetCallCount += 1 disconnectedTargetsHistory.append(targets) } - func streamClientCount(for target: ShareTarget) -> Int { + package func streamClientCount(for target: ShareTarget) -> Int { streamClientCountByTarget[target] ?? 0 } } diff --git a/Tests/VoidDisplaySharingTests/TestSupport/TestSignalSessionHub.swift b/Tests/VoidDisplaySharingTestingSupport/TestSignalSessionHub.swift similarity index 87% rename from Tests/VoidDisplaySharingTests/TestSupport/TestSignalSessionHub.swift rename to Tests/VoidDisplaySharingTestingSupport/TestSignalSessionHub.swift index 5e8787f..da8d642 100644 --- a/Tests/VoidDisplaySharingTests/TestSupport/TestSignalSessionHub.swift +++ b/Tests/VoidDisplaySharingTestingSupport/TestSignalSessionHub.swift @@ -1,10 +1,10 @@ -@testable import VoidDisplaySharing +import VoidDisplaySharing import CoreVideo import Foundation import Synchronization import VoidDisplayFoundation -final class TestSignalSessionHub: SignalSessionHub, @unchecked Sendable { +package final class TestSignalSessionHub: SignalSessionHub, @unchecked Sendable { private struct ClientState { nonisolated(unsafe) let connection: any SignalSocketConnection let clientID: String @@ -22,19 +22,21 @@ final class TestSignalSessionHub: SignalSessionHub, @unchecked Sendable { private let state = Mutex(State()) - nonisolated var activeClientCount: Int { + package init() {} + + package nonisolated var activeClientCount: Int { state.withLock { $0.clients.count } } - nonisolated var hasDemand: Bool { + package nonisolated var hasDemand: Bool { activeClientCount > 0 } - nonisolated func updateDemandHandler(_ onDemandChanged: @escaping @Sendable (Bool) -> Void) { + package nonisolated func updateDemandHandler(_ onDemandChanged: @escaping @Sendable (Bool) -> Void) { state.withLock { $0.onDemandChanged = onDemandChanged } } - nonisolated func addClient( + package nonisolated func addClient( _ connection: any SignalSocketConnection, target: ShareTarget, makeClientID: @escaping @Sendable () -> String = { UUID().uuidString }, @@ -60,21 +62,21 @@ final class TestSignalSessionHub: SignalSessionHub, @unchecked Sendable { return .accepted(clientID: clientID) } - nonisolated func removeClient(_ connection: any SignalSocketConnection) { + package nonisolated func removeClient(_ connection: any SignalSocketConnection) { removeClient(for: ObjectIdentifier(connection as AnyObject), cancelConnection: false) } - nonisolated func sendRejection(reason: String, to connection: any SignalSocketConnection) { + package nonisolated func sendRejection(reason: String, to connection: any SignalSocketConnection) { send(message: SignalingOutboundMessage(type: .error, reason: reason), to: connection) } - nonisolated func disconnectAllClients() { + package nonisolated func disconnectAllClients() { for key in state.withLock({ Array($0.clients.keys) }) { removeClient(for: key, cancelConnection: true) } } - nonisolated func stopSharing() { + package nonisolated func stopSharing() { for key in state.withLock({ Array($0.clients.keys) }) { if let connection = state.withLock({ $0.clients[key]?.connection }) { send(message: SignalingOutboundMessage(type: .stopped), to: connection) @@ -83,11 +85,11 @@ final class TestSignalSessionHub: SignalSessionHub, @unchecked Sendable { } } - nonisolated func updateSourceVideoSpec(_: SourceVideoSpec) {} + package nonisolated func updateSourceVideoSpec(_: SourceVideoSpec) {} - nonisolated func updatePerformanceMode(_: CapturePerformanceMode) {} + package nonisolated func updatePerformanceMode(_: CapturePerformanceMode) {} - nonisolated func receiveSignalText(_ text: String, from connection: any SignalSocketConnection) { + package nonisolated func receiveSignalText(_ text: String, from connection: any SignalSocketConnection) { let key = ObjectIdentifier(connection as AnyObject) guard let message = parseMessage(text) else { send(message: SignalingOutboundMessage(type: .error, reason: "invalid_signal_payload"), to: connection) @@ -123,7 +125,7 @@ final class TestSignalSessionHub: SignalSessionHub, @unchecked Sendable { } } - nonisolated func submitFrame(pixelBuffer _: CVPixelBuffer, ptsUs _: UInt64) {} + package nonisolated func submitFrame(pixelBuffer _: CVPixelBuffer, ptsUs _: UInt64) {} private nonisolated func removeClient(for key: ObjectIdentifier, cancelConnection: Bool) { let result = state.withLock { state -> ( diff --git a/Tests/VoidDisplaySharingTests/Integration/SharingEndToEndIntegrationTests.swift b/Tests/VoidDisplaySharingTests/Integration/SharingEndToEndIntegrationTests.swift index 6427881..1e508c3 100644 --- a/Tests/VoidDisplaySharingTests/Integration/SharingEndToEndIntegrationTests.swift +++ b/Tests/VoidDisplaySharingTests/Integration/SharingEndToEndIntegrationTests.swift @@ -1,5 +1,7 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation +@testable import VoidDisplaySharingTestingSupport +@testable import VoidDisplayTestingSupport import CoreGraphics import Foundation import ScreenCaptureKit @@ -149,7 +151,7 @@ struct SharingEndToEndIntegrationTests { service.stopWebService() - let fullyStopped = await waitUntil(timeout: .seconds(2)) { + let fullyStopped = await waitUntil(timeoutNanoseconds: 2_000_000_000) { service.activeSharingDisplayIDs.isEmpty && service.hasAnyActiveSharing == false && service.isSharing(displayID: displayID) == false && @@ -217,18 +219,6 @@ struct SharingEndToEndIntegrationTests { } } - private func waitUntil(timeout: Duration, condition: @escaping @MainActor () -> Bool) async -> Bool { - let clock = ContinuousClock() - let deadline = clock.now + timeout - while clock.now < deadline { - if await condition() { - return true - } - await Task.yield() - } - return await condition() - } - private func temporaryStoreURL() -> URL { let base = FileManager.default.temporaryDirectory .appendingPathComponent("sharing-e2e-\(UUID().uuidString)", isDirectory: true) diff --git a/Tests/VoidDisplaySharingTests/Integration/SharingWorkflowSmokeTests.swift b/Tests/VoidDisplaySharingTests/Integration/SharingWorkflowSmokeTests.swift index 5c0c5c5..cb758d6 100644 --- a/Tests/VoidDisplaySharingTests/Integration/SharingWorkflowSmokeTests.swift +++ b/Tests/VoidDisplaySharingTests/Integration/SharingWorkflowSmokeTests.swift @@ -1,5 +1,7 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation +@testable import VoidDisplaySharingTestingSupport +@testable import VoidDisplayTestingSupport import CoreGraphics import Foundation import Testing diff --git a/Tests/VoidDisplaySharingTests/Integration/SocketTestSupport.swift b/Tests/VoidDisplaySharingTests/Integration/SocketTestSupport.swift index 9afdd7c..dc40397 100644 --- a/Tests/VoidDisplaySharingTests/Integration/SocketTestSupport.swift +++ b/Tests/VoidDisplaySharingTests/Integration/SocketTestSupport.swift @@ -1,5 +1,6 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation +@testable import VoidDisplayTestingSupport import Darwin import Foundation import Network diff --git a/Tests/VoidDisplaySharingTests/Integration/WebServerSocketIntegrationTests.swift b/Tests/VoidDisplaySharingTests/Integration/WebServerSocketIntegrationTests.swift index b733782..89ce57b 100644 --- a/Tests/VoidDisplaySharingTests/Integration/WebServerSocketIntegrationTests.swift +++ b/Tests/VoidDisplaySharingTests/Integration/WebServerSocketIntegrationTests.swift @@ -1,5 +1,6 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation +@testable import VoidDisplaySharingTestingSupport import Foundation import Darwin import JavaScriptCore diff --git a/Tests/VoidDisplaySharingTests/Services/DisplaySharingCoordinatorTests.swift b/Tests/VoidDisplaySharingTests/Services/DisplaySharingCoordinatorTests.swift index 4ebfe1d..beb1bea 100644 --- a/Tests/VoidDisplaySharingTests/Services/DisplaySharingCoordinatorTests.swift +++ b/Tests/VoidDisplaySharingTests/Services/DisplaySharingCoordinatorTests.swift @@ -1,5 +1,7 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation +@testable import VoidDisplaySharingTestingSupport +@testable import VoidDisplayTestingSupport import CoreGraphics import Foundation import ScreenCaptureKit diff --git a/Tests/VoidDisplaySharingTests/Services/SharingServiceTests.swift b/Tests/VoidDisplaySharingTests/Services/SharingServiceTests.swift index 87f9735..cb1f89b 100644 --- a/Tests/VoidDisplaySharingTests/Services/SharingServiceTests.swift +++ b/Tests/VoidDisplaySharingTests/Services/SharingServiceTests.swift @@ -1,5 +1,7 @@ @testable import VoidDisplaySharing @testable import VoidDisplayFoundation +@testable import VoidDisplaySharingTestingSupport +@testable import VoidDisplayTestingSupport import Foundation import CoreGraphics import ScreenCaptureKit diff --git a/Tests/VoidDisplaySharingTests/Services/WebServiceControllerTests.swift b/Tests/VoidDisplaySharingTests/Services/WebServiceControllerTests.swift index c4f0710..39801e6 100644 --- a/Tests/VoidDisplaySharingTests/Services/WebServiceControllerTests.swift +++ b/Tests/VoidDisplaySharingTests/Services/WebServiceControllerTests.swift @@ -1,4 +1,6 @@ @testable import VoidDisplaySharing +@testable import VoidDisplaySharingTestingSupport +@testable import VoidDisplayTestingSupport import Foundation import Network import Darwin diff --git a/Tests/VoidDisplaySharingTests/TestSupport/AsyncTestHelpers.swift b/Tests/VoidDisplaySharingTests/TestSupport/AsyncTestHelpers.swift deleted file mode 100644 index 72abca8..0000000 --- a/Tests/VoidDisplaySharingTests/TestSupport/AsyncTestHelpers.swift +++ /dev/null @@ -1,60 +0,0 @@ -import Foundation - -package enum AsyncTestTimeouts { - package static let shortStabilityWindow: UInt64 = 1_500_000_000 - package static let defaultAsyncAssertion: UInt64 = 3_000_000_000 -} - -@MainActor -package func waitUntil( - timeoutNanoseconds: UInt64 = AsyncTestTimeouts.defaultAsyncAssertion, - pollNanoseconds: UInt64 = 10_000_000, - condition: @MainActor () -> Bool -) async -> Bool { - let deadline = DispatchTime.now().uptimeNanoseconds + timeoutNanoseconds - while DispatchTime.now().uptimeNanoseconds < deadline { - if condition() { - return true - } - try? await Task.sleep(nanoseconds: pollNanoseconds) - } - return condition() -} - -@MainActor -package func staysTrue( - timeoutNanoseconds: UInt64 = AsyncTestTimeouts.shortStabilityWindow, - pollNanoseconds: UInt64 = 10_000_000, - condition: @MainActor () -> Bool -) async -> Bool { - let deadline = DispatchTime.now().uptimeNanoseconds + timeoutNanoseconds - while DispatchTime.now().uptimeNanoseconds < deadline { - if !condition() { - return false - } - try? await Task.sleep(nanoseconds: pollNanoseconds) - } - return condition() -} - -package func staysTrue( - timeoutNanoseconds: UInt64 = AsyncTestTimeouts.shortStabilityWindow, - pollNanoseconds: UInt64 = 10_000_000, - condition: @escaping @Sendable () async -> Bool -) async -> Bool { - let deadline = DispatchTime.now().uptimeNanoseconds + timeoutNanoseconds - while DispatchTime.now().uptimeNanoseconds < deadline { - if !(await condition()) { - return false - } - try? await Task.sleep(nanoseconds: pollNanoseconds) - } - return await condition() -} - -@MainActor -package func drainMainActorTasks(iterations: Int = 5) async { - for _ in 0.. Void)? - var onLifecycleStateChanged: (@MainActor @Sendable (WebServiceLifecycleState) -> Void)? - - var startResult: WebServiceStartResult = .started( - WebServiceBinding(requestedPort: 9090, boundPort: 9090) - ) - var lastRequestedPort: UInt16? - var startCallCount = 0 - var stopCallCount = 0 - var disconnectCallCount = 0 - var disconnectTargetCallCount = 0 - var disconnectedTargetsHistory: [Set] = [] - var capturedTargetStateProvider: (@MainActor @Sendable (ShareTarget) -> ShareTargetState)? - var capturedConcreteTargetResolver: (@MainActor @Sendable (ShareTarget) -> ShareTarget?)? - var capturedSessionHubProvider: (@MainActor @Sendable (ShareTarget) -> (any SignalSessionHub)?)? - var capturedSharingEventSink: (@Sendable (SharingSessionEvent) -> Void)? - - func start( - requestedPort: UInt16, - targetStateProvider: @escaping @MainActor @Sendable (ShareTarget) -> ShareTargetState, - concreteTargetResolver: @escaping @MainActor @Sendable (ShareTarget) -> ShareTarget?, - sessionHubProvider: @escaping @MainActor @Sendable (ShareTarget) -> (any SignalSessionHub)?, - sharingEventSink: @escaping @Sendable (SharingSessionEvent) -> Void - ) async -> WebServiceStartResult { - startCallCount += 1 - lastRequestedPort = requestedPort - capturedTargetStateProvider = targetStateProvider - capturedConcreteTargetResolver = concreteTargetResolver - capturedSessionHubProvider = sessionHubProvider - capturedSharingEventSink = sharingEventSink - switch startResult { - case .started(let binding), .alreadyRunning(let binding): - isRunning = true - portValue = binding.boundPort - lifecycleState = .running(binding) - case .failed: - isRunning = false - lifecycleState = .failed(startResult.failure ?? .listenerFailed(port: requestedPort, message: "mock_failure")) - } - onRunningStateChanged?(isRunning) - onLifecycleStateChanged?(lifecycleState) - return startResult - } - - func stop() { - stopCallCount += 1 - isRunning = false - lifecycleState = .stopped - onRunningStateChanged?(isRunning) - onLifecycleStateChanged?(lifecycleState) - } - - func disconnectAllStreamClients() { - disconnectCallCount += 1 - } - - func disconnectStreamClients(for targets: Set) { - disconnectTargetCallCount += 1 - disconnectedTargetsHistory.append(targets) - } - - func streamClientCount(for target: ShareTarget) -> Int { - streamClientCountByTarget[target] ?? 0 - } -} diff --git a/Tests/VoidDisplaySharingTests/TestSupport/TestPortAllocator.swift b/Tests/VoidDisplaySharingTests/TestSupport/TestPortAllocator.swift deleted file mode 100644 index 66727cf..0000000 --- a/Tests/VoidDisplaySharingTests/TestSupport/TestPortAllocator.swift +++ /dev/null @@ -1,29 +0,0 @@ -import Foundation - -enum TestPortAllocator { - private static let portRange: ClosedRange = 20_000...59_999 - - static func randomUnprivilegedPort() -> UInt16 { - randomPortCandidates(count: 1).first ?? 20_000 - } - - static func randomPortCandidates(count: Int) -> [UInt16] { - guard count > 0 else { return [] } - - let boundedCount = min( - count, - Int(portRange.upperBound - portRange.lowerBound + 1) - ) - var generator = SystemRandomNumberGenerator() - var used = Set() - var ports: [UInt16] = [] - ports.reserveCapacity(boundedCount) - - while ports.count < boundedCount { - let candidate = UInt16.random(in: portRange, using: &generator) - guard used.insert(candidate).inserted else { continue } - ports.append(candidate) - } - return ports - } -} diff --git a/Tests/VoidDisplaySharingTests/Web/RelaySessionHubTests.swift b/Tests/VoidDisplaySharingTests/Web/RelaySessionHubTests.swift index d9cae82..175edd6 100644 --- a/Tests/VoidDisplaySharingTests/Web/RelaySessionHubTests.swift +++ b/Tests/VoidDisplaySharingTests/Web/RelaySessionHubTests.swift @@ -1,5 +1,6 @@ @testable import VoidDisplayFoundation @testable import VoidDisplaySharing +@testable import VoidDisplayTestingSupport import CoreVideo import Foundation import Synchronization @@ -552,17 +553,3 @@ private func isRelayAccepted(_ result: SignalSessionClientAddResult) -> Bool { } return false } - -private func waitUntil( - timeoutNanoseconds: UInt64 = AsyncTestTimeouts.defaultAsyncAssertion, - condition: @escaping @Sendable () -> Bool -) async -> Bool { - let deadline = DispatchTime.now().uptimeNanoseconds + timeoutNanoseconds - while DispatchTime.now().uptimeNanoseconds < deadline { - if condition() { - return true - } - await Task.yield() - } - return condition() -} diff --git a/Tests/VoidDisplaySupportTests/AppSettingsFeedbackControllerTests.swift b/Tests/VoidDisplaySupportTests/AppSettingsFeedbackControllerTests.swift index bccdc90..167f82c 100644 --- a/Tests/VoidDisplaySupportTests/AppSettingsFeedbackControllerTests.swift +++ b/Tests/VoidDisplaySupportTests/AppSettingsFeedbackControllerTests.swift @@ -1,6 +1,7 @@ @testable import VoidDisplaySupport @testable import VoidDisplayObservability @testable import VoidDisplayFoundation +@testable import VoidDisplayTestingSupport import Foundation import Testing diff --git a/Tests/VoidDisplaySupportTests/SupportHistoryStoreTests.swift b/Tests/VoidDisplaySupportTests/SupportHistoryStoreTests.swift index 5d15ec6..4057029 100644 --- a/Tests/VoidDisplaySupportTests/SupportHistoryStoreTests.swift +++ b/Tests/VoidDisplaySupportTests/SupportHistoryStoreTests.swift @@ -1,6 +1,7 @@ @testable import VoidDisplaySupport @testable import VoidDisplayObservability @testable import VoidDisplayFoundation +@testable import VoidDisplayTestingSupport import Foundation import Testing diff --git a/Tests/VoidDisplaySupportTests/TestSupport/TemporaryDirectory.swift b/Tests/VoidDisplaySupportTests/TestSupport/TemporaryDirectory.swift deleted file mode 100644 index 2ce0334..0000000 --- a/Tests/VoidDisplaySupportTests/TestSupport/TemporaryDirectory.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation - -package func makeTemporaryDirectory(prefix: String) throws -> URL { - let url = FileManager.default.temporaryDirectory - .appendingPathComponent("\(prefix)-\(UUID().uuidString)", isDirectory: true) - try FileManager.default.createDirectory( - at: url, - withIntermediateDirectories: true - ) - return url -} diff --git a/Tests/VoidDisplayTestingSupport/AsyncTestHelpers.swift b/Tests/VoidDisplayTestingSupport/AsyncTestHelpers.swift index f2a2ae6..72abca8 100644 --- a/Tests/VoidDisplayTestingSupport/AsyncTestHelpers.swift +++ b/Tests/VoidDisplayTestingSupport/AsyncTestHelpers.swift @@ -1,13 +1,12 @@ -@testable import VoidDisplayFoundation import Foundation -enum AsyncTestTimeouts { - static let shortStabilityWindow: UInt64 = 1_500_000_000 - static let defaultAsyncAssertion: UInt64 = 3_000_000_000 +package enum AsyncTestTimeouts { + package static let shortStabilityWindow: UInt64 = 1_500_000_000 + package static let defaultAsyncAssertion: UInt64 = 3_000_000_000 } @MainActor -func waitUntil( +package func waitUntil( timeoutNanoseconds: UInt64 = AsyncTestTimeouts.defaultAsyncAssertion, pollNanoseconds: UInt64 = 10_000_000, condition: @MainActor () -> Bool @@ -23,7 +22,7 @@ func waitUntil( } @MainActor -func staysTrue( +package func staysTrue( timeoutNanoseconds: UInt64 = AsyncTestTimeouts.shortStabilityWindow, pollNanoseconds: UInt64 = 10_000_000, condition: @MainActor () -> Bool @@ -38,7 +37,7 @@ func staysTrue( return condition() } -func staysTrue( +package func staysTrue( timeoutNanoseconds: UInt64 = AsyncTestTimeouts.shortStabilityWindow, pollNanoseconds: UInt64 = 10_000_000, condition: @escaping @Sendable () async -> Bool @@ -54,7 +53,7 @@ func staysTrue( } @MainActor -func drainMainActorTasks(iterations: Int = 5) async { +package func drainMainActorTasks(iterations: Int = 5) async { for _ in 0.. = 20_000...59_999 - static func randomUnprivilegedPort() -> UInt16 { + package static func randomUnprivilegedPort() -> UInt16 { randomPortCandidates(count: 1).first ?? 20_000 } - static func randomPortCandidates(count: Int) -> [UInt16] { + package static func randomPortCandidates(count: Int) -> [UInt16] { guard count > 0 else { return [] } let boundedCount = min( diff --git a/Tests/VoidDisplayVirtualDisplayTests/TestSupport/TestVirtualDisplayClock.swift b/Tests/VoidDisplayVirtualDisplayTestingSupport/TestVirtualDisplayClock.swift similarity index 64% rename from Tests/VoidDisplayVirtualDisplayTests/TestSupport/TestVirtualDisplayClock.swift rename to Tests/VoidDisplayVirtualDisplayTestingSupport/TestVirtualDisplayClock.swift index c65992c..545eb00 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/TestSupport/TestVirtualDisplayClock.swift +++ b/Tests/VoidDisplayVirtualDisplayTestingSupport/TestVirtualDisplayClock.swift @@ -1,20 +1,20 @@ -@testable import VoidDisplayVirtualDisplay -@testable import VoidDisplayFoundation +import VoidDisplayVirtualDisplay +import VoidDisplayFoundation import Foundation @MainActor -final class TestVirtualDisplayClock: VirtualDisplayClocking { - private(set) var currentTime: TimeInterval +package final class TestVirtualDisplayClock: VirtualDisplayClocking { + package private(set) var currentTime: TimeInterval - init(startTime: TimeInterval = 0) { + package init(startTime: TimeInterval = 0) { self.currentTime = startTime } - func now() -> TimeInterval { + package func now() -> TimeInterval { currentTime } - func sleep(for duration: Duration) async { + package func sleep(for duration: Duration) async { let components = duration.components let seconds = Double(components.seconds) + diff --git a/Tests/VoidDisplayAppTests/TestSupport/TestVirtualDisplayRuntimeDriver.swift b/Tests/VoidDisplayVirtualDisplayTestingSupport/TestVirtualDisplayRuntimeDriver.swift similarity index 100% rename from Tests/VoidDisplayAppTests/TestSupport/TestVirtualDisplayRuntimeDriver.swift rename to Tests/VoidDisplayVirtualDisplayTestingSupport/TestVirtualDisplayRuntimeDriver.swift diff --git a/Tests/VoidDisplayVirtualDisplayTests/DebouncingDisplayReconfigurationMonitorTests.swift b/Tests/VoidDisplayVirtualDisplayTests/DebouncingDisplayReconfigurationMonitorTests.swift index 532f48f..9eb3a0b 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/DebouncingDisplayReconfigurationMonitorTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/DebouncingDisplayReconfigurationMonitorTests.swift @@ -1,5 +1,6 @@ @testable import VoidDisplayVirtualDisplay @testable import VoidDisplayFoundation +@testable import VoidDisplayTestingSupport import CoreGraphics import Testing diff --git a/Tests/VoidDisplayVirtualDisplayTests/DisplayRebuildCoordinatorTests.swift b/Tests/VoidDisplayVirtualDisplayTests/DisplayRebuildCoordinatorTests.swift index 788e58c..e7135e5 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/DisplayRebuildCoordinatorTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/DisplayRebuildCoordinatorTests.swift @@ -1,5 +1,6 @@ @testable import VoidDisplayVirtualDisplay @testable import VoidDisplayFoundation +@testable import VoidDisplayVirtualDisplayTestingSupport import CoreGraphics import Foundation import Testing diff --git a/Tests/VoidDisplayVirtualDisplayTests/DisplayTeardownCoordinatorOfflineWaitTests.swift b/Tests/VoidDisplayVirtualDisplayTests/DisplayTeardownCoordinatorOfflineWaitTests.swift index 022ab86..e3ca40b 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/DisplayTeardownCoordinatorOfflineWaitTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/DisplayTeardownCoordinatorOfflineWaitTests.swift @@ -1,5 +1,6 @@ @testable import VoidDisplayVirtualDisplay @testable import VoidDisplayFoundation +@testable import VoidDisplayVirtualDisplayTestingSupport import Foundation import Testing diff --git a/Tests/VoidDisplayVirtualDisplayTests/DisplayTeardownCoordinatorTests.swift b/Tests/VoidDisplayVirtualDisplayTests/DisplayTeardownCoordinatorTests.swift index 778c5c1..a6db580 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/DisplayTeardownCoordinatorTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/DisplayTeardownCoordinatorTests.swift @@ -1,5 +1,6 @@ @testable import VoidDisplayVirtualDisplay @testable import VoidDisplayFoundation +@testable import VoidDisplayVirtualDisplayTestingSupport import Foundation import Testing diff --git a/Tests/VoidDisplayVirtualDisplayTests/PrimaryDisplayFallbackCoordinatorTests.swift b/Tests/VoidDisplayVirtualDisplayTests/PrimaryDisplayFallbackCoordinatorTests.swift index 92588c8..8b66a1f 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/PrimaryDisplayFallbackCoordinatorTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/PrimaryDisplayFallbackCoordinatorTests.swift @@ -1,5 +1,6 @@ @testable import VoidDisplayVirtualDisplay @testable import VoidDisplayFoundation +@testable import VoidDisplayTestingSupport import Foundation import Testing diff --git a/Tests/VoidDisplayVirtualDisplayTests/TestSupport/AsyncTestHelpers.swift b/Tests/VoidDisplayVirtualDisplayTests/TestSupport/AsyncTestHelpers.swift deleted file mode 100644 index 72abca8..0000000 --- a/Tests/VoidDisplayVirtualDisplayTests/TestSupport/AsyncTestHelpers.swift +++ /dev/null @@ -1,60 +0,0 @@ -import Foundation - -package enum AsyncTestTimeouts { - package static let shortStabilityWindow: UInt64 = 1_500_000_000 - package static let defaultAsyncAssertion: UInt64 = 3_000_000_000 -} - -@MainActor -package func waitUntil( - timeoutNanoseconds: UInt64 = AsyncTestTimeouts.defaultAsyncAssertion, - pollNanoseconds: UInt64 = 10_000_000, - condition: @MainActor () -> Bool -) async -> Bool { - let deadline = DispatchTime.now().uptimeNanoseconds + timeoutNanoseconds - while DispatchTime.now().uptimeNanoseconds < deadline { - if condition() { - return true - } - try? await Task.sleep(nanoseconds: pollNanoseconds) - } - return condition() -} - -@MainActor -package func staysTrue( - timeoutNanoseconds: UInt64 = AsyncTestTimeouts.shortStabilityWindow, - pollNanoseconds: UInt64 = 10_000_000, - condition: @MainActor () -> Bool -) async -> Bool { - let deadline = DispatchTime.now().uptimeNanoseconds + timeoutNanoseconds - while DispatchTime.now().uptimeNanoseconds < deadline { - if !condition() { - return false - } - try? await Task.sleep(nanoseconds: pollNanoseconds) - } - return condition() -} - -package func staysTrue( - timeoutNanoseconds: UInt64 = AsyncTestTimeouts.shortStabilityWindow, - pollNanoseconds: UInt64 = 10_000_000, - condition: @escaping @Sendable () async -> Bool -) async -> Bool { - let deadline = DispatchTime.now().uptimeNanoseconds + timeoutNanoseconds - while DispatchTime.now().uptimeNanoseconds < deadline { - if !(await condition()) { - return false - } - try? await Task.sleep(nanoseconds: pollNanoseconds) - } - return await condition() -} - -@MainActor -package func drainMainActorTasks(iterations: Int = 5) async { - for _ in 0.. Void - ) throws -> any VirtualDisplayRuntimeHandling { - throw VirtualDisplayOperationError.creationFailed - } -} diff --git a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayAndResolutionTests.swift b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayAndResolutionTests.swift index 7a46c80..112e210 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayAndResolutionTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayAndResolutionTests.swift @@ -13,7 +13,7 @@ import Foundation struct VirtualDisplayAndResolutionTests { @Test func resolutionsParsing() { - let res = DisplayResolutionPreset.w1920h1080.resolutions + let res = DisplayResolutionPreset.w1920h1080.logicalSize #expect(res.0 == 1920) #expect(res.1 == 1080) } diff --git a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayControllerTests.swift b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayControllerTests.swift index 315345c..2529c95 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayControllerTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayControllerTests.swift @@ -1,6 +1,7 @@ @testable import VoidDisplayVirtualDisplay @testable import VoidDisplayObservability @testable import VoidDisplayFoundation +@testable import VoidDisplayTestingSupport import CoreGraphics import Foundation import Testing diff --git a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayListViewModelTests.swift b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayListViewModelTests.swift index cdb8f6e..d4a75f7 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayListViewModelTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayListViewModelTests.swift @@ -1,5 +1,6 @@ @testable import VoidDisplayVirtualDisplay @testable import VoidDisplayFoundation +@testable import VoidDisplayTestingSupport import CoreGraphics import Foundation import Testing diff --git a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayOrchestratorLightTests.swift b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayOrchestratorLightTests.swift index 1d6375e..ea581b5 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayOrchestratorLightTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayOrchestratorLightTests.swift @@ -3,6 +3,7 @@ import Foundation import Testing @testable import VoidDisplayVirtualDisplay @testable import VoidDisplayFoundation +@testable import VoidDisplayVirtualDisplayTestingSupport @MainActor @Suite(.serialized) diff --git a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayTopologyRecoveryTests.swift b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayTopologyRecoveryTests.swift index de3fdfd..c1f48ae 100644 --- a/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayTopologyRecoveryTests.swift +++ b/Tests/VoidDisplayVirtualDisplayTests/VirtualDisplayTopologyRecoveryTests.swift @@ -1,5 +1,6 @@ @testable import VoidDisplayVirtualDisplay @testable import VoidDisplayFoundation +@testable import VoidDisplayVirtualDisplayTestingSupport import CoreGraphics import Foundation import Testing