]>
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"); | |
16 | git_diff_list *diff; | |
5f69a31f | 17 | size_t d, num_d; |
f335ecd6 RB |
18 | |
19 | cl_git_pass(git_diff_workdir_to_index(repo, NULL, &diff)); | |
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; |
5f69a31f RB |
24 | cl_git_pass(git_diff_get_patch(NULL, &delta, diff, d)); |
25 | } | |
26 | ||
f335ecd6 RB |
27 | git_diff_list_free(diff); |
28 | } | |
29 | ||
30 | void test_diff_diffiter__iterate_files(void) | |
31 | { | |
32 | git_repository *repo = cl_git_sandbox_init("attr"); | |
33 | git_diff_list *diff; | |
5f69a31f RB |
34 | size_t d, num_d; |
35 | int count = 0; | |
f335ecd6 RB |
36 | |
37 | cl_git_pass(git_diff_workdir_to_index(repo, NULL, &diff)); | |
f335ecd6 | 38 | |
5f69a31f RB |
39 | num_d = git_diff_num_deltas(diff); |
40 | cl_assert_equal_i(6, num_d); | |
41 | ||
42 | for (d = 0; d < num_d; ++d) { | |
bae957b9 | 43 | const git_diff_delta *delta; |
5f69a31f | 44 | cl_git_pass(git_diff_get_patch(NULL, &delta, diff, d)); |
f335ecd6 RB |
45 | cl_assert(delta != NULL); |
46 | count++; | |
47 | } | |
f335ecd6 RB |
48 | cl_assert_equal_i(6, count); |
49 | ||
f335ecd6 RB |
50 | git_diff_list_free(diff); |
51 | } | |
52 | ||
53 | void test_diff_diffiter__iterate_files_2(void) | |
54 | { | |
55 | git_repository *repo = cl_git_sandbox_init("status"); | |
56 | git_diff_list *diff; | |
5f69a31f RB |
57 | size_t d, num_d; |
58 | int count = 0; | |
f335ecd6 RB |
59 | |
60 | cl_git_pass(git_diff_workdir_to_index(repo, NULL, &diff)); | |
f335ecd6 | 61 | |
5f69a31f RB |
62 | num_d = git_diff_num_deltas(diff); |
63 | cl_assert_equal_i(8, num_d); | |
64 | ||
65 | for (d = 0; d < num_d; ++d) { | |
bae957b9 | 66 | const git_diff_delta *delta; |
5f69a31f | 67 | cl_git_pass(git_diff_get_patch(NULL, &delta, diff, d)); |
f335ecd6 RB |
68 | cl_assert(delta != NULL); |
69 | count++; | |
70 | } | |
f335ecd6 RB |
71 | cl_assert_equal_i(8, count); |
72 | ||
f335ecd6 RB |
73 | git_diff_list_free(diff); |
74 | } | |
75 | ||
76 | void test_diff_diffiter__iterate_files_and_hunks(void) | |
77 | { | |
78 | git_repository *repo = cl_git_sandbox_init("status"); | |
79 | git_diff_options opts = {0}; | |
80 | git_diff_list *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 | ||
88 | cl_git_pass(git_diff_workdir_to_index(repo, &opts, &diff)); | |
89 | ||
5f69a31f RB |
90 | num_d = git_diff_num_deltas(diff); |
91 | ||
92 | for (d = 0; d < num_d; ++d) { | |
93 | git_diff_patch *patch; | |
bae957b9 | 94 | const git_diff_delta *delta; |
5f69a31f RB |
95 | size_t h, num_h; |
96 | ||
97 | cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); | |
f335ecd6 | 98 | |
f335ecd6 | 99 | cl_assert(delta); |
5f69a31f | 100 | cl_assert(patch); |
f335ecd6 RB |
101 | |
102 | file_count++; | |
103 | ||
5f69a31f RB |
104 | num_h = git_diff_patch_num_hunks(patch); |
105 | ||
106 | for (h = 0; h < num_h; h++) { | |
bae957b9 | 107 | const git_diff_range *range; |
5f69a31f RB |
108 | const char *header; |
109 | size_t header_len, num_l; | |
110 | ||
111 | cl_git_pass(git_diff_patch_get_hunk( | |
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 RB |
119 | |
120 | git_diff_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 | ||
f335ecd6 RB |
126 | git_diff_list_free(diff); |
127 | } | |
1f35e89d RB |
128 | |
129 | void test_diff_diffiter__max_size_threshold(void) | |
130 | { | |
131 | git_repository *repo = cl_git_sandbox_init("status"); | |
132 | git_diff_options opts = {0}; | |
133 | git_diff_list *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 | ||
141 | cl_git_pass(git_diff_workdir_to_index(repo, &opts, &diff)); | |
5f69a31f | 142 | num_d = git_diff_num_deltas(diff); |
1f35e89d | 143 | |
5f69a31f RB |
144 | for (d = 0; d < num_d; ++d) { |
145 | git_diff_patch *patch; | |
bae957b9 | 146 | const git_diff_delta *delta; |
5f69a31f RB |
147 | |
148 | cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); | |
1f35e89d | 149 | cl_assert(delta); |
5f69a31f | 150 | cl_assert(patch); |
1f35e89d RB |
151 | |
152 | file_count++; | |
5f69a31f | 153 | hunk_count += git_diff_patch_num_hunks(patch); |
1f35e89d RB |
154 | |
155 | assert(delta->binary == 0 || delta->binary == 1); | |
1f35e89d | 156 | binary_count += delta->binary; |
1f35e89d | 157 | |
5f69a31f RB |
158 | git_diff_patch_free(patch); |
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 | ||
1f35e89d RB |
165 | git_diff_list_free(diff); |
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 | ||
176 | cl_git_pass(git_diff_workdir_to_index(repo, &opts, &diff)); | |
5f69a31f | 177 | num_d = git_diff_num_deltas(diff); |
1f35e89d | 178 | |
5f69a31f RB |
179 | for (d = 0; d < num_d; ++d) { |
180 | git_diff_patch *patch; | |
bae957b9 | 181 | const git_diff_delta *delta; |
1f35e89d | 182 | |
5f69a31f | 183 | cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); |
1f35e89d | 184 | |
5f69a31f RB |
185 | file_count++; |
186 | hunk_count += git_diff_patch_num_hunks(patch); | |
1f35e89d RB |
187 | |
188 | assert(delta->binary == 0 || delta->binary == 1); | |
1f35e89d | 189 | binary_count += delta->binary; |
1f35e89d | 190 | |
5f69a31f RB |
191 | git_diff_patch_free(patch); |
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 | ||
1f35e89d | 203 | git_diff_list_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"); | |
210 | git_diff_options opts = {0}; | |
211 | git_diff_list *diff = NULL; | |
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 | ||
219 | cl_git_pass(git_diff_workdir_to_index(repo, &opts, &diff)); | |
220 | ||
221 | num_d = git_diff_num_deltas(diff); | |
222 | for (d = 0; d < num_d; ++d) { | |
223 | git_diff_patch *patch; | |
bae957b9 | 224 | const git_diff_delta *delta; |
5f69a31f RB |
225 | size_t h, num_h; |
226 | ||
227 | cl_git_pass(git_diff_get_patch(&patch, &delta, diff, d)); | |
228 | cl_assert(patch && delta); | |
229 | exp.files++; | |
230 | ||
231 | num_h = git_diff_patch_num_hunks(patch); | |
232 | for (h = 0; h < num_h; h++) { | |
bae957b9 | 233 | const git_diff_range *range; |
5f69a31f RB |
234 | const char *header; |
235 | size_t header_len, l, num_l; | |
236 | ||
237 | cl_git_pass(git_diff_patch_get_hunk( | |
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 | ||
247 | cl_git_pass(git_diff_patch_get_line_in_hunk( | |
248 | &origin, &content, &content_len, NULL, NULL, patch, h, l)); | |
249 | cl_assert(content); | |
250 | exp.lines++; | |
251 | } | |
252 | } | |
253 | ||
254 | git_diff_patch_free(patch); | |
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 RB |
260 | |
261 | git_diff_list_free(diff); | |
262 | } | |
263 | ||
264 | static void iterate_over_patch(git_diff_patch *patch, diff_expects *exp) | |
265 | { | |
64286308 | 266 | size_t h, num_h = git_diff_patch_num_hunks(patch), num_l; |
5f69a31f RB |
267 | |
268 | exp->files++; | |
269 | exp->hunks += num_h; | |
270 | ||
271 | /* let's iterate in reverse, just because we can! */ | |
64286308 RB |
272 | for (h = 1, num_l = 0; h <= num_h; ++h) |
273 | num_l += git_diff_patch_num_lines_in_hunk(patch, num_h - h); | |
274 | ||
275 | exp->lines += 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"); | |
283 | git_diff_options opts = {0}; | |
284 | git_diff_list *diff = NULL; | |
285 | diff_expects exp = {0}; | |
286 | git_diff_patch *patches[PATCH_CACHE]; | |
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 | ||
295 | cl_git_pass(git_diff_workdir_to_index(repo, &opts, &diff)); | |
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 */ | |
311 | git_diff_patch *patch = patches[p]; | |
312 | patches[p] = NULL; | |
313 | ||
314 | /* cache new patch */ | |
315 | cl_git_pass(git_diff_get_patch(&patches[p], NULL, diff, d)); | |
316 | cl_assert(patches[p] != NULL); | |
317 | ||
318 | /* process old patch if non-NULL */ | |
319 | if (patch != NULL) { | |
320 | iterate_over_patch(patch, &exp); | |
321 | git_diff_patch_free(patch); | |
322 | } | |
323 | ||
324 | p = rand() % PATCH_CACHE; | |
325 | } | |
326 | ||
327 | /* free diff list now - refcounts should keep things safe */ | |
328 | git_diff_list_free(diff); | |
329 | ||
330 | /* process remaining unprocessed patches */ | |
331 | for (p = 0; p < PATCH_CACHE; p++) { | |
332 | git_diff_patch *patch = patches[p]; | |
333 | ||
334 | if (patch != NULL) { | |
335 | iterate_over_patch(patch, &exp); | |
336 | git_diff_patch_free(patch); | |
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 | } |