Mark many merge tests as skip-against-old-server.
[svn.git] / subversion / tests / libsvn_subr / mergeinfo-test.c
blobcea1954a7e07226c83d680817461f418e68af432
1 /*
2 * mergeinfo-test.c -- test the mergeinfo functions
4 * ====================================================================
5 * Copyright (c) 2006-2007 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 * ====================================================================
19 #include <stdio.h>
20 #include <string.h>
21 #include <apr_hash.h>
22 #include <apr_tables.h>
24 #include "svn_pools.h"
25 #include "svn_types.h"
26 #include "svn_mergeinfo.h"
27 #include "private/svn_mergeinfo_private.h"
28 #include "../svn_test.h"
30 /* A quick way to create error messages. */
31 static svn_error_t *
32 fail(apr_pool_t *pool, const char *fmt, ...)
34 va_list ap;
35 char *msg;
37 va_start(ap, fmt);
38 msg = apr_pvsprintf(pool, fmt, ap);
39 va_end(ap);
41 return svn_error_create(SVN_ERR_TEST_FAILED, 0, msg);
44 #define MAX_NBR_RANGES 3
46 /* Verify that INPUT is parsed properly, and returns an error if
47 parsing fails, or incorret parsing is detected. Assumes that INPUT
48 contains only one path -> ranges mapping, and that EXPECTED_RANGES points
49 to the first range in an array whose size is greater than or equal to
50 the number of ranges in INPUTS path -> ranges mapping but less than
51 MAX_NBR_RANGES. If fewer than MAX_NBR_RANGES ranges are present, then the
52 trailing expected_ranges should be have their end revision set to 0. */
53 static svn_error_t *
54 verify_mergeinfo_parse(const char *input,
55 const char *expected_path,
56 const svn_merge_range_t *expected_ranges,
57 apr_pool_t *pool)
59 svn_error_t *err;
60 apr_hash_t *path_to_merge_ranges;
61 apr_hash_index_t *hi;
63 /* Test valid input. */
64 err = svn_mergeinfo_parse(&path_to_merge_ranges, input, pool);
65 if (err || apr_hash_count(path_to_merge_ranges) != 1)
66 return svn_error_createf(SVN_ERR_TEST_FAILED, err,
67 "svn_mergeinfo_parse (%s) failed unexpectedly",
68 input);
69 for (hi = apr_hash_first(pool, path_to_merge_ranges); hi;
70 hi = apr_hash_next(hi))
72 const void *path;
73 void *val;
74 apr_array_header_t *ranges;
75 svn_merge_range_t *range;
76 int j;
78 apr_hash_this(hi, &path, NULL, &val);
79 ranges = val;
80 if (strcmp((const char *) path, expected_path) != 0)
81 return fail(pool, "svn_mergeinfo_parse (%s) failed to parse the "
82 "correct path (%s)", input, expected_path);
84 /* Test each parsed range. */
85 for (j = 0; j < ranges->nelts; j++)
87 range = APR_ARRAY_IDX(ranges, j, svn_merge_range_t *);
88 if (range->start != expected_ranges[j].start
89 || range->end != expected_ranges[j].end
90 || range->inheritable != expected_ranges[j].inheritable)
91 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
92 "svn_mergeinfo_parse (%s) failed to "
93 "parse the correct range",
94 input);
97 /* Were we expecting any more ranges? */
98 if (j < MAX_NBR_RANGES - 1
99 && !expected_ranges[j].end == 0)
100 return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
101 "svn_mergeinfo_parse (%s) failed to "
102 "produce the expected number of ranges",
103 input);
105 return SVN_NO_ERROR;
109 /* Some of our own global variables (for simplicity), which map paths
110 -> merge ranges. */
111 static apr_hash_t *info1, *info2;
113 #define NBR_MERGEINFO_VALS 5
114 /* Valid mergeinfo values. */
115 static const char * const mergeinfo_vals[NBR_MERGEINFO_VALS] =
117 "/trunk:1",
118 "/trunk/foo:1-6",
119 "/trunk: 5,7-9,10,11,13,14",
120 "/trunk: 3-10,11*,13,14",
121 "/branch: 1,2-18*,33*"
123 /* Paths corresponding to mergeinfo_vals. */
124 static const char * const mergeinfo_paths[NBR_MERGEINFO_VALS] =
126 "/trunk",
127 "/trunk/foo",
128 "/trunk",
129 "/trunk",
130 "/branch"
132 /* First ranges from the paths identified by mergeinfo_paths. */
133 static svn_merge_range_t mergeinfo_ranges[NBR_MERGEINFO_VALS][MAX_NBR_RANGES] =
135 { {0, 1, TRUE} },
136 { {0, 6, TRUE} },
137 { {4, 5, TRUE}, { 6, 11, TRUE }, {12, 14, TRUE } },
138 { {2, 10, TRUE}, {10, 11, FALSE}, {12, 14, TRUE } },
139 { {0, 1, TRUE}, { 1, 18, FALSE}, {32, 33, FALSE} }
142 static svn_error_t *
143 test_parse_single_line_mergeinfo(const char **msg,
144 svn_boolean_t msg_only,
145 svn_test_opts_t *opts,
146 apr_pool_t *pool)
148 int i;
150 *msg = "parse single line mergeinfo";
152 if (msg_only)
153 return SVN_NO_ERROR;
155 for (i = 0; i < NBR_MERGEINFO_VALS; i++)
156 SVN_ERR(verify_mergeinfo_parse(mergeinfo_vals[i], mergeinfo_paths[i],
157 mergeinfo_ranges[i], pool));
159 return SVN_NO_ERROR;
162 static const char *single_mergeinfo = "/trunk: 5,7-9,10,11,13,14";
164 static svn_error_t *
165 test_mergeinfo_dup(const char **msg,
166 svn_boolean_t msg_only,
167 svn_test_opts_t *opts,
168 apr_pool_t *pool)
170 apr_hash_t *orig_mergeinfo, *copied_mergeinfo;
171 apr_pool_t *subpool;
172 apr_array_header_t *rangelist;
174 *msg = "copy a mergeinfo data structure";
176 if (msg_only)
177 return SVN_NO_ERROR;
179 /* Assure that copies which should be empty turn out that way. */
180 subpool = svn_pool_create(pool);
181 orig_mergeinfo = apr_hash_make(subpool);
182 copied_mergeinfo = svn_mergeinfo_dup(orig_mergeinfo, subpool);
183 if (apr_hash_count(copied_mergeinfo) != 0)
184 return fail(pool, "Copied mergeinfo should be empty");
186 /* Create some mergeinfo, copy it using another pool, then destroy
187 the pool with which the original mergeinfo was created. */
188 SVN_ERR(svn_mergeinfo_parse(&orig_mergeinfo, single_mergeinfo, subpool));
189 copied_mergeinfo = svn_mergeinfo_dup(orig_mergeinfo, pool);
190 svn_pool_destroy(subpool);
191 if (apr_hash_count(copied_mergeinfo) != 1)
192 return fail(pool, "Copied mergeinfo should contain one merge source");
193 rangelist = apr_hash_get(copied_mergeinfo, "/trunk", APR_HASH_KEY_STRING);
194 if (! rangelist)
195 return fail(pool, "Expected copied mergeinfo; got nothing");
196 if (rangelist->nelts != 3)
197 return fail(pool, "Copied mergeinfo should contain 3 revision ranges, "
198 "rather than the %d it contains", rangelist->nelts);
200 return SVN_NO_ERROR;
203 static svn_error_t *
204 test_parse_combine_rangeinfo(const char **msg,
205 svn_boolean_t msg_only,
206 svn_test_opts_t *opts,
207 apr_pool_t *pool)
209 apr_array_header_t *result;
210 svn_merge_range_t *resultrange;
212 *msg = "parse single line mergeinfo and combine ranges";
214 if (msg_only)
215 return SVN_NO_ERROR;
217 SVN_ERR(svn_mergeinfo_parse(&info1, single_mergeinfo, pool));
219 if (apr_hash_count(info1) != 1)
220 return fail(pool, "Wrong number of paths in parsed mergeinfo");
222 result = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
223 if (!result)
224 return fail(pool, "Missing path in parsed mergeinfo");
226 /* /trunk should have three ranges, 5-5, 7-11, 13-14 */
227 if (result->nelts != 3)
228 return fail(pool, "Parsing failed to combine ranges");
230 resultrange = APR_ARRAY_IDX(result, 0, svn_merge_range_t *);
232 if (resultrange->start != 4 || resultrange->end != 5)
233 return fail(pool, "Range combining produced wrong result");
235 resultrange = APR_ARRAY_IDX(result, 1, svn_merge_range_t *);
237 if (resultrange->start != 6 || resultrange->end != 11)
238 return fail(pool, "Range combining produced wrong result");
240 resultrange = APR_ARRAY_IDX(result, 2, svn_merge_range_t *);
242 if (resultrange->start != 12 || resultrange->end != 14)
243 return fail(pool, "Range combining produced wrong result");
245 return SVN_NO_ERROR;
249 #define NBR_BROKEN_MERGEINFO_VALS 38
250 /* Invalid mergeinfo values. */
251 static const char * const broken_mergeinfo_vals[NBR_BROKEN_MERGEINFO_VALS] =
253 /* Invalid grammar */
254 "/missing-revs",
255 "/trunk: 5,7-9,10,11,13,14,",
256 "/trunk 5,7-9,10,11,13,14",
257 "/trunk:5 7--9 10 11 13 14",
258 /* Unordered revs */
259 "/trunk:3-6,15,18,9,22",
260 "/trunk:5,3",
261 "/trunk:3-6*,15*,18*,9,22*",
262 "/trunk:5,3*",
263 /* Overlapping revs differing inheritability */
264 "/trunk:5-9*,9",
265 "/trunk:5,5-9*",
266 "/trunk:5-9,9*",
267 "/trunk:5*,5-9",
268 "/trunk:4,4*",
269 "/trunk:4*,4",
270 "/trunk:3-7*,4-23",
271 "/trunk:3-7,4-23*",
272 /* Overlapping revs same inheritability */
273 "/trunk:5-9*,9*",
274 "/trunk:5*,5-9*",
275 "/trunk:5-9,9",
276 "/trunk:5,5-9",
277 "/trunk:4,4",
278 "/trunk:4*,4*",
279 "/trunk:3-7,4-23",
280 "/trunk:3-7*,4-23*",
281 /* Reversed revision ranges */
282 "/trunk:22-20",
283 "/trunk:22-20*",
284 "/trunk:3,7-12,22-20,25",
285 "/trunk:3,7,22-20*,25-30",
286 /* Range with same start and end revision */
287 "/trunk:22-22",
288 "/trunk:22-22*",
289 "/trunk:3,7-12,20-20,25",
290 "/trunk:3,7,20-20*,25-30",
291 /* path mapped to range with no revisions */
292 "/trunk:",
293 "/trunk:2-9\n/branch:",
294 /* No path */
295 ":1-3",
296 /* Invalid revisions */
297 "trunk:a-3",
298 "branch:3-four",
299 "trunk:yadayadayada"
302 static svn_error_t *
303 test_parse_broken_mergeinfo(const char **msg,
304 svn_boolean_t msg_only,
305 svn_test_opts_t *opts,
306 apr_pool_t *pool)
308 int i;
309 svn_error_t *err;
310 *msg = "parse broken single line mergeinfo";
312 if (msg_only)
313 return SVN_NO_ERROR;
315 /* Trigger some error(s) with mal-formed input. */
316 for (i = 0; i < NBR_BROKEN_MERGEINFO_VALS; i++)
318 err = svn_mergeinfo_parse(&info1, broken_mergeinfo_vals[i], pool);
319 if (err == SVN_NO_ERROR)
321 return fail(pool, "svn_mergeinfo_parse (%s) failed to detect an error",
322 broken_mergeinfo_vals[i]);
324 else if (err->apr_err != SVN_ERR_MERGEINFO_PARSE_ERROR)
326 svn_error_clear(err);
327 return fail(pool, "svn_mergeinfo_parse (%s) returned some error other"
328 " than SVN_ERR_MERGEINFO_PARSE_ERROR",
329 broken_mergeinfo_vals[i]);
331 else
333 svn_error_clear(err);
337 return SVN_NO_ERROR;
341 static const char *mergeinfo1 = "/trunk: 3,5,7-9,10,11,13,14\n/fred:8-10";
343 #define NBR_RANGELIST_DELTAS 4
346 /* Convert a single svn_merge_range_t * back into an svn_stringbuf_t *. */
347 static char *
348 range_to_string(svn_merge_range_t *range,
349 apr_pool_t *pool)
351 if (range->start == range->end - 1)
352 return apr_psprintf(pool, "%ld%s", range->end,
353 range->inheritable
354 ? "" : SVN_MERGEINFO_NONINHERITABLE_STR);
355 else
356 return apr_psprintf(pool, "%ld-%ld%s", range->start + 1,
357 range->end, range->inheritable
358 ? "" : SVN_MERGEINFO_NONINHERITABLE_STR);
362 /* Verify that ACTUAL_RANGELIST matches EXPECTED_RANGES (an array of
363 NBR_EXPECTED length). Return an error based careful examination if
364 they do not match. FUNC_VERIFIED is the name of the API being
365 verified (e.g. "svn_rangelist_intersect"), while TYPE is a word
366 describing what the ranges being examined represent. */
367 static svn_error_t *
368 verify_ranges_match(apr_array_header_t *actual_rangelist,
369 svn_merge_range_t *expected_ranges, int nbr_expected,
370 const char *func_verified, const char *type,
371 apr_pool_t *pool)
373 int i;
375 if (actual_rangelist->nelts != nbr_expected)
376 return fail(pool, "%s should report %d range %ss, but found %d",
377 func_verified, nbr_expected, type, actual_rangelist->nelts);
379 for (i = 0; i < actual_rangelist->nelts; i++)
381 svn_merge_range_t *range = APR_ARRAY_IDX(actual_rangelist, i,
382 svn_merge_range_t *);
383 if (range->start != expected_ranges[i].start
384 || range->end != expected_ranges[i].end
385 || range->inheritable != expected_ranges[i].inheritable)
386 return fail(pool, "%s should report range %s, but found %s",
387 func_verified,
388 range_to_string(&expected_ranges[i], pool),
389 range_to_string(range, pool));
391 return SVN_NO_ERROR;
394 /* Verify that DELTAS matches EXPECTED_DELTAS (both expected to
395 contain only a rangelist for "/trunk"). Return an error based
396 careful examination if they do not match. FUNC_VERIFIED is the
397 name of the API being verified (e.g. "svn_mergeinfo_diff"), while
398 TYPE is a word describing what the deltas being examined
399 represent. */
400 static svn_error_t *
401 verify_mergeinfo_deltas(apr_hash_t *deltas, svn_merge_range_t *expected_deltas,
402 const char *func_verified, const char *type,
403 apr_pool_t *pool)
405 apr_array_header_t *rangelist;
407 if (apr_hash_count(deltas) != 1)
408 /* Deltas on "/trunk" expected. */
409 return fail(pool, "%s should report 1 path %s, but found %d",
410 func_verified, type, apr_hash_count(deltas));
412 rangelist = apr_hash_get(deltas, "/trunk", APR_HASH_KEY_STRING);
413 if (rangelist == NULL)
414 return fail(pool, "%s failed to produce a rangelist for /trunk",
415 func_verified);
417 return verify_ranges_match(rangelist, expected_deltas, NBR_RANGELIST_DELTAS,
418 func_verified, type, pool);
421 static svn_error_t *
422 test_diff_mergeinfo(const char **msg,
423 svn_boolean_t msg_only,
424 svn_test_opts_t *opts,
425 apr_pool_t *pool)
427 apr_hash_t *deleted, *added, *from, *to;
428 svn_merge_range_t expected_rangelist_deletions[NBR_RANGELIST_DELTAS] =
429 { {6, 7, TRUE}, {8, 9, TRUE}, {10, 11, TRUE}, {32, 34, TRUE} };
430 svn_merge_range_t expected_rangelist_additions[NBR_RANGELIST_DELTAS] =
431 { {1, 2, TRUE}, {4, 6, TRUE}, {12, 16, TRUE}, {29, 30, TRUE} };
433 *msg = "diff of mergeinfo";
434 if (msg_only)
435 return SVN_NO_ERROR;
437 SVN_ERR(svn_mergeinfo_parse(&from, "/trunk: 1,3-4,7,9,11-12,31-34", pool));
438 SVN_ERR(svn_mergeinfo_parse(&to, "/trunk: 1-6,12-16,30-32", pool));
439 /* On /trunk: deleted (7, 9, 11, 33-34) and added (2, 5-6, 13-16, 30) */
440 SVN_ERR(svn_mergeinfo_diff(&deleted, &added, from, to,
441 FALSE, pool));
443 /* Verify calculation of range list deltas. */
444 SVN_ERR(verify_mergeinfo_deltas(deleted, expected_rangelist_deletions,
445 "svn_mergeinfo_diff", "deletion", pool));
446 SVN_ERR(verify_mergeinfo_deltas(added, expected_rangelist_additions,
447 "svn_mergeinfo_diff", "addition", pool));
449 return SVN_NO_ERROR;
452 static svn_error_t *
453 test_rangelist_reverse(const char **msg,
454 svn_boolean_t msg_only,
455 svn_test_opts_t *opts,
456 apr_pool_t *pool)
458 apr_array_header_t *rangelist;
459 svn_merge_range_t expected_rangelist[3] =
460 { {10, 9, TRUE}, {7, 4, TRUE}, {3, 2, TRUE} };
462 *msg = "reversal of rangelist";
463 if (msg_only)
464 return SVN_NO_ERROR;
466 SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 3,5-7,10", pool));
467 rangelist = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
469 SVN_ERR(svn_rangelist_reverse(rangelist, pool));
471 return verify_ranges_match(rangelist, expected_rangelist, 3,
472 "svn_rangelist_reverse", "reversal", pool);
475 static svn_error_t *
476 test_rangelist_intersect(const char **msg,
477 svn_boolean_t msg_only,
478 svn_test_opts_t *opts,
479 apr_pool_t *pool)
481 apr_array_header_t *rangelist1, *rangelist2, *intersection;
482 svn_merge_range_t expected_intersection[] =
483 { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE}, {30, 32, TRUE},
484 {39, 42, TRUE} };
486 *msg = "intersection of rangelists";
487 if (msg_only)
488 return SVN_NO_ERROR;
490 SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16,30-32,40-42", pool));
491 SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4,7,9,11-12,31-34,38-44",
492 pool));
493 rangelist1 = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
494 rangelist2 = apr_hash_get(info2, "/trunk", APR_HASH_KEY_STRING);
496 SVN_ERR(svn_rangelist_intersect(&intersection, rangelist1, rangelist2,
497 pool));
499 return verify_ranges_match(intersection, expected_intersection, 5,
500 "svn_rangelist_intersect", "intersect", pool);
503 static svn_error_t *
504 test_mergeinfo_intersect(const char **msg,
505 svn_boolean_t msg_only,
506 svn_test_opts_t *opts,
507 apr_pool_t *pool)
509 svn_merge_range_t expected_intersection[3] =
510 { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE} };
511 apr_array_header_t *rangelist;
512 apr_hash_t *intersection;
514 *msg = "intersection of mergeinfo";
515 if (msg_only)
516 return SVN_NO_ERROR;
518 SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16\n/foo: 31", pool));
519 SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4,7,9,11-12", pool));
521 SVN_ERR(svn_mergeinfo_intersect(&intersection, info1, info2, pool));
522 if (apr_hash_count(intersection) != 1)
523 return fail(pool, "Unexpected number of rangelists in mergeinfo "
524 "intersection: Expected %d, found %d", 1,
525 apr_hash_count(intersection));
527 rangelist = apr_hash_get(intersection, "/trunk", APR_HASH_KEY_STRING);
528 return verify_ranges_match(rangelist, expected_intersection, 3,
529 "svn_rangelist_intersect", "intersect", pool);
532 static svn_error_t *
533 test_merge_mergeinfo(const char **msg,
534 svn_boolean_t msg_only,
535 svn_test_opts_t *opts,
536 apr_pool_t *pool)
538 int i;
540 /* Structures and constants for test_merge_mergeinfo() */
541 /* Number of svn_mergeinfo_merge test sets */
542 #define NBR_MERGEINFO_MERGES 12
544 /* Maximum number of expected paths in the results
545 of the svn_mergeinfo_merge tests */
546 #define MAX_NBR_MERGEINFO_PATHS 4
548 /* Maximum number of expected ranges in the results
549 of the svn_mergeinfo_merge tests */
550 #define MAX_NBR_MERGEINFO_RANGES 10
552 /* Struct to store a path and it's expected ranges,
553 i.e. the expected result of an svn_mergeinfo_merge
554 test. */
555 struct mergeinfo_merge_path_range
557 const char *path;
558 svn_merge_range_t expected_rngs[MAX_NBR_MERGEINFO_RANGES];
561 /* Struct for svn_mergeinfo_merge test data.
562 If MERGEINFO1 and MERGEINFO2 are parsed to a hash with
563 svn_mergeinfo_parse() and then merged with svn_mergeinfo_merge(),
564 the resulting hash should have EXPECTED_PATHS number of paths
565 mapped to rangelists and each mapping is described by PATH_RNGS
566 where PATH_RNGS->PATH is not NULL. */
567 struct mergeinfo_merge_test_data
569 const char *mergeinfo1;
570 const char *mergeinfo2;
571 int expected_paths;
572 struct mergeinfo_merge_path_range path_rngs[MAX_NBR_MERGEINFO_PATHS];
575 static struct mergeinfo_merge_test_data mergeinfo[NBR_MERGEINFO_MERGES] =
577 /* One path, intersecting inheritable ranges */
578 { "/trunk: 5-10",
579 "/trunk: 6", 1,
580 { {"/trunk", { {4, 10, TRUE} } } } },
582 /* One path, intersecting non-inheritable ranges */
583 { "/trunk: 5-10*",
584 "/trunk: 6*", 1,
585 { {"/trunk", { {4, 10, FALSE} } } } },
587 /* One path, intersecting ranges with different inheritability */
588 { "/trunk: 5-10",
589 "/trunk: 6*", 1,
590 { {"/trunk", { {4, 10, TRUE} } } } },
592 /* One path, intersecting ranges with different inheritability */
593 { "/trunk: 5-10*",
594 "/trunk: 6", 1,
595 { {"/trunk", { {4, 5, FALSE}, {5, 6, TRUE}, {6, 10, FALSE} } } } },
597 /* Adjacent ranges all inheritable ranges */
598 { "/trunk: 1,3,5-11,13",
599 "/trunk: 2,4,12,14-22", 1,
600 { {"/trunk", { {0, 22, TRUE} } } } },
602 /* Adjacent ranges all non-inheritable ranges */
603 { "/trunk: 1*,3*,5-11*,13*",
604 "/trunk: 2*,4*,12*,14-22*", 1,
605 { {"/trunk", { {0, 22, FALSE} } } } },
607 /* Adjacent ranges differing inheritability */
608 { "/trunk: 1*,3*,5-11*,13*",
609 "/trunk: 2,4,12,14-22", 1,
610 { {"/trunk", { { 0, 1, FALSE}, { 1, 2, TRUE},
611 { 2, 3, FALSE}, { 3, 4, TRUE},
612 { 4, 11, FALSE}, {11, 12, TRUE},
613 {12, 13, FALSE}, {13, 22, TRUE} } } } },
615 /* Adjacent ranges differing inheritability */
616 { "/trunk: 1,3,5-11,13",
617 "/trunk: 2*,4*,12*,14-22*", 1,
618 { {"/trunk", { { 0, 1, TRUE}, { 1, 2, FALSE},
619 { 2, 3, TRUE}, { 3, 4, FALSE},
620 { 4, 11, TRUE}, {11, 12, FALSE},
621 {12, 13, TRUE}, {13, 22, FALSE} } } } },
623 /* Two paths all inheritable ranges */
624 { "/trunk: 3,5,7-9,10,11,13,14\n/fred:8-10",
625 "/trunk: 1-4,6\n/fred:9-12", 2,
626 { {"/trunk", { {0, 11, TRUE}, {12, 14, TRUE} } },
627 {"/fred", { {7, 12, TRUE} } } } },
629 /* Two paths all non-inheritable ranges */
630 { "/trunk: 3*,5*,7-9*,10*,11*,13*,14*\n/fred:8-10*",
631 "/trunk: 1-4*,6*\n/fred:9-12*", 2,
632 { {"/trunk", { {0, 11, FALSE}, {12, 14, FALSE} } },
633 {"/fred", { {7, 12, FALSE} } } } },
635 /* Two paths mixed inheritability */
636 { "/trunk: 3,5*,7-9,10,11*,13,14\n/fred:8-10",
637 "/trunk: 1-4,6\n/fred:9-12*", 2,
638 { {"/trunk", { { 0, 4, TRUE }, { 4, 5, FALSE}, {5, 10, TRUE},
639 {10, 11, FALSE}, {12, 14, TRUE } } },
640 {"/fred", { { 7, 10, TRUE }, {10, 12, FALSE} } } } },
642 /* A slew of different paths but no ranges to be merged */
643 { "/trunk: 3,5-9*\n/betty: 2-4",
644 "/fred: 1-18\n/barney: 1,3-43", 4,
645 { {"/trunk", { {2, 3, TRUE}, {4, 9, FALSE} } },
646 {"/betty", { {1, 4, TRUE} } },
647 {"/barney", { {0, 1, TRUE}, {2, 43, TRUE} } },
648 {"/fred", { {0, 18, TRUE} } } } }
651 *msg = "merging of mergeinfo hashs";
652 if (msg_only)
653 return SVN_NO_ERROR;
655 for (i = 0; i < NBR_MERGEINFO_MERGES; i++)
657 int j;
658 SVN_ERR(svn_mergeinfo_parse(&info1, mergeinfo[i].mergeinfo1, pool));
659 SVN_ERR(svn_mergeinfo_parse(&info2, mergeinfo[i].mergeinfo2, pool));
660 SVN_ERR(svn_mergeinfo_merge(info1, info2, pool));
661 if (mergeinfo[i].expected_paths != apr_hash_count(info1))
662 return fail(pool, "Wrong number of paths in merged mergeinfo");
663 for (j = 0; j < mergeinfo[i].expected_paths; j++)
665 int k;
666 apr_array_header_t *rangelist =
667 apr_hash_get(info1, mergeinfo[i].path_rngs[j].path,
668 APR_HASH_KEY_STRING);
669 if (!rangelist)
670 return fail(pool, "Missing path '%s' in merged mergeinfo",
671 mergeinfo[i].path_rngs->path);
672 for (k = 0; k < rangelist->nelts; k++)
674 svn_merge_range_t *ranges =
675 APR_ARRAY_IDX(rangelist, k, svn_merge_range_t *);
676 if (ranges->start
677 != mergeinfo[i].path_rngs[j].expected_rngs[k].start
678 || ranges->end
679 != mergeinfo[i].path_rngs[j].expected_rngs[k].end
680 || ranges->inheritable
681 != mergeinfo[i].path_rngs[j].expected_rngs[k].inheritable)
682 return fail(
683 pool,
684 "Range'%i-%i%s' not found in merged mergeinfo",
685 mergeinfo[i].path_rngs->expected_rngs[k].start,
686 mergeinfo[i].path_rngs->expected_rngs[k].end,
687 mergeinfo[i].path_rngs->expected_rngs[k].inheritable
688 ? "" : "*");
690 /* Were more ranges expected? */
691 if (k < MAX_NBR_MERGEINFO_RANGES
692 && mergeinfo[i].path_rngs[j].expected_rngs[k].start != 0)
693 return fail(pool,
694 "Not all expected ranges found in merged mergeinfo");
698 return SVN_NO_ERROR;
701 static svn_error_t *
702 test_remove_rangelist(const char **msg,
703 svn_boolean_t msg_only,
704 svn_test_opts_t *opts,
705 apr_pool_t *pool)
707 int i, j;
708 svn_error_t *err, *child_err;
709 apr_array_header_t *output, *eraser, *whiteboard;
711 /* Struct for svn_rangelist_remove test data.
712 Parse WHITEBOARD and ERASER to hashes and then get the rangelist for
713 path 'A' from both.
715 Remove ERASER's rangelist from WHITEBOARD's twice, once while
716 considering inheritance and once while not. In the first case the
717 resulting rangelist should have EXPECTED_RANGES_CONSIDER_INHERITANCE
718 number of ranges and these ranges should match the ranges in
719 EXPECTED_REMOVED_CONSIDER_INHERITANCE. In the second case there
720 should be EXPECTED_RANGES_IGNORE_INHERITANCE number of ranges and
721 these should match EXPECTED_REMOVED_IGNORE_INHERITANCE */
722 struct rangelist_remove_test_data
724 const char *whiteboard;
725 const char *eraser;
726 int expected_ranges_consider_inheritance;
727 svn_merge_range_t expected_removed_consider_inheritance[10];
728 int expected_ranges_ignore_inheritance;
729 svn_merge_range_t expected_removed_ignore_inheritance[10];
732 #define SIZE_OF_RANGE_REMOVE_TEST_ARRAY 15
734 /* The actual test data */
735 struct rangelist_remove_test_data test_data[SIZE_OF_RANGE_REMOVE_TEST_ARRAY] =
737 /* Eraser is a proper subset of whiteboard */
738 {"/A: 1-44", "/A: 5", 2, { {0, 4, TRUE }, {5, 44, TRUE }},
739 2, { {0, 4, TRUE }, {5, 44, TRUE }}},
740 {"/A: 1-44*", "/A: 5", 1, { {0, 44, FALSE} },
741 2, { {0, 4, FALSE}, {5, 44, FALSE}}},
742 {"/A: 1-44", "/A: 5*", 1, { {0, 44, TRUE } },
743 2, { {0, 4, TRUE }, {5, 44, TRUE }}},
744 {"/A: 1-44*", "/A: 5*", 2, { {0, 4, FALSE}, {5, 44, FALSE}},
745 2, { {0, 4, FALSE}, {5, 44, FALSE}}},
746 /* Non-intersecting ranges...nothing is removed */
747 {"/A: 2-9,14-19", "/A: 12", 2, { {1, 9, TRUE }, {13, 19, TRUE }},
748 2, { {1, 9, TRUE }, {13, 19, TRUE }}},
749 {"/A: 2-9*,14-19*", "/A: 12", 2, { {1, 9, FALSE}, {13, 19, FALSE}},
750 2, { {1, 9, FALSE}, {13, 19, FALSE}}},
751 {"/A: 2-9,14-19", "/A: 12*", 2, { {1, 9, TRUE }, {13, 19, TRUE }},
752 2, { {1, 9, TRUE }, {13, 19, TRUE }}},
753 {"/A: 2-9*,14-19*", "/A: 12*", 2, { {1, 9, FALSE}, {13, 19, FALSE}},
754 2, { {1, 9, FALSE}, {13, 19, FALSE}}},
755 /* Eraser overlaps whiteboard */
756 {"/A: 1,9-17", "/A: 12-20", 2, { {0, 1, TRUE }, {8, 11, TRUE }},
757 2, { {0, 1, TRUE }, {8, 11, TRUE }}},
758 {"/A: 1,9-17*", "/A: 12-20", 2, { {0, 1, TRUE }, {8, 17, FALSE}},
759 2, { {0, 1, TRUE }, {8, 11, FALSE}}},
760 {"/A: 1,9-17", "/A: 12-20*", 2, { {0, 1, TRUE }, {8, 17, TRUE }},
761 2, { {0, 1, TRUE }, {8, 11, TRUE }}},
762 {"/A: 1,9-17*", "/A: 12-20*", 2, { {0, 1, TRUE }, {8, 11, FALSE}},
763 2, { {0, 1, TRUE }, {8, 11, FALSE}}},
764 /* Empty mergeinfo (i.e. empty rangelist) */
765 {"", "", 0, { {0, 0, FALSE}},
766 0, { {0, 0, FALSE}}},
767 {"", "/A: 5-8,10-100", 0, { {0, 0, FALSE}},
768 0, { {0, 0, FALSE}}},
769 {"/A: 5-8,10-100", "", 2, { {4, 8, TRUE }, {9, 100, TRUE }},
770 2, { {4, 8, TRUE }, {9, 100, TRUE }}}
773 *msg = "remove rangelists";
774 err = child_err = SVN_NO_ERROR;
775 for (j = 0; j < 2; j++)
777 for (i = 0; i < SIZE_OF_RANGE_REMOVE_TEST_ARRAY; i++)
779 int expected_nbr_ranges;
780 svn_merge_range_t *expected_ranges;
782 SVN_ERR(svn_mergeinfo_parse(&info1, (test_data[i]).eraser, pool));
783 SVN_ERR(svn_mergeinfo_parse(&info2, (test_data[i]).whiteboard, pool));
784 eraser = apr_hash_get(info1, "/A", APR_HASH_KEY_STRING);
785 whiteboard = apr_hash_get(info2, "/A", APR_HASH_KEY_STRING);
787 /* Represent empty mergeinfo with an empty rangelist. */
788 if (eraser == NULL)
789 eraser = apr_array_make(pool, 0, sizeof(*eraser));
790 if (whiteboard == NULL)
791 whiteboard = apr_array_make(pool, 0, sizeof(*whiteboard));
793 /* First pass try removal considering inheritance, on the
794 second pass ignore it. */
795 if (j == 0)
797 expected_nbr_ranges = (test_data[i]).expected_ranges_consider_inheritance;
798 expected_ranges = (test_data[i]).expected_removed_consider_inheritance;
801 else
803 expected_nbr_ranges = (test_data[i]).expected_ranges_ignore_inheritance;
804 expected_ranges = (test_data[i]).expected_removed_ignore_inheritance;
807 SVN_ERR(svn_rangelist_remove(&output, eraser, whiteboard,
808 j == 0 ? TRUE : FALSE,
809 pool));
810 child_err = verify_ranges_match(output, expected_ranges,
811 expected_nbr_ranges,
812 apr_psprintf(pool,
813 "svn_rangelist_remove "
814 "case %i", i),
815 "remove", pool);
817 /* Collect all the errors rather than returning on the first. */
818 if (child_err)
820 if (err)
821 svn_error_compose(err, child_err);
822 else
823 err = child_err;
827 return err;
830 #define RANDOM_REV_ARRAY_LENGTH 100
832 /* Random number seed. */
833 static apr_uint32_t random_rev_array_seed;
835 /* Fill 3/4 of the array with 1s. */
836 static void
837 randomly_fill_rev_array(svn_boolean_t *revs)
839 int i;
840 for (i = 0; i < RANDOM_REV_ARRAY_LENGTH; i++)
842 apr_uint32_t next = svn_test_rand(&random_rev_array_seed);
843 revs[i] = (next < 0x40000000) ? 0 : 1;
847 static svn_error_t *
848 rev_array_to_rangelist(apr_array_header_t **rangelist,
849 svn_boolean_t *revs,
850 apr_pool_t *pool)
852 svn_stringbuf_t *buf = svn_stringbuf_create("/trunk: ", pool);
853 svn_boolean_t first = TRUE;
854 apr_hash_t *mergeinfo;
855 int i;
857 for (i = 0; i < RANDOM_REV_ARRAY_LENGTH; i++)
859 if (revs[i])
861 if (first)
862 first = FALSE;
863 else
864 svn_stringbuf_appendcstr(buf, ",");
865 svn_stringbuf_appendcstr(buf, apr_psprintf(pool, "%d", i));
869 SVN_ERR(svn_mergeinfo_parse(&mergeinfo, buf->data, pool));
870 *rangelist = apr_hash_get(mergeinfo, "/trunk", APR_HASH_KEY_STRING);
872 return SVN_NO_ERROR;
875 static svn_error_t *
876 test_rangelist_remove_randomly(const char **msg,
877 svn_boolean_t msg_only,
878 svn_test_opts_t *opts,
879 apr_pool_t *pool)
881 int i;
882 apr_pool_t *iterpool;
884 *msg = "test rangelist remove with random data";
885 if (msg_only)
886 return SVN_NO_ERROR;
888 random_rev_array_seed = (apr_uint32_t) apr_time_now();
890 iterpool = svn_pool_create(pool);
892 for (i = 0; i < 20; i++)
894 svn_boolean_t first_revs[RANDOM_REV_ARRAY_LENGTH],
895 second_revs[RANDOM_REV_ARRAY_LENGTH],
896 expected_revs[RANDOM_REV_ARRAY_LENGTH];
897 apr_array_header_t *first_rangelist, *second_rangelist,
898 *expected_rangelist, *actual_rangelist;
899 /* There will be at most RANDOM_REV_ARRAY_LENGTH ranges in
900 expected_rangelist. */
901 svn_merge_range_t expected_range_array[RANDOM_REV_ARRAY_LENGTH];
902 int j;
904 svn_pool_clear(iterpool);
906 randomly_fill_rev_array(first_revs);
907 randomly_fill_rev_array(second_revs);
908 for (j = 0; j < RANDOM_REV_ARRAY_LENGTH; j++)
909 expected_revs[j] = second_revs[j] && !first_revs[j];
911 SVN_ERR(rev_array_to_rangelist(&first_rangelist, first_revs, iterpool));
912 SVN_ERR(rev_array_to_rangelist(&second_rangelist, second_revs, iterpool));
913 SVN_ERR(rev_array_to_rangelist(&expected_rangelist, expected_revs,
914 iterpool));
916 for (j = 0; j < expected_rangelist->nelts; j++)
918 expected_range_array[j] = *(APR_ARRAY_IDX(expected_rangelist, j,
919 svn_merge_range_t *));
922 SVN_ERR(svn_rangelist_remove(&actual_rangelist, first_rangelist,
923 second_rangelist, TRUE, iterpool));
925 SVN_ERR(verify_ranges_match(actual_rangelist,
926 expected_range_array,
927 expected_rangelist->nelts,
928 "svn_rangelist_remove random call",
929 "remove", iterpool));
932 svn_pool_destroy(iterpool);
934 return SVN_NO_ERROR;
937 static svn_error_t *
938 test_rangelist_intersect_randomly(const char **msg,
939 svn_boolean_t msg_only,
940 svn_test_opts_t *opts,
941 apr_pool_t *pool)
943 int i;
944 apr_pool_t *iterpool;
946 *msg = "test rangelist intersect with random data";
947 if (msg_only)
948 return SVN_NO_ERROR;
950 random_rev_array_seed = (apr_uint32_t) apr_time_now();
952 iterpool = svn_pool_create(pool);
954 for (i = 0; i < 20; i++)
956 svn_boolean_t first_revs[RANDOM_REV_ARRAY_LENGTH],
957 second_revs[RANDOM_REV_ARRAY_LENGTH],
958 expected_revs[RANDOM_REV_ARRAY_LENGTH];
959 apr_array_header_t *first_rangelist, *second_rangelist,
960 *expected_rangelist, *actual_rangelist;
961 /* There will be at most RANDOM_REV_ARRAY_LENGTH ranges in
962 expected_rangelist. */
963 svn_merge_range_t expected_range_array[RANDOM_REV_ARRAY_LENGTH];
964 int j;
966 svn_pool_clear(iterpool);
968 randomly_fill_rev_array(first_revs);
969 randomly_fill_rev_array(second_revs);
970 for (j = 0; j < RANDOM_REV_ARRAY_LENGTH; j++)
971 expected_revs[j] = second_revs[j] && first_revs[j];
973 SVN_ERR(rev_array_to_rangelist(&first_rangelist, first_revs, iterpool));
974 SVN_ERR(rev_array_to_rangelist(&second_rangelist, second_revs, iterpool));
975 SVN_ERR(rev_array_to_rangelist(&expected_rangelist, expected_revs,
976 iterpool));
978 for (j = 0; j < expected_rangelist->nelts; j++)
980 expected_range_array[j] = *(APR_ARRAY_IDX(expected_rangelist, j,
981 svn_merge_range_t *));
984 SVN_ERR(svn_rangelist_intersect(&actual_rangelist, first_rangelist,
985 second_rangelist, iterpool));
987 SVN_ERR(verify_ranges_match(actual_rangelist,
988 expected_range_array,
989 expected_rangelist->nelts,
990 "svn_rangelist_intersect random call",
991 "intersect", iterpool));
994 svn_pool_destroy(iterpool);
996 return SVN_NO_ERROR;
999 /* ### Share code with test_diff_mergeinfo() and test_remove_rangelist(). */
1000 static svn_error_t *
1001 test_remove_mergeinfo(const char **msg,
1002 svn_boolean_t msg_only,
1003 svn_test_opts_t *opts,
1004 apr_pool_t *pool)
1006 apr_hash_t *output, *whiteboard, *eraser;
1007 svn_merge_range_t expected_rangelist_remainder[NBR_RANGELIST_DELTAS] =
1008 { {6, 7, TRUE}, {8, 9, TRUE}, {10, 11, TRUE}, {32, 34, TRUE} };
1010 *msg = "remove of mergeinfo";
1011 if (msg_only)
1012 return SVN_NO_ERROR;
1014 SVN_ERR(svn_mergeinfo_parse(&whiteboard,
1015 "/trunk: 1,3-4,7,9,11-12,31-34", pool));
1016 SVN_ERR(svn_mergeinfo_parse(&eraser, "/trunk: 1-6,12-16,30-32", pool));
1018 /* Leftover on /trunk should be the set (7, 9, 11, 33-34) */
1019 SVN_ERR(svn_mergeinfo_remove(&output, eraser, whiteboard, pool));
1021 /* Verify calculation of range list remainder. */
1022 return verify_mergeinfo_deltas(output, expected_rangelist_remainder,
1023 "svn_mergeinfo_remove", "leftover", pool);
1025 #undef NBR_RANGELIST_DELTAS
1027 static svn_error_t *
1028 test_rangelist_to_string(const char **msg,
1029 svn_boolean_t msg_only,
1030 svn_test_opts_t *opts,
1031 apr_pool_t *pool)
1033 apr_array_header_t *result;
1034 svn_string_t *output;
1035 svn_string_t *expected = svn_string_create("3,5,7-11,13-14", pool);
1037 *msg = "turning rangelist back into a string";
1039 if (msg_only)
1040 return SVN_NO_ERROR;
1042 SVN_ERR(svn_mergeinfo_parse(&info1, mergeinfo1, pool));
1044 result = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
1045 if (!result)
1046 return fail(pool, "Missing path in parsed mergeinfo");
1048 SVN_ERR(svn_rangelist_to_string(&output, result, pool));
1050 if (svn_string_compare(expected, output) != TRUE)
1051 return fail(pool, "Rangelist string not what we expected");
1053 return SVN_NO_ERROR;
1056 static svn_error_t *
1057 test_mergeinfo_to_string(const char **msg,
1058 svn_boolean_t msg_only,
1059 svn_test_opts_t *opts,
1060 apr_pool_t *pool)
1062 svn_string_t *output;
1063 svn_string_t *expected;
1064 expected = svn_string_create("/fred:8-10\n/trunk:3,5,7-11,13-14", pool);
1066 *msg = "turning mergeinfo back into a string";
1068 if (msg_only)
1069 return SVN_NO_ERROR;
1071 SVN_ERR(svn_mergeinfo_parse(&info1, mergeinfo1, pool));
1073 SVN_ERR(svn_mergeinfo_to_string(&output, info1, pool));
1075 if (svn_string_compare(expected, output) != TRUE)
1076 return fail(pool, "Mergeinfo string not what we expected");
1078 return SVN_NO_ERROR;
1082 static svn_error_t *
1083 test_rangelist_merge(const char **msg,
1084 svn_boolean_t msg_only,
1085 svn_test_opts_t *opts,
1086 apr_pool_t *pool)
1088 int i;
1089 svn_error_t *err, *child_err;
1090 apr_array_header_t *rangelist1, *rangelist2;
1092 /* Struct for svn_rangelist_merge test data. Similar to
1093 mergeinfo_merge_test_data struct in svn_mergeinfo_merge() test. */
1094 struct rangelist_merge_test_data
1096 const char *mergeinfo1;
1097 const char *mergeinfo2;
1098 int expected_ranges;
1099 svn_merge_range_t expected_merge[6];
1102 #define SIZE_OF_RANGE_MERGE_TEST_ARRAY 59
1103 /* The actual test data. */
1104 struct rangelist_merge_test_data test_data[SIZE_OF_RANGE_MERGE_TEST_ARRAY] =
1106 /* Non-intersecting ranges */
1107 {"/A: 1-44", "/A: 70-101", 2, {{ 0, 44, TRUE }, {69, 101, TRUE }}},
1108 {"/A: 1-44*", "/A: 70-101", 2, {{ 0, 44, FALSE}, {69, 101, TRUE }}},
1109 {"/A: 1-44", "/A: 70-101*", 2, {{ 0, 44, TRUE }, {69, 101, FALSE}}},
1110 {"/A: 1-44*", "/A: 70-101*", 2, {{ 0, 44, FALSE}, {69, 101, FALSE}}},
1111 {"/A: 70-101", "/A: 1-44", 2, {{ 0, 44, TRUE }, {69, 101, TRUE }}},
1112 {"/A: 70-101*", "/A: 1-44", 2, {{ 0, 44, TRUE }, {69, 101, FALSE}}},
1113 {"/A: 70-101", "/A: 1-44*", 2, {{ 0, 44, FALSE}, {69, 101, TRUE }}},
1114 {"/A: 70-101*", "/A: 1-44*", 2, {{ 0, 44, FALSE}, {69, 101, FALSE}}},
1116 /* Intersecting ranges with same starting and ending revisions */
1117 {"/A: 4-20", "/A: 4-20", 1, {{3, 20, TRUE }}},
1118 {"/A: 4-20*", "/A: 4-20", 1, {{3, 20, TRUE }}},
1119 {"/A: 4-20", "/A: 4-20*", 1, {{3, 20, TRUE }}},
1120 {"/A: 4-20*", "/A: 4-20*", 1, {{3, 20, FALSE}}},
1122 /* Intersecting ranges with same starting revision */
1123 {"/A: 6-17", "/A: 6-12", 1, {{5, 17, TRUE}}},
1124 {"/A: 6-17*", "/A: 6-12", 2, {{5, 12, TRUE }, {12, 17, FALSE}}},
1125 {"/A: 6-17", "/A: 6-12*", 1, {{5, 17, TRUE }}},
1126 {"/A: 6-17*", "/A: 6-12*", 1, {{5, 17, FALSE}}},
1127 {"/A: 6-12", "/A: 6-17", 1, {{5, 17, TRUE }}},
1128 {"/A: 6-12*", "/A: 6-17", 1, {{5, 17, TRUE }}},
1129 {"/A: 6-12", "/A: 6-17*", 2, {{5, 12, TRUE }, {12, 17, FALSE}}},
1130 {"/A: 6-12*", "/A: 6-17*", 1, {{5, 17, FALSE}}},
1132 /* Intersecting ranges with same ending revision */
1133 {"/A: 5-77", "/A: 44-77", 1, {{4, 77, TRUE }}},
1134 {"/A: 5-77*", "/A: 44-77", 2, {{4, 43, FALSE}, {43, 77, TRUE}}},
1135 {"/A: 5-77", "/A: 44-77*", 1, {{4, 77, TRUE }}},
1136 {"/A: 5-77*", "/A: 44-77*", 1, {{4, 77, FALSE}}},
1137 {"/A: 44-77", "/A: 5-77", 1, {{4, 77, TRUE }}},
1138 {"/A: 44-77*", "/A: 5-77", 1, {{4, 77, TRUE }}},
1139 {"/A: 44-77", "/A: 5-77*", 2, {{4, 43, FALSE}, {43, 77, TRUE}}},
1140 {"/A: 44-77*", "/A: 5-77*", 1, {{4, 77, FALSE}}},
1142 /* Intersecting ranges with different starting and ending revision
1143 where one range is a proper subset of the other. */
1144 {"/A: 12-24", "/A: 20-23", 1, {{11, 24, TRUE }}},
1145 {"/A: 12-24*", "/A: 20-23", 3, {{11, 19, FALSE}, {19, 23, TRUE },
1146 {23, 24, FALSE}}},
1147 {"/A: 12-24", "/A: 20-23*", 1, {{11, 24, TRUE }}},
1148 {"/A: 12-24*", "/A: 20-23*", 1, {{11, 24, FALSE}}},
1149 {"/A: 20-23", "/A: 12-24", 1, {{11, 24, TRUE }}},
1150 {"/A: 20-23*", "/A: 12-24", 1, {{11, 24, TRUE }}},
1151 {"/A: 20-23", "/A: 12-24*", 3, {{11, 19, FALSE}, {19, 23, TRUE },
1152 {23, 24, FALSE}}},
1153 {"/A: 20-23*", "/A: 12-24*", 1, {{11, 24, FALSE}}},
1155 /* Intersecting ranges with different starting and ending revision
1156 where neither range is a proper subset of the other. */
1157 {"/A: 50-73", "/A: 60-99", 1, {{49, 99, TRUE }}},
1158 {"/A: 50-73*", "/A: 60-99", 2, {{49, 59, FALSE}, {59, 99, TRUE }}},
1159 {"/A: 50-73", "/A: 60-99*", 2, {{49, 73, TRUE }, {73, 99, FALSE}}},
1160 {"/A: 50-73*", "/A: 60-99*", 1, {{49, 99, FALSE}}},
1161 {"/A: 60-99", "/A: 50-73", 1, {{49, 99, TRUE }}},
1162 {"/A: 60-99*", "/A: 50-73", 2, {{49, 73, TRUE }, {73, 99, FALSE}}},
1163 {"/A: 60-99", "/A: 50-73*", 2, {{49, 59, FALSE}, {59, 99, TRUE }}},
1164 {"/A: 60-99*", "/A: 50-73*", 1, {{49, 99, FALSE}}},
1166 /* Multiple ranges. */
1167 {"/A: 1-5,7,12-13", "/A: 2-17", 1, {{0, 17, TRUE }}},
1168 {"/A: 1-5*,7*,12-13*", "/A: 2-17*", 1, {{0, 17, FALSE}}},
1170 {"/A: 1-5,7,12-13", "/A: 2-17*", 6,
1171 {{0, 5, TRUE }, { 5, 6, FALSE}, { 6, 7, TRUE },
1172 {7, 11, FALSE}, {11, 13, TRUE }, {13, 17, FALSE}}},
1174 {"/A: 1-5*,7*,12-13*", "/A: 2-17", 2,
1175 {{0, 1, FALSE}, {1, 17, TRUE }}},
1177 {"/A: 2-17", "/A: 1-5,7,12-13", 1, {{0, 17, TRUE }}},
1178 {"/A: 2-17*", "/A: 1-5*,7*,12-13*", 1, {{0, 17, FALSE}}},
1180 {"/A: 2-17*", "/A: 1-5,7,12-13", 6,
1181 {{0, 5, TRUE }, { 5, 6, FALSE}, { 6, 7, TRUE },
1182 {7, 11, FALSE}, {11, 13, TRUE }, {13, 17, FALSE}}},
1184 {"/A: 2-17", "/A: 1-5*,7*,12-13*", 2,
1185 {{0, 1, FALSE}, {1, 17, TRUE}}},
1187 /* A rangelist merged with an empty rangelist should equal the
1188 non-empty rangelist but in compacted form. */
1189 {"/A: 1-44,45,46,47-50", "", 1, {{ 0, 50, TRUE }}},
1190 {"/A: 1,2,3,4,5,6,7,8", "", 1, {{ 0, 8, TRUE }}},
1191 {"/A: 6-10,12-13,14,15,16-22", "", 2,
1192 {{ 5, 10, TRUE }, { 11, 22, TRUE }}},
1193 {"", "/A: 1-44,45,46,47-50", 1, {{ 0, 50, TRUE }}},
1194 {"", "/A: 1,2,3,4,5,6,7,8", 1, {{ 0, 8, TRUE }}},
1195 {"", "/A: 6-10,12-13,14,15,16-22", 2,
1196 {{ 5, 10, TRUE }, { 11, 22, TRUE }}},
1198 /* An empty rangelist merged with an empty rangelist is, drum-roll
1199 please, an empty rangelist. */
1200 {"", "", 0, {{0, 0, FALSE}}}
1202 *msg = "merge of rangelists";
1203 if (msg_only)
1204 return SVN_NO_ERROR;
1206 err = child_err = SVN_NO_ERROR;
1207 for (i = 0; i < SIZE_OF_RANGE_MERGE_TEST_ARRAY; i++)
1209 SVN_ERR(svn_mergeinfo_parse(&info1, (test_data[i]).mergeinfo1, pool));
1210 SVN_ERR(svn_mergeinfo_parse(&info2, (test_data[i]).mergeinfo2, pool));
1211 rangelist1 = apr_hash_get(info1, "/A", APR_HASH_KEY_STRING);
1212 rangelist2 = apr_hash_get(info2, "/A", APR_HASH_KEY_STRING);
1214 /* Create empty rangelists if necessary. */
1215 if (rangelist1 == NULL)
1216 rangelist1 = apr_array_make(pool, 0, sizeof(svn_merge_range_t *));
1217 if (rangelist2 == NULL)
1218 rangelist2 = apr_array_make(pool, 0, sizeof(svn_merge_range_t *));
1220 SVN_ERR(svn_rangelist_merge(&rangelist1, rangelist2, pool));
1221 child_err = verify_ranges_match(rangelist1,
1222 (test_data[i]).expected_merge,
1223 (test_data[i]).expected_ranges,
1224 apr_psprintf(pool,
1225 "svn_rangelist_merge "
1226 "case %i", i),
1227 "merge", pool);
1229 /* Collect all the errors rather than returning on the first. */
1230 if (child_err)
1232 if (err)
1233 svn_error_compose(err, child_err);
1234 else
1235 err = child_err;
1238 return err;
1241 static svn_error_t *
1242 test_rangelist_diff(const char **msg,
1243 svn_boolean_t msg_only,
1244 svn_test_opts_t *opts,
1245 apr_pool_t *pool)
1247 int i;
1248 svn_error_t *err, *child_err;
1249 apr_array_header_t *from, *to, *added, *deleted;
1251 /* Structure containing two ranges to diff and the expected output of the
1252 diff both when considering and ignoring range inheritance. */
1253 struct rangelist_diff_test_data
1255 /* svn:mergeinfo string representations */
1256 const char *from;
1257 const char *to;
1259 /* Expected results for performing svn_rangelist_diff
1260 while considering differences in inheritability to be real
1261 differences. */
1262 int expected_add_ranges;
1263 svn_merge_range_t expected_adds[10];
1264 int expected_del_ranges;
1265 svn_merge_range_t expected_dels[10];
1267 /* Expected results for performing svn_rangelist_diff
1268 while ignoring differences in inheritability. */
1269 int expected_add_ranges_ignore_inheritance;
1270 svn_merge_range_t expected_adds_ignore_inheritance[10];
1271 int expected_del_ranges_ignore_inheritance;
1272 svn_merge_range_t expected_dels_ignore_inheritance[10];
1275 #define SIZE_OF_RANGE_DIFF_TEST_ARRAY 16
1276 /* The actual test data array.
1278 'from' --> {"/A: 1,5-8", "/A: 1,6,10-12", <-- 'to'
1279 Number of adds when --> 1, { { 9, 12, TRUE } },
1280 considering inheritance
1282 Number of dels when --> 2, { { 4, 5, TRUE }, { 6, 8, TRUE } },
1283 considering inheritance
1285 Number of adds when --> 1, { { 9, 12, TRUE } },
1286 ignoring inheritance
1288 Number of dels when --> 2, { { 4, 5, TRUE }, { 6, 8, TRUE } } },
1289 ignoring inheritance
1291 The expected svn_merge_range_t's
1293 struct rangelist_diff_test_data test_data[SIZE_OF_RANGE_DIFF_TEST_ARRAY] =
1295 /* Add and Delete */
1296 {"/A: 1", "/A: 3",
1297 1, { { 2, 3, TRUE } },
1298 1, { { 0, 1, TRUE } },
1299 1, { { 2, 3, TRUE } },
1300 1, { { 0, 1, TRUE } } },
1302 /* Add only */
1303 {"/A: 1", "/A: 1,3",
1304 1, { { 2, 3, TRUE } },
1305 0, { { 0, 0, FALSE } },
1306 1, { { 2, 3, TRUE } },
1307 0, { { 0, 0, FALSE } } },
1309 /* Delete only */
1310 {"/A: 1,3", "/A: 1",
1311 0, { { 0, 0, FALSE } },
1312 1, { { 2, 3, TRUE } },
1313 0, { { 0, 0, FALSE } },
1314 1, { { 2, 3, TRUE } } },
1316 /* No diff */
1317 {"/A: 1,3", "/A: 1,3",
1318 0, { { 0, 0, FALSE } },
1319 0, { { 0, 0, FALSE } },
1320 0, { { 0, 0, FALSE } },
1321 0, { { 0, 0, FALSE } } },
1323 {"/A: 1,3*", "/A: 1,3*",
1324 0, { { 0, 0, FALSE } },
1325 0, { { 0, 0, FALSE } },
1326 0, { { 0, 0, FALSE } },
1327 0, { { 0, 0, FALSE } } },
1329 /* Adds and Deletes */
1330 {"/A: 1,5-8", "/A: 1,6,10-12",
1331 1, { { 9, 12, TRUE } },
1332 2, { { 4, 5, TRUE }, { 6, 8, TRUE } },
1333 1, { { 9, 12, TRUE } },
1334 2, { { 4, 5, TRUE }, { 6, 8, TRUE } } },
1336 {"/A: 6*", "/A: 6",
1337 1, { { 5, 6, TRUE } },
1338 1, { { 5, 6, FALSE } },
1339 0, { { 0, 0, FALSE } },
1340 0, { { 0, 0, FALSE } } },
1342 /* Intersecting range with different inheritability */
1343 {"/A: 6", "/A: 6*",
1344 1, { { 5, 6, FALSE } },
1345 1, { { 5, 6, TRUE } },
1346 0, { { 0, 0, FALSE } },
1347 0, { { 0, 0, FALSE } } },
1349 {"/A: 6*", "/A: 6",
1350 1, { { 5, 6, TRUE } },
1351 1, { { 5, 6, FALSE } },
1352 0, { { 0, 0, FALSE } },
1353 0, { { 0, 0, FALSE } } },
1355 {"/A: 1,5-8", "/A: 1,6*,10-12",
1356 2, { { 5, 6, FALSE }, { 9, 12, TRUE } },
1357 1, { { 4, 8, TRUE } },
1358 1, { { 9, 12, TRUE } },
1359 2, { { 4, 5, TRUE }, { 6, 8, TRUE } } },
1361 {"/A: 1,5-8*", "/A: 1,6,10-12",
1362 2, { { 5, 6, TRUE }, { 9, 12, TRUE } },
1363 1, { { 4, 8, FALSE } },
1364 1, { { 9, 12, TRUE } },
1365 2, { { 4, 5, FALSE }, { 6, 8, FALSE } } },
1367 /* Empty range diffs */
1368 {"/A: 3-9", "",
1369 0, { { 0, 0, FALSE } },
1370 1, { { 2, 9, TRUE } },
1371 0, { { 0, 0, FALSE } },
1372 1, { { 2, 9, TRUE } } },
1374 {"/A: 3-9*", "",
1375 0, { { 0, 0, FALSE } },
1376 1, { { 2, 9, FALSE } },
1377 0, { { 0, 0, FALSE } },
1378 1, { { 2, 9, FALSE } } },
1380 {"", "/A: 3-9",
1381 1, { { 2, 9, TRUE } },
1382 0, { { 0, 0, FALSE } },
1383 1, { { 2, 9, TRUE } },
1384 0, { { 0, 0, FALSE } } },
1386 {"", "/A: 3-9*",
1387 1, { { 2, 9, FALSE } },
1388 0, { { 0, 0, FALSE } },
1389 1, { { 2, 9, FALSE } },
1390 0, { { 0, 0, FALSE } } },
1392 /* Empty range no diff */
1393 {"", "",
1394 0, { { 0, 0, FALSE } },
1395 0, { { 0, 0, FALSE } },
1396 0, { { 0, 0, FALSE } },
1397 0, { { 0, 0, FALSE } } },
1400 *msg = "diff of rangelists";
1401 if (msg_only)
1402 return SVN_NO_ERROR;
1404 err = child_err = SVN_NO_ERROR;
1405 for (i = 0; i < SIZE_OF_RANGE_DIFF_TEST_ARRAY; i++)
1407 SVN_ERR(svn_mergeinfo_parse(&info1, (test_data[i]).to, pool));
1408 SVN_ERR(svn_mergeinfo_parse(&info2, (test_data[i]).from, pool));
1409 to = apr_hash_get(info1, "/A", APR_HASH_KEY_STRING);
1410 from = apr_hash_get(info2, "/A", APR_HASH_KEY_STRING);
1412 /* Represent empty mergeinfo with an empty rangelist. */
1413 if (to == NULL)
1414 to = apr_array_make(pool, 0, sizeof(*to));
1415 if (from == NULL)
1416 from = apr_array_make(pool, 0, sizeof(*from));
1418 /* First diff the ranges while considering
1419 differences in inheritance. */
1420 SVN_ERR(svn_rangelist_diff(&deleted, &added, from, to, TRUE, pool));
1422 child_err = verify_ranges_match(added,
1423 (test_data[i]).expected_adds,
1424 (test_data[i]).expected_add_ranges,
1425 apr_psprintf(pool,
1426 "svn_rangelist_diff"
1427 "case %i", i),
1428 "diff", pool);
1429 if (!child_err)
1430 child_err = verify_ranges_match(deleted,
1431 (test_data[i]).expected_dels,
1432 (test_data[i]).expected_del_ranges,
1433 apr_psprintf(pool,
1434 "svn_rangelist_diff"
1435 "case %i", i),
1436 "diff", pool);
1437 if (!child_err)
1439 /* Now do the diff while ignoring differences in inheritance. */
1440 SVN_ERR(svn_rangelist_diff(&deleted, &added, from, to, FALSE,
1441 pool));
1442 child_err = verify_ranges_match(
1443 added,
1444 (test_data[i]).expected_adds_ignore_inheritance,
1445 (test_data[i]).expected_add_ranges_ignore_inheritance,
1446 apr_psprintf(pool, "svn_rangelist_diff case %i", i),
1447 "diff", pool);
1449 if (!child_err)
1450 child_err = verify_ranges_match(
1451 deleted,
1452 (test_data[i]).expected_dels_ignore_inheritance,
1453 (test_data[i]).expected_del_ranges_ignore_inheritance,
1454 apr_psprintf(pool, "svn_rangelist_diff case %i", i),
1455 "diff", pool);
1458 /* Collect all the errors rather than returning on the first. */
1459 if (child_err)
1461 if (err)
1462 svn_error_compose(err, child_err);
1463 else
1464 err = child_err;
1467 return err;
1470 /* The test table. */
1472 struct svn_test_descriptor_t test_funcs[] =
1474 SVN_TEST_NULL,
1475 SVN_TEST_PASS(test_parse_single_line_mergeinfo),
1476 SVN_TEST_PASS(test_mergeinfo_dup),
1477 SVN_TEST_PASS(test_parse_combine_rangeinfo),
1478 SVN_TEST_PASS(test_parse_broken_mergeinfo),
1479 SVN_TEST_PASS(test_remove_rangelist),
1480 SVN_TEST_PASS(test_rangelist_remove_randomly),
1481 SVN_TEST_PASS(test_remove_mergeinfo),
1482 SVN_TEST_PASS(test_rangelist_reverse),
1483 SVN_TEST_PASS(test_rangelist_intersect),
1484 SVN_TEST_PASS(test_rangelist_intersect_randomly),
1485 SVN_TEST_PASS(test_diff_mergeinfo),
1486 SVN_TEST_PASS(test_merge_mergeinfo),
1487 SVN_TEST_PASS(test_mergeinfo_intersect),
1488 SVN_TEST_PASS(test_rangelist_to_string),
1489 SVN_TEST_PASS(test_mergeinfo_to_string),
1490 SVN_TEST_PASS(test_rangelist_merge),
1491 SVN_TEST_PASS(test_rangelist_diff),
1492 SVN_TEST_NULL