]> git.proxmox.com Git - libgit2.git/blame - tests-clar/diff/workdir.c
Merge pull request #1148 from scunz/test_fix
[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
bbe6dbec 29 cl_git_pass(git_diff_workdir_to_index(&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
74fa4bfa
RB
87 /* You can't really generate the equivalent of git_diff_workdir_to_tree()
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 */
5735bf5e 97 cl_git_pass(git_diff_workdir_to_tree(&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 */
bbe6dbec
RB
130 cl_git_pass(git_diff_index_to_tree(&diff, g_repo, a, NULL, &opts));
131 cl_git_pass(git_diff_workdir_to_index(&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 */
bbe6dbec
RB
167 cl_git_pass(git_diff_index_to_tree(&diff, g_repo, b, NULL, &opts));
168 cl_git_pass(git_diff_workdir_to_index(&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
bbe6dbec 219 cl_git_pass(git_diff_workdir_to_index(&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
bbe6dbec 242 cl_git_pass(git_diff_workdir_to_index(&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
bbe6dbec 265 cl_git_pass(git_diff_workdir_to_index(&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
bbe6dbec 288 cl_git_pass(git_diff_workdir_to_index(&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
0abd7244
RB
310void test_diff_workdir__filemode_changes(void)
311{
312 git_config *cfg;
313 git_diff_list *diff = NULL;
314 diff_expects exp;
f335ecd6 315 int use_iterator;
0abd7244
RB
316
317 if (!cl_is_chmod_supported())
318 return;
319
320 g_repo = cl_git_sandbox_init("issue_592");
321
322 cl_git_pass(git_repository_config(&cfg, g_repo));
323 cl_git_pass(git_config_set_bool(cfg, "core.filemode", true));
324
325 /* test once with no mods */
326
bbe6dbec 327 cl_git_pass(git_diff_workdir_to_index(&diff, g_repo, NULL, NULL));
0abd7244 328
f335ecd6
RB
329 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
330 memset(&exp, 0, sizeof(exp));
0abd7244 331
f335ecd6
RB
332 if (use_iterator)
333 cl_git_pass(diff_foreach_via_iterator(
793c4385 334 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
335 else
336 cl_git_pass(git_diff_foreach(
793c4385 337 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
338
339 cl_assert_equal_i(0, exp.files);
b4f5bb07 340 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
341 cl_assert_equal_i(0, exp.hunks);
342 }
0abd7244
RB
343
344 git_diff_list_free(diff);
345
346 /* chmod file and test again */
347
348 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
349
bbe6dbec 350 cl_git_pass(git_diff_workdir_to_index(&diff, g_repo, NULL, NULL));
0abd7244 351
f335ecd6
RB
352 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
353 memset(&exp, 0, sizeof(exp));
0abd7244 354
f335ecd6
RB
355 if (use_iterator)
356 cl_git_pass(diff_foreach_via_iterator(
793c4385 357 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
358 else
359 cl_git_pass(git_diff_foreach(
793c4385 360 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
361
362 cl_assert_equal_i(1, exp.files);
b4f5bb07 363 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
364 cl_assert_equal_i(0, exp.hunks);
365 }
0abd7244
RB
366
367 git_diff_list_free(diff);
368
369 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
370 git_config_free(cfg);
371}
372
373void test_diff_workdir__filemode_changes_with_filemode_false(void)
374{
375 git_config *cfg;
376 git_diff_list *diff = NULL;
377 diff_expects exp;
378
379 if (!cl_is_chmod_supported())
380 return;
381
382 g_repo = cl_git_sandbox_init("issue_592");
383
384 cl_git_pass(git_repository_config(&cfg, g_repo));
385 cl_git_pass(git_config_set_bool(cfg, "core.filemode", false));
386
387 /* test once with no mods */
388
bbe6dbec 389 cl_git_pass(git_diff_workdir_to_index(&diff, g_repo, NULL, NULL));
0abd7244
RB
390
391 memset(&exp, 0, sizeof(exp));
392 cl_git_pass(git_diff_foreach(
793c4385 393 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
0abd7244
RB
394
395 cl_assert_equal_i(0, exp.files);
b4f5bb07 396 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
0abd7244
RB
397 cl_assert_equal_i(0, exp.hunks);
398
399 git_diff_list_free(diff);
400
401 /* chmod file and test again */
402
403 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
404
bbe6dbec 405 cl_git_pass(git_diff_workdir_to_index(&diff, g_repo, NULL, NULL));
0abd7244
RB
406
407 memset(&exp, 0, sizeof(exp));
408 cl_git_pass(git_diff_foreach(
793c4385 409 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
0abd7244
RB
410
411 cl_assert_equal_i(0, exp.files);
b4f5bb07 412 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
0abd7244
RB
413 cl_assert_equal_i(0, exp.hunks);
414
415 git_diff_list_free(diff);
416
417 cl_assert(cl_toggle_filemode("issue_592/a.txt"));
418 git_config_free(cfg);
419}
420
145e696b
RB
421void test_diff_workdir__head_index_and_workdir_all_differ(void)
422{
2f8d30be 423 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
145e696b
RB
424 git_diff_list *diff_i2t = NULL, *diff_w2i = NULL;
425 diff_expects exp;
426 char *pathspec = "staged_changes_modified_file";
427 git_tree *tree;
f335ecd6 428 int use_iterator;
145e696b
RB
429
430 /* For this file,
431 * - head->index diff has 1 line of context, 1 line of diff
432 * - index->workdir diff has 2 lines of context, 1 line of diff
433 * but
434 * - head->workdir diff has 1 line of context, 2 lines of diff
435 * Let's make sure the right one is returned from each fn.
436 */
437
438 g_repo = cl_git_sandbox_init("status");
439
440 tree = resolve_commit_oid_to_tree(g_repo, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f");
441
442 opts.pathspec.strings = &pathspec;
443 opts.pathspec.count = 1;
444
bbe6dbec
RB
445 cl_git_pass(git_diff_index_to_tree(&diff_i2t, g_repo, tree, NULL, &opts));
446 cl_git_pass(git_diff_workdir_to_index(&diff_w2i, g_repo, NULL, &opts));
145e696b 447
f335ecd6
RB
448 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
449 memset(&exp, 0, sizeof(exp));
450
451 if (use_iterator)
452 cl_git_pass(diff_foreach_via_iterator(
793c4385 453 diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
454 else
455 cl_git_pass(git_diff_foreach(
793c4385 456 diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
457
458 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
459 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
460 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
461 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
462 cl_assert_equal_i(1, exp.hunks);
463 cl_assert_equal_i(2, exp.lines);
464 cl_assert_equal_i(1, exp.line_ctxt);
465 cl_assert_equal_i(1, exp.line_adds);
466 cl_assert_equal_i(0, exp.line_dels);
467 }
468
469 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
470 memset(&exp, 0, sizeof(exp));
471
472 if (use_iterator)
473 cl_git_pass(diff_foreach_via_iterator(
793c4385 474 diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
475 else
476 cl_git_pass(git_diff_foreach(
793c4385 477 diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
478
479 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
480 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
481 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
482 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
483 cl_assert_equal_i(1, exp.hunks);
484 cl_assert_equal_i(3, exp.lines);
485 cl_assert_equal_i(2, exp.line_ctxt);
486 cl_assert_equal_i(1, exp.line_adds);
487 cl_assert_equal_i(0, exp.line_dels);
488 }
145e696b
RB
489
490 cl_git_pass(git_diff_merge(diff_i2t, diff_w2i));
491
f335ecd6
RB
492 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
493 memset(&exp, 0, sizeof(exp));
494
495 if (use_iterator)
496 cl_git_pass(diff_foreach_via_iterator(
793c4385 497 diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
498 else
499 cl_git_pass(git_diff_foreach(
793c4385 500 diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
501
502 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
503 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
504 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
505 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
506 cl_assert_equal_i(1, exp.hunks);
507 cl_assert_equal_i(3, exp.lines);
508 cl_assert_equal_i(1, exp.line_ctxt);
509 cl_assert_equal_i(2, exp.line_adds);
510 cl_assert_equal_i(0, exp.line_dels);
511 }
145e696b
RB
512
513 git_diff_list_free(diff_i2t);
514 git_diff_list_free(diff_w2i);
cdca82c7
CMN
515
516 git_tree_free(tree);
145e696b
RB
517}
518
519void test_diff_workdir__eof_newline_changes(void)
520{
2f8d30be 521 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
145e696b
RB
522 git_diff_list *diff = NULL;
523 diff_expects exp;
524 char *pathspec = "current_file";
f335ecd6 525 int use_iterator;
145e696b
RB
526
527 g_repo = cl_git_sandbox_init("status");
528
529 opts.pathspec.strings = &pathspec;
530 opts.pathspec.count = 1;
531
bbe6dbec 532 cl_git_pass(git_diff_workdir_to_index(&diff, g_repo, NULL, &opts));
145e696b 533
f335ecd6
RB
534 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
535 memset(&exp, 0, sizeof(exp));
536
537 if (use_iterator)
538 cl_git_pass(diff_foreach_via_iterator(
793c4385 539 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
540 else
541 cl_git_pass(git_diff_foreach(
793c4385 542 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
543
544 cl_assert_equal_i(0, exp.files);
b4f5bb07
RB
545 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
546 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
547 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
548 cl_assert_equal_i(0, exp.hunks);
549 cl_assert_equal_i(0, exp.lines);
550 cl_assert_equal_i(0, exp.line_ctxt);
551 cl_assert_equal_i(0, exp.line_adds);
552 cl_assert_equal_i(0, exp.line_dels);
553 }
145e696b
RB
554
555 git_diff_list_free(diff);
556
557 cl_git_append2file("status/current_file", "\n");
558
bbe6dbec 559 cl_git_pass(git_diff_workdir_to_index(&diff, g_repo, NULL, &opts));
145e696b 560
f335ecd6
RB
561 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
562 memset(&exp, 0, sizeof(exp));
563
564 if (use_iterator)
565 cl_git_pass(diff_foreach_via_iterator(
793c4385 566 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
567 else
568 cl_git_pass(git_diff_foreach(
793c4385 569 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
570
571 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
572 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
573 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
574 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
575 cl_assert_equal_i(1, exp.hunks);
576 cl_assert_equal_i(2, exp.lines);
577 cl_assert_equal_i(1, exp.line_ctxt);
578 cl_assert_equal_i(1, exp.line_adds);
579 cl_assert_equal_i(0, exp.line_dels);
580 }
145e696b
RB
581
582 git_diff_list_free(diff);
583
584 cl_git_rewritefile("status/current_file", "current_file");
585
bbe6dbec 586 cl_git_pass(git_diff_workdir_to_index(&diff, g_repo, NULL, &opts));
145e696b 587
f335ecd6
RB
588 for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
589 memset(&exp, 0, sizeof(exp));
590
591 if (use_iterator)
592 cl_git_pass(diff_foreach_via_iterator(
793c4385 593 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
594 else
595 cl_git_pass(git_diff_foreach(
793c4385 596 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
f335ecd6
RB
597
598 cl_assert_equal_i(1, exp.files);
b4f5bb07
RB
599 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
600 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
601 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
f335ecd6
RB
602 cl_assert_equal_i(1, exp.hunks);
603 cl_assert_equal_i(3, exp.lines);
604 cl_assert_equal_i(0, exp.line_ctxt);
605 cl_assert_equal_i(1, exp.line_adds);
606 cl_assert_equal_i(2, exp.line_dels);
607 }
145e696b
RB
608
609 git_diff_list_free(diff);
610}
611
74fa4bfa
RB
612/* PREPARATION OF TEST DATA
613 *
614 * Since there is no command line equivalent of git_diff_workdir_to_tree,
615 * it was a bit of a pain to confirm that I was getting the expected
616 * results in the first part of this tests. Here is what I ended up
617 * doing to set my expectation for the file counts and results:
618 *
619 * Running "git ls-tree 26a125" and "git ls-tree aa27a6" shows:
620 *
621 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
622 * B 5452d32f1dd538eb0405e8a83cc185f79e25e80f file_deleted
623 * C 452e4244b5d083ddf0460acf1ecc74db9dcfa11a modified_file
624 * D 32504b727382542f9f089e24fddac5e78533e96c staged_changes
625 * E 061d42a44cacde5726057b67558821d95db96f19 staged_changes_file_deleted
626 * F 70bd9443ada07063e7fbf0b3ff5c13f7494d89c2 staged_changes_modified_file
627 * G e9b9107f290627c04d097733a10055af941f6bca staged_delete_file_deleted
628 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
629 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
630 * J 1888c805345ba265b0ee9449b8877b6064592058 subdir/deleted_file
631 * K a6191982709b746d5650e93c2acf34ef74e11504 subdir/modified_file
632 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
633 *
634 * --------
635 *
636 * find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths
637 *
638 * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file
639 * M 6a79f808a9c6bc9531ac726c184bbcd9351ccf11 ignored_file
640 * C 0a539630525aca2e7bc84975958f92f10a64c9b6 modified_file
641 * N d4fa8600b4f37d7516bef4816ae2c64dbf029e3a new_file
642 * D 55d316c9ba708999f1918e9677d01dfcae69c6b9 staged_changes
643 * F 011c3440d5c596e21d836aa6d7b10eb581f68c49 staged_changes_modified_file
644 * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file
645 * O 529a16e8e762d4acb7b9636ff540a00831f9155a staged_new_file
646 * P 8b090c06d14ffa09c4e880088ebad33893f921d1 staged_new_file_modified_file
647 * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file
648 * K 57274b75eeb5f36fd55527806d567b2240a20c57 subdir/modified_file
649 * Q 80a86a6931b91bc01c2dbf5ca55bdd24ad1ef466 subdir/new_file
650 * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt
651 *
652 * --------
653 *
654 * A - current_file (UNMODIFIED) -> not in results
655 * B D file_deleted
656 * M I ignored_file (IGNORED)
657 * C M modified_file
658 * N U new_file (UNTRACKED)
659 * D M staged_changes
660 * E D staged_changes_file_deleted
661 * F M staged_changes_modified_file
662 * G D staged_delete_file_deleted
663 * H - staged_delete_modified_file (UNMODIFIED) -> not in results
664 * O U staged_new_file
665 * P U staged_new_file_modified_file
666 * I - subdir/current_file (UNMODIFIED) -> not in results
667 * J D subdir/deleted_file
668 * K M subdir/modified_file
669 * Q U subdir/new_file
670 * L - subdir.txt (UNMODIFIED) -> not in results
671 *
672 * Expect 13 files, 0 ADD, 4 DEL, 4 MOD, 1 IGN, 4 UNTR
673 */
49d34c1c
RB
674
675
676void test_diff_workdir__larger_hunks(void)
677{
678 const char *a_commit = "d70d245ed97ed2aa596dd1af6536e4bfdb047b69";
679 const char *b_commit = "7a9e0b02e63179929fed24f0a3e0f19168114d10";
680 git_tree *a, *b;
2f8d30be 681 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
5f69a31f 682 size_t i, d, num_d, h, num_h, l, num_l, header_len, line_len;
49d34c1c
RB
683
684 g_repo = cl_git_sandbox_init("diff");
685
686 cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
687 cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
688
689 opts.context_lines = 1;
690 opts.interhunk_lines = 0;
691
692 for (i = 0; i <= 2; ++i) {
693 git_diff_list *diff = NULL;
5f69a31f 694 git_diff_patch *patch;
bae957b9 695 const git_diff_range *range;
5f69a31f
RB
696 const char *header, *line;
697 char origin;
49d34c1c
RB
698
699 /* okay, this is a bit silly, but oh well */
700 switch (i) {
701 case 0:
bbe6dbec 702 cl_git_pass(git_diff_workdir_to_index(&diff, g_repo, NULL, &opts));
49d34c1c
RB
703 break;
704 case 1:
5735bf5e 705 cl_git_pass(git_diff_workdir_to_tree(&diff, g_repo, a, &opts));
49d34c1c
RB
706 break;
707 case 2:
5735bf5e 708 cl_git_pass(git_diff_workdir_to_tree(&diff, g_repo, b, &opts));
49d34c1c
RB
709 break;
710 }
711
5f69a31f
RB
712 num_d = git_diff_num_deltas(diff);
713 cl_assert_equal_i(2, (int)num_d);
49d34c1c 714
5f69a31f
RB
715 for (d = 0; d < num_d; ++d) {
716 cl_git_pass(git_diff_get_patch(&patch, NULL, diff, d));
717 cl_assert(patch);
49d34c1c 718
5f69a31f
RB
719 num_h = git_diff_patch_num_hunks(patch);
720 for (h = 0; h < num_h; h++) {
721 cl_git_pass(git_diff_patch_get_hunk(
722 &range, &header, &header_len, &num_l, patch, h));
49d34c1c 723
5f69a31f
RB
724 for (l = 0; l < num_l; ++l) {
725 cl_git_pass(git_diff_patch_get_line_in_hunk(
726 &origin, &line, &line_len, NULL, NULL, patch, h, l));
727 cl_assert(line);
49d34c1c
RB
728 }
729
5f69a31f
RB
730 /* confirm fail after the last item */
731 cl_git_fail(git_diff_patch_get_line_in_hunk(
732 &origin, &line, &line_len, NULL, NULL, patch, h, num_l));
49d34c1c
RB
733 }
734
5f69a31f
RB
735 /* confirm fail after the last item */
736 cl_git_fail(git_diff_patch_get_hunk(
737 &range, &header, &header_len, &num_l, patch, num_h));
49d34c1c 738
5f69a31f
RB
739 git_diff_patch_free(patch);
740 }
49d34c1c 741
49d34c1c
RB
742 git_diff_list_free(diff);
743 }
744
745 git_tree_free(a);
746 git_tree_free(b);
747}
5d1308f2
RB
748
749/* Set up a test that exercises this code. The easiest test using existing
750 * test data is probably to create a sandbox of submod2 and then run a
751 * git_diff_workdir_to_tree against tree
752 * 873585b94bdeabccea991ea5e3ec1a277895b698. As for what you should actually
753 * test, you can start by just checking that the number of lines of diff
754 * content matches the actual output of git diff. That will at least
755 * demonstrate that the submodule content is being used to generate somewhat
756 * comparable outputs. It is a test that would fail without this code and
757 * will succeed with it.
758 */
759
760#include "../submodule/submodule_helpers.h"
761
762void test_diff_workdir__submodules(void)
763{
764 const char *a_commit = "873585b94bdeabccea991ea5e3ec1a277895b698";
765 git_tree *a;
2f8d30be 766 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
5d1308f2
RB
767 git_diff_list *diff = NULL;
768 diff_expects exp;
769
770 g_repo = cl_git_sandbox_init("submod2");
771
772 cl_fixture_sandbox("submod2_target");
773 p_rename("submod2_target/.gitted", "submod2_target/.git");
774
775 rewrite_gitmodules(git_repository_workdir(g_repo));
776 p_rename("submod2/not_submodule/.gitted", "submod2/not_submodule/.git");
777
778 cl_fixture_cleanup("submod2_target");
779
780 a = resolve_commit_oid_to_tree(g_repo, a_commit);
781
782 opts.flags =
783 GIT_DIFF_INCLUDE_UNTRACKED |
784 GIT_DIFF_RECURSE_UNTRACKED_DIRS |
785 GIT_DIFF_INCLUDE_UNTRACKED_CONTENT;
786
5735bf5e 787 cl_git_pass(git_diff_workdir_to_tree(&diff, g_repo, a, &opts));
5d1308f2
RB
788
789 /* diff_print(stderr, diff); */
790
791 /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */
792
793 memset(&exp, 0, sizeof(exp));
794 cl_git_pass(git_diff_foreach(
793c4385 795 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
5d1308f2
RB
796
797 /* the following differs from "git diff 873585" by one "untracked" file
798 * because the diff list includes the "not_submodule/" directory which
799 * is not displayed in the text diff.
800 */
801
802 cl_assert_equal_i(10, exp.files);
803
b4f5bb07
RB
804 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]);
805 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]);
806 cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]);
807 cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]);
808 cl_assert_equal_i(9, exp.file_status[GIT_DELTA_UNTRACKED]);
5d1308f2
RB
809
810 /* the following numbers match "git diff 873585" exactly */
811
812 cl_assert_equal_i(9, exp.hunks);
813
814 cl_assert_equal_i(33, exp.lines);
815 cl_assert_equal_i(2, exp.line_ctxt);
816 cl_assert_equal_i(30, exp.line_adds);
817 cl_assert_equal_i(1, exp.line_dels);
818
819 git_diff_list_free(diff);
820 git_tree_free(a);
821}
c2e43fb1 822
823void test_diff_workdir__cannot_diff_against_a_bare_repository(void)
824{
2f8d30be 825 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
c2e43fb1 826 git_diff_list *diff = NULL;
827 git_tree *tree;
828
829 g_repo = cl_git_sandbox_init("testrepo.git");
830
5735bf5e 831 cl_assert_equal_i(
bbe6dbec 832 GIT_EBAREREPO, git_diff_workdir_to_index(&diff, g_repo, NULL, &opts));
c2e43fb1 833
834 cl_git_pass(git_repository_head_tree(&tree, g_repo));
5735bf5e
RB
835
836 cl_assert_equal_i(
837 GIT_EBAREREPO, git_diff_workdir_to_tree(&diff, g_repo, tree, &opts));
c2e43fb1 838
839 git_tree_free(tree);
840}
59a0d772 841
842void test_diff_workdir__to_null_tree(void)
843{
844 git_diff_list *diff;
845 diff_expects exp;
2f8d30be 846 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
59a0d772 847
848 opts.flags = GIT_DIFF_INCLUDE_UNTRACKED |
849 GIT_DIFF_RECURSE_UNTRACKED_DIRS;
850
851 g_repo = cl_git_sandbox_init("status");
852
853 cl_git_pass(git_diff_workdir_to_tree(&diff, g_repo, NULL, &opts));
854
855 memset(&exp, 0, sizeof(exp));
856
857 cl_git_pass(git_diff_foreach(
858 diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp));
859
860 cl_assert_equal_i(exp.files, exp.file_status[GIT_DELTA_UNTRACKED]);
861
862 git_diff_list_free(diff);
863}
2f8d30be
BS
864
865void test_diff_workdir__checks_options_version(void)
866{
867 git_diff_list *diff;
868 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
869 const git_error *err;
870
871 g_repo = cl_git_sandbox_init("status");
872
873 opts.version = 0;
874 cl_git_fail(git_diff_workdir_to_tree(&diff, g_repo, NULL, &opts));
875 err = giterr_last();
876 cl_assert_equal_i(GITERR_INVALID, err->klass);
877
878 giterr_clear();
879 opts.version = 1024;
880 cl_git_fail(git_diff_workdir_to_tree(&diff, g_repo, NULL, &opts));
881 err = giterr_last();
882 cl_assert_equal_i(GITERR_INVALID, err->klass);
883}