diff options
| author | Paul Buetow <paul@buetow.org> | 2026-03-08 08:41:59 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-03-08 08:41:59 +0200 |
| commit | aa733f9a86b02d7b4d6edd8022a44e4ba417b24c (patch) | |
| tree | efdea87ad377557bb222e948894b5db5832ce6e9 | |
| parent | 3a255c0c64f858d5c05797aba9a6d159b0c7d82f (diff) | |
test(task-374): fix errcheck issues in tests and support code
| -rw-r--r-- | internal/anki/apkg_generator_test.go | 28 | ||||
| -rw-r--r-- | internal/anki/generator_test.go | 80 | ||||
| -rw-r--r-- | internal/cli/command_test.go | 40 | ||||
| -rw-r--r-- | internal/gui/app.go | 16 | ||||
| -rw-r--r-- | internal/gui/generator.go | 4 | ||||
| -rw-r--r-- | internal/gui/widgets.go | 12 | ||||
| -rw-r--r-- | internal/processor/processor_test.go | 30 | ||||
| -rw-r--r-- | internal/testutil/helpers.go | 18 |
8 files changed, 176 insertions, 52 deletions
diff --git a/internal/anki/apkg_generator_test.go b/internal/anki/apkg_generator_test.go index 01e5a26..4f2db18 100644 --- a/internal/anki/apkg_generator_test.go +++ b/internal/anki/apkg_generator_test.go @@ -36,8 +36,12 @@ func TestAPKGAddCard(t *testing.T) { audioFile := filepath.Join(tempDir, "audio.mp3") imageFile := filepath.Join(tempDir, "image.jpg") - os.WriteFile(audioFile, []byte("audio data"), 0644) - os.WriteFile(imageFile, []byte("image data"), 0644) + if err := os.WriteFile(audioFile, []byte("audio data"), 0644); err != nil { + t.Fatalf("Failed to create test audio file: %v", err) + } + if err := os.WriteFile(imageFile, []byte("image data"), 0644); err != nil { + t.Fatalf("Failed to create test image file: %v", err) + } card := Card{ Bulgarian: "ябълка", @@ -85,8 +89,12 @@ func TestGenerateAPKG(t *testing.T) { audioFile := filepath.Join(tempDir, "audio.mp3") imageFile := filepath.Join(tempDir, "image.jpg") - os.WriteFile(audioFile, []byte("test audio data"), 0644) - os.WriteFile(imageFile, []byte("test image data"), 0644) + if err := os.WriteFile(audioFile, []byte("test audio data"), 0644); err != nil { + t.Fatalf("Failed to create APKG test audio file: %v", err) + } + if err := os.WriteFile(imageFile, []byte("test image data"), 0644); err != nil { + t.Fatalf("Failed to create APKG test image file: %v", err) + } gen := NewAPKGGenerator("Test Bulgarian Deck") @@ -121,7 +129,11 @@ func TestGenerateAPKG(t *testing.T) { if err != nil { t.Fatalf("Failed to open APKG as zip: %v", err) } - defer reader.Close() + defer func() { + if closeErr := reader.Close(); closeErr != nil { + t.Errorf("Failed to close APKG zip reader: %v", closeErr) + } + }() // Check for required files requiredFiles := map[string]bool{ @@ -172,7 +184,11 @@ func TestCreateDatabase(t *testing.T) { if err != nil { t.Fatalf("Failed to open database: %v", err) } - defer db.Close() + defer func() { + if closeErr := db.Close(); closeErr != nil { + t.Errorf("Failed to close database: %v", closeErr) + } + }() // Check core tables exist coreTables := []string{"col", "notes", "cards"} diff --git a/internal/anki/generator_test.go b/internal/anki/generator_test.go index 56d7035..685f864 100644 --- a/internal/anki/generator_test.go +++ b/internal/anki/generator_test.go @@ -207,7 +207,11 @@ func TestGenerateCSV(t *testing.T) { if err != nil { t.Fatalf("Failed to open CSV file: %v", err) } - defer file.Close() + defer func() { + if closeErr := file.Close(); closeErr != nil { + t.Errorf("Failed to close CSV file: %v", closeErr) + } + }() reader := csv.NewReader(file) records, err := reader.ReadAll() @@ -276,7 +280,11 @@ func TestGenerateCSVWithoutHeaders(t *testing.T) { if err != nil { t.Fatalf("Failed to open CSV file: %v", err) } - defer file.Close() + defer func() { + if closeErr := file.Close(); closeErr != nil { + t.Errorf("Failed to close CSV file: %v", closeErr) + } + }() reader := csv.NewReader(file) records, err := reader.ReadAll() @@ -299,28 +307,50 @@ func TestGenerateFromDirectory(t *testing.T) { // Create word directories word1Dir := filepath.Join(tempDir, "ябълка") - os.MkdirAll(word1Dir, 0755) + if err := os.MkdirAll(word1Dir, 0755); err != nil { + t.Fatalf("Failed to create word1 dir: %v", err) + } word2Dir := filepath.Join(tempDir, "котка") - os.MkdirAll(word2Dir, 0755) + if err := os.MkdirAll(word2Dir, 0755); err != nil { + t.Fatalf("Failed to create word2 dir: %v", err) + } // Create hidden directory (should be skipped) hiddenDir := filepath.Join(tempDir, ".hidden") - os.MkdirAll(hiddenDir, 0755) + if err := os.MkdirAll(hiddenDir, 0755); err != nil { + t.Fatalf("Failed to create hidden dir: %v", err) + } // Create word files - os.WriteFile(filepath.Join(word1Dir, "word.txt"), []byte("ябълка"), 0644) - os.WriteFile(filepath.Join(word1Dir, "translation.txt"), []byte("ябълка = apple"), 0644) - os.WriteFile(filepath.Join(word1Dir, "audio.mp3"), []byte("audio data"), 0644) - os.WriteFile(filepath.Join(word1Dir, "image.jpg"), []byte("image data"), 0644) - os.WriteFile(filepath.Join(word1Dir, "phonetic.txt"), []byte("YA-bul-ka\nStress on first syllable"), 0644) + if err := os.WriteFile(filepath.Join(word1Dir, "word.txt"), []byte("ябълка"), 0644); err != nil { + t.Fatalf("Failed to write word1 word.txt: %v", err) + } + if err := os.WriteFile(filepath.Join(word1Dir, "translation.txt"), []byte("ябълка = apple"), 0644); err != nil { + t.Fatalf("Failed to write word1 translation.txt: %v", err) + } + if err := os.WriteFile(filepath.Join(word1Dir, "audio.mp3"), []byte("audio data"), 0644); err != nil { + t.Fatalf("Failed to write word1 audio.mp3: %v", err) + } + if err := os.WriteFile(filepath.Join(word1Dir, "image.jpg"), []byte("image data"), 0644); err != nil { + t.Fatalf("Failed to write word1 image.jpg: %v", err) + } + if err := os.WriteFile(filepath.Join(word1Dir, "phonetic.txt"), []byte("YA-bul-ka\nStress on first syllable"), 0644); err != nil { + t.Fatalf("Failed to write word1 phonetic.txt: %v", err) + } // Word 2 with old format - os.WriteFile(filepath.Join(word2Dir, "_word.txt"), []byte("котка"), 0644) - os.WriteFile(filepath.Join(word2Dir, "audio.wav"), []byte("audio data"), 0644) + if err := os.WriteFile(filepath.Join(word2Dir, "_word.txt"), []byte("котка"), 0644); err != nil { + t.Fatalf("Failed to write word2 _word.txt: %v", err) + } + if err := os.WriteFile(filepath.Join(word2Dir, "audio.wav"), []byte("audio data"), 0644); err != nil { + t.Fatalf("Failed to write word2 audio.wav: %v", err) + } // Hidden directory files (should be ignored) - os.WriteFile(filepath.Join(hiddenDir, "word.txt"), []byte("hidden"), 0644) + if err := os.WriteFile(filepath.Join(hiddenDir, "word.txt"), []byte("hidden"), 0644); err != nil { + t.Fatalf("Failed to write hidden word.txt: %v", err) + } gen := NewGenerator(nil) err := gen.GenerateFromDirectory(tempDir) @@ -368,14 +398,20 @@ func TestCopyMediaFile(t *testing.T) { // Create source file structure srcDir := filepath.Join(tempDir, "src", "word123") - os.MkdirAll(srcDir, 0755) + if err := os.MkdirAll(srcDir, 0755); err != nil { + t.Fatalf("Failed to create source directory: %v", err) + } srcFile := filepath.Join(srcDir, "audio.mp3") - os.WriteFile(srcFile, []byte("test audio"), 0644) + if err := os.WriteFile(srcFile, []byte("test audio"), 0644); err != nil { + t.Fatalf("Failed to write source audio file: %v", err) + } // Create destination directory destDir := filepath.Join(tempDir, "dest") - os.MkdirAll(destDir, 0755) + if err := os.MkdirAll(destDir, 0755); err != nil { + t.Fatalf("Failed to create destination directory: %v", err) + } gen := NewGenerator(nil) @@ -472,13 +508,19 @@ func TestGeneratePackage(t *testing.T) { // Create source files srcDir := filepath.Join(tempDir, "src", "word1") - os.MkdirAll(srcDir, 0755) + if err := os.MkdirAll(srcDir, 0755); err != nil { + t.Fatalf("Failed to create package source directory: %v", err) + } audioFile := filepath.Join(srcDir, "audio.mp3") - os.WriteFile(audioFile, []byte("audio data"), 0644) + if err := os.WriteFile(audioFile, []byte("audio data"), 0644); err != nil { + t.Fatalf("Failed to write package audio file: %v", err) + } imageFile := filepath.Join(srcDir, "image.jpg") - os.WriteFile(imageFile, []byte("image data"), 0644) + if err := os.WriteFile(imageFile, []byte("image data"), 0644); err != nil { + t.Fatalf("Failed to write package image file: %v", err) + } // Create generator with card gen := NewGenerator(nil) diff --git a/internal/cli/command_test.go b/internal/cli/command_test.go index aac2e60..c6fa3d8 100644 --- a/internal/cli/command_test.go +++ b/internal/cli/command_test.go @@ -151,8 +151,14 @@ output: InitConfig(tt.cfgFile) // Test environment variable prefix - os.Setenv("TOTALRECALL_TEST_VAR", "test-value") - defer os.Unsetenv("TOTALRECALL_TEST_VAR") + if err := os.Setenv("TOTALRECALL_TEST_VAR", "test-value"); err != nil { + t.Fatalf("Failed to set env var: %v", err) + } + defer func() { + if err := os.Unsetenv("TOTALRECALL_TEST_VAR"); err != nil { + t.Errorf("Failed to unset env var: %v", err) + } + }() if viper.GetString("test_var") != "test-value" { t.Error("Environment variable not properly loaded") @@ -204,10 +210,18 @@ func TestGetOpenAIKey(t *testing.T) { // Set up environment if tt.envKey != "" { - os.Setenv("OPENAI_API_KEY", tt.envKey) - defer os.Unsetenv("OPENAI_API_KEY") + if err := os.Setenv("OPENAI_API_KEY", tt.envKey); err != nil { + t.Fatalf("Failed to set OPENAI_API_KEY: %v", err) + } + defer func() { + if err := os.Unsetenv("OPENAI_API_KEY"); err != nil { + t.Errorf("Failed to unset OPENAI_API_KEY: %v", err) + } + }() } else { - os.Unsetenv("OPENAI_API_KEY") + if err := os.Unsetenv("OPENAI_API_KEY"); err != nil { + t.Fatalf("Failed to unset OPENAI_API_KEY: %v", err) + } } // Set up config @@ -239,11 +253,19 @@ func TestBindFlagsToViper(t *testing.T) { setupFlags(cmd, flags) // Set some flag values - cmd.Flags().Set("output", "/test/output") - cmd.Flags().Set("format", "wav") - cmd.Flags().Set("openai-model", "tts-1-hd") + if err := cmd.Flags().Set("output", "/test/output"); err != nil { + t.Fatalf("Failed to set output flag: %v", err) + } + if err := cmd.Flags().Set("format", "wav"); err != nil { + t.Fatalf("Failed to set format flag: %v", err) + } + if err := cmd.Flags().Set("openai-model", "tts-1-hd"); err != nil { + t.Fatalf("Failed to set openai-model flag: %v", err) + } - bindFlagsToViper(cmd) + if err := bindFlagsToViper(cmd); err != nil { + t.Fatalf("bindFlagsToViper() failed: %v", err) + } // Test that values are bound if viper.GetString("output.directory") != "/test/output" { diff --git a/internal/gui/app.go b/internal/gui/app.go index c65cb42..5d37879 100644 --- a/internal/gui/app.go +++ b/internal/gui/app.go @@ -146,7 +146,9 @@ func New(config *Config) *Application { } // Ensure output directory exists - os.MkdirAll(config.OutputDir, 0755) + if err := os.MkdirAll(config.OutputDir, 0755); err != nil { + fmt.Fprintf(os.Stderr, "Warning: failed to create output directory %q: %v\n", config.OutputDir, err) + } ctx, cancel := context.WithCancel(context.Background()) @@ -629,7 +631,9 @@ func (a *Application) generateMaterials(word string) { if translation != "" { translationFile := filepath.Join(cardDir, "translation.txt") content := fmt.Sprintf("%s = %s\n", word, translation) - os.WriteFile(translationFile, []byte(content), 0644) + if err := os.WriteFile(translationFile, []byte(content), 0644); err != nil { + fmt.Printf("Warning: Failed to save translation for '%s': %v\n", word, err) + } } } // Create channels for parallel operations @@ -722,7 +726,9 @@ func (a *Application) generateMaterials(word string) { // Save phonetic info to disk using the pre-determined directory if phoneticInfo != "" && phoneticInfo != "Failed to fetch phonetic information" { phoneticFile := filepath.Join(cardDir, "phonetic.txt") - os.WriteFile(phoneticFile, []byte(phoneticInfo), 0644) + if err := os.WriteFile(phoneticFile, []byte(phoneticInfo), 0644); err != nil { + fmt.Printf("Warning: Failed to save phonetic info for '%s': %v\n", word, err) + } } // Update UI immediately with phonetic info if this is still the current word if phoneticInfo != "" && phoneticInfo != "Failed to fetch phonetic information" { @@ -2161,7 +2167,9 @@ func (a *Application) processWordJob(job *WordJob) { // Save phonetic info to disk immediately for this specific word if phoneticInfo != "" && phoneticInfo != "Failed to fetch phonetic information" { phoneticFile := filepath.Join(cardDir, "phonetic.txt") - os.WriteFile(phoneticFile, []byte(phoneticInfo), 0644) + if err := os.WriteFile(phoneticFile, []byte(phoneticInfo), 0644); err != nil { + fmt.Printf("Warning: Failed to save phonetic info for '%s': %v\n", job.Word, err) + } } // Update UI immediately with phonetic info if this is still the current job diff --git a/internal/gui/generator.go b/internal/gui/generator.go index 9c20e92..14f0f60 100644 --- a/internal/gui/generator.go +++ b/internal/gui/generator.go @@ -327,7 +327,9 @@ func (a *Application) generateImagesWithPrompt(ctx context.Context, word string, openaiClient.SetPromptCallback(func(prompt string) { // Save the prompt to disk immediately for this word promptFile := filepath.Join(cardDir, "image_prompt.txt") - os.WriteFile(promptFile, []byte(prompt), 0644) + if err := os.WriteFile(promptFile, []byte(prompt), 0644); err != nil { + fmt.Printf("Warning: Failed to save prompt for '%s': %v\n", word, err) + } // Only update UI if this word is still the current word a.mu.Lock() diff --git a/internal/gui/widgets.go b/internal/gui/widgets.go index 6e40391..aee6f13 100644 --- a/internal/gui/widgets.go +++ b/internal/gui/widgets.go @@ -81,7 +81,11 @@ func (d *ImageDisplay) SetImage(imagePath string) { d.imageLabel.SetText(fmt.Sprintf("Error loading image: %v", err)) return } - defer file.Close() + defer func() { + if closeErr := file.Close(); closeErr != nil { + fmt.Printf("Warning: failed to close image file %q: %v\n", imagePath, closeErr) + } + }() // Get file info to ensure it's fully written stat, err := file.Stat() @@ -141,7 +145,11 @@ func ResourceFromPath(path string) (fyne.Resource, error) { if err != nil { return nil, err } - defer file.Close() + defer func() { + if closeErr := file.Close(); closeErr != nil { + fmt.Printf("Warning: failed to close resource file %q: %v\n", path, closeErr) + } + }() data, err := os.ReadFile(path) if err != nil { diff --git a/internal/processor/processor_test.go b/internal/processor/processor_test.go index 2c8eaa6..e835681 100644 --- a/internal/processor/processor_test.go +++ b/internal/processor/processor_test.go @@ -10,8 +10,14 @@ import ( func TestNewProcessor(t *testing.T) { // Set up test environment - os.Setenv("OPENAI_API_KEY", "test-key") - defer os.Unsetenv("OPENAI_API_KEY") + if err := os.Setenv("OPENAI_API_KEY", "test-key"); err != nil { + t.Fatalf("Failed to set OPENAI_API_KEY: %v", err) + } + defer func() { + if err := os.Unsetenv("OPENAI_API_KEY"); err != nil { + t.Errorf("Failed to unset OPENAI_API_KEY: %v", err) + } + }() flags := cli.NewFlags() p := NewProcessor(flags) @@ -223,7 +229,9 @@ func TestGenerateAnkiFile(t *testing.T) { if _, err := os.Stat(csvFile); os.IsNotExist(err) { t.Error("CSV file was not created in home directory") } - os.Remove(csvFile) // Clean up + if err := os.Remove(csvFile); err != nil && !os.IsNotExist(err) { + t.Errorf("Failed to remove CSV file: %v", err) + } } func TestGenerateAnkiFile_APKG(t *testing.T) { @@ -243,9 +251,15 @@ func TestGenerateAnkiFile_APKG(t *testing.T) { p.translationCache.Add("котка", "cat") // Create dummy audio and image files - os.WriteFile(filepath.Join(word1Dir, "audio.mp3"), []byte("audio1"), 0644) - os.WriteFile(filepath.Join(word2Dir, "audio.mp3"), []byte("audio2"), 0644) - os.WriteFile(filepath.Join(word1Dir, "image.jpg"), []byte("image1"), 0644) + if err := os.WriteFile(filepath.Join(word1Dir, "audio.mp3"), []byte("audio1"), 0644); err != nil { + t.Fatalf("Failed to create test audio1 file: %v", err) + } + if err := os.WriteFile(filepath.Join(word2Dir, "audio.mp3"), []byte("audio2"), 0644); err != nil { + t.Fatalf("Failed to create test audio2 file: %v", err) + } + if err := os.WriteFile(filepath.Join(word1Dir, "image.jpg"), []byte("image1"), 0644); err != nil { + t.Fatalf("Failed to create test image file: %v", err) + } _, err := p.GenerateAnkiFile() if err != nil { @@ -264,6 +278,8 @@ func TestGenerateAnkiFile_APKG(t *testing.T) { // Clean up the created file for _, file := range files { - os.Remove(file) + if err := os.Remove(file); err != nil && !os.IsNotExist(err) { + t.Errorf("Failed to remove APKG file %s: %v", file, err) + } } } diff --git a/internal/testutil/helpers.go b/internal/testutil/helpers.go index 8f82a9e..08e03a5 100644 --- a/internal/testutil/helpers.go +++ b/internal/testutil/helpers.go @@ -189,8 +189,14 @@ func CaptureOutput(t *testing.T, f func()) (stdout, stderr string) { oldStderr := os.Stderr // Create pipes - rOut, wOut, _ := os.Pipe() - rErr, wErr, _ := os.Pipe() + rOut, wOut, err := os.Pipe() + if err != nil { + t.Fatalf("failed to create stdout pipe: %v", err) + } + rErr, wErr, err := os.Pipe() + if err != nil { + t.Fatalf("failed to create stderr pipe: %v", err) + } // Redirect stdout/stderr os.Stdout = wOut @@ -200,8 +206,12 @@ func CaptureOutput(t *testing.T, f func()) (stdout, stderr string) { f() // Close writers - wOut.Close() - wErr.Close() + if err := wOut.Close(); err != nil { + t.Fatalf("failed to close stdout writer: %v", err) + } + if err := wErr.Close(); err != nil { + t.Fatalf("failed to close stderr writer: %v", err) + } // Read output outBytes := make([]byte, 1024) |
