diff --git a/apps/macos/Tests/ClawdisIPCTests/AgentIdentityTests.swift b/apps/macos/Tests/ClawdisIPCTests/AgentIdentityTests.swift new file mode 100644 index 000000000..b326e6146 --- /dev/null +++ b/apps/macos/Tests/ClawdisIPCTests/AgentIdentityTests.swift @@ -0,0 +1,21 @@ +import Foundation +import Testing +@testable import Clawdis + +@Suite +struct AgentIdentityTests { + @Test + func isEmptyTreatsWhitespaceAsEmpty() { + #expect(AgentIdentity(name: " ", theme: "\n", emoji: "\t").isEmpty == true) + #expect(AgentIdentity(name: "Pi", theme: "", emoji: "").isEmpty == false) + } + + @Test + func emojiSuggestMatchesKnownThemes() { + #expect(AgentIdentityEmoji.suggest(theme: "") == "🦞") + #expect(AgentIdentityEmoji.suggest(theme: "shark") == "🦈") + #expect(AgentIdentityEmoji.suggest(theme: " Octopus helper ") == "🐙") + #expect(AgentIdentityEmoji.suggest(theme: "unknown") == "🦞") + } +} + diff --git a/apps/macos/Tests/ClawdisIPCTests/ControlRequestHandlerTests.swift b/apps/macos/Tests/ClawdisIPCTests/ControlRequestHandlerTests.swift index 9145ad31d..892e4b806 100644 --- a/apps/macos/Tests/ClawdisIPCTests/ControlRequestHandlerTests.swift +++ b/apps/macos/Tests/ClawdisIPCTests/ControlRequestHandlerTests.swift @@ -5,6 +5,28 @@ import Testing @Suite(.serialized) struct ControlRequestHandlerTests { + private static func withDefaultOverride( + _ key: String, + value: Any?, + operation: () async throws -> T) async rethrows -> T + { + let defaults = UserDefaults.standard + let previous = defaults.object(forKey: key) + if let value { + defaults.set(value, forKey: key) + } else { + defaults.removeObject(forKey: key) + } + defer { + if let previous { + defaults.set(previous, forKey: key) + } else { + defaults.removeObject(forKey: key) + } + } + return try await operation() + } + @Test func statusReturnsReadyWhenNotPaused() async throws { let defaults = UserDefaults.standard @@ -58,5 +80,94 @@ struct ControlRequestHandlerTests { #expect(res.ok == false) #expect(res.message == "clawdis paused") } -} + @Test + func agentRejectsEmptyMessage() async throws { + let res = try await Self.withDefaultOverride(pauseDefaultsKey, value: false) { + try await ControlRequestHandler.process(request: .agent( + message: " ", + thinking: nil, + session: nil, + deliver: false, + to: nil)) + } + #expect(res.ok == false) + #expect(res.message == "message empty") + } + + @Test + func runShellEchoReturnsPayload() async throws { + let res = try await Self.withDefaultOverride(pauseDefaultsKey, value: false) { + try await ControlRequestHandler.process(request: .runShell( + command: ["echo", "hello"], + cwd: nil, + env: nil, + timeoutSec: nil, + needsScreenRecording: false)) + } + #expect(res.ok == true) + #expect(String(data: res.payload ?? Data(), encoding: .utf8) == "hello\n") + } + + @Test + func cameraRequestsReturnDisabledWhenCameraDisabled() async throws { + let snap = try await Self.withDefaultOverride(pauseDefaultsKey, value: false) { + try await Self.withDefaultOverride(cameraEnabledKey, value: false) { + try await ControlRequestHandler.process(request: .cameraSnap( + facing: nil, + maxWidth: nil, + quality: nil, + outPath: nil)) + } + } + #expect(snap.ok == false) + #expect(snap.message == "Camera disabled by user") + + let clip = try await Self.withDefaultOverride(pauseDefaultsKey, value: false) { + try await Self.withDefaultOverride(cameraEnabledKey, value: false) { + try await ControlRequestHandler.process(request: .cameraClip( + facing: nil, + durationMs: nil, + includeAudio: true, + outPath: nil)) + } + } + #expect(clip.ok == false) + #expect(clip.message == "Camera disabled by user") + } + + @Test + func canvasRequestsReturnDisabledWhenCanvasDisabled() async throws { + let show = try await Self.withDefaultOverride(pauseDefaultsKey, value: false) { + try await Self.withDefaultOverride(canvasEnabledKey, value: false) { + try await ControlRequestHandler.process(request: .canvasShow(session: "s", path: nil, placement: nil)) + } + } + #expect(show.ok == false) + #expect(show.message == "Canvas disabled by user") + + let goto = try await Self.withDefaultOverride(pauseDefaultsKey, value: false) { + try await Self.withDefaultOverride(canvasEnabledKey, value: false) { + try await ControlRequestHandler.process(request: .canvasGoto(session: "s", path: "/tmp", placement: nil)) + } + } + #expect(goto.ok == false) + #expect(goto.message == "Canvas disabled by user") + + let eval = try await Self.withDefaultOverride(pauseDefaultsKey, value: false) { + try await Self.withDefaultOverride(canvasEnabledKey, value: false) { + try await ControlRequestHandler.process(request: .canvasEval(session: "s", javaScript: "1+1")) + } + } + #expect(eval.ok == false) + #expect(eval.message == "Canvas disabled by user") + + let snap = try await Self.withDefaultOverride(pauseDefaultsKey, value: false) { + try await Self.withDefaultOverride(canvasEnabledKey, value: false) { + try await ControlRequestHandler.process(request: .canvasSnapshot(session: "s", outPath: nil)) + } + } + #expect(snap.ok == false) + #expect(snap.message == "Canvas disabled by user") + } +} diff --git a/apps/macos/Tests/ClawdisIPCTests/ScreenshotSizeTests.swift b/apps/macos/Tests/ClawdisIPCTests/ScreenshotSizeTests.swift new file mode 100644 index 000000000..47d92a84c --- /dev/null +++ b/apps/macos/Tests/ClawdisIPCTests/ScreenshotSizeTests.swift @@ -0,0 +1,22 @@ +import Foundation +import Testing +@testable import Clawdis + +@Suite +struct ScreenshotSizeTests { + @Test + func readPNGSizeReturnsDimensions() throws { + let pngBase64 = + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+WZxkAAAAASUVORK5CYII=" + let data = try #require(Data(base64Encoded: pngBase64)) + let size = ScreenshotSize.readPNGSize(data: data) + #expect(size?.width == 1) + #expect(size?.height == 1) + } + + @Test + func readPNGSizeRejectsNonPNGData() { + #expect(ScreenshotSize.readPNGSize(data: Data("nope".utf8)) == nil) + } +} +