返回 DeepSeek-Reasonix
diff_extra_test.go
根目录 / internal / diff / diff_extra_test.go
1 package diff
2
3 import (
4 "strings"
5 "testing"
6 )
7
8 // --- splitLines ---
9
10 func TestSplitLinesEmpty(t *testing.T) {
11 lines, eol := splitLines("")
12 if len(lines) != 0 {
13 t.Errorf("empty: got %d lines", len(lines))
14 }
15 if !eol {
16 t.Error("empty should report endsWithNewline=true")
17 }
18 }
19
20 func TestSplitLinesNoTrailingNewline(t *testing.T) {
21 lines, eol := splitLines("a\nb")
22 if len(lines) != 2 {
23 t.Errorf("got %d lines", len(lines))
24 }
25 if lines[0] != "a" || lines[1] != "b" {
26 t.Errorf("lines = %v", lines)
27 }
28 if eol {
29 t.Error("should report no trailing newline")
30 }
31 }
32
33 func TestSplitLinesTrailingNewline(t *testing.T) {
34 lines, eol := splitLines("a\nb\n")
35 if len(lines) != 2 {
36 t.Errorf("got %d lines", len(lines))
37 }
38 if !eol {
39 t.Error("should report trailing newline")
40 }
41 }
42
43 func TestSplitLinesSingleLine(t *testing.T) {
44 lines, eol := splitLines("hello")
45 if len(lines) != 1 || lines[0] != "hello" {
46 t.Errorf("lines = %v", lines)
47 }
48 if eol {
49 t.Error("single line without newline should report false")
50 }
51 }
52
53 func TestSplitLinesSingleLineWithNewline(t *testing.T) {
54 lines, eol := splitLines("hello\n")
55 if len(lines) != 1 || lines[0] != "hello" {
56 t.Errorf("lines = %v", lines)
57 }
58 if !eol {
59 t.Error("single line with newline should report true")
60 }
61 }
62
63 // --- isBinary ---
64
65 func TestIsBinaryEmpty(t *testing.T) {
66 if isBinary("") {
67 t.Error("empty string is not binary")
68 }
69 }
70
71 func TestIsBinaryText(t *testing.T) {
72 if isBinary("hello world\nline 2") {
73 t.Error("plain text is not binary")
74 }
75 }
76
77 func TestIsBinaryNUL(t *testing.T) {
78 if !isBinary("hello\x00world") {
79 t.Error("string with NUL should be binary")
80 }
81 }
82
83 func TestIsBinaryNULAtEnd(t *testing.T) {
84 if !isBinary("hello\x00") {
85 t.Error("NUL at end should be binary")
86 }
87 }
88
89 // --- Build edge cases ---
90
91 func TestBuildBothEmpty(t *testing.T) {
92 c := Build("empty.txt", "", "", Modify)
93 if c.Diff != "" || c.Added != 0 || c.Removed != 0 {
94 t.Errorf("both empty should be no-op: %+v", c)
95 }
96 }
97
98 func TestBuildEmptyOldNonEmptyNew(t *testing.T) {
99 c := Build("new.txt", "", "line1\nline2\n", Create)
100 if c.Added != 2 || c.Removed != 0 {
101 t.Errorf("added/removed = %d/%d", c.Added, c.Removed)
102 }
103 if c.Kind != Create {
104 t.Errorf("kind = %q", c.Kind)
105 }
106 }
107
108 func TestBuildNonEmptyOldEmptyNew(t *testing.T) {
109 c := Build("del.txt", "line1\nline2\n", "", Delete)
110 if c.Added != 0 || c.Removed != 2 {
111 t.Errorf("added/removed = %d/%d", c.Added, c.Removed)
112 }
113 }
114
115 func TestBuildCRLF(t *testing.T) {
116 old := "line1\r\nline2\r\n"
117 neu := "line1\r\nLINE2\r\n"
118 c := Build("crlf.txt", old, neu, Modify)
119 // CRLF should be handled (split on \n, \r stays in line content).
120 if c.Added != 1 || c.Removed != 1 {
121 t.Errorf("added/removed = %d/%d, want 1/1", c.Added, c.Removed)
122 }
123 }
124
125 func TestBuildWhitespaceOnly(t *testing.T) {
126 old := "a\tb\n"
127 neu := "a b\n"
128 c := Build("ws.txt", old, neu, Modify)
129 if c.Added != 1 || c.Removed != 1 {
130 t.Errorf("added/removed = %d/%d", c.Added, c.Removed)
131 }
132 }
133
134 func TestBuildLargeFile(t *testing.T) {
135 // Build a large file with one changed line in the middle.
136 var oldB, newB strings.Builder
137 for i := 0; i < 1000; i++ {
138 oldB.WriteString("line\n")
139 if i == 500 {
140 newB.WriteString("CHANGED\n")
141 } else {
142 newB.WriteString("line\n")
143 }
144 }
145 c := Build("large.txt", oldB.String(), newB.String(), Modify)
146 if c.Added != 1 || c.Removed != 1 {
147 t.Errorf("added/removed = %d/%d, want 1/1", c.Added, c.Removed)
148 }
149 }
150
151 // --- Kind constants ---
152
153 func TestKindConstants(t *testing.T) {
154 if Create != "create" {
155 t.Errorf("Create = %q", Create)
156 }
157 if Modify != "modify" {
158 t.Errorf("Modify = %q", Modify)
159 }
160 if Delete != "delete" {
161 t.Errorf("Delete = %q", Delete)
162 }
163 }
164
165 // --- itoa ---
166
167 func TestItoa(t *testing.T) {
168 cases := []struct {
169 n int
170 want string
171 }{
172 {0, "0"},
173 {1, "1"},
174 {42, "42"},
175 {1000, "1000"},
176 }
177 for _, c := range cases {
178 if got := itoa(c.n); got != c.want {
179 t.Errorf("itoa(%d) = %q, want %q", c.n, got, c.want)
180 }
181 }
182 }
183
183 lines GO