]> git.proxmox.com Git - libgit2.git/blame - tests/merge/files.c
New upstream version 1.1.0+dfsg.1
[libgit2.git] / tests / merge / files.c
CommitLineData
05d47768
ET
1#include "clar_libgit2.h"
2#include "git2/repository.h"
3#include "git2/merge.h"
4#include "buffer.h"
5#include "merge.h"
6#include "merge_helpers.h"
dcde5720 7#include "conflict_data.h"
05d47768 8#include "refs.h"
22a2d3d5 9#include "futils.h"
6c014bcc 10#include "diff_xdiff.h"
05d47768
ET
11
12#define TEST_REPO_PATH "merge-resolve"
13#define TEST_INDEX_PATH TEST_REPO_PATH "/.git/index"
14
15static git_repository *repo;
16static git_index *repo_index;
17
ac3d33df 18/* Fixture setup and teardown */
05d47768
ET
19void test_merge_files__initialize(void)
20{
21 git_config *cfg;
22
23 repo = cl_git_sandbox_init(TEST_REPO_PATH);
24 git_repository_index(&repo_index, repo);
25
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"));
29 git_config_free(cfg);
30}
31
32void test_merge_files__cleanup(void)
33{
34 git_index_free(repo_index);
35 cl_git_sandbox_cleanup();
36}
37
38void test_merge_files__automerge_from_bufs(void)
39{
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";
45
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;
50
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";
54 ours.mode = 0100755;
55
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;
60
61 cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, 0));
62
63 cl_assert_equal_i(1, result.automergeable);
64
65 cl_assert_equal_s("testfile.txt", result.path);
66 cl_assert_equal_i(0100755, result.mode);
67
68 cl_assert_equal_i(strlen(expected), result.len);
69 cl_assert_equal_strn(expected, result.ptr, result.len);
70
71 git_merge_file_result_free(&result);
72}
73
74void test_merge_files__automerge_use_best_path_and_mode(void)
75{
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";
81
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;
86
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";
90 ours.mode = 0100644;
91
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;
96
97 cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, 0));
98
99 cl_assert_equal_i(1, result.automergeable);
100
101 cl_assert_equal_s("theirs.txt", result.path);
102 cl_assert_equal_i(0100644, result.mode);
103
104 cl_assert_equal_i(strlen(expected), result.len);
105 cl_assert_equal_strn(expected, result.ptr, result.len);
106
107 git_merge_file_result_free(&result);
108}
109
110void test_merge_files__conflict_from_bufs(void)
111{
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};
116
117 const char *expected = "<<<<<<< testfile.txt\nAloha!\nOurs.\n=======\nHi!\nTheirs.\n>>>>>>> theirs.txt\n";
118 size_t expected_len = strlen(expected);
119
120 ancestor.ptr = "Hello!\nAncestor!\n";
121 ancestor.size = strlen(ancestor.ptr);
122 ancestor.path = "testfile.txt";
123 ancestor.mode = 0100755;
124
125 ours.ptr = "Aloha!\nOurs.\n";
126 ours.size = strlen(ours.ptr);
127 ours.path = "testfile.txt";
128 ours.mode = 0100644;
129
130 theirs.ptr = "Hi!\nTheirs.\n";
131 theirs.size = strlen(theirs.ptr);
132 theirs.path = "theirs.txt";
133 theirs.mode = 0100755;
134
135 cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, NULL));
136
137 cl_assert_equal_i(0, result.automergeable);
138
139 cl_assert_equal_s("theirs.txt", result.path);
140 cl_assert_equal_i(0100644, result.mode);
141
142 cl_assert_equal_i(expected_len, result.len);
143 cl_assert_equal_strn(expected, result.ptr, expected_len);
144
145 git_merge_file_result_free(&result);
146}
147
148void test_merge_files__automerge_from_index(void)
149{
150 git_merge_file_result result = {0};
151 git_index_entry ancestor, ours, theirs;
152
153 git_oid_fromstr(&ancestor.id, "6212c31dab5e482247d7977e4f0dd3601decf13b");
154 ancestor.path = "automergeable.txt";
155 ancestor.mode = 0100644;
156
157 git_oid_fromstr(&ours.id, "ee3fa1b8c00aff7fe02065fdb50864bb0d932ccf");
158 ours.path = "automergeable.txt";
159 ours.mode = 0100755;
160
161 git_oid_fromstr(&theirs.id, "058541fc37114bfc1dddf6bd6bffc7fae5c2e6fe");
162 theirs.path = "newname.txt";
163 theirs.mode = 0100644;
164
165 cl_git_pass(git_merge_file_from_index(&result, repo,
166 &ancestor, &ours, &theirs, 0));
167
168 cl_assert_equal_i(1, result.automergeable);
169
170 cl_assert_equal_s("newname.txt", result.path);
171 cl_assert_equal_i(0100755, result.mode);
172
173 cl_assert_equal_i(strlen(AUTOMERGEABLE_MERGED_FILE), result.len);
174 cl_assert_equal_strn(AUTOMERGEABLE_MERGED_FILE, result.ptr, result.len);
175
176 git_merge_file_result_free(&result);
177}
0f24cac2
JG
178
179void test_merge_files__automerge_whitespace_eol(void)
180{
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";
187
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;
192
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";
196 ours.mode = 0100755;
197
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;
202
13de9363 203 opts.flags |= GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL;
0f24cac2
JG
204 cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, &opts));
205
206 cl_assert_equal_i(1, result.automergeable);
207
208 cl_assert_equal_s("testfile.txt", result.path);
209 cl_assert_equal_i(0100755, result.mode);
210
211 cl_assert_equal_i(strlen(expected), result.len);
212 cl_assert_equal_strn(expected, result.ptr, result.len);
213
214 git_merge_file_result_free(&result);
215}
216
217void test_merge_files__automerge_whitespace_change(void)
218{
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";
225
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;
230
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";
234 ours.mode = 0100755;
235
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;
240
13de9363 241 opts.flags |= GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE;
0f24cac2
JG
242 cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, &opts));
243
244 cl_assert_equal_i(1, result.automergeable);
245
246 cl_assert_equal_s("testfile.txt", result.path);
247 cl_assert_equal_i(0100755, result.mode);
248
249 cl_assert_equal_i(strlen(expected), result.len);
250 cl_assert_equal_strn(expected, result.ptr, result.len);
251
252 git_merge_file_result_free(&result);
253}
ae8f7260
ET
254
255void test_merge_files__doesnt_add_newline(void)
256{
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";
263
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;
268
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";
272 ours.mode = 0100755;
273
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;
278
279 opts.flags |= GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE;
280 cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, &opts));
281
282 cl_assert_equal_i(1, result.automergeable);
283
284 cl_assert_equal_s("testfile.txt", result.path);
285 cl_assert_equal_i(0100755, result.mode);
286
287 cl_assert_equal_i(strlen(expected), result.len);
288 cl_assert_equal_strn(expected, result.ptr, result.len);
289
290 git_merge_file_result_free(&result);
291}
292
e4352066
ET
293void test_merge_files__skips_large_files(void)
294{
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};
299
6c014bcc 300 ours.size = GIT_XDIFF_MAX_SIZE + 1;
e4352066
ET
301 ours.path = "testfile.txt";
302 ours.mode = 0100755;
303
6c014bcc 304 theirs.size = GIT_XDIFF_MAX_SIZE + 1;
e4352066
ET
305 theirs.path = "testfile.txt";
306 theirs.mode = 0100755;
307
308 cl_git_pass(git_merge_file(&result, NULL, &ours, &theirs, &opts));
309
310 cl_assert_equal_i(0, result.automergeable);
311
312 git_merge_file_result_free(&result);
313}
314
315void test_merge_files__skips_binaries(void)
316{
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};
321
322 ancestor.ptr = "ance\0stor\0";
323 ancestor.size = 10;
324 ancestor.path = "ancestor.txt";
325 ancestor.mode = 0100755;
326
327 ours.ptr = "foo\0bar\0";
328 ours.size = 8;
329 ours.path = "ours.txt";
330 ours.mode = 0100755;
331
332 theirs.ptr = "bar\0foo\0";
333 theirs.size = 8;
334 theirs.path = "theirs.txt";
335 theirs.mode = 0100644;
336
337 cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, NULL));
338
339 cl_assert_equal_i(0, result.automergeable);
340
341 git_merge_file_result_free(&result);
342}
343
344void test_merge_files__handles_binaries_when_favored(void)
345{
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};
351
352 ancestor.ptr = "ance\0stor\0";
353 ancestor.size = 10;
354 ancestor.path = "ancestor.txt";
355 ancestor.mode = 0100755;
356
357 ours.ptr = "foo\0bar\0";
358 ours.size = 8;
359 ours.path = "ours.txt";
360 ours.mode = 0100755;
361
362 theirs.ptr = "bar\0foo\0";
363 theirs.size = 8;
364 theirs.path = "theirs.txt";
365 theirs.mode = 0100644;
366
367 opts.favor = GIT_MERGE_FILE_FAVOR_OURS;
368 cl_git_pass(git_merge_file(&result, &ancestor, &ours, &theirs, &opts));
369
370 cl_assert_equal_i(1, result.automergeable);
371
372 cl_assert_equal_s("ours.txt", result.path);
373 cl_assert_equal_i(0100755, result.mode);
374
375 cl_assert_equal_i(ours.size, result.len);
376 cl_assert(memcmp(result.ptr, ours.ptr, ours.size) == 0);
377
378 git_merge_file_result_free(&result);
379}
eae0bfdc
PP
380
381void test_merge_files__crlf_conflict_markers_for_crlf_files(void)
382{
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};
388
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);
393
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);
399
400 ancestor.ptr = "This file has\r\nCRLF line endings.\r\n";
401 ancestor.size = 35;
402 ancestor.path = "file.txt";
403 ancestor.mode = 0100644;
404
405 ours.ptr = "This file\r\ndoes, too.\r\n";
406 ours.size = 23;
407 ours.path = "file.txt";
408 ours.mode = 0100644;
409
410 theirs.ptr = "And so does\r\nthis one.\r\n";
411 theirs.size = 24;
412 theirs.path = "file.txt";
413 theirs.mode = 0100644;
414
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);
420
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);
427}