Debugging and clarifications for assertion failure in merge_tests.py 125,
aka issue #3432 'Merge can record mergeinfo from natural history gaps'.

* subversion/include/svn_ra.h
  (svn_ra_get_location_segments): 

* subversion/include/svn_types.h
  (svn_location_segment_t): 

* subversion/libsvn_client/merge.c
  (find_gaps_in_merge_source_history): 
  (compare_merge_source_ts): 
  (normalize_merge_sources_internal): 
  (do_mergeinfo_aware_dir_merge): 

* subversion/libsvn_client/mergeinfo.h
  (svn_client__get_history_as_mergeinfo): 
--This line, and those below, will be ignored--

Index: subversion/include/svn_ra.h
===================================================================
--- subversion/include/svn_ra.h	(revision 1414688)
+++ subversion/include/svn_ra.h	(working copy)
@@ -1634,6 +1634,12 @@ svn_ra_get_locations(svn_ra_session_t *s
  * @a peg_revision may be @c SVN_INVALID_REVNUM to indicate "the HEAD
  * revision", and must evaluate to be at least as young as @a start_rev.
  *
+ * The sequence of segments passed to @a receiver will describe adjacent,
+ * non-overlapping ranges of revisions.  The highest reported revision
+ * (@c range_end of the first segment) will always be @a start_rev, and the
+ * lowest reported revision (@c range_start of the last segment) will be
+ * @a end_rev or the origin of the object, whichever is higher.
+ *
  * Use @a pool for all allocations.
  *
  * @since New in 1.5.
Index: subversion/include/svn_types.h
===================================================================
--- subversion/include/svn_types.h	(revision 1414688)
+++ subversion/include/svn_types.h	(working copy)
@@ -1212,7 +1212,7 @@ svn_merge_range_contains_rev(const svn_m
  *  @{ */
 
 /**
- * A representation of a segment of a object's version history with an
+ * A representation of a segment of an object's version history with an
  * emphasis on the object's location in the repository as of various
  * revisions.
  *
@@ -1221,7 +1221,7 @@ svn_merge_range_contains_rev(const svn_m
 typedef struct svn_location_segment_t
 {
   /** The beginning (oldest) and ending (youngest) revisions for this
-      segment. */
+      segment, both inclusive. */
   svn_revnum_t range_start;
   svn_revnum_t range_end;
 
Index: subversion/libsvn_client/merge.c
===================================================================
--- subversion/libsvn_client/merge.c	(revision 1414688)
+++ subversion/libsvn_client/merge.c	(working copy)
@@ -215,7 +215,14 @@
 
 /*** Repos-Diff Editor Callbacks ***/
 
-/* */
+/* A forward or reverse segment of an object's history, representing a
+   source-side diff within a merge.
+
+   This may represent a single contiguous segment of history as described
+   under 'MERGEINFO MERGE SOURCE NORMALIZATION' in which case ANCESTRAL must
+   be true, or any arbitrary segment of history in which case ANCESTRAL may
+   be true or false.
+*/
 typedef struct merge_source_t
 {
   /* "left" side URL and revision (inclusive iff youngest) */
@@ -4384,6 +4391,9 @@ find_gaps_in_merge_source_history(svn_re
   SVN_ERR_ASSERT(*gap_start == MIN(source->loc1->rev, source->loc2->rev)
                  || (*gap_start == SVN_INVALID_REVNUM
                      && *gap_end == SVN_INVALID_REVNUM));
+  SVN_ERR_ASSERT(*gap_end > *gap_start
+                 || (*gap_start == SVN_INVALID_REVNUM
+                     && *gap_end == SVN_INVALID_REVNUM));
   return SVN_NO_ERROR;
 }
 
@@ -6407,12 +6417,24 @@ compare_merge_source_ts(const void *a,
   return a_rev < b_rev ? 1 : -1;
 }
 
-/* Set *MERGE_SOURCE_TS_P to a list of merge sources generated by
-   slicing history location SEGMENTS with a given requested merge
-   RANGE.  Use SOURCE_LOC for full source URL calculation.
+/* Slice the location history SEGMENTS with the revision range RANGE.
+
+   Set *MERGE_SOURCE_TS_P to a list of (merge_source_t *) merge sources
+   representing the instersection of the SEGMENTS with the requested
+   forward or reverse merge range RANGE.
+
+   ### RANGE represents an (exclusive:inclusive? / inclusive?)
+   range.  For example:
+
+     RANGE    { start=2, end=9 }                     ### TODO...
+     SEGMENTS { {2,2,'A'}, {3,7,NULL}, {8,9,'B'} }   ### TODO...
+     OUTPUT   { }                                    ### TODO...
+
+   Obtain the repository root URL and UUID from SOURCE_LOC.
 
    Order the merge sources in *MERGE_SOURCE_TS_P from oldest to
-   youngest. */
+   youngest.
+*/
 static svn_error_t *
 combine_range_with_segments(apr_array_header_t **merge_source_ts_p,
                             const svn_merge_range_t *range,
@@ -6535,9 +6557,13 @@ normalize_merge_sources_internal(apr_arr
   if (merge_range_ts->nelts == 0)
     return SVN_NO_ERROR;
 
-  /* Find the extremes of the revisions across our set of ranges. */
+  /* Find the extremes of the revisions across our set of ranges.  These
+     are the inclusive bounds on the history segment of interest.  (If we
+     think of revision numbers as identifying changes to be merged, then
+     OLDEST_REQUESTED is exclusive and YOUNGEST_REQUESTED is inclusive.) */
   merge_range_find_extremes(&oldest_requested, &youngest_requested,
                             merge_range_ts);
+  SVN_DBG(("oldest %ld, youngest %ld", oldest_requested, youngest_requested));
 
   /* ### FIXME:  Our underlying APIs can't yet handle the case where
      the peg revision isn't the youngest of the three revisions.  So
@@ -6563,6 +6589,14 @@ normalize_merge_sources_internal(apr_arr
                                               oldest_requested,
                                               ctx, result_pool));
 
+  SVN_DBG(("Location segments:"));
+  for (i = 0; i < segments->nelts; i++)
+    {
+      svn_location_segment_t *s = APR_ARRAY_IDX(segments, i, svn_location_segment_t *);
+
+      SVN_DBG(("%3d: %ld-%ld '%s'", i, s->range_start, s->range_end, s->path));
+    }
+
   /* See if we fetched enough history to do the job.  "Surely we did,"
      you say.  "After all, we covered the entire requested merge
      range."  Yes, that's true, but if our first segment doesn't
@@ -6572,15 +6606,15 @@ normalize_merge_sources_internal(apr_arr
   trim_revision = SVN_INVALID_REVNUM;
   if (segments->nelts)
     {
-      svn_location_segment_t *segment =
+      svn_location_segment_t *first_segment =
         APR_ARRAY_IDX(segments, 0, svn_location_segment_t *);
 
       /* If the first segment doesn't start with the OLDEST_REQUESTED
          revision, we'll need to pass a trim revision to our range
          cruncher. */
-      if (segment->range_start != oldest_requested)
+      if (first_segment->range_start != oldest_requested)
         {
-          trim_revision = segment->range_start;
+          trim_revision = first_segment->range_start;
         }
 
       /* Else, if the first segment has no path (and therefore is a
@@ -6594,7 +6628,7 @@ normalize_merge_sources_internal(apr_arr
          ### really penalize clients hitting pre-1.5 repositories with
          ### the typical small merge range request (because of the
          ### lack of a node-origins cache in the repository).  */
-      else if (! segment->path)
+      else if (! first_segment->path)
         {
           if (segments->nelts > 1)
             {
@@ -6626,7 +6660,7 @@ normalize_merge_sources_internal(apr_arr
                   new_segment->path = original_repos_relpath;
                   new_segment->range_start = original_revision;
                   new_segment->range_end = original_revision;
-                  segment->range_start = original_revision + 1;
+                  first_segment->range_start = original_revision + 1;  /* ### variable not used */
                   svn_sort__array_insert(&new_segment, segments, 0);
                 }
             }
@@ -6664,6 +6698,15 @@ normalize_merge_sources_internal(apr_arr
       apr_array_cat(*merge_sources_p, merge_sources);
     }
 
+  SVN_DBG(("Resulting merge_source_ts:"));
+  for (i = 0; i < (*merge_sources_p)->nelts; i++)
+    {
+      merge_source_t *s = APR_ARRAY_IDX(*merge_sources_p, i, merge_source_t *);
+
+      SVN_DBG(("%3d: %ld '%s'", i, s->loc1->rev, s->loc2->url+40));
+      SVN_DBG(("     %ld '%s'",    s->loc2->rev, s->loc2->url+40));
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -8888,6 +8931,8 @@ do_mergeinfo_aware_dir_merge(svn_mergein
 
 /* Helper for do_merge() when the merge target is a directory.
 
+   If honoring mergeinfo, then SOURCE must represent a single 'ancestral'
+   segment as described under 'MERGEINFO MERGE SOURCE NORMALIZATION'.
 */
 static svn_error_t *
 do_directory_merge(svn_mergeinfo_catalog_t result_catalog,
Index: subversion/libsvn_client/mergeinfo.h
===================================================================
--- subversion/libsvn_client/mergeinfo.h	(revision 1414688)
+++ subversion/libsvn_client/mergeinfo.h	(working copy)
@@ -292,9 +292,10 @@ svn_client__get_wc_or_repos_mergeinfo_ca
 /* Set *MERGEINFO_P to a mergeinfo constructed solely from the
    natural history of PATHREV.
 
-   If RANGE_YOUNGEST and RANGE_OLDEST are valid, use them to bound the
-   revision ranges of returned mergeinfo.  They are governed by the same
-   rules as the PEG_REVISION, START_REV, and END_REV parameters of
+   If RANGE_YOUNGEST and RANGE_OLDEST are valid, use them as inclusive
+   bounds on the revision ranges of returned mergeinfo.  PATHREV->rev,
+   RANGE_YOUNGEST and RANGE_OLDEST are governed by the same rules as the
+   PEG_REVISION, START_REV, and END_REV parameters (respectively) of
    svn_ra_get_location_segments().
 
    If HAS_REV_ZERO_HISTORY is not NULL, then set *HAS_REV_ZERO_HISTORY to
