Skip to content

Commit c12bc15

Browse files
committed
support long_line test case
1 parent 0df814d commit c12bc15

File tree

3 files changed

+54
-44
lines changed

3 files changed

+54
-44
lines changed

diff/diff_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func TestParseHunkNoChunksize(t *testing.T) {
2020
t.Errorf("%s: got ParseHunks err %v, want %v", filename, err, nil)
2121
}
2222
if len(diff) != 1 {
23-
t.Errorf("%s: Got %d hunks, want only one", filename, len(diff))
23+
t.Fatalf("%s: Got %d hunks, want only one", filename, len(diff))
2424
}
2525

2626
correct := &Hunk{
@@ -142,6 +142,9 @@ func TestParseMultiFileDiffAndPrintMultiFileDiff(t *testing.T) {
142142
{
143143
filename: "sample_multi_file_single.diff",
144144
},
145+
{
146+
filename: "long_line_multi.diff",
147+
},
145148
{filename: "empty.diff"},
146149
{filename: "empty_multi.diff"},
147150
}

diff/parse.go

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,24 @@ import (
1010
"time"
1111
)
1212

13-
// ParseMultiFileDiff parses a multi-file unified diff.
13+
// ParseMultiFileDiff parses a multi-file unified diff. It returns an error if parsing failed as a whole, but does its
14+
// best to parse as many files in the case of per-file errors. In the case of non-fatal per-file errors, the error
15+
// return value is null and the Errs field in the returned MultiFileDiff is set.
1416
func ParseMultiFileDiff(diff []byte) ([]*FileDiff, error) {
1517
return NewMultiFileDiffReader(bytes.NewReader(diff)).ReadAllFiles()
1618
}
1719

1820
// NewMultiFileDiffReader returns a new MultiFileDiffReader that reads
1921
// a multi-file unified diff from r.
2022
func NewMultiFileDiffReader(r io.Reader) *MultiFileDiffReader {
21-
return &MultiFileDiffReader{scanner: bufio.NewScanner(r)}
23+
return &MultiFileDiffReader{reader: bufio.NewReader(r)}
2224
}
2325

2426
// MultiFileDiffReader reads a multi-file unified diff.
2527
type MultiFileDiffReader struct {
26-
line int
27-
offset int64
28-
scanner *bufio.Scanner
28+
line int
29+
offset int64
30+
reader *bufio.Reader
2931

3032
// TODO(sqs): line and offset tracking in multi-file diffs is broken; add tests and fix
3133

@@ -44,7 +46,7 @@ func (r *MultiFileDiffReader) ReadFile() (*FileDiff, error) {
4446
fr := &FileDiffReader{
4547
line: r.line,
4648
offset: r.offset,
47-
scanner: r.scanner,
49+
reader: r.reader,
4850
fileHeaderLine: r.nextFileFirstLine,
4951
}
5052
r.nextFileFirstLine = nil
@@ -66,11 +68,11 @@ func (r *MultiFileDiffReader) ReadFile() (*FileDiff, error) {
6668
// caused by the lack of any hunks, or a malformatted hunk, so we
6769
// need to perform the check here.
6870
hr := fr.HunksReader()
69-
ok := r.scanner.Scan()
70-
if !ok {
71-
return d, r.scanner.Err()
71+
line, err := r.reader.ReadBytes('\n')
72+
if err != nil && !(err == io.EOF && len(line) > 0) {
73+
return d, err
7274
}
73-
line := r.scanner.Bytes()
75+
line = bytes.TrimSuffix(line, []byte{'\n'})
7476
if bytes.HasPrefix(line, hunkPrefix) {
7577
hr.nextHunkHeaderLine = line
7678
d.Hunks, err = hr.ReadAllHunks()
@@ -122,14 +124,14 @@ func ParseFileDiff(diff []byte) (*FileDiff, error) {
122124
// NewFileDiffReader returns a new FileDiffReader that reads a file
123125
// unified diff.
124126
func NewFileDiffReader(r io.Reader) *FileDiffReader {
125-
return &FileDiffReader{scanner: bufio.NewScanner(r)}
127+
return &FileDiffReader{reader: bufio.NewReader(r)}
126128
}
127129

128130
// FileDiffReader reads a unified file diff.
129131
type FileDiffReader struct {
130-
line int
131-
offset int64
132-
scanner *bufio.Scanner
132+
line int
133+
offset int64
134+
reader *bufio.Reader
133135

134136
// fileHeaderLine is the first file header line, set by:
135137
//
@@ -184,9 +186,9 @@ func (r *FileDiffReader) ReadAllHeaders() (*FileDiff, error) {
184186
// correct position information).
185187
func (r *FileDiffReader) HunksReader() *HunksReader {
186188
return &HunksReader{
187-
line: r.line,
188-
offset: r.offset,
189-
scanner: r.scanner,
189+
line: r.line,
190+
offset: r.offset,
191+
reader: r.reader,
190192
}
191193
}
192194

@@ -213,14 +215,16 @@ func (r *FileDiffReader) readOneFileHeader(prefix []byte) (filename string, time
213215
var line []byte
214216

215217
if r.fileHeaderLine == nil {
216-
ok := r.scanner.Scan()
217-
if !ok {
218-
return "", nil, &ParseError{r.line, r.offset, ErrNoFileHeader}
219-
}
220-
if err := r.scanner.Err(); err != nil {
218+
var err error
219+
line, err = r.reader.ReadBytes('\n')
220+
if err == io.EOF {
221+
if len(line) == 0 {
222+
return "", nil, &ParseError{r.line, r.offset, ErrNoFileHeader}
223+
}
224+
} else if err != nil {
221225
return "", nil, err
222226
}
223-
line = r.scanner.Bytes()
227+
line = bytes.TrimSuffix(line, []byte{'\n'})
224228
} else {
225229
line = r.fileHeaderLine
226230
r.fileHeaderLine = nil
@@ -258,14 +262,16 @@ func (r *FileDiffReader) ReadExtendedHeaders() ([]string, error) {
258262
for {
259263
var line []byte
260264
if r.fileHeaderLine == nil {
261-
ok := r.scanner.Scan()
262-
if !ok {
263-
return xheaders, &ParseError{r.line, r.offset, ErrExtendedHeadersEOF}
264-
}
265-
if err := r.scanner.Err(); err != nil {
265+
var err error
266+
line, err = r.reader.ReadBytes('\n')
267+
if err == io.EOF {
268+
if len(line) == 0 {
269+
return xheaders, &ParseError{r.line, r.offset, ErrExtendedHeadersEOF}
270+
}
271+
} else if err != nil {
266272
return xheaders, err
267273
}
268-
line = r.scanner.Bytes()
274+
line = bytes.TrimSuffix(line, []byte{'\n'})
269275
} else {
270276
line = r.fileHeaderLine
271277
r.fileHeaderLine = nil
@@ -311,15 +317,15 @@ func ParseHunks(diff []byte) ([]*Hunk, error) {
311317
// NewHunksReader returns a new HunksReader that reads unified diff hunks
312318
// from r.
313319
func NewHunksReader(r io.Reader) *HunksReader {
314-
return &HunksReader{scanner: bufio.NewScanner(r)}
320+
return &HunksReader{reader: bufio.NewReader(r)}
315321
}
316322

317323
// A HunksReader reads hunks from a unified diff.
318324
type HunksReader struct {
319-
line int
320-
offset int64
321-
hunk *Hunk
322-
scanner *bufio.Scanner
325+
line int
326+
offset int64
327+
hunk *Hunk
328+
reader *bufio.Reader
323329

324330
nextHunkHeaderLine []byte
325331
}
@@ -330,18 +336,22 @@ func (r *HunksReader) ReadHunk() (*Hunk, error) {
330336
r.hunk = nil
331337
lastLineFromOrig := true
332338
var line []byte
339+
var err error
333340
for {
334341
if r.nextHunkHeaderLine != nil {
335342
// Use stored hunk header line that was scanned in at the
336343
// completion of the previous hunk's ReadHunk.
337344
line = r.nextHunkHeaderLine
338345
r.nextHunkHeaderLine = nil
339346
} else {
340-
ok := r.scanner.Scan()
341-
if !ok {
342-
break
347+
line, err = r.reader.ReadBytes('\n')
348+
if err != nil {
349+
if err == io.EOF && r.hunk != nil {
350+
return r.hunk, nil
351+
}
352+
return nil, err
343353
}
344-
line = r.scanner.Bytes()
354+
line = bytes.TrimSuffix(line, []byte{'\n'})
345355
}
346356

347357
// Record position.
@@ -422,9 +432,6 @@ func (r *HunksReader) ReadHunk() (*Hunk, error) {
422432
r.hunk.Body = append(r.hunk.Body, '\n')
423433
}
424434
}
425-
if err := r.scanner.Err(); err != nil {
426-
return nil, err
427-
}
428435

429436
// Final hunk is complete. But if we never saw a hunk in this call to ReadHunk, then it means we hit EOF.
430437
if r.hunk != nil {

diff/testdata/long_line.diff renamed to diff/testdata/long_line_multi.diff

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ new file mode 100644
33
index 0000000..6b8710a
44
--- /dev/null
55
+++ b/blah.txt
6-
@@ -0,0 +1 @@
6+
@@ -0,0 +1,1 @@
77
+blah
88
diff --git a/foo/bar.svg b/foo/bar.svg
99
new file mode 100644
@@ -20,5 +20,5 @@ new file mode 100644
2020
index 0000000..6b8710a
2121
--- /dev/null
2222
+++ b/more.txt
23-
@@ -0,0 +1 @@
23+
@@ -0,0 +1,1 @@
2424
+more

0 commit comments

Comments
 (0)