]> git.proxmox.com Git - libgit2.git/blob - tests/diff/tree.c
a3b00ec08e2f63be012ae875d9c2d919838b15bd
[libgit2.git] / tests / diff / tree.c
1 #include "clar_libgit2.h"
2 #include "diff_helpers.h"
3
4 static git_repository *g_repo = NULL;
5 static git_diff_options opts;
6 static git_diff *diff;
7 static git_tree *a, *b;
8 static diff_expects expect;
9
10 void test_diff_tree__initialize(void)
11 {
12 cl_git_pass(git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION));
13
14 memset(&expect, 0, sizeof(expect));
15
16 diff = NULL;
17 a = NULL;
18 b = NULL;
19 }
20
21 void test_diff_tree__cleanup(void)
22 {
23 git_diff_free(diff);
24 git_tree_free(a);
25 git_tree_free(b);
26
27 cl_git_sandbox_cleanup();
28
29 }
30
31 void test_diff_tree__0(void)
32 {
33 /* grabbed a couple of commit oids from the history of the attr repo */
34 const char *a_commit = "605812a";
35 const char *b_commit = "370fe9ec22";
36 const char *c_commit = "f5b0af1fb4f5c";
37 git_tree *c;
38
39 g_repo = cl_git_sandbox_init("attr");
40
41 cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
42 cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
43 cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL);
44
45 opts.context_lines = 1;
46 opts.interhunk_lines = 1;
47
48
49 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
50
51 cl_git_pass(git_diff_foreach(
52 diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
53
54 cl_assert_equal_i(5, expect.files);
55 cl_assert_equal_i(2, expect.file_status[GIT_DELTA_ADDED]);
56 cl_assert_equal_i(1, expect.file_status[GIT_DELTA_DELETED]);
57 cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
58
59 cl_assert_equal_i(5, expect.hunks);
60
61 cl_assert_equal_i(7 + 24 + 1 + 6 + 6, expect.lines);
62 cl_assert_equal_i(1, expect.line_ctxt);
63 cl_assert_equal_i(24 + 1 + 5 + 5, expect.line_adds);
64 cl_assert_equal_i(7 + 1, expect.line_dels);
65
66 git_diff_free(diff);
67 diff = NULL;
68
69 memset(&expect, 0, sizeof(expect));
70
71 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, c, b, &opts));
72
73 cl_git_pass(git_diff_foreach(
74 diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
75
76 cl_assert_equal_i(2, expect.files);
77 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]);
78 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_DELETED]);
79 cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
80
81 cl_assert_equal_i(2, expect.hunks);
82
83 cl_assert_equal_i(8 + 15, expect.lines);
84 cl_assert_equal_i(1, expect.line_ctxt);
85 cl_assert_equal_i(1, expect.line_adds);
86 cl_assert_equal_i(7 + 14, expect.line_dels);
87
88 git_tree_free(c);
89 }
90
91 #define DIFF_OPTS(FLAGS, CTXT) \
92 {GIT_DIFF_OPTIONS_VERSION, (FLAGS), GIT_SUBMODULE_IGNORE_UNSPECIFIED, \
93 {NULL,0}, NULL, NULL, NULL, (CTXT), 1}
94
95 void test_diff_tree__options(void)
96 {
97 /* grabbed a couple of commit oids from the history of the attr repo */
98 const char *a_commit = "6bab5c79cd5140d0";
99 const char *b_commit = "605812ab7fe421fdd";
100 const char *c_commit = "f5b0af1fb4f5";
101 const char *d_commit = "a97cc019851";
102 git_tree *c, *d;
103 diff_expects actual;
104 int test_ab_or_cd[] = { 0, 0, 0, 0, 1, 1, 1, 1, 1 };
105 git_diff_options test_options[] = {
106 /* a vs b tests */
107 DIFF_OPTS(GIT_DIFF_NORMAL, 1),
108 DIFF_OPTS(GIT_DIFF_NORMAL, 3),
109 DIFF_OPTS(GIT_DIFF_REVERSE, 2),
110 DIFF_OPTS(GIT_DIFF_FORCE_TEXT, 2),
111 /* c vs d tests */
112 DIFF_OPTS(GIT_DIFF_NORMAL, 3),
113 DIFF_OPTS(GIT_DIFF_IGNORE_WHITESPACE, 3),
114 DIFF_OPTS(GIT_DIFF_IGNORE_WHITESPACE_CHANGE, 3),
115 DIFF_OPTS(GIT_DIFF_IGNORE_WHITESPACE_EOL, 3),
116 DIFF_OPTS(GIT_DIFF_IGNORE_WHITESPACE | GIT_DIFF_REVERSE, 1),
117 };
118
119 /* to generate these values:
120 * - cd to tests/resources/attr,
121 * - mv .gitted .git
122 * - git diff [options] 6bab5c79cd5140d0 605812ab7fe421fdd
123 * - mv .git .gitted
124 */
125 #define EXPECT_STATUS_ADM(ADDS,DELS,MODS) { 0, ADDS, DELS, MODS, 0, 0, 0, 0, 0 }
126
127 diff_expects test_expects[] = {
128 /* a vs b tests */
129 { 5, 0, EXPECT_STATUS_ADM(3, 0, 2), 4, 0, 0, 51, 2, 46, 3 },
130 { 5, 0, EXPECT_STATUS_ADM(3, 0, 2), 4, 0, 0, 53, 4, 46, 3 },
131 { 5, 0, EXPECT_STATUS_ADM(0, 3, 2), 4, 0, 0, 52, 3, 3, 46 },
132 { 5, 0, EXPECT_STATUS_ADM(3, 0, 2), 5, 0, 0, 54, 3, 47, 4 },
133 /* c vs d tests */
134 { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 22, 9, 10, 3 },
135 { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 19, 12, 7, 0 },
136 { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 20, 11, 8, 1 },
137 { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 20, 11, 8, 1 },
138 { 1, 0, EXPECT_STATUS_ADM(0, 0, 1), 1, 0, 0, 18, 11, 0, 7 },
139 { 0 },
140 };
141 diff_expects *expected;
142 int i, j;
143
144 g_repo = cl_git_sandbox_init("attr");
145
146 cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
147 cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
148 cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL);
149 cl_assert((d = resolve_commit_oid_to_tree(g_repo, d_commit)) != NULL);
150
151 for (i = 0; test_expects[i].files > 0; i++) {
152 memset(&actual, 0, sizeof(actual)); /* clear accumulator */
153 opts = test_options[i];
154
155 if (test_ab_or_cd[i] == 0)
156 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
157 else
158 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, c, d, &opts));
159
160 cl_git_pass(git_diff_foreach(
161 diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &actual));
162
163 expected = &test_expects[i];
164 cl_assert_equal_i(actual.files, expected->files);
165 for (j = GIT_DELTA_UNMODIFIED; j <= GIT_DELTA_TYPECHANGE; ++j)
166 cl_assert_equal_i(expected->file_status[j], actual.file_status[j]);
167 cl_assert_equal_i(actual.hunks, expected->hunks);
168 cl_assert_equal_i(actual.lines, expected->lines);
169 cl_assert_equal_i(actual.line_ctxt, expected->line_ctxt);
170 cl_assert_equal_i(actual.line_adds, expected->line_adds);
171 cl_assert_equal_i(actual.line_dels, expected->line_dels);
172
173 git_diff_free(diff);
174 diff = NULL;
175 }
176
177 git_tree_free(c);
178 git_tree_free(d);
179 }
180
181 void test_diff_tree__bare(void)
182 {
183 const char *a_commit = "8496071c1b46c85";
184 const char *b_commit = "be3563ae3f79";
185
186 g_repo = cl_git_sandbox_init("testrepo.git");
187
188 cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
189 cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
190
191 opts.context_lines = 1;
192 opts.interhunk_lines = 1;
193
194 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
195
196 cl_git_pass(git_diff_foreach(
197 diff, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
198
199 cl_assert_equal_i(3, expect.files);
200 cl_assert_equal_i(2, expect.file_status[GIT_DELTA_ADDED]);
201 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_DELETED]);
202 cl_assert_equal_i(1, expect.file_status[GIT_DELTA_MODIFIED]);
203
204 cl_assert_equal_i(3, expect.hunks);
205
206 cl_assert_equal_i(4, expect.lines);
207 cl_assert_equal_i(0, expect.line_ctxt);
208 cl_assert_equal_i(3, expect.line_adds);
209 cl_assert_equal_i(1, expect.line_dels);
210 }
211
212 void test_diff_tree__merge(void)
213 {
214 /* grabbed a couple of commit oids from the history of the attr repo */
215 const char *a_commit = "605812a";
216 const char *b_commit = "370fe9ec22";
217 const char *c_commit = "f5b0af1fb4f5c";
218 git_tree *c;
219 git_diff *diff1 = NULL, *diff2 = NULL;
220
221 g_repo = cl_git_sandbox_init("attr");
222
223 cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
224 cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
225 cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL);
226
227 cl_git_pass(git_diff_tree_to_tree(&diff1, g_repo, a, b, NULL));
228
229 cl_git_pass(git_diff_tree_to_tree(&diff2, g_repo, c, b, NULL));
230
231 git_tree_free(c);
232
233 cl_git_pass(git_diff_merge(diff1, diff2));
234
235 git_diff_free(diff2);
236
237 cl_git_pass(git_diff_foreach(
238 diff1, diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
239
240 cl_assert_equal_i(6, expect.files);
241 cl_assert_equal_i(2, expect.file_status[GIT_DELTA_ADDED]);
242 cl_assert_equal_i(1, expect.file_status[GIT_DELTA_DELETED]);
243 cl_assert_equal_i(3, expect.file_status[GIT_DELTA_MODIFIED]);
244
245 cl_assert_equal_i(6, expect.hunks);
246
247 cl_assert_equal_i(59, expect.lines);
248 cl_assert_equal_i(1, expect.line_ctxt);
249 cl_assert_equal_i(36, expect.line_adds);
250 cl_assert_equal_i(22, expect.line_dels);
251
252 git_diff_free(diff1);
253 }
254
255 void test_diff_tree__larger_hunks(void)
256 {
257 const char *a_commit = "d70d245ed97ed2aa596dd1af6536e4bfdb047b69";
258 const char *b_commit = "7a9e0b02e63179929fed24f0a3e0f19168114d10";
259 size_t d, num_d, h, num_h, l, num_l;
260 git_patch *patch;
261 const git_diff_hunk *hunk;
262 const git_diff_line *line;
263
264 g_repo = cl_git_sandbox_init("diff");
265
266 cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
267 cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
268
269 opts.context_lines = 1;
270 opts.interhunk_lines = 0;
271
272 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
273
274 num_d = git_diff_num_deltas(diff);
275 for (d = 0; d < num_d; ++d) {
276 cl_git_pass(git_patch_from_diff(&patch, diff, d));
277 cl_assert(patch);
278
279 num_h = git_patch_num_hunks(patch);
280 for (h = 0; h < num_h; h++) {
281 cl_git_pass(git_patch_get_hunk(&hunk, &num_l, patch, h));
282
283 for (l = 0; l < num_l; ++l) {
284 cl_git_pass(git_patch_get_line_in_hunk(&line, patch, h, l));
285 cl_assert(line);
286 }
287
288 cl_git_fail(git_patch_get_line_in_hunk(&line, patch, h, num_l));
289 }
290
291 cl_git_fail(git_patch_get_hunk(&hunk, &num_l, patch, num_h));
292
293 git_patch_free(patch);
294 }
295
296 cl_git_fail(git_patch_from_diff(&patch, diff, num_d));
297
298 cl_assert_equal_i(2, (int)num_d);
299 }
300
301 void test_diff_tree__checks_options_version(void)
302 {
303 const char *a_commit = "8496071c1b46c85";
304 const char *b_commit = "be3563ae3f79";
305 const git_error *err;
306
307 g_repo = cl_git_sandbox_init("testrepo.git");
308
309 cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
310 cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
311
312 opts.version = 0;
313 cl_git_fail(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
314 err = git_error_last();
315 cl_assert_equal_i(GIT_ERROR_INVALID, err->klass);
316
317 git_error_clear();
318 opts.version = 1024;
319 cl_git_fail(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
320 err = git_error_last();
321 }
322
323 void process_tree_to_tree_diffing(
324 const char *old_commit,
325 const char *new_commit)
326 {
327 g_repo = cl_git_sandbox_init("unsymlinked.git");
328
329 cl_assert((a = resolve_commit_oid_to_tree(g_repo, old_commit)) != NULL);
330 cl_assert((b = resolve_commit_oid_to_tree(g_repo, new_commit)) != NULL);
331
332 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
333
334 cl_git_pass(git_diff_foreach(
335 diff, diff_file_cb, NULL, NULL, NULL, &expect));
336 }
337
338 void test_diff_tree__symlink_blob_mode_changed_to_regular_file(void)
339 {
340 /*
341 * $ git diff 7fccd7..806999
342 * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h
343 * deleted file mode 120000
344 * index 19bf568..0000000
345 * --- a/include/Nu/Nu.h
346 * +++ /dev/null
347 * @@ -1 +0,0 @@
348 * -../../objc/Nu.h
349 * \ No newline at end of file
350 * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h
351 * new file mode 100644
352 * index 0000000..f9e6561
353 * --- /dev/null
354 * +++ b/include/Nu/Nu.h
355 * @@ -0,0 +1 @@
356 * +awesome content
357 * diff --git a/objc/Nu.h b/objc/Nu.h
358 * deleted file mode 100644
359 * index f9e6561..0000000
360 * --- a/objc/Nu.h
361 * +++ /dev/null
362 * @@ -1 +0,0 @@
363 * -awesome content
364 */
365
366 process_tree_to_tree_diffing("7fccd7", "806999");
367
368 cl_assert_equal_i(3, expect.files);
369 cl_assert_equal_i(2, expect.file_status[GIT_DELTA_DELETED]);
370 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_MODIFIED]);
371 cl_assert_equal_i(1, expect.file_status[GIT_DELTA_ADDED]);
372 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]);
373 }
374
375 void test_diff_tree__symlink_blob_mode_changed_to_regular_file_as_typechange(void)
376 {
377 /*
378 * $ git diff 7fccd7..a8595c
379 * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h
380 * deleted file mode 120000
381 * index 19bf568..0000000
382 * --- a/include/Nu/Nu.h
383 * +++ /dev/null
384 * @@ -1 +0,0 @@
385 * -../../objc/Nu.h
386 * \ No newline at end of file
387 * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h
388 * new file mode 100755
389 * index 0000000..f9e6561
390 * --- /dev/null
391 * +++ b/include/Nu/Nu.h
392 * @@ -0,0 +1 @@
393 * +awesome content
394 * diff --git a/objc/Nu.h b/objc/Nu.h
395 * deleted file mode 100644
396 * index f9e6561..0000000
397 * --- a/objc/Nu.h
398 * +++ /dev/null
399 * @@ -1 +0,0 @@
400 * -awesome content
401 */
402
403 opts.flags = GIT_DIFF_INCLUDE_TYPECHANGE;
404 process_tree_to_tree_diffing("7fccd7", "a8595c");
405
406 cl_assert_equal_i(2, expect.files);
407 cl_assert_equal_i(1, expect.file_status[GIT_DELTA_DELETED]);
408 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_MODIFIED]);
409 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]);
410 cl_assert_equal_i(1, expect.file_status[GIT_DELTA_TYPECHANGE]);
411 }
412
413 void test_diff_tree__regular_blob_mode_changed_to_executable_file(void)
414 {
415 /*
416 * $ git diff 806999..a8595c
417 * diff --git a/include/Nu/Nu.h b/include/Nu/Nu.h
418 * old mode 100644
419 * new mode 100755
420 */
421
422 process_tree_to_tree_diffing("806999", "a8595c");
423
424 cl_assert_equal_i(1, expect.files);
425 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_DELETED]);
426 cl_assert_equal_i(1, expect.file_status[GIT_DELTA_MODIFIED]);
427 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]);
428 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]);
429 }
430
431 void test_diff_tree__issue_1397(void)
432 {
433 /* this test shows that it is not needed */
434
435 g_repo = cl_git_sandbox_init("issue_1397");
436
437 cl_repo_set_bool(g_repo, "core.autocrlf", true);
438
439 cl_assert((a = resolve_commit_oid_to_tree(g_repo, "8a7ef04")) != NULL);
440 cl_assert((b = resolve_commit_oid_to_tree(g_repo, "7f483a7")) != NULL);
441
442 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, &opts));
443
444 cl_git_pass(git_diff_foreach(diff,
445 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
446
447 cl_assert_equal_i(1, expect.files);
448 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_DELETED]);
449 cl_assert_equal_i(1, expect.file_status[GIT_DELTA_MODIFIED]);
450 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_ADDED]);
451 cl_assert_equal_i(0, expect.file_status[GIT_DELTA_TYPECHANGE]);
452 }
453
454 static void set_config_int(git_repository *repo, const char *name, int value)
455 {
456 git_config *cfg;
457
458 cl_git_pass(git_repository_config(&cfg, repo));
459 cl_git_pass(git_config_set_int32(cfg, name, value));
460 git_config_free(cfg);
461 }
462
463 void test_diff_tree__diff_configs(void)
464 {
465 const char *a_commit = "d70d245e";
466 const char *b_commit = "7a9e0b02";
467
468 g_repo = cl_git_sandbox_init("diff");
469
470 cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
471 cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
472
473 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
474
475 cl_git_pass(git_diff_foreach(diff,
476 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
477
478 cl_assert_equal_i(2, expect.files);
479 cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
480 cl_assert_equal_i(6, expect.hunks);
481 cl_assert_equal_i(55, expect.lines);
482 cl_assert_equal_i(33, expect.line_ctxt);
483 cl_assert_equal_i(7, expect.line_adds);
484 cl_assert_equal_i(15, expect.line_dels);
485
486 git_diff_free(diff);
487 diff = NULL;
488
489 set_config_int(g_repo, "diff.context", 1);
490
491 memset(&expect, 0, sizeof(expect));
492
493 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
494
495 cl_git_pass(git_diff_foreach(diff,
496 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
497
498 cl_assert_equal_i(2, expect.files);
499 cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
500 cl_assert_equal_i(7, expect.hunks);
501 cl_assert_equal_i(34, expect.lines);
502 cl_assert_equal_i(12, expect.line_ctxt);
503 cl_assert_equal_i(7, expect.line_adds);
504 cl_assert_equal_i(15, expect.line_dels);
505
506 git_diff_free(diff);
507 diff = NULL;
508
509 set_config_int(g_repo, "diff.context", 0);
510 set_config_int(g_repo, "diff.noprefix", 1);
511
512 memset(&expect, 0, sizeof(expect));
513
514 cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, a, b, NULL));
515
516 cl_git_pass(git_diff_foreach(diff,
517 diff_file_cb, diff_binary_cb, diff_hunk_cb, diff_line_cb, &expect));
518
519 cl_assert_equal_i(2, expect.files);
520 cl_assert_equal_i(2, expect.file_status[GIT_DELTA_MODIFIED]);
521 cl_assert_equal_i(7, expect.hunks);
522 cl_assert_equal_i(22, expect.lines);
523 cl_assert_equal_i(0, expect.line_ctxt);
524 cl_assert_equal_i(7, expect.line_adds);
525 cl_assert_equal_i(15, expect.line_dels);
526 }