1 #include "clar_libgit2.h"
2 #include "git2/repository.h"
3 #include "git2/merge.h"
6 #include "merge_helpers.h"
7 #include "conflict_data.h"
10 #include "diff_xdiff.h"
12 #define TEST_REPO_PATH "merge-resolve"
13 #define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
15 static git_repository
*repo
;
16 static git_index
*repo_index
;
18 /* Fixture setup and teardown */
19 void test_merge_files__initialize(void)
23 repo
= cl_git_sandbox_init(TEST_REPO_PATH
);
24 git_repository_index(&repo_index
, repo
);
26 /* Ensure that the user's merge.conflictstyle doesn't interfere */
27 cl_git_pass(git_repository_config(&cfg
, repo
));
28 cl_git_pass(git_config_set_string(cfg
, "merge.conflictstyle", "merge"));
32 void test_merge_files__cleanup(void)
34 git_index_free(repo_index
);
35 cl_git_sandbox_cleanup();
38 void test_merge_files__automerge_from_bufs(void)
40 git_merge_file_input ancestor
= GIT_MERGE_FILE_INPUT_INIT
,
41 ours
= GIT_MERGE_FILE_INPUT_INIT
,
42 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
43 git_merge_file_result result
= {0};
44 const char *expected
= "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
46 ancestor
.ptr
= "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n";
47 ancestor
.size
= strlen(ancestor
.ptr
);
48 ancestor
.path
= "testfile.txt";
49 ancestor
.mode
= 0100755;
51 ours
.ptr
= "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n";
52 ours
.size
= strlen(ours
.ptr
);
53 ours
.path
= "testfile.txt";
56 theirs
.ptr
= "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
57 theirs
.size
= strlen(theirs
.ptr
);
58 theirs
.path
= "testfile.txt";
59 theirs
.mode
= 0100755;
61 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, 0));
63 cl_assert_equal_i(1, result
.automergeable
);
65 cl_assert_equal_s("testfile.txt", result
.path
);
66 cl_assert_equal_i(0100755, result
.mode
);
68 cl_assert_equal_i(strlen(expected
), result
.len
);
69 cl_assert_equal_strn(expected
, result
.ptr
, result
.len
);
71 git_merge_file_result_free(&result
);
74 void test_merge_files__automerge_use_best_path_and_mode(void)
76 git_merge_file_input ancestor
= GIT_MERGE_FILE_INPUT_INIT
,
77 ours
= GIT_MERGE_FILE_INPUT_INIT
,
78 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
79 git_merge_file_result result
= {0};
80 const char *expected
= "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
82 ancestor
.ptr
= "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n";
83 ancestor
.size
= strlen(ancestor
.ptr
);
84 ancestor
.path
= "testfile.txt";
85 ancestor
.mode
= 0100755;
87 ours
.ptr
= "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n";
88 ours
.size
= strlen(ours
.ptr
);
89 ours
.path
= "testfile.txt";
92 theirs
.ptr
= "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
93 theirs
.size
= strlen(theirs
.ptr
);
94 theirs
.path
= "theirs.txt";
95 theirs
.mode
= 0100755;
97 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, 0));
99 cl_assert_equal_i(1, result
.automergeable
);
101 cl_assert_equal_s("theirs.txt", result
.path
);
102 cl_assert_equal_i(0100644, result
.mode
);
104 cl_assert_equal_i(strlen(expected
), result
.len
);
105 cl_assert_equal_strn(expected
, result
.ptr
, result
.len
);
107 git_merge_file_result_free(&result
);
110 void test_merge_files__conflict_from_bufs(void)
112 git_merge_file_input ancestor
= GIT_MERGE_FILE_INPUT_INIT
,
113 ours
= GIT_MERGE_FILE_INPUT_INIT
,
114 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
115 git_merge_file_result result
= {0};
117 const char *expected
= "<<<<<<< testfile.txt\nAloha!\nOurs.\n=======\nHi!\nTheirs.\n>>>>>>> theirs.txt\n";
118 size_t expected_len
= strlen(expected
);
120 ancestor
.ptr
= "Hello!\nAncestor!\n";
121 ancestor
.size
= strlen(ancestor
.ptr
);
122 ancestor
.path
= "testfile.txt";
123 ancestor
.mode
= 0100755;
125 ours
.ptr
= "Aloha!\nOurs.\n";
126 ours
.size
= strlen(ours
.ptr
);
127 ours
.path
= "testfile.txt";
130 theirs
.ptr
= "Hi!\nTheirs.\n";
131 theirs
.size
= strlen(theirs
.ptr
);
132 theirs
.path
= "theirs.txt";
133 theirs
.mode
= 0100755;
135 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, NULL
));
137 cl_assert_equal_i(0, result
.automergeable
);
139 cl_assert_equal_s("theirs.txt", result
.path
);
140 cl_assert_equal_i(0100644, result
.mode
);
142 cl_assert_equal_i(expected_len
, result
.len
);
143 cl_assert_equal_strn(expected
, result
.ptr
, expected_len
);
145 git_merge_file_result_free(&result
);
148 void test_merge_files__automerge_from_index(void)
150 git_merge_file_result result
= {0};
151 git_index_entry ancestor
, ours
, theirs
;
153 git_oid_fromstr(&ancestor
.id
, "6212c31dab5e482247d7977e4f0dd3601decf13b");
154 ancestor
.path
= "automergeable.txt";
155 ancestor
.mode
= 0100644;
157 git_oid_fromstr(&ours
.id
, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
158 ours
.path
= "automergeable.txt";
161 git_oid_fromstr(&theirs
.id
, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe");
162 theirs
.path
= "newname.txt";
163 theirs
.mode
= 0100644;
165 cl_git_pass(git_merge_file_from_index(&result
, repo
,
166 &ancestor
, &ours
, &theirs
, 0));
168 cl_assert_equal_i(1, result
.automergeable
);
170 cl_assert_equal_s("newname.txt", result
.path
);
171 cl_assert_equal_i(0100755, result
.mode
);
173 cl_assert_equal_i(strlen(AUTOMERGEABLE_MERGED_FILE
), result
.len
);
174 cl_assert_equal_strn(AUTOMERGEABLE_MERGED_FILE
, result
.ptr
, result
.len
);
176 git_merge_file_result_free(&result
);
179 void test_merge_files__automerge_whitespace_eol(void)
181 git_merge_file_input ancestor
= GIT_MERGE_FILE_INPUT_INIT
,
182 ours
= GIT_MERGE_FILE_INPUT_INIT
,
183 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
184 git_merge_file_options opts
= GIT_MERGE_FILE_OPTIONS_INIT
;
185 git_merge_file_result result
= {0};
186 const char *expected
= "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
188 ancestor
.ptr
= "0 \n1\n2\n3\n4\n5\n6\n7\n8\n9\n10 \n";
189 ancestor
.size
= strlen(ancestor
.ptr
);
190 ancestor
.path
= "testfile.txt";
191 ancestor
.mode
= 0100755;
193 ours
.ptr
= "Zero\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n";
194 ours
.size
= strlen(ours
.ptr
);
195 ours
.path
= "testfile.txt";
198 theirs
.ptr
= "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\nTen\n";
199 theirs
.size
= strlen(theirs
.ptr
);
200 theirs
.path
= "testfile.txt";
201 theirs
.mode
= 0100755;
203 opts
.flags
|= GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL
;
204 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, &opts
));
206 cl_assert_equal_i(1, result
.automergeable
);
208 cl_assert_equal_s("testfile.txt", result
.path
);
209 cl_assert_equal_i(0100755, result
.mode
);
211 cl_assert_equal_i(strlen(expected
), result
.len
);
212 cl_assert_equal_strn(expected
, result
.ptr
, result
.len
);
214 git_merge_file_result_free(&result
);
217 void test_merge_files__automerge_whitespace_change(void)
219 git_merge_file_input ancestor
= GIT_MERGE_FILE_INPUT_INIT
,
220 ours
= GIT_MERGE_FILE_INPUT_INIT
,
221 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
222 git_merge_file_options opts
= GIT_MERGE_FILE_OPTIONS_INIT
;
223 git_merge_file_result result
= {0};
224 const char *expected
= "Zero\n1\n2\n3\n4\n5 XXX\n6 YYY\n7\n8\n9\nTen\n";
226 ancestor
.ptr
= "0\n1\n2\n3\n4\n5 XXX\n6YYY\n7\n8\n9\n10\n";
227 ancestor
.size
= strlen(ancestor
.ptr
);
228 ancestor
.path
= "testfile.txt";
229 ancestor
.mode
= 0100755;
231 ours
.ptr
= "Zero\n1\n2\n3\n4\n5 XXX\n6 YYY\n7\n8\n9\n10\n";
232 ours
.size
= strlen(ours
.ptr
);
233 ours
.path
= "testfile.txt";
236 theirs
.ptr
= "0\n1\n2\n3\n4\n5 XXX\n6 YYY\n7\n8\n9\nTen\n";
237 theirs
.size
= strlen(theirs
.ptr
);
238 theirs
.path
= "testfile.txt";
239 theirs
.mode
= 0100755;
241 opts
.flags
|= GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE
;
242 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, &opts
));
244 cl_assert_equal_i(1, result
.automergeable
);
246 cl_assert_equal_s("testfile.txt", result
.path
);
247 cl_assert_equal_i(0100755, result
.mode
);
249 cl_assert_equal_i(strlen(expected
), result
.len
);
250 cl_assert_equal_strn(expected
, result
.ptr
, result
.len
);
252 git_merge_file_result_free(&result
);
255 void test_merge_files__doesnt_add_newline(void)
257 git_merge_file_input ancestor
= GIT_MERGE_FILE_INPUT_INIT
,
258 ours
= GIT_MERGE_FILE_INPUT_INIT
,
259 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
260 git_merge_file_options opts
= GIT_MERGE_FILE_OPTIONS_INIT
;
261 git_merge_file_result result
= {0};
262 const char *expected
= "Zero\n1\n2\n3\n4\n5 XXX\n6 YYY\n7\n8\n9\nTen";
264 ancestor
.ptr
= "0\n1\n2\n3\n4\n5 XXX\n6YYY\n7\n8\n9\n10";
265 ancestor
.size
= strlen(ancestor
.ptr
);
266 ancestor
.path
= "testfile.txt";
267 ancestor
.mode
= 0100755;
269 ours
.ptr
= "Zero\n1\n2\n3\n4\n5 XXX\n6 YYY\n7\n8\n9\n10";
270 ours
.size
= strlen(ours
.ptr
);
271 ours
.path
= "testfile.txt";
274 theirs
.ptr
= "0\n1\n2\n3\n4\n5 XXX\n6 YYY\n7\n8\n9\nTen";
275 theirs
.size
= strlen(theirs
.ptr
);
276 theirs
.path
= "testfile.txt";
277 theirs
.mode
= 0100755;
279 opts
.flags
|= GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE
;
280 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, &opts
));
282 cl_assert_equal_i(1, result
.automergeable
);
284 cl_assert_equal_s("testfile.txt", result
.path
);
285 cl_assert_equal_i(0100755, result
.mode
);
287 cl_assert_equal_i(strlen(expected
), result
.len
);
288 cl_assert_equal_strn(expected
, result
.ptr
, result
.len
);
290 git_merge_file_result_free(&result
);
293 void test_merge_files__skips_large_files(void)
295 git_merge_file_input ours
= GIT_MERGE_FILE_INPUT_INIT
,
296 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
297 git_merge_file_options opts
= GIT_MERGE_FILE_OPTIONS_INIT
;
298 git_merge_file_result result
= {0};
300 ours
.size
= GIT_XDIFF_MAX_SIZE
+ 1;
301 ours
.path
= "testfile.txt";
304 theirs
.size
= GIT_XDIFF_MAX_SIZE
+ 1;
305 theirs
.path
= "testfile.txt";
306 theirs
.mode
= 0100755;
308 cl_git_pass(git_merge_file(&result
, NULL
, &ours
, &theirs
, &opts
));
310 cl_assert_equal_i(0, result
.automergeable
);
312 git_merge_file_result_free(&result
);
315 void test_merge_files__skips_binaries(void)
317 git_merge_file_input ancestor
= GIT_MERGE_FILE_INPUT_INIT
,
318 ours
= GIT_MERGE_FILE_INPUT_INIT
,
319 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
320 git_merge_file_result result
= {0};
322 ancestor
.ptr
= "ance\0stor\0";
324 ancestor
.path
= "ancestor.txt";
325 ancestor
.mode
= 0100755;
327 ours
.ptr
= "foo\0bar\0";
329 ours
.path
= "ours.txt";
332 theirs
.ptr
= "bar\0foo\0";
334 theirs
.path
= "theirs.txt";
335 theirs
.mode
= 0100644;
337 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, NULL
));
339 cl_assert_equal_i(0, result
.automergeable
);
341 git_merge_file_result_free(&result
);
344 void test_merge_files__handles_binaries_when_favored(void)
346 git_merge_file_input ancestor
= GIT_MERGE_FILE_INPUT_INIT
,
347 ours
= GIT_MERGE_FILE_INPUT_INIT
,
348 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
349 git_merge_file_options opts
= GIT_MERGE_FILE_OPTIONS_INIT
;
350 git_merge_file_result result
= {0};
352 ancestor
.ptr
= "ance\0stor\0";
354 ancestor
.path
= "ancestor.txt";
355 ancestor
.mode
= 0100755;
357 ours
.ptr
= "foo\0bar\0";
359 ours
.path
= "ours.txt";
362 theirs
.ptr
= "bar\0foo\0";
364 theirs
.path
= "theirs.txt";
365 theirs
.mode
= 0100644;
367 opts
.favor
= GIT_MERGE_FILE_FAVOR_OURS
;
368 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, &opts
));
370 cl_assert_equal_i(1, result
.automergeable
);
372 cl_assert_equal_s("ours.txt", result
.path
);
373 cl_assert_equal_i(0100755, result
.mode
);
375 cl_assert_equal_i(ours
.size
, result
.len
);
376 cl_assert(memcmp(result
.ptr
, ours
.ptr
, ours
.size
) == 0);
378 git_merge_file_result_free(&result
);
381 void test_merge_files__crlf_conflict_markers_for_crlf_files(void)
383 git_merge_file_input ancestor
= GIT_MERGE_FILE_INPUT_INIT
,
384 ours
= GIT_MERGE_FILE_INPUT_INIT
,
385 theirs
= GIT_MERGE_FILE_INPUT_INIT
;
386 git_merge_file_options opts
= GIT_MERGE_FILE_OPTIONS_INIT
;
387 git_merge_file_result result
= {0};
389 const char *expected
=
390 "<<<<<<< file.txt\r\nThis file\r\ndoes, too.\r\n"
391 "=======\r\nAnd so does\r\nthis one.\r\n>>>>>>> file.txt\r\n";
392 size_t expected_len
= strlen(expected
);
394 const char *expected_diff3
=
395 "<<<<<<< file.txt\r\nThis file\r\ndoes, too.\r\n"
396 "||||||| file.txt\r\nThis file has\r\nCRLF line endings.\r\n"
397 "=======\r\nAnd so does\r\nthis one.\r\n>>>>>>> file.txt\r\n";
398 size_t expected_diff3_len
= strlen(expected_diff3
);
400 ancestor
.ptr
= "This file has\r\nCRLF line endings.\r\n";
402 ancestor
.path
= "file.txt";
403 ancestor
.mode
= 0100644;
405 ours
.ptr
= "This file\r\ndoes, too.\r\n";
407 ours
.path
= "file.txt";
410 theirs
.ptr
= "And so does\r\nthis one.\r\n";
412 theirs
.path
= "file.txt";
413 theirs
.mode
= 0100644;
415 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, &opts
));
416 cl_assert_equal_i(0, result
.automergeable
);
417 cl_assert_equal_i(expected_len
, result
.len
);
418 cl_assert(memcmp(expected
, result
.ptr
, expected_len
) == 0);
419 git_merge_file_result_free(&result
);
421 opts
.flags
|= GIT_MERGE_FILE_STYLE_DIFF3
;
422 cl_git_pass(git_merge_file(&result
, &ancestor
, &ours
, &theirs
, &opts
));
423 cl_assert_equal_i(0, result
.automergeable
);
424 cl_assert_equal_i(expected_diff3_len
, result
.len
);
425 cl_assert(memcmp(expected_diff3
, result
.ptr
, expected_len
) == 0);
426 git_merge_file_result_free(&result
);