]> git.proxmox.com Git - libgit2.git/blob - tests/apply/both.c
400df5e3861170c7035042486a135436c44a517d
[libgit2.git] / tests / apply / both.c
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
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
21 void test_apply_both__cleanup(void)
22 {
23 cl_git_sandbox_cleanup();
24 }
25
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }