]> git.proxmox.com Git - libgit2.git/blame - tests-clar/diff/workdir.c
Add has_cr_in_index check to CRLF filter
[libgit2.git] / tests-clar / diff / workdir.c
CommitLineData
74fa4bfa
RB
1#include "clar_libgit2.h"
2#include "diff_helpers.h"
c2e43fb1 3#include "repository.h"
74fa4bfa
RB
4
5static git_repository *g_repo = NULL;
6
7void test_diff_workdir__initialize(void)
8{
74fa4bfa
RB
9}
10
11void test_diff_workdir__cleanup(void)
12{
854eccbb 13 cl_git_sandbox_cleanup();
74fa4bfa
RB
14}
15
16void test_diff_workdir__to_index(void)
17{
2f8d30be 18 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
74fa4bfa
RB
19 git_diff_list *diff = NULL;
20 diff_expects exp;
f335ecd6 21 int use_iterator;
74fa4bfa 22
0abd7244
RB
23 g_repo = cl_git_sandbox_init("status");
24
74fa4bfa
RB
25 opts.context_lines = 3;
26 opts.interhunk_lines = 1;
27 opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
28
56c72b75 29 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
74fa4bfa 30
f335ecd6
RB
31 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
32 memset(&exp, 0, sizeof(exp));
33
34 if (use_iterator)
35 cl_git_pass(diff_foreach_via_iterator(
793c4385 36 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
37 else
38 cl_git_pass(git_diff_foreach(
793c4385 39 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
40
41 /* to generate these values:
42 * - cd to tests/resources/status,
43 * - mv .gitted .git
44 * - git diff --name-status
45 * - git diff
46 * - mv .git .gitted
47 */
48 cl_assert_equal_i(13, exp.files);
b4f5bb07
RB
49 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
50 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]);
51 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]);
52 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
53 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]);
f335ecd6
RB
54
55 cl_assert_equal_i(8, exp.hunks);
56
57 cl_assert_equal_i(14, exp.lines);
58 cl_assert_equal_i(5, exp.line_ctxt);
59 cl_assert_equal_i(4, exp.line_adds);
60 cl_assert_equal_i(5, exp.line_dels);
61 }
74fa4bfa
RB
62
63 git_diff_list_free(diff);
64}
65
66void test_diff_workdir__to_tree(void)
67{
68 /* grabbed a couple of commit oids from the history of the attr repo */
69 const char *a_commit = "26a125ee1bf"; /* the current HEAD */
70 const char *b_commit = "0017bd4ab1ec3"; /* the start */
0abd7244 71 git_tree *a, *b;
2f8d30be 72 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
74fa4bfa
RB
73 git_diff_list *diff = NULL;
74 git_diff_list *diff2 = NULL;
75 diff_expects exp;
f335ecd6 76 int use_iterator;
74fa4bfa 77
0abd7244
RB
78 g_repo = cl_git_sandbox_init("status");
79
80 a = resolve_commit_oid_to_tree(g_repo, a_commit);
81 b = resolve_commit_oid_to_tree(g_repo, b_commit);
82
74fa4bfa
RB
83 opts.context_lines = 3;
84 opts.interhunk_lines = 1;
85 opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
86
56c72b75 87 /* You can't really generate the equivalent of git_diff_tree_to_workdir()
74fa4bfa
RB
88 * using C git. It really wants to interpose the index into the diff.
89 *
90 * To validate the following results with command line git, I ran the
91 * following:
92 * - git ls-tree 26a125
93 * - find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
94 * The results are documented at the bottom of this file in the
95 * long comment entitled "PREPARATION OF TEST DATA".
96 */
56c72b75 97 cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts));
74fa4bfa 98
f335ecd6
RB
99 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
100 memset(&exp, 0, sizeof(exp));
74fa4bfa 101
f335ecd6
RB
102 if (use_iterator)
103 cl_git_pass(diff_foreach_via_iterator(
793c4385 104 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
105 else
106 cl_git_pass(git_diff_foreach(
793c4385 107 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
108
109 cl_assert_equal_i(14, exp.files);
b4f5bb07
RB
110 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
111 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]);
112 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]);
113 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
114 cl_assert_equal_i(5, exp.file_status[GIT_DELTA_UNTRACKED]);
f335ecd6 115 }
74fa4bfa
RB
116
117 /* Since there is no git diff equivalent, let's just assume that the
118 * text diffs produced by git_diff_foreach are accurate here. We will
119 * do more apples-to-apples test comparison below.
120 */
121
122 git_diff_list_free(diff);
123 diff = NULL;
124 memset(&exp, 0, sizeof(exp));
125
126 /* This is a compatible emulation of "git diff <sha>" which looks like
127 * a workdir to tree diff (even though it is not really). This is what
128 * you would get from "git diff --name-status 26a125ee1bf"
129 */
56c72b75
RB
130 cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts));
131 cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts));
74fa4bfa
RB
132 cl_git_pass(git_diff_merge(diff, diff2));
133 git_diff_list_free(diff2);
134
f335ecd6
RB
135 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
136 memset(&exp, 0, sizeof(exp));
137
138 if (use_iterator)
139 cl_git_pass(diff_foreach_via_iterator(
793c4385 140 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
141 else
142 cl_git_pass(git_diff_foreach(
793c4385 143 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
74fa4bfa 144
f335ecd6 145 cl_assert_equal_i(15, exp.files);
b4f5bb07
RB
146 cl_assert_equal_i(2, exp.file_status[GIT_DELTA_ADDED]);
147 cl_assert_equal_i(5, exp.file_status[GIT_DELTA_DELETED]);
148 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]);
149 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
150 cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]);
74fa4bfa 151
f335ecd6 152 cl_assert_equal_i(11, exp.hunks);
74fa4bfa 153
f335ecd6
RB
154 cl_assert_equal_i(17, exp.lines);
155 cl_assert_equal_i(4, exp.line_ctxt);
156 cl_assert_equal_i(8, exp.line_adds);
157 cl_assert_equal_i(5, exp.line_dels);
158 }
74fa4bfa
RB
159
160 git_diff_list_free(diff);
161 diff = NULL;
162 memset(&exp, 0, sizeof(exp));
163
164 /* Again, emulating "git diff <sha>" for testing purposes using
165 * "git diff --name-status 0017bd4ab1ec3" instead.
166 */
56c72b75
RB
167 cl_git_pass(git_diff_tree_to_index(&diff, g_repo, b, NULL, &opts));
168 cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts));
74fa4bfa
RB
169 cl_git_pass(git_diff_merge(diff, diff2));
170 git_diff_list_free(diff2);
171
f335ecd6
RB
172 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
173 memset(&exp, 0, sizeof(exp));
74fa4bfa 174
f335ecd6
RB
175 if (use_iterator)
176 cl_git_pass(diff_foreach_via_iterator(
793c4385 177 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
178 else
179 cl_git_pass(git_diff_foreach(
793c4385 180 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
74fa4bfa 181
f335ecd6 182 cl_assert_equal_i(16, exp.files);
b4f5bb07
RB
183 cl_assert_equal_i(5, exp.file_status[GIT_DELTA_ADDED]);
184 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]);
185 cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]);
186 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
187 cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]);
74fa4bfa 188
f335ecd6
RB
189 cl_assert_equal_i(12, exp.hunks);
190
191 cl_assert_equal_i(19, exp.lines);
192 cl_assert_equal_i(3, exp.line_ctxt);
193 cl_assert_equal_i(12, exp.line_adds);
194 cl_assert_equal_i(4, exp.line_dels);
195 }
74fa4bfa 196
c19bc93c
RB
197 git_diff_list_free(diff);
198
74fa4bfa
RB
199 git_tree_free(a);
200 git_tree_free(b);
201}
202
14a513e0
RB
203void test_diff_workdir__to_index_with_pathspec(void)
204{
2f8d30be 205 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
14a513e0
RB
206 git_diff_list *diff = NULL;
207 diff_expects exp;
208 char *pathspec = NULL;
f335ecd6 209 int use_iterator;
14a513e0 210
0abd7244
RB
211 g_repo = cl_git_sandbox_init("status");
212
14a513e0
RB
213 opts.context_lines = 3;
214 opts.interhunk_lines = 1;
215 opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
216 opts.pathspec.strings = &pathspec;
217 opts.pathspec.count = 1;
218
56c72b75 219 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
14a513e0 220
f335ecd6
RB
221 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
222 memset(&exp, 0, sizeof(exp));
223
224 if (use_iterator)
225 cl_git_pass(diff_foreach_via_iterator(
793c4385 226 diff, diff_file_cb, NULL, NULL, &exp));
f335ecd6 227 else
793c4385 228 cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
f335ecd6
RB
229
230 cl_assert_equal_i(13, exp.files);
b4f5bb07
RB
231 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
232 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]);
233 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]);
234 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]);
235 cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]);
f335ecd6 236 }
14a513e0
RB
237
238 git_diff_list_free(diff);
239
14a513e0
RB
240 pathspec = "modified_file";
241
56c72b75 242 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
14a513e0 243
f335ecd6
RB
244 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
245 memset(&exp, 0, sizeof(exp));
246
247 if (use_iterator)
248 cl_git_pass(diff_foreach_via_iterator(
793c4385 249 diff, diff_file_cb, NULL, NULL, &exp));
f335ecd6 250 else
793c4385 251 cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
f335ecd6
RB
252
253 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
254 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
255 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
256 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
257 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
258 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_UNTRACKED]);
f335ecd6 259 }
14a513e0
RB
260
261 git_diff_list_free(diff);
262
14a513e0
RB
263 pathspec = "subdir";
264
56c72b75 265 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
14a513e0 266
f335ecd6
RB
267 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
268 memset(&exp, 0, sizeof(exp));
269
270 if (use_iterator)
271 cl_git_pass(diff_foreach_via_iterator(
793c4385 272 diff, diff_file_cb, NULL, NULL, &exp));
f335ecd6 273 else
793c4385 274 cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
f335ecd6
RB
275
276 cl_assert_equal_i(3, exp.files);
b4f5bb07
RB
277 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
278 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]);
279 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
280 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
281 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]);
f335ecd6 282 }
14a513e0
RB
283
284 git_diff_list_free(diff);
285
14a513e0
RB
286 pathspec = "*_deleted";
287
56c72b75 288 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
14a513e0 289
f335ecd6
RB
290 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
291 memset(&exp, 0, sizeof(exp));
292
293 if (use_iterator)
294 cl_git_pass(diff_foreach_via_iterator(
793c4385 295 diff, diff_file_cb, NULL, NULL, &exp));
f335ecd6 296 else
793c4385 297 cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
f335ecd6
RB
298
299 cl_assert_equal_i(2, exp.files);
b4f5bb07
RB
300 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
301 cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]);
302 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
303 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
304 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_UNTRACKED]);
f335ecd6 305 }
14a513e0
RB
306
307 git_diff_list_free(diff);
308}
309
0d64ba48 310static int assert_called_notifications(
311 const git_diff_list *diff_so_far,
312 const git_diff_delta *delta_to_add,
313 const char *matched_pathspec,
314 void *payload)
315{
316 bool found = false;
317 notify_expected *exp = (notify_expected*)payload;
318 notify_expected *e;;
319
320 GIT_UNUSED(diff_so_far);
321
322 for (e = exp; e->path != NULL; e++) {
323 if (strcmp(e->path, delta_to_add->new_file.path))
324 continue;
325
326 cl_assert_equal_s(e->matched_pathspec, matched_pathspec);
327
328 found = true;
329 break;
330 }
331
332 cl_assert(found);
333 return 0;
334}
335
336void test_diff_workdir__to_index_notify(void)
337{
338 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
339 git_diff_list *diff = NULL;
340 diff_expects exp;
341
342 char *searched_pathspecs_solo[] = {
343 "*_deleted",
344 };
345 notify_expected expected_matched_pathspecs_solo[] = {
346 { "file_deleted", "*_deleted" },
347 { "staged_changes_file_deleted", "*_deleted" },
348 { NULL, NULL }
349 };
350
351 char *searched_pathspecs_multiple[] = {
352 "staged_changes_cant_find_me",
353 "subdir/modified_cant_find_me",
354 "subdir/*",
355 "staged*"
356 };
357 notify_expected expected_matched_pathspecs_multiple[] = {
358 { "staged_changes_file_deleted", "staged*" },
359 { "staged_changes_modified_file", "staged*" },
360 { "staged_delete_modified_file", "staged*" },
361 { "staged_new_file_deleted_file", "staged*" },
362 { "staged_new_file_modified_file", "staged*" },
363 { "subdir/deleted_file", "subdir/*" },
364 { "subdir/modified_file", "subdir/*" },
365 { "subdir/new_file", "subdir/*" },
366 { NULL, NULL }
367 };
368
369 g_repo = cl_git_sandbox_init("status");
370
371 opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
372 opts.notify_cb = assert_called_notifications;
373 opts.pathspec.strings = searched_pathspecs_solo;
374 opts.pathspec.count = 1;
375
376 opts.notify_payload = &expected_matched_pathspecs_solo;
377 memset(&exp, 0, sizeof(exp));
378
379 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
380 cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
381
382 cl_assert_equal_i(2, exp.files);
383
384 git_diff_list_free(diff);
385
386 opts.pathspec.strings = searched_pathspecs_multiple;
387 opts.pathspec.count = 4;
388 opts.notify_payload = &expected_matched_pathspecs_multiple;
389 memset(&exp, 0, sizeof(exp));
390
391 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
392 cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
393
394 cl_assert_equal_i(8, exp.files);
395
396 git_diff_list_free(diff);
397}
398
399static int abort_diff(
400 const git_diff_list *diff_so_far,
401 const git_diff_delta *delta_to_add,
402 const char *matched_pathspec,
403 void *payload)
404{
405 GIT_UNUSED(diff_so_far);
406 GIT_UNUSED(delta_to_add);
407 GIT_UNUSED(matched_pathspec);
408 GIT_UNUSED(payload);
409
410 return -42;
411}
412
413void test_diff_workdir__to_index_notify_can_be_aborted_by_callback(void)
414{
415 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
416 git_diff_list *diff = NULL;
417 char *pathspec = NULL;
418
419 g_repo = cl_git_sandbox_init("status");
420
421 opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
422 opts.notify_cb = abort_diff;
423 opts.pathspec.strings = &pathspec;
424 opts.pathspec.count = 1;
425
426 pathspec = "file_deleted";
427 cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
428
429 pathspec = "staged_changes_modified_file";
430 cl_git_fail(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
431}
432
433static int filter_all(
434 const git_diff_list *diff_so_far,
435 const git_diff_delta *delta_to_add,
436 const char *matched_pathspec,
437 void *payload)
438{
439 GIT_UNUSED(diff_so_far);
440 GIT_UNUSED(delta_to_add);
441 GIT_UNUSED(matched_pathspec);
442 GIT_UNUSED(payload);
443
444 return 42;
445}
446
447void test_diff_workdir__to_index_notify_can_be_used_as_filtering_function(void)
448{
449 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
450 git_diff_list *diff = NULL;
451 char *pathspec = NULL;
452 diff_expects exp;
453
454 g_repo = cl_git_sandbox_init("status");
455
456 opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
457 opts.notify_cb = filter_all;
458 opts.pathspec.strings = &pathspec;
459 opts.pathspec.count = 1;
460
461 pathspec = "*_deleted";
462 memset(&exp, 0, sizeof(exp));
463
464 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
465 cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp));
466
467 cl_assert_equal_i(0, exp.files);
468
469 git_diff_list_free(diff);
470}
471
472
0abd7244
RB
473void test_diff_workdir__filemode_changes(void)
474{
0abd7244
RB
475 git_diff_list *diff = NULL;
476 diff_expects exp;
f335ecd6 477 int use_iterator;
0abd7244
RB
478
479 if (!cl_is_chmod_supported())
480 return;
481
482 g_repo = cl_git_sandbox_init("issue_592");
483
1323c6d1 484 cl_repo_set_bool(g_repo, "core.filemode", true);
0abd7244
RB
485
486 /* test once with no mods */
487
56c72b75 488 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL));
0abd7244 489
f335ecd6
RB
490 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
491 memset(&exp, 0, sizeof(exp));
0abd7244 492
f335ecd6
RB
493 if (use_iterator)
494 cl_git_pass(diff_foreach_via_iterator(
793c4385 495 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
496 else
497 cl_git_pass(git_diff_foreach(
793c4385 498 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
499
500 cl_assert_equal_i(0, exp.files);
b4f5bb07 501 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
502 cl_assert_equal_i(0, exp.hunks);
503 }
0abd7244
RB
504
505 git_diff_list_free(diff);
506
507 /* chmod file and test again */
508
509 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
510
56c72b75 511 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL));
0abd7244 512
f335ecd6
RB
513 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
514 memset(&exp, 0, sizeof(exp));
0abd7244 515
f335ecd6
RB
516 if (use_iterator)
517 cl_git_pass(diff_foreach_via_iterator(
793c4385 518 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
519 else
520 cl_git_pass(git_diff_foreach(
793c4385 521 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
522
523 cl_assert_equal_i(1, exp.files);
b4f5bb07 524 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
525 cl_assert_equal_i(0, exp.hunks);
526 }
0abd7244
RB
527
528 git_diff_list_free(diff);
529
530 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
0abd7244
RB
531}
532
533void test_diff_workdir__filemode_changes_with_filemode_false(void)
534{
0abd7244
RB
535 git_diff_list *diff = NULL;
536 diff_expects exp;
537
538 if (!cl_is_chmod_supported())
539 return;
540
541 g_repo = cl_git_sandbox_init("issue_592");
542
1323c6d1 543 cl_repo_set_bool(g_repo, "core.filemode", false);
0abd7244
RB
544
545 /* test once with no mods */
546
56c72b75 547 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL));
0abd7244
RB
548
549 memset(&exp, 0, sizeof(exp));
550 cl_git_pass(git_diff_foreach(
793c4385 551 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
0abd7244
RB
552
553 cl_assert_equal_i(0, exp.files);
b4f5bb07 554 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
0abd7244
RB
555 cl_assert_equal_i(0, exp.hunks);
556
557 git_diff_list_free(diff);
558
559 /* chmod file and test again */
560
561 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
562
56c72b75 563 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL));
0abd7244
RB
564
565 memset(&exp, 0, sizeof(exp));
566 cl_git_pass(git_diff_foreach(
793c4385 567 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
0abd7244
RB
568
569 cl_assert_equal_i(0, exp.files);
b4f5bb07 570 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
0abd7244
RB
571 cl_assert_equal_i(0, exp.hunks);
572
573 git_diff_list_free(diff);
574
575 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
0abd7244
RB
576}
577
145e696b
RB
578void test_diff_workdir__head_index_and_workdir_all_differ(void)
579{
2f8d30be 580 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
145e696b
RB
581 git_diff_list *diff_i2t = NULL, *diff_w2i = NULL;
582 diff_expects exp;
583 char *pathspec = "staged_changes_modified_file";
584 git_tree *tree;
f335ecd6 585 int use_iterator;
145e696b
RB
586
587 /* For this file,
588 * - head->index diff has 1 line of context, 1 line of diff
589 * - index->workdir diff has 2 lines of context, 1 line of diff
590 * but
591 * - head->workdir diff has 1 line of context, 2 lines of diff
592 * Let's make sure the right one is returned from each fn.
593 */
594
595 g_repo = cl_git_sandbox_init("status");
596
597 tree = resolve_commit_oid_to_tree(g_repo, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f");
598
599 opts.pathspec.strings = &pathspec;
600 opts.pathspec.count = 1;
601
56c72b75
RB
602 cl_git_pass(git_diff_tree_to_index(&diff_i2t, g_repo, tree, NULL, &opts));
603 cl_git_pass(git_diff_index_to_workdir(&diff_w2i, g_repo, NULL, &opts));
145e696b 604
f335ecd6
RB
605 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
606 memset(&exp, 0, sizeof(exp));
607
608 if (use_iterator)
609 cl_git_pass(diff_foreach_via_iterator(
793c4385 610 diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
611 else
612 cl_git_pass(git_diff_foreach(
793c4385 613 diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
614
615 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
616 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
617 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
618 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
619 cl_assert_equal_i(1, exp.hunks);
620 cl_assert_equal_i(2, exp.lines);
621 cl_assert_equal_i(1, exp.line_ctxt);
622 cl_assert_equal_i(1, exp.line_adds);
623 cl_assert_equal_i(0, exp.line_dels);
624 }
625
626 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
627 memset(&exp, 0, sizeof(exp));
628
629 if (use_iterator)
630 cl_git_pass(diff_foreach_via_iterator(
793c4385 631 diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
632 else
633 cl_git_pass(git_diff_foreach(
793c4385 634 diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
635
636 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
637 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
638 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
639 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
640 cl_assert_equal_i(1, exp.hunks);
641 cl_assert_equal_i(3, exp.lines);
642 cl_assert_equal_i(2, exp.line_ctxt);
643 cl_assert_equal_i(1, exp.line_adds);
644 cl_assert_equal_i(0, exp.line_dels);
645 }
145e696b
RB
646
647 cl_git_pass(git_diff_merge(diff_i2t, diff_w2i));
648
f335ecd6
RB
649 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
650 memset(&exp, 0, sizeof(exp));
651
652 if (use_iterator)
653 cl_git_pass(diff_foreach_via_iterator(
793c4385 654 diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
655 else
656 cl_git_pass(git_diff_foreach(
793c4385 657 diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
658
659 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
660 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
661 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
662 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
663 cl_assert_equal_i(1, exp.hunks);
664 cl_assert_equal_i(3, exp.lines);
665 cl_assert_equal_i(1, exp.line_ctxt);
666 cl_assert_equal_i(2, exp.line_adds);
667 cl_assert_equal_i(0, exp.line_dels);
668 }
145e696b
RB
669
670 git_diff_list_free(diff_i2t);
671 git_diff_list_free(diff_w2i);
cdca82c7
CMN
672
673 git_tree_free(tree);
145e696b
RB
674}
675
676void test_diff_workdir__eof_newline_changes(void)
677{
2f8d30be 678 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
145e696b
RB
679 git_diff_list *diff = NULL;
680 diff_expects exp;
681 char *pathspec = "current_file";
f335ecd6 682 int use_iterator;
145e696b
RB
683
684 g_repo = cl_git_sandbox_init("status");
685
686 opts.pathspec.strings = &pathspec;
687 opts.pathspec.count = 1;
688
56c72b75 689 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
145e696b 690
f335ecd6
RB
691 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
692 memset(&exp, 0, sizeof(exp));
693
694 if (use_iterator)
695 cl_git_pass(diff_foreach_via_iterator(
793c4385 696 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
697 else
698 cl_git_pass(git_diff_foreach(
793c4385 699 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
700
701 cl_assert_equal_i(0, exp.files);
b4f5bb07
RB
702 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
703 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
704 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
705 cl_assert_equal_i(0, exp.hunks);
706 cl_assert_equal_i(0, exp.lines);
707 cl_assert_equal_i(0, exp.line_ctxt);
708 cl_assert_equal_i(0, exp.line_adds);
709 cl_assert_equal_i(0, exp.line_dels);
710 }
145e696b
RB
711
712 git_diff_list_free(diff);
713
714 cl_git_append2file("status/current_file", "\n");
715
56c72b75 716 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
145e696b 717
f335ecd6
RB
718 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
719 memset(&exp, 0, sizeof(exp));
720
721 if (use_iterator)
722 cl_git_pass(diff_foreach_via_iterator(
793c4385 723 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
724 else
725 cl_git_pass(git_diff_foreach(
793c4385 726 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
727
728 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
729 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
730 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
731 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
732 cl_assert_equal_i(1, exp.hunks);
733 cl_assert_equal_i(2, exp.lines);
734 cl_assert_equal_i(1, exp.line_ctxt);
735 cl_assert_equal_i(1, exp.line_adds);
736 cl_assert_equal_i(0, exp.line_dels);
737 }
145e696b
RB
738
739 git_diff_list_free(diff);
740
741 cl_git_rewritefile("status/current_file", "current_file");
742
56c72b75 743 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
145e696b 744
f335ecd6
RB
745 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
746 memset(&exp, 0, sizeof(exp));
747
748 if (use_iterator)
749 cl_git_pass(diff_foreach_via_iterator(
793c4385 750 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
751 else
752 cl_git_pass(git_diff_foreach(
793c4385 753 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
754
755 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
756 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
757 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
758 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
759 cl_assert_equal_i(1, exp.hunks);
760 cl_assert_equal_i(3, exp.lines);
761 cl_assert_equal_i(0, exp.line_ctxt);
762 cl_assert_equal_i(1, exp.line_adds);
763 cl_assert_equal_i(2, exp.line_dels);
764 }
145e696b
RB
765
766 git_diff_list_free(diff);
767}
768
74fa4bfa
RB
769/* PREPARATION OF TEST DATA
770 *
56c72b75 771 * Since there is no command line equivalent of git_diff_tree_to_workdir,
74fa4bfa
RB
772 * it was a bit of a pain to confirm that I was getting the expected
773 * results in the first part of this tests. Here is what I ended up
774 * doing to set my expectation for the file counts and results:
775 *
776 * Running "git ls-tree 26a125" and "git ls-tree aa27a6" shows:
777 *
778 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
779 * B 5452d32f1dd538eb0405e8a83cc185f79e25e80f file_deleted
780 * C 452e4244b5d083ddf0460acf1ecc74db9dcfa11a modified_file
781 * D 32504b727382542f9f089e24fddac5e78533e96c staged_changes
782 * E 061d42a44cacde5726057b67558821d95db96f19 staged_changes_file_deleted
783 * F 70bd9443ada07063e7fbf0b3ff5c13f7494d89c2 staged_changes_modified_file
784 * G e9b9107f290627c04d097733a10055af941f6bca staged_delete_file_deleted
785 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
786 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
787 * J 1888c805345ba265b0ee9449b8877b6064592058 subdir/deleted_file
788 * K a6191982709b746d5650e93c2acf34ef74e11504 subdir/modified_file
789 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
790 *
791 * --------
792 *
793 * find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
794 *
795 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
796 * M 6a79f808a9c6bc9531ac726c184bbcd9351ccf11 ignored_file
797 * C 0a539630525aca2e7bc84975958f92f10a64c9b6 modified_file
798 * N d4fa8600b4f37d7516bef4816ae2c64dbf029e3a new_file
799 * D 55d316c9ba708999f1918e9677d01dfcae69c6b9 staged_changes
800 * F 011c3440d5c596e21d836aa6d7b10eb581f68c49 staged_changes_modified_file
801 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
802 * O 529a16e8e762d4acb7b9636ff540a00831f9155a staged_new_file
803 * P 8b090c06d14ffa09c4e880088ebad33893f921d1 staged_new_file_modified_file
804 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
805 * K 57274b75eeb5f36fd55527806d567b2240a20c57 subdir/modified_file
806 * Q 80a86a6931b91bc01c2dbf5ca55bdd24ad1ef466 subdir/new_file
807 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
808 *
809 * --------
810 *
811 * A - current_file (UNMODIFIED) -> not in results
812 * B D file_deleted
813 * M I ignored_file (IGNORED)
814 * C M modified_file
815 * N U new_file (UNTRACKED)
816 * D M staged_changes
817 * E D staged_changes_file_deleted
818 * F M staged_changes_modified_file
819 * G D staged_delete_file_deleted
820 * H - staged_delete_modified_file (UNMODIFIED) -> not in results
821 * O U staged_new_file
822 * P U staged_new_file_modified_file
823 * I - subdir/current_file (UNMODIFIED) -> not in results
824 * J D subdir/deleted_file
825 * K M subdir/modified_file
826 * Q U subdir/new_file
827 * L - subdir.txt (UNMODIFIED) -> not in results
828 *
829 * Expect 13 files, 0 ADD, 4 DEL, 4 MOD, 1 IGN, 4 UNTR
830 */
49d34c1c
RB
831
832
833void test_diff_workdir__larger_hunks(void)
834{
835 const char *a_commit = "d70d245ed97ed2aa596dd1af6536e4bfdb047b69";
836 const char *b_commit = "7a9e0b02e63179929fed24f0a3e0f19168114d10";
837 git_tree *a, *b;
2f8d30be 838 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
5f69a31f 839 size_t i, d, num_d, h, num_h, l, num_l, header_len, line_len;
49d34c1c
RB
840
841 g_repo = cl_git_sandbox_init("diff");
842
843 cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
844 cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
845
846 opts.context_lines = 1;
847 opts.interhunk_lines = 0;
848
849 for (i = 0; i <= 2; ++i) {
850 git_diff_list *diff = NULL;
5f69a31f 851 git_diff_patch *patch;
bae957b9 852 const git_diff_range *range;
5f69a31f
RB
853 const char *header, *line;
854 char origin;
49d34c1c
RB
855
856 /* okay, this is a bit silly, but oh well */
857 switch (i) {
858 case 0:
56c72b75 859 cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
49d34c1c
RB
860 break;
861 case 1:
56c72b75 862 cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts));
49d34c1c
RB
863 break;
864 case 2:
56c72b75 865 cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, b, &opts));
49d34c1c
RB
866 break;
867 }
868
5f69a31f
RB
869 num_d = git_diff_num_deltas(diff);
870 cl_assert_equal_i(2, (int)num_d);
49d34c1c 871
5f69a31f
RB
872 for (d = 0; d < num_d; ++d) {
873 cl_git_pass(git_diff_get_patch(&patch, NULL, diff, d));
874 cl_assert(patch);
49d34c1c 875
5f69a31f
RB
876 num_h = git_diff_patch_num_hunks(patch);
877 for (h = 0; h < num_h; h++) {
878 cl_git_pass(git_diff_patch_get_hunk(
879 &range, &header, &header_len, &num_l, patch, h));
49d34c1c 880
5f69a31f
RB
881 for (l = 0; l < num_l; ++l) {
882 cl_git_pass(git_diff_patch_get_line_in_hunk(
883 &origin, &line, &line_len, NULL, NULL, patch, h, l));
884 cl_assert(line);
49d34c1c
RB
885 }
886
5f69a31f
RB
887 /* confirm fail after the last item */
888 cl_git_fail(git_diff_patch_get_line_in_hunk(
889 &origin, &line, &line_len, NULL, NULL, patch, h, num_l));
49d34c1c
RB
890 }
891
5f69a31f
RB
892 /* confirm fail after the last item */
893 cl_git_fail(git_diff_patch_get_hunk(
894 &range, &header, &header_len, &num_l, patch, num_h));
49d34c1c 895
5f69a31f
RB
896 git_diff_patch_free(patch);
897 }
49d34c1c 898
49d34c1c
RB
899 git_diff_list_free(diff);
900 }
901
902 git_tree_free(a);
903 git_tree_free(b);
904}
5d1308f2
RB
905
906/* Set up a test that exercises this code. The easiest test using existing
907 * test data is probably to create a sandbox of submod2 and then run a
56c72b75 908 * git_diff_tree_to_workdir against tree
5d1308f2
RB
909 * 873585b94bdeabccea991ea5e3ec1a277895b698. As for what you should actually
910 * test, you can start by just checking that the number of lines of diff
911 * content matches the actual output of git diff. That will at least
912 * demonstrate that the submodule content is being used to generate somewhat
913 * comparable outputs. It is a test that would fail without this code and
914 * will succeed with it.
915 */
916
917#include "../submodule/submodule_helpers.h"
918
919void test_diff_workdir__submodules(void)
920{
921 const char *a_commit = "873585b94bdeabccea991ea5e3ec1a277895b698";
922 git_tree *a;
2f8d30be 923 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
5d1308f2
RB
924 git_diff_list *diff = NULL;
925 diff_expects exp;
926
927 g_repo = cl_git_sandbox_init("submod2");
928
929 cl_fixture_sandbox("submod2_target");
930 p_rename("submod2_target/.gitted", "submod2_target/.git");
931
932 rewrite_gitmodules(git_repository_workdir(g_repo));
65025cb8
RB
933 p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git");
934 p_rename("submod2/not/.gitted", "submod2/not/.git");
5d1308f2
RB
935
936 cl_fixture_cleanup("submod2_target");
937
938 a = resolve_commit_oid_to_tree(g_repo, a_commit);
939
940 opts.flags =
941 GIT_DIFF_INCLUDE_UNTRACKED |
942 GIT_DIFF_RECURSE_UNTRACKED_DIRS |
943 GIT_DIFF_INCLUDE_UNTRACKED_CONTENT;
944
56c72b75 945 cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts));
5d1308f2
RB
946
947 /* diff_print(stderr, diff); */
948
949 /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */
950
951 memset(&exp, 0, sizeof(exp));
65025cb8 952
5d1308f2 953 cl_git_pass(git_diff_foreach(
793c4385 954 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
5d1308f2 955
65025cb8
RB
956 /* the following differs from "git diff 873585" by two "untracked" file
957 * because the diff list includes the "not" and "not-submodule" dirs which
958 * are not displayed in the text diff.
5d1308f2
RB
959 */
960
65025cb8 961 cl_assert_equal_i(11, exp.files);
5d1308f2 962
b4f5bb07
RB
963 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
964 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
965 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
966 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
65025cb8 967 cl_assert_equal_i(10, exp.file_status[GIT_DELTA_UNTRACKED]);
5d1308f2
RB
968
969 /* the following numbers match "git diff 873585" exactly */
970
971 cl_assert_equal_i(9, exp.hunks);
972
973 cl_assert_equal_i(33, exp.lines);
974 cl_assert_equal_i(2, exp.line_ctxt);
975 cl_assert_equal_i(30, exp.line_adds);
976 cl_assert_equal_i(1, exp.line_dels);
977
978 git_diff_list_free(diff);
979 git_tree_free(a);
980}
c2e43fb1 981
982void test_diff_workdir__cannot_diff_against_a_bare_repository(void)
983{
2f8d30be 984 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
c2e43fb1 985 git_diff_list *diff = NULL;
986 git_tree *tree;
987
988 g_repo = cl_git_sandbox_init("testrepo.git");
989
5735bf5e 990 cl_assert_equal_i(
56c72b75 991 GIT_EBAREREPO, git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
c2e43fb1 992
993 cl_git_pass(git_repository_head_tree(&tree, g_repo));
5735bf5e
RB
994
995 cl_assert_equal_i(
56c72b75 996 GIT_EBAREREPO, git_diff_tree_to_workdir(&diff, g_repo, tree, &opts));
c2e43fb1 997
998 git_tree_free(tree);
999}
59a0d772 1000
1001void test_diff_workdir__to_null_tree(void)
1002{
1003 git_diff_list *diff;
1004 diff_expects exp;
2f8d30be 1005 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
59a0d772 1006
1007 opts.flags = GIT_DIFF_INCLUDE_UNTRACKED |
1008 GIT_DIFF_RECURSE_UNTRACKED_DIRS;
1009
1010 g_repo = cl_git_sandbox_init("status");
1011
56c72b75 1012 cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts));
59a0d772 1013
1014 memset(&exp, 0, sizeof(exp));
1015
1016 cl_git_pass(git_diff_foreach(
1017 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
1018
1019 cl_assert_equal_i(exp.files, exp.file_status[GIT_DELTA_UNTRACKED]);
1020
1021 git_diff_list_free(diff);
1022}
2f8d30be
BS
1023
1024void test_diff_workdir__checks_options_version(void)
1025{
1026 git_diff_list *diff;
1027 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
1028 const git_error *err;
1029
1030 g_repo = cl_git_sandbox_init("status");
1031
1032 opts.version = 0;
56c72b75 1033 cl_git_fail(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts));
2f8d30be
BS
1034 err = giterr_last();
1035 cl_assert_equal_i(GITERR_INVALID, err->klass);
1036
1037 giterr_clear();
1038 opts.version = 1024;
56c72b75 1039 cl_git_fail(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts));
2f8d30be
BS
1040 err = giterr_last();
1041 cl_assert_equal_i(GITERR_INVALID, err->klass);
1042}
de590550
RB
1043
1044void test_diff_workdir__can_diff_empty_file(void)
1045{
1046 git_diff_list *diff;
1047 git_tree *tree;
1048 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
1049 struct stat st;
1050 git_diff_patch *patch;
1051
1052 g_repo = cl_git_sandbox_init("attr_index");
1053
1054 tree = resolve_commit_oid_to_tree(g_repo, "3812cfef3661"); /* HEAD */
1055
1056 /* baseline - make sure there are no outstanding diffs */
1057
1058 cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts));
2086e1ba 1059 git_tree_free(tree);
de590550
RB
1060 cl_assert_equal_i(2, (int)git_diff_num_deltas(diff));
1061 git_diff_list_free(diff);
1062
1063 /* empty contents of file */
1064
1065 cl_git_rewritefile("attr_index/README.txt", "");
1066 cl_git_pass(git_path_lstat("attr_index/README.txt", &st));
1067 cl_assert_equal_i(0, (int)st.st_size);
1068
1069 cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts));
1070 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff));
1071 /* diffs are: .gitattributes, README.txt, sub/sub/.gitattributes */
1072 cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 1));
1073 git_diff_patch_free(patch);
1074 git_diff_list_free(diff);
1075
1076 /* remove a file altogether */
1077
1078 cl_git_pass(p_unlink("attr_index/README.txt"));
1079 cl_assert(!git_path_exists("attr_index/README.txt"));
1080
1081 cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts));
1082 cl_assert_equal_i(3, (int)git_diff_num_deltas(diff));
1083 cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 1));
1084 git_diff_patch_free(patch);
1085 git_diff_list_free(diff);
1086}