this repo has no description
1package gitdiff
2
3import (
4 "bytes"
5 "errors"
6 "io"
7 "io/ioutil"
8 "path/filepath"
9 "strings"
10 "testing"
11)
12
13func TestTextFragmentApplyStrict(t *testing.T) {
14 tests := map[string]struct {
15 Files applyFiles
16 Err error
17 }{
18 "createFile": {Files: getApplyFiles("text_fragment_new")},
19 "deleteFile": {Files: getApplyFiles("text_fragment_delete_all")},
20
21 "addStart": {Files: getApplyFiles("text_fragment_add_start")},
22 "addMiddle": {Files: getApplyFiles("text_fragment_add_middle")},
23 "addEnd": {Files: getApplyFiles("text_fragment_add_end")},
24 "addEndNoEOL": {Files: getApplyFiles("text_fragment_add_end_noeol")},
25
26 "changeStart": {Files: getApplyFiles("text_fragment_change_start")},
27 "changeMiddle": {Files: getApplyFiles("text_fragment_change_middle")},
28 "changeEnd": {Files: getApplyFiles("text_fragment_change_end")},
29 "changeExact": {Files: getApplyFiles("text_fragment_change_exact")},
30 "changeSingleNoEOL": {Files: getApplyFiles("text_fragment_change_single_noeol")},
31
32 "errorShortSrcBefore": {
33 Files: applyFiles{
34 Src: "text_fragment_error.src",
35 Patch: "text_fragment_error_short_src_before.patch",
36 },
37 Err: io.ErrUnexpectedEOF,
38 },
39 "errorShortSrc": {
40 Files: applyFiles{
41 Src: "text_fragment_error.src",
42 Patch: "text_fragment_error_short_src.patch",
43 },
44 Err: io.ErrUnexpectedEOF,
45 },
46 "errorContextConflict": {
47 Files: applyFiles{
48 Src: "text_fragment_error.src",
49 Patch: "text_fragment_error_context_conflict.patch",
50 },
51 Err: &Conflict{},
52 },
53 "errorDeleteConflict": {
54 Files: applyFiles{
55 Src: "text_fragment_error.src",
56 Patch: "text_fragment_error_delete_conflict.patch",
57 },
58 Err: &Conflict{},
59 },
60 "errorNewFile": {
61 Files: applyFiles{
62 Src: "text_fragment_error.src",
63 Patch: "text_fragment_error_new_file.patch",
64 },
65 Err: &Conflict{},
66 },
67 }
68
69 for name, test := range tests {
70 t.Run(name, func(t *testing.T) {
71 src, patch, out := test.Files.Load(t)
72
73 files, _, err := Parse(bytes.NewReader(patch))
74 if err != nil {
75 t.Fatalf("failed to parse patch file: %v", err)
76 }
77 if len(files) != 1 {
78 t.Fatalf("patch should contain exactly one file, but it has %d", len(files))
79 }
80 if len(files[0].TextFragments) != 1 {
81 t.Fatalf("patch should contain exactly one fragment, but it has %d", len(files[0].TextFragments))
82 }
83
84 applier := NewApplier(bytes.NewReader(src))
85
86 var dst bytes.Buffer
87 err = applier.ApplyTextFragment(&dst, files[0].TextFragments[0])
88 if test.Err != nil {
89 checkApplyError(t, test.Err, err)
90 return
91 }
92 if err != nil {
93 t.Fatalf("unexpected error applying fragment: %v", err)
94 }
95
96 if !bytes.Equal(out, dst.Bytes()) {
97 t.Errorf("incorrect result after apply\nexpected:\n%s\nactual:\n%s", out, dst.Bytes())
98 }
99 })
100 }
101}
102
103func TestBinaryFragmentApply(t *testing.T) {
104 tests := map[string]struct {
105 Files applyFiles
106 Err interface{}
107 }{
108 "literalCreate": {Files: getApplyFiles("bin_fragment_literal_create")},
109 "literalModify": {Files: getApplyFiles("bin_fragment_literal_modify")},
110 "deltaModify": {Files: getApplyFiles("bin_fragment_delta_modify")},
111 "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 },
141 }
142
143 for name, test := range tests {
144 t.Run(name, func(t *testing.T) {
145 src, patch, out := test.Files.Load(t)
146
147 files, _, err := Parse(bytes.NewReader(patch))
148 if err != nil {
149 t.Fatalf("failed to parse patch file: %v", err)
150 }
151 if len(files) != 1 {
152 t.Fatalf("patch should contain exactly one file, but it has %d", len(files))
153 }
154
155 applier := NewApplier(bytes.NewReader(src))
156
157 var dst bytes.Buffer
158 err = applier.ApplyBinaryFragment(&dst, files[0].BinaryFragment)
159 if test.Err != nil {
160 checkApplyError(t, test.Err, err)
161 return
162 }
163 if err != nil {
164 t.Fatalf("unexpected error applying fragment: %v", err)
165 }
166
167 if !bytes.Equal(out, dst.Bytes()) {
168 t.Errorf("incorrect result after apply\nexpected:\n%x\nactual:\n%x", out, dst.Bytes())
169 }
170 })
171 }
172}
173
174func checkApplyError(t *testing.T, terr interface{}, err error) {
175 if err == nil {
176 t.Fatalf("expected error applying fragment, but got nil")
177 }
178
179 switch terr := terr.(type) {
180 case string:
181 if !strings.Contains(err.Error(), terr) {
182 t.Fatalf("incorrect apply error: %q does not contain %q", err.Error(), terr)
183 }
184 case error:
185 if !errors.Is(err, terr) {
186 t.Fatalf("incorrect apply error: expected: %T (%v), actual: %T (%v)", terr, terr, err, err)
187 }
188 default:
189 t.Fatalf("unsupported error type: %T", terr)
190 }
191}
192
193type applyFiles struct {
194 Src string
195 Patch string
196 Out string
197}
198
199func getApplyFiles(name string) applyFiles {
200 return applyFiles{
201 Src: name + ".src",
202 Patch: name + ".patch",
203 Out: name + ".out",
204 }
205}
206
207func (f applyFiles) Load(t *testing.T) (src []byte, patch []byte, out []byte) {
208 load := func(name, kind string) []byte {
209 d, err := ioutil.ReadFile(filepath.Join("testdata", "apply", name))
210 if err != nil {
211 t.Fatalf("failed to read %s file: %v", kind, err)
212 }
213 return d
214 }
215
216 if f.Src != "" {
217 src = load(f.Src, "source")
218 }
219 if f.Patch != "" {
220 patch = load(f.Patch, "patch")
221 }
222 if f.Out != "" {
223 out = load(f.Out, "output")
224 }
225 return
226}