]> git.proxmox.com Git - libgit2.git/blob - tests/diff/blob.c
50edf6bc061a8c5c71cf02c9d01897f5c4586d7d
[libgit2.git] / tests / diff / blob.c
1 #include "clar_libgit2.h"
2 #include "diff_helpers.h"
3
4 #define BLOB_DIFF \
5 "diff --git a/file b/file\n" \
6 "index 45141a7..4d713dc 100644\n" \
7 "--- a/file\n" \
8 "+++ b/file\n" \
9 "@@ -1 +1,6 @@\n" \
10 " Hello from the root\n" \
11 "+\n" \
12 "+Some additional lines\n" \
13 "+\n" \
14 "+Down here below\n" \
15 "+\n"
16
17 static git_repository *g_repo = NULL;
18 static diff_expects expected;
19 static git_diff_options opts;
20 static git_blob *d, *alien;
21
22 static void quick_diff_blob_to_str(
23 const git_blob *blob, const char *blob_path,
24 const char *str, size_t len, const char *str_path)
25 {
26 memset(&expected, 0, sizeof(expected));
27
28 if (str && !len)
29 len = strlen(str);
30
31 cl_git_pass(git_diff_blob_to_buffer(
32 blob, blob_path, str, len, str_path,
33 &opts, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
34 }
35
36 void test_diff_blob__initialize(void)
37 {
38 git_oid oid;
39
40 g_repo = cl_git_sandbox_init("attr");
41
42 cl_git_pass(git_diff_options_init(&opts, GIT_DIFF_OPTIONS_VERSION));
43 opts.context_lines = 1;
44
45 memset(&expected, 0, sizeof(expected));
46
47 /* tests/resources/attr/root_test4.txt */
48 cl_git_pass(git_oid_fromstrn(&oid, "a0f7217a", 8));
49 cl_git_pass(git_blob_lookup_prefix(&d, g_repo, &oid, 8));
50
51 /* alien.png */
52 cl_git_pass(git_oid_fromstrn(&oid, "edf3dcee", 8));
53 cl_git_pass(git_blob_lookup_prefix(&alien, g_repo, &oid, 8));
54 }
55
56 void test_diff_blob__cleanup(void)
57 {
58 git_blob_free(d);
59 d = NULL;
60
61 git_blob_free(alien);
62 alien = NULL;
63
64 cl_git_sandbox_cleanup();
65 }
66
67 static void assert_one_modified(
68 int hunks, int lines, int ctxt, int adds, int dels, diff_expects *exp)
69 {
70 cl_assert_equal_i(1, exp->files);
71 cl_assert_equal_i(1, exp->file_status[GIT_DELTA_MODIFIED]);
72 cl_assert_equal_i(0, exp->files_binary);
73
74 cl_assert_equal_i(hunks, exp->hunks);
75 cl_assert_equal_i(lines, exp->lines);
76 cl_assert_equal_i(ctxt, exp->line_ctxt);
77 cl_assert_equal_i(adds, exp->line_adds);
78 cl_assert_equal_i(dels, exp->line_dels);
79 }
80
81 void test_diff_blob__patch_with_freed_blobs(void)
82 {
83 git_oid a_oid, b_oid;
84 git_blob *a, *b;
85 git_patch *p;
86 git_buf buf = GIT_BUF_INIT;
87
88 /* tests/resources/attr/root_test1 */
89 cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
90 cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));
91 /* tests/resources/attr/root_test2 */
92 cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
93 cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4));
94
95 cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, NULL));
96
97 git_blob_free(a);
98 git_blob_free(b);
99
100 cl_git_pass(git_patch_to_buf(&buf, p));
101 cl_assert_equal_s(buf.ptr, BLOB_DIFF);
102
103 git_patch_free(p);
104 git_buf_dispose(&buf);
105 }
106
107 void test_diff_blob__can_compare_text_blobs(void)
108 {
109 git_blob *a, *b, *c;
110 git_oid a_oid, b_oid, c_oid;
111
112 /* tests/resources/attr/root_test1 */
113 cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
114 cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 4));
115
116 /* tests/resources/attr/root_test2 */
117 cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
118 cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 4));
119
120 /* tests/resources/attr/root_test3 */
121 cl_git_pass(git_oid_fromstrn(&c_oid, "c96bbb2c2557a832", 16));
122 cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 16));
123
124 /* Doing the equivalent of a `git diff -U1` on these files */
125
126 /* diff on tests/resources/attr/root_test1 */
127 memset(&expected, 0, sizeof(expected));
128 cl_git_pass(git_diff_blobs(
129 a, NULL, b, NULL, &opts,
130 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
131 assert_one_modified(1, 6, 1, 5, 0, &expected);
132
133 /* same diff but use direct buffers */
134 memset(&expected, 0, sizeof(expected));
135 cl_git_pass(git_diff_buffers(
136 git_blob_rawcontent(a), (size_t)git_blob_rawsize(a), NULL,
137 git_blob_rawcontent(b), (size_t)git_blob_rawsize(b), NULL, &opts,
138 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
139 assert_one_modified(1, 6, 1, 5, 0, &expected);
140
141 /* diff on tests/resources/attr/root_test2 */
142 memset(&expected, 0, sizeof(expected));
143 cl_git_pass(git_diff_blobs(
144 b, NULL, c, NULL, &opts,
145 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
146 assert_one_modified(1, 15, 3, 9, 3, &expected);
147
148 /* diff on tests/resources/attr/root_test3 */
149 memset(&expected, 0, sizeof(expected));
150 cl_git_pass(git_diff_blobs(
151 a, NULL, c, NULL, &opts,
152 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
153 assert_one_modified(1, 13, 0, 12, 1, &expected);
154
155 memset(&expected, 0, sizeof(expected));
156 cl_git_pass(git_diff_blobs(
157 c, NULL, d, NULL, &opts,
158 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
159 assert_one_modified(2, 14, 4, 6, 4, &expected);
160
161 git_blob_free(a);
162 git_blob_free(b);
163 git_blob_free(c);
164 }
165
166 static void assert_patch_matches_blobs(
167 git_patch *p, git_blob *a, git_blob *b,
168 int hunks, int l0, int l1, int ctxt, int adds, int dels)
169 {
170 const git_diff_delta *delta;
171 size_t tc, ta, td;
172
173 cl_assert(p != NULL);
174
175 delta = git_patch_get_delta(p);
176 cl_assert(delta != NULL);
177
178 cl_assert_equal_i(GIT_DELTA_MODIFIED, delta->status);
179 cl_assert_equal_oid(git_blob_id(a), &delta->old_file.id);
180 cl_assert_equal_sz(git_blob_rawsize(a), delta->old_file.size);
181 cl_assert_equal_oid(git_blob_id(b), &delta->new_file.id);
182 cl_assert_equal_sz(git_blob_rawsize(b), delta->new_file.size);
183
184 cl_assert_equal_i(hunks, (int)git_patch_num_hunks(p));
185
186 if (hunks > 0)
187 cl_assert_equal_i(l0, git_patch_num_lines_in_hunk(p, 0));
188 if (hunks > 1)
189 cl_assert_equal_i(l1, git_patch_num_lines_in_hunk(p, 1));
190
191 cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
192 cl_assert_equal_i(ctxt, (int)tc);
193 cl_assert_equal_i(adds, (int)ta);
194 cl_assert_equal_i(dels, (int)td);
195 }
196
197 void test_diff_blob__can_compare_text_blobs_with_patch(void)
198 {
199 git_blob *a, *b, *c;
200 git_oid a_oid, b_oid, c_oid;
201 git_patch *p;
202
203 /* tests/resources/attr/root_test1 */
204 cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
205 cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8));
206
207 /* tests/resources/attr/root_test2 */
208 cl_git_pass(git_oid_fromstrn(&b_oid, "4d713dc4", 8));
209 cl_git_pass(git_blob_lookup_prefix(&b, g_repo, &b_oid, 8));
210
211 /* tests/resources/attr/root_test3 */
212 cl_git_pass(git_oid_fromstrn(&c_oid, "c96bbb2c2557a832", 16));
213 cl_git_pass(git_blob_lookup_prefix(&c, g_repo, &c_oid, 16));
214
215 /* Doing the equivalent of a `git diff -U1` on these files */
216
217 /* diff on tests/resources/attr/root_test1 */
218 cl_git_pass(git_patch_from_blobs(&p, a, NULL, b, NULL, &opts));
219 assert_patch_matches_blobs(p, a, b, 1, 6, 0, 1, 5, 0);
220 git_patch_free(p);
221
222 /* diff on tests/resources/attr/root_test2 */
223 cl_git_pass(git_patch_from_blobs(&p, b, NULL, c, NULL, &opts));
224 assert_patch_matches_blobs(p, b, c, 1, 15, 0, 3, 9, 3);
225 git_patch_free(p);
226
227 /* diff on tests/resources/attr/root_test3 */
228 cl_git_pass(git_patch_from_blobs(&p, a, NULL, c, NULL, &opts));
229 assert_patch_matches_blobs(p, a, c, 1, 13, 0, 0, 12, 1);
230 git_patch_free(p);
231
232 /* one more */
233 cl_git_pass(git_patch_from_blobs(&p, c, NULL, d, NULL, &opts));
234 assert_patch_matches_blobs(p, c, d, 2, 5, 9, 4, 6, 4);
235 git_patch_free(p);
236
237 git_blob_free(a);
238 git_blob_free(b);
239 git_blob_free(c);
240 }
241
242 void test_diff_blob__can_compare_against_null_blobs(void)
243 {
244 git_blob *e = NULL;
245
246 cl_git_pass(git_diff_blobs(
247 d, NULL, e, NULL, &opts,
248 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
249
250 cl_assert_equal_i(1, expected.files);
251 cl_assert_equal_i(1, expected.file_status[GIT_DELTA_DELETED]);
252 cl_assert_equal_i(0, expected.files_binary);
253
254 cl_assert_equal_i(1, expected.hunks);
255 cl_assert_equal_i(14, expected.hunk_old_lines);
256 cl_assert_equal_i(14, expected.lines);
257 cl_assert_equal_i(14, expected.line_dels);
258
259 opts.flags |= GIT_DIFF_REVERSE;
260 memset(&expected, 0, sizeof(expected));
261
262 cl_git_pass(git_diff_blobs(
263 d, NULL, e, NULL, &opts,
264 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
265
266 cl_assert_equal_i(1, expected.files);
267 cl_assert_equal_i(1, expected.file_status[GIT_DELTA_ADDED]);
268 cl_assert_equal_i(0, expected.files_binary);
269
270 cl_assert_equal_i(1, expected.hunks);
271 cl_assert_equal_i(14, expected.hunk_new_lines);
272 cl_assert_equal_i(14, expected.lines);
273 cl_assert_equal_i(14, expected.line_adds);
274
275 opts.flags ^= GIT_DIFF_REVERSE;
276 memset(&expected, 0, sizeof(expected));
277
278 cl_git_pass(git_diff_blobs(
279 alien, NULL, NULL, NULL, &opts,
280 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
281
282 cl_assert_equal_i(1, expected.files);
283 cl_assert_equal_i(1, expected.files_binary);
284 cl_assert_equal_i(1, expected.file_status[GIT_DELTA_DELETED]);
285 cl_assert_equal_i(0, expected.hunks);
286 cl_assert_equal_i(0, expected.lines);
287
288 memset(&expected, 0, sizeof(expected));
289
290 cl_git_pass(git_diff_blobs(
291 NULL, NULL, alien, NULL, &opts,
292 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
293
294 cl_assert_equal_i(1, expected.files);
295 cl_assert_equal_i(1, expected.files_binary);
296 cl_assert_equal_i(1, expected.file_status[GIT_DELTA_ADDED]);
297 cl_assert_equal_i(0, expected.hunks);
298 cl_assert_equal_i(0, expected.lines);
299 }
300
301 void test_diff_blob__can_compare_against_null_blobs_with_patch(void)
302 {
303 git_blob *e = NULL;
304 git_patch *p;
305 const git_diff_delta *delta;
306 const git_diff_line *line;
307 int l, max_l;
308
309 cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts));
310
311 cl_assert(p != NULL);
312
313 delta = git_patch_get_delta(p);
314 cl_assert(delta != NULL);
315 cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
316 cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id);
317 cl_assert_equal_sz(git_blob_rawsize(d), delta->old_file.size);
318 cl_assert(git_oid_is_zero(&delta->new_file.id));
319 cl_assert_equal_sz(0, delta->new_file.size);
320
321 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
322 cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0));
323
324 max_l = git_patch_num_lines_in_hunk(p, 0);
325 for (l = 0; l < max_l; ++l) {
326 cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l));
327 cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)line->origin);
328 }
329
330 git_patch_free(p);
331
332 opts.flags |= GIT_DIFF_REVERSE;
333
334 cl_git_pass(git_patch_from_blobs(&p, d, NULL, e, NULL, &opts));
335
336 cl_assert(p != NULL);
337
338 delta = git_patch_get_delta(p);
339 cl_assert(delta != NULL);
340 cl_assert_equal_i(GIT_DELTA_ADDED, delta->status);
341 cl_assert(git_oid_is_zero(&delta->old_file.id));
342 cl_assert_equal_sz(0, delta->old_file.size);
343 cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id);
344 cl_assert_equal_sz(git_blob_rawsize(d), delta->new_file.size);
345
346 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
347 cl_assert_equal_i(14, git_patch_num_lines_in_hunk(p, 0));
348
349 max_l = git_patch_num_lines_in_hunk(p, 0);
350 for (l = 0; l < max_l; ++l) {
351 cl_git_pass(git_patch_get_line_in_hunk(&line, p, 0, l));
352 cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)line->origin);
353 }
354
355 git_patch_free(p);
356
357 opts.flags ^= GIT_DIFF_REVERSE;
358
359 cl_git_pass(git_patch_from_blobs(&p, alien, NULL, NULL, NULL, &opts));
360
361 cl_assert(p != NULL);
362
363 delta = git_patch_get_delta(p);
364 cl_assert(delta != NULL);
365 cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
366 cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);
367
368 cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
369
370 git_patch_free(p);
371
372 cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, alien, NULL, &opts));
373
374 cl_assert(p != NULL);
375
376 delta = git_patch_get_delta(p);
377 cl_assert(delta != NULL);
378 cl_assert_equal_i(GIT_DELTA_ADDED, delta->status);
379 cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0);
380
381 cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
382
383 git_patch_free(p);
384 }
385
386 static void assert_identical_blobs_comparison(diff_expects *expected)
387 {
388 cl_assert_equal_i(1, expected->files);
389 cl_assert_equal_i(1, expected->file_status[GIT_DELTA_UNMODIFIED]);
390 cl_assert_equal_i(0, expected->hunks);
391 cl_assert_equal_i(0, expected->lines);
392 }
393
394 void test_diff_blob__can_compare_identical_blobs(void)
395 {
396 opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
397
398 cl_git_pass(git_diff_blobs(
399 d, NULL, d, NULL, &opts,
400 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
401
402 assert_identical_blobs_comparison(&expected);
403 cl_assert_equal_i(0, expected.files_binary);
404
405 memset(&expected, 0, sizeof(expected));
406 cl_git_pass(git_diff_blobs(
407 NULL, NULL, NULL, NULL, &opts,
408 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
409
410 assert_identical_blobs_comparison(&expected);
411 cl_assert_equal_i(0, expected.files_binary);
412
413 memset(&expected, 0, sizeof(expected));
414 cl_git_pass(git_diff_blobs(
415 alien, NULL, alien, NULL, &opts,
416 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
417
418 assert_identical_blobs_comparison(&expected);
419 cl_assert(expected.files_binary > 0);
420 }
421
422 void test_diff_blob__can_compare_identical_blobs_with_patch(void)
423 {
424 git_patch *p;
425 const git_diff_delta *delta;
426
427 cl_git_pass(git_patch_from_blobs(&p, d, NULL, d, NULL, &opts));
428 cl_assert(p != NULL);
429
430 delta = git_patch_get_delta(p);
431 cl_assert(delta != NULL);
432 cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status);
433 cl_assert_equal_sz(delta->old_file.size, git_blob_rawsize(d));
434 cl_assert_equal_oid(git_blob_id(d), &delta->old_file.id);
435 cl_assert_equal_sz(delta->new_file.size, git_blob_rawsize(d));
436 cl_assert_equal_oid(git_blob_id(d), &delta->new_file.id);
437
438 cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
439 git_patch_free(p);
440
441 cl_git_pass(git_patch_from_blobs(&p, NULL, NULL, NULL, NULL, &opts));
442 cl_assert(p != NULL);
443
444 delta = git_patch_get_delta(p);
445 cl_assert(delta != NULL);
446 cl_assert_equal_i(GIT_DELTA_UNMODIFIED, delta->status);
447 cl_assert_equal_sz(0, delta->old_file.size);
448 cl_assert(git_oid_is_zero(&delta->old_file.id));
449 cl_assert_equal_sz(0, delta->new_file.size);
450 cl_assert(git_oid_is_zero(&delta->new_file.id));
451
452 cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
453 git_patch_free(p);
454
455 cl_git_pass(git_patch_from_blobs(&p, alien, NULL, alien, NULL, &opts));
456 cl_assert(p != NULL);
457 cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status);
458 cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
459 git_patch_free(p);
460 }
461
462 static void assert_binary_blobs_comparison(diff_expects *expected)
463 {
464 cl_assert(expected->files_binary > 0);
465
466 cl_assert_equal_i(1, expected->files);
467 cl_assert_equal_i(1, expected->file_status[GIT_DELTA_MODIFIED]);
468 cl_assert_equal_i(0, expected->hunks);
469 cl_assert_equal_i(0, expected->lines);
470 }
471
472 void test_diff_blob__can_compare_two_binary_blobs(void)
473 {
474 git_blob *heart;
475 git_oid h_oid;
476
477 /* heart.png */
478 cl_git_pass(git_oid_fromstrn(&h_oid, "de863bff", 8));
479 cl_git_pass(git_blob_lookup_prefix(&heart, g_repo, &h_oid, 8));
480
481 cl_git_pass(git_diff_blobs(
482 alien, NULL, heart, NULL, &opts,
483 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
484
485 assert_binary_blobs_comparison(&expected);
486
487 memset(&expected, 0, sizeof(expected));
488
489 cl_git_pass(git_diff_blobs(
490 heart, NULL, alien, NULL, &opts,
491 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
492
493 assert_binary_blobs_comparison(&expected);
494
495 git_blob_free(heart);
496 }
497
498 void test_diff_blob__can_compare_a_binary_blob_and_a_text_blob(void)
499 {
500 cl_git_pass(git_diff_blobs(
501 alien, NULL, d, NULL, &opts,
502 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
503
504 assert_binary_blobs_comparison(&expected);
505
506 memset(&expected, 0, sizeof(expected));
507
508 cl_git_pass(git_diff_blobs(
509 d, NULL, alien, NULL, &opts,
510 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
511
512 assert_binary_blobs_comparison(&expected);
513 }
514
515 /*
516 * $ git diff fe773770 a0f7217
517 * diff --git a/fe773770 b/a0f7217
518 * index fe77377..a0f7217 100644
519 * --- a/fe773770
520 * +++ b/a0f7217
521 * @@ -1,6 +1,6 @@
522 * Here is some stuff at the start
523 *
524 * -This should go in one hunk
525 * +This should go in one hunk (first)
526 *
527 * Some additional lines
528 *
529 * @@ -8,7 +8,7 @@ Down here below the other lines
530 *
531 * With even more at the end
532 *
533 * -Followed by a second hunk of stuff
534 * +Followed by a second hunk of stuff (second)
535 *
536 * That happens down here
537 */
538 void test_diff_blob__comparing_two_text_blobs_honors_interhunkcontext(void)
539 {
540 git_blob *old_d;
541 git_oid old_d_oid;
542
543 opts.context_lines = 3;
544
545 /* tests/resources/attr/root_test1 from commit f5b0af1 */
546 cl_git_pass(git_oid_fromstrn(&old_d_oid, "fe773770", 8));
547 cl_git_pass(git_blob_lookup_prefix(&old_d, g_repo, &old_d_oid, 8));
548
549 /* Test with default inter-hunk-context (not set) => default is 0 */
550 cl_git_pass(git_diff_blobs(
551 old_d, NULL, d, NULL, &opts,
552 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
553
554 cl_assert_equal_i(2, expected.hunks);
555
556 /* Test with inter-hunk-context explicitly set to 0 */
557 opts.interhunk_lines = 0;
558 memset(&expected, 0, sizeof(expected));
559 cl_git_pass(git_diff_blobs(
560 old_d, NULL, d, NULL, &opts,
561 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
562
563 cl_assert_equal_i(2, expected.hunks);
564
565 /* Test with inter-hunk-context explicitly set to 1 */
566 opts.interhunk_lines = 1;
567 memset(&expected, 0, sizeof(expected));
568 cl_git_pass(git_diff_blobs(
569 old_d, NULL, d, NULL, &opts,
570 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
571
572 cl_assert_equal_i(1, expected.hunks);
573
574 git_blob_free(old_d);
575 }
576
577 void test_diff_blob__checks_options_version_too_low(void)
578 {
579 const git_error *err;
580
581 opts.version = 0;
582 cl_git_fail(git_diff_blobs(
583 d, NULL, alien, NULL, &opts,
584 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
585 err = git_error_last();
586 cl_assert_equal_i(GIT_ERROR_INVALID, err->klass);
587 }
588
589 void test_diff_blob__checks_options_version_too_high(void)
590 {
591 const git_error *err;
592
593 opts.version = 1024;
594 cl_git_fail(git_diff_blobs(
595 d, NULL, alien, NULL, &opts,
596 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
597 err = git_error_last();
598 cl_assert_equal_i(GIT_ERROR_INVALID, err->klass);
599 }
600
601 void test_diff_blob__can_correctly_detect_a_binary_blob_as_binary(void)
602 {
603 /* alien.png */
604 cl_assert_equal_i(true, git_blob_is_binary(alien));
605 }
606
607 void test_diff_blob__can_correctly_detect_a_textual_blob_as_non_binary(void)
608 {
609 /* tests/resources/attr/root_test4.txt */
610 cl_assert_equal_i(false, git_blob_is_binary(d));
611 }
612
613 /*
614 * git_diff_blob_to_buffer tests
615 */
616
617 static void assert_changed_single_one_line_file(
618 diff_expects *expected, git_delta_t mod)
619 {
620 cl_assert_equal_i(1, expected->files);
621 cl_assert_equal_i(1, expected->file_status[mod]);
622 cl_assert_equal_i(1, expected->hunks);
623 cl_assert_equal_i(1, expected->lines);
624
625 if (mod == GIT_DELTA_ADDED)
626 cl_assert_equal_i(1, expected->line_adds);
627 else if (mod == GIT_DELTA_DELETED)
628 cl_assert_equal_i(1, expected->line_dels);
629 }
630
631 void test_diff_blob__can_compare_blob_to_buffer(void)
632 {
633 git_blob *a;
634 git_oid a_oid;
635 const char *a_content = "Hello from the root\n";
636 const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n";
637
638 /* tests/resources/attr/root_test1 */
639 cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
640 cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8));
641
642 /* diff from blob a to content of b */
643 quick_diff_blob_to_str(a, NULL, b_content, 0, NULL);
644 assert_one_modified(1, 6, 1, 5, 0, &expected);
645
646 /* diff from blob a to content of a */
647 opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
648 quick_diff_blob_to_str(a, NULL, a_content, 0, NULL);
649 assert_identical_blobs_comparison(&expected);
650
651 /* diff from NULL blob to content of a */
652 memset(&expected, 0, sizeof(expected));
653 quick_diff_blob_to_str(NULL, NULL, a_content, 0, NULL);
654 assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED);
655
656 /* diff from blob a to NULL buffer */
657 memset(&expected, 0, sizeof(expected));
658 quick_diff_blob_to_str(a, NULL, NULL, 0, NULL);
659 assert_changed_single_one_line_file(&expected, GIT_DELTA_DELETED);
660
661 /* diff with reverse */
662 opts.flags ^= GIT_DIFF_REVERSE;
663
664 memset(&expected, 0, sizeof(expected));
665 quick_diff_blob_to_str(a, NULL, NULL, 0, NULL);
666 assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED);
667
668 git_blob_free(a);
669 }
670
671 void test_diff_blob__can_compare_blob_to_buffer_with_patch(void)
672 {
673 git_patch *p;
674 git_blob *a;
675 git_oid a_oid;
676 const char *a_content = "Hello from the root\n";
677 const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n";
678 size_t tc, ta, td;
679
680 /* tests/resources/attr/root_test1 */
681 cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
682 cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8));
683
684 /* diff from blob a to content of b */
685 cl_git_pass(git_patch_from_blob_and_buffer(
686 &p, a, NULL, b_content, strlen(b_content), NULL, &opts));
687
688 cl_assert(p != NULL);
689 cl_assert_equal_i(GIT_DELTA_MODIFIED, git_patch_get_delta(p)->status);
690 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
691 cl_assert_equal_i(6, git_patch_num_lines_in_hunk(p, 0));
692
693 cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
694 cl_assert_equal_i(1, (int)tc);
695 cl_assert_equal_i(5, (int)ta);
696 cl_assert_equal_i(0, (int)td);
697
698 git_patch_free(p);
699
700 /* diff from blob a to content of a */
701 opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
702 cl_git_pass(git_patch_from_blob_and_buffer(
703 &p, a, NULL, a_content, strlen(a_content), NULL, &opts));
704 cl_assert(p != NULL);
705 cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status);
706 cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
707 git_patch_free(p);
708
709 /* diff from NULL blob to content of a */
710 cl_git_pass(git_patch_from_blob_and_buffer(
711 &p, NULL, NULL, a_content, strlen(a_content), NULL, &opts));
712 cl_assert(p != NULL);
713 cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status);
714 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
715 cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
716 git_patch_free(p);
717
718 /* diff from blob a to NULL buffer */
719 cl_git_pass(git_patch_from_blob_and_buffer(
720 &p, a, NULL, NULL, 0, NULL, &opts));
721 cl_assert(p != NULL);
722 cl_assert_equal_i(GIT_DELTA_DELETED, git_patch_get_delta(p)->status);
723 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
724 cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
725 git_patch_free(p);
726
727 /* diff with reverse */
728 opts.flags ^= GIT_DIFF_REVERSE;
729
730 cl_git_pass(git_patch_from_blob_and_buffer(
731 &p, a, NULL, NULL, 0, NULL, &opts));
732 cl_assert(p != NULL);
733 cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status);
734 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
735 cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
736 git_patch_free(p);
737
738 git_blob_free(a);
739 }
740
741 static void assert_one_modified_with_lines(diff_expects *expected, int lines)
742 {
743 cl_assert_equal_i(1, expected->files);
744 cl_assert_equal_i(1, expected->file_status[GIT_DELTA_MODIFIED]);
745 cl_assert_equal_i(0, expected->files_binary);
746 cl_assert_equal_i(lines, expected->lines);
747 }
748
749 void test_diff_blob__binary_data_comparisons(void)
750 {
751 git_blob *bin, *nonbin;
752 git_oid oid;
753 const char *nonbin_content = "Hello from the root\n";
754 size_t nonbin_len = 20;
755 const char *bin_content = "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n";
756 size_t bin_len = 33;
757
758 opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
759
760 cl_git_pass(git_oid_fromstrn(&oid, "45141a79", 8));
761 cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 8));
762
763 cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8));
764 cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 8));
765
766 /* non-binary to reference content */
767
768 quick_diff_blob_to_str(nonbin, NULL, nonbin_content, nonbin_len, NULL);
769 assert_identical_blobs_comparison(&expected);
770 cl_assert_equal_i(0, expected.files_binary);
771
772 /* binary to reference content */
773
774 quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
775 assert_identical_blobs_comparison(&expected);
776
777 cl_assert_equal_i(1, expected.files_binary);
778
779 /* non-binary to binary content */
780
781 quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL);
782 assert_binary_blobs_comparison(&expected);
783
784 /* binary to non-binary content */
785
786 quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL);
787 assert_binary_blobs_comparison(&expected);
788
789 /* non-binary to binary blob */
790
791 memset(&expected, 0, sizeof(expected));
792 cl_git_pass(git_diff_blobs(
793 bin, NULL, nonbin, NULL, &opts,
794 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
795 assert_binary_blobs_comparison(&expected);
796
797 /*
798 * repeat with FORCE_TEXT
799 */
800
801 opts.flags |= GIT_DIFF_FORCE_TEXT;
802
803 quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
804 assert_identical_blobs_comparison(&expected);
805
806 quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL);
807 assert_one_modified_with_lines(&expected, 4);
808
809 quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL);
810 assert_one_modified_with_lines(&expected, 4);
811
812 memset(&expected, 0, sizeof(expected));
813 cl_git_pass(git_diff_blobs(
814 bin, NULL, nonbin, NULL, &opts,
815 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
816 assert_one_modified_with_lines(&expected, 4);
817
818 /* cleanup */
819 git_blob_free(bin);
820 git_blob_free(nonbin);
821 }
822
823 void test_diff_blob__using_path_and_attributes(void)
824 {
825 git_config *cfg;
826 git_blob *bin, *nonbin;
827 git_oid oid;
828 const char *nonbin_content = "Hello from the root\n";
829 const char *bin_content =
830 "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n";
831 size_t bin_len = 33;
832 const char *changed;
833 git_patch *p;
834 git_buf buf = GIT_BUF_INIT;
835
836 /* set up custom diff drivers and 'diff' attribute mappings for them */
837
838 cl_git_pass(git_repository_config(&cfg, g_repo));
839 cl_git_pass(git_config_set_bool(cfg, "diff.iam_binary.binary", 1));
840 cl_git_pass(git_config_set_bool(cfg, "diff.iam_text.binary", 0));
841 cl_git_pass(git_config_set_string(
842 cfg, "diff.iam_alphactx.xfuncname", "^[A-Za-z].*$"));
843 cl_git_pass(git_config_set_bool(cfg, "diff.iam_textalpha.binary", 0));
844 cl_git_pass(git_config_set_string(
845 cfg, "diff.iam_textalpha.xfuncname", "^[A-Za-z].*$"));
846 cl_git_pass(git_config_set_string(
847 cfg, "diff.iam_numctx.funcname", "^[0-9][0-9]*"));
848 cl_git_pass(git_config_set_bool(cfg, "diff.iam_textnum.binary", 0));
849 cl_git_pass(git_config_set_string(
850 cfg, "diff.iam_textnum.funcname", "^[0-9][0-9]*"));
851 git_config_free(cfg);
852
853 cl_git_append2file(
854 "attr/.gitattributes",
855 "\n\n# test_diff_blob__using_path_and_attributes extra\n\n"
856 "*.binary diff=iam_binary\n"
857 "*.textary diff=iam_text\n"
858 "*.alphary diff=iam_alphactx\n"
859 "*.textalphary diff=iam_textalpha\n"
860 "*.textnumary diff=iam_textnum\n"
861 "*.numary diff=iam_numctx\n\n");
862
863 opts.context_lines = 0;
864 opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
865
866 cl_git_pass(git_oid_fromstrn(&oid, "45141a79", 8));
867 cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 8));
868 /* 20b: "Hello from the root\n" */
869
870 cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8));
871 cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 8));
872 /* 33b: "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\n0123456789\n" */
873
874 /* non-binary to reference content */
875
876 quick_diff_blob_to_str(nonbin, NULL, nonbin_content, 0, NULL);
877 assert_identical_blobs_comparison(&expected);
878 cl_assert_equal_i(0, expected.files_binary);
879
880 /* binary to reference content */
881
882 quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
883 assert_identical_blobs_comparison(&expected);
884 cl_assert_equal_i(1, expected.files_binary);
885
886 /* add some text */
887
888 changed = "Hello from the root\nMore lines\nAnd more\nGo here\n";
889
890 quick_diff_blob_to_str(nonbin, NULL, changed, 0, NULL);
891 assert_one_modified(1, 3, 0, 3, 0, &expected);
892
893 quick_diff_blob_to_str(nonbin, "foo/bar.binary", changed, 0, NULL);
894 cl_assert_equal_i(1, expected.files);
895 cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
896 cl_assert_equal_i(1, expected.files_binary);
897 cl_assert_equal_i(0, expected.hunks);
898 cl_assert_equal_i(0, expected.lines);
899
900 quick_diff_blob_to_str(nonbin, "foo/bar.textary", changed, 0, NULL);
901 assert_one_modified(1, 3, 0, 3, 0, &expected);
902
903 quick_diff_blob_to_str(nonbin, "foo/bar.alphary", changed, 0, NULL);
904 assert_one_modified(1, 3, 0, 3, 0, &expected);
905
906 cl_git_pass(git_patch_from_blob_and_buffer(
907 &p, nonbin, "zzz.normal", changed, strlen(changed), NULL, &opts));
908 cl_git_pass(git_patch_to_buf(&buf, p));
909 cl_assert_equal_s(
910 "diff --git a/zzz.normal b/zzz.normal\n"
911 "index 45141a7..75b0dbb 100644\n"
912 "--- a/zzz.normal\n"
913 "+++ b/zzz.normal\n"
914 "@@ -1,0 +2,3 @@ Hello from the root\n"
915 "+More lines\n"
916 "+And more\n"
917 "+Go here\n", buf.ptr);
918 git_buf_clear(&buf);
919 git_patch_free(p);
920
921 cl_git_pass(git_patch_from_blob_and_buffer(
922 &p, nonbin, "zzz.binary", changed, strlen(changed), NULL, &opts));
923 cl_git_pass(git_patch_to_buf(&buf, p));
924 cl_assert_equal_s(
925 "diff --git a/zzz.binary b/zzz.binary\n"
926 "index 45141a7..75b0dbb 100644\n"
927 "Binary files a/zzz.binary and b/zzz.binary differ\n", buf.ptr);
928 git_buf_clear(&buf);
929 git_patch_free(p);
930
931 cl_git_pass(git_patch_from_blob_and_buffer(
932 &p, nonbin, "zzz.alphary", changed, strlen(changed), NULL, &opts));
933 cl_git_pass(git_patch_to_buf(&buf, p));
934 cl_assert_equal_s(
935 "diff --git a/zzz.alphary b/zzz.alphary\n"
936 "index 45141a7..75b0dbb 100644\n"
937 "--- a/zzz.alphary\n"
938 "+++ b/zzz.alphary\n"
939 "@@ -1,0 +2,3 @@ Hello from the root\n"
940 "+More lines\n"
941 "+And more\n"
942 "+Go here\n", buf.ptr);
943 git_buf_clear(&buf);
944 git_patch_free(p);
945
946 cl_git_pass(git_patch_from_blob_and_buffer(
947 &p, nonbin, "zzz.numary", changed, strlen(changed), NULL, &opts));
948 cl_git_pass(git_patch_to_buf(&buf, p));
949 cl_assert_equal_s(
950 "diff --git a/zzz.numary b/zzz.numary\n"
951 "index 45141a7..75b0dbb 100644\n"
952 "--- a/zzz.numary\n"
953 "+++ b/zzz.numary\n"
954 "@@ -1,0 +2,3 @@\n"
955 "+More lines\n"
956 "+And more\n"
957 "+Go here\n", buf.ptr);
958 git_buf_clear(&buf);
959 git_patch_free(p);
960
961 /* "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n"
962 * 33 bytes
963 */
964
965 changed = "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\nreplace a line\n";
966
967 cl_git_pass(git_patch_from_blob_and_buffer(
968 &p, bin, "zzz.normal", changed, 37, NULL, &opts));
969 cl_git_pass(git_patch_to_buf(&buf, p));
970 cl_assert_equal_s(
971 "diff --git a/zzz.normal b/zzz.normal\n"
972 "index b435cd5..1604519 100644\n"
973 "Binary files a/zzz.normal and b/zzz.normal differ\n", buf.ptr);
974 git_buf_clear(&buf);
975 git_patch_free(p);
976
977 cl_git_pass(git_patch_from_blob_and_buffer(
978 &p, bin, "zzz.textary", changed, 37, NULL, &opts));
979 cl_git_pass(git_patch_to_buf(&buf, p));
980 cl_assert_equal_s(
981 "diff --git a/zzz.textary b/zzz.textary\n"
982 "index b435cd5..1604519 100644\n"
983 "--- a/zzz.textary\n"
984 "+++ b/zzz.textary\n"
985 "@@ -3 +3 @@\n"
986 "-0123456789\n"
987 "+replace a line\n", buf.ptr);
988 git_buf_clear(&buf);
989 git_patch_free(p);
990
991 cl_git_pass(git_patch_from_blob_and_buffer(
992 &p, bin, "zzz.textalphary", changed, 37, NULL, &opts));
993 cl_git_pass(git_patch_to_buf(&buf, p));
994 cl_assert_equal_s(
995 "diff --git a/zzz.textalphary b/zzz.textalphary\n"
996 "index b435cd5..1604519 100644\n"
997 "--- a/zzz.textalphary\n"
998 "+++ b/zzz.textalphary\n"
999 "@@ -3 +3 @@\n"
1000 "-0123456789\n"
1001 "+replace a line\n", buf.ptr);
1002 git_buf_clear(&buf);
1003 git_patch_free(p);
1004
1005 cl_git_pass(git_patch_from_blob_and_buffer(
1006 &p, bin, "zzz.textnumary", changed, 37, NULL, &opts));
1007 cl_git_pass(git_patch_to_buf(&buf, p));
1008 cl_assert_equal_s(
1009 "diff --git a/zzz.textnumary b/zzz.textnumary\n"
1010 "index b435cd5..1604519 100644\n"
1011 "--- a/zzz.textnumary\n"
1012 "+++ b/zzz.textnumary\n"
1013 "@@ -3 +3 @@ 0123456789\n"
1014 "-0123456789\n"
1015 "+replace a line\n", buf.ptr);
1016 git_buf_clear(&buf);
1017 git_patch_free(p);
1018
1019 git_buf_dispose(&buf);
1020 git_blob_free(nonbin);
1021 git_blob_free(bin);
1022 }
1023
1024 void test_diff_blob__can_compare_buffer_to_buffer(void)
1025 {
1026 const char *a = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\n";
1027 const char *b = "a\nB\nc\nd\nE\nF\nh\nj\nk\n";
1028
1029 opts.interhunk_lines = 0;
1030 opts.context_lines = 0;
1031
1032 memset(&expected, 0, sizeof(expected));
1033
1034 cl_git_pass(git_diff_buffers(
1035 a, strlen(a), NULL, b, strlen(b), NULL, &opts,
1036 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
1037 assert_one_modified(4, 9, 0, 4, 5, &expected);
1038
1039 opts.flags ^= GIT_DIFF_REVERSE;
1040
1041 memset(&expected, 0, sizeof(expected));
1042
1043 cl_git_pass(git_diff_buffers(
1044 a, strlen(a), NULL, b, strlen(b), NULL, &opts,
1045 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
1046 assert_one_modified(4, 9, 0, 5, 4, &expected);
1047 }