]> git.proxmox.com Git - libgit2.git/blob - tests/diff/parse.c
New upstream version 1.4.3+dfsg.1
[libgit2.git] / tests / diff / parse.c
1 #include "clar_libgit2.h"
2 #include "patch.h"
3 #include "patch_parse.h"
4 #include "diff_helpers.h"
5
6 #include "../patch/patch_common.h"
7
8 void test_diff_parse__cleanup(void)
9 {
10 cl_git_sandbox_cleanup();
11 }
12
13 void test_diff_parse__nonpatches_fail_with_notfound(void)
14 {
15 git_diff *diff;
16 const char *not = PATCH_NOT_A_PATCH;
17 const char *not_with_leading = "Leading text.\n" PATCH_NOT_A_PATCH;
18 const char *not_with_trailing = PATCH_NOT_A_PATCH "Trailing text.\n";
19 const char *not_with_both = "Lead.\n" PATCH_NOT_A_PATCH "Trail.\n";
20
21 cl_git_fail_with(GIT_ENOTFOUND,
22 git_diff_from_buffer(&diff,
23 not,
24 strlen(not)));
25 cl_git_fail_with(GIT_ENOTFOUND,
26 git_diff_from_buffer(&diff,
27 not_with_leading,
28 strlen(not_with_leading)));
29 cl_git_fail_with(GIT_ENOTFOUND,
30 git_diff_from_buffer(&diff,
31 not_with_trailing,
32 strlen(not_with_trailing)));
33 cl_git_fail_with(GIT_ENOTFOUND,
34 git_diff_from_buffer(&diff,
35 not_with_both,
36 strlen(not_with_both)));
37 }
38
39 static void test_parse_invalid_diff(const char *invalid_diff)
40 {
41 git_diff *diff;
42 git_str buf = GIT_STR_INIT;
43
44 /* throw some random (legitimate) diffs in with the given invalid
45 * one.
46 */
47 git_str_puts(&buf, PATCH_ORIGINAL_TO_CHANGE_FIRSTLINE);
48 git_str_puts(&buf, PATCH_BINARY_DELTA);
49 git_str_puts(&buf, invalid_diff);
50 git_str_puts(&buf, PATCH_ORIGINAL_TO_CHANGE_MIDDLE);
51 git_str_puts(&buf, PATCH_BINARY_LITERAL);
52
53 cl_git_fail_with(GIT_ERROR,
54 git_diff_from_buffer(&diff, buf.ptr, buf.size));
55
56 git_str_dispose(&buf);
57 }
58
59 void test_diff_parse__exact_rename(void)
60 {
61 const char *content =
62 "---\n"
63 " old_name.c => new_name.c | 0\n"
64 " 1 file changed, 0 insertions(+), 0 deletions(-)\n"
65 " rename old_name.c => new_name.c (100%)\n"
66 "\n"
67 "diff --git a/old_name.c b/new_name.c\n"
68 "similarity index 100%\n"
69 "rename from old_name.c\n"
70 "rename to new_name.c\n"
71 "-- \n"
72 "2.9.3\n";
73 git_diff *diff;
74
75 cl_git_pass(git_diff_from_buffer(
76 &diff, content, strlen(content)));
77 git_diff_free(diff);
78 }
79
80 void test_diff_parse__empty_file(void)
81 {
82 const char *content =
83 "---\n"
84 " file | 0\n"
85 " 1 file changed, 0 insertions(+), 0 deletions(-)\n"
86 " created mode 100644 file\n"
87 "\n"
88 "diff --git a/file b/file\n"
89 "new file mode 100644\n"
90 "index 0000000..e69de29\n"
91 "-- \n"
92 "2.20.1\n";
93 git_diff *diff;
94
95 cl_git_pass(git_diff_from_buffer(
96 &diff, content, strlen(content)));
97 git_diff_free(diff);
98 }
99
100 void test_diff_parse__no_extended_headers(void)
101 {
102 const char *content = PATCH_NO_EXTENDED_HEADERS;
103 git_diff *diff;
104
105 cl_git_pass(git_diff_from_buffer(
106 &diff, content, strlen(content)));
107 git_diff_free(diff);
108 }
109
110 void test_diff_parse__add_delete_no_index(void)
111 {
112 const char *content =
113 "diff --git a/file.txt b/file.txt\n"
114 "new file mode 100644\n"
115 "--- /dev/null\n"
116 "+++ b/file.txt\n"
117 "@@ -0,0 +1,2 @@\n"
118 "+one\n"
119 "+two\n"
120 "diff --git a/otherfile.txt b/otherfile.txt\n"
121 "deleted file mode 100644\n"
122 "--- a/otherfile.txt\n"
123 "+++ /dev/null\n"
124 "@@ -1,1 +0,0 @@\n"
125 "-three\n";
126 git_diff *diff;
127
128 cl_git_pass(git_diff_from_buffer(
129 &diff, content, strlen(content)));
130 git_diff_free(diff);
131 }
132
133 void test_diff_parse__invalid_patches_fails(void)
134 {
135 test_parse_invalid_diff(PATCH_CORRUPT_MISSING_NEW_FILE);
136 test_parse_invalid_diff(PATCH_CORRUPT_MISSING_OLD_FILE);
137 test_parse_invalid_diff(PATCH_CORRUPT_NO_CHANGES);
138 test_parse_invalid_diff(PATCH_CORRUPT_MISSING_HUNK_HEADER);
139 }
140
141 static void test_tree_to_tree_computed_to_parsed(
142 const char *sandbox, const char *a_id, const char *b_id,
143 uint32_t diff_flags, uint32_t find_flags)
144 {
145 git_repository *repo;
146 git_diff *computed, *parsed;
147 git_tree *a, *b;
148 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
149 git_diff_find_options findopts = GIT_DIFF_FIND_OPTIONS_INIT;
150 git_buf computed_buf = GIT_BUF_INIT;
151
152 repo = cl_git_sandbox_init(sandbox);
153
154 opts.id_abbrev = GIT_OID_HEXSZ;
155 opts.flags = GIT_DIFF_SHOW_BINARY | diff_flags;
156 findopts.flags = find_flags;
157
158 cl_assert((a = resolve_commit_oid_to_tree(repo, a_id)) != NULL);
159 cl_assert((b = resolve_commit_oid_to_tree(repo, b_id)) != NULL);
160
161 cl_git_pass(git_diff_tree_to_tree(&computed, repo, a, b, &opts));
162
163 if (find_flags)
164 cl_git_pass(git_diff_find_similar(computed, &findopts));
165
166 cl_git_pass(git_diff_to_buf(&computed_buf,
167 computed, GIT_DIFF_FORMAT_PATCH));
168
169 cl_git_pass(git_diff_from_buffer(&parsed,
170 computed_buf.ptr, computed_buf.size));
171
172 diff_assert_equal(computed, parsed);
173
174 git_tree_free(a);
175 git_tree_free(b);
176
177 git_diff_free(computed);
178 git_diff_free(parsed);
179
180 git_buf_dispose(&computed_buf);
181
182 cl_git_sandbox_cleanup();
183 }
184
185 void test_diff_parse__can_parse_generated_diff(void)
186 {
187 test_tree_to_tree_computed_to_parsed(
188 "diff", "d70d245e", "7a9e0b02", 0, 0);
189 test_tree_to_tree_computed_to_parsed(
190 "unsymlinked.git", "806999", "a8595c", 0, 0);
191 test_tree_to_tree_computed_to_parsed("diff",
192 "d70d245ed97ed2aa596dd1af6536e4bfdb047b69",
193 "7a9e0b02e63179929fed24f0a3e0f19168114d10", 0, 0);
194 test_tree_to_tree_computed_to_parsed(
195 "unsymlinked.git", "7fccd7", "806999", 0, 0);
196 test_tree_to_tree_computed_to_parsed(
197 "unsymlinked.git", "7fccd7", "a8595c", 0, 0);
198 test_tree_to_tree_computed_to_parsed(
199 "attr", "605812a", "370fe9ec22", 0, 0);
200 test_tree_to_tree_computed_to_parsed(
201 "attr", "f5b0af1fb4f5c", "370fe9ec22", 0, 0);
202 test_tree_to_tree_computed_to_parsed(
203 "diff", "d70d245e", "d70d245e", 0, 0);
204 test_tree_to_tree_computed_to_parsed("diff_format_email",
205 "873806f6f27e631eb0b23e4b56bea2bfac14a373",
206 "897d3af16ca9e420cd071b1c4541bd2b91d04c8c",
207 GIT_DIFF_SHOW_BINARY, 0);
208 test_tree_to_tree_computed_to_parsed("diff_format_email",
209 "897d3af16ca9e420cd071b1c4541bd2b91d04c8c",
210 "873806f6f27e631eb0b23e4b56bea2bfac14a373",
211 GIT_DIFF_SHOW_BINARY, 0);
212 test_tree_to_tree_computed_to_parsed("renames",
213 "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2",
214 "2bc7f351d20b53f1c72c16c4b036e491c478c49a",
215 0, GIT_DIFF_FIND_RENAMES);
216 test_tree_to_tree_computed_to_parsed("renames",
217 "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2",
218 "2bc7f351d20b53f1c72c16c4b036e491c478c49a",
219 GIT_DIFF_INCLUDE_UNMODIFIED,
220 0);
221 test_tree_to_tree_computed_to_parsed("renames",
222 "31e47d8c1fa36d7f8d537b96158e3f024de0a9f2",
223 "2bc7f351d20b53f1c72c16c4b036e491c478c49a",
224 GIT_DIFF_INCLUDE_UNMODIFIED,
225 GIT_DIFF_FIND_COPIES_FROM_UNMODIFIED | GIT_DIFF_FIND_EXACT_MATCH_ONLY);
226 }
227
228 void test_diff_parse__get_patch_from_diff(void)
229 {
230 git_repository *repo;
231 git_diff *computed, *parsed;
232 git_tree *a, *b;
233 git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
234 git_buf computed_buf = GIT_BUF_INIT;
235 git_patch *patch_computed, *patch_parsed;
236
237 repo = cl_git_sandbox_init("diff");
238
239 opts.flags = GIT_DIFF_SHOW_BINARY;
240
241 cl_assert((a = resolve_commit_oid_to_tree(repo,
242 "d70d245ed97ed2aa596dd1af6536e4bfdb047b69")) != NULL);
243 cl_assert((b = resolve_commit_oid_to_tree(repo,
244 "7a9e0b02e63179929fed24f0a3e0f19168114d10")) != NULL);
245
246 cl_git_pass(git_diff_tree_to_tree(&computed, repo, a, b, &opts));
247 cl_git_pass(git_diff_to_buf(&computed_buf,
248 computed, GIT_DIFF_FORMAT_PATCH));
249 cl_git_pass(git_patch_from_diff(&patch_computed, computed, 0));
250
251 cl_git_pass(git_diff_from_buffer(&parsed,
252 computed_buf.ptr, computed_buf.size));
253 cl_git_pass(git_patch_from_diff(&patch_parsed, parsed, 0));
254
255 cl_assert_equal_i(
256 git_patch_num_hunks(patch_computed),
257 git_patch_num_hunks(patch_parsed));
258
259 git_patch_free(patch_computed);
260 git_patch_free(patch_parsed);
261
262 git_tree_free(a);
263 git_tree_free(b);
264
265 git_diff_free(computed);
266 git_diff_free(parsed);
267
268 git_buf_dispose(&computed_buf);
269
270 cl_git_sandbox_cleanup();
271 }
272
273 static int file_cb(const git_diff_delta *delta, float progress, void *payload)
274 {
275 int *called = (int *) payload;
276 GIT_UNUSED(delta);
277 GIT_UNUSED(progress);
278 (*called)++;
279 return 0;
280 }
281
282 void test_diff_parse__foreach_works_with_parsed_patch(void)
283 {
284 const char patch[] =
285 "diff --git a/obj1 b/obj2\n"
286 "index 1234567..7654321 10644\n"
287 "--- a/obj1\n"
288 "+++ b/obj2\n"
289 "@@ -1 +1 @@\n"
290 "-abcde\n"
291 "+12345\n";
292 int called = 0;
293 git_diff *diff;
294
295 cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch)));
296 cl_git_pass(git_diff_foreach(diff, file_cb, NULL, NULL, NULL, &called));
297 cl_assert_equal_i(called, 1);
298
299 git_diff_free(diff);
300 }
301
302 void test_diff_parse__parsing_minimal_patch_succeeds(void)
303 {
304 const char patch[] =
305 "diff --git a/obj1 b/obj2\n"
306 "index 1234567..7654321 10644\n"
307 "--- a/obj1\n"
308 "+++ b/obj2\n"
309 "@@ -1 +1 @@\n"
310 "-a\n"
311 "+\n";
312 git_buf buf = GIT_BUF_INIT;
313 git_diff *diff;
314
315 cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch)));
316 cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH));
317 cl_assert_equal_s(patch, buf.ptr);
318
319 git_diff_free(diff);
320 git_buf_dispose(&buf);
321 }
322
323 void test_diff_parse__patch_roundtrip_succeeds(void)
324 {
325 const char buf1[] = "a\n", buf2[] = "b\n";
326 git_buf patchbuf = GIT_BUF_INIT, diffbuf = GIT_BUF_INIT;
327 git_patch *patch;
328 git_diff *diff;
329
330 cl_git_pass(git_patch_from_buffers(&patch, buf1, strlen(buf1), "obj1", buf2, strlen(buf2), "obj2", NULL));
331 cl_git_pass(git_patch_to_buf(&patchbuf, patch));
332
333 cl_git_pass(git_diff_from_buffer(&diff, patchbuf.ptr, patchbuf.size));
334 cl_git_pass(git_diff_to_buf(&diffbuf, diff, GIT_DIFF_FORMAT_PATCH));
335
336 cl_assert_equal_s(patchbuf.ptr, diffbuf.ptr);
337
338 git_patch_free(patch);
339 git_diff_free(diff);
340 git_buf_dispose(&patchbuf);
341 git_buf_dispose(&diffbuf);
342 }
343
344 #define cl_assert_equal_i_src(i1,i2,file,func,line) clar__assert_equal(file,func,line,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
345
346 static void cl_git_assert_lineinfo_(int old_lineno, int new_lineno, int num_lines, git_patch *patch, size_t hunk_idx, size_t line_idx, const char *file, const char *func, int lineno)
347 {
348 const git_diff_line *line;
349
350 cl_git_expect(git_patch_get_line_in_hunk(&line, patch, hunk_idx, line_idx), 0, file, func, lineno);
351 cl_assert_equal_i_src(old_lineno, line->old_lineno, file, func, lineno);
352 cl_assert_equal_i_src(new_lineno, line->new_lineno, file, func, lineno);
353 cl_assert_equal_i_src(num_lines, line->num_lines, file, func, lineno);
354 }
355
356 #define cl_git_assert_lineinfo(old, new, num, p, h, l) \
357 cl_git_assert_lineinfo_(old,new,num,p,h,l,__FILE__,__func__,__LINE__)
358
359
360 void test_diff_parse__issue4672(void)
361 {
362 const char *text = "diff --git a/a b/a\n"
363 "index 7f129fd..af431f2 100644\n"
364 "--- a/a\n"
365 "+++ b/a\n"
366 "@@ -3 +3 @@\n"
367 "-a contents 2\n"
368 "+a contents\n";
369
370 git_diff *diff;
371 git_patch *patch;
372 const git_diff_hunk *hunk;
373 size_t n, l = 0;
374
375 cl_git_pass(git_diff_from_buffer(&diff, text, strlen(text)));
376 cl_git_pass(git_patch_from_diff(&patch, diff, 0));
377 cl_git_pass(git_patch_get_hunk(&hunk, &n, patch, 0));
378
379 cl_git_assert_lineinfo(3, -1, 1, patch, 0, l++);
380 cl_git_assert_lineinfo(-1, 3, 1, patch, 0, l++);
381
382 cl_assert_equal_i(n, l);
383
384 git_patch_free(patch);
385 git_diff_free(diff);
386 }
387
388 void test_diff_parse__lineinfo(void)
389 {
390 const char *text = PATCH_ORIGINAL_TO_CHANGE_MIDDLE;
391 git_diff *diff;
392 git_patch *patch;
393 const git_diff_hunk *hunk;
394 size_t n, l = 0;
395
396 cl_git_pass(git_diff_from_buffer(&diff, text, strlen(text)));
397 cl_git_pass(git_patch_from_diff(&patch, diff, 0));
398 cl_git_pass(git_patch_get_hunk(&hunk, &n, patch, 0));
399
400 cl_git_assert_lineinfo(3, 3, 1, patch, 0, l++);
401 cl_git_assert_lineinfo(4, 4, 1, patch, 0, l++);
402 cl_git_assert_lineinfo(5, 5, 1, patch, 0, l++);
403 cl_git_assert_lineinfo(6, -1, 1, patch, 0, l++);
404 cl_git_assert_lineinfo(-1, 6, 1, patch, 0, l++);
405 cl_git_assert_lineinfo(7, 7, 1, patch, 0, l++);
406 cl_git_assert_lineinfo(8, 8, 1, patch, 0, l++);
407 cl_git_assert_lineinfo(9, 9, 1, patch, 0, l++);
408
409 cl_assert_equal_i(n, l);
410
411 git_patch_free(patch);
412 git_diff_free(diff);
413 }
414
415
416 void test_diff_parse__new_file_with_space(void)
417 {
418 const char *content = PATCH_ORIGINAL_NEW_FILE_WITH_SPACE;
419 git_patch *patch;
420 git_diff *diff;
421
422 cl_git_pass(git_diff_from_buffer(&diff, content, strlen(content)));
423 cl_git_pass(git_patch_from_diff((git_patch **) &patch, diff, 0));
424
425 cl_assert_equal_p(patch->diff_opts.old_prefix, NULL);
426 cl_assert_equal_p(patch->delta->old_file.path, NULL);
427 cl_assert_equal_s(patch->diff_opts.new_prefix, "b/");
428 cl_assert_equal_s(patch->delta->new_file.path, "sp ace.txt");
429
430 git_patch_free(patch);
431 git_diff_free(diff);
432 }
433
434 void test_diff_parse__new_file_with_space_and_regenerate_patch(void)
435 {
436 const char *content = PATCH_ORIGINAL_NEW_FILE_WITH_SPACE;
437 git_diff *diff = NULL;
438 git_buf buf = GIT_BUF_INIT;
439
440 cl_git_pass(git_diff_from_buffer(&diff, content, strlen(content)));
441 cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH));
442
443 git_buf_dispose(&buf);
444 git_diff_free(diff);
445 }
446
447 void test_diff_parse__delete_file_with_space_and_regenerate_patch(void)
448 {
449 const char *content = PATCH_DELETE_FILE_WITH_SPACE;
450 git_diff *diff = NULL;
451 git_buf buf = GIT_BUF_INIT;
452
453 cl_git_pass(git_diff_from_buffer(&diff, content, strlen(content)));
454 cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH));
455
456 git_buf_dispose(&buf);
457 git_diff_free(diff);
458 }
459
460 void test_diff_parse__crlf(void)
461 {
462 const char *text = PATCH_CRLF;
463 git_diff *diff;
464 git_patch *patch;
465 const git_diff_delta *delta;
466
467 cl_git_pass(git_diff_from_buffer(&diff, text, strlen(text)));
468 cl_git_pass(git_patch_from_diff(&patch, diff, 0));
469 delta = git_patch_get_delta(patch);
470
471 cl_assert_equal_s(delta->old_file.path, "test-file");
472 cl_assert_equal_s(delta->new_file.path, "test-file");
473
474 git_patch_free(patch);
475 git_diff_free(diff);
476 }