//go:build integration package edge import ( "context" "os" "path/filepath" "testing" "time" "github.com/memohai/memoh/internal/tts" ) // Real Edge TTS integration tests. Not compiled by default (requires -tags=integration). // Requires network access to speech.platform.bing.com. // // Run: // // go test -tags=integration ./internal/tts/adapter/edge/... -run TestRealEdgeTTS -v func TestRealEdgeTTS_Synthesize(t *testing.T) { client := NewEdgeWsClient() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() config := tts.AudioConfig{Voice: tts.VoiceConfig{ID: "en-US-JennyNeural", Lang: "en-US"}, Speed: 1.0} audio, err := client.Synthesize(ctx, "Hello, this is a real Edge TTS test.", config) if err != nil { t.Fatalf("Synthesize: %v", err) } if len(audio) == 0 { t.Fatal("expected non-empty audio from real Edge TTS") } t.Logf("got %d bytes of audio", len(audio)) } func TestRealEdgeTTS_Stream(t *testing.T) { client := NewEdgeWsClient() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() config := tts.AudioConfig{Voice: tts.VoiceConfig{ID: "zh-CN-XiaoxiaoNeural", Lang: "zh-CN"}} ch, errCh := client.Stream(ctx, "你好,这是流式测试。", config) var total int for b := range ch { total += len(b) } if err := <-errCh; err != nil { t.Fatalf("Stream: %v", err) } if total == 0 { t.Fatal("expected non-empty audio stream") } t.Logf("streamed %d bytes total", total) } // TestRealEdgeTTS_Formats tries every candidate format and reports which ones are supported. // // go test -tags=integration ./internal/tts/adapter/edge/... -run TestRealEdgeTTS_Formats -v func TestRealEdgeTTS_Formats(t *testing.T) { formats := []string{ "audio-24khz-48kbitrate-mono-mp3", "audio-24khz-96kbitrate-mono-mp3", "webm-24khz-16bit-mono-opus", } for _, fmt := range formats { t.Run(fmt, func(t *testing.T) { client := NewEdgeWsClient() ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() config := tts.AudioConfig{ Voice: tts.VoiceConfig{ID: "en-US-JennyNeural", Lang: "en-US"}, Format: fmt, Speed: 1.0, } audio, err := client.Synthesize(ctx, "Hello, format test.", config) if err != nil { t.Errorf("UNSUPPORTED format %q: %v", fmt, err) return } t.Logf("OK format %q -> %d bytes", fmt, len(audio)) }) } } // TestRealEdgeTTS_SaveAudio synthesizes speech and writes the result to a file for manual inspection. // // go test -tags=integration ./internal/tts/adapter/edge/... -run TestRealEdgeTTS_SaveAudio -v func TestRealEdgeTTS_SaveAudio(t *testing.T) { client := NewEdgeWsClient() ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) defer cancel() cases := []struct { name string text string voice tts.VoiceConfig file string }{ {"en", "Hello, this is an Edge TTS audio save test.", tts.VoiceConfig{ID: "en-US-JennyNeural", Lang: "en-US"}, "test_en.mp3"}, {"zh", "你好,这是一段中文语音合成测试。", tts.VoiceConfig{ID: "zh-CN-XiaoxiaoNeural", Lang: "zh-CN"}, "test_zh.mp3"}, } outDir := filepath.Join(os.TempDir(), "edge_tts_test") if err := os.MkdirAll(outDir, 0o755); err != nil { t.Fatalf("mkdir %s: %v", outDir, err) } for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { config := tts.AudioConfig{Voice: tc.voice, Speed: 1.0, Pitch: -10.0} audio, err := client.Synthesize(ctx, tc.text, config) if err != nil { t.Fatalf("Synthesize: %v", err) } if len(audio) == 0 { t.Fatal("expected non-empty audio") } outPath := filepath.Join(outDir, tc.file) if err := os.WriteFile(outPath, audio, 0o644); err != nil { t.Fatalf("write file: %v", err) } t.Logf("saved %d bytes -> %s", len(audio), outPath) }) } }