summaryrefslogtreecommitdiff
path: root/internal/batch/processor_test.go
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2025-07-20 23:10:50 +0300
committerPaul Buetow <paul@buetow.org>2025-07-20 23:10:50 +0300
commit9c12e879c5d6833ce50f5b6d646ccce03a78db31 (patch)
tree206906b551d595b35d00586b6cc5bf9e1f3fe7f8 /internal/batch/processor_test.go
parente580fb57a29ec3c3f3e180b20cfa6ec28687689b (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.go247
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)
+ }
+ })
+ }
+}