fix(macos): clean swiftformat pass and sendable warning

This commit is contained in:
Peter Steinberger
2026-03-08 13:22:46 +00:00
parent eb0758e172
commit 53fb317e7f
129 changed files with 505 additions and 512 deletions

View File

@@ -6,14 +6,14 @@ import OpenClawKit
import OSLog
actor CameraCaptureService {
struct CameraDeviceInfo: Encodable, Sendable {
struct CameraDeviceInfo: Encodable {
let id: String
let name: String
let position: String
let deviceType: String
}
enum CameraError: LocalizedError, Sendable {
enum CameraError: LocalizedError {
case cameraUnavailable
case microphoneUnavailable
case permissionDenied(kind: String)

View File

@@ -2,7 +2,7 @@ import Foundation
import OpenClawProtocol
enum ConfigStore {
struct Overrides: Sendable {
struct Overrides {
var isRemoteMode: (@Sendable () async -> Bool)?
var loadLocal: (@MainActor @Sendable () -> [String: Any])?
var saveLocal: (@MainActor @Sendable ([String: Any]) -> Void)?

View File

@@ -1,13 +1,13 @@
import Foundation
enum EffectiveConnectionModeSource: Sendable, Equatable {
enum EffectiveConnectionModeSource: Equatable {
case configMode
case configRemoteURL
case userDefaults
case onboarding
}
struct EffectiveConnectionMode: Sendable, Equatable {
struct EffectiveConnectionMode: Equatable {
let mode: AppState.ConnectionMode
let source: EffectiveConnectionModeSource
}

View File

@@ -14,7 +14,7 @@ struct ControlHeartbeatEvent: Codable {
let reason: String?
}
struct ControlAgentEvent: Codable, Sendable, Identifiable {
struct ControlAgentEvent: Codable, Identifiable {
var id: String {
"\(self.runId)-\(self.seq)"
}

View File

@@ -226,7 +226,7 @@ struct CronJob: Identifiable, Codable, Equatable {
}
}
struct CronEvent: Codable, Sendable {
struct CronEvent: Codable {
let jobId: String
let action: String
let runAtMs: Int?
@@ -237,7 +237,7 @@ struct CronEvent: Codable, Sendable {
let nextRunAtMs: Int?
}
struct CronRunLogEntry: Codable, Identifiable, Sendable {
struct CronRunLogEntry: Codable, Identifiable {
var id: String {
"\(self.jobId)-\(self.ts)"
}

View File

@@ -1,6 +1,6 @@
import Foundation
struct DevicePresentation: Sendable {
struct DevicePresentation {
let title: String
let symbol: String?
}

View File

@@ -7,7 +7,7 @@ actor DiagnosticsFileLog {
private let maxBytes: Int64 = 5 * 1024 * 1024
private let maxBackups = 5
struct Record: Codable, Sendable {
struct Record: Codable {
let ts: String
let pid: Int32
let category: String

View File

@@ -84,13 +84,13 @@ enum ExecAsk: String, CaseIterable, Codable, Identifiable {
}
}
enum ExecApprovalDecision: String, Codable, Sendable {
enum ExecApprovalDecision: String, Codable {
case allowOnce = "allow-once"
case allowAlways = "allow-always"
case deny
}
enum ExecAllowlistPatternValidationReason: String, Codable, Sendable, Equatable {
enum ExecAllowlistPatternValidationReason: String, Codable, Equatable {
case empty
case missingPathComponent
@@ -104,12 +104,12 @@ enum ExecAllowlistPatternValidationReason: String, Codable, Sendable, Equatable
}
}
enum ExecAllowlistPatternValidation: Sendable, Equatable {
enum ExecAllowlistPatternValidation: Equatable {
case valid(String)
case invalid(ExecAllowlistPatternValidationReason)
}
struct ExecAllowlistRejectedEntry: Sendable, Equatable {
struct ExecAllowlistRejectedEntry: Equatable {
let id: UUID
let pattern: String
let reason: ExecAllowlistPatternValidationReason
@@ -753,7 +753,7 @@ enum ExecApprovalHelpers {
}
}
struct ExecEventPayload: Codable, Sendable {
struct ExecEventPayload: Codable {
var sessionKey: String
var runId: String
var host: String

View File

@@ -11,7 +11,7 @@ final class ExecApprovalsGatewayPrompter {
private let logger = Logger(subsystem: "ai.openclaw", category: "exec-approvals.gateway")
private var task: Task<Void, Never>?
struct GatewayApprovalRequest: Codable, Sendable {
struct GatewayApprovalRequest: Codable {
var id: String
var request: ExecApprovalPromptRequest
var createdAtMs: Int

View File

@@ -5,7 +5,7 @@ import Foundation
import OpenClawKit
import OSLog
struct ExecApprovalPromptRequest: Codable, Sendable {
struct ExecApprovalPromptRequest: Codable {
var command: String
var cwd: String?
var host: String?

View File

@@ -1,6 +1,6 @@
import Foundation
struct ExecCommandResolution: Sendable {
struct ExecCommandResolution {
let rawExecutable: String
let resolvedPath: String?
let executableName: String

View File

@@ -6,7 +6,7 @@ import OSLog
private let gatewayConnectionLogger = Logger(subsystem: "ai.openclaw", category: "gateway.connection")
enum GatewayAgentChannel: String, Codable, CaseIterable, Sendable {
enum GatewayAgentChannel: String, Codable, CaseIterable {
case last
case whatsapp
case telegram
@@ -33,7 +33,7 @@ enum GatewayAgentChannel: String, Codable, CaseIterable, Sendable {
}
}
struct GatewayAgentInvocation: Sendable {
struct GatewayAgentInvocation {
var message: String
var sessionKey: String = "main"
var thinking: String?
@@ -53,7 +53,7 @@ actor GatewayConnection {
typealias Config = (url: URL, token: String?, password: String?)
enum Method: String, Sendable {
enum Method: String {
case agent
case status
case setHeartbeats = "set-heartbeats"
@@ -428,9 +428,9 @@ actor GatewayConnection {
// MARK: - Typed gateway API
extension GatewayConnection {
struct ConfigGetSnapshot: Decodable, Sendable {
struct SnapshotConfig: Decodable, Sendable {
struct Session: Decodable, Sendable {
struct ConfigGetSnapshot: Decodable {
struct SnapshotConfig: Decodable {
struct Session: Decodable {
let mainKey: String?
let scope: String?
}
@@ -729,7 +729,7 @@ extension GatewayConnection {
// MARK: - Cron
struct CronSchedulerStatus: Decodable, Sendable {
struct CronSchedulerStatus: Decodable {
let enabled: Bool
let storePath: String
let jobs: Int

View File

@@ -2,7 +2,7 @@ import ConcurrencyExtras
import Foundation
import OSLog
enum GatewayEndpointState: Sendable, Equatable {
enum GatewayEndpointState: Equatable {
case ready(mode: AppState.ConnectionMode, url: URL, token: String?, password: String?)
case connecting(mode: AppState.ConnectionMode, detail: String)
case unavailable(mode: AppState.ConnectionMode, reason: String)
@@ -24,14 +24,14 @@ actor GatewayEndpointStore {
]
private static let remoteConnectingDetail = "Connecting to remote gateway…"
private static let staticLogger = Logger(subsystem: "ai.openclaw", category: "gateway-endpoint")
private enum EnvOverrideWarningKind: Sendable {
private enum EnvOverrideWarningKind {
case token
case password
}
private static let envOverrideWarnings = LockIsolated((token: false, password: false))
struct Deps: Sendable {
struct Deps {
let mode: @Sendable () async -> AppState.ConnectionMode
let token: @Sendable () -> String?
let password: @Sendable () -> String?

View File

@@ -3,7 +3,7 @@ import OpenClawIPC
import OSLog
/// Lightweight SemVer helper (major.minor.patch only) for gateway compatibility checks.
struct Semver: Comparable, CustomStringConvertible, Sendable {
struct Semver: Comparable, CustomStringConvertible {
let major: Int
let minor: Int
let patch: Int

View File

@@ -3,14 +3,14 @@ import Network
import Observation
import SwiftUI
struct HealthSnapshot: Codable, Sendable {
struct ChannelSummary: Codable, Sendable {
struct Probe: Codable, Sendable {
struct Bot: Codable, Sendable {
struct HealthSnapshot: Codable {
struct ChannelSummary: Codable {
struct Probe: Codable {
struct Bot: Codable {
let username: String?
}
struct Webhook: Codable, Sendable {
struct Webhook: Codable {
let url: String?
}
@@ -29,13 +29,13 @@ struct HealthSnapshot: Codable, Sendable {
let lastProbeAt: Double?
}
struct SessionInfo: Codable, Sendable {
struct SessionInfo: Codable {
let key: String
let updatedAt: Double?
let age: Double?
}
struct Sessions: Codable, Sendable {
struct Sessions: Codable {
let path: String
let count: Int
let recent: [SessionInfo]

View File

@@ -22,7 +22,7 @@ enum HostEnvSecurityPolicy {
"PS4",
"GCONV_PATH",
"IFS",
"SSLKEYLOGFILE"
"SSLKEYLOGFILE",
]
static let blockedOverrideKeys: Set<String> = [
@@ -50,17 +50,17 @@ enum HostEnvSecurityPolicy {
"OPENSSL_ENGINES",
"PYTHONSTARTUP",
"WGETRC",
"CURL_HOME"
"CURL_HOME",
]
static let blockedOverridePrefixes: [String] = [
"GIT_CONFIG_",
"NPM_CONFIG_"
"NPM_CONFIG_",
]
static let blockedPrefixes: [String] = [
"DYLD_",
"LD_",
"BASH_FUNC_"
"BASH_FUNC_",
]
}

View File

@@ -1,7 +1,7 @@
import Foundation
enum Launchctl {
struct Result: Sendable {
struct Result {
let status: Int32
let output: String
}
@@ -26,7 +26,7 @@ enum Launchctl {
}
}
struct LaunchAgentPlistSnapshot: Equatable, Sendable {
struct LaunchAgentPlistSnapshot: Equatable {
let programArguments: [String]
let environment: [String: String]
let stdoutPath: String?

View File

@@ -122,7 +122,7 @@ actor MacNodeBrowserProxy {
}
}
let profile = params.profile?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
if !profile.isEmpty && !queryItems.contains(where: { $0.name == "profile" }) {
if !profile.isEmpty, !queryItems.contains(where: { $0.name == "profile" }) {
queryItems.append(URLQueryItem(name: "profile", value: profile))
}
if !queryItems.isEmpty {
@@ -172,7 +172,7 @@ actor MacNodeBrowserProxy {
}
if let text = String(data: data, encoding: .utf8)?
.trimmingCharacters(in: .whitespacesAndNewlines),
!text.isEmpty
!text.isEmpty
{
return text
}

View File

@@ -1,10 +1,10 @@
import Foundation
enum MacNodeScreenCommand: String, Codable, Sendable {
enum MacNodeScreenCommand: String, Codable {
case record = "screen.record"
}
struct MacNodeScreenRecordParams: Codable, Sendable, Equatable {
struct MacNodeScreenRecordParams: Codable, Equatable {
var screenIndex: Int?
var durationMs: Int?
var fps: Double?

View File

@@ -87,7 +87,7 @@ enum OverlayPanelFactory {
offsetX: CGFloat = 6,
offsetY: CGFloat = 6,
duration: TimeInterval = 0.16,
completion: @escaping () -> Void)
completion: @escaping @MainActor @Sendable () -> Void)
{
let target = window.frame.offsetBy(dx: offsetX, dy: offsetY)
NSAnimationContext.runAnimationGroup { context in
@@ -96,7 +96,7 @@ enum OverlayPanelFactory {
window.animator().setFrame(target, display: true)
window.animator().alphaValue = 0
} completionHandler: {
completion()
Task { @MainActor in completion() }
}
}
@@ -109,10 +109,8 @@ enum OverlayPanelFactory {
onHidden: @escaping @MainActor () -> Void)
{
self.animateDismiss(window: window, offsetX: offsetX, offsetY: offsetY, duration: duration) {
Task { @MainActor in
window.orderOut(nil)
onHidden()
}
window.orderOut(nil)
onHidden()
}
}

View File

@@ -56,7 +56,7 @@ final class PeekabooBridgeHostCoordinator {
private func startIfNeeded() async {
guard self.host == nil else { return }
var allowlistedTeamIDs: Set<String> = ["Y5PE65HELJ"]
var allowlistedTeamIDs: Set = ["Y5PE65HELJ"]
if let teamID = Self.currentTeamID() {
allowlistedTeamIDs.insert(teamID)
}

View File

@@ -15,7 +15,7 @@ actor PortGuardian {
let timestamp: TimeInterval
}
struct Descriptor: Sendable {
struct Descriptor {
let pid: Int32
let command: String
let executablePath: String?

View File

@@ -4,13 +4,13 @@ import OpenClawProtocol
import OSLog
import SwiftUI
struct SessionPreviewItem: Identifiable, Sendable {
struct SessionPreviewItem: Identifiable {
let id: String
let role: PreviewRole
let text: String
}
enum PreviewRole: String, Sendable {
enum PreviewRole: String {
case user
case assistant
case tool
@@ -114,7 +114,7 @@ extension SessionPreviewCache {
}
#endif
struct SessionMenuPreviewSnapshot: Sendable {
struct SessionMenuPreviewSnapshot {
let items: [SessionPreviewItem]
let status: SessionMenuPreviewView.LoadStatus
}

View File

@@ -152,7 +152,7 @@ final class TalkAudioPlayer: NSObject, @preconcurrency AVAudioPlayerDelegate {
}
}
struct TalkPlaybackResult: Sendable {
struct TalkPlaybackResult {
let finished: Bool
let interruptedAt: Double?
}

View File

@@ -2,7 +2,7 @@ import AppKit
import Foundation
import OSLog
enum VoiceWakeChime: Codable, Equatable, Sendable {
enum VoiceWakeChime: Codable, Equatable {
case none
case system(name: String)
case custom(displayName: String, bookmark: Data)

View File

@@ -32,7 +32,7 @@ enum VoiceWakeForwarder {
}
}
struct ForwardOptions: Sendable {
struct ForwardOptions {
var sessionKey: String = "main"
var thinking: String = "low"
var deliver: Bool = true

View File

@@ -16,7 +16,7 @@ private enum WebChatSwiftUILayout {
static let anchorPadding: CGFloat = 8
}
struct MacGatewayChatTransport: OpenClawChatTransport, Sendable {
struct MacGatewayChatTransport: OpenClawChatTransport {
func requestHistory(sessionKey: String) async throws -> OpenClawChatHistoryPayload {
try await GatewayConnection.shared.chatHistory(sessionKey: sessionKey)
}

View File

@@ -374,9 +374,9 @@ public final class GatewayDiscoveryModel {
if let host = gateway.serviceHost?
.trimmingCharacters(in: .whitespacesAndNewlines)
.lowercased(),
!host.isEmpty,
let port = gateway.servicePort,
port > 0
!host.isEmpty,
let port = gateway.servicePort,
port > 0
{
return "endpoint|\(host):\(port)"
}
@@ -674,7 +674,7 @@ public final class GatewayDiscoveryModel {
}
}
struct ResolvedGatewayService: Equatable, Sendable {
struct ResolvedGatewayService: Equatable {
var txt: [String: String]
var host: String?
var port: Int?

View File

@@ -1,7 +1,7 @@
import Foundation
import OpenClawKit
struct TailscaleServeGatewayBeacon: Sendable, Equatable {
struct TailscaleServeGatewayBeacon: Equatable {
var displayName: String
var tailnetDns: String
var host: String
@@ -13,7 +13,7 @@ enum TailscaleServeGatewayDiscovery {
private static let probeConcurrency = 6
private static let defaultProbeTimeoutSeconds: TimeInterval = 1.6
struct DiscoveryContext: Sendable {
struct DiscoveryContext {
var tailscaleStatus: @Sendable () async -> String?
var probeHost: @Sendable (_ host: String, _ timeout: TimeInterval) async -> Bool
@@ -85,13 +85,13 @@ enum TailscaleServeGatewayDiscovery {
}
}
private struct Candidate: Sendable {
private struct Candidate {
var dnsName: String
var displayName: String
}
private static func collectCandidates(status: TailscaleStatus) -> [Candidate] {
let selfDns = normalizeDnsName(status.selfNode?.dnsName)
let selfDns = self.normalizeDnsName(status.selfNode?.dnsName)
var out: [Candidate] = []
var seen = Set<String>()
@@ -112,7 +112,7 @@ enum TailscaleServeGatewayDiscovery {
out.append(Candidate(
dnsName: dnsName,
displayName: displayName(hostName: node.hostName, dnsName: dnsName)))
displayName: self.displayName(hostName: node.hostName, dnsName: dnsName)))
if out.count >= self.maxCandidates {
break
@@ -257,7 +257,7 @@ enum TailscaleServeGatewayDiscovery {
operation: {
while true {
let message = try await task.receive()
if isConnectChallenge(message: message) {
if self.isConnectChallenge(message: message) {
return true
}
}

View File

@@ -1,7 +1,7 @@
import Foundation
import OpenClawKit
struct WideAreaGatewayBeacon: Sendable, Equatable {
struct WideAreaGatewayBeacon: Equatable {
var instanceName: String
var displayName: String
var host: String
@@ -19,7 +19,7 @@ enum WideAreaGatewayDiscovery {
private static let defaultTimeoutSeconds: TimeInterval = 0.2
private static let nameserverProbeConcurrency = 6
struct DiscoveryContext: Sendable {
struct DiscoveryContext {
var tailscaleStatus: @Sendable () -> String?
var dig: @Sendable (_ args: [String], _ timeout: TimeInterval) -> String?

View File

@@ -3,11 +3,10 @@ import OpenClawProtocol
import Testing
@testable import OpenClaw
@Suite
@MainActor
struct AgentEventStoreTests {
@Test
func appendAndClear() {
func `append and clear`() {
let store = AgentEventStore()
#expect(store.events.isEmpty)
@@ -25,7 +24,7 @@ struct AgentEventStoreTests {
}
@Test
func trimsToMaxEvents() {
func `trims to max events`() {
let store = AgentEventStore()
for i in 1...401 {
store.append(ControlAgentEvent(

View File

@@ -2,10 +2,9 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite
struct AgentWorkspaceTests {
@Test
func displayPathUsesTildeForHome() {
func `display path uses tilde for home`() {
let home = FileManager().homeDirectoryForCurrentUser
#expect(AgentWorkspace.displayPath(for: home) == "~")
@@ -14,20 +13,20 @@ struct AgentWorkspaceTests {
}
@Test
func resolveWorkspaceURLExpandsTilde() {
func `resolve workspace URL expands tilde`() {
let url = AgentWorkspace.resolveWorkspaceURL(from: "~/tmp")
#expect(url.path.hasSuffix("/tmp"))
}
@Test
func agentsURLAppendsFilename() {
func `agents URL appends filename`() {
let root = URL(fileURLWithPath: "/tmp/ws", isDirectory: true)
let url = AgentWorkspace.agentsURL(workspaceURL: root)
#expect(url.lastPathComponent == AgentWorkspace.agentsFilename)
}
@Test
func bootstrapCreatesAgentsFileWhenMissing() throws {
func `bootstrap creates agents file when missing`() throws {
let tmp = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-ws-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: tmp) }
@@ -50,7 +49,7 @@ struct AgentWorkspaceTests {
}
@Test
func bootstrapSafetyRejectsNonEmptyFolderWithoutAgents() throws {
func `bootstrap safety rejects non empty folder without agents`() throws {
let tmp = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-ws-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: tmp) }
@@ -63,7 +62,7 @@ struct AgentWorkspaceTests {
}
@Test
func bootstrapSafetyAllowsExistingAgentsFile() throws {
func `bootstrap safety allows existing agents file`() throws {
let tmp = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-ws-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: tmp) }
@@ -76,7 +75,7 @@ struct AgentWorkspaceTests {
}
@Test
func bootstrapSkipsBootstrapFileWhenWorkspaceHasContent() throws {
func `bootstrap skips bootstrap file when workspace has content`() throws {
let tmp = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-ws-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: tmp) }
@@ -91,7 +90,7 @@ struct AgentWorkspaceTests {
}
@Test
func needsBootstrapFalseWhenIdentityAlreadySet() throws {
func `needs bootstrap false when identity already set`() throws {
let tmp = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-ws-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: tmp) }

View File

@@ -3,8 +3,8 @@ import OpenClawProtocol
import Testing
@testable import OpenClaw
@Suite struct AnyCodableEncodingTests {
@Test func encodesSwiftArrayAndDictionaryValues() throws {
struct AnyCodableEncodingTests {
@Test func `encodes swift array and dictionary values`() throws {
let payload: [String: Any] = [
"tags": ["node", "ios"],
"meta": ["count": 2],
@@ -19,7 +19,7 @@ import Testing
#expect(obj["null"] is NSNull)
}
@Test func protocolAnyCodableEncodesPrimitiveArrays() throws {
@Test func `protocol any codable encodes primitive arrays`() throws {
let payload: [String: Any] = [
"items": [1, "two", NSNull(), ["ok": true]],
]

View File

@@ -2,15 +2,15 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct AudioInputDeviceObserverTests {
@Test func hasUsableDefaultInputDeviceReturnsBool() {
struct AudioInputDeviceObserverTests {
@Test func `has usable default input device returns bool`() {
// Smoke test: verifies the composition logic runs without crashing.
// Actual result depends on whether the host has an audio input device.
let result = AudioInputDeviceObserver.hasUsableDefaultInputDevice()
_ = result // suppress unused-variable warning; the assertion is "no crash"
}
@Test func hasUsableDefaultInputDeviceConsistentWithComponents() {
@Test func `has usable default input device consistent with components`() {
// When no default UID exists, the method must return false.
// When a default UID exists, the result must match alive-set membership.
let uid = AudioInputDeviceObserver.defaultInputDeviceUID()

View File

@@ -5,7 +5,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct CLIInstallerTests {
@Test func installedLocationFindsExecutable() throws {
@Test func `installed location finds executable`() throws {
let fm = FileManager()
let root = fm.temporaryDirectory.appendingPathComponent(
"openclaw-cli-installer-\(UUID().uuidString)")

View File

@@ -1,14 +1,14 @@
import Testing
@testable import OpenClaw
@Suite struct CameraCaptureServiceTests {
@Test func normalizeSnapDefaults() {
struct CameraCaptureServiceTests {
@Test func `normalize snap defaults`() {
let res = CameraCaptureService.normalizeSnap(maxWidth: nil, quality: nil)
#expect(res.maxWidth == 1600)
#expect(res.quality == 0.9)
}
@Test func normalizeSnapClampsValues() {
@Test func `normalize snap clamps values`() {
let low = CameraCaptureService.normalizeSnap(maxWidth: -1, quality: -10)
#expect(low.maxWidth == 1600)
#expect(low.quality == 0.05)

View File

@@ -2,8 +2,8 @@ import Foundation
import OpenClawIPC
import Testing
@Suite struct CameraIPCTests {
@Test func cameraSnapCodableRoundtrip() throws {
struct CameraIPCTests {
@Test func `camera snap codable roundtrip`() throws {
let req: Request = .cameraSnap(
facing: .front,
maxWidth: 640,
@@ -24,7 +24,7 @@ import Testing
}
}
@Test func cameraClipCodableRoundtrip() throws {
@Test func `camera clip codable roundtrip`() throws {
let req: Request = .cameraClip(
facing: .back,
durationMs: 3000,
@@ -45,7 +45,7 @@ import Testing
}
}
@Test func cameraClipDefaultsIncludeAudioToTrueWhenMissing() throws {
@Test func `camera clip defaults include audio to true when missing`() throws {
let json = """
{"type":"cameraClip","durationMs":1234}
"""

View File

@@ -11,7 +11,7 @@ import Testing
return dir
}
@Test func detectsInPlaceFileWrites() async throws {
@Test func `detects in place file writes`() async throws {
let dir = try self.makeTempDir()
defer { try? FileManager().removeItem(at: dir) }

View File

@@ -2,8 +2,8 @@ import Foundation
import OpenClawIPC
import Testing
@Suite struct CanvasIPCTests {
@Test func canvasPresentCodableRoundtrip() throws {
struct CanvasIPCTests {
@Test func `canvas present codable roundtrip`() throws {
let placement = CanvasPlacement(x: 10, y: 20, width: 640, height: 480)
let req: Request = .canvasPresent(session: "main", path: "/index.html", placement: placement)
@@ -23,7 +23,7 @@ import Testing
}
}
@Test func canvasPresentDecodesNilPlacementWhenMissing() throws {
@Test func `canvas present decodes nil placement when missing`() throws {
let json = """
{"type":"canvasPresent","session":"s","path":"/"}
"""

View File

@@ -7,7 +7,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct CanvasWindowSmokeTests {
@Test func panelControllerShowsAndHides() async throws {
@Test func `panel controller shows and hides`() async throws {
let root = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-canvas-test-\(UUID().uuidString)")
try FileManager().createDirectory(at: root, withIntermediateDirectories: true)
@@ -30,7 +30,7 @@ struct CanvasWindowSmokeTests {
controller.close()
}
@Test func windowControllerShowsAndCloses() throws {
@Test func `window controller shows and closes`() throws {
let root = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-canvas-test-\(UUID().uuidString)")
try FileManager().createDirectory(at: root, withIntermediateDirectories: true)

View File

@@ -41,7 +41,7 @@ private func makeChannelsStore(
@Suite(.serialized)
@MainActor
struct ChannelsSettingsSmokeTests {
@Test func channelsSettingsBuildsBodyWithSnapshot() {
@Test func `channels settings builds body with snapshot`() {
let store = makeChannelsStore(
channels: [
"whatsapp": SnapshotAnyCodable([
@@ -108,7 +108,7 @@ struct ChannelsSettingsSmokeTests {
_ = view.body
}
@Test func channelsSettingsBuildsBodyWithoutSnapshot() {
@Test func `channels settings builds body without snapshot`() {
let store = makeChannelsStore(
channels: [
"whatsapp": SnapshotAnyCodable([

View File

@@ -23,7 +23,7 @@ import Testing
return (tmp, pnpmPath)
}
@Test func prefersOpenClawBinary() throws {
@Test func `prefers open claw binary`() throws {
let defaults = self.makeLocalDefaults()
let tmp = try makeTempDirForTests()
@@ -36,7 +36,7 @@ import Testing
#expect(cmd.prefix(2).elementsEqual([openclawPath.path, "gateway"]))
}
@Test func fallsBackToNodeAndScript() throws {
@Test func `falls back to node and script`() throws {
let defaults = self.makeLocalDefaults()
let tmp = try makeTempDirForTests()
@@ -63,7 +63,7 @@ import Testing
}
}
@Test func prefersOpenClawBinaryOverPnpm() throws {
@Test func `prefers open claw binary over pnpm`() throws {
let defaults = self.makeLocalDefaults()
let tmp = try makeTempDirForTests()
@@ -84,7 +84,7 @@ import Testing
#expect(cmd.prefix(2).elementsEqual([openclawPath.path, "rpc"]))
}
@Test func usesOpenClawBinaryWithoutNodeRuntime() throws {
@Test func `uses open claw binary without node runtime`() throws {
let defaults = self.makeLocalDefaults()
let tmp = try makeTempDirForTests()
@@ -103,7 +103,7 @@ import Testing
#expect(cmd.prefix(2).elementsEqual([openclawPath.path, "gateway"]))
}
@Test func fallsBackToPnpm() throws {
@Test func `falls back to pnpm`() throws {
let defaults = self.makeLocalDefaults()
let (tmp, pnpmPath) = try self.makeProjectRootWithPnpm()
@@ -116,7 +116,7 @@ import Testing
#expect(cmd.prefix(4).elementsEqual([pnpmPath.path, "--silent", "openclaw", "rpc"]))
}
@Test func pnpmKeepsExtraArgsAfterSubcommand() throws {
@Test func `pnpm keeps extra args after subcommand`() throws {
let defaults = self.makeLocalDefaults()
let (tmp, pnpmPath) = try self.makeProjectRootWithPnpm()
@@ -131,7 +131,7 @@ import Testing
#expect(cmd.suffix(2).elementsEqual(["--timeout", "5"]))
}
@Test func preferredPathsStartWithProjectNodeBins() throws {
@Test func `preferred paths start with project node bins`() throws {
let tmp = try makeTempDirForTests()
CommandResolver.setProjectRoot(tmp.path)
@@ -139,7 +139,7 @@ import Testing
#expect(first == tmp.appendingPathComponent("node_modules/.bin").path)
}
@Test func buildsSSHCommandForRemoteMode() {
@Test func `builds SSH command for remote mode`() {
let defaults = self.makeDefaults()
defaults.set(AppState.ConnectionMode.remote.rawValue, forKey: connectionModeKey)
defaults.set("openclaw@example.com:2222", forKey: remoteTargetKey)
@@ -170,13 +170,13 @@ import Testing
}
}
@Test func rejectsUnsafeSSHTargets() {
@Test func `rejects unsafe SSH targets`() {
#expect(CommandResolver.parseSSHTarget("-oProxyCommand=calc") == nil)
#expect(CommandResolver.parseSSHTarget("host:-oProxyCommand=calc") == nil)
#expect(CommandResolver.parseSSHTarget("user@host:2222")?.port == 2222)
}
@Test func configRootLocalOverridesRemoteDefaults() throws {
@Test func `config root local overrides remote defaults`() throws {
let defaults = self.makeDefaults()
defaults.set(AppState.ConnectionMode.remote.rawValue, forKey: connectionModeKey)
defaults.set("openclaw@example.com:2222", forKey: remoteTargetKey)

View File

@@ -4,7 +4,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct ConfigStoreTests {
@Test func loadUsesRemoteInRemoteMode() async {
@Test func `load uses remote in remote mode`() async {
var localHit = false
var remoteHit = false
await ConfigStore._testSetOverrides(.init(
@@ -20,7 +20,7 @@ struct ConfigStoreTests {
#expect(result["remote"] as? Bool == true)
}
@Test func loadUsesLocalInLocalMode() async {
@Test func `load uses local in local mode`() async {
var localHit = false
var remoteHit = false
await ConfigStore._testSetOverrides(.init(
@@ -36,7 +36,7 @@ struct ConfigStoreTests {
#expect(result["local"] as? Bool == true)
}
@Test func saveRoutesToRemoteInRemoteMode() async throws {
@Test func `save routes to remote in remote mode`() async throws {
var localHit = false
var remoteHit = false
await ConfigStore._testSetOverrides(.init(
@@ -51,7 +51,7 @@ struct ConfigStoreTests {
#expect(!localHit)
}
@Test func saveRoutesToLocalInLocalMode() async throws {
@Test func `save routes to local in local mode`() async throws {
var localHit = false
var remoteHit = false
await ConfigStore._testSetOverrides(.init(

View File

@@ -4,7 +4,7 @@ import Testing
@Suite(.serialized)
struct CoverageDumpTests {
@Test func periodicallyFlushCoverage() async {
@Test func `periodically flush coverage`() async {
guard ProcessInfo.processInfo.environment["LLVM_PROFILE_FILE"] != nil else { return }
guard let writeProfile = resolveProfileWriteFile() else { return }
let deadline = Date().addingTimeInterval(4)

View File

@@ -2,10 +2,9 @@ import AppKit
import Testing
@testable import OpenClaw
@Suite
@MainActor
struct CritterIconRendererTests {
@Test func makeIconRendersExpectedSize() {
@Test func `make icon renders expected size`() {
let image = CritterIconRenderer.makeIcon(
blink: 0.25,
legWiggle: 0.5,
@@ -19,7 +18,7 @@ struct CritterIconRendererTests {
#expect(image.tiffRepresentation != nil)
}
@Test func makeIconRendersWithBadge() {
@Test func `make icon renders with badge`() {
let image = CritterIconRenderer.makeIcon(
blink: 0,
legWiggle: 0,
@@ -31,7 +30,7 @@ struct CritterIconRendererTests {
#expect(image.tiffRepresentation != nil)
}
@Test func critterStatusLabelExercisesHelpers() async {
@Test func `critter status label exercises helpers`() async {
await CritterStatusLabel.exerciseForTesting()
}
}

View File

@@ -15,17 +15,17 @@ struct CronJobEditorSmokeTests {
onSave: { _ in })
}
@Test func statusPillBuildsBody() {
@Test func `status pill builds body`() {
_ = StatusPill(text: "ok", tint: .green).body
_ = StatusPill(text: "disabled", tint: .secondary).body
}
@Test func cronJobEditorBuildsBodyForNewJob() {
@Test func `cron job editor builds body for new job`() {
let view = self.makeEditor()
_ = view.body
}
@Test func cronJobEditorBuildsBodyForExistingJob() {
@Test func `cron job editor builds body for existing job`() {
let channelsStore = ChannelsStore(isPreview: true)
let job = CronJob(
id: "job-1",
@@ -60,12 +60,12 @@ struct CronJobEditorSmokeTests {
_ = view.body
}
@Test func cronJobEditorExercisesBuilders() {
@Test func `cron job editor exercises builders`() {
var view = self.makeEditor()
view.exerciseForTesting()
}
@Test func cronJobEditorIncludesDeleteAfterRunForAtSchedule() {
@Test func `cron job editor includes delete after run for at schedule`() {
let view = self.makeEditor()
var root: [String: Any] = [:]

View File

@@ -2,7 +2,6 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite
struct CronModelsTests {
private func makeCronJob(
name: String,
@@ -26,14 +25,14 @@ struct CronModelsTests {
state: state)
}
@Test func scheduleAtEncodesAndDecodes() throws {
@Test func `schedule at encodes and decodes`() throws {
let schedule = CronSchedule.at(at: "2026-02-03T18:00:00Z")
let data = try JSONEncoder().encode(schedule)
let decoded = try JSONDecoder().decode(CronSchedule.self, from: data)
#expect(decoded == schedule)
}
@Test func scheduleAtDecodesLegacyAtMs() throws {
@Test func `schedule at decodes legacy at ms`() throws {
let json = """
{"kind":"at","atMs":1700000000000}
"""
@@ -45,21 +44,21 @@ struct CronModelsTests {
}
}
@Test func scheduleEveryEncodesAndDecodesWithAnchor() throws {
@Test func `schedule every encodes and decodes with anchor`() throws {
let schedule = CronSchedule.every(everyMs: 5000, anchorMs: 10000)
let data = try JSONEncoder().encode(schedule)
let decoded = try JSONDecoder().decode(CronSchedule.self, from: data)
#expect(decoded == schedule)
}
@Test func scheduleCronEncodesAndDecodesWithTimezone() throws {
@Test func `schedule cron encodes and decodes with timezone`() throws {
let schedule = CronSchedule.cron(expr: "*/5 * * * *", tz: "Europe/Vienna")
let data = try JSONEncoder().encode(schedule)
let decoded = try JSONDecoder().decode(CronSchedule.self, from: data)
#expect(decoded == schedule)
}
@Test func payloadAgentTurnEncodesAndDecodes() throws {
@Test func `payload agent turn encodes and decodes`() throws {
let payload = CronPayload.agentTurn(
message: "hello",
thinking: "low",
@@ -73,7 +72,7 @@ struct CronModelsTests {
#expect(decoded == payload)
}
@Test func jobEncodesAndDecodesDeleteAfterRun() throws {
@Test func `job encodes and decodes delete after run`() throws {
let job = CronJob(
id: "job-1",
agentId: nil,
@@ -94,7 +93,7 @@ struct CronModelsTests {
#expect(decoded.deleteAfterRun == true)
}
@Test func scheduleDecodeRejectsUnknownKind() {
@Test func `schedule decode rejects unknown kind`() {
let json = """
{"kind":"wat","at":"2026-02-03T18:00:00Z"}
"""
@@ -103,7 +102,7 @@ struct CronModelsTests {
}
}
@Test func payloadDecodeRejectsUnknownKind() {
@Test func `payload decode rejects unknown kind`() {
let json = """
{"kind":"wat","text":"hello"}
"""
@@ -112,8 +111,8 @@ struct CronModelsTests {
}
}
@Test func displayNameTrimsWhitespaceAndFallsBack() {
let base = makeCronJob(name: " hello ", payloadText: "hi")
@Test func `display name trims whitespace and falls back`() {
let base = self.makeCronJob(name: " hello ", payloadText: "hi")
#expect(base.displayName == "hello")
var unnamed = base
@@ -121,8 +120,8 @@ struct CronModelsTests {
#expect(unnamed.displayName == "Untitled job")
}
@Test func nextRunDateAndLastRunDateDeriveFromState() {
let job = makeCronJob(
@Test func `next run date and last run date derive from state`() {
let job = self.makeCronJob(
name: "t",
payloadText: "hi",
state: CronJobState(
@@ -136,7 +135,7 @@ struct CronModelsTests {
#expect(job.lastRunDate == Date(timeIntervalSince1970: 1_700_000_050))
}
@Test func decodeCronListResponseSkipsMalformedJobs() throws {
@Test func `decode cron list response skips malformed jobs`() throws {
let json = """
{
"jobs": [
@@ -177,7 +176,7 @@ struct CronModelsTests {
#expect(jobs.first?.id == "good")
}
@Test func decodeCronRunsResponseSkipsMalformedEntries() throws {
@Test func `decode cron runs response skips malformed entries`() throws {
let json = """
{
"entries": [

View File

@@ -2,8 +2,8 @@ import OpenClawKit
import Testing
@testable import OpenClaw
@Suite struct DeepLinkAgentPolicyTests {
@Test func validateMessageForHandleRejectsTooLongWhenUnkeyed() {
struct DeepLinkAgentPolicyTests {
@Test func `validate message for handle rejects too long when unkeyed`() {
let msg = String(repeating: "a", count: DeepLinkAgentPolicy.maxUnkeyedConfirmChars + 1)
let res = DeepLinkAgentPolicy.validateMessageForHandle(message: msg, allowUnattended: false)
switch res {
@@ -17,7 +17,7 @@ import Testing
}
}
@Test func validateMessageForHandleAllowsTooLongWhenKeyed() {
@Test func `validate message for handle allows too long when keyed`() {
let msg = String(repeating: "a", count: DeepLinkAgentPolicy.maxUnkeyedConfirmChars + 1)
let res = DeepLinkAgentPolicy.validateMessageForHandle(message: msg, allowUnattended: true)
switch res {
@@ -28,7 +28,7 @@ import Testing
}
}
@Test func effectiveDeliveryIgnoresDeliveryFieldsWhenUnkeyed() {
@Test func `effective delivery ignores delivery fields when unkeyed`() {
let link = AgentDeepLink(
message: "Hello",
sessionKey: "s",
@@ -44,7 +44,7 @@ import Testing
#expect(res.channel == .last)
}
@Test func effectiveDeliveryHonorsDeliverForDeliverableChannelsWhenKeyed() {
@Test func `effective delivery honors deliver for deliverable channels when keyed`() {
let link = AgentDeepLink(
message: "Hello",
sessionKey: "s",
@@ -60,7 +60,7 @@ import Testing
#expect(res.channel == .whatsapp)
}
@Test func effectiveDeliveryStillBlocksWebChatDeliveryWhenKeyed() {
@Test func `effective delivery still blocks web chat delivery when keyed`() {
let link = AgentDeepLink(
message: "Hello",
sessionKey: "s",

View File

@@ -1,10 +1,9 @@
import Testing
@testable import OpenClaw
@Suite
struct DeviceModelCatalogTests {
@Test
func symbolPrefersModelIdentifierPrefixes() {
func `symbol prefers model identifier prefixes`() {
#expect(DeviceModelCatalog
.symbol(deviceFamily: "iPad", modelIdentifier: "iPad16,6", friendlyName: nil) == "ipad")
#expect(DeviceModelCatalog
@@ -12,7 +11,7 @@ struct DeviceModelCatalogTests {
}
@Test
func symbolUsesFriendlyNameForMacVariants() {
func `symbol uses friendly name for mac variants`() {
#expect(DeviceModelCatalog.symbol(
deviceFamily: "Mac",
modelIdentifier: "Mac99,1",
@@ -28,13 +27,13 @@ struct DeviceModelCatalogTests {
}
@Test
func symbolFallsBackToDeviceFamily() {
func `symbol falls back to device family`() {
#expect(DeviceModelCatalog.symbol(deviceFamily: "Android", modelIdentifier: "", friendlyName: nil) == "android")
#expect(DeviceModelCatalog.symbol(deviceFamily: "Linux", modelIdentifier: "", friendlyName: nil) == "cpu")
}
@Test
func presentationUsesBundledModelMappings() {
func `presentation uses bundled model mappings`() {
let presentation = DeviceModelCatalog.presentation(deviceFamily: "iPhone", modelIdentifier: "iPhone1,1")
#expect(presentation?.title == "iPhone")
}

View File

@@ -59,21 +59,21 @@ struct ExecAllowlistTests {
cwd: nil)
}
@Test func matchUsesResolvedPath() {
@Test func `match uses resolved path`() {
let entry = ExecAllowlistEntry(pattern: "/opt/homebrew/bin/rg")
let resolution = Self.homebrewRGResolution()
let match = ExecAllowlistMatcher.match(entries: [entry], resolution: resolution)
#expect(match?.pattern == entry.pattern)
}
@Test func matchIgnoresBasenamePattern() {
@Test func `match ignores basename pattern`() {
let entry = ExecAllowlistEntry(pattern: "rg")
let resolution = Self.homebrewRGResolution()
let match = ExecAllowlistMatcher.match(entries: [entry], resolution: resolution)
#expect(match == nil)
}
@Test func matchIgnoresBasenameForRelativeExecutable() {
@Test func `match ignores basename for relative executable`() {
let entry = ExecAllowlistEntry(pattern: "echo")
let resolution = ExecCommandResolution(
rawExecutable: "./echo",
@@ -84,21 +84,21 @@ struct ExecAllowlistTests {
#expect(match == nil)
}
@Test func matchIsCaseInsensitive() {
@Test func `match is case insensitive`() {
let entry = ExecAllowlistEntry(pattern: "/OPT/HOMEBREW/BIN/RG")
let resolution = Self.homebrewRGResolution()
let match = ExecAllowlistMatcher.match(entries: [entry], resolution: resolution)
#expect(match?.pattern == entry.pattern)
}
@Test func matchSupportsGlobStar() {
@Test func `match supports glob star`() {
let entry = ExecAllowlistEntry(pattern: "/opt/**/rg")
let resolution = Self.homebrewRGResolution()
let match = ExecAllowlistMatcher.match(entries: [entry], resolution: resolution)
#expect(match?.pattern == entry.pattern)
}
@Test func resolveForAllowlistSplitsShellChains() {
@Test func `resolve for allowlist splits shell chains`() {
let command = ["/bin/sh", "-lc", "echo allowlisted && /usr/bin/touch /tmp/openclaw-allowlist-test"]
let resolutions = ExecCommandResolution.resolveForAllowlist(
command: command,
@@ -110,7 +110,7 @@ struct ExecAllowlistTests {
#expect(resolutions[1].executableName == "touch")
}
@Test func resolveForAllowlistKeepsQuotedOperatorsInSingleSegment() {
@Test func `resolve for allowlist keeps quoted operators in single segment`() {
let command = ["/bin/sh", "-lc", "echo \"a && b\""]
let resolutions = ExecCommandResolution.resolveForAllowlist(
command: command,
@@ -121,7 +121,7 @@ struct ExecAllowlistTests {
#expect(resolutions[0].executableName == "echo")
}
@Test func resolveForAllowlistFailsClosedOnCommandSubstitution() {
@Test func `resolve for allowlist fails closed on command substitution`() {
let command = ["/bin/sh", "-lc", "echo $(/usr/bin/touch /tmp/openclaw-allowlist-test-subst)"]
let resolutions = ExecCommandResolution.resolveForAllowlist(
command: command,
@@ -131,7 +131,7 @@ struct ExecAllowlistTests {
#expect(resolutions.isEmpty)
}
@Test func resolveForAllowlistFailsClosedOnQuotedCommandSubstitution() {
@Test func `resolve for allowlist fails closed on quoted command substitution`() {
let command = ["/bin/sh", "-lc", "echo \"ok $(/usr/bin/touch /tmp/openclaw-allowlist-test-quoted-subst)\""]
let resolutions = ExecCommandResolution.resolveForAllowlist(
command: command,
@@ -141,7 +141,7 @@ struct ExecAllowlistTests {
#expect(resolutions.isEmpty)
}
@Test func resolveForAllowlistFailsClosedOnQuotedBackticks() {
@Test func `resolve for allowlist fails closed on quoted backticks`() {
let command = ["/bin/sh", "-lc", "echo \"ok `/usr/bin/id`\""]
let resolutions = ExecCommandResolution.resolveForAllowlist(
command: command,
@@ -151,7 +151,7 @@ struct ExecAllowlistTests {
#expect(resolutions.isEmpty)
}
@Test func resolveForAllowlistMatchesSharedShellParserFixture() throws {
@Test func `resolve for allowlist matches shared shell parser fixture`() throws {
let fixtures = try Self.loadShellParserParityCases()
for fixture in fixtures {
let resolutions = ExecCommandResolution.resolveForAllowlist(
@@ -169,7 +169,7 @@ struct ExecAllowlistTests {
}
}
@Test func resolveMatchesSharedWrapperResolutionFixture() throws {
@Test func `resolve matches shared wrapper resolution fixture`() throws {
let fixtures = try Self.loadWrapperResolutionParityCases()
for fixture in fixtures {
let resolution = ExecCommandResolution.resolve(
@@ -180,7 +180,7 @@ struct ExecAllowlistTests {
}
}
@Test func resolveForAllowlistTreatsPlainShInvocationAsDirectExec() {
@Test func `resolve for allowlist treats plain sh invocation as direct exec`() {
let command = ["/bin/sh", "./script.sh"]
let resolutions = ExecCommandResolution.resolveForAllowlist(
command: command,
@@ -191,7 +191,7 @@ struct ExecAllowlistTests {
#expect(resolutions[0].executableName == "sh")
}
@Test func resolveForAllowlistUnwrapsEnvShellWrapperChains() {
@Test func `resolve for allowlist unwraps env shell wrapper chains`() {
let command = [
"/usr/bin/env",
"/bin/sh",
@@ -208,7 +208,7 @@ struct ExecAllowlistTests {
#expect(resolutions[1].executableName == "touch")
}
@Test func resolveForAllowlistUnwrapsEnvToEffectiveDirectExecutable() {
@Test func `resolve for allowlist unwraps env to effective direct executable`() {
let command = ["/usr/bin/env", "FOO=bar", "/usr/bin/printf", "ok"]
let resolutions = ExecCommandResolution.resolveForAllowlist(
command: command,
@@ -220,7 +220,7 @@ struct ExecAllowlistTests {
#expect(resolutions[0].executableName == "printf")
}
@Test func matchAllRequiresEverySegmentToMatch() {
@Test func `match all requires every segment to match`() {
let first = ExecCommandResolution(
rawExecutable: "echo",
resolvedPath: "/usr/bin/echo",

View File

@@ -2,8 +2,8 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct ExecApprovalHelpersTests {
@Test func parseDecisionTrimsAndRejectsInvalid() {
struct ExecApprovalHelpersTests {
@Test func `parse decision trims and rejects invalid`() {
#expect(ExecApprovalHelpers.parseDecision("allow-once") == .allowOnce)
#expect(ExecApprovalHelpers.parseDecision(" allow-always ") == .allowAlways)
#expect(ExecApprovalHelpers.parseDecision("deny") == .deny)
@@ -11,7 +11,7 @@ import Testing
#expect(ExecApprovalHelpers.parseDecision("nope") == nil)
}
@Test func allowlistPatternPrefersResolution() {
@Test func `allowlist pattern prefers resolution`() {
let resolved = ExecCommandResolution(
rawExecutable: "rg",
resolvedPath: "/opt/homebrew/bin/rg",
@@ -29,7 +29,7 @@ import Testing
#expect(ExecApprovalHelpers.allowlistPattern(command: [], resolution: nil) == nil)
}
@Test func validateAllowlistPatternReturnsReasons() {
@Test func `validate allowlist pattern returns reasons`() {
#expect(ExecApprovalHelpers.isPathPattern("/usr/bin/rg"))
#expect(ExecApprovalHelpers.isPathPattern(" ~/bin/rg "))
#expect(!ExecApprovalHelpers.isPathPattern("rg"))
@@ -47,7 +47,7 @@ import Testing
}
}
@Test func requiresAskMatchesPolicy() {
@Test func `requires ask matches policy`() {
let entry = ExecAllowlistEntry(pattern: "/bin/ls", lastUsedAt: nil, lastUsedCommand: nil, lastResolvedPath: nil)
#expect(ExecApprovalHelpers.requiresAsk(
ask: .always,

View File

@@ -1,10 +1,9 @@
import Testing
@testable import OpenClaw
@Suite
@MainActor
struct ExecApprovalsGatewayPrompterTests {
@Test func sessionMatchPrefersActiveSession() {
@Test func `session match prefers active session`() {
let matches = ExecApprovalsGatewayPrompter._testShouldPresent(
mode: .remote,
activeSession: " main ",
@@ -20,7 +19,7 @@ struct ExecApprovalsGatewayPrompterTests {
#expect(!mismatched)
}
@Test func sessionFallbackUsesRecentActivity() {
@Test func `session fallback uses recent activity`() {
let recent = ExecApprovalsGatewayPrompter._testShouldPresent(
mode: .remote,
activeSession: nil,
@@ -38,7 +37,7 @@ struct ExecApprovalsGatewayPrompterTests {
#expect(!stale)
}
@Test func defaultBehaviorMatchesMode() {
@Test func `default behavior matches mode`() {
let local = ExecApprovalsGatewayPrompter._testShouldPresent(
mode: .local,
activeSession: nil,

View File

@@ -5,7 +5,7 @@ import Testing
@Suite(.serialized)
struct ExecApprovalsSocketPathGuardTests {
@Test
func hardenParentDirectoryCreatesDirectoryWith0700Permissions() throws {
func `harden parent directory creates directory with0700 permissions`() throws {
let root = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-socket-guard-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: root) }
@@ -24,7 +24,7 @@ struct ExecApprovalsSocketPathGuardTests {
}
@Test
func removeExistingSocketRejectsSymlinkPath() throws {
func `remove existing socket rejects symlink path`() throws {
let root = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-socket-guard-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: root) }
@@ -50,7 +50,7 @@ struct ExecApprovalsSocketPathGuardTests {
}
@Test
func removeExistingSocketRejectsRegularFilePath() throws {
func `remove existing socket rejects regular file path`() throws {
let root = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-socket-guard-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: root) }

View File

@@ -17,8 +17,8 @@ struct ExecApprovalsStoreRefactorTests {
}
@Test
func ensureFileSkipsRewriteWhenUnchanged() async throws {
try await self.withTempStateDir { stateDir in
func `ensure file skips rewrite when unchanged`() async throws {
try await self.withTempStateDir { _ in
_ = ExecApprovalsStore.ensureFile()
let url = ExecApprovalsStore.fileURL()
let firstWriteDate = try Self.modificationDate(at: url)
@@ -32,7 +32,7 @@ struct ExecApprovalsStoreRefactorTests {
}
@Test
func updateAllowlistReportsRejectedBasenamePattern() async throws {
func `update allowlist reports rejected basename pattern`() async throws {
try await self.withTempStateDir { _ in
let rejected = ExecApprovalsStore.updateAllowlist(
agentId: "main",
@@ -50,7 +50,7 @@ struct ExecApprovalsStoreRefactorTests {
}
@Test
func updateAllowlistMigratesLegacyPatternFromResolvedPath() async throws {
func `update allowlist migrates legacy pattern from resolved path`() async throws {
try await self.withTempStateDir { _ in
let rejected = ExecApprovalsStore.updateAllowlist(
agentId: "main",
@@ -69,7 +69,7 @@ struct ExecApprovalsStoreRefactorTests {
}
@Test
func ensureFileHardensStateDirectoryPermissions() async throws {
func `ensure file hardens state directory permissions`() async throws {
try await self.withTempStateDir { stateDir in
try FileManager().createDirectory(at: stateDir, withIntermediateDirectories: true)
try FileManager().setAttributes([.posixPermissions: 0o755], ofItemAtPath: stateDir.path)

View File

@@ -3,7 +3,7 @@ import Testing
@testable import OpenClaw
struct ExecHostRequestEvaluatorTests {
@Test func validateRequestRejectsEmptyCommand() {
@Test func `validate request rejects empty command`() {
let request = ExecHostRequest(
command: [],
rawCommand: nil,
@@ -23,7 +23,7 @@ struct ExecHostRequestEvaluatorTests {
}
}
@Test func evaluateRequiresPromptOnAllowlistMissWithoutDecision() {
@Test func `evaluate requires prompt on allowlist miss without decision`() {
let context = Self.makeContext(security: .allowlist, ask: .onMiss, allowlistSatisfied: false, skillAllow: false)
let decision = ExecHostRequestEvaluator.evaluate(context: context, approvalDecision: nil)
switch decision {
@@ -36,7 +36,7 @@ struct ExecHostRequestEvaluatorTests {
}
}
@Test func evaluateAllowsAllowOnceDecisionOnAllowlistMiss() {
@Test func `evaluate allows allow once decision on allowlist miss`() {
let context = Self.makeContext(security: .allowlist, ask: .onMiss, allowlistSatisfied: false, skillAllow: false)
let decision = ExecHostRequestEvaluator.evaluate(context: context, approvalDecision: .allowOnce)
switch decision {
@@ -49,7 +49,7 @@ struct ExecHostRequestEvaluatorTests {
}
}
@Test func evaluateDeniesOnExplicitDenyDecision() {
@Test func `evaluate denies on explicit deny decision`() {
let context = Self.makeContext(security: .full, ask: .off, allowlistSatisfied: true, skillAllow: false)
let decision = ExecHostRequestEvaluator.evaluate(context: context, approvalDecision: .deny)
switch decision {

View File

@@ -20,7 +20,7 @@ private struct SystemRunCommandContractExpected: Decodable {
}
struct ExecSystemRunCommandValidatorTests {
@Test func matchesSharedSystemRunCommandContractFixture() throws {
@Test func `matches shared system run command contract fixture`() throws {
for entry in try Self.loadContractCases() {
let result = ExecSystemRunCommandValidator.resolve(command: entry.command, rawCommand: entry.rawCommand)

View File

@@ -1,8 +1,8 @@
import Foundation
import Testing
@Suite struct FileHandleLegacyAPIGuardTests {
@Test func sourcesAvoidLegacyNonThrowingFileHandleReadAPIs() throws {
struct FileHandleLegacyAPIGuardTests {
@Test func `sources avoid legacy non throwing file handle read AP is`() throws {
let testFile = URL(fileURLWithPath: #filePath)
let packageRoot = testFile
.deletingLastPathComponent() // OpenClawIPCTests

View File

@@ -2,8 +2,8 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct FileHandleSafeReadTests {
@Test func readToEndSafelyReturnsEmptyForClosedHandle() {
struct FileHandleSafeReadTests {
@Test func `read to end safely returns empty for closed handle`() {
let pipe = Pipe()
let handle = pipe.fileHandleForReading
try? handle.close()
@@ -12,7 +12,7 @@ import Testing
#expect(data.isEmpty)
}
@Test func readSafelyUpToCountReturnsEmptyForClosedHandle() {
@Test func `read safely up to count returns empty for closed handle`() {
let pipe = Pipe()
let handle = pipe.fileHandleForReading
try? handle.close()
@@ -21,7 +21,7 @@ import Testing
#expect(data.isEmpty)
}
@Test func readToEndSafelyReadsPipeContents() {
@Test func `read to end safely reads pipe contents`() {
let pipe = Pipe()
let writeHandle = pipe.fileHandleForWriting
writeHandle.write(Data("hello".utf8))
@@ -31,7 +31,7 @@ import Testing
#expect(String(data: data, encoding: .utf8) == "hello")
}
@Test func readSafelyUpToCountReadsIncrementally() {
@Test func `read safely up to count reads incrementally`() {
let pipe = Pipe()
let writeHandle = pipe.fileHandleForWriting
writeHandle.write(Data("hello world".utf8))

View File

@@ -1,13 +1,13 @@
import Testing
@testable import OpenClaw
@Suite struct GatewayAgentChannelTests {
@Test func shouldDeliverBlocksWebChat() {
struct GatewayAgentChannelTests {
@Test func `should deliver blocks web chat`() {
#expect(GatewayAgentChannel.webchat.shouldDeliver(true) == false)
#expect(GatewayAgentChannel.webchat.shouldDeliver(false) == false)
}
@Test func shouldDeliverAllowsLastAndProviderChannels() {
@Test func `should deliver allows last and provider channels`() {
#expect(GatewayAgentChannel.last.shouldDeliver(true) == true)
#expect(GatewayAgentChannel.whatsapp.shouldDeliver(true) == true)
#expect(GatewayAgentChannel.telegram.shouldDeliver(true) == true)
@@ -16,7 +16,7 @@ import Testing
#expect(GatewayAgentChannel.last.shouldDeliver(false) == false)
}
@Test func initRawNormalizesAndFallsBackToLast() {
@Test func `init raw normalizes and falls back to last`() {
#expect(GatewayAgentChannel(raw: nil) == .last)
#expect(GatewayAgentChannel(raw: " ") == .last)
#expect(GatewayAgentChannel(raw: "WEBCHAT") == .webchat)

View File

@@ -3,14 +3,14 @@ import Testing
@Suite(.serialized)
struct GatewayAutostartPolicyTests {
@Test func startsGatewayOnlyWhenLocalAndNotPaused() {
@Test func `starts gateway only when local and not paused`() {
#expect(GatewayAutostartPolicy.shouldStartGateway(mode: .local, paused: false))
#expect(!GatewayAutostartPolicy.shouldStartGateway(mode: .local, paused: true))
#expect(!GatewayAutostartPolicy.shouldStartGateway(mode: .remote, paused: false))
#expect(!GatewayAutostartPolicy.shouldStartGateway(mode: .unconfigured, paused: false))
}
@Test func ensuresLaunchAgentWhenLocalAndNotAttachOnly() {
@Test func `ensures launch agent when local and not attach only`() {
#expect(GatewayAutostartPolicy.shouldEnsureLaunchAgent(
mode: .local,
paused: false))

View File

@@ -4,7 +4,7 @@ import os
import Testing
@testable import OpenClaw
@Suite struct GatewayConnectionTests {
struct GatewayConnectionTests {
private func makeConnection(
session: GatewayTestWebSocketSession,
token: String? = nil) throws -> (GatewayConnection, ConfigSource)
@@ -56,7 +56,7 @@ import Testing
}
}
@Test func requestReusesSingleWebSocketForSameConfig() async throws {
@Test func `request reuses single web socket for same config`() async throws {
let session = self.makeSession()
let (conn, _) = try self.makeConnection(session: session)
@@ -68,7 +68,7 @@ import Testing
#expect(session.snapshotCancelCount() == 0)
}
@Test func requestReconfiguresAndCancelsOnTokenChange() async throws {
@Test func `request reconfigures and cancels on token change`() async throws {
let session = self.makeSession()
let (conn, cfg) = try self.makeConnection(session: session, token: "a")
@@ -81,7 +81,7 @@ import Testing
#expect(session.snapshotCancelCount() == 1)
}
@Test func concurrentRequestsStillUseSingleWebSocket() async throws {
@Test func `concurrent requests still use single web socket`() async throws {
let session = self.makeSession(helloDelayMs: 150)
let (conn, _) = try self.makeConnection(session: session)
@@ -92,7 +92,7 @@ import Testing
#expect(session.snapshotMakeCount() == 1)
}
@Test func subscribeReplaysLatestSnapshot() async throws {
@Test func `subscribe replays latest snapshot`() async throws {
let session = self.makeSession()
let (conn, _) = try self.makeConnection(session: session)
@@ -109,7 +109,7 @@ import Testing
#expect(snap.type == "hello-ok")
}
@Test func subscribeEmitsSeqGapBeforeEvent() async throws {
@Test func `subscribe emits seq gap before event`() async throws {
let session = self.makeSession()
let (conn, _) = try self.makeConnection(session: session)

View File

@@ -3,7 +3,7 @@ import OpenClawKit
import Testing
@testable import OpenClaw
@Suite struct GatewayChannelConnectTests {
struct GatewayChannelConnectTests {
private enum FakeResponse {
case helloOk(delayMs: Int)
case invalid(delayMs: Int)
@@ -34,7 +34,7 @@ import Testing
})
}
@Test func concurrentConnectIsSingleFlightOnSuccess() async throws {
@Test func `concurrent connect is single flight on success`() async throws {
let session = self.makeSession(response: .helloOk(delayMs: 200))
let channel = try GatewayChannelActor(
url: #require(URL(string: "ws://example.invalid")),
@@ -50,7 +50,7 @@ import Testing
#expect(session.snapshotMakeCount() == 1)
}
@Test func concurrentConnectSharesFailure() async throws {
@Test func `concurrent connect shares failure`() async throws {
let session = self.makeSession(response: .invalid(delayMs: 200))
let channel = try GatewayChannelActor(
url: #require(URL(string: "ws://example.invalid")),

View File

@@ -3,7 +3,7 @@ import OpenClawKit
import Testing
@testable import OpenClaw
@Suite struct GatewayChannelRequestTests {
struct GatewayChannelRequestTests {
private func makeSession(requestSendDelayMs: Int) -> GatewayTestWebSocketSession {
GatewayTestWebSocketSession(
taskFactory: {
@@ -16,7 +16,7 @@ import Testing
})
}
@Test func requestTimeoutThenSendFailureDoesNotDoubleResume() async throws {
@Test func `request timeout then send failure does not double resume`() async throws {
let session = self.makeSession(requestSendDelayMs: 100)
let channel = try GatewayChannelActor(
url: #require(URL(string: "ws://example.invalid")),

View File

@@ -3,8 +3,8 @@ import OpenClawKit
import Testing
@testable import OpenClaw
@Suite struct GatewayChannelShutdownTests {
@Test func shutdownPreventsReconnectLoopFromReceiveFailure() async throws {
struct GatewayChannelShutdownTests {
@Test func `shutdown prevents reconnect loop from receive failure`() async throws {
let session = GatewayTestWebSocketSession()
let channel = try GatewayChannelActor(
url: #require(URL(string: "ws://example.invalid")),

View File

@@ -39,14 +39,14 @@ private func makeTestGatewayConnection() -> GatewayConnection {
}
@Suite(.serialized) struct GatewayConnectionControlTests {
@Test func statusFailsWhenProcessMissing() async {
@Test func `status fails when process missing`() async {
let connection = makeTestGatewayConnection()
let result = await connection.status()
#expect(result.ok == false)
#expect(result.error != nil)
}
@Test func rejectEmptyMessage() async {
@Test func `reject empty message`() async {
let connection = makeTestGatewayConnection()
let result = await connection.sendAgent(
message: "",

View File

@@ -3,7 +3,6 @@ import OpenClawDiscovery
import Testing
@testable import OpenClaw
@Suite
struct GatewayDiscoveryHelpersTests {
private func makeGateway(
serviceHost: String?,
@@ -41,23 +40,23 @@ struct GatewayDiscoveryHelpersTests {
#expect(parsed?.port == port)
}
@Test func sshTargetUsesResolvedServiceHostOnly() {
@Test func `ssh target uses resolved service host only`() {
let gateway = self.makeGateway(
serviceHost: "resolved.example.ts.net",
servicePort: 18789,
sshPort: 2201)
assertSSHTarget(for: gateway, host: "resolved.example.ts.net", port: 2201)
self.assertSSHTarget(for: gateway, host: "resolved.example.ts.net", port: 2201)
}
@Test func sshTargetAllowsMissingResolvedServicePort() {
@Test func `ssh target allows missing resolved service port`() {
let gateway = self.makeGateway(
serviceHost: "resolved.example.ts.net",
servicePort: nil,
sshPort: 2201)
assertSSHTarget(for: gateway, host: "resolved.example.ts.net", port: 2201)
self.assertSSHTarget(for: gateway, host: "resolved.example.ts.net", port: 2201)
}
@Test func sshTargetRejectsTxtOnlyGateways() {
@Test func `ssh target rejects txt only gateways`() {
let gateway = self.makeGateway(
serviceHost: nil,
servicePort: nil,
@@ -68,7 +67,7 @@ struct GatewayDiscoveryHelpersTests {
#expect(GatewayDiscoveryHelpers.sshTarget(for: gateway) == nil)
}
@Test func directUrlUsesResolvedServiceEndpointOnly() {
@Test func `direct url uses resolved service endpoint only`() {
let tlsGateway = self.makeGateway(
serviceHost: "resolved.example.ts.net",
servicePort: 443)
@@ -85,7 +84,7 @@ struct GatewayDiscoveryHelpersTests {
#expect(GatewayDiscoveryHelpers.directUrl(for: localGateway) == "ws://127.0.0.1:18789")
}
@Test func directUrlRejectsTxtOnlyFallback() {
@Test func `direct url rejects txt only fallback`() {
let gateway = self.makeGateway(
serviceHost: nil,
servicePort: nil,

View File

@@ -1,10 +1,9 @@
@testable import OpenClawDiscovery
import Testing
@testable import OpenClawDiscovery
@Suite
@MainActor
struct GatewayDiscoveryModelTests {
@Test func localGatewayMatchesLanHost() {
@Test func `local gateway matches lan host`() {
let local = GatewayDiscoveryModel.LocalIdentity(
hostTokens: ["studio"],
displayTokens: [])
@@ -16,7 +15,7 @@ struct GatewayDiscoveryModelTests {
local: local))
}
@Test func localGatewayMatchesTailnetDns() {
@Test func `local gateway matches tailnet dns`() {
let local = GatewayDiscoveryModel.LocalIdentity(
hostTokens: ["studio"],
displayTokens: [])
@@ -28,7 +27,7 @@ struct GatewayDiscoveryModelTests {
local: local))
}
@Test func localGatewayMatchesDisplayName() {
@Test func `local gateway matches display name`() {
let local = GatewayDiscoveryModel.LocalIdentity(
hostTokens: [],
displayTokens: ["peter's mac studio"])
@@ -40,7 +39,7 @@ struct GatewayDiscoveryModelTests {
local: local))
}
@Test func remoteGatewayDoesNotMatch() {
@Test func `remote gateway does not match`() {
let local = GatewayDiscoveryModel.LocalIdentity(
hostTokens: ["studio"],
displayTokens: ["peter's mac studio"])
@@ -52,7 +51,7 @@ struct GatewayDiscoveryModelTests {
local: local))
}
@Test func localGatewayMatchesServiceName() {
@Test func `local gateway matches service name`() {
let local = GatewayDiscoveryModel.LocalIdentity(
hostTokens: ["studio"],
displayTokens: [])
@@ -64,7 +63,7 @@ struct GatewayDiscoveryModelTests {
local: local))
}
@Test func serviceNameDoesNotFalsePositiveOnSubstringHostToken() {
@Test func `service name does not false positive on substring host token`() {
let local = GatewayDiscoveryModel.LocalIdentity(
hostTokens: ["steipete"],
displayTokens: [])
@@ -82,7 +81,7 @@ struct GatewayDiscoveryModelTests {
local: local))
}
@Test func parsesGatewayTXTFields() {
@Test func `parses gateway TXT fields`() {
let parsed = GatewayDiscoveryModel.parseGatewayTXT([
"lanHost": " studio.local ",
"tailnetDns": " peters-mac-studio-1.ts.net ",
@@ -97,7 +96,7 @@ struct GatewayDiscoveryModelTests {
#expect(parsed.cliPath == "/opt/openclaw")
}
@Test func parsesGatewayTXTDefaults() {
@Test func `parses gateway TXT defaults`() {
let parsed = GatewayDiscoveryModel.parseGatewayTXT([
"lanHost": " ",
"tailnetDns": "\n",
@@ -111,7 +110,7 @@ struct GatewayDiscoveryModelTests {
#expect(parsed.cliPath == nil)
}
@Test func buildsSSHTarget() {
@Test func `builds SSH target`() {
#expect(GatewayDiscoveryModel.buildSSHTarget(
user: "peter",
host: "studio.local",
@@ -122,7 +121,7 @@ struct GatewayDiscoveryModelTests {
port: 2201) == "peter@studio.local:2201")
}
@Test func dedupeKeyPrefersResolvedEndpointAcrossSources() {
@Test func `dedupe key prefers resolved endpoint across sources`() {
let wideArea = GatewayDiscoveryModel.DiscoveredGateway(
displayName: "Gateway",
serviceHost: "gateway-host.tailnet-example.ts.net",
@@ -151,7 +150,7 @@ struct GatewayDiscoveryModelTests {
#expect(GatewayDiscoveryModel.dedupeKey(for: wideArea) == GatewayDiscoveryModel.dedupeKey(for: serve))
}
@Test func dedupeKeyFallsBackToStableIDWithoutEndpoint() {
@Test func `dedupe key falls back to stable ID without endpoint`() {
let unresolved = GatewayDiscoveryModel.DiscoveredGateway(
displayName: "Gateway",
serviceHost: nil,
@@ -165,6 +164,7 @@ struct GatewayDiscoveryModelTests {
debugID: "serve",
isLocal: false)
#expect(GatewayDiscoveryModel.dedupeKey(for: unresolved) == "stable|tailscale-serve|gateway-host.tailnet-example.ts.net")
#expect(GatewayDiscoveryModel
.dedupeKey(for: unresolved) == "stable|tailscale-serve|gateway-host.tailnet-example.ts.net")
}
}

View File

@@ -2,7 +2,7 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct GatewayEndpointStoreTests {
struct GatewayEndpointStoreTests {
private func makeLaunchAgentSnapshot(
env: [String: String],
token: String?,
@@ -26,7 +26,7 @@ import Testing
return defaults
}
@Test func resolveGatewayTokenPrefersEnvAndFallsBackToLaunchd() {
@Test func `resolve gateway token prefers env and falls back to launchd`() {
let snapshot = self.makeLaunchAgentSnapshot(
env: ["OPENCLAW_GATEWAY_TOKEN": "launchd-token"],
token: "launchd-token",
@@ -47,7 +47,7 @@ import Testing
#expect(fallbackToken == "launchd-token")
}
@Test func resolveGatewayTokenIgnoresLaunchdInRemoteMode() {
@Test func `resolve gateway token ignores launchd in remote mode`() {
let snapshot = self.makeLaunchAgentSnapshot(
env: ["OPENCLAW_GATEWAY_TOKEN": "launchd-token"],
token: "launchd-token",
@@ -61,7 +61,7 @@ import Testing
#expect(token == nil)
}
@Test func resolveGatewayPasswordFallsBackToLaunchd() {
@Test func `resolve gateway password falls back to launchd`() {
let snapshot = self.makeLaunchAgentSnapshot(
env: ["OPENCLAW_GATEWAY_PASSWORD": "launchd-pass"],
token: nil,
@@ -75,7 +75,7 @@ import Testing
#expect(password == "launchd-pass")
}
@Test func connectionModeResolverPrefersConfigModeOverDefaults() {
@Test func `connection mode resolver prefers config mode over defaults`() {
let defaults = self.makeDefaults()
defaults.set("remote", forKey: connectionModeKey)
@@ -89,7 +89,7 @@ import Testing
#expect(resolved.mode == .local)
}
@Test func connectionModeResolverTrimsConfigMode() {
@Test func `connection mode resolver trims config mode`() {
let defaults = self.makeDefaults()
defaults.set("local", forKey: connectionModeKey)
@@ -103,7 +103,7 @@ import Testing
#expect(resolved.mode == .remote)
}
@Test func connectionModeResolverFallsBackToDefaultsWhenMissingConfig() {
@Test func `connection mode resolver falls back to defaults when missing config`() {
let defaults = self.makeDefaults()
defaults.set("remote", forKey: connectionModeKey)
@@ -111,7 +111,7 @@ import Testing
#expect(resolved.mode == .remote)
}
@Test func connectionModeResolverFallsBackToDefaultsOnUnknownConfig() {
@Test func `connection mode resolver falls back to defaults on unknown config`() {
let defaults = self.makeDefaults()
defaults.set("local", forKey: connectionModeKey)
@@ -125,7 +125,7 @@ import Testing
#expect(resolved.mode == .local)
}
@Test func connectionModeResolverPrefersRemoteURLWhenModeMissing() {
@Test func `connection mode resolver prefers remote URL when mode missing`() {
let defaults = self.makeDefaults()
defaults.set("local", forKey: connectionModeKey)
@@ -141,35 +141,35 @@ import Testing
#expect(resolved.mode == .remote)
}
@Test func resolveLocalGatewayHostUsesLoopbackForAutoEvenWithTailnet() {
@Test func `resolve local gateway host uses loopback for auto even with tailnet`() {
let host = GatewayEndpointStore._testResolveLocalGatewayHost(
bindMode: "auto",
tailscaleIP: "100.64.1.2")
#expect(host == "127.0.0.1")
}
@Test func resolveLocalGatewayHostUsesLoopbackForAutoWithoutTailnet() {
@Test func `resolve local gateway host uses loopback for auto without tailnet`() {
let host = GatewayEndpointStore._testResolveLocalGatewayHost(
bindMode: "auto",
tailscaleIP: nil)
#expect(host == "127.0.0.1")
}
@Test func resolveLocalGatewayHostPrefersTailnetForTailnetMode() {
@Test func `resolve local gateway host prefers tailnet for tailnet mode`() {
let host = GatewayEndpointStore._testResolveLocalGatewayHost(
bindMode: "tailnet",
tailscaleIP: "100.64.1.5")
#expect(host == "100.64.1.5")
}
@Test func resolveLocalGatewayHostFallsBackToLoopbackForTailnetMode() {
@Test func `resolve local gateway host falls back to loopback for tailnet mode`() {
let host = GatewayEndpointStore._testResolveLocalGatewayHost(
bindMode: "tailnet",
tailscaleIP: nil)
#expect(host == "127.0.0.1")
}
@Test func resolveLocalGatewayHostUsesCustomBindHost() {
@Test func `resolve local gateway host uses custom bind host`() {
let host = GatewayEndpointStore._testResolveLocalGatewayHost(
bindMode: "custom",
tailscaleIP: "100.64.1.9",
@@ -177,7 +177,7 @@ import Testing
#expect(host == "192.168.1.10")
}
@Test func localConfigUsesLocalGatewayAuthAndHostResolution() throws {
@Test func `local config uses local gateway auth and host resolution`() {
let snapshot = self.makeLaunchAgentSnapshot(
env: [:],
token: "launchd-token",
@@ -204,7 +204,7 @@ import Testing
#expect(config.password == "launchd-pass")
}
@Test func dashboardURLUsesLocalBasePathInLocalMode() throws {
@Test func `dashboard URL uses local base path in local mode`() throws {
let config: GatewayConnection.Config = try (
url: #require(URL(string: "ws://127.0.0.1:18789")),
token: nil,
@@ -217,7 +217,7 @@ import Testing
#expect(url.absoluteString == "http://127.0.0.1:18789/control/")
}
@Test func dashboardURLSkipsLocalBasePathInRemoteMode() throws {
@Test func `dashboard URL skips local base path in remote mode`() throws {
let config: GatewayConnection.Config = try (
url: #require(URL(string: "ws://gateway.example:18789")),
token: nil,
@@ -230,7 +230,7 @@ import Testing
#expect(url.absoluteString == "http://gateway.example:18789/")
}
@Test func dashboardURLPrefersPathFromConfigURL() throws {
@Test func `dashboard URL prefers path from config URL`() throws {
let config: GatewayConnection.Config = try (
url: #require(URL(string: "wss://gateway.example:443/remote-ui")),
token: nil,
@@ -243,7 +243,7 @@ import Testing
#expect(url.absoluteString == "https://gateway.example:443/remote-ui/")
}
@Test func dashboardURLUsesFragmentTokenAndOmitsPassword() throws {
@Test func `dashboard URL uses fragment token and omits password`() throws {
let config: GatewayConnection.Config = try (
url: #require(URL(string: "ws://127.0.0.1:18789")),
token: "abc123",
@@ -257,18 +257,18 @@ import Testing
#expect(url.query == nil)
}
@Test func normalizeGatewayUrlAddsDefaultPortForLoopbackWs() {
@Test func `normalize gateway url adds default port for loopback ws`() {
let url = GatewayRemoteConfig.normalizeGatewayUrl("ws://127.0.0.1")
#expect(url?.port == 18789)
#expect(url?.absoluteString == "ws://127.0.0.1:18789")
}
@Test func normalizeGatewayUrlRejectsNonLoopbackWs() {
@Test func `normalize gateway url rejects non loopback ws`() {
let url = GatewayRemoteConfig.normalizeGatewayUrl("ws://gateway.example:18789")
#expect(url == nil)
}
@Test func normalizeGatewayUrlRejectsPrefixBypassLoopbackHost() {
@Test func `normalize gateway url rejects prefix bypass loopback host`() {
let url = GatewayRemoteConfig.normalizeGatewayUrl("ws://127.attacker.example")
#expect(url == nil)
}

View File

@@ -2,8 +2,8 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct GatewayEnvironmentTests {
@Test func semverParsesCommonForms() {
struct GatewayEnvironmentTests {
@Test func `semver parses common forms`() {
#expect(Semver.parse("1.2.3") == Semver(major: 1, minor: 2, patch: 3))
#expect(Semver.parse(" v1.2.3 \n") == Semver(major: 1, minor: 2, patch: 3))
#expect(Semver.parse("v2.0.0") == Semver(major: 2, minor: 0, patch: 0))
@@ -21,7 +21,7 @@ import Testing
#expect(Semver.parse("1.2.x") == nil)
}
@Test func semverCompatibilityRequiresSameMajorAndNotOlder() {
@Test func `semver compatibility requires same major and not older`() {
let required = Semver(major: 2, minor: 1, patch: 0)
#expect(Semver(major: 2, minor: 1, patch: 0).compatible(with: required))
#expect(Semver(major: 2, minor: 2, patch: 0).compatible(with: required))
@@ -31,7 +31,7 @@ import Testing
#expect(Semver(major: 1, minor: 9, patch: 9).compatible(with: required) == false)
}
@Test func gatewayPortDefaultsAndRespectsOverride() async {
@Test func `gateway port defaults and respects override`() async {
let configPath = TestIsolation.tempConfigPath()
await TestIsolation.withIsolatedState(
env: ["OPENCLAW_CONFIG_PATH": configPath],
@@ -46,7 +46,7 @@ import Testing
}
}
@Test func expectedGatewayVersionFromStringUsesParser() {
@Test func `expected gateway version from string uses parser`() {
#expect(GatewayEnvironment.expectedGatewayVersion(from: "v9.1.2") == Semver(major: 9, minor: 1, patch: 2))
#expect(GatewayEnvironment.expectedGatewayVersion(from: "2026.1.11-4") == Semver(
major: 2026,

View File

@@ -2,8 +2,8 @@ import Foundation
import OpenClawProtocol
import Testing
@Suite struct GatewayFrameDecodeTests {
@Test func decodesEventFrameWithAnyCodablePayload() throws {
struct GatewayFrameDecodeTests {
@Test func `decodes event frame with any codable payload`() throws {
let json = """
{
"type": "event",
@@ -29,7 +29,7 @@ import Testing
#expect(evt.seq == 7)
}
@Test func decodesRequestFrameWithNestedParams() throws {
@Test func `decodes request frame with nested params`() throws {
let json = """
{
"type": "req",
@@ -68,7 +68,7 @@ import Testing
#expect(meta?["count"]?.value as? Int == 2)
}
@Test func decodesUnknownFrameAndPreservesRaw() throws {
@Test func `decodes unknown frame and preserves raw`() throws {
let json = """
{
"type": "made-up",

View File

@@ -2,8 +2,8 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct GatewayLaunchAgentManagerTests {
@Test func launchAgentPlistSnapshotParsesArgsAndEnv() throws {
struct GatewayLaunchAgentManagerTests {
@Test func `launch agent plist snapshot parses args and env`() throws {
let url = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-launchd-\(UUID().uuidString).plist")
let plist: [String: Any] = [
@@ -24,7 +24,7 @@ import Testing
#expect(snapshot.password == "pw")
}
@Test func launchAgentPlistSnapshotAllowsMissingBind() throws {
@Test func `launch agent plist snapshot allows missing bind`() throws {
let url = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-launchd-\(UUID().uuidString).plist")
let plist: [String: Any] = [

View File

@@ -6,7 +6,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct GatewayProcessManagerTests {
@Test func clearsLastFailureWhenHealthSucceeds() async throws {
@Test func `clears last failure when health succeeds`() async throws {
let session = GatewayTestWebSocketSession(
taskFactory: {
GatewayTestWebSocketTask(

View File

@@ -83,9 +83,9 @@ enum GatewayWebSocketTestSupport {
}
}
private extension NSLock {
extension NSLock {
@inline(__always)
func withLock<T>(_ body: () throws -> T) rethrows -> T {
fileprivate func withLock<T>(_ body: () throws -> T) rethrows -> T {
self.lock(); defer { self.unlock() }
return try body()
}
@@ -129,7 +129,10 @@ final class GatewayTestWebSocketTask: WebSocketTasking, @unchecked Sendable {
func cancel(with closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
_ = (closeCode, reason)
let handler = self.lock.withLock { () -> (@Sendable (Result<URLSessionWebSocketTask.Message, Error>) -> Void)? in
let handler = self.lock.withLock { () -> (@Sendable (Result<
URLSessionWebSocketTask.Message,
Error,
>) -> Void)? in
self._state = .canceling
self.cancelCount += 1
defer { self.pendingReceiveHandler = nil }

View File

@@ -2,13 +2,13 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct HealthDecodeTests {
struct HealthDecodeTests {
private let sampleJSON: String = // minimal but complete payload
"""
{"ts":1733622000,"durationMs":420,"channels":{"whatsapp":{"linked":true,"authAgeMs":120000},"telegram":{"configured":true,"probe":{"ok":true,"elapsedMs":800}}},"channelOrder":["whatsapp","telegram"],"heartbeatSeconds":60,"sessions":{"path":"/tmp/sessions.json","count":1,"recent":[{"key":"abc","updatedAt":1733621900,"age":120000}]}}
"""
@Test func decodesCleanJSON() {
@Test func `decodes clean JSON`() {
let data = Data(sampleJSON.utf8)
let snap = decodeHealthSnapshot(from: data)
@@ -16,14 +16,14 @@ import Testing
#expect(snap?.sessions.count == 1)
}
@Test func decodesWithLeadingNoise() {
@Test func `decodes with leading noise`() {
let noisy = "debug: something logged\n" + self.sampleJSON + "\ntrailer"
let snap = decodeHealthSnapshot(from: Data(noisy.utf8))
#expect(snap?.channels["telegram"]?.probe?.elapsedMs == 800)
}
@Test func failsWithoutBraces() {
@Test func `fails without braces`() {
let data = Data("no json here".utf8)
let snap = decodeHealthSnapshot(from: data)

View File

@@ -2,8 +2,8 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct HealthStoreStateTests {
@Test @MainActor func linkedChannelProbeFailureDegradesState() {
struct HealthStoreStateTests {
@Test @MainActor func `linked channel probe failure degrades state`() {
let snap = HealthSnapshot(
ok: true,
ts: 0,

View File

@@ -2,7 +2,7 @@ import Testing
@testable import OpenClaw
struct HostEnvSanitizerTests {
@Test func sanitizeBlocksShellTraceVariables() {
@Test func `sanitize blocks shell trace variables`() {
let env = HostEnvSanitizer.sanitize(overrides: [
"SHELLOPTS": "xtrace",
"PS4": "$(touch /tmp/pwned)",
@@ -13,7 +13,7 @@ struct HostEnvSanitizerTests {
#expect(env["OPENCLAW_TEST"] == "1")
}
@Test func sanitizeShellWrapperAllowsOnlyExplicitOverrideKeys() {
@Test func `sanitize shell wrapper allows only explicit override keys`() {
let env = HostEnvSanitizer.sanitize(
overrides: [
"LANG": "C",
@@ -29,7 +29,7 @@ struct HostEnvSanitizerTests {
#expect(env["PS4"] == nil)
}
@Test func sanitizeNonShellWrapperKeepsRegularOverrides() {
@Test func `sanitize non shell wrapper keeps regular overrides`() {
let env = HostEnvSanitizer.sanitize(overrides: ["OPENCLAW_TOKEN": "secret"])
#expect(env["OPENCLAW_TOKEN"] == "secret")
}

View File

@@ -5,7 +5,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct HoverHUDControllerTests {
@Test func hoverHUDControllerPresentsAndDismisses() async {
@Test func `hover HUD controller presents and dismisses`() async {
let controller = HoverHUDController()
controller.setSuppressed(false)

View File

@@ -4,7 +4,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct InstancesSettingsSmokeTests {
@Test func instancesSettingsBuildsBodyWithMultipleInstances() {
@Test func `instances settings builds body with multiple instances`() {
let store = InstancesStore(isPreview: true)
store.statusMessage = "Loaded"
store.instances = [
@@ -53,7 +53,7 @@ struct InstancesSettingsSmokeTests {
_ = view.body
}
@Test func instancesSettingsExercisesHelpers() {
@Test func `instances settings exercises helpers`() {
InstancesSettings.exerciseForTesting()
}
}

View File

@@ -2,10 +2,10 @@ import OpenClawProtocol
import Testing
@testable import OpenClaw
@Suite struct InstancesStoreTests {
struct InstancesStoreTests {
@Test
@MainActor
func presenceEventPayloadDecodesViaJSONEncoder() {
func `presence event payload decodes via JSON encoder`() {
// Build a payload that mirrors the gateway's presence event shape:
// { "presence": [ PresenceEntry ] }
let entry: [String: OpenClawProtocol.AnyCodable] = [

View File

@@ -3,8 +3,8 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct LogLocatorTests {
@Test func launchdGatewayLogPathEnsuresTmpDirExists() {
struct LogLocatorTests {
@Test func `launchd gateway log path ensures tmp dir exists`() {
let fm = FileManager()
let baseDir = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
let logDir = baseDir.appendingPathComponent("openclaw-tests-\(UUID().uuidString)")

View File

@@ -8,7 +8,7 @@ import Testing
struct LowCoverageHelperTests {
private typealias ProtoAnyCodable = OpenClawProtocol.AnyCodable
@Test func anyCodableHelperAccessors() throws {
@Test func `any codable helper accessors`() throws {
let payload: [String: ProtoAnyCodable] = [
"title": ProtoAnyCodable("Hello"),
"flag": ProtoAnyCodable(true),
@@ -28,7 +28,7 @@ struct LowCoverageHelperTests {
#expect((foundation?["title"] as? String) == "Hello")
}
@Test func attributedStringStripsForegroundColor() {
@Test func `attributed string strips foreground color`() {
let text = NSMutableAttributedString(string: "Test")
text.addAttribute(.foregroundColor, value: NSColor.red, range: NSRange(location: 0, length: 4))
let stripped = text.strippingForegroundColor()
@@ -36,29 +36,29 @@ struct LowCoverageHelperTests {
#expect(color == nil)
}
@Test func viewMetricsReduceWidth() {
@Test func `view metrics reduce width`() {
let value = ViewMetricsTesting.reduceWidth(current: 120, next: 180)
#expect(value == 180)
}
@Test func shellExecutorHandlesEmptyCommand() async {
@Test func `shell executor handles empty command`() async {
let result = await ShellExecutor.runDetailed(command: [], cwd: nil, env: nil, timeout: nil)
#expect(result.success == false)
#expect(result.errorMessage != nil)
}
@Test func shellExecutorRunsCommand() async {
@Test func `shell executor runs command`() async {
let result = await ShellExecutor.runDetailed(command: ["/bin/echo", "ok"], cwd: nil, env: nil, timeout: 2)
#expect(result.success == true)
#expect(result.stdout.contains("ok") || result.stderr.contains("ok"))
}
@Test func shellExecutorTimesOut() async {
@Test func `shell executor times out`() async {
let result = await ShellExecutor.runDetailed(command: ["/bin/sleep", "1"], cwd: nil, env: nil, timeout: 0.05)
#expect(result.timedOut == true)
}
@Test func shellExecutorDrainsStdoutAndStderr() async {
@Test func `shell executor drains stdout and stderr`() async {
let script = """
i=0
while [ $i -lt 2000 ]; do
@@ -77,7 +77,7 @@ struct LowCoverageHelperTests {
#expect(result.stderr.contains("stderr-1999"))
}
@Test func nodeInfoCodableRoundTrip() throws {
@Test func `node info codable round trip`() throws {
let info = NodeInfo(
nodeId: "node-1",
displayName: "Node One",
@@ -100,7 +100,7 @@ struct LowCoverageHelperTests {
#expect(decoded.isConnected == false)
}
@Test @MainActor func presenceReporterHelpers() {
@Test @MainActor func `presence reporter helpers`() {
let summary = PresenceReporter._testComposePresenceSummary(mode: "local", reason: "test")
#expect(summary.contains("mode local"))
#expect(!PresenceReporter._testAppVersionString().isEmpty)
@@ -109,7 +109,7 @@ struct LowCoverageHelperTests {
_ = PresenceReporter._testPrimaryIPv4Address()
}
@Test func portGuardianParsesListenersAndBuildsReports() {
@Test func `port guardian parses listeners and builds reports`() {
let output = """
p123
cnode
@@ -139,7 +139,7 @@ struct LowCoverageHelperTests {
#expect(emptyReport.summary.contains("Nothing is listening"))
}
@Test @MainActor func canvasSchemeHandlerResolvesFilesAndErrors() throws {
@Test @MainActor func `canvas scheme handler resolves files and errors`() throws {
let root = FileManager().temporaryDirectory
.appendingPathComponent("canvas-\(UUID().uuidString)", isDirectory: true)
defer { try? FileManager().removeItem(at: root) }
@@ -168,7 +168,7 @@ struct LowCoverageHelperTests {
#expect(handler._testTextEncodingName(for: "application/octet-stream") == nil)
}
@Test @MainActor func menuContextCardInjectorInsertsAndFindsIndex() {
@Test @MainActor func `menu context card injector inserts and finds index`() {
let injector = MenuContextCardInjector()
let menu = NSMenu()
menu.minimumWidth = 280
@@ -190,7 +190,7 @@ struct LowCoverageHelperTests {
#expect(injector._testFindInsertIndex(in: fallbackMenu) == 1)
}
@Test @MainActor func canvasWindowHelperFunctions() throws {
@Test @MainActor func `canvas window helper functions`() throws {
#expect(CanvasWindowController._testSanitizeSessionKey(" main ") == "main")
#expect(CanvasWindowController._testSanitizeSessionKey("bad/..") == "bad___")
#expect(CanvasWindowController._testJSOptionalStringLiteral(nil) == "null")

View File

@@ -7,7 +7,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct LowCoverageViewSmokeTests {
@Test func contextMenuCardBuildsBody() {
@Test func `context menu card builds body`() {
let loading = ContextMenuCardView(rows: [], statusText: "Loading…", isLoading: true)
_ = loading.body
@@ -18,14 +18,14 @@ struct LowCoverageViewSmokeTests {
_ = withRows.body
}
@Test func settingsToggleRowBuildsBody() {
@Test func `settings toggle row builds body`() {
var flag = false
let binding = Binding(get: { flag }, set: { flag = $0 })
let view = SettingsToggleRow(title: "Enable", subtitle: "Detail", binding: binding)
_ = view.body
}
@Test func voiceWakeTestCardBuildsBodyAcrossStates() {
@Test func `voice wake test card builds body across states`() {
var state = VoiceWakeTestState.idle
var isTesting = false
let stateBinding = Binding(get: { state }, set: { state = $0 })
@@ -44,7 +44,7 @@ struct LowCoverageViewSmokeTests {
_ = VoiceWakeTestCard(testState: stateBinding, isTesting: testingBinding, onToggle: {}).body
}
@Test func agentEventsWindowBuildsBodyWithEvent() {
@Test func `agent events window builds body with event`() {
AgentEventStore.shared.clear()
let sample = ControlAgentEvent(
runId: "run-1",
@@ -58,7 +58,7 @@ struct LowCoverageViewSmokeTests {
AgentEventStore.shared.clear()
}
@Test func notifyOverlayPresentsAndDismisses() async {
@Test func `notify overlay presents and dismisses`() async {
let controller = NotifyOverlayController()
controller.present(title: "Hello", body: "World", autoDismissAfter: 0)
controller.present(title: "Updated", body: "Again", autoDismissAfter: 0)
@@ -66,14 +66,14 @@ struct LowCoverageViewSmokeTests {
try? await Task.sleep(nanoseconds: 250_000_000)
}
@Test func visualEffectViewHostsInNSHostingView() {
@Test func `visual effect view hosts in NS hosting view`() {
let hosting = NSHostingView(rootView: VisualEffectView(material: .sidebar))
_ = hosting.fittingSize
hosting.rootView = VisualEffectView(material: .popover, emphasized: true)
_ = hosting.fittingSize
}
@Test func menuHostedItemHostsContent() {
@Test func `menu hosted item hosts content`() {
let view = MenuHostedItem(width: 240, rootView: AnyView(Text("Menu")))
let hosting = NSHostingView(rootView: view)
_ = hosting.fittingSize
@@ -81,18 +81,18 @@ struct LowCoverageViewSmokeTests {
_ = hosting.fittingSize
}
@Test func dockIconManagerUpdatesVisibility() {
@Test func `dock icon manager updates visibility`() {
_ = NSApplication.shared
UserDefaults.standard.set(false, forKey: showDockIconKey)
DockIconManager.shared.updateDockVisibility()
DockIconManager.shared.temporarilyShowDock()
}
@Test func voiceWakeSettingsExercisesHelpers() {
@Test func `voice wake settings exercises helpers`() {
VoiceWakeSettings.exerciseForTesting()
}
@Test func debugSettingsExercisesHelpers() async {
@Test func `debug settings exercises helpers`() async {
await DebugSettings.exerciseForTesting()
}
}

View File

@@ -3,8 +3,8 @@ import OpenClawProtocol
import Testing
@testable import OpenClaw
@Suite struct MacGatewayChatTransportMappingTests {
@Test func snapshotMapsToHealth() {
struct MacGatewayChatTransportMappingTests {
@Test func `snapshot maps to health`() {
let snapshot = Snapshot(
presence: [],
health: OpenClawProtocol.AnyCodable(["ok": OpenClawProtocol.AnyCodable(false)]),
@@ -35,7 +35,7 @@ import Testing
}
}
@Test func healthEventMapsToHealth() {
@Test func `health event maps to health`() {
let frame = EventFrame(
type: "event",
event: "health",
@@ -52,7 +52,7 @@ import Testing
}
}
@Test func tickEventMapsToTick() {
@Test func `tick event maps to tick`() {
let frame = EventFrame(type: "event", event: "tick", payload: nil, seq: 1, stateversion: nil)
let mapped = MacGatewayChatTransport.mapPushToTransportEvent(.event(frame))
#expect({
@@ -61,7 +61,7 @@ import Testing
}())
}
@Test func chatEventMapsToChat() {
@Test func `chat event maps to chat`() {
let payload = OpenClawProtocol.AnyCodable([
"runId": OpenClawProtocol.AnyCodable("run-1"),
"sessionKey": OpenClawProtocol.AnyCodable("main"),
@@ -80,7 +80,7 @@ import Testing
}
}
@Test func unknownEventMapsToNil() {
@Test func `unknown event maps to nil`() {
let frame = EventFrame(
type: "event",
event: "unknown",
@@ -91,7 +91,7 @@ import Testing
#expect(mapped == nil)
}
@Test func seqGapMapsToSeqGap() {
@Test func `seq gap maps to seq gap`() {
let mapped = MacGatewayChatTransport.mapPushToTransportEvent(.seqGap(expected: 1, received: 9))
#expect({
if case .seqGap = mapped { return true }

View File

@@ -3,7 +3,7 @@ import Testing
@testable import OpenClaw
struct MacNodeBrowserProxyTests {
@Test func requestUsesBrowserControlEndpointAndWrapsResult() async throws {
@Test func `request uses browser control endpoint and wraps result`() async throws {
let proxy = MacNodeBrowserProxy(
endpointProvider: {
MacNodeBrowserProxy.Endpoint(

View File

@@ -5,14 +5,14 @@ import Testing
@testable import OpenClaw
struct MacNodeRuntimeTests {
@Test func handleInvokeRejectsUnknownCommand() async {
@Test func `handle invoke rejects unknown command`() async {
let runtime = MacNodeRuntime()
let response = await runtime.handleInvoke(
BridgeInvokeRequest(id: "req-1", command: "unknown.command"))
#expect(response.ok == false)
}
@Test func handleInvokeRejectsEmptySystemRun() async throws {
@Test func `handle invoke rejects empty system run`() async throws {
let runtime = MacNodeRuntime()
let params = OpenClawSystemRunParams(command: [])
let json = try String(data: JSONEncoder().encode(params), encoding: .utf8)
@@ -21,7 +21,7 @@ struct MacNodeRuntimeTests {
#expect(response.ok == false)
}
@Test func handleInvokeRejectsEmptySystemWhich() async throws {
@Test func `handle invoke rejects empty system which`() async throws {
let runtime = MacNodeRuntime()
let params = OpenClawSystemWhichParams(bins: [])
let json = try String(data: JSONEncoder().encode(params), encoding: .utf8)
@@ -30,7 +30,7 @@ struct MacNodeRuntimeTests {
#expect(response.ok == false)
}
@Test func handleInvokeRejectsEmptyNotification() async throws {
@Test func `handle invoke rejects empty notification`() async throws {
let runtime = MacNodeRuntime()
let params = OpenClawSystemNotifyParams(title: "", body: "")
let json = try String(data: JSONEncoder().encode(params), encoding: .utf8)
@@ -39,7 +39,7 @@ struct MacNodeRuntimeTests {
#expect(response.ok == false)
}
@Test func handleInvokeCameraListRequiresEnabledCamera() async {
@Test func `handle invoke camera list requires enabled camera`() async {
await TestIsolation.withUserDefaultsValues([cameraEnabledKey: false]) {
let runtime = MacNodeRuntime()
let response = await runtime.handleInvoke(
@@ -49,7 +49,7 @@ struct MacNodeRuntimeTests {
}
}
@Test func handleInvokeScreenRecordUsesInjectedServices() async throws {
@Test func `handle invoke screen record uses injected services`() async throws {
@MainActor
final class FakeMainActorServices: MacNodeRuntimeMainActorServices, @unchecked Sendable {
func recordScreen(
@@ -101,20 +101,23 @@ struct MacNodeRuntimeTests {
#expect(!payload.base64.isEmpty)
}
@Test func handleInvokeBrowserProxyUsesInjectedRequest() async throws {
@Test func `handle invoke browser proxy uses injected request`() async {
let runtime = MacNodeRuntime(browserProxyRequest: { paramsJSON in
#expect(paramsJSON?.contains("/tabs") == true)
return #"{"result":{"ok":true,"tabs":[{"id":"tab-1"}]}}"#
})
let paramsJSON = #"{"method":"GET","path":"/tabs","timeoutMs":2500}"#
let response = await runtime.handleInvoke(
BridgeInvokeRequest(id: "req-browser", command: OpenClawBrowserCommand.proxy.rawValue, paramsJSON: paramsJSON))
BridgeInvokeRequest(
id: "req-browser",
command: OpenClawBrowserCommand.proxy.rawValue,
paramsJSON: paramsJSON))
#expect(response.ok == true)
#expect(response.payloadJSON == #"{"result":{"ok":true,"tabs":[{"id":"tab-1"}]}}"#)
}
@Test func handleInvokeBrowserProxyRejectsDisabledBrowserControl() async throws {
@Test func `handle invoke browser proxy rejects disabled browser control`() async throws {
let override = TestIsolation.tempConfigPath()
try await TestIsolation.withEnvValues(["OPENCLAW_CONFIG_PATH": override]) {
try JSONSerialization.data(withJSONObject: ["browser": ["enabled": false]])

View File

@@ -6,7 +6,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct MasterDiscoveryMenuSmokeTests {
@Test func inlineListBuildsBodyWhenEmpty() {
@Test func `inline list builds body when empty`() {
let discovery = GatewayDiscoveryModel(localDisplayName: InstanceIdentity.displayName)
discovery.statusText = "Searching…"
discovery.gateways = []
@@ -20,7 +20,7 @@ struct MasterDiscoveryMenuSmokeTests {
_ = view.body
}
@Test func inlineListBuildsBodyWithMasterAndSelection() {
@Test func `inline list builds body with master and selection`() {
let discovery = GatewayDiscoveryModel(localDisplayName: InstanceIdentity.displayName)
discovery.statusText = "Found 1"
discovery.gateways = [
@@ -46,7 +46,7 @@ struct MasterDiscoveryMenuSmokeTests {
_ = view.body
}
@Test func menuBuildsBodyWithMasters() {
@Test func `menu builds body with masters`() {
let discovery = GatewayDiscoveryModel(localDisplayName: InstanceIdentity.displayName)
discovery.statusText = "Found 2"
discovery.gateways = [

View File

@@ -5,28 +5,28 @@ import Testing
@Suite(.serialized)
@MainActor
struct MenuContentSmokeTests {
@Test func menuContentBuildsBodyLocalMode() {
@Test func `menu content builds body local mode`() {
let state = AppState(preview: true)
state.connectionMode = .local
let view = MenuContent(state: state, updater: nil)
_ = view.body
}
@Test func menuContentBuildsBodyRemoteMode() {
@Test func `menu content builds body remote mode`() {
let state = AppState(preview: true)
state.connectionMode = .remote
let view = MenuContent(state: state, updater: nil)
_ = view.body
}
@Test func menuContentBuildsBodyUnconfiguredMode() {
@Test func `menu content builds body unconfigured mode`() {
let state = AppState(preview: true)
state.connectionMode = .unconfigured
let view = MenuContent(state: state, updater: nil)
_ = view.body
}
@Test func menuContentBuildsBodyWithDebugAndCanvas() {
@Test func `menu content builds body with debug and canvas`() {
let state = AppState(preview: true)
state.connectionMode = .local
state.debugPaneEnabled = true

View File

@@ -5,7 +5,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct MenuSessionsInjectorTests {
@Test func injectsDisconnectedMessage() {
@Test func `injects disconnected message`() {
let injector = MenuSessionsInjector()
injector.setTestingControlChannelConnected(false)
injector.setTestingSnapshot(nil, errorText: nil)
@@ -19,7 +19,7 @@ struct MenuSessionsInjectorTests {
#expect(menu.items.contains { $0.tag == 9_415_557 })
}
@Test func injectsSessionRows() {
@Test func `injects session rows`() {
let injector = MenuSessionsInjector()
injector.setTestingControlChannelConnected(true)
@@ -94,7 +94,7 @@ struct MenuSessionsInjectorTests {
#expect(menu.items.contains { $0.tag == 9_415_557 && $0.isSeparatorItem })
}
@Test func costUsageSubmenuDoesNotUseInjectorDelegate() {
@Test func `cost usage submenu does not use injector delegate`() {
let injector = MenuSessionsInjector()
injector.setTestingControlChannelConnected(true)

View File

@@ -2,10 +2,9 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite
struct ModelCatalogLoaderTests {
@Test
func loadParsesModelsFromTypeScriptAndSorts() async throws {
func `load parses models from type script and sorts`() async throws {
let src = """
export const MODELS = {
openai: {
@@ -40,7 +39,7 @@ struct ModelCatalogLoaderTests {
}
@Test
func loadWithNoExportReturnsEmptyChoices() async throws {
func `load with no export returns empty choices`() async throws {
let src = "const NOPE = 1;"
let tmp = FileManager().temporaryDirectory
.appendingPathComponent("models-\(UUID().uuidString).ts")

View File

@@ -4,7 +4,7 @@ import Testing
@Suite(.serialized)
struct NixModeStableSuiteTests {
@Test func resolvesFromStableSuiteForAppBundles() throws {
@Test func `resolves from stable suite for app bundles`() throws {
let suite = try #require(UserDefaults(suiteName: launchdLabel))
let key = "openclaw.nixMode"
let prev = suite.object(forKey: key)
@@ -25,7 +25,7 @@ struct NixModeStableSuiteTests {
#expect(resolved)
}
@Test func ignoresStableSuiteOutsideAppBundles() throws {
@Test func `ignores stable suite outside app bundles`() throws {
let suite = try #require(UserDefaults(suiteName: launchdLabel))
let key = "openclaw.nixMode"
let prev = suite.object(forKey: key)

View File

@@ -2,8 +2,8 @@ import Foundation
import Testing
@testable import OpenClaw
@Suite struct NodeManagerPathsTests {
@Test func fnmNodeBinsPreferNewestInstalledVersion() throws {
struct NodeManagerPathsTests {
@Test func `fnm node bins prefer newest installed version`() throws {
let home = try makeTempDirForTests()
let v20Bin = home
@@ -18,7 +18,7 @@ import Testing
#expect(bins.contains(v20Bin.deletingLastPathComponent().path))
}
@Test func ignoresEntriesWithoutNodeExecutable() throws {
@Test func `ignores entries without node executable`() throws {
let home = try makeTempDirForTests()
let missingNodeBin = home
.appendingPathComponent(".local/share/fnm/node-versions/v99.0.0/installation/bin")

View File

@@ -4,7 +4,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct NodePairingApprovalPrompterTests {
@Test func nodePairingApprovalPrompterExercises() async {
@Test func `node pairing approval prompter exercises`() async {
await NodePairingApprovalPrompter.exerciseForTesting()
}
}

View File

@@ -1,14 +1,14 @@
import Testing
@testable import OpenClaw
@Suite struct NodePairingReconcilePolicyTests {
@Test func policyPollsOnlyWhenActive() {
struct NodePairingReconcilePolicyTests {
@Test func `policy polls only when active`() {
#expect(NodePairingReconcilePolicy.shouldPoll(pendingCount: 0, isPresenting: false) == false)
#expect(NodePairingReconcilePolicy.shouldPoll(pendingCount: 1, isPresenting: false))
#expect(NodePairingReconcilePolicy.shouldPoll(pendingCount: 0, isPresenting: true))
}
@Test func policyUsesSlowSafetyInterval() {
@Test func `policy uses slow safety interval`() {
#expect(NodePairingReconcilePolicy.activeIntervalMs >= 10000)
}
}

View File

@@ -4,7 +4,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct OnboardingCoverageTests {
@Test func exerciseOnboardingPages() {
@Test func `exercise onboarding pages`() {
OnboardingView.exerciseForTesting()
}
}

View File

@@ -7,7 +7,7 @@ import Testing
@Suite(.serialized)
@MainActor
struct OnboardingViewSmokeTests {
@Test func onboardingViewBuildsBody() {
@Test func `onboarding view builds body`() {
let state = AppState(preview: true)
let view = OnboardingView(
state: state,
@@ -16,18 +16,18 @@ struct OnboardingViewSmokeTests {
_ = view.body
}
@Test func pageOrderOmitsWorkspaceAndIdentitySteps() {
@Test func `page order omits workspace and identity steps`() {
let order = OnboardingView.pageOrder(for: .local, showOnboardingChat: false)
#expect(!order.contains(7))
#expect(order.contains(3))
}
@Test func pageOrderOmitsOnboardingChatWhenIdentityKnown() {
@Test func `page order omits onboarding chat when identity known`() {
let order = OnboardingView.pageOrder(for: .local, showOnboardingChat: false)
#expect(!order.contains(8))
}
@Test func selectRemoteGatewayClearsStaleSshTargetWhenEndpointUnresolved() async {
@Test func `select remote gateway clears stale ssh target when endpoint unresolved`() async {
let override = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-config-\(UUID().uuidString)")
.appendingPathComponent("openclaw.json")

View File

@@ -8,7 +8,7 @@ private typealias ProtoAnyCodable = OpenClawProtocol.AnyCodable
@Suite(.serialized)
@MainActor
struct OnboardingWizardStepViewTests {
@Test func noteStepBuilds() {
@Test func `note step builds`() {
let step = WizardStep(
id: "step-1",
type: ProtoAnyCodable("note"),
@@ -23,7 +23,7 @@ struct OnboardingWizardStepViewTests {
_ = view.body
}
@Test func selectStepBuilds() {
@Test func `select step builds`() {
let options: [[String: ProtoAnyCodable]] = [
["value": ProtoAnyCodable("local"), "label": ProtoAnyCodable("Local"), "hint": ProtoAnyCodable("This Mac")],
["value": ProtoAnyCodable("remote"), "label": ProtoAnyCodable("Remote")],

View File

@@ -12,8 +12,8 @@ struct OpenClawConfigFileTests {
}
@Test
func configPathRespectsEnvOverride() async {
let override = makeConfigOverridePath()
func `config path respects env override`() async {
let override = self.makeConfigOverridePath()
await TestIsolation.withEnvValues(["OPENCLAW_CONFIG_PATH": override]) {
#expect(OpenClawConfigFile.url().path == override)
@@ -22,8 +22,8 @@ struct OpenClawConfigFileTests {
@MainActor
@Test
func remoteGatewayPortParsesAndMatchesHost() async {
let override = makeConfigOverridePath()
func `remote gateway port parses and matches host`() async {
let override = self.makeConfigOverridePath()
await TestIsolation.withEnvValues(["OPENCLAW_CONFIG_PATH": override]) {
OpenClawConfigFile.saveDict([
@@ -42,8 +42,8 @@ struct OpenClawConfigFileTests {
@MainActor
@Test
func setRemoteGatewayUrlPreservesScheme() async {
let override = makeConfigOverridePath()
func `set remote gateway url preserves scheme`() async {
let override = self.makeConfigOverridePath()
await TestIsolation.withEnvValues(["OPENCLAW_CONFIG_PATH": override]) {
OpenClawConfigFile.saveDict([
@@ -62,8 +62,8 @@ struct OpenClawConfigFileTests {
@MainActor
@Test
func clearRemoteGatewayUrlRemovesOnlyUrlField() async {
let override = makeConfigOverridePath()
func `clear remote gateway url removes only url field`() async {
let override = self.makeConfigOverridePath()
await TestIsolation.withEnvValues(["OPENCLAW_CONFIG_PATH": override]) {
OpenClawConfigFile.saveDict([
@@ -83,7 +83,7 @@ struct OpenClawConfigFileTests {
}
@Test
func stateDirOverrideSetsConfigPath() async {
func `state dir override sets config path`() async {
let dir = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-state-\(UUID().uuidString)", isDirectory: true)
.path
@@ -99,7 +99,7 @@ struct OpenClawConfigFileTests {
@MainActor
@Test
func saveDictAppendsConfigAuditLog() async throws {
func `save dict appends config audit log`() async throws {
let stateDir = FileManager().temporaryDirectory
.appendingPathComponent("openclaw-state-\(UUID().uuidString)", isDirectory: true)
let configPath = stateDir.appendingPathComponent("openclaw.json")

View File

@@ -2,16 +2,15 @@ import CoreLocation
import Testing
@testable import OpenClaw
@Suite("PermissionManager Location")
struct PermissionManagerLocationTests {
@Test("authorizedAlways counts for both modes")
func authorizedAlwaysCountsForBothModes() {
@Test
func `authorizedAlways counts for both modes`() {
#expect(PermissionManager.isLocationAuthorized(status: .authorizedAlways, requireAlways: false))
#expect(PermissionManager.isLocationAuthorized(status: .authorizedAlways, requireAlways: true))
}
@Test("other statuses not authorized")
func otherStatusesNotAuthorized() {
@Test
func `other statuses not authorized`() {
#expect(!PermissionManager.isLocationAuthorized(status: .notDetermined, requireAlways: false))
#expect(!PermissionManager.isLocationAuthorized(status: .denied, requireAlways: false))
#expect(!PermissionManager.isLocationAuthorized(status: .restricted, requireAlways: false))

View File

@@ -6,31 +6,31 @@ import Testing
@Suite(.serialized)
@MainActor
struct PermissionManagerTests {
@Test func voiceWakePermissionHelpersMatchStatus() async {
@Test func `voice wake permission helpers match status`() async {
let direct = PermissionManager.voiceWakePermissionsGranted()
let ensured = await PermissionManager.ensureVoiceWakePermissions(interactive: false)
#expect(ensured == direct)
}
@Test func statusCanQueryNonInteractiveCaps() async {
@Test func `status can query non interactive caps`() async {
let caps: [Capability] = [.microphone, .speechRecognition, .screenRecording]
let status = await PermissionManager.status(caps)
#expect(status.keys.count == caps.count)
}
@Test func ensureNonInteractiveDoesNotThrow() async {
@Test func `ensure non interactive does not throw`() async {
let caps: [Capability] = [.microphone, .speechRecognition, .screenRecording]
let ensured = await PermissionManager.ensure(caps, interactive: false)
#expect(ensured.keys.count == caps.count)
}
@Test func locationStatusMatchesAuthorizationAlways() async {
@Test func `location status matches authorization always`() async {
let status = CLLocationManager().authorizationStatus
let results = await PermissionManager.status([.location])
#expect(results[.location] == (status == .authorizedAlways))
}
@Test func ensureLocationNonInteractiveMatchesAuthorizationAlways() async {
@Test func `ensure location non interactive matches authorization always`() async {
let status = CLLocationManager().authorizationStatus
let ensured = await PermissionManager.ensure([.location], interactive: false)
#expect(ensured[.location] == (status == .authorizedAlways))

View File

@@ -1,6 +1,6 @@
import Testing
@Suite struct PlaceholderTests {
struct PlaceholderTests {
@Test func placeholder() {
#expect(true)
}

Some files were not shown because too many files have changed in this diff Show More