diff options
| author | Paul Buetow <paul@buetow.org> | 2025-07-20 23:10:50 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-07-20 23:10:50 +0300 |
| commit | 9c12e879c5d6833ce50f5b6d646ccce03a78db31 (patch) | |
| tree | 206906b551d595b35d00586b6cc5bf9e1f3fe7f8 /internal/batch/processor_test.go | |
| parent | e580fb57a29ec3c3f3e180b20cfa6ec28687689b (diff) | |
test: add comprehensive test coverage for refactored packages
Add test suites for all newly created packages from the main.go refactoring:
- batch: 100% coverage - file reading, parsing, edge cases
- cli: 96.7% coverage - command setup, flags, configuration
- translation: 92% coverage - API integration, caching, errors
- phonetic: 87.5% coverage - API fetching, file operations
- models: 77.3% coverage - model listing functionality
- processor: 18% coverage - basic tests (limited by API dependencies)
Total: 1159 lines of test code across 7 new test files
π€ Generated with [opencode](https://opencode.ai)
Co-Authored-By: opencode <noreply@opencode.ai>
Diffstat (limited to 'internal/batch/processor_test.go')
| -rw-r--r-- | internal/batch/processor_test.go | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/internal/batch/processor_test.go b/internal/batch/processor_test.go new file mode 100644 index 0000000..1df8284 --- /dev/null +++ b/internal/batch/processor_test.go @@ -0,0 +1,247 @@ +package batch + +import ( + "os" + "path/filepath" + "reflect" + "testing" +) + +func TestReadBatchFile(t *testing.T) { + tests := []struct { + name string + fileContent string + want []WordEntry + wantErr bool + }{ + { + name: "empty file", + fileContent: "", + want: nil, + }, + { + name: "only whitespace", + fileContent: " \n\t\r\n ", + want: nil, + }, + { + name: "words with translations", + fileContent: `ΡΠ±ΡΠ»ΠΊΠ° = apple +ΠΊΠΎΡΠΊΠ° = cat +ΠΊΡΡΠ΅ = dog`, + want: []WordEntry{ + {Bulgarian: "ΡΠ±ΡΠ»ΠΊΠ°", Translation: "apple"}, + {Bulgarian: "ΠΊΠΎΡΠΊΠ°", Translation: "cat"}, + {Bulgarian: "ΠΊΡΡΠ΅", Translation: "dog"}, + }, + }, + { + name: "mixed format", + fileContent: `ΡΠ±ΡΠ»ΠΊΠ° +ΠΊΠΎΡΠΊΠ° = cat +ΠΊΡΡΠ΅ +Ρ
Π»ΡΠ± = bread`, + want: []WordEntry{ + {Bulgarian: "ΡΠ±ΡΠ»ΠΊΠ°", Translation: ""}, + {Bulgarian: "ΠΊΠΎΡΠΊΠ°", Translation: "cat"}, + {Bulgarian: "ΠΊΡΡΠ΅", Translation: ""}, + {Bulgarian: "Ρ
Π»ΡΠ±", Translation: "bread"}, + }, + }, + { + name: "empty lines and whitespace", + fileContent: ` +ΡΠ±ΡΠ»ΠΊΠ° + +ΠΊΠΎΡΠΊΠ° = cat + + ΠΊΡΡΠ΅ + +`, + want: []WordEntry{ + {Bulgarian: "ΡΠ±ΡΠ»ΠΊΠ°", Translation: ""}, + {Bulgarian: "ΠΊΠΎΡΠΊΠ°", Translation: "cat"}, + {Bulgarian: "ΠΊΡΡΠ΅", Translation: ""}, + }, + }, + { + name: "windows line endings", + fileContent: "ΡΠ±ΡΠ»ΠΊΠ°\r\nΠΊΠΎΡΠΊΠ° = cat\r\nΠΊΡΡΠ΅", + want: []WordEntry{ + {Bulgarian: "ΡΠ±ΡΠ»ΠΊΠ°", Translation: ""}, + {Bulgarian: "ΠΊΠΎΡΠΊΠ°", Translation: "cat"}, + {Bulgarian: "ΠΊΡΡΠ΅", Translation: ""}, + }, + }, + { + name: "multiple equals signs", + fileContent: `test = word = with = equals`, + want: []WordEntry{ + {Bulgarian: "test", Translation: "word = with = equals"}, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Create temp file + tmpDir := t.TempDir() + tmpFile := filepath.Join(tmpDir, "test.txt") + err := os.WriteFile(tmpFile, []byte(tt.fileContent), 0644) + if err != nil { + t.Fatalf("Failed to create test file: %v", err) + } + + got, err := ReadBatchFile(tmpFile) + if (err != nil) != tt.wantErr { + t.Errorf("ReadBatchFile() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("ReadBatchFile() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestReadBatchFile_FileNotFound(t *testing.T) { + _, err := ReadBatchFile("/nonexistent/file.txt") + if err == nil { + t.Error("Expected error for non-existent file") + } +} + +func TestSplitLines(t *testing.T) { + tests := []struct { + name string + input string + want []string + }{ + { + name: "unix line endings", + input: "line1\nline2\nline3", + want: []string{"line1", "line2", "line3"}, + }, + { + name: "windows line endings", + input: "line1\r\nline2\r\nline3", + want: []string{"line1", "line2", "line3"}, + }, + { + name: "mixed line endings", + input: "line1\nline2\r\nline3", + want: []string{"line1", "line2", "line3"}, + }, + { + name: "empty string", + input: "", + want: nil, + }, + { + name: "single line no ending", + input: "single line", + want: []string{"single line"}, + }, + { + name: "trailing newline", + input: "line1\nline2\n", + want: []string{"line1", "line2"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := splitLines(tt.input) + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("splitLines() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestTrimSpace(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + { + name: "no whitespace", + input: "hello", + want: "hello", + }, + { + name: "leading spaces", + input: " hello", + want: "hello", + }, + { + name: "trailing spaces", + input: "hello ", + want: "hello", + }, + { + name: "both sides", + input: " hello ", + want: "hello", + }, + { + name: "tabs and spaces", + input: "\t hello \t", + want: "hello", + }, + { + name: "newlines", + input: "\nhello\n", + want: "hello", + }, + { + name: "all whitespace types", + input: " \t\n\rhello \t\n\r", + want: "hello", + }, + { + name: "empty string", + input: "", + want: "", + }, + { + name: "only whitespace", + input: " \t\n\r ", + want: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := trimSpace(tt.input) + if got != tt.want { + t.Errorf("trimSpace() = %q, want %q", got, tt.want) + } + }) + } +} + +func TestIsSpace(t *testing.T) { + tests := []struct { + r rune + want bool + }{ + {' ', true}, + {'\t', true}, + {'\n', true}, + {'\r', true}, + {'a', false}, + {'1', false}, + {'!', false}, + {0, false}, + } + + for _, tt := range tests { + t.Run(string(tt.r), func(t *testing.T) { + if got := isSpace(tt.r); got != tt.want { + t.Errorf("isSpace(%q) = %v, want %v", tt.r, got, tt.want) + } + }) + } +} |
