package edge import ( "bytes" "context" "log/slog" "net/http/httptest" "strings" "testing" "github.com/memohai/memoh/internal/tts" ) func TestEdgeAdapter_TypeAndMeta(t *testing.T) { t.Parallel() adapter := NewEdgeAdapter(slog.Default()) if adapter.Type() != TtsTypeEdge { t.Errorf("Type() = %q, want %q", adapter.Type(), TtsTypeEdge) } meta := adapter.Meta() if meta.Provider != "Microsoft Edge" { t.Errorf("Meta().Provider = %q, want %q", meta.Provider, "Microsoft Edge") } if meta.Description != "Microsoft Edge TTS" { t.Errorf("Meta().Description = %q, want %q", meta.Description, "Microsoft Edge TTS") } } func TestEdgeAdapter_Synthesize_WithMockServer(t *testing.T) { t.Parallel() srv := httptest.NewServer(mockEdgeTTSHandler(t)) defer srv.Close() wsURL := "ws" + strings.TrimPrefix(srv.URL, "http") + "/edge/v1" client := NewEdgeWsClient() client.BaseURL = wsURL adapter := NewEdgeAdapterWithClient(slog.Default(), client) ctx := context.Background() config := tts.AudioConfig{Voice: tts.VoiceConfig{ID: "en-US-JennyNeural", Lang: "en-US"}} audio, err := adapter.Synthesize(ctx, "Hello", edgeModelReadAloud, config) if err != nil { t.Fatalf("Synthesize: %v", err) } if len(audio) == 0 { t.Fatal("expected non-empty audio") } if !bytes.Equal(audio, []byte("fake-webm-audio-data")) { t.Errorf("audio = %q", string(audio)) } } func TestEdgeAdapter_Stream_WithMockServer(t *testing.T) { t.Parallel() srv := httptest.NewServer(mockEdgeTTSHandler(t)) defer srv.Close() wsURL := "ws" + strings.TrimPrefix(srv.URL, "http") + "/edge/v1" client := NewEdgeWsClient() client.BaseURL = wsURL adapter := NewEdgeAdapterWithClient(slog.Default(), client) ctx := context.Background() config := tts.AudioConfig{Voice: tts.VoiceConfig{ID: "en-US-JennyNeural", Lang: "en-US"}} ch, errCh := adapter.Stream(ctx, "Hi", edgeModelReadAloud, config) var chunks [][]byte for b := range ch { chunks = append(chunks, b) } if err := <-errCh; err != nil { t.Fatalf("Stream err: %v", err) } if len(chunks) != 1 { t.Fatalf("expected 1 chunk, got %d", len(chunks)) } if !bytes.Equal(chunks[0], []byte("fake-webm-audio-data")) { t.Errorf("chunk = %q", chunks[0]) } } func TestEdgeAdapter_Synthesize_NotConnected(t *testing.T) { t.Parallel() // use client without BaseURL and not Connect, Synthesize will try to connect real Edge address, here use invalid URL to trigger quick failure client := NewEdgeWsClient() client.BaseURL = "ws://127.0.0.1:0/edge/v1" // no service adapter := NewEdgeAdapterWithClient(slog.Default(), client) ctx := context.Background() _, err := adapter.Synthesize(ctx, "x", edgeModelReadAloud, tts.AudioConfig{}) if err == nil { t.Fatal("expected error when connection fails") } } func TestEdgeAdapter_ResolveModel(t *testing.T) { t.Parallel() adapter := NewEdgeAdapter(slog.Default()) got, err := adapter.ResolveModel("") if err != nil { t.Fatalf("ResolveModel default: %v", err) } if got != edgeModelReadAloud { t.Fatalf("ResolveModel default got %q, want %q", got, edgeModelReadAloud) } got, err = adapter.ResolveModel("EDGE-READ-ALOUD") if err != nil { t.Fatalf("ResolveModel case-insensitive: %v", err) } if got != edgeModelReadAloud { t.Fatalf("ResolveModel normalized got %q, want %q", got, edgeModelReadAloud) } if _, err := adapter.ResolveModel("unsupported"); err == nil { t.Fatal("expected unsupported model error") } }