]>
Commit | Line | Data |
---|---|---|
74fa4bfa RB |
1 | #include "clar_libgit2.h" |
2 | #include "diff_helpers.h" | |
c2e43fb1 | 3 | #include "repository.h" |
74fa4bfa RB |
4 | |
5 | static git_repository *g_repo = NULL; | |
6 | ||
7 | void test_diff_workdir__initialize(void) | |
8 | { | |
74fa4bfa RB |
9 | } |
10 | ||
11 | void test_diff_workdir__cleanup(void) | |
12 | { | |
854eccbb | 13 | cl_git_sandbox_cleanup(); |
74fa4bfa RB |
14 | } |
15 | ||
16 | void 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 | ||
66 | void 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 |
203 | void 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 | ||
0abd7244 RB |
310 | void test_diff_workdir__filemode_changes(void) |
311 | { | |
0abd7244 RB |
312 | git_diff_list *diff = NULL; |
313 | diff_expects exp; | |
f335ecd6 | 314 | int use_iterator; |
0abd7244 RB |
315 | |
316 | if (!cl_is_chmod_supported()) | |
317 | return; | |
318 | ||
319 | g_repo = cl_git_sandbox_init("issue_592"); | |
320 | ||
1323c6d1 | 321 | cl_repo_set_bool(g_repo, "core.filemode", true); |
0abd7244 RB |
322 | |
323 | /* test once with no mods */ | |
324 | ||
56c72b75 | 325 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); |
0abd7244 | 326 | |
f335ecd6 RB |
327 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
328 | memset(&exp, 0, sizeof(exp)); | |
0abd7244 | 329 | |
f335ecd6 RB |
330 | if (use_iterator) |
331 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 332 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
333 | else |
334 | cl_git_pass(git_diff_foreach( | |
793c4385 | 335 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
336 | |
337 | cl_assert_equal_i(0, exp.files); | |
b4f5bb07 | 338 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); |
f335ecd6 RB |
339 | cl_assert_equal_i(0, exp.hunks); |
340 | } | |
0abd7244 RB |
341 | |
342 | git_diff_list_free(diff); | |
343 | ||
344 | /* chmod file and test again */ | |
345 | ||
346 | cl_assert(cl_toggle_filemode("issue_592/a.txt")); | |
347 | ||
56c72b75 | 348 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); |
0abd7244 | 349 | |
f335ecd6 RB |
350 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
351 | memset(&exp, 0, sizeof(exp)); | |
0abd7244 | 352 | |
f335ecd6 RB |
353 | if (use_iterator) |
354 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 355 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
356 | else |
357 | cl_git_pass(git_diff_foreach( | |
793c4385 | 358 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
359 | |
360 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 | 361 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); |
f335ecd6 RB |
362 | cl_assert_equal_i(0, exp.hunks); |
363 | } | |
0abd7244 RB |
364 | |
365 | git_diff_list_free(diff); | |
366 | ||
367 | cl_assert(cl_toggle_filemode("issue_592/a.txt")); | |
0abd7244 RB |
368 | } |
369 | ||
370 | void test_diff_workdir__filemode_changes_with_filemode_false(void) | |
371 | { | |
0abd7244 RB |
372 | git_diff_list *diff = NULL; |
373 | diff_expects exp; | |
374 | ||
375 | if (!cl_is_chmod_supported()) | |
376 | return; | |
377 | ||
378 | g_repo = cl_git_sandbox_init("issue_592"); | |
379 | ||
1323c6d1 | 380 | cl_repo_set_bool(g_repo, "core.filemode", false); |
0abd7244 RB |
381 | |
382 | /* test once with no mods */ | |
383 | ||
56c72b75 | 384 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); |
0abd7244 RB |
385 | |
386 | memset(&exp, 0, sizeof(exp)); | |
387 | cl_git_pass(git_diff_foreach( | |
793c4385 | 388 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
0abd7244 RB |
389 | |
390 | cl_assert_equal_i(0, exp.files); | |
b4f5bb07 | 391 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); |
0abd7244 RB |
392 | cl_assert_equal_i(0, exp.hunks); |
393 | ||
394 | git_diff_list_free(diff); | |
395 | ||
396 | /* chmod file and test again */ | |
397 | ||
398 | cl_assert(cl_toggle_filemode("issue_592/a.txt")); | |
399 | ||
56c72b75 | 400 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); |
0abd7244 RB |
401 | |
402 | memset(&exp, 0, sizeof(exp)); | |
403 | cl_git_pass(git_diff_foreach( | |
793c4385 | 404 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
0abd7244 RB |
405 | |
406 | cl_assert_equal_i(0, exp.files); | |
b4f5bb07 | 407 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); |
0abd7244 RB |
408 | cl_assert_equal_i(0, exp.hunks); |
409 | ||
410 | git_diff_list_free(diff); | |
411 | ||
412 | cl_assert(cl_toggle_filemode("issue_592/a.txt")); | |
0abd7244 RB |
413 | } |
414 | ||
145e696b RB |
415 | void test_diff_workdir__head_index_and_workdir_all_differ(void) |
416 | { | |
2f8d30be | 417 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
145e696b RB |
418 | git_diff_list *diff_i2t = NULL, *diff_w2i = NULL; |
419 | diff_expects exp; | |
420 | char *pathspec = "staged_changes_modified_file"; | |
421 | git_tree *tree; | |
f335ecd6 | 422 | int use_iterator; |
145e696b RB |
423 | |
424 | /* For this file, | |
425 | * - head->index diff has 1 line of context, 1 line of diff | |
426 | * - index->workdir diff has 2 lines of context, 1 line of diff | |
427 | * but | |
428 | * - head->workdir diff has 1 line of context, 2 lines of diff | |
429 | * Let's make sure the right one is returned from each fn. | |
430 | */ | |
431 | ||
432 | g_repo = cl_git_sandbox_init("status"); | |
433 | ||
434 | tree = resolve_commit_oid_to_tree(g_repo, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f"); | |
435 | ||
436 | opts.pathspec.strings = &pathspec; | |
437 | opts.pathspec.count = 1; | |
438 | ||
56c72b75 RB |
439 | cl_git_pass(git_diff_tree_to_index(&diff_i2t, g_repo, tree, NULL, &opts)); |
440 | cl_git_pass(git_diff_index_to_workdir(&diff_w2i, g_repo, NULL, &opts)); | |
145e696b | 441 | |
f335ecd6 RB |
442 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
443 | memset(&exp, 0, sizeof(exp)); | |
444 | ||
445 | if (use_iterator) | |
446 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 447 | diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
448 | else |
449 | cl_git_pass(git_diff_foreach( | |
793c4385 | 450 | diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
451 | |
452 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 RB |
453 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
454 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
455 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
456 | cl_assert_equal_i(1, exp.hunks); |
457 | cl_assert_equal_i(2, exp.lines); | |
458 | cl_assert_equal_i(1, exp.line_ctxt); | |
459 | cl_assert_equal_i(1, exp.line_adds); | |
460 | cl_assert_equal_i(0, exp.line_dels); | |
461 | } | |
462 | ||
463 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { | |
464 | memset(&exp, 0, sizeof(exp)); | |
465 | ||
466 | if (use_iterator) | |
467 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 468 | diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
469 | else |
470 | cl_git_pass(git_diff_foreach( | |
793c4385 | 471 | diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
472 | |
473 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 RB |
474 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
475 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
476 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
477 | cl_assert_equal_i(1, exp.hunks); |
478 | cl_assert_equal_i(3, exp.lines); | |
479 | cl_assert_equal_i(2, exp.line_ctxt); | |
480 | cl_assert_equal_i(1, exp.line_adds); | |
481 | cl_assert_equal_i(0, exp.line_dels); | |
482 | } | |
145e696b RB |
483 | |
484 | cl_git_pass(git_diff_merge(diff_i2t, diff_w2i)); | |
485 | ||
f335ecd6 RB |
486 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
487 | memset(&exp, 0, sizeof(exp)); | |
488 | ||
489 | if (use_iterator) | |
490 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 491 | diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
492 | else |
493 | cl_git_pass(git_diff_foreach( | |
793c4385 | 494 | diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
495 | |
496 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 RB |
497 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
498 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
499 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
500 | cl_assert_equal_i(1, exp.hunks); |
501 | cl_assert_equal_i(3, exp.lines); | |
502 | cl_assert_equal_i(1, exp.line_ctxt); | |
503 | cl_assert_equal_i(2, exp.line_adds); | |
504 | cl_assert_equal_i(0, exp.line_dels); | |
505 | } | |
145e696b RB |
506 | |
507 | git_diff_list_free(diff_i2t); | |
508 | git_diff_list_free(diff_w2i); | |
cdca82c7 CMN |
509 | |
510 | git_tree_free(tree); | |
145e696b RB |
511 | } |
512 | ||
513 | void test_diff_workdir__eof_newline_changes(void) | |
514 | { | |
2f8d30be | 515 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
145e696b RB |
516 | git_diff_list *diff = NULL; |
517 | diff_expects exp; | |
518 | char *pathspec = "current_file"; | |
f335ecd6 | 519 | int use_iterator; |
145e696b RB |
520 | |
521 | g_repo = cl_git_sandbox_init("status"); | |
522 | ||
523 | opts.pathspec.strings = &pathspec; | |
524 | opts.pathspec.count = 1; | |
525 | ||
56c72b75 | 526 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
145e696b | 527 | |
f335ecd6 RB |
528 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
529 | memset(&exp, 0, sizeof(exp)); | |
530 | ||
531 | if (use_iterator) | |
532 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 533 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
534 | else |
535 | cl_git_pass(git_diff_foreach( | |
793c4385 | 536 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
537 | |
538 | cl_assert_equal_i(0, exp.files); | |
b4f5bb07 RB |
539 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
540 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
541 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
542 | cl_assert_equal_i(0, exp.hunks); |
543 | cl_assert_equal_i(0, exp.lines); | |
544 | cl_assert_equal_i(0, exp.line_ctxt); | |
545 | cl_assert_equal_i(0, exp.line_adds); | |
546 | cl_assert_equal_i(0, exp.line_dels); | |
547 | } | |
145e696b RB |
548 | |
549 | git_diff_list_free(diff); | |
550 | ||
551 | cl_git_append2file("status/current_file", "\n"); | |
552 | ||
56c72b75 | 553 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
145e696b | 554 | |
f335ecd6 RB |
555 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
556 | memset(&exp, 0, sizeof(exp)); | |
557 | ||
558 | if (use_iterator) | |
559 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 560 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
561 | else |
562 | cl_git_pass(git_diff_foreach( | |
793c4385 | 563 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
564 | |
565 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 RB |
566 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
567 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
568 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
569 | cl_assert_equal_i(1, exp.hunks); |
570 | cl_assert_equal_i(2, exp.lines); | |
571 | cl_assert_equal_i(1, exp.line_ctxt); | |
572 | cl_assert_equal_i(1, exp.line_adds); | |
573 | cl_assert_equal_i(0, exp.line_dels); | |
574 | } | |
145e696b RB |
575 | |
576 | git_diff_list_free(diff); | |
577 | ||
578 | cl_git_rewritefile("status/current_file", "current_file"); | |
579 | ||
56c72b75 | 580 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
145e696b | 581 | |
f335ecd6 RB |
582 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
583 | memset(&exp, 0, sizeof(exp)); | |
584 | ||
585 | if (use_iterator) | |
586 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 587 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
588 | else |
589 | cl_git_pass(git_diff_foreach( | |
793c4385 | 590 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
591 | |
592 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 RB |
593 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
594 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
595 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
596 | cl_assert_equal_i(1, exp.hunks); |
597 | cl_assert_equal_i(3, exp.lines); | |
598 | cl_assert_equal_i(0, exp.line_ctxt); | |
599 | cl_assert_equal_i(1, exp.line_adds); | |
600 | cl_assert_equal_i(2, exp.line_dels); | |
601 | } | |
145e696b RB |
602 | |
603 | git_diff_list_free(diff); | |
604 | } | |
605 | ||
74fa4bfa RB |
606 | /* PREPARATION OF TEST DATA |
607 | * | |
56c72b75 | 608 | * Since there is no command line equivalent of git_diff_tree_to_workdir, |
74fa4bfa RB |
609 | * it was a bit of a pain to confirm that I was getting the expected |
610 | * results in the first part of this tests. Here is what I ended up | |
611 | * doing to set my expectation for the file counts and results: | |
612 | * | |
613 | * Running "git ls-tree 26a125" and "git ls-tree aa27a6" shows: | |
614 | * | |
615 | * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file | |
616 | * B 5452d32f1dd538eb0405e8a83cc185f79e25e80f file_deleted | |
617 | * C 452e4244b5d083ddf0460acf1ecc74db9dcfa11a modified_file | |
618 | * D 32504b727382542f9f089e24fddac5e78533e96c staged_changes | |
619 | * E 061d42a44cacde5726057b67558821d95db96f19 staged_changes_file_deleted | |
620 | * F 70bd9443ada07063e7fbf0b3ff5c13f7494d89c2 staged_changes_modified_file | |
621 | * G e9b9107f290627c04d097733a10055af941f6bca staged_delete_file_deleted | |
622 | * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file | |
623 | * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file | |
624 | * J 1888c805345ba265b0ee9449b8877b6064592058 subdir/deleted_file | |
625 | * K a6191982709b746d5650e93c2acf34ef74e11504 subdir/modified_file | |
626 | * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt | |
627 | * | |
628 | * -------- | |
629 | * | |
630 | * find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths | |
631 | * | |
632 | * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file | |
633 | * M 6a79f808a9c6bc9531ac726c184bbcd9351ccf11 ignored_file | |
634 | * C 0a539630525aca2e7bc84975958f92f10a64c9b6 modified_file | |
635 | * N d4fa8600b4f37d7516bef4816ae2c64dbf029e3a new_file | |
636 | * D 55d316c9ba708999f1918e9677d01dfcae69c6b9 staged_changes | |
637 | * F 011c3440d5c596e21d836aa6d7b10eb581f68c49 staged_changes_modified_file | |
638 | * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file | |
639 | * O 529a16e8e762d4acb7b9636ff540a00831f9155a staged_new_file | |
640 | * P 8b090c06d14ffa09c4e880088ebad33893f921d1 staged_new_file_modified_file | |
641 | * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file | |
642 | * K 57274b75eeb5f36fd55527806d567b2240a20c57 subdir/modified_file | |
643 | * Q 80a86a6931b91bc01c2dbf5ca55bdd24ad1ef466 subdir/new_file | |
644 | * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt | |
645 | * | |
646 | * -------- | |
647 | * | |
648 | * A - current_file (UNMODIFIED) -> not in results | |
649 | * B D file_deleted | |
650 | * M I ignored_file (IGNORED) | |
651 | * C M modified_file | |
652 | * N U new_file (UNTRACKED) | |
653 | * D M staged_changes | |
654 | * E D staged_changes_file_deleted | |
655 | * F M staged_changes_modified_file | |
656 | * G D staged_delete_file_deleted | |
657 | * H - staged_delete_modified_file (UNMODIFIED) -> not in results | |
658 | * O U staged_new_file | |
659 | * P U staged_new_file_modified_file | |
660 | * I - subdir/current_file (UNMODIFIED) -> not in results | |
661 | * J D subdir/deleted_file | |
662 | * K M subdir/modified_file | |
663 | * Q U subdir/new_file | |
664 | * L - subdir.txt (UNMODIFIED) -> not in results | |
665 | * | |
666 | * Expect 13 files, 0 ADD, 4 DEL, 4 MOD, 1 IGN, 4 UNTR | |
667 | */ | |
49d34c1c RB |
668 | |
669 | ||
670 | void test_diff_workdir__larger_hunks(void) | |
671 | { | |
672 | const char *a_commit = "d70d245ed97ed2aa596dd1af6536e4bfdb047b69"; | |
673 | const char *b_commit = "7a9e0b02e63179929fed24f0a3e0f19168114d10"; | |
674 | git_tree *a, *b; | |
2f8d30be | 675 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
5f69a31f | 676 | size_t i, d, num_d, h, num_h, l, num_l, header_len, line_len; |
49d34c1c RB |
677 | |
678 | g_repo = cl_git_sandbox_init("diff"); | |
679 | ||
680 | cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); | |
681 | cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); | |
682 | ||
683 | opts.context_lines = 1; | |
684 | opts.interhunk_lines = 0; | |
685 | ||
686 | for (i = 0; i <= 2; ++i) { | |
687 | git_diff_list *diff = NULL; | |
5f69a31f | 688 | git_diff_patch *patch; |
bae957b9 | 689 | const git_diff_range *range; |
5f69a31f RB |
690 | const char *header, *line; |
691 | char origin; | |
49d34c1c RB |
692 | |
693 | /* okay, this is a bit silly, but oh well */ | |
694 | switch (i) { | |
695 | case 0: | |
56c72b75 | 696 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
49d34c1c RB |
697 | break; |
698 | case 1: | |
56c72b75 | 699 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); |
49d34c1c RB |
700 | break; |
701 | case 2: | |
56c72b75 | 702 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, b, &opts)); |
49d34c1c RB |
703 | break; |
704 | } | |
705 | ||
5f69a31f RB |
706 | num_d = git_diff_num_deltas(diff); |
707 | cl_assert_equal_i(2, (int)num_d); | |
49d34c1c | 708 | |
5f69a31f RB |
709 | for (d = 0; d < num_d; ++d) { |
710 | cl_git_pass(git_diff_get_patch(&patch, NULL, diff, d)); | |
711 | cl_assert(patch); | |
49d34c1c | 712 | |
5f69a31f RB |
713 | num_h = git_diff_patch_num_hunks(patch); |
714 | for (h = 0; h < num_h; h++) { | |
715 | cl_git_pass(git_diff_patch_get_hunk( | |
716 | &range, &header, &header_len, &num_l, patch, h)); | |
49d34c1c | 717 | |
5f69a31f RB |
718 | for (l = 0; l < num_l; ++l) { |
719 | cl_git_pass(git_diff_patch_get_line_in_hunk( | |
720 | &origin, &line, &line_len, NULL, NULL, patch, h, l)); | |
721 | cl_assert(line); | |
49d34c1c RB |
722 | } |
723 | ||
5f69a31f RB |
724 | /* confirm fail after the last item */ |
725 | cl_git_fail(git_diff_patch_get_line_in_hunk( | |
726 | &origin, &line, &line_len, NULL, NULL, patch, h, num_l)); | |
49d34c1c RB |
727 | } |
728 | ||
5f69a31f RB |
729 | /* confirm fail after the last item */ |
730 | cl_git_fail(git_diff_patch_get_hunk( | |
731 | &range, &header, &header_len, &num_l, patch, num_h)); | |
49d34c1c | 732 | |
5f69a31f RB |
733 | git_diff_patch_free(patch); |
734 | } | |
49d34c1c | 735 | |
49d34c1c RB |
736 | git_diff_list_free(diff); |
737 | } | |
738 | ||
739 | git_tree_free(a); | |
740 | git_tree_free(b); | |
741 | } | |
5d1308f2 RB |
742 | |
743 | /* Set up a test that exercises this code. The easiest test using existing | |
744 | * test data is probably to create a sandbox of submod2 and then run a | |
56c72b75 | 745 | * git_diff_tree_to_workdir against tree |
5d1308f2 RB |
746 | * 873585b94bdeabccea991ea5e3ec1a277895b698. As for what you should actually |
747 | * test, you can start by just checking that the number of lines of diff | |
748 | * content matches the actual output of git diff. That will at least | |
749 | * demonstrate that the submodule content is being used to generate somewhat | |
750 | * comparable outputs. It is a test that would fail without this code and | |
751 | * will succeed with it. | |
752 | */ | |
753 | ||
754 | #include "../submodule/submodule_helpers.h" | |
755 | ||
756 | void test_diff_workdir__submodules(void) | |
757 | { | |
758 | const char *a_commit = "873585b94bdeabccea991ea5e3ec1a277895b698"; | |
759 | git_tree *a; | |
2f8d30be | 760 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
5d1308f2 RB |
761 | git_diff_list *diff = NULL; |
762 | diff_expects exp; | |
763 | ||
764 | g_repo = cl_git_sandbox_init("submod2"); | |
765 | ||
766 | cl_fixture_sandbox("submod2_target"); | |
767 | p_rename("submod2_target/.gitted", "submod2_target/.git"); | |
768 | ||
769 | rewrite_gitmodules(git_repository_workdir(g_repo)); | |
65025cb8 RB |
770 | p_rename("submod2/not-submodule/.gitted", "submod2/not-submodule/.git"); |
771 | p_rename("submod2/not/.gitted", "submod2/not/.git"); | |
5d1308f2 RB |
772 | |
773 | cl_fixture_cleanup("submod2_target"); | |
774 | ||
775 | a = resolve_commit_oid_to_tree(g_repo, a_commit); | |
776 | ||
777 | opts.flags = | |
778 | GIT_DIFF_INCLUDE_UNTRACKED | | |
779 | GIT_DIFF_RECURSE_UNTRACKED_DIRS | | |
780 | GIT_DIFF_INCLUDE_UNTRACKED_CONTENT; | |
781 | ||
56c72b75 | 782 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); |
5d1308f2 RB |
783 | |
784 | /* diff_print(stderr, diff); */ | |
785 | ||
786 | /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */ | |
787 | ||
788 | memset(&exp, 0, sizeof(exp)); | |
65025cb8 | 789 | |
5d1308f2 | 790 | cl_git_pass(git_diff_foreach( |
793c4385 | 791 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
5d1308f2 | 792 | |
ccfa6805 RB |
793 | /* so "git diff 873585" returns: |
794 | * M .gitmodules | |
795 | * A just_a_dir/contents | |
796 | * A just_a_file | |
797 | * A sm_added_and_uncommited | |
798 | * A sm_changed_file | |
799 | * A sm_changed_head | |
800 | * A sm_changed_index | |
801 | * A sm_changed_untracked_file | |
802 | * M sm_missing_commits | |
803 | * A sm_unchanged | |
804 | * which is a little deceptive because of the difference between the | |
805 | * "git diff <treeish>" results from "git_diff_tree_to_workdir". The | |
806 | * only significant difference is that those Added items will show up | |
807 | * as Untracked items in the pure libgit2 diff. | |
808 | * | |
809 | * Then add in the two extra untracked items "not" and "not-submodule" | |
810 | * to get the 12 files reported here. | |
5d1308f2 RB |
811 | */ |
812 | ||
ccfa6805 | 813 | cl_assert_equal_i(12, exp.files); |
5d1308f2 | 814 | |
b4f5bb07 RB |
815 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
816 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
ccfa6805 | 817 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); |
b4f5bb07 | 818 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); |
65025cb8 | 819 | cl_assert_equal_i(10, exp.file_status[GIT_DELTA_UNTRACKED]); |
5d1308f2 RB |
820 | |
821 | /* the following numbers match "git diff 873585" exactly */ | |
822 | ||
823 | cl_assert_equal_i(9, exp.hunks); | |
824 | ||
825 | cl_assert_equal_i(33, exp.lines); | |
826 | cl_assert_equal_i(2, exp.line_ctxt); | |
827 | cl_assert_equal_i(30, exp.line_adds); | |
828 | cl_assert_equal_i(1, exp.line_dels); | |
829 | ||
830 | git_diff_list_free(diff); | |
831 | git_tree_free(a); | |
832 | } | |
c2e43fb1 | 833 | |
834 | void test_diff_workdir__cannot_diff_against_a_bare_repository(void) | |
835 | { | |
2f8d30be | 836 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
c2e43fb1 | 837 | git_diff_list *diff = NULL; |
838 | git_tree *tree; | |
839 | ||
840 | g_repo = cl_git_sandbox_init("testrepo.git"); | |
841 | ||
5735bf5e | 842 | cl_assert_equal_i( |
56c72b75 | 843 | GIT_EBAREREPO, git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
c2e43fb1 | 844 | |
845 | cl_git_pass(git_repository_head_tree(&tree, g_repo)); | |
5735bf5e RB |
846 | |
847 | cl_assert_equal_i( | |
56c72b75 | 848 | GIT_EBAREREPO, git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); |
c2e43fb1 | 849 | |
850 | git_tree_free(tree); | |
851 | } | |
59a0d772 | 852 | |
853 | void test_diff_workdir__to_null_tree(void) | |
854 | { | |
855 | git_diff_list *diff; | |
856 | diff_expects exp; | |
2f8d30be | 857 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
59a0d772 | 858 | |
859 | opts.flags = GIT_DIFF_INCLUDE_UNTRACKED | | |
860 | GIT_DIFF_RECURSE_UNTRACKED_DIRS; | |
861 | ||
862 | g_repo = cl_git_sandbox_init("status"); | |
863 | ||
56c72b75 | 864 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts)); |
59a0d772 | 865 | |
866 | memset(&exp, 0, sizeof(exp)); | |
867 | ||
868 | cl_git_pass(git_diff_foreach( | |
869 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
870 | ||
871 | cl_assert_equal_i(exp.files, exp.file_status[GIT_DELTA_UNTRACKED]); | |
872 | ||
873 | git_diff_list_free(diff); | |
874 | } | |
2f8d30be BS |
875 | |
876 | void test_diff_workdir__checks_options_version(void) | |
877 | { | |
878 | git_diff_list *diff; | |
879 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
880 | const git_error *err; | |
881 | ||
882 | g_repo = cl_git_sandbox_init("status"); | |
883 | ||
884 | opts.version = 0; | |
56c72b75 | 885 | cl_git_fail(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts)); |
2f8d30be BS |
886 | err = giterr_last(); |
887 | cl_assert_equal_i(GITERR_INVALID, err->klass); | |
888 | ||
889 | giterr_clear(); | |
890 | opts.version = 1024; | |
56c72b75 | 891 | cl_git_fail(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts)); |
2f8d30be BS |
892 | err = giterr_last(); |
893 | cl_assert_equal_i(GITERR_INVALID, err->klass); | |
894 | } | |
de590550 RB |
895 | |
896 | void test_diff_workdir__can_diff_empty_file(void) | |
897 | { | |
898 | git_diff_list *diff; | |
899 | git_tree *tree; | |
900 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
901 | struct stat st; | |
902 | git_diff_patch *patch; | |
903 | ||
904 | g_repo = cl_git_sandbox_init("attr_index"); | |
905 | ||
906 | tree = resolve_commit_oid_to_tree(g_repo, "3812cfef3661"); /* HEAD */ | |
907 | ||
908 | /* baseline - make sure there are no outstanding diffs */ | |
909 | ||
910 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); | |
911 | cl_assert_equal_i(2, (int)git_diff_num_deltas(diff)); | |
912 | git_diff_list_free(diff); | |
913 | ||
914 | /* empty contents of file */ | |
915 | ||
916 | cl_git_rewritefile("attr_index/README.txt", ""); | |
917 | cl_git_pass(git_path_lstat("attr_index/README.txt", &st)); | |
918 | cl_assert_equal_i(0, (int)st.st_size); | |
919 | ||
920 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); | |
921 | cl_assert_equal_i(3, (int)git_diff_num_deltas(diff)); | |
922 | /* diffs are: .gitattributes, README.txt, sub/sub/.gitattributes */ | |
923 | cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 1)); | |
924 | git_diff_patch_free(patch); | |
925 | git_diff_list_free(diff); | |
926 | ||
927 | /* remove a file altogether */ | |
928 | ||
929 | cl_git_pass(p_unlink("attr_index/README.txt")); | |
930 | cl_assert(!git_path_exists("attr_index/README.txt")); | |
931 | ||
932 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); | |
933 | cl_assert_equal_i(3, (int)git_diff_num_deltas(diff)); | |
934 | cl_git_pass(git_diff_get_patch(&patch, NULL, diff, 1)); | |
935 | git_diff_patch_free(patch); | |
936 | git_diff_list_free(diff); | |
8842c75f VM |
937 | |
938 | git_tree_free(tree); | |
de590550 | 939 | } |
b8acb775 | 940 | |
b8acb775 SS |
941 | void test_diff_workdir__to_index_issue_1397(void) |
942 | { | |
943 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
944 | git_diff_list *diff = NULL; | |
945 | diff_expects exp; | |
b8acb775 SS |
946 | |
947 | g_repo = cl_git_sandbox_init("issue_1397"); | |
948 | ||
1098cfae | 949 | cl_repo_set_bool(g_repo, "core.autocrlf", true); |
b8acb775 SS |
950 | |
951 | opts.context_lines = 3; | |
952 | opts.interhunk_lines = 1; | |
953 | ||
954 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
955 | ||
1098cfae RB |
956 | memset(&exp, 0, sizeof(exp)); |
957 | cl_git_pass(git_diff_foreach( | |
958 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
b8acb775 | 959 | |
1098cfae RB |
960 | cl_assert_equal_i(0, exp.files); |
961 | cl_assert_equal_i(0, exp.hunks); | |
962 | cl_assert_equal_i(0, exp.lines); | |
b8acb775 SS |
963 | |
964 | git_diff_list_free(diff); | |
965 | diff = NULL; | |
b8acb775 | 966 | |
1098cfae RB |
967 | cl_git_rewritefile("issue_1397/crlf_file.txt", |
968 | "first line\r\nsecond line modified\r\nboth with crlf"); | |
b8acb775 SS |
969 | |
970 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
971 | ||
1098cfae RB |
972 | memset(&exp, 0, sizeof(exp)); |
973 | cl_git_pass(git_diff_foreach( | |
974 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
b8acb775 | 975 | |
1098cfae RB |
976 | cl_assert_equal_i(1, exp.files); |
977 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
b8acb775 | 978 | |
1098cfae | 979 | cl_assert_equal_i(1, exp.hunks); |
b8acb775 | 980 | |
1098cfae RB |
981 | cl_assert_equal_i(5, exp.lines); |
982 | cl_assert_equal_i(3, exp.line_ctxt); | |
983 | cl_assert_equal_i(1, exp.line_adds); | |
984 | cl_assert_equal_i(1, exp.line_dels); | |
b8acb775 SS |
985 | |
986 | git_diff_list_free(diff); | |
987 | } | |
988 | ||
989 | void test_diff_workdir__to_tree_issue_1397(void) | |
990 | { | |
1098cfae | 991 | const char *a_commit = "7f483a738"; /* the current HEAD */ |
b8acb775 SS |
992 | git_tree *a; |
993 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
994 | git_diff_list *diff = NULL; | |
995 | git_diff_list *diff2 = NULL; | |
996 | diff_expects exp; | |
b8acb775 SS |
997 | |
998 | g_repo = cl_git_sandbox_init("issue_1397"); | |
999 | ||
1098cfae | 1000 | cl_repo_set_bool(g_repo, "core.autocrlf", true); |
b8acb775 SS |
1001 | |
1002 | a = resolve_commit_oid_to_tree(g_repo, a_commit); | |
1003 | ||
1004 | opts.context_lines = 3; | |
1005 | opts.interhunk_lines = 1; | |
1006 | ||
1007 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); | |
1008 | ||
1098cfae RB |
1009 | memset(&exp, 0, sizeof(exp)); |
1010 | cl_git_pass(git_diff_foreach( | |
1011 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
b8acb775 | 1012 | |
1098cfae RB |
1013 | cl_assert_equal_i(0, exp.files); |
1014 | cl_assert_equal_i(0, exp.hunks); | |
1015 | cl_assert_equal_i(0, exp.lines); | |
b8acb775 SS |
1016 | |
1017 | git_diff_list_free(diff); | |
1018 | diff = NULL; | |
b8acb775 | 1019 | |
b8acb775 SS |
1020 | cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); |
1021 | cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts)); | |
1022 | cl_git_pass(git_diff_merge(diff, diff2)); | |
1023 | git_diff_list_free(diff2); | |
1024 | ||
1098cfae RB |
1025 | memset(&exp, 0, sizeof(exp)); |
1026 | cl_git_pass(git_diff_foreach( | |
1027 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
b8acb775 | 1028 | |
1098cfae RB |
1029 | cl_assert_equal_i(0, exp.files); |
1030 | cl_assert_equal_i(0, exp.hunks); | |
1031 | cl_assert_equal_i(0, exp.lines); | |
b8acb775 SS |
1032 | |
1033 | git_diff_list_free(diff); | |
1034 | git_tree_free(a); | |
1035 | } | |
a66c4bc8 RB |
1036 | |
1037 | void test_diff_workdir__untracked_directory_scenarios(void) | |
1038 | { | |
1039 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
1040 | git_diff_list *diff = NULL; | |
1041 | diff_expects exp; | |
1042 | char *pathspec = NULL; | |
1043 | static const char *files0[] = { | |
1044 | "subdir/deleted_file", | |
1045 | "subdir/modified_file", | |
1046 | "subdir/new_file", | |
1047 | NULL | |
1048 | }; | |
1049 | static const char *files1[] = { | |
1050 | "subdir/deleted_file", | |
1051 | "subdir/directory/", | |
1052 | "subdir/modified_file", | |
1053 | "subdir/new_file", | |
1054 | NULL | |
1055 | }; | |
1056 | static const char *files2[] = { | |
1057 | "subdir/deleted_file", | |
1058 | "subdir/directory/more/notignored", | |
1059 | "subdir/modified_file", | |
1060 | "subdir/new_file", | |
1061 | NULL | |
1062 | }; | |
1063 | ||
1064 | g_repo = cl_git_sandbox_init("status"); | |
1065 | cl_git_mkfile("status/.gitignore", "ignored\n"); | |
1066 | ||
1067 | opts.context_lines = 3; | |
1068 | opts.interhunk_lines = 1; | |
1069 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
1070 | opts.pathspec.strings = &pathspec; | |
1071 | opts.pathspec.count = 1; | |
1072 | pathspec = "subdir"; | |
1073 | ||
1074 | /* baseline for "subdir" pathspec */ | |
1075 | ||
1076 | memset(&exp, 0, sizeof(exp)); | |
1077 | exp.names = files0; | |
1078 | ||
1079 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1080 | ||
1081 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1082 | ||
1083 | cl_assert_equal_i(3, exp.files); | |
1084 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1085 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1086 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1087 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
1088 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1089 | ||
1090 | git_diff_list_free(diff); | |
1091 | ||
1092 | /* empty directory */ | |
1093 | ||
1094 | cl_git_pass(p_mkdir("status/subdir/directory", 0777)); | |
1095 | ||
1096 | memset(&exp, 0, sizeof(exp)); | |
1097 | exp.names = files1; | |
1098 | ||
1099 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1100 | ||
1101 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1102 | ||
1103 | cl_assert_equal_i(4, exp.files); | |
1104 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1105 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1106 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1107 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
1108 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1109 | ||
1110 | git_diff_list_free(diff); | |
1111 | ||
1112 | /* directory with only ignored files */ | |
1113 | ||
1114 | cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777)); | |
1115 | cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n"); | |
1116 | ||
1117 | cl_git_pass(p_mkdir("status/subdir/directory/another", 0777)); | |
1118 | cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n"); | |
1119 | ||
1120 | memset(&exp, 0, sizeof(exp)); | |
1121 | exp.names = files1; | |
1122 | ||
1123 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1124 | ||
1125 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1126 | ||
1127 | cl_assert_equal_i(4, exp.files); | |
1128 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1129 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1130 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1131 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
1132 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1133 | ||
1134 | git_diff_list_free(diff); | |
1135 | ||
1136 | /* directory with ignored directory (contents irrelevant) */ | |
1137 | ||
1138 | cl_git_pass(p_mkdir("status/subdir/directory/more", 0777)); | |
1139 | cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777)); | |
1140 | cl_git_mkfile("status/subdir/directory/more/ignored/notignored", | |
1141 | "inside ignored dir\n"); | |
1142 | ||
1143 | memset(&exp, 0, sizeof(exp)); | |
1144 | exp.names = files1; | |
1145 | ||
1146 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1147 | ||
1148 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1149 | ||
1150 | cl_assert_equal_i(4, exp.files); | |
1151 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1152 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1153 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1154 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
1155 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1156 | ||
1157 | git_diff_list_free(diff); | |
1158 | ||
1159 | /* quick version avoids directory scan */ | |
1160 | ||
1161 | opts.flags = opts.flags | GIT_DIFF_FAST_UNTRACKED_DIRS; | |
1162 | ||
1163 | memset(&exp, 0, sizeof(exp)); | |
1164 | exp.names = files1; | |
1165 | ||
1166 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1167 | ||
1168 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1169 | ||
1170 | cl_assert_equal_i(4, exp.files); | |
1171 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1172 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1173 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1174 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
1175 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1176 | ||
1177 | git_diff_list_free(diff); | |
1178 | ||
1179 | /* directory with nested non-ignored content */ | |
1180 | ||
1181 | opts.flags = opts.flags & ~GIT_DIFF_FAST_UNTRACKED_DIRS; | |
1182 | ||
1183 | cl_git_mkfile("status/subdir/directory/more/notignored", | |
1184 | "not ignored deep under untracked\n"); | |
1185 | ||
1186 | memset(&exp, 0, sizeof(exp)); | |
1187 | exp.names = files1; | |
1188 | ||
1189 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1190 | ||
1191 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1192 | ||
1193 | cl_assert_equal_i(4, exp.files); | |
1194 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1195 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1196 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1197 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
1198 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1199 | ||
1200 | git_diff_list_free(diff); | |
1201 | ||
1202 | /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */ | |
1203 | ||
1204 | opts.flags = opts.flags & ~GIT_DIFF_INCLUDE_IGNORED; | |
1205 | opts.flags = opts.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS; | |
1206 | ||
1207 | memset(&exp, 0, sizeof(exp)); | |
1208 | exp.names = files2; | |
1209 | ||
1210 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1211 | ||
1212 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1213 | ||
1214 | cl_assert_equal_i(4, exp.files); | |
1215 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1216 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1217 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1218 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
1219 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1220 | ||
1221 | git_diff_list_free(diff); | |
1222 | } |