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