From 38f43bcdea45a41e4d28532b09f87e15a8e2ba34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9D=93=92=F0=9D=93=B1=F0=9D=93=B2=F0=9D=93=B2=20?= =?UTF-8?q?=F0=9D=93=9C=F0=9D=93=AA=F0=9D=93=B0=F0=9D=93=B7=F0=9D=93=BE?= =?UTF-8?q?=F0=9D=93=BC?= Date: Fri, 16 Jan 2026 15:00:45 +0800 Subject: [PATCH 1/5] ci: expand test matrix --- .github/workflows/test.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d14c4db..8ee1d4f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,7 +12,13 @@ permissions: jobs: test: name: Run Tests - runs-on: macos-latest + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - macos-latest + - ubuntu-latest + - windows-latest steps: - name: Checkout code @@ -24,4 +30,10 @@ jobs: swift-version: '6.2' - name: Run Swift tests + if: matrix.os != 'windows-latest' run: swift test + + - name: Run Swift tests + if: matrix.os == 'windows-latest' + run: swift test + shell: bash From 36b4c3fb3cf6988e8b9cbd90b58fa5cf60911b41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9D=93=92=F0=9D=93=B1=F0=9D=93=B2=F0=9D=93=B2=20?= =?UTF-8?q?=F0=9D=93=9C=F0=9D=93=AA=F0=9D=93=B0=F0=9D=93=B7=F0=9D=93=BE?= =?UTF-8?q?=F0=9D=93=BC?= Date: Fri, 16 Jan 2026 15:01:36 +0800 Subject: [PATCH 2/5] ci: align test runners with release workflow --- .github/workflows/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8ee1d4f..8a70279 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -17,8 +17,8 @@ jobs: matrix: os: - macos-latest - - ubuntu-latest - - windows-latest + - ubuntu-22.04 + - windows-2022 steps: - name: Checkout code @@ -30,10 +30,10 @@ jobs: swift-version: '6.2' - name: Run Swift tests - if: matrix.os != 'windows-latest' + if: matrix.os != 'windows-2022' run: swift test - name: Run Swift tests - if: matrix.os == 'windows-latest' + if: matrix.os == 'windows-2022' run: swift test shell: bash From 744a0efdbadc9762778510b8e639dbdd229fcbfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9D=93=92=F0=9D=93=B1=F0=9D=93=B2=F0=9D=93=B2=20?= =?UTF-8?q?=F0=9D=93=9C=F0=9D=93=AA=F0=9D=93=B0=F0=9D=93=B7=F0=9D=93=BE?= =?UTF-8?q?=F0=9D=93=BC?= Date: Fri, 16 Jan 2026 15:08:17 +0800 Subject: [PATCH 3/5] ci: use SwiftyLab setup on Windows --- .github/workflows/test.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8a70279..7162e8a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,6 +9,9 @@ on: permissions: contents: read +env: + SWIFT_VERSION: '6.2' + jobs: test: name: Run Tests @@ -25,9 +28,16 @@ jobs: uses: actions/checkout@v4 - name: Setup Swift + if: matrix.os != 'windows-2022' uses: swift-actions/setup-swift@v2 with: - swift-version: '6.2' + swift-version: ${{ env.SWIFT_VERSION }} + + - name: Setup Swift (Windows) + if: matrix.os == 'windows-2022' + uses: SwiftyLab/setup-swift@latest + with: + swift-version: ${{ env.SWIFT_VERSION }} - name: Run Swift tests if: matrix.os != 'windows-2022' From 70b11aa0e0cc6ef10f5ec5f060083a103fa836b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9D=93=92=F0=9D=93=B1=F0=9D=93=B2=F0=9D=93=B2=20?= =?UTF-8?q?=F0=9D=93=9C=F0=9D=93=AA=F0=9D=93=B0=F0=9D=93=B7=F0=9D=93=BE?= =?UTF-8?q?=F0=9D=93=BC?= Date: Fri, 16 Jan 2026 15:17:39 +0800 Subject: [PATCH 4/5] test: skip POSIX stdout capture on Windows --- Tests/GameCLITests/ScreenAndRoomCoverageTests.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Tests/GameCLITests/ScreenAndRoomCoverageTests.swift b/Tests/GameCLITests/ScreenAndRoomCoverageTests.swift index 67471db..d8c8d0a 100644 --- a/Tests/GameCLITests/ScreenAndRoomCoverageTests.swift +++ b/Tests/GameCLITests/ScreenAndRoomCoverageTests.swift @@ -3,6 +3,13 @@ import XCTest @testable import GameCLI import GameCore +#if os(Windows) +final class ScreenAndRoomCoverageTests: XCTestCase { + func testWindowsSkip() throws { + throw XCTSkip("Screen output capture uses POSIX APIs that are unavailable on Windows.") + } +} +#else #if canImport(Darwin) @preconcurrency import Darwin #else @@ -199,6 +206,7 @@ final class ScreenAndRoomCoverageTests: XCTestCase { XCTAssertEqual(store.records.first?.won, true) } } +#endif private extension String { func strippingANSICodes() -> String { From 1f10442c5cfc81346942488cd46628ea9fe070a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=F0=9D=93=92=F0=9D=93=B1=F0=9D=93=B2=F0=9D=93=B2=20?= =?UTF-8?q?=F0=9D=93=9C=F0=9D=93=AA=F0=9D=93=B0=F0=9D=93=B7=F0=9D=93=BE?= =?UTF-8?q?=F0=9D=93=BC?= Date: Fri, 16 Jan 2026 15:25:55 +0800 Subject: [PATCH 5/5] test: use WinSDK env helpers for run log test --- .../GameCLITests/RunLogPersistenceTests.swift | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/Tests/GameCLITests/RunLogPersistenceTests.swift b/Tests/GameCLITests/RunLogPersistenceTests.swift index 060840c..c5c83ba 100644 --- a/Tests/GameCLITests/RunLogPersistenceTests.swift +++ b/Tests/GameCLITests/RunLogPersistenceTests.swift @@ -2,6 +2,10 @@ import Foundation import XCTest @testable import GameCLI +#if os(Windows) +import WinSDK +#endif + final class RunLogPersistenceTests: XCTestCase { func testRunLogService_stripsANSIAndAddsTimestamp() { print("🧪 测试:testRunLogService_stripsANSIAndAddsTimestamp") @@ -39,6 +43,13 @@ final class RunLogPersistenceTests: XCTestCase { defer { try? FileManager.default.removeItem(at: tmp) } let key = "SALU_DATA_DIR" +#if os(Windows) + let old = ProcessInfo.processInfo.environment[key] + defer { + setEnvironmentVariable(key, old) + } + setEnvironmentVariable(key, tmp.path) +#else let old = getenv(key).flatMap { String(cString: $0) } defer { if let old { @@ -48,6 +59,7 @@ final class RunLogPersistenceTests: XCTestCase { } } setenv(key, tmp.path, 1) +#endif let store = FileRunLogStore() store.appendLine("line1\n") @@ -91,3 +103,17 @@ private final class InMemoryRunLogStore: RunLogStore, @unchecked Sendable { clearCount += 1 } } + +#if os(Windows) +private func setEnvironmentVariable(_ key: String, _ value: String?) { + let result: Bool = key.withCString(encodedAs: UTF16.self) { keyPtr in + if let value { + return value.withCString(encodedAs: UTF16.self) { valuePtr in + SetEnvironmentVariableW(keyPtr, valuePtr) + } + } + return SetEnvironmentVariableW(keyPtr, nil) + } + XCTAssertTrue(result, "Failed to set environment variable \(key)") +} +#endif