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