Skip to content

Commit a34334d

Browse files
committed
Add error tests for BinaryFragment#Apply
These cover some of the possible errors with delta fragments. Many of the same tests could be implemented slightly easier by testing the helper functions, but the infrastructure is already set up to test the full function. This is made easier by the bin.go CLI, which can parse and encode binary patch data. Once parsed, fragments were manipulated with truncate and dd, encoded, and placed in the patch files.
1 parent 194589f commit a34334d

7 files changed

+196
-13
lines changed

gitdiff/apply_test.go

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io"
77
"io/ioutil"
88
"path/filepath"
9+
"strings"
910
"testing"
1011
)
1112

@@ -85,12 +86,7 @@ func TestTextFragmentApplyStrict(t *testing.T) {
8586
var dst bytes.Buffer
8687
err = frag.ApplyStrict(&dst, NewLineReader(bytes.NewReader(src), 0))
8788
if test.Err != nil {
88-
if err == nil {
89-
t.Fatalf("expected error applying fragment, but got nil")
90-
}
91-
if !errors.Is(err, test.Err) {
92-
t.Fatalf("incorrect apply error: expected: %T (%v), actual: %T (%v)", test.Err, test.Err, err, err)
93-
}
89+
checkApplyError(t, test.Err, err)
9490
return
9591
}
9692
if err != nil {
@@ -107,12 +103,41 @@ func TestTextFragmentApplyStrict(t *testing.T) {
107103
func TestBinaryFragmentApply(t *testing.T) {
108104
tests := map[string]struct {
109105
Files applyFiles
110-
Err error
106+
Err interface{}
111107
}{
112108
"literalCreate": {Files: getApplyFiles("bin_fragment_literal_create")},
113109
"literalModify": {Files: getApplyFiles("bin_fragment_literal_modify")},
114110
"deltaModify": {Files: getApplyFiles("bin_fragment_delta_modify")},
115111
"deltaModifyLarge": {Files: getApplyFiles("bin_fragment_delta_modify_large")},
112+
113+
"errorIncompleteAdd": {
114+
Files: applyFiles{
115+
Src: "bin_fragment_delta_error.src",
116+
Patch: "bin_fragment_delta_error_incomplete_add.patch",
117+
},
118+
Err: "incomplete add",
119+
},
120+
"errorIncompleteCopy": {
121+
Files: applyFiles{
122+
Src: "bin_fragment_delta_error.src",
123+
Patch: "bin_fragment_delta_error_incomplete_copy.patch",
124+
},
125+
Err: "incomplete copy",
126+
},
127+
"errorSrcSize": {
128+
Files: applyFiles{
129+
Src: "bin_fragment_delta_error.src",
130+
Patch: "bin_fragment_delta_error_src_size.patch",
131+
},
132+
Err: &Conflict{},
133+
},
134+
"errorDstSize": {
135+
Files: applyFiles{
136+
Src: "bin_fragment_delta_error.src",
137+
Patch: "bin_fragment_delta_error_dst_size.patch",
138+
},
139+
Err: "insufficient or extra data",
140+
},
116141
}
117142

118143
for name, test := range tests {
@@ -135,12 +160,7 @@ func TestBinaryFragmentApply(t *testing.T) {
135160
var dst bytes.Buffer
136161
err = frag.Apply(&dst, bytes.NewReader(src))
137162
if test.Err != nil {
138-
if err == nil {
139-
t.Fatalf("expected error applying fragment, but got nil")
140-
}
141-
if !errors.Is(err, test.Err) {
142-
t.Fatalf("incorrect apply error: expected: %T (%v), actual: %T (%v)", test.Err, test.Err, err, err)
143-
}
163+
checkApplyError(t, test.Err, err)
144164
return
145165
}
146166
if err != nil {
@@ -154,6 +174,25 @@ func TestBinaryFragmentApply(t *testing.T) {
154174
}
155175
}
156176

177+
func checkApplyError(t *testing.T, terr interface{}, err error) {
178+
if err == nil {
179+
t.Fatalf("expected error applying fragment, but got nil")
180+
}
181+
182+
switch terr := terr.(type) {
183+
case string:
184+
if !strings.Contains(err.Error(), terr) {
185+
t.Fatalf("incorrect apply error: %q does not contain %q", err.Error(), terr)
186+
}
187+
case error:
188+
if !errors.Is(err, terr) {
189+
t.Fatalf("incorrect apply error: expected: %T (%v), actual: %T (%v)", terr, terr, err, err)
190+
}
191+
default:
192+
t.Fatalf("unsupported error type: %T", terr)
193+
}
194+
}
195+
157196
type applyFiles struct {
158197
Src string
159198
Patch string

gitdiff/testdata/apply/bin.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
//+build ignore
2+
3+
// bin.go is a helper CLI to manipulate binary diff data for testing purposes.
4+
// It can decode patches generated by git using the standard parsing functions
5+
// or it can encode binary data back into the format expected by Git. It
6+
// operates on stdin writes results (possibly binary) to stdout.
7+
8+
package main
9+
10+
import (
11+
"bytes"
12+
"compress/zlib"
13+
"encoding/binary"
14+
"flag"
15+
"io/ioutil"
16+
"log"
17+
"os"
18+
"strings"
19+
20+
"github.com/bluekeyes/go-gitdiff/gitdiff"
21+
)
22+
23+
var (
24+
b85Powers = []uint32{52200625, 614125, 7225, 85, 1}
25+
b85Alpha = []byte(
26+
"0123456789" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "!#$%&()*+-;<=>?@^_`{|}~",
27+
)
28+
)
29+
30+
var mode string
31+
32+
func base85Encode(data []byte) []byte {
33+
chunks, remaining := len(data)/4, len(data)%4
34+
if remaining > 0 {
35+
data = append(data, make([]byte, 4-remaining)...)
36+
chunks++
37+
}
38+
39+
var n int
40+
out := make([]byte, 5*chunks)
41+
42+
for i := 0; i < len(data); i += 4 {
43+
v := binary.BigEndian.Uint32(data[i : i+4])
44+
for j := 0; j < 5; j++ {
45+
p := v / b85Powers[j]
46+
out[n+j] = b85Alpha[p]
47+
v -= b85Powers[j] * p
48+
}
49+
n += 5
50+
}
51+
52+
return out
53+
}
54+
55+
func compress(data []byte) ([]byte, error) {
56+
var b bytes.Buffer
57+
w := zlib.NewWriter(&b)
58+
59+
if _, err := w.Write(data); err != nil {
60+
return nil, err
61+
}
62+
if err := w.Close(); err != nil {
63+
return nil, err
64+
}
65+
66+
return b.Bytes(), nil
67+
}
68+
69+
func wrap(data []byte) string {
70+
var s strings.Builder
71+
for i := 0; i < len(data); i += 52 {
72+
c := 52
73+
if c > len(data)-i {
74+
c = len(data) - i
75+
}
76+
b := (c / 5) * 4
77+
78+
if b <= 26 {
79+
s.WriteByte(byte('A' + b - 1))
80+
} else {
81+
s.WriteByte(byte('a' + b - 27))
82+
}
83+
s.Write(data[i : i+c])
84+
s.WriteByte('\n')
85+
}
86+
return s.String()
87+
}
88+
89+
func init() {
90+
flag.StringVar(&mode, "mode", "parse", "operation mode, one of 'parse' or 'encode'")
91+
}
92+
93+
func main() {
94+
flag.Parse()
95+
96+
switch mode {
97+
case "parse":
98+
files, _, err := gitdiff.Parse(os.Stdin)
99+
if err != nil {
100+
log.Fatalf("failed to parse file: %v", err)
101+
}
102+
if len(files) != 1 {
103+
log.Fatalf("patch contains more than one file: %d", len(files))
104+
}
105+
if files[0].BinaryFragment == nil {
106+
log.Fatalf("patch file does not contain a binary fragment")
107+
}
108+
os.Stdout.Write(files[0].BinaryFragment.Data)
109+
110+
case "encode":
111+
data, err := ioutil.ReadAll(os.Stdin)
112+
if err != nil {
113+
log.Fatalf("failed to read input: %v", err)
114+
}
115+
data, err = compress(data)
116+
if err != nil {
117+
log.Fatalf("failed to compress data: %v", err)
118+
}
119+
os.Stdout.WriteString(wrap(base85Encode(data)))
120+
121+
default:
122+
log.Fatalf("unknown mode: %s", mode)
123+
}
124+
}
130 Bytes
Binary file not shown.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
2+
GIT binary patch
3+
delta 18
4+
fc${itY+{<=z`_4AtEhVK$zKyatN;N30RR6$D+j^=
5+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
2+
GIT binary patch
3+
delta 11
4+
Xc${itY+{_?z`_4As|XMP0RR6K8UwQc
5+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
2+
GIT binary patch
3+
delta 17
4+
fc${itY+{_?z`_4AtEhVK$zKya00961|Nl5!2ZsOv
5+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
diff --git a/gitdiff/testdata/apply/bin_fragment_delta_error.src b/gitdiff/testdata/apply/bin_fragment_delta_error.src
2+
GIT binary patch
3+
delta 18
4+
fc${itYGRz=z`_4AtEhVK$zKyatN;N30RR6$EeFB?
5+

0 commit comments

Comments
 (0)