Skip to content

Commit a8fab66

Browse files
committed
Add tests for LineReader
1 parent 1625299 commit a8fab66

File tree

2 files changed

+179
-0
lines changed

2 files changed

+179
-0
lines changed

diff/reader_util.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ package diff
33
import (
44
"bufio"
55
"bytes"
6+
"errors"
67
"io"
78
)
89

10+
var ErrLineReaderUninitialized = errors.New("line reader not initialized")
11+
912
func newLineReader(r io.Reader) *lineReader {
1013
return &lineReader{reader: bufio.NewReader(r)}
1114
}
@@ -43,6 +46,10 @@ func (l *lineReader) readLine() ([]byte, error) {
4346
// io.EOF and bufio.ErrBufferFull errors are ignored so that the function can
4447
// be used when at the end of the file.
4548
func (l *lineReader) nextLineStartsWith(prefix string) (bool, error) {
49+
if l.cachedNextLine == nil && l.cachedNextLineErr == nil {
50+
l.cachedNextLine, l.cachedNextLineErr = readLine(l.reader)
51+
}
52+
4653
return l.lineHasPrefix(l.cachedNextLine, prefix, l.cachedNextLineErr)
4754
}
4855

@@ -51,7 +58,15 @@ func (l *lineReader) nextLineStartsWith(prefix string) (bool, error) {
5158
//
5259
// io.EOF and bufio.ErrBufferFull errors are ignored so that the function can
5360
// be used when at the end of the file.
61+
//
62+
// The lineReader MUST be initialized by calling readLine at least once before
63+
// calling nextLineStartsWith. Otherwise ErrLineReaderUninitialized will be
64+
// returned.
5465
func (l *lineReader) nextNextLineStartsWith(prefix string) (bool, error) {
66+
if l.cachedNextLine == nil && l.cachedNextLineErr == nil {
67+
l.cachedNextLine, l.cachedNextLineErr = readLine(l.reader)
68+
}
69+
5570
next, err := l.reader.Peek(len(prefix))
5671
return l.lineHasPrefix(next, prefix, err)
5772
}

diff/reader_util_test.go

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,167 @@ index 0000000..3be2928`,
6666
})
6767
}
6868
}
69+
70+
func TestLineReader_ReadLine(t *testing.T) {
71+
tests := []struct {
72+
name string
73+
input string
74+
want []string
75+
}{
76+
{
77+
name: "empty",
78+
input: "",
79+
want: []string{},
80+
},
81+
{
82+
name: "single_line",
83+
input: "@@ -0,0 +1,62 @@",
84+
want: []string{"@@ -0,0 +1,62 @@"},
85+
},
86+
{
87+
name: "single_lf_terminated_line",
88+
input: "@@ -0,0 +1,62 @@\n",
89+
want: []string{"@@ -0,0 +1,62 @@"},
90+
},
91+
{
92+
name: "single_crlf_terminated_line",
93+
input: "@@ -0,0 +1,62 @@\r\n",
94+
want: []string{"@@ -0,0 +1,62 @@"},
95+
},
96+
{
97+
name: "multi_line",
98+
input: `diff --git a/test.go b/test.go
99+
new file mode 100644
100+
index 0000000..3be2928`,
101+
want: []string{
102+
"diff --git a/test.go b/test.go",
103+
"new file mode 100644",
104+
"index 0000000..3be2928",
105+
},
106+
},
107+
}
108+
for _, test := range tests {
109+
t.Run(test.name, func(t *testing.T) {
110+
in := newLineReader(strings.NewReader(test.input))
111+
out := []string{}
112+
for {
113+
l, err := in.readLine()
114+
if err == io.EOF {
115+
break
116+
}
117+
if err != nil {
118+
t.Fatal(err)
119+
}
120+
out = append(out, string(l))
121+
}
122+
if !reflect.DeepEqual(test.want, out) {
123+
t.Errorf("read lines not equal: want %v, got %v", test.want, out)
124+
}
125+
})
126+
}
127+
}
128+
129+
func TestLineReader_NextLineStartsWith(t *testing.T) {
130+
input := `aaa rest of line
131+
bbbrest of line
132+
ccc rest of line`
133+
134+
in := newLineReader(strings.NewReader(input))
135+
136+
type assertion struct {
137+
prefix string
138+
want bool
139+
}
140+
141+
testsPerReadLine := []struct {
142+
nextLine []assertion
143+
nextNextLine []assertion
144+
wantReadLineErr error
145+
}{
146+
{
147+
nextLine: []assertion{
148+
{prefix: "a", want: true},
149+
{prefix: "aa", want: true},
150+
{prefix: "aaa", want: true},
151+
{prefix: "bbb", want: false},
152+
{prefix: "ccc", want: false},
153+
},
154+
nextNextLine: []assertion{
155+
{prefix: "aaa", want: false},
156+
{prefix: "bbb", want: true},
157+
{prefix: "ccc", want: false},
158+
},
159+
},
160+
{
161+
nextLine: []assertion{
162+
{prefix: "aaa", want: false},
163+
{prefix: "bbb", want: true},
164+
{prefix: "ccc", want: false},
165+
},
166+
nextNextLine: []assertion{
167+
{prefix: "aaa", want: false},
168+
{prefix: "bbb", want: false},
169+
{prefix: "ccc", want: true},
170+
},
171+
},
172+
{
173+
nextLine: []assertion{
174+
{prefix: "aaa", want: false},
175+
{prefix: "bbb", want: false},
176+
{prefix: "ccc", want: true},
177+
{prefix: "ddd", want: false},
178+
},
179+
nextNextLine: []assertion{
180+
{prefix: "aaa", want: false},
181+
{prefix: "bbb", want: false},
182+
{prefix: "ccc", want: false},
183+
{prefix: "ddd", want: false},
184+
},
185+
},
186+
{
187+
nextLine: []assertion{
188+
{prefix: "aaa", want: false},
189+
{prefix: "bbb", want: false},
190+
{prefix: "ccc", want: false},
191+
{prefix: "ddd", want: false},
192+
},
193+
nextNextLine: []assertion{
194+
{prefix: "aaa", want: false},
195+
{prefix: "bbb", want: false},
196+
{prefix: "ccc", want: false},
197+
{prefix: "ddd", want: false},
198+
},
199+
wantReadLineErr: io.EOF,
200+
},
201+
}
202+
203+
for _, tc := range testsPerReadLine {
204+
for _, assert := range tc.nextLine {
205+
got, err := in.nextLineStartsWith(assert.prefix)
206+
if err != nil {
207+
t.Fatalf("nextLineStartsWith returned unexpected error: %s", err)
208+
}
209+
210+
if got != assert.want {
211+
t.Fatalf("unexpected result for prefix %q. got=%t, want=%t", assert.prefix, got, assert.want)
212+
}
213+
}
214+
215+
for _, assert := range tc.nextNextLine {
216+
got, err := in.nextNextLineStartsWith(assert.prefix)
217+
if err != nil {
218+
t.Fatalf("nextLineStartsWith returned unexpected error: %s", err)
219+
}
220+
221+
if got != assert.want {
222+
t.Fatalf("unexpected result for prefix %q. got=%t, want=%t", assert.prefix, got, assert.want)
223+
}
224+
}
225+
226+
_, err := in.readLine()
227+
if err != tc.wantReadLineErr {
228+
t.Fatalf("readLine returned unexpected error. got=%s, want=%s", err, tc.wantReadLineErr)
229+
}
230+
231+
}
232+
}

0 commit comments

Comments
 (0)