1 #include "clar_libgit2.h"
3 #include "patch_parse.h"
4 #include "diff_helpers.h"
6 #include "../patch/patch_common.h"
8 void test_diff_parse__cleanup(void)
10 cl_git_sandbox_cleanup();
13 void test_diff_parse__nonpatches_fail_with_notfound(void)
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";
21 cl_git_fail_with(GIT_ENOTFOUND
,
22 git_diff_from_buffer(&diff
,
25 cl_git_fail_with(GIT_ENOTFOUND
,
26 git_diff_from_buffer(&diff
,
28 strlen(not_with_leading
)));
29 cl_git_fail_with(GIT_ENOTFOUND
,
30 git_diff_from_buffer(&diff
,
32 strlen(not_with_trailing
)));
33 cl_git_fail_with(GIT_ENOTFOUND
,
34 git_diff_from_buffer(&diff
,
36 strlen(not_with_both
)));
39 static void test_parse_invalid_diff(const char *invalid_diff
)
42 git_str buf
= GIT_STR_INIT
;
44 /* throw some random (legitimate) diffs in with the given invalid
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
);
53 cl_git_fail_with(GIT_ERROR
,
54 git_diff_from_buffer(&diff
, buf
.ptr
, buf
.size
));
56 git_str_dispose(&buf
);
59 void test_diff_parse__exact_rename(void)
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"
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"
75 cl_git_pass(git_diff_from_buffer(
76 &diff
, content
, strlen(content
)));
80 void test_diff_parse__empty_file(void)
85 " 1 file changed, 0 insertions(+), 0 deletions(-)\n"
86 " created mode 100644 file\n"
88 "diff --git a/file b/file\n"
89 "new file mode 100644\n"
90 "index 0000000..e69de29\n"
95 cl_git_pass(git_diff_from_buffer(
96 &diff
, content
, strlen(content
)));
100 void test_diff_parse__no_extended_headers(void)
102 const char *content
= PATCH_NO_EXTENDED_HEADERS
;
105 cl_git_pass(git_diff_from_buffer(
106 &diff
, content
, strlen(content
)));
110 void test_diff_parse__add_delete_no_index(void)
112 const char *content
=
113 "diff --git a/file.txt b/file.txt\n"
114 "new file mode 100644\n"
120 "diff --git a/otherfile.txt b/otherfile.txt\n"
121 "deleted file mode 100644\n"
122 "--- a/otherfile.txt\n"
128 cl_git_pass(git_diff_from_buffer(
129 &diff
, content
, strlen(content
)));
133 void test_diff_parse__invalid_patches_fails(void)
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
);
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
)
145 git_repository
*repo
;
146 git_diff
*computed
, *parsed
;
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
;
152 repo
= cl_git_sandbox_init(sandbox
);
154 opts
.id_abbrev
= GIT_OID_HEXSZ
;
155 opts
.flags
= GIT_DIFF_SHOW_BINARY
| diff_flags
;
156 findopts
.flags
= find_flags
;
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
);
161 cl_git_pass(git_diff_tree_to_tree(&computed
, repo
, a
, b
, &opts
));
164 cl_git_pass(git_diff_find_similar(computed
, &findopts
));
166 cl_git_pass(git_diff_to_buf(&computed_buf
,
167 computed
, GIT_DIFF_FORMAT_PATCH
));
169 cl_git_pass(git_diff_from_buffer(&parsed
,
170 computed_buf
.ptr
, computed_buf
.size
));
172 diff_assert_equal(computed
, parsed
);
177 git_diff_free(computed
);
178 git_diff_free(parsed
);
180 git_buf_dispose(&computed_buf
);
182 cl_git_sandbox_cleanup();
185 void test_diff_parse__can_parse_generated_diff(void)
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
,
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
);
228 void test_diff_parse__get_patch_from_diff(void)
230 git_repository
*repo
;
231 git_diff
*computed
, *parsed
;
233 git_diff_options opts
= GIT_DIFF_OPTIONS_INIT
;
234 git_buf computed_buf
= GIT_BUF_INIT
;
235 git_patch
*patch_computed
, *patch_parsed
;
237 repo
= cl_git_sandbox_init("diff");
239 opts
.flags
= GIT_DIFF_SHOW_BINARY
;
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
);
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));
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));
256 git_patch_num_hunks(patch_computed
),
257 git_patch_num_hunks(patch_parsed
));
259 git_patch_free(patch_computed
);
260 git_patch_free(patch_parsed
);
265 git_diff_free(computed
);
266 git_diff_free(parsed
);
268 git_buf_dispose(&computed_buf
);
270 cl_git_sandbox_cleanup();
273 static int file_cb(const git_diff_delta
*delta
, float progress
, void *payload
)
275 int *called
= (int *) payload
;
277 GIT_UNUSED(progress
);
282 void test_diff_parse__foreach_works_with_parsed_patch(void)
285 "diff --git a/obj1 b/obj2\n"
286 "index 1234567..7654321 10644\n"
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);
302 void test_diff_parse__parsing_minimal_patch_succeeds(void)
305 "diff --git a/obj1 b/obj2\n"
306 "index 1234567..7654321 10644\n"
312 git_buf buf
= GIT_BUF_INIT
;
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
);
320 git_buf_dispose(&buf
);
323 void test_diff_parse__patch_roundtrip_succeeds(void)
325 const char buf1
[] = "a\n", buf2
[] = "b\n";
326 git_buf patchbuf
= GIT_BUF_INIT
, diffbuf
= GIT_BUF_INIT
;
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
));
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
));
336 cl_assert_equal_s(patchbuf
.ptr
, diffbuf
.ptr
);
338 git_patch_free(patch
);
340 git_buf_dispose(&patchbuf
);
341 git_buf_dispose(&diffbuf
);
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))
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
)
348 const git_diff_line
*line
;
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
);
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__)
360 void test_diff_parse__issue4672(void)
362 const char *text
= "diff --git a/a b/a\n"
363 "index 7f129fd..af431f2 100644\n"
372 const git_diff_hunk
*hunk
;
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));
379 cl_git_assert_lineinfo(3, -1, 1, patch
, 0, l
++);
380 cl_git_assert_lineinfo(-1, 3, 1, patch
, 0, l
++);
382 cl_assert_equal_i(n
, l
);
384 git_patch_free(patch
);
388 void test_diff_parse__lineinfo(void)
390 const char *text
= PATCH_ORIGINAL_TO_CHANGE_MIDDLE
;
393 const git_diff_hunk
*hunk
;
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));
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
++);
409 cl_assert_equal_i(n
, l
);
411 git_patch_free(patch
);
416 void test_diff_parse__new_file_with_space(void)
418 const char *content
= PATCH_ORIGINAL_NEW_FILE_WITH_SPACE
;
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));
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");
430 git_patch_free(patch
);
434 void test_diff_parse__new_file_with_space_and_regenerate_patch(void)
436 const char *content
= PATCH_ORIGINAL_NEW_FILE_WITH_SPACE
;
437 git_diff
*diff
= NULL
;
438 git_buf buf
= GIT_BUF_INIT
;
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
));
443 git_buf_dispose(&buf
);
447 void test_diff_parse__delete_file_with_space_and_regenerate_patch(void)
449 const char *content
= PATCH_DELETE_FILE_WITH_SPACE
;
450 git_diff
*diff
= NULL
;
451 git_buf buf
= GIT_BUF_INIT
;
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
));
456 git_buf_dispose(&buf
);
460 void test_diff_parse__crlf(void)
462 const char *text
= PATCH_CRLF
;
465 const git_diff_delta
*delta
;
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
);
471 cl_assert_equal_s(delta
->old_file
.path
, "test-file");
472 cl_assert_equal_s(delta
->new_file
.path
, "test-file");
474 git_patch_free(patch
);