test: expand menu and node coverage
This commit is contained in:
10
apps/macos/Tests/ClawdisIPCTests/BridgeServerTests.swift
Normal file
10
apps/macos/Tests/ClawdisIPCTests/BridgeServerTests.swift
Normal file
@@ -0,0 +1,10 @@
|
||||
import Testing
|
||||
@testable import Clawdis
|
||||
|
||||
@Suite(.serialized)
|
||||
struct BridgeServerTests {
|
||||
@Test func bridgeServerExercisesPaths() async {
|
||||
let server = BridgeServer()
|
||||
await server.exerciseForTesting()
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import Darwin
|
||||
import Foundation
|
||||
import Network
|
||||
import Testing
|
||||
@@ -39,17 +40,7 @@ import Testing
|
||||
|
||||
@MainActor
|
||||
@Test func probeEndpointFailsForClosedPort() async throws {
|
||||
let listener = try NWListener(using: .tcp, on: .any)
|
||||
listener.start(queue: DispatchQueue(label: "com.steipete.clawdis.tests.bridge-listener-close"))
|
||||
try await waitForListenerReady(listener, timeoutSeconds: 1.0)
|
||||
let port = listener.port
|
||||
listener.cancel()
|
||||
try await Task.sleep(nanoseconds: 150_000_000)
|
||||
|
||||
guard let port else {
|
||||
throw TestError(message: "listener port missing")
|
||||
}
|
||||
|
||||
let port = try reserveEphemeralPort()
|
||||
let endpoint = NWEndpoint.hostPort(host: "127.0.0.1", port: port)
|
||||
let ok = await MacNodeModeCoordinator.probeEndpoint(endpoint, timeoutSeconds: 0.4)
|
||||
#expect(ok == false)
|
||||
@@ -118,3 +109,43 @@ private func withEnv(_ key: String, value: String?, _ body: () -> Void) {
|
||||
}
|
||||
body()
|
||||
}
|
||||
|
||||
private func reserveEphemeralPort() throws -> NWEndpoint.Port {
|
||||
let fd = socket(AF_INET, SOCK_STREAM, 0)
|
||||
if fd < 0 {
|
||||
throw TestError(message: "socket failed")
|
||||
}
|
||||
defer { close(fd) }
|
||||
|
||||
var addr = sockaddr_in()
|
||||
addr.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
|
||||
addr.sin_family = sa_family_t(AF_INET)
|
||||
addr.sin_port = in_port_t(0)
|
||||
addr.sin_addr = in_addr(s_addr: inet_addr("127.0.0.1"))
|
||||
|
||||
let bindResult = withUnsafePointer(to: &addr) { pointer -> Int32 in
|
||||
pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) {
|
||||
Darwin.bind(fd, $0, socklen_t(MemoryLayout<sockaddr_in>.size))
|
||||
}
|
||||
}
|
||||
if bindResult != 0 {
|
||||
throw TestError(message: "bind failed")
|
||||
}
|
||||
|
||||
var resolved = sockaddr_in()
|
||||
var length = socklen_t(MemoryLayout<sockaddr_in>.size)
|
||||
let nameResult = withUnsafeMutablePointer(to: &resolved) { pointer -> Int32 in
|
||||
pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) {
|
||||
getsockname(fd, $0, &length)
|
||||
}
|
||||
}
|
||||
if nameResult != 0 {
|
||||
throw TestError(message: "getsockname failed")
|
||||
}
|
||||
|
||||
let port = UInt16(bigEndian: resolved.sin_port)
|
||||
guard let endpointPort = NWEndpoint.Port(rawValue: port), endpointPort.rawValue != 0 else {
|
||||
throw TestError(message: "ephemeral port missing")
|
||||
}
|
||||
return endpointPort
|
||||
}
|
||||
|
||||
32
apps/macos/Tests/ClawdisIPCTests/MacNodeRuntimeTests.swift
Normal file
32
apps/macos/Tests/ClawdisIPCTests/MacNodeRuntimeTests.swift
Normal file
@@ -0,0 +1,32 @@
|
||||
import ClawdisKit
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import Clawdis
|
||||
|
||||
@Suite(.serialized)
|
||||
struct MacNodeRuntimeTests {
|
||||
@Test func handleInvokeRejectsUnknownCommand() 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 {
|
||||
let runtime = MacNodeRuntime()
|
||||
let params = ClawdisSystemRunParams(command: [])
|
||||
let json = String(data: try JSONEncoder().encode(params), encoding: .utf8)
|
||||
let response = await runtime.handleInvoke(
|
||||
BridgeInvokeRequest(id: "req-2", command: ClawdisSystemCommand.run.rawValue, paramsJSON: json))
|
||||
#expect(response.ok == false)
|
||||
}
|
||||
|
||||
@Test func handleInvokeRejectsEmptyNotification() async throws {
|
||||
let runtime = MacNodeRuntime()
|
||||
let params = ClawdisSystemNotifyParams(title: "", body: "")
|
||||
let json = String(data: try JSONEncoder().encode(params), encoding: .utf8)
|
||||
let response = await runtime.handleInvoke(
|
||||
BridgeInvokeRequest(id: "req-3", command: ClawdisSystemCommand.notify.rawValue, paramsJSON: json))
|
||||
#expect(response.ok == false)
|
||||
}
|
||||
}
|
||||
@@ -25,4 +25,17 @@ struct MenuContentSmokeTests {
|
||||
let view = MenuContent(state: state, updater: nil)
|
||||
_ = view.body
|
||||
}
|
||||
|
||||
@Test func menuContentBuildsBodyWithDebugAndCanvas() {
|
||||
let state = AppState(preview: true)
|
||||
state.connectionMode = .local
|
||||
state.debugPaneEnabled = true
|
||||
state.canvasEnabled = true
|
||||
state.canvasPanelVisible = true
|
||||
state.swabbleEnabled = true
|
||||
state.voicePushToTalkEnabled = true
|
||||
state.heartbeatsEnabled = true
|
||||
let view = MenuContent(state: state, updater: nil)
|
||||
_ = view.body
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
import AppKit
|
||||
import Testing
|
||||
@testable import Clawdis
|
||||
|
||||
@Suite(.serialized)
|
||||
@MainActor
|
||||
struct MenuSessionsInjectorTests {
|
||||
@Test func injectsDisconnectedMessage() {
|
||||
let injector = MenuSessionsInjector()
|
||||
injector.setTestingControlChannelConnected(false)
|
||||
injector.setTestingSnapshot(nil, errorText: nil)
|
||||
|
||||
let menu = NSMenu()
|
||||
menu.addItem(NSMenuItem(title: "Header", action: nil, keyEquivalent: ""))
|
||||
menu.addItem(.separator())
|
||||
menu.addItem(NSMenuItem(title: "Send Heartbeats", action: nil, keyEquivalent: ""))
|
||||
|
||||
injector.injectForTesting(into: menu)
|
||||
#expect(menu.items.contains { $0.tag == 9_415_557 })
|
||||
}
|
||||
|
||||
@Test func injectsSessionRows() {
|
||||
let injector = MenuSessionsInjector()
|
||||
injector.setTestingControlChannelConnected(true)
|
||||
|
||||
let defaults = SessionDefaults(model: "claude-opus-4-5", contextTokens: 200_000)
|
||||
let rows = [
|
||||
SessionRow(
|
||||
id: "main",
|
||||
key: "main",
|
||||
kind: .direct,
|
||||
updatedAt: Date(),
|
||||
sessionId: "s1",
|
||||
thinkingLevel: "low",
|
||||
verboseLevel: nil,
|
||||
systemSent: false,
|
||||
abortedLastRun: false,
|
||||
tokens: SessionTokenStats(input: 10, output: 20, total: 30, contextTokens: 200_000),
|
||||
model: "claude-opus-4-5"),
|
||||
SessionRow(
|
||||
id: "group:alpha",
|
||||
key: "group:alpha",
|
||||
kind: .group,
|
||||
updatedAt: Date(timeIntervalSinceNow: -60),
|
||||
sessionId: "s2",
|
||||
thinkingLevel: "high",
|
||||
verboseLevel: "debug",
|
||||
systemSent: true,
|
||||
abortedLastRun: true,
|
||||
tokens: SessionTokenStats(input: 50, output: 50, total: 100, contextTokens: 200_000),
|
||||
model: "claude-opus-4-5"),
|
||||
]
|
||||
let snapshot = SessionStoreSnapshot(
|
||||
storePath: "/tmp/sessions.json",
|
||||
defaults: defaults,
|
||||
rows: rows)
|
||||
injector.setTestingSnapshot(snapshot, errorText: nil)
|
||||
|
||||
let menu = NSMenu()
|
||||
menu.addItem(NSMenuItem(title: "Header", action: nil, keyEquivalent: ""))
|
||||
menu.addItem(.separator())
|
||||
menu.addItem(NSMenuItem(title: "Send Heartbeats", action: nil, keyEquivalent: ""))
|
||||
|
||||
injector.injectForTesting(into: menu)
|
||||
#expect(menu.items.contains { $0.tag == 9_415_557 })
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import Testing
|
||||
@testable import Clawdis
|
||||
|
||||
@Suite(.serialized)
|
||||
@MainActor
|
||||
struct NodePairingApprovalPrompterTests {
|
||||
@Test func nodePairingApprovalPrompterExercises() async {
|
||||
await NodePairingApprovalPrompter.exerciseForTesting()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user