From f3ebb2e9cec8cdff13207f6a21f5d7a6759c416c Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 7 Dec 2025 17:56:40 +0100 Subject: [PATCH] test(mac): cover voice wake helpers --- .../Sources/Clawdis/VoiceWakeHelpers.swift | 22 ++++++++++++++++++ .../Sources/Clawdis/VoiceWakeSettings.swift | 21 ++--------------- .../Sources/Clawdis/VoiceWakeTester.swift | 4 ++++ .../VoiceWakeHelpersTests.swift | 23 +++++++++++++++++++ .../VoiceWakeTesterTests.swift | 15 ++++++++++++ 5 files changed, 66 insertions(+), 19 deletions(-) create mode 100644 apps/macos/Sources/Clawdis/VoiceWakeHelpers.swift create mode 100644 apps/macos/Tests/ClawdisIPCTests/VoiceWakeHelpersTests.swift create mode 100644 apps/macos/Tests/ClawdisIPCTests/VoiceWakeTesterTests.swift diff --git a/apps/macos/Sources/Clawdis/VoiceWakeHelpers.swift b/apps/macos/Sources/Clawdis/VoiceWakeHelpers.swift new file mode 100644 index 000000000..a60aa7d7c --- /dev/null +++ b/apps/macos/Sources/Clawdis/VoiceWakeHelpers.swift @@ -0,0 +1,22 @@ +import Foundation + +func sanitizeVoiceWakeTriggers(_ words: [String]) -> [String] { + let cleaned = words + .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) } + .filter { !$0.isEmpty } + return cleaned.isEmpty ? defaultVoiceWakeTriggers : cleaned +} + +func normalizeLocaleIdentifier(_ raw: String) -> String { + var trimmed = raw + if let at = trimmed.firstIndex(of: "@") { + trimmed = String(trimmed[.. [String] { - let cleaned = self.state.swabbleTriggerWords - .map { $0.trimmingCharacters(in: .whitespacesAndNewlines) } - .filter { !$0.isEmpty } - return cleaned.isEmpty ? defaultVoiceWakeTriggers : cleaned + sanitizeVoiceWakeTriggers(self.state.swabbleTriggerWords) } private var micPicker: some View { @@ -343,7 +340,7 @@ struct VoiceWakeSettings: View { } private func friendlyName(for locale: Locale) -> String { - let cleanedID = self.normalizedLocaleIdentifier(locale.identifier) + let cleanedID = normalizeLocaleIdentifier(locale.identifier) let cleanLocale = Locale(identifier: cleanedID) if let langCode = cleanLocale.language.languageCode?.identifier, @@ -361,20 +358,6 @@ struct VoiceWakeSettings: View { return cleanLocale.localizedString(forIdentifier: cleanedID) ?? cleanedID } - private func normalizedLocaleIdentifier(_ raw: String) -> String { - var trimmed = raw - if let at = trimmed.firstIndex(of: "@") { - trimmed = String(trimmed[.. Bool { + self.matches(text: text, triggers: triggers) + } + private nonisolated static func ensurePermissions() async throws -> Bool { let speechStatus = SFSpeechRecognizer.authorizationStatus() if speechStatus == .notDetermined { diff --git a/apps/macos/Tests/ClawdisIPCTests/VoiceWakeHelpersTests.swift b/apps/macos/Tests/ClawdisIPCTests/VoiceWakeHelpersTests.swift new file mode 100644 index 000000000..ab030e291 --- /dev/null +++ b/apps/macos/Tests/ClawdisIPCTests/VoiceWakeHelpersTests.swift @@ -0,0 +1,23 @@ +import Testing +@testable import Clawdis + +struct VoiceWakeHelpersTests { + @Test func sanitizeTriggersTrimsAndDropsEmpty() { + let cleaned = sanitizeVoiceWakeTriggers([" hi ", " ", "\n", "there"]) + #expect(cleaned == ["hi", "there"]) + } + + @Test func sanitizeTriggersFallsBackToDefaults() { + let cleaned = sanitizeVoiceWakeTriggers([" ", ""]) + #expect(cleaned == defaultVoiceWakeTriggers) + } + + @Test func normalizeLocaleStripsCollation() { + #expect(normalizeLocaleIdentifier("en_US@collation=phonebook") == "en_US") + } + + @Test func normalizeLocaleStripsUnicodeExtensions() { + #expect(normalizeLocaleIdentifier("de-DE-u-co-phonebk") == "de-DE") + #expect(normalizeLocaleIdentifier("ja-JP-t-ja") == "ja-JP") + } +} diff --git a/apps/macos/Tests/ClawdisIPCTests/VoiceWakeTesterTests.swift b/apps/macos/Tests/ClawdisIPCTests/VoiceWakeTesterTests.swift new file mode 100644 index 000000000..38990930a --- /dev/null +++ b/apps/macos/Tests/ClawdisIPCTests/VoiceWakeTesterTests.swift @@ -0,0 +1,15 @@ +import Testing +@testable import Clawdis + +struct VoiceWakeTesterTests { + @Test func matchesIsCaseInsensitiveAndSubstring() { + let triggers = ["Claude", "wake word"] + #expect(VoiceWakeTester._testMatches(text: "hey claude are you there", triggers: triggers)) + #expect(VoiceWakeTester._testMatches(text: "this has wake word inside", triggers: triggers)) + } + + @Test func matchesReturnsFalseWhenNoTrigger() { + let triggers = ["claude"] + #expect(!VoiceWakeTester._testMatches(text: "random text", triggers: triggers)) + } +}