subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhuij...@apache.org
Subject svn commit: r1489856 [2/2] - in /subversion/trunk/subversion/tests/cmdline: ./ svntest/
Date Wed, 05 Jun 2013 13:28:15 GMT
Copied: subversion/trunk/subversion/tests/cmdline/svntest/mergetrees.py (from r1489841, subversion/trunk/subversion/tests/cmdline/merge_tests.py)
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/mergetrees.py?p2=subversion/trunk/subversion/tests/cmdline/svntest/mergetrees.py&p1=subversion/trunk/subversion/tests/cmdline/merge_tests.py&r1=1489841&r2=1489856&rev=1489856&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svntest/mergetrees.py Wed Jun  5 13:28:15 2013
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 #
-#  merge_tests.py:  testing merge
+#  mergetrees.py:  routines that create merge scenarios
 #
 #  Subversion is a tool for revision control.
 #  See http://subversion.apache.org for more information.
@@ -29,27 +29,21 @@ import shutil, sys, re, os
 import time
 
 # Our testing module
-import svntest
-from svntest import main, wc, verify, actions
+import main, wc, verify, actions, testcase
 
 from prop_tests import binary_mime_type_on_text_file_warning
 
 # (abbreviation)
 Item = wc.StateItem
-Skip = svntest.testcase.Skip_deco
-SkipUnless = svntest.testcase.SkipUnless_deco
-XFail = svntest.testcase.XFail_deco
-Issues = svntest.testcase.Issues_deco
-Issue = svntest.testcase.Issue_deco
-Wimp = svntest.testcase.Wimp_deco
-exp_noop_up_out = svntest.actions.expected_noop_update_output
+Skip = testcase.Skip_deco
+SkipUnless = testcase.SkipUnless_deco
+XFail = testcase.XFail_deco
+Issues = testcase.Issues_deco
+Issue = testcase.Issue_deco
+Wimp = testcase.Wimp_deco
+exp_noop_up_out = actions.expected_noop_update_output
 
 from svntest.main import SVN_PROP_MERGEINFO
-from svntest.main import server_has_mergeinfo
-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
-from svntest.verify import RegexListOutput
 
 def expected_merge_output(rev_ranges, additional_lines=[], foreign=False,
                           elides=False, two_url=False, target=None,
@@ -82,7 +76,7 @@ def expected_merge_output(rev_ranges, ad
   """
 
   if rev_ranges is None:
-    lines = [svntest.main.merge_notify_line(None, None, False, foreign)]
+    lines = [main.merge_notify_line(None, None, False, foreign)]
   else:
     lines = []
     for rng in rev_ranges:
@@ -91,9 +85,9 @@ def expected_merge_output(rev_ranges, ad
         end_rev = rng[1]
       else:
         end_rev = None
-      lines += [svntest.main.merge_notify_line(start_rev, end_rev,
+      lines += [main.merge_notify_line(start_rev, end_rev,
                                                True, foreign, target)]
-      lines += [svntest.main.mergeinfo_notify_line(start_rev, end_rev, target)]
+      lines += [main.mergeinfo_notify_line(start_rev, end_rev, target)]
 
   if (elides):
     lines += ["--- Eliding mergeinfo from .*\n"]
@@ -114,7 +108,7 @@ def expected_merge_output(rev_ranges, ad
     additional_lines = [line.replace("\\", "\\\\") for line in additional_lines]
   lines += additional_lines
 
-  lines += svntest.main.summary_of_conflicts(
+  lines += main.summary_of_conflicts(
              text_conflicts, prop_conflicts, tree_conflicts,
              text_resolved, prop_resolved, tree_resolved,
              skipped_paths,
@@ -125,317 +119,20 @@ def expected_merge_output(rev_ranges, ad
 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(
+  expected = verify.UnorderedOutput(
     [path + ' - ' + subpaths_mergeinfo[path] + '\n'
      for path in subpaths_mergeinfo])
-  svntest.actions.run_and_verify_svn(None, expected, [],
+  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.
-
-#----------------------------------------------------------------------
-@SkipUnless(server_has_mergeinfo)
-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 = sbox.ospath('A/mu')
-  rho_path = sbox.ospath('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 = sbox.ospath('A/B/lambda')
-  pi_path = sbox.ospath('A/D/G/pi')
-  tau_path = sbox.ospath('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)),
-                                       None, None, False, True,
-                                       '--allow-mixed-revisions',
-                                       other_wc)
-
-  # 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.
-  ### TODO: We can use run_and_verify_merge() here now.
-  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
-@SkipUnless(server_has_mergeinfo)
-def add_with_history(sbox):
-  "merge and add new files/dirs with history"
+def set_up_dir_replace(sbox):
+  """Set up the working copy for directory replace tests, creating
+  directory 'A/B/F/foo' with files 'new file' and 'new file2' within
+  it (r2), and merging 'foo' onto 'C' (r3), then deleting 'A/B/F/foo'
+  (r4)."""
 
   sbox.build()
   wc_dir = sbox.wc_dir
@@ -444,54 +141,39 @@ def add_with_history(sbox):
   F_path = sbox.ospath('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')
+  new_file = os.path.join(foo_path, "new file")
+  new_file2 = os.path.join(foo_path, "new file 2")
 
-  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)
+  # Make directory foo in F, and add some files within it.
+  actions.run_and_verify_svn(None, None, [], 'mkdir', foo_path)
+  main.file_append(new_file, "Initial text in new file.\n")
+  main.file_append(new_file2, "Initial text in new file 2.\n")
+  main.run_svn(None, "add", new_file)
+  main.run_svn(None, "add", new_file2)
 
+  # Commit all the new content, creating r2.
   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'),
+    'A/B/F/foo'            : Item(verb='Adding'),
+    'A/B/F/foo/new file'   : Item(verb='Adding'),
+    'A/B/F/foo/new file 2' : Item(verb='Adding'),
     })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status = 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),
+    'A/B/F/foo'             : Item(status='  ', wc_rev=2),
+    'A/B/F/foo/new file'    : Item(status='  ', wc_rev=2),
+    'A/B/F/foo/new file 2'  : Item(status='  ', wc_rev=2),
     })
-  svntest.actions.run_and_verify_commit(wc_dir,
+  actions.run_and_verify_commit(wc_dir,
                                         expected_output,
                                         expected_status,
-                                        None,
-                                        wc_dir)
+                                        None, wc_dir)
 
+  # Merge foo onto C
   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 '),
+    'foo' : Item(status='A '),
+    'foo/new file'   : Item(status='A '),
+    'foo/new file 2' : Item(status='A '),
     })
   expected_mergeinfo_output = wc.State(C_path, {
     '' : Item(status=' U'),
@@ -499,18811 +181,343 @@ def add_with_history(sbox):
   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'}),
+    ''               : Item(props={SVN_PROP_MERGEINFO : '/A/B/F:2'}),
+    'foo' : Item(),
+    'foo/new file'   : Item("Initial text in new file.\n"),
+    'foo/new file 2' : Item("Initial text in new file 2.\n"),
     })
   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='+'),
+    ''    : Item(status=' M', wc_rev=1),
+    'foo' : Item(status='A ', wc_rev='-', copied='+'),
+    'foo/new file'   : Item(status='  ', wc_rev='-', copied='+'),
+    'foo/new file 2' : Item(status='  ', wc_rev='-', copied='+'),
     })
-
   expected_skip = wc.State(C_path, { })
-
-  # Add some unversioned directory obstructions to the incoming
-  # additions.  This should be tolerated and *not* result in any
-  # difference between the --dry-run and actual merge.
-  # See http://svn.haxx.se/dev/archive-2012-11/0696.shtml
-  os.mkdir(sbox.ospath('A/C/Q'))
-  os.mkdir(sbox.ospath('A/C/Q2'))
-
-  svntest.actions.run_and_verify_merge(C_path, '1', '2', F_url, None,
+  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
+                                       None, None, None, None, None, 1)
+  # Commit merge of foo onto C, creating r3.
+  expected_output = wc.State(wc_dir, {
+    'A/C'        : Item(verb='Sending'),
+    'A/C/foo'    : Item(verb='Adding'),
+    })
+  expected_status = actions.get_virginal_state(wc_dir, 1)
+  expected_status.add({
+    'A/B/F/foo'  : Item(status='  ', wc_rev=2),
+    'A/C'        : Item(status='  ', wc_rev=3),
+    'A/B/F/foo/new file'      : Item(status='  ', wc_rev=2),
+    'A/B/F/foo/new file 2'    : Item(status='  ', wc_rev=2),
+    'A/C/foo'    : Item(status='  ', wc_rev=3),
+    'A/C/foo/new file'      : Item(status='  ', wc_rev=3),
+    'A/C/foo/new file 2'    : Item(status='  ', wc_rev=3),
+
+    })
+  actions.run_and_verify_commit(wc_dir,
+                                        expected_output,
+                                        expected_status,
+                                        None, wc_dir)
 
-  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'),
+  # Delete foo on F, creating r4.
+  actions.run_and_verify_svn(None, None, [], 'rm', foo_path)
+  expected_output = wc.State(wc_dir, {
+    'A/B/F/foo'   : Item(verb='Deleting'),
     })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status = 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),
+    'A/C/foo/new file'      : Item(status='  ', wc_rev=3),
+    'A/C/foo/new file 2'    : Item(status='  ', wc_rev=3),
     })
-  svntest.actions.run_and_verify_commit(wc_dir,
+  actions.run_and_verify_commit(wc_dir,
                                         expected_output,
                                         expected_status,
-                                        None,
-                                        wc_dir)
+                                        None, wc_dir)
 
 #----------------------------------------------------------------------
-# Issue 953
-@SkipUnless(server_has_mergeinfo)
-@Issue(953)
-def simple_property_merges(sbox):
-  "some simple property merges"
+def set_up_branch(sbox, branch_only = False, nbr_of_branches = 1):
+  '''Starting with standard greek tree, copy 'A' NBR_OF_BRANCHES times
+  to A_COPY, A_COPY_2, A_COPY_3, and so on.  Then, unless BRANCH_ONLY is
+  true, make four modifications (setting file contents to "New content")
+  under A:
+    r(2 + NBR_OF_BRANCHES) - A/D/H/psi
+    r(3 + NBR_OF_BRANCHES) - A/D/G/rho
+    r(4 + NBR_OF_BRANCHES) - A/B/E/beta
+    r(5 + NBR_OF_BRANCHES) - A/D/H/omega
+  Return (expected_disk, expected_status).'''
+
+  # With the default parameters, the branching looks like this:
+  #
+  #   A         -1-----3-4-5-6--
+  #                \
+  #   A_COPY        2-----------
 
-  sbox.build()
   wc_dir = sbox.wc_dir
 
-  # Add a property to a file and a directory
-  alpha_path = sbox.ospath('A/B/E/alpha')
-  beta_path = sbox.ospath('A/B/E/beta')
-  E_path = sbox.ospath('A/B/E')
+  expected_status = actions.get_virginal_state(wc_dir, 1)
+  expected_disk = main.greek_state.copy()
 
-  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)
+  def copy_A(dest_name, rev):
+    expected = verify.UnorderedOutput(
+      ["A    " + os.path.join(wc_dir, dest_name, "B") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "B", "lambda") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "B", "E") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "B", "E", "alpha") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "B", "E", "beta") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "B", "F") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "mu") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "C") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D", "gamma") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D", "G") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D", "G", "pi") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D", "G", "rho") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D", "G", "tau") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D", "H") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D", "H", "chi") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D", "H", "omega") + "\n",
+       "A    " + os.path.join(wc_dir, dest_name, "D", "H", "psi") + "\n",
+       "Checked out revision " + str(rev - 1) + ".\n",
+       "A         " + os.path.join(wc_dir, dest_name) + "\n"])
+    expected_status.add({
+      dest_name + "/B"         : Item(status='  ', wc_rev=rev),
+      dest_name + "/B/lambda"  : Item(status='  ', wc_rev=rev),
+      dest_name + "/B/E"       : Item(status='  ', wc_rev=rev),
+      dest_name + "/B/E/alpha" : Item(status='  ', wc_rev=rev),
+      dest_name + "/B/E/beta"  : Item(status='  ', wc_rev=rev),
+      dest_name + "/B/F"       : Item(status='  ', wc_rev=rev),
+      dest_name + "/mu"        : Item(status='  ', wc_rev=rev),
+      dest_name + "/C"         : Item(status='  ', wc_rev=rev),
+      dest_name + "/D"         : Item(status='  ', wc_rev=rev),
+      dest_name + "/D/gamma"   : Item(status='  ', wc_rev=rev),
+      dest_name + "/D/G"       : Item(status='  ', wc_rev=rev),
+      dest_name + "/D/G/pi"    : Item(status='  ', wc_rev=rev),
+      dest_name + "/D/G/rho"   : Item(status='  ', wc_rev=rev),
+      dest_name + "/D/G/tau"   : Item(status='  ', wc_rev=rev),
+      dest_name + "/D/H"       : Item(status='  ', wc_rev=rev),
+      dest_name + "/D/H/chi"   : Item(status='  ', wc_rev=rev),
+      dest_name + "/D/H/omega" : Item(status='  ', wc_rev=rev),
+      dest_name + "/D/H/psi"   : Item(status='  ', wc_rev=rev),
+      dest_name                : Item(status='  ', wc_rev=rev)})
+    expected_disk.add({
+      dest_name                : Item(),
+      dest_name + '/B'         : Item(),
+      dest_name + '/B/lambda'  : Item("This is the file 'lambda'.\n"),
+      dest_name + '/B/E'       : Item(),
+      dest_name + '/B/E/alpha' : Item("This is the file 'alpha'.\n"),
+      dest_name + '/B/E/beta'  : Item("This is the file 'beta'.\n"),
+      dest_name + '/B/F'       : Item(),
+      dest_name + '/mu'        : Item("This is the file 'mu'.\n"),
+      dest_name + '/C'         : Item(),
+      dest_name + '/D'         : Item(),
+      dest_name + '/D/gamma'   : Item("This is the file 'gamma'.\n"),
+      dest_name + '/D/G'       : Item(),
+      dest_name + '/D/G/pi'    : Item("This is the file 'pi'.\n"),
+      dest_name + '/D/G/rho'   : Item("This is the file 'rho'.\n"),
+      dest_name + '/D/G/tau'   : Item("This is the file 'tau'.\n"),
+      dest_name + '/D/H'       : Item(),
+      dest_name + '/D/H/chi'   : Item("This is the file 'chi'.\n"),
+      dest_name + '/D/H/omega' : Item("This is the file 'omega'.\n"),
+      dest_name + '/D/H/psi'   : Item("This is the file 'psi'.\n"),
+      })
 
-  # 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)
+    # Make a branch A_COPY to merge into.
+    actions.run_and_verify_svn(None, expected, [], 'copy',
+                                       sbox.repo_url + "/A",
+                                       os.path.join(wc_dir,
+                                                    dest_name))
 
-  # Copy B to B2 as rev 3
-  B_url = sbox.repo_url + '/A/B'
-  B2_url = sbox.repo_url + '/A/B2'
+    expected_output = wc.State(wc_dir, {dest_name : Item(verb='Adding')})
+    actions.run_and_verify_commit(wc_dir,
+                                          expected_output,
+                                          expected_status,
+                                          None,
+                                          wc_dir)
+  for i in range(nbr_of_branches):
+    if i == 0:
+      copy_A('A_COPY', i + 2)
+    else:
+      copy_A('A_COPY_' + str(i + 1), i + 2)
 
-  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)
+  if branch_only:
+    return expected_disk, expected_status
 
-  # 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)
+  # Make some changes under A which we'll later merge under A_COPY:
 
-  # 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)
+  # r(nbr_of_branches + 2) - modify and commit A/D/H/psi
+  main.file_write(sbox.ospath('A/D/H/psi'),
+                          "New content")
+  expected_output = wc.State(wc_dir, {'A/D/H/psi' : Item(verb='Sending')})
+  expected_status.tweak('A/D/H/psi', wc_rev=nbr_of_branches + 2)
+  actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+  expected_disk.tweak('A/D/H/psi', contents="New content")
 
-  pristine_status = expected_status
-  pristine_status.tweak(wc_rev=4)
+  # r(nbr_of_branches + 3) - modify and commit A/D/G/rho
+  main.file_write(sbox.ospath('A/D/G/rho'),
+                          "New content")
+  expected_output = wc.State(wc_dir, {'A/D/G/rho' : Item(verb='Sending')})
+  expected_status.tweak('A/D/G/rho', wc_rev=nbr_of_branches + 3)
+  actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+  expected_disk.tweak('A/D/G/rho', contents="New content")
 
-  # Merge B 3:4 into B2
-  B2_path = sbox.ospath('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)
+  # r(nbr_of_branches + 4) - modify and commit A/B/E/beta
+  main.file_write(sbox.ospath('A/B/E/beta'),
+                          "New content")
+  expected_output = wc.State(wc_dir, {'A/B/E/beta' : Item(verb='Sending')})
+  expected_status.tweak('A/B/E/beta', wc_rev=nbr_of_branches + 4)
+  actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+  expected_disk.tweak('A/B/E/beta', contents="New content")
 
-  # Revert merge
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'revert', '--recursive', wc_dir)
-  svntest.actions.run_and_verify_status(wc_dir, pristine_status)
+  # r(nbr_of_branches + 5) - modify and commit A/D/H/omega
+  main.file_write(sbox.ospath('A/D/H/omega'),
+                          "New content")
+  expected_output = wc.State(wc_dir, {'A/D/H/omega' : Item(verb='Sending')})
+  expected_status.tweak('A/D/H/omega', wc_rev=nbr_of_branches + 5)
+  actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+  expected_disk.tweak('A/D/H/omega', contents="New content")
 
-  # 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'\n" \
-           "but the property has been locally deleted.\n" \
-           "<<<<<<< (local property value)\n=======\n" \
-           "%s>>>>>>> (incoming property value)\n" % (property, 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.main.safe_rmtree(wc_dir)
-  svntest.actions.run_and_verify_svn(None, None, [], 'checkout',
-                                     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 = sbox.ospath('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.
-@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 = sbox.ospath('base1')
-  base2_path = sbox.ospath('base2')
-  apply_path = sbox.ospath('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'
-  ### TODO: We can use run_and_verify_merge() here now.
-  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) or
-  '*' (no revision specified)."""
-
-  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 = sbox.ospath('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)
-
-#----------------------------------------------------------------------
-@SkipUnless(server_has_mergeinfo)
-@Issue(1150)
-def merge_one_file_using_r(sbox):
-  "merge one file using the -r option"
-  merge_one_file_helper(sbox, 'r')
-
-#----------------------------------------------------------------------
-@SkipUnless(server_has_mergeinfo)
-@Issue(1150)
-def merge_one_file_using_c(sbox):
-  "merge one file using the -c option"
-  merge_one_file_helper(sbox, 'c')
-
-#----------------------------------------------------------------------
-@SkipUnless(server_has_mergeinfo)
-def merge_one_file_using_implicit_revs(sbox):
-  "merge one file without explicit revisions"
-  merge_one_file_helper(sbox, '*')
-
-#----------------------------------------------------------------------
-@SkipUnless(server_has_mergeinfo)
-def merge_record_only(sbox):
-  "mark a revision range as merged"
-  merge_one_file_helper(sbox, 'r', 1)
-
-#----------------------------------------------------------------------
-# This is a regression test for the enhancement added in issue #785 "add
-# friendly enhancement to 'svn merge'", which is about inferring that
-# the default target of "svn merge [-r...] FILE" should not be "." but
-# rather should be "FILE".
-def merge_with_implicit_target_helper(sbox, arg_flav):
-  """ARG_FLAV is one of 'r' (revision range) or 'c' (single change) or
-  '*' (no revision specified)."""
-
-  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 = sbox.ospath('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))
-
-#----------------------------------------------------------------------
-@Issue(785)
-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')
-
-#----------------------------------------------------------------------
-@Issue(785)
-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')
-
-#----------------------------------------------------------------------
-@Issue(785)
-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 = sbox.ospath('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 = sbox.ospath('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.
-@SkipUnless(server_has_mergeinfo)
-@Issue(1319)
-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 = sbox.ospath('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,
-                                       True, True, '--allow-mixed-revisions',
-                                       other_wc)
-
-#----------------------------------------------------------------------
-# Regression test for Issue #1297:
-# A merge that creates a new file followed by an immediate diff
-# The diff should succeed.
-@SkipUnless(server_has_mergeinfo)
-@Issue(1297)
-def merge_in_new_file_and_diff(sbox):
-  "diff after merge that creates a new file"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  trunk_url = sbox.repo_url + '/A/B/E'
-
-  # 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)
-
-  new_file_path = sbox.ospath('A/B/E/newfile')
-  svntest.main.file_write(new_file_path, "newfile\n")
-
-  # 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)
-
-  branch_path = sbox.ospath('branch')
-  url_branch_path = branch_path.replace(os.path.sep, '/')
-
-  # Merge our addition into the branch.
-  expected_output = svntest.wc.State(branch_path, {
-    'newfile' : Item(status='A '),
-    })
-  expected_mergeinfo_output = svntest.wc.State(branch_path, {
-    '' : Item(status=' U'),
-    })
-  expected_elision_output = wc.State(branch_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"),
-    })
-  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('', { })
-
-  svntest.actions.run_and_verify_merge(branch_path,
-                                       '1', 'HEAD', trunk_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip)
-
-  # Finally, run diff.
-  expected_output = [
-    "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",
-
-    "Index: " + url_branch_path + "\n",
-    "===================================================================\n",
-    "--- "+ url_branch_path + "\t(revision 2)\n",
-    "+++ "+ url_branch_path + "\t(working copy)\n",
-    "\n",
-    "Property changes on: " + url_branch_path + "\n",
-    "___________________________________________________________________\n",
-    "Added: " + SVN_PROP_MERGEINFO + "\n",
-    "   Merged /A/B/E:r2-3\n",
-  ]
-  svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff',
-                                     '--show-copies-as-adds', branch_path)
-
-
-#----------------------------------------------------------------------
-# Issue #1425:  'svn merge' should skip over any unversioned obstructions.
-# This test involves tree conflicts. - but attempting to test for
-# pre-tree-conflict behaviour
-@SkipUnless(server_has_mergeinfo)
-@Issues(1425, 2898)
-def merge_skips_obstructions(sbox):
-  "merge should skip over unversioned obstructions"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  C_path = sbox.ospath('A/C')
-  F_path = sbox.ospath('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)
-
-  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'),
-    })
-  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),
-    })
-  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 '),
-    })
-  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(),
-    'Q/bar'  : Item("bar"),
-    'foo'    : Item("foo"),
-    })
-  expected_status = wc.State(C_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(verb='Skipped'),
-    })
-  # 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_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_output = wc.State(C_path, {
-    'foo'    : Item(status='A '),
-    'Q/bar'  : Item(status='  ', treeconflict='A'), # Skipped
-    })
-  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(verb='Skipped'),
-    })
-
-  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)
-
-  # 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)
-
-  iota_path = sbox.ospath('iota')
-  G_path = sbox.ospath('A/D/G')
-  svntest.actions.run_and_verify_svn(None, None, [], 'rm', iota_path, G_path)
-
-  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)
-
-  # 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.
-
-  svntest.main.file_append(iota_path, "foo") # unversioned
-  os.mkdir(G_path) # unversioned
-
-  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 = 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_disk.tweak('iota', contents="foo")
-  # No-op merge still sets mergeinfo
-  expected_status.tweak('', status=' M')
-  expected_skip = wc.State(wc_dir, {
-    'iota'  : Item(verb='Skipped'),
-    'A/D/G' : Item(verb='Skipped'),
-    })
-  svntest.actions.run_and_verify_merge(wc_dir, '2', '3',
-                                       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,
-                                       True, False, '--allow-mixed-revisions',
-                                       wc_dir)
-
-  # 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 = sbox.ospath('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)
-
-  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)
-
-  # 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.
-
-  svntest.main.file_append(lambda_path, "foo") # unversioned
-
-  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(verb='Skipped'),
-    })
-  # No-op merge still sets mergeinfo.
-  expected_status_short = expected_status.copy(wc_dir)
-  expected_status_short.tweak('', status=' M')
-
-  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,
-                                       True, False, '--allow-mixed-revisions',
-                                       wc_dir)
-
-  # 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.
-
-  svntest.actions.run_and_verify_svn(None, None, [], 'add', lambda_path)
-
-  # Mergeinfo prop changed so update to avoid out of date error.
-  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
-
-  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='  ')
-  expected_skip = wc.State(wc_dir, {
-    'A/B/lambda' : Item(verb='Skipped missing target'),
-    })
-  # 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',
-                                       '--allow-mixed-revisions', wc_dir)
-
-#----------------------------------------------------------------------
-# 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.
-@SkipUnless(server_has_mergeinfo)
-def merge_into_missing(sbox):
-  "merge into missing must not break working copy"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  F_path = sbox.ospath('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)
-
-  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),
-    # Missing data still available
-    'Q/R'      : Item(status='! ', wc_rev=3),
-    'Q/R/bar'  : Item(status='! ', wc_rev=3),
-    'Q/baz'    : Item(status='! ', wc_rev=3),
-  })
-  expected_skip = wc.State(F_path, {
-    'Q'   : Item(verb='Skipped missing target'),
-    'foo' : Item(verb='Skipped missing target'),
-    })
-  # Use --ignore-ancestry because merge tracking aware merges raise an
-  # error when the merge target is missing subtrees due to OS-level
-  # deletes.
-
-  ### 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',
-                                       '--ignore-ancestry',
-                                       '--allow-mixed-revisions',
-                                       F_path)
-
-  expected_status = wc.State(F_path, {
-    ''      : Item(status='  ', wc_rev=1),
-    'foo'   : Item(status='! ', wc_rev=2),
-    'Q'     : Item(status='! ', wc_rev='2'),
-    # Revision is known and we can record mergeinfo
-    'Q/R'      : Item(status='! ', wc_rev='3'),
-    'Q/R/bar'  : Item(status='! ', wc_rev='3'),
-    'Q/baz'    : Item(status='! ', wc_rev='3'),
-  })
-  expected_mergeinfo_output = wc.State(F_path, {
-    })
-
-  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,
-                                       '--ignore-ancestry',
-                                       '--allow-mixed-revisions',
-                                       F_path)
-
-  # 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)
-
-  # Check working copy is not locked.
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.add({
-    'A/B/F'     : Item(status='  ', wc_rev=1),
-    'A/B/F/foo' : Item(status='! ', wc_rev=2),
-    'A/B/F/Q'   : Item(status='! ', wc_rev=2),
-    'A/B/F/Q/baz'    : Item(status='! ', wc_rev='3'),
-    'A/B/F/Q/R'      : Item(status='! ', wc_rev='3'),
-    'A/B/F/Q/R/bar'  : Item(status='! ', wc_rev='3'),
-  })
-
-  svntest.actions.run_and_verify_status(wc_dir, expected_status)
-
-#----------------------------------------------------------------------
-# A test for issue 1738
-@Issue(1738)
-@SkipUnless(server_has_mergeinfo)
-def dry_run_adds_file_with_prop(sbox):
-  "merge --dry-run adding a new file with props"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  # Commit a new file which has a property.
-  zig_path = sbox.ospath('A/B/E/zig')
-  svntest.main.file_append(zig_path, "zig contents")
-  svntest.actions.run_and_verify_svn(None, None, [], 'add', zig_path)
-  svntest.actions.run_and_verify_svn(None, None, [],
-                                     'propset', 'foo', 'foo_val',
-                                     zig_path)
-
-  expected_output = wc.State(wc_dir, {
-    'A/B/E/zig'     : Item(verb='Adding'),
-    })
-  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  expected_status.add({
-    'A/B/E/zig'   : Item(status='  ', wc_rev=2),
-    })
-  svntest.actions.run_and_verify_commit(wc_dir,
-                                        expected_output,
-                                        expected_status,
-                                        None, wc_dir)
-
-  # Do a regular merge of that change into a different dir.
-  F_path = sbox.ospath('A/B/F')
-  E_url = sbox.repo_url + '/A/B/E'
-
-  expected_output = wc.State(F_path, {
-    'zig'  : Item(status='A '),
-    })
-  expected_mergeinfo_output = wc.State(F_path, {
-    '' : Item(status=' U'),
-    })
-  expected_elision_output = wc.State(F_path, {
-    })
-  expected_disk = wc.State('', {
-    ''         : Item(props={SVN_PROP_MERGEINFO : '/A/B/E:2'}),
-    'zig'      : Item("zig contents", {'foo':'foo_val'}),
-    })
-  expected_skip = wc.State('', { })
-  expected_status = None  # status is optional
-
-  svntest.actions.run_and_verify_merge(F_path, '1', '2', E_url, None,
-                                       expected_output,
-                                       expected_mergeinfo_output,
-                                       expected_elision_output,
-                                       expected_disk,
-                                       expected_status,
-                                       expected_skip,
-                                       None, None, None, None, None,
-                                       1, # please check props
-                                       1) # and do a dry-run also)
-
-#----------------------------------------------------------------------
-# Regression test for issue #1673
-# Merge a binary file from two URL with a common ancestry
-@Issue(1673)
-def merge_binary_with_common_ancestry(sbox):
-  "merge binary files with common ancestry"
-
-  sbox.build()
-  wc_dir = sbox.wc_dir
-
-  # Create the common ancestry path
-  I_path = sbox.ospath('I')
-  svntest.main.run_svn(None, 'mkdir', I_path)

[... 17468 lines stripped ...]


Mime
View raw message