mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-15 10:16:07 +00:00
163 lines
7.9 KiB
Swift
163 lines
7.9 KiB
Swift
import Foundation
|
|
import Testing
|
|
@testable import OpenClaw
|
|
|
|
struct RuntimeLocalizationSourceGuardTests {
|
|
@Test func liveActivityStatePersistsSemanticsAndExternalDetail() throws {
|
|
for status in OpenClawActivityAttributes.ContentState.Status.allCases {
|
|
let state = OpenClawActivityAttributes.ContentState(
|
|
status: status,
|
|
verbatimDetail: status == .attention ? "Backend supplied detail" : nil,
|
|
startedAt: Date(timeIntervalSince1970: 1_234))
|
|
let data = try JSONEncoder().encode(state)
|
|
let decoded = try JSONDecoder().decode(OpenClawActivityAttributes.ContentState.self, from: data)
|
|
|
|
#expect(decoded == state)
|
|
}
|
|
}
|
|
|
|
@Test func liveActivityStateDecodesShippedLegacyPayloads() throws {
|
|
let cases: [(LegacyContentState, OpenClawActivityAttributes.ContentState.Status, String?)] = [
|
|
(LegacyContentState(statusText: "Disconnected", isDisconnected: true), .disconnected, nil),
|
|
(LegacyContentState(statusText: "Idle", isIdle: true), .idle, nil),
|
|
(LegacyContentState(statusText: "Reconnecting...", isConnecting: true), .reconnecting, nil),
|
|
(LegacyContentState(statusText: "Ansluter igen...", isConnecting: true), .reconnecting, nil),
|
|
(LegacyContentState(statusText: "Approval needed"), .approvalNeeded, nil),
|
|
(LegacyContentState(statusText: "Backend supplied attention"), .attention, "Backend supplied attention"),
|
|
(
|
|
LegacyContentState(statusText: "Backend supplied connection detail", isConnecting: true),
|
|
.connecting,
|
|
"Backend supplied connection detail"),
|
|
]
|
|
|
|
for (legacy, expectedStatus, expectedDetail) in cases {
|
|
let data = try JSONEncoder().encode(legacy)
|
|
let decoded = try JSONDecoder().decode(OpenClawActivityAttributes.ContentState.self, from: data)
|
|
|
|
#expect(decoded.status == expectedStatus)
|
|
#expect(decoded.verbatimDetail == expectedDetail)
|
|
#expect(decoded.startedAt == legacy.startedAt)
|
|
}
|
|
}
|
|
|
|
@Test func runtimeOwnedCopyRemainsLocalizableAtRenderTime() throws {
|
|
let attributes = try Self.source("Sources/LiveActivity/OpenClawActivityAttributes.swift")
|
|
let manager = try Self.source("Sources/LiveActivity/LiveActivityManager.swift")
|
|
let widget = try Self.source("ActivityWidget/OpenClawLiveActivity.swift")
|
|
let project = try Self.source("project.yml")
|
|
let dreaming = try Self.source("Sources/Design/AgentProDreamingDestination.swift")
|
|
let phoneControlHub = try Self.source("Sources/Design/RootTabsPhoneControlHub.swift")
|
|
let proComponents = try Self.source("Sources/Design/OpenClawProComponents.swift")
|
|
let skillWorkshop = try Self.source("Sources/Design/IPadSkillWorkshopScreen.swift")
|
|
let workboard = try Self.source("Sources/Design/IPadWorkboardScreen.swift")
|
|
let talkPro = try Self.source("Sources/Design/TalkProTab.swift")
|
|
let talkManager = try Self.source("Sources/Voice/TalkModeManager.swift")
|
|
let rootTabs = try Self.source("Sources/RootTabs.swift")
|
|
let rootTabsNavigation = try Self.source("Sources/RootTabsNavigation.swift")
|
|
let watchInbox = try Self.source("WatchApp/Sources/WatchInboxView.swift")
|
|
let chat = try Self.sharedSource("OpenClawChatUI/ChatMessageViews.swift")
|
|
|
|
#expect(!attributes.contains("var statusText"))
|
|
#expect(attributes.contains("var status: Status"))
|
|
#expect(attributes.contains("var verbatimDetail: String?"))
|
|
#expect(attributes.contains("private enum LegacyCodingKeys"))
|
|
#expect(manager.contains("status: .disconnected"))
|
|
#expect(!manager.contains("statusText: String(localized: \"Disconnected\")"))
|
|
#expect(widget.contains("Text(verbatim: detail)"))
|
|
#expect(widget.contains("case .reconnecting: Text(\"Reconnecting...\")"))
|
|
#expect(project.contains("""
|
|
OpenClawActivityWidget:
|
|
"""))
|
|
#expect(project.contains("""
|
|
- path: Resources/Localizable.xcstrings
|
|
buildPhase: resources
|
|
"""))
|
|
#expect(dreaming.contains("AttributedString(localized: \"^[\\(recallCount) recall](inflect: true)\""))
|
|
#expect(dreaming.contains("format: String(localized: \"%@ grounded\")"))
|
|
#expect(dreaming.contains("parts.formatted(.list(type: .and, width: .short))"))
|
|
#expect(chat.contains("private var title: LocalizedStringResource"))
|
|
#expect(chat.contains("private var accessibilityText: LocalizedStringResource"))
|
|
#expect(chat.contains("Text(self.accessibilityText)"))
|
|
#expect(watchInbox.contains("case localized(LocalizedStringResource)"))
|
|
#expect(!watchInbox.contains("WatchTextValue: ExpressibleByStringLiteral"))
|
|
#expect(watchInbox.contains("accessory: .verbatim(self.store.talkSummaryText)"))
|
|
for status in ["Online", "Connecting", "Needs attention", "Offline"] {
|
|
#expect(rootTabs.contains("String(localized: \"\(status)\")"))
|
|
}
|
|
let destinationTitles = [
|
|
"Chat",
|
|
"Talk",
|
|
"Overview",
|
|
"Activity",
|
|
"Agents",
|
|
"Workboard",
|
|
"Skill Workshop",
|
|
"Instances",
|
|
"Sessions",
|
|
"Files",
|
|
"Dreaming",
|
|
"Usage",
|
|
"Cron Jobs",
|
|
"Terminal",
|
|
"Docs",
|
|
"Settings",
|
|
"Settings / Gateway",
|
|
]
|
|
for title in destinationTitles {
|
|
#expect(rootTabsNavigation.contains("String(localized: \"\(title)\")"))
|
|
}
|
|
#expect(rootTabsNavigation.contains("case .gateway: String(localized: \"Connection\")"))
|
|
for status in ["Online", "Connecting", "Attention", "Offline"] {
|
|
#expect(phoneControlHub.contains("String(localized: \"\(status)\")"))
|
|
#expect(proComponents.contains("String(localized: \"\(status)\")"))
|
|
}
|
|
#expect(phoneControlHub.contains("String(localized: \"Default Agent\")"))
|
|
#expect(proComponents.contains("OpenClawStatusBadge(label: .verbatim(self.title)"))
|
|
#expect(
|
|
skillWorkshop.components(separatedBy: "String(localized: \"Default agent\")").count - 1 == 2)
|
|
#expect(workboard.components(separatedBy: "String(localized: \"Default agent\")").count - 1 == 4)
|
|
#expect(!workboard.contains("?? \"Default agent\""))
|
|
#expect(talkPro.contains("if title.isEmpty { return String(localized: \"Not active\") }"))
|
|
#expect(talkManager.contains(
|
|
"var gatewayTalkActiveModeTitle: String = .init(localized: \"Not active\")"))
|
|
for title in [
|
|
"Not active",
|
|
"Paused",
|
|
"Realtime unavailable",
|
|
"iOS Speech + TTS",
|
|
"iOS Speech fallback",
|
|
] {
|
|
#expect(talkManager.contains("localized: \"\(title)\""))
|
|
}
|
|
#expect(!talkManager.contains("gatewayTalkActiveModeTitle: String = \""))
|
|
#expect(!talkManager.contains("gatewayTalkActiveModeTitle = \""))
|
|
}
|
|
|
|
private static func source(_ path: String) throws -> String {
|
|
try String(
|
|
contentsOf: Self.iosRoot.appendingPathComponent(path),
|
|
encoding: .utf8)
|
|
}
|
|
|
|
private static func sharedSource(_ path: String) throws -> String {
|
|
try String(
|
|
contentsOf: Self.iosRoot
|
|
.deletingLastPathComponent()
|
|
.appendingPathComponent("shared/OpenClawKit/Sources")
|
|
.appendingPathComponent(path),
|
|
encoding: .utf8)
|
|
}
|
|
|
|
private static let iosRoot = URL(fileURLWithPath: #filePath)
|
|
.deletingLastPathComponent()
|
|
.deletingLastPathComponent()
|
|
|
|
private struct LegacyContentState: Encodable {
|
|
let statusText: String
|
|
var isIdle = false
|
|
var isDisconnected = false
|
|
var isConnecting = false
|
|
var startedAt = Date(timeIntervalSince1970: 1_234)
|
|
}
|
|
}
|