]> git.proxmox.com Git - libgit2.git/blame - tests/diff/binary.c
binary diff: test that the diff and patch otputs are the same
[libgit2.git] / tests / diff / binary.c
CommitLineData
e349ed50
ET
1#include "clar_libgit2.h"
2
76633215
CMN
3#include "git2/sys/diff.h"
4
e349ed50
ET
5#include "buffer.h"
6#include "filebuf.h"
7
8static git_repository *repo;
9
10void test_diff_binary__initialize(void)
11{
12}
13
14void test_diff_binary__cleanup(void)
15{
16 cl_git_sandbox_cleanup();
17}
18
19void test_patch(
20 const char *one,
21 const char *two,
22 const git_diff_options *opts,
23 const char *expected)
24{
25 git_oid id_one, id_two;
26 git_index *index = NULL;
27 git_commit *commit_one, *commit_two = NULL;
28 git_tree *tree_one, *tree_two;
29 git_diff *diff;
30 git_patch *patch;
31 git_buf actual = GIT_BUF_INIT;
32
33 cl_git_pass(git_oid_fromstr(&id_one, one));
34 cl_git_pass(git_commit_lookup(&commit_one, repo, &id_one));
35 cl_git_pass(git_commit_tree(&tree_one, commit_one));
36
37 if (two) {
38 cl_git_pass(git_oid_fromstr(&id_two, two));
39 cl_git_pass(git_commit_lookup(&commit_two, repo, &id_two));
40 cl_git_pass(git_commit_tree(&tree_two, commit_two));
41 } else {
42 cl_git_pass(git_repository_index(&index, repo));
43 cl_git_pass(git_index_write_tree(&id_two, index));
44 cl_git_pass(git_tree_lookup(&tree_two, repo, &id_two));
45 }
46
47 cl_git_pass(git_diff_tree_to_tree(&diff, repo, tree_one, tree_two, opts));
48
49 cl_git_pass(git_patch_from_diff(&patch, diff, 0));
50 cl_git_pass(git_patch_to_buf(&actual, patch));
51
52 cl_assert_equal_s(expected, actual.ptr);
53
76633215
CMN
54 git_buf_clear(&actual);
55 cl_git_pass(git_diff_print(diff, GIT_DIFF_FORMAT_PATCH, git_diff_print_callback__to_buf, &actual));
56
57 cl_assert_equal_s(expected, actual.ptr);
58
e349ed50
ET
59 git_buf_free(&actual);
60 git_patch_free(patch);
61 git_diff_free(diff);
62 git_tree_free(tree_one);
63 git_tree_free(tree_two);
64 git_commit_free(commit_one);
65 git_commit_free(commit_two);
66 git_index_free(index);
67}
68
69void test_diff_binary__add_normal(void)
70{
71 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
72 const char *expected =
73 "diff --git a/binary.bin b/binary.bin\n" \
74 "new file mode 100644\n" \
75 "index 0000000..bd474b2\n" \
76 "Binary files /dev/null and b/binary.bin differ\n";
77
78 repo = cl_git_sandbox_init("diff_format_email");
79 test_patch(
80 "873806f6f27e631eb0b23e4b56bea2bfac14a373",
81 "897d3af16ca9e420cd071b1c4541bd2b91d04c8c",
82 &opts,
83 expected);
84}
85
86void test_diff_binary__add(void)
87{
88 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
89 const char *expected =
90 "diff --git a/binary.bin b/binary.bin\n" \
91 "new file mode 100644\n" \
92 "index 0000000000000000000000000000000000000000..bd474b2519cc15eab801ff851cc7d50f0dee49a1\n" \
93 "GIT binary patch\n" \
94 "literal 3\n" \
95 "Kc${Nk-~s>u4FC%O\n"
96 "\n" \
97 "literal 0\n" \
98 "Hc$@<O00001\n";
99
100 opts.flags = GIT_DIFF_SHOW_BINARY;
101 opts.id_abbrev = GIT_OID_HEXSZ;
102
103 repo = cl_git_sandbox_init("diff_format_email");
104 test_patch(
105 "873806f6f27e631eb0b23e4b56bea2bfac14a373",
106 "897d3af16ca9e420cd071b1c4541bd2b91d04c8c",
107 &opts,
108 expected);
109}
110
111void test_diff_binary__modify_normal(void)
112{
113 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
114 const char *expected =
115 "diff --git a/binary.bin b/binary.bin\n" \
116 "index bd474b2..9ac35ff 100644\n" \
117 "Binary files a/binary.bin and b/binary.bin differ\n";
118
119 repo = cl_git_sandbox_init("diff_format_email");
120 test_patch(
121 "897d3af16ca9e420cd071b1c4541bd2b91d04c8c",
122 "8d7523f6fcb2404257889abe0d96f093d9f524f9",
123 &opts,
124 expected);
125}
126
127void test_diff_binary__modify(void)
128{
129 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
130 const char *expected =
131 "diff --git a/binary.bin b/binary.bin\n" \
132 "index bd474b2519cc15eab801ff851cc7d50f0dee49a1..9ac35ff15cd8864aeafd889e4826a3150f0b06c4 100644\n" \
133 "GIT binary patch\n" \
134 "literal 5\n" \
135 "Mc${NkU}WL~000&M4gdfE\n" \
136 "\n" \
137 "literal 3\n" \
138 "Kc${Nk-~s>u4FC%O\n";
139
140 opts.flags = GIT_DIFF_SHOW_BINARY;
141
142 repo = cl_git_sandbox_init("diff_format_email");
143 test_patch(
144 "897d3af16ca9e420cd071b1c4541bd2b91d04c8c",
145 "8d7523f6fcb2404257889abe0d96f093d9f524f9",
146 &opts,
147 expected);
148}
149
150void test_diff_binary__delete_normal(void)
151{
152 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
153 const char *expected =
154 "diff --git a/binary.bin b/binary.bin\n" \
155 "deleted file mode 100644\n" \
156 "index bd474b2..0000000\n" \
157 "Binary files a/binary.bin and /dev/null differ\n";
158
159 repo = cl_git_sandbox_init("diff_format_email");
160 test_patch(
161 "897d3af16ca9e420cd071b1c4541bd2b91d04c8c",
162 "873806f6f27e631eb0b23e4b56bea2bfac14a373",
163 &opts,
164 expected);
165}
166
167void test_diff_binary__delete(void)
168{
169 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
170 const char *expected =
171 "diff --git a/binary.bin b/binary.bin\n" \
172 "deleted file mode 100644\n" \
173 "index bd474b2519cc15eab801ff851cc7d50f0dee49a1..0000000000000000000000000000000000000000\n" \
174 "GIT binary patch\n" \
175 "literal 0\n" \
176 "Hc$@<O00001\n" \
177 "\n" \
178 "literal 3\n" \
179 "Kc${Nk-~s>u4FC%O\n";
180
181 opts.flags = GIT_DIFF_SHOW_BINARY;
182 opts.id_abbrev = GIT_OID_HEXSZ;
183
184 repo = cl_git_sandbox_init("diff_format_email");
185 test_patch(
186 "897d3af16ca9e420cd071b1c4541bd2b91d04c8c",
187 "873806f6f27e631eb0b23e4b56bea2bfac14a373",
188 &opts,
189 expected);
190}
191
192void test_diff_binary__delta(void)
193{
194 git_index *index;
195 git_buf contents = GIT_BUF_INIT;
196 size_t i;
197 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
198 const char *expected =
199 "diff --git a/songof7cities.txt b/songof7cities.txt\n" \
200 "index 4210ffd5c390b21dd5483375e75288dea9ede512..cc84ec183351c9944ed90a619ca08911924055b5 100644\n" \
201 "GIT binary patch\n" \
202 "delta 198\n" \
203 "zc$}LmI8{(0BqLQJI6p64AwNwaIJGP_Pa)Ye#M3o+qJ$<Jl;sX*mF<MGCYv&*L7AHu\n" \
204 "zGA1*^gt?gYVN82wTbPO_W)+x<&1+cP;HrPHR>PQ;Y(X&QMK*C5^Br3bjG4d=XI^5@\n" \
205 "JfH567LIG)KJdFSV\n" \
206 "\n" \
207 "delta 198\n" \
208 "zc$}LmI8{(0BqLQJI6p64AwNwaIJGP_Pr*5}Br~;mqJ$<Jl;sX*mF<MGCYv&*L7AHu\n" \
209 "zGA1*^gt?gYVN82wTbPO_W)+x<&1+cP;HrPHR>PQ;Y(X&QMK*C5^Br3bjG4d=XI^5@\n" \
210 "JfH567LIF3FM2!Fd\n";
211
212 opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
213 opts.id_abbrev = GIT_OID_HEXSZ;
214
215 repo = cl_git_sandbox_init("renames");
216 cl_git_pass(git_repository_index(&index, repo));
217
218 cl_git_pass(git_futils_readbuffer(&contents, "renames/songof7cities.txt"));
219
220 for (i = 0; i < contents.size - 6; i++) {
221 if (strncmp(&contents.ptr[i], "Cities", 6) == 0)
222 memcpy(&contents.ptr[i], "cITIES", 6);
223 }
224
225 cl_git_rewritefile("renames/songof7cities.txt", contents.ptr);
226 cl_git_pass(git_index_add_bypath(index, "songof7cities.txt"));
227 cl_git_pass(git_index_write(index));
228
229 test_patch(
230 "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13",
231 NULL,
232 &opts,
233 expected);
234
235 git_index_free(index);
236 git_buf_free(&contents);
237}
238
239void test_diff_binary__delta_append(void)
240{
241 git_index *index;
242 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
243 const char *expected =
244 "diff --git a/untimely.txt b/untimely.txt\n" \
245 "index 9a69d960ae94b060f56c2a8702545e2bb1abb935..1111d4f11f4b35bf6759e0fb714fe09731ef0840 100644\n" \
246 "GIT binary patch\n" \
247 "delta 32\n" \
248 "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \
249 "\n" \
250 "delta 7\n" \
251 "Oc%18D`@*{63ljhg(E~C7\n";
252
253 opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
254 opts.id_abbrev = GIT_OID_HEXSZ;
255
256 repo = cl_git_sandbox_init("renames");
257 cl_git_pass(git_repository_index(&index, repo));
258
259 cl_git_append2file("renames/untimely.txt", "Oh that crazy Kipling!\r\n");
260 cl_git_pass(git_index_add_bypath(index, "untimely.txt"));
261 cl_git_pass(git_index_write(index));
262
263 test_patch(
264 "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13",
265 NULL,
266 &opts,
267 expected);
268
269 git_index_free(index);
270}
ac7012a8
ET
271
272void test_diff_binary__index_to_workdir(void)
273{
274 git_index *index;
275 git_diff *diff;
276 git_patch *patch;
277 git_buf actual = GIT_BUF_INIT;
278 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
279 const char *expected =
280 "diff --git a/untimely.txt b/untimely.txt\n" \
281 "index 9a69d960ae94b060f56c2a8702545e2bb1abb935..1111d4f11f4b35bf6759e0fb714fe09731ef0840 100644\n" \
282 "GIT binary patch\n" \
283 "delta 32\n" \
284 "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \
285 "\n" \
286 "delta 7\n" \
287 "Oc%18D`@*{63ljhg(E~C7\n";
288
289 opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
290 opts.id_abbrev = GIT_OID_HEXSZ;
291
292 repo = cl_git_sandbox_init("renames");
293 cl_git_pass(git_repository_index(&index, repo));
294
295 cl_git_append2file("renames/untimely.txt", "Oh that crazy Kipling!\r\n");
296
297 cl_git_pass(git_diff_index_to_workdir(&diff, repo, index, &opts));
298
299 cl_git_pass(git_patch_from_diff(&patch, diff, 0));
300 cl_git_pass(git_patch_to_buf(&actual, patch));
301
302 cl_assert_equal_s(expected, actual.ptr);
303
304 cl_git_pass(git_index_add_bypath(index, "untimely.txt"));
305 cl_git_pass(git_index_write(index));
306
307 test_patch(
308 "19dd32dfb1520a64e5bbaae8dce6ef423dfa2f13",
309 NULL,
310 &opts,
311 expected);
312
313 git_buf_free(&actual);
314 git_patch_free(patch);
315 git_diff_free(diff);
316 git_index_free(index);
317}
318
319static int print_cb(
320 const git_diff_delta *delta,
321 const git_diff_hunk *hunk,
322 const git_diff_line *line,
323 void *payload)
324{
325 git_buf *buf = (git_buf *)payload;
326
0f4d9c03
POL
327 GIT_UNUSED(delta);
328
ac7012a8
ET
329 if (hunk)
330 git_buf_put(buf, hunk->header, hunk->header_len);
331
332 if (line)
333 git_buf_put(buf, line->content, line->content_len);
334
335 return git_buf_oom(buf) ? -1 : 0;
336}
337
338void test_diff_binary__print_patch_from_diff(void)
339{
340 git_index *index;
341 git_diff *diff;
342 git_buf actual = GIT_BUF_INIT;
343 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
344 const char *expected =
345 "diff --git a/untimely.txt b/untimely.txt\n" \
346 "index 9a69d960ae94b060f56c2a8702545e2bb1abb935..1111d4f11f4b35bf6759e0fb714fe09731ef0840 100644\n" \
347 "GIT binary patch\n" \
348 "delta 32\n" \
349 "nc%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW\n" \
350 "\n" \
351 "delta 7\n" \
352 "Oc%18D`@*{63ljhg(E~C7\n";
353
354 opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
355 opts.id_abbrev = GIT_OID_HEXSZ;
356
357 repo = cl_git_sandbox_init("renames");
358 cl_git_pass(git_repository_index(&index, repo));
359
360 cl_git_append2file("renames/untimely.txt", "Oh that crazy Kipling!\r\n");
361
362 cl_git_pass(git_diff_index_to_workdir(&diff, repo, index, &opts));
363
364 cl_git_pass(git_diff_print(diff, GIT_DIFF_FORMAT_PATCH, print_cb, &actual));
365
366 cl_assert_equal_s(expected, actual.ptr);
367
368 git_buf_free(&actual);
369 git_diff_free(diff);
370 git_index_free(index);
371}
391281ae
ET
372
373struct diff_data {
374 char *old_path;
375 git_oid old_id;
376 git_buf old_binary_base85;
377 size_t old_binary_inflatedlen;
378 git_diff_binary_t old_binary_type;
379
380 char *new_path;
381 git_oid new_id;
382 git_buf new_binary_base85;
383 size_t new_binary_inflatedlen;
384 git_diff_binary_t new_binary_type;
385};
386
387static int file_cb(
388 const git_diff_delta *delta,
389 float progress,
390 void *payload)
391{
392 struct diff_data *diff_data = payload;
393
0f4d9c03
POL
394 GIT_UNUSED(progress);
395
391281ae
ET
396 if (delta->old_file.path)
397 diff_data->old_path = git__strdup(delta->old_file.path);
398
399 if (delta->new_file.path)
400 diff_data->new_path = git__strdup(delta->new_file.path);
401
402 git_oid_cpy(&diff_data->old_id, &delta->old_file.id);
403 git_oid_cpy(&diff_data->new_id, &delta->new_file.id);
404
405 return 0;
406}
407
408static int binary_cb(
409 const git_diff_delta *delta,
410 const git_diff_binary *binary,
411 void *payload)
412{
413 struct diff_data *diff_data = payload;
414
0f4d9c03
POL
415 GIT_UNUSED(delta);
416
391281ae
ET
417 git_buf_encode_base85(&diff_data->old_binary_base85,
418 binary->old_file.data, binary->old_file.datalen);
419 diff_data->old_binary_inflatedlen = binary->old_file.inflatedlen;
420 diff_data->old_binary_type = binary->old_file.type;
421
422 git_buf_encode_base85(&diff_data->new_binary_base85,
423 binary->new_file.data, binary->new_file.datalen);
424 diff_data->new_binary_inflatedlen = binary->new_file.inflatedlen;
425 diff_data->new_binary_type = binary->new_file.type;
426
427 return 0;
428}
429
430static int hunk_cb(
431 const git_diff_delta *delta,
432 const git_diff_hunk *hunk,
433 void *payload)
434{
0f4d9c03
POL
435 GIT_UNUSED(delta);
436 GIT_UNUSED(hunk);
437 GIT_UNUSED(payload);
438
391281ae
ET
439 cl_fail("did not expect hunk callback");
440 return 0;
441}
442
443static int line_cb(
444 const git_diff_delta *delta,
445 const git_diff_hunk *hunk,
446 const git_diff_line *line,
447 void *payload)
448{
0f4d9c03
POL
449 GIT_UNUSED(delta);
450 GIT_UNUSED(hunk);
451 GIT_UNUSED(line);
452 GIT_UNUSED(payload);
453
391281ae
ET
454 cl_fail("did not expect line callback");
455 return 0;
456}
457
458void test_diff_binary__blob_to_blob(void)
459{
460 git_index *index;
461 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
462 git_blob *old_blob, *new_blob;
463 git_oid old_id, new_id;
464 struct diff_data diff_data = {0};
391281ae
ET
465
466 opts.flags = GIT_DIFF_SHOW_BINARY | GIT_DIFF_FORCE_BINARY;
467 opts.id_abbrev = GIT_OID_HEXSZ;
468
469 repo = cl_git_sandbox_init("renames");
470 cl_git_pass(git_repository_index(&index, repo));
471
472 cl_git_append2file("renames/untimely.txt", "Oh that crazy Kipling!\r\n");
473 cl_git_pass(git_index_add_bypath(index, "untimely.txt"));
474 cl_git_pass(git_index_write(index));
475
476 git_oid_fromstr(&old_id, "9a69d960ae94b060f56c2a8702545e2bb1abb935");
477 git_oid_fromstr(&new_id, "1111d4f11f4b35bf6759e0fb714fe09731ef0840");
478
479 cl_git_pass(git_blob_lookup(&old_blob, repo, &old_id));
480 cl_git_pass(git_blob_lookup(&new_blob, repo, &new_id));
481
482 cl_git_pass(git_diff_blobs(old_blob,
483 "untimely.txt", new_blob, "untimely.txt", &opts,
484 file_cb, binary_cb, hunk_cb, line_cb, &diff_data));
485
486 cl_assert_equal_s("untimely.txt", diff_data.old_path);
487 cl_assert_equal_oid(&old_id, &diff_data.old_id);
488 cl_assert_equal_i(GIT_DIFF_BINARY_DELTA, diff_data.old_binary_type);
489 cl_assert_equal_i(7, diff_data.old_binary_inflatedlen);
490 cl_assert_equal_s("c%18D`@*{63ljhg(E~C7",
491 diff_data.old_binary_base85.ptr);
492
493 cl_assert_equal_s("untimely.txt", diff_data.new_path);
494 cl_assert_equal_oid(&new_id, &diff_data.new_id);
495 cl_assert_equal_i(GIT_DIFF_BINARY_DELTA, diff_data.new_binary_type);
496 cl_assert_equal_i(32, diff_data.new_binary_inflatedlen);
497 cl_assert_equal_s("c%1vf+QYWt3zLL@hC)e3Vu?a>QDRl4f_G*?PG(-ZA}<#J$+QbW",
498 diff_data.new_binary_base85.ptr);
499
500 git_blob_free(old_blob);
501 git_blob_free(new_blob);
502
503 git__free(diff_data.old_path);
504 git__free(diff_data.new_path);
505}