You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by pb...@apache.org on 2010/05/27 18:00:39 UTC

svn commit: r948873 [4/4] - in /subversion/trunk/subversion/tests/cmdline: merge_reintegrate_tests.py merge_tests.py merge_tree_conflict_tests.py

Copied: subversion/trunk/subversion/tests/cmdline/merge_tree_conflict_tests.py (from r948821, subversion/trunk/subversion/tests/cmdline/merge_tests.py)
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_tree_conflict_tests.py?p2=subversion/trunk/subversion/tests/cmdline/merge_tree_conflict_tests.py&p1=subversion/trunk/subversion/tests/cmdline/merge_tests.py&r1=948821&r2=948873&rev=948873&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_tree_conflict_tests.py Thu May 27 16:00:39 2010
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-#  merge_tests.py:  testing merge
+#  merge_tests.py:  testing tree conflicts during merge
 #
 #  Subversion is a tool for revision control.
 #  See http://subversion.apache.org for more information.
@@ -40,496 +40,13 @@ SkipUnless = svntest.testcase.SkipUnless
 
 from svntest.main import SVN_PROP_MERGEINFO
 from svntest.main import server_has_mergeinfo
-from svntest.main import is_fs_case_insensitive
-from svntest.actions import fill_file_with_lines
-from svntest.actions import make_conflict_marker_text
-from svntest.actions import inject_conflict_into_expected_state
-
-def expected_merge_output(rev_ranges, additional_lines=None, foreign=False,
-                          elides=False, two_url=False):
-  """Generate an (inefficient) regex representing the expected merge
-  output and mergeinfo notifications from REV_RANGES (a list of 'range' lists
-  of the form [start, end] or [single_rev] --> [single_rev - 1, single_rev]),
-  and ADDITIONAL_LINES (a list of strings).  If REV_RANGES is None then only
-  the standard notification for a 3-way merge is expected.  If ELIDES is true
-  add to the regex an expression representing elision notification.  If TWO_URL
-  us true tweak the regex to expect the appropriate mergeinfo notification
-  for a 3-way merge."""
-  if rev_ranges is None:
-    lines = [svntest.main.merge_notify_line(None, None, False, foreign)]
-  else:
-    lines = []
-    for rng in rev_ranges:
-      start_rev = rng[0]
-      if len(rng) > 1:
-        end_rev = rng[1]
-      else:
-        end_rev = None
-      lines += [svntest.main.merge_notify_line(start_rev, end_rev,
-                                               True, foreign)]
-      lines += [svntest.main.mergeinfo_notify_line(start_rev, end_rev)]
-
-  if (elides):
-    lines += ["--- Eliding mergeinfo from .*\n"]
-
-  if (two_url):
-    lines += ["--- Recording mergeinfo for merge between repository URLs .*\n"]
-
-  if isinstance(additional_lines, list):
-    # Address "The Backslash Plague"
-    #
-    # If ADDITIONAL_LINES are present there are possibly paths in it with
-    # multiple components and on Windows these components are separated with
-    # '\'.  These need to be escaped properly in the regexp for the match to
-    # work correctly.  See http://aspn.activestate.com/ASPN/docs/ActivePython
-    # /2.2/howto/regex/regex.html#SECTION000420000000000000000.
-    if sys.platform == 'win32':
-      for i in range(0, len(additional_lines)):
-        additional_lines[i] = additional_lines[i].replace("\\", "\\\\")
-    lines.extend(additional_lines)
-  else:
-    if sys.platform == 'win32' and additional_lines != None:
-      additional_lines = additional_lines.replace("\\", "\\\\")
-    lines.append(str(additional_lines))
-  return "|".join(lines)
-
-def check_mergeinfo_recursively(root_path, subpaths_mergeinfo):
-  """Check that the mergeinfo properties on and under ROOT_PATH are those in
-     SUBPATHS_MERGEINFO, a {path: mergeinfo-prop-val} dictionary."""
-  expected = svntest.verify.UnorderedOutput(
-    [path + ' - ' + subpaths_mergeinfo[path] + '\n'
-     for path in subpaths_mergeinfo])
-  svntest.actions.run_and_verify_svn(None, expected, [],
-                                     'propget', '-R', SVN_PROP_MERGEINFO,
-                                     root_path)
-
-######################################################################
-# Tests
-#
-#   Each test must return on success or raise on failure.
-
-
-#----------------------------------------------------------------------
-
-def textual_merges_galore(sbox):
-  "performing a merge, with mixed results"
-
-  ## The Plan:
-  ##
-  ## The goal is to test that "svn merge" does the right thing in the
-  ## following cases:
-  ##
-  ##   1 : _ :  Received changes already present in unmodified local file
-  ##   2 : U :  No local mods, received changes folded in without trouble
-  ##   3 : G :  Received changes already exist as local mods
-  ##   4 : G :  Received changes do not conflict with local mods
-  ##   5 : C :  Received changes conflict with local mods
-  ##
-  ## So first modify these files and commit:
-  ##
-  ##    Revision 2:
-  ##    -----------
-  ##    A/mu ............... add ten or so lines
-  ##    A/D/G/rho .......... add ten or so lines
-  ##
-  ## Now check out an "other" working copy, from revision 2.
-  ##
-  ## Next further modify and commit some files from the original
-  ## working copy:
-  ##
-  ##    Revision 3:
-  ##    -----------
-  ##    A/B/lambda ......... add ten or so lines
-  ##    A/D/G/pi ........... add ten or so lines
-  ##    A/D/G/tau .......... add ten or so lines
-  ##    A/D/G/rho .......... add an additional ten or so lines
-  ##
-  ## In the other working copy (which is at rev 2), update rho back
-  ## to revision 1, while giving other files local mods.  This sets
-  ## things up so that "svn merge -r 1:3" will test all of the above
-  ## cases except case 4:
-  ##
-  ##    case 1: A/mu .......... do nothing, the only change was in rev 2
-  ##    case 2: A/B/lambda .... do nothing, so we accept the merge easily
-  ##    case 3: A/D/G/pi ...... add same ten lines as committed in rev 3
-  ##    case 5: A/D/G/tau ..... add ten or so lines at the end
-  ##    [none]: A/D/G/rho ..... ignore what happens to this file for now
-  ##
-  ## Now run
-  ##
-  ##    $ cd wc.other
-  ##    $ svn merge -r 1:3 url-to-repo
-  ##
-  ## ...and expect the right output.
-  ##
-  ## Now revert rho, then update it to revision 2, then *prepend* a
-  ## bunch of lines, which will be separated by enough distance from
-  ## the changes about to be received that the merge will be clean.
-  ##
-  ##    $ cd wc.other/A/D/G
-  ##    $ svn merge -r 2:3 url-to-repo/A/D/G
-  ##
-  ## Which tests case 4.  (Ignore the changes to the other files,
-  ## we're only interested in rho here.)
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-  #  url = os.path.join(svntest.main.test_area_url, sbox.repo_dir)
-
-  # Change mu and rho for revision 2
-  mu_path = os.path.join(wc_dir, 'A', 'mu')
-  rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
-  mu_text = fill_file_with_lines(mu_path, 2)
-  rho_text = fill_file_with_lines(rho_path, 2)
-
-  # Create expected output tree for initial commit
-  expected_output = wc.State(wc_dir, {
-    'A/mu' : Item(verb='Sending'),
-    'A/D/G/rho' : Item(verb='Sending'),
-    })
-
-  # Create expected status tree; all local revisions should be at 1,
-  # but mu and rho should be at revision 2.
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.tweak('A/mu', 'A/D/G/rho', wc_rev=2)
-
-  # Initial commit.
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None,
-                                        wc_dir)
-
-  # Make the "other" working copy
-  other_wc = sbox.add_wc_path('other')
-  svntest.actions.duplicate_dir(wc_dir, other_wc)
-
-  # Now commit some more mods from the original working copy, to
-  # produce revision 3.
-  lambda_path = os.path.join(wc_dir, 'A', 'B', 'lambda')
-  pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
-  tau_path = os.path.join(wc_dir, 'A', 'D', 'G', 'tau')
-
-  lambda_text = fill_file_with_lines(lambda_path, 2)
-  pi_text = fill_file_with_lines(pi_path, 2)
-  tau_text = fill_file_with_lines(tau_path, 2)
-  additional_rho_text = fill_file_with_lines(rho_path, 2)
-
-  # Created expected output tree for 'svn ci'
-  expected_output = wc.State(wc_dir, {
-    'A/B/lambda' : Item(verb='Sending'),
-    'A/D/G/pi' : Item(verb='Sending'),
-    'A/D/G/tau' : Item(verb='Sending'),
-    'A/D/G/rho' : Item(verb='Sending'),
-    })
-
-  # Create expected status tree.
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.tweak('A/mu', wc_rev=2)
-  expected_status.tweak('A/B/lambda', 'A/D/G/pi', 'A/D/G/tau', 'A/D/G/rho',
-                        wc_rev=3)
-
-  # Commit revision 3.
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None,
-                                        wc_dir)
-
-  # Make local mods in wc.other
-  other_pi_path = os.path.join(other_wc, 'A', 'D', 'G', 'pi')
-  other_rho_path = os.path.join(other_wc, 'A', 'D', 'G', 'rho')
-  other_tau_path = os.path.join(other_wc, 'A', 'D', 'G', 'tau')
-
-  # For A/mu and A/B/lambda, we do nothing.  For A/D/G/pi, we add the
-  # same ten lines as were already committed in revision 3.
-  # (Remember, wc.other is only at revision 2, so it doesn't have
-  # these changes.)
-  svntest.main.file_append(other_pi_path, pi_text)
-
-  # We skip A/D/G/rho in this merge; it will be tested with a separate
-  # merge command.  Temporarily put it back to revision 1, so this
-  # merge succeeds cleanly.
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'up', '-r', '1', other_rho_path)
-
-  # For A/D/G/tau, we append few different lines, to conflict with the
-  # few lines appended in revision 3.
-  other_tau_text = fill_file_with_lines(other_tau_path, 2,
-                                        line_descrip="Conflicting line")
-
-  # Do the first merge, revs 1:3.  This tests all the cases except
-  # case 4, which we'll handle in a second pass.
-  expected_output = wc.State(other_wc, {'A/B/lambda' : Item(status='U '),
-                                        'A/D/G/rho'  : Item(status='U '),
-                                        'A/D/G/tau'  : Item(status='C '),
-                                        })
-  expected_mergeinfo_output = wc.State(other_wc, {''  : Item(status=' U')})
-  expected_elision_output = wc.State(other_wc, {})
-  expected_disk = svntest.main.greek_state.copy()
-  expected_disk.tweak('A/mu',
-                      contents=expected_disk.desc['A/mu'].contents
-                      + mu_text)
-  expected_disk.tweak('A/B/lambda',
-                      contents=expected_disk.desc['A/B/lambda'].contents
-                      + lambda_text)
-  expected_disk.tweak('A/D/G/rho',
-                      contents=expected_disk.desc['A/D/G/rho'].contents
-                      + rho_text + additional_rho_text)
-  expected_disk.tweak('A/D/G/pi',
-                      contents=expected_disk.desc['A/D/G/pi'].contents
-                      + pi_text)
-
-  expected_status = svntest.actions.get_virginal_state(other_wc, 1)
-  expected_status.tweak('', status=' M')
-  expected_status.tweak('A/mu', wc_rev=2)
-  expected_status.tweak('A/B/lambda', status='M ')
-  expected_status.tweak('A/D/G/pi', status='M ')
-  expected_status.tweak('A/D/G/rho', status='M ')
-
-  inject_conflict_into_expected_state('A/D/G/tau', expected_disk,
-                                      expected_status, other_tau_text, tau_text,
-                                      3)
-
-  expected_skip = wc.State('', { })
-
-  tau_conflict_support_files = ["tau\.working",
-                                "tau\.merge-right\.r3",
-                                "tau\.merge-left\.r1"]
-
-  svntest.actions.run_and_verify_merge(other_wc, '1', '3',
-                                       sbox.repo_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None,
-                                       svntest.tree.detect_conflict_files,
-                                       list(tau_conflict_support_files))
-
-  # Now reverse merge r3 into A/D/G/rho, give it non-conflicting local
-  # mods, then merge in the 2:3 change.  ### Not bothering to do the
-  # whole expected_foo routine for these intermediate operations;
-  # they're not what we're here to test, after all, so it's enough to
-  # know that they worked.  Is this a bad practice? ###
-  #
-  # run_and_verify_merge doesn't support merging to a file WCPATH
-  # so use run_and_verify_svn.
-  svntest.actions.run_and_verify_svn(
-    None,
-    expected_merge_output([[-3]],
-                          ['G    ' + other_rho_path + '\n',
-                           ' G   ' + other_rho_path + '\n',]),
-    [], 'merge', '-c-3',
-    sbox.repo_url + '/A/D/G/rho',
-    other_rho_path)
-
-  # Now *prepend* ten or so lines to A/D/G/rho.  Since rho had ten
-  # lines appended in revision 2, and then another ten in revision 3,
-  # these new local mods will be separated from the rev 3 changes by
-  # enough distance that they won't conflict, so the merge should be
-  # clean.
-  other_rho_text = ""
-  for x in range(1,10):
-    other_rho_text = other_rho_text + 'Unobtrusive line ' + repr(x) + ' in rho\n'
-  current_other_rho_text = open(other_rho_path).read()
-  svntest.main.file_write(other_rho_path,
-                          other_rho_text + current_other_rho_text)
-
-  # We expect no merge attempt for pi and tau because they inherit
-  # mergeinfo from the WC root.  There is explicit mergeinfo on rho
-  # ('/A/D/G/rho:2') so expect it to be merged (cleanly).
-  G_path = os.path.join(other_wc, 'A', 'D', 'G')
-  expected_output = wc.State(os.path.join(other_wc, 'A', 'D', 'G'),
-                             {'rho' : Item(status='G ')})
-  expected_mergeinfo_output = wc.State(G_path, {
-    ''    : Item(status=' G'),
-    'rho' : Item(status=' G')
-    })
-  expected_elision_output = wc.State(G_path, {
-    ''    : Item(status=' U'),
-    'rho' : Item(status=' U')
-    })
-  expected_disk = wc.State("", {
-    'pi'    : Item("This is the file 'pi'.\n"),
-    'rho'   : Item("This is the file 'rho'.\n"),
-    'tau'   : Item("This is the file 'tau'.\n"),
-    })
-  expected_disk.tweak('rho',
-                      contents=other_rho_text
-                      + expected_disk.desc['rho'].contents
-                      + rho_text
-                      + additional_rho_text)
-  expected_disk.tweak('pi',
-                      contents=expected_disk.desc['pi'].contents
-                      + pi_text)
-
-  expected_status = wc.State(os.path.join(other_wc, 'A', 'D', 'G'),
-                             { ''     : Item(wc_rev=1, status='  '),
-                               'rho'  : Item(wc_rev=1, status='M '),
-                               'pi'   : Item(wc_rev=1, status='M '),
-                               'tau'  : Item(wc_rev=1, status='C '),
-                               })
-
-  inject_conflict_into_expected_state('tau', expected_disk, expected_status,
-                                      other_tau_text, tau_text, 3)
-
-  # Do the merge, but check svn:mergeinfo props separately since
-  # run_and_verify_merge would attempt to proplist tau's conflict
-  # files if we asked it to check props.
-  svntest.actions.run_and_verify_merge(
-    os.path.join(other_wc, 'A', 'D', 'G'),
-    '2', '3',
-    sbox.repo_url + '/A/D/G', None,
-    expected_output,
-    expected_mergeinfo_output,
-    expected_elision_output,
-    expected_disk,
-    expected_status,
-    expected_skip,
-    None,
-    svntest.tree.detect_conflict_files, list(tau_conflict_support_files))
-
-
-  svntest.actions.run_and_verify_svn(None, [], [],
-                                     'propget', SVN_PROP_MERGEINFO,
-                                     os.path.join(other_wc,
-                                                  "A", "D", "G", "rho"))
-
-
-#----------------------------------------------------------------------
-
-# Merge should copy-with-history when adding files or directories
-
-def add_with_history(sbox):
-  "merge and add new files/dirs with history"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  C_path = os.path.join(wc_dir, 'A', 'C')
-  F_path = os.path.join(wc_dir, 'A', 'B', 'F')
-  F_url = sbox.repo_url + '/A/B/F'
-
-  Q_path = os.path.join(F_path, 'Q')
-  Q2_path = os.path.join(F_path, 'Q2')
-  foo_path = os.path.join(F_path, 'foo')
-  foo2_path = os.path.join(F_path, 'foo2')
-  bar_path = os.path.join(F_path, 'Q', 'bar')
-  bar2_path = os.path.join(F_path, 'Q', 'bar2')
-
-  svntest.main.run_svn(None, 'mkdir', Q_path)
-  svntest.main.run_svn(None, 'mkdir', Q2_path)
-  svntest.main.file_append(foo_path, "foo")
-  svntest.main.file_append(foo2_path, "foo2")
-  svntest.main.file_append(bar_path, "bar")
-  svntest.main.file_append(bar2_path, "bar2")
-  svntest.main.run_svn(None, 'add', foo_path, foo2_path, bar_path, bar2_path)
-  svntest.main.run_svn(None, 'propset', 'x', 'x', Q2_path)
-  svntest.main.run_svn(None, 'propset', 'y', 'y', foo2_path)
-  svntest.main.run_svn(None, 'propset', 'z', 'z', bar2_path)
-
-  expected_output = wc.State(wc_dir, {
-    'A/B/F/Q'     : Item(verb='Adding'),
-    'A/B/F/Q2'    : Item(verb='Adding'),
-    'A/B/F/Q/bar' : Item(verb='Adding'),
-    'A/B/F/Q/bar2': Item(verb='Adding'),
-    'A/B/F/foo'   : Item(verb='Adding'),
-    'A/B/F/foo2'  : Item(verb='Adding'),
-    })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.add({
-    'A/B/F/Q'     : Item(status='  ', wc_rev=2),
-    'A/B/F/Q2'    : Item(status='  ', wc_rev=2),
-    'A/B/F/Q/bar' : Item(status='  ', wc_rev=2),
-    'A/B/F/Q/bar2': Item(status='  ', wc_rev=2),
-    'A/B/F/foo'   : Item(status='  ', wc_rev=2),
-    'A/B/F/foo2'  : Item(status='  ', wc_rev=2),
-    })
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None,
-                                        wc_dir)
-
-  expected_output = wc.State(C_path, {
-    'Q'      : Item(status='A '),
-    'Q2'     : Item(status='A '),
-    'Q/bar'  : Item(status='A '),
-    'Q/bar2' : Item(status='A '),
-    'foo'    : Item(status='A '),
-    'foo2'   : Item(status='A '),
-    })
-  expected_mergeinfo_output = wc.State(C_path, {
-    '' : Item(status=' U'),
-    })
-  expected_elision_output = wc.State(C_path, {
-    })
-  expected_disk = wc.State('', {
-    ''       : Item(props={SVN_PROP_MERGEINFO : '/A/B/F:2'}),
-    'Q'      : Item(),
-    'Q2'     : Item(props={'x' : 'x'}),
-    'Q/bar'  : Item("bar"),
-    'Q/bar2' : Item("bar2", props={'z' : 'z'}),
-    'foo'    : Item("foo"),
-    'foo2'   : Item("foo2", props={'y' : 'y'}),
-    })
-  expected_status = wc.State(C_path, {
-    ''       : Item(status=' M', wc_rev=1),
-    'Q'      : Item(status='A ', wc_rev='-', copied='+'),
-    'Q2'     : Item(status='A ', wc_rev='-', copied='+'),
-    'Q/bar'  : Item(status='  ', wc_rev='-', copied='+'),
-    'Q/bar2' : Item(status='  ', wc_rev='-', copied='+'),
-    'foo'    : Item(status='A ', wc_rev='-', copied='+'),
-    'foo2'   : Item(status='A ', wc_rev='-', copied='+'),
-    })
-
-  expected_skip = wc.State(C_path, { })
-
-  svntest.actions.run_and_verify_merge(C_path, '1', '2', F_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       1) # check props
-
-  expected_output = svntest.wc.State(wc_dir, {
-    'A/C'       : Item(verb='Sending'),
-    'A/C/Q'     : Item(verb='Adding'),
-    'A/C/Q2'    : Item(verb='Adding'),
-    'A/C/foo'   : Item(verb='Adding'),
-    'A/C/foo2'  : Item(verb='Adding'),
-    })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.add({
-    'A/C'         : Item(status='  ', wc_rev=3),
-    'A/B/F/Q'     : Item(status='  ', wc_rev=2),
-    'A/B/F/Q2'    : Item(status='  ', wc_rev=2),
-    'A/B/F/Q/bar' : Item(status='  ', wc_rev=2),
-    'A/B/F/Q/bar2': Item(status='  ', wc_rev=2),
-    'A/B/F/foo'   : Item(status='  ', wc_rev=2),
-    'A/B/F/foo2'  : Item(status='  ', wc_rev=2),
-    'A/C/Q'       : Item(status='  ', wc_rev=3),
-    'A/C/Q2'      : Item(status='  ', wc_rev=3),
-    'A/C/Q/bar'   : Item(status='  ', wc_rev=3),
-    'A/C/Q/bar2'  : Item(status='  ', wc_rev=3),
-    'A/C/foo'     : Item(status='  ', wc_rev=3),
-    'A/C/foo2'    : Item(status='  ', wc_rev=3),
-    })
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None,
-                                        wc_dir)
+from merge_tests import set_up_branch
+from merge_tests import svn_commit
+from merge_tests import svn_delete
+from merge_tests import svn_copy
+from merge_tests import svn_merge
 
 #----------------------------------------------------------------------
-
-# This test involves tree conflicts.
 def delete_file_and_dir(sbox):
   "merge that deletes items"
 
@@ -640,229 +157,8 @@ def delete_file_and_dir(sbox):
                                        None, None, None, None, None,
                                        True)
 
-
-#----------------------------------------------------------------------
-
-# Issue 953
-def simple_property_merges(sbox):
-  "some simple property merges"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  # Add a property to a file and a directory
-  alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
-  beta_path = os.path.join(wc_dir, 'A', 'B', 'E', 'beta')
-  E_path = os.path.join(wc_dir, 'A', 'B', 'E')
-
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'foo', 'foo_val',
-                                     alpha_path)
-  # A binary, non-UTF8 property value
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'foo', 'foo\201val',
-                                     beta_path)
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'foo', 'foo_val',
-                                     E_path)
-
-  # Commit change as rev 2
-  expected_output = svntest.wc.State(wc_dir, {
-    'A/B/E'       : Item(verb='Sending'),
-    'A/B/E/alpha' : Item(verb='Sending'),
-    'A/B/E/beta'  : Item(verb='Sending'),
-    })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta',
-                        wc_rev=2, status='  ')
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output, expected_status,
-                                        None, wc_dir)
-  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-
-  # Copy B to B2 as rev 3
-  B_url = sbox.repo_url + '/A/B'
-  B2_url = sbox.repo_url + '/A/B2'
-
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'copy', '-m', 'copy B to B2',
-                                     B_url, B2_url)
-  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-
-  # Modify a property and add a property for the file and directory
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'foo', 'mod_foo', alpha_path)
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'bar', 'bar_val', alpha_path)
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'foo', 'mod\201foo', beta_path)
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'bar', 'bar\201val', beta_path)
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'foo', 'mod_foo', E_path)
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'bar', 'bar_val', E_path)
-
-  # Commit change as rev 4
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
-  expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta',
-                        wc_rev=4, status='  ')
-  expected_status.add({
-    'A/B2'         : Item(status='  ', wc_rev=3),
-    'A/B2/E'       : Item(status='  ', wc_rev=3),
-    'A/B2/E/alpha' : Item(status='  ', wc_rev=3),
-    'A/B2/E/beta'  : Item(status='  ', wc_rev=3),
-    'A/B2/F'       : Item(status='  ', wc_rev=3),
-    'A/B2/lambda'  : Item(status='  ', wc_rev=3),
-    })
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output, expected_status,
-                                        None, wc_dir)
-  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-
-  pristine_status = expected_status
-  pristine_status.tweak(wc_rev=4)
-
-  # Merge B 3:4 into B2
-  B2_path = os.path.join(wc_dir, 'A', 'B2')
-  expected_output = wc.State(B2_path, {
-    'E'        : Item(status=' U'),
-    'E/alpha'  : Item(status=' U'),
-    'E/beta'   : Item(status=' U'),
-    })
-  expected_mergeinfo_output = wc.State(B2_path, {
-    '' : Item(status=' U'),
-    })
-  expected_elision_output = wc.State(B2_path, {
-    })
-  expected_disk = wc.State('', {
-    ''         : Item(props={SVN_PROP_MERGEINFO : '/A/B:4'}),
-    'E'        : Item(),
-    'E/alpha'  : Item("This is the file 'alpha'.\n"),
-    'E/beta'   : Item("This is the file 'beta'.\n"),
-    'F'        : Item(),
-    'lambda'   : Item("This is the file 'lambda'.\n"),
-    })
-  expected_disk.tweak('E', 'E/alpha',
-                      props={'foo' : 'mod_foo', 'bar' : 'bar_val'})
-  expected_disk.tweak('E/beta',
-                      props={'foo' : 'mod\201foo', 'bar' : 'bar\201val'})
-  expected_status = wc.State(B2_path, {
-    ''        : Item(status=' M'),
-    'E'       : Item(status=' M'),
-    'E/alpha' : Item(status=' M'),
-    'E/beta'  : Item(status=' M'),
-    'F'       : Item(status='  '),
-    'lambda'  : Item(status='  '),
-    })
-  expected_status.tweak(wc_rev=4)
-  expected_skip = wc.State('', { })
-  svntest.actions.run_and_verify_merge(B2_path, '3', '4', B_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None, 1)
-
-  # Revert merge
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'revert', '--recursive', wc_dir)
-  svntest.actions.run_and_verify_status(wc_dir, pristine_status)
-
-  # Merge B 2:1 into B2 (B2's mergeinfo should get elided away)
-  expected_status.tweak('', status='  ')
-  expected_disk.remove('')
-  expected_disk.tweak('E', 'E/alpha', 'E/beta', props={})
-  expected_elision_output = wc.State(B2_path, {
-    '' : Item(status=' U'),
-    })
-  svntest.actions.run_and_verify_merge(B2_path, '2', '1', B_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None, 1)
-
-  def error_message(property, old_value, new_value):
-    return "Trying to change property '%s' from '%s' to '%s',\n" \
-           "but it has been locally deleted.\n" % (property, old_value, new_value)
-
-  # Merge B 3:4 into B2 now causes a conflict
-  expected_disk.add({
-    '' : Item(props={SVN_PROP_MERGEINFO : '/A/B:4'}),
-    'E/dir_conflicts.prej'
-    : Item(error_message('foo', 'foo_val', 'mod_foo')),
-    'E/alpha.prej'
-    : Item(error_message('foo', 'foo_val', 'mod_foo')),
-    'E/beta.prej'
-    : Item(error_message('foo', 'foo?\\129val', 'mod?\\129foo')),
-    })
-  expected_disk.tweak('E', 'E/alpha', props={'bar' : 'bar_val'})
-  expected_disk.tweak('E/beta', props={'bar' : 'bar\201val'})
-  expected_status.tweak('', status=' M')
-  expected_status.tweak('E', 'E/alpha', 'E/beta', status=' C')
-  expected_output.tweak('E', 'E/alpha', 'E/beta', status=' C')
-  expected_elision_output = wc.State(B2_path, {
-    })
-  svntest.actions.run_and_verify_merge(B2_path, '3', '4', B_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None, 1)
-
-  # issue 1109 : single file property merge.  This test performs a merge
-  # that should be a no-op (adding properties that are already present).
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'revert', '--recursive', wc_dir)
-  svntest.actions.run_and_verify_status(wc_dir, pristine_status)
-
-  # Copy A at rev 4 to A2 to make revision 5.
-  A_url = sbox.repo_url + '/A'
-  A2_url = sbox.repo_url + '/A2'
-  svntest.actions.run_and_verify_svn(None,
-                                     ['\n', 'Committed revision 5.\n'], [],
-                                     'copy', '-m', 'copy A to A2',
-                                     A_url, A2_url)
-
-  # Re-root the WC at A2.
-  svntest.actions.run_and_verify_svn(None, None, [], 'switch', A2_url, wc_dir)
-
-  # Attempt to re-merge rev 4 of the original A's alpha.  Mergeinfo
-  # inherited from A2 (created by its copy from A) allows us to avoid
-  # a repeated merge.
-  alpha_url = sbox.repo_url + '/A/B/E/alpha'
-  alpha_path = os.path.join(wc_dir, 'B', 'E', 'alpha')
-
-  # Cannot use run_and_verify_merge with a file target
-  svntest.actions.run_and_verify_svn(None, [], [], 'merge', '-r', '3:4',
-                                     alpha_url, alpha_path)
-
-  exit_code, output, err = svntest.actions.run_and_verify_svn(None, None, [],
-                                                              'pl', alpha_path)
-
-  saw_foo = 0
-  saw_bar = 0
-  for line in output:
-    if re.match("\\s*foo\\s*$", line):
-      saw_foo = 1
-    if re.match("\\s*bar\\s*$", line):
-      saw_bar = 1
-
-  if not saw_foo or not saw_bar:
-    raise svntest.Failure("Expected properties not found")
-
-
 #----------------------------------------------------------------------
 # This is a regression for issue #1176.
-
-# This test involves tree conflicts.
 def merge_catches_nonexistent_target(sbox):
   "merge should not die if a target file is absent"
 
@@ -964,10 +260,7 @@ def merge_catches_nonexistent_target(sbo
     })
   svntest.actions.run_and_verify_unquiet_status('', expected_status)
 
-
 #----------------------------------------------------------------------
-
-# This test involves tree conflicts.
 def merge_tree_deleted_in_target(sbox):
   "merge on deleted directory in target"
 
@@ -1042,620 +335,38 @@ def merge_tree_deleted_in_target(sbox):
   svntest.actions.run_and_verify_unquiet_status(I_path, expected_status)
 
 #----------------------------------------------------------------------
-# Issue #2515
-
-# This test involves tree conflicts.
-def merge_added_dir_to_deleted_in_target(sbox):
-  "merge an added dir on a deleted dir in target"
+# Regression test for issue #2403: Incorrect 3-way merge of "added"
+# binary file which already exists (unmodified) in the WC
+def three_way_merge_add_of_existing_binary_file(sbox):
+  "3-way merge of 'file add' into existing binary"
 
   sbox.build()
   wc_dir = sbox.wc_dir
 
-  # copy B to a new directory, I.
-  # delete F in I.
-  # add J to B/F.
-  # merge add to I.
-
-  B_url = sbox.repo_url + '/A/B'
-  I_url = sbox.repo_url + '/A/I'
-  F_url = sbox.repo_url + '/A/I/F'
-  J_url = sbox.repo_url + '/A/B/F/J'
-  I_path = os.path.join(wc_dir, 'A', 'I')
-
-
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'cp', B_url, I_url, '-m', 'rev 2')
-
+  # Create a branch of A, creating revision 2.
+  A_url = sbox.repo_url + "/A"
+  branch_A_url = sbox.repo_url + "/copy-of-A"
   svntest.actions.run_and_verify_svn(None, None, [],
-                                     'rm', F_url, '-m', 'rev 3')
+                                     "cp",
+                                     A_url, branch_A_url,
+                                     "-m", "Creating copy-of-A")
 
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'mkdir', '-m', 'rev 4', J_url)
+  # Add a binary file to the WC.
+  theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read()
+  # Write PNG file data into 'A/theta'.
+  A_path = os.path.join(wc_dir, 'A')
+  theta_path = os.path.join(wc_dir, 'A', 'theta')
+  svntest.main.file_write(theta_path, theta_contents, 'wb')
 
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                      'up', os.path.join(wc_dir,'A'))
+  svntest.main.run_svn(None, "add", theta_path)
 
-  expected_output = wc.State(I_path, {
-    'F'       : Item(status='  ', treeconflict='C'),
-    })
-  expected_mergeinfo_output = wc.State(I_path, {
-    '' : Item(status=' U'),
-    })
-  expected_elision_output = wc.State(I_path, {
+  # Commit the new binary file to the repos, creating revision 3.
+  expected_output = svntest.wc.State(wc_dir, {
+    "A/theta" : Item(verb="Adding  (bin)"),
     })
-  expected_disk = wc.State('', {
-    'E'       : Item(),
-    'E/alpha' : Item("This is the file 'alpha'.\n"),
-    'E/beta'  : Item("This is the file 'beta'.\n"),
-    'lambda'  : Item("This is the file 'lambda'.\n"),
-    })
-  expected_skip = wc.State(I_path, {
-    })
-
-  svntest.actions.run_and_verify_merge(I_path, '2', '4', B_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       None,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       0, 0)
-
-#----------------------------------------------------------------------
-# This is a regression for issue #1176.
-
-def merge_similar_unrelated_trees(sbox):
-  "merging similar trees ancestrally unrelated"
-
-  ## See http://subversion.tigris.org/issues/show_bug.cgi?id=1249. ##
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  # Simple test.  Make three directories with the same content.
-  # Modify some stuff in the second one.  Now merge
-  # (firstdir:seconddir->thirddir).
-
-  base1_path = os.path.join(wc_dir, 'base1')
-  base2_path = os.path.join(wc_dir, 'base2')
-  apply_path = os.path.join(wc_dir, 'apply')
-
-  base1_url = os.path.join(sbox.repo_url + '/base1')
-  base2_url = os.path.join(sbox.repo_url + '/base2')
-
-  # Make a tree of stuff ...
-  os.mkdir(base1_path)
-  svntest.main.file_append(os.path.join(base1_path, 'iota'),
-                           "This is the file iota\n")
-  os.mkdir(os.path.join(base1_path, 'A'))
-  svntest.main.file_append(os.path.join(base1_path, 'A', 'mu'),
-                           "This is the file mu\n")
-  os.mkdir(os.path.join(base1_path, 'A', 'B'))
-  svntest.main.file_append(os.path.join(base1_path, 'A', 'B', 'alpha'),
-                           "This is the file alpha\n")
-  svntest.main.file_append(os.path.join(base1_path, 'A', 'B', 'beta'),
-                           "This is the file beta\n")
-
-  # ... Copy it twice ...
-  shutil.copytree(base1_path, base2_path)
-  shutil.copytree(base1_path, apply_path)
-
-  # ... Gonna see if merge is naughty or nice!
-  svntest.main.file_append(os.path.join(base2_path, 'A', 'mu'),
-                           "A new line in mu.\n")
-  os.rename(os.path.join(base2_path, 'A', 'B', 'beta'),
-            os.path.join(base2_path, 'A', 'B', 'zeta'))
-
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                  'add', base1_path, base2_path, apply_path)
-
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'ci', '-m', 'rev 2', wc_dir)
-
-  expected_output = wc.State(apply_path, {
-    'A/mu'     : Item(status='U '),
-    'A/B/zeta' : Item(status='A '),
-    'A/B/beta' : Item(status='D '),
-    })
-
-  # run_and_verify_merge doesn't support 'svn merge URL URL path'
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'merge',
-                                     '--ignore-ancestry',
-                                     base1_url, base2_url,
-                                     apply_path)
-
-  expected_status = wc.State(apply_path, {
-    ''            : Item(status='  '),
-    'A'           : Item(status='  '),
-    'A/mu'        : Item(status='M '),
-    'A/B'         : Item(status='  '),
-    'A/B/zeta'    : Item(status='A ', copied='+'),
-    'A/B/alpha'   : Item(status='  '),
-    'A/B/beta'    : Item(status='D '),
-    'iota'        : Item(status='  '),
-    })
-  expected_status.tweak(wc_rev=2)
-  expected_status.tweak('A/B/zeta', wc_rev='-')
-  svntest.actions.run_and_verify_status(apply_path, expected_status)
-
-#----------------------------------------------------------------------
-def merge_one_file_helper(sbox, arg_flav, record_only = 0):
-  "ARG_FLAV is one of 'r' (revision range) or 'c' (single change)."
-
-  if arg_flav not in ('r', 'c', '*'):
-    raise svntest.Failure("Unrecognized flavor of merge argument")
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  rho_rel_path = os.path.join('A', 'D', 'G', 'rho')
-  rho_path = os.path.join(wc_dir, rho_rel_path)
-  G_path = os.path.join(wc_dir, 'A', 'D', 'G')
-  rho_url = sbox.repo_url + '/A/D/G/rho'
-
-  # Change rho for revision 2
-  svntest.main.file_append(rho_path, 'A new line in rho.\n')
-
-  expected_output = wc.State(wc_dir, { rho_rel_path : Item(verb='Sending'), })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.tweak('A/D/G/rho', wc_rev=2)
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None,
-                                        wc_dir)
-
-  # Backdate rho to revision 1, so we can merge in the rev 2 changes.
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'up', '-r', '1', rho_path)
-
-  # Try one merge with an explicit target; it should succeed.
-  ### Yes, it would be nice to use run_and_verify_merge(), but it
-  # appears to be impossible to get the expected_foo trees working
-  # right.  I think something is still assuming a directory target.
-  if arg_flav == 'r':
-    svntest.actions.run_and_verify_svn(
-      None,
-      expected_merge_output([[2]],
-                            ['U    ' + rho_path + '\n',
-                             ' U   ' + rho_path + '\n']),
-      [], 'merge', '-r', '1:2', rho_url, rho_path)
-  elif arg_flav == 'c':
-    svntest.actions.run_and_verify_svn(
-      None,
-      expected_merge_output([[2]],
-                            ['U    ' + rho_path + '\n',
-                             ' U   ' + rho_path + '\n']),
-      [], 'merge', '-c', '2', rho_url, rho_path)
-  elif arg_flav == '*':
-    svntest.actions.run_and_verify_svn(
-      None,
-      expected_merge_output([[2]],
-                            ['U    ' + rho_path + '\n',
-                             ' U   ' + rho_path + '\n']),
-      [], 'merge', rho_url, rho_path)
-
-  expected_status.tweak(wc_rev=1)
-  expected_status.tweak('A/D/G/rho', status='MM')
-  svntest.actions.run_and_verify_status(wc_dir, expected_status)
-
-  # Inspect rho, make sure it's right.
-  rho_text = svntest.tree.get_text(rho_path)
-  if rho_text != "This is the file 'rho'.\nA new line in rho.\n":
-    raise svntest.Failure("Unexpected text in merged '" + rho_path + "'")
-
-  # Restore rho to pristine revision 1, for another merge.
-  svntest.actions.run_and_verify_svn(None, None, [], 'revert', rho_path)
-  expected_status.tweak('A/D/G/rho', status='  ')
-  svntest.actions.run_and_verify_status(wc_dir, expected_status)
-
-  # Cd into the directory and run merge with no targets.
-  # It should still merge into rho.
-  saved_cwd = os.getcwd()
-  os.chdir(G_path)
-
-  # Cannot use run_and_verify_merge with a file target
-  merge_cmd = ['merge']
-  if arg_flav == 'r':
-    merge_cmd += ['-r', '1:2']
-  elif arg_flav == 'c':
-    merge_cmd += ['-c', '2']
-
-  if record_only:
-    expected_output = expected_merge_output([[2]],
-                                            [' U   rho\n'])
-    merge_cmd.append('--record-only')
-    rho_expected_status = ' M'
-  else:
-    expected_output = expected_merge_output([[2]],
-                                            ['U    rho\n',
-                                             ' U   rho\n'])
-    rho_expected_status = 'MM'
-  merge_cmd.append(rho_url)
-
-  svntest.actions.run_and_verify_svn(None, expected_output, [], *merge_cmd)
-
-  # Inspect rho, make sure it's right.
-  rho_text = svntest.tree.get_text('rho')
-  if record_only:
-    expected_text = "This is the file 'rho'.\n"
-  else:
-    expected_text = "This is the file 'rho'.\nA new line in rho.\n"
-  if rho_text != expected_text:
-    print("")
-    raise svntest.Failure("Unexpected text merged to 'rho' in '" +
-                          G_path + "'")
-  os.chdir(saved_cwd)
-
-  expected_status.tweak('A/D/G/rho', status=rho_expected_status)
-  svntest.actions.run_and_verify_status(wc_dir, expected_status)
-
-def merge_one_file_using_r(sbox):
-  "merge one file (issue #1150) using the -r option"
-  merge_one_file_helper(sbox, 'r')
-
-def merge_one_file_using_c(sbox):
-  "merge one file (issue #1150) using the -c option"
-  merge_one_file_helper(sbox, 'c')
-
-def merge_one_file_using_implicit_revs(sbox):
-  "merge one file without explicit revisions"
-  merge_one_file_helper(sbox, '*')
-
-def merge_record_only(sbox):
-  "mark a revision range as merged"
-  merge_one_file_helper(sbox, 'r', 1)
-
-#----------------------------------------------------------------------
-# This is a regression for the enhancement added in issue #785.
-
-def merge_with_implicit_target_helper(sbox, arg_flav):
-  "ARG_FLAV is one of 'r' (revision range) or 'c' (single change)."
-
-  if arg_flav not in ('r', 'c', '*'):
-    raise svntest.Failure("Unrecognized flavor of merge argument")
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  # Change mu for revision 2
-  mu_path = os.path.join(wc_dir, 'A', 'mu')
-  orig_mu_text = svntest.tree.get_text(mu_path)
-  added_mu_text = ""
-  for x in range(2,11):
-    added_mu_text = added_mu_text + 'This is line ' + repr(x) + ' in mu\n'
-  svntest.main.file_append(mu_path, added_mu_text)
-
-  # Create expected output tree for initial commit
-  expected_output = wc.State(wc_dir, {
-    'A/mu' : Item(verb='Sending'),
-    })
-
-  # Create expected status tree; all local revisions should be at 1,
-  # but mu should be at revision 2.
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.tweak('A/mu', wc_rev=2)
-
-  # Initial commit.
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None,
-                                        wc_dir)
-
-  # Make the "other" working copy, at r1
-  other_wc = sbox.add_wc_path('other')
-  svntest.actions.duplicate_dir(wc_dir, other_wc)
-  svntest.main.run_svn(None, 'up', '-r', 1, other_wc)
-
-  # Try the merge without an explicit target; it should succeed.
-  # Can't use run_and_verify_merge cuz it expects a directory argument.
-  mu_url = sbox.repo_url + '/A/mu'
-
-  os.chdir(os.path.join(other_wc, 'A'))
-
-  # merge using filename for sourcepath
-  # Cannot use run_and_verify_merge with a file target
-  if arg_flav == 'r':
-    svntest.actions.run_and_verify_svn(None,
-                                       expected_merge_output([[2]],
-                                                             ['U    mu\n',
-                                                              ' U   mu\n']),
-                                       [],
-                                       'merge', '-r', '1:2', 'mu')
-  elif arg_flav == 'c':
-    svntest.actions.run_and_verify_svn(None,
-                                       expected_merge_output([[2]],
-                                                             ['U    mu\n',
-                                                              ' U   mu\n']),
-                                       [],
-                                       'merge', '-c', '2', 'mu')
-
-  elif arg_flav == '*':
-    # Without a peg revision, the default merge range of BASE:1 (which
-    # is a no-op) will be chosen.  Let's do it both ways (no-op first,
-    # of course).
-    svntest.actions.run_and_verify_svn(None, None, [], 'merge', 'mu')
-    svntest.actions.run_and_verify_svn(None,
-                                       expected_merge_output([[2]],
-                                                             ['U    mu\n',
-                                                              ' U   mu\n']),
-                                       [],
-                                       'merge', 'mu@2')
-
-  # sanity-check resulting file
-  if svntest.tree.get_text('mu') != orig_mu_text + added_mu_text:
-    raise svntest.Failure("Unexpected text in 'mu'")
-
-  # merge using URL for sourcepath
-  if arg_flav == 'r':
-    svntest.actions.run_and_verify_svn(None,
-                                       expected_merge_output([[-2]],
-                                                             ['G    mu\n',
-                                                              ' U   mu\n',
-                                                              ' G   mu\n',],
-                                                             elides=True),
-                                       [],
-                                       'merge', '-r', '2:1', mu_url)
-  elif arg_flav == 'c':
-    svntest.actions.run_and_verify_svn(None,
-                                       expected_merge_output([[-2]],
-                                                             ['G    mu\n',
-                                                              ' U   mu\n',
-                                                              ' G   mu\n'],
-                                                             elides=True),
-                                       [],
-                                       'merge', '-c', '-2', mu_url)
-  elif arg_flav == '*':
-    # Implicit merge source URL and revision range detection is for
-    # forward merges only (e.g. non-reverts).  Undo application of
-    # r2 to enable continuation of the test case.
-    svntest.actions.run_and_verify_svn(None,
-                                       expected_merge_output([[-2]],
-                                                             ['G    mu\n',
-                                                              ' U   mu\n',
-                                                              ' G   mu\n'],
-                                                             elides=True),
-                                       [],
-                                       'merge', '-c', '-2', mu_url)
-
-  # sanity-check resulting file
-  if svntest.tree.get_text('mu') != orig_mu_text:
-    raise svntest.Failure("Unexpected text '%s' in 'mu', expected '%s'" %
-                          (svntest.tree.get_text('mu'), orig_mu_text))
-
-
-
-def merge_with_implicit_target_using_r(sbox):
-  "merging a file w/no explicit target path using -r"
-  merge_with_implicit_target_helper(sbox, 'r')
-
-def merge_with_implicit_target_using_c(sbox):
-  "merging a file w/no explicit target path using -c"
-  merge_with_implicit_target_helper(sbox, 'c')
-
-def merge_with_implicit_target_and_revs(sbox):
-  "merging a file w/no explicit target path or revs"
-  merge_with_implicit_target_helper(sbox, '*')
-
-
-#----------------------------------------------------------------------
-
-def merge_with_prev(sbox):
-  "merge operations using PREV revision"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  # Change mu for revision 2
-  mu_path = os.path.join(wc_dir, 'A', 'mu')
-  orig_mu_text = svntest.tree.get_text(mu_path)
-  added_mu_text = ""
-  for x in range(2,11):
-    added_mu_text = added_mu_text + '\nThis is line ' + repr(x) + ' in mu'
-  added_mu_text += "\n"
-  svntest.main.file_append(mu_path, added_mu_text)
-
-  zot_path = os.path.join(wc_dir, 'A', 'zot')
-
-  svntest.main.file_append(zot_path, "bar")
-  svntest.main.run_svn(None, 'add', zot_path)
-
-  # Create expected output tree for initial commit
-  expected_output = wc.State(wc_dir, {
-    'A/mu' : Item(verb='Sending'),
-    'A/zot' : Item(verb='Adding'),
-    })
-
-  # Create expected status tree; all local revisions should be at 1,
-  # but mu should be at revision 2.
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.tweak('A/mu', wc_rev=2)
-  expected_status.add({'A/zot' : Item(status='  ', wc_rev=2)})
-
-  # Initial commit.
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None,
-                                        wc_dir)
-
-  # Make some other working copies
-  other_wc = sbox.add_wc_path('other')
-  svntest.actions.duplicate_dir(wc_dir, other_wc)
-
-  another_wc = sbox.add_wc_path('another')
-  svntest.actions.duplicate_dir(wc_dir, another_wc)
-
-  was_cwd = os.getcwd()
-
-  os.chdir(os.path.join(other_wc, 'A'))
-
-  # Try to revert the last change to mu via svn merge
-  # Cannot use run_and_verify_merge with a file target
-  svntest.actions.run_and_verify_svn(None,
-                                     expected_merge_output([[-2]],
-                                                           ['U    mu\n',
-                                                            ' U   mu\n'],
-                                                           elides=True),
-                                     [],
-                                     'merge', '-r', 'HEAD:PREV', 'mu')
-
-  # sanity-check resulting file
-  if svntest.tree.get_text('mu') != orig_mu_text:
-    raise svntest.Failure("Unexpected text in 'mu'")
-
-  os.chdir(was_cwd)
-
-  other_status = expected_status
-  other_status.wc_dir = other_wc
-  other_status.tweak('A/mu', status='M ', wc_rev=2)
-  other_status.tweak('A/zot', wc_rev=2)
-  svntest.actions.run_and_verify_status(other_wc, other_status)
-
-  os.chdir(another_wc)
-
-  # ensure 'A' will be at revision 2
-  svntest.actions.run_and_verify_svn(None, None, [], 'up')
-
-  # now try a revert on a directory, and verify that it removed the zot
-  # file we had added previously
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'merge', '-r', 'COMMITTED:PREV',
-                                     'A', 'A')
-
-  if svntest.tree.get_text('A/zot') != None:
-    raise svntest.Failure("Unexpected text in 'A/zot'")
-
-  os.chdir(was_cwd)
-
-  another_status = expected_status
-  another_status.wc_dir = another_wc
-  another_status.tweak(wc_rev=2)
-  another_status.tweak('A/mu', status='M ')
-  another_status.tweak('A/zot', status='D ')
-  svntest.actions.run_and_verify_status(another_wc, another_status)
-
-#----------------------------------------------------------------------
-# Regression test for issue #1319: 'svn merge' should *not* 'C' when
-# merging a change into a binary file, unless it has local mods, or has
-# different contents from the left side of the merge.
-
-def merge_binary_file(sbox):
-  "merge change into unchanged binary file"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  # Add a binary file to the project
-  theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read()
-  # Write PNG file data into 'A/theta'.
-  theta_path = os.path.join(wc_dir, 'A', 'theta')
-  svntest.main.file_write(theta_path, theta_contents, 'wb')
-
-  svntest.main.run_svn(None, 'add', theta_path)
-
-  # Commit the new binary file, creating revision 2.
-  expected_output = svntest.wc.State(wc_dir, {
-    'A/theta' : Item(verb='Adding  (bin)'),
-    })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.add({
-    'A/theta' : Item(status='  ', wc_rev=2),
-    })
-  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
-                                        expected_status, None,
-                                        wc_dir)
-
-  # Make the "other" working copy
-  other_wc = sbox.add_wc_path('other')
-  svntest.actions.duplicate_dir(wc_dir, other_wc)
-
-  # Change the binary file in first working copy, commit revision 3.
-  svntest.main.file_append(theta_path, "some extra junk")
-  expected_output = wc.State(wc_dir, {
-    'A/theta' : Item(verb='Sending'),
-    })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.add({
-    'A/theta' : Item(status='  ', wc_rev=3),
-    })
-  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
-                                        expected_status, None,
-                                        wc_dir)
-
-  # In second working copy, attempt to 'svn merge -r 2:3'.
-  # We should *not* see a conflict during the update, but a 'U'.
-  # And after the merge, the status should be 'M'.
-  expected_output = wc.State(other_wc, {
-    'A/theta' : Item(status='U '),
-    })
-  expected_mergeinfo_output = wc.State(other_wc, {
-    '' : Item(status=' U'),
-    })
-  expected_elision_output = wc.State(other_wc, {
-    })
-  expected_disk = svntest.main.greek_state.copy()
-  expected_disk.add({
-    ''        : Item(props={SVN_PROP_MERGEINFO : '/:3'}),
-    'A/theta' : Item(theta_contents + "some extra junk",
-                     props={'svn:mime-type' : 'application/octet-stream'}),
-    })
-  expected_status = svntest.actions.get_virginal_state(other_wc, 1)
-  expected_status.add({
-    ''        : Item(status=' M', wc_rev=1),
-    'A/theta' : Item(status='M ', wc_rev=2),
-    })
-  expected_skip = wc.State('', { })
-
-  svntest.actions.run_and_verify_merge(other_wc, '2', '3',
-                                       sbox.repo_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       1)
-
-#----------------------------------------------------------------------
-# Regression test for issue #2403: Incorrect 3-way merge of "added"
-# binary file which already exists (unmodified) in the WC
-
-# This test involves tree conflicts.
-def three_way_merge_add_of_existing_binary_file(sbox):
-  "3-way merge of 'file add' into existing binary"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  # Create a branch of A, creating revision 2.
-  A_url = sbox.repo_url + "/A"
-  branch_A_url = sbox.repo_url + "/copy-of-A"
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     "cp",
-                                     A_url, branch_A_url,
-                                     "-m", "Creating copy-of-A")
-
-  # Add a binary file to the WC.
-  theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read()
-  # Write PNG file data into 'A/theta'.
-  A_path = os.path.join(wc_dir, 'A')
-  theta_path = os.path.join(wc_dir, 'A', 'theta')
-  svntest.main.file_write(theta_path, theta_contents, 'wb')
-
-  svntest.main.run_svn(None, "add", theta_path)
-
-  # Commit the new binary file to the repos, creating revision 3.
-  expected_output = svntest.wc.State(wc_dir, {
-    "A/theta" : Item(verb="Adding  (bin)"),
-    })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.add({
-    "A/theta" : Item(status="  ", wc_rev=3),
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.add({
+    "A/theta" : Item(status="  ", wc_rev=3),
     })
   svntest.actions.run_and_verify_commit(wc_dir, expected_output,
                                         expected_status, None,
@@ -1708,17527 +419,1450 @@ def three_way_merge_add_of_existing_bina
                                        1)
 
 #----------------------------------------------------------------------
-# Regression test for Issue #1297:
-# A merge that creates a new file followed by an immediate diff
-# The diff should succeed.
-
-def merge_in_new_file_and_diff(sbox):
-  "diff after merge that creates a new file"
+# Issue #2515
+def merge_added_dir_to_deleted_in_target(sbox):
+  "merge an added dir on a deleted dir in target"
 
   sbox.build()
   wc_dir = sbox.wc_dir
 
-  trunk_url = sbox.repo_url + '/A/B/E'
+  # copy B to a new directory, I.
+  # delete F in I.
+  # add J to B/F.
+  # merge add to I.
+
+  B_url = sbox.repo_url + '/A/B'
+  I_url = sbox.repo_url + '/A/I'
+  F_url = sbox.repo_url + '/A/I/F'
+  J_url = sbox.repo_url + '/A/B/F/J'
+  I_path = os.path.join(wc_dir, 'A', 'I')
 
-  # Create a branch
-  svntest.actions.run_and_verify_svn(None, None, [], 'cp',
-                                     trunk_url,
-                                     sbox.repo_url + '/branch',
-                                     '-m', "Creating the Branch")
 
-  # Update to revision 2.
   svntest.actions.run_and_verify_svn(None, None, [],
-                                     'update', wc_dir)
+                                     'cp', B_url, I_url, '-m', 'rev 2')
 
-  new_file_path = os.path.join(wc_dir, 'A', 'B', 'E', 'newfile')
-  svntest.main.file_write(new_file_path, "newfile\n")
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'rm', F_url, '-m', 'rev 3')
 
-  # Add the new file, and commit revision 3.
-  svntest.actions.run_and_verify_svn(None, None, [], "add", new_file_path)
   svntest.actions.run_and_verify_svn(None, None, [],
-                                     'ci', '-m',
-                                     "Changing the trunk.", wc_dir)
+                                     'mkdir', '-m', 'rev 4', J_url)
 
-  branch_path = os.path.join(wc_dir, "branch")
-  url_branch_path = branch_path.replace(os.path.sep, '/')
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                      'up', os.path.join(wc_dir,'A'))
 
-  # Merge our addition into the branch.
-  expected_output = svntest.wc.State(branch_path, {
-    'newfile' : Item(status='A '),
+  expected_output = wc.State(I_path, {
+    'F'       : Item(status='  ', treeconflict='C'),
     })
-  expected_mergeinfo_output = svntest.wc.State(branch_path, {
+  expected_mergeinfo_output = wc.State(I_path, {
     '' : Item(status=' U'),
     })
-  expected_elision_output = wc.State(branch_path, {
+  expected_elision_output = wc.State(I_path, {
     })
   expected_disk = wc.State('', {
-    'alpha'   : Item("This is the file 'alpha'.\n"),
-    'beta'    : Item("This is the file 'beta'.\n"),
-    'newfile' : Item("newfile\n"),
+    'E'       : Item(),
+    'E/alpha' : Item("This is the file 'alpha'.\n"),
+    'E/beta'  : Item("This is the file 'beta'.\n"),
+    'lambda'  : Item("This is the file 'lambda'.\n"),
     })
-  expected_status = wc.State(branch_path, {
-    ''        : Item(status=' M', wc_rev=2),
-    'alpha'   : Item(status='  ', wc_rev=2),
-    'beta'    : Item(status='  ', wc_rev=2),
-    'newfile' : Item(status='A ', wc_rev='-', copied='+')
+  expected_skip = wc.State(I_path, {
     })
-  expected_skip = wc.State('', { })
 
-  svntest.actions.run_and_verify_merge(branch_path,
-                                       '1', 'HEAD', trunk_url, None,
+  svntest.actions.run_and_verify_merge(I_path, '2', '4', B_url, None,
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_disk,
-                                       expected_status,
-                                       expected_skip)
-
-  # Finally, run diff.
-  expected_output = [
-    "\n",
-    "Property changes on: " + branch_path + "\n",
-    "___________________________________________________________________\n",
-    "Added: " + SVN_PROP_MERGEINFO + "\n",
-    "   Merged /A/B/E:r2-3\n",
-    "Index: " + url_branch_path + "/newfile\n",
-    "===================================================================\n",
-    "--- "+ url_branch_path + "/newfile	(revision 0)\n",
-    "+++ "+ url_branch_path + "/newfile	(working copy)\n",
-    "@@ -0,0 +1 @@\n",
-    "+newfile\n"]
-  svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff',
-                                     '--show-copies-as-adds', branch_path)
-
+                                       None,
+                                       expected_skip,
+                                       None, None, None, None, None,
+                                       0, 0)
 
 #----------------------------------------------------------------------
-
-# Issue #1425:  'svn merge' should skip over any unversioned obstructions.
-
-# This test involves tree conflicts. - but attempting to test for pre-tree-conflict behaviour
-def merge_skips_obstructions(sbox):
-  "merge should skip over unversioned obstructions"
+# Issue 2584
+def merge_add_over_versioned_file_conflicts(sbox):
+  "conflict from merge of add over versioned file"
 
   sbox.build()
   wc_dir = sbox.wc_dir
 
-  C_path = os.path.join(wc_dir, 'A', 'C')
-  F_path = os.path.join(wc_dir, 'A', 'B', 'F')
-  F_url = sbox.repo_url + '/A/B/F'
-
-  Q_path = os.path.join(F_path, 'Q')
-  foo_path = os.path.join(F_path, 'foo')
-  bar_path = os.path.join(F_path, 'Q', 'bar')
-
-  svntest.main.run_svn(None, 'mkdir', Q_path)
-  svntest.main.file_append(foo_path, "foo")
-  svntest.main.file_append(bar_path, "bar")
-  svntest.main.run_svn(None, 'add', foo_path, bar_path)
+  E_path = os.path.join(wc_dir, 'A', 'B', 'E')
+  alpha_path = os.path.join(E_path, 'alpha')
+  new_alpha_path = os.path.join(wc_dir, 'A', 'C', 'alpha')
 
-  expected_output = wc.State(wc_dir, {
-    'A/B/F/Q'     : Item(verb='Adding'),
-    'A/B/F/Q/bar' : Item(verb='Adding'),
-    'A/B/F/foo'   : Item(verb='Adding'),
+  # Create a new "alpha" file, with enough differences to cause a conflict.
+  svntest.main.file_write(new_alpha_path, 'new alpha content\n')
+
+  # Add and commit the new "alpha" file, creating revision 2.
+  svntest.main.run_svn(None, "add", new_alpha_path)
+
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/C/alpha' : Item(verb='Adding'),
     })
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
   expected_status.add({
-    'A/B/F/Q'     : Item(status='  ', wc_rev=2),
-    'A/B/F/Q/bar' : Item(status='  ', wc_rev=2),
-    'A/B/F/foo'   : Item(status='  ', wc_rev=2),
+    'A/C/alpha' : Item(status='  ', wc_rev=2),
     })
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None,
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None,
                                         wc_dir)
 
-  pre_merge_status = expected_status
-
-  # Revision 2 now has A/B/F/foo, A/B/F/Q, A/B/F/Q/bar.  Let's merge
-  # those 'F' changes into empty dir 'C'.  But first, create an
-  # unversioned 'foo' within C, and make sure 'svn merge' doesn't
-  # error when the addition of foo is obstructed.
-
-  expected_output = wc.State(C_path, {
-    'Q'      : Item(status='A '),
-    'Q/bar'  : Item(status='A '),
+  # Merge r1:2 from A/C to A/B/E.  This will attempt to add A/C/alpha,
+  # but since A/B/E/alpha already exists we get a tree conflict.
+  expected_output = wc.State(E_path, {
+    'alpha'   : Item(status='  ', treeconflict='C'),
     })
-  expected_mergeinfo_output = wc.State(C_path, {
+  expected_mergeinfo_output = wc.State(E_path, {
     '' : Item(status=' U'),
     })
-  expected_elision_output = wc.State(C_path, {
+  expected_elision_output = wc.State(E_path, {
     })
   expected_disk = wc.State('', {
-    ''       : Item(props={SVN_PROP_MERGEINFO : '/A/B/F:2'}),
-    'Q'      : Item(),
-    'Q/bar'  : Item("bar"),
-    'foo'    : Item("foo"),
+    'alpha'   : Item("This is the file 'alpha'.\n"),
+    'beta'    : Item("This is the file 'beta'.\n"),
     })
-  expected_status = wc.State(C_path, {
+  expected_status = wc.State(E_path, {
     ''       : Item(status=' M', wc_rev=1),
-    'Q'      : Item(status='A ', wc_rev='-', copied='+'),
-    'Q/bar'  : Item(status='  ', wc_rev='-', copied='+'),
-    })
-  expected_skip = wc.State(C_path, {
-    'foo' : Item(),
+    'alpha'  : Item(status='  ', wc_rev=1, treeconflict='C'),
+    'beta'   : Item(status='  ', wc_rev=1),
     })
-  # Unversioned:
-  svntest.main.file_append(os.path.join(C_path, "foo"), "foo")
-
-  svntest.actions.run_and_verify_merge(C_path, '1', '2', F_url, None,
+  expected_skip = wc.State(E_path, { })
+  svntest.actions.run_and_verify_merge(E_path, '1', '2',
+                                       sbox.repo_url + '/A/C', None,
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_disk,
                                        expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       1, 0)
-
-  # Revert the local mods, and this time make "Q" obstructed.  An
-  # unversioned file called "Q" will obstruct the adding of the
-  # directory of the same name.
-
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'revert', '-R', wc_dir)
-  os.unlink(os.path.join(C_path, "foo"))
-  svntest.main.safe_rmtree(os.path.join(C_path, "Q"))
-  svntest.main.file_append(os.path.join(C_path, "Q"), "foo") # unversioned
-  svntest.actions.run_and_verify_status(wc_dir, pre_merge_status)
+                                       expected_skip)
 
-  expected_output = wc.State(C_path, {
-    'foo'    : Item(status='A '),
-    })
-  expected_mergeinfo_output = wc.State(C_path, {
-    '' : Item(status=' U'),
-    })
-  expected_elision_output = wc.State(C_path, {
-    })
-  expected_disk = wc.State('', {
-    ''       : Item(props={SVN_PROP_MERGEINFO : '/A/B/F:2'}),
-    'Q'      : Item("foo"),
-    'foo'    : Item("foo"),
-    })
-  expected_status = wc.State(C_path, {
-    ''     : Item(status=' M', wc_rev=1),
-    'foo'  : Item(status='A ', wc_rev='-', copied='+'),
-    })
-  expected_skip = wc.State(C_path, {
-    'Q'     : Item(),
-    'Q/bar' : Item(),
-    })
+#----------------------------------------------------------------------
+def mergeinfo_recording_in_skipped_merge(sbox):
+  "mergeinfo recording in skipped merge"
 
-  svntest.actions.run_and_verify_merge(C_path, '1', '2', F_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       1, 0)
+  ## See http://subversion.tigris.org/issues/show_bug.cgi?id=2829. ##
 
-  # Revert the local mods, and commit the deletion of iota and A/D/G. (r3)
-  os.unlink(os.path.join(C_path, "foo"))
-  svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir)
-  svntest.actions.run_and_verify_status(wc_dir, pre_merge_status)
+  # Create a WC with a single branch
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  wc_disk, wc_status = set_up_branch(sbox, True, 1)
 
-  iota_path = os.path.join(wc_dir, 'iota')
-  G_path = os.path.join(wc_dir, 'A', 'D', 'G')
-  svntest.actions.run_and_verify_svn(None, None, [], 'rm', iota_path, G_path)
+  # Some paths we'll care about
+  A_url = sbox.repo_url + '/A'
+  A_COPY_path = os.path.join(wc_dir, 'A_COPY')
+  mu_path = os.path.join(wc_dir, 'A', 'mu')
+  alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
+  A_COPY_B_E_path = os.path.join(wc_dir, 'A_COPY', 'B', 'E')
+  A_COPY_alpha_path = os.path.join(wc_dir, 'A_COPY', 'B', 'E', 'alpha')
+  A_COPY_beta_path = os.path.join(wc_dir, 'A_COPY', 'B', 'E', 'beta')
 
-  expected_output = wc.State(wc_dir, {
-    'A/D/G'  : Item(verb='Deleting'),
-    'iota'   : Item(verb='Deleting'),
-    })
-  expected_status = pre_merge_status
-  expected_status.remove('iota', 'A/D/G', 'A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None, wc_dir)
+  # Make a modification to A/mu
+  svntest.main.file_write(mu_path, "This is the file 'mu' modified.\n")
+  expected_output = wc.State(wc_dir, {'A/mu' : Item(verb='Sending')})
+  wc_status.add({'A/mu'     : Item(status='  ', wc_rev=3)})
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        wc_status, None, wc_dir)
 
-  # Now create unversioned iota and A/D/G, try running a merge -r2:3.
-  # The merge process should skip over these targets, since they're
-  # unversioned.
+  # Make a modification to A/B/E/alpha
+  svntest.main.file_write(alpha_path, "This is the file 'alpha' modified.\n")
+  expected_output = wc.State(wc_dir, {'A/B/E/alpha' : Item(verb='Sending')})
+  wc_status.add({'A/B/E/alpha'     : Item(status='  ', wc_rev=4)})
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        wc_status, None, wc_dir)
 
-  svntest.main.file_append(iota_path, "foo") # unversioned
-  os.mkdir(G_path) # unversioned
+  # Delete A_COPY/B/E
+  svntest.actions.run_and_verify_svn(None, None, [], 'rm',
+                                     A_COPY_B_E_path)
 
-  expected_output = wc.State(wc_dir, {
+  # Merge /A to /A_COPY ie., r1 to r4
+  expected_output = wc.State(A_COPY_path, {
+    'mu'  : Item(status='U '),
+    'B/E' : Item(status='  ', treeconflict='C'),
     })
-  expected_mergeinfo_output = wc.State(wc_dir, {
+  expected_mergeinfo_output = wc.State(A_COPY_path, {
     '' : Item(status=' U'),
     })
-  expected_elision_output = wc.State(wc_dir, {
+  expected_elision_output = wc.State(A_COPY_path, {
     })
-  expected_disk = svntest.main.greek_state.copy()
-  expected_disk.remove('A/D/G/pi', 'A/D/G/rho', 'A/D/G/tau')
-  expected_disk.add({
-    ''             : Item(props={SVN_PROP_MERGEINFO : '/:3'}),
-    'A/B/F/Q'      : Item(),
-    'A/B/F/Q/bar'  : Item("bar"),
-    'A/B/F/foo'    : Item("foo"),
-    'A/C/Q'        : Item("foo"),
+  expected_status = wc.State(A_COPY_path, {
+    ''         : Item(status=' M', wc_rev=2),
+    'mu'       : Item(status='M ', wc_rev=2),
+    'B'        : Item(status='  ', wc_rev=2),
+    'B/lambda' : Item(status='  ', wc_rev=2),
+    'B/F'      : Item(status='  ', wc_rev=2),
+    'B/E'      : Item(status='D ', wc_rev=2, treeconflict='C'),
+    'B/E/alpha': Item(status='D ', wc_rev=2),
+    'B/E/beta' : Item(status='D ', wc_rev=2),
+    'C'        : Item(status='  ', wc_rev=2),
+    'D'        : Item(status='  ', wc_rev=2),
+    'D/gamma'  : Item(status='  ', wc_rev=2),
+    'D/G'      : Item(status='  ', wc_rev=2),
+    'D/G/pi'   : Item(status='  ', wc_rev=2),
+    'D/G/rho'  : Item(status='  ', wc_rev=2),
+    'D/G/tau'  : Item(status='  ', wc_rev=2),
+    'D/H'      : Item(status='  ', wc_rev=2),
+    'D/H/chi'  : Item(status='  ', wc_rev=2),
+    'D/H/omega': Item(status='  ', wc_rev=2),
+    'D/H/psi'  : Item(status='  ', wc_rev=2),
     })
-  expected_disk.tweak('iota', contents="foo")
-  # No-op merge still sets mergeinfo
-  expected_status.tweak('', status=' M')
-  expected_skip = wc.State(wc_dir, {
-    'iota'   : Item(),
-    'A/D/G'  : Item(),
+  expected_disk = wc.State('', {
+    ''         : Item(props={SVN_PROP_MERGEINFO : '/A:2-4'}),
+    'mu'       : Item("This is the file 'mu' modified.\n"),
+    'C'        : Item(),
+    'D'        : Item(),
+    'B'        : Item(),
+    'B/lambda' : Item(contents="This is the file 'lambda'.\n"),
+    'B/F'      : Item(),
+    'B/E'      : Item(),
+    'D/gamma'  : Item("This is the file 'gamma'.\n"),
+    'D/G'      : Item(),
+    'D/G/pi'   : Item("This is the file 'pi'.\n"),
+    'D/G/rho'  : Item("This is the file 'rho'.\n"),
+    'D/G/tau'  : Item("This is the file 'tau'.\n"),
+    'D/H'      : Item(),
+    'D/H/chi'  : Item("This is the file 'chi'.\n"),
+    'D/H/omega': Item("This is the file 'omega'.\n"),
+    'D/H/psi'  : Item("This is the file 'psi'.\n"),
     })
-  svntest.actions.run_and_verify_merge(wc_dir, '2', '3',
-                                       sbox.repo_url, None,
+  expected_skip = wc.State(A_COPY_path, {})
+  svntest.actions.run_and_verify_merge(A_COPY_path, None, None,
+                                       A_url, None,
                                        expected_output,
                                        expected_mergeinfo_output,
                                        expected_elision_output,
                                        expected_disk,
-                                       expected_status.copy(wc_dir),
+                                       expected_status,
                                        expected_skip,
                                        None, None, None, None, None,
-                                       1, 0)
-
-  # Revert the local mods, and commit a change to A/B/lambda (r4), and then
-  # commit the deletion of the same file. (r5)
-  svntest.main.safe_rmtree(G_path)
-  svntest.actions.run_and_verify_svn(None, None, [], 'revert', '-R', wc_dir)
-  expected_status.tweak('', status='  ')
-  svntest.actions.run_and_verify_status(wc_dir, expected_status)
-
-  lambda_path = os.path.join(wc_dir, 'A', 'B', 'lambda')
-  svntest.main.file_append(lambda_path, "more text")
-  expected_output = wc.State(wc_dir, {
-    'A/B/lambda'  : Item(verb='Sending'),
-    })
-  expected_status.tweak('A/B/lambda', wc_rev=4)
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None, wc_dir)
-
-  svntest.actions.run_and_verify_svn(None, None, [], 'rm', lambda_path)
+                                       1, 1)
 
-  expected_output = wc.State(wc_dir, {
-    'A/B/lambda'  : Item(verb='Deleting'),
-    })
-  expected_status.remove('A/B/lambda')
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None, wc_dir)
+#----------------------------------------------------------------------
+def del_differing_file(sbox):
+  "merge tries to delete a file of different content"
 
-  # lambda is gone, so create an unversioned lambda in its place.
-  # Then attempt to merge -r3:4, which is a change to lambda.  The merge
-  # should simply skip the unversioned file.
+  # Setup a standard greek tree in r1.
+  sbox.build()
+  svn_commit.repo_rev = 1
 
-  svntest.main.file_append(lambda_path, "foo") # unversioned
+  saved_cwd = os.getcwd()
+  os.chdir(sbox.wc_dir)
 
-  expected_output = wc.State(wc_dir, { })
-  expected_mergeinfo_output = wc.State(wc_dir, {
-    '' : Item(status=' U'),
-    })
-  expected_elision_output = wc.State(wc_dir, {
-    })
-  expected_disk.add({
-    'A/B/lambda'      : Item("foo"),
-    })
-  expected_disk.remove('A/D/G')
-  expected_disk.tweak('', props={SVN_PROP_MERGEINFO : '/:4'})
-  expected_skip = wc.State(wc_dir, {
-    'A/B/lambda'  : Item(),
-    })
-  # No-op merge still sets mergeinfo.
-  expected_status_short = expected_status.copy(wc_dir)
-  expected_status_short.tweak('', status=' M')
+  source = 'A/D/G'
+  s_rev_orig = 1
 
-  svntest.actions.run_and_verify_merge(wc_dir, '3', '4',
-                                       sbox.repo_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status_short,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       1, 0)
+  # Delete files in the source
+  svn_delete(source+"/tau")
+  s_rev_tau = svn_commit(source)
+  svn_delete(source+"/pi")
+  s_rev_pi = svn_commit(source)
 
-  # OK, so let's commit the new lambda (r6), and then delete the
-  # working file.  Then re-run the -r3:4 merge, and see how svn deals
-  # with a file being under version control, but missing.
+  # Copy a file, modify it, and merge a deletion to it.
+  target = 'A/D/G2'
+  svn_copy(s_rev_orig, source, target)
+  svntest.main.file_append(target+"/tau", "An extra line in the target.\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'propset',
+                                     'newprop', 'v', target+"/pi")
 
-  svntest.actions.run_and_verify_svn(None, None, [], 'add', lambda_path)
+  dir_D = os.path.join('A','D')
+  dir_G2 = os.path.join(dir_D, 'G2')
+  tau = os.path.join(dir_D,'G2','tau')
+  pi = os.path.join(dir_D, 'G2', 'pi')
+  # Should complain and "skip" it.
+  svn_merge(s_rev_tau, source, target, [
+      "--- Merging r2 into '%s':\n" % dir_G2,
+      "   C %s\n" % tau,
+      "--- Recording mergeinfo for merge of r2 into '%s':\n" % (dir_G2),
+      " U   %s\n" % (dir_G2),
+      "Summary of conflicts:\n",
+      "  Tree conflicts: 1\n"])
 
-  # Mergeinfo prop changed so update to avoid out of date error.
-  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  svn_merge(s_rev_pi, source, target, [
+      "--- Merging r3 into '%s':\n" % dir_G2,
+      "   C %s\n" % pi,
+      "--- Recording mergeinfo for merge of r3 into '%s':\n" % (dir_G2),
+      " G   %s\n" % (dir_G2),
+      "Summary of conflicts:\n",
+      "  Tree conflicts: 1\n"])
 
-  expected_output = wc.State(wc_dir, {
-    ''            : Item(verb='Sending'),
-    'A/B/lambda'  : Item(verb='Adding'),
-    })
-  expected_mergeinfo_output = wc.State(wc_dir, {})
-  expected_elision_output = wc.State(wc_dir, {})
-  expected_status.tweak(wc_rev=5)
-  expected_status.add({
-    'A/B/lambda'  : Item(wc_rev=6, status='  '),
-    })
-  expected_status.tweak('', status='  ', wc_rev=6)
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None, wc_dir)
-  os.unlink(lambda_path)
 
-  expected_output = wc.State(wc_dir, { })
-  expected_disk.remove('A/B/lambda')
-  expected_status.tweak('A/B/lambda', status='! ')
-  expected_status.tweak('', status='  ')
-  # Why do we need to --ignore-ancestry?  Because the previous merge of r4,
-  # despite being inoperative, set mergeinfo for r4 on the WC.  With the
-  # advent of merge tracking this repeat merge attempt would not be attempted.
-  # By using --ignore-ancestry we disregard the mergeinfo and *really* try to
-  # merge into a missing path.  This is another facet of issue #2898.
-  svntest.actions.run_and_verify_merge(wc_dir, '3', '4',
-                                       sbox.repo_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status.copy(wc_dir),
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       1, 0, '--ignore-ancestry')
+  # Copy a file, modify it, commit, and merge a deletion to it.
+  target = 'A/D/G3'
+  svn_copy(s_rev_orig, source, target)
+  svntest.main.file_append(target+"/tau", "An extra line in the target.\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'propset',
+                                     'newprop', 'v', target+"/pi")
+  svn_commit(target)
 
-#----------------------------------------------------------------------
-# At one time, a merge that added items with the same name as missing
-# items would attempt to add the items and fail, leaving the working
-# copy locked and broken.
-
-# This test involves tree conflicts.
-def merge_into_missing(sbox):
-  "merge into missing must not break working copy"
 
-  sbox.build()
-  wc_dir = sbox.wc_dir
+  dir_G3 = os.path.join(dir_D, 'G3')
+  tau = os.path.join(dir_D,'G3','tau')
+  pi = os.path.join(dir_D, 'G3', 'pi')
 
-  F_path = os.path.join(wc_dir, 'A', 'B', 'F')
-  F_url = sbox.repo_url + '/A/B/F'
-  Q_path = os.path.join(F_path, 'Q')
-  foo_path = os.path.join(F_path, 'foo')
-
-  svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', Q_path)
-  svntest.main.file_append(foo_path, "foo")
-  svntest.actions.run_and_verify_svn(None, None, [], 'add', foo_path)
+  # Should complain and "skip" it.
+  svn_merge(s_rev_tau, source, target, [
+      "--- Merging r2 into '%s':\n" % dir_G3,
+      "   C %s\n" % tau,
+      "--- Recording mergeinfo for merge of r2 into '%s':\n" % (dir_G3),
+      " U   %s\n" % (dir_G3),
+      "Summary of conflicts:\n",
+      "  Tree conflicts: 1\n"])
 
-  expected_output = wc.State(wc_dir, {
-    'A/B/F/Q'       : Item(verb='Adding'),
-    'A/B/F/foo'     : Item(verb='Adding'),
-    })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.add({
-    'A/B/F/Q'       : Item(status='  ', wc_rev=2),
-    'A/B/F/foo'     : Item(status='  ', wc_rev=2),
-    })
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None, wc_dir)
-
-  R_path = os.path.join(Q_path, 'R')
-  bar_path = os.path.join(R_path, 'bar')
-  baz_path = os.path.join(Q_path, 'baz')
-  svntest.actions.run_and_verify_svn(None, None, [], 'mkdir', R_path)
-  svntest.main.file_append(bar_path, "bar")
-  svntest.actions.run_and_verify_svn(None, None, [], 'add', bar_path)
-  svntest.main.file_append(baz_path, "baz")
-  svntest.actions.run_and_verify_svn(None, None, [], 'add', baz_path)
-
-  expected_output = wc.State(wc_dir, {
-    'A/B/F/Q/R'     : Item(verb='Adding'),
-    'A/B/F/Q/R/bar' : Item(verb='Adding'),
-    'A/B/F/Q/baz'   : Item(verb='Adding'),
-    })
-  expected_status.add({
-    'A/B/F/Q/R'     : Item(status='  ', wc_rev=3),
-    'A/B/F/Q/R/bar' : Item(status='  ', wc_rev=3),
-    'A/B/F/Q/baz'   : Item(status='  ', wc_rev=3),
-    })
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None, wc_dir)
-
-  os.unlink(foo_path)
-  svntest.main.safe_rmtree(Q_path)
-
-  expected_output = wc.State(F_path, {
-    })
-  expected_mergeinfo_output = wc.State(F_path, {
-    })
-  expected_elision_output = wc.State(F_path, {
-    })
-  expected_disk = wc.State('', {
-    })
-  expected_status = wc.State(F_path, {
-    ''      : Item(status='  ', wc_rev=1),
-    'foo'   : Item(status='! ', wc_rev=2),
-    'Q'     : Item(status='! ', wc_rev='2', entry_rev='?'),
-    })
-  expected_skip = wc.State(F_path, {
-    'Q'   : Item(),
-    'foo' : Item(),
-    })
-
-  ### Need to real and dry-run separately since real merge notifies Q
-  ### twice!
-  svntest.actions.run_and_verify_merge(F_path, '1', '2', F_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       0, 0, '--dry-run')
-
-  expected_status = wc.State(F_path, {
-    ''      : Item(status=' M', wc_rev=1),
-    'foo'   : Item(status='!M', wc_rev=2),
-    'Q'     : Item(status='! ', wc_rev='2', entry_rev='?'),
-    })
-  expected_mergeinfo_output = wc.State(F_path, {
-    ''    : Item(status=' U'),
-    'foo' : Item(status=' U'), # Mergeinfo is set on missing/obstructed files.
-    })
-  svntest.actions.run_and_verify_merge(F_path, '1', '2', F_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       0, 0)
-
-  # This merge fails when it attempts to descend into the missing
-  # directory.  That's OK, there is no real need to support merge into
-  # an incomplete working copy, so long as when it fails it doesn't
-  # break the working copy.
-  svntest.main.run_svn('Working copy not locked',
-                       'merge', '-r1:3', '--dry-run', F_url, F_path)
-
-  svntest.main.run_svn('Working copy not locked',
-                       'merge', '-r1:3', F_url, F_path)
+  svn_merge(s_rev_pi, source, target, [
+      "--- Merging r3 into '%s':\n" % dir_G3,
+      "   C %s\n" % pi,
+      "--- Recording mergeinfo for merge of r3 into '%s':\n" % (dir_G3),
+      " G   %s\n" % (dir_G3),
+      "Summary of conflicts:\n",
+      "  Tree conflicts: 1\n"])
 
-  # Check working copy is not locked.
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.add({
-    'A/B/F'     : Item(status=' M', wc_rev=1),
-    'A/B/F/foo' : Item(status='!M', wc_rev=2),
-    'A/B/F/Q'   : Item(status='! ', wc_rev='2', entry_rev='?'),
-    })
-  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+  os.chdir(saved_cwd)
 
 #----------------------------------------------------------------------
-# A test for issue 1738
+# This test used to involve tree conflicts, hence its name.
+def tree_conflicts_and_obstructions(sbox):
+  "tree conflicts and obstructions"
 
-def dry_run_adds_file_with_prop(sbox):
-  "merge --dry-run adding a new file with props"
+  ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3146. ##
 
   sbox.build()
   wc_dir = sbox.wc_dir
 
-  # Commit a new file which has a property.
-  zig_path = os.path.join(wc_dir, 'A', 'B', 'E', 'zig')
-  svntest.main.file_append(zig_path, "zig contents")
-  svntest.actions.run_and_verify_svn(None, None, [], 'add', zig_path)
+  trunk_url = sbox.repo_url + '/A/B/E'
+  branch_path = os.path.join(wc_dir, 'branch')
+  br_alpha_moved = os.path.join(branch_path, 'alpha-moved')
+
+  # Create a branch
+  svntest.actions.run_and_verify_svn(None, None, [], 'cp',
+                                     trunk_url,
+                                     sbox.repo_url + '/branch',

[... 18148 lines stripped ...]