]>
Commit | Line | Data |
---|---|---|
74fa4bfa RB |
1 | #include "clar_libgit2.h" |
2 | #include "diff_helpers.h" | |
c2e43fb1 | 3 | #include "repository.h" |
9c8ed499 | 4 | #include "git2/sys/diff.h" |
240f4af3 | 5 | |
74fa4bfa RB |
6 | static git_repository *g_repo = NULL; |
7 | ||
74fa4bfa RB |
8 | void test_diff_workdir__cleanup(void) |
9 | { | |
854eccbb | 10 | cl_git_sandbox_cleanup(); |
74fa4bfa RB |
11 | } |
12 | ||
13 | void test_diff_workdir__to_index(void) | |
14 | { | |
2f8d30be | 15 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 16 | git_diff *diff = NULL; |
74fa4bfa | 17 | diff_expects exp; |
f335ecd6 | 18 | int use_iterator; |
74fa4bfa | 19 | |
0abd7244 RB |
20 | g_repo = cl_git_sandbox_init("status"); |
21 | ||
74fa4bfa RB |
22 | opts.context_lines = 3; |
23 | opts.interhunk_lines = 1; | |
24 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
25 | ||
56c72b75 | 26 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
74fa4bfa | 27 | |
f335ecd6 RB |
28 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
29 | memset(&exp, 0, sizeof(exp)); | |
30 | ||
31 | if (use_iterator) | |
32 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 33 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
34 | else |
35 | cl_git_pass(git_diff_foreach( | |
793c4385 | 36 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
37 | |
38 | /* to generate these values: | |
39 | * - cd to tests/resources/status, | |
40 | * - mv .gitted .git | |
41 | * - git diff --name-status | |
42 | * - git diff | |
43 | * - mv .git .gitted | |
44 | */ | |
45 | cl_assert_equal_i(13, exp.files); | |
b4f5bb07 RB |
46 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
47 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); | |
48 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); | |
49 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
50 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]); | |
f335ecd6 RB |
51 | |
52 | cl_assert_equal_i(8, exp.hunks); | |
53 | ||
54 | cl_assert_equal_i(14, exp.lines); | |
55 | cl_assert_equal_i(5, exp.line_ctxt); | |
56 | cl_assert_equal_i(4, exp.line_adds); | |
57 | cl_assert_equal_i(5, exp.line_dels); | |
9c8ed499 | 58 | } |
240f4af3 | 59 | |
9c8ed499 RB |
60 | { |
61 | git_diff_perfdata perf = GIT_DIFF_PERFDATA_INIT; | |
62 | cl_git_pass(git_diff_get_perfdata(&perf, diff)); | |
240f4af3 | 63 | cl_assert_equal_sz( |
9c8ed499 RB |
64 | 13 /* in root */ + 3 /* in subdir */, perf.stat_calls); |
65 | cl_assert_equal_sz(5, perf.oid_calculations); | |
f335ecd6 | 66 | } |
74fa4bfa | 67 | |
3ff1d123 | 68 | git_diff_free(diff); |
74fa4bfa RB |
69 | } |
70 | ||
b22369ef ET |
71 | void test_diff_workdir__to_index_with_conflicts(void) |
72 | { | |
73 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
74 | git_diff *diff = NULL; | |
75 | git_index *index; | |
76 | git_index_entry our_entry = {0}, their_entry = {0}; | |
77 | diff_expects exp = {0}; | |
78 | ||
79 | g_repo = cl_git_sandbox_init("status"); | |
80 | ||
81 | opts.context_lines = 3; | |
82 | opts.interhunk_lines = 1; | |
83 | ||
84 | /* Adding an entry that represents a rename gets two files in conflict */ | |
85 | our_entry.path = "subdir/modified_file"; | |
86 | our_entry.mode = 0100644; | |
87 | ||
88 | their_entry.path = "subdir/rename_conflict"; | |
89 | their_entry.mode = 0100644; | |
90 | ||
91 | cl_git_pass(git_repository_index(&index, g_repo)); | |
92 | cl_git_pass(git_index_conflict_add(index, NULL, &our_entry, &their_entry)); | |
93 | ||
94 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, index, &opts)); | |
95 | ||
96 | cl_git_pass(diff_foreach_via_iterator( | |
97 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
98 | ||
99 | cl_assert_equal_i(9, exp.files); | |
100 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
101 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); | |
102 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); | |
103 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_CONFLICTED]); | |
104 | ||
105 | cl_assert_equal_i(7, exp.hunks); | |
106 | ||
107 | cl_assert_equal_i(12, exp.lines); | |
108 | cl_assert_equal_i(4, exp.line_ctxt); | |
109 | cl_assert_equal_i(3, exp.line_adds); | |
110 | cl_assert_equal_i(5, exp.line_dels); | |
111 | ||
112 | git_diff_free(diff); | |
113 | git_index_free(index); | |
114 | } | |
115 | ||
3e57069e RB |
116 | void test_diff_workdir__to_index_with_assume_unchanged(void) |
117 | { | |
118 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
119 | git_diff *diff = NULL; | |
120 | git_index *idx = NULL; | |
121 | diff_expects exp; | |
122 | const git_index_entry *iep; | |
123 | git_index_entry ie; | |
124 | ||
125 | g_repo = cl_git_sandbox_init("status"); | |
126 | ||
127 | /* do initial diff */ | |
128 | ||
129 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
130 | memset(&exp, 0, sizeof(exp)); | |
131 | cl_git_pass(git_diff_foreach( | |
132 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
133 | cl_assert_equal_i(8, exp.files); | |
134 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
135 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); | |
136 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); | |
137 | git_diff_free(diff); | |
138 | ||
139 | /* mark a couple of entries with ASSUME_UNCHANGED */ | |
140 | ||
141 | cl_git_pass(git_repository_index(&idx, g_repo)); | |
142 | ||
143 | cl_assert((iep = git_index_get_bypath(idx, "modified_file", 0)) != NULL); | |
144 | memcpy(&ie, iep, sizeof(ie)); | |
145 | ie.flags |= GIT_IDXENTRY_VALID; | |
146 | cl_git_pass(git_index_add(idx, &ie)); | |
147 | ||
148 | cl_assert((iep = git_index_get_bypath(idx, "file_deleted", 0)) != NULL); | |
149 | memcpy(&ie, iep, sizeof(ie)); | |
150 | ie.flags |= GIT_IDXENTRY_VALID; | |
151 | cl_git_pass(git_index_add(idx, &ie)); | |
152 | ||
153 | cl_git_pass(git_index_write(idx)); | |
154 | git_index_free(idx); | |
155 | ||
156 | /* redo diff and see that entries are skipped */ | |
157 | ||
158 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
159 | memset(&exp, 0, sizeof(exp)); | |
160 | cl_git_pass(git_diff_foreach( | |
161 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
162 | cl_assert_equal_i(6, exp.files); | |
163 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
164 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_DELETED]); | |
165 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); | |
166 | git_diff_free(diff); | |
167 | ||
168 | } | |
169 | ||
74fa4bfa RB |
170 | void test_diff_workdir__to_tree(void) |
171 | { | |
172 | /* grabbed a couple of commit oids from the history of the attr repo */ | |
173 | const char *a_commit = "26a125ee1bf"; /* the current HEAD */ | |
174 | const char *b_commit = "0017bd4ab1ec3"; /* the start */ | |
0abd7244 | 175 | git_tree *a, *b; |
2f8d30be | 176 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 RB |
177 | git_diff *diff = NULL; |
178 | git_diff *diff2 = NULL; | |
74fa4bfa | 179 | diff_expects exp; |
f335ecd6 | 180 | int use_iterator; |
74fa4bfa | 181 | |
0abd7244 RB |
182 | g_repo = cl_git_sandbox_init("status"); |
183 | ||
184 | a = resolve_commit_oid_to_tree(g_repo, a_commit); | |
185 | b = resolve_commit_oid_to_tree(g_repo, b_commit); | |
186 | ||
74fa4bfa RB |
187 | opts.context_lines = 3; |
188 | opts.interhunk_lines = 1; | |
189 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
190 | ||
56c72b75 | 191 | /* You can't really generate the equivalent of git_diff_tree_to_workdir() |
74fa4bfa RB |
192 | * using C git. It really wants to interpose the index into the diff. |
193 | * | |
194 | * To validate the following results with command line git, I ran the | |
195 | * following: | |
196 | * - git ls-tree 26a125 | |
197 | * - find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths | |
198 | * The results are documented at the bottom of this file in the | |
199 | * long comment entitled "PREPARATION OF TEST DATA". | |
200 | */ | |
56c72b75 | 201 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); |
74fa4bfa | 202 | |
f335ecd6 RB |
203 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
204 | memset(&exp, 0, sizeof(exp)); | |
74fa4bfa | 205 | |
f335ecd6 RB |
206 | if (use_iterator) |
207 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 208 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
209 | else |
210 | cl_git_pass(git_diff_foreach( | |
793c4385 | 211 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
212 | |
213 | cl_assert_equal_i(14, exp.files); | |
b4f5bb07 RB |
214 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
215 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); | |
216 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); | |
217 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
218 | cl_assert_equal_i(5, exp.file_status[GIT_DELTA_UNTRACKED]); | |
f335ecd6 | 219 | } |
74fa4bfa RB |
220 | |
221 | /* Since there is no git diff equivalent, let's just assume that the | |
222 | * text diffs produced by git_diff_foreach are accurate here. We will | |
223 | * do more apples-to-apples test comparison below. | |
224 | */ | |
225 | ||
3ff1d123 | 226 | git_diff_free(diff); |
74fa4bfa RB |
227 | diff = NULL; |
228 | memset(&exp, 0, sizeof(exp)); | |
229 | ||
230 | /* This is a compatible emulation of "git diff <sha>" which looks like | |
231 | * a workdir to tree diff (even though it is not really). This is what | |
232 | * you would get from "git diff --name-status 26a125ee1bf" | |
233 | */ | |
56c72b75 RB |
234 | cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); |
235 | cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts)); | |
74fa4bfa | 236 | cl_git_pass(git_diff_merge(diff, diff2)); |
3ff1d123 | 237 | git_diff_free(diff2); |
74fa4bfa | 238 | |
f335ecd6 RB |
239 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
240 | memset(&exp, 0, sizeof(exp)); | |
241 | ||
242 | if (use_iterator) | |
243 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 244 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
245 | else |
246 | cl_git_pass(git_diff_foreach( | |
793c4385 | 247 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
74fa4bfa | 248 | |
f335ecd6 | 249 | cl_assert_equal_i(15, exp.files); |
b4f5bb07 RB |
250 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_ADDED]); |
251 | cl_assert_equal_i(5, exp.file_status[GIT_DELTA_DELETED]); | |
252 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); | |
253 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
254 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); | |
74fa4bfa | 255 | |
f335ecd6 | 256 | cl_assert_equal_i(11, exp.hunks); |
74fa4bfa | 257 | |
f335ecd6 RB |
258 | cl_assert_equal_i(17, exp.lines); |
259 | cl_assert_equal_i(4, exp.line_ctxt); | |
260 | cl_assert_equal_i(8, exp.line_adds); | |
261 | cl_assert_equal_i(5, exp.line_dels); | |
262 | } | |
74fa4bfa | 263 | |
3ff1d123 | 264 | git_diff_free(diff); |
74fa4bfa RB |
265 | diff = NULL; |
266 | memset(&exp, 0, sizeof(exp)); | |
267 | ||
268 | /* Again, emulating "git diff <sha>" for testing purposes using | |
269 | * "git diff --name-status 0017bd4ab1ec3" instead. | |
270 | */ | |
56c72b75 RB |
271 | cl_git_pass(git_diff_tree_to_index(&diff, g_repo, b, NULL, &opts)); |
272 | cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts)); | |
74fa4bfa | 273 | cl_git_pass(git_diff_merge(diff, diff2)); |
3ff1d123 | 274 | git_diff_free(diff2); |
74fa4bfa | 275 | |
f335ecd6 RB |
276 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
277 | memset(&exp, 0, sizeof(exp)); | |
74fa4bfa | 278 | |
f335ecd6 RB |
279 | if (use_iterator) |
280 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 281 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
282 | else |
283 | cl_git_pass(git_diff_foreach( | |
793c4385 | 284 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
74fa4bfa | 285 | |
f335ecd6 | 286 | cl_assert_equal_i(16, exp.files); |
b4f5bb07 RB |
287 | cl_assert_equal_i(5, exp.file_status[GIT_DELTA_ADDED]); |
288 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); | |
289 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); | |
290 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
291 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); | |
74fa4bfa | 292 | |
f335ecd6 RB |
293 | cl_assert_equal_i(12, exp.hunks); |
294 | ||
295 | cl_assert_equal_i(19, exp.lines); | |
296 | cl_assert_equal_i(3, exp.line_ctxt); | |
297 | cl_assert_equal_i(12, exp.line_adds); | |
298 | cl_assert_equal_i(4, exp.line_dels); | |
299 | } | |
74fa4bfa | 300 | |
3ff1d123 | 301 | git_diff_free(diff); |
c19bc93c | 302 | |
e7c85120 RB |
303 | /* Let's try that once more with a reversed diff */ |
304 | ||
305 | opts.flags |= GIT_DIFF_REVERSE; | |
306 | ||
307 | cl_git_pass(git_diff_tree_to_index(&diff, g_repo, b, NULL, &opts)); | |
308 | cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts)); | |
309 | cl_git_pass(git_diff_merge(diff, diff2)); | |
310 | git_diff_free(diff2); | |
311 | ||
312 | memset(&exp, 0, sizeof(exp)); | |
313 | ||
314 | cl_git_pass(git_diff_foreach( | |
315 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
316 | ||
317 | cl_assert_equal_i(16, exp.files); | |
318 | cl_assert_equal_i(5, exp.file_status[GIT_DELTA_DELETED]); | |
319 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_ADDED]); | |
320 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_MODIFIED]); | |
321 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
322 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); | |
323 | ||
324 | cl_assert_equal_i(12, exp.hunks); | |
325 | ||
326 | cl_assert_equal_i(19, exp.lines); | |
327 | cl_assert_equal_i(3, exp.line_ctxt); | |
328 | cl_assert_equal_i(12, exp.line_dels); | |
329 | cl_assert_equal_i(4, exp.line_adds); | |
330 | ||
331 | git_diff_free(diff); | |
332 | ||
333 | /* all done now */ | |
334 | ||
74fa4bfa RB |
335 | git_tree_free(a); |
336 | git_tree_free(b); | |
337 | } | |
338 | ||
14a513e0 RB |
339 | void test_diff_workdir__to_index_with_pathspec(void) |
340 | { | |
2f8d30be | 341 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 342 | git_diff *diff = NULL; |
14a513e0 RB |
343 | diff_expects exp; |
344 | char *pathspec = NULL; | |
f335ecd6 | 345 | int use_iterator; |
14a513e0 | 346 | |
0abd7244 RB |
347 | g_repo = cl_git_sandbox_init("status"); |
348 | ||
14a513e0 RB |
349 | opts.context_lines = 3; |
350 | opts.interhunk_lines = 1; | |
351 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
352 | opts.pathspec.strings = &pathspec; | |
353 | opts.pathspec.count = 1; | |
354 | ||
56c72b75 | 355 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
14a513e0 | 356 | |
f335ecd6 RB |
357 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
358 | memset(&exp, 0, sizeof(exp)); | |
359 | ||
360 | if (use_iterator) | |
361 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 362 | diff, diff_file_cb, NULL, NULL, &exp)); |
f335ecd6 | 363 | else |
793c4385 | 364 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); |
f335ecd6 RB |
365 | |
366 | cl_assert_equal_i(13, exp.files); | |
b4f5bb07 RB |
367 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
368 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); | |
369 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); | |
370 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
371 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]); | |
f335ecd6 | 372 | } |
14a513e0 | 373 | |
3ff1d123 | 374 | git_diff_free(diff); |
14a513e0 | 375 | |
14a513e0 RB |
376 | pathspec = "modified_file"; |
377 | ||
56c72b75 | 378 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
14a513e0 | 379 | |
f335ecd6 RB |
380 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
381 | memset(&exp, 0, sizeof(exp)); | |
382 | ||
383 | if (use_iterator) | |
384 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 385 | diff, diff_file_cb, NULL, NULL, &exp)); |
f335ecd6 | 386 | else |
793c4385 | 387 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); |
f335ecd6 RB |
388 | |
389 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 RB |
390 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
391 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
392 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
393 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
394 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_UNTRACKED]); | |
f335ecd6 | 395 | } |
14a513e0 | 396 | |
3ff1d123 | 397 | git_diff_free(diff); |
14a513e0 | 398 | |
14a513e0 RB |
399 | pathspec = "subdir"; |
400 | ||
56c72b75 | 401 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
14a513e0 | 402 | |
f335ecd6 RB |
403 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
404 | memset(&exp, 0, sizeof(exp)); | |
405 | ||
406 | if (use_iterator) | |
407 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 408 | diff, diff_file_cb, NULL, NULL, &exp)); |
f335ecd6 | 409 | else |
793c4385 | 410 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); |
f335ecd6 RB |
411 | |
412 | cl_assert_equal_i(3, exp.files); | |
b4f5bb07 RB |
413 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
414 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
415 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
416 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
417 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
f335ecd6 | 418 | } |
14a513e0 | 419 | |
3ff1d123 | 420 | git_diff_free(diff); |
14a513e0 | 421 | |
14a513e0 RB |
422 | pathspec = "*_deleted"; |
423 | ||
56c72b75 | 424 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
14a513e0 | 425 | |
f335ecd6 RB |
426 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
427 | memset(&exp, 0, sizeof(exp)); | |
428 | ||
429 | if (use_iterator) | |
430 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 431 | diff, diff_file_cb, NULL, NULL, &exp)); |
f335ecd6 | 432 | else |
793c4385 | 433 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); |
f335ecd6 RB |
434 | |
435 | cl_assert_equal_i(2, exp.files); | |
b4f5bb07 RB |
436 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
437 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_DELETED]); | |
438 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); | |
439 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
440 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_UNTRACKED]); | |
f335ecd6 | 441 | } |
14a513e0 | 442 | |
3ff1d123 | 443 | git_diff_free(diff); |
14a513e0 RB |
444 | } |
445 | ||
0abd7244 RB |
446 | void test_diff_workdir__filemode_changes(void) |
447 | { | |
3ff1d123 | 448 | git_diff *diff = NULL; |
0abd7244 | 449 | diff_expects exp; |
f335ecd6 | 450 | int use_iterator; |
0abd7244 RB |
451 | |
452 | if (!cl_is_chmod_supported()) | |
453 | return; | |
454 | ||
455 | g_repo = cl_git_sandbox_init("issue_592"); | |
456 | ||
1323c6d1 | 457 | cl_repo_set_bool(g_repo, "core.filemode", true); |
0abd7244 RB |
458 | |
459 | /* test once with no mods */ | |
460 | ||
56c72b75 | 461 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); |
0abd7244 | 462 | |
f335ecd6 RB |
463 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
464 | memset(&exp, 0, sizeof(exp)); | |
0abd7244 | 465 | |
f335ecd6 RB |
466 | if (use_iterator) |
467 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 468 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
469 | else |
470 | cl_git_pass(git_diff_foreach( | |
793c4385 | 471 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
472 | |
473 | cl_assert_equal_i(0, exp.files); | |
b4f5bb07 | 474 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); |
f335ecd6 RB |
475 | cl_assert_equal_i(0, exp.hunks); |
476 | } | |
0abd7244 | 477 | |
3ff1d123 | 478 | git_diff_free(diff); |
0abd7244 RB |
479 | |
480 | /* chmod file and test again */ | |
481 | ||
482 | cl_assert(cl_toggle_filemode("issue_592/a.txt")); | |
483 | ||
56c72b75 | 484 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); |
0abd7244 | 485 | |
f335ecd6 RB |
486 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
487 | memset(&exp, 0, sizeof(exp)); | |
0abd7244 | 488 | |
f335ecd6 RB |
489 | if (use_iterator) |
490 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 491 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
492 | else |
493 | cl_git_pass(git_diff_foreach( | |
793c4385 | 494 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
495 | |
496 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 | 497 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); |
f335ecd6 RB |
498 | cl_assert_equal_i(0, exp.hunks); |
499 | } | |
0abd7244 | 500 | |
3ff1d123 | 501 | git_diff_free(diff); |
0abd7244 RB |
502 | |
503 | cl_assert(cl_toggle_filemode("issue_592/a.txt")); | |
0abd7244 RB |
504 | } |
505 | ||
506 | void test_diff_workdir__filemode_changes_with_filemode_false(void) | |
507 | { | |
3ff1d123 | 508 | git_diff *diff = NULL; |
0abd7244 RB |
509 | diff_expects exp; |
510 | ||
511 | if (!cl_is_chmod_supported()) | |
512 | return; | |
513 | ||
514 | g_repo = cl_git_sandbox_init("issue_592"); | |
515 | ||
1323c6d1 | 516 | cl_repo_set_bool(g_repo, "core.filemode", false); |
0abd7244 RB |
517 | |
518 | /* test once with no mods */ | |
519 | ||
56c72b75 | 520 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); |
0abd7244 RB |
521 | |
522 | memset(&exp, 0, sizeof(exp)); | |
523 | cl_git_pass(git_diff_foreach( | |
793c4385 | 524 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
0abd7244 RB |
525 | |
526 | cl_assert_equal_i(0, exp.files); | |
b4f5bb07 | 527 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); |
0abd7244 RB |
528 | cl_assert_equal_i(0, exp.hunks); |
529 | ||
3ff1d123 | 530 | git_diff_free(diff); |
0abd7244 RB |
531 | |
532 | /* chmod file and test again */ | |
533 | ||
534 | cl_assert(cl_toggle_filemode("issue_592/a.txt")); | |
535 | ||
56c72b75 | 536 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); |
0abd7244 RB |
537 | |
538 | memset(&exp, 0, sizeof(exp)); | |
539 | cl_git_pass(git_diff_foreach( | |
793c4385 | 540 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
0abd7244 RB |
541 | |
542 | cl_assert_equal_i(0, exp.files); | |
b4f5bb07 | 543 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); |
0abd7244 RB |
544 | cl_assert_equal_i(0, exp.hunks); |
545 | ||
3ff1d123 | 546 | git_diff_free(diff); |
0abd7244 RB |
547 | |
548 | cl_assert(cl_toggle_filemode("issue_592/a.txt")); | |
0abd7244 RB |
549 | } |
550 | ||
145e696b RB |
551 | void test_diff_workdir__head_index_and_workdir_all_differ(void) |
552 | { | |
2f8d30be | 553 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 554 | git_diff *diff_i2t = NULL, *diff_w2i = NULL; |
145e696b RB |
555 | diff_expects exp; |
556 | char *pathspec = "staged_changes_modified_file"; | |
557 | git_tree *tree; | |
f335ecd6 | 558 | int use_iterator; |
145e696b RB |
559 | |
560 | /* For this file, | |
561 | * - head->index diff has 1 line of context, 1 line of diff | |
562 | * - index->workdir diff has 2 lines of context, 1 line of diff | |
563 | * but | |
564 | * - head->workdir diff has 1 line of context, 2 lines of diff | |
565 | * Let's make sure the right one is returned from each fn. | |
566 | */ | |
567 | ||
568 | g_repo = cl_git_sandbox_init("status"); | |
569 | ||
570 | tree = resolve_commit_oid_to_tree(g_repo, "26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f"); | |
571 | ||
572 | opts.pathspec.strings = &pathspec; | |
573 | opts.pathspec.count = 1; | |
574 | ||
56c72b75 RB |
575 | cl_git_pass(git_diff_tree_to_index(&diff_i2t, g_repo, tree, NULL, &opts)); |
576 | cl_git_pass(git_diff_index_to_workdir(&diff_w2i, g_repo, NULL, &opts)); | |
145e696b | 577 | |
f335ecd6 RB |
578 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
579 | memset(&exp, 0, sizeof(exp)); | |
580 | ||
581 | if (use_iterator) | |
582 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 583 | diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
584 | else |
585 | cl_git_pass(git_diff_foreach( | |
793c4385 | 586 | diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
587 | |
588 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 RB |
589 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
590 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
591 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
592 | cl_assert_equal_i(1, exp.hunks); |
593 | cl_assert_equal_i(2, exp.lines); | |
594 | cl_assert_equal_i(1, exp.line_ctxt); | |
595 | cl_assert_equal_i(1, exp.line_adds); | |
596 | cl_assert_equal_i(0, exp.line_dels); | |
597 | } | |
598 | ||
599 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { | |
600 | memset(&exp, 0, sizeof(exp)); | |
601 | ||
602 | if (use_iterator) | |
603 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 604 | diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
605 | else |
606 | cl_git_pass(git_diff_foreach( | |
793c4385 | 607 | diff_w2i, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
608 | |
609 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 RB |
610 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
611 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
612 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
613 | cl_assert_equal_i(1, exp.hunks); |
614 | cl_assert_equal_i(3, exp.lines); | |
615 | cl_assert_equal_i(2, exp.line_ctxt); | |
616 | cl_assert_equal_i(1, exp.line_adds); | |
617 | cl_assert_equal_i(0, exp.line_dels); | |
618 | } | |
145e696b RB |
619 | |
620 | cl_git_pass(git_diff_merge(diff_i2t, diff_w2i)); | |
621 | ||
f335ecd6 RB |
622 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
623 | memset(&exp, 0, sizeof(exp)); | |
624 | ||
625 | if (use_iterator) | |
626 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 627 | diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
628 | else |
629 | cl_git_pass(git_diff_foreach( | |
793c4385 | 630 | diff_i2t, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
631 | |
632 | cl_assert_equal_i(1, exp.files); | |
b4f5bb07 RB |
633 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
634 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
635 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
636 | cl_assert_equal_i(1, exp.hunks); |
637 | cl_assert_equal_i(3, exp.lines); | |
638 | cl_assert_equal_i(1, exp.line_ctxt); | |
639 | cl_assert_equal_i(2, exp.line_adds); | |
640 | cl_assert_equal_i(0, exp.line_dels); | |
641 | } | |
145e696b | 642 | |
3ff1d123 RB |
643 | git_diff_free(diff_i2t); |
644 | git_diff_free(diff_w2i); | |
cdca82c7 CMN |
645 | |
646 | git_tree_free(tree); | |
145e696b RB |
647 | } |
648 | ||
649 | void test_diff_workdir__eof_newline_changes(void) | |
650 | { | |
2f8d30be | 651 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 652 | git_diff *diff = NULL; |
145e696b RB |
653 | diff_expects exp; |
654 | char *pathspec = "current_file"; | |
f335ecd6 | 655 | int use_iterator; |
145e696b RB |
656 | |
657 | g_repo = cl_git_sandbox_init("status"); | |
658 | ||
659 | opts.pathspec.strings = &pathspec; | |
660 | opts.pathspec.count = 1; | |
661 | ||
56c72b75 | 662 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
145e696b | 663 | |
f335ecd6 RB |
664 | for (use_iterator = 0; use_iterator <= 1; use_iterator++) { |
665 | memset(&exp, 0, sizeof(exp)); | |
666 | ||
667 | if (use_iterator) | |
668 | cl_git_pass(diff_foreach_via_iterator( | |
793c4385 | 669 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
670 | else |
671 | cl_git_pass(git_diff_foreach( | |
793c4385 | 672 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
f335ecd6 RB |
673 | |
674 | cl_assert_equal_i(0, exp.files); | |
b4f5bb07 RB |
675 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
676 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
677 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
678 | cl_assert_equal_i(0, exp.hunks); |
679 | cl_assert_equal_i(0, exp.lines); | |
680 | cl_assert_equal_i(0, exp.line_ctxt); | |
681 | cl_assert_equal_i(0, exp.line_adds); | |
682 | cl_assert_equal_i(0, exp.line_dels); | |
683 | } | |
145e696b | 684 | |
3ff1d123 | 685 | git_diff_free(diff); |
145e696b RB |
686 | |
687 | cl_git_append2file("status/current_file", "\n"); | |
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(1, 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(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
f335ecd6 RB |
705 | cl_assert_equal_i(1, exp.hunks); |
706 | cl_assert_equal_i(2, exp.lines); | |
707 | cl_assert_equal_i(1, exp.line_ctxt); | |
708 | cl_assert_equal_i(1, exp.line_adds); | |
709 | cl_assert_equal_i(0, exp.line_dels); | |
710 | } | |
145e696b | 711 | |
3ff1d123 | 712 | git_diff_free(diff); |
145e696b RB |
713 | |
714 | cl_git_rewritefile("status/current_file", "current_file"); | |
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(3, exp.lines); | |
734 | cl_assert_equal_i(0, exp.line_ctxt); | |
735 | cl_assert_equal_i(1, exp.line_adds); | |
736 | cl_assert_equal_i(2, exp.line_dels); | |
737 | } | |
145e696b | 738 | |
3ff1d123 | 739 | git_diff_free(diff); |
145e696b RB |
740 | } |
741 | ||
74fa4bfa RB |
742 | /* PREPARATION OF TEST DATA |
743 | * | |
56c72b75 | 744 | * Since there is no command line equivalent of git_diff_tree_to_workdir, |
74fa4bfa RB |
745 | * it was a bit of a pain to confirm that I was getting the expected |
746 | * results in the first part of this tests. Here is what I ended up | |
747 | * doing to set my expectation for the file counts and results: | |
748 | * | |
749 | * Running "git ls-tree 26a125" and "git ls-tree aa27a6" shows: | |
750 | * | |
751 | * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file | |
752 | * B 5452d32f1dd538eb0405e8a83cc185f79e25e80f file_deleted | |
753 | * C 452e4244b5d083ddf0460acf1ecc74db9dcfa11a modified_file | |
754 | * D 32504b727382542f9f089e24fddac5e78533e96c staged_changes | |
755 | * E 061d42a44cacde5726057b67558821d95db96f19 staged_changes_file_deleted | |
756 | * F 70bd9443ada07063e7fbf0b3ff5c13f7494d89c2 staged_changes_modified_file | |
757 | * G e9b9107f290627c04d097733a10055af941f6bca staged_delete_file_deleted | |
758 | * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file | |
759 | * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file | |
760 | * J 1888c805345ba265b0ee9449b8877b6064592058 subdir/deleted_file | |
761 | * K a6191982709b746d5650e93c2acf34ef74e11504 subdir/modified_file | |
762 | * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt | |
763 | * | |
764 | * -------- | |
765 | * | |
766 | * find . ! -path ./.git/\* -a -type f | git hash-object --stdin-paths | |
767 | * | |
768 | * A a0de7e0ac200c489c41c59dfa910154a70264e6e current_file | |
769 | * M 6a79f808a9c6bc9531ac726c184bbcd9351ccf11 ignored_file | |
770 | * C 0a539630525aca2e7bc84975958f92f10a64c9b6 modified_file | |
771 | * N d4fa8600b4f37d7516bef4816ae2c64dbf029e3a new_file | |
772 | * D 55d316c9ba708999f1918e9677d01dfcae69c6b9 staged_changes | |
773 | * F 011c3440d5c596e21d836aa6d7b10eb581f68c49 staged_changes_modified_file | |
774 | * H dabc8af9bd6e9f5bbe96a176f1a24baf3d1f8916 staged_delete_modified_file | |
775 | * O 529a16e8e762d4acb7b9636ff540a00831f9155a staged_new_file | |
776 | * P 8b090c06d14ffa09c4e880088ebad33893f921d1 staged_new_file_modified_file | |
777 | * I 53ace0d1cc1145a5f4fe4f78a186a60263190733 subdir/current_file | |
778 | * K 57274b75eeb5f36fd55527806d567b2240a20c57 subdir/modified_file | |
779 | * Q 80a86a6931b91bc01c2dbf5ca55bdd24ad1ef466 subdir/new_file | |
780 | * L e8ee89e15bbe9b20137715232387b3de5b28972e subdir.txt | |
781 | * | |
782 | * -------- | |
783 | * | |
784 | * A - current_file (UNMODIFIED) -> not in results | |
785 | * B D file_deleted | |
786 | * M I ignored_file (IGNORED) | |
787 | * C M modified_file | |
788 | * N U new_file (UNTRACKED) | |
789 | * D M staged_changes | |
790 | * E D staged_changes_file_deleted | |
791 | * F M staged_changes_modified_file | |
792 | * G D staged_delete_file_deleted | |
793 | * H - staged_delete_modified_file (UNMODIFIED) -> not in results | |
794 | * O U staged_new_file | |
795 | * P U staged_new_file_modified_file | |
796 | * I - subdir/current_file (UNMODIFIED) -> not in results | |
797 | * J D subdir/deleted_file | |
798 | * K M subdir/modified_file | |
799 | * Q U subdir/new_file | |
800 | * L - subdir.txt (UNMODIFIED) -> not in results | |
801 | * | |
802 | * Expect 13 files, 0 ADD, 4 DEL, 4 MOD, 1 IGN, 4 UNTR | |
803 | */ | |
49d34c1c RB |
804 | |
805 | ||
806 | void test_diff_workdir__larger_hunks(void) | |
807 | { | |
808 | const char *a_commit = "d70d245ed97ed2aa596dd1af6536e4bfdb047b69"; | |
809 | const char *b_commit = "7a9e0b02e63179929fed24f0a3e0f19168114d10"; | |
810 | git_tree *a, *b; | |
2f8d30be | 811 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3b5f7954 | 812 | size_t i, d, num_d, h, num_h, l, num_l; |
49d34c1c RB |
813 | |
814 | g_repo = cl_git_sandbox_init("diff"); | |
815 | ||
816 | cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL); | |
817 | cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL); | |
818 | ||
819 | opts.context_lines = 1; | |
820 | opts.interhunk_lines = 0; | |
821 | ||
822 | for (i = 0; i <= 2; ++i) { | |
3ff1d123 RB |
823 | git_diff *diff = NULL; |
824 | git_patch *patch; | |
3b5f7954 RB |
825 | const git_diff_hunk *hunk; |
826 | const git_diff_line *line; | |
49d34c1c RB |
827 | |
828 | /* okay, this is a bit silly, but oh well */ | |
829 | switch (i) { | |
830 | case 0: | |
56c72b75 | 831 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
49d34c1c RB |
832 | break; |
833 | case 1: | |
56c72b75 | 834 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); |
49d34c1c RB |
835 | break; |
836 | case 2: | |
56c72b75 | 837 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, b, &opts)); |
49d34c1c RB |
838 | break; |
839 | } | |
840 | ||
5f69a31f RB |
841 | num_d = git_diff_num_deltas(diff); |
842 | cl_assert_equal_i(2, (int)num_d); | |
49d34c1c | 843 | |
5f69a31f | 844 | for (d = 0; d < num_d; ++d) { |
10672e3e | 845 | cl_git_pass(git_patch_from_diff(&patch, diff, d)); |
5f69a31f | 846 | cl_assert(patch); |
49d34c1c | 847 | |
3ff1d123 | 848 | num_h = git_patch_num_hunks(patch); |
5f69a31f | 849 | for (h = 0; h < num_h; h++) { |
3b5f7954 | 850 | cl_git_pass(git_patch_get_hunk(&hunk, &num_l, patch, h)); |
49d34c1c | 851 | |
5f69a31f | 852 | for (l = 0; l < num_l; ++l) { |
3b5f7954 RB |
853 | cl_git_pass( |
854 | git_patch_get_line_in_hunk(&line, patch, h, l)); | |
5f69a31f | 855 | cl_assert(line); |
49d34c1c RB |
856 | } |
857 | ||
5f69a31f | 858 | /* confirm fail after the last item */ |
3b5f7954 RB |
859 | cl_git_fail( |
860 | git_patch_get_line_in_hunk(&line, patch, h, num_l)); | |
49d34c1c RB |
861 | } |
862 | ||
5f69a31f | 863 | /* confirm fail after the last item */ |
3b5f7954 | 864 | cl_git_fail(git_patch_get_hunk(&hunk, &num_l, patch, num_h)); |
49d34c1c | 865 | |
3ff1d123 | 866 | git_patch_free(patch); |
5f69a31f | 867 | } |
49d34c1c | 868 | |
3ff1d123 | 869 | git_diff_free(diff); |
49d34c1c RB |
870 | } |
871 | ||
872 | git_tree_free(a); | |
873 | git_tree_free(b); | |
874 | } | |
5d1308f2 RB |
875 | |
876 | /* Set up a test that exercises this code. The easiest test using existing | |
877 | * test data is probably to create a sandbox of submod2 and then run a | |
56c72b75 | 878 | * git_diff_tree_to_workdir against tree |
5d1308f2 RB |
879 | * 873585b94bdeabccea991ea5e3ec1a277895b698. As for what you should actually |
880 | * test, you can start by just checking that the number of lines of diff | |
881 | * content matches the actual output of git diff. That will at least | |
882 | * demonstrate that the submodule content is being used to generate somewhat | |
883 | * comparable outputs. It is a test that would fail without this code and | |
884 | * will succeed with it. | |
885 | */ | |
886 | ||
887 | #include "../submodule/submodule_helpers.h" | |
888 | ||
889 | void test_diff_workdir__submodules(void) | |
890 | { | |
891 | const char *a_commit = "873585b94bdeabccea991ea5e3ec1a277895b698"; | |
892 | git_tree *a; | |
2f8d30be | 893 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 894 | git_diff *diff = NULL; |
5d1308f2 RB |
895 | diff_expects exp; |
896 | ||
14997dc5 | 897 | g_repo = setup_fixture_submod2(); |
5d1308f2 RB |
898 | |
899 | a = resolve_commit_oid_to_tree(g_repo, a_commit); | |
900 | ||
901 | opts.flags = | |
902 | GIT_DIFF_INCLUDE_UNTRACKED | | |
125655fe | 903 | GIT_DIFF_INCLUDE_IGNORED | |
5d1308f2 | 904 | GIT_DIFF_RECURSE_UNTRACKED_DIRS | |
10672e3e | 905 | GIT_DIFF_SHOW_UNTRACKED_CONTENT; |
5d1308f2 | 906 | |
56c72b75 | 907 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); |
5d1308f2 RB |
908 | |
909 | /* diff_print(stderr, diff); */ | |
910 | ||
911 | /* essentially doing: git diff 873585b94bdeabccea991ea5e3ec1a277895b698 */ | |
912 | ||
913 | memset(&exp, 0, sizeof(exp)); | |
65025cb8 | 914 | |
5d1308f2 | 915 | cl_git_pass(git_diff_foreach( |
793c4385 | 916 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); |
5d1308f2 | 917 | |
ccfa6805 RB |
918 | /* so "git diff 873585" returns: |
919 | * M .gitmodules | |
920 | * A just_a_dir/contents | |
921 | * A just_a_file | |
922 | * A sm_added_and_uncommited | |
923 | * A sm_changed_file | |
924 | * A sm_changed_head | |
925 | * A sm_changed_index | |
926 | * A sm_changed_untracked_file | |
927 | * M sm_missing_commits | |
928 | * A sm_unchanged | |
929 | * which is a little deceptive because of the difference between the | |
930 | * "git diff <treeish>" results from "git_diff_tree_to_workdir". The | |
931 | * only significant difference is that those Added items will show up | |
932 | * as Untracked items in the pure libgit2 diff. | |
933 | * | |
d3bc95fd | 934 | * Then add in the two extra untracked items "not" and "not-submodule" |
ccfa6805 | 935 | * to get the 12 files reported here. |
5d1308f2 RB |
936 | */ |
937 | ||
ccfa6805 | 938 | cl_assert_equal_i(12, exp.files); |
5d1308f2 | 939 | |
b4f5bb07 RB |
940 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); |
941 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_DELETED]); | |
ccfa6805 | 942 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_MODIFIED]); |
d3bc95fd RB |
943 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); |
944 | cl_assert_equal_i(10, exp.file_status[GIT_DELTA_UNTRACKED]); | |
5d1308f2 RB |
945 | |
946 | /* the following numbers match "git diff 873585" exactly */ | |
947 | ||
948 | cl_assert_equal_i(9, exp.hunks); | |
949 | ||
950 | cl_assert_equal_i(33, exp.lines); | |
951 | cl_assert_equal_i(2, exp.line_ctxt); | |
952 | cl_assert_equal_i(30, exp.line_adds); | |
953 | cl_assert_equal_i(1, exp.line_dels); | |
954 | ||
3ff1d123 | 955 | git_diff_free(diff); |
5d1308f2 RB |
956 | git_tree_free(a); |
957 | } | |
c2e43fb1 | 958 | |
959 | void test_diff_workdir__cannot_diff_against_a_bare_repository(void) | |
960 | { | |
2f8d30be | 961 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 962 | git_diff *diff = NULL; |
c2e43fb1 | 963 | git_tree *tree; |
964 | ||
965 | g_repo = cl_git_sandbox_init("testrepo.git"); | |
966 | ||
5735bf5e | 967 | cl_assert_equal_i( |
56c72b75 | 968 | GIT_EBAREREPO, git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
c2e43fb1 | 969 | |
970 | cl_git_pass(git_repository_head_tree(&tree, g_repo)); | |
5735bf5e RB |
971 | |
972 | cl_assert_equal_i( | |
56c72b75 | 973 | GIT_EBAREREPO, git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); |
c2e43fb1 | 974 | |
975 | git_tree_free(tree); | |
976 | } | |
59a0d772 | 977 | |
978 | void test_diff_workdir__to_null_tree(void) | |
979 | { | |
3ff1d123 | 980 | git_diff *diff; |
59a0d772 | 981 | diff_expects exp; |
2f8d30be | 982 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
59a0d772 | 983 | |
984 | opts.flags = GIT_DIFF_INCLUDE_UNTRACKED | | |
985 | GIT_DIFF_RECURSE_UNTRACKED_DIRS; | |
986 | ||
987 | g_repo = cl_git_sandbox_init("status"); | |
988 | ||
56c72b75 | 989 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts)); |
59a0d772 | 990 | |
991 | memset(&exp, 0, sizeof(exp)); | |
992 | ||
993 | cl_git_pass(git_diff_foreach( | |
994 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
995 | ||
996 | cl_assert_equal_i(exp.files, exp.file_status[GIT_DELTA_UNTRACKED]); | |
997 | ||
3ff1d123 | 998 | git_diff_free(diff); |
59a0d772 | 999 | } |
2f8d30be BS |
1000 | |
1001 | void test_diff_workdir__checks_options_version(void) | |
1002 | { | |
3ff1d123 | 1003 | git_diff *diff; |
2f8d30be BS |
1004 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
1005 | const git_error *err; | |
1006 | ||
1007 | g_repo = cl_git_sandbox_init("status"); | |
1008 | ||
1009 | opts.version = 0; | |
56c72b75 | 1010 | cl_git_fail(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts)); |
2f8d30be BS |
1011 | err = giterr_last(); |
1012 | cl_assert_equal_i(GITERR_INVALID, err->klass); | |
1013 | ||
1014 | giterr_clear(); | |
1015 | opts.version = 1024; | |
56c72b75 | 1016 | cl_git_fail(git_diff_tree_to_workdir(&diff, g_repo, NULL, &opts)); |
2f8d30be BS |
1017 | err = giterr_last(); |
1018 | cl_assert_equal_i(GITERR_INVALID, err->klass); | |
1019 | } | |
de590550 RB |
1020 | |
1021 | void test_diff_workdir__can_diff_empty_file(void) | |
1022 | { | |
3ff1d123 | 1023 | git_diff *diff; |
de590550 RB |
1024 | git_tree *tree; |
1025 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
1026 | struct stat st; | |
3ff1d123 | 1027 | git_patch *patch; |
de590550 RB |
1028 | |
1029 | g_repo = cl_git_sandbox_init("attr_index"); | |
1030 | ||
1031 | tree = resolve_commit_oid_to_tree(g_repo, "3812cfef3661"); /* HEAD */ | |
1032 | ||
1033 | /* baseline - make sure there are no outstanding diffs */ | |
1034 | ||
1035 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); | |
1036 | cl_assert_equal_i(2, (int)git_diff_num_deltas(diff)); | |
3ff1d123 | 1037 | git_diff_free(diff); |
de590550 RB |
1038 | |
1039 | /* empty contents of file */ | |
1040 | ||
1041 | cl_git_rewritefile("attr_index/README.txt", ""); | |
1042 | cl_git_pass(git_path_lstat("attr_index/README.txt", &st)); | |
1043 | cl_assert_equal_i(0, (int)st.st_size); | |
1044 | ||
1045 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); | |
1046 | cl_assert_equal_i(3, (int)git_diff_num_deltas(diff)); | |
1047 | /* diffs are: .gitattributes, README.txt, sub/sub/.gitattributes */ | |
10672e3e | 1048 | cl_git_pass(git_patch_from_diff(&patch, diff, 1)); |
3ff1d123 RB |
1049 | git_patch_free(patch); |
1050 | git_diff_free(diff); | |
de590550 RB |
1051 | |
1052 | /* remove a file altogether */ | |
1053 | ||
1054 | cl_git_pass(p_unlink("attr_index/README.txt")); | |
1055 | cl_assert(!git_path_exists("attr_index/README.txt")); | |
1056 | ||
1057 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, tree, &opts)); | |
1058 | cl_assert_equal_i(3, (int)git_diff_num_deltas(diff)); | |
10672e3e | 1059 | cl_git_pass(git_patch_from_diff(&patch, diff, 1)); |
3ff1d123 RB |
1060 | git_patch_free(patch); |
1061 | git_diff_free(diff); | |
8842c75f VM |
1062 | |
1063 | git_tree_free(tree); | |
de590550 | 1064 | } |
b8acb775 | 1065 | |
b8acb775 SS |
1066 | void test_diff_workdir__to_index_issue_1397(void) |
1067 | { | |
1068 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
3ff1d123 | 1069 | git_diff *diff = NULL; |
b8acb775 | 1070 | diff_expects exp; |
b8acb775 SS |
1071 | |
1072 | g_repo = cl_git_sandbox_init("issue_1397"); | |
1073 | ||
1098cfae | 1074 | cl_repo_set_bool(g_repo, "core.autocrlf", true); |
b8acb775 SS |
1075 | |
1076 | opts.context_lines = 3; | |
1077 | opts.interhunk_lines = 1; | |
1078 | ||
1079 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1080 | ||
1098cfae RB |
1081 | memset(&exp, 0, sizeof(exp)); |
1082 | cl_git_pass(git_diff_foreach( | |
1083 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
b8acb775 | 1084 | |
1098cfae RB |
1085 | cl_assert_equal_i(0, exp.files); |
1086 | cl_assert_equal_i(0, exp.hunks); | |
1087 | cl_assert_equal_i(0, exp.lines); | |
b8acb775 | 1088 | |
3ff1d123 | 1089 | git_diff_free(diff); |
b8acb775 | 1090 | diff = NULL; |
b8acb775 | 1091 | |
1098cfae RB |
1092 | cl_git_rewritefile("issue_1397/crlf_file.txt", |
1093 | "first line\r\nsecond line modified\r\nboth with crlf"); | |
b8acb775 SS |
1094 | |
1095 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1096 | ||
1098cfae RB |
1097 | memset(&exp, 0, sizeof(exp)); |
1098 | cl_git_pass(git_diff_foreach( | |
1099 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
b8acb775 | 1100 | |
1098cfae RB |
1101 | cl_assert_equal_i(1, exp.files); |
1102 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
b8acb775 | 1103 | |
1098cfae | 1104 | cl_assert_equal_i(1, exp.hunks); |
b8acb775 | 1105 | |
1098cfae RB |
1106 | cl_assert_equal_i(5, exp.lines); |
1107 | cl_assert_equal_i(3, exp.line_ctxt); | |
1108 | cl_assert_equal_i(1, exp.line_adds); | |
1109 | cl_assert_equal_i(1, exp.line_dels); | |
b8acb775 | 1110 | |
3ff1d123 | 1111 | git_diff_free(diff); |
b8acb775 SS |
1112 | } |
1113 | ||
1114 | void test_diff_workdir__to_tree_issue_1397(void) | |
1115 | { | |
1098cfae | 1116 | const char *a_commit = "7f483a738"; /* the current HEAD */ |
b8acb775 SS |
1117 | git_tree *a; |
1118 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
3ff1d123 RB |
1119 | git_diff *diff = NULL; |
1120 | git_diff *diff2 = NULL; | |
b8acb775 | 1121 | diff_expects exp; |
b8acb775 SS |
1122 | |
1123 | g_repo = cl_git_sandbox_init("issue_1397"); | |
1124 | ||
1098cfae | 1125 | cl_repo_set_bool(g_repo, "core.autocrlf", true); |
b8acb775 SS |
1126 | |
1127 | a = resolve_commit_oid_to_tree(g_repo, a_commit); | |
1128 | ||
1129 | opts.context_lines = 3; | |
1130 | opts.interhunk_lines = 1; | |
1131 | ||
1132 | cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, a, &opts)); | |
1133 | ||
1098cfae RB |
1134 | memset(&exp, 0, sizeof(exp)); |
1135 | cl_git_pass(git_diff_foreach( | |
1136 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
b8acb775 | 1137 | |
1098cfae RB |
1138 | cl_assert_equal_i(0, exp.files); |
1139 | cl_assert_equal_i(0, exp.hunks); | |
1140 | cl_assert_equal_i(0, exp.lines); | |
b8acb775 | 1141 | |
3ff1d123 | 1142 | git_diff_free(diff); |
b8acb775 | 1143 | diff = NULL; |
b8acb775 | 1144 | |
b8acb775 SS |
1145 | cl_git_pass(git_diff_tree_to_index(&diff, g_repo, a, NULL, &opts)); |
1146 | cl_git_pass(git_diff_index_to_workdir(&diff2, g_repo, NULL, &opts)); | |
1147 | cl_git_pass(git_diff_merge(diff, diff2)); | |
3ff1d123 | 1148 | git_diff_free(diff2); |
b8acb775 | 1149 | |
1098cfae RB |
1150 | memset(&exp, 0, sizeof(exp)); |
1151 | cl_git_pass(git_diff_foreach( | |
1152 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
b8acb775 | 1153 | |
1098cfae RB |
1154 | cl_assert_equal_i(0, exp.files); |
1155 | cl_assert_equal_i(0, exp.hunks); | |
1156 | cl_assert_equal_i(0, exp.lines); | |
b8acb775 | 1157 | |
3ff1d123 | 1158 | git_diff_free(diff); |
b8acb775 SS |
1159 | git_tree_free(a); |
1160 | } | |
a66c4bc8 RB |
1161 | |
1162 | void test_diff_workdir__untracked_directory_scenarios(void) | |
1163 | { | |
1164 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
3ff1d123 | 1165 | git_diff *diff = NULL; |
a66c4bc8 RB |
1166 | diff_expects exp; |
1167 | char *pathspec = NULL; | |
1168 | static const char *files0[] = { | |
1169 | "subdir/deleted_file", | |
1170 | "subdir/modified_file", | |
1171 | "subdir/new_file", | |
1172 | NULL | |
1173 | }; | |
1174 | static const char *files1[] = { | |
1175 | "subdir/deleted_file", | |
1176 | "subdir/directory/", | |
1177 | "subdir/modified_file", | |
1178 | "subdir/new_file", | |
1179 | NULL | |
1180 | }; | |
1181 | static const char *files2[] = { | |
1182 | "subdir/deleted_file", | |
1183 | "subdir/directory/more/notignored", | |
1184 | "subdir/modified_file", | |
1185 | "subdir/new_file", | |
1186 | NULL | |
1187 | }; | |
1188 | ||
1189 | g_repo = cl_git_sandbox_init("status"); | |
1190 | cl_git_mkfile("status/.gitignore", "ignored\n"); | |
1191 | ||
1192 | opts.context_lines = 3; | |
1193 | opts.interhunk_lines = 1; | |
1194 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
1195 | opts.pathspec.strings = &pathspec; | |
1196 | opts.pathspec.count = 1; | |
1197 | pathspec = "subdir"; | |
1198 | ||
1199 | /* baseline for "subdir" pathspec */ | |
1200 | ||
1201 | memset(&exp, 0, sizeof(exp)); | |
1202 | exp.names = files0; | |
1203 | ||
1204 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1205 | ||
1206 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1207 | ||
1208 | cl_assert_equal_i(3, exp.files); | |
1209 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1210 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1211 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1212 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
1213 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1214 | ||
3ff1d123 | 1215 | git_diff_free(diff); |
a66c4bc8 RB |
1216 | |
1217 | /* empty directory */ | |
1218 | ||
1219 | cl_git_pass(p_mkdir("status/subdir/directory", 0777)); | |
1220 | ||
1221 | memset(&exp, 0, sizeof(exp)); | |
1222 | exp.names = files1; | |
1223 | ||
94ef2a35 RB |
1224 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
1225 | ||
1226 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1227 | ||
1228 | cl_assert_equal_i(4, exp.files); | |
1229 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1230 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1231 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1232 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
1233 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1234 | ||
3ff1d123 | 1235 | git_diff_free(diff); |
94ef2a35 RB |
1236 | |
1237 | /* empty directory in empty directory */ | |
1238 | ||
1239 | cl_git_pass(p_mkdir("status/subdir/directory/empty", 0777)); | |
1240 | ||
1241 | memset(&exp, 0, sizeof(exp)); | |
1242 | exp.names = files1; | |
1243 | ||
a66c4bc8 RB |
1244 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); |
1245 | ||
1246 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1247 | ||
1248 | cl_assert_equal_i(4, exp.files); | |
1249 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1250 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1251 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1252 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
1253 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1254 | ||
3ff1d123 | 1255 | git_diff_free(diff); |
a66c4bc8 RB |
1256 | |
1257 | /* directory with only ignored files */ | |
1258 | ||
1259 | cl_git_pass(p_mkdir("status/subdir/directory/deeper", 0777)); | |
1260 | cl_git_mkfile("status/subdir/directory/deeper/ignored", "ignore me\n"); | |
1261 | ||
1262 | cl_git_pass(p_mkdir("status/subdir/directory/another", 0777)); | |
1263 | cl_git_mkfile("status/subdir/directory/another/ignored", "ignore me\n"); | |
1264 | ||
1265 | memset(&exp, 0, sizeof(exp)); | |
1266 | exp.names = files1; | |
1267 | ||
1268 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1269 | ||
1270 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1271 | ||
1272 | cl_assert_equal_i(4, exp.files); | |
1273 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1274 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1275 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1276 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
1277 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1278 | ||
3ff1d123 | 1279 | git_diff_free(diff); |
a66c4bc8 RB |
1280 | |
1281 | /* directory with ignored directory (contents irrelevant) */ | |
1282 | ||
1283 | cl_git_pass(p_mkdir("status/subdir/directory/more", 0777)); | |
1284 | cl_git_pass(p_mkdir("status/subdir/directory/more/ignored", 0777)); | |
1285 | cl_git_mkfile("status/subdir/directory/more/ignored/notignored", | |
1286 | "inside ignored dir\n"); | |
1287 | ||
1288 | memset(&exp, 0, sizeof(exp)); | |
1289 | exp.names = files1; | |
1290 | ||
1291 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1292 | ||
1293 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1294 | ||
1295 | cl_assert_equal_i(4, exp.files); | |
1296 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1297 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1298 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1299 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
1300 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1301 | ||
3ff1d123 | 1302 | git_diff_free(diff); |
a66c4bc8 RB |
1303 | |
1304 | /* quick version avoids directory scan */ | |
1305 | ||
10672e3e | 1306 | opts.flags = opts.flags | GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS; |
a66c4bc8 RB |
1307 | |
1308 | memset(&exp, 0, sizeof(exp)); | |
1309 | exp.names = files1; | |
1310 | ||
1311 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1312 | ||
1313 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1314 | ||
1315 | cl_assert_equal_i(4, exp.files); | |
1316 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1317 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1318 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1319 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
1320 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1321 | ||
3ff1d123 | 1322 | git_diff_free(diff); |
a66c4bc8 RB |
1323 | |
1324 | /* directory with nested non-ignored content */ | |
1325 | ||
10672e3e | 1326 | opts.flags = opts.flags & ~GIT_DIFF_ENABLE_FAST_UNTRACKED_DIRS; |
a66c4bc8 RB |
1327 | |
1328 | cl_git_mkfile("status/subdir/directory/more/notignored", | |
1329 | "not ignored deep under untracked\n"); | |
1330 | ||
1331 | memset(&exp, 0, sizeof(exp)); | |
1332 | exp.names = files1; | |
1333 | ||
1334 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1335 | ||
1336 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1337 | ||
1338 | cl_assert_equal_i(4, exp.files); | |
1339 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1340 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1341 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1342 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
1343 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1344 | ||
3ff1d123 | 1345 | git_diff_free(diff); |
a66c4bc8 RB |
1346 | |
1347 | /* use RECURSE_UNTRACKED_DIRS to get actual untracked files (no ignores) */ | |
1348 | ||
1349 | opts.flags = opts.flags & ~GIT_DIFF_INCLUDE_IGNORED; | |
1350 | opts.flags = opts.flags | GIT_DIFF_RECURSE_UNTRACKED_DIRS; | |
1351 | ||
1352 | memset(&exp, 0, sizeof(exp)); | |
1353 | exp.names = files2; | |
1354 | ||
1355 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1356 | ||
1357 | cl_git_pass(git_diff_foreach(diff, diff_file_cb, NULL, NULL, &exp)); | |
1358 | ||
1359 | cl_assert_equal_i(4, exp.files); | |
1360 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1361 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_DELETED]); | |
1362 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_MODIFIED]); | |
1363 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_IGNORED]); | |
1364 | cl_assert_equal_i(2, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1365 | ||
3ff1d123 | 1366 | git_diff_free(diff); |
a66c4bc8 | 1367 | } |
79ef3be4 RB |
1368 | |
1369 | ||
1370 | void test_diff_workdir__untracked_directory_comes_last(void) | |
1371 | { | |
1372 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
3ff1d123 | 1373 | git_diff *diff = NULL; |
79ef3be4 RB |
1374 | |
1375 | g_repo = cl_git_sandbox_init("renames"); | |
1376 | ||
1377 | cl_git_mkfile("renames/.gitignore", "*.ign\n"); | |
1378 | cl_git_pass(p_mkdir("renames/zzz_untracked", 0777)); | |
1379 | cl_git_mkfile("renames/zzz_untracked/an.ign", "ignore me please"); | |
1380 | cl_git_mkfile("renames/zzz_untracked/skip.ign", "ignore me really"); | |
1381 | cl_git_mkfile("renames/zzz_untracked/test.ign", "ignore me now"); | |
1382 | ||
1383 | opts.context_lines = 3; | |
1384 | opts.interhunk_lines = 1; | |
1385 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
1386 | ||
1387 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1388 | ||
1389 | cl_assert(diff != NULL); | |
1390 | ||
3ff1d123 | 1391 | git_diff_free(diff); |
79ef3be4 | 1392 | } |
634f10f6 RB |
1393 | |
1394 | void test_diff_workdir__untracked_with_bom(void) | |
1395 | { | |
1396 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
3ff1d123 | 1397 | git_diff *diff = NULL; |
634f10f6 RB |
1398 | const git_diff_delta *delta; |
1399 | ||
1400 | g_repo = cl_git_sandbox_init("empty_standard_repo"); | |
1401 | cl_repo_set_bool(g_repo, "core.autocrlf", true); | |
1402 | ||
1403 | cl_git_write2file("empty_standard_repo/bom.txt", | |
1404 | "\xFF\xFE\x31\x00\x32\x00\x33\x00\x34\x00", 10, O_WRONLY|O_CREAT, 0664); | |
1405 | ||
1406 | opts.flags = | |
10672e3e | 1407 | GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_SHOW_UNTRACKED_CONTENT; |
634f10f6 RB |
1408 | |
1409 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1410 | ||
1411 | cl_assert_equal_i(1, git_diff_num_deltas(diff)); | |
10672e3e | 1412 | cl_assert((delta = git_diff_get_delta(diff, 0)) != NULL); |
634f10f6 | 1413 | cl_assert_equal_i(GIT_DELTA_UNTRACKED, delta->status); |
10672e3e RB |
1414 | |
1415 | /* not known at this point | |
1416 | * cl_assert((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); | |
1417 | */ | |
634f10f6 | 1418 | |
3ff1d123 | 1419 | git_diff_free(diff); |
634f10f6 | 1420 | } |
5de4ec81 RB |
1421 | |
1422 | void test_diff_workdir__patience_diff(void) | |
1423 | { | |
1424 | git_index *index; | |
1425 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
1426 | git_diff *diff = NULL; | |
1427 | git_patch *patch = NULL; | |
c05cd792 | 1428 | git_buf buf = GIT_BUF_INIT; |
5de4ec81 RB |
1429 | const char *expected_normal = "diff --git a/test.txt b/test.txt\nindex 34a5acc..d52725f 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,10 +1,7 @@\n When I wrote this\n I did not know\n-how to create\n-a patience diff\n I did not know\n how to create\n+a patience diff\n another problem\n-I did not know\n-how to create\n a minimal diff\n"; |
1430 | const char *expected_patience = "diff --git a/test.txt b/test.txt\nindex 34a5acc..d52725f 100644\n--- a/test.txt\n+++ b/test.txt\n@@ -1,10 +1,7 @@\n When I wrote this\n I did not know\n+I did not know\n how to create\n a patience diff\n-I did not know\n-how to create\n another problem\n-I did not know\n-how to create\n a minimal diff\n"; | |
1431 | ||
1432 | g_repo = cl_git_sandbox_init("empty_standard_repo"); | |
1433 | cl_repo_set_bool(g_repo, "core.autocrlf", true); | |
1434 | cl_git_pass(git_repository_index(&index, g_repo)); | |
1435 | ||
1436 | cl_git_mkfile( | |
1437 | "empty_standard_repo/test.txt", | |
1438 | "When I wrote this\nI did not know\nhow to create\na patience diff\nI did not know\nhow to create\nanother problem\nI did not know\nhow to create\na minimal diff\n"); | |
1439 | cl_git_pass(git_index_add_bypath(index, "test.txt")); | |
1440 | cl_repo_commit_from_index(NULL, g_repo, NULL, 1372350000, "Base"); | |
187009e2 | 1441 | git_index_free(index); |
5de4ec81 RB |
1442 | |
1443 | cl_git_rewritefile( | |
1444 | "empty_standard_repo/test.txt", | |
1445 | "When I wrote this\nI did not know\nI did not know\nhow to create\na patience diff\nanother problem\na minimal diff\n"); | |
1446 | ||
1447 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1448 | cl_assert_equal_i(1, git_diff_num_deltas(diff)); | |
1449 | cl_git_pass(git_patch_from_diff(&patch, diff, 0)); | |
c05cd792 | 1450 | cl_git_pass(git_patch_to_buf(&buf, patch)); |
5de4ec81 | 1451 | |
c05cd792 NH |
1452 | cl_assert_equal_s(expected_normal, buf.ptr); |
1453 | git_buf_clear(&buf); | |
5de4ec81 RB |
1454 | git_patch_free(patch); |
1455 | git_diff_free(diff); | |
1456 | ||
1457 | opts.flags |= GIT_DIFF_PATIENCE; | |
1458 | ||
1459 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1460 | cl_assert_equal_i(1, git_diff_num_deltas(diff)); | |
1461 | cl_git_pass(git_patch_from_diff(&patch, diff, 0)); | |
c05cd792 | 1462 | cl_git_pass(git_patch_to_buf(&buf, patch)); |
5de4ec81 | 1463 | |
c05cd792 NH |
1464 | cl_assert_equal_s(expected_patience, buf.ptr); |
1465 | git_buf_clear(&buf); | |
1466 | ||
1467 | git_buf_free(&buf); | |
5de4ec81 RB |
1468 | git_patch_free(patch); |
1469 | git_diff_free(diff); | |
1470 | } | |
4bf630b6 RB |
1471 | |
1472 | void test_diff_workdir__with_stale_index(void) | |
1473 | { | |
1474 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
1475 | git_diff *diff = NULL; | |
1476 | git_index *idx = NULL; | |
1477 | diff_expects exp; | |
1478 | ||
1479 | g_repo = cl_git_sandbox_init("status"); | |
1480 | cl_git_pass(git_repository_index(&idx, g_repo)); | |
1481 | ||
1482 | /* make the in-memory index invalid */ | |
1483 | { | |
1484 | git_repository *r2; | |
1485 | git_index *idx2; | |
1486 | cl_git_pass(git_repository_open(&r2, "status")); | |
1487 | cl_git_pass(git_repository_index(&idx2, r2)); | |
1488 | cl_git_pass(git_index_add_bypath(idx2, "new_file")); | |
1489 | cl_git_pass(git_index_add_bypath(idx2, "subdir/new_file")); | |
1490 | cl_git_pass(git_index_remove_bypath(idx2, "staged_new_file")); | |
1491 | cl_git_pass(git_index_remove_bypath(idx2, "staged_changes_file_deleted")); | |
1492 | cl_git_pass(git_index_write(idx2)); | |
1493 | git_index_free(idx2); | |
1494 | git_repository_free(r2); | |
1495 | } | |
1496 | ||
1497 | opts.context_lines = 3; | |
1498 | opts.interhunk_lines = 1; | |
1499 | opts.flags |= GIT_DIFF_INCLUDE_UNTRACKED | GIT_DIFF_INCLUDE_UNMODIFIED; | |
1500 | ||
1501 | /* first try with index pointer which should prevent reload */ | |
1502 | ||
1503 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, idx, &opts)); | |
1504 | ||
1505 | memset(&exp, 0, sizeof(exp)); | |
1506 | ||
1507 | cl_git_pass(git_diff_foreach( | |
1508 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
1509 | ||
1510 | cl_assert_equal_i(17, exp.files); | |
1511 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1512 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); | |
1513 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); | |
1514 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1515 | cl_assert_equal_i(5, exp.file_status[GIT_DELTA_UNMODIFIED]); | |
1516 | ||
1517 | git_diff_free(diff); | |
1518 | ||
1519 | /* now let's try without the index pointer which should trigger reload */ | |
1520 | ||
1521 | /* two files that were UNTRACKED should have become UNMODIFIED */ | |
1522 | /* one file that was UNMODIFIED should now have become UNTRACKED */ | |
1523 | /* one file that was DELETED should now be gone completely */ | |
1524 | ||
1525 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts)); | |
1526 | ||
1527 | memset(&exp, 0, sizeof(exp)); | |
1528 | ||
1529 | cl_git_pass(git_diff_foreach( | |
1530 | diff, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
1531 | ||
61080a95 | 1532 | git_diff_free(diff); |
1533 | ||
4bf630b6 RB |
1534 | cl_assert_equal_i(16, exp.files); |
1535 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1536 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_DELETED]); | |
1537 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); | |
1538 | cl_assert_equal_i(3, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1539 | cl_assert_equal_i(6, exp.file_status[GIT_DELTA_UNMODIFIED]); | |
1540 | ||
1541 | git_index_free(idx); | |
1542 | } | |
94fb4aad RB |
1543 | |
1544 | static int touch_file(void *payload, git_buf *path) | |
1545 | { | |
1546 | int fd; | |
1547 | char b; | |
1548 | ||
1549 | GIT_UNUSED(payload); | |
1550 | if (git_path_isdir(path->ptr)) | |
1551 | return 0; | |
1552 | ||
1553 | cl_assert((fd = p_open(path->ptr, O_RDWR)) >= 0); | |
1554 | cl_assert_equal_i(1, p_read(fd, &b, 1)); | |
1555 | cl_must_pass(p_lseek(fd, 0, SEEK_SET)); | |
1556 | cl_must_pass(p_write(fd, &b, 1)); | |
1557 | cl_must_pass(p_close(fd)); | |
1558 | ||
1559 | return 0; | |
1560 | } | |
1561 | ||
1562 | static void basic_diff_status(git_diff **out, const git_diff_options *opts) | |
1563 | { | |
1564 | diff_expects exp; | |
1565 | ||
1566 | cl_git_pass(git_diff_index_to_workdir(out, g_repo, NULL, opts)); | |
1567 | ||
1568 | memset(&exp, 0, sizeof(exp)); | |
1569 | ||
1570 | cl_git_pass(git_diff_foreach( | |
1571 | *out, diff_file_cb, diff_hunk_cb, diff_line_cb, &exp)); | |
1572 | ||
1573 | cl_assert_equal_i(13, exp.files); | |
1574 | cl_assert_equal_i(0, exp.file_status[GIT_DELTA_ADDED]); | |
1575 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_DELETED]); | |
1576 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_MODIFIED]); | |
1577 | cl_assert_equal_i(1, exp.file_status[GIT_DELTA_IGNORED]); | |
1578 | cl_assert_equal_i(4, exp.file_status[GIT_DELTA_UNTRACKED]); | |
1579 | } | |
1580 | ||
1581 | void test_diff_workdir__can_update_index(void) | |
1582 | { | |
1583 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
1584 | git_diff *diff = NULL; | |
9c8ed499 | 1585 | git_diff_perfdata perf = GIT_DIFF_PERFDATA_INIT; |
94fb4aad RB |
1586 | |
1587 | g_repo = cl_git_sandbox_init("status"); | |
1588 | ||
1589 | /* touch all the files so stat times are different */ | |
1590 | { | |
1591 | git_buf path = GIT_BUF_INIT; | |
1592 | cl_git_pass(git_buf_sets(&path, "status")); | |
1593 | cl_git_pass(git_path_direach(&path, 0, touch_file, NULL)); | |
1594 | git_buf_free(&path); | |
1595 | } | |
1596 | ||
1597 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
1598 | ||
1599 | basic_diff_status(&diff, &opts); | |
9c8ed499 RB |
1600 | |
1601 | cl_git_pass(git_diff_get_perfdata(&perf, diff)); | |
1602 | cl_assert_equal_sz(13 + 3, perf.stat_calls); | |
1603 | cl_assert_equal_sz(5, perf.oid_calculations); | |
94fb4aad RB |
1604 | |
1605 | git_diff_free(diff); | |
1606 | ||
1607 | /* now allow diff to update stat cache */ | |
1608 | opts.flags |= GIT_DIFF_UPDATE_INDEX; | |
1609 | ||
1610 | basic_diff_status(&diff, &opts); | |
9c8ed499 RB |
1611 | |
1612 | cl_git_pass(git_diff_get_perfdata(&perf, diff)); | |
1613 | cl_assert_equal_sz(13 + 3, perf.stat_calls); | |
1614 | cl_assert_equal_sz(5, perf.oid_calculations); | |
94fb4aad RB |
1615 | |
1616 | git_diff_free(diff); | |
1617 | ||
1618 | /* now if we do it again, we should see fewer OID calculations */ | |
1619 | ||
1620 | basic_diff_status(&diff, &opts); | |
9c8ed499 RB |
1621 | |
1622 | cl_git_pass(git_diff_get_perfdata(&perf, diff)); | |
1623 | cl_assert_equal_sz(13 + 3, perf.stat_calls); | |
1624 | cl_assert_equal_sz(0, perf.oid_calculations); | |
94fb4aad RB |
1625 | |
1626 | git_diff_free(diff); | |
1627 | } | |
8af4966d RB |
1628 | |
1629 | #define STR7 "0123456" | |
1630 | #define STR8 "01234567" | |
1631 | #define STR40 STR8 STR8 STR8 STR8 STR8 | |
1632 | #define STR200 STR40 STR40 STR40 STR40 STR40 | |
1633 | #define STR999Z STR200 STR200 STR200 STR200 STR40 STR40 STR40 STR40 \ | |
1634 | STR8 STR8 STR8 STR8 STR7 "\0" | |
1635 | #define STR1000 STR200 STR200 STR200 STR200 STR200 | |
1636 | #define STR3999Z STR1000 STR1000 STR1000 STR999Z | |
1637 | #define STR4000 STR1000 STR1000 STR1000 STR1000 | |
1638 | ||
1639 | static void assert_delta_binary(git_diff *diff, size_t idx, int is_binary) | |
1640 | { | |
1641 | git_patch *patch; | |
1642 | const git_diff_delta *delta; | |
1643 | ||
1644 | cl_git_pass(git_patch_from_diff(&patch, diff, idx)); | |
1645 | delta = git_patch_get_delta(patch); | |
1646 | cl_assert_equal_b((delta->flags & GIT_DIFF_FLAG_BINARY), is_binary); | |
1647 | git_patch_free(patch); | |
1648 | } | |
1649 | ||
1650 | void test_diff_workdir__binary_detection(void) | |
1651 | { | |
1652 | git_index *idx; | |
1653 | git_diff *diff = NULL; | |
1654 | git_buf b = GIT_BUF_INIT; | |
1655 | int i; | |
1656 | git_buf data[10] = { | |
1657 | { "1234567890", 0, 0 }, /* 0 - all ascii text control */ | |
3ac1ff42 CH |
1658 | { "\xC3\x85\xC3\xBC\xE2\x80\xA0\x48\xC3\xB8\xCF\x80\xCE\xA9", 0, 0 }, /* 1 - UTF-8 multibyte text */ |
1659 | { "\xEF\xBB\xBF\xC3\x9C\xE2\xA4\x92\xC6\x92\x38\xC2\xA3\xE2\x82\xAC", 0, 0 }, /* 2 - UTF-8 with BOM */ | |
8af4966d RB |
1660 | { STR999Z, 0, 1000 }, /* 3 - ASCII with NUL at 1000 */ |
1661 | { STR3999Z, 0, 4000 }, /* 4 - ASCII with NUL at 4000 */ | |
1662 | { STR4000 STR3999Z "x", 0, 8001 }, /* 5 - ASCII with NUL at 8000 */ | |
1663 | { STR4000 STR4000 "\0", 0, 8001 }, /* 6 - ASCII with NUL at 8001 */ | |
1664 | { "\x00\xDC\x00\x6E\x21\x39\xFE\x0E\x00\x63\x00\xF8" | |
1665 | "\x00\x64\x00\x65\x20\x48", 0, 18 }, /* 7 - UTF-16 text */ | |
1666 | { "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d" | |
1667 | "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d", | |
1668 | 0, 26 }, /* 8 - All non-printable characters (no NUL) */ | |
1669 | { "Hello \x01\x02\x03\x04\x05\x06 World!\x01\x02\x03\x04" | |
1670 | "\x05\x06\x07", 0, 26 }, /* 9 - 50-50 non-printable (no NUL) */ | |
1671 | }; | |
1672 | ||
1673 | g_repo = cl_git_sandbox_init("empty_standard_repo"); | |
1674 | cl_git_pass(git_repository_index(&idx, g_repo)); | |
1675 | ||
1676 | /* We start with ASCII in index and test data in workdir, | |
1677 | * then we will try with test data in index and ASCII in workdir. | |
1678 | */ | |
1679 | ||
1680 | cl_git_pass(git_buf_sets(&b, "empty_standard_repo/0")); | |
1681 | for (i = 0; i < 10; ++i) { | |
1682 | b.ptr[b.size - 1] = '0' + i; | |
1683 | cl_git_mkfile(b.ptr, "baseline"); | |
1684 | cl_git_pass(git_index_add_bypath(idx, &b.ptr[b.size - 1])); | |
1685 | ||
1686 | if (data[i].size == 0) | |
1687 | data[i].size = strlen(data[i].ptr); | |
1688 | cl_git_write2file( | |
1689 | b.ptr, data[i].ptr, data[i].size, O_WRONLY|O_TRUNC, 0664); | |
1690 | } | |
1691 | git_index_write(idx); | |
1692 | ||
1693 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); | |
1694 | ||
1695 | cl_assert_equal_i(10, git_diff_num_deltas(diff)); | |
1696 | ||
1697 | /* using diff binary detection (i.e. looking for NUL byte) */ | |
1698 | assert_delta_binary(diff, 0, false); | |
1699 | assert_delta_binary(diff, 1, false); | |
1700 | assert_delta_binary(diff, 2, false); | |
1701 | assert_delta_binary(diff, 3, true); | |
1702 | assert_delta_binary(diff, 4, true); | |
1703 | assert_delta_binary(diff, 5, true); | |
1704 | assert_delta_binary(diff, 6, false); | |
1705 | assert_delta_binary(diff, 7, true); | |
1706 | assert_delta_binary(diff, 8, false); | |
1707 | assert_delta_binary(diff, 9, false); | |
1708 | /* The above have been checked to match command-line Git */ | |
1709 | ||
1710 | git_diff_free(diff); | |
1711 | ||
1712 | cl_git_pass(git_buf_sets(&b, "empty_standard_repo/0")); | |
1713 | for (i = 0; i < 10; ++i) { | |
1714 | b.ptr[b.size - 1] = '0' + i; | |
1715 | cl_git_pass(git_index_add_bypath(idx, &b.ptr[b.size - 1])); | |
1716 | ||
1717 | cl_git_write2file(b.ptr, "baseline\n", 9, O_WRONLY|O_TRUNC, 0664); | |
1718 | } | |
1719 | git_index_write(idx); | |
1720 | ||
1721 | cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, NULL)); | |
1722 | ||
1723 | cl_assert_equal_i(10, git_diff_num_deltas(diff)); | |
1724 | ||
1725 | /* using diff binary detection (i.e. looking for NUL byte) */ | |
1726 | assert_delta_binary(diff, 0, false); | |
1727 | assert_delta_binary(diff, 1, false); | |
1728 | assert_delta_binary(diff, 2, false); | |
1729 | assert_delta_binary(diff, 3, true); | |
1730 | assert_delta_binary(diff, 4, true); | |
1731 | assert_delta_binary(diff, 5, true); | |
1732 | assert_delta_binary(diff, 6, false); | |
1733 | assert_delta_binary(diff, 7, true); | |
1734 | assert_delta_binary(diff, 8, false); | |
1735 | assert_delta_binary(diff, 9, false); | |
1736 | ||
1737 | git_diff_free(diff); | |
1738 | ||
1739 | git_index_free(idx); | |
1740 | git_buf_free(&b); | |
1741 | } |