You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2011/10/21 17:49:04 UTC

svn commit: r1187412 - in /subversion/trunk/subversion: include/private/svn_mergeinfo_private.h libsvn_subr/mergeinfo.c tests/libsvn_subr/mergeinfo-test.c

Author: julianfoad
Date: Fri Oct 21 15:49:03 2011
New Revision: 1187412

URL: http://svn.apache.org/viewvc?rev=1187412&view=rev
Log:
Expose svn_rangelist__parse() as a private API and use it to simplify some
rangelist tests. This exposes a bug in svn_rangelist_merge() so mark the
test for that as XFAIL.

The bug is that svn_rangelist_merge() doesn't always ensure its output is
minimal, contrary to its doc string. The test was previously parsing the
input data with svn_mergeinfo_parse() instead of svn_rangelist__parse(), and
svn_mergeinfo_parse() condenses the ranges so svn_rangelist_merge() was not
getting the intended non-canonical input.

* subversion/include/private/svn_mergeinfo_private.h,
  subversion/libsvn_subr/mergeinfo.c
  (svn_rangelist__parse): New function.

* subversion/tests/libsvn_subr/mergeinfo-test.c
  (test_rangelist_reverse, test_rangelist_intersect, test_remove_rangelist,
   test_rangelist_merge, test_rangelist_diff): Use svn_rangelist__parse()
    instead of svn_mergeinfo_parse() and so remove "path: " prefixes from
    the test data.
  (test_funcs): Mark 'test_rangelist_merge' as XFAIL.

Modified:
    subversion/trunk/subversion/include/private/svn_mergeinfo_private.h
    subversion/trunk/subversion/libsvn_subr/mergeinfo.c
    subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c

Modified: subversion/trunk/subversion/include/private/svn_mergeinfo_private.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_mergeinfo_private.h?rev=1187412&r1=1187411&r2=1187412&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_mergeinfo_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_mergeinfo_private.h Fri Oct 21 15:49:03 2011
@@ -44,6 +44,18 @@ void
 svn_rangelist__set_inheritance(apr_array_header_t *rangelist,
                                svn_boolean_t inheritable);
 
+/* Parse a rangelist from the string STR. Set *RANGELIST to the result,
+ * allocated in RESULT_POOL. Return an error if the rangelist is not
+ * well-formed (for example, if it contains invalid characters or if
+ * R1 >= R2 in a "R1-R2" range element).
+ *
+ * Unlike svn_mergeinfo_parse(), this does not sort the ranges into order
+ * or combine adjacent and overlapping ranges. */
+svn_error_t *
+svn_rangelist__parse(apr_array_header_t **rangelist,
+                     const char *str,
+                     apr_pool_t *result_pool);
+
 /* Set inheritability of all rangelists in MERGEINFO to INHERITABLE.
    If MERGEINFO is NULL do nothing.  If a rangelist in MERGEINFO is
    NULL leave it alone. */

Modified: subversion/trunk/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/mergeinfo.c?rev=1187412&r1=1187411&r2=1187412&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/trunk/subversion/libsvn_subr/mergeinfo.c Fri Oct 21 15:49:03 2011
@@ -598,6 +598,18 @@ parse_rangelist(const char **input, cons
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_rangelist__parse(apr_array_header_t **rangelist,
+                     const char *str,
+                     apr_pool_t *result_pool)
+{
+  const char *s = str;
+
+  *rangelist = apr_array_make(result_pool, 1, sizeof(svn_merge_range_t *));
+  SVN_ERR(parse_rangelist(&s, s + strlen(s), *rangelist, result_pool));
+  return SVN_NO_ERROR;
+}
+
 /* revisionline -> PATHNAME COLON revisionlist */
 static svn_error_t *
 parse_revision_line(const char **input, const char *end, svn_mergeinfo_t hash,

Modified: subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c?rev=1187412&r1=1187411&r2=1187412&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/mergeinfo-test.c Fri Oct 21 15:49:03 2011
@@ -483,8 +483,7 @@ test_rangelist_reverse(apr_pool_t *pool)
   svn_merge_range_t expected_rangelist[3] =
     { {10, 9, TRUE}, {7, 4, TRUE}, {3, 2, TRUE} };
 
-  SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 3,5-7,10", pool));
-  rangelist = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
+  SVN_ERR(svn_rangelist__parse(&rangelist, "3,5-7,10", pool));
 
   SVN_ERR(svn_rangelist_reverse(rangelist, pool));
 
@@ -506,11 +505,9 @@ test_rangelist_intersect(apr_pool_t *poo
     { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE}, {30, 32, FALSE},
       {39, 42, TRUE} };
 
-  SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16,30-32*,40-42", pool));
-  SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4*,7,9,11-12,31-34*,38-44",
-                              pool));
-  rangelist1 = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
-  rangelist2 = apr_hash_get(info2, "/trunk", APR_HASH_KEY_STRING);
+  SVN_ERR(svn_rangelist__parse(&rangelist1, "1-6,12-16,30-32*,40-42", pool));
+  SVN_ERR(svn_rangelist__parse(&rangelist2, "1,3-4*,7,9,11-12,31-34*,38-44",
+                               pool));
 
   /* Check the intersection while considering inheritance twice, reversing
      the order of the rangelist arguments on the second call to
@@ -783,39 +780,39 @@ test_remove_rangelist(apr_pool_t *pool)
   struct rangelist_remove_test_data test_data[SIZE_OF_RANGE_REMOVE_TEST_ARRAY] =
     {
       /* Eraser is a proper subset of whiteboard */
-      {"/A: 1-44",  "/A: 5",  2, { {0,  4, TRUE }, {5, 44, TRUE }},
-                              2, { {0,  4, TRUE }, {5, 44, TRUE }}},
-      {"/A: 1-44*", "/A: 5",  1, { {0, 44, FALSE} },
-                              2, { {0,  4, FALSE}, {5, 44, FALSE}}},
-      {"/A: 1-44",  "/A: 5*", 1, { {0, 44, TRUE } },
-                              2, { {0,  4, TRUE }, {5, 44, TRUE }}},
-      {"/A: 1-44*", "/A: 5*", 2, { {0,  4, FALSE}, {5, 44, FALSE}},
-                              2, { {0,  4, FALSE}, {5, 44, FALSE}}},
+      {"1-44",  "5",  2, { {0,  4, TRUE }, {5, 44, TRUE }},
+                      2, { {0,  4, TRUE }, {5, 44, TRUE }}},
+      {"1-44*", "5",  1, { {0, 44, FALSE} },
+                      2, { {0,  4, FALSE}, {5, 44, FALSE}}},
+      {"1-44",  "5*", 1, { {0, 44, TRUE } },
+                      2, { {0,  4, TRUE }, {5, 44, TRUE }}},
+      {"1-44*", "5*", 2, { {0,  4, FALSE}, {5, 44, FALSE}},
+                      2, { {0,  4, FALSE}, {5, 44, FALSE}}},
       /* Non-intersecting ranges...nothing is removed */
-      {"/A: 2-9,14-19",   "/A: 12",  2, { {1, 9, TRUE }, {13, 19, TRUE }},
-                                     2, { {1, 9, TRUE }, {13, 19, TRUE }}},
-      {"/A: 2-9*,14-19*", "/A: 12",  2, { {1, 9, FALSE}, {13, 19, FALSE}},
-                                     2, { {1, 9, FALSE}, {13, 19, FALSE}}},
-      {"/A: 2-9,14-19",   "/A: 12*", 2, { {1, 9, TRUE }, {13, 19, TRUE }},
-                                     2, { {1, 9, TRUE }, {13, 19, TRUE }}},
-      {"/A: 2-9*,14-19*", "/A: 12*", 2, { {1, 9, FALSE}, {13, 19, FALSE}},
-                                     2, { {1, 9, FALSE}, {13, 19, FALSE}}},
+      {"2-9,14-19",   "12",  2, { {1, 9, TRUE }, {13, 19, TRUE }},
+                             2, { {1, 9, TRUE }, {13, 19, TRUE }}},
+      {"2-9*,14-19*", "12",  2, { {1, 9, FALSE}, {13, 19, FALSE}},
+                             2, { {1, 9, FALSE}, {13, 19, FALSE}}},
+      {"2-9,14-19",   "12*", 2, { {1, 9, TRUE }, {13, 19, TRUE }},
+                             2, { {1, 9, TRUE }, {13, 19, TRUE }}},
+      {"2-9*,14-19*", "12*", 2, { {1, 9, FALSE}, {13, 19, FALSE}},
+                             2, { {1, 9, FALSE}, {13, 19, FALSE}}},
       /* Eraser overlaps whiteboard */
-      {"/A: 1,9-17",  "/A: 12-20",  2, { {0,  1, TRUE }, {8, 11, TRUE }},
-                                    2, { {0,  1, TRUE }, {8, 11, TRUE }}},
-      {"/A: 1,9-17*", "/A: 12-20",  2, { {0,  1, TRUE }, {8, 17, FALSE}},
-                                    2, { {0,  1, TRUE }, {8, 11, FALSE}}},
-      {"/A: 1,9-17",  "/A: 12-20*", 2, { {0,  1, TRUE }, {8, 17, TRUE }},
-                                    2, { {0,  1, TRUE }, {8, 11, TRUE }}},
-      {"/A: 1,9-17*", "/A: 12-20*", 2, { {0,  1, TRUE }, {8, 11, FALSE}},
-                                    2, { {0,  1, TRUE }, {8, 11, FALSE}}},
-      /* Empty mergeinfo (i.e. empty rangelist) */
-      {"",  "",               0, { {0, 0, FALSE}},
-                              0, { {0, 0, FALSE}}},
-      {"",  "/A: 5-8,10-100", 0, { {0, 0, FALSE}},
-                              0, { {0, 0, FALSE}}},
-      {"/A: 5-8,10-100",  "", 2, { {4, 8, TRUE }, {9, 100, TRUE }},
-                              2, { {4, 8, TRUE }, {9, 100, TRUE }}}
+      {"1,9-17",  "12-20",  2, { {0,  1, TRUE }, {8, 11, TRUE }},
+                            2, { {0,  1, TRUE }, {8, 11, TRUE }}},
+      {"1,9-17*", "12-20",  2, { {0,  1, TRUE }, {8, 17, FALSE}},
+                            2, { {0,  1, TRUE }, {8, 11, FALSE}}},
+      {"1,9-17",  "12-20*", 2, { {0,  1, TRUE }, {8, 17, TRUE }},
+                            2, { {0,  1, TRUE }, {8, 11, TRUE }}},
+      {"1,9-17*", "12-20*", 2, { {0,  1, TRUE }, {8, 11, FALSE}},
+                            2, { {0,  1, TRUE }, {8, 11, FALSE}}},
+      /* Empty rangelist */
+      {"",  "",           0, { {0, 0, FALSE}},
+                          0, { {0, 0, FALSE}}},
+      {"",  "5-8,10-100", 0, { {0, 0, FALSE}},
+                          0, { {0, 0, FALSE}}},
+      {"5-8,10-100",  "", 2, { {4, 8, TRUE }, {9, 100, TRUE }},
+                          2, { {4, 8, TRUE }, {9, 100, TRUE }}}
     };
 
   err = child_err = SVN_NO_ERROR;
@@ -830,10 +827,8 @@ test_remove_rangelist(apr_pool_t *pool)
           svn_string_t *whiteboard_starting;
           svn_string_t *whiteboard_ending;
 
-          SVN_ERR(svn_mergeinfo_parse(&info1, (test_data[i]).eraser, pool));
-          SVN_ERR(svn_mergeinfo_parse(&info2, (test_data[i]).whiteboard, pool));
-          eraser = apr_hash_get(info1, "/A", APR_HASH_KEY_STRING);
-          whiteboard = apr_hash_get(info2, "/A", APR_HASH_KEY_STRING);
+          SVN_ERR(svn_rangelist__parse(&eraser, test_data[i].eraser, pool));
+          SVN_ERR(svn_rangelist__parse(&whiteboard, test_data[i].whiteboard, pool));
 
           /* Represent empty mergeinfo with an empty rangelist. */
           if (eraser == NULL)
@@ -1184,118 +1179,118 @@ test_rangelist_merge(apr_pool_t *pool)
   struct rangelist_merge_test_data test_data[SIZE_OF_RANGE_MERGE_TEST_ARRAY] =
     {
       /* Non-intersecting ranges */
-      {"/A: 1-44",    "/A: 70-101",  2, {{ 0, 44, TRUE }, {69, 101, TRUE }}},
-      {"/A: 1-44*",   "/A: 70-101",  2, {{ 0, 44, FALSE}, {69, 101, TRUE }}},
-      {"/A: 1-44",    "/A: 70-101*", 2, {{ 0, 44, TRUE }, {69, 101, FALSE}}},
-      {"/A: 1-44*",   "/A: 70-101*", 2, {{ 0, 44, FALSE}, {69, 101, FALSE}}},
-      {"/A: 70-101",  "/A: 1-44",    2, {{ 0, 44, TRUE }, {69, 101, TRUE }}},
-      {"/A: 70-101*", "/A: 1-44",    2, {{ 0, 44, TRUE }, {69, 101, FALSE}}},
-      {"/A: 70-101",  "/A: 1-44*",   2, {{ 0, 44, FALSE}, {69, 101, TRUE }}},
-      {"/A: 70-101*", "/A: 1-44*",   2, {{ 0, 44, FALSE}, {69, 101, FALSE}}},
+      {"1-44",    "70-101",  2, {{ 0, 44, TRUE }, {69, 101, TRUE }}},
+      {"1-44*",   "70-101",  2, {{ 0, 44, FALSE}, {69, 101, TRUE }}},
+      {"1-44",    "70-101*", 2, {{ 0, 44, TRUE }, {69, 101, FALSE}}},
+      {"1-44*",   "70-101*", 2, {{ 0, 44, FALSE}, {69, 101, FALSE}}},
+      {"70-101",  "1-44",    2, {{ 0, 44, TRUE }, {69, 101, TRUE }}},
+      {"70-101*", "1-44",    2, {{ 0, 44, TRUE }, {69, 101, FALSE}}},
+      {"70-101",  "1-44*",   2, {{ 0, 44, FALSE}, {69, 101, TRUE }}},
+      {"70-101*", "1-44*",   2, {{ 0, 44, FALSE}, {69, 101, FALSE}}},
 
       /* Intersecting ranges with same starting and ending revisions */
-      {"/A: 4-20",  "/A: 4-20",  1, {{3, 20, TRUE }}},
-      {"/A: 4-20*", "/A: 4-20",  1, {{3, 20, TRUE }}},
-      {"/A: 4-20",  "/A: 4-20*", 1, {{3, 20, TRUE }}},
-      {"/A: 4-20*", "/A: 4-20*", 1, {{3, 20, FALSE}}},
+      {"4-20",  "4-20",  1, {{3, 20, TRUE }}},
+      {"4-20*", "4-20",  1, {{3, 20, TRUE }}},
+      {"4-20",  "4-20*", 1, {{3, 20, TRUE }}},
+      {"4-20*", "4-20*", 1, {{3, 20, FALSE}}},
 
       /* Intersecting ranges with same starting revision */
-      {"/A: 6-17",  "/A: 6-12",  1, {{5, 17, TRUE}}},
-      {"/A: 6-17*", "/A: 6-12",  2, {{5, 12, TRUE }, {12, 17, FALSE}}},
-      {"/A: 6-17",  "/A: 6-12*", 1, {{5, 17, TRUE }}},
-      {"/A: 6-17*", "/A: 6-12*", 1, {{5, 17, FALSE}}},
-      {"/A: 6-12",  "/A: 6-17",  1, {{5, 17, TRUE }}},
-      {"/A: 6-12*", "/A: 6-17",  1, {{5, 17, TRUE }}},
-      {"/A: 6-12",  "/A: 6-17*", 2, {{5, 12, TRUE }, {12, 17, FALSE}}},
-      {"/A: 6-12*", "/A: 6-17*", 1, {{5, 17, FALSE}}},
+      {"6-17",  "6-12",  1, {{5, 17, TRUE}}},
+      {"6-17*", "6-12",  2, {{5, 12, TRUE }, {12, 17, FALSE}}},
+      {"6-17",  "6-12*", 1, {{5, 17, TRUE }}},
+      {"6-17*", "6-12*", 1, {{5, 17, FALSE}}},
+      {"6-12",  "6-17",  1, {{5, 17, TRUE }}},
+      {"6-12*", "6-17",  1, {{5, 17, TRUE }}},
+      {"6-12",  "6-17*", 2, {{5, 12, TRUE }, {12, 17, FALSE}}},
+      {"6-12*", "6-17*", 1, {{5, 17, FALSE}}},
 
       /* Intersecting ranges with same ending revision */
-      {"/A: 5-77",   "/A: 44-77",  1, {{4, 77, TRUE }}},
-      {"/A: 5-77*",  "/A: 44-77",  2, {{4, 43, FALSE}, {43, 77, TRUE}}},
-      {"/A: 5-77",   "/A: 44-77*", 1, {{4, 77, TRUE }}},
-      {"/A: 5-77*",  "/A: 44-77*", 1, {{4, 77, FALSE}}},
-      {"/A: 44-77",  "/A: 5-77",   1, {{4, 77, TRUE }}},
-      {"/A: 44-77*", "/A: 5-77",   1, {{4, 77, TRUE }}},
-      {"/A: 44-77",  "/A: 5-77*",  2, {{4, 43, FALSE}, {43, 77, TRUE}}},
-      {"/A: 44-77*", "/A: 5-77*",  1, {{4, 77, FALSE}}},
+      {"5-77",   "44-77",  1, {{4, 77, TRUE }}},
+      {"5-77*",  "44-77",  2, {{4, 43, FALSE}, {43, 77, TRUE}}},
+      {"5-77",   "44-77*", 1, {{4, 77, TRUE }}},
+      {"5-77*",  "44-77*", 1, {{4, 77, FALSE}}},
+      {"44-77",  "5-77",   1, {{4, 77, TRUE }}},
+      {"44-77*", "5-77",   1, {{4, 77, TRUE }}},
+      {"44-77",  "5-77*",  2, {{4, 43, FALSE}, {43, 77, TRUE}}},
+      {"44-77*", "5-77*",  1, {{4, 77, FALSE}}},
 
       /* Intersecting ranges with different starting and ending revision
          where one range is a proper subset of the other. */
-      {"/A: 12-24",  "/A: 20-23",  1, {{11, 24, TRUE }}},
-      {"/A: 12-24*", "/A: 20-23",  3, {{11, 19, FALSE}, {19, 23, TRUE },
-                                       {23, 24, FALSE}}},
-      {"/A: 12-24",  "/A: 20-23*", 1, {{11, 24, TRUE }}},
-      {"/A: 12-24*", "/A: 20-23*", 1, {{11, 24, FALSE}}},
-      {"/A: 20-23",  "/A: 12-24",  1, {{11, 24, TRUE }}},
-      {"/A: 20-23*", "/A: 12-24",  1, {{11, 24, TRUE }}},
-      {"/A: 20-23",  "/A: 12-24*", 3, {{11, 19, FALSE}, {19, 23, TRUE },
-                                       {23, 24, FALSE}}},
-      {"/A: 20-23*", "/A: 12-24*", 1, {{11, 24, FALSE}}},
+      {"12-24",  "20-23",  1, {{11, 24, TRUE }}},
+      {"12-24*", "20-23",  3, {{11, 19, FALSE}, {19, 23, TRUE },
+                               {23, 24, FALSE}}},
+      {"12-24",  "20-23*", 1, {{11, 24, TRUE }}},
+      {"12-24*", "20-23*", 1, {{11, 24, FALSE}}},
+      {"20-23",  "12-24",  1, {{11, 24, TRUE }}},
+      {"20-23*", "12-24",  1, {{11, 24, TRUE }}},
+      {"20-23",  "12-24*", 3, {{11, 19, FALSE}, {19, 23, TRUE },
+                               {23, 24, FALSE}}},
+      {"20-23*", "12-24*", 1, {{11, 24, FALSE}}},
 
       /* Intersecting ranges with different starting and ending revision
          where neither range is a proper subset of the other. */
-      {"/A: 50-73",  "/A: 60-99",  1, {{49, 99, TRUE }}},
-      {"/A: 50-73*", "/A: 60-99",  2, {{49, 59, FALSE}, {59, 99, TRUE }}},
-      {"/A: 50-73",  "/A: 60-99*", 2, {{49, 73, TRUE }, {73, 99, FALSE}}},
-      {"/A: 50-73*", "/A: 60-99*", 1, {{49, 99, FALSE}}},
-      {"/A: 60-99",  "/A: 50-73",  1, {{49, 99, TRUE }}},
-      {"/A: 60-99*", "/A: 50-73",  2, {{49, 73, TRUE }, {73, 99, FALSE}}},
-      {"/A: 60-99",  "/A: 50-73*", 2, {{49, 59, FALSE}, {59, 99, TRUE }}},
-      {"/A: 60-99*", "/A: 50-73*", 1, {{49, 99, FALSE}}},
+      {"50-73",  "60-99",  1, {{49, 99, TRUE }}},
+      {"50-73*", "60-99",  2, {{49, 59, FALSE}, {59, 99, TRUE }}},
+      {"50-73",  "60-99*", 2, {{49, 73, TRUE }, {73, 99, FALSE}}},
+      {"50-73*", "60-99*", 1, {{49, 99, FALSE}}},
+      {"60-99",  "50-73",  1, {{49, 99, TRUE }}},
+      {"60-99*", "50-73",  2, {{49, 73, TRUE }, {73, 99, FALSE}}},
+      {"60-99",  "50-73*", 2, {{49, 59, FALSE}, {59, 99, TRUE }}},
+      {"60-99*", "50-73*", 1, {{49, 99, FALSE}}},
 
       /* Multiple ranges. */
-      {"/A: 1-5,7,12-13",    "/A: 2-17",  1, {{0,  17, TRUE }}},
-      {"/A: 1-5*,7*,12-13*", "/A: 2-17*", 1, {{0,  17, FALSE}}},
+      {"1-5,7,12-13",    "2-17",  1, {{0,  17, TRUE }}},
+      {"1-5*,7*,12-13*", "2-17*", 1, {{0,  17, FALSE}}},
 
-      {"/A: 1-5,7,12-13",    "/A: 2-17*", 6,
+      {"1-5,7,12-13",    "2-17*", 6,
        {{0,  5, TRUE }, { 5,  6, FALSE}, { 6,  7, TRUE },
         {7, 11, FALSE}, {11, 13, TRUE }, {13, 17, FALSE}}},
 
-      {"/A: 1-5*,7*,12-13*", "/A: 2-17", 2,
+      {"1-5*,7*,12-13*", "2-17", 2,
        {{0, 1, FALSE}, {1, 17, TRUE }}},
 
-      {"/A: 2-17",  "/A: 1-5,7,12-13",    1, {{0,  17, TRUE }}},
-      {"/A: 2-17*", "/A: 1-5*,7*,12-13*", 1, {{0,  17, FALSE}}},
+      {"2-17",  "1-5,7,12-13",    1, {{0,  17, TRUE }}},
+      {"2-17*", "1-5*,7*,12-13*", 1, {{0,  17, FALSE}}},
 
-      {"/A: 2-17*", "/A: 1-5,7,12-13", 6,
+      {"2-17*", "1-5,7,12-13", 6,
        {{0,  5, TRUE }, { 5,  6, FALSE}, { 6,  7, TRUE },
         {7, 11, FALSE}, {11, 13, TRUE }, {13, 17, FALSE}}},
 
-      {"/A: 2-17", "/A: 1-5*,7*,12-13*", 2,
+      {"2-17", "1-5*,7*,12-13*", 2,
        {{0, 1, FALSE}, {1, 17, TRUE}}},
 
-      {"/A: 3-4*,10-15,20", "/A: 5-60*", 5,
+      {"3-4*,10-15,20", "5-60*", 5,
        {{2, 9, FALSE}, {9, 15, TRUE}, {15, 19, FALSE},{19, 20, TRUE},
         {20, 60, FALSE}}},
 
-      {"/A: 5-60*", "/A: 3-4*,10-15,20", 5,
+      {"5-60*", "3-4*,10-15,20", 5,
        {{2, 9, FALSE}, {9, 15, TRUE}, {15, 19, FALSE},{19, 20, TRUE},
         {20, 60, FALSE}}},
 
-      {"/A: 3-4*,50-100*", "/A: 5-60*", 1, {{2, 100, FALSE}}},
+      {"3-4*,50-100*", "5-60*", 1, {{2, 100, FALSE}}},
 
-      {"/A: 5-60*", "/A: 3-4*,50-100*", 1, {{2, 100, FALSE}}},
+      {"5-60*", "3-4*,50-100*", 1, {{2, 100, FALSE}}},
 
-      {"/A: 3-4*,50-100", "/A: 5-60*", 2, {{2, 49, FALSE}, {49, 100, TRUE}}},
+      {"3-4*,50-100", "5-60*", 2, {{2, 49, FALSE}, {49, 100, TRUE}}},
 
-      {"/A: 5-60*", "/A: 3-4*,50-100", 2, {{2, 49, FALSE}, {49, 100, TRUE}}},
+      {"5-60*", "3-4*,50-100", 2, {{2, 49, FALSE}, {49, 100, TRUE}}},
 
-      {"/A: 3-4,50-100*", "/A: 5-60", 2, {{2, 60, TRUE}, {60, 100, FALSE}}},
+      {"3-4,50-100*", "5-60", 2, {{2, 60, TRUE}, {60, 100, FALSE}}},
 
-      {"/A: 5-60", "/A: 3-4,50-100*", 2, {{2, 60, TRUE}, {60, 100, FALSE}}},
+      {"5-60", "3-4,50-100*", 2, {{2, 60, TRUE}, {60, 100, FALSE}}},
 
-      {"/A: 5,9,11-15,17,200-300,999", "/A: 7-50", 4,
+      {"5,9,11-15,17,200-300,999", "7-50", 4,
        {{4, 5, TRUE}, {6, 50, TRUE}, {199, 300, TRUE}, {998, 999, TRUE}}},
 
       /* A rangelist merged with an empty rangelist should equal the
          non-empty rangelist but in compacted form. */
-      {"/A: 1-44,45,46,47-50",       "",  1, {{ 0, 50, TRUE }}},
-      {"/A: 1,2,3,4,5,6,7,8",        "",  1, {{ 0, 8,  TRUE }}},
-      {"/A: 6-10,12-13,14,15,16-22", "",  2,
+      {"1-44,45,46,47-50",       "",  1, {{ 0, 50, TRUE }}},
+      {"1,2,3,4,5,6,7,8",        "",  1, {{ 0, 8,  TRUE }}},
+      {"6-10,12-13,14,15,16-22", "",  2,
        {{ 5, 10, TRUE }, { 11, 22, TRUE }}},
-      {"", "/A: 1-44,45,46,47-50",        1, {{ 0, 50, TRUE }}},
-      {"", "/A: 1,2,3,4,5,6,7,8",         1, {{ 0, 8,  TRUE }}},
-      {"", "/A: 6-10,12-13,14,15,16-22",  2,
+      {"", "1-44,45,46,47-50",        1, {{ 0, 50, TRUE }}},
+      {"", "1,2,3,4,5,6,7,8",         1, {{ 0, 8,  TRUE }}},
+      {"", "6-10,12-13,14,15,16-22",  2,
        {{ 5, 10, TRUE }, { 11, 22, TRUE }}},
 
       /* An empty rangelist merged with an empty rangelist is, drum-roll
@@ -1308,10 +1303,8 @@ test_rangelist_merge(apr_pool_t *pool)
     {
       svn_string_t *rangelist2_starting, *rangelist2_ending;
 
-      SVN_ERR(svn_mergeinfo_parse(&info1, (test_data[i]).mergeinfo1, pool));
-      SVN_ERR(svn_mergeinfo_parse(&info2, (test_data[i]).mergeinfo2, pool));
-      rangelist1 = apr_hash_get(info1, "/A", APR_HASH_KEY_STRING);
-      rangelist2 = apr_hash_get(info2, "/A", APR_HASH_KEY_STRING);
+      SVN_ERR(svn_rangelist__parse(&rangelist1, test_data[i].mergeinfo1, pool));
+      SVN_ERR(svn_rangelist__parse(&rangelist2, test_data[i].mergeinfo2, pool));
 
       /* Create empty rangelists if necessary. */
       if (rangelist1 == NULL)
@@ -1395,7 +1388,7 @@ test_rangelist_diff(apr_pool_t *pool)
   #define SIZE_OF_RANGE_DIFF_TEST_ARRAY 16
   /* The actual test data array.
 
-                    'from' --> {"/A: 1,5-8",  "/A: 1,6,10-12", <-- 'to'
+                    'from' --> {"1,5-8",  "1,6,10-12", <-- 'to'
       Number of adds when  -->  1, { { 9, 12, TRUE } },
       considering inheritance
 
@@ -1413,97 +1406,97 @@ test_rangelist_diff(apr_pool_t *pool)
   struct rangelist_diff_test_data test_data[SIZE_OF_RANGE_DIFF_TEST_ARRAY] =
     {
       /* Add and Delete */
-      {"/A: 1",  "/A: 3",
+      {"1",  "3",
        1, { { 2, 3, TRUE } },
        1, { { 0, 1, TRUE } },
        1, { { 2, 3, TRUE } },
        1, { { 0, 1, TRUE } } },
 
       /* Add only */
-      {"/A: 1",  "/A: 1,3",
+      {"1",  "1,3",
        1, { { 2, 3, TRUE } },
        0, { { 0, 0, FALSE } },
        1, { { 2, 3, TRUE } },
        0, { { 0, 0, FALSE } } },
 
       /* Delete only */
-      {"/A: 1,3",  "/A: 1",
+      {"1,3",  "1",
        0, { { 0, 0, FALSE } },
        1, { { 2, 3, TRUE  } },
        0, { { 0, 0, FALSE } },
        1, { { 2, 3, TRUE  } } },
 
       /* No diff */
-      {"/A: 1,3",  "/A: 1,3",
+      {"1,3",  "1,3",
        0, { { 0, 0, FALSE } },
        0, { { 0, 0, FALSE } },
        0, { { 0, 0, FALSE } },
        0, { { 0, 0, FALSE } } },
 
-      {"/A: 1,3*",  "/A: 1,3*",
+      {"1,3*",  "1,3*",
        0, { { 0, 0, FALSE } },
        0, { { 0, 0, FALSE } },
        0, { { 0, 0, FALSE } },
        0, { { 0, 0, FALSE } } },
 
       /* Adds and Deletes */
-      {"/A: 1,5-8",  "/A: 1,6,10-12",
+      {"1,5-8",  "1,6,10-12",
        1, { { 9, 12, TRUE } },
        2, { { 4, 5, TRUE }, { 6, 8, TRUE } },
        1, { { 9, 12, TRUE } },
        2, { { 4, 5, TRUE }, { 6, 8, TRUE } } },
 
-      {"/A: 6*",  "/A: 6",
+      {"6*",  "6",
        1, { { 5, 6, TRUE  } },
        1, { { 5, 6, FALSE } },
        0, { { 0, 0, FALSE } },
        0, { { 0, 0, FALSE } } },
 
       /* Intersecting range with different inheritability */
-      {"/A: 6",  "/A: 6*",
+      {"6",  "6*",
        1, { { 5, 6, FALSE } },
        1, { { 5, 6, TRUE  } },
        0, { { 0, 0, FALSE } },
        0, { { 0, 0, FALSE } } },
 
-      {"/A: 6*",  "/A: 6",
+      {"6*",  "6",
        1, { { 5, 6, TRUE  } },
        1, { { 5, 6, FALSE } },
        0, { { 0, 0, FALSE } },
        0, { { 0, 0, FALSE } } },
 
-      {"/A: 1,5-8",  "/A: 1,6*,10-12",
+      {"1,5-8",  "1,6*,10-12",
        2, { { 5,  6, FALSE }, { 9, 12, TRUE } },
        1, { { 4,  8, TRUE  } },
        1, { { 9, 12, TRUE  } },
        2, { { 4,  5, TRUE  }, { 6,  8, TRUE } } },
 
-     {"/A: 1,5-8*",  "/A: 1,6,10-12",
+     {"1,5-8*",  "1,6,10-12",
        2, { { 5,  6, TRUE  }, { 9, 12, TRUE  } },
        1, { { 4,  8, FALSE } },
        1, { { 9, 12, TRUE  } },
        2, { { 4,  5, FALSE }, { 6,  8, FALSE } } },
 
       /* Empty range diffs */
-      {"/A: 3-9",  "",
+      {"3-9",  "",
        0, { { 0, 0, FALSE } },
        1, { { 2, 9, TRUE  } },
        0, { { 0, 0, FALSE } },
        1, { { 2, 9, TRUE  } } },
 
-      {"/A: 3-9*",  "",
+      {"3-9*",  "",
        0, { { 0, 0, FALSE } },
        1, { { 2, 9, FALSE } },
        0, { { 0, 0, FALSE } },
        1, { { 2, 9, FALSE } } },
 
-      {"",  "/A: 3-9",
+      {"",  "3-9",
        1, { { 2, 9, TRUE  } },
        0, { { 0, 0, FALSE } },
        1, { { 2, 9, TRUE  } },
        0, { { 0, 0, FALSE } } },
 
-      {"",  "/A: 3-9*",
+      {"",  "3-9*",
        1, { { 2, 9, FALSE } },
        0, { { 0, 0, FALSE } },
        1, { { 2, 9, FALSE } },
@@ -1520,10 +1513,8 @@ test_rangelist_diff(apr_pool_t *pool)
   err = child_err = SVN_NO_ERROR;
   for (i = 0; i < SIZE_OF_RANGE_DIFF_TEST_ARRAY; i++)
     {
-      SVN_ERR(svn_mergeinfo_parse(&info1, (test_data[i]).to, pool));
-      SVN_ERR(svn_mergeinfo_parse(&info2, (test_data[i]).from, pool));
-      to = apr_hash_get(info1, "/A", APR_HASH_KEY_STRING);
-      from = apr_hash_get(info2, "/A", APR_HASH_KEY_STRING);
+      SVN_ERR(svn_rangelist__parse(&to, test_data[i].to, pool));
+      SVN_ERR(svn_rangelist__parse(&from, test_data[i].from, pool));
 
       /* Represent empty mergeinfo with an empty rangelist. */
       if (to == NULL)
@@ -1711,7 +1702,7 @@ struct svn_test_descriptor_t test_funcs[
                    "turning rangelist back into a string"),
     SVN_TEST_PASS2(test_mergeinfo_to_string,
                    "turning mergeinfo back into a string"),
-    SVN_TEST_PASS2(test_rangelist_merge,
+    SVN_TEST_XFAIL2(test_rangelist_merge,
                    "merge of rangelists"),
     SVN_TEST_PASS2(test_rangelist_diff,
                    "diff of rangelists"),