1 #include "clar_libgit2.h"
2 #include "patch.h"
3 #include "patch_parse.h"
4 
5 #include "patch_common.h"
6 
ensure_patch_validity(git_patch * patch)7 static void ensure_patch_validity(git_patch *patch)
8 {
9 	const git_diff_delta *delta;
10 	char idstr[GIT_OID_HEXSZ+1] = {0};
11 
12 	cl_assert((delta = git_patch_get_delta(patch)) != NULL);
13 	cl_assert_equal_i(2, delta->nfiles);
14 
15 	cl_assert_equal_s(delta->old_file.path, "file.txt");
16 	cl_assert(delta->old_file.mode == GIT_FILEMODE_BLOB);
17 	cl_assert_equal_i(7, delta->old_file.id_abbrev);
18 	git_oid_nfmt(idstr, delta->old_file.id_abbrev, &delta->old_file.id);
19 	cl_assert_equal_s(idstr, "9432026");
20 	cl_assert_equal_i(0, delta->old_file.size);
21 
22 	cl_assert_equal_s(delta->new_file.path, "file.txt");
23 	cl_assert(delta->new_file.mode == GIT_FILEMODE_BLOB);
24 	cl_assert_equal_i(7, delta->new_file.id_abbrev);
25 	git_oid_nfmt(idstr, delta->new_file.id_abbrev, &delta->new_file.id);
26 	cl_assert_equal_s(idstr, "cd8fd12");
27 	cl_assert_equal_i(0, delta->new_file.size);
28 }
29 
ensure_identical_patch_inout(const char * content)30 static void ensure_identical_patch_inout(const char *content) {
31 	git_buf buf = GIT_BUF_INIT;
32 	git_patch *patch;
33 
34 	cl_git_pass(git_patch_from_buffer(&patch, content, strlen(content), NULL));
35 	cl_git_pass(git_patch_to_buf(&buf, patch));
36 	cl_assert_equal_strn(git_buf_cstr(&buf), content, strlen(content));
37 
38 	git_patch_free(patch);
39 	git_buf_dispose(&buf);
40 }
41 
test_patch_parse__original_to_change_middle(void)42 void test_patch_parse__original_to_change_middle(void)
43 {
44 	git_patch *patch;
45 
46 	cl_git_pass(git_patch_from_buffer(
47 		&patch, PATCH_ORIGINAL_TO_CHANGE_MIDDLE,
48 		strlen(PATCH_ORIGINAL_TO_CHANGE_MIDDLE), NULL));
49 	ensure_patch_validity(patch);
50 	git_patch_free(patch);
51 }
52 
test_patch_parse__leading_and_trailing_garbage(void)53 void test_patch_parse__leading_and_trailing_garbage(void)
54 {
55 	git_patch *patch;
56 	const char *leading = "This is some leading garbage.\n"
57 		"Maybe it's email headers?\n"
58 		"\n"
59 		PATCH_ORIGINAL_TO_CHANGE_MIDDLE;
60 	const char *trailing = PATCH_ORIGINAL_TO_CHANGE_MIDDLE
61 		"\n"
62 		"This is some trailing garbage.\n"
63 		"Maybe it's an email signature?\n";
64 	const char *both = "Here's some leading garbage\n"
65 		PATCH_ORIGINAL_TO_CHANGE_MIDDLE
66 		"And here's some trailing.\n";
67 
68 	cl_git_pass(git_patch_from_buffer(&patch, leading, strlen(leading),
69 		NULL));
70 	ensure_patch_validity(patch);
71 	git_patch_free(patch);
72 
73 	cl_git_pass(git_patch_from_buffer(&patch, trailing, strlen(trailing),
74 		NULL));
75 	ensure_patch_validity(patch);
76 	git_patch_free(patch);
77 
78 	cl_git_pass(git_patch_from_buffer(&patch, both, strlen(both),
79 		NULL));
80 	ensure_patch_validity(patch);
81 	git_patch_free(patch);
82 }
83 
test_patch_parse__nonpatches_fail_with_notfound(void)84 void test_patch_parse__nonpatches_fail_with_notfound(void)
85 {
86 	git_patch *patch;
87 
88 	cl_git_fail_with(GIT_ENOTFOUND,
89 		git_patch_from_buffer(&patch, PATCH_NOT_A_PATCH,
90 		strlen(PATCH_NOT_A_PATCH), NULL));
91 }
92 
test_patch_parse__invalid_patches_fails(void)93 void test_patch_parse__invalid_patches_fails(void)
94 {
95 	git_patch *patch;
96 
97 	cl_git_fail_with(GIT_ERROR,
98 		git_patch_from_buffer(&patch, PATCH_CORRUPT_GIT_HEADER,
99 		strlen(PATCH_CORRUPT_GIT_HEADER), NULL));
100 	cl_git_fail_with(GIT_ERROR,
101 		git_patch_from_buffer(&patch,
102 		PATCH_CORRUPT_MISSING_NEW_FILE,
103 		strlen(PATCH_CORRUPT_MISSING_NEW_FILE), NULL));
104 	cl_git_fail_with(GIT_ERROR,
105 		git_patch_from_buffer(&patch,
106 		PATCH_CORRUPT_MISSING_OLD_FILE,
107 		strlen(PATCH_CORRUPT_MISSING_OLD_FILE), NULL));
108 	cl_git_fail_with(GIT_ERROR,
109 		git_patch_from_buffer(&patch, PATCH_CORRUPT_NO_CHANGES,
110 		strlen(PATCH_CORRUPT_NO_CHANGES), NULL));
111 	cl_git_fail_with(GIT_ERROR,
112 		git_patch_from_buffer(&patch,
113 		PATCH_CORRUPT_MISSING_HUNK_HEADER,
114 		strlen(PATCH_CORRUPT_MISSING_HUNK_HEADER), NULL));
115 }
116 
test_patch_parse__no_newline_at_end_of_new_file(void)117 void test_patch_parse__no_newline_at_end_of_new_file(void)
118 {
119 	ensure_identical_patch_inout(PATCH_APPEND_NO_NL);
120 }
121 
test_patch_parse__no_newline_at_end_of_old_file(void)122 void test_patch_parse__no_newline_at_end_of_old_file(void)
123 {
124 	ensure_identical_patch_inout(PATCH_APPEND_NO_NL_IN_OLD_FILE);
125 }
126 
test_patch_parse__files_with_whitespaces_succeeds(void)127 void test_patch_parse__files_with_whitespaces_succeeds(void)
128 {
129 	ensure_identical_patch_inout(PATCH_NAME_WHITESPACE);
130 }
131 
test_patch_parse__lifetime_of_patch_does_not_depend_on_buffer(void)132 void test_patch_parse__lifetime_of_patch_does_not_depend_on_buffer(void)
133 {
134 	git_buf diff = GIT_BUF_INIT, rendered = GIT_BUF_INIT;
135 	git_patch *patch;
136 
137 	cl_git_pass(git_buf_sets(&diff, PATCH_ORIGINAL_TO_CHANGE_MIDDLE));
138 	cl_git_pass(git_patch_from_buffer(&patch, diff.ptr, diff.size, NULL));
139 	git_buf_dispose(&diff);
140 
141 	cl_git_pass(git_patch_to_buf(&rendered, patch));
142 	cl_assert_equal_s(PATCH_ORIGINAL_TO_CHANGE_MIDDLE, rendered.ptr);
143 	git_buf_dispose(&rendered);
144 
145 	cl_git_pass(git_patch_to_buf(&rendered, patch));
146 	cl_assert_equal_s(PATCH_ORIGINAL_TO_CHANGE_MIDDLE, rendered.ptr);
147 	git_buf_dispose(&rendered);
148 
149 	git_patch_free(patch);
150 }
151 
test_patch_parse__binary_file_with_missing_paths(void)152 void test_patch_parse__binary_file_with_missing_paths(void)
153 {
154 	git_patch *patch;
155 	cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_MISSING_PATHS,
156 					  strlen(PATCH_BINARY_FILE_WITH_MISSING_PATHS), NULL));
157 }
158 
test_patch_parse__binary_file_with_whitespace_paths(void)159 void test_patch_parse__binary_file_with_whitespace_paths(void)
160 {
161 	git_patch *patch;
162 	cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_WHITESPACE_PATHS,
163 					  strlen(PATCH_BINARY_FILE_WITH_WHITESPACE_PATHS), NULL));
164 }
165 
test_patch_parse__binary_file_with_empty_quoted_paths(void)166 void test_patch_parse__binary_file_with_empty_quoted_paths(void)
167 {
168 	git_patch *patch;
169 	cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_QUOTED_EMPTY_PATHS,
170 					  strlen(PATCH_BINARY_FILE_WITH_QUOTED_EMPTY_PATHS), NULL));
171 }
172 
test_patch_parse__binary_file_path_with_spaces(void)173 void test_patch_parse__binary_file_path_with_spaces(void)
174 {
175 	git_patch *patch;
176 	cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_PATH_WITH_SPACES,
177 					  strlen(PATCH_BINARY_FILE_PATH_WITH_SPACES), NULL));
178 }
179 
test_patch_parse__binary_file_path_without_body_paths(void)180 void test_patch_parse__binary_file_path_without_body_paths(void)
181 {
182 	git_patch *patch;
183 	cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_PATH_WITHOUT_BODY_PATHS,
184 					  strlen(PATCH_BINARY_FILE_PATH_WITHOUT_BODY_PATHS), NULL));
185 }
186 
test_patch_parse__binary_file_with_truncated_delta(void)187 void test_patch_parse__binary_file_with_truncated_delta(void)
188 {
189 	git_patch *patch;
190 	cl_git_fail(git_patch_from_buffer(&patch, PATCH_BINARY_FILE_WITH_TRUNCATED_DELTA,
191 					  strlen(PATCH_BINARY_FILE_WITH_TRUNCATED_DELTA), NULL));
192 	cl_assert_equal_s(git_error_last()->message, "truncated binary data at line 5");
193 }
194 
test_patch_parse__memory_leak_on_multiple_paths(void)195 void test_patch_parse__memory_leak_on_multiple_paths(void)
196 {
197 	git_patch *patch;
198 	cl_git_fail(git_patch_from_buffer(&patch, PATCH_MULTIPLE_OLD_PATHS, strlen(PATCH_MULTIPLE_OLD_PATHS), NULL));
199 }
200 
test_patch_parse__truncated_no_newline_at_end_of_file(void)201 void test_patch_parse__truncated_no_newline_at_end_of_file(void)
202 {
203 	size_t len = strlen(PATCH_APPEND_NO_NL) - strlen("at end of file\n");
204 	const git_diff_line *line;
205 	git_patch *patch;
206 
207 	cl_git_pass(git_patch_from_buffer(&patch, PATCH_APPEND_NO_NL, len, NULL));
208 	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 4));
209 	cl_assert_equal_s(line->content, "\\ No newline ");
210 
211 	git_patch_free(patch);
212 }
213 
test_patch_parse__line_number_overflow(void)214 void test_patch_parse__line_number_overflow(void)
215 {
216 	git_patch *patch;
217 	cl_git_fail(git_patch_from_buffer(&patch, PATCH_INTMAX_NEW_LINES, strlen(PATCH_INTMAX_NEW_LINES), NULL));
218 	git_patch_free(patch);
219 }
220