summaryrefslogtreecommitdiff
path: root/internal/batch
diff options
context:
space:
mode:
Diffstat (limited to 'internal/batch')
-rw-r--r--internal/batch/processor.go49
-rw-r--r--internal/batch/processor_test.go134
2 files changed, 5 insertions, 178 deletions
diff --git a/internal/batch/processor.go b/internal/batch/processor.go
index 314d67f..2b002a9 100644
--- a/internal/batch/processor.go
+++ b/internal/batch/processor.go
@@ -31,10 +31,11 @@ func ReadBatchFile(filename string) ([]WordEntry, error) {
}
var entries []WordEntry
- lines := string(content)
-
- for _, line := range splitLines(lines) {
- if line = trimSpace(line); line != "" {
+ // Normalize \r\n to \n before splitting so both Windows and Unix line
+ // endings are handled uniformly by strings.Split.
+ normalized := strings.ReplaceAll(string(content), "\r\n", "\n")
+ for _, line := range strings.Split(normalized, "\n") {
+ if line = strings.TrimSpace(line); line != "" {
entry := parseBatchLine(line)
if entry != nil {
entries = append(entries, *entry)
@@ -103,43 +104,3 @@ func parseBatchLine(line string) *WordEntry {
}
}
-// splitLines splits a string by newlines, handling both \n and \r\n line endings.
-// Uses strings.Builder to avoid per-character heap allocations from += concatenation.
-func splitLines(s string) []string {
- var lines []string
- var current strings.Builder
- for _, r := range s {
- if r == '\n' {
- lines = append(lines, current.String())
- current.Reset()
- } else if r != '\r' {
- current.WriteRune(r)
- }
- }
- if current.Len() > 0 {
- lines = append(lines, current.String())
- }
- return lines
-}
-
-// trimSpace trims whitespace from string
-func trimSpace(s string) string {
- start := 0
- end := len(s)
-
- // Trim from start
- for start < end && isSpace(rune(s[start])) {
- start++
- }
-
- // Trim from end
- for end > start && isSpace(rune(s[end-1])) {
- end--
- }
-
- return s[start:end]
-}
-
-func isSpace(r rune) bool {
- return r == ' ' || r == '\t' || r == '\n' || r == '\r'
-}
diff --git a/internal/batch/processor_test.go b/internal/batch/processor_test.go
index fc4f7b0..8bc8079 100644
--- a/internal/batch/processor_test.go
+++ b/internal/batch/processor_test.go
@@ -163,137 +163,3 @@ func TestReadBatchFile_FileNotFound(t *testing.T) {
}
}
-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)
- }
- })
- }
-}