You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2013/01/27 01:01:59 UTC

svn commit: r1438999 [6/7] - in /subversion/branches/windows-build-update: ./ build/generator/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_diff/ subversion/libsvn_ra_serf/ subversion/libsvn_repos/ subvers...

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/patch_tests.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/patch_tests.py Sun Jan 27 00:01:57 2013
@@ -34,6 +34,7 @@ import tempfile
 import textwrap
 import zlib
 import posixpath
+import filecmp
 
 # Our testing module
 import svntest
@@ -4222,7 +4223,7 @@ def patch_change_symlink_target(sbox):
     "@@ -1 +1 @@",
     "-link foo",
     "\\ No newline at end of file",
-    "+link bar",
+    "+link bardame",
     "\\ No newline at end of file",
     "",
     ]))
@@ -4230,24 +4231,37 @@ def patch_change_symlink_target(sbox):
   # r2 - Try as plain text with how we encode the symlink
   svntest.main.file_write(sbox.ospath('link'), 'link foo')
   sbox.simple_add('link')
-  sbox.simple_commit()
 
-  expected_output = [
+  expected_output = svntest.wc.State(wc_dir, {
+    'link'       : Item(verb='Adding'),
+  })
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        None, None, wc_dir)
+
+  patch_output = [
     'U         %s\n' % sbox.ospath('link'),
   ]
 
-  svntest.actions.run_and_verify_svn(None, expected_output, [],
+  svntest.actions.run_and_verify_svn(None, patch_output, [],
                                      'patch', patch_file_path, wc_dir)
 
   # r3 - Store result
-  sbox.simple_commit()
+  expected_output = svntest.wc.State(wc_dir, {
+    'link'       : Item(verb='Sending'),
+  })
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        None, None, wc_dir)
 
   # r4 - Now as symlink
   sbox.simple_rm('link')
   sbox.simple_add_symlink('foo', 'link')
-  sbox.simple_commit()
+  expected_output = svntest.wc.State(wc_dir, {
+    'link'       : Item(verb='Replacing'),
+  })
+  svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+                                        None, None, wc_dir)
 
-  svntest.actions.run_and_verify_svn(None, expected_output, [],
+  svntest.actions.run_and_verify_svn(None, patch_output, [],
                                      'patch', patch_file_path, wc_dir)
 
   # TODO: when it passes, verify that the on-disk 'link' is correct ---
@@ -4395,6 +4409,174 @@ def single_line_mismatch(sbox):
   svntest.actions.run_and_verify_svn(None, expected_output, [],
                                      'patch', patch_file_path, wc_dir)
 
+@Issue(3644)
+def patch_empty_file(sbox):
+  "apply a patch to an empty file"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  patch_file_path = make_patch_path(sbox)
+  svntest.main.file_write(patch_file_path, ''.join([
+  # patch a file containing just '\n' to 'replacement\n'
+    "Index: lf.txt\n",
+    "===================================================================\n",
+    "--- lf.txt\t(revision 2)\n",
+    "+++ lf.txt\t(working copy)\n",
+    "@@ -1 +1 @@\n",
+    "\n"
+    "+replacement\n",
+
+  # patch a new file 'new.txt\n'
+    "Index: new.txt\n",
+    "===================================================================\n",
+    "--- new.txt\t(revision 0)\n",
+    "+++ new.txt\t(working copy)\n",
+    "@@ -0,0 +1 @@\n",
+    "+new file\n",
+
+  # patch a file containing 0 bytes to 'replacement\n'
+    "Index: empty.txt\n",
+    "===================================================================\n",
+    "--- empty.txt\t(revision 2)\n",
+    "+++ empty.txt\t(working copy)\n",
+    "@@ -0,0 +1 @@\n",
+    "+replacement\n",
+  ]))
+
+  sbox.simple_add_text('', 'empty.txt')
+  sbox.simple_add_text('\n', 'lf.txt')
+  sbox.simple_commit()
+
+  expected_output = [
+    'U         %s\n' % sbox.ospath('lf.txt'),
+    'A         %s\n' % sbox.ospath('new.txt'),
+    'U         %s\n' % sbox.ospath('empty.txt'),
+    # Not sure if this line is necessary, but it doesn't hurt
+    '>         applied hunk @@ -0,0 +1,1 @@ with offset 0\n',
+  ]
+
+  # Current result: lf.txt patched ok, new created, empty succeeds with offset.
+  svntest.actions.run_and_verify_svn(None, expected_output, [],
+                                     'patch', patch_file_path, wc_dir)
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+    'lf.txt'            : Item(contents="\n"),
+    'new.txt'           : Item(contents="new file\n"),
+    'empty.txt'         : Item(contents="replacement\n"),
+  })
+
+  svntest.actions.verify_disk(wc_dir, expected_disk)
+
+@Issue(3362)
+def patch_apply_no_fuz(sbox):
+  "svn diff created patch should apply without fuz"
+
+  sbox.build(read_only=True)
+  wc_dir = sbox.wc_dir
+
+  svntest.main.file_write(sbox.ospath('test.txt'), '\n'.join([
+      "line_1",
+      "line_2",
+      "line_3",
+      "line_4",
+      "line_5",
+      "line_6",
+      "line_7",
+      "line_8",
+      "line_9",
+      "line_10",
+      "line_11",
+      "line_12",
+      "line_13",
+      "line_14",
+      "line_15",
+      "line_16",
+      "line_17",
+      "line_18",
+      "line_19",
+      "line_20",
+      "line_21",
+      "line_22",
+      "line_23",
+      "line_24",
+      "line_25",
+      "line_26",
+      "line_27",
+      "line_28",
+      "line_29",
+      "line_30",
+      ""
+    ]))
+  svntest.main.file_write(sbox.ospath('test_v2.txt'), '\n'.join([
+      "line_1a",
+      "line_1b",
+      "line_1c",
+      "line_1",
+      "line_2",
+      "line_3",
+      "line_4",
+      "line_5a",
+      "line_5b",
+      "line_5c",
+      "line_6",
+      "line_7",
+      "line_8",
+      "line_9",
+      "line_10",
+      "line_11a",
+      "line_11b",
+      "line_11c",
+      "line_12",
+      "line_13",
+      "line_14",
+      "line_15",
+      "line_16",
+      "line_17",
+      "line_18",
+      "line_19a",
+      "line_19b",
+      "line_19c",
+      "line_20",
+      "line_21",
+      "line_22",
+      "line_23",
+      "line_24",
+      "line_25",
+      "line_26",
+      "line_27a",
+      "line_27b",
+      "line_27c",
+      "line_28",
+      "line_29",
+      "line_30",
+      ""
+    ]))
+
+  sbox.simple_add('test.txt', 'test_v2.txt')
+
+  result, out_text, err_text = svntest.main.run_svn(None,
+                                                    'diff',
+                                                    '--old',
+                                                    sbox.ospath('test.txt'),
+                                                    '--new',
+                                                    sbox.ospath('test_v2.txt'))
+
+  patch_path = sbox.ospath('patch.diff')
+  svntest.main.file_write(patch_path, ''.join(out_text))
+
+  expected_output = [
+    'G         %s\n' % sbox.ospath('test.txt'),
+  ]
+
+  # Current result: lf.txt patched ok, new created, empty succeeds with offset.
+  svntest.actions.run_and_verify_svn(None, expected_output, [],
+                                     'patch', patch_path, wc_dir)
+
+  if not filecmp.cmp(sbox.ospath('test.txt'), sbox.ospath('test_v2.txt')):
+    raise svntest.Failure("Patch result not identical")
+
 
 ########################################################################
 #Run the tests
@@ -4444,6 +4626,8 @@ test_list = [ None,
               patch_change_symlink_target,
               patch_replace_dir_with_file_and_vv,
               single_line_mismatch,
+              patch_empty_file,
+              patch_apply_no_fuz,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/svnadmin_tests.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/svnadmin_tests.py Sun Jan 27 00:01:57 2013
@@ -548,12 +548,22 @@ def verify_windows_paths_in_repos(sbox):
 
   exit_code, output, errput = svntest.main.run_svnadmin("verify",
                                                         sbox.repo_dir)
-  svntest.verify.compare_and_display_lines(
-    "Error while running 'svnadmin verify'.",
-    'STDERR', ["* Verifying global structure ...\n",
-               "* Verified revision 0.\n",
-               "* Verified revision 1.\n",
-               "* Verified revision 2.\n"], errput)
+
+  # unfortunately, FSFS needs to do more checks than BDB resulting in
+  # different progress output
+  if svntest.main.is_fs_type_fsfs():
+    svntest.verify.compare_and_display_lines(
+      "Error while running 'svnadmin verify'.",
+      'STDERR', ["* Verifying global structure ...\n",
+                 "* Verified revision 0.\n",
+                 "* Verified revision 1.\n",
+                 "* Verified revision 2.\n"], errput)
+  else:
+    svntest.verify.compare_and_display_lines(
+      "Error while running 'svnadmin verify'.",
+      'STDERR', ["* Verified revision 0.\n",
+                 "* Verified revision 1.\n",
+                 "* Verified revision 2.\n"], errput)
 
 #----------------------------------------------------------------------
 

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/actions.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/actions.py Sun Jan 27 00:01:57 2013
@@ -424,6 +424,22 @@ def expected_noop_update_output(rev):
                                      % (rev),
                                      "no-op update")
 
+def run_and_verify_svnauthz(message, expected_stdout, expected_stderr,
+                            expected_exit, compat_mode, *varargs):
+  """Run svnauthz command and check its output and exit code.
+     If COMPAT_MODE is True then run the command in pre-1.8
+     compatibility mode"""
+
+  if compat_mode:
+    exit_code, out, err = main.run_svnauthz_validate(*varargs)
+  else:
+    exit_code, out, err = main.run_svnauthz(*varargs)
+
+  verify.verify_outputs("Unexpected output", out, err,
+                        expected_stdout, expected_stderr)
+  verify.verify_exit_code(message, exit_code, expected_exit)
+  return exit_code, out, err
+
 ######################################################################
 # Subversion Actions
 #

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/main.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/main.py Sun Jan 27 00:01:57 2013
@@ -157,6 +157,15 @@ atomic_ra_revprop_change_binary = os.pat
 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)
 
+######################################################################
+# The location of svnauthz binary, relative to the only scripts that
+# import this file right now (they live in ../).
+# Use --tools to overide these defaults.
+svnauthz_binary = os.path.abspath('../../../tools/server-side/svnauthz' + _exe)
+svnauthz_validate_binary = os.path.abspath(
+    '../../../tools/server-side/svnauthz-validate' + _exe
+)
+
 # Location to the pristine repository, will be calculated from test_area_url
 # when we know what the user specified for --url.
 pristine_greek_repos_url = None
@@ -703,6 +712,16 @@ def run_svnmucc(*varargs):
   return run_command(svnmucc_binary, 1, True,
                      *(_with_auth(_with_config_dir(varargs))))
 
+def run_svnauthz(*varargs):
+  """Run svnauthz with VARARGS, returns exit code as int; stdout, stderr
+  as list of lines (including line terminators)."""
+  return run_command(svnauthz_binary, 1, False, *varargs)
+
+def run_svnauthz_validate(*varargs):
+  """Run svnauthz-validate with VARARGS, returns exit code as int; stdout,
+  stderr as list of lines (including line terminators)."""
+  return run_command(svnauthz_validate_binary, 1, False, *varargs)
+
 def run_entriesdump(path):
   """Run the entries-dump helper, returning a dict of Entry objects."""
   # use spawn_process rather than run_command to avoid copying all the data
@@ -727,6 +746,23 @@ def run_entriesdump_subdirs(path):
                                                         0, False, None, '--subdirs', path)
   return map(lambda line: line.strip(), filter_dbg(stdout_lines))
 
+def run_entriesdump_tree(path):
+  """Run the entries-dump helper, returning a dict of a dict of Entry objects."""
+  # use spawn_process rather than run_command to avoid copying all the data
+  # to stdout in verbose mode.
+  exit_code, stdout_lines, stderr_lines = spawn_process(entriesdump_binary,
+                                                        0, False, None,
+                                                        '--tree-dump', path)
+  if exit_code or stderr_lines:
+    ### report on this? or continue to just skip it?
+    return None
+
+  class Entry(object):
+    pass
+  dirs = { }
+  exec(''.join(filter_dbg(stdout_lines)))
+  return dirs
+
 def run_atomic_ra_revprop_change(url, revision, propname, skel, want_error):
   """Run the atomic-ra-revprop-change helper, returning its exit code, stdout,
   and stderr.  For HTTP, default HTTP library is used."""
@@ -1029,6 +1065,19 @@ def write_restrictive_svnserve_conf(repo
     fp.write("password-db = passwd\n")
   fp.close()
 
+def write_restrictive_svnserve_conf_with_groups(repo_dir,
+                                                anon_access="none"):
+  "Create a restrictive configuration with groups stored in a separate file."
+
+  fp = open(get_svnserve_conf_file_path(repo_dir), 'w')
+  fp.write("[general]\nanon-access = %s\nauth-access = write\n"
+           "authz-db = authz\ngroups-db = groups\n" % anon_access)
+  if options.enable_sasl:
+    fp.write("realm = svntest\n[sasl]\nuse-sasl = true\n");
+  else:
+    fp.write("password-db = passwd\n")
+  fp.close()
+
 # Warning: because mod_dav_svn uses one shared authz file for all
 # repositories, you *cannot* use write_authz_file in any test that
 # might be run in parallel.
@@ -1064,6 +1113,18 @@ an appropriate list of mappings.
     fp.write("[%s%s]\n%s\n" % (prefix, p, r))
   fp.close()
 
+# See the warning about parallel test execution in write_authz_file
+# method description.
+def write_groups_file(sbox, groups):
+  """Write a groups file to SBOX, appropriate for the RA method used,
+with group contents set to GROUPS."""
+  fp = open(sbox.groups_file, 'w')
+  fp.write("[groups]\n")
+  if groups:
+    for p, r in groups.items():
+      fp.write("%s = %s\n" % (p, r))
+  fp.close()
+
 def use_editor(func):
   os.environ['SVN_EDITOR'] = svneditor_script
   os.environ['SVN_MERGE'] = svneditor_script
@@ -1643,6 +1704,8 @@ def _create_parser():
                     help='Path to SSL server certificate.')
   parser.add_option('--http-proxy', action='store',
                     help='Use the HTTP Proxy at hostname:port.')
+  parser.add_option('--tools-bin', action='store', dest='tools_bin',
+                    help='Use the svn tools installed in this path')
 
   # most of the defaults are None, but some are other values, set them here
   parser.set_defaults(
@@ -1783,6 +1846,8 @@ def execute_tests(test_list, serial_only
   global svndumpfilter_binary
   global svnversion_binary
   global svnmucc_binary
+  global svnauthz_binary
+  global svnauthz_validate_binary
   global options
 
   if test_name:
@@ -1900,6 +1965,11 @@ def execute_tests(test_list, serial_only
       svnversion_binary = os.path.join(options.svn_bin, 'svnversion' + _exe)
       svnmucc_binary = os.path.join(options.svn_bin, 'svnmucc' + _exe)
 
+  if options.tools_bin:
+    svnauthz_binary = os.path.join(options.tools_bin, 'svnauthz' + _exe)
+    svnauthz_validate_binary = os.path.join(options.tools_bin,
+                                            'svnauthz-validate' + _exe)
+
   ######################################################################
 
   # Cleanup: if a previous run crashed or interrupted the python

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/sandbox.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/sandbox.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/sandbox.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/sandbox.py Sun Jan 27 00:01:57 2013
@@ -78,12 +78,14 @@ class Sandbox:
       tmp_authz_file = os.path.join(svntest.main.work_dir, "authz-" + self.name)
       open(tmp_authz_file, 'w').write("[/]\n* = rw\n")
       shutil.move(tmp_authz_file, self.authz_file)
+      self.groups_file = os.path.join(svntest.main.work_dir, "groups")
 
     # For svnserve tests we have a per-repository authz file, and it
     # doesn't need to be there in order for things to work, so we don't
     # have any default contents.
     elif self.repo_url.startswith("svn"):
       self.authz_file = os.path.join(self.repo_dir, "conf", "authz")
+      self.groups_file = os.path.join(self.repo_dir, "conf", "groups")
 
   def clone_dependent(self, copy_wc=False):
     """A convenience method for creating a near-duplicate of this
@@ -231,8 +233,8 @@ class Sandbox:
       target = self.ospath(target)
     if message is None:
       message = svntest.main.make_log_msg()
-    svntest.main.run_svn(False, 'commit', '-m', message,
-                         target)
+    svntest.actions.run_and_verify_commit(self.wc_dir, None, None, [],
+                                          '-m', message, target)
 
   def simple_rm(self, *targets):
     """Schedule TARGETS for deletion.

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/verify.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/verify.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/verify.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/verify.py Sun Jan 27 00:01:57 2013
@@ -215,6 +215,7 @@ class ExpectedOutput:
 
 
 class AnyOutput(ExpectedOutput):
+  """Matches any non-empty output."""
   def __init__(self):
     ExpectedOutput.__init__(self, None, False)
 

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/wc.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/wc.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/wc.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/svntest/wc.py Sun Jan 27 00:01:57 2013
@@ -337,7 +337,8 @@ class State:
       if item.status:
         # If this is an unversioned tree-conflict, remove it.
         # These are only in their parents' THIS_DIR, they don't have entries.
-        if item.status[0] in '!?' and item.treeconflict == 'C':
+        if item.status[0] in '!?' and item.treeconflict == 'C' and \
+                                      item.entry_status is None:
           del self.desc[path]
         # Normal externals are not stored in the parent wc, drop the root
         # and everything in these working copies
@@ -663,21 +664,14 @@ class State:
     desc = { }
     dot_svn = svntest.main.get_admin_name()
 
-    for dirpath in svntest.main.run_entriesdump_subdirs(base):
+    dump_data = svntest.main.run_entriesdump_tree(base)
 
-      if base == '.' and dirpath != '.':
-        dirpath = '.' + os.path.sep + dirpath
+    if not dump_data:
+      # Probably 'svn status' run on an actual only node
+      # ### Improve!
+      return cls('', desc)
 
-      entries = svntest.main.run_entriesdump(dirpath)
-      if entries is None:
-        continue
-
-      if dirpath == '.':
-        parent = ''
-      elif dirpath.startswith('.' + os.sep):
-        parent = to_relpath(dirpath[2:])
-      else:
-        parent = to_relpath(dirpath)
+    for parent, entries in sorted(dump_data.items()):
 
       parent_url = entries[''].url
 

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/switch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/switch_tests.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/switch_tests.py Sun Jan 27 00:01:57 2013
@@ -2906,6 +2906,33 @@ def different_node_kind(sbox):
   switch_to_file(sbox, 'iota', 'A/C')
   switch_to_file(sbox, 'A/D/gamma', 'A/D/G')
 
+@Issue(3332, 3333)
+def switch_to_spaces(sbox):
+  "switch to a directory with spaces in its name"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  repo_url = sbox.repo_url
+
+  # Paths are normalized in the command processing, so %20 is equivalent to ' '
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'cp', repo_url + '/A',
+                                           repo_url + '/A%20with space',
+                                     '-m', '')
+
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'mv', repo_url + '/A%20with space',
+                                           repo_url + '/A with%20more spaces',
+                                     '-m', '')
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 3)
+  expected_status.tweak('A', switched='S')
+  expected_status.tweak('', 'iota', wc_rev=1)
+
+  svntest.actions.run_and_verify_switch(sbox.wc_dir, sbox.ospath('A'),
+                                        repo_url + '/A%20with more%20spaces',
+                                        None, None, expected_status)
+
 ########################################################################
 # Run the tests
 
@@ -2946,6 +2973,7 @@ test_list = [ None,
               copy_with_switched_subdir,
               up_to_old_rev_with_subtree_switched_to_root,
               different_node_kind,
+              switch_to_spaces,
               ]
 
 if __name__ == '__main__':

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/update_tests.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/update_tests.py Sun Jan 27 00:01:57 2013
@@ -3943,6 +3943,11 @@ def update_accept_conflicts(sbox):
 # WC update editor flush and run incomplete logs and lead to WC
 # corruption, detectable by another update command.
 
+# FIXME: With issue #4280 fixed and this test using --force-interactive,
+#        the test driver can no longer redirect terminal input to cause
+#        an EOF. Consequently, skip this test so that it does not hang
+#        the test suite.
+@Skip()
 def eof_in_interactive_conflict_resolver(sbox):
   "eof in interactive resolution can't break wc"
 
@@ -3995,11 +4000,11 @@ interactive-conflicts = true
   # Modify iota differently and try to update *with the interactive
   # resolver*.  ### The parser won't go so well with the output
   svntest.main.file_append(iota_path, "Local mods to r1 text.\n")
-  svntest.actions.run_and_verify_update(wc_dir, None, None, None,
-                                        "Can't read stdin: End of file found",
-                                        None, None, None, None, 1,
-                                        wc_dir, '--force-interactive',
-                                        '--config-dir', config_dir)
+  svntest.actions.run_and_verify_update(
+    wc_dir, None, None, None,
+    "End of file while reading from terminal",
+    None, None, None, None, 1,
+    wc_dir, '--force-interactive', '--config-dir', config_dir)
 
   # Now update -r1 again.  Hopefully we don't get a checksum error!
   expected_output = svntest.wc.State(wc_dir, {
@@ -5464,14 +5469,13 @@ def update_moved_dir_leaf_del(sbox):
                                         None, None, 1)
 
   # Now resolve the conflict, using --accept=mine-conflict applying
-  # the update to A/B/E2 causing a delete-delete conflict
+  # the update to A/B/E2
   svntest.actions.run_and_verify_svn("resolve failed", None, [],
                                      'resolve',
                                      '--accept=mine-conflict',
                                      sbox.ospath('A/B/E'))
   expected_status.tweak('A/B/E', treeconflict=None)
-  expected_status.tweak('A/B/E2/alpha', status='? ', treeconflict='C',
-                        copied=None, wc_rev=None)
+  expected_status.remove('A/B/E2/alpha')
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
 @XFail()
@@ -5699,15 +5703,14 @@ def update_moved_dir_file_move(sbox):
 
   # The incoming change is a delete as we don't yet track server-side
   # moves.  Resolving the tree-conflict as "mine-conflict" applies the
-  # delete to the move destination creating a delete-delete conflict.
+  # delete to the move destination.
   svntest.actions.run_and_verify_svn("resolve failed", None, [],
                                      'resolve',
                                      '--accept=mine-conflict',
                                      sbox.ospath('A/B/E'))
 
   expected_status.tweak('A/B/E', treeconflict=None)
-  expected_status.tweak('A/B/E2/alpha', status='? ', treeconflict='C',
-                        copied=None, wc_rev=None)
+  expected_status.remove('A/B/E2/alpha')
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
 
@@ -6358,6 +6361,71 @@ def incomplete_overcomplete(sbox):
                                         True,
                                         wc_dir, '-r', 3)
 
+@Issue(4300)
+def update_swapped_depth_dirs(sbox):
+  "text mod to file in swapped depth dir"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  svntest.main.file_append(sbox.ospath('A/B/E/alpha'), "modified\n")
+  sbox.simple_commit()
+  sbox.simple_update(revision=1)
+
+  sbox.simple_move("A/B/E", "A/E")
+  sbox.simple_move("A/B", "A/E/B")
+  # This is almost certainly not the right status but it's what
+  # is currently being output so we're using it here so we
+  # can get to the deeper problem.
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.tweak("A/B", "A/B/lambda", "A/B/F", "A/B/E",
+                        "A/B/E/alpha", "A/B/E/beta", status="D ")
+  expected_status.tweak("A/B", moved_to="A/E/B")
+  expected_status.add({
+      'A/E'          : Item(status='A ', copied='+', wc_rev='-',
+                            moved_from='A/E/B/E'),
+      'A/E/B'        : Item(status='A ', copied='+', wc_rev='-',
+                            moved_from='A/B'),
+      'A/E/B/E'      : Item(status='D ', copied='+', wc_rev='-',
+                            moved_to='A/E'),
+      'A/E/B/F'      : Item(status='  ', copied='+', wc_rev='-'),
+      'A/E/B/lambda' : Item(status='  ', copied='+', wc_rev='-'),
+      'A/E/alpha'    : Item(status='  ', copied='+', wc_rev='-'),
+      'A/E/beta'     : Item(status='  ', copied='+', wc_rev='-'),
+      'A/E/B/E/alpha': Item(status='D ', copied='+', wc_rev='-'),
+      'A/E/B/E/beta' : Item(status='D ', copied='+', wc_rev='-'),
+      })
+
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
+
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/B'         : Item(status='  ', treeconflict='C'),
+    'A/B/E'       : Item(status='  ', treeconflict='U'),
+    'A/B/E/alpha' : Item(status='  ', treeconflict='U'),
+  })
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.remove('A/B', 'A/B/lambda', 'A/B/F', 'A/B/E',
+                       'A/B/E/alpha', 'A/B/E/beta')
+  expected_disk.add({
+    'A/E'          : Item(),
+    'A/E/alpha'    : Item(contents="This is the file 'alpha'.\n"),
+    'A/E/beta'     : Item(contents="This is the file 'beta'.\n"),
+    'A/E/B'        : Item(),
+    'A/E/B/lambda' : Item(contents="This is the file 'lambda'.\n"),
+    'A/E/B/F'      : Item(),
+  })
+  expected_status.tweak(wc_rev=2)
+  expected_status.tweak('A/B', treeconflict='C')
+  expected_status.tweak('A/E', 'A/E/alpha', 'A/E/beta', 'A/E/B',
+                        'A/E/B/E', 'A/E/B/E/alpha', 'A/E/B/E/beta',
+                        'A/E/B/lambda', 'A/E/B/F', wc_rev='-')
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output,
+                                        expected_disk,
+                                        expected_status,
+                                        None, None, None,
+                                        None, None, 1)
 
 
 #######################################################################
@@ -6440,6 +6508,7 @@ test_list = [ None,
               break_moved_replaced_dir,
               update_removes_switched,
               incomplete_overcomplete,
+              update_swapped_depth_dirs,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/windows-build-update/subversion/tests/cmdline/upgrade_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/cmdline/upgrade_tests.py?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/branches/windows-build-update/subversion/tests/cmdline/upgrade_tests.py Sun Jan 27 00:01:57 2013
@@ -1206,7 +1206,7 @@ def upgrade_file_externals(sbox):
 
 
 @Issue(4035)
-@XFail()
+@Wimp('Fails in maintainer mode')
 def upgrade_missing_replaced(sbox):
   "upgrade with missing replaced dir"
 
@@ -1221,12 +1221,14 @@ def upgrade_missing_replaced(sbox):
                                      sbox.wc_dir)
 
   expected_output = svntest.wc.State(sbox.wc_dir, {
-      'A/B/E'         : Item(status='  ', treeconflict='C', prev_verb='Restored'),
+      'A/B/E'         : Item(status='  ', treeconflict='C',
+                             prev_verb='Restored'),
       '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', status='! ', treeconflict='C', wc_rev='-',
+                        entry_status='R ', entry_rev='1')
   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)

Modified: subversion/branches/windows-build-update/subversion/tests/libsvn_client/client-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/libsvn_client/client-test.c?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/libsvn_client/client-test.c (original)
+++ subversion/branches/windows-build-update/subversion/tests/libsvn_client/client-test.c Sun Jan 27 00:01:57 2013
@@ -721,6 +721,53 @@ test_youngest_common_ancestor(const svn_
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_foreign_repos_copy(const svn_test_opts_t *opts,
+                        apr_pool_t *pool)
+{
+  svn_opt_revision_t rev;
+  svn_opt_revision_t peg_rev;
+  const char *repos_url;
+  const char *repos2_url;
+  const char *wc_path;
+  svn_client_ctx_t *ctx;
+/* Create a filesytem and repository containing the Greek tree. */
+  SVN_ERR(create_greek_repos(&repos_url, "foreign-copy1", opts, pool));
+  SVN_ERR(create_greek_repos(&repos2_url, "foreign-copy2", opts, pool));
+
+  SVN_ERR(svn_dirent_get_absolute(&wc_path, "test-wc-add", pool));
+
+  wc_path = svn_dirent_join(wc_path, "foreign-wc", pool);
+
+  /* Remove old test data from the previous run */
+  SVN_ERR(svn_io_remove_dir2(wc_path, TRUE, NULL, NULL, pool));
+
+  SVN_ERR(svn_io_make_dir_recursively(wc_path, pool));
+  svn_test_add_dir_cleanup(wc_path);
+
+  rev.kind = svn_opt_revision_head;
+  peg_rev.kind = svn_opt_revision_unspecified;
+  SVN_ERR(svn_client_create_context(&ctx, pool));
+  /* Checkout greek tree as wc_path */
+  SVN_ERR(svn_client_checkout3(NULL, repos_url, wc_path, &peg_rev, &rev,
+                               svn_depth_infinity, FALSE, FALSE, ctx, pool));
+
+  SVN_ERR(svn_client__copy_foreign(svn_path_url_add_component2(repos2_url, "A",
+                                                               pool),
+                                   svn_dirent_join(wc_path, "A-copied", pool),
+                                   &peg_rev, &rev, svn_depth_infinity, FALSE, FALSE,
+                                   ctx, pool));
+
+
+  SVN_ERR(svn_client__copy_foreign(svn_path_url_add_component2(repos2_url,
+                                                               "iota",
+                                                               pool),
+                                   svn_dirent_join(wc_path, "iota-copied", pool),
+                                   &peg_rev, &rev, svn_depth_infinity, FALSE, FALSE,
+                                   ctx, pool));
+
+  return SVN_NO_ERROR;
+}
 
 /* ========================================================================== */
 
@@ -738,5 +785,6 @@ struct svn_test_descriptor_t test_funcs[
     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_OPTS_PASS(test_foreign_repos_copy, "test foreign repository copy"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/windows-build-update/subversion/tests/libsvn_diff/diff-diff3-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/libsvn_diff/diff-diff3-test.c?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/libsvn_diff/diff-diff3-test.c (original)
+++ subversion/branches/windows-build-update/subversion/tests/libsvn_diff/diff-diff3-test.c Sun Jan 27 00:01:57 2013
@@ -76,16 +76,14 @@ make_random_file(const char *filename,
                  apr_pool_t *pool)
 {
   apr_file_t *file;
-  apr_status_t status;
   int num_lines;
 
   num_lines = range_rand(min_lines, max_lines);
 
-  status = apr_file_open(&file, filename,
-                         APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
-                         pool);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to open '%s'", filename);
+  SVN_ERR(svn_io_file_open(&file, filename,
+                           APR_WRITE | APR_CREATE | APR_TRUNCATE,
+                           APR_OS_DEFAULT,
+                           pool));
 
   while (num_lines--)
     {
@@ -100,9 +98,7 @@ make_random_file(const char *filename,
         apr_file_printf(file, "line %d line %d line %d", x, x, x);
     }
 
-  status = apr_file_close(file);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to close '%s'", filename);
+  SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
 }
@@ -117,19 +113,15 @@ make_file(const char *filename,
   apr_file_t *file;
   apr_status_t status;
 
-  status = apr_file_open(&file, filename,
-                         APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
-                         pool);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to open '%s'", filename);
+  SVN_ERR(svn_io_file_open(&file, filename,
+                           APR_WRITE | APR_CREATE | APR_TRUNCATE,
+                           APR_OS_DEFAULT, pool));
 
   status = apr_file_write_full(file, contents, strlen(contents), NULL);
   if (status)
     return svn_error_createf(status, NULL, "failed to write '%s'", filename);
 
-  status = apr_file_close(file);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to close '%s'", filename);
+  SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
 }
@@ -159,7 +151,6 @@ three_way_merge(const char *filename1,
   svn_diff_t *diff;
   apr_file_t *output;
   svn_stream_t *ostream;
-  apr_status_t status;
   svn_stringbuf_t *actual;
   char *merge_name = apr_psprintf(pool, "merge-%s-%s-%s",
                                   filename1, filename2, filename3);
@@ -199,34 +190,29 @@ three_way_merge(const char *filename1,
 
   SVN_ERR(svn_diff_file_diff3_2(&diff, filename1, filename2, filename3,
                                 options, pool));
-  status = apr_file_open(&output, merge_name,
-                         APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
-                         pool);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to open '%s'", merge_name);
+  SVN_ERR(svn_io_file_open(&output, merge_name,
+                           APR_WRITE | APR_CREATE | APR_TRUNCATE,
+                           APR_OS_DEFAULT, pool));
 
-  ostream = svn_stream_from_aprfile(output, pool);
+  ostream = svn_stream_from_aprfile2(output, FALSE, pool);
   SVN_ERR(svn_diff_file_output_merge2(ostream, diff,
                                       filename1, filename2, filename3,
                                       NULL, NULL, NULL, NULL,
                                       style,
                                       pool));
   SVN_ERR(svn_stream_close(ostream));
-  status = apr_file_close(output);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to close '%s'", merge_name);
-  SVN_ERR(svn_stringbuf_from_file(&actual, merge_name, pool));
+  SVN_ERR(svn_stringbuf_from_file2(&actual, merge_name, pool));
   if (strcmp(actual->data, expected))
     return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
                              "failed merging diff '%s' to '%s' into '%s'",
                              filename1, filename2, filename3);
 
-  SVN_ERR(svn_io_remove_file(filename1, pool));
+  SVN_ERR(svn_io_remove_file2(filename1, TRUE, pool));
   if (strcmp(filename1, filename2))
-    SVN_ERR(svn_io_remove_file(filename2, pool));
+    SVN_ERR(svn_io_remove_file2(filename2, TRUE, pool));
   if (strcmp(filename1, filename3) && strcmp(filename2, filename3))
-    SVN_ERR(svn_io_remove_file(filename3, pool));
-  SVN_ERR(svn_io_remove_file(merge_name, pool));
+    SVN_ERR(svn_io_remove_file2(filename3, TRUE, pool));
+  SVN_ERR(svn_io_remove_file2(merge_name, TRUE, pool));
 
   return SVN_NO_ERROR;
 }
@@ -252,7 +238,6 @@ two_way_diff(const char *filename1,
   svn_diff_t *diff;
   apr_file_t *output;
   svn_stream_t *ostream;
-  apr_status_t status;
   svn_stringbuf_t *actual;
   char *diff_name = apr_psprintf(pool, "diff-%s-%s", filename1, filename2);
 
@@ -285,27 +270,42 @@ two_way_diff(const char *filename1,
   /* Check that two-way diff between contents1 and contents2 produces
      expected output. */
   SVN_ERR(svn_diff_file_diff_2(&diff, filename1, filename2, options, pool));
-  status = apr_file_open(&output, diff_name,
-                         APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
-                         pool);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to open '%s'", diff_name);
 
-  ostream = svn_stream_from_aprfile(output, pool);
+  SVN_ERR(svn_io_file_open(&output, diff_name,
+                           APR_WRITE | APR_CREATE | APR_TRUNCATE,
+                           APR_OS_DEFAULT, pool));
+
+  ostream = svn_stream_from_aprfile2(output, FALSE, pool);
   SVN_ERR(svn_diff_file_output_unified2(ostream, diff,
                                         filename1, filename2,
                                         filename1, filename2,
                                         SVN_APR_LOCALE_CHARSET, pool));
   SVN_ERR(svn_stream_close(ostream));
-  status = apr_file_close(output);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to close '%s'", diff_name);
 
-  SVN_ERR(svn_stringbuf_from_file(&actual, diff_name, pool));
+  SVN_ERR(svn_stringbuf_from_file2(&actual, diff_name, pool));
   if (strcmp(actual->data, expected))
-    return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
-                             "failed comparing '%s' and '%s'",
-                             filename1, filename2);
+    {
+      /*svn_stringbuf_t *dump_actual;
+      svn_stream_t *dump_ostream;
+      dump_actual = svn_stringbuf_create_empty(pool);
+      dump_ostream = svn_stream_from_stringbuf(dump_actual, pool);
+
+      SVN_ERR(svn_diff_mem_string_output_unified(dump_ostream, diff,
+                                                 "expected", "actual",
+                                                 SVN_APR_LOCALE_CHARSET,
+                                                 svn_string_create(expected, pool),
+                                                 svn_string_create(actual->data, pool),
+                                                 pool));
+      SVN_ERR(svn_stream_close(ostream));
+
+      SVN_DBG(("%s\n", dump_actual->data));
+
+      SVN_ERR(make_file("memory", expected, pool));*/
+      return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                               "failed comparing '%s' and '%s'"
+                               " (memory and file results are different)",
+                               filename1, filename2);
+    }
 
   /* May as well do the trivial merges while we are here */
   SVN_ERR(three_way_merge(filename1, filename2, filename1,
@@ -317,7 +317,7 @@ two_way_diff(const char *filename1,
                           svn_diff_conflict_display_modified_latest,
                           pool));
 
-  SVN_ERR(svn_io_remove_file(diff_name, pool));
+  SVN_ERR(svn_io_remove_file2(diff_name, TRUE, pool));
 
   return SVN_NO_ERROR;
 }
@@ -373,14 +373,11 @@ make_random_merge_file(const char *filen
                        apr_pool_t *pool)
 {
   apr_file_t *file;
-  apr_status_t status;
   int i;
 
-  status = apr_file_open(&file, filename,
-                         APR_WRITE | APR_CREATE | APR_TRUNCATE, APR_OS_DEFAULT,
-                         pool);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to open '%s'", filename);
+  SVN_ERR(svn_io_file_open(&file, filename,
+                           APR_WRITE | APR_CREATE | APR_TRUNCATE,
+                           APR_OS_DEFAULT, pool));
 
   for (i = 0; i < num_lines; ++i)
     {
@@ -413,9 +410,7 @@ make_random_merge_file(const char *filen
         }
     }
 
-  status = apr_file_close(file);
-  if (status)
-    return svn_error_createf(status, NULL, "failed to close '%s'", filename);
+  SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
 }
@@ -2193,8 +2188,8 @@ random_trivial_merge(apr_pool_t *pool)
                                min_lines, max_lines, var_lines, block_lines,
                                i % 2, subpool));
 
-      SVN_ERR(svn_stringbuf_from_file(&contents1, filename1, subpool));
-      SVN_ERR(svn_stringbuf_from_file(&contents2, filename2, subpool));
+      SVN_ERR(svn_stringbuf_from_file2(&contents1, filename1, subpool));
+      SVN_ERR(svn_stringbuf_from_file2(&contents2, filename2, subpool));
 
       SVN_ERR(three_way_merge(filename1, filename2, filename1,
                               contents1->data, contents2->data,
@@ -2262,10 +2257,10 @@ random_three_way_merge(apr_pool_t *pool)
       SVN_ERR(make_random_merge_file(filename4, num_lines, mrg_lines,
                                      num_src + num_dst, pool));
 
-      SVN_ERR(svn_stringbuf_from_file(&original, filename1, pool));
-      SVN_ERR(svn_stringbuf_from_file(&modified1, filename2, pool));
-      SVN_ERR(svn_stringbuf_from_file(&modified2, filename3, pool));
-      SVN_ERR(svn_stringbuf_from_file(&combined, filename4, pool));
+      SVN_ERR(svn_stringbuf_from_file2(&original, filename1, pool));
+      SVN_ERR(svn_stringbuf_from_file2(&modified1, filename2, pool));
+      SVN_ERR(svn_stringbuf_from_file2(&modified2, filename3, pool));
+      SVN_ERR(svn_stringbuf_from_file2(&combined, filename4, pool));
 
       SVN_ERR(three_way_merge(filename1, filename2, filename3,
                               original->data, modified1->data,
@@ -2278,7 +2273,7 @@ random_three_way_merge(apr_pool_t *pool)
                               svn_diff_conflict_display_modified_latest,
                               subpool));
 
-      SVN_ERR(svn_io_remove_file(filename4, pool));
+      SVN_ERR(svn_io_remove_file2(filename4, TRUE, pool));
 
       svn_pool_clear(subpool);
     }
@@ -2335,10 +2330,10 @@ merge_with_part_already_present(apr_pool
       SVN_ERR(make_random_merge_file(filename4, num_lines, mrg_lines,
                                      num_src + num_dst / 2, pool));
 
-      SVN_ERR(svn_stringbuf_from_file(&original, filename1, pool));
-      SVN_ERR(svn_stringbuf_from_file(&modified1, filename2, pool));
-      SVN_ERR(svn_stringbuf_from_file(&modified2, filename3, pool));
-      SVN_ERR(svn_stringbuf_from_file(&combined, filename4, pool));
+      SVN_ERR(svn_stringbuf_from_file2(&original, filename1, pool));
+      SVN_ERR(svn_stringbuf_from_file2(&modified1, filename2, pool));
+      SVN_ERR(svn_stringbuf_from_file2(&modified2, filename3, pool));
+      SVN_ERR(svn_stringbuf_from_file2(&combined, filename4, pool));
 
       SVN_ERR(three_way_merge(filename1, filename2, filename3,
                               original->data, modified1->data,
@@ -2351,7 +2346,7 @@ merge_with_part_already_present(apr_pool
                               svn_diff_conflict_display_modified_latest,
                               subpool));
 
-      SVN_ERR(svn_io_remove_file(filename4, pool));
+      SVN_ERR(svn_io_remove_file2(filename4, TRUE, pool));
 
       svn_pool_clear(subpool);
     }
@@ -2617,6 +2612,265 @@ test_token_compare(apr_pool_t *pool)
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+two_way_issue_3362_v1(apr_pool_t *pool)
+{
+  svn_diff_file_options_t *diff_opts = svn_diff_file_options_create(pool);
+
+  SVN_ERR(two_way_diff("issue-3362-1-v1",
+                       "issue-3362-2-v1",
+                        /* File 1 */
+                                "line_1\n"
+                                "line_2\n"
+                                "line_3\n"
+                                "line_4\n"
+                                "line_5\n"
+                                "line_6\n"
+                                "line_7\n"
+                                "line_8\n"
+                                "line_9\n"
+                                "line_10\n"
+                                "line_11\n"
+                                "line_12\n"
+                                "line_13\n"
+                                "line_14\n"
+                                "line_15\n"
+                                "line_16\n"
+                                "line_17\n"
+                                "line_18\n"
+                                "line_19\n"
+                                "line_20\n"
+                                "line_21\n"
+                                "line_22\n"
+                                "line_23\n"
+                                "line_24\n"
+                                "line_25\n"
+                                "line_26\n"
+                                "line_27\n"
+                                "line_28\n"
+                                "line_29\n"
+                                "line_30\n",
+                        /* File 2 */
+                                "line_1a\n"
+                                "line_2a\n"
+                                "line_3a\n"
+                                "line_1\n"
+                                "line_2\n"
+                                "line_3\n"
+                                "line_4\n"
+                                "line_5a\n"
+                                "line_6b\n"
+                                "line_7c\n"
+                                "line_8\n"
+                                "line_9\n"
+                                "line_10\n"
+                                "line_11a\n"
+                                "line_11b\n"
+                                "line_11c\n"
+                                "line_12\n"
+                                "line_13\n"
+                                "line_14\n"
+                                "line_15\n"
+                                "line_16\n"
+                                "line_17\n"
+                                "line_18\n"
+                                "line_19a\n"
+                                "line_19b\n"
+                                "line_19c\n"
+                                "line_20\n"
+                                "line_21\n"
+                                "line_22\n"
+                                "line_23\n"
+                                "line_24\n"
+                                "line_25\n"
+                                "line_26\n"
+                                "line_27\n"
+                                "line_27a\n",
+                        /* Expected */
+                        "--- issue-3362-1-v1" APR_EOL_STR
+                        "+++ issue-3362-2-v1" APR_EOL_STR
+                        "@@ -1,14 +1,19 @@" APR_EOL_STR
+                        "+line_1a\n"
+                        "+line_2a\n"
+                        "+line_3a\n"
+                        " line_1\n" /* 1.7 mem diff: line missing */
+                        " line_2\n"
+                        " line_3\n"
+                        " line_4\n"
+                        "-line_5\n"
+                        "-line_6\n"
+                        "-line_7\n"
+                        "+line_5a\n"
+                        "+line_6b\n"
+                        "+line_7c\n"
+                        " line_8\n"
+                        " line_9\n"
+                        " line_10\n"
+                        "-line_11\n"
+                        "+line_11a\n"
+                        "+line_11b\n"
+                        "+line_11c\n"
+                        " line_12\n"
+                        " line_13\n"
+                        " line_14\n" /* 1.7 mem diff: line missing */
+                        "@@ -16,7 +21,9 @@" APR_EOL_STR
+                        " line_16\n"
+                        " line_17\n"
+                        " line_18\n"
+                        "-line_19\n"
+                        "+line_19a\n"
+                        "+line_19b\n"
+                        "+line_19c\n"
+                        " line_20\n"
+                        " line_21\n"
+                        " line_22\n"
+                        "@@ -25,6 +32,4 @@" APR_EOL_STR
+                        " line_25\n"
+                        " line_26\n"
+                        " line_27\n"
+                        "-line_28\n"
+                        "-line_29\n"
+                        "-line_30\n"
+                        "+line_27a\n",
+                        diff_opts, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+two_way_issue_3362_v2(apr_pool_t *pool)
+{
+  svn_diff_file_options_t *diff_opts = svn_diff_file_options_create(pool);
+
+  SVN_ERR(two_way_diff("issue-3362-1-v2",
+                       "issue-3362-2-v2",
+                        /* File 1 */
+                                "line_1\n"
+                                "line_2\n"
+                                "line_3\n"
+                                "line_4\n"
+                                "line_5\n"
+                                "line_6\n"
+                                "line_7\n"
+                                "line_8\n"
+                                "line_9\n"
+                                "line_10\n"
+                                "line_11\n"
+                                "line_12\n"
+                                "line_13\n"
+                                "line_14\n"
+                                "line_15\n"
+                                "line_16\n"
+                                "line_17\n"
+                                "line_18\n"
+                                "line_19\n"
+                                "line_20\n"
+                                "line_21\n"
+                                "line_22\n"
+                                "line_23\n"
+                                "line_24\n"
+                                "line_25\n"
+                                "line_26\n"
+                                "line_27\n"
+                                "line_28\n"
+                                "line_29\n"
+                                "line_30\n",
+                        /* File 2 */
+                                "line_1a\n"
+                                "line_1b\n"
+                                "line_1c\n"
+                                "line_1\n"
+                                "line_2\n"
+                                "line_3\n"
+                                "line_4\n"
+                                "line_5a\n"
+                                "line_5b\n"
+                                "line_5c\n"
+                                "line_6\n"
+                                "line_7\n"
+                                "line_8\n"
+                                "line_9\n"
+                                "line_10\n"
+                                "line_11a\n"
+                                "line_11b\n"
+                                "line_11c\n"
+                                "line_12\n"
+                                "line_13\n"
+                                "line_14\n"
+                                "line_15\n"
+                                "line_16\n"
+                                "line_17\n"
+                                "line_18\n"
+                                "line_19a\n"
+                                "line_19b\n"
+                                "line_19c\n"
+                                "line_20\n"
+                                "line_21\n"
+                                "line_22\n"
+                                "line_23\n"
+                                "line_24\n"
+                                "line_25\n"
+                                "line_26\n"
+                                "line_27a\n"
+                                "line_27b\n"
+                                "line_27c\n"
+                                "line_28\n"
+                                "line_29\n"
+                                "line_30\n",
+                        /* Expected */
+                        "--- issue-3362-1-v2" APR_EOL_STR
+                        "+++ issue-3362-2-v2" APR_EOL_STR
+                        "@@ -1,14 +1,21 @@" APR_EOL_STR
+                        "+line_1a\n"
+                        "+line_1b\n"
+                        "+line_1c\n"
+                        " line_1\n" /* 1.7 mem diff: line missing */
+                        " line_2\n"
+                        " line_3\n"
+                        " line_4\n"
+                        "-line_5\n"
+                        "+line_5a\n"
+                        "+line_5b\n"
+                        "+line_5c\n"
+                        " line_6\n"
+                        " line_7\n"
+                        " line_8\n"
+                        " line_9\n"
+                        " line_10\n"
+                        "-line_11\n"
+                        "+line_11a\n"
+                        "+line_11b\n"
+                        "+line_11c\n"
+                        " line_12\n"
+                        " line_13\n"
+                        " line_14\n" /* 1.7 mem diff: line missing */
+                        "@@ -16,7 +23,9 @@" APR_EOL_STR
+                        " line_16\n"
+                        " line_17\n"
+                        " line_18\n"
+                        "-line_19\n"
+                        "+line_19a\n"
+                        "+line_19b\n"
+                        "+line_19c\n"
+                        " line_20\n"
+                        " line_21\n"
+                        " line_22\n"
+                        "@@ -24,7 +33,9 @@" APR_EOL_STR
+                        " line_24\n"
+                        " line_25\n"
+                        " line_26\n"
+                        "-line_27\n"
+                        "+line_27a\n"
+                        "+line_27b\n"
+                        "+line_27c\n"
+                        " line_28\n"
+                        " line_29\n"
+                        " line_30\n",
+                        diff_opts, pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* ========================================================================== */
 
 struct svn_test_descriptor_t test_funcs[] =
@@ -2652,5 +2906,9 @@ struct svn_test_descriptor_t test_funcs[
                    "identical suffix starts at the boundary of a chunk"),
     SVN_TEST_PASS2(test_token_compare,
                    "compare tokes at the chunk boundary"),
+    SVN_TEST_PASS2(two_way_issue_3362_v1,
+                   "2-way issue #3362 test v1"),
+    SVN_TEST_PASS2(two_way_issue_3362_v2,
+                   "2-way issue #3362 test v2"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/windows-build-update/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/windows-build-update/subversion/tests/libsvn_repos/repos-test.c?rev=1438999&r1=1438998&r2=1438999&view=diff
==============================================================================
--- subversion/branches/windows-build-update/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/branches/windows-build-update/subversion/tests/libsvn_repos/repos-test.c Sun Jan 27 00:01:57 2013
@@ -1157,7 +1157,7 @@ authz_get_handle(svn_authz_t **authz_p, 
       SVN_ERR_W(svn_stream_puts(stream, authz_contents),
                 "Writing authz contents to stream");
 
-      SVN_ERR_W(svn_repos_authz_parse(authz_p, stream, pool),
+      SVN_ERR_W(svn_repos_authz_parse(authz_p, stream, NULL, pool),
                 "Parsing the authz contents");
 
       SVN_ERR_W(svn_stream_close(stream),
@@ -1451,24 +1451,25 @@ in_repo_authz(const svn_test_opts_t *opt
 
   /* repos relative URL */
   repos_root = svn_repos_path(repos, pool);
-  SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/authz", TRUE, repos_root,
-                                pool));
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/authz", NULL, TRUE,
+                                repos_root, pool));
   SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
 
   /* absolute file URL, repos_root is NULL to validate the contract that it
    * is not needed except when a repos relative URL is passed. */
   SVN_ERR(svn_uri_get_file_url_from_dirent(&repos_url, repos_root, pool));
   authz_url = apr_pstrcat(pool, repos_url, "/authz", (char *)NULL);
-  SVN_ERR(svn_repos_authz_read2(&authz_cfg, authz_url, TRUE, NULL, pool));
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, authz_url, NULL, TRUE,
+                                NULL, pool));
   SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
   
   /* Non-existant path in the repo with must_exist set to FALSE */ 
-  SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/A/authz", FALSE, repos_root,
-                                pool));
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/A/authz", NULL, FALSE,
+                                repos_root, pool));
 
   /* Non-existant path in the repo with must_exist set to TRUE */ 
-  err = svn_repos_authz_read2(&authz_cfg, "^/A/authz", TRUE, repos_root,
-                              pool);
+  err = svn_repos_authz_read2(&authz_cfg, "^/A/authz", NULL, TRUE,
+                              repos_root, pool);
   if (!err || err->apr_err != SVN_ERR_AUTHZ_INVALID_CONFIG)
     return svn_error_createf(SVN_ERR_TEST_FAILED, err,
                              "Got %s error instead of expected "
@@ -1478,7 +1479,7 @@ in_repo_authz(const svn_test_opts_t *opt
 
   /* http:// URL which is unsupported */
   err = svn_repos_authz_read2(&authz_cfg, "http://example.com/repo/authz",
-                              TRUE, repos_root, pool);
+                              NULL, TRUE, repos_root, pool);
   if (!err || err->apr_err != SVN_ERR_RA_ILLEGAL_URL)
     return svn_error_createf(SVN_ERR_TEST_FAILED, err,
                              "Got %s error instead of expected "
@@ -1488,6 +1489,160 @@ in_repo_authz(const svn_test_opts_t *opt
 
   /* svn:// URL which is unsupported */
   err = svn_repos_authz_read2(&authz_cfg, "svn://example.com/repo/authz",
+                              NULL, TRUE, repos_root, pool);
+  if (!err || err->apr_err != SVN_ERR_RA_ILLEGAL_URL)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_RA_ILLEGAL_URL",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+
+  return SVN_NO_ERROR;
+}
+
+
+/* Test in-repo authz with global groups. */
+static svn_error_t *
+in_repo_groups_authz(const svn_test_opts_t *opts,
+                     apr_pool_t *pool)
+{
+  svn_repos_t *repos;
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root;
+  svn_revnum_t youngest_rev;
+  svn_authz_t *authz_cfg;
+  const char *groups_contents;
+  const char *authz_contents;
+  const char *repos_root;
+  const char *repos_url;
+  const char *groups_url;
+  const char *authz_url;
+  svn_error_t *err;
+  struct check_access_tests test_set[] = {
+    /* reads */
+    { "/A", NULL, NULL, svn_authz_read, FALSE },
+    { "/A", NULL, "plato", svn_authz_read, TRUE },
+    { "/A", NULL, "socrates", svn_authz_read, TRUE },
+    { "/A", NULL, "solon", svn_authz_read, TRUE },
+    { "/A", NULL, "ephialtes", svn_authz_read, TRUE },
+    /* writes */
+    { "/A", NULL, NULL, svn_authz_write, FALSE },
+    { "/A", NULL, "plato", svn_authz_write, FALSE },
+    { "/A", NULL, "socrates", svn_authz_write, FALSE },
+    { "/A", NULL, "solon", svn_authz_write, TRUE },
+    { "/A", NULL, "ephialtes", svn_authz_write, TRUE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Test plan:
+   * 1. Create an authz file, a global groups file and an empty authz file,
+   *    put all these files in the repository.  The empty authz file is
+   *    required to perform the non-existent path checks (4-7) --
+   *    otherwise we would get the authz validation error due to undefined
+   *    groups.
+   * 2. Verify that the groups file can be read with an relative URL.
+   * 3. Verify that the groups file can be read with an absolute URL.
+   * 4. Verify that non-existent groups file path does not error out when
+   *    must_exist is FALSE.
+   * 5. Same as (4), but when both authz and groups file paths do
+   *    not exist.
+   * 6. Verify that non-existent path for the groups file does error out when
+   *    must_exist is TRUE.
+   * 7. Verify that an http:// URL produces an error.
+   * 8. Verify that an svn:// URL produces an error.
+   */
+
+  /* What we'll put in the authz and groups files, it's simple since
+   * we're not testing the parsing, just that we got what we expected. */
+
+  groups_contents =
+    "[groups]"                                                               NL
+    "philosophers = plato, socrates"                                         NL
+    "senate = solon, ephialtes"                                              NL
+    ""                                                                       NL;
+
+  authz_contents =
+    "[/]"                                                                    NL
+    "@senate = rw"                                                           NL
+    "@philosophers = r"                                                      NL
+    ""                                                                       NL;
+
+  /* Create a filesystem and repository. */
+  SVN_ERR(svn_test__create_repos(&repos,
+                                 "test-repo-in-repo-global-groups-authz",
+                                 opts, pool));
+  fs = svn_repos_fs(repos);
+
+  /* Commit the authz, empty authz and groups files to the repo. */
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, 0, pool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
+  SVN_ERR(svn_fs_make_file(txn_root, "groups", pool));
+  SVN_ERR(svn_fs_make_file(txn_root, "authz", pool));
+  SVN_ERR(svn_fs_make_file(txn_root, "empty-authz", pool));
+  SVN_ERR(svn_test__set_file_contents(txn_root, "groups",
+                                      groups_contents, pool));
+  SVN_ERR(svn_test__set_file_contents(txn_root, "authz",
+                                      authz_contents, pool));
+  SVN_ERR(svn_test__set_file_contents(txn_root, "empty-authz", "", pool));
+  SVN_ERR(svn_repos_fs_commit_txn(NULL, repos, &youngest_rev, txn, pool));
+  SVN_TEST_ASSERT(SVN_IS_VALID_REVNUM(youngest_rev));
+
+  /* repos relative URLs */
+  repos_root = svn_repos_path(repos, pool);
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/authz", "^/groups",
+                                TRUE, repos_root, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+  /* absolute file URLs, repos_root is NULL to validate the contract that it
+   * is not needed except when a repos relative URLs are passed. */
+  SVN_ERR(svn_uri_get_file_url_from_dirent(&repos_url, repos_root, pool));
+  authz_url = apr_pstrcat(pool, repos_url, "/authz", (char *)NULL);
+  groups_url = apr_pstrcat(pool, repos_url, "/groups", (char *)NULL);
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, authz_url, groups_url,
+                                TRUE, NULL, pool));
+  SVN_ERR(authz_check_access(authz_cfg, test_set, pool));
+
+  /* Non-existent path for the groups file with must_exist
+   * set to TRUE */
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/empty-authz",
+                                "^/A/groups", FALSE,
+                                repos_root, pool));
+
+  /* Non-existent paths for both the authz and the groups files
+   * with must_exist set to TRUE */
+  SVN_ERR(svn_repos_authz_read2(&authz_cfg, "^/A/authz",
+                                "^/A/groups", FALSE,
+                                repos_root, pool));
+
+  /* Non-existent path for the groups file with must_exist
+   * set to TRUE */
+  err = svn_repos_authz_read2(&authz_cfg, "^/empty-authz",
+                              "^/A/groups", TRUE,
+                              repos_root, pool);
+  if (!err || err->apr_err != SVN_ERR_AUTHZ_INVALID_CONFIG)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_AUTHZ_INVALID_CONFIG",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+  /* http:// URL which is unsupported */
+  err = svn_repos_authz_read2(&authz_cfg, "^/empty-authz",
+                              "http://example.com/repo/groups",
+                              TRUE, repos_root, pool);
+  if (!err || err->apr_err != SVN_ERR_RA_ILLEGAL_URL)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_RA_ILLEGAL_URL",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+  /* svn:// URL which is unsupported */
+  err = svn_repos_authz_read2(&authz_cfg, "^/empty-authz",
+                              "http://example.com/repo/groups",
                               TRUE, repos_root, pool);
   if (!err || err->apr_err != SVN_ERR_RA_ILLEGAL_URL)
     return svn_error_createf(SVN_ERR_TEST_FAILED, err,
@@ -1500,6 +1655,249 @@ in_repo_authz(const svn_test_opts_t *opt
   return SVN_NO_ERROR;
 }
 
+
+/* Helper for the groups_authz test.  Set *AUTHZ_P to a representation of
+   AUTHZ_CONTENTS in conjuction with GROUPS_CONTENTS, using POOL for
+   temporary allocation.  If DISK is TRUE then write the contents to
+   temporary files and use svn_repos_authz_read2() to get the data if FALSE
+   write the data to a buffered stream and use svn_repos_authz_parse(). */
+static svn_error_t *
+authz_groups_get_handle(svn_authz_t **authz_p,
+                        const char *authz_contents,
+                        const char *groups_contents,
+                        svn_boolean_t disk,
+                        apr_pool_t *pool)
+{
+  if (disk)
+    {
+      const char *authz_file_path;
+      const char *groups_file_path;
+
+      /* Create temporary files. */
+      SVN_ERR_W(svn_io_write_unique(&authz_file_path, NULL,
+                                    authz_contents,
+                                    strlen(authz_contents),
+                                    svn_io_file_del_on_pool_cleanup, pool),
+                "Writing temporary authz file");
+      SVN_ERR_W(svn_io_write_unique(&groups_file_path, NULL,
+                                    groups_contents,
+                                    strlen(groups_contents),
+                                    svn_io_file_del_on_pool_cleanup, pool),
+                "Writing temporary groups file");
+
+      /* Read the authz configuration back and start testing. */
+      SVN_ERR_W(svn_repos_authz_read2(authz_p, authz_file_path,
+                                      groups_file_path, TRUE, NULL, pool),
+                "Opening test authz and groups files");
+
+      /* Done with the files. */
+      SVN_ERR_W(svn_io_remove_file(authz_file_path, pool),
+                "Removing test authz file");
+      SVN_ERR_W(svn_io_remove_file(groups_file_path, pool),
+                "Removing test groups file");
+    }
+  else
+    {
+      svn_stream_t *stream;
+      svn_stream_t *groups_stream;
+
+      /* Create the streams. */
+      stream = svn_stream_buffered(pool);
+      groups_stream = svn_stream_buffered(pool);
+
+      SVN_ERR_W(svn_stream_puts(stream, authz_contents),
+                "Writing authz contents to stream");
+      SVN_ERR_W(svn_stream_puts(groups_stream, groups_contents),
+                "Writing groups contents to stream");
+
+      /* Read the authz configuration from the streams and start testing. */
+      SVN_ERR_W(svn_repos_authz_parse(authz_p, stream, groups_stream, pool),
+                "Parsing the authz and groups contents");
+
+      /* Done with the streams. */
+      SVN_ERR_W(svn_stream_close(stream),
+                "Closing the authz stream");
+      SVN_ERR_W(svn_stream_close(groups_stream),
+                "Closing the groups stream");
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Test authz with global groups. */
+static svn_error_t *
+groups_authz(const svn_test_opts_t *opts,
+             apr_pool_t *pool)
+{
+  svn_authz_t *authz_cfg;
+  const char *authz_contents;
+  const char *groups_contents;
+  svn_error_t *err;
+
+  struct check_access_tests test_set1[] = {
+    /* reads */
+    { "/A", "greek", NULL, svn_authz_read, FALSE },
+    { "/A", "greek", "plato", svn_authz_read, TRUE },
+    { "/A", "greek", "demetrius", svn_authz_read, TRUE },
+    { "/A", "greek", "galenos", svn_authz_read, TRUE },
+    { "/A", "greek", "pamphilos", svn_authz_read, FALSE },
+    /* writes */
+    { "/A", "greek", NULL, svn_authz_write, FALSE },
+    { "/A", "greek", "plato", svn_authz_write, TRUE },
+    { "/A", "greek", "demetrius", svn_authz_write, FALSE },
+    { "/A", "greek", "galenos", svn_authz_write, FALSE },
+    { "/A", "greek", "pamphilos", svn_authz_write, FALSE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  struct check_access_tests test_set2[] = {
+    /* reads */
+    { "/A", "greek", NULL, svn_authz_read, FALSE },
+    { "/A", "greek", "socrates", svn_authz_read, FALSE },
+    { "/B", "greek", NULL, svn_authz_read, FALSE},
+    { "/B", "greek", "socrates", svn_authz_read, TRUE },
+    /* writes */
+    { "/A", "greek", NULL, svn_authz_write, FALSE },
+    { "/A", "greek", "socrates", svn_authz_write, FALSE },
+    { "/B", "greek", NULL, svn_authz_write, FALSE},
+    { "/B", "greek", "socrates", svn_authz_write, TRUE },
+    /* Sentinel */
+    { NULL, NULL, NULL, svn_authz_none, FALSE }
+  };
+
+  /* Test plan:
+   * 1. Ensure that a simple setup with global groups and access rights in
+   *    two separate files works as expected.
+   * 2. Verify that access rights written in the global groups file are
+   *    discarded and affect nothing in authorization terms.
+   * 3. Verify that local groups in the authz file are prohibited in
+   *    conjuction with global groups (and that a configuration error is
+   *    reported in this scenario).
+   * 4. Ensure that group cycles in the global groups file are reported.
+   *
+   * All checks are performed twice -- for the configurations stored on disk
+   * and in memory.  See authz_groups_get_handle.
+   */
+
+  groups_contents =
+    "[groups]"                                                               NL
+    "slaves = pamphilos,@gladiators"                                         NL
+    "gladiators = demetrius,galenos"                                         NL
+    "philosophers = plato"                                                   NL
+    ""                                                                       NL;
+
+  authz_contents =
+    "[greek:/A]"                                                             NL
+    "@slaves = "                                                             NL
+    "@gladiators = r"                                                        NL
+    "@philosophers = rw"                                                     NL
+    ""                                                                       NL;
+
+  SVN_ERR(authz_groups_get_handle(&authz_cfg, authz_contents,
+                                  groups_contents, TRUE, pool));
+
+  SVN_ERR(authz_check_access(authz_cfg, test_set1, pool));
+
+  SVN_ERR(authz_groups_get_handle(&authz_cfg, authz_contents,
+                                  groups_contents, FALSE, pool));
+
+  SVN_ERR(authz_check_access(authz_cfg, test_set1, pool));
+
+  /* Access rights in the global groups file are discarded. */
+  groups_contents =
+    "[groups]"                                                               NL
+    "philosophers = socrates"                                                NL
+    ""                                                                       NL
+    "[greek:/A]"                                                             NL
+    "@philosophers = rw"                                                     NL
+    ""                                                                       NL;
+
+  authz_contents =
+    "[greek:/B]"                                                             NL
+    "@philosophers = rw"                                                     NL
+    ""                                                                       NL;
+
+  SVN_ERR(authz_groups_get_handle(&authz_cfg, authz_contents,
+                                  groups_contents, TRUE, pool));
+
+  SVN_ERR(authz_check_access(authz_cfg, test_set2, pool));
+
+  SVN_ERR(authz_groups_get_handle(&authz_cfg, authz_contents,
+                                  groups_contents, FALSE, pool));
+
+  SVN_ERR(authz_check_access(authz_cfg, test_set2, pool));
+
+  /* Local groups cannot be used in conjuction with global groups. */
+  groups_contents =
+    "[groups]"                                                               NL
+    "slaves = maximus"                                                       NL
+    ""                                                                       NL;
+
+  authz_contents =
+    "[greek:/A]"                                                             NL
+    "@slaves = "                                                             NL
+    "@kings = rw"                                                            NL
+    ""                                                                       NL
+    "[groups]"                                                               NL
+    /* That's an epic story of the slave who tried to become a king. */
+    "kings = maximus"                                                        NL
+    ""                                                                       NL;
+
+  err = authz_groups_get_handle(&authz_cfg, authz_contents,
+                                groups_contents, TRUE, pool);
+
+  if (!err || err->apr_err != SVN_ERR_AUTHZ_INVALID_CONFIG)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_AUTHZ_INVALID_CONFIG",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+  err = authz_groups_get_handle(&authz_cfg, authz_contents,
+                                groups_contents, FALSE, pool);
+
+  if (!err || err->apr_err != SVN_ERR_AUTHZ_INVALID_CONFIG)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_AUTHZ_INVALID_CONFIG",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+  /* Ensure that group cycles are reported. */
+  groups_contents =
+    "[groups]"                                                               NL
+    "slaves = cooks,scribes,@gladiators"                                     NL
+    "gladiators = equites,thraces,@slaves"                                   NL
+    ""                                                                       NL;
+
+  authz_contents =
+    "[greek:/A]"                                                             NL
+    "@slaves = r"                                                            NL
+    ""                                                                       NL;
+
+  err = authz_groups_get_handle(&authz_cfg, authz_contents,
+                                groups_contents, TRUE, pool);
+
+  if (!err || err->apr_err != SVN_ERR_AUTHZ_INVALID_CONFIG)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_AUTHZ_INVALID_CONFIG",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+  err = authz_groups_get_handle(&authz_cfg, authz_contents,
+                                groups_contents, FALSE, pool);
+
+  if (!err || err->apr_err != SVN_ERR_AUTHZ_INVALID_CONFIG)
+    return svn_error_createf(SVN_ERR_TEST_FAILED, err,
+                             "Got %s error instead of expected "
+                             "SVN_ERR_AUTHZ_INVALID_CONFIG",
+                             err ? "unexpected" : "no");
+  svn_error_clear(err);
+
+  return SVN_NO_ERROR;
+}
 
 /* Callback for the commit editor tests that relays requests to
    authz. */
@@ -2423,7 +2821,7 @@ prop_validation(const svn_test_opts_t *o
 {
   svn_error_t *err;
   svn_repos_t *repos;
-  const char non_utf8_string[5] = { 'a', (char)0xff, 'b', '\n', 0 };
+  const char non_utf8_string[5] = { 'a', '\xff', 'b', '\n', 0 };
   const char *non_lf_string = "a\r\nb\n\rc\rd\n";
   apr_pool_t *subpool = svn_pool_create(pool);
 
@@ -2723,6 +3121,36 @@ issue_4060(const svn_test_opts_t *opts,
   return SVN_NO_ERROR;
 }
 
+/* Test svn_repos_delete(). */
+static svn_error_t *
+test_delete_repos(const svn_test_opts_t *opts,
+                  apr_pool_t *pool)
+{
+  const char *path;
+  svn_node_kind_t kind;
+
+  /* We have to use a subpool to close the svn_repos_t before calling
+     svn_repos_delete. */
+  {
+    svn_repos_t *repos;
+    apr_pool_t *subpool = svn_pool_create(pool);
+    SVN_ERR(svn_test__create_repos(&repos, "test-repo-delete-repos", opts,
+                                   subpool));
+    path = svn_repos_path(repos, pool);
+    svn_pool_destroy(subpool);
+  }
+
+  SVN_ERR(svn_io_check_path(path, &kind, pool));
+  SVN_TEST_ASSERT(kind != svn_node_none);
+  SVN_ERR(svn_repos_delete(path, pool));
+  SVN_ERR(svn_io_check_path(path, &kind, pool));
+  SVN_TEST_ASSERT(kind == svn_node_none);
+
+  /* Recreate dir so that test cleanup doesn't fail. */
+  SVN_ERR(svn_io_dir_make(path, APR_OS_DEFAULT, pool));
+
+  return SVN_NO_ERROR;
+}
 
 /* The test table.  */
 
@@ -2745,6 +3173,10 @@ struct svn_test_descriptor_t test_funcs[
                    "test authz access control"),
     SVN_TEST_OPTS_PASS(in_repo_authz,
                        "test authz stored in the repo"),
+    SVN_TEST_OPTS_PASS(in_repo_groups_authz,
+                       "test authz and global groups stored in the repo"),
+    SVN_TEST_OPTS_PASS(groups_authz,
+                       "test authz with global groups"),
     SVN_TEST_OPTS_PASS(commit_editor_authz,
                        "test authz in the commit editor"),
     SVN_TEST_OPTS_PASS(commit_continue_txn,
@@ -2761,5 +3193,7 @@ struct svn_test_descriptor_t test_funcs[
                        "test svn_repos_get_file_revsN"),
     SVN_TEST_OPTS_PASS(issue_4060,
                        "test issue 4060"),
+    SVN_TEST_OPTS_PASS(test_delete_repos,
+                       "test svn_repos_delete"),
     SVN_TEST_NULL
   };