import Foundation import SwabbleKit import Testing @testable import Clawdbot @Suite struct VoiceWakeRuntimeTests { @Test func trimsAfterTriggerKeepsPostSpeech() { let triggers = ["claude", "clawd"] let text = "hey Claude how are you" #expect(VoiceWakeRuntime._testTrimmedAfterTrigger(text, triggers: triggers) == "how are you") } @Test func trimsAfterTriggerReturnsOriginalWhenNoTrigger() { let triggers = ["claude"] let text = "good morning friend" #expect(VoiceWakeRuntime._testTrimmedAfterTrigger(text, triggers: triggers) == text) } @Test func trimsAfterFirstMatchingTrigger() { let triggers = ["buddy", "claude"] let text = "hello buddy this is after trigger claude also here" #expect(VoiceWakeRuntime ._testTrimmedAfterTrigger(text, triggers: triggers) == "this is after trigger claude also here") } @Test func hasContentAfterTriggerFalseWhenOnlyTrigger() { let triggers = ["clawd"] let text = "hey clawd" #expect(!VoiceWakeRuntime._testHasContentAfterTrigger(text, triggers: triggers)) } @Test func hasContentAfterTriggerTrueWhenSpeechContinues() { let triggers = ["claude"] let text = "claude write a note" #expect(VoiceWakeRuntime._testHasContentAfterTrigger(text, triggers: triggers)) } @Test func gateRequiresGapBetweenTriggerAndCommand() { let transcript = "hey clawd do thing" let segments = makeSegments( transcript: transcript, words: [ ("hey", 0.0, 0.1), ("clawd", 0.2, 0.1), ("do", 0.35, 0.1), ("thing", 0.5, 0.1), ]) let config = WakeWordGateConfig(triggers: ["clawd"], minPostTriggerGap: 0.3) #expect(WakeWordGate.match(transcript: transcript, segments: segments, config: config) == nil) } @Test func gateAcceptsGapAndExtractsCommand() { let transcript = "hey clawd do thing" let segments = makeSegments( transcript: transcript, words: [ ("hey", 0.0, 0.1), ("clawd", 0.2, 0.1), ("do", 0.9, 0.1), ("thing", 1.1, 0.1), ]) let config = WakeWordGateConfig(triggers: ["clawd"], minPostTriggerGap: 0.3) #expect(WakeWordGate.match(transcript: transcript, segments: segments, config: config)?.command == "do thing") } } private func makeSegments( transcript: String, words: [(String, TimeInterval, TimeInterval)]) -> [WakeWordSegment] { var searchStart = transcript.startIndex var output: [WakeWordSegment] = [] for (word, start, duration) in words { let range = transcript.range(of: word, range: searchStart..