Add a little more to the svn_rangelist_intersect test to test the
[svn.git] / subversion / tests / libsvn_subr / mergeinfo-test.c
blob97ec3517fcc89a4ac7c848bb2a3a0eec62617110
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 35
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"
298 static svn_error_t *
299 test_parse_broken_mergeinfo(const char **msg,
300 svn_boolean_t msg_only,
301 svn_test_opts_t *opts,
302 apr_pool_t *pool)
304 int i;
305 svn_error_t *err;
306 *msg = "parse broken single line mergeinfo";
308 if (msg_only)
309 return SVN_NO_ERROR;
311 /* Trigger some error(s) with mal-formed input. */
312 for (i = 0; i < NBR_BROKEN_MERGEINFO_VALS; i++)
314 err = svn_mergeinfo_parse(&info1, broken_mergeinfo_vals[i], pool);
315 if (err == SVN_NO_ERROR)
316 return fail(pool, "svn_mergeinfo_parse (%s) failed to detect an error",
317 broken_mergeinfo_vals[i]);
318 else
319 svn_error_clear(err);
322 return SVN_NO_ERROR;
326 static const char *mergeinfo1 = "/trunk: 3,5,7-9,10,11,13,14\n/fred:8-10";
328 #define NBR_RANGELIST_DELTAS 4
330 /* Verify that ACTUAL_RANGELIST matches EXPECTED_RANGES (an array of
331 NBR_EXPECTED length). Return an error based careful examination if
332 they do not match. FUNC_VERIFIED is the name of the API being
333 verified (e.g. "svn_rangelist_intersect"), while TYPE is a word
334 describing what the ranges being examined represent. */
335 static svn_error_t *
336 verify_ranges_match(apr_array_header_t *actual_rangelist,
337 svn_merge_range_t *expected_ranges, int nbr_expected,
338 const char *func_verified, const char *type,
339 apr_pool_t *pool)
341 int i;
343 if (actual_rangelist->nelts != nbr_expected)
344 return fail(pool, "%s should report %d range %ss, but found %d",
345 func_verified, nbr_expected, type, actual_rangelist->nelts);
347 for (i = 0; i < actual_rangelist->nelts; i++)
349 svn_merge_range_t *range = APR_ARRAY_IDX(actual_rangelist, i,
350 svn_merge_range_t *);
351 if (range->start != expected_ranges[i].start
352 || range->end != expected_ranges[i].end
353 || range->inheritable != expected_ranges[i].inheritable)
354 return fail(pool, "%s should report range %ld-%ld%s, "
355 "but found %ld-%ld%s",
356 func_verified, expected_ranges[i].start,
357 expected_ranges[i].end,
358 expected_ranges[i].inheritable ? "*" : "",
359 range->start, range->end,
360 range->inheritable ? "*" : "");
362 return SVN_NO_ERROR;
365 /* Verify that DELTAS matches EXPECTED_DELTAS (both expected to
366 contain only a rangelist for "/trunk"). Return an error based
367 careful examination if they do not match. FUNC_VERIFIED is the
368 name of the API being verified (e.g. "svn_mergeinfo_diff"), while
369 TYPE is a word describing what the deltas being examined
370 represent. */
371 static svn_error_t *
372 verify_mergeinfo_deltas(apr_hash_t *deltas, svn_merge_range_t *expected_deltas,
373 const char *func_verified, const char *type,
374 apr_pool_t *pool)
376 apr_array_header_t *rangelist;
378 if (apr_hash_count(deltas) != 1)
379 /* Deltas on "/trunk" expected. */
380 return fail(pool, "%s should report 1 path %s, but found %d",
381 func_verified, type, apr_hash_count(deltas));
383 rangelist = apr_hash_get(deltas, "/trunk", APR_HASH_KEY_STRING);
384 if (rangelist == NULL)
385 return fail(pool, "%s failed to produce a rangelist for /trunk",
386 func_verified);
388 return verify_ranges_match(rangelist, expected_deltas, NBR_RANGELIST_DELTAS,
389 func_verified, type, pool);
392 static svn_error_t *
393 test_diff_mergeinfo(const char **msg,
394 svn_boolean_t msg_only,
395 svn_test_opts_t *opts,
396 apr_pool_t *pool)
398 apr_hash_t *deleted, *added, *from, *to;
399 svn_merge_range_t expected_rangelist_deletions[NBR_RANGELIST_DELTAS] =
400 { {6, 7, TRUE}, {8, 9, TRUE}, {10, 11, TRUE}, {32, 34, TRUE} };
401 svn_merge_range_t expected_rangelist_additions[NBR_RANGELIST_DELTAS] =
402 { {1, 2, TRUE}, {4, 6, TRUE}, {12, 16, TRUE}, {29, 30, TRUE} };
404 *msg = "diff of mergeinfo";
405 if (msg_only)
406 return SVN_NO_ERROR;
408 SVN_ERR(svn_mergeinfo_parse(&from, "/trunk: 1,3-4,7,9,11-12,31-34", pool));
409 SVN_ERR(svn_mergeinfo_parse(&to, "/trunk: 1-6,12-16,30-32", pool));
410 /* On /trunk: deleted (7, 9, 11, 33-34) and added (2, 5-6, 13-16, 30) */
411 SVN_ERR(svn_mergeinfo_diff(&deleted, &added, from, to,
412 FALSE, pool));
414 /* Verify calculation of range list deltas. */
415 SVN_ERR(verify_mergeinfo_deltas(deleted, expected_rangelist_deletions,
416 "svn_mergeinfo_diff", "deletion", pool));
417 SVN_ERR(verify_mergeinfo_deltas(added, expected_rangelist_additions,
418 "svn_mergeinfo_diff", "addition", pool));
420 return SVN_NO_ERROR;
423 static svn_error_t *
424 test_rangelist_reverse(const char **msg,
425 svn_boolean_t msg_only,
426 svn_test_opts_t *opts,
427 apr_pool_t *pool)
429 apr_array_header_t *rangelist;
430 svn_merge_range_t expected_rangelist[3] =
431 { {10, 9, TRUE}, {7, 4, TRUE}, {3, 2, TRUE} };
433 *msg = "reversal of rangelist";
434 if (msg_only)
435 return SVN_NO_ERROR;
437 SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 3,5-7,10", pool));
438 rangelist = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
440 SVN_ERR(svn_rangelist_reverse(rangelist, pool));
442 return verify_ranges_match(rangelist, expected_rangelist, 3,
443 "svn_rangelist_reverse", "reversal", pool);
446 static svn_error_t *
447 test_rangelist_count_revs(const char **msg,
448 svn_boolean_t msg_only,
449 svn_test_opts_t *opts,
450 apr_pool_t *pool)
452 apr_array_header_t *rangelist;
453 apr_uint64_t nbr_revs;
455 *msg = "counting revs in rangelist";
456 if (msg_only)
457 return SVN_NO_ERROR;
459 SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 3,5-7,10", pool));
460 rangelist = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
462 nbr_revs = svn_rangelist_count_revs(rangelist);
464 if (nbr_revs != 5)
465 return fail(pool, "expecting 5 revs in count, found %d", nbr_revs);
467 return SVN_NO_ERROR;
470 static svn_error_t *
471 test_rangelist_to_revs(const char **msg,
472 svn_boolean_t msg_only,
473 svn_test_opts_t *opts,
474 apr_pool_t *pool)
476 apr_array_header_t *revs, *rangelist;
477 svn_revnum_t expected_revs[] = {3, 5, 6, 7, 10};
478 int i;
480 *msg = "returning revs in rangelist";
481 if (msg_only)
482 return SVN_NO_ERROR;
484 SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 3,5-7,10", pool));
485 rangelist = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
487 SVN_ERR(svn_rangelist_to_revs(&revs, rangelist, pool));
489 for (i = 0; i < revs->nelts; i++)
491 svn_revnum_t rev = APR_ARRAY_IDX(revs, i, svn_revnum_t);
493 if (rev != expected_revs[i])
494 return fail(pool, "rev mis-match at position %d: expecting %d, "
495 "found %d", i, expected_revs[i], rev);
498 return SVN_NO_ERROR;
501 static svn_error_t *
502 test_rangelist_intersect(const char **msg,
503 svn_boolean_t msg_only,
504 svn_test_opts_t *opts,
505 apr_pool_t *pool)
507 apr_array_header_t *rangelist1, *rangelist2, *intersection;
508 svn_merge_range_t expected_intersection[] =
509 { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE}, {30, 32, TRUE},
510 {39, 42, TRUE} };
512 *msg = "intersection of rangelists";
513 if (msg_only)
514 return SVN_NO_ERROR;
516 SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16,30-32,40-42", pool));
517 SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4,7,9,11-12,31-34,38-44",
518 pool));
519 rangelist1 = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
520 rangelist2 = apr_hash_get(info2, "/trunk", APR_HASH_KEY_STRING);
522 SVN_ERR(svn_rangelist_intersect(&intersection, rangelist1, rangelist2,
523 pool));
525 return verify_ranges_match(intersection, expected_intersection, 5,
526 "svn_rangelist_intersect", "intersect", pool);
529 static svn_error_t *
530 test_mergeinfo_intersect(const char **msg,
531 svn_boolean_t msg_only,
532 svn_test_opts_t *opts,
533 apr_pool_t *pool)
535 svn_merge_range_t expected_intersection[3] =
536 { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE} };
537 apr_array_header_t *rangelist;
538 apr_hash_t *intersection;
540 *msg = "intersection of mergeinfo";
541 if (msg_only)
542 return SVN_NO_ERROR;
544 SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16\n/foo: 31", pool));
545 SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4,7,9,11-12", pool));
547 SVN_ERR(svn_mergeinfo_intersect(&intersection, info1, info2, pool));
548 if (apr_hash_count(intersection) != 1)
549 return fail(pool, "Unexpected number of rangelists in mergeinfo "
550 "intersection: Expected %d, found %d", 1,
551 apr_hash_count(intersection));
553 rangelist = apr_hash_get(intersection, "/trunk", APR_HASH_KEY_STRING);
554 return verify_ranges_match(rangelist, expected_intersection, 3,
555 "svn_rangelist_intersect", "intersect", pool);
558 static svn_error_t *
559 test_merge_mergeinfo(const char **msg,
560 svn_boolean_t msg_only,
561 svn_test_opts_t *opts,
562 apr_pool_t *pool)
564 int i;
565 svn_stringbuf_t *output;
567 /* Structures and constants for test_merge_mergeinfo() */
568 /* Number of svn_mergeinfo_merge test sets */
569 #define NBR_MERGEINFO_MERGES 12
571 /* Maximum number of expected paths in the results
572 of the svn_mergeinfo_merge tests */
573 #define MAX_NBR_MERGEINFO_PATHS 4
575 /* Maximum number of expected ranges in the results
576 of the svn_mergeinfo_merge tests */
577 #define MAX_NBR_MERGEINFO_RANGES 10
579 /* Struct to store a path and it's expected ranges,
580 i.e. the expected result of an svn_mergeinfo_merge
581 test. */
582 struct mergeinfo_merge_path_range
584 const char *path;
585 svn_merge_range_t expected_rngs[MAX_NBR_MERGEINFO_RANGES];
588 /* Struct for svn_mergeinfo_merge test data.
589 If MERGEINFO1 and MERGEINFO2 are parsed to a hash with
590 svn_mergeinfo_parse() and then merged with svn_mergeinfo_merge(),
591 the resulting hash should have EXPECTED_PATHS number of paths
592 mapped to rangelists and each mapping is described by PATH_RNGS
593 where PATH_RNGS->PATH is not NULL. */
594 struct mergeinfo_merge_test_data
596 const char *mergeinfo1;
597 const char *mergeinfo2;
598 int expected_paths;
599 struct mergeinfo_merge_path_range path_rngs[MAX_NBR_MERGEINFO_PATHS];
602 static struct mergeinfo_merge_test_data mergeinfo[NBR_MERGEINFO_MERGES] =
604 /* One path, intersecting inheritable ranges */
605 { "/trunk: 5-10",
606 "/trunk: 6", 1,
607 { {"/trunk", { {4, 10, TRUE} } } } },
609 /* One path, intersecting non-inheritable ranges */
610 { "/trunk: 5-10*",
611 "/trunk: 6*", 1,
612 { {"/trunk", { {4, 10, FALSE} } } } },
614 /* One path, intersecting ranges with different inheritability */
615 { "/trunk: 5-10",
616 "/trunk: 6*", 1,
617 { {"/trunk", { {4, 10, TRUE} } } } },
619 /* One path, intersecting ranges with different inheritability */
620 { "/trunk: 5-10*",
621 "/trunk: 6", 1,
622 { {"/trunk", { {4, 5, FALSE}, {5, 6, TRUE}, {6, 10, FALSE} } } } },
624 /* Adjacent ranges all inheritable ranges */
625 { "/trunk: 1,3,5-11,13",
626 "/trunk: 2,4,12,14-22", 1,
627 { {"/trunk", { {0, 22, TRUE} } } } },
629 /* Adjacent ranges all non-inheritable ranges */
630 { "/trunk: 1*,3*,5-11*,13*",
631 "/trunk: 2*,4*,12*,14-22*", 1,
632 { {"/trunk", { {0, 22, FALSE} } } } },
634 /* Adjacent ranges differing inheritability */
635 { "/trunk: 1*,3*,5-11*,13*",
636 "/trunk: 2,4,12,14-22", 1,
637 { {"/trunk", { { 0, 1, FALSE}, { 1, 2, TRUE},
638 { 2, 3, FALSE}, { 3, 4, TRUE},
639 { 4, 11, FALSE}, {11, 12, TRUE},
640 {12, 13, FALSE}, {13, 22, TRUE} } } } },
642 /* Adjacent ranges differing inheritability */
643 { "/trunk: 1,3,5-11,13",
644 "/trunk: 2*,4*,12*,14-22*", 1,
645 { {"/trunk", { { 0, 1, TRUE}, { 1, 2, FALSE},
646 { 2, 3, TRUE}, { 3, 4, FALSE},
647 { 4, 11, TRUE}, {11, 12, FALSE},
648 {12, 13, TRUE}, {13, 22, FALSE} } } } },
650 /* Two paths all inheritable ranges */
651 { "/trunk: 3,5,7-9,10,11,13,14\n/fred:8-10",
652 "/trunk: 1-4,6\n/fred:9-12", 2,
653 { {"/trunk", { {0, 11, TRUE}, {12, 14, TRUE} } },
654 {"/fred", { {7, 12, TRUE} } } } },
656 /* Two paths all non-inheritable ranges */
657 { "/trunk: 3*,5*,7-9*,10*,11*,13*,14*\n/fred:8-10*",
658 "/trunk: 1-4*,6*\n/fred:9-12*", 2,
659 { {"/trunk", { {0, 11, FALSE}, {12, 14, FALSE} } },
660 {"/fred", { {7, 12, FALSE} } } } },
662 /* Two paths mixed inheritability */
663 { "/trunk: 3,5*,7-9,10,11*,13,14\n/fred:8-10",
664 "/trunk: 1-4,6\n/fred:9-12*", 2,
665 { {"/trunk", { { 0, 4, TRUE }, { 4, 5, FALSE}, {5, 10, TRUE},
666 {10, 11, FALSE}, {12, 14, TRUE } } },
667 {"/fred", { { 7, 10, TRUE }, {10, 12, FALSE} } } } },
669 /* A slew of different paths but no ranges to be merged */
670 { "/trunk: 3,5-9*\n/betty: 2-4",
671 "/fred: 1-18\n/barney: 1,3-43", 4,
672 { {"/trunk", { {2, 3, TRUE}, {4, 9, FALSE} } },
673 {"/betty", { {1, 4, TRUE} } },
674 {"/barney", { {0, 1, TRUE}, {2, 43, TRUE} } },
675 {"/fred", { {0, 18, TRUE} } } } }
678 *msg = "merging of mergeinfo hashs";
679 if (msg_only)
680 return SVN_NO_ERROR;
682 for (i = 0; i < NBR_MERGEINFO_MERGES; i++)
684 int j;
685 SVN_ERR(svn_mergeinfo_parse(&info1, mergeinfo[i].mergeinfo1, pool));
686 SVN_ERR(svn_mergeinfo_parse(&info2, mergeinfo[i].mergeinfo2, pool));
687 SVN_ERR(svn_mergeinfo_merge(info1, info2, pool));
688 SVN_ERR(svn_mergeinfo_to_stringbuf(&output, info1, pool));
689 if (mergeinfo[i].expected_paths != apr_hash_count(info1))
690 return fail(pool, "Wrong number of paths in merged mergeinfo");
691 for (j = 0; j < mergeinfo[i].expected_paths; j++)
693 int k;
694 apr_array_header_t *rangelist =
695 apr_hash_get(info1, mergeinfo[i].path_rngs[j].path,
696 APR_HASH_KEY_STRING);
697 if (!rangelist)
698 return fail(pool, "Missing path '%s' in merged mergeinfo",
699 mergeinfo[i].path_rngs->path);
700 for (k = 0; k < rangelist->nelts; k++)
702 svn_merge_range_t *ranges =
703 APR_ARRAY_IDX(rangelist, k, svn_merge_range_t *);
704 if (ranges->start
705 != mergeinfo[i].path_rngs[j].expected_rngs[k].start
706 || ranges->end
707 != mergeinfo[i].path_rngs[j].expected_rngs[k].end
708 || ranges->inheritable
709 != mergeinfo[i].path_rngs[j].expected_rngs[k].inheritable)
710 return fail(
711 pool,
712 "Range'%i-%i%s' not found in merged mergeinfo",
713 mergeinfo[i].path_rngs->expected_rngs[k].start,
714 mergeinfo[i].path_rngs->expected_rngs[k].end,
715 mergeinfo[i].path_rngs->expected_rngs[k].inheritable
716 ? "" : "*");
718 /* Were more ranges expected? */
719 if (k < MAX_NBR_MERGEINFO_RANGES
720 && mergeinfo[i].path_rngs[j].expected_rngs[k].start != 0)
721 return fail(pool,
722 "Not all expected ranges found in merged mergeinfo");
726 return SVN_NO_ERROR;
729 static svn_error_t *
730 test_remove_rangelist(const char **msg,
731 svn_boolean_t msg_only,
732 svn_test_opts_t *opts,
733 apr_pool_t *pool)
735 int i, j;
736 svn_error_t *err, *child_err;
737 apr_array_header_t *output, *eraser, *whiteboard;
739 /* Struct for svn_rangelist_remove test data.
740 Parse WHITEBOARD and ERASER to hashes and then get the rangelist for
741 path 'A' from both.
743 Remove ERASER's rangelist from WHITEBOARD's twice, once while
744 considering inheritance and once while not. In the first case the
745 resulting rangelist should have EXPECTED_RANGES_CONSIDER_INHERITANCE
746 number of ranges and these ranges should match the ranges in
747 EXPECTED_REMOVED_CONSIDER_INHERITANCE. In the second case there
748 should be EXPECTED_RANGES_IGNORE_INHERITANCE number of ranges and
749 these should match EXPECTED_REMOVED_IGNORE_INHERITANCE */
750 struct rangelist_remove_test_data
752 const char *whiteboard;
753 const char *eraser;
754 int expected_ranges_consider_inheritance;
755 svn_merge_range_t expected_removed_consider_inheritance[10];
756 int expected_ranges_ignore_inheritance;
757 svn_merge_range_t expected_removed_ignore_inheritance[10];
760 #define SIZE_OF_RANGE_REMOVE_TEST_ARRAY 15
762 /* The actual test data */
763 struct rangelist_remove_test_data test_data[SIZE_OF_RANGE_REMOVE_TEST_ARRAY] =
765 /* Eraser is a proper subset of whiteboard */
766 {"/A: 1-44", "/A: 5", 2, { {0, 4, TRUE }, {5, 44, TRUE }},
767 2, { {0, 4, TRUE }, {5, 44, TRUE }}},
768 {"/A: 1-44*", "/A: 5", 1, { {0, 44, FALSE} },
769 2, { {0, 4, FALSE}, {5, 44, FALSE}}},
770 {"/A: 1-44", "/A: 5*", 1, { {0, 44, TRUE } },
771 2, { {0, 4, TRUE }, {5, 44, TRUE }}},
772 {"/A: 1-44*", "/A: 5*", 2, { {0, 4, FALSE}, {5, 44, FALSE}},
773 2, { {0, 4, FALSE}, {5, 44, FALSE}}},
774 /* Non-intersecting ranges...nothing is removed */
775 {"/A: 2-9,14-19", "/A: 12", 2, { {1, 9, TRUE }, {13, 19, TRUE }},
776 2, { {1, 9, TRUE }, {13, 19, TRUE }}},
777 {"/A: 2-9*,14-19*", "/A: 12", 2, { {1, 9, FALSE}, {13, 19, FALSE}},
778 2, { {1, 9, FALSE}, {13, 19, FALSE}}},
779 {"/A: 2-9,14-19", "/A: 12*", 2, { {1, 9, TRUE }, {13, 19, TRUE }},
780 2, { {1, 9, TRUE }, {13, 19, TRUE }}},
781 {"/A: 2-9*,14-19*", "/A: 12*", 2, { {1, 9, FALSE}, {13, 19, FALSE}},
782 2, { {1, 9, FALSE}, {13, 19, FALSE}}},
783 /* Eraser overlaps whiteboard */
784 {"/A: 1,9-17", "/A: 12-20", 2, { {0, 1, TRUE }, {8, 11, TRUE }},
785 2, { {0, 1, TRUE }, {8, 11, TRUE }}},
786 {"/A: 1,9-17*", "/A: 12-20", 2, { {0, 1, TRUE }, {8, 17, FALSE}},
787 2, { {0, 1, TRUE }, {8, 11, FALSE}}},
788 {"/A: 1,9-17", "/A: 12-20*", 2, { {0, 1, TRUE }, {8, 17, TRUE }},
789 2, { {0, 1, TRUE }, {8, 11, TRUE }}},
790 {"/A: 1,9-17*", "/A: 12-20*", 2, { {0, 1, TRUE }, {8, 11, FALSE}},
791 2, { {0, 1, TRUE }, {8, 11, FALSE}}},
792 /* Empty mergeinfo (i.e. empty rangelist) */
793 {"", "", 0, { {0, 0, FALSE}},
794 0, { {0, 0, FALSE}}},
795 {"", "/A: 5-8,10-100", 0, { {0, 0, FALSE}},
796 0, { {0, 0, FALSE}}},
797 {"/A: 5-8,10-100", "", 2, { {4, 8, TRUE }, {9, 100, TRUE }},
798 2, { {4, 8, TRUE }, {9, 100, TRUE }}}
801 *msg = "remove rangelists";
802 err = child_err = SVN_NO_ERROR;
803 for (j = 0; j < 2; j++)
805 for (i = 0; i < SIZE_OF_RANGE_REMOVE_TEST_ARRAY; i++)
807 int expected_nbr_ranges;
808 svn_merge_range_t *expected_ranges;
810 SVN_ERR(svn_mergeinfo_parse(&info1, (test_data[i]).eraser, pool));
811 SVN_ERR(svn_mergeinfo_parse(&info2, (test_data[i]).whiteboard, pool));
812 eraser = apr_hash_get(info1, "/A", APR_HASH_KEY_STRING);
813 whiteboard = apr_hash_get(info2, "/A", APR_HASH_KEY_STRING);
815 /* Represent empty mergeinfo with an empty rangelist. */
816 if (eraser == NULL)
817 eraser = apr_array_make(pool, 0, sizeof(*eraser));
818 if (whiteboard == NULL)
819 whiteboard = apr_array_make(pool, 0, sizeof(*whiteboard));
821 /* First pass try removal considering inheritance, on the
822 second pass ignore it. */
823 if (j == 0)
825 expected_nbr_ranges = (test_data[i]).expected_ranges_consider_inheritance;
826 expected_ranges = (test_data[i]).expected_removed_consider_inheritance;
829 else
831 expected_nbr_ranges = (test_data[i]).expected_ranges_ignore_inheritance;
832 expected_ranges = (test_data[i]).expected_removed_ignore_inheritance;
835 SVN_ERR(svn_rangelist_remove(&output, eraser, whiteboard,
836 j == 0 ? TRUE : FALSE,
837 pool));
838 child_err = verify_ranges_match(output, expected_ranges,
839 expected_nbr_ranges,
840 apr_psprintf(pool,
841 "svn_rangelist_remove "
842 "case %i", i),
843 "remove", pool);
845 /* Collect all the errors rather than returning on the first. */
846 if (child_err)
848 if (err)
849 svn_error_compose(err, child_err);
850 else
851 err = child_err;
855 return err;
858 /* ### Share code with test_diff_mergeinfo() and test_remove_rangelist(). */
859 static svn_error_t *
860 test_remove_mergeinfo(const char **msg,
861 svn_boolean_t msg_only,
862 svn_test_opts_t *opts,
863 apr_pool_t *pool)
865 apr_hash_t *output, *whiteboard, *eraser;
866 svn_merge_range_t expected_rangelist_remainder[NBR_RANGELIST_DELTAS] =
867 { {6, 7, TRUE}, {8, 9, TRUE}, {10, 11, TRUE}, {32, 34, TRUE} };
869 *msg = "remove of mergeinfo";
870 if (msg_only)
871 return SVN_NO_ERROR;
873 SVN_ERR(svn_mergeinfo_parse(&whiteboard,
874 "/trunk: 1,3-4,7,9,11-12,31-34", pool));
875 SVN_ERR(svn_mergeinfo_parse(&eraser, "/trunk: 1-6,12-16,30-32", pool));
877 /* Leftover on /trunk should be the set (7, 9, 11, 33-34) */
878 SVN_ERR(svn_mergeinfo_remove(&output, eraser, whiteboard, pool));
880 /* Verify calculation of range list remainder. */
881 return verify_mergeinfo_deltas(output, expected_rangelist_remainder,
882 "svn_mergeinfo_remove", "leftover", pool);
884 #undef NBR_RANGELIST_DELTAS
886 static svn_error_t *
887 test_rangelist_to_string(const char **msg,
888 svn_boolean_t msg_only,
889 svn_test_opts_t *opts,
890 apr_pool_t *pool)
892 apr_array_header_t *result;
893 svn_stringbuf_t *output;
894 svn_stringbuf_t *expected = svn_stringbuf_create("3,5,7-11,13-14", pool);
896 *msg = "turning rangelist back into a string";
898 if (msg_only)
899 return SVN_NO_ERROR;
901 SVN_ERR(svn_mergeinfo_parse(&info1, mergeinfo1, pool));
903 result = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
904 if (!result)
905 return fail(pool, "Missing path in parsed mergeinfo");
907 SVN_ERR(svn_rangelist_to_stringbuf(&output, result, pool));
909 if (svn_stringbuf_compare(expected, output) != TRUE)
910 return fail(pool, "Rangelist string not what we expected");
912 return SVN_NO_ERROR;
915 static svn_error_t *
916 test_mergeinfo_to_string(const char **msg,
917 svn_boolean_t msg_only,
918 svn_test_opts_t *opts,
919 apr_pool_t *pool)
921 svn_string_t *output;
922 svn_string_t *expected;
923 expected = svn_string_create("/fred:8-10\n/trunk:3,5,7-11,13-14", pool);
925 *msg = "turning mergeinfo back into a string";
927 if (msg_only)
928 return SVN_NO_ERROR;
930 SVN_ERR(svn_mergeinfo_parse(&info1, mergeinfo1, pool));
932 SVN_ERR(svn_mergeinfo__to_string(&output, info1, pool));
934 if (svn_string_compare(expected, output) != TRUE)
935 return fail(pool, "Mergeinfo string not what we expected");
937 return SVN_NO_ERROR;
940 static svn_error_t *
941 test_range_compact(const char **msg,
942 svn_boolean_t msg_only,
943 svn_test_opts_t *opts,
944 apr_pool_t *pool)
946 #define SIZE_OF_TEST_ARRAY 44
947 svn_merge_range_t rangelist[SIZE_OF_TEST_ARRAY][4] =
948 /* For each ith element of rangelist[][], try to combine/compact
949 rangelist[i][0] and rangelist[i][1]. If the combined ranges can
950 be combined, then the expected range is rangelist[i][2] and
951 rangelist[i][3] is {-1, -1, TRUE}. If the ranges cancel each
952 other out, then both rangelist[i][2] and rangelist[i][3] are
953 {-1, -1, TRUE}.
954 range1 + range2 = range3 , range4 */
955 { /* Non-intersecting ranges */
956 { { 2, 4, TRUE}, { 6, 13, TRUE}, { 2, 4, TRUE}, { 6, 13, TRUE} },
957 { { 4, 2, TRUE}, { 6, 13, TRUE}, { 4, 2, TRUE}, { 6, 13, TRUE} },
958 { { 4, 2, TRUE}, {13, 6, TRUE}, { 4, 2, TRUE}, {13, 6, TRUE} },
959 { { 2, 4, TRUE}, {13, 6, TRUE}, { 2, 4, TRUE}, {13, 6, TRUE} },
960 { { 6, 13, TRUE}, { 2, 4, TRUE}, { 6, 13, TRUE}, { 2, 4, TRUE} },
961 { { 6, 13, TRUE}, { 4, 2, TRUE}, { 6, 13, TRUE}, { 4, 2, TRUE} },
962 { {13, 6, TRUE}, { 4, 2, TRUE}, {13, 6, TRUE}, { 4, 2, TRUE} },
963 { {13, 6, TRUE}, { 2, 4, TRUE}, {13, 6, TRUE}, { 2, 4, TRUE} },
964 /* Intersecting ranges with no common start or end points */
965 { { 2, 5, TRUE}, { 4, 6, TRUE}, { 2, 6, TRUE}, {-1, -1, TRUE} },
966 { { 2, 5, TRUE}, { 6, 4, TRUE}, { 2, 4, TRUE}, { 6, 5, TRUE} },
967 { { 5, 2, TRUE}, { 4, 6, TRUE}, { 4, 2, TRUE}, { 5, 6, TRUE} },
968 { { 5, 2, TRUE}, { 6, 4, TRUE}, { 6, 2, TRUE}, {-1, -1, TRUE} },
969 { { 4, 6, TRUE}, { 2, 5, TRUE}, { 2, 6, TRUE}, {-1, -1, TRUE} },
970 { { 6, 4, TRUE}, { 2, 5, TRUE}, { 6, 5, TRUE}, { 2, 4, TRUE} },
971 { { 4, 6, TRUE}, { 5, 2, TRUE}, { 5, 6, TRUE}, { 4, 2, TRUE} },
972 { { 6, 4, TRUE}, { 5, 2, TRUE}, { 6, 2, TRUE}, {-1, -1, TRUE} },
973 /* One range is a proper subset of the other. */
974 { {33, 43, TRUE}, {37, 38, TRUE}, {33, 43, TRUE}, {-1, -1, TRUE} },
975 { {33, 43, TRUE}, {38, 37, TRUE}, {33, 37, TRUE}, {38, 43, TRUE} },
976 { {43, 33, TRUE}, {37, 38, TRUE}, {37, 33, TRUE}, {43, 38, TRUE} },
977 { {43, 33, TRUE}, {38, 37, TRUE}, {43, 33, TRUE}, {-1, -1, TRUE} },
978 { {37, 38, TRUE}, {33, 43, TRUE}, {33, 43, TRUE}, {-1, -1, TRUE} },
979 { {38, 37, TRUE}, {33, 43, TRUE}, {33, 37, TRUE}, {38, 43, TRUE} },
980 { {37, 38, TRUE}, {43, 33, TRUE}, {37, 33, TRUE}, {43, 38, TRUE} },
981 { {38, 37, TRUE}, {43, 33, TRUE}, {43, 33, TRUE}, {-1, -1, TRUE} },
982 /* Intersecting ranges share same start and end points */
983 { { 4, 20, TRUE}, { 4, 20, TRUE}, { 4, 20, TRUE}, {-1, -1, TRUE} },
984 { { 4, 20, TRUE}, {20, 4, TRUE}, {-1, -1, TRUE}, {-1, -1, TRUE} },
985 { {20, 4, TRUE}, { 4, 20, TRUE}, {-1, -1, TRUE}, {-1, -1, TRUE} },
986 { {20, 4, TRUE}, {20, 4, TRUE}, {20, 4, TRUE}, {-1, -1, TRUE} },
987 /* Intersecting ranges share same start point */
988 { { 7, 13, TRUE}, { 7, 19, TRUE}, { 7, 19, TRUE}, {-1, -1, TRUE} },
989 { { 7, 13, TRUE}, {19, 7, TRUE}, {19, 13, TRUE}, {-1, -1, TRUE} },
990 { {13, 7, TRUE}, {7, 19, TRUE}, {13, 19, TRUE}, {-1, -1, TRUE} },
991 { {13, 7, TRUE}, {19, 7, TRUE}, {19, 7, TRUE}, {-1, -1, TRUE} },
992 { { 7, 19, TRUE}, { 7, 13, TRUE}, { 7, 19, TRUE}, {-1, -1, TRUE} },
993 { {19, 7, TRUE}, { 7, 13, TRUE}, {19, 13, TRUE}, {-1, -1, TRUE} },
994 { { 7, 19, TRUE}, {13, 7, TRUE}, {13, 19, TRUE}, {-1, -1, TRUE} },
995 { {19, 7, TRUE}, {13, 7, TRUE}, {19, 7, TRUE}, {-1, -1, TRUE} },
996 /* Intersecting ranges share same end point */
997 { {12, 23, TRUE}, {18, 23, TRUE}, {12, 23, TRUE}, {-1, -1, TRUE} },
998 { {12, 23, TRUE}, {23, 18, TRUE}, {12, 18, TRUE}, {-1, -1, TRUE} },
999 { {23, 12, TRUE}, {18, 23, TRUE}, {18, 12, TRUE}, {-1, -1, TRUE} },
1000 { {23, 12, TRUE}, {23, 18, TRUE}, {23, 12, TRUE}, {-1, -1, TRUE} },
1001 { {18, 23, TRUE}, {12, 23, TRUE}, {12, 23, TRUE}, {-1, -1, TRUE} },
1002 { {23, 18, TRUE}, {12, 23, TRUE}, {12, 18, TRUE}, {-1, -1, TRUE} },
1003 { {18, 23, TRUE}, {23, 12, TRUE}, {18, 12, TRUE}, {-1, -1, TRUE} },
1004 { {23, 18, TRUE}, {23, 12, TRUE}, {23, 12, TRUE}, {-1, -1, TRUE} } };
1005 int i;
1007 *msg = "combination of ranges";
1008 if (msg_only)
1009 return SVN_NO_ERROR;
1011 for (i = 0; i < SIZE_OF_TEST_ARRAY; i++)
1013 svn_merge_range_t *r1 = apr_palloc(pool, sizeof(*r1));
1014 svn_merge_range_t *r2 = apr_palloc(pool, sizeof(*r2));
1015 svn_merge_range_t *r1_expected = &(rangelist[i][2]);
1016 svn_merge_range_t *r2_expected = &(rangelist[i][3]);
1018 r1->start = rangelist[i][0].start;
1019 r1->end = rangelist[i][0].end;
1020 r1->inheritable = TRUE;
1022 r2->start = rangelist[i][1].start;
1023 r2->end = rangelist[i][1].end;
1024 r2->inheritable = TRUE;
1026 svn_range_compact(&r1, &r2);
1027 if (!(((!r1 && r1_expected->start == -1
1028 && r1_expected->end == -1)
1029 || (r1 && (r1->start == r1_expected->start
1030 && r1->end == r1_expected->end)))
1031 && ((!r2 && r2_expected->start == -1
1032 && r2_expected->end == -1)
1033 || (r2 && (r2->start == r2_expected->start
1034 && r2->end == r2_expected->end)))))
1036 const char *fail_msg = "svn_range_compact() should combine ranges ";
1037 fail_msg = apr_pstrcat(pool, fail_msg,
1038 apr_psprintf(pool, "(%ld-%ld),(%ld-%ld) "
1039 "into ",
1040 rangelist[i][0].start,
1041 rangelist[i][0].end,
1042 rangelist[i][1].start,
1043 rangelist[i][1].end), NULL);
1044 if (r1_expected->start == -1)
1045 fail_msg = apr_pstrcat(pool, fail_msg, "(NULL),",NULL);
1046 else
1047 fail_msg = apr_pstrcat(pool, fail_msg,
1048 apr_psprintf(pool, "(%ld-%ld),",
1049 r1_expected->start,
1050 r1_expected->end), NULL);
1051 if (r2_expected->start == -1)
1052 fail_msg = apr_pstrcat(pool, fail_msg, "(NULL) ",NULL);
1053 else
1054 fail_msg = apr_pstrcat(pool, fail_msg,
1055 apr_psprintf(pool, "(%ld-%ld) ",
1056 r2_expected->start,
1057 r2_expected->end), NULL);
1058 fail_msg = apr_pstrcat(pool, fail_msg, "but instead resulted in ",
1059 NULL);
1060 if (r1)
1061 fail_msg = apr_pstrcat(pool, fail_msg,
1062 apr_psprintf(pool, "(%ld-%ld),",
1063 r1->start, r1->end), NULL);
1064 else
1065 fail_msg = apr_pstrcat(pool, fail_msg, "(NULL),",NULL);
1066 if (r2)
1067 fail_msg = apr_pstrcat(pool, fail_msg,
1068 apr_psprintf(pool, "(%ld-%ld),",
1069 r2->start, r2->end), NULL);
1070 else
1071 fail_msg = apr_pstrcat(pool, fail_msg, "(NULL)",NULL);
1073 return fail(pool, fail_msg);
1076 return SVN_NO_ERROR;
1079 static svn_error_t *
1080 test_rangelist_merge(const char **msg,
1081 svn_boolean_t msg_only,
1082 svn_test_opts_t *opts,
1083 apr_pool_t *pool)
1085 int i;
1086 svn_error_t *err, *child_err;
1087 apr_array_header_t *rangelist1, *rangelist2;
1089 /* Struct for svn_rangelist_merge test data. Similar to
1090 mergeinfo_merge_test_data struct in svn_mergeinfo_merge() test. */
1091 struct rangelist_merge_test_data
1093 const char *mergeinfo1;
1094 const char *mergeinfo2;
1095 int expected_ranges;
1096 svn_merge_range_t expected_merge[6];
1099 #define SIZE_OF_RANGE_MERGE_TEST_ARRAY 52
1100 /* The actual test data. */
1101 struct rangelist_merge_test_data test_data[SIZE_OF_RANGE_MERGE_TEST_ARRAY] =
1103 /* Non-intersecting ranges */
1104 {"/A: 1-44", "/A: 70-101", 2, {{ 0, 44, TRUE }, {69, 101, TRUE }}},
1105 {"/A: 1-44*", "/A: 70-101", 2, {{ 0, 44, FALSE}, {69, 101, TRUE }}},
1106 {"/A: 1-44", "/A: 70-101*", 2, {{ 0, 44, TRUE }, {69, 101, FALSE}}},
1107 {"/A: 1-44*", "/A: 70-101*", 2, {{ 0, 44, FALSE}, {69, 101, FALSE}}},
1108 {"/A: 70-101", "/A: 1-44", 2, {{ 0, 44, TRUE }, {69, 101, TRUE }}},
1109 {"/A: 70-101*", "/A: 1-44", 2, {{ 0, 44, TRUE }, {69, 101, FALSE}}},
1110 {"/A: 70-101", "/A: 1-44*", 2, {{ 0, 44, FALSE}, {69, 101, TRUE }}},
1111 {"/A: 70-101*", "/A: 1-44*", 2, {{ 0, 44, FALSE}, {69, 101, FALSE}}},
1113 /* Intersecting ranges with same starting and ending revisions */
1114 {"/A: 4-20", "/A: 4-20", 1, {{3, 20, TRUE }}},
1115 {"/A: 4-20*", "/A: 4-20", 1, {{3, 20, TRUE }}},
1116 {"/A: 4-20", "/A: 4-20*", 1, {{3, 20, TRUE }}},
1117 {"/A: 4-20*", "/A: 4-20*", 1, {{3, 20, FALSE}}},
1119 /* Intersecting ranges with same starting revision */
1120 {"/A: 6-17", "/A: 6-12", 1, {{5, 17, TRUE}}},
1121 {"/A: 6-17*", "/A: 6-12", 2, {{5, 12, TRUE }, {12, 17, FALSE}}},
1122 {"/A: 6-17", "/A: 6-12*", 1, {{5, 17, TRUE }}},
1123 {"/A: 6-17*", "/A: 6-12*", 1, {{5, 17, FALSE}}},
1124 {"/A: 6-12", "/A: 6-17", 1, {{5, 17, TRUE }}},
1125 {"/A: 6-12*", "/A: 6-17", 1, {{5, 17, TRUE }}},
1126 {"/A: 6-12", "/A: 6-17*", 2, {{5, 12, TRUE }, {12, 17, FALSE}}},
1127 {"/A: 6-12*", "/A: 6-17*", 1, {{5, 17, FALSE}}},
1129 /* Intersecting ranges with same ending revision */
1130 {"/A: 5-77", "/A: 44-77", 1, {{4, 77, TRUE }}},
1131 {"/A: 5-77*", "/A: 44-77", 2, {{4, 43, FALSE}, {43, 77, TRUE}}},
1132 {"/A: 5-77", "/A: 44-77*", 1, {{4, 77, TRUE }}},
1133 {"/A: 5-77*", "/A: 44-77*", 1, {{4, 77, FALSE}}},
1134 {"/A: 44-77", "/A: 5-77", 1, {{4, 77, TRUE }}},
1135 {"/A: 44-77*", "/A: 5-77", 1, {{4, 77, TRUE }}},
1136 {"/A: 44-77", "/A: 5-77*", 2, {{4, 43, FALSE}, {43, 77, TRUE}}},
1137 {"/A: 44-77*", "/A: 5-77*", 1, {{4, 77, FALSE}}},
1139 /* Intersecting ranges with different starting and ending revision
1140 where one range is a proper subset of the other. */
1141 {"/A: 12-24", "/A: 20-23", 1, {{11, 24, TRUE }}},
1142 {"/A: 12-24*", "/A: 20-23", 3, {{11, 19, FALSE}, {19, 23, TRUE },
1143 {23, 24, FALSE}}},
1144 {"/A: 12-24", "/A: 20-23*", 1, {{11, 24, TRUE }}},
1145 {"/A: 12-24*", "/A: 20-23*", 1, {{11, 24, FALSE}}},
1146 {"/A: 20-23", "/A: 12-24", 1, {{11, 24, TRUE }}},
1147 {"/A: 20-23*", "/A: 12-24", 1, {{11, 24, TRUE }}},
1148 {"/A: 20-23", "/A: 12-24*", 3, {{11, 19, FALSE}, {19, 23, TRUE },
1149 {23, 24, FALSE}}},
1150 {"/A: 20-23*", "/A: 12-24*", 1, {{11, 24, FALSE}}},
1152 /* Intersecting ranges with different starting and ending revision
1153 where neither range is a proper subset of the other. */
1154 {"/A: 50-73", "/A: 60-99", 1, {{49, 99, TRUE }}},
1155 {"/A: 50-73*", "/A: 60-99", 2, {{49, 59, FALSE}, {59, 99, TRUE }}},
1156 {"/A: 50-73", "/A: 60-99*", 2, {{49, 73, TRUE }, {73, 99, FALSE}}},
1157 {"/A: 50-73*", "/A: 60-99*", 1, {{49, 99, FALSE}}},
1158 {"/A: 60-99", "/A: 50-73", 1, {{49, 99, TRUE }}},
1159 {"/A: 60-99*", "/A: 50-73", 2, {{49, 73, TRUE }, {73, 99, FALSE}}},
1160 {"/A: 60-99", "/A: 50-73*", 2, {{49, 59, FALSE}, {59, 99, TRUE }}},
1161 {"/A: 60-99*", "/A: 50-73*", 1, {{49, 99, FALSE}}},
1163 /* Multiple ranges. */
1164 {"/A: 1-5,7,12-13", "/A: 2-17", 1, {{0, 17, TRUE }}},
1165 {"/A: 1-5*,7*,12-13*", "/A: 2-17*", 1, {{0, 17, FALSE}}},
1167 {"/A: 1-5,7,12-13", "/A: 2-17*", 6,
1168 {{0, 5, TRUE }, { 5, 6, FALSE}, { 6, 7, TRUE },
1169 {7, 11, FALSE}, {11, 13, TRUE }, {13, 17, FALSE}}},
1171 {"/A: 1-5*,7*,12-13*", "/A: 2-17", 2,
1172 {{0, 1, FALSE}, {1, 17, TRUE }}},
1174 {"/A: 2-17", "/A: 1-5,7,12-13", 1, {{0, 17, TRUE }}},
1175 {"/A: 2-17*", "/A: 1-5*,7*,12-13*", 1, {{0, 17, FALSE}}},
1177 {"/A: 2-17*", "/A: 1-5,7,12-13", 6,
1178 {{0, 5, TRUE }, { 5, 6, FALSE}, { 6, 7, TRUE },
1179 {7, 11, FALSE}, {11, 13, TRUE }, {13, 17, FALSE}}},
1181 {"/A: 2-17", "/A: 1-5*,7*,12-13*", 2,
1182 {{0, 1, FALSE}, {1, 17, TRUE}}},
1184 *msg = "merge of rangelists";
1185 if (msg_only)
1186 return SVN_NO_ERROR;
1188 err = child_err = SVN_NO_ERROR;
1189 for (i = 0; i < SIZE_OF_RANGE_MERGE_TEST_ARRAY; i++)
1191 SVN_ERR(svn_mergeinfo_parse(&info1, (test_data[i]).mergeinfo1, pool));
1192 SVN_ERR(svn_mergeinfo_parse(&info2, (test_data[i]).mergeinfo2, pool));
1193 rangelist1 = apr_hash_get(info1, "/A", APR_HASH_KEY_STRING);
1194 rangelist2 = apr_hash_get(info2, "/A", APR_HASH_KEY_STRING);
1195 SVN_ERR(svn_rangelist_merge(&rangelist1, rangelist2, pool));
1196 child_err = verify_ranges_match(rangelist1,
1197 (test_data[i]).expected_merge,
1198 (test_data[i]).expected_ranges,
1199 apr_psprintf(pool,
1200 "svn_rangelist_merge "
1201 "case %i", i),
1202 "merge", pool);
1204 /* Collect all the errors rather than returning on the first. */
1205 if (child_err)
1207 if (err)
1208 svn_error_compose(err, child_err);
1209 else
1210 err = child_err;
1213 return err;
1216 static svn_error_t *
1217 test_rangelist_diff(const char **msg,
1218 svn_boolean_t msg_only,
1219 svn_test_opts_t *opts,
1220 apr_pool_t *pool)
1222 int i;
1223 svn_error_t *err, *child_err;
1224 apr_array_header_t *from, *to, *added, *deleted;
1226 /* Structure containing two ranges to diff and the expected output of the
1227 diff both when considering and ignoring range inheritance. */
1228 struct rangelist_diff_test_data
1230 /* svn:mergeinfo string representations */
1231 const char *from;
1232 const char *to;
1234 /* Expected results for performing svn_rangelist_diff
1235 while considering differences in inheritability to be real
1236 differences. */
1237 int expected_add_ranges;
1238 svn_merge_range_t expected_adds[10];
1239 int expected_del_ranges;
1240 svn_merge_range_t expected_dels[10];
1242 /* Expected results for performing svn_rangelist_diff
1243 while ignoring differences in inheritability. */
1244 int expected_add_ranges_ignore_inheritance;
1245 svn_merge_range_t expected_adds_ignore_inheritance[10];
1246 int expected_del_ranges_ignore_inheritance;
1247 svn_merge_range_t expected_dels_ignore_inheritance[10];
1250 #define SIZE_OF_RANGE_DIFF_TEST_ARRAY 16
1251 /* The actual test data array.
1253 'from' --> {"/A: 1,5-8", "/A: 1,6,10-12", <-- 'to'
1254 Number of adds when --> 1, { { 9, 12, TRUE } },
1255 considering inheritance
1257 Number of dels when --> 2, { { 4, 5, TRUE }, { 6, 8, TRUE } },
1258 considering inheritance
1260 Number of adds when --> 1, { { 9, 12, TRUE } },
1261 ignoring inheritance
1263 Number of dels when --> 2, { { 4, 5, TRUE }, { 6, 8, TRUE } } },
1264 ignoring inheritance
1266 The expected svn_merge_range_t's
1268 struct rangelist_diff_test_data test_data[SIZE_OF_RANGE_DIFF_TEST_ARRAY] =
1270 /* Add and Delete */
1271 {"/A: 1", "/A: 3",
1272 1, { { 2, 3, TRUE } },
1273 1, { { 0, 1, TRUE } },
1274 1, { { 2, 3, TRUE } },
1275 1, { { 0, 1, TRUE } } },
1277 /* Add only */
1278 {"/A: 1", "/A: 1,3",
1279 1, { { 2, 3, TRUE } },
1280 0, { { 0, 0, FALSE } },
1281 1, { { 2, 3, TRUE } },
1282 0, { { 0, 0, FALSE } } },
1284 /* Delete only */
1285 {"/A: 1,3", "/A: 1",
1286 0, { { 0, 0, FALSE } },
1287 1, { { 2, 3, TRUE } },
1288 0, { { 0, 0, FALSE } },
1289 1, { { 2, 3, TRUE } } },
1291 /* No diff */
1292 {"/A: 1,3", "/A: 1,3",
1293 0, { { 0, 0, FALSE } },
1294 0, { { 0, 0, FALSE } },
1295 0, { { 0, 0, FALSE } },
1296 0, { { 0, 0, FALSE } } },
1298 {"/A: 1,3*", "/A: 1,3*",
1299 0, { { 0, 0, FALSE } },
1300 0, { { 0, 0, FALSE } },
1301 0, { { 0, 0, FALSE } },
1302 0, { { 0, 0, FALSE } } },
1304 /* Adds and Deletes */
1305 {"/A: 1,5-8", "/A: 1,6,10-12",
1306 1, { { 9, 12, TRUE } },
1307 2, { { 4, 5, TRUE }, { 6, 8, TRUE } },
1308 1, { { 9, 12, TRUE } },
1309 2, { { 4, 5, TRUE }, { 6, 8, TRUE } } },
1311 {"/A: 6*", "/A: 6",
1312 1, { { 5, 6, TRUE } },
1313 1, { { 5, 6, FALSE } },
1314 0, { { 0, 0, FALSE } },
1315 0, { { 0, 0, FALSE } } },
1317 /* Intersecting range with different inheritability */
1318 {"/A: 6", "/A: 6*",
1319 1, { { 5, 6, FALSE } },
1320 1, { { 5, 6, TRUE } },
1321 0, { { 0, 0, FALSE } },
1322 0, { { 0, 0, FALSE } } },
1324 {"/A: 6*", "/A: 6",
1325 1, { { 5, 6, TRUE } },
1326 1, { { 5, 6, FALSE } },
1327 0, { { 0, 0, FALSE } },
1328 0, { { 0, 0, FALSE } } },
1330 {"/A: 1,5-8", "/A: 1,6*,10-12",
1331 2, { { 5, 6, FALSE }, { 9, 12, TRUE } },
1332 1, { { 4, 8, TRUE } },
1333 1, { { 9, 12, TRUE } },
1334 2, { { 4, 5, TRUE }, { 6, 8, TRUE } } },
1336 {"/A: 1,5-8*", "/A: 1,6,10-12",
1337 2, { { 5, 6, TRUE }, { 9, 12, TRUE } },
1338 1, { { 4, 8, FALSE } },
1339 1, { { 9, 12, TRUE } },
1340 2, { { 4, 5, FALSE }, { 6, 8, FALSE } } },
1342 /* Empty range diffs */
1343 {"/A: 3-9", "",
1344 0, { { 0, 0, FALSE } },
1345 1, { { 2, 9, TRUE } },
1346 0, { { 0, 0, FALSE } },
1347 1, { { 2, 9, TRUE } } },
1349 {"/A: 3-9*", "",
1350 0, { { 0, 0, FALSE } },
1351 1, { { 2, 9, FALSE } },
1352 0, { { 0, 0, FALSE } },
1353 1, { { 2, 9, FALSE } } },
1355 {"", "/A: 3-9",
1356 1, { { 2, 9, TRUE } },
1357 0, { { 0, 0, FALSE } },
1358 1, { { 2, 9, TRUE } },
1359 0, { { 0, 0, FALSE } } },
1361 {"", "/A: 3-9*",
1362 1, { { 2, 9, FALSE } },
1363 0, { { 0, 0, FALSE } },
1364 1, { { 2, 9, FALSE } },
1365 0, { { 0, 0, FALSE } } },
1367 /* Empty range no diff */
1368 {"", "",
1369 0, { { 0, 0, FALSE } },
1370 0, { { 0, 0, FALSE } },
1371 0, { { 0, 0, FALSE } },
1372 0, { { 0, 0, FALSE } } },
1375 *msg = "diff of rangelists";
1376 if (msg_only)
1377 return SVN_NO_ERROR;
1379 err = child_err = SVN_NO_ERROR;
1380 for (i = 0; i < SIZE_OF_RANGE_DIFF_TEST_ARRAY; i++)
1382 SVN_ERR(svn_mergeinfo_parse(&info1, (test_data[i]).to, pool));
1383 SVN_ERR(svn_mergeinfo_parse(&info2, (test_data[i]).from, pool));
1384 to = apr_hash_get(info1, "/A", APR_HASH_KEY_STRING);
1385 from = apr_hash_get(info2, "/A", APR_HASH_KEY_STRING);
1387 /* Represent empty mergeinfo with an empty rangelist. */
1388 if (to == NULL)
1389 to = apr_array_make(pool, 0, sizeof(*to));
1390 if (from == NULL)
1391 from = apr_array_make(pool, 0, sizeof(*from));
1393 /* First diff the ranges while considering
1394 differences in inheritance. */
1395 SVN_ERR(svn_rangelist_diff(&deleted, &added, from, to, TRUE, pool));
1397 child_err = verify_ranges_match(added,
1398 (test_data[i]).expected_adds,
1399 (test_data[i]).expected_add_ranges,
1400 apr_psprintf(pool,
1401 "svn_rangelist_diff"
1402 "case %i", i),
1403 "diff", pool);
1404 if (!child_err)
1405 child_err = verify_ranges_match(deleted,
1406 (test_data[i]).expected_dels,
1407 (test_data[i]).expected_del_ranges,
1408 apr_psprintf(pool,
1409 "svn_rangelist_diff"
1410 "case %i", i),
1411 "diff", pool);
1412 if (!child_err)
1414 /* Now do the diff while ignoring differences in inheritance. */
1415 SVN_ERR(svn_rangelist_diff(&deleted, &added, from, to, FALSE,
1416 pool));
1417 child_err = verify_ranges_match(
1418 added,
1419 (test_data[i]).expected_adds_ignore_inheritance,
1420 (test_data[i]).expected_add_ranges_ignore_inheritance,
1421 apr_psprintf(pool, "svn_rangelist_diff case %i", i),
1422 "diff", pool);
1424 if (!child_err)
1425 child_err = verify_ranges_match(
1426 deleted,
1427 (test_data[i]).expected_dels_ignore_inheritance,
1428 (test_data[i]).expected_del_ranges_ignore_inheritance,
1429 apr_psprintf(pool, "svn_rangelist_diff case %i", i),
1430 "diff", pool);
1433 /* Collect all the errors rather than returning on the first. */
1434 if (child_err)
1436 if (err)
1437 svn_error_compose(err, child_err);
1438 else
1439 err = child_err;
1442 return err;
1445 /* The test table. */
1447 struct svn_test_descriptor_t test_funcs[] =
1449 SVN_TEST_NULL,
1450 SVN_TEST_PASS(test_parse_single_line_mergeinfo),
1451 SVN_TEST_PASS(test_mergeinfo_dup),
1452 SVN_TEST_PASS(test_parse_combine_rangeinfo),
1453 SVN_TEST_PASS(test_parse_broken_mergeinfo),
1454 SVN_TEST_PASS(test_remove_rangelist),
1455 SVN_TEST_PASS(test_remove_mergeinfo),
1456 SVN_TEST_PASS(test_rangelist_reverse),
1457 SVN_TEST_PASS(test_rangelist_count_revs),
1458 SVN_TEST_PASS(test_rangelist_to_revs),
1459 SVN_TEST_XFAIL(test_rangelist_intersect),
1460 SVN_TEST_PASS(test_diff_mergeinfo),
1461 SVN_TEST_PASS(test_merge_mergeinfo),
1462 SVN_TEST_PASS(test_mergeinfo_intersect),
1463 SVN_TEST_PASS(test_rangelist_to_string),
1464 SVN_TEST_PASS(test_mergeinfo_to_string),
1465 SVN_TEST_PASS(test_range_compact),
1466 SVN_TEST_PASS(test_rangelist_merge),
1467 SVN_TEST_PASS(test_rangelist_diff),
1468 SVN_TEST_NULL