]>
Commit | Line | Data |
---|---|---|
f335ecd6 RB |
1 | #include "clar_libgit2.h" |
2 | #include "diff_helpers.h" | |
3 | ||
4 | void test_diff_diffiter__initialize(void) | |
5 | { | |
6 | } | |
7 | ||
8 | void test_diff_diffiter__cleanup(void) | |
9 | { | |
10 | cl_git_sandbox_cleanup(); | |
11 | } | |
12 | ||
13 | void test_diff_diffiter__create(void) | |
14 | { | |
15 | git_repository *repo = cl_git_sandbox_init("attr"); | |
3ff1d123 | 16 | git_diff *diff; |
5f69a31f | 17 | size_t d, num_d; |
f335ecd6 | 18 | |
56c72b75 | 19 | cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL)); |
5f69a31f RB |
20 | |
21 | num_d = git_diff_num_deltas(diff); | |
22 | for (d = 0; d < num_d; ++d) { | |
10672e3e RB |
23 | const git_diff_delta *delta = git_diff_get_delta(diff, d); |
24 | cl_assert(delta != NULL); | |
5f69a31f RB |
25 | } |
26 | ||
10672e3e RB |
27 | cl_assert(!git_diff_get_delta(diff, num_d)); |
28 | ||
3ff1d123 | 29 | git_diff_free(diff); |
f335ecd6 RB |
30 | } |
31 | ||
5173ea92 | 32 | void test_diff_diffiter__iterate_files_1(void) |
f335ecd6 RB |
33 | { |
34 | git_repository *repo = cl_git_sandbox_init("attr"); | |
3ff1d123 | 35 | git_diff *diff; |
5f69a31f | 36 | size_t d, num_d; |
5173ea92 | 37 | diff_expects exp = { 0 }; |
f335ecd6 | 38 | |
56c72b75 | 39 | cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL)); |
f335ecd6 | 40 | |
5f69a31f | 41 | num_d = git_diff_num_deltas(diff); |
5f69a31f RB |
42 | |
43 | for (d = 0; d < num_d; ++d) { | |
10672e3e | 44 | const git_diff_delta *delta = git_diff_get_delta(diff, d); |
f335ecd6 | 45 | cl_assert(delta != NULL); |
5173ea92 RB |
46 | |
47 | diff_file_cb(delta, (float)d / (float)num_d, &exp); | |
f335ecd6 | 48 | } |
5173ea92 | 49 | cl_assert_equal_sz(6, exp.files); |
f335ecd6 | 50 | |
3ff1d123 | 51 | git_diff_free(diff); |
f335ecd6 RB |
52 | } |
53 | ||
54 | void test_diff_diffiter__iterate_files_2(void) | |
55 | { | |
56 | git_repository *repo = cl_git_sandbox_init("status"); | |
3ff1d123 | 57 | git_diff *diff; |
5f69a31f RB |
58 | size_t d, num_d; |
59 | int count = 0; | |
f335ecd6 | 60 | |
56c72b75 | 61 | cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL)); |
f335ecd6 | 62 | |
5f69a31f | 63 | num_d = git_diff_num_deltas(diff); |
cc5bf359 | 64 | cl_assert_equal_i(8, (int)num_d); |
5f69a31f RB |
65 | |
66 | for (d = 0; d < num_d; ++d) { | |
10672e3e | 67 | const git_diff_delta *delta = git_diff_get_delta(diff, d); |
f335ecd6 RB |
68 | cl_assert(delta != NULL); |
69 | count++; | |
70 | } | |
f335ecd6 RB |
71 | cl_assert_equal_i(8, count); |
72 | ||
3ff1d123 | 73 | git_diff_free(diff); |
f335ecd6 RB |
74 | } |
75 | ||
76 | void test_diff_diffiter__iterate_files_and_hunks(void) | |
77 | { | |
78 | git_repository *repo = cl_git_sandbox_init("status"); | |
2f8d30be | 79 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 80 | git_diff *diff = NULL; |
5f69a31f RB |
81 | size_t d, num_d; |
82 | int file_count = 0, hunk_count = 0; | |
f335ecd6 RB |
83 | |
84 | opts.context_lines = 3; | |
85 | opts.interhunk_lines = 1; | |
86 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
87 | ||
56c72b75 | 88 | cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); |
f335ecd6 | 89 | |
5f69a31f RB |
90 | num_d = git_diff_num_deltas(diff); |
91 | ||
92 | for (d = 0; d < num_d; ++d) { | |
3ff1d123 | 93 | git_patch *patch; |
5f69a31f RB |
94 | size_t h, num_h; |
95 | ||
10672e3e | 96 | cl_git_pass(git_patch_from_diff(&patch, diff, d)); |
5f69a31f | 97 | cl_assert(patch); |
f335ecd6 RB |
98 | |
99 | file_count++; | |
100 | ||
3ff1d123 | 101 | num_h = git_patch_num_hunks(patch); |
5f69a31f RB |
102 | |
103 | for (h = 0; h < num_h; h++) { | |
3b5f7954 | 104 | const git_diff_hunk *hunk; |
5f69a31f | 105 | |
3b5f7954 RB |
106 | cl_git_pass(git_patch_get_hunk(&hunk, NULL, patch, h)); |
107 | cl_assert(hunk); | |
5f69a31f | 108 | |
f335ecd6 RB |
109 | hunk_count++; |
110 | } | |
5f69a31f | 111 | |
3ff1d123 | 112 | git_patch_free(patch); |
f335ecd6 RB |
113 | } |
114 | ||
f335ecd6 RB |
115 | cl_assert_equal_i(13, file_count); |
116 | cl_assert_equal_i(8, hunk_count); | |
117 | ||
3ff1d123 | 118 | git_diff_free(diff); |
f335ecd6 | 119 | } |
1f35e89d RB |
120 | |
121 | void test_diff_diffiter__max_size_threshold(void) | |
122 | { | |
123 | git_repository *repo = cl_git_sandbox_init("status"); | |
2f8d30be | 124 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 125 | git_diff *diff = NULL; |
5f69a31f RB |
126 | int file_count = 0, binary_count = 0, hunk_count = 0; |
127 | size_t d, num_d; | |
1f35e89d RB |
128 | |
129 | opts.context_lines = 3; | |
130 | opts.interhunk_lines = 1; | |
131 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
132 | ||
56c72b75 | 133 | cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); |
5f69a31f | 134 | num_d = git_diff_num_deltas(diff); |
1f35e89d | 135 | |
5f69a31f | 136 | for (d = 0; d < num_d; ++d) { |
3ff1d123 | 137 | git_patch *patch; |
bae957b9 | 138 | const git_diff_delta *delta; |
5f69a31f | 139 | |
10672e3e | 140 | cl_git_pass(git_patch_from_diff(&patch, diff, d)); |
5f69a31f | 141 | cl_assert(patch); |
10672e3e RB |
142 | delta = git_patch_get_delta(patch); |
143 | cl_assert(delta); | |
1f35e89d RB |
144 | |
145 | file_count++; | |
3ff1d123 | 146 | hunk_count += (int)git_patch_num_hunks(patch); |
1f35e89d | 147 | |
71a3d27e RB |
148 | assert((delta->flags & (GIT_DIFF_FLAG_BINARY|GIT_DIFF_FLAG_NOT_BINARY)) != 0); |
149 | binary_count += ((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); | |
1f35e89d | 150 | |
3ff1d123 | 151 | git_patch_free(patch); |
5f69a31f | 152 | } |
1f35e89d RB |
153 | |
154 | cl_assert_equal_i(13, file_count); | |
155 | cl_assert_equal_i(0, binary_count); | |
156 | cl_assert_equal_i(8, hunk_count); | |
157 | ||
3ff1d123 | 158 | git_diff_free(diff); |
1f35e89d RB |
159 | |
160 | /* try again with low file size threshold */ | |
161 | ||
5f69a31f | 162 | file_count = binary_count = hunk_count = 0; |
1f35e89d RB |
163 | |
164 | opts.context_lines = 3; | |
165 | opts.interhunk_lines = 1; | |
166 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
167 | opts.max_size = 50; /* treat anything over 50 bytes as binary! */ | |
168 | ||
56c72b75 | 169 | cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); |
5f69a31f | 170 | num_d = git_diff_num_deltas(diff); |
1f35e89d | 171 | |
5f69a31f | 172 | for (d = 0; d < num_d; ++d) { |
3ff1d123 | 173 | git_patch *patch; |
bae957b9 | 174 | const git_diff_delta *delta; |
1f35e89d | 175 | |
10672e3e RB |
176 | cl_git_pass(git_patch_from_diff(&patch, diff, d)); |
177 | delta = git_patch_get_delta(patch); | |
1f35e89d | 178 | |
5f69a31f | 179 | file_count++; |
3ff1d123 | 180 | hunk_count += (int)git_patch_num_hunks(patch); |
1f35e89d | 181 | |
71a3d27e RB |
182 | assert((delta->flags & (GIT_DIFF_FLAG_BINARY|GIT_DIFF_FLAG_NOT_BINARY)) != 0); |
183 | binary_count += ((delta->flags & GIT_DIFF_FLAG_BINARY) != 0); | |
1f35e89d | 184 | |
3ff1d123 | 185 | git_patch_free(patch); |
5f69a31f | 186 | } |
1f35e89d RB |
187 | |
188 | cl_assert_equal_i(13, file_count); | |
1f35e89d RB |
189 | /* Three files are over the 50 byte threshold: |
190 | * - staged_changes_file_deleted | |
191 | * - staged_changes_modified_file | |
192 | * - staged_new_file_modified_file | |
193 | */ | |
194 | cl_assert_equal_i(3, binary_count); | |
1f35e89d RB |
195 | cl_assert_equal_i(5, hunk_count); |
196 | ||
3ff1d123 | 197 | git_diff_free(diff); |
5f69a31f RB |
198 | } |
199 | ||
200 | ||
201 | void test_diff_diffiter__iterate_all(void) | |
202 | { | |
203 | git_repository *repo = cl_git_sandbox_init("status"); | |
2f8d30be | 204 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 205 | git_diff *diff = NULL; |
5f69a31f RB |
206 | diff_expects exp = {0}; |
207 | size_t d, num_d; | |
208 | ||
209 | opts.context_lines = 3; | |
210 | opts.interhunk_lines = 1; | |
211 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
212 | ||
56c72b75 | 213 | cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); |
5f69a31f RB |
214 | |
215 | num_d = git_diff_num_deltas(diff); | |
216 | for (d = 0; d < num_d; ++d) { | |
3ff1d123 | 217 | git_patch *patch; |
5f69a31f RB |
218 | size_t h, num_h; |
219 | ||
10672e3e RB |
220 | cl_git_pass(git_patch_from_diff(&patch, diff, d)); |
221 | cl_assert(patch); | |
5f69a31f RB |
222 | exp.files++; |
223 | ||
3ff1d123 | 224 | num_h = git_patch_num_hunks(patch); |
5f69a31f | 225 | for (h = 0; h < num_h; h++) { |
3ff1d123 | 226 | const git_diff_hunk *range; |
3b5f7954 | 227 | size_t l, num_l; |
5f69a31f | 228 | |
3b5f7954 RB |
229 | cl_git_pass(git_patch_get_hunk(&range, &num_l, patch, h)); |
230 | cl_assert(range); | |
5f69a31f RB |
231 | exp.hunks++; |
232 | ||
233 | for (l = 0; l < num_l; ++l) { | |
3b5f7954 | 234 | const git_diff_line *line; |
5f69a31f | 235 | |
3b5f7954 RB |
236 | cl_git_pass(git_patch_get_line_in_hunk(&line, patch, h, l)); |
237 | cl_assert(line && line->content); | |
5f69a31f RB |
238 | exp.lines++; |
239 | } | |
240 | } | |
241 | ||
3ff1d123 | 242 | git_patch_free(patch); |
5f69a31f RB |
243 | } |
244 | ||
245 | cl_assert_equal_i(13, exp.files); | |
246 | cl_assert_equal_i(8, exp.hunks); | |
64286308 | 247 | cl_assert_equal_i(14, exp.lines); |
5f69a31f | 248 | |
3ff1d123 | 249 | git_diff_free(diff); |
5f69a31f RB |
250 | } |
251 | ||
3ff1d123 | 252 | static void iterate_over_patch(git_patch *patch, diff_expects *exp) |
5f69a31f | 253 | { |
3ff1d123 | 254 | size_t h, num_h = git_patch_num_hunks(patch), num_l; |
5f69a31f RB |
255 | |
256 | exp->files++; | |
cc5bf359 | 257 | exp->hunks += (int)num_h; |
5f69a31f RB |
258 | |
259 | /* let's iterate in reverse, just because we can! */ | |
64286308 | 260 | for (h = 1, num_l = 0; h <= num_h; ++h) |
3ff1d123 | 261 | num_l += git_patch_num_lines_in_hunk(patch, num_h - h); |
64286308 | 262 | |
cc5bf359 | 263 | exp->lines += (int)num_l; |
5f69a31f RB |
264 | } |
265 | ||
266 | #define PATCH_CACHE 5 | |
267 | ||
268 | void test_diff_diffiter__iterate_randomly_while_saving_state(void) | |
269 | { | |
270 | git_repository *repo = cl_git_sandbox_init("status"); | |
2f8d30be | 271 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; |
3ff1d123 | 272 | git_diff *diff = NULL; |
5f69a31f | 273 | diff_expects exp = {0}; |
3ff1d123 | 274 | git_patch *patches[PATCH_CACHE]; |
5f69a31f RB |
275 | size_t p, d, num_d; |
276 | ||
277 | memset(patches, 0, sizeof(patches)); | |
278 | ||
279 | opts.context_lines = 3; | |
280 | opts.interhunk_lines = 1; | |
281 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
282 | ||
56c72b75 | 283 | cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); |
5f69a31f RB |
284 | |
285 | num_d = git_diff_num_deltas(diff); | |
286 | ||
287 | /* To make sure that references counts work for diff and patch objects, | |
288 | * this generates patches and randomly caches them. Only when the patch | |
289 | * is removed from the cache are hunks and lines counted. At the end, | |
290 | * there are still patches in the cache, so free the diff and try to | |
291 | * process remaining patches after the diff is freed. | |
292 | */ | |
293 | ||
294 | srand(121212); | |
295 | p = rand() % PATCH_CACHE; | |
296 | ||
297 | for (d = 0; d < num_d; ++d) { | |
298 | /* take old patch */ | |
3ff1d123 | 299 | git_patch *patch = patches[p]; |
5f69a31f RB |
300 | patches[p] = NULL; |
301 | ||
302 | /* cache new patch */ | |
10672e3e | 303 | cl_git_pass(git_patch_from_diff(&patches[p], diff, d)); |
5f69a31f RB |
304 | cl_assert(patches[p] != NULL); |
305 | ||
306 | /* process old patch if non-NULL */ | |
307 | if (patch != NULL) { | |
308 | iterate_over_patch(patch, &exp); | |
3ff1d123 | 309 | git_patch_free(patch); |
5f69a31f RB |
310 | } |
311 | ||
312 | p = rand() % PATCH_CACHE; | |
313 | } | |
314 | ||
315 | /* free diff list now - refcounts should keep things safe */ | |
3ff1d123 | 316 | git_diff_free(diff); |
5f69a31f RB |
317 | |
318 | /* process remaining unprocessed patches */ | |
319 | for (p = 0; p < PATCH_CACHE; p++) { | |
3ff1d123 | 320 | git_patch *patch = patches[p]; |
5f69a31f RB |
321 | |
322 | if (patch != NULL) { | |
323 | iterate_over_patch(patch, &exp); | |
3ff1d123 | 324 | git_patch_free(patch); |
5f69a31f RB |
325 | } |
326 | } | |
1f35e89d | 327 | |
5f69a31f RB |
328 | /* hopefully it all still added up right */ |
329 | cl_assert_equal_i(13, exp.files); | |
330 | cl_assert_equal_i(8, exp.hunks); | |
64286308 | 331 | cl_assert_equal_i(14, exp.lines); |
1f35e89d | 332 | } |
93cf7bb8 RB |
333 | |
334 | /* This output is taken directly from `git diff` on the status test data */ | |
335 | static const char *expected_patch_text[8] = { | |
336 | /* 0 */ | |
337 | "diff --git a/file_deleted b/file_deleted\n" | |
338 | "deleted file mode 100644\n" | |
339 | "index 5452d32..0000000\n" | |
340 | "--- a/file_deleted\n" | |
341 | "+++ /dev/null\n" | |
342 | "@@ -1 +0,0 @@\n" | |
343 | "-file_deleted\n", | |
344 | /* 1 */ | |
345 | "diff --git a/modified_file b/modified_file\n" | |
346 | "index 452e424..0a53963 100644\n" | |
347 | "--- a/modified_file\n" | |
348 | "+++ b/modified_file\n" | |
349 | "@@ -1 +1,2 @@\n" | |
350 | " modified_file\n" | |
351 | "+modified_file\n", | |
352 | /* 2 */ | |
353 | "diff --git a/staged_changes_file_deleted b/staged_changes_file_deleted\n" | |
354 | "deleted file mode 100644\n" | |
355 | "index a6be623..0000000\n" | |
356 | "--- a/staged_changes_file_deleted\n" | |
357 | "+++ /dev/null\n" | |
358 | "@@ -1,2 +0,0 @@\n" | |
359 | "-staged_changes_file_deleted\n" | |
360 | "-staged_changes_file_deleted\n", | |
361 | /* 3 */ | |
362 | "diff --git a/staged_changes_modified_file b/staged_changes_modified_file\n" | |
363 | "index 906ee77..011c344 100644\n" | |
364 | "--- a/staged_changes_modified_file\n" | |
365 | "+++ b/staged_changes_modified_file\n" | |
366 | "@@ -1,2 +1,3 @@\n" | |
367 | " staged_changes_modified_file\n" | |
368 | " staged_changes_modified_file\n" | |
369 | "+staged_changes_modified_file\n", | |
370 | /* 4 */ | |
371 | "diff --git a/staged_new_file_deleted_file b/staged_new_file_deleted_file\n" | |
372 | "deleted file mode 100644\n" | |
373 | "index 90b8c29..0000000\n" | |
374 | "--- a/staged_new_file_deleted_file\n" | |
375 | "+++ /dev/null\n" | |
376 | "@@ -1 +0,0 @@\n" | |
377 | "-staged_new_file_deleted_file\n", | |
378 | /* 5 */ | |
379 | "diff --git a/staged_new_file_modified_file b/staged_new_file_modified_file\n" | |
380 | "index ed06290..8b090c0 100644\n" | |
381 | "--- a/staged_new_file_modified_file\n" | |
382 | "+++ b/staged_new_file_modified_file\n" | |
383 | "@@ -1 +1,2 @@\n" | |
384 | " staged_new_file_modified_file\n" | |
385 | "+staged_new_file_modified_file\n", | |
386 | /* 6 */ | |
387 | "diff --git a/subdir/deleted_file b/subdir/deleted_file\n" | |
388 | "deleted file mode 100644\n" | |
389 | "index 1888c80..0000000\n" | |
390 | "--- a/subdir/deleted_file\n" | |
391 | "+++ /dev/null\n" | |
392 | "@@ -1 +0,0 @@\n" | |
393 | "-subdir/deleted_file\n", | |
394 | /* 7 */ | |
395 | "diff --git a/subdir/modified_file b/subdir/modified_file\n" | |
396 | "index a619198..57274b7 100644\n" | |
397 | "--- a/subdir/modified_file\n" | |
398 | "+++ b/subdir/modified_file\n" | |
399 | "@@ -1 +1,2 @@\n" | |
400 | " subdir/modified_file\n" | |
401 | "+subdir/modified_file\n" | |
402 | }; | |
403 | ||
404 | void test_diff_diffiter__iterate_and_generate_patch_text(void) | |
405 | { | |
406 | git_repository *repo = cl_git_sandbox_init("status"); | |
3ff1d123 | 407 | git_diff *diff; |
93cf7bb8 RB |
408 | size_t d, num_d; |
409 | ||
56c72b75 | 410 | cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL)); |
93cf7bb8 RB |
411 | |
412 | num_d = git_diff_num_deltas(diff); | |
413 | cl_assert_equal_i(8, (int)num_d); | |
414 | ||
415 | for (d = 0; d < num_d; ++d) { | |
3ff1d123 | 416 | git_patch *patch; |
c05cd792 | 417 | git_buf buf = GIT_BUF_INIT; |
93cf7bb8 | 418 | |
10672e3e | 419 | cl_git_pass(git_patch_from_diff(&patch, diff, d)); |
93cf7bb8 RB |
420 | cl_assert(patch != NULL); |
421 | ||
c05cd792 | 422 | cl_git_pass(git_patch_to_buf(&buf, patch)); |
93cf7bb8 | 423 | |
c05cd792 | 424 | cl_assert_equal_s(expected_patch_text[d], buf.ptr); |
93cf7bb8 | 425 | |
ac3d33df | 426 | git_buf_dispose(&buf); |
3ff1d123 | 427 | git_patch_free(patch); |
93cf7bb8 RB |
428 | } |
429 | ||
3ff1d123 | 430 | git_diff_free(diff); |
93cf7bb8 | 431 | } |
2f8d30be BS |
432 | |
433 | void test_diff_diffiter__checks_options_version(void) | |
434 | { | |
435 | git_repository *repo = cl_git_sandbox_init("status"); | |
436 | git_diff_options opts = GIT_DIFF_OPTIONS_INIT; | |
3ff1d123 | 437 | git_diff *diff = NULL; |
2f8d30be BS |
438 | const git_error *err; |
439 | ||
440 | opts.version = 0; | |
441 | opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED; | |
442 | ||
56c72b75 | 443 | cl_git_fail(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); |
ac3d33df JK |
444 | err = git_error_last(); |
445 | cl_assert_equal_i(GIT_ERROR_INVALID, err->klass); | |
2f8d30be | 446 | |
ac3d33df | 447 | git_error_clear(); |
2f8d30be | 448 | opts.version = 1024; |
56c72b75 | 449 | cl_git_fail(git_diff_index_to_workdir(&diff, repo, NULL, &opts)); |
ac3d33df JK |
450 | err = git_error_last(); |
451 | cl_assert_equal_i(GIT_ERROR_INVALID, err->klass); | |
2f8d30be BS |
452 | } |
453 |