mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-28 21:01:43 +03:00
Revert "iOS: wire node services and tests"
This reverts commit 7b0a0f3dac.
This commit is contained in:
@@ -1,20 +0,0 @@
|
||||
import Contacts
|
||||
import Testing
|
||||
@testable import OpenClaw
|
||||
|
||||
@Suite(.serialized) struct ContactsServiceTests {
|
||||
@Test func matchesPhoneOrEmailForDedupe() {
|
||||
let contact = CNMutableContact()
|
||||
contact.givenName = "Test"
|
||||
contact.phoneNumbers = [
|
||||
CNLabeledValue(label: CNLabelPhoneNumberMobile, value: CNPhoneNumber(stringValue: "+1 (555) 000-0000")),
|
||||
]
|
||||
contact.emailAddresses = [
|
||||
CNLabeledValue(label: CNLabelHome, value: "test@example.com" as NSString),
|
||||
]
|
||||
|
||||
#expect(ContactsService._test_matches(contact: contact, phoneNumbers: ["15550000000"], emails: []))
|
||||
#expect(ContactsService._test_matches(contact: contact, phoneNumbers: [], emails: ["TEST@example.com"]))
|
||||
#expect(!ContactsService._test_matches(contact: contact, phoneNumbers: ["999"], emails: ["nope@example.com"]))
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,6 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
|
||||
|
||||
let resolved = controller._test_resolvedDisplayName(defaults: defaults)
|
||||
#expect(!resolved.isEmpty)
|
||||
#expect(resolved != "iOS Node")
|
||||
#expect(defaults.string(forKey: displayKey) == resolved)
|
||||
}
|
||||
}
|
||||
@@ -62,11 +61,6 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
|
||||
#expect(caps.contains(OpenClawCapability.camera.rawValue))
|
||||
#expect(caps.contains(OpenClawCapability.location.rawValue))
|
||||
#expect(caps.contains(OpenClawCapability.voiceWake.rawValue))
|
||||
#expect(caps.contains(OpenClawCapability.device.rawValue))
|
||||
#expect(caps.contains(OpenClawCapability.photos.rawValue))
|
||||
#expect(caps.contains(OpenClawCapability.contacts.rawValue))
|
||||
#expect(caps.contains(OpenClawCapability.calendar.rawValue))
|
||||
#expect(caps.contains(OpenClawCapability.reminders.rawValue))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,48 +76,4 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
|
||||
#expect(commands.contains(OpenClawLocationCommand.get.rawValue))
|
||||
}
|
||||
}
|
||||
|
||||
@Test @MainActor func currentCommandsExcludeShellAndIncludeNotifyAndDevice() {
|
||||
withUserDefaults([
|
||||
"node.instanceId": "ios-test",
|
||||
]) {
|
||||
let appModel = NodeAppModel()
|
||||
let controller = GatewayConnectionController(appModel: appModel, startDiscovery: false)
|
||||
let commands = Set(controller._test_currentCommands())
|
||||
|
||||
#expect(commands.contains(OpenClawSystemCommand.notify.rawValue))
|
||||
#expect(commands.contains(OpenClawChatCommand.push.rawValue))
|
||||
#expect(!commands.contains(OpenClawSystemCommand.run.rawValue))
|
||||
#expect(!commands.contains(OpenClawSystemCommand.which.rawValue))
|
||||
#expect(!commands.contains(OpenClawSystemCommand.execApprovalsGet.rawValue))
|
||||
#expect(!commands.contains(OpenClawSystemCommand.execApprovalsSet.rawValue))
|
||||
|
||||
#expect(commands.contains(OpenClawDeviceCommand.status.rawValue))
|
||||
#expect(commands.contains(OpenClawDeviceCommand.info.rawValue))
|
||||
#expect(commands.contains(OpenClawContactsCommand.add.rawValue))
|
||||
#expect(commands.contains(OpenClawCalendarCommand.add.rawValue))
|
||||
#expect(commands.contains(OpenClawRemindersCommand.add.rawValue))
|
||||
#expect(commands.contains(OpenClawTalkCommand.pttStart.rawValue))
|
||||
#expect(commands.contains(OpenClawTalkCommand.pttStop.rawValue))
|
||||
#expect(commands.contains(OpenClawTalkCommand.pttCancel.rawValue))
|
||||
#expect(commands.contains(OpenClawTalkCommand.pttOnce.rawValue))
|
||||
}
|
||||
}
|
||||
|
||||
@Test @MainActor func currentPermissionsIncludeExpectedKeys() {
|
||||
let appModel = NodeAppModel()
|
||||
let controller = GatewayConnectionController(appModel: appModel, startDiscovery: false)
|
||||
let permissions = controller._test_currentPermissions()
|
||||
let keys = Set(permissions.keys)
|
||||
|
||||
#expect(keys.contains("camera"))
|
||||
#expect(keys.contains("microphone"))
|
||||
#expect(keys.contains("location"))
|
||||
#expect(keys.contains("screenRecording"))
|
||||
#expect(keys.contains("photos"))
|
||||
#expect(keys.contains("contacts"))
|
||||
#expect(keys.contains("calendar"))
|
||||
#expect(keys.contains("reminders"))
|
||||
#expect(keys.contains("motion"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,60 +0,0 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import OpenClaw
|
||||
|
||||
private actor Counter {
|
||||
private var value = 0
|
||||
|
||||
func increment() {
|
||||
value += 1
|
||||
}
|
||||
|
||||
func get() -> Int {
|
||||
value
|
||||
}
|
||||
|
||||
func set(_ newValue: Int) {
|
||||
value = newValue
|
||||
}
|
||||
}
|
||||
|
||||
@Suite struct GatewayHealthMonitorTests {
|
||||
@Test @MainActor func triggersFailureAfterThreshold() async {
|
||||
let failureCount = Counter()
|
||||
let monitor = GatewayHealthMonitor(
|
||||
config: .init(intervalSeconds: 0.001, timeoutSeconds: 0.0, maxFailures: 2))
|
||||
|
||||
monitor.start(
|
||||
check: { false },
|
||||
onFailure: { _ in
|
||||
await failureCount.increment()
|
||||
await monitor.stop()
|
||||
})
|
||||
|
||||
try? await Task.sleep(nanoseconds: 60_000_000)
|
||||
#expect(await failureCount.get() == 1)
|
||||
}
|
||||
|
||||
@Test @MainActor func resetsFailuresAfterSuccess() async {
|
||||
let failureCount = Counter()
|
||||
let calls = Counter()
|
||||
let monitor = GatewayHealthMonitor(
|
||||
config: .init(intervalSeconds: 0.001, timeoutSeconds: 0.0, maxFailures: 2))
|
||||
|
||||
monitor.start(
|
||||
check: {
|
||||
await calls.increment()
|
||||
let callCount = await calls.get()
|
||||
if callCount >= 6 {
|
||||
await monitor.stop()
|
||||
}
|
||||
return callCount % 2 == 0
|
||||
},
|
||||
onFailure: { _ in
|
||||
await failureCount.increment()
|
||||
})
|
||||
|
||||
try? await Task.sleep(nanoseconds: 60_000_000)
|
||||
#expect(await failureCount.get() == 0)
|
||||
}
|
||||
}
|
||||
@@ -7,14 +7,11 @@ private struct KeychainEntry: Hashable {
|
||||
let account: String
|
||||
}
|
||||
|
||||
private let gatewayService = "ai.openclaw.gateway"
|
||||
private let nodeService = "ai.openclaw.node"
|
||||
private let gatewayService = "bot.molt.gateway"
|
||||
private let nodeService = "bot.molt.node"
|
||||
private let instanceIdEntry = KeychainEntry(service: nodeService, account: "instanceId")
|
||||
private let preferredGatewayEntry = KeychainEntry(service: gatewayService, account: "preferredStableID")
|
||||
private let lastGatewayEntry = KeychainEntry(service: gatewayService, account: "lastDiscoveredStableID")
|
||||
private func gatewayPasswordEntry(instanceId: String) -> KeychainEntry {
|
||||
KeychainEntry(service: gatewayService, account: "gateway-password.\(instanceId)")
|
||||
}
|
||||
|
||||
private func snapshotDefaults(_ keys: [String]) -> [String: Any?] {
|
||||
let defaults = UserDefaults.standard
|
||||
@@ -127,33 +124,4 @@ private func restoreKeychain(_ snapshot: [KeychainEntry: String?]) {
|
||||
#expect(defaults.string(forKey: "gateway.preferredStableID") == "preferred-from-keychain")
|
||||
#expect(defaults.string(forKey: "gateway.lastDiscoveredStableID") == "last-from-keychain")
|
||||
}
|
||||
|
||||
@Test func bootstrapCopiesManualPasswordToKeychainWhenMissing() {
|
||||
let instanceId = "node-test"
|
||||
let defaultsKeys = [
|
||||
"node.instanceId",
|
||||
"gateway.manual.password",
|
||||
]
|
||||
let passwordEntry = gatewayPasswordEntry(instanceId: instanceId)
|
||||
let defaultsSnapshot = snapshotDefaults(defaultsKeys)
|
||||
let keychainSnapshot = snapshotKeychain([passwordEntry, instanceIdEntry])
|
||||
defer {
|
||||
restoreDefaults(defaultsSnapshot)
|
||||
restoreKeychain(keychainSnapshot)
|
||||
}
|
||||
|
||||
applyDefaults([
|
||||
"node.instanceId": instanceId,
|
||||
"gateway.manual.password": "manual-secret",
|
||||
])
|
||||
applyKeychain([
|
||||
passwordEntry: nil,
|
||||
instanceIdEntry: nil,
|
||||
])
|
||||
|
||||
GatewaySettingsStore.bootstrapPersistence()
|
||||
|
||||
#expect(KeychainStore.loadString(service: gatewayService, account: passwordEntry.account) == "manual-secret")
|
||||
#expect(UserDefaults.standard.string(forKey: "gateway.manual.password") != "manual-secret")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import CoreLocation
|
||||
import Foundation
|
||||
import OpenClawKit
|
||||
import Foundation
|
||||
import Testing
|
||||
import UIKit
|
||||
import UserNotifications
|
||||
@testable import OpenClaw
|
||||
|
||||
private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws -> T) rethrows -> T {
|
||||
@@ -31,210 +29,6 @@ private func withUserDefaults<T>(_ updates: [String: Any?], _ body: () throws ->
|
||||
return try body()
|
||||
}
|
||||
|
||||
private final class TestNotificationCenter: NotificationCentering, @unchecked Sendable {
|
||||
private(set) var requestAuthorizationCalls = 0
|
||||
private(set) var addedRequests: [UNNotificationRequest] = []
|
||||
private var status: NotificationAuthorizationStatus
|
||||
|
||||
init(status: NotificationAuthorizationStatus) {
|
||||
self.status = status
|
||||
}
|
||||
|
||||
func authorizationStatus() async -> NotificationAuthorizationStatus {
|
||||
status
|
||||
}
|
||||
|
||||
func requestAuthorization(options: UNAuthorizationOptions) async throws -> Bool {
|
||||
requestAuthorizationCalls += 1
|
||||
status = .authorized
|
||||
return true
|
||||
}
|
||||
|
||||
func add(_ request: UNNotificationRequest) async throws {
|
||||
addedRequests.append(request)
|
||||
}
|
||||
}
|
||||
|
||||
private struct TestCameraService: CameraServicing {
|
||||
func listDevices() async -> [CameraController.CameraDeviceInfo] { [] }
|
||||
func snap(params: OpenClawCameraSnapParams) async throws -> (format: String, base64: String, width: Int, height: Int) {
|
||||
("jpeg", "dGVzdA==", 1, 1)
|
||||
}
|
||||
func clip(params: OpenClawCameraClipParams) async throws -> (format: String, base64: String, durationMs: Int, hasAudio: Bool) {
|
||||
("mp4", "dGVzdA==", 1000, true)
|
||||
}
|
||||
}
|
||||
|
||||
private struct TestScreenRecorder: ScreenRecordingServicing {
|
||||
func record(
|
||||
screenIndex: Int?,
|
||||
durationMs: Int?,
|
||||
fps: Double?,
|
||||
includeAudio: Bool?,
|
||||
outPath: String?) async throws -> String
|
||||
{
|
||||
let url = FileManager.default.temporaryDirectory.appendingPathComponent("openclaw-screen-test.mp4")
|
||||
FileManager.default.createFile(atPath: url.path, contents: Data())
|
||||
return url.path
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private struct TestLocationService: LocationServicing {
|
||||
func authorizationStatus() -> CLAuthorizationStatus { .authorizedWhenInUse }
|
||||
func accuracyAuthorization() -> CLAccuracyAuthorization { .fullAccuracy }
|
||||
func ensureAuthorization(mode: OpenClawLocationMode) async -> CLAuthorizationStatus { .authorizedWhenInUse }
|
||||
func currentLocation(
|
||||
params: OpenClawLocationGetParams,
|
||||
desiredAccuracy: OpenClawLocationAccuracy,
|
||||
maxAgeMs: Int?,
|
||||
timeoutMs: Int?) async throws -> CLLocation
|
||||
{
|
||||
CLLocation(latitude: 37.3349, longitude: -122.0090)
|
||||
}
|
||||
}
|
||||
|
||||
private struct TestDeviceStatusService: DeviceStatusServicing {
|
||||
let statusPayload: OpenClawDeviceStatusPayload
|
||||
let infoPayload: OpenClawDeviceInfoPayload
|
||||
|
||||
func status() async throws -> OpenClawDeviceStatusPayload { statusPayload }
|
||||
func info() -> OpenClawDeviceInfoPayload { infoPayload }
|
||||
}
|
||||
|
||||
private struct TestPhotosService: PhotosServicing {
|
||||
let payload: OpenClawPhotosLatestPayload
|
||||
func latest(params: OpenClawPhotosLatestParams) async throws -> OpenClawPhotosLatestPayload { payload }
|
||||
}
|
||||
|
||||
private struct TestContactsService: ContactsServicing {
|
||||
let searchPayload: OpenClawContactsSearchPayload
|
||||
let addPayload: OpenClawContactsAddPayload
|
||||
func search(params: OpenClawContactsSearchParams) async throws -> OpenClawContactsSearchPayload { searchPayload }
|
||||
func add(params: OpenClawContactsAddParams) async throws -> OpenClawContactsAddPayload { addPayload }
|
||||
}
|
||||
|
||||
private struct TestCalendarService: CalendarServicing {
|
||||
let eventsPayload: OpenClawCalendarEventsPayload
|
||||
let addPayload: OpenClawCalendarAddPayload
|
||||
func events(params: OpenClawCalendarEventsParams) async throws -> OpenClawCalendarEventsPayload { eventsPayload }
|
||||
func add(params: OpenClawCalendarAddParams) async throws -> OpenClawCalendarAddPayload { addPayload }
|
||||
}
|
||||
|
||||
private struct TestRemindersService: RemindersServicing {
|
||||
let listPayload: OpenClawRemindersListPayload
|
||||
let addPayload: OpenClawRemindersAddPayload
|
||||
func list(params: OpenClawRemindersListParams) async throws -> OpenClawRemindersListPayload { listPayload }
|
||||
func add(params: OpenClawRemindersAddParams) async throws -> OpenClawRemindersAddPayload { addPayload }
|
||||
}
|
||||
|
||||
private struct TestMotionService: MotionServicing {
|
||||
let activityPayload: OpenClawMotionActivityPayload
|
||||
let pedometerPayload: OpenClawPedometerPayload
|
||||
|
||||
func activities(params: OpenClawMotionActivityParams) async throws -> OpenClawMotionActivityPayload {
|
||||
activityPayload
|
||||
}
|
||||
|
||||
func pedometer(params: OpenClawPedometerParams) async throws -> OpenClawPedometerPayload {
|
||||
pedometerPayload
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func makeTestAppModel(
|
||||
notificationCenter: NotificationCentering = TestNotificationCenter(status: .authorized),
|
||||
deviceStatusService: DeviceStatusServicing,
|
||||
photosService: PhotosServicing,
|
||||
contactsService: ContactsServicing,
|
||||
calendarService: CalendarServicing,
|
||||
remindersService: RemindersServicing,
|
||||
motionService: MotionServicing,
|
||||
talkMode: TalkModeManager = TalkModeManager(allowSimulatorCapture: true)) -> NodeAppModel
|
||||
{
|
||||
NodeAppModel(
|
||||
screen: ScreenController(),
|
||||
camera: TestCameraService(),
|
||||
screenRecorder: TestScreenRecorder(),
|
||||
locationService: TestLocationService(),
|
||||
notificationCenter: notificationCenter,
|
||||
deviceStatusService: deviceStatusService,
|
||||
photosService: photosService,
|
||||
contactsService: contactsService,
|
||||
calendarService: calendarService,
|
||||
remindersService: remindersService,
|
||||
motionService: motionService,
|
||||
talkMode: talkMode)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func makeTalkTestAppModel(talkMode: TalkModeManager) -> NodeAppModel {
|
||||
makeTestAppModel(
|
||||
deviceStatusService: TestDeviceStatusService(
|
||||
statusPayload: OpenClawDeviceStatusPayload(
|
||||
battery: OpenClawBatteryStatusPayload(level: 0.5, state: .unplugged, lowPowerModeEnabled: false),
|
||||
thermal: OpenClawThermalStatusPayload(state: .nominal),
|
||||
storage: OpenClawStorageStatusPayload(totalBytes: 10, freeBytes: 5, usedBytes: 5),
|
||||
network: OpenClawNetworkStatusPayload(
|
||||
status: .satisfied,
|
||||
isExpensive: false,
|
||||
isConstrained: false,
|
||||
interfaces: [.wifi]),
|
||||
uptimeSeconds: 1),
|
||||
infoPayload: OpenClawDeviceInfoPayload(
|
||||
deviceName: "Test",
|
||||
modelIdentifier: "Test1,1",
|
||||
systemName: "iOS",
|
||||
systemVersion: "1.0",
|
||||
appVersion: "dev",
|
||||
appBuild: "0",
|
||||
locale: "en-US")),
|
||||
photosService: TestPhotosService(payload: OpenClawPhotosLatestPayload(photos: [])),
|
||||
contactsService: TestContactsService(
|
||||
searchPayload: OpenClawContactsSearchPayload(contacts: []),
|
||||
addPayload: OpenClawContactsAddPayload(contact: OpenClawContactPayload(
|
||||
identifier: "c0",
|
||||
displayName: "",
|
||||
givenName: "",
|
||||
familyName: "",
|
||||
organizationName: "",
|
||||
phoneNumbers: [],
|
||||
emails: []))),
|
||||
calendarService: TestCalendarService(
|
||||
eventsPayload: OpenClawCalendarEventsPayload(events: []),
|
||||
addPayload: OpenClawCalendarAddPayload(event: OpenClawCalendarEventPayload(
|
||||
identifier: "e0",
|
||||
title: "Test",
|
||||
startISO: "2024-01-01T00:00:00Z",
|
||||
endISO: "2024-01-01T00:10:00Z",
|
||||
isAllDay: false,
|
||||
location: nil,
|
||||
calendarTitle: nil))),
|
||||
remindersService: TestRemindersService(
|
||||
listPayload: OpenClawRemindersListPayload(reminders: []),
|
||||
addPayload: OpenClawRemindersAddPayload(reminder: OpenClawReminderPayload(
|
||||
identifier: "r0",
|
||||
title: "Test",
|
||||
dueISO: nil,
|
||||
completed: false,
|
||||
listName: nil))),
|
||||
motionService: TestMotionService(
|
||||
activityPayload: OpenClawMotionActivityPayload(activities: []),
|
||||
pedometerPayload: OpenClawPedometerPayload(
|
||||
startISO: "2024-01-01T00:00:00Z",
|
||||
endISO: "2024-01-01T01:00:00Z",
|
||||
steps: nil,
|
||||
distanceMeters: nil,
|
||||
floorsAscended: nil,
|
||||
floorsDescended: nil)),
|
||||
talkMode: talkMode)
|
||||
}
|
||||
|
||||
private func decodePayload<T: Decodable>(_ json: String?, as type: T.Type) throws -> T {
|
||||
let data = try #require(json?.data(using: .utf8))
|
||||
return try JSONDecoder().decode(type, from: data)
|
||||
}
|
||||
|
||||
@Suite(.serialized) struct NodeAppModelInvokeTests {
|
||||
@Test @MainActor func decodeParamsFailsWithoutJSON() {
|
||||
#expect(throws: Error.self) {
|
||||
@@ -330,11 +124,6 @@ private func decodePayload<T: Decodable>(_ json: String?, as type: T.Type) throw
|
||||
let payloadData = try #require(evalRes.payloadJSON?.data(using: .utf8))
|
||||
let payload = try JSONSerialization.jsonObject(with: payloadData) as? [String: Any]
|
||||
#expect(payload?["result"] as? String == "2")
|
||||
|
||||
let hide = BridgeInvokeRequest(id: "hide", command: OpenClawCanvasCommand.hide.rawValue)
|
||||
let hideRes = await appModel._test_handleInvoke(hide)
|
||||
#expect(hideRes.ok == true)
|
||||
#expect(appModel.screen.urlString.isEmpty)
|
||||
}
|
||||
|
||||
@Test @MainActor func handleInvokeA2UICommandsFailWhenHostMissing() async throws {
|
||||
@@ -366,470 +155,6 @@ private func decodePayload<T: Decodable>(_ json: String?, as type: T.Type) throw
|
||||
#expect(res.error?.code == .invalidRequest)
|
||||
}
|
||||
|
||||
@Test @MainActor func handleInvokeSystemNotifyCreatesNotificationRequest() async throws {
|
||||
let notifier = TestNotificationCenter(status: .notDetermined)
|
||||
let deviceStatus = TestDeviceStatusService(
|
||||
statusPayload: OpenClawDeviceStatusPayload(
|
||||
battery: OpenClawBatteryStatusPayload(level: 0.5, state: .charging, lowPowerModeEnabled: false),
|
||||
thermal: OpenClawThermalStatusPayload(state: .nominal),
|
||||
storage: OpenClawStorageStatusPayload(totalBytes: 100, freeBytes: 50, usedBytes: 50),
|
||||
network: OpenClawNetworkStatusPayload(
|
||||
status: .satisfied,
|
||||
isExpensive: false,
|
||||
isConstrained: false,
|
||||
interfaces: [.wifi]),
|
||||
uptimeSeconds: 10),
|
||||
infoPayload: OpenClawDeviceInfoPayload(
|
||||
deviceName: "Test",
|
||||
modelIdentifier: "Test1,1",
|
||||
systemName: "iOS",
|
||||
systemVersion: "1.0",
|
||||
appVersion: "dev",
|
||||
appBuild: "0",
|
||||
locale: "en-US"))
|
||||
let emptyContact = OpenClawContactPayload(
|
||||
identifier: "c0",
|
||||
displayName: "",
|
||||
givenName: "",
|
||||
familyName: "",
|
||||
organizationName: "",
|
||||
phoneNumbers: [],
|
||||
emails: [])
|
||||
let emptyEvent = OpenClawCalendarEventPayload(
|
||||
identifier: "e0",
|
||||
title: "Test",
|
||||
startISO: "2024-01-01T00:00:00Z",
|
||||
endISO: "2024-01-01T00:30:00Z",
|
||||
isAllDay: false,
|
||||
location: nil,
|
||||
calendarTitle: nil)
|
||||
let emptyReminder = OpenClawReminderPayload(
|
||||
identifier: "r0",
|
||||
title: "Test",
|
||||
dueISO: nil,
|
||||
completed: false,
|
||||
listName: nil)
|
||||
let appModel = makeTestAppModel(
|
||||
notificationCenter: notifier,
|
||||
deviceStatusService: deviceStatus,
|
||||
photosService: TestPhotosService(payload: OpenClawPhotosLatestPayload(photos: [])),
|
||||
contactsService: TestContactsService(
|
||||
searchPayload: OpenClawContactsSearchPayload(contacts: []),
|
||||
addPayload: OpenClawContactsAddPayload(contact: emptyContact)),
|
||||
calendarService: TestCalendarService(
|
||||
eventsPayload: OpenClawCalendarEventsPayload(events: []),
|
||||
addPayload: OpenClawCalendarAddPayload(event: emptyEvent)),
|
||||
remindersService: TestRemindersService(
|
||||
listPayload: OpenClawRemindersListPayload(reminders: []),
|
||||
addPayload: OpenClawRemindersAddPayload(reminder: emptyReminder)),
|
||||
motionService: TestMotionService(
|
||||
activityPayload: OpenClawMotionActivityPayload(activities: []),
|
||||
pedometerPayload: OpenClawPedometerPayload(
|
||||
startISO: "2024-01-01T00:00:00Z",
|
||||
endISO: "2024-01-01T01:00:00Z",
|
||||
steps: nil,
|
||||
distanceMeters: nil,
|
||||
floorsAscended: nil,
|
||||
floorsDescended: nil)))
|
||||
|
||||
let params = OpenClawSystemNotifyParams(title: "Hello", body: "World")
|
||||
let data = try JSONEncoder().encode(params)
|
||||
let json = String(decoding: data, as: UTF8.self)
|
||||
let req = BridgeInvokeRequest(
|
||||
id: "notify",
|
||||
command: OpenClawSystemCommand.notify.rawValue,
|
||||
paramsJSON: json)
|
||||
let res = await appModel._test_handleInvoke(req)
|
||||
#expect(res.ok == true)
|
||||
#expect(notifier.requestAuthorizationCalls == 1)
|
||||
#expect(notifier.addedRequests.count == 1)
|
||||
let request = try #require(notifier.addedRequests.first)
|
||||
#expect(request.content.title == "Hello")
|
||||
#expect(request.content.body == "World")
|
||||
}
|
||||
|
||||
@Test @MainActor func handleInvokeChatPushCreatesNotification() async throws {
|
||||
let notifier = TestNotificationCenter(status: .authorized)
|
||||
let deviceStatus = TestDeviceStatusService(
|
||||
statusPayload: OpenClawDeviceStatusPayload(
|
||||
battery: OpenClawBatteryStatusPayload(level: 0.5, state: .charging, lowPowerModeEnabled: false),
|
||||
thermal: OpenClawThermalStatusPayload(state: .nominal),
|
||||
storage: OpenClawStorageStatusPayload(totalBytes: 100, freeBytes: 50, usedBytes: 50),
|
||||
network: OpenClawNetworkStatusPayload(
|
||||
status: .satisfied,
|
||||
isExpensive: false,
|
||||
isConstrained: false,
|
||||
interfaces: [.wifi]),
|
||||
uptimeSeconds: 10),
|
||||
infoPayload: OpenClawDeviceInfoPayload(
|
||||
deviceName: "Test",
|
||||
modelIdentifier: "Test1,1",
|
||||
systemName: "iOS",
|
||||
systemVersion: "1.0",
|
||||
appVersion: "dev",
|
||||
appBuild: "0",
|
||||
locale: "en-US"))
|
||||
let emptyContact = OpenClawContactPayload(
|
||||
identifier: "c0",
|
||||
displayName: "",
|
||||
givenName: "",
|
||||
familyName: "",
|
||||
organizationName: "",
|
||||
phoneNumbers: [],
|
||||
emails: [])
|
||||
let emptyEvent = OpenClawCalendarEventPayload(
|
||||
identifier: "e0",
|
||||
title: "Test",
|
||||
startISO: "2024-01-01T00:00:00Z",
|
||||
endISO: "2024-01-01T00:30:00Z",
|
||||
isAllDay: false,
|
||||
location: nil,
|
||||
calendarTitle: nil)
|
||||
let emptyReminder = OpenClawReminderPayload(
|
||||
identifier: "r0",
|
||||
title: "Test",
|
||||
dueISO: nil,
|
||||
completed: false,
|
||||
listName: nil)
|
||||
let appModel = makeTestAppModel(
|
||||
notificationCenter: notifier,
|
||||
deviceStatusService: deviceStatus,
|
||||
photosService: TestPhotosService(payload: OpenClawPhotosLatestPayload(photos: [])),
|
||||
contactsService: TestContactsService(
|
||||
searchPayload: OpenClawContactsSearchPayload(contacts: []),
|
||||
addPayload: OpenClawContactsAddPayload(contact: emptyContact)),
|
||||
calendarService: TestCalendarService(
|
||||
eventsPayload: OpenClawCalendarEventsPayload(events: []),
|
||||
addPayload: OpenClawCalendarAddPayload(event: emptyEvent)),
|
||||
remindersService: TestRemindersService(
|
||||
listPayload: OpenClawRemindersListPayload(reminders: []),
|
||||
addPayload: OpenClawRemindersAddPayload(reminder: emptyReminder)),
|
||||
motionService: TestMotionService(
|
||||
activityPayload: OpenClawMotionActivityPayload(activities: []),
|
||||
pedometerPayload: OpenClawPedometerPayload(
|
||||
startISO: "2024-01-01T00:00:00Z",
|
||||
endISO: "2024-01-01T01:00:00Z",
|
||||
steps: nil,
|
||||
distanceMeters: nil,
|
||||
floorsAscended: nil,
|
||||
floorsDescended: nil)))
|
||||
|
||||
let params = OpenClawChatPushParams(text: "Ping", speak: false)
|
||||
let data = try JSONEncoder().encode(params)
|
||||
let json = String(decoding: data, as: UTF8.self)
|
||||
let req = BridgeInvokeRequest(
|
||||
id: "chat-push",
|
||||
command: OpenClawChatCommand.push.rawValue,
|
||||
paramsJSON: json)
|
||||
let res = await appModel._test_handleInvoke(req)
|
||||
#expect(res.ok == true)
|
||||
#expect(notifier.addedRequests.count == 1)
|
||||
let request = try #require(notifier.addedRequests.first)
|
||||
#expect(request.content.title == "OpenClaw")
|
||||
#expect(request.content.body == "Ping")
|
||||
let payloadJSON = try #require(res.payloadJSON)
|
||||
let decoded = try JSONDecoder().decode(OpenClawChatPushPayload.self, from: Data(payloadJSON.utf8))
|
||||
#expect((decoded.messageId ?? "").isEmpty == false)
|
||||
#expect(request.identifier == decoded.messageId)
|
||||
}
|
||||
|
||||
@Test @MainActor func handleInvokeDeviceAndDataCommandsReturnPayloads() async throws {
|
||||
let deviceStatusPayload = OpenClawDeviceStatusPayload(
|
||||
battery: OpenClawBatteryStatusPayload(level: 0.25, state: .unplugged, lowPowerModeEnabled: false),
|
||||
thermal: OpenClawThermalStatusPayload(state: .fair),
|
||||
storage: OpenClawStorageStatusPayload(totalBytes: 200, freeBytes: 80, usedBytes: 120),
|
||||
network: OpenClawNetworkStatusPayload(
|
||||
status: .satisfied,
|
||||
isExpensive: true,
|
||||
isConstrained: false,
|
||||
interfaces: [.cellular]),
|
||||
uptimeSeconds: 42)
|
||||
let deviceInfoPayload = OpenClawDeviceInfoPayload(
|
||||
deviceName: "TestPhone",
|
||||
modelIdentifier: "Test2,1",
|
||||
systemName: "iOS",
|
||||
systemVersion: "2.0",
|
||||
appVersion: "dev",
|
||||
appBuild: "1",
|
||||
locale: "en-US")
|
||||
let photosPayload = OpenClawPhotosLatestPayload(
|
||||
photos: [
|
||||
OpenClawPhotoPayload(format: "jpeg", base64: "dGVzdA==", width: 1, height: 1, createdAt: nil),
|
||||
])
|
||||
let contactsPayload = OpenClawContactsSearchPayload(
|
||||
contacts: [
|
||||
OpenClawContactPayload(
|
||||
identifier: "c1",
|
||||
displayName: "Jane Doe",
|
||||
givenName: "Jane",
|
||||
familyName: "Doe",
|
||||
organizationName: "",
|
||||
phoneNumbers: ["+1"],
|
||||
emails: ["jane@example.com"]),
|
||||
])
|
||||
let contactsAddPayload = OpenClawContactsAddPayload(
|
||||
contact: OpenClawContactPayload(
|
||||
identifier: "c2",
|
||||
displayName: "Added",
|
||||
givenName: "Added",
|
||||
familyName: "",
|
||||
organizationName: "",
|
||||
phoneNumbers: ["+2"],
|
||||
emails: ["add@example.com"]))
|
||||
let calendarPayload = OpenClawCalendarEventsPayload(
|
||||
events: [
|
||||
OpenClawCalendarEventPayload(
|
||||
identifier: "e1",
|
||||
title: "Standup",
|
||||
startISO: "2024-01-01T00:00:00Z",
|
||||
endISO: "2024-01-01T00:30:00Z",
|
||||
isAllDay: false,
|
||||
location: nil,
|
||||
calendarTitle: "Work"),
|
||||
])
|
||||
let calendarAddPayload = OpenClawCalendarAddPayload(
|
||||
event: OpenClawCalendarEventPayload(
|
||||
identifier: "e2",
|
||||
title: "Added Event",
|
||||
startISO: "2024-01-02T00:00:00Z",
|
||||
endISO: "2024-01-02T01:00:00Z",
|
||||
isAllDay: false,
|
||||
location: "HQ",
|
||||
calendarTitle: "Work"))
|
||||
let remindersPayload = OpenClawRemindersListPayload(
|
||||
reminders: [
|
||||
OpenClawReminderPayload(
|
||||
identifier: "r1",
|
||||
title: "Ship build",
|
||||
dueISO: "2024-01-02T00:00:00Z",
|
||||
completed: false,
|
||||
listName: "Inbox"),
|
||||
])
|
||||
let remindersAddPayload = OpenClawRemindersAddPayload(
|
||||
reminder: OpenClawReminderPayload(
|
||||
identifier: "r2",
|
||||
title: "Added Reminder",
|
||||
dueISO: "2024-01-03T00:00:00Z",
|
||||
completed: false,
|
||||
listName: "Inbox"))
|
||||
let motionPayload = OpenClawMotionActivityPayload(
|
||||
activities: [
|
||||
OpenClawMotionActivityEntry(
|
||||
startISO: "2024-01-01T00:00:00Z",
|
||||
endISO: "2024-01-01T00:10:00Z",
|
||||
confidence: "high",
|
||||
isWalking: true,
|
||||
isRunning: false,
|
||||
isCycling: false,
|
||||
isAutomotive: false,
|
||||
isStationary: false,
|
||||
isUnknown: false),
|
||||
])
|
||||
let pedometerPayload = OpenClawPedometerPayload(
|
||||
startISO: "2024-01-01T00:00:00Z",
|
||||
endISO: "2024-01-01T01:00:00Z",
|
||||
steps: 123,
|
||||
distanceMeters: 456,
|
||||
floorsAscended: 1,
|
||||
floorsDescended: 2)
|
||||
|
||||
let appModel = makeTestAppModel(
|
||||
deviceStatusService: TestDeviceStatusService(
|
||||
statusPayload: deviceStatusPayload,
|
||||
infoPayload: deviceInfoPayload),
|
||||
photosService: TestPhotosService(payload: photosPayload),
|
||||
contactsService: TestContactsService(
|
||||
searchPayload: contactsPayload,
|
||||
addPayload: contactsAddPayload),
|
||||
calendarService: TestCalendarService(
|
||||
eventsPayload: calendarPayload,
|
||||
addPayload: calendarAddPayload),
|
||||
remindersService: TestRemindersService(
|
||||
listPayload: remindersPayload,
|
||||
addPayload: remindersAddPayload),
|
||||
motionService: TestMotionService(
|
||||
activityPayload: motionPayload,
|
||||
pedometerPayload: pedometerPayload))
|
||||
|
||||
let deviceStatusReq = BridgeInvokeRequest(id: "device", command: OpenClawDeviceCommand.status.rawValue)
|
||||
let deviceStatusRes = await appModel._test_handleInvoke(deviceStatusReq)
|
||||
#expect(deviceStatusRes.ok == true)
|
||||
let decodedDeviceStatus = try decodePayload(deviceStatusRes.payloadJSON, as: OpenClawDeviceStatusPayload.self)
|
||||
#expect(decodedDeviceStatus == deviceStatusPayload)
|
||||
|
||||
let deviceInfoReq = BridgeInvokeRequest(id: "device-info", command: OpenClawDeviceCommand.info.rawValue)
|
||||
let deviceInfoRes = await appModel._test_handleInvoke(deviceInfoReq)
|
||||
#expect(deviceInfoRes.ok == true)
|
||||
let decodedDeviceInfo = try decodePayload(deviceInfoRes.payloadJSON, as: OpenClawDeviceInfoPayload.self)
|
||||
#expect(decodedDeviceInfo == deviceInfoPayload)
|
||||
|
||||
let photosReq = BridgeInvokeRequest(id: "photos", command: OpenClawPhotosCommand.latest.rawValue)
|
||||
let photosRes = await appModel._test_handleInvoke(photosReq)
|
||||
#expect(photosRes.ok == true)
|
||||
let decodedPhotos = try decodePayload(photosRes.payloadJSON, as: OpenClawPhotosLatestPayload.self)
|
||||
#expect(decodedPhotos == photosPayload)
|
||||
|
||||
let contactsReq = BridgeInvokeRequest(id: "contacts", command: OpenClawContactsCommand.search.rawValue)
|
||||
let contactsRes = await appModel._test_handleInvoke(contactsReq)
|
||||
#expect(contactsRes.ok == true)
|
||||
let decodedContacts = try decodePayload(contactsRes.payloadJSON, as: OpenClawContactsSearchPayload.self)
|
||||
#expect(decodedContacts == contactsPayload)
|
||||
|
||||
let contactsAddParams = OpenClawContactsAddParams(
|
||||
givenName: "Added",
|
||||
phoneNumbers: ["+2"],
|
||||
emails: ["add@example.com"])
|
||||
let contactsAddData = try JSONEncoder().encode(contactsAddParams)
|
||||
let contactsAddReq = BridgeInvokeRequest(
|
||||
id: "contacts-add",
|
||||
command: OpenClawContactsCommand.add.rawValue,
|
||||
paramsJSON: String(decoding: contactsAddData, as: UTF8.self))
|
||||
let contactsAddRes = await appModel._test_handleInvoke(contactsAddReq)
|
||||
#expect(contactsAddRes.ok == true)
|
||||
let decodedContactsAdd = try decodePayload(contactsAddRes.payloadJSON, as: OpenClawContactsAddPayload.self)
|
||||
#expect(decodedContactsAdd == contactsAddPayload)
|
||||
|
||||
let calendarReq = BridgeInvokeRequest(id: "calendar", command: OpenClawCalendarCommand.events.rawValue)
|
||||
let calendarRes = await appModel._test_handleInvoke(calendarReq)
|
||||
#expect(calendarRes.ok == true)
|
||||
let decodedCalendar = try decodePayload(calendarRes.payloadJSON, as: OpenClawCalendarEventsPayload.self)
|
||||
#expect(decodedCalendar == calendarPayload)
|
||||
|
||||
let calendarAddParams = OpenClawCalendarAddParams(
|
||||
title: "Added Event",
|
||||
startISO: "2024-01-02T00:00:00Z",
|
||||
endISO: "2024-01-02T01:00:00Z",
|
||||
location: "HQ",
|
||||
calendarTitle: "Work")
|
||||
let calendarAddData = try JSONEncoder().encode(calendarAddParams)
|
||||
let calendarAddReq = BridgeInvokeRequest(
|
||||
id: "calendar-add",
|
||||
command: OpenClawCalendarCommand.add.rawValue,
|
||||
paramsJSON: String(decoding: calendarAddData, as: UTF8.self))
|
||||
let calendarAddRes = await appModel._test_handleInvoke(calendarAddReq)
|
||||
#expect(calendarAddRes.ok == true)
|
||||
let decodedCalendarAdd = try decodePayload(calendarAddRes.payloadJSON, as: OpenClawCalendarAddPayload.self)
|
||||
#expect(decodedCalendarAdd == calendarAddPayload)
|
||||
|
||||
let remindersReq = BridgeInvokeRequest(id: "reminders", command: OpenClawRemindersCommand.list.rawValue)
|
||||
let remindersRes = await appModel._test_handleInvoke(remindersReq)
|
||||
#expect(remindersRes.ok == true)
|
||||
let decodedReminders = try decodePayload(remindersRes.payloadJSON, as: OpenClawRemindersListPayload.self)
|
||||
#expect(decodedReminders == remindersPayload)
|
||||
|
||||
let remindersAddParams = OpenClawRemindersAddParams(
|
||||
title: "Added Reminder",
|
||||
dueISO: "2024-01-03T00:00:00Z",
|
||||
listName: "Inbox")
|
||||
let remindersAddData = try JSONEncoder().encode(remindersAddParams)
|
||||
let remindersAddReq = BridgeInvokeRequest(
|
||||
id: "reminders-add",
|
||||
command: OpenClawRemindersCommand.add.rawValue,
|
||||
paramsJSON: String(decoding: remindersAddData, as: UTF8.self))
|
||||
let remindersAddRes = await appModel._test_handleInvoke(remindersAddReq)
|
||||
#expect(remindersAddRes.ok == true)
|
||||
let decodedRemindersAdd = try decodePayload(remindersAddRes.payloadJSON, as: OpenClawRemindersAddPayload.self)
|
||||
#expect(decodedRemindersAdd == remindersAddPayload)
|
||||
|
||||
let motionReq = BridgeInvokeRequest(id: "motion", command: OpenClawMotionCommand.activity.rawValue)
|
||||
let motionRes = await appModel._test_handleInvoke(motionReq)
|
||||
#expect(motionRes.ok == true)
|
||||
let decodedMotion = try decodePayload(motionRes.payloadJSON, as: OpenClawMotionActivityPayload.self)
|
||||
#expect(decodedMotion == motionPayload)
|
||||
|
||||
let pedometerReq = BridgeInvokeRequest(id: "pedometer", command: OpenClawMotionCommand.pedometer.rawValue)
|
||||
let pedometerRes = await appModel._test_handleInvoke(pedometerReq)
|
||||
#expect(pedometerRes.ok == true)
|
||||
let decodedPedometer = try decodePayload(pedometerRes.payloadJSON, as: OpenClawPedometerPayload.self)
|
||||
#expect(decodedPedometer == pedometerPayload)
|
||||
}
|
||||
|
||||
@Test @MainActor func handleInvokePushToTalkReturnsTranscriptStatus() async throws {
|
||||
let talkMode = TalkModeManager(allowSimulatorCapture: true)
|
||||
talkMode.updateGatewayConnected(false)
|
||||
let appModel = makeTalkTestAppModel(talkMode: talkMode)
|
||||
|
||||
let startReq = BridgeInvokeRequest(id: "ptt-start", command: OpenClawTalkCommand.pttStart.rawValue)
|
||||
let startRes = await appModel._test_handleInvoke(startReq)
|
||||
#expect(startRes.ok == true)
|
||||
let startPayload = try decodePayload(startRes.payloadJSON, as: OpenClawTalkPTTStartPayload.self)
|
||||
#expect(!startPayload.captureId.isEmpty)
|
||||
|
||||
talkMode._test_seedTranscript("Hello from PTT")
|
||||
|
||||
let stopReq = BridgeInvokeRequest(id: "ptt-stop", command: OpenClawTalkCommand.pttStop.rawValue)
|
||||
let stopRes = await appModel._test_handleInvoke(stopReq)
|
||||
#expect(stopRes.ok == true)
|
||||
let stopPayload = try decodePayload(stopRes.payloadJSON, as: OpenClawTalkPTTStopPayload.self)
|
||||
#expect(stopPayload.captureId == startPayload.captureId)
|
||||
#expect(stopPayload.transcript == "Hello from PTT")
|
||||
#expect(stopPayload.status == "offline")
|
||||
}
|
||||
|
||||
@Test @MainActor func handleInvokePushToTalkCancelStopsSession() async throws {
|
||||
let talkMode = TalkModeManager(allowSimulatorCapture: true)
|
||||
talkMode.updateGatewayConnected(false)
|
||||
let appModel = makeTalkTestAppModel(talkMode: talkMode)
|
||||
|
||||
let startReq = BridgeInvokeRequest(id: "ptt-start", command: OpenClawTalkCommand.pttStart.rawValue)
|
||||
let startRes = await appModel._test_handleInvoke(startReq)
|
||||
#expect(startRes.ok == true)
|
||||
let startPayload = try decodePayload(startRes.payloadJSON, as: OpenClawTalkPTTStartPayload.self)
|
||||
|
||||
let cancelReq = BridgeInvokeRequest(id: "ptt-cancel", command: OpenClawTalkCommand.pttCancel.rawValue)
|
||||
let cancelRes = await appModel._test_handleInvoke(cancelReq)
|
||||
#expect(cancelRes.ok == true)
|
||||
let cancelPayload = try decodePayload(cancelRes.payloadJSON, as: OpenClawTalkPTTStopPayload.self)
|
||||
#expect(cancelPayload.captureId == startPayload.captureId)
|
||||
#expect(cancelPayload.status == "cancelled")
|
||||
}
|
||||
|
||||
@Test @MainActor func handleInvokePushToTalkOnceAutoStopsAfterSilence() async throws {
|
||||
let talkMode = TalkModeManager(allowSimulatorCapture: true)
|
||||
talkMode.updateGatewayConnected(false)
|
||||
let appModel = makeTalkTestAppModel(talkMode: talkMode)
|
||||
|
||||
let onceReq = BridgeInvokeRequest(id: "ptt-once", command: OpenClawTalkCommand.pttOnce.rawValue)
|
||||
let onceTask = Task { await appModel._test_handleInvoke(onceReq) }
|
||||
|
||||
for _ in 0..<5 where !talkMode.isPushToTalkActive {
|
||||
await Task.yield()
|
||||
}
|
||||
#expect(talkMode.isPushToTalkActive == true)
|
||||
|
||||
talkMode._test_seedTranscript("Hello from PTT once")
|
||||
talkMode._test_backdateLastHeard(seconds: 1.0)
|
||||
await talkMode._test_runSilenceCheck()
|
||||
|
||||
let onceRes = await onceTask.value
|
||||
#expect(onceRes.ok == true)
|
||||
let oncePayload = try decodePayload(onceRes.payloadJSON, as: OpenClawTalkPTTStopPayload.self)
|
||||
#expect(oncePayload.transcript == "Hello from PTT once")
|
||||
#expect(oncePayload.status == "offline")
|
||||
}
|
||||
|
||||
@Test @MainActor func handleInvokePushToTalkOnceStopsOnFinalTranscript() async throws {
|
||||
let talkMode = TalkModeManager(allowSimulatorCapture: true)
|
||||
talkMode.updateGatewayConnected(false)
|
||||
let appModel = makeTalkTestAppModel(talkMode: talkMode)
|
||||
|
||||
let onceReq = BridgeInvokeRequest(id: "ptt-once-final", command: OpenClawTalkCommand.pttOnce.rawValue)
|
||||
let onceTask = Task { await appModel._test_handleInvoke(onceReq) }
|
||||
|
||||
for _ in 0..<5 where !talkMode.isPushToTalkActive {
|
||||
await Task.yield()
|
||||
}
|
||||
#expect(talkMode.isPushToTalkActive == true)
|
||||
|
||||
await talkMode._test_handleTranscript("Hello final", isFinal: true)
|
||||
|
||||
let onceRes = await onceTask.value
|
||||
#expect(onceRes.ok == true)
|
||||
let oncePayload = try decodePayload(onceRes.payloadJSON, as: OpenClawTalkPTTStopPayload.self)
|
||||
#expect(oncePayload.transcript == "Hello final")
|
||||
#expect(oncePayload.status == "offline")
|
||||
}
|
||||
|
||||
@Test @MainActor func handleDeepLinkSetsErrorWhenNotConnected() async {
|
||||
let appModel = NodeAppModel()
|
||||
let url = URL(string: "openclaw://agent?message=hello")!
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
import Testing
|
||||
@testable import OpenClaw
|
||||
|
||||
struct NodeDisplayNameTests {
|
||||
@Test func keepsCustomName() {
|
||||
let resolved = NodeDisplayName.resolve(
|
||||
existing: "Razor Phone",
|
||||
deviceName: "iPhone",
|
||||
interfaceIdiom: .phone)
|
||||
#expect(resolved == "Razor Phone")
|
||||
}
|
||||
|
||||
@Test func usesDeviceNameWhenMatchesIphone() {
|
||||
let resolved = NodeDisplayName.resolve(
|
||||
existing: "iOS Node",
|
||||
deviceName: "iPhone 17 Pro",
|
||||
interfaceIdiom: .phone)
|
||||
#expect(resolved == "iPhone 17 Pro")
|
||||
}
|
||||
|
||||
@Test func usesDefaultWhenDeviceNameIsGeneric() {
|
||||
let resolved = NodeDisplayName.resolve(
|
||||
existing: nil,
|
||||
deviceName: "Work Phone",
|
||||
interfaceIdiom: .phone)
|
||||
#expect(NodeDisplayName.isGeneric(resolved))
|
||||
}
|
||||
|
||||
@Test func identifiesGenericValues() {
|
||||
#expect(NodeDisplayName.isGeneric("iOS Node"))
|
||||
#expect(NodeDisplayName.isGeneric("iPhone Node"))
|
||||
#expect(NodeDisplayName.isGeneric("iPad Node"))
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import Foundation
|
||||
import Testing
|
||||
@testable import OpenClaw
|
||||
|
||||
@Suite struct TalkModeIncrementalTests {
|
||||
@Test @MainActor func incrementalSpeechSplitsOnBoundary() {
|
||||
let talkMode = TalkModeManager(allowSimulatorCapture: true)
|
||||
talkMode._test_incrementalReset()
|
||||
let segments = talkMode._test_incrementalIngest("Hello world. Next", isFinal: false)
|
||||
#expect(segments.count == 1)
|
||||
#expect(segments.first == "Hello world.")
|
||||
}
|
||||
|
||||
@Test @MainActor func incrementalSpeechSkipsDirectiveLine() {
|
||||
let talkMode = TalkModeManager(allowSimulatorCapture: true)
|
||||
talkMode._test_incrementalReset()
|
||||
let segments = talkMode._test_incrementalIngest("{\"voice\":\"abc\"}\nHello.", isFinal: false)
|
||||
#expect(segments.count == 1)
|
||||
#expect(segments.first == "Hello.")
|
||||
}
|
||||
|
||||
@Test @MainActor func incrementalSpeechIgnoresCodeBlocks() {
|
||||
let talkMode = TalkModeManager(allowSimulatorCapture: true)
|
||||
talkMode._test_incrementalReset()
|
||||
let text = "Here is code:\n```js\nx=1\n```\nDone."
|
||||
let segments = talkMode._test_incrementalIngest(text, isFinal: true)
|
||||
#expect(segments.count == 1)
|
||||
let value = segments.first ?? ""
|
||||
#expect(value.contains("x=1") == false)
|
||||
#expect(value.contains("Here is code") == true)
|
||||
#expect(value.contains("Done.") == true)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user