test(mac): cover voice wake helpers
parent
df9f72134b
commit
f3ebb2e9ce
|
|
@ -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[..<at])
|
||||||
|
}
|
||||||
|
if let u = trimmed.range(of: "-u-") {
|
||||||
|
trimmed = String(trimmed[..<u.lowerBound])
|
||||||
|
}
|
||||||
|
if let t = trimmed.range(of: "-t-") {
|
||||||
|
trimmed = String(trimmed[..<t.lowerBound])
|
||||||
|
}
|
||||||
|
return trimmed
|
||||||
|
}
|
||||||
|
|
@ -209,10 +209,7 @@ struct VoiceWakeSettings: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func sanitizedTriggers() -> [String] {
|
private func sanitizedTriggers() -> [String] {
|
||||||
let cleaned = self.state.swabbleTriggerWords
|
sanitizeVoiceWakeTriggers(self.state.swabbleTriggerWords)
|
||||||
.map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }
|
|
||||||
.filter { !$0.isEmpty }
|
|
||||||
return cleaned.isEmpty ? defaultVoiceWakeTriggers : cleaned
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private var micPicker: some View {
|
private var micPicker: some View {
|
||||||
|
|
@ -343,7 +340,7 @@ struct VoiceWakeSettings: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func friendlyName(for locale: Locale) -> String {
|
private func friendlyName(for locale: Locale) -> String {
|
||||||
let cleanedID = self.normalizedLocaleIdentifier(locale.identifier)
|
let cleanedID = normalizeLocaleIdentifier(locale.identifier)
|
||||||
let cleanLocale = Locale(identifier: cleanedID)
|
let cleanLocale = Locale(identifier: cleanedID)
|
||||||
|
|
||||||
if let langCode = cleanLocale.language.languageCode?.identifier,
|
if let langCode = cleanLocale.language.languageCode?.identifier,
|
||||||
|
|
@ -361,20 +358,6 @@ struct VoiceWakeSettings: View {
|
||||||
return cleanLocale.localizedString(forIdentifier: cleanedID) ?? cleanedID
|
return cleanLocale.localizedString(forIdentifier: cleanedID) ?? cleanedID
|
||||||
}
|
}
|
||||||
|
|
||||||
private func normalizedLocaleIdentifier(_ raw: String) -> String {
|
|
||||||
var trimmed = raw
|
|
||||||
if let at = trimmed.firstIndex(of: "@") {
|
|
||||||
trimmed = String(trimmed[..<at])
|
|
||||||
}
|
|
||||||
if let u = trimmed.range(of: "-u-") {
|
|
||||||
trimmed = String(trimmed[..<u.lowerBound])
|
|
||||||
}
|
|
||||||
if let t = trimmed.range(of: "-t-") {
|
|
||||||
trimmed = String(trimmed[..<t.lowerBound])
|
|
||||||
}
|
|
||||||
return trimmed
|
|
||||||
}
|
|
||||||
|
|
||||||
private var levelMeter: some View {
|
private var levelMeter: some View {
|
||||||
VStack(alignment: .leading, spacing: 6) {
|
VStack(alignment: .leading, spacing: 6) {
|
||||||
HStack(alignment: .center, spacing: 10) {
|
HStack(alignment: .center, spacing: 10) {
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,10 @@ final class VoiceWakeTester {
|
||||||
return triggers.contains { lowered.contains($0.lowercased()) }
|
return triggers.contains { lowered.contains($0.lowercased()) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static func _testMatches(text: String, triggers: [String]) -> Bool {
|
||||||
|
self.matches(text: text, triggers: triggers)
|
||||||
|
}
|
||||||
|
|
||||||
private nonisolated static func ensurePermissions() async throws -> Bool {
|
private nonisolated static func ensurePermissions() async throws -> Bool {
|
||||||
let speechStatus = SFSpeechRecognizer.authorizationStatus()
|
let speechStatus = SFSpeechRecognizer.authorizationStatus()
|
||||||
if speechStatus == .notDetermined {
|
if speechStatus == .notDetermined {
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue