Skip to content

Commit 206a57e

Browse files
committed
Add tests for LineReaderAt implementation
This adds minimal new coverage, since the apply tests already exercise this, but it's complicated enough that dedicated tests will be helpful.
1 parent 18058d1 commit 206a57e

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

gitdiff/io.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ func (r *lineReaderAt) ReadLinesAt(lines [][]byte, offset int64) (n int, err err
3535
// - it's generally not clear when something is bytes vs lines
3636
// - offset is a good example of this
3737

38+
if offset < 0 {
39+
return 0, errors.New("ReadLinesAt: negative offset")
40+
}
3841
if len(lines) == 0 {
3942
return 0, nil
4043
}

gitdiff/io_test.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package gitdiff
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"io"
7+
"testing"
8+
)
9+
10+
func TestLineReaderAt(t *testing.T) {
11+
tests := map[string]struct {
12+
InputLines int
13+
Offset int64
14+
Count int
15+
Err bool
16+
EOF bool
17+
EOFCount int
18+
}{
19+
"readLines": {
20+
InputLines: 32,
21+
Offset: 0,
22+
Count: 4,
23+
},
24+
"readLinesOffset": {
25+
InputLines: 32,
26+
Offset: 8,
27+
Count: 4,
28+
},
29+
"readLinesLargeOffset": {
30+
InputLines: 8192,
31+
Offset: 4096,
32+
Count: 64,
33+
},
34+
"readSingleLine": {
35+
InputLines: 4,
36+
Offset: 2,
37+
Count: 1,
38+
},
39+
"readZeroLines": {
40+
InputLines: 4,
41+
Offset: 2,
42+
Count: 0,
43+
},
44+
"readThroughEOF": {
45+
InputLines: 16,
46+
Offset: 12,
47+
Count: 8,
48+
EOF: true,
49+
EOFCount: 4,
50+
},
51+
"offsetAfterEOF": {
52+
InputLines: 8,
53+
Offset: 10,
54+
Count: 2,
55+
EOF: true,
56+
EOFCount: 0,
57+
},
58+
"offsetNegative": {
59+
InputLines: 8,
60+
Offset: -1,
61+
Count: 2,
62+
Err: true,
63+
},
64+
}
65+
66+
const lineTemplate = "generated test line %d\n"
67+
68+
for name, test := range tests {
69+
t.Run(name, func(t *testing.T) {
70+
var input bytes.Buffer
71+
for i := 0; i < test.InputLines; i++ {
72+
fmt.Fprintf(&input, lineTemplate, i)
73+
}
74+
75+
output := make([][]byte, test.Count)
76+
for i := 0; i < test.Count; i++ {
77+
output[i] = []byte(fmt.Sprintf(lineTemplate, test.Offset+int64(i)))
78+
}
79+
80+
r := &lineReaderAt{r: bytes.NewReader(input.Bytes())}
81+
lines := make([][]byte, test.Count)
82+
83+
n, err := r.ReadLinesAt(lines, test.Offset)
84+
if test.Err {
85+
if err == nil {
86+
t.Fatal("expected error reading lines, but got nil")
87+
}
88+
return
89+
}
90+
if err != nil && (!test.EOF || err != io.EOF) {
91+
t.Fatalf("unexpected error reading lines: %v", err)
92+
}
93+
94+
count := test.Count
95+
if test.EOF {
96+
count = test.EOFCount
97+
}
98+
99+
if n != count {
100+
t.Fatalf("incorrect number of lines read: expected %d, actual %d", count, n)
101+
}
102+
for i := 0; i < n; i++ {
103+
if !bytes.Equal(output[i], lines[i]) {
104+
t.Errorf("incorrect content in line %d:\nexpected: %q\nactual: %q", i, output[i], lines[i])
105+
}
106+
}
107+
})
108+
}
109+
}

0 commit comments

Comments
 (0)