You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2011/12/19 19:49:43 UTC

svn commit: r1220893 [17/19] - in /subversion/branches/fs-py: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/mod_dontdothat/ notes/ subversion/bindings/javahl/native/ s...

Modified: subversion/branches/fs-py/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/patch_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/patch_tests.py Mon Dec 19 18:49:34 2011
@@ -3427,7 +3427,6 @@ def patch_strip_cwd(sbox):
   "patch --strip propchanges cwd"
   return patch_one_property(sbox, True)
 
-@XFail()
 @Issue(3814)
 def patch_set_prop_no_eol(sbox):
   "patch doesn't append newline to properties"
@@ -3615,7 +3614,6 @@ def patch_moved_away(sbox):
                                        1, # check-props
                                        1) # dry-run
 
-@XFail()
 @Issue(3991)
 def patch_lacking_trailing_eol(sbox):
   "patch file lacking trailing eol"
@@ -3650,12 +3648,11 @@ def patch_lacking_trailing_eol(sbox):
 
   expected_output = [
     'U         %s\n' % os.path.join(wc_dir, 'iota'),
-    'svn: W[0-9]+: .*', # warning about appending a newline to iota's last line
   ]
 
   # Expect a newline to be appended
   expected_disk = svntest.main.greek_state.copy()
-  expected_disk.tweak('iota', contents=iota_contents+"Some more bytes\n")
+  expected_disk.tweak('iota', contents=iota_contents + "Some more bytes")
 
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
   expected_status.tweak('iota', status='M ')
@@ -3858,6 +3855,196 @@ def patch_reversed_add_with_props2(sbox)
                                        1, # dry-run
                                        '--reverse-diff') 
 
+def patch_dev_null(sbox):
+  "patch with /dev/null filenames"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  patch_file_path = make_patch_path(sbox)
+
+  # Git (and maybe other tools) use '/dev/null' as the old path for
+  # newly added files, and as the new path for deleted files.
+  # The path selection algorithm in 'svn patch' must detect this and
+  # avoid using '/dev/null' as a patch target.
+  unidiff_patch = [
+    "Index: new\n",
+    "===================================================================\n",
+    "--- /dev/null\n",
+    "+++ new	(revision 0)\n",
+    "@@ -0,0 +1 @@\n",
+    "+new\n",
+    "\n",
+    "Index: A/B/E/beta\n",
+    "===================================================================\n",
+    "--- A/B/E/beta	(revision 1)\n",
+    "+++ /dev/null\n",
+    "@@ -1 +0,0 @@\n",
+    "-This is the file 'beta'.\n",
+  ]
+
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  new_contents = "new\n"
+  expected_output = [
+    'A         %s\n' % os.path.join(wc_dir, 'new'),
+    'D         %s\n' % os.path.join(wc_dir, 'A', 'B', 'E', 'beta'),
+  ]
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({'new' : Item(contents=new_contents)})
+  expected_disk.remove('A/B/E/beta')
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.add({'new' : Item(status='A ', wc_rev=0)})
+  expected_status.tweak('A/B/E/beta', status='D ')
+
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       1, # check-props
+                                       1) # dry-run
+
+@Issue(4049)
+def patch_delete_and_skip(sbox):
+  "patch that deletes and skips"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  patch_file_path = make_patch_path(sbox)
+
+  os.chdir(wc_dir)
+
+  # We need to use abspaths to trigger the segmentation fault.
+  abs = os.path.abspath('.')
+  if sys.platform == 'win32':
+      abs = abs.replace("\\", "/")
+
+  outside_wc = os.path.join(os.pardir, 'X')
+  if sys.platform == 'win32':
+      outside_wc = outside_wc.replace("\\", "/")
+
+  unidiff_patch = [
+    "Index: %s/A/B/E/alpha\n" % abs,
+    "===================================================================\n",
+    "--- %s/A/B/E/alpha\t(revision 1)\n" % abs,
+    "+++ %s/A/B/E/alpha\t(working copy)\n" % abs,
+    "@@ -1 +0,0 @@\n",
+    "-This is the file 'alpha'.\n",
+    "Index: %s/A/B/E/beta\n" % abs,
+    "===================================================================\n",
+    "--- %s/A/B/E/beta\t(revision 1)\n" % abs,
+    "+++ %s/A/B/E/beta\t(working copy)\n" % abs,
+    "@@ -1 +0,0 @@\n",
+    "-This is the file 'beta'.\n",
+    "Index: %s/A/B/E/out-of-reach\n" % abs,
+    "===================================================================\n",
+    "--- %s/iota\t(revision 1)\n" % outside_wc,
+    "+++ %s/iota\t(working copy)\n" % outside_wc,
+    "\n",
+    "Property changes on: iota\n",
+    "___________________________________________________________________\n",
+    "Added: propname\n",
+    "## -0,0 +1 ##\n",
+    "+propvalue\n",
+  ]
+
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  skipped_path = os.path.join(os.pardir, 'X', 'iota')
+  expected_output = [
+    'D         %s\n' % os.path.join('A', 'B', 'E', 'alpha'),
+    'D         %s\n' % os.path.join('A', 'B', 'E', 'beta'),
+    'Skipped missing target: \'%s\'\n' % skipped_path,
+    'D         %s\n' % os.path.join('A', 'B', 'E'),
+    'Summary of conflicts:\n',
+    '  Skipped paths: 1\n'
+  ]
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/B/E/alpha')
+  expected_disk.remove('A/B/E/beta')
+  expected_disk.remove('A/B/E')
+
+  expected_status = svntest.actions.get_virginal_state('.', 1)
+  expected_status.tweak('A/B/E', status='D ')
+  expected_status.tweak('A/B/E/alpha', status='D ')
+  expected_status.tweak('A/B/E/beta', status='D ')
+
+  expected_skip = wc.State('', {skipped_path: Item()})
+
+  svntest.actions.run_and_verify_patch('.', os.path.abspath(patch_file_path),
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       1, # check-props
+                                       1) # dry-run
+
+def patch_target_no_eol_at_eof(sbox):
+  "patch target with no eol at eof"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  patch_file_path = make_patch_path(sbox)
+  iota_path = os.path.join(wc_dir, 'iota')
+
+  iota_contents = [
+    "This is the file iota."
+  ]
+
+  svntest.main.file_write(iota_path, ''.join(iota_contents))
+  expected_output = svntest.wc.State(wc_dir, {
+    'iota'  : Item(verb='Sending'),
+    })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('iota', wc_rev=2)
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        expected_status, None, wc_dir)
+  unidiff_patch = [
+    "--- iota\t(revision 1)\n",
+    "+++ iota\t(working copy)\n",
+    "@@ -1,7 +1,7 @@\n",
+    "-This is the file iota.\n"
+    "\\ No newline at end of file\n",
+    "+It is really the file 'iota'.\n",
+    "\\ No newline at end of file\n",
+  ]
+
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  iota_contents = [
+    "It is really the file 'iota'."
+  ]
+  expected_output = [
+    'U         %s\n' % os.path.join(wc_dir, 'iota'),
+  ]
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.tweak('iota', contents=''.join(iota_contents))
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak('iota', status='M ', wc_rev=2)
+
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       1, # check-props
+                                       1) # dry-run
+
 ########################################################################
 #Run the tests
 
@@ -3898,6 +4085,9 @@ test_list = [ None,
               patch_deletes_prop,
               patch_reversed_add_with_props,
               patch_reversed_add_with_props2,
+              patch_dev_null,
+              patch_delete_and_skip,
+              patch_target_no_eol_at_eof,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/prop_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/prop_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/prop_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/prop_tests.py Mon Dec 19 18:49:34 2011
@@ -893,8 +893,7 @@ def prop_value_conversions(sbox):
   svntest.actions.set_prop('svn:executable', '*', lambda_path)
   for pval in ('      ', '', 'no', 'off', 'false'):
     svntest.actions.set_prop('svn:executable', pval, mu_path,
-                             ["svn: warning: To turn off the svn:executable property, use 'svn propdel';\n",
-                              "setting the property to '" + pval + "' will not turn it off.\n"])
+                             "svn: warning: W125005.*use 'svn propdel'")
 
   # Anything else should be untouched
   svntest.actions.set_prop('svn:some-prop', 'bar', lambda_path)

Modified: subversion/branches/fs-py/subversion/tests/cmdline/resolve_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/resolve_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/resolve_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/resolve_tests.py Mon Dec 19 18:49:34 2011
@@ -42,6 +42,7 @@ Issue = svntest.testcase.Issue_deco
 Wimp = svntest.testcase.Wimp_deco
 
 from merge_tests import set_up_branch
+from merge_tests import expected_merge_output
 
 # 'svn resolve --accept [ base | mine-full | theirs-full ]' was segfaulting
 # on 1.6.x.  Prior to this test, the bug was only caught by the Ruby binding
@@ -69,12 +70,10 @@ def automatic_conflict_resolution(sbox):
                                        'revert', '--recursive', A_COPY_path)
     svntest.actions.run_and_verify_svn(
       None,
-      "(--- Merging r3 into .*A_COPY':\n)|"
-      "(C    .*psi\n)|"
-      "(--- Recording mergeinfo for merge of r3 into .*A_COPY':\n)|"
-      "( U   .*A_COPY\n)|"
-      "(Summary of conflicts:\n)|"
-      "(  Text conflicts: 1\n)",
+      expected_merge_output([[3]], [
+        "C    %s\n" % psi_COPY_path,
+        " U   %s\n" % A_COPY_path],
+        target=A_COPY_path, text_conflicts=1),
       [], 'merge', '-c3', '--allow-mixed-revisions',
       sbox.repo_url + '/A',
       A_COPY_path)

Modified: subversion/branches/fs-py/subversion/tests/cmdline/special_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/special_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/special_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/special_tests.py Mon Dec 19 18:49:34 2011
@@ -551,7 +551,9 @@ def diff_symlink_to_dir(sbox):
     "___________________________________________________________________\n",
     "Added: svn:special\n",
     "## -0,0 +1 ##\n",
-    "+*\n" ]
+    "+*\n",
+    "\\ No newline at end of property\n"
+  ]
   svntest.actions.run_and_verify_svn(None, expected_output, [], 'diff',
                                      '.')
   # We should get the same output if we the diff the symlink itself.
@@ -860,6 +862,49 @@ def symlink_to_wc_svnversion(sbox):
                                             symlink_path, sbox.repo_url,
                                             [ "1\n" ], [])
 
+# Regression in 1.7.0: Update fails to change a symlink
+@SkipUnless(svntest.main.is_posix_os)
+def update_symlink(sbox):
+  "update a symlink"
+
+  svntest.actions.do_sleep_for_timestamps()
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  mu_path = sbox.ospath('A/mu')
+  iota_path = sbox.ospath('iota')
+  symlink_path = sbox.ospath('symlink')
+
+  # create a symlink to /A/mu
+  os.symlink("A/mu", symlink_path)
+  sbox.simple_add('symlink')
+  sbox.simple_commit()
+
+  # change the symlink to /iota
+  os.remove(symlink_path)
+  os.symlink("iota", symlink_path)
+  sbox.simple_commit()
+
+  # update back to r2
+  svntest.main.run_svn(False, 'update', '-r', '2', wc_dir)
+
+  # now update to head; 1.7.0 throws an assertion here
+  expected_output = svntest.wc.State(wc_dir, {
+    'symlink'          : Item(status='U '),
+  })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({'symlink': Item(contents="This is the file 'iota'.\n",
+                                     props={'svn:special' : '*'})})
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
+  expected_status.add({
+    'symlink'           : Item(status='  ', wc_rev='3'),
+  })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, 1)
 
 ########################################################################
 # Run the tests
@@ -887,6 +932,7 @@ test_list = [ None,
               merge_foreign_symlink,
               symlink_to_wc_basic,
               symlink_to_wc_svnversion,
+              update_symlink,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/stat_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/stat_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/stat_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/stat_tests.py Mon Dec 19 18:49:34 2011
@@ -1924,6 +1924,31 @@ def wclock_status(sbox):
                                      'status', wc_dir)
 
 
+@Issue(4072)
+@XFail()
+def modified_modulo_translation(sbox):
+  "modified before translation, unmodified after"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # iota is a shell script.
+  sbox.simple_propset('svn:eol-style', 'LF', 'iota')
+  sbox.simple_commit()
+
+  # CRLF it.
+  open(sbox.ospath('iota'), 'wb').write("This is the file 'iota'.\r\n")
+
+  # Run status.  Expect some output.
+  # TODO: decide how such files should show in the output; whether they
+  #       always show, or only with some --flag; and adjust this accordingly.
+  svntest.actions.run_and_verify_svn(None, svntest.verify.AnyOutput, [],
+                                     'status', wc_dir)
+
+  # Expect the file to be renormalized (to LF) after a revert.
+  sbox.simple_revert('iota')
+  svntest.actions.run_and_verify_svn(None, [], [], 'status', wc_dir)
+
 ########################################################################
 # Run the tests
 
@@ -1965,6 +1990,7 @@ test_list = [ None,
               status_locked_deleted,
               wc_wc_copy_timestamp,
               wclock_status,
+              modified_modulo_translation,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/svnadmin_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/svnadmin_tests.py Mon Dec 19 18:49:34 2011
@@ -1478,6 +1478,68 @@ def test_lslocks_and_rmlocks(sbox):
     "Unexpected output while running 'svnadmin rmlocks'.",
     output, [], expected_output, None)
 
+#----------------------------------------------------------------------
+@Issue(3734)
+def load_ranges(sbox):
+  "'svnadmin load --revision X:Y'"
+
+  ## See http://subversion.tigris.org/issues/show_bug.cgi?id=3734. ##
+  test_create(sbox)
+
+  dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]),
+                                   'svnadmin_tests_data',
+                                   'skeleton_repos.dump')
+  dumplines = open(dumpfile_location).readlines()
+  dumpdata = "".join(dumplines)
+
+  # Load our dumpfile, 2 revisions at a time, verifying that we have
+  # the correct youngest revision after each load.
+  load_and_verify_dumpstream(sbox, [], [], None, dumpdata, '-r0:2')
+  svntest.actions.run_and_verify_svnlook("Unexpected output", ['2\n'],
+                                         None, 'youngest', sbox.repo_dir)
+  load_and_verify_dumpstream(sbox, [], [], None, dumpdata, '-r3:4')
+  svntest.actions.run_and_verify_svnlook("Unexpected output", ['4\n'],
+                                         None, 'youngest', sbox.repo_dir)
+  load_and_verify_dumpstream(sbox, [], [], None, dumpdata, '-r5:6')
+  svntest.actions.run_and_verify_svnlook("Unexpected output", ['6\n'],
+                                         None, 'youngest', sbox.repo_dir)
+
+  # There are ordering differences in the property blocks.
+  expected_dump = UnorderedOutput(dumplines)
+  new_dumpdata = svntest.actions.run_and_verify_dump(sbox.repo_dir)
+  svntest.verify.compare_and_display_lines("Dump files", "DUMP",
+                                           expected_dump, new_dumpdata)
+
+@SkipUnless(svntest.main.is_fs_type_fsfs)
+def hotcopy_incremental(sbox):
+  "'svnadmin hotcopy --incremental PATH .'"
+  sbox.build()
+
+  backup_dir, backup_url = sbox.add_repo_path('backup')
+  os.mkdir(backup_dir)
+  cwd = os.getcwd()
+
+  for i in [1, 2, 3]:
+    os.chdir(backup_dir)
+    svntest.actions.run_and_verify_svnadmin(
+      None, None, [],
+      "hotcopy", "--incremental", os.path.join(cwd, sbox.repo_dir), '.')
+
+    os.chdir(cwd)
+
+    exit_code, origout, origerr = svntest.main.run_svnadmin("dump",
+                                                            sbox.repo_dir,
+                                                            '--quiet')
+    exit_code, backout, backerr = svntest.main.run_svnadmin("dump",
+                                                            backup_dir,
+                                                            '--quiet')
+    if origerr or backerr or origout != backout:
+      raise svntest.Failure
+
+    if i < 3:
+      sbox.simple_mkdir("newdir-%i" % i)
+      sbox.simple_commit()
+
 ########################################################################
 # Run the tests
 
@@ -1508,6 +1570,8 @@ test_list = [ None,
               load_bad_props,
               verify_non_utf8_paths,
               test_lslocks_and_rmlocks,
+              load_ranges,
+              hotcopy_incremental,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/svnmucc_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/svnmucc_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/svnmucc_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/svnmucc_tests.py Mon Dec 19 18:49:34 2011
@@ -25,6 +25,7 @@
 ######################################################################
 
 import svntest
+import re
 
 XFail = svntest.testcase.XFail_deco
 Issues = svntest.testcase.Issues_deco
@@ -46,10 +47,276 @@ def reject_bogus_mergeinfo(sbox):
                                          'propset', 'svn:mergeinfo', '/B:0',
                                          sbox.repo_url + '/A')
 
+_svnmucc_re = re.compile('^(r[0-9]+) committed by jrandom at (.*)$')
+_log_re = re.compile('^   ([ADRM] /[^\(]+($| \(from .*:[0-9]+\)$))')
+_err_re = re.compile('^svnmucc: (.*)$')
+
+def test_svnmucc(repo_url, expected_path_changes, *varargs):
+  """Run svnmucc with the list of SVNMUCC_ARGS arguments.  Verify that
+  its run results in a new commit with 'svn log -rHEAD' changed paths
+  that match the list of EXPECTED_PATH_CHANGES."""
+
+  # First, run svnmucc.
+  exit_code, outlines, errlines = svntest.main.run_svnmucc('-U', repo_url,
+                                                           *varargs)
+  if errlines:
+    raise svntest.main.SVNCommitFailure(str(errlines))
+  if len(outlines) != 1 or not _svnmucc_re.match(outlines[0]):
+    raise svntest.main.SVNLineUnequal(str(outlines))
+
+  # Now, run 'svn log -vq -rHEAD'
+  changed_paths = []
+  exit_code, outlines, errlines = \
+    svntest.main.run_svn(None, 'log', '-vqrHEAD', repo_url)
+  if errlines:
+    raise svntest.Failure("Unable to verify commit with 'svn log': %s"
+                          % (str(errlines)))
+  for line in outlines:
+    match = _log_re.match(line)
+    if match:
+      changed_paths.append(match.group(1).rstrip('\n\r'))
+
+  expected_path_changes.sort()
+  changed_paths.sort()
+  if changed_paths != expected_path_changes:
+    raise svntest.Failure("Logged path changes differ from expectations\n"
+                          "   expected: %s\n"
+                          "     actual: %s" % (str(expected_path_changes),
+                                               str(changed_paths)))
+
+def xtest_svnmucc(repo_url, expected_errors, *varargs):
+  """Run svnmucc with the list of SVNMUCC_ARGS arguments.  Verify that
+  its run results match the list of EXPECTED_ERRORS."""
+
+  # First, run svnmucc.
+  exit_code, outlines, errlines = svntest.main.run_svnmucc('-U', repo_url,
+                                                           *varargs)
+  errors = []
+  for line in errlines:
+    match = _err_re.match(line)
+    if match:
+      errors.append(line.rstrip('\n\r'))
+  if errors != expected_errors:
+    raise svntest.main.SVNUnmatchedError(str(errors))
+
+
+def basic_svnmucc(sbox):
+  "basic svnmucc tests"
+
+  sbox.build()
+  empty_file = sbox.ospath('empty')
+  svntest.main.file_append(empty_file, '')
+
+  # revision 2
+  test_svnmucc(sbox.repo_url,
+               ['A /foo'
+                ], # ---------
+               'mkdir', 'foo')
+
+  # revision 3
+  test_svnmucc(sbox.repo_url,
+               ['A /z.c',
+                ], # ---------
+               'put', empty_file, 'z.c')
+
+  # revision 4
+  test_svnmucc(sbox.repo_url,
+               ['A /foo/z.c (from /z.c:3)',
+                'A /foo/bar (from /foo:3)',
+                ], # ---------
+               'cp', '3', 'z.c', 'foo/z.c',
+               'cp', '3', 'foo', 'foo/bar')
+
+  # revision 5
+  test_svnmucc(sbox.repo_url,
+               ['A /zig (from /foo:4)',
+                'D /zig/bar',
+                'D /foo',
+                'A /zig/zag (from /foo:4)',
+                ], # ---------
+               'cp', '4', 'foo', 'zig',
+               'rm',             'zig/bar',
+               'mv',      'foo', 'zig/zag')
+
+  # revision 6
+  test_svnmucc(sbox.repo_url,
+               ['D /z.c',
+                'A /zig/zag/bar/y.c (from /z.c:5)',
+                'A /zig/zag/bar/x.c (from /z.c:3)',
+                ], # ---------
+               'mv',      'z.c', 'zig/zag/bar/y.c',
+               'cp', '3', 'z.c', 'zig/zag/bar/x.c')
+
+  # revision 7
+  test_svnmucc(sbox.repo_url,
+               ['D /zig/zag/bar/y.c',
+                'A /zig/zag/bar/y y.c (from /zig/zag/bar/y.c:6)',
+                'A /zig/zag/bar/y%20y.c (from /zig/zag/bar/y.c:6)',
+                ], # ---------
+               'mv',         'zig/zag/bar/y.c', 'zig/zag/bar/y%20y.c',
+               'cp', 'HEAD', 'zig/zag/bar/y.c', 'zig/zag/bar/y%2520y.c')
+
+  # revision 8
+  test_svnmucc(sbox.repo_url,
+               ['D /zig/zag/bar/y y.c',
+                'A /zig/zag/bar/z z1.c (from /zig/zag/bar/y y.c:7)',
+                'A /zig/zag/bar/z%20z.c (from /zig/zag/bar/y%20y.c:7)',
+                'A /zig/zag/bar/z z2.c (from /zig/zag/bar/y y.c:7)',
+                ], #---------
+               'mv',         'zig/zag/bar/y%20y.c',   'zig/zag/bar/z z1.c',
+               'cp', 'HEAD', 'zig/zag/bar/y%2520y.c', 'zig/zag/bar/z%2520z.c',
+               'cp', 'HEAD', 'zig/zag/bar/y y.c',     'zig/zag/bar/z z2.c')
+
+
+  # revision 9
+  test_svnmucc(sbox.repo_url,
+               ['D /zig/zag',
+                'A /zig/foo (from /zig/zag:8)',
+                'D /zig/foo/bar/z%20z.c',
+                'D /zig/foo/bar/z z2.c',
+                'R /zig/foo/bar/z z1.c (from /zig/zag/bar/x.c:6)',
+                ], #---------
+               'mv',      'zig/zag',         'zig/foo',
+               'rm',                         'zig/foo/bar/z z1.c',
+               'rm',                         'zig/foo/bar/z%20z2.c',
+               'rm',                         'zig/foo/bar/z%2520z.c',
+               'cp', '6', 'zig/zag/bar/x.c', 'zig/foo/bar/z%20z1.c')
+
+  # revision 10
+  test_svnmucc(sbox.repo_url,
+               ['R /zig/foo/bar (from /zig/z.c:9)',
+                ], #---------
+               'rm',                 'zig/foo/bar',
+               'cp', '9', 'zig/z.c', 'zig/foo/bar')
+
+  # revision 11
+  test_svnmucc(sbox.repo_url,
+               ['R /zig/foo/bar (from /zig/foo/bar:9)',
+                'D /zig/foo/bar/z z1.c',
+                ], #---------
+               'rm',                     'zig/foo/bar',
+               'cp', '9', 'zig/foo/bar', 'zig/foo/bar',
+               'rm',                     'zig/foo/bar/z%20z1.c')
+
+  # revision 12
+  test_svnmucc(sbox.repo_url,
+               ['R /zig/foo (from /zig/foo/bar:11)',
+                ], #---------
+               'rm',                        'zig/foo',
+               'cp', 'head', 'zig/foo/bar', 'zig/foo')
+
+  # revision 13
+  test_svnmucc(sbox.repo_url,
+               ['D /zig',
+                'A /foo (from /foo:4)',
+                'A /foo/foo (from /foo:4)',
+                'A /foo/foo/foo (from /foo:4)',
+                'D /foo/foo/bar',
+                'R /foo/foo/foo/bar (from /foo:4)',
+                ], #---------
+               'rm',             'zig',
+               'cp', '4', 'foo', 'foo',
+               'cp', '4', 'foo', 'foo/foo',
+               'cp', '4', 'foo', 'foo/foo/foo',
+               'rm',             'foo/foo/bar',
+               'rm',             'foo/foo/foo/bar',
+               'cp', '4', 'foo', 'foo/foo/foo/bar')
+
+  # revision 14
+  test_svnmucc(sbox.repo_url,
+               ['A /boozle (from /foo:4)',
+                'A /boozle/buz',
+                'A /boozle/buz/nuz',
+                ], #---------
+               'cp',    '4', 'foo', 'boozle',
+               'mkdir',             'boozle/buz',
+               'mkdir',             'boozle/buz/nuz')
+
+  # revision 15
+  test_svnmucc(sbox.repo_url,
+               ['A /boozle/buz/svnmucc-test.py',
+                'A /boozle/guz (from /boozle/buz:14)',
+                'A /boozle/guz/svnmucc-test.py',
+                ], #---------
+               'put',      empty_file,   'boozle/buz/svnmucc-test.py',
+               'cp', '14', 'boozle/buz', 'boozle/guz',
+               'put',      empty_file,   'boozle/guz/svnmucc-test.py')
+
+  # revision 16
+  test_svnmucc(sbox.repo_url,
+               ['M /boozle/buz/svnmucc-test.py',
+                'R /boozle/guz/svnmucc-test.py',
+                ], #---------
+               'put', empty_file, 'boozle/buz/svnmucc-test.py',
+               'rm',              'boozle/guz/svnmucc-test.py',
+               'put', empty_file, 'boozle/guz/svnmucc-test.py')
+
+  # revision 17
+  test_svnmucc(sbox.repo_url,
+               ['R /foo/bar (from /foo/foo:16)'], #---------
+               'rm',                            'foo/bar',
+               'cp', '16', 'foo/foo',           'foo/bar',
+               'propset',  'testprop',  'true', 'foo/bar')
+
+  # revision 18
+  test_svnmucc(sbox.repo_url,
+               ['M /foo/bar'], #---------
+               'propdel', 'testprop', 'foo/bar')
+
+  # revision 19
+  test_svnmucc(sbox.repo_url,
+               ['M /foo/z.c',
+                'M /foo/foo',
+                ], #---------
+               'propset', 'testprop', 'true', 'foo/z.c',
+               'propset', 'testprop', 'true', 'foo/foo')
+
+  # revision 20
+  test_svnmucc(sbox.repo_url,
+               ['M /foo/z.c',
+                'M /foo/foo',
+                ], #---------
+               'propsetf', 'testprop', empty_file, 'foo/z.c',
+               'propsetf', 'testprop', empty_file, 'foo/foo')
+
+  # Expected missing revision error
+  xtest_svnmucc(sbox.repo_url,
+                ["svnmucc: E200004: 'a' is not a revision"
+                 ], #---------
+                'cp', 'a', 'b')
+
+  # Expected cannot be younger error
+  xtest_svnmucc(sbox.repo_url,
+                ['svnmucc: E205000: Copy source revision cannot be younger ' +
+                 'than base revision',
+                 ], #---------
+                'cp', '42', 'a', 'b')
+
+  # Expected already exists error
+  xtest_svnmucc(sbox.repo_url,
+                ["svnmucc: E125002: 'foo' already exists",
+                 ], #---------
+                'cp', '17', 'a', 'foo')
+
+  # Expected copy_src already exists error
+  xtest_svnmucc(sbox.repo_url,
+                ["svnmucc: E125002: 'a/bar' (from 'foo/bar:17') already exists",
+                 ], #---------
+                'cp', '17', 'foo', 'a',
+                'cp', '17', 'foo/foo', 'a/bar')
+
+  # Expected not found error
+  xtest_svnmucc(sbox.repo_url,
+                ["svnmucc: E125002: 'a' not found",
+                 ], #---------
+                'cp', '17', 'a', 'b')
+
+
 ######################################################################
 
 test_list = [ None,
               reject_bogus_mergeinfo,
+              basic_svnmucc,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/svntest/actions.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/svntest/actions.py Mon Dec 19 18:49:34 2011
@@ -1258,7 +1258,7 @@ def run_and_verify_mergeinfo(error_re_st
     verify.verify_outputs(None, None, err, None, expected_err)
     return
 
-  out = sorted([_f for _f in [x.rstrip()[1:] for x in out] if _f])
+  out = [_f for _f in [x.rstrip()[1:] for x in out] if _f]
   expected_output.sort()
   extra_out = []
   if out != expected_output:
@@ -1748,6 +1748,11 @@ def lock_admin_dir(wc_dir, recursive=Fal
 
   svntest.main.run_wc_lock_tester(recursive, wc_dir)
 
+def set_incomplete(wc_dir, revision):
+  "Make wc_dir incomplete at revision"
+
+  svntest.main.run_wc_incomplete_tester(wc_dir, revision)
+
 def get_wc_uuid(wc_dir):
   "Return the UUID of the working copy at WC_DIR."
   return run_and_parse_info(wc_dir)[0]['Repository UUID']
@@ -1818,7 +1823,7 @@ def create_failing_post_commit_hook(repo
 # set_prop can be used for properties with NULL characters which are not
 # handled correctly when passed to subprocess.Popen() and values like "*"
 # which are not handled correctly on Windows.
-def set_prop(name, value, path, expected_err=None):
+def set_prop(name, value, path, expected_re_string=None):
   """Set a property with specified value"""
   if value and (value[0] == '-' or '\x00' in value or sys.platform == 'win32'):
     from tempfile import mkstemp
@@ -1828,10 +1833,17 @@ def set_prop(name, value, path, expected
     value_file.write(value)
     value_file.flush()
     value_file.close()
-    main.run_svn(expected_err, 'propset', '-F', value_file_path, name, path)
+    exit_code, out, err = main.run_svn(expected_re_string, 'propset',
+                                       '-F', value_file_path, name, path)
     os.remove(value_file_path)
   else:
-    main.run_svn(expected_err, 'propset', name, value, path)
+    exit_code, out, err = main.run_svn(expected_re_string, 'propset',
+                                       name, value, path)
+  if expected_re_string:
+    if not expected_re_string.startswith(".*"):
+      expected_re_string = ".*(" + expected_re_string + ")"
+    expected_err = verify.RegexOutput(expected_re_string, match_all=False)
+    verify.verify_outputs(None, None, err, None, expected_err)
 
 def check_prop(name, path, exp_out, revprop=None):
   """Verify that property NAME on PATH has a value of EXP_OUT.

Modified: subversion/branches/fs-py/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/svntest/main.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/svntest/main.py Mon Dec 19 18:49:34 2011
@@ -165,6 +165,7 @@ entriesdump_binary = os.path.abspath('en
 atomic_ra_revprop_change_binary = os.path.abspath('atomic-ra-revprop-change' + \
                                                   _exe)
 wc_lock_tester_binary = os.path.abspath('../libsvn_wc/wc-lock-tester' + _exe)
+wc_incomplete_tester_binary = os.path.abspath('../libsvn_wc/wc-incomplete-tester' + _exe)
 svnmucc_binary=os.path.abspath('../../../tools/client-side/svnmucc/svnmucc' + \
                                _exe)
 
@@ -683,6 +684,10 @@ def run_wc_lock_tester(recursive, path):
     option = "-1"
   return run_command(wc_lock_tester_binary, False, False, option, path)
 
+def run_wc_incomplete_tester(wc_dir, revision):
+  "Run the wc-incomplete tool, returning its exit code, stdout and stderr"
+  return run_command(wc_incomplete_tester_binary, False, False,
+                     wc_dir, revision)
 
 def youngest(repos_path):
   "run 'svnlook youngest' on REPOS_PATH, returns revision as int"
@@ -993,51 +998,60 @@ def use_editor(func):
   os.environ['SVNTEST_EDITOR_FUNC'] = func
   os.environ['SVN_TEST_PYTHON'] = sys.executable
 
-def mergeinfo_notify_line(revstart, revend):
+def mergeinfo_notify_line(revstart, revend, target=None):
   """Return an expected output line that describes the beginning of a
   mergeinfo recording notification on revisions REVSTART through REVEND."""
+  if target:
+    target_re = re.escape(target)
+  else:
+    target_re = ".+"
   if (revend is None):
     if (revstart < 0):
       revstart = abs(revstart)
-      return "--- Recording mergeinfo for reverse merge of r%ld .*:\n" \
-             % (revstart)
+      return "--- Recording mergeinfo for reverse merge of r%ld into '%s':\n" \
+             % (revstart, target_re)
     else:
-      return "--- Recording mergeinfo for merge of r%ld .*:\n" % (revstart)
+      return "--- Recording mergeinfo for merge of r%ld into '%s':\n" \
+             % (revstart, target_re)
   elif (revstart < revend):
-    return "--- Recording mergeinfo for merge of r%ld through r%ld .*:\n" \
-           % (revstart, revend)
+    return "--- Recording mergeinfo for merge of r%ld through r%ld into '%s':\n" \
+           % (revstart, revend, target_re)
   else:
     return "--- Recording mergeinfo for reverse merge of r%ld through " \
-           "r%ld .*:\n" % (revstart, revend)
+           "r%ld into '%s':\n" % (revstart, revend, target_re)
 
 def merge_notify_line(revstart=None, revend=None, same_URL=True,
-                      foreign=False):
+                      foreign=False, target=None):
   """Return an expected output line that describes the beginning of a
   merge operation on revisions REVSTART through REVEND.  Omit both
   REVSTART and REVEND for the case where the left and right sides of
   the merge are from different URLs."""
   from_foreign_phrase = foreign and "\(from foreign repository\) " or ""
+  if target:
+    target_re = re.escape(target)
+  else:
+    target_re = ".+"
   if not same_URL:
-    return "--- Merging differences between %srepository URLs into '.+':\n" \
-           % (foreign and "foreign " or "")
+    return "--- Merging differences between %srepository URLs into '%s':\n" \
+           % (foreign and "foreign " or "", target_re)
   if revend is None:
     if revstart is None:
       # The left and right sides of the merge are from different URLs.
-      return "--- Merging differences between %srepository URLs into '.+':\n" \
-             % (foreign and "foreign " or "")
+      return "--- Merging differences between %srepository URLs into '%s':\n" \
+             % (foreign and "foreign " or "", target_re)
     elif revstart < 0:
-      return "--- Reverse-merging %sr%ld into '.+':\n" \
-             % (from_foreign_phrase, abs(revstart))
+      return "--- Reverse-merging %sr%ld into '%s':\n" \
+             % (from_foreign_phrase, abs(revstart), target_re)
     else:
-      return "--- Merging %sr%ld into '.+':\n" \
-             % (from_foreign_phrase, revstart)
+      return "--- Merging %sr%ld into '%s':\n" \
+             % (from_foreign_phrase, revstart, target_re)
   else:
     if revstart > revend:
-      return "--- Reverse-merging %sr%ld through r%ld into '.+':\n" \
-             % (from_foreign_phrase, revstart, revend)
+      return "--- Reverse-merging %sr%ld through r%ld into '%s':\n" \
+             % (from_foreign_phrase, revstart, revend, target_re)
     else:
-      return "--- Merging %sr%ld through r%ld into '.+':\n" \
-             % (from_foreign_phrase, revstart, revend)
+      return "--- Merging %sr%ld through r%ld into '%s':\n" \
+             % (from_foreign_phrase, revstart, revend, target_re)
 
 
 def make_log_msg():

Modified: subversion/branches/fs-py/subversion/tests/cmdline/tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/tree_conflict_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/tree_conflict_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/tree_conflict_tests.py Mon Dec 19 18:49:34 2011
@@ -278,6 +278,9 @@ f_moves = [
 
 d_dels = [
   ( create_d, ['dD'] ),
+]
+
+d_moves = [
   ( create_d, ['dM'] ),
 ]
 
@@ -604,12 +607,12 @@ def up_sw_dir_mod_onto_del(sbox):
 def up_sw_dir_del_onto_mod(sbox):
   "up/sw dir: del/rpl/mv onto modify"
   # WC state: any (D necessarily exists; children may have any state)
-  test_tc_up_sw(sbox, d_dels + d_rpls, d_mods)
+  test_tc_up_sw(sbox, d_dels + d_moves + d_rpls, d_mods)
 
 def up_sw_dir_del_onto_del(sbox):
   "up/sw dir: del/rpl/mv onto del/rpl/mv"
   # WC state: any (D necessarily exists; children may have any state)
-  test_tc_up_sw(sbox, d_dels + d_rpls, d_dels + d_rpls)
+  test_tc_up_sw(sbox, d_dels + d_moves + d_rpls, d_dels + d_rpls)
 
 # This is currently set as XFail over ra_dav because it hits
 # issue #3314 'DAV can overwrite directories during copy'
@@ -690,8 +693,8 @@ def merge_file_add_onto_not_none(sbox):
 def merge_dir_mod_onto_not_dir(sbox):
   "merge dir: modify onto not-dir"
   sbox2 = sbox.clone_dependent()
-  test_tc_merge(sbox, d_mods, br_scen = d_dels + d_rpl_f)
-  test_tc_merge(sbox2, d_mods, wc_scen = d_dels)
+  test_tc_merge(sbox, d_mods, br_scen = d_dels + d_moves + d_rpl_f)
+  test_tc_merge(sbox2, d_mods, wc_scen = d_dels + d_moves)
 
 # Test for issue #3150 'tree conflicts with directories as victims'.
 @XFail()
@@ -699,14 +702,14 @@ def merge_dir_mod_onto_not_dir(sbox):
 def merge_dir_del_onto_not_same(sbox):
   "merge dir: del/rpl/mv onto not-same"
   sbox2 = sbox.clone_dependent()
-  test_tc_merge(sbox, d_dels + d_rpls, br_scen = d_mods)
-  test_tc_merge(sbox2, d_dels + d_rpls, wc_scen = d_mods)
+  test_tc_merge(sbox, d_dels + d_moves + d_rpls, br_scen = d_mods)
+  test_tc_merge(sbox2, d_dels + d_moves + d_rpls, wc_scen = d_mods)
 
 def merge_dir_del_onto_not_dir(sbox):
   "merge dir: del/rpl/mv onto not-dir"
   sbox2 = sbox.clone_dependent()
-  test_tc_merge(sbox, d_dels + d_rpls, br_scen = d_dels + d_rpl_f)
-  test_tc_merge(sbox2, d_dels + d_rpls, wc_scen = d_dels)
+  test_tc_merge(sbox, d_dels + d_moves + d_rpls, br_scen = d_dels + d_moves + d_rpl_f)
+  test_tc_merge(sbox2, d_dels + d_moves + d_rpls, wc_scen = d_dels + d_moves)
 
 def merge_dir_add_onto_not_none(sbox):
   "merge dir: add onto not-none"

Modified: subversion/branches/fs-py/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/update_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/update_tests.py Mon Dec 19 18:49:34 2011
@@ -5404,6 +5404,212 @@ def update_to_HEAD_plus_1(sbox):
                                         None, None,
                                         None, None, None, wc_dir, '-r', '2')
 
+def update_moved_dir_leaf_del(sbox):
+  "update locally moved dir with leaf del"
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  svntest.main.run_svn(False, 'rm', '-m', 'remove /A/B/E/alpha',
+                       sbox.repo_url + "/A/B/E/alpha")
+  sbox.simple_move("A/B/E", "A/B/E2")
+
+  # since alpha isn't locally modified, the incoming delete should auto-merge
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/E2/alpha' : Item(status='D '),
+  })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E')
+  expected_disk.add({
+    'A/B/E2'           : Item(),
+    'A/B/E2/beta'      : Item(contents="This is the file 'beta'.\n"),
+  })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.add({
+    'A/B/E2'            : Item(status='A ', copied='+', wc_rev='-'),
+    'A/B/E2/beta'       : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E2/alpha'      : Item(status='D ', copied='+', wc_rev='-'),
+  })
+  expected_status.remove('A/B/E/alpha')
+  expected_status.tweak('A/B/E', 'A/B/E/beta', status='D ')
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, 1)
+
+def update_moved_dir_edited_leaf_del(sbox):
+  "update locally moved dir with edited leaf del"
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  svntest.main.run_svn(False, 'rm', '-m', 'remove /A/B/E/alpha',
+                       sbox.repo_url + "/A/B/E/alpha")
+  sbox.simple_move("A/B/E", "A/B/E2")
+  svntest.main.file_write(sbox.ospath('A/B/E2/alpha'),
+                          "This is a changed 'alpha'.\n")
+
+  # since alpha was modified post-move, the incoming delete should conflict
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/E/alpha'       : Item(status='  ', treeconflict='C'),
+  })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E')
+  expected_disk.add({
+    'A/B/E2'           : Item(),
+    'A/B/E2/alpha'     : Item(contents="This is a changed 'alpha'.\n"),
+    'A/B/E2/beta'      : Item(contents="This is the file 'beta'.\n"),
+  })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.tweak('A/B/E', 'A/B/E/beta', status='D ')
+  expected_status.remove('A/B/E/alpha')
+  expected_status.add({
+    'A/B/E/alpha'       : Item(status='! ', treeconflict='C'),
+    'A/B/E2'            : Item(status='A ', copied='+', wc_rev='-'),
+    'A/B/E2/beta'       : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E2/alpha'      : Item(status='M ', copied='+', wc_rev='-'),
+  })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, 1)
+
+def update_moved_dir_file_add(sbox):
+  "update locally moved dir with incoming file"
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  foo_path = "A/B/E/foo"
+  foo_content = "This is the file 'foo'.\n"
+
+  svntest.main.file_write(sbox.ospath(foo_path), foo_content, 'wb')
+  sbox.simple_add(foo_path)
+  sbox.simple_commit()
+  # update to go back in time, before the last commit
+  svntest.main.run_svn(False, 'update', '-r', '1', wc_dir)
+  sbox.simple_move("A/B/E", "A/B/E2")
+
+  # the incoming file should auto-merge
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/E2/foo' : Item(status='A '),
+  })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E')
+  expected_disk.add({
+    'A/B/E2'           : Item(),
+    'A/B/E2/alpha'     : Item(contents="This is the file 'alpha'.\n"),
+    'A/B/E2/beta'      : Item(contents="This is the file 'beta'.\n"),
+    'A/B/E2/foo'       : Item(contents=foo_content),
+  })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', status='D ')
+  expected_status.add({
+    'A/B/E/foo'         : Item(status='D ', wc_rev='2'),
+    'A/B/E2'            : Item(status='A ', copied='+', wc_rev='-'),
+    'A/B/E2/beta'       : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E2/alpha'      : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E2/foo'        : Item(status='A ', copied='+', wc_rev='-'),
+  })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, 1)
+
+def update_moved_dir_dir_add(sbox):
+  "update locally moved dir with incoming dir"
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  foo_path = "A/B/E/foo"
+  bar_path = "A/B/E/foo/bar"
+  bar_content = "This is the file 'bar'.\n"
+
+  sbox.simple_mkdir(foo_path)
+  svntest.main.file_write(sbox.ospath(bar_path), bar_content, 'wb')
+  sbox.simple_add(bar_path)
+  sbox.simple_commit()
+  # update to go back in time, before the last commit
+  svntest.main.run_svn(False, 'update', '-r', '1', wc_dir)
+  sbox.simple_move("A/B/E", "A/B/E2")
+
+  # the incoming file should auto-merge
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/E2/foo'      : Item(status='A '),
+    'A/B/E2/foo/bar'  : Item(status='A '),
+  })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E')
+  expected_disk.add({
+    'A/B/E2'           : Item(),
+    'A/B/E2/alpha'     : Item(contents="This is the file 'alpha'.\n"),
+    'A/B/E2/beta'      : Item(contents="This is the file 'beta'.\n"),
+    'A/B/E2/foo'       : Item(),
+    'A/B/E2/foo/bar'   : Item(contents=bar_content),
+  })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', status='D ')
+  expected_status.add({
+    'A/B/E/foo'         : Item(status='D ', wc_rev='2'),
+    'A/B/E/foo/bar'     : Item(status='D ', wc_rev='2'),
+    'A/B/E2'            : Item(status='A ', copied='+', wc_rev='-'),
+    'A/B/E2/beta'       : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E2/alpha'      : Item(status='  ', copied='+', wc_rev='-'),
+    'A/B/E2/foo'        : Item(status='A ', copied='+', wc_rev='-'),
+    'A/B/E2/foo/bar'    : Item(status='A ', copied='+', wc_rev='-'),
+  })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, 1)
+
+@XFail()
+@Issue(4037)
+def update_moved_dir_file_move(sbox):
+  "update locally moved dir with incoming file move"
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  sbox.simple_move("A/B/E/alpha", "A/B/F/alpha")
+  sbox.simple_commit()
+  # update to go back in time, before the previous commit
+  svntest.main.run_svn(False, 'update', '-r', '1', wc_dir)
+  sbox.simple_move("A/B/E", "A/B/E2")
+
+  # The incoming move should auto-merge such that A/B/F/alpha appears
+  # as moved to A/B/E2/alpha -- this strategy prefers the local user's
+  # change as the solution to the conflict.
+  # ### Ideally, the user should be offered a set of alternative solutions.
+  # ### E.g. the user might prefer if A/B/E2/alpha disappeared and A/B/E/alpha
+  # ### appeared as moved to A/B/F/alpha. But the --accept option does not yet
+  # ### support tree conflicts.
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B/E2/alpha' : Item(status='A '),
+  })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/B/E/alpha', 'A/B/E/beta', 'A/B/E')
+  expected_disk.add({
+    'A/B/E2'           : Item(),
+    'A/B/E2/alpha'     : Item(contents="This is the file 'alpha'.\n"),
+    'A/B/E2/beta'      : Item(contents="This is the file 'beta'.\n"),
+  })
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.tweak('A/B/E', 'A/B/E/alpha', 'A/B/E/beta', status='D ')
+  expected_status.add({
+    'A/B/F/alpha'       : Item(status='D '),
+    'A/B/E2'            : Item(status='A ', copied='+', wc_rev='-'),
+    'A/B/E2/alpha'      : Item(status='A ', copied='+', wc_rev='-'),
+    'A/B/E2/beta'       : Item(status='  ', copied='+', wc_rev='-'),
+  })
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, 1)
 
 #######################################################################
 # Run the tests
@@ -5471,6 +5677,11 @@ test_list = [ None,
               revive_children_of_copy,
               skip_access_denied,
               update_to_HEAD_plus_1,
+              update_moved_dir_leaf_del,
+              update_moved_dir_edited_leaf_del,
+              update_moved_dir_file_add,
+              update_moved_dir_dir_add,
+              update_moved_dir_file_move,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/fs-py/subversion/tests/cmdline/upgrade_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/cmdline/upgrade_tests.py?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/branches/fs-py/subversion/tests/cmdline/upgrade_tests.py Mon Dec 19 18:49:34 2011
@@ -75,6 +75,23 @@ def replace_sbox_with_tarfile(sbox, tar_
 
   shutil.move(os.path.join(extract_dir, dir), sbox.wc_dir)
 
+def replace_sbox_repo_with_tarfile(sbox, tar_filename, dir=None):
+  try:
+    svntest.main.safe_rmtree(sbox.repo_dir)
+  except OSError, e:
+    pass
+
+  if not dir:
+    dir = tar_filename.split('.')[0]
+    
+  tarpath = os.path.join(os.path.dirname(sys.argv[0]), 'upgrade_tests_data',
+                         tar_filename)
+  t = tarfile.open(tarpath, 'r:bz2')
+  extract_dir = tempfile.mkdtemp(dir=svntest.main.temp_dir)
+  for member in t.getmembers():
+    t.extract(member, extract_dir)
+
+  shutil.move(os.path.join(extract_dir, dir), sbox.repo_dir)
 
 def check_format(sbox, expected_format):
   dot_svn = svntest.main.get_admin_name()
@@ -1181,6 +1198,61 @@ def upgrade_file_externals(sbox):
       'alpha' : {'pname3' : 'pvalue3' },
       })
 
+
+@Issue(4035)
+def upgrade_missing_replaced(sbox):
+  "upgrade with missing replaced dir"
+
+  sbox.build(create_wc=False)
+  replace_sbox_with_tarfile(sbox, 'upgrade_missing_replaced.tar.bz2')
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'upgrade', sbox.wc_dir)
+  svntest.main.run_svnadmin('setuuid', sbox.repo_dir,
+                            'd7130b12-92f6-45c9-9217-b9f0472c3fab')
+  svntest.actions.run_and_verify_svn(None, None, [], 'relocate',
+                                     'file:///tmp/repo', sbox.repo_url,
+                                     sbox.wc_dir)
+
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+      'A/B/E'         : Item(status='  ', treeconflict='C'),
+      'A/B/E/alpha'   : Item(status='  ', treeconflict='A'),
+      'A/B/E/beta'    : Item(status='  ', treeconflict='A'),
+      })
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+  expected_status.tweak('A/B/E', status='! ', treeconflict='C', wc_rev='-')
+  expected_status.tweak('A/B/E/alpha', 'A/B/E/beta', status='D ')
+  svntest.actions.run_and_verify_update(sbox.wc_dir, expected_output,
+                                        None, expected_status)
+
+  svntest.actions.run_and_verify_svn(None, 'Reverted.*', [], 'revert', '-R',
+                                     sbox.wc_dir)
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+  svntest.actions.run_and_verify_status(sbox.wc_dir, expected_status)
+
+@Issue(4033)
+def upgrade_not_present_replaced(sbox):
+  "upgrade with not-present replaced nodes"
+
+  sbox.build(create_wc=False)
+  replace_sbox_with_tarfile(sbox, 'upgrade_not_present_replaced.tar.bz2')
+
+  svntest.actions.run_and_verify_svn(None, None, [], 'upgrade', sbox.wc_dir)
+  svntest.main.run_svnadmin('setuuid', sbox.repo_dir,
+                            'd7130b12-92f6-45c9-9217-b9f0472c3fab')
+  svntest.actions.run_and_verify_svn(None, None, [], 'relocate',
+                                     'file:///tmp/repo', sbox.repo_url,
+                                     sbox.wc_dir)
+
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+      'A/B/E'         : Item(status='E '),
+      'A/B/E/alpha'   : Item(status='A '),
+      'A/B/E/beta'    : Item(status='A '),
+      'A/B/lambda'    : Item(status='E '),
+      })
+  expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+  svntest.actions.run_and_verify_update(sbox.wc_dir, expected_output,
+                                        None, expected_status)
+
 ########################################################################
 # Run the tests
 
@@ -1230,6 +1302,8 @@ test_list = [ None,
               upgrade_with_missing_subdir,
               upgrade_locked,
               upgrade_file_externals,
+              upgrade_missing_replaced,
+              upgrade_not_present_replaced,
              ]
 
 

Modified: subversion/branches/fs-py/subversion/tests/libsvn_client/client-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/libsvn_client/client-test.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/libsvn_client/client-test.c (original)
+++ subversion/branches/fs-py/subversion/tests/libsvn_client/client-test.c Mon Dec 19 18:49:34 2011
@@ -28,6 +28,7 @@
 #include <limits.h>
 #include "svn_mergeinfo.h"
 #include "../../libsvn_client/mergeinfo.h"
+#include "../../libsvn_client/client.h"
 #include "svn_pools.h"
 #include "svn_client.h"
 #include "svn_repos.h"
@@ -102,26 +103,28 @@ test_elide_mergeinfo_catalog(apr_pool_t 
        i < sizeof(elide_testcases) / sizeof(elide_testcases[0]);
        i++)
     {
-      apr_hash_t *catalog;
+      svn_mergeinfo_catalog_t mergeinfo_catalog;
       mergeinfo_catalog_item *item;
 
       svn_pool_clear(iterpool);
 
-      catalog = apr_hash_make(iterpool);
+      mergeinfo_catalog = apr_hash_make(iterpool);
       for (item = elide_testcases[i]; item->path; item++)
         {
-          apr_hash_t *mergeinfo;
+          svn_mergeinfo_t mergeinfo;
 
           SVN_ERR(svn_mergeinfo_parse(&mergeinfo, item->unparsed_mergeinfo,
                                       iterpool));
-          apr_hash_set(catalog, item->path, APR_HASH_KEY_STRING, mergeinfo);
+          apr_hash_set(mergeinfo_catalog, item->path, APR_HASH_KEY_STRING,
+                       mergeinfo);
         }
 
-      SVN_ERR(svn_client__elide_mergeinfo_catalog(catalog, iterpool));
+      SVN_ERR(svn_client__elide_mergeinfo_catalog(mergeinfo_catalog,
+                                                  iterpool));
 
       for (item = elide_testcases[i]; item->path; item++)
         {
-          apr_hash_t *mergeinfo = apr_hash_get(catalog, item->path,
+          apr_hash_t *mergeinfo = apr_hash_get(mergeinfo_catalog, item->path,
                                                APR_HASH_KEY_STRING);
           if (item->remains && !mergeinfo)
             return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
@@ -648,6 +651,71 @@ test_16k_add(const svn_test_opts_t *opts
 }
 #endif
 
+static svn_error_t *
+test_youngest_common_ancestor(const svn_test_opts_t *opts,
+                              apr_pool_t *pool)
+{
+  const char *repos_url;
+  svn_client_ctx_t *ctx;
+  svn_opt_revision_t head_rev = { svn_opt_revision_head, { 0 } };
+  svn_opt_revision_t zero_rev = { svn_opt_revision_number, { 0 } };
+  svn_client_copy_source_t source;
+  apr_array_header_t *sources;
+  const char *dest;
+  const char *yc_ancestor_relpath;
+  svn_revnum_t yc_ancestor_rev;
+
+  /* Create a filesytem and repository containing the Greek tree. */
+  SVN_ERR(create_greek_repos(&repos_url, "test-youngest-common-ancestor", opts, pool));
+
+  svn_client_create_context(&ctx, pool);
+
+  /* Copy a file into dir 'A', keeping its own basename. */
+  sources = apr_array_make(pool, 1, sizeof(svn_client_copy_source_t *));
+  source.path = svn_path_url_add_component2(repos_url, "iota", pool);
+  source.peg_revision = &head_rev;
+  source.revision = &head_rev;
+  APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = &source;
+  dest = svn_path_url_add_component2(repos_url, "A", pool);
+  SVN_ERR(svn_client_copy6(sources, dest, TRUE /* copy_as_child */,
+                           FALSE /* make_parents */,
+                           FALSE /* ignore_externals */,
+                           NULL, NULL, NULL, ctx, pool));
+
+  /* Test: YCA(iota@2, A/iota@2) is iota@1. */
+  SVN_ERR(svn_client__get_youngest_common_ancestor(
+            &yc_ancestor_relpath, NULL, &yc_ancestor_rev,
+            svn_path_url_add_component2(repos_url, "iota", pool), 2,
+            svn_path_url_add_component2(repos_url, "A/iota", pool), 2,
+            ctx, pool));
+  SVN_TEST_STRING_ASSERT(yc_ancestor_relpath, "iota");
+  SVN_TEST_ASSERT(yc_ancestor_rev == 1);
+
+  /* Copy the root directory (at revision 0) into A as 'ROOT'. */
+  sources = apr_array_make(pool, 1, sizeof(svn_client_copy_source_t *));
+  source.path = repos_url;
+  source.peg_revision = &zero_rev;
+  source.revision = &zero_rev;
+  APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = &source;
+  dest = svn_path_url_add_component2(repos_url, "A/ROOT", pool);
+  SVN_ERR(svn_client_copy6(sources, dest, FALSE /* copy_as_child */,
+                           FALSE /* make_parents */,
+                           FALSE /* ignore_externals */,
+                           NULL, NULL, NULL, ctx, pool));
+
+  /* Test: YCA(''@0, A/ROOT@3) is ''@0 (handled as a special case). */
+  SVN_ERR(svn_client__get_youngest_common_ancestor(
+            &yc_ancestor_relpath, NULL, &yc_ancestor_rev,
+            svn_path_url_add_component2(repos_url, "", pool), 0,
+            svn_path_url_add_component2(repos_url, "A/ROOT", pool), 3,
+            ctx, pool));
+  SVN_TEST_STRING_ASSERT(yc_ancestor_relpath, "");
+  SVN_TEST_ASSERT(yc_ancestor_rev == 0);
+
+  return SVN_NO_ERROR;
+}
+
+
 /* ========================================================================== */
 
 struct svn_test_descriptor_t test_funcs[] =
@@ -663,5 +731,6 @@ struct svn_test_descriptor_t test_funcs[
 #ifdef TEST16K_ADD
     SVN_TEST_OPTS_PASS(test_16k_add, "test adding 16k files"),
 #endif
+    SVN_TEST_OPTS_PASS(test_youngest_common_ancestor, "test youngest_common_ancestor"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/fs-py/subversion/tests/libsvn_diff/diff-diff3-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/libsvn_diff/diff-diff3-test.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/libsvn_diff/diff-diff3-test.c (original)
+++ subversion/branches/fs-py/subversion/tests/libsvn_diff/diff-diff3-test.c Mon Dec 19 18:49:34 2011
@@ -175,7 +175,7 @@ three_way_merge(const char *filename1,
   SVN_ERR(svn_diff_mem_string_diff3(&diff,
                                     original, modified, latest, options, pool));
 
-  actual = svn_stringbuf_create("", pool);
+  actual = svn_stringbuf_create_empty(pool);
   ostream = svn_stream_from_stringbuf(actual, pool);
 
   SVN_ERR(svn_diff_mem_string_output_merge2
@@ -265,7 +265,7 @@ two_way_diff(const char *filename1,
 
   SVN_ERR(svn_diff_mem_string_diff(&diff, original, modified, options, pool));
 
-  actual = svn_stringbuf_create("", pool);
+  actual = svn_stringbuf_create_empty(pool);
   ostream = svn_stream_from_stringbuf(actual, pool);
 
   SVN_ERR(svn_diff_mem_string_output_unified(ostream, diff,

Modified: subversion/branches/fs-py/subversion/tests/libsvn_diff/parse-diff-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/libsvn_diff/parse-diff-test.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/libsvn_diff/parse-diff-test.c (original)
+++ subversion/branches/fs-py/subversion/tests/libsvn_diff/parse-diff-test.c Mon Dec 19 18:49:34 2011
@@ -314,7 +314,8 @@ check_content(svn_diff_hunk_t *hunk, svn
     SVN_TEST_STRING_ASSERT(exp_buf->data, hunk_buf->data);
   }
 
-  SVN_TEST_ASSERT(hunk_buf->len == 0);
+  if (!hunk_eof)
+    SVN_TEST_ASSERT(hunk_buf->len == 0);
 
   return SVN_NO_ERROR;
 }
@@ -946,11 +947,9 @@ test_parse_unidiff_lacking_trailing_eol(
                             "This is the file 'gamma'." NL,
                             pool));
 
-      /* Verify that the contents are as expected, with a NL appended.
-         TODO: test for notification about the NL silently appended */
       SVN_ERR(check_content(hunk, reverse,
                             "This is the file 'gamma'." NL
-                            "some more bytes to 'gamma'" NL,
+                            "some more bytes to 'gamma'",
                             pool));
 
       reverse = !reverse;
@@ -981,7 +980,7 @@ struct svn_test_descriptor_t test_funcs[
                    "test property diffs with odd symbols"),
     SVN_TEST_PASS2(test_git_diffs_with_spaces_diff,
                    "test git diffs with spaces in paths"),
-    SVN_TEST_XFAIL2(test_parse_unidiff_lacking_trailing_eol,
+    SVN_TEST_PASS2(test_parse_unidiff_lacking_trailing_eol,
                    "test parsing unidiffs lacking trailing eol"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/fs-py/subversion/tests/libsvn_fs/locks-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/libsvn_fs/locks-test.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/libsvn_fs/locks-test.c (original)
+++ subversion/branches/fs-py/subversion/tests/libsvn_fs/locks-test.c Mon Dec 19 18:49:34 2011
@@ -358,6 +358,18 @@ get_locks(const svn_test_opts_t *opts,
                                        num_expected_paths, pool));
   }
 
+  /* A path that is longer and alphabetically earlier than some locked
+     paths, this exercises the r1205848 BDB lock code. */
+  {
+    static const char *expected_paths[] = { 0 };
+    num_expected_paths = 0;
+    get_locks_baton = make_get_locks_baton(pool);
+    SVN_ERR(svn_fs_get_locks(fs, "A/D/H/ABCDEFGHIJKLMNOPQR", get_locks_callback,
+                             get_locks_baton, pool));
+    SVN_ERR(verify_matching_lock_paths(get_locks_baton, expected_paths,
+                                       num_expected_paths, pool));
+  }
+
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/fs-py/subversion/tests/libsvn_fs_base/strings-reps-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/libsvn_fs_base/strings-reps-test.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/libsvn_fs_base/strings-reps-test.c (original)
+++ subversion/branches/fs-py/subversion/tests/libsvn_fs_base/strings-reps-test.c Mon Dec 19 18:49:34 2011
@@ -360,7 +360,7 @@ verify_expected_record(svn_fs_t *fs,
                              size, expected_len);
 
   /* Read the string back in 100-byte chunks. */
-  text = svn_stringbuf_create("", trail->pool);
+  text = svn_stringbuf_create_empty(trail->pool);
   while (1)
     {
       size = sizeof(buf);

Modified: subversion/branches/fs-py/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/libsvn_repos/repos-test.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/branches/fs-py/subversion/tests/libsvn_repos/repos-test.c Mon Dec 19 18:49:34 2011
@@ -1348,6 +1348,149 @@ commit_authz_cb(svn_repos_authz_access_t
 
 
 
+enum action_t {
+  A_DELETE,
+  A_ADD_FILE,
+  A_ADD_DIR,
+  A_CHANGE_FILE_PROP
+};
+struct authz_path_action_t
+{
+  enum action_t action;
+  const char *path;
+  svn_boolean_t authz_error_expected;
+  const char *copyfrom_path;
+};
+
+/* Return the appropriate dir baton for the parent of PATH in *DIR_BATON,
+   allocated in POOL. */
+static svn_error_t *
+get_dir_baton(void **dir_baton,
+              const char *path,
+              const svn_delta_editor_t *editor,
+              void *root_baton,
+              apr_pool_t *pool)
+{
+  int i;
+  apr_array_header_t *path_bits = svn_path_decompose(path, pool);
+  const char *path_so_far = "";
+
+  *dir_baton = root_baton;
+  for (i = 0; i < (path_bits->nelts - 1); i++)
+    {
+      const char *path_bit = APR_ARRAY_IDX(path_bits, i, const char *);
+      path_so_far = svn_path_join(path_so_far, path_bit, pool);
+      SVN_ERR(editor->open_directory(path_so_far, *dir_baton,
+                                     SVN_INVALID_REVNUM, pool, dir_baton));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Return the appropriate file baton for PATH in *FILE_BATON, allocated in
+   POOL. */
+static svn_error_t *
+get_file_baton(void **file_baton,
+               const char *path,
+               const svn_delta_editor_t *editor,
+               void *root_baton,
+               apr_pool_t *pool)
+{
+  void *dir_baton;
+
+  SVN_ERR(get_dir_baton(&dir_baton, path, editor, root_baton, pool));
+
+  SVN_ERR(editor->open_file(path, dir_baton, SVN_INVALID_REVNUM, pool,
+                            file_baton));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_path_authz(svn_repos_t *repos,
+                struct authz_path_action_t *path_action,
+                svn_authz_t *authz_file,
+                svn_revnum_t youngest_rev,
+                apr_pool_t *scratch_pool)
+{
+  void *edit_baton;
+  void *root_baton;
+  void *dir_baton;
+  void *file_baton;
+  void *out_baton;
+  const svn_delta_editor_t *editor;
+  svn_error_t *err;
+  svn_error_t *err2;
+
+  /* Create a new commit editor in which we're going to play with
+     authz */
+  SVN_ERR(svn_repos_get_commit_editor4(&editor, &edit_baton, repos,
+                                       NULL, "file://test", "/",
+                                       "plato", "test commit", NULL,
+                                       NULL, commit_authz_cb, authz_file,
+                                       scratch_pool));
+
+  /* Start fiddling.  First get the root, which is readonly. */
+  SVN_ERR(editor->open_root(edit_baton, 1, scratch_pool, &root_baton));
+
+  /* Fetch the appropriate baton for our action.  This may involve opening
+     intermediate batons, but we only care about the final one for the
+     cooresponding action. */
+  if (path_action->action == A_CHANGE_FILE_PROP)
+    SVN_ERR(get_file_baton(&file_baton, path_action->path, editor, root_baton,
+                           scratch_pool));
+  else
+    SVN_ERR(get_dir_baton(&dir_baton, path_action->path, editor, root_baton,
+                          scratch_pool));
+
+  /* Test the appropriate action. */
+  switch (path_action->action)
+    {
+      case A_DELETE:
+        err = editor->delete_entry(path_action->path, SVN_INVALID_REVNUM,
+                                   dir_baton, scratch_pool);
+        break;
+
+      case A_CHANGE_FILE_PROP:
+        err = editor->change_file_prop(file_baton, "svn:test",
+                                       svn_string_create("test", scratch_pool),
+                                       scratch_pool);
+        break;
+
+      case A_ADD_FILE:
+        err = editor->add_file(path_action->path, dir_baton,
+                               path_action->copyfrom_path, youngest_rev,
+                               scratch_pool, &out_baton);
+        break;
+
+      case A_ADD_DIR:
+        err = editor->add_directory(path_action->path, dir_baton,
+                                    path_action->copyfrom_path, youngest_rev,
+                                    scratch_pool, &out_baton);
+        break;
+    }
+
+  /* Don't worry about closing batons, just abort the edit.  Since errors
+     may be delayed, we need to capture results of the abort as well. */
+  err2 = editor->abort_edit(edit_baton, scratch_pool);
+  if (!err)
+    err = err2;
+  else
+    svn_error_clear(err2);
+
+  /* Check for potential errors. */
+  if (path_action->authz_error_expected)
+    {
+      SVN_TEST_ASSERT_ERROR(err, SVN_ERR_AUTHZ_UNWRITABLE);
+      svn_error_clear(err);
+    }
+  else
+    SVN_ERR(err);
+
+  return SVN_NO_ERROR;
+}
+
+
 /* Test that the commit editor is taking authz into account
    properly */
 static svn_error_t *
@@ -1359,13 +1502,26 @@ commit_editor_authz(const svn_test_opts_
   svn_fs_txn_t *txn;
   svn_fs_root_t *txn_root;
   svn_revnum_t youngest_rev;
-  void *edit_baton;
-  void *root_baton, *dir_baton, *dir2_baton, *file_baton;
-  svn_error_t *err;
-  const svn_delta_editor_t *editor;
   svn_authz_t *authz_file;
-  apr_pool_t *subpool = svn_pool_create(pool);
+  apr_pool_t *iterpool;
   const char *authz_contents;
+  int i;
+  struct authz_path_action_t path_actions[] = {
+      { A_DELETE,             "/iota",      TRUE },
+      { A_CHANGE_FILE_PROP,   "/iota",      TRUE },
+      { A_ADD_FILE,           "/alpha",     TRUE },
+      { A_ADD_FILE,           "/alpha",     TRUE,   "file://test/A/B/lambda" },
+      { A_ADD_DIR,            "/I",         TRUE },
+      { A_ADD_DIR,            "/J",         TRUE,   "file://test/A/D" },
+      { A_ADD_FILE,           "/A/alpha",   TRUE },
+      { A_ADD_FILE,           "/A/B/theta", FALSE },
+      { A_DELETE,             "/A/mu",      FALSE },
+      { A_ADD_DIR,            "/A/E",       FALSE },
+      { A_ADD_DIR,            "/A/J",       FALSE,  "file://test/A/D" },
+      { A_DELETE,             "A/D/G",      TRUE },
+      { A_DELETE,             "A/D/H",      FALSE },
+      { A_CHANGE_FILE_PROP,   "A/D/gamma",  FALSE }
+    };
 
   /* The Test Plan
    *
@@ -1375,25 +1531,24 @@ commit_editor_authz(const svn_test_opts_
    * authorized/denied when necessary.  We don't try to be exhaustive
    * in the kinds of authz lookups.  We just make sure that the editor
    * replies to the calls in a way that proves it is doing authz
-   * lookups.
+   * lookups.  Some actions are tested implicitly (such as open_file being
+   * required for change_file_props).
    *
-   * Note that this use of the commit editor is not kosher according
-   * to the generic editor API (we aren't allowed to continue editing
-   * after an error, nor are we allowed to assume that errors are
-   * returned by the operations which caused them).  But it should
-   * work fine with this particular editor implementation.
+   * Note that because of the error handling requirements of the generic
+   * editor API, each operation needs its own editor, which is handled by
+   * a helper function above.
    */
 
   /* Create a filesystem and repository. */
   SVN_ERR(svn_test__create_repos(&repos, "test-repo-commit-authz",
-                                 opts, subpool));
+                                 opts, pool));
   fs = svn_repos_fs(repos);
 
   /* Prepare a txn to receive the greek tree. */
-  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, subpool));
-  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
-  SVN_ERR(svn_test__create_greek_tree(txn_root, subpool));
-  SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, subpool));
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_test__create_greek_tree(txn_root, pool));
+  SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
   SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
 
   /* Load the authz rules for the greek tree. */
@@ -1419,147 +1574,18 @@ commit_editor_authz(const svn_test_opts_
     "[/A/D/G]"                                                               NL
     "plato = r"; /* No newline at end of file. */
 
-  SVN_ERR(authz_get_handle(&authz_file, authz_contents, subpool));
+  SVN_ERR(authz_get_handle(&authz_file, authz_contents, pool));
 
-  /* Create a new commit editor in which we're going to play with
-     authz */
-  SVN_ERR(svn_repos_get_commit_editor4(&editor, &edit_baton, repos,
-                                       NULL, "file://test", "/",
-                                       "plato", "test commit", NULL,
-                                       NULL, commit_authz_cb, authz_file,
-                                       subpool));
-
-  /* Start fiddling.  First get the root, which is readonly.  All
-     write operations fail because of the root's permissions. */
-  SVN_ERR(editor->open_root(edit_baton, 1, subpool, &root_baton));
-
-  /* Test denied file deletion. */
-  err = editor->delete_entry("/iota", SVN_INVALID_REVNUM, root_baton, subpool);
-  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
-    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
-                             "Got %s error instead of expected "
-                             "SVN_ERR_AUTHZ_UNWRITABLE",
-                             err ? "unexpected" : "no");
-  svn_error_clear(err);
-
-  /* Test authorized file open. */
-  SVN_ERR(editor->open_file("/iota", root_baton, SVN_INVALID_REVNUM,
-                            subpool, &file_baton));
-
-  /* Test unauthorized file prop set. */
-  err = editor->change_file_prop(file_baton, "svn:test",
-                                 svn_string_create("test", subpool),
-                                 subpool);
-  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
-    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
-                             "Got %s error instead of expected "
-                             "SVN_ERR_AUTHZ_UNWRITABLE",
-                             err ? "unexpected" : "no");
-  svn_error_clear(err);
-
-  /* Test denied file addition. */
-  err = editor->add_file("/alpha", root_baton, NULL, SVN_INVALID_REVNUM,
-                         subpool, &file_baton);
-  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
-    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
-                             "Got %s error instead of expected "
-                             "SVN_ERR_AUTHZ_UNWRITABLE",
-                             err ? "unexpected" : "no");
-  svn_error_clear(err);
-
-  /* Test denied file copy. */
-  err = editor->add_file("/alpha", root_baton, "file://test/A/B/lambda",
-                         youngest_rev, subpool, &file_baton);
-  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
-    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
-                             "Got %s error instead of expected "
-                             "SVN_ERR_AUTHZ_UNWRITABLE",
-                             err ? "unexpected" : "no");
-  svn_error_clear(err);
-
-  /* Test denied directory addition. */
-  err = editor->add_directory("/I", root_baton, NULL,
-                              SVN_INVALID_REVNUM, subpool, &dir_baton);
-  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
-    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
-                             "Got %s error instead of expected "
-                             "SVN_ERR_AUTHZ_UNWRITABLE",
-                             err ? "unexpected" : "no");
-  svn_error_clear(err);
-
-  /* Test denied directory copy. */
-  err = editor->add_directory("/J", root_baton, "file://test/A/D",
-                              youngest_rev, subpool, &dir_baton);
-  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
-    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
-                             "Got %s error instead of expected "
-                             "SVN_ERR_AUTHZ_UNWRITABLE",
-                             err ? "unexpected" : "no");
-  svn_error_clear(err);
-
-  /* Open directory /A, to which we have read/write access. */
-  SVN_ERR(editor->open_directory("/A", root_baton,
-                                 SVN_INVALID_REVNUM,
-                                 subpool, &dir_baton));
-
-  /* Test denied file addition.  Denied because of a conflicting rule
-     on the file path itself. */
-  err = editor->add_file("/A/alpha", dir_baton, NULL,
-                         SVN_INVALID_REVNUM, subpool, &file_baton);
-  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
-    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
-                             "Got %s error instead of expected "
-                             "SVN_ERR_AUTHZ_UNWRITABLE",
-                             err ? "unexpected" : "no");
-  svn_error_clear(err);
-
-  /* Test authorized file addition. */
-  SVN_ERR(editor->add_file("/A/B/theta", dir_baton, NULL,
-                           SVN_INVALID_REVNUM, subpool,
-                           &file_baton));
-
-  /* Test authorized file deletion. */
-  SVN_ERR(editor->delete_entry("/A/mu", SVN_INVALID_REVNUM, dir_baton,
-                               subpool));
-
-  /* Test authorized directory creation. */
-  SVN_ERR(editor->add_directory("/A/E", dir_baton, NULL,
-                                SVN_INVALID_REVNUM, subpool,
-                                &dir2_baton));
-
-  /* Test authorized copy of a tree. */
-  SVN_ERR(editor->add_directory("/A/J", dir_baton, "file://test/A/D",
-                                youngest_rev, subpool,
-                                &dir2_baton));
-
-  /* Open /A/D.  This should be granted. */
-  SVN_ERR(editor->open_directory("/A/D", dir_baton, SVN_INVALID_REVNUM,
-                                 subpool, &dir_baton));
-
-  /* Test denied recursive deletion. */
-  err = editor->delete_entry("/A/D/G", SVN_INVALID_REVNUM, dir_baton,
-                             subpool);
-  if (err == SVN_NO_ERROR || err->apr_err != SVN_ERR_AUTHZ_UNWRITABLE)
-    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
-                             "Got %s error instead of expected "
-                             "SVN_ERR_AUTHZ_UNWRITABLE",
-                             err ? "unexpected" : "no");
-  svn_error_clear(err);
-
-  /* Test authorized recursive deletion. */
-  SVN_ERR(editor->delete_entry("/A/D/H", SVN_INVALID_REVNUM,
-                               dir_baton, subpool));
-
-  /* Test authorized propset (open the file first). */
-  SVN_ERR(editor->open_file("/A/D/gamma", dir_baton, SVN_INVALID_REVNUM,
-                            subpool, &file_baton));
-  SVN_ERR(editor->change_file_prop(file_baton, "svn:test",
-                                   svn_string_create("test", subpool),
-                                   subpool));
+  iterpool = svn_pool_create(pool);
+  for (i = 0; i < (sizeof(path_actions) / sizeof(struct authz_path_action_t));
+        i++)
+    {
+      svn_pool_clear(iterpool);
+      SVN_ERR(test_path_authz(repos, &path_actions[i], authz_file,
+                              youngest_rev, iterpool));
+    }
 
-  /* Done. */
-  SVN_ERR(editor->abort_edit(edit_baton, subpool));
-  svn_pool_destroy(subpool);
+  svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }
@@ -2495,6 +2521,45 @@ test_get_file_revs(const svn_test_opts_t
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+issue_4060(const svn_test_opts_t *opts,
+           apr_pool_t *pool)
+{
+  apr_pool_t *subpool = svn_pool_create(pool);
+  svn_authz_t *authz_cfg;
+  svn_boolean_t allowed;
+  const char *authz_contents =
+    "[/A/B]"                                                               NL
+    "ozymandias = rw"                                                      NL
+    "[/]"                                                                  NL
+    "ozymandias = r"                                                       NL
+    ""                                                                     NL;
+
+  SVN_ERR(authz_get_handle(&authz_cfg, authz_contents, subpool));
+
+  SVN_ERR(svn_repos_authz_check_access(authz_cfg, "babylon",
+                                       "/A/B/C", "ozymandias",
+                                       svn_authz_write | svn_authz_recursive,
+                                       &allowed, subpool));
+  SVN_TEST_ASSERT(allowed);
+
+  SVN_ERR(svn_repos_authz_check_access(authz_cfg, "",
+                                       "/A/B/C", "ozymandias",
+                                       svn_authz_write | svn_authz_recursive,
+                                       &allowed, subpool));
+  SVN_TEST_ASSERT(allowed);
+
+  SVN_ERR(svn_repos_authz_check_access(authz_cfg, NULL,
+                                       "/A/B/C", "ozymandias",
+                                       svn_authz_write | svn_authz_recursive,
+                                       &allowed, subpool));
+  SVN_TEST_ASSERT(allowed);
+
+  svn_pool_destroy(subpool);
+
+  return SVN_NO_ERROR;
+}
+
 
 /* The test table.  */
 
@@ -2529,5 +2594,7 @@ struct svn_test_descriptor_t test_funcs[
                        "test svn_repos_get_logs ranges and limits"),
     SVN_TEST_OPTS_PASS(test_get_file_revs,
                        "test svn_repos_get_file_revsN"),
+    SVN_TEST_OPTS_PASS(issue_4060,
+                       "test issue 4060"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/fs-py/subversion/tests/libsvn_subr/cache-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/libsvn_subr/cache-test.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/libsvn_subr/cache-test.c (original)
+++ subversion/branches/fs-py/subversion/tests/libsvn_subr/cache-test.c Mon Dec 19 18:49:34 2011
@@ -135,7 +135,7 @@ test_inprocess_cache_basic(apr_pool_t *p
                                       APR_HASH_KEY_STRING,
                                       1,
                                       1,
-                                      APR_HAS_THREADS,
+                                      TRUE,
                                       "",
                                       pool));
 
@@ -182,16 +182,9 @@ test_membuffer_cache_basic(apr_pool_t *p
 {
   svn_cache__t *cache;
   svn_membuffer_t *membuffer;
-  svn_boolean_t thread_safe;
-
-#if APR_HAS_THREADS
-  thread_safe = TRUE;
-#else
-  thread_safe = FALSE;
-#endif
 
   SVN_ERR(svn_cache__membuffer_cache_create(&membuffer, 10*1024, 1,
-                                            thread_safe, pool));
+                                            TRUE, pool));
 
   /* Create a cache with just one entry. */
   SVN_ERR(svn_cache__create_membuffer_cache(&cache,
@@ -200,6 +193,7 @@ test_membuffer_cache_basic(apr_pool_t *p
                                             deserialize_revnum,
                                             APR_HASH_KEY_STRING,
                                             "cache:",
+                                            FALSE,
                                             pool));
 
   return basic_cache_test(cache, FALSE, pool);

Modified: subversion/branches/fs-py/subversion/tests/libsvn_subr/config-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/tests/libsvn_subr/config-test.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/tests/libsvn_subr/config-test.c (original)
+++ subversion/branches/fs-py/subversion/tests/libsvn_subr/config-test.c Mon Dec 19 18:49:34 2011
@@ -211,7 +211,7 @@ test_boolean_retrieval(apr_pool_t *pool)
 }
 
 static svn_error_t *
-test_has_section(apr_pool_t *pool)
+test_has_section_case_insensitive(apr_pool_t *pool)
 {
   svn_config_t *cfg;
   const char *cfg_file;
@@ -225,12 +225,50 @@ test_has_section(apr_pool_t *pool)
   if (! svn_config_has_section(cfg, "section1"))
     return fail(pool, "Failed to find section1");
 
+  if (! svn_config_has_section(cfg, "SECTION1"))
+    return fail(pool, "Failed to find SECTION1");
+
+  if (! svn_config_has_section(cfg, "UpperCaseSection"))
+    return fail(pool, "Failed to find UpperCaseSection");
+
+  if (! svn_config_has_section(cfg, "uppercasesection"))
+    return fail(pool, "Failed to find UpperCaseSection");
+
   if (svn_config_has_section(cfg, "notthere"))
     return fail(pool, "Returned true on missing section");
 
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_has_section_case_sensitive(apr_pool_t *pool)
+{
+  svn_config_t *cfg;
+  const char *cfg_file;
+
+  if (!srcdir)
+    SVN_ERR(init_params(pool));
+
+  cfg_file = apr_pstrcat(pool, srcdir, "/", "config-test.cfg", (char *)NULL);
+  SVN_ERR(svn_config_read2(&cfg, cfg_file, TRUE, TRUE, pool));
+
+  if (! svn_config_has_section(cfg, "section1"))
+    return fail(pool, "Failed to find section1");
+
+  if (svn_config_has_section(cfg, "SECTION1"))
+    return fail(pool, "Returned true on missing section");
+
+  if (! svn_config_has_section(cfg, "UpperCaseSection"))
+    return fail(pool, "Failed to find UpperCaseSection");
+
+  if (svn_config_has_section(cfg, "uppercasesection"))
+    return fail(pool, "Returned true on missing section");
+
+  if (svn_config_has_section(cfg, "notthere"))
+    return fail(pool, "Returned true on missing section");
+
+  return SVN_NO_ERROR;
+}
 /*
    ====================================================================
    If you add a new test to this file, update this array.
@@ -246,7 +284,9 @@ struct svn_test_descriptor_t test_funcs[
                    "test svn_config"),
     SVN_TEST_PASS2(test_boolean_retrieval,
                    "test svn_config boolean conversion"),
-    SVN_TEST_PASS2(test_has_section,
-                   "test svn_config_has_section"),
+    SVN_TEST_PASS2(test_has_section_case_insensitive,
+                   "test svn_config_has_section (case insensitive)"),
+    SVN_TEST_PASS2(test_has_section_case_sensitive,
+                   "test svn_config_has_section (case sensitive)"),
     SVN_TEST_NULL
   };