]> git.proxmox.com Git - libgit2.git/blame - tests/diff/diffiter.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / tests / diff / diffiter.c
CommitLineData
f335ecd6
RB
1#include "clar_libgit2.h"
2#include "diff_helpers.h"
3
4void test_diff_diffiter__initialize(void)
5{
6}
7
8void test_diff_diffiter__cleanup(void)
9{
10 cl_git_sandbox_cleanup();
11}
12
13void 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 32void 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
54void 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
76void 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
121void 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
201void 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 252static 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
268void 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 */
335static 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
404void 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
433void 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