diff options
| author | Paul Buetow <paul@buetow.org> | 2026-04-01 13:40:50 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-04-01 13:40:50 +0300 |
| commit | be758529bd22fd1f0d43a8b9f8a55197db0f1f60 (patch) | |
| tree | 603b07c6d80b1b71e8c726c5a33046ad6a3b3510 /internal/audio/gemini_provider_test.go | |
| parent | 7435d08d70107d20e13a0a725c9e8645ac3f7c57 (diff) | |
zf: add Gemini TTS provider
Diffstat (limited to 'internal/audio/gemini_provider_test.go')
| -rw-r--r-- | internal/audio/gemini_provider_test.go | 143 |
1 files changed, 143 insertions, 0 deletions
diff --git a/internal/audio/gemini_provider_test.go b/internal/audio/gemini_provider_test.go new file mode 100644 index 0000000..1c04f55 --- /dev/null +++ b/internal/audio/gemini_provider_test.go @@ -0,0 +1,143 @@ +package audio + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "google.golang.org/genai" +) + +func TestNewGeminiProvider(t *testing.T) { + tests := []struct { + name string + config *Config + wantErr bool + }{ + { + name: "missing google api key", + config: &Config{}, + wantErr: true, + }, + { + name: "valid config", + config: &Config{ + GoogleAPIKey: "test-key", + GeminiTTSModel: "gemini-2.5-flash", + GeminiVoice: "Kore", + GeminiSpeed: 1.0, + }, + wantErr: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + provider, err := NewGeminiProvider(tt.config) + if (err != nil) != tt.wantErr { + t.Fatalf("NewGeminiProvider() error = %v, wantErr %v", err, tt.wantErr) + } + if err != nil { + return + } + + if provider.Name() != "gemini" { + t.Fatalf("Name() = %q, want %q", provider.Name(), "gemini") + } + }) + } +} + +func TestGeminiProviderIsAvailable(t *testing.T) { + provider := &GeminiProvider{ + config: &Config{GoogleAPIKey: "test-key"}, + } + + if err := provider.IsAvailable(); err != nil { + t.Fatalf("IsAvailable() unexpected error: %v", err) + } + + provider.config.GoogleAPIKey = "" + if err := provider.IsAvailable(); err == nil { + t.Fatal("IsAvailable() expected error when API key is missing") + } +} + +func TestGeminiProviderBuildPrompt(t *testing.T) { + provider := &GeminiProvider{ + config: &Config{ + GeminiVoice: "Kore", + GeminiSpeed: 0.92, + }, + } + + prompt := provider.buildPrompt("ябълка") + + for _, want := range []string{ + "Bulgarian language", + "authentic Bulgarian phonetics", + "Speak slowly and clearly for language learners.", + "ябълка", + "voice named Kore", + } { + if !strings.Contains(prompt, want) { + t.Fatalf("buildPrompt() = %q, missing %q", prompt, want) + } + } +} + +func TestExtractAudioData(t *testing.T) { + response := &genai.GenerateContentResponse{ + Candidates: []*genai.Candidate{ + { + Content: &genai.Content{ + Parts: []*genai.Part{ + { + InlineData: &genai.Blob{ + Data: []byte{0x01, 0x02, 0x03}, + MIMEType: "audio/pcm", + }, + }, + }, + }, + }, + }, + } + + data, mimeType, err := extractAudioData(response) + if err != nil { + t.Fatalf("extractAudioData() unexpected error: %v", err) + } + + if mimeType != "audio/pcm" { + t.Fatalf("extractAudioData() mimeType = %q, want %q", mimeType, "audio/pcm") + } + + if len(data) != 3 || data[0] != 0x01 || data[1] != 0x02 || data[2] != 0x03 { + t.Fatalf("extractAudioData() data = %v, want raw audio bytes", data) + } +} + +func TestWriteGeminiAudioFileWritesWAV(t *testing.T) { + dir := t.TempDir() + outputFile := filepath.Join(dir, "output.wav") + pcmData := []byte{0x11, 0x22, 0x33, 0x44} + + if err := writeGeminiAudioFile(outputFile, pcmData, "audio/pcm"); err != nil { + t.Fatalf("writeGeminiAudioFile() unexpected error: %v", err) + } + + fileData, err := os.ReadFile(outputFile) + if err != nil { + t.Fatalf("ReadFile() unexpected error: %v", err) + } + + if !strings.HasPrefix(string(fileData[:4]), "RIFF") { + t.Fatalf("output file does not look like WAV data: %q", fileData[:4]) + } + + if got, want := len(fileData), 44+len(pcmData); got != want { + t.Fatalf("len(output) = %d, want %d", got, want) + } +} |
