1 #include "clar_libgit2.h"
2 #include "apply_helpers.h"
3 
4 static git_repository *repo;
5 
6 #define TEST_REPO_PATH "merge-recursive"
7 
test_apply_both__initialize(void)8 void test_apply_both__initialize(void)
9 {
10 	git_oid oid;
11 	git_commit *commit;
12 
13 	repo = cl_git_sandbox_init(TEST_REPO_PATH);
14 
15 	git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707");
16 	cl_git_pass(git_commit_lookup(&commit, repo, &oid));
17 	cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL));
18 	git_commit_free(commit);
19 }
20 
test_apply_both__cleanup(void)21 void test_apply_both__cleanup(void)
22 {
23 	cl_git_sandbox_cleanup();
24 }
25 
test_apply_both__generated_diff(void)26 void test_apply_both__generated_diff(void)
27 {
28 	git_oid a_oid, b_oid;
29 	git_commit *a_commit, *b_commit;
30 	git_tree *a_tree, *b_tree;
31 	git_diff *diff;
32 	git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
33 
34 	struct merge_index_entry both_expected[] = {
35 		{ 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" },
36 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
37 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
38 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
39 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
40 		{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" },
41 	};
42 	size_t both_expected_cnt = sizeof(both_expected) /
43 		sizeof(struct merge_index_entry);
44 
45 	git_oid_fromstr(&a_oid, "539bd011c4822c560c1d17cab095006b7a10f707");
46 	git_oid_fromstr(&b_oid, "7c7bf85e978f1d18c0566f702d2cb7766b9c8d4f");
47 	cl_git_pass(git_commit_lookup(&a_commit, repo, &a_oid));
48 	cl_git_pass(git_commit_lookup(&b_commit, repo, &b_oid));
49 
50 	cl_git_pass(git_commit_tree(&a_tree, a_commit));
51 	cl_git_pass(git_commit_tree(&b_tree, b_commit));
52 
53 	cl_git_pass(git_diff_tree_to_tree(&diff, repo, a_tree, b_tree, &diff_opts));
54 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
55 
56 	validate_apply_index(repo, both_expected, both_expected_cnt);
57 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
58 
59 	git_diff_free(diff);
60 	git_tree_free(a_tree);
61 	git_tree_free(b_tree);
62 	git_commit_free(a_commit);
63 	git_commit_free(b_commit);
64 }
65 
test_apply_both__parsed_diff(void)66 void test_apply_both__parsed_diff(void)
67 {
68 	git_diff *diff;
69 
70 	struct merge_index_entry both_expected[] = {
71 		{ 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" },
72 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
73 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
74 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
75 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
76 		{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" },
77 	};
78 	size_t both_expected_cnt = sizeof(both_expected) /
79 		sizeof(struct merge_index_entry);
80 
81 	cl_git_pass(git_diff_from_buffer(&diff,
82 		DIFF_MODIFY_TWO_FILES, strlen(DIFF_MODIFY_TWO_FILES)));
83 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
84 
85 	validate_apply_index(repo, both_expected, both_expected_cnt);
86 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
87 
88 	git_diff_free(diff);
89 }
90 
test_apply_both__removes_file(void)91 void test_apply_both__removes_file(void)
92 {
93 	git_diff *diff;
94 
95 	struct merge_index_entry both_expected[] = {
96 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
97 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
98 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
99 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
100 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" },
101 	};
102 	size_t both_expected_cnt = sizeof(both_expected) /
103 	    sizeof(struct merge_index_entry);
104 
105 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_FILE,
106 		strlen(DIFF_DELETE_FILE)));
107 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
108 
109 	validate_apply_index(repo, both_expected, both_expected_cnt);
110 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
111 
112 	git_diff_free(diff);
113 }
114 
test_apply_both__adds_file(void)115 void test_apply_both__adds_file(void)
116 {
117 	git_diff *diff;
118 
119 	struct merge_index_entry both_expected[] = {
120 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
121 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
122 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
123 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
124 		{ 0100644, "6370543fcfedb3e6516ec53b06158f3687dc1447", 0, "newfile.txt" },
125 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
126 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" },
127 	};
128 	size_t both_expected_cnt = sizeof(both_expected) /
129 	    sizeof(struct merge_index_entry);
130 
131 	cl_git_pass(git_diff_from_buffer(&diff,
132 		DIFF_ADD_FILE, strlen(DIFF_ADD_FILE)));
133 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
134 
135 	validate_apply_index(repo, both_expected, both_expected_cnt);
136 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
137 
138 	git_diff_free(diff);
139 }
140 
test_apply_both__application_failure_leaves_index_unmodified(void)141 void test_apply_both__application_failure_leaves_index_unmodified(void)
142 {
143 	git_diff *diff;
144 	git_index *index;
145 
146 	const char *diff_file = DIFF_MODIFY_TWO_FILES;
147 
148 	struct merge_index_entry index_expected[] = {
149 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
150 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
151 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
152 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
153 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
154 	};
155 	size_t index_expected_cnt = sizeof(index_expected) /
156 		sizeof(struct merge_index_entry);
157 
158 	/* mutate the index */
159 	cl_git_pass(git_repository_index(&index, repo));
160 	cl_git_pass(git_index_remove(index, "veal.txt", 0));
161 	cl_git_pass(git_index_write(index));
162 	git_index_free(index);
163 
164 	cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file)));
165 	cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
166 
167 	validate_apply_index(repo, index_expected, index_expected_cnt);
168 	validate_workdir_unchanged(repo);
169 
170 	git_diff_free(diff);
171 }
172 
test_apply_both__index_must_match_workdir(void)173 void test_apply_both__index_must_match_workdir(void)
174 {
175 	git_diff *diff;
176 	git_index *index;
177 	git_index_entry idx_entry;
178 
179 	const char *diff_file = DIFF_MODIFY_TWO_FILES;
180 
181 	/*
182 	 * Append a line to the end of the file in both the index and the
183 	 * working directory.  Although the appended line would allow for
184 	 * patch application in each, the line appended is different in
185 	 * each, so the application should not be allowed.
186 	 */
187 	cl_git_append2file("merge-recursive/asparagus.txt",
188 	    "This is a modification.\n");
189 
190 	cl_git_pass(git_repository_index(&index, repo));
191 
192 	memset(&idx_entry, 0, sizeof(git_index_entry));
193 	idx_entry.mode = 0100644;
194 	idx_entry.path = "asparagus.txt";
195 	cl_git_pass(git_oid_fromstr(&idx_entry.id, "06d3fefb8726ab1099acc76e02dfb85e034b2538"));
196 	cl_git_pass(git_index_add(index, &idx_entry));
197 
198 	cl_git_pass(git_index_write(index));
199 	git_index_free(index);
200 
201 	cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file)));
202 	cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
203 
204 	git_diff_free(diff);
205 }
206 
test_apply_both__index_mode_must_match_workdir(void)207 void test_apply_both__index_mode_must_match_workdir(void)
208 {
209 	git_diff *diff;
210 
211 	if (!cl_is_chmod_supported())
212 		clar__skip();
213 
214 	/* Set a file in the working directory executable. */
215 	cl_must_pass(p_chmod("merge-recursive/asparagus.txt", 0755));
216 
217 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_MODIFY_TWO_FILES,
218 	    strlen(DIFF_MODIFY_TWO_FILES)));
219 	cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
220 
221 	git_diff_free(diff);
222 }
223 
test_apply_both__application_failure_leaves_workdir_unmodified(void)224 void test_apply_both__application_failure_leaves_workdir_unmodified(void)
225 {
226 	git_diff *diff;
227 	git_index *index;
228 
229 	const char *diff_file = DIFF_MODIFY_TWO_FILES;
230 
231 	struct merge_index_entry workdir_expected[] = {
232 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
233 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
234 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
235 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
236 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
237 		{ 0100644, "8684724651336001c5dbce74bed6736d2443958d", 0, "veal.txt" },
238 	};
239 	size_t workdir_expected_cnt = sizeof(workdir_expected) /
240 		sizeof(struct merge_index_entry);
241 
242 	/* mutate the workdir */
243 	cl_git_rewritefile("merge-recursive/veal.txt",
244 	    "This is a modification.\n");
245 
246 	cl_git_pass(git_repository_index(&index, repo));
247 	cl_git_pass(git_index_add_bypath(index, "veal.txt"));
248 	cl_git_pass(git_index_write(index));
249 	git_index_free(index);
250 
251 	cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file)));
252 	cl_git_fail_with(GIT_EAPPLYFAIL, git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
253 
254 	validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt);
255 
256 	git_diff_free(diff);
257 }
258 
test_apply_both__keeps_nonconflicting_changes(void)259 void test_apply_both__keeps_nonconflicting_changes(void)
260 {
261 	git_diff *diff;
262 	git_index *index;
263 	git_index_entry idx_entry;
264 
265 	const char *diff_file = DIFF_MODIFY_TWO_FILES;
266 
267 	struct merge_index_entry index_expected[] = {
268 		{ 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" },
269 		{ 0100644, "898d12687fb35be271c27c795a6b32c8b51da79e", 0, "beef.txt" },
270 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
271 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
272 		{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" },
273 	};
274 	size_t index_expected_cnt = sizeof(index_expected) /
275 		sizeof(struct merge_index_entry);
276 
277 	struct merge_index_entry workdir_expected[] = {
278 		{ 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" },
279 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
280 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
281 		{ 0100644, "f75ba05f340c51065cbea2e1fdbfe5fe13144c97", 0, "gravy.txt" },
282 		{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" },
283 	};
284 	size_t workdir_expected_cnt = sizeof(workdir_expected) /
285 		sizeof(struct merge_index_entry);
286 
287 	/* mutate the index */
288 	cl_git_pass(git_repository_index(&index, repo));
289 
290 	memset(&idx_entry, 0, sizeof(git_index_entry));
291 	idx_entry.mode = 0100644;
292 	idx_entry.path = "beef.txt";
293 	cl_git_pass(git_oid_fromstr(&idx_entry.id, "898d12687fb35be271c27c795a6b32c8b51da79e"));
294 	cl_git_pass(git_index_add(index, &idx_entry));
295 
296 	cl_git_pass(git_index_remove(index, "bouilli.txt", 0));
297 	cl_git_pass(git_index_write(index));
298 	git_index_free(index);
299 
300 	/* and mutate the working directory */
301 	cl_git_rmfile("merge-recursive/oyster.txt");
302 	cl_git_rewritefile("merge-recursive/gravy.txt", "Hello, world.\n");
303 
304 	cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file)));
305 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
306 
307 	validate_apply_index(repo, index_expected, index_expected_cnt);
308 	validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt);
309 
310 	git_diff_free(diff);
311 }
312 
test_apply_both__can_apply_nonconflicting_file_changes(void)313 void test_apply_both__can_apply_nonconflicting_file_changes(void)
314 {
315 	git_diff *diff;
316 	git_index *index;
317 
318 	const char *diff_file = DIFF_MODIFY_TWO_FILES;
319 
320 	struct merge_index_entry both_expected[] = {
321 		{ 0100644, "f8a701c8a1a22c1729ee50faff1111f2d64f96fc", 0, "asparagus.txt" },
322 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
323 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
324 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
325 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
326 		{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" },
327 	};
328 	size_t both_expected_cnt = sizeof(both_expected) /
329 		sizeof(struct merge_index_entry);
330 
331 	/*
332 	 * Replace the workdir file with a version that is different than
333 	 * HEAD but such that the patch still applies cleanly.  This item
334 	 * has a new line appended.
335 	 */
336 	cl_git_append2file("merge-recursive/asparagus.txt",
337 	    "This line is added in the index and the workdir.\n");
338 
339 	cl_git_pass(git_repository_index(&index, repo));
340 	cl_git_pass(git_index_add_bypath(index, "asparagus.txt"));
341 	cl_git_pass(git_index_write(index));
342 	git_index_free(index);
343 
344 	cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file)));
345 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
346 
347 	validate_apply_index(repo, both_expected, both_expected_cnt);
348 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
349 
350 	git_diff_free(diff);
351 }
352 
test_apply_both__honors_crlf_attributes(void)353 void test_apply_both__honors_crlf_attributes(void)
354 {
355 	git_diff *diff;
356 	git_oid oid;
357 	git_commit *commit;
358 
359 	const char *diff_file = DIFF_MODIFY_TWO_FILES;
360 
361 	struct merge_index_entry index_expected[] = {
362 		{ 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" },
363 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
364 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
365 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
366 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
367 		{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" },
368 	};
369 	size_t index_expected_cnt = sizeof(index_expected) /
370 		sizeof(struct merge_index_entry);
371 
372 	struct merge_index_entry workdir_expected[] = {
373 		{ 0100644, "176a458f94e0ea5272ce67c36bf30b6be9caf623", 0, ".gitattributes" },
374 		{ 0100644, "ffb36e513f5fdf8a6ba850a20142676a2ac4807d", 0, "asparagus.txt" },
375 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
376 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
377 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
378 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
379 		{ 0100644, "a7b066537e6be7109abfe4ff97b675d4e077da20", 0, "veal.txt" },
380 	};
381 	size_t workdir_expected_cnt = sizeof(workdir_expected) /
382 		sizeof(struct merge_index_entry);
383 
384 	cl_git_mkfile("merge-recursive/.gitattributes", "* text=auto\n");
385 
386 	cl_git_rmfile("merge-recursive/asparagus.txt");
387 	cl_git_rmfile("merge-recursive/veal.txt");
388 
389 	git_oid_fromstr(&oid, "539bd011c4822c560c1d17cab095006b7a10f707");
390 	cl_git_pass(git_commit_lookup(&commit, repo, &oid));
391 	cl_git_pass(git_reset(repo, (git_object *)commit, GIT_RESET_HARD, NULL));
392 	git_commit_free(commit);
393 
394 	cl_git_pass(git_diff_from_buffer(&diff, diff_file, strlen(diff_file)));
395 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
396 
397 	validate_apply_index(repo, index_expected, index_expected_cnt);
398 	validate_apply_workdir(repo, workdir_expected, workdir_expected_cnt);
399 
400 	git_diff_free(diff);
401 }
402 
test_apply_both__rename(void)403 void test_apply_both__rename(void)
404 {
405 	git_diff *diff;
406 
407 	struct merge_index_entry both_expected[] = {
408 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
409 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
410 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
411 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "notbeef.txt" },
412 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
413 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" },
414 	};
415 	size_t both_expected_cnt = sizeof(both_expected) /
416 		sizeof(struct merge_index_entry);
417 
418 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_FILE,
419 		strlen(DIFF_RENAME_FILE)));
420 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
421 
422 	validate_apply_index(repo, both_expected, both_expected_cnt);
423 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
424 
425 	git_diff_free(diff);
426 }
427 
test_apply_both__rename_and_modify(void)428 void test_apply_both__rename_and_modify(void)
429 {
430 	git_diff *diff;
431 
432 	struct merge_index_entry both_expected[] = {
433 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
434 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
435 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
436 		{ 0100644, "6fa10147f00fe1fab1d5e835529a9dad53db8552", 0, "notbeef.txt" },
437 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
438 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" },
439 	};
440 	size_t both_expected_cnt = sizeof(both_expected) /
441 		sizeof(struct merge_index_entry);
442 
443 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_FILE,
444 		strlen(DIFF_RENAME_AND_MODIFY_FILE)));
445 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
446 
447     validate_apply_index(repo, both_expected, both_expected_cnt);
448 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
449 
450 	git_diff_free(diff);
451 }
452 
test_apply_both__rename_a_to_b_to_c(void)453 void test_apply_both__rename_a_to_b_to_c(void)
454 {
455 	git_diff *diff;
456 
457 	struct merge_index_entry both_expected[] = {
458 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "beef.txt" },
459 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
460 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
461 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "notbeef.txt" },
462 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
463 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" },
464 	};
465 	size_t both_expected_cnt = sizeof(both_expected) /
466 		sizeof(struct merge_index_entry);
467 
468 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_A_TO_B_TO_C,
469 		strlen(DIFF_RENAME_A_TO_B_TO_C)));
470 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
471 
472 	validate_apply_index(repo, both_expected, both_expected_cnt);
473 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
474 
475 	git_diff_free(diff);
476 }
477 
test_apply_both__rename_a_to_b_to_c_exact(void)478 void test_apply_both__rename_a_to_b_to_c_exact(void)
479 {
480 	git_diff *diff;
481 
482 	struct merge_index_entry both_expected[] = {
483 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "beef.txt" },
484 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
485 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
486 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "notbeef.txt" },
487 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
488 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" },
489 	};
490 	size_t both_expected_cnt = sizeof(both_expected) /
491 		sizeof(struct merge_index_entry);
492 
493 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_A_TO_B_TO_C_EXACT,
494 		strlen(DIFF_RENAME_A_TO_B_TO_C_EXACT)));
495 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
496 
497 	validate_apply_index(repo, both_expected, both_expected_cnt);
498 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
499 
500 	git_diff_free(diff);
501 }
502 
test_apply_both__rename_circular(void)503 void test_apply_both__rename_circular(void)
504 {
505 	git_diff *diff;
506 
507 	struct merge_index_entry both_expected[] = {
508 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "asparagus.txt" },
509 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "beef.txt" },
510 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
511 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
512 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
513 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }
514 	};
515 	size_t both_expected_cnt = sizeof(both_expected) /
516 		sizeof(struct merge_index_entry);
517 
518 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_CIRCULAR,
519 		strlen(DIFF_RENAME_CIRCULAR)));
520 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
521 
522 	validate_apply_index(repo, both_expected, both_expected_cnt);
523 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
524 
525 	git_diff_free(diff);
526 }
527 
test_apply_both__rename_2_to_1(void)528 void test_apply_both__rename_2_to_1(void)
529 {
530 	git_diff *diff;
531 
532 	struct merge_index_entry both_expected[] = {
533 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "2.txt" },
534 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
535 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
536 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
537 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }
538 	};
539 	size_t both_expected_cnt = sizeof(both_expected) /
540 		sizeof(struct merge_index_entry);
541 
542 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_2_TO_1,
543 		strlen(DIFF_RENAME_2_TO_1)));
544 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
545 
546 	validate_apply_index(repo, both_expected, both_expected_cnt);
547 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
548 
549 	git_diff_free(diff);
550 }
551 
test_apply_both__rename_1_to_2(void)552 void test_apply_both__rename_1_to_2(void)
553 {
554 	git_diff *diff;
555 
556 	struct merge_index_entry both_expected[] = {
557 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "1.txt" },
558 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "2.txt" },
559 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
560 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
561 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
562 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
563 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }
564 	};
565 	size_t both_expected_cnt = sizeof(both_expected) /
566 		sizeof(struct merge_index_entry);
567 
568 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_1_TO_2,
569 		strlen(DIFF_RENAME_1_TO_2)));
570 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
571 
572 	validate_apply_index(repo, both_expected, both_expected_cnt);
573 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
574 
575 	git_diff_free(diff);
576 }
577 
test_apply_both__two_deltas_one_file(void)578 void test_apply_both__two_deltas_one_file(void)
579 {
580 	git_diff *diff;
581 
582 	struct merge_index_entry both_expected[] = {
583 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
584 		{ 0100644, "0a9fd4415635e72573f0f6b5e68084cfe18f5075", 0, "beef.txt" },
585 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
586 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
587 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
588 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }
589 	};
590 	size_t both_expected_cnt = sizeof(both_expected) /
591 		sizeof(struct merge_index_entry);
592 
593 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_TWO_DELTAS_ONE_FILE,
594 		strlen(DIFF_TWO_DELTAS_ONE_FILE)));
595 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
596 
597 	validate_apply_index(repo, both_expected, both_expected_cnt);
598 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
599 
600 	git_diff_free(diff);
601 }
602 
test_apply_both__two_deltas_one_new_file(void)603 void test_apply_both__two_deltas_one_new_file(void)
604 {
605 	git_diff *diff;
606 
607 	struct merge_index_entry both_expected[] = {
608 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
609 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
610 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
611 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
612 		{ 0100644, "08d4c445cf0078f3d9b604b82f32f4d87e083325", 0, "newfile.txt" },
613 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
614 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }
615 	};
616 	size_t both_expected_cnt = sizeof(both_expected) /
617 		sizeof(struct merge_index_entry);
618 
619 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_TWO_DELTAS_ONE_NEW_FILE,
620 		strlen(DIFF_TWO_DELTAS_ONE_NEW_FILE)));
621 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
622 
623 	validate_apply_index(repo, both_expected, both_expected_cnt);
624 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
625 
626 	git_diff_free(diff);
627 }
628 
test_apply_both__rename_and_modify_deltas(void)629 void test_apply_both__rename_and_modify_deltas(void)
630 {
631 	git_diff *diff;
632 
633 	struct merge_index_entry both_expected[] = {
634 		{ 0100644, "61c686bed39684eee8a2757ceb1291004a21333f", 0, "asdf.txt" },
635 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
636 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
637 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
638 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
639 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
640 	};
641 	size_t both_expected_cnt = sizeof(both_expected) /
642 		sizeof(struct merge_index_entry);
643 
644 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_DELTAS,
645 		strlen(DIFF_RENAME_AND_MODIFY_DELTAS)));
646 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
647 
648 	validate_apply_index(repo, both_expected, both_expected_cnt);
649 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
650 
651 	git_diff_free(diff);
652 }
653 
test_apply_both__rename_delta_after_modify_delta(void)654 void test_apply_both__rename_delta_after_modify_delta(void)
655 {
656 	git_diff *diff;
657 
658 	struct merge_index_entry both_expected[] = {
659 		{ 0100644, "f51658077d85f2264fa179b4d0848268cb3475c3", 0, "asparagus.txt" },
660 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
661 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
662 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
663 		{ 0100644, "292cb60ce5e25c337c5b6e12957bbbfe1be4bf49", 0, "other.txt" },
664 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
665 		{ 0100644, "c8c120f466591bbe3b8867361d5ec3cdd9fda756", 0, "veal.txt" }
666 	};
667 	size_t both_expected_cnt = sizeof(both_expected) /
668 		sizeof(struct merge_index_entry);
669 
670 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AFTER_MODIFY,
671 		strlen(DIFF_RENAME_AFTER_MODIFY)));
672 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
673 
674 	validate_apply_index(repo, both_expected, both_expected_cnt);
675 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
676 
677 	git_diff_free(diff);
678 }
679 
test_apply_both__cant_rename_after_modify_nonexistent_target_path(void)680 void test_apply_both__cant_rename_after_modify_nonexistent_target_path(void)
681 {
682 	git_diff *diff;
683 
684 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AFTER_MODIFY_TARGET_PATH,
685 		strlen(DIFF_RENAME_AFTER_MODIFY_TARGET_PATH)));
686 	cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
687 
688 	git_diff_free(diff);
689 }
690 
test_apply_both__cant_modify_source_path_after_rename(void)691 void test_apply_both__cant_modify_source_path_after_rename(void)
692 {
693 	git_diff *diff;
694 
695 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_RENAME_AND_MODIFY_SOURCE_PATH,
696 		strlen(DIFF_RENAME_AND_MODIFY_SOURCE_PATH)));
697 	cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
698 
699 	git_diff_free(diff);
700 }
701 
test_apply_both__readd_deleted_file(void)702 void test_apply_both__readd_deleted_file(void)
703 {
704 	git_diff *diff;
705 
706 	struct merge_index_entry both_expected[] = {
707 		{ 0100644, "2dc7f8b24ba27f3888368bd180df03ff4c6c6fab", 0, "asparagus.txt" },
708 		{ 0100644, "68f6182f4c85d39e1309d97c7e456156dc9c0096", 0, "beef.txt" },
709 		{ 0100644, "4b7c5650008b2e747fe1809eeb5a1dde0e80850a", 0, "bouilli.txt" },
710 		{ 0100644, "c4e6cca3ec6ae0148ed231f97257df8c311e015f", 0, "gravy.txt" },
711 		{ 0100644, "68af1fc7407fd9addf1701a87eb1c95c7494c598", 0, "oyster.txt" },
712 		{ 0100644, "94d2c01087f48213bd157222d54edfefd77c9bba", 0, "veal.txt" }
713 	};
714 	size_t both_expected_cnt = sizeof(both_expected) /
715 		sizeof(struct merge_index_entry);
716 
717 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_DELETE_AND_READD_FILE,
718 		strlen(DIFF_DELETE_AND_READD_FILE)));
719 	cl_git_pass(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
720 
721 	validate_apply_index(repo, both_expected, both_expected_cnt);
722 	validate_apply_workdir(repo, both_expected, both_expected_cnt);
723 
724 	git_diff_free(diff);
725 }
726 
test_apply_both__cant_remove_file_twice(void)727 void test_apply_both__cant_remove_file_twice(void)
728 {
729 	git_diff *diff;
730 
731 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_REMOVE_FILE_TWICE,
732 		strlen(DIFF_REMOVE_FILE_TWICE)));
733 	cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
734 
735 	git_diff_free(diff);
736 }
737 
test_apply_both__cant_add_invalid_filename(void)738 void test_apply_both__cant_add_invalid_filename(void)
739 {
740 	git_diff *diff;
741 
742 	cl_git_pass(git_diff_from_buffer(&diff, DIFF_ADD_INVALID_FILENAME,
743 		strlen(DIFF_ADD_INVALID_FILENAME)));
744 	cl_git_fail(git_apply(repo, diff, GIT_APPLY_LOCATION_BOTH, NULL));
745 
746 	git_diff_free(diff);
747 }
748