summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-01 20:35:55 +0300
committerPaul Buetow <paul@buetow.org>2026-04-01 20:35:55 +0300
commit443694d226db91695c2cdddf97d6b9e06923b7be (patch)
treeaa1e31dda33b245316917fa94a4e8fbb8c52628c
parent5ae64f1658fb8e1daa9400efab96f3fcee5d17c0 (diff)
zg: add bg-bg consumer coverage
-rw-r--r--internal/gui/generator.go2
-rw-r--r--internal/gui/generator_test.go75
-rw-r--r--internal/processor/processor_test.go87
3 files changed, 163 insertions, 1 deletions
diff --git a/internal/gui/generator.go b/internal/gui/generator.go
index 34e713e..34e63fc 100644
--- a/internal/gui/generator.go
+++ b/internal/gui/generator.go
@@ -205,7 +205,7 @@ func (a *Application) generateAudioBgBg(ctx context.Context, front, back, cardDi
audioConfig.OpenAISpeed = speed
audioConfig.OutputDir = a.config.OutputDir
- provider, err := audio.NewProvider(&audioConfig)
+ provider, err := newAudioProvider(&audioConfig)
if err != nil {
return "", "", err
}
diff --git a/internal/gui/generator_test.go b/internal/gui/generator_test.go
index d768560..5493de9 100644
--- a/internal/gui/generator_test.go
+++ b/internal/gui/generator_test.go
@@ -56,12 +56,16 @@ func (f *fakePromptAwareImageClient) SetPromptCallback(callback func(prompt stri
type fakeAudioProvider struct {
generateCalls int
+ texts []string
+ outputFiles []string
lastText string
lastOutputFile string
}
func (f *fakeAudioProvider) GenerateAudio(_ context.Context, text, outputFile string) error {
f.generateCalls++
+ f.texts = append(f.texts, text)
+ f.outputFiles = append(f.outputFiles, outputFile)
f.lastText = text
f.lastOutputFile = outputFile
return nil
@@ -214,3 +218,74 @@ func TestGenerateAudioUsesSharedOpenAIVoices(t *testing.T) {
t.Fatalf("outputPath = %q, want shared audio filename", outputPath)
}
}
+
+func TestGenerateAudioBgBgUsesSharedOpenAIVoices(t *testing.T) {
+ originalFactory := newAudioProvider
+ t.Cleanup(func() {
+ newAudioProvider = originalFactory
+ })
+
+ originalVoices := append([]string(nil), audio.OpenAIVoices...)
+ t.Cleanup(func() {
+ audio.OpenAIVoices = originalVoices
+ })
+
+ audio.OpenAIVoices = []string{"sentinel-bg-gui-voice"}
+
+ fakeProvider := &fakeAudioProvider{}
+ var capturedConfig *audio.Config
+ newAudioProvider = func(config *audio.Config) (audio.Provider, error) {
+ copyConfig := *config
+ capturedConfig = &copyConfig
+ return fakeProvider, nil
+ }
+
+ tempDir := t.TempDir()
+ cardDir := filepath.Join(tempDir, "card")
+ if err := os.MkdirAll(cardDir, 0755); err != nil {
+ t.Fatalf("failed to create card dir: %v", err)
+ }
+
+ app := &Application{
+ config: &Config{
+ OutputDir: tempDir,
+ AudioFormat: "mp3",
+ },
+ audioConfig: &audio.Config{
+ Provider: "openai",
+ OutputDir: tempDir,
+ OpenAIModel: "gpt-4o-mini-tts",
+ OpenAIInstruction: "Speak clearly.",
+ },
+ }
+
+ frontPath, backPath, err := app.generateAudioBgBg(context.Background(), "ябълка", "круша", cardDir)
+ if err != nil {
+ t.Fatalf("generateAudioBgBg() unexpected error: %v", err)
+ }
+
+ if capturedConfig == nil {
+ t.Fatal("expected audio provider config to be captured")
+ }
+ if capturedConfig.OpenAIVoice != "sentinel-bg-gui-voice" {
+ t.Fatalf("captured OpenAIVoice = %q, want %q", capturedConfig.OpenAIVoice, "sentinel-bg-gui-voice")
+ }
+ if fakeProvider.generateCalls != 2 {
+ t.Fatalf("GenerateAudio() calls = %d, want %d", fakeProvider.generateCalls, 2)
+ }
+ if len(fakeProvider.outputFiles) != 2 {
+ t.Fatalf("output file count = %d, want %d", len(fakeProvider.outputFiles), 2)
+ }
+ if !strings.HasSuffix(fakeProvider.outputFiles[0], "audio_front.mp3") {
+ t.Fatalf("front output file = %q, want audio_front.mp3", fakeProvider.outputFiles[0])
+ }
+ if !strings.HasSuffix(fakeProvider.outputFiles[1], "audio_back.mp3") {
+ t.Fatalf("back output file = %q, want audio_back.mp3", fakeProvider.outputFiles[1])
+ }
+ if !strings.HasSuffix(frontPath, "audio_front.mp3") {
+ t.Fatalf("frontPath = %q, want audio_front.mp3", frontPath)
+ }
+ if !strings.HasSuffix(backPath, "audio_back.mp3") {
+ t.Fatalf("backPath = %q, want audio_back.mp3", backPath)
+ }
+}
diff --git a/internal/processor/processor_test.go b/internal/processor/processor_test.go
index 1b86910..c944d7a 100644
--- a/internal/processor/processor_test.go
+++ b/internal/processor/processor_test.go
@@ -2,6 +2,7 @@ package processor
import (
"context"
+ "errors"
"io"
"os"
"path/filepath"
@@ -59,12 +60,16 @@ func (s *stubImageSearcher) GetLastPrompt() string {
type fakeAudioProvider struct {
generateCalls int
+ texts []string
+ outputFiles []string
lastText string
lastOutputFile string
}
func (f *fakeAudioProvider) GenerateAudio(_ context.Context, text, outputFile string) error {
f.generateCalls++
+ f.texts = append(f.texts, text)
+ f.outputFiles = append(f.outputFiles, outputFile)
f.lastText = text
f.lastOutputFile = outputFile
return nil
@@ -303,6 +308,88 @@ func TestGenerateAudioUsesSharedOpenAIVoices(t *testing.T) {
}
}
+func TestGenerateAudioBgBgUsesSharedOpenAIVoices(t *testing.T) {
+ originalFactory := newAudioProvider
+ t.Cleanup(func() {
+ newAudioProvider = originalFactory
+ })
+
+ originalVoices := append([]string(nil), audio.OpenAIVoices...)
+ t.Cleanup(func() {
+ audio.OpenAIVoices = originalVoices
+ })
+
+ audio.OpenAIVoices = []string{"sentinel-bg-voice"}
+
+ fakeProvider := &fakeAudioProvider{}
+ var capturedConfig *audio.Config
+ newAudioProvider = func(config *audio.Config) (audio.Provider, error) {
+ copyConfig := *config
+ capturedConfig = &copyConfig
+ return fakeProvider, nil
+ }
+
+ tempDir := t.TempDir()
+ flags := cli.NewFlags()
+ flags.OutputDir = tempDir
+ flags.AudioFormat = "mp3"
+
+ p := NewProcessor(flags)
+ if err := p.generateAudioBgBg("ябълка", "круша"); err != nil {
+ t.Fatalf("generateAudioBgBg() unexpected error: %v", err)
+ }
+
+ if capturedConfig == nil {
+ t.Fatal("expected audio provider config to be captured")
+ }
+ if capturedConfig.OpenAIVoice != "sentinel-bg-voice" {
+ t.Fatalf("captured OpenAIVoice = %q, want %q", capturedConfig.OpenAIVoice, "sentinel-bg-voice")
+ }
+ if fakeProvider.generateCalls != 2 {
+ t.Fatalf("GenerateAudio() calls = %d, want %d", fakeProvider.generateCalls, 2)
+ }
+ if len(fakeProvider.outputFiles) != 2 {
+ t.Fatalf("output file count = %d, want %d", len(fakeProvider.outputFiles), 2)
+ }
+ if !strings.HasSuffix(fakeProvider.outputFiles[0], "audio_front.mp3") {
+ t.Fatalf("front output file = %q, want audio_front.mp3", fakeProvider.outputFiles[0])
+ }
+ if !strings.HasSuffix(fakeProvider.outputFiles[1], "audio_back.mp3") {
+ t.Fatalf("back output file = %q, want audio_back.mp3", fakeProvider.outputFiles[1])
+ }
+}
+
+func TestGenerateAudioProviderFactoryError(t *testing.T) {
+ originalFactory := newAudioProvider
+ t.Cleanup(func() {
+ newAudioProvider = originalFactory
+ })
+
+ originalVoices := append([]string(nil), audio.OpenAIVoices...)
+ t.Cleanup(func() {
+ audio.OpenAIVoices = originalVoices
+ })
+
+ audio.OpenAIVoices = []string{"sentinel-failure-voice"}
+ newAudioProvider = func(*audio.Config) (audio.Provider, error) {
+ return nil, errors.New("provider factory failed")
+ }
+
+ tempDir := t.TempDir()
+ flags := cli.NewFlags()
+ flags.OutputDir = tempDir
+ flags.AudioFormat = "mp3"
+
+ p := NewProcessor(flags)
+ err := p.generateAudio("ябълка")
+ if err == nil {
+ t.Fatal("generateAudio() expected error from provider factory")
+ }
+ if !strings.Contains(err.Error(), "provider factory failed") {
+ t.Fatalf("generateAudio() error = %q, want it to contain %q", err.Error(), "provider factory failed")
+ }
+}
+
func TestDownloadImagesWithTranslationUsesNanoBananaConfigAndSavesPrompt(t *testing.T) {
t.Setenv("OPENAI_API_KEY", "test-openai-key")
t.Setenv("GOOGLE_API_KEY", "test-google-key")