From 079e08f7815dab6bcc6b8ce5c02a98c4ce6543e6 Mon Sep 17 00:00:00 2001 From: Qijia Liu Date: Tue, 3 Nov 2026 21:55:32 -0500 Subject: [PATCH] Check Swift formatting in CI --- .github/workflows/build.yml | 2 + src/AppDelegate.swift | 6 +- src/ContentView.swift | 38 +++++------ src/SimStoreApp.swift | 12 ++-- tests/AppLifecycleTest.swift | 50 +++++++-------- tests/AppSmokeTest.swift | 120 +++++++++++++++++++---------------- 6 files changed, 119 insertions(+), 109 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c8a2e7f..ac5219d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,6 +34,8 @@ jobs: path: build/SimStore.app.tar.bz2 archive: false if-no-files-found: error + - name: Check Swift formatting + run: xcrun swift-format lint --recursive --strict src tests - name: Test run: ctest --preset release --verbose diff --git a/src/AppDelegate.swift b/src/AppDelegate.swift index 99a5256..e0a8ebd 100644 --- a/src/AppDelegate.swift +++ b/src/AppDelegate.swift @@ -2,7 +2,7 @@ import AppKit @MainActor final class AppDelegate: NSObject, NSApplicationDelegate { - func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - true - } + func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + true + } } diff --git a/src/ContentView.swift b/src/ContentView.swift index f61a5d1..d3d062d 100644 --- a/src/ContentView.swift +++ b/src/ContentView.swift @@ -3,26 +3,26 @@ import SwiftUI @MainActor struct ContentView: View { - @State private var cannotOpenRepository = false + @State private var cannotOpenRepository = false - private let repositoryURL = URL(string: "https://github.com/eagleoflqj/simstore-builds")! + private let repositoryURL = URL(string: "https://github.com/eagleoflqj/simstore-builds")! - var body: some View { - ContentUnavailableView { - Label("SimStore", systemImage: "square.stack.3d.up.fill") - } description: { - Text("Open-source apps for iOS Simulator.") - } actions: { - Button("View App Repository", systemImage: "arrow.up.right") { - cannotOpenRepository = !NSWorkspace.shared.open(repositoryURL) - } - .controlSize(.large) - } - .frame(minWidth: 640, minHeight: 420) - .alert("Couldn’t Open Repository", isPresented: $cannotOpenRepository) { - Button("OK", role: .cancel) {} - } message: { - Text("Open this address in your web browser: \(repositoryURL.absoluteString)") - } + var body: some View { + ContentUnavailableView { + Label("SimStore", systemImage: "square.stack.3d.up.fill") + } description: { + Text("Open-source apps for iOS Simulator.") + } actions: { + Button("View App Repository", systemImage: "arrow.up.right") { + cannotOpenRepository = !NSWorkspace.shared.open(repositoryURL) + } + .controlSize(.large) } + .frame(minWidth: 640, minHeight: 420) + .alert("Couldn’t Open Repository", isPresented: $cannotOpenRepository) { + Button("OK", role: .cancel) {} + } message: { + Text("Open this address in your web browser: \(repositoryURL.absoluteString)") + } + } } diff --git a/src/SimStoreApp.swift b/src/SimStoreApp.swift index 9a25b88..1a7a1de 100644 --- a/src/SimStoreApp.swift +++ b/src/SimStoreApp.swift @@ -2,12 +2,12 @@ import SwiftUI @main struct SimStoreApp: App { - @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate + @NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate - var body: some Scene { - WindowGroup("SimStore") { - ContentView() - } - .defaultSize(width: 800, height: 540) + var body: some Scene { + WindowGroup("SimStore") { + ContentView() } + .defaultSize(width: 800, height: 540) + } } diff --git a/tests/AppLifecycleTest.swift b/tests/AppLifecycleTest.swift index 51e1fe8..20c90c4 100644 --- a/tests/AppLifecycleTest.swift +++ b/tests/AppLifecycleTest.swift @@ -2,31 +2,31 @@ import AppKit @main struct AppLifecycleTest { - @MainActor - static func main() { - let application = NSApplication.shared - let delegate = AppDelegate() - application.delegate = delegate - application.setActivationPolicy(.regular) + @MainActor + static func main() { + let application = NSApplication.shared + let delegate = AppDelegate() + application.delegate = delegate + application.setActivationPolicy(.regular) - let window = NSWindow( - contentRect: NSRect(x: 200, y: 200, width: 640, height: 420), - styleMask: [.titled, .closable], - backing: .buffered, - defer: false - ) - window.isReleasedWhenClosed = false - window.makeKeyAndOrderFront(nil) - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - guard window.isVisible else { - fatalError("The test window did not appear.") - } - print("Closing the last window; the process must exit normally.") - window.performClose(nil) - } - withExtendedLifetime(delegate) { - application.run() - } - fatalError("The application event loop returned without terminating the process.") + let window = NSWindow( + contentRect: NSRect(x: 200, y: 200, width: 640, height: 420), + styleMask: [.titled, .closable], + backing: .buffered, + defer: false + ) + window.isReleasedWhenClosed = false + window.makeKeyAndOrderFront(nil) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { + guard window.isVisible else { + fatalError("The test window did not appear.") + } + print("Closing the last window; the process must exit normally.") + window.performClose(nil) } + withExtendedLifetime(delegate) { + application.run() + } + fatalError("The application event loop returned without terminating the process.") + } } diff --git a/tests/AppSmokeTest.swift b/tests/AppSmokeTest.swift index 5a2cd14..9865324 100644 --- a/tests/AppSmokeTest.swift +++ b/tests/AppSmokeTest.swift @@ -3,66 +3,74 @@ import Foundation @main struct AppSmokeTest { - static func main() { - do { - try verifyWindow() - } catch { - FileHandle.standardError.write(Data("App smoke test failed: \(error.localizedDescription)\n".utf8)) - exit(EXIT_FAILURE) - } + static func main() { + do { + try verifyWindow() + } catch { + FileHandle.standardError.write( + Data("App smoke test failed: \(error.localizedDescription)\n".utf8)) + exit(EXIT_FAILURE) } + } - static func verifyWindow() throws { - guard CommandLine.arguments.count == 2 else { - throw failure("Expected the App Bundle path.") - } - let bundleURL = URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true) - guard let executable = Bundle(url: bundleURL)?.executableURL else { - throw failure("The App Bundle has no executable.") - } - let process = Process() - process.executableURL = executable - try process.run() - defer { - if process.isRunning { - process.terminate() - } - process.waitUntilExit() - } + static func verifyWindow() throws { + guard CommandLine.arguments.count == 2 else { + throw failure("Expected the App Bundle path.") + } + let bundleURL = URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true) + guard let executable = Bundle(url: bundleURL)?.executableURL else { + throw failure("The App Bundle has no executable.") + } + let process = Process() + process.executableURL = executable + try process.run() + defer { + if process.isRunning { + process.terminate() + } + process.waitUntilExit() + } - let deadline = Date().addingTimeInterval(10) - var foundWindow = false - while Date() < deadline { - guard process.isRunning else { - throw failure("The app exited before its window appeared (status \(process.terminationStatus)).") - } - let windows = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] ?? [] - foundWindow = windows.contains { window in - guard (window[kCGWindowOwnerPID as String] as? Int32) == process.processIdentifier, - (window[kCGWindowLayer as String] as? Int) == 0, - let bounds = window[kCGWindowBounds as String] as? [String: Any], - let width = bounds["Width"] as? Double, - let height = bounds["Height"] as? Double else { - return false - } - return width >= 600 && height >= 400 - } - if foundWindow { - break - } - Thread.sleep(forTimeInterval: 0.1) - } - guard foundWindow else { - throw failure("No visible app window appeared. Run this test from a logged-in macOS GUI session.") - } - Thread.sleep(forTimeInterval: 2) - guard process.isRunning else { - throw failure("The app exited after showing its window.") + let deadline = Date().addingTimeInterval(10) + var foundWindow = false + while Date() < deadline { + guard process.isRunning else { + throw failure( + "The app exited before its window appeared (status \(process.terminationStatus)).") + } + let windows = + CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) + as? [[String: Any]] ?? [] + foundWindow = windows.contains { window in + guard (window[kCGWindowOwnerPID as String] as? Int32) == process.processIdentifier, + (window[kCGWindowLayer as String] as? Int) == 0, + let bounds = window[kCGWindowBounds as String] as? [String: Any], + let width = bounds["Width"] as? Double, + let height = bounds["Height"] as? Double + else { + return false } - print("PASS: SimStore launched with a visible window and remained alive (PID \(process.processIdentifier)).") + return width >= 600 && height >= 400 + } + if foundWindow { + break + } + Thread.sleep(forTimeInterval: 0.1) } - - static func failure(_ message: String) -> NSError { - NSError(domain: "SimStoreSmokeTest", code: 1, userInfo: [NSLocalizedDescriptionKey: message]) + guard foundWindow else { + throw failure( + "No visible app window appeared. Run this test from a logged-in macOS GUI session.") + } + Thread.sleep(forTimeInterval: 2) + guard process.isRunning else { + throw failure("The app exited after showing its window.") } + print( + "PASS: SimStore launched with a visible window and remained alive (PID \(process.processIdentifier))." + ) + } + + static func failure(_ message: String) -> NSError { + NSError(domain: "SimStoreSmokeTest", code: 1, userInfo: [NSLocalizedDescriptionKey: message]) + } }