summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-03-08 08:41:59 +0200
committerPaul Buetow <paul@buetow.org>2026-03-08 08:41:59 +0200
commitaa733f9a86b02d7b4d6edd8022a44e4ba417b24c (patch)
treeefdea87ad377557bb222e948894b5db5832ce6e9
parent3a255c0c64f858d5c05797aba9a6d159b0c7d82f (diff)
test(task-374): fix errcheck issues in tests and support code
-rw-r--r--internal/anki/apkg_generator_test.go28
-rw-r--r--internal/anki/generator_test.go80
-rw-r--r--internal/cli/command_test.go40
-rw-r--r--internal/gui/app.go16
-rw-r--r--internal/gui/generator.go4
-rw-r--r--internal/gui/widgets.go12
-rw-r--r--internal/processor/processor_test.go30
-rw-r--r--internal/testutil/helpers.go18
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)