summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-04-01 13:31:12 +0300
committerPaul Buetow <paul@buetow.org>2026-04-01 13:31:12 +0300
commit7435d08d70107d20e13a0a725c9e8645ac3f7c57 (patch)
tree58036d3b2cc978734ea001b8a8f1b25a95d6d71d /internal
parent327817bae6a386f37d31d50a962c559d747a5383 (diff)
zs: preserve OpenAI default for phonetics
Diffstat (limited to 'internal')
-rw-r--r--internal/phonetic/fetcher.go9
-rw-r--r--internal/phonetic/fetcher_test.go86
-rw-r--r--internal/processor/processor_test.go40
3 files changed, 111 insertions, 24 deletions
diff --git a/internal/phonetic/fetcher.go b/internal/phonetic/fetcher.go
index 8919345..a59d1f4 100644
--- a/internal/phonetic/fetcher.go
+++ b/internal/phonetic/fetcher.go
@@ -147,6 +147,11 @@ func (f *Fetcher) FetchAndSave(word, wordDir string) error {
return nil
}
+// Provider reports the configured phonetic backend.
+func (f *Fetcher) Provider() Provider {
+ return f.provider
+}
+
func (f *Fetcher) fetchPhoneticInfo(ctx context.Context, word string) (string, error) {
switch f.provider {
case ProviderOpenAI:
@@ -185,7 +190,7 @@ func (f *Fetcher) fetchWithGemini(ctx context.Context, word string) (string, err
func normalizeConfig(config *Config) Config {
normalized := Config{
- Provider: ProviderGemini,
+ Provider: ProviderOpenAI,
OpenAIKey: "",
GoogleAPIKey: "",
}
@@ -204,7 +209,7 @@ func normalizeConfig(config *Config) Config {
func normalizeProvider(provider Provider) Provider {
normalized := Provider(strings.ToLower(strings.TrimSpace(string(provider))))
if normalized == "" {
- return ProviderGemini
+ return ProviderOpenAI
}
return normalized
diff --git a/internal/phonetic/fetcher_test.go b/internal/phonetic/fetcher_test.go
index 3382457..fedc5c2 100644
--- a/internal/phonetic/fetcher_test.go
+++ b/internal/phonetic/fetcher_test.go
@@ -10,28 +10,34 @@ import (
"google.golang.org/genai"
)
-func TestNewFetcher_DefaultsToGemini(t *testing.T) {
+func TestNewFetcher_DefaultsToOpenAI(t *testing.T) {
fetcher := NewFetcher(nil)
if fetcher == nil {
t.Fatal("NewFetcher returned nil")
}
- if fetcher.provider != ProviderGemini {
- t.Fatalf("expected default provider %q, got %q", ProviderGemini, fetcher.provider)
+ if got := fetcher.Provider(); got != ProviderOpenAI {
+ t.Fatalf("expected default provider %q, got %q", ProviderOpenAI, got)
}
+}
- if fetcher.openAIClient != nil {
- t.Error("expected OpenAI client to be nil without an API key")
+func TestFetchAndSave_NoOpenAIAPIKey(t *testing.T) {
+ fetcher := NewFetcher(&Config{Provider: ProviderOpenAI})
+ tmpDir := t.TempDir()
+
+ err := fetcher.FetchAndSave("ябълка", tmpDir)
+ if err == nil {
+ t.Fatal("expected error for missing OpenAI API key")
}
- if fetcher.geminiClient != nil {
- t.Error("expected Gemini client to be nil without an API key")
+ if err.Error() != "OpenAI API key not configured" {
+ t.Fatalf("expected OpenAI API key error, got %v", err)
}
}
func TestFetchAndSave_NoGoogleAPIKey(t *testing.T) {
- fetcher := NewFetcher(nil)
+ fetcher := NewFetcher(&Config{Provider: ProviderGemini})
tmpDir := t.TempDir()
err := fetcher.FetchAndSave("ябълка", tmpDir)
@@ -44,17 +50,17 @@ func TestFetchAndSave_NoGoogleAPIKey(t *testing.T) {
}
}
-func TestFetchAndSave_NoOpenAIAPIKey(t *testing.T) {
- fetcher := NewFetcher(&Config{Provider: ProviderOpenAI})
+func TestFetchAndSave_UnknownProvider(t *testing.T) {
+ fetcher := NewFetcher(&Config{Provider: Provider("mystery")})
tmpDir := t.TempDir()
err := fetcher.FetchAndSave("ябълка", tmpDir)
if err == nil {
- t.Fatal("expected error for missing OpenAI API key")
+ t.Fatal("expected error for unknown provider")
}
- if err.Error() != "OpenAI API key not configured" {
- t.Fatalf("expected OpenAI API key error, got %v", err)
+ if err.Error() != "unknown phonetic provider: mystery" {
+ t.Fatalf("expected unknown provider error, got %v", err)
}
}
@@ -124,22 +130,58 @@ func TestFetchAndSave_GeminiProvider_WritesFile(t *testing.T) {
}
}
-func TestFetchAndSave_InvalidDirectory(t *testing.T) {
- originalFetch := fetchOpenAIPhonetic
- fetchOpenAIPhonetic = func(context.Context, *openai.Client, string) (string, error) {
- return "[ˈjɤbɐlkɐ]", nil
+func TestFetchAndSave_GeminiInitFailure(t *testing.T) {
+ originalNewGeminiClient := newGeminiClient
+ newGeminiClient = func(context.Context, *genai.ClientConfig) (*genai.Client, error) {
+ return nil, context.Canceled
}
t.Cleanup(func() {
- fetchOpenAIPhonetic = originalFetch
+ newGeminiClient = originalNewGeminiClient
})
fetcher := NewFetcher(&Config{
- Provider: ProviderOpenAI,
- OpenAIKey: "test-openai-key",
+ Provider: ProviderGemini,
+ GoogleAPIKey: "test-google-key",
})
- err := fetcher.FetchAndSave("ябълка", "/nonexistent/path")
+ err := fetcher.FetchAndSave("ябълка", t.TempDir())
if err == nil {
- t.Fatal("expected error for invalid directory")
+ t.Fatal("expected Gemini init failure")
+ }
+
+ if err.Error() != "Gemini client initialization failed: context canceled" {
+ t.Fatalf("unexpected Gemini init error: %v", err)
+ }
+}
+
+func TestFetchAndSave_GeminiAPIFailure(t *testing.T) {
+ originalFetch := fetchGeminiPhonetic
+ fetchGeminiPhonetic = func(context.Context, *genai.Client, string) (string, error) {
+ return "", context.DeadlineExceeded
+ }
+ t.Cleanup(func() {
+ fetchGeminiPhonetic = originalFetch
+ })
+
+ originalNewGeminiClient := newGeminiClient
+ newGeminiClient = func(context.Context, *genai.ClientConfig) (*genai.Client, error) {
+ return &genai.Client{}, nil
+ }
+ t.Cleanup(func() {
+ newGeminiClient = originalNewGeminiClient
+ })
+
+ fetcher := NewFetcher(&Config{
+ Provider: ProviderGemini,
+ GoogleAPIKey: "test-google-key",
+ })
+
+ err := fetcher.FetchAndSave("ябълка", t.TempDir())
+ if err == nil {
+ t.Fatal("expected Gemini API failure")
+ }
+
+ if err.Error() != "context deadline exceeded" {
+ t.Fatalf("unexpected Gemini API error: %v", err)
}
}
diff --git a/internal/processor/processor_test.go b/internal/processor/processor_test.go
index d0a0070..ad71263 100644
--- a/internal/processor/processor_test.go
+++ b/internal/processor/processor_test.go
@@ -6,6 +6,7 @@ import (
"testing"
"codeberg.org/snonux/totalrecall/internal/cli"
+ "codeberg.org/snonux/totalrecall/internal/phonetic"
"github.com/spf13/viper"
)
@@ -44,6 +45,45 @@ func TestNewProcessor(t *testing.T) {
}
}
+func TestNewProcessor_DefaultPhoneticProviderUsesOpenAI(t *testing.T) {
+ t.Setenv("OPENAI_API_KEY", "")
+ t.Setenv("GOOGLE_API_KEY", "")
+
+ originalConfig := viper.New()
+ *originalConfig = *viper.GetViper()
+ defer func() {
+ *viper.GetViper() = *originalConfig
+ }()
+ viper.Reset()
+
+ flags := cli.NewFlags()
+ p := NewProcessor(flags)
+
+ if got := p.phoneticFetcher.Provider(); got != phonetic.ProviderOpenAI {
+ t.Fatalf("expected default phonetic provider %q, got %q", phonetic.ProviderOpenAI, got)
+ }
+}
+
+func TestNewProcessor_ExplicitGeminiPhoneticProvider(t *testing.T) {
+ t.Setenv("OPENAI_API_KEY", "")
+ t.Setenv("GOOGLE_API_KEY", "")
+
+ originalConfig := viper.New()
+ *originalConfig = *viper.GetViper()
+ defer func() {
+ *viper.GetViper() = *originalConfig
+ }()
+ viper.Reset()
+ viper.Set("phonetic.provider", "gemini")
+
+ flags := cli.NewFlags()
+ p := NewProcessor(flags)
+
+ if got := p.phoneticFetcher.Provider(); got != phonetic.ProviderGemini {
+ t.Fatalf("expected gemini phonetic provider %q, got %q", phonetic.ProviderGemini, got)
+ }
+}
+
func TestNewProcessor_DefaultTranslationProviderUsesOpenAI(t *testing.T) {
t.Setenv("OPENAI_API_KEY", "")
t.Setenv("GOOGLE_API_KEY", "")