package stt import ( "context" "testing" "github.com/kami/maven/internal/audio" "github.com/kami/maven/internal/worker" ) // fakeTranscriber — a worker.Transcriber that records the call. type fakeTranscriber struct { got audio.Audio } func (f *fakeTranscriber) Transcribe(_ context.Context, req worker.TranscribeReq) (worker.TranscribeResp, error) { f.got = req.Audio return worker.TranscribeResp{Text: "hello world", Confidence: 0.7}, nil } func TestStubReturnsDeterministicPhrase(t *testing.T) { t.Parallel() s := NewStub() a := audio.Audio{Format: audio.PCM16kMono, Bytes: []byte("utterance-A")} text, conf, err := s.Transcribe(context.Background(), a) if err != nil { t.Fatalf("Stub.Transcribe: %v", err) } if conf != 1.0 { t.Fatalf("Stub confidence should be 1.0, got %v", conf) } // same input ⇒ same output (deterministic; tests can rely on this). text2, _, _ := s.Transcribe(context.Background(), a) if text != text2 { t.Fatalf("Stub should be deterministic: %q vs %q", text, text2) } // phrases come from the stubPhrases list. found := false for _, p := range stubPhrases { if p == text { found = true break } } if !found { t.Fatalf("Stub phrase %q not in stubPhrases", text) } } func TestStubEmptyAudioReturnsFirstPhrase(t *testing.T) { t.Parallel() s := NewStub() text, _, err := s.Transcribe(context.Background(), audio.Audio{Format: audio.PCM16kMono}) if err != nil { t.Fatalf("Stub.Transcribe: %v", err) } if text != stubPhrases[0] { t.Fatalf("empty audio should return first phrase %q, got %q", stubPhrases[0], text) } } func TestStubDifferentAudioMayPickDifferentPhrase(t *testing.T) { t.Parallel() s := NewStub() // try enough variants to land at least two different phrases. seen := map[string]struct{}{} for i := 0; i < 200; i++ { b := make([]byte, 64) for j := range b { b[j] = byte(i + j) } text, _, _ := s.Transcribe(context.Background(), audio.Audio{Format: audio.PCM16kMono, Bytes: b}) seen[text] = struct{}{} if len(seen) >= 2 { return } } t.Fatalf("expected ≥2 distinct phrases across varied audio, got %d", len(seen)) } func TestRemoteForwardsToClient(t *testing.T) { t.Parallel() // stand up a worker.Server with the fakeTranscriber behind it. srv := worker.NewServer(t.TempDir()+"/stt.sock", &fakeTranscriber{}) if err := srv.Listen(); err != nil { t.Fatalf("listen: %v", err) } defer srv.Close() go srv.Serve() c := worker.Dial(srv.Path()) defer c.Close() r := NewRemote(c, "ru") in := audio.Audio{Format: audio.PCM16kMono, Bytes: []byte("payload")} text, conf, err := r.Transcribe(context.Background(), in) if err != nil { t.Fatalf("Remote.Transcribe: %v", err) } if text != "hello world" { t.Fatalf("Text: %q, want %q", text, "hello world") } if conf != 0.7 { t.Fatalf("Confidence: %v, want 0.7", conf) } } func TestRemoteErrorWraps(t *testing.T) { t.Parallel() // a server with no transcriber ⇒ ErrUnknownMethod on Transcribe. srv := worker.NewSynthesizerServer(t.TempDir()+"/stt.sock", nil) if err := srv.Listen(); err != nil { t.Fatalf("listen: %v", err) } defer srv.Close() go srv.Serve() c := worker.Dial(srv.Path()) defer c.Close() r := NewRemote(c, "ru") _, _, err := r.Transcribe(context.Background(), audio.Audio{Format: audio.PCM16kMono, Bytes: []byte("x")}) if err == nil { t.Fatalf("want error, got nil") } }