In the command-line client, forbid
[svn.git] / subversion / tests / libsvn_diff / diff-diff3-test.c
blob60bd09008cf0d855e8821e4dc92231c000ec0938
1 /*
2 * Incomplete regression tests for the diff/diff3 library.
4 * ====================================================================
5 * Copyright (c) 2003-2006 CollabNet. All rights reserved.
7 * This software is licensed as described in the file COPYING, which
8 * you should have received as part of this distribution. The terms
9 * are also available at http://subversion.tigris.org/license-1.html.
10 * If newer versions of this license are posted there, you may use a
11 * newer version instead, at your option.
13 * This software consists of voluntary contributions made by many
14 * individuals. For exact contribution history, see the revision
15 * history and logs, available at http://subversion.tigris.org/.
16 * ====================================================================
20 #include "svn_diff.h"
21 #include "svn_pools.h"
22 #include "svn_utf.h"
24 #include "../svn_test.h"
26 /* Used to terminate lines in large multi-line string literals. */
27 #define NL APR_EOL_STR
29 /* Random number seed. Yes, it's global, just pretend you can't see it. */
30 static apr_uint32_t diff_diff3_seed;
32 /* Return the value of the current random number seed, initializing it if
33 necessary */
34 static apr_uint32_t
35 seed_val(void)
37 static svn_boolean_t first = TRUE;
39 if (first)
41 diff_diff3_seed = (apr_uint32_t) apr_time_now();
42 first = FALSE;
45 return diff_diff3_seed;
48 /* Return a random number N such that MIN_VAL <= N <= MAX_VAL */
49 static apr_uint32_t
50 range_rand(apr_uint32_t min_val,
51 apr_uint32_t max_val)
53 apr_uint64_t diff = max_val - min_val;
54 apr_uint64_t val = diff * svn_test_rand(&diff_diff3_seed);
55 val /= 0xffffffff;
56 return min_val + (apr_uint32_t) val;
59 /* Make a file that is between MIN_LINES and MAX_LINES lines long, with at
60 most VAR_LINES distinct lines. If BLOCK_LINES is non-zero then every
61 other block of BLOCK_LINES lines will be identical, if BLOCK_LINES is
62 zero all lines will have contents chosen at random. If TRAILING_NEWLINE
63 is TRUE then the file will have a trailing newline, if not then it wont. */
64 static svn_error_t *
65 make_random_file(const char *filename,
66 int min_lines,
67 int max_lines,
68 int var_lines,
69 int block_lines,
70 svn_boolean_t trailing_newline,
71 apr_pool_t *pool)
73 apr_file_t *file;
74 apr_status_t status;
75 int num_lines;
77 num_lines = range_rand(min_lines, max_lines);
79 status = apr_file_open(&file, filename,
80 APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
81 pool);
82 if (status)
83 return svn_error_createf(status, NULL, "failed to open '%s'", filename);
85 while (num_lines--)
87 int x;
88 if (! (block_lines && (num_lines / block_lines % 2)))
89 x = range_rand(1, var_lines);
90 else
91 x = 0;
92 if (num_lines || trailing_newline)
93 apr_file_printf(file, "line %d line %d line %d\n", x, x, x);
94 else
95 apr_file_printf(file, "line %d line %d line %d", x, x, x);
98 status = apr_file_close(file);
99 if (status)
100 return svn_error_createf(status, NULL, "failed to close '%s'", filename);
102 return SVN_NO_ERROR;
106 /* Create a file called FILENAME containing CONTENTS */
107 static svn_error_t *
108 make_file(const char *filename,
109 const char *contents,
110 apr_pool_t *pool)
112 apr_file_t *file;
113 apr_status_t status;
115 status = apr_file_open(&file, filename,
116 APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
117 pool);
118 if (status)
119 return svn_error_createf(status, NULL, "failed to open '%s'", filename);
121 status = apr_file_write_full(file, contents, strlen(contents), NULL);
122 if (status)
123 return svn_error_createf(status, NULL, "failed to write '%s'", filename);
125 status = apr_file_close(file);
126 if (status)
127 return svn_error_createf(status, NULL, "failed to close '%s'", filename);
129 return SVN_NO_ERROR;
133 /* Create three files called FILENAME1, FILENAME2 and FILENAME3
134 containing CONTENTS1, CONTENTS2 and CONTENTS3 respectively. Run a
135 three way merge to merge the difference between CONTENTS1 and
136 CONTENTS2 into CONTENTS3, using OPTIONS, and verify that it results
137 in EXPECTED. The files FILENAME1, FILENAME2 and FILENAME3 will be
138 deleted if the merge is successful, and preserved otherwise. If
139 the merge fails the merge output will be in a file called
140 "merge-FILENAME1-FILENAME2-FILENAME3". */
141 static svn_error_t *
142 three_way_merge(const char *filename1,
143 const char *filename2,
144 const char *filename3,
145 const char *contents1,
146 const char *contents2,
147 const char *contents3,
148 const char *expected,
149 const svn_diff_file_options_t *options,
150 apr_pool_t *pool)
152 svn_diff_t *diff;
153 apr_file_t *output;
154 svn_stream_t *ostream;
155 apr_status_t status;
156 svn_stringbuf_t *actual;
157 char *merge_name = apr_psprintf(pool, "merge-%s-%s-%s",
158 filename1, filename2, filename3);
160 /* We have an EXPECTED string we can match, because we don't support
161 any other combinations (yet) than the ones above. */
162 svn_string_t *original = svn_string_create(contents1, pool);
163 svn_string_t *modified = svn_string_create(contents2, pool);
164 svn_string_t *latest = svn_string_create(contents3, pool);
166 options = options ? options : svn_diff_file_options_create(pool);
168 SVN_ERR(svn_diff_mem_string_diff3(&diff,
169 original, modified, latest, options, pool));
171 actual = svn_stringbuf_create("", pool);
172 ostream = svn_stream_from_stringbuf(actual, pool);
174 SVN_ERR(svn_diff_mem_string_output_merge
175 (ostream, diff, original, modified, latest,
176 apr_psprintf(pool, "||||||| %s", filename1),
177 apr_psprintf(pool, "<<<<<<< %s", filename2),
178 apr_psprintf(pool, ">>>>>>> %s", filename3),
179 NULL, /* separator */
180 FALSE, FALSE, pool));
182 SVN_ERR(svn_stream_close(ostream));
183 if (strcmp(actual->data, expected) != 0)
184 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
185 "Failed mem-diff, expected and actual "
186 "outputs differ.\nEXPECTED:\n%s\n"
187 "ACTUAL:\n%s\n", expected, actual->data);
189 SVN_ERR(make_file(filename1, contents1, pool));
190 SVN_ERR(make_file(filename2, contents2, pool));
191 SVN_ERR(make_file(filename3, contents3, pool));
193 SVN_ERR(svn_diff_file_diff3_2(&diff, filename1, filename2, filename3,
194 options, pool));
195 status = apr_file_open(&output, merge_name,
196 APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
197 pool);
198 if (status)
199 return svn_error_createf(status, NULL, "failed to open '%s'", merge_name);
201 ostream = svn_stream_from_aprfile(output, pool);
202 SVN_ERR(svn_diff_file_output_merge(ostream, diff,
203 filename1, filename2, filename3,
204 NULL, NULL, NULL, NULL,
205 FALSE,
206 FALSE,
207 pool));
208 SVN_ERR(svn_stream_close(ostream));
209 status = apr_file_close(output);
210 if (status)
211 return svn_error_createf(status, NULL, "failed to close '%s'", merge_name);
212 SVN_ERR(svn_stringbuf_from_file(&actual, merge_name, pool));
213 if (strcmp(actual->data, expected))
214 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
215 "failed merging diff '%s' to '%s' into '%s'",
216 filename1, filename2, filename3);
218 SVN_ERR(svn_io_remove_file(filename1, pool));
219 if (strcmp(filename1, filename2))
220 SVN_ERR(svn_io_remove_file(filename2, pool));
221 if (strcmp(filename1, filename3) && strcmp(filename2, filename3))
222 SVN_ERR(svn_io_remove_file(filename3, pool));
223 SVN_ERR(svn_io_remove_file(merge_name, pool));
225 return SVN_NO_ERROR;
229 /* Create two files called FILENAME1 and FILENAME2 containing
230 CONTENTS1 and CONTENTS2 respectively. Run a two way diff between
231 CONTENTS1 and CONTENTS2, using OPTIONS, and verify that it results
232 in EXPECTED. Then run the trivial merges to update CONTENTS1 to
233 CONTENTS2 and CONTENTS2 to CONTENTS1. The files FILENAME1,
234 FILENAME2 and be deleted if the diff and merges are successful, and
235 preserved otherwise. If the diff fails the diff output will be in
236 a file called "diff-FILENAME1-FILENAME2". */
237 static svn_error_t *
238 two_way_diff(const char *filename1,
239 const char *filename2,
240 const char *contents1,
241 const char *contents2,
242 const char *expected,
243 const svn_diff_file_options_t *options,
244 apr_pool_t *pool)
246 svn_diff_t *diff;
247 apr_file_t *output;
248 svn_stream_t *ostream;
249 apr_status_t status;
250 svn_stringbuf_t *actual;
251 char *diff_name = apr_psprintf(pool, "diff-%s-%s", filename1, filename2);
253 /* We have an EXPECTED string we can match, because we don't support
254 any other combinations (yet) than the ones above. */
255 svn_string_t *original = svn_string_create(contents1, pool);
256 svn_string_t *modified = svn_string_create(contents2, pool);
258 options = options ? options : svn_diff_file_options_create(pool);
260 SVN_ERR(svn_diff_mem_string_diff(&diff, original, modified, options, pool));
262 actual = svn_stringbuf_create("", pool);
263 ostream = svn_stream_from_stringbuf(actual, pool);
265 SVN_ERR(svn_diff_mem_string_output_unified(ostream, diff,
266 filename1, filename2,
267 SVN_APR_LOCALE_CHARSET,
268 original, modified, pool));
269 SVN_ERR(svn_stream_close(ostream));
270 if (strcmp(actual->data, expected) != 0)
271 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
272 "Failed mem-diff, expected and actual "
273 "outputs differ.\nEXPECTED:\n%s\n"
274 "ACTUAL:\n%s\n", expected, actual->data);
276 SVN_ERR(make_file(filename1, contents1, pool));
277 SVN_ERR(make_file(filename2, contents2, pool));
279 /* Check that two-way diff between contents1 and contents2 produces
280 expected output. */
281 SVN_ERR(svn_diff_file_diff_2(&diff, filename1, filename2, options, pool));
282 status = apr_file_open(&output, diff_name,
283 APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
284 pool);
285 if (status)
286 return svn_error_createf(status, NULL, "failed to open '%s'", diff_name);
288 ostream = svn_stream_from_aprfile(output, pool);
289 SVN_ERR(svn_diff_file_output_unified2(ostream, diff,
290 filename1, filename2,
291 filename1, filename2,
292 SVN_APR_LOCALE_CHARSET, pool));
293 SVN_ERR(svn_stream_close(ostream));
294 status = apr_file_close(output);
295 if (status)
296 return svn_error_createf(status, NULL, "failed to close '%s'", diff_name);
298 SVN_ERR(svn_stringbuf_from_file(&actual, diff_name, pool));
299 if (strcmp(actual->data, expected))
300 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
301 "failed comparing '%s' and '%s'",
302 filename1, filename2);
304 /* May as well do the trivial merges while we are here */
305 SVN_ERR(three_way_merge(filename1, filename2, filename1,
306 contents1, contents2, contents1, contents2, NULL,
307 pool));
308 SVN_ERR(three_way_merge(filename2, filename1, filename2,
309 contents2, contents1, contents2, contents1, NULL,
310 pool));
312 SVN_ERR(svn_io_remove_file(diff_name, pool));
314 return SVN_NO_ERROR;
317 struct random_mod
319 int index; /* Zero based line number */
320 int mod; /* Type of mod: 0, 1, 2 (can be interpreted as you like just
321 do it consistently) */
324 /* Fill the SELECTED array of length NUM to select with randomly chosen
325 values, ensuring that none of SELECTED.INDEX are duplicates and that all
326 the SELECTED.INDEX values are less than NUM_LINES. Also ensure that for
327 each SELECTED.INDEX the three elements of LINES from SELECTED.INDEX-1 to
328 SELECTED.INDEX+1 are unset. Set all LINES[SELECTED.INDEX]. */
329 static void
330 select_lines(struct random_mod *selected,
331 int num_to_select,
332 svn_boolean_t *lines,
333 int num_lines)
335 int i;
336 for (i = 0; i < num_to_select; ++i)
338 int j;
339 for (;;)
341 j= range_rand(0, num_lines - 1);
342 if (lines[j] /* already selected */
344 (j > 0 && lines[j - 1]) /* previous selected */
346 (j < num_lines - 1 && lines[j + 1])) /* next selected */
347 continue; /* try again */
348 break; /* got one */
350 selected[i].index = j;
351 selected[i].mod = range_rand(0, 2);
352 lines[j] = TRUE;
357 /* Create a file called FILENAME where the contents are obtained by
358 applying the modifications in MOD_LINES, of which there are NUM_MODS, to
359 a theoretical pristine file of length NUM_LINES lines. */
360 static svn_error_t *
361 make_random_merge_file(const char *filename,
362 int num_lines,
363 struct random_mod *mod_lines,
364 int num_mods,
365 apr_pool_t *pool)
367 apr_file_t *file;
368 apr_status_t status;
369 int i;
371 status = apr_file_open(&file, filename,
372 APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
373 pool);
374 if (status)
375 return svn_error_createf(status, NULL, "failed to open '%s'", filename);
377 for (i = 0; i < num_lines; ++i)
379 int j;
380 for (j = 0; j < num_mods; ++j)
381 if (mod_lines[j].index == i)
382 break;
384 if (j < num_mods)
386 switch (mod_lines[j].mod)
388 case 0:
389 apr_file_printf(file, "replace line %d\n", i);
390 break;
391 case 1:
392 apr_file_printf(file,
393 "added line %d\n"
394 "unmodified line %d\n"
395 "added line %d\n",
396 i, i, i);
397 break;
398 default:
399 ; /* Delete the line */
402 else
404 apr_file_printf(file, "unmodified line %d\n", i);
408 status = apr_file_close(file);
409 if (status)
410 return svn_error_createf(status, NULL, "failed to close '%s'", filename);
412 return SVN_NO_ERROR;
416 /* ========================================================================== */
418 static svn_error_t *
419 dump_core(const char **msg,
420 svn_boolean_t msg_only,
421 svn_test_opts_t *opts,
422 apr_pool_t *pool)
424 *msg = "these dump core";
425 if (msg_only)
426 return SVN_NO_ERROR;
428 SVN_ERR(two_way_diff("foo1", "bar1",
432 NULL, pool));
434 SVN_ERR(two_way_diff("foo2", "bar2",
435 "Aa\n"
436 "Bb\n"
437 "Cc\n",
441 "--- foo2" NL
442 "+++ bar2" NL
443 "@@ -1,3 +0,0 @@" NL
444 "-Aa\n"
445 "-Bb\n"
446 "-Cc\n",
447 NULL, pool));
449 SVN_ERR(two_way_diff("foo3", "bar3",
452 "Aa\n"
453 "Bb\n"
454 "Cc\n",
456 "--- foo3" NL
457 "+++ bar3" NL
458 "@@ -0,0 +1,3 @@" NL
459 "+Aa\n"
460 "+Bb\n"
461 "+Cc\n",
462 NULL, pool));
464 return SVN_NO_ERROR;
468 static svn_error_t *
469 test_two_way_unified(const char **msg,
470 svn_boolean_t msg_only,
471 svn_test_opts_t *opts,
472 apr_pool_t *pool)
474 svn_diff_file_options_t *diff_opts = svn_diff_file_options_create(pool);
475 *msg = "2-way unified diff and trivial merge";
476 if (msg_only)
477 return SVN_NO_ERROR;
479 SVN_ERR(two_way_diff("foo4", "bar4",
480 "Aa\n",
482 "Aa\n"
483 "Bb\n"
484 "Cc\n",
486 "--- foo4" NL
487 "+++ bar4" NL
488 "@@ -1 +1,3 @@" NL
489 " Aa\n"
490 "+Bb\n"
491 "+Cc\n",
492 NULL, pool));
494 SVN_ERR(two_way_diff("foo4b", "bar4b",
495 "Cc\n",
497 "Aa\n"
498 "Bb\n"
499 "Cc\n",
501 "--- foo4b" NL
502 "+++ bar4b" NL
503 "@@ -1 +1,3 @@" NL
504 "+Aa\n"
505 "+Bb\n"
506 " Cc\n",
507 NULL, pool));
509 diff_opts->ignore_eol_style = TRUE;
510 SVN_ERR(two_way_diff("foo4c", "bar4c",
511 "Cc\n",
513 "Aa\r"
514 "Bb\r"
515 "Cc\r",
517 "--- foo4c" NL
518 "+++ bar4c" NL
519 "@@ -1 +1,3 @@" NL
520 "+Aa\r"
521 "+Bb\r"
522 " Cc\n",
523 diff_opts, pool));
524 diff_opts->ignore_eol_style = FALSE;
526 SVN_ERR(two_way_diff("foo5", "bar5",
527 "Aa\n"
528 "Bb\n"
529 "Cc\n",
531 "Aa\n",
533 "--- foo5" NL
534 "+++ bar5" NL
535 "@@ -1,3 +1 @@" NL
536 " Aa\n"
537 "-Bb\n"
538 "-Cc\n",
539 NULL, pool));
541 SVN_ERR(two_way_diff("foo5b", "bar5b",
542 "Aa\n"
543 "Bb\n"
544 "Cc\n",
546 "Cc\n",
548 "--- foo5b" NL
549 "+++ bar5b" NL
550 "@@ -1,3 +1 @@" NL
551 "-Aa\n"
552 "-Bb\n"
553 " Cc\n",
554 NULL, pool));
556 diff_opts->ignore_eol_style = TRUE;
557 SVN_ERR(two_way_diff("foo5c", "bar5c",
558 "Aa\r\n"
559 "Bb\r\n"
560 "Cc\r\n",
562 "Cc\n",
564 "--- foo5c" NL
565 "+++ bar5c" NL
566 "@@ -1,3 +1 @@" NL
567 "-Aa\r\n"
568 "-Bb\r\n"
569 " Cc\r\n",
570 diff_opts, pool));
573 SVN_ERR(two_way_diff("foo5d", "bar5d",
574 "Aa\r\n"
575 "\r\n"
576 "Bb\r\n"
577 "\r\n"
578 "Cc\r\n"
579 "\r\n",
581 "Aa\n"
582 "\n"
583 "Bb\n"
584 "\n"
585 "Cc\n"
586 "\n",
589 diff_opts, pool));
590 diff_opts->ignore_eol_style = FALSE;
592 SVN_ERR(two_way_diff("foo6", "bar6",
593 "Aa\n"
594 "Bb\n"
595 "Cc\n",
597 "Aa\n"
598 "Bb\n"
599 "Cc\n",
602 NULL, pool));
604 SVN_ERR(two_way_diff("foo6b", "bar6b",
605 "Aa\n"
606 "Bb\n"
607 "Cc\n",
609 "Aa\n"
610 "Xx\n"
611 "Cc\n",
613 "--- foo6b" NL
614 "+++ bar6b" NL
615 "@@ -1,3 +1,3 @@" NL
616 " Aa\n"
617 "-Bb\n"
618 "+Xx\n"
619 " Cc\n",
620 NULL, pool));
622 SVN_ERR(two_way_diff("foo6c", "bar6c",
623 "Aa\r\n"
624 "Bb\r\n"
625 "Cc\r\n",
627 "Aa\r\n"
628 "Xx\r\n"
629 "Cc\r\n",
631 "--- foo6c" NL
632 "+++ bar6c" NL
633 "@@ -1,3 +1,3 @@" NL
634 " Aa\r\n"
635 "-Bb\r\n"
636 "+Xx\r\n"
637 " Cc\r\n",
638 NULL, pool));
640 SVN_ERR(two_way_diff("foo6d", "bar6d",
641 "Aa\r"
642 "Bb\r"
643 "Cc\r",
645 "Aa\r"
646 "Xx\r"
647 "Cc\r",
649 "--- foo6d" NL
650 "+++ bar6d" NL
651 "@@ -1,3 +1,3 @@" NL
652 " Aa\r"
653 "-Bb\r"
654 "+Xx\r"
655 " Cc\r",
656 NULL, pool));
658 diff_opts->ignore_space = svn_diff_file_ignore_space_change;
659 SVN_ERR(two_way_diff("foo6e", "bar6e",
660 " A a \n"
661 " B b \r"
662 " C c \r\n",
664 " A a \n"
665 " B b \r"
666 " C c \r\n",
669 diff_opts, pool));
670 diff_opts->ignore_space = svn_diff_file_ignore_space_none;
672 diff_opts->ignore_space = svn_diff_file_ignore_space_all;
673 SVN_ERR(two_way_diff("foo6f", "bar6f",
674 "Aa\n"
675 "Bb\r"
676 "Cc\r\n",
678 " A a \n"
679 " B b \r"
680 " C c \r\n",
683 diff_opts, pool));
684 diff_opts->ignore_space = svn_diff_file_ignore_space_none;
686 diff_opts->ignore_space = svn_diff_file_ignore_space_all;
687 diff_opts->ignore_eol_style = TRUE;
688 SVN_ERR(two_way_diff("foo6f", "bar6f",
689 "Aa\n"
690 "Bb\r"
691 "Cc\r\n",
693 " A a \r"
694 " B b \r\n"
695 " C c \n",
698 diff_opts, pool));
699 diff_opts->ignore_space = svn_diff_file_ignore_space_none;
700 diff_opts->ignore_eol_style = FALSE;
702 SVN_ERR(two_way_diff("foo7", "bar7",
703 "Aa\n",
705 "Bb\n",
707 "--- foo7" NL
708 "+++ bar7" NL
709 "@@ -1 +1 @@" NL
710 "-Aa\n"
711 "+Bb\n",
712 NULL, pool));
714 SVN_ERR(two_way_diff("foo7a", "bar7a",
715 "Aa\n"
716 "Cc\n",
718 "Bb\n"
719 "Cc\n",
721 "--- foo7a" NL
722 "+++ bar7a" NL
723 "@@ -1,2 +1,2 @@" NL
724 "-Aa\n"
725 "+Bb\n"
726 " Cc\n",
727 NULL, pool));
729 SVN_ERR(two_way_diff("foo7b", "bar7b",
730 "Aa\r"
731 "Cc\n",
733 "Bb\n"
734 "Cc\n",
736 "--- foo7b" NL
737 "+++ bar7b" NL
738 "@@ -1,2 +1,2 @@" NL
739 "-Aa\r"
740 "+Bb\n"
741 " Cc\n",
742 NULL, pool));
744 SVN_ERR(two_way_diff("foo8", "bar8",
745 "Aa\n"
746 "Bb\n"
747 "Cc\n",
749 "Xx\n"
750 "Yy\n",
752 "--- foo8" NL
753 "+++ bar8" NL
754 "@@ -1,3 +1,2 @@" NL
755 "-Aa\n"
756 "-Bb\n"
757 "-Cc\n"
758 "+Xx\n"
759 "+Yy\n",
760 NULL, pool));
762 SVN_ERR(two_way_diff("foo9", "bar9",
763 "Aa\n"
764 "Bb\n"
765 "Cc\n",
767 "Bb\n",
769 "--- foo9" NL
770 "+++ bar9" NL
771 "@@ -1,3 +1 @@" NL
772 "-Aa\n"
773 " Bb\n"
774 "-Cc\n",
775 NULL, pool));
777 SVN_ERR(two_way_diff("foo10", "bar10",
778 "Aa\n"
779 "Bb\n"
780 "Cc",
782 "Aa\n"
783 "Xx\n"
784 "Yy\n",
786 "--- foo10" NL
787 "+++ bar10" NL
788 "@@ -1,3 +1,3 @@" NL
789 " Aa\n"
790 "-Bb\n"
791 "-Cc" NL
792 "\\ No newline at end of file" NL
793 "+Xx\n"
794 "+Yy\n",
795 NULL, pool));
797 SVN_ERR(two_way_diff("foo11", "bar11",
798 "Aa\n"
799 "Xx\n"
800 "Yy\n",
802 "Aa\n"
803 "Bb\n"
804 "Cc",
806 "--- foo11" NL
807 "+++ bar11" NL
808 "@@ -1,3 +1,3 @@" NL
809 " Aa\n"
810 "-Xx\n"
811 "-Yy\n"
812 "+Bb\n"
813 "+Cc" NL
814 "\\ No newline at end of file" NL,
815 NULL, pool));
817 SVN_ERR(two_way_diff("foo12", "bar12",
818 "Aa\n"
819 "Xx\n"
820 "Yy",
822 "Aa\n"
823 "Bb\n"
824 "Cc",
826 "--- foo12" NL
827 "+++ bar12" NL
828 "@@ -1,3 +1,3 @@" NL
829 " Aa\n"
830 "-Xx\n"
831 "-Yy" NL
832 "\\ No newline at end of file" NL
833 "+Bb\n"
834 "+Cc" NL
835 "\\ No newline at end of file" NL,
836 NULL, pool));
838 SVN_ERR(two_way_diff("foo13", "bar13",
839 "Aa\n"
840 "Bb\n"
841 "Cc\n"
842 "Dd\n"
843 "Ee\n"
844 "Ff\n"
845 "Gg\n",
847 "Xx\n"
848 "Aa\n"
849 "Bb\n"
850 "Cc\n"
851 "Dd\n"
852 "Ee\n"
853 "Ff\n"
854 "Gg\n"
855 "Yy\n",
857 "--- foo13" NL
858 "+++ bar13" NL
859 "@@ -1,3 +1,4 @@" NL
860 "+Xx\n"
861 " Aa\n"
862 " Bb\n"
863 " Cc\n"
864 "@@ -5,3 +6,4 @@" NL
865 " Ee\n"
866 " Ff\n"
867 " Gg\n"
868 "+Yy\n",
869 NULL, pool));
871 SVN_ERR(two_way_diff("foo14", "bar14",
872 "Aa\n"
873 "Bb\n"
874 "Cc\n"
875 "Dd\n"
876 "Ee\n"
877 "Ff\n"
878 "Gg\n",
880 "Bb\n"
881 "Aa\n"
882 "Cc\n"
883 "Dd\n"
884 "Ee\n"
885 "Gg\n"
886 "Ff\n",
888 "--- foo14" NL
889 "+++ bar14" NL
890 "@@ -1,7 +1,7 @@" NL
891 "+Bb\n"
892 " Aa\n"
893 "-Bb\n"
894 " Cc\n"
895 " Dd\n"
896 " Ee\n"
897 "+Gg\n"
898 " Ff\n"
899 "-Gg\n",
900 NULL, pool));
902 SVN_ERR(two_way_diff("foo16", "bar16",
903 "Aa\n"
904 "\n"
905 "Cc\n",
907 "Aa\n"
908 "Bb\n"
909 "Cc\n",
911 "--- foo16" NL
912 "+++ bar16" NL
913 "@@ -1,3 +1,3 @@" NL
914 " Aa\n"
915 "-\n"
916 "+Bb\n"
917 " Cc\n",
918 NULL, pool));
920 return SVN_NO_ERROR;
924 static svn_error_t *
925 test_two_way_unified_suspect(const char **msg,
926 svn_boolean_t msg_only,
927 svn_test_opts_t *opts,
928 apr_pool_t *pool)
930 *msg = "2-way unified diff where output is suspect";
931 if (msg_only)
932 return SVN_NO_ERROR;
934 SVN_ERR(two_way_diff("foo15a", "bar15a",
935 "Aa\n"
936 "Bb\n"
937 "Cc\n"
938 "Dd\n"
939 "Ee\n"
940 "Ff\n"
941 "Gg\n"
942 "Hh\n"
943 "Ii\n",
945 "Aa\n"
946 "Bb\n"
947 "Cc\n"
948 "Dd\n"
949 "Ff\n"
950 "Gg\n"
951 "Hh\n"
952 "Ii\n",
954 "--- foo15a" NL
955 "+++ bar15a" NL
956 "@@ -2,7 +2,6 @@" NL
957 " Bb\n"
958 " Cc\n"
959 " Dd\n"
960 "-Ee\n"
961 " Ff\n"
962 " Gg\n"
963 " Hh\n",
964 NULL, pool));
966 SVN_ERR(two_way_diff("foo15b", "bar15b",
967 "Aa\n"
968 "Bb\n"
969 "Cc\n"
970 "Dd\n"
971 "Ee\n"
972 "Ff\n"
973 "Gg\n"
974 "Hh\n"
975 "Ii\n",
977 "Aa\n"
978 "Bb\n"
979 "Cc\n"
980 "Dd\n"
981 "Ee\n"
982 "Xx\n"
983 "Yy\n"
984 "Ff\n"
985 "Gg\n"
986 "Hh\n"
987 "Ii\n",
989 "--- foo15b" NL
990 "+++ bar15b" NL
991 "@@ -3,6 +3,8 @@" NL
992 " Cc\n"
993 " Dd\n"
994 " Ee\n"
995 "+Xx\n"
996 "+Yy\n"
997 " Ff\n"
998 " Gg\n"
999 " Hh\n",
1000 NULL, pool));
1002 SVN_ERR(two_way_diff("foo15c", "bar15c",
1003 "Aa\n"
1004 "Bb\n"
1005 "Cc\n"
1006 "Dd\n"
1007 "Ee\n"
1008 "Ff\n"
1009 "Gg\n"
1010 "Hh\n"
1011 "Ii\n",
1013 "Aa\n"
1014 "Bb\n"
1015 "Cc\n"
1016 "Dd\n"
1017 "Xx\n"
1018 "Yy\n"
1019 "Ff\n"
1020 "Gg\n"
1021 "Hh\n"
1022 "Ii\n",
1024 "--- foo15c" NL
1025 "+++ bar15c" NL
1026 "@@ -2,7 +2,8 @@" NL
1027 " Bb\n"
1028 " Cc\n"
1029 " Dd\n"
1030 "-Ee\n"
1031 "+Xx\n"
1032 "+Yy\n"
1033 " Ff\n"
1034 " Gg\n"
1035 " Hh\n",
1036 NULL, pool));
1038 return SVN_NO_ERROR;
1042 static svn_error_t *
1043 test_three_way_merge_no_overlap(const char **msg,
1044 svn_boolean_t msg_only,
1045 svn_test_opts_t *opts,
1046 apr_pool_t *pool)
1048 svn_diff_file_options_t *diff_opts = svn_diff_file_options_create(pool);
1049 *msg = "3-way merge, non-overlapping changes";
1050 if (msg_only)
1051 return SVN_NO_ERROR;
1053 SVN_ERR(three_way_merge("zig1", "zag1", "zog1",
1054 "Aa\n"
1055 "Bb\n"
1056 "Cc\n",
1058 "Xx\n"
1059 "Aa\n"
1060 "Bb\n"
1061 "Cc\n",
1063 "Aa\n"
1064 "Bb\n"
1065 "Cc\n"
1066 "Yy\n",
1068 "Xx\n"
1069 "Aa\n"
1070 "Bb\n"
1071 "Cc\n"
1072 "Yy\n",
1073 NULL, pool));
1075 SVN_ERR(three_way_merge("zig1a", "zag1a", "zog1a",
1076 "Aa\r\n"
1077 "Bb\r\n"
1078 "Cc\r\n",
1080 "Xx\r\n"
1081 "Aa\r\n"
1082 "Bb\r\n"
1083 "Cc\r\n",
1085 "Aa\r\n"
1086 "Bb\r\n"
1087 "Cc\r\n"
1088 "Yy\r\n",
1090 "Xx\r\n"
1091 "Aa\r\n"
1092 "Bb\r\n"
1093 "Cc\r\n"
1094 "Yy\r\n",
1095 NULL, pool));
1097 SVN_ERR(three_way_merge("zig1b", "zag1b", "zog1b",
1098 "Aa\r"
1099 "Bb\r"
1100 "Cc\r",
1102 "Xx\r"
1103 "Aa\r"
1104 "Bb\r"
1105 "Cc\r",
1107 "Aa\r"
1108 "Bb\r"
1109 "Cc\r"
1110 "Yy\r",
1112 "Xx\r"
1113 "Aa\r"
1114 "Bb\r"
1115 "Cc\r"
1116 "Yy\r",
1117 NULL, pool));
1119 diff_opts->ignore_space = svn_diff_file_ignore_space_all;
1120 SVN_ERR(three_way_merge("zig1c", "zag1c", "zog1c",
1121 "Aa\n"
1122 "Bb\n"
1123 "Cc\n",
1125 "X x\n"
1126 "A a\n"
1127 "B b\n"
1128 "C c\n",
1130 "Aa\n"
1131 "Bb\n"
1132 "Cc\n"
1133 "Yy\n",
1135 "X x\n"
1136 "A a\n"
1137 "B b\n"
1138 "C c\n"
1139 "Yy\n",
1140 diff_opts, pool));
1141 diff_opts->ignore_space = svn_diff_file_ignore_space_none;
1143 SVN_ERR(three_way_merge("zig2", "zag2", "zog2",
1144 "Aa\n"
1145 "Bb\n"
1146 "Cc\n",
1148 "Xx\n"
1149 "Aa\n"
1150 "Bb\n"
1151 "Cc\n"
1152 "Yy\n",
1154 "Aa\n"
1155 "Bb\n"
1156 "Zz\n"
1157 "Cc\n",
1159 "Xx\n"
1160 "Aa\n"
1161 "Bb\n"
1162 "Zz\n"
1163 "Cc\n"
1164 "Yy\n",
1165 NULL, pool));
1167 SVN_ERR(three_way_merge("zig3a", "zag3a", "zog3a",
1168 "Aa\n"
1169 "Bb\n"
1170 "Cc\n",
1172 "Aa\n"
1173 "Bb\n"
1174 "Cc",
1176 "Xx\n"
1177 "Bb\n"
1178 "Cc\n",
1180 "Xx\n"
1181 "Bb\n"
1182 "Cc",
1183 NULL, pool));
1185 SVN_ERR(three_way_merge("zig3b", "zag3b", "zog3b",
1186 "Aa\n"
1187 "Bb\n"
1188 "Cc\n",
1190 "Xx\n"
1191 "Bb\n"
1192 "Cc\n",
1194 "Aa\n"
1195 "Bb\n"
1196 "Cc",
1198 "Xx\n"
1199 "Bb\n"
1200 "Cc",
1201 NULL, pool));
1203 diff_opts->ignore_space = svn_diff_file_ignore_space_all;
1204 diff_opts->ignore_eol_style = TRUE;
1205 SVN_ERR(three_way_merge("zig2c", "zag2c", "zog2c",
1206 "Aa\n"
1207 "Bb\n"
1208 "Cc\n",
1210 " Xx\r\n"
1211 " Aa\r\n"
1212 " Bb\r\n"
1213 " Cc\r\n"
1214 " Yy\r\n",
1216 "Aa\n"
1217 "Bb\n"
1218 "Zz\n"
1219 "Cc\n",
1221 " Xx\r\n"
1222 " Aa\r\n"
1223 " Bb\r\n"
1224 "Zz\n"
1225 " Cc\r\n"
1226 " Yy\r\n",
1227 diff_opts, pool));
1228 diff_opts->ignore_space = svn_diff_file_ignore_space_none;
1229 diff_opts->ignore_eol_style = FALSE;
1231 SVN_ERR(three_way_merge("zig4", "zag4", "zog4",
1232 "Aa\n"
1233 "Bb\n"
1234 "Cc\n"
1235 "Dd\n"
1236 "Ee\n"
1237 "Ff\n"
1238 "Gg\n"
1239 "Hh\n"
1240 "Ii\n",
1242 "Aa\n"
1243 "Bb\n"
1244 "Cc\n"
1245 "Dd\n"
1246 "Ee\n"
1247 "Ff\n"
1248 "Yy\n"
1249 "Zz\n"
1250 "Hh\n"
1251 "Ii\n",
1253 "Bb\n"
1254 "Cc\n"
1255 "Dd\n"
1256 "Ee\n"
1257 "Ff\n"
1258 "Gg\n"
1259 "Hh\n"
1260 "Ii\n",
1262 "Bb\n"
1263 "Cc\n"
1264 "Dd\n"
1265 "Ee\n"
1266 "Ff\n"
1267 "Yy\n"
1268 "Zz\n"
1269 "Hh\n"
1270 "Ii\n",
1271 NULL, pool));
1273 SVN_ERR(three_way_merge("zig5", "zag5", "zog5",
1274 "Aa\r\n"
1275 "Bb\n"
1276 "Cc\n",
1278 "Xx\r\n"
1279 "Aa\r\n"
1280 "Bb\n"
1281 "Cc\n",
1283 "Aa\r\n"
1284 "Bb\n"
1285 "Cc\n"
1286 "Yy\r\n",
1288 "Xx\r\n"
1289 "Aa\r\n"
1290 "Bb\n"
1291 "Cc\n"
1292 "Yy\r\n",
1293 NULL, pool));
1295 SVN_ERR(three_way_merge("zig6", "zag6", "zog6",
1296 "AaAaAaAaAaAa\n"
1297 "Bb\n"
1298 "Cc\n",
1300 "Xx\n"
1301 "Bb\n"
1302 "Cc\n",
1304 "AaAaAaAaAaAa\n"
1305 "Bb\n"
1306 "CcCcCcCcCcCc\n"
1307 "Yy\n",
1309 "Xx\n"
1310 "Bb\n"
1311 "CcCcCcCcCcCc\n"
1312 "Yy\n",
1313 NULL, pool));
1315 SVN_ERR(three_way_merge("zig7", "zag7", "zog7",
1316 "Aa\n"
1317 "Bb\n"
1318 "Cc\n",
1320 "Aa\n"
1321 "Bb\n"
1322 "Cc\n"
1323 "Dd",
1325 "Aa\n"
1326 "Bb\n"
1327 "Cc\n",
1329 "Aa\n"
1330 "Bb\n"
1331 "Cc\n"
1332 "Dd",
1333 NULL, pool));
1335 diff_opts->ignore_space = svn_diff_file_ignore_space_all;
1336 diff_opts->ignore_eol_style = FALSE;
1337 SVN_ERR(three_way_merge("zig8", "zag8", "zog8",
1338 "Aa\n"
1339 "Bb\n"
1340 "Cc\n",
1342 " Aa\n"
1343 "B b\n"
1344 "C c\n",
1346 "A a\n"
1347 "Bb \n"
1348 " Cc\n"
1349 "New line in zog8\n",
1351 " Aa\n"
1352 "B b\n"
1353 "C c\n"
1354 "New line in zog8\n",
1355 diff_opts, pool));
1357 return SVN_NO_ERROR;
1361 static svn_error_t *
1362 test_three_way_merge_with_overlap(const char **msg,
1363 svn_boolean_t msg_only,
1364 svn_test_opts_t *opts,
1365 apr_pool_t *pool)
1367 *msg = "3-way merge, non-conflicting overlapping changes";
1368 if (msg_only)
1369 return SVN_NO_ERROR;
1371 SVN_ERR(three_way_merge("splish1", "splash1", "splosh1",
1372 "Aa\n"
1373 "Bb\n"
1374 "Cc\n"
1375 "Dd\n"
1376 "Ee\n",
1378 "Aa\n"
1379 "Xx\n"
1380 "Bb\n"
1381 "Cc\n"
1382 "Yy\n"
1383 "Ee\n",
1385 "Aa\n"
1386 "Bb\n"
1387 "Cc\n"
1388 "Yy\n"
1389 "Ee\n"
1390 "Zz\n",
1392 "Aa\n"
1393 "Xx\n"
1394 "Bb\n"
1395 "Cc\n"
1396 "Yy\n"
1397 "Ee\n"
1398 "Zz\n",
1399 NULL, pool));
1401 SVN_ERR(three_way_merge("splish2", "splash2", "splosh2",
1402 "Aa\n"
1403 "Bb\n"
1404 "Cc\n"
1405 "Dd\n"
1406 "Ee\n"
1407 "Ff\n",
1409 "Aa\n"
1410 "Yy\n"
1411 "Zz\n"
1412 "Dd\n"
1413 "Pp\n"
1414 "Qq\n"
1415 "Ff\n",
1417 "Pp\n"
1418 "Qq\n"
1419 "Aa\n"
1420 "Bb\n"
1421 "Cc\n"
1422 "Dd\n"
1423 "Pp\n"
1424 "Qq\n"
1425 "Ff\n"
1426 "Pp\n"
1427 "Qq\n",
1429 "Pp\n"
1430 "Qq\n"
1431 "Aa\n"
1432 "Yy\n"
1433 "Zz\n"
1434 "Dd\n"
1435 "Pp\n"
1436 "Qq\n"
1437 "Ff\n"
1438 "Pp\n"
1439 "Qq\n",
1440 NULL, pool));
1442 SVN_ERR(three_way_merge("splish3", "splash3", "splosh3",
1443 "Aa\n"
1444 "Bb\n"
1445 "Cc\n",
1447 "Xx\n"
1448 "Aa\n"
1449 "Bb\n"
1450 "Cc",
1452 "Aa\n"
1453 "Xx\n"
1454 "Bb\n"
1455 "Cc",
1457 "Xx\n"
1458 "Aa\n"
1459 "Xx\n"
1460 "Bb\n"
1461 "Cc",
1462 NULL, pool));
1464 SVN_ERR(three_way_merge("splish4", "splash4", "splosh4",
1465 "Aa\n"
1466 "Bb\n"
1467 "Cc\n"
1468 "Dd\n"
1469 "Ee\n"
1470 "Ff\n"
1471 "Gg\n"
1472 "Hh\n",
1474 "Aa\n"
1475 "Ff\n"
1476 "Gg\n"
1477 "Hh\n"
1478 "Bb\n"
1479 "Cc\n"
1480 "Xx\n"
1481 "Dd\n"
1482 "Ee\n"
1483 "Yy\n"
1484 "Ff\n"
1485 "Gg\n"
1486 "Hh\n",
1488 "Aa\n"
1489 "Bb\n"
1490 "Cc\n"
1491 "Xx\n"
1492 "Dd\n"
1493 "Ee\n"
1494 "Ff\n"
1495 "Gg\n"
1496 "Zz\n"
1497 "Hh\n",
1499 "Aa\n"
1500 "Ff\n"
1501 "Gg\n"
1502 "Hh\n"
1503 "Bb\n"
1504 "Cc\n"
1505 "Xx\n"
1506 "Dd\n"
1507 "Ee\n"
1508 "Yy\n"
1509 "Ff\n"
1510 "Gg\n"
1511 "Zz\n"
1512 "Hh\n",
1513 NULL, pool));
1515 return SVN_NO_ERROR;
1519 static svn_error_t *
1520 test_three_way_merge_with_conflict(const char **msg,
1521 svn_boolean_t msg_only,
1522 svn_test_opts_t *opts,
1523 apr_pool_t *pool)
1525 *msg = "3-way merge, conflicting overlapping changes";
1526 if (msg_only)
1527 return SVN_NO_ERROR;
1529 SVN_ERR(three_way_merge("dig1", "dug1", "dag1",
1530 "Aa\n"
1531 "Bb\n"
1532 "Cc\n",
1539 NULL, pool));
1541 SVN_ERR(three_way_merge("dig2", "dug2", "dag2",
1542 "Aa\n"
1543 "Bb\n"
1544 "Cc\n",
1546 "Aa\n"
1547 "Bb\n"
1548 "Cc\n"
1549 "Dd\n"
1550 "Ee\n"
1551 "Ff\n",
1555 "<<<<<<< dug2\n"
1556 "Aa\n"
1557 "Bb\n"
1558 "Cc\n"
1559 "Dd\n"
1560 "Ee\n"
1561 "Ff\n"
1562 "=======\n"
1563 ">>>>>>> dag2\n",
1564 NULL, pool));
1566 SVN_ERR(three_way_merge("dig2a", "dug2a", "dag2a",
1567 "Aa\r\n"
1568 "Bb\r\n"
1569 "Cc\r\n",
1571 "Aa\r\n"
1572 "Bb\r\n"
1573 "Cc\r\n"
1574 "Dd\r\n"
1575 "Ee\r\n"
1576 "Ff\r\n",
1580 "<<<<<<< dug2a\r\n"
1581 "Aa\r\n"
1582 "Bb\r\n"
1583 "Cc\r\n"
1584 "Dd\r\n"
1585 "Ee\r\n"
1586 "Ff\r\n"
1587 "=======\r\n"
1588 ">>>>>>> dag2a\r\n",
1589 NULL, pool));
1591 SVN_ERR(three_way_merge("dig2b", "dug2b", "dag2b",
1592 "Aa\n"
1593 "Bb\n"
1594 "Cc\n",
1596 "Aa\r"
1597 "Bb\r"
1598 "Cc\r"
1599 "Dd\r"
1600 "Ee\r"
1601 "Ff\r",
1605 "<<<<<<< dug2b\r"
1606 "Aa\r"
1607 "Bb\r"
1608 "Cc\r"
1609 "Dd\r"
1610 "Ee\r"
1611 "Ff\r"
1612 "=======\r"
1613 ">>>>>>> dag2b\r",
1614 NULL, pool));
1616 SVN_ERR(three_way_merge("dig3", "dug3", "dag3",
1617 "Aa\n"
1618 "Bb\n"
1619 "Cc\n",
1621 "Aa\n"
1622 "Bb\n"
1623 "Cc\n"
1624 "Dd\n"
1625 "Ee\n"
1626 "Ff\n",
1628 "Aa\n"
1629 "Bb\n",
1631 "Aa\n"
1632 "Bb\n"
1633 "<<<<<<< dug3\n"
1634 "Cc\n"
1635 "Dd\n"
1636 "Ee\n"
1637 "Ff\n"
1638 "=======\n"
1639 ">>>>>>> dag3\n",
1640 NULL, pool));
1642 SVN_ERR(three_way_merge("dig4", "dug4", "dag4",
1643 "Aa\n"
1644 "Bb\n"
1645 "Cc\n",
1647 "Aa\n"
1648 "Bb\n"
1649 "Cc\n"
1650 "Dd",
1652 "Aa\n"
1653 "Bb\n"
1654 "Cc\n"
1655 "Ee",
1657 "Aa\n"
1658 "Bb\n"
1659 "Cc\n"
1660 "<<<<<<< dug4\n"
1661 "Dd=======\n"
1662 "Ee>>>>>>> dag4\n",
1663 NULL, pool));
1665 return SVN_NO_ERROR;
1669 static svn_error_t *
1670 random_trivial_merge(const char **msg,
1671 svn_boolean_t msg_only,
1672 svn_test_opts_t *opts,
1673 apr_pool_t *pool)
1675 int i;
1676 apr_pool_t *subpool = svn_pool_create(pool);
1678 *msg = apr_psprintf(pool, "random trivial merge (seed:%u)", seed_val());
1679 if (msg_only)
1680 return SVN_NO_ERROR;
1682 for (i = 0; i < 5; ++i)
1684 const char *filename1 = "trivial1";
1685 const char *filename2 = "trivial2";
1686 int min_lines = 1000;
1687 int max_lines = 1100;
1688 int var_lines = 50;
1689 int block_lines = 10;
1690 svn_stringbuf_t *contents1, *contents2;
1692 SVN_ERR(make_random_file(filename1,
1693 min_lines, max_lines, var_lines, block_lines,
1694 i % 3, subpool));
1695 SVN_ERR(make_random_file(filename2,
1696 min_lines, max_lines, var_lines, block_lines,
1697 i % 2, subpool));
1699 SVN_ERR(svn_stringbuf_from_file(&contents1, filename1, subpool));
1700 SVN_ERR(svn_stringbuf_from_file(&contents2, filename2, subpool));
1702 SVN_ERR(three_way_merge(filename1, filename2, filename1,
1703 contents1->data, contents2->data,
1704 contents1->data, contents2->data, NULL,
1705 subpool));
1706 SVN_ERR(three_way_merge(filename2, filename1, filename2,
1707 contents2->data, contents1->data,
1708 contents2->data, contents1->data, NULL,
1709 subpool));
1710 svn_pool_clear(subpool);
1712 svn_pool_destroy(subpool);
1714 return SVN_NO_ERROR;
1718 /* The "original" file has a number of distinct lines. We generate two
1719 random modifications by selecting two subsets of the original lines and
1720 for each selected line either adding an additional line, replacing the
1721 line, or deleting the line. The two subsets are chosen so that each
1722 selected line is distinct and no two selected lines are adjacent. This
1723 means the two sets of changes should merge without conflict. */
1724 static svn_error_t *
1725 random_three_way_merge(const char **msg,
1726 svn_boolean_t msg_only,
1727 svn_test_opts_t *opts,
1728 apr_pool_t *pool)
1730 int i;
1731 apr_pool_t *subpool = svn_pool_create(pool);
1733 *msg = apr_psprintf(pool, "random 3-way merge (seed:%u)", seed_val());
1734 if (msg_only)
1735 return SVN_NO_ERROR;
1737 for (i = 0; i < 20; ++i)
1739 const char *filename1 = "original";
1740 const char *filename2 = "modified1";
1741 const char *filename3 = "modified2";
1742 const char *filename4 = "combined";
1743 svn_stringbuf_t *original, *modified1, *modified2, *combined;
1744 int num_lines = 100, num_src = 10, num_dst = 10;
1745 svn_boolean_t *lines = apr_pcalloc(subpool, sizeof(*lines) * num_lines);
1746 struct random_mod *src_lines = apr_palloc(subpool,
1747 sizeof(*src_lines) * num_src);
1748 struct random_mod *dst_lines = apr_palloc(subpool,
1749 sizeof(*dst_lines) * num_dst);
1750 struct random_mod *mrg_lines = apr_palloc(subpool,
1751 (sizeof(*mrg_lines)
1752 * (num_src + num_dst)));
1754 select_lines(src_lines, num_src, lines, num_lines);
1755 select_lines(dst_lines, num_dst, lines, num_lines);
1756 memcpy(mrg_lines, src_lines, sizeof(*mrg_lines) * num_src);
1757 memcpy(mrg_lines + num_src, dst_lines, sizeof(*mrg_lines) * num_dst);
1759 SVN_ERR(make_random_merge_file(filename1, num_lines, NULL, 0, pool));
1760 SVN_ERR(make_random_merge_file(filename2, num_lines, src_lines, num_src,
1761 pool));
1762 SVN_ERR(make_random_merge_file(filename3, num_lines, dst_lines, num_dst,
1763 pool));
1764 SVN_ERR(make_random_merge_file(filename4, num_lines, mrg_lines,
1765 num_src + num_dst, pool));
1767 SVN_ERR(svn_stringbuf_from_file(&original, filename1, pool));
1768 SVN_ERR(svn_stringbuf_from_file(&modified1, filename2, pool));
1769 SVN_ERR(svn_stringbuf_from_file(&modified2, filename3, pool));
1770 SVN_ERR(svn_stringbuf_from_file(&combined, filename4, pool));
1772 SVN_ERR(three_way_merge(filename1, filename2, filename3,
1773 original->data, modified1->data,
1774 modified2->data, combined->data, NULL, subpool));
1775 SVN_ERR(three_way_merge(filename1, filename3, filename2,
1776 original->data, modified2->data,
1777 modified1->data, combined->data, NULL, subpool));
1779 SVN_ERR(svn_io_remove_file(filename4, pool));
1781 svn_pool_clear(subpool);
1783 svn_pool_destroy(subpool);
1785 return SVN_NO_ERROR;
1788 /* This is similar to random_three_way_merge above, except this time half
1789 of the original-to-modified1 changes are already present in modified2
1790 (or, equivalently, half the original-to-modified2 changes are already
1791 present in modified1). Since the overlapping changes match exactly the
1792 merge should work without a conflict. */
1793 static svn_error_t *
1794 merge_with_part_already_present(const char **msg,
1795 svn_boolean_t msg_only,
1796 svn_test_opts_t *opts,
1797 apr_pool_t *pool)
1799 int i;
1800 apr_pool_t *subpool = svn_pool_create(pool);
1802 *msg = apr_psprintf(pool, "merge with part already present (seed:%u)",
1803 seed_val());
1804 if (msg_only)
1805 return SVN_NO_ERROR;
1807 for (i = 0; i < 20; ++i)
1809 const char *filename1 = "pap-original";
1810 const char *filename2 = "pap-modified1";
1811 const char *filename3 = "pap-modified2";
1812 const char *filename4 = "pap-combined";
1813 svn_stringbuf_t *original, *modified1, *modified2, *combined;
1814 int num_lines = 200, num_src = 20, num_dst = 20;
1815 svn_boolean_t *lines = apr_pcalloc(subpool, sizeof(*lines) * num_lines);
1816 struct random_mod *src_lines = apr_palloc(subpool,
1817 sizeof(*src_lines) * num_src);
1818 struct random_mod *dst_lines = apr_palloc(subpool,
1819 sizeof(*dst_lines) * num_dst);
1820 struct random_mod *mrg_lines = apr_palloc(subpool,
1821 (sizeof(*mrg_lines)
1822 * (num_src + num_dst / 2)));
1824 select_lines(src_lines, num_src, lines, num_lines);
1825 /* Select half the destination changes at random */
1826 select_lines(dst_lines, num_dst / 2, lines, num_lines);
1827 /* Copy the other half from the source changes */
1828 memcpy(dst_lines + num_dst / 2, src_lines,
1829 sizeof(*dst_lines) * (num_dst - num_dst / 2));
1830 memcpy(mrg_lines, src_lines, sizeof(*mrg_lines) * num_src);
1831 memcpy(mrg_lines + num_src, dst_lines,
1832 sizeof(*mrg_lines) * num_dst / 2);
1834 SVN_ERR(make_random_merge_file(filename1, num_lines, NULL, 0, pool));
1835 SVN_ERR(make_random_merge_file(filename2, num_lines, src_lines, num_src,
1836 pool));
1837 SVN_ERR(make_random_merge_file(filename3, num_lines, dst_lines, num_dst,
1838 pool));
1839 SVN_ERR(make_random_merge_file(filename4, num_lines, mrg_lines,
1840 num_src + num_dst / 2, pool));
1842 SVN_ERR(svn_stringbuf_from_file(&original, filename1, pool));
1843 SVN_ERR(svn_stringbuf_from_file(&modified1, filename2, pool));
1844 SVN_ERR(svn_stringbuf_from_file(&modified2, filename3, pool));
1845 SVN_ERR(svn_stringbuf_from_file(&combined, filename4, pool));
1847 SVN_ERR(three_way_merge(filename1, filename2, filename3,
1848 original->data, modified1->data,
1849 modified2->data, combined->data, NULL, subpool));
1850 SVN_ERR(three_way_merge(filename1, filename3, filename2,
1851 original->data, modified2->data,
1852 modified1->data, combined->data, NULL, subpool));
1854 SVN_ERR(svn_io_remove_file(filename4, pool));
1856 svn_pool_clear(subpool);
1858 svn_pool_destroy(subpool);
1860 return SVN_NO_ERROR;
1863 /* Merge is more "aggressive" about resolving conflicts than traditional
1864 * patch or diff3. Some people consider this behaviour to be a bug, see
1865 * http://subversion.tigris.org/servlets/ReadMsg?list=dev&msgNo=35014
1867 static svn_error_t *
1868 merge_adjacent_changes(const char **msg,
1869 svn_boolean_t msg_only,
1870 svn_test_opts_t *opts,
1871 apr_pool_t *pool)
1873 *msg = "3-way merge, adjacent changes";
1874 if (msg_only)
1875 return SVN_NO_ERROR;
1877 SVN_ERR(three_way_merge("adj1", "adj2", "adj3",
1879 "foo\n"
1880 "bar\n"
1881 "baz\n",
1883 "foo\n"
1884 "new_bar\n"
1885 "baz\n",
1887 "zig\n"
1888 "foo\n"
1889 "bar\n"
1890 "new_baz\n",
1892 "zig\n"
1893 "foo\n"
1894 "new_bar\n"
1895 "new_baz\n",
1897 NULL, pool));
1899 return SVN_NO_ERROR;
1904 /* ========================================================================== */
1906 struct svn_test_descriptor_t test_funcs[] =
1908 SVN_TEST_NULL,
1909 SVN_TEST_PASS(dump_core),
1910 SVN_TEST_PASS(test_two_way_unified),
1911 SVN_TEST_PASS(test_two_way_unified_suspect),
1912 SVN_TEST_PASS(test_three_way_merge_no_overlap),
1913 SVN_TEST_PASS(test_three_way_merge_with_overlap),
1914 SVN_TEST_PASS(test_three_way_merge_with_conflict),
1915 SVN_TEST_PASS(random_trivial_merge),
1916 SVN_TEST_PASS(random_three_way_merge),
1917 SVN_TEST_PASS(merge_with_part_already_present),
1918 SVN_TEST_PASS(merge_adjacent_changes),
1919 SVN_TEST_NULL