]> git.proxmox.com Git - libgit2.git/blob - tests/diff/blob.c
New upstream version 1.4.3+dfsg.1
[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_binary_blob_data_as_binary(void)
608 {
609 /* alien.png */
610 const char *content = git_blob_rawcontent(alien);
611 size_t len = (size_t)git_blob_rawsize(alien);
612 cl_assert_equal_i(true, git_blob_data_is_binary(content, len));
613 }
614
615 void test_diff_blob__can_correctly_detect_a_textual_blob_as_non_binary(void)
616 {
617 /* tests/resources/attr/root_test4.txt */
618 cl_assert_equal_i(false, git_blob_is_binary(d));
619 }
620
621 void test_diff_blob__can_correctly_detect_textual_blob_data_as_non_binary(void)
622 {
623 /* tests/resources/attr/root_test4.txt */
624 const char *content = git_blob_rawcontent(d);
625 size_t len = (size_t)git_blob_rawsize(d);
626 cl_assert_equal_i(false, git_blob_data_is_binary(content, len));
627 }
628
629 /*
630 * git_diff_blob_to_buffer tests
631 */
632
633 static void assert_changed_single_one_line_file(
634 diff_expects *expected, git_delta_t mod)
635 {
636 cl_assert_equal_i(1, expected->files);
637 cl_assert_equal_i(1, expected->file_status[mod]);
638 cl_assert_equal_i(1, expected->hunks);
639 cl_assert_equal_i(1, expected->lines);
640
641 if (mod == GIT_DELTA_ADDED)
642 cl_assert_equal_i(1, expected->line_adds);
643 else if (mod == GIT_DELTA_DELETED)
644 cl_assert_equal_i(1, expected->line_dels);
645 }
646
647 void test_diff_blob__can_compare_blob_to_buffer(void)
648 {
649 git_blob *a;
650 git_oid a_oid;
651 const char *a_content = "Hello from the root\n";
652 const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n";
653
654 /* tests/resources/attr/root_test1 */
655 cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
656 cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8));
657
658 /* diff from blob a to content of b */
659 quick_diff_blob_to_str(a, NULL, b_content, 0, NULL);
660 assert_one_modified(1, 6, 1, 5, 0, &expected);
661
662 /* diff from blob a to content of a */
663 opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
664 quick_diff_blob_to_str(a, NULL, a_content, 0, NULL);
665 assert_identical_blobs_comparison(&expected);
666
667 /* diff from NULL blob to content of a */
668 memset(&expected, 0, sizeof(expected));
669 quick_diff_blob_to_str(NULL, NULL, a_content, 0, NULL);
670 assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED);
671
672 /* diff from blob a to NULL buffer */
673 memset(&expected, 0, sizeof(expected));
674 quick_diff_blob_to_str(a, NULL, NULL, 0, NULL);
675 assert_changed_single_one_line_file(&expected, GIT_DELTA_DELETED);
676
677 /* diff with reverse */
678 opts.flags ^= GIT_DIFF_REVERSE;
679
680 memset(&expected, 0, sizeof(expected));
681 quick_diff_blob_to_str(a, NULL, NULL, 0, NULL);
682 assert_changed_single_one_line_file(&expected, GIT_DELTA_ADDED);
683
684 git_blob_free(a);
685 }
686
687 void test_diff_blob__can_compare_blob_to_buffer_with_patch(void)
688 {
689 git_patch *p;
690 git_blob *a;
691 git_oid a_oid;
692 const char *a_content = "Hello from the root\n";
693 const char *b_content = "Hello from the root\n\nSome additional lines\n\nDown here below\n\n";
694 size_t tc, ta, td;
695
696 /* tests/resources/attr/root_test1 */
697 cl_git_pass(git_oid_fromstrn(&a_oid, "45141a79", 8));
698 cl_git_pass(git_blob_lookup_prefix(&a, g_repo, &a_oid, 8));
699
700 /* diff from blob a to content of b */
701 cl_git_pass(git_patch_from_blob_and_buffer(
702 &p, a, NULL, b_content, strlen(b_content), NULL, &opts));
703
704 cl_assert(p != NULL);
705 cl_assert_equal_i(GIT_DELTA_MODIFIED, git_patch_get_delta(p)->status);
706 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
707 cl_assert_equal_i(6, git_patch_num_lines_in_hunk(p, 0));
708
709 cl_git_pass(git_patch_line_stats(&tc, &ta, &td, p));
710 cl_assert_equal_i(1, (int)tc);
711 cl_assert_equal_i(5, (int)ta);
712 cl_assert_equal_i(0, (int)td);
713
714 git_patch_free(p);
715
716 /* diff from blob a to content of a */
717 opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
718 cl_git_pass(git_patch_from_blob_and_buffer(
719 &p, a, NULL, a_content, strlen(a_content), NULL, &opts));
720 cl_assert(p != NULL);
721 cl_assert_equal_i(GIT_DELTA_UNMODIFIED, git_patch_get_delta(p)->status);
722 cl_assert_equal_i(0, (int)git_patch_num_hunks(p));
723 git_patch_free(p);
724
725 /* diff from NULL blob to content of a */
726 cl_git_pass(git_patch_from_blob_and_buffer(
727 &p, NULL, NULL, a_content, strlen(a_content), NULL, &opts));
728 cl_assert(p != NULL);
729 cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status);
730 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
731 cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
732 git_patch_free(p);
733
734 /* diff from blob a to NULL buffer */
735 cl_git_pass(git_patch_from_blob_and_buffer(
736 &p, a, NULL, NULL, 0, NULL, &opts));
737 cl_assert(p != NULL);
738 cl_assert_equal_i(GIT_DELTA_DELETED, git_patch_get_delta(p)->status);
739 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
740 cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
741 git_patch_free(p);
742
743 /* diff with reverse */
744 opts.flags ^= GIT_DIFF_REVERSE;
745
746 cl_git_pass(git_patch_from_blob_and_buffer(
747 &p, a, NULL, NULL, 0, NULL, &opts));
748 cl_assert(p != NULL);
749 cl_assert_equal_i(GIT_DELTA_ADDED, git_patch_get_delta(p)->status);
750 cl_assert_equal_i(1, (int)git_patch_num_hunks(p));
751 cl_assert_equal_i(1, git_patch_num_lines_in_hunk(p, 0));
752 git_patch_free(p);
753
754 git_blob_free(a);
755 }
756
757 static void assert_one_modified_with_lines(diff_expects *expected, int lines)
758 {
759 cl_assert_equal_i(1, expected->files);
760 cl_assert_equal_i(1, expected->file_status[GIT_DELTA_MODIFIED]);
761 cl_assert_equal_i(0, expected->files_binary);
762 cl_assert_equal_i(lines, expected->lines);
763 }
764
765 void test_diff_blob__binary_data_comparisons(void)
766 {
767 git_blob *bin, *nonbin;
768 git_oid oid;
769 const char *nonbin_content = "Hello from the root\n";
770 size_t nonbin_len = 20;
771 const char *bin_content = "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n";
772 size_t bin_len = 33;
773
774 opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
775
776 cl_git_pass(git_oid_fromstrn(&oid, "45141a79", 8));
777 cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 8));
778
779 cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8));
780 cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 8));
781
782 /* non-binary to reference content */
783
784 quick_diff_blob_to_str(nonbin, NULL, nonbin_content, nonbin_len, NULL);
785 assert_identical_blobs_comparison(&expected);
786 cl_assert_equal_i(0, expected.files_binary);
787
788 /* binary to reference content */
789
790 quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
791 assert_identical_blobs_comparison(&expected);
792
793 cl_assert_equal_i(1, expected.files_binary);
794
795 /* non-binary to binary content */
796
797 quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL);
798 assert_binary_blobs_comparison(&expected);
799
800 /* binary to non-binary content */
801
802 quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL);
803 assert_binary_blobs_comparison(&expected);
804
805 /* non-binary to binary blob */
806
807 memset(&expected, 0, sizeof(expected));
808 cl_git_pass(git_diff_blobs(
809 bin, NULL, nonbin, NULL, &opts,
810 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
811 assert_binary_blobs_comparison(&expected);
812
813 /*
814 * repeat with FORCE_TEXT
815 */
816
817 opts.flags |= GIT_DIFF_FORCE_TEXT;
818
819 quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
820 assert_identical_blobs_comparison(&expected);
821
822 quick_diff_blob_to_str(nonbin, NULL, bin_content, bin_len, NULL);
823 assert_one_modified_with_lines(&expected, 4);
824
825 quick_diff_blob_to_str(bin, NULL, nonbin_content, nonbin_len, NULL);
826 assert_one_modified_with_lines(&expected, 4);
827
828 memset(&expected, 0, sizeof(expected));
829 cl_git_pass(git_diff_blobs(
830 bin, NULL, nonbin, NULL, &opts,
831 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
832 assert_one_modified_with_lines(&expected, 4);
833
834 /* cleanup */
835 git_blob_free(bin);
836 git_blob_free(nonbin);
837 }
838
839 void test_diff_blob__using_path_and_attributes(void)
840 {
841 git_config *cfg;
842 git_blob *bin, *nonbin;
843 git_oid oid;
844 const char *nonbin_content = "Hello from the root\n";
845 const char *bin_content =
846 "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n";
847 size_t bin_len = 33;
848 const char *changed;
849 git_patch *p;
850 git_buf buf = GIT_BUF_INIT;
851
852 /* set up custom diff drivers and 'diff' attribute mappings for them */
853
854 cl_git_pass(git_repository_config(&cfg, g_repo));
855 cl_git_pass(git_config_set_bool(cfg, "diff.iam_binary.binary", 1));
856 cl_git_pass(git_config_set_bool(cfg, "diff.iam_text.binary", 0));
857 cl_git_pass(git_config_set_string(
858 cfg, "diff.iam_alphactx.xfuncname", "^[A-Za-z].*$"));
859 cl_git_pass(git_config_set_bool(cfg, "diff.iam_textalpha.binary", 0));
860 cl_git_pass(git_config_set_string(
861 cfg, "diff.iam_textalpha.xfuncname", "^[A-Za-z].*$"));
862 cl_git_pass(git_config_set_string(
863 cfg, "diff.iam_numctx.funcname", "^[0-9][0-9]*"));
864 cl_git_pass(git_config_set_bool(cfg, "diff.iam_textnum.binary", 0));
865 cl_git_pass(git_config_set_string(
866 cfg, "diff.iam_textnum.funcname", "^[0-9][0-9]*"));
867 git_config_free(cfg);
868
869 cl_git_append2file(
870 "attr/.gitattributes",
871 "\n\n# test_diff_blob__using_path_and_attributes extra\n\n"
872 "*.binary diff=iam_binary\n"
873 "*.textary diff=iam_text\n"
874 "*.alphary diff=iam_alphactx\n"
875 "*.textalphary diff=iam_textalpha\n"
876 "*.textnumary diff=iam_textnum\n"
877 "*.numary diff=iam_numctx\n\n");
878
879 opts.context_lines = 0;
880 opts.flags |= GIT_DIFF_INCLUDE_UNMODIFIED;
881
882 cl_git_pass(git_oid_fromstrn(&oid, "45141a79", 8));
883 cl_git_pass(git_blob_lookup_prefix(&nonbin, g_repo, &oid, 8));
884 /* 20b: "Hello from the root\n" */
885
886 cl_git_pass(git_oid_fromstrn(&oid, "b435cd56", 8));
887 cl_git_pass(git_blob_lookup_prefix(&bin, g_repo, &oid, 8));
888 /* 33b: "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\n0123456789\n" */
889
890 /* non-binary to reference content */
891
892 quick_diff_blob_to_str(nonbin, NULL, nonbin_content, 0, NULL);
893 assert_identical_blobs_comparison(&expected);
894 cl_assert_equal_i(0, expected.files_binary);
895
896 /* binary to reference content */
897
898 quick_diff_blob_to_str(bin, NULL, bin_content, bin_len, NULL);
899 assert_identical_blobs_comparison(&expected);
900 cl_assert_equal_i(1, expected.files_binary);
901
902 /* add some text */
903
904 changed = "Hello from the root\nMore lines\nAnd more\nGo here\n";
905
906 quick_diff_blob_to_str(nonbin, NULL, changed, 0, NULL);
907 assert_one_modified(1, 3, 0, 3, 0, &expected);
908
909 quick_diff_blob_to_str(nonbin, "foo/bar.binary", changed, 0, NULL);
910 cl_assert_equal_i(1, expected.files);
911 cl_assert_equal_i(1, expected.file_status[GIT_DELTA_MODIFIED]);
912 cl_assert_equal_i(1, expected.files_binary);
913 cl_assert_equal_i(0, expected.hunks);
914 cl_assert_equal_i(0, expected.lines);
915
916 quick_diff_blob_to_str(nonbin, "foo/bar.textary", changed, 0, NULL);
917 assert_one_modified(1, 3, 0, 3, 0, &expected);
918
919 quick_diff_blob_to_str(nonbin, "foo/bar.alphary", changed, 0, NULL);
920 assert_one_modified(1, 3, 0, 3, 0, &expected);
921
922 cl_git_pass(git_patch_from_blob_and_buffer(
923 &p, nonbin, "zzz.normal", changed, strlen(changed), NULL, &opts));
924 cl_git_pass(git_patch_to_buf(&buf, p));
925 cl_assert_equal_s(
926 "diff --git a/zzz.normal b/zzz.normal\n"
927 "index 45141a7..75b0dbb 100644\n"
928 "--- a/zzz.normal\n"
929 "+++ b/zzz.normal\n"
930 "@@ -1,0 +2,3 @@ Hello from the root\n"
931 "+More lines\n"
932 "+And more\n"
933 "+Go here\n", buf.ptr);
934 git_buf_dispose(&buf);
935 git_patch_free(p);
936
937 cl_git_pass(git_patch_from_blob_and_buffer(
938 &p, nonbin, "zzz.binary", changed, strlen(changed), NULL, &opts));
939 cl_git_pass(git_patch_to_buf(&buf, p));
940 cl_assert_equal_s(
941 "diff --git a/zzz.binary b/zzz.binary\n"
942 "index 45141a7..75b0dbb 100644\n"
943 "Binary files a/zzz.binary and b/zzz.binary differ\n", buf.ptr);
944 git_buf_dispose(&buf);
945 git_patch_free(p);
946
947 cl_git_pass(git_patch_from_blob_and_buffer(
948 &p, nonbin, "zzz.alphary", changed, strlen(changed), NULL, &opts));
949 cl_git_pass(git_patch_to_buf(&buf, p));
950 cl_assert_equal_s(
951 "diff --git a/zzz.alphary b/zzz.alphary\n"
952 "index 45141a7..75b0dbb 100644\n"
953 "--- a/zzz.alphary\n"
954 "+++ b/zzz.alphary\n"
955 "@@ -1,0 +2,3 @@ Hello from the root\n"
956 "+More lines\n"
957 "+And more\n"
958 "+Go here\n", buf.ptr);
959 git_buf_dispose(&buf);
960 git_patch_free(p);
961
962 cl_git_pass(git_patch_from_blob_and_buffer(
963 &p, nonbin, "zzz.numary", changed, strlen(changed), NULL, &opts));
964 cl_git_pass(git_patch_to_buf(&buf, p));
965 cl_assert_equal_s(
966 "diff --git a/zzz.numary b/zzz.numary\n"
967 "index 45141a7..75b0dbb 100644\n"
968 "--- a/zzz.numary\n"
969 "+++ b/zzz.numary\n"
970 "@@ -1,0 +2,3 @@\n"
971 "+More lines\n"
972 "+And more\n"
973 "+Go here\n", buf.ptr);
974 git_buf_dispose(&buf);
975 git_patch_free(p);
976
977 /* "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\n0123456789\n"
978 * 33 bytes
979 */
980
981 changed = "0123456789\n\x01\x02\x03\x04\x05\x06\x07\x08\x09\x00\nreplace a line\n";
982
983 cl_git_pass(git_patch_from_blob_and_buffer(
984 &p, bin, "zzz.normal", changed, 37, NULL, &opts));
985 cl_git_pass(git_patch_to_buf(&buf, p));
986 cl_assert_equal_s(
987 "diff --git a/zzz.normal b/zzz.normal\n"
988 "index b435cd5..1604519 100644\n"
989 "Binary files a/zzz.normal and b/zzz.normal differ\n", buf.ptr);
990 git_buf_dispose(&buf);
991 git_patch_free(p);
992
993 cl_git_pass(git_patch_from_blob_and_buffer(
994 &p, bin, "zzz.textary", changed, 37, NULL, &opts));
995 cl_git_pass(git_patch_to_buf(&buf, p));
996 cl_assert_equal_s(
997 "diff --git a/zzz.textary b/zzz.textary\n"
998 "index b435cd5..1604519 100644\n"
999 "--- a/zzz.textary\n"
1000 "+++ b/zzz.textary\n"
1001 "@@ -3 +3 @@\n"
1002 "-0123456789\n"
1003 "+replace a line\n", buf.ptr);
1004 git_buf_dispose(&buf);
1005 git_patch_free(p);
1006
1007 cl_git_pass(git_patch_from_blob_and_buffer(
1008 &p, bin, "zzz.textalphary", changed, 37, NULL, &opts));
1009 cl_git_pass(git_patch_to_buf(&buf, p));
1010 cl_assert_equal_s(
1011 "diff --git a/zzz.textalphary b/zzz.textalphary\n"
1012 "index b435cd5..1604519 100644\n"
1013 "--- a/zzz.textalphary\n"
1014 "+++ b/zzz.textalphary\n"
1015 "@@ -3 +3 @@\n"
1016 "-0123456789\n"
1017 "+replace a line\n", buf.ptr);
1018 git_buf_dispose(&buf);
1019 git_patch_free(p);
1020
1021 cl_git_pass(git_patch_from_blob_and_buffer(
1022 &p, bin, "zzz.textnumary", changed, 37, NULL, &opts));
1023 cl_git_pass(git_patch_to_buf(&buf, p));
1024 cl_assert_equal_s(
1025 "diff --git a/zzz.textnumary b/zzz.textnumary\n"
1026 "index b435cd5..1604519 100644\n"
1027 "--- a/zzz.textnumary\n"
1028 "+++ b/zzz.textnumary\n"
1029 "@@ -3 +3 @@ 0123456789\n"
1030 "-0123456789\n"
1031 "+replace a line\n", buf.ptr);
1032 git_buf_dispose(&buf);
1033 git_patch_free(p);
1034
1035 git_buf_dispose(&buf);
1036 git_blob_free(nonbin);
1037 git_blob_free(bin);
1038 }
1039
1040 void test_diff_blob__can_compare_buffer_to_buffer(void)
1041 {
1042 const char *a = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\n";
1043 const char *b = "a\nB\nc\nd\nE\nF\nh\nj\nk\n";
1044
1045 opts.interhunk_lines = 0;
1046 opts.context_lines = 0;
1047
1048 memset(&expected, 0, sizeof(expected));
1049
1050 cl_git_pass(git_diff_buffers(
1051 a, strlen(a), NULL, b, strlen(b), NULL, &opts,
1052 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
1053 assert_one_modified(4, 9, 0, 4, 5, &expected);
1054
1055 opts.flags ^= GIT_DIFF_REVERSE;
1056
1057 memset(&expected, 0, sizeof(expected));
1058
1059 cl_git_pass(git_diff_buffers(
1060 a, strlen(a), NULL, b, strlen(b), NULL, &opts,
1061 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expected));
1062 assert_one_modified(4, 9, 0, 5, 4, &expected);
1063 }