You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by da...@apache.org on 2010/03/30 22:58:01 UTC

svn commit: r929279 [20/20] - in /subversion/branches/svn-patch-improvements: ./ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/emacs/ notes/feedback/ notes/meetings/ notes/wc-ng/ subversion/ subversion/bindings/javahl...

Modified: subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svnadmin_tests.py?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svnadmin_tests.py Tue Mar 30 20:57:53 2010
@@ -33,6 +33,7 @@ import sys
 import svntest
 from svntest.verify import SVNExpectedStdout, SVNExpectedStderr
 from svntest.verify import SVNUnexpectedStderr
+from svntest.main import SVN_PROP_MERGEINFO
 
 # (abbreviation)
 Skip = svntest.testcase.Skip
@@ -812,22 +813,22 @@ def reflect_dropped_renumbered_revs(sbox
                              '/toplevel')
 
   # Verify the svn:mergeinfo properties
-  svntest.actions.run_and_verify_svn(None, ["/trunk:1-4\n"],
+  svntest.actions.run_and_verify_svn(None, ["/trunk:2-4\n"],
                                      [], 'propget', 'svn:mergeinfo',
                                      sbox.repo_url + '/branch2')
   svntest.actions.run_and_verify_svn(None, ["/branch1:5-9\n"],
                                      [], 'propget', 'svn:mergeinfo',
                                      sbox.repo_url + '/trunk')
-  svntest.actions.run_and_verify_svn(None, ["/toplevel/trunk:1-13\n"],
+  svntest.actions.run_and_verify_svn(None, ["/toplevel/trunk:11-13\n"],
                                      [], 'propget', 'svn:mergeinfo',
                                      sbox.repo_url + '/toplevel/branch2')
   svntest.actions.run_and_verify_svn(None, ["/toplevel/branch1:14-18\n"],
                                      [], 'propget', 'svn:mergeinfo',
                                      sbox.repo_url + '/toplevel/trunk')
-  svntest.actions.run_and_verify_svn(None, ["/toplevel/trunk:1-12\n"],
+  svntest.actions.run_and_verify_svn(None, ["/toplevel/trunk:11-12\n"],
                                      [], 'propget', 'svn:mergeinfo',
                                      sbox.repo_url + '/toplevel/branch1')
-  svntest.actions.run_and_verify_svn(None, ["/trunk:1-3\n"],
+  svntest.actions.run_and_verify_svn(None, ["/trunk:2-3\n"],
                                      [], 'propget', 'svn:mergeinfo',
                                      sbox.repo_url + '/branch1')
 
@@ -958,6 +959,152 @@ def verify_with_invalid_revprops(sbox):
     ".*Malformed file"):
     raise svntest.Failure
 
+#----------------------------------------------------------------------
+# More testing for issue #3020 'Reflect dropped/renumbered revisions in
+# svn:mergeinfo data during svnadmin load'
+#
+# Specifically, test that loading a partial dump file filters out
+# mergeinfo that refers to revisions that are older than the oldest
+# loaded revisions -- See
+# http://subversion.tigris.org/issues/show_bug.cgi?id=3020#desc10.
+def drop_mergeinfo_outside_of_dump_stream(sbox):
+  "filter mergeinfo revs outside of dump stream"
+
+  test_create(sbox)
+
+  # Load a partial dump into an existing repository.
+  #
+  # Picture == 1k words:
+  #
+  # The existing repos loaded from skeleton_repos.dump looks like this:
+  #
+  # Projects/       (Added r1)
+  #   README        (Added r2)
+  #   Project-X     (Added r3)
+  #   Project-Y     (Added r4)
+  #   Project-Z     (Added r5)
+  #   docs/         (Added r6)
+  #     README      (Added r6)
+  #
+  # The dump file 'mergeinfo_included_partial.dump' is a dump of r6:HEAD of
+  # the following repos:
+  #                       __________________________________________
+  #                      |                                         |
+  #                      |             ____________________________|_____
+  #                      |            |                            |     |
+  # trunk---r2---r3-----r5---r6-------r8---r9--------------->      |     |
+  #   r1             |        |     |       |                      |     |
+  # intial           |        |     |       |______                |     |
+  # import         copy       |   copy             |            merge   merge
+  #                  |        |     |            merge           (r5)   (r8)
+  #                  |        |     |            (r9)              |     |
+  #                  |        |     |              |               |     |
+  #                  |        |     V              V               |     |
+  #                  |        | branches/B2-------r11---r12---->   |     |
+  #                  |        |     r7              |____|         |     |
+  #                  |        |                        |           |     |
+  #                  |      merge                      |___        |     |
+  #                  |      (r6)                           |       |     |
+  #                  |        |_________________           |       |     |
+  #                  |                          |        merge     |     |
+  #                  |                          |      (r11-12)    |     |
+  #                  |                          |          |       |     |
+  #                  V                          V          V       |     |
+  #              branches/B1-------------------r10--------r13-->   |     |
+  #                  r4                                            |     |
+  #                   |                                            V     V
+  #                  branches/B1/B/E------------------------------r14---r15->
+  #                  
+  #
+  # The mergeinfo on the complete repos in the preceeding repos looks like:
+  #
+  #   Properties on 'branches/B1':
+  #     svn:mergeinfo
+  #       /branches/B2:11-12
+  #       /trunk:6,9
+  #   Properties on 'branches/B1/B/E':
+  #     svn:mergeinfo
+  #       /branches/B2/B/E:11-12
+  #       /trunk/B/E:5-6,8-9
+  #   Properties on 'branches/B2':
+  #     svn:mergeinfo
+  #       /trunk:9
+  #
+  # If we were to load the dump of r6:HEAD into an empty repository, we'd
+  # expect any references to revisions <r6 to be removed entirely (since
+  # that history no longer exists) and the the remaining mergeinfo should
+  # have its revisions offset by -5.  The resulting mergeinfo should look
+  # like this:
+  #
+  #   Properties on 'branches/B1':
+  #     svn:mergeinfo
+  #       /branches/B2:6-7
+  #       /trunk:1,4
+  #   Properties on 'branches/B1/B/E':
+  #     svn:mergeinfo
+  #       /branches/B2/B/E:6-7
+  #       /trunk/B/E:1,3-4
+  #   Properties on 'branches/B2':
+  #     svn:mergeinfo
+  #       /trunk:4
+  #
+  # But here we will load it into the existing skeleton repository in the
+  # Projects/Project-X directory.  Since we are loading the dump into a
+  # subtree, all the merge sources should be prefixed with the path to
+  # that subtree, i.e. 'Projects/Project-X', compared to the mergeinfo above.
+  # In addition, since the skeleton repos already has 6 revisions, we expect
+  # all the remaining revisions to be offset +6 from the above.  That should
+  # result in this mergeinfo:
+  #
+  #   Properties on 'Projects/Project-X/branches/B1':
+  #     svn:mergeinfo
+  #       /Projects/Project-X/branches/B2:12-13
+  #       /Projects/Project-X/trunk:7,10
+  #   Properties on 'Projects/Project-X/branches/B1/B/E':
+  #     svn:mergeinfo
+  #       /Projects/Project-X/branches/B2/B/E:12-13
+  #       /Projects/Project-X/trunk/B/E:7,9-10
+  #   Properties on 'Projects/Project-X/branches/B2':
+  #     svn:mergeinfo
+  #       /Projects/Project-X/trunk:10
+
+  # Load the skeleton dump:
+  dumpfile1 = svntest.main.file_read(
+    os.path.join(os.path.dirname(sys.argv[0]),
+                 'svnadmin_tests_data',
+                 'skeleton_repos.dump'))
+  load_and_verify_dumpstream(sbox, [], [], None, dumpfile1, '--ignore-uuid')
+
+  # Load the partial repository with mergeinfo dump:
+  dumpfile2 = svntest.main.file_read(
+    os.path.join(os.path.dirname(sys.argv[0]),
+                 'svnadmin_tests_data',
+                 'mergeinfo_included_partial.dump'))
+  load_and_verify_dumpstream(sbox, [], [], None, dumpfile2, '--ignore-uuid',
+                             '--parent-dir', '/Projects/Project-X')
+
+  # Check the resulting mergeinfo.
+  #
+  # TODO: Use pg -vR, which would make the expected output easier on the eyes.
+  #       Not using it because pg -vR on windows is outputting <CR><CR><LF>
+  #       after the first line of multiline mergeinfo, which breaks the
+  #       comparison, e.g.:
+  #
+  #   Properties on 'Projects/Project-X/branches/B1/B/E':<CR><LF>
+  #     svn:mergeinfo<CR><LF>
+  #       /Projects/Project-X/branches/B2:12-13<CR><CR><LF>
+  #                                            ^^^
+  #       /Projects/Project-X/trunk:7,10<CR><LF>
+  url = sbox.repo_url + '/Projects/Project-X/branches/'
+  expected_output = svntest.verify.UnorderedOutput([
+    url + "B1 - /Projects/Project-X/branches/B2:12-13\n",
+    "/Projects/Project-X/trunk:7,10\n",
+    url + "B2 - /Projects/Project-X/trunk:10\n",
+    url + "B1/B/E - /Projects/Project-X/branches/B2/B/E:12-13\n",
+    "/Projects/Project-X/trunk/B/E:7,9-10\n"])
+  svntest.actions.run_and_verify_svn(None, expected_output, [],
+                                     'propget', 'svn:mergeinfo', '-R',
+                                     sbox.repo_url)
 
 ########################################################################
 # Run the tests
@@ -986,6 +1133,7 @@ test_list = [ None,
               create_in_repo_subdir,
               SkipUnless(verify_with_invalid_revprops,
                          svntest.main.is_fs_type_fsfs),
+              drop_mergeinfo_outside_of_dump_stream,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svntest/actions.py?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svntest/actions.py Tue Mar 30 20:57:53 2010
@@ -213,8 +213,12 @@ def run_and_verify_svn(message, expected
   be 0 if no output is expected on stderr, and 1 otherwise."""
 
   expected_exit = 0
-  if expected_stderr is not None and expected_stderr != []:
-    expected_exit = 1
+  if expected_stderr is not None:
+    if isinstance(expected_stderr, verify.ExpectedOutput):
+      if not expected_stderr.matches([]):
+        expected_exit = 1
+    elif expected_stderr != []:
+      expected_exit = 1
   return run_and_verify_svn2(message, expected_stdout, expected_stderr,
                              expected_exit, *varargs)
 
@@ -248,7 +252,10 @@ def run_and_verify_svn2(message, expecte
     raise verify.SVNIncorrectDatatype("expected_stderr must not be None")
 
   want_err = None
-  if expected_stderr != []:
+  if isinstance(expected_stderr, verify.ExpectedOutput):
+    if not expected_stderr.matches([]):
+      want_err = True
+  elif expected_stderr != []:
     want_err = True
 
   exit_code, out, err = main.run_svn(want_err, *varargs)
@@ -2172,13 +2179,13 @@ class DeepTreesTestCase:
     expected_info = {
       'F/alpha' : {
         'Revision' : '3',
-        'Tree conflict' : 
+        'Tree conflict' :
           '^local delete, incoming edit upon update'
           + ' Source  left: .file.*/F/alpha@2'
           + ' Source right: .file.*/F/alpha@3$',
       },
       'DF/D1' : {
-        'Tree conflict' : 
+        'Tree conflict' :
           '^local delete, incoming edit upon update'
           + ' Source  left: .dir.*/DF/D1@2'
           + ' Source right: .dir.*/DF/D1@3$',

Modified: subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svntest/verify.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svntest/verify.py?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svntest/verify.py (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/cmdline/svntest/verify.py Tue Mar 30 20:57:53 2010
@@ -79,7 +79,7 @@ def createExpectedOutput(expected, outpu
     expected = ExpectedOutput(expected)
   elif isinstance(expected, str):
     expected = RegexOutput(expected, match_all)
-  elif expected == AnyOutput:
+  elif expected is AnyOutput:
     expected = AnyOutput()
   elif expected is not None and not isinstance(expected, ExpectedOutput):
     raise SVNIncorrectDatatype("Unexpected type for '%s' data" % output_type)
@@ -87,6 +87,10 @@ def createExpectedOutput(expected, outpu
 
 class ExpectedOutput:
   """Contains expected output, and performs comparisons."""
+
+  is_regex = False
+  is_unordered = False
+
   def __init__(self, output, match_all=True):
     """Initialize the expected output to OUTPUT which is a string, or a list
     of strings, or None meaning an empty list. If MATCH_ALL is True, the
@@ -96,12 +100,14 @@ class ExpectedOutput:
     strings among the matching ones."""
     self.output = output
     self.match_all = match_all
-    self.is_reg_exp = False
 
   def __str__(self):
     return str(self.output)
 
   def __cmp__(self, other):
+    raise 'badness'
+
+  def matches(self, other):
     """Return whether SELF.output matches OTHER (which may be a list
     of newline-terminated lines, or a single string).  Either value
     may be None."""
@@ -114,77 +120,64 @@ class ExpectedOutput:
     else:
       actual = other
 
-    if isinstance(actual, list):
-      if isinstance(expected, str):
-        expected = [expected]
-      is_match = self.is_equivalent_list(expected, actual)
-    elif isinstance(actual, str):
-      is_match = self.is_equivalent_line(expected, actual)
-    else: # unhandled type
-      is_match = False
+    if not isinstance(actual, list):
+      actual = [actual]
+    if not isinstance(expected, list):
+      expected = [expected]
 
-    if is_match:
-      return 0
-    else:
-      return 1
+    return self.is_equivalent_list(expected, actual)
 
   def is_equivalent_list(self, expected, actual):
     "Return whether EXPECTED and ACTUAL are equivalent."
-    if not self.is_reg_exp:
+    if not self.is_regex:
       if self.match_all:
         # The EXPECTED lines must match the ACTUAL lines, one-to-one, in
         # the same order.
-        if len(expected) != len(actual):
-          return False
-        for i in range(0, len(actual)):
-          if not self.is_equivalent_line(expected[i], actual[i]):
-            return False
-        return True
-      else:
-        # The EXPECTED lines must match a subset of the ACTUAL lines,
-        # one-to-one, in the same order, with zero or more other ACTUAL
-        # lines interspersed among the matching ACTUAL lines.
-        i_expected = 0
-        for actual_line in actual:
-          if self.is_equivalent_line(expected[i_expected], actual_line):
-            i_expected += 1
-            if i_expected == len(expected):
-              return True
-        return False
+        return expected == actual
+
+      # The EXPECTED lines must match a subset of the ACTUAL lines,
+      # one-to-one, in the same order, with zero or more other ACTUAL
+      # lines interspersed among the matching ACTUAL lines.
+      i_expected = 0
+      for actual_line in actual:
+        if expected[i_expected] == actual_line:
+          i_expected += 1
+          if i_expected == len(expected):
+            return True
+      return False
+
+    expected_re = expected[0]
+    # If we want to check that every line matches the regexp
+    # assume they all match and look for any that don't.  If
+    # only one line matching the regexp is enough, assume none
+    # match and look for even one that does.
+    if self.match_all:
+      all_lines_match_re = True
     else:
-      expected_re = expected[0]
-      # If we want to check that every line matches the regexp
-      # assume they all match and look for any that don't.  If
-      # only one line matching the regexp is enough, assume none
-      # match and look for even one that does.
-      if self.match_all:
-        all_lines_match_re = True
-      else:
-        all_lines_match_re = False
+      all_lines_match_re = False
 
-      # If a regex was provided assume that we actually require
-      # some output. Fail if we don't have any.
-      if len(actual) == 0:
-        return False
+    # If a regex was provided assume that we actually require
+    # some output. Fail if we don't have any.
+    if len(actual) == 0:
+      return False
 
-      for i in range(0, len(actual)):
-        if self.match_all:
-          if not self.is_equivalent_line(expected_re, actual[i]):
-            all_lines_match_re = False
-            break
-        else:
-          if self.is_equivalent_line(expected_re, actual[i]):
-            return True
-      return all_lines_match_re
+    for actual_line in actual:
+      if self.match_all:
+        if not re.match(expected_re, actual_line):
+          return False
+      else:
+        # As soon an actual_line matches something, then we're good.
+        if re.match(expected_re, actual_line):
+          return True
 
-  def is_equivalent_line(self, expected, actual):
-    "Return whether EXPECTED and ACTUAL are equal."
-    return expected == actual
+    return all_lines_match_re
 
   def display_differences(self, message, label, actual):
     """Delegate to the display_lines() routine with the appropriate
     args.  MESSAGE is ignored if None."""
-    display_lines(message, label, self.output, actual, False, False)
+    display_lines(message, label, self.output, actual,
+                  self.is_regex, self.is_unordered)
+
 
 class AnyOutput(ExpectedOutput):
   def __init__(self):
@@ -192,86 +185,72 @@ class AnyOutput(ExpectedOutput):
 
   def is_equivalent_list(self, ignored, actual):
     if len(actual) == 0:
-      # Empty text or empty list -- either way, no output!
-      return False
-    elif isinstance(actual, list):
-      for line in actual:
-        if self.is_equivalent_line(None, line):
-          return True
+      # No actual output. No match.
       return False
-    else:
-      return True
 
-  def is_equivalent_line(self, ignored, actual):
-    return len(actual) > 0
+    for line in actual:
+      # If any line has some text, then there is output, so we match.
+      if line:
+        return True
+
+    # We did not find a line with text. No match.
+    return False
 
   def display_differences(self, message, label, actual):
     if message:
       print(message)
 
-class RegexOutput(ExpectedOutput):
-  def __init__(self, output, match_all=True, is_reg_exp=True):
-    self.output = output
-    self.match_all = match_all
-    self.is_reg_exp = is_reg_exp
 
-  def is_equivalent_line(self, expected, actual):
-    "Return whether the regex EXPECTED matches the ACTUAL text."
-    return re.match(expected, actual) is not None
+class RegexOutput(ExpectedOutput):
+  is_regex = True
 
-  def display_differences(self, message, label, actual):
-    display_lines(message, label, self.output, actual, True, False)
 
 class UnorderedOutput(ExpectedOutput):
   """Marks unordered output, and performs comparisons."""
 
+  is_unordered = True
+
   def __cmp__(self, other):
-    "Handle ValueError."
-    try:
-      return ExpectedOutput.__cmp__(self, other)
-    except ValueError:
-      return 1
+    raise 'badness'
 
   def is_equivalent_list(self, expected, actual):
     "Disregard the order of ACTUAL lines during comparison."
+
+    e_set = set(expected)
+    a_set = set(actual)
+
     if self.match_all:
-      if len(expected) != len(actual):
+      if len(e_set) != len(a_set):
         return False
-      expected = list(expected)
-      for actual_line in actual:
-        try:
-          i = self.is_equivalent_line(expected, actual_line)
-          expected.pop(i)
-        except ValueError:
-          return False
-      return True
-    else:
-      for actual_line in actual:
-        try:
-          self.is_equivalent_line(expected, actual_line)
-          return True
-        except ValueError:
-          pass
+      if self.is_regex:
+        for expect_re in e_set:
+          for actual_line in a_set:
+            if re.match(expect_re, actual_line):
+              a_set.remove(actual_line)
+              break
+          else:
+            # One of the regexes was not found
+            return False
+        return True
+
+      # All expected lines must be in the output.
+      return e_set == a_set
+
+    if self.is_regex:
+      # If any of the expected regexes are in the output, then we match.
+      for expect_re in e_set:
+        for actual_line in a_set:
+          if re.match(expect_re, actual_line):
+            return True
       return False
 
-  def is_equivalent_line(self, expected, actual):
-    """Return the index into the EXPECTED lines of the line ACTUAL.
-    Raise ValueError if not found."""
-    return expected.index(actual)
+    # If any of the expected lines are in the output, then we match.
+    return len(e_set.intersection(a_set)) > 0
 
-  def display_differences(self, message, label, actual):
-    display_lines(message, label, self.output, actual, False, True)
 
 class UnorderedRegexOutput(UnorderedOutput, RegexOutput):
-  def is_equivalent_line(self, expected, actual):
-    for i in range(0, len(expected)):
-      if RegexOutput.is_equivalent_line(self, expected[i], actual):
-        return i
-      else:
-        raise ValueError("'%s' not found" % actual)
-
-  def display_differences(self, message, label, actual):
-    display_lines(message, label, self.output, actual, True, True)
+  is_regex = True
+  is_unordered = True
 
 
 ######################################################################
@@ -331,7 +310,7 @@ def compare_and_display_lines(message, l
     actual = [actual]
   actual = [line for line in actual if not line.startswith('DBG:')]
 
-  if expected != actual:
+  if not expected.matches(actual):
     expected.display_differences(message, label, actual)
     raise raisable
 

Modified: subversion/branches/svn-patch-improvements/subversion/tests/cmdline/switch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/cmdline/switch_tests.py?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/cmdline/switch_tests.py Tue Mar 30 20:57:53 2010
@@ -2334,37 +2334,37 @@ def tree_conflicts_on_switch_1_1(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .file.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .dir.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .dir.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .dir.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .dir.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .dir.*/DDD/D1@3$',
@@ -2426,37 +2426,37 @@ def tree_conflicts_on_switch_1_2(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .none.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .dir.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .dir.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .none.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .dir.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon switch'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .dir.*/DDD/D1@3$',
@@ -2508,37 +2508,37 @@ def tree_conflicts_on_switch_2_1(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon switch'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .none.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon switch'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .none.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon switch'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .none.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon switch'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .none.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon switch'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .none.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon switch'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .none.*/DDD/D1@3$',
@@ -2602,37 +2602,37 @@ def tree_conflicts_on_switch_2_2(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .none.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .none.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .none.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .none.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .none.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .none.*/DDD/D1@3$',
@@ -2691,37 +2691,37 @@ def tree_conflicts_on_switch_3(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .none.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .none.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .none.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .none.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .none.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon switch'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .none.*/DDD/D1@3$',

Modified: subversion/branches/svn-patch-improvements/subversion/tests/cmdline/tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/cmdline/tree_conflict_tests.py?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/cmdline/tree_conflict_tests.py (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/cmdline/tree_conflict_tests.py Tue Mar 30 20:57:53 2010
@@ -1130,6 +1130,67 @@ def query_absent_tree_conflicted_dir(sbo
   # using info:
   run_and_verify_svn(None, None, [], 'info', C_C_path)
 
+#----------------------------------------------------------------------
+
+def up_add_onto_add_revert(sbox):
+  "issue #3608: reverting an add onto add conflict"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+  wc2_dir = sbox.add_wc_path('wc2')
+  svntest.actions.run_and_verify_svn(None, None, [], 'checkout',
+                                     sbox.repo_url, wc2_dir)
+
+  file1 = os.path.join(wc_dir, 'newfile')
+  file2 = os.path.join(wc2_dir, 'newfile')
+
+  dir1 = os.path.join(wc_dir, 'NewDir')
+  dir2 = os.path.join(wc2_dir, 'NewDir')
+
+  main.run_svn(None, 'cp', os.path.join(wc_dir, 'iota'), file1)
+  main.run_svn(None, 'cp', os.path.join(wc2_dir, 'iota'), file2)
+
+  main.run_svn(None, 'cp', os.path.join(wc_dir, 'A/C'), dir1)
+  main.run_svn(None, 'cp', os.path.join(wc2_dir, 'A/C'), dir2)
+
+  main.run_svn(None, 'ci', wc_dir, '-m', 'Added file')
+
+  expected_disk = main.greek_state.copy()
+  expected_disk.add({
+    'newfile'           : Item(contents="This is the file 'iota'.\n"),
+    'NewDir'            : Item(),
+    })
+
+  expected_status = get_virginal_state(wc2_dir, 2)
+  expected_status.add({
+    'newfile' : Item(status='A ', copied='+', treeconflict='C', wc_rev='-'),
+    'NewDir'  : Item(status='A ', copied='+', treeconflict='C', wc_rev='-'),
+    })
+
+  run_and_verify_update(wc2_dir,
+                        None, expected_disk, expected_status,
+                        None, None, None, None, None, 1,
+                        wc2_dir)
+
+  # Currently (r927086), this removes dir2 and file2 in a way that
+  # they don't reappear after update.
+  main.run_svn(None, 'revert', file2)
+  main.run_svn(None, 'revert', dir2)
+
+  expected_status = get_virginal_state(wc2_dir, 2)
+  expected_status.add({
+    'newfile' : Item(status='  ', wc_rev='2'),
+    'NewDir'  : Item(status='  ', wc_rev='2'),
+    })
+
+  # Expected behavior is that after revert + update the tree matches
+  # the repository
+  run_and_verify_update(wc2_dir,
+                        None, expected_disk, expected_status,
+                        None, None, None, None, None, 1,
+                        wc2_dir)
+
+
 
 #######################################################################
 # Run the tests
@@ -1159,6 +1220,7 @@ test_list = [ None,
               XFail(keep_local_del_tc_is_target),
               XFail(force_del_tc_is_target),
               XFail(query_absent_tree_conflicted_dir),
+              XFail(up_add_onto_add_revert),
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/svn-patch-improvements/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/cmdline/update_tests.py?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/cmdline/update_tests.py Tue Mar 30 20:57:53 2010
@@ -2208,10 +2208,18 @@ def update_wc_on_windows_drive(sbox):
         if not drive + ':\\' in drives:
           return drive
     except ImportError:
-      return None
+      # In ActiveState python x64 win32api is not available
+      for d in range(ord('G'), ord('Z')+1):
+        drive = chr(d)
+        if not os.path.isdir(drive + ':\\'):
+          return drive
 
     return None
 
+  # Skip the test if not on Windows
+  if not svntest.main.windows:
+    raise svntest.Skip
+
   # just create an empty folder, we'll checkout later.
   sbox.build(create_wc = False)
   svntest.main.safe_rmtree(sbox.wc_dir)
@@ -4324,37 +4332,37 @@ def tree_conflicts_on_update_1_1(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .file.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .dir.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .dir.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .dir.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .dir.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .dir.*/DDD/D1@3$',
@@ -4408,7 +4416,7 @@ def tree_conflicts_on_update_1_2(sbox):
                          'DDD/D1/D2/D3',
                          'DDF/D1/D2/gamma',
                          'DF/D1/beta')
-  
+
   ### Why does the deep trees state not include files?
   expected_disk.remove('D/D1',
                        'DD/D1/D2',
@@ -4416,37 +4424,37 @@ def tree_conflicts_on_update_1_2(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .none.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .dir.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .dir.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .none.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .dir.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming edit upon update'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .dir.*/DDD/D1@3$',
@@ -4499,37 +4507,37 @@ def tree_conflicts_on_update_2_1(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon update'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .none.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon update'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .none.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon update'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .none.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon update'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .none.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon update'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .none.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local edit, incoming delete upon update'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .none.*/DDD/D1@3$',
@@ -4602,37 +4610,37 @@ def tree_conflicts_on_update_2_2(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .none.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .none.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .none.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .none.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .none.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .none.*/DDD/D1@3$',
@@ -4763,37 +4771,37 @@ def tree_conflicts_on_update_3(sbox):
 
   expected_info = {
     'F/alpha' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .file.*/F/alpha@2'
         + ' Source right: .none.*/F/alpha@3$',
     },
     'DF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/DF/D1@2'
         + ' Source right: .none.*/DF/D1@3$',
     },
     'DDF/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/DDF/D1@2'
         + ' Source right: .none.*/DDF/D1@3$',
     },
     'D/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/D/D1@2'
         + ' Source right: .none.*/D/D1@3$',
     },
     'DD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/DD/D1@2'
         + ' Source right: .none.*/DD/D1@3$',
     },
     'DDD/D1' : {
-      'Tree conflict' : 
+      'Tree conflict' :
         '^local delete, incoming delete upon update'
         + ' Source  left: .dir.*/DDD/D1@2'
         + ' Source right: .none.*/DDD/D1@3$',
@@ -5210,21 +5218,21 @@ def set_deep_depth_on_target_with_shallo
     'A/D/H/omega' : Item(status='D '),
     'A/D/H/psi'   : Item(status='D '),
     })
-  
+
   expected_status.remove('A/D/G/pi',
                          'A/D/G/rho',
                          'A/D/G/tau',
                          'A/D/H/chi',
                          'A/D/H/omega',
                          'A/D/H/psi')
-  
+
   expected_disk.remove('A/D/G/pi',
                        'A/D/G/rho',
                        'A/D/G/tau',
                        'A/D/H/chi',
                        'A/D/H/omega',
                        'A/D/H/psi')
-  
+
   svntest.actions.run_and_verify_update(wc_dir,
                                         expected_output,
                                         expected_disk,
@@ -5249,11 +5257,11 @@ def set_deep_depth_on_target_with_shallo
     'A/D/H/omega' : Item(status='A '),
     'A/D/H/psi'   : Item(status='A '),
     })
-  
+
   expected_disk = svntest.main.greek_state.copy()
-  
+
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
-  
+
   svntest.actions.run_and_verify_update(wc_dir,
                                         expected_output,
                                         expected_disk,
@@ -5303,7 +5311,7 @@ def update_deleted_locked_files(sbox):
   svntest.main.run_svn(None, 'delete', E)#iota, E)
 
   expected_output = svntest.wc.State(wc_dir, {})
-  
+
   expected_disk = svntest.main.greek_state.copy()
   expected_disk.remove('iota',
                        'A/B/E/alpha',
@@ -5384,7 +5392,7 @@ def update_empty_hides_entries(sbox):
                                         wc_dir)
 
   # Now update the rest back to head
-  
+
   # This operation is currently a NO-OP, because the WC-Crawler
   # tells the repository that it contains a full tree of the HEAD
   # revision.
@@ -5440,7 +5448,7 @@ def mergeinfo_updates_merge_with_local_m
                                      sbox.repo_url + '/A', A_COPY_path)
   svntest.actions.run_and_verify_svn(None, [A_COPY_path + " - /A:3\n"], [],
                                      'pg', SVN_PROP_MERGEINFO, '-R',
-                                     A_COPY_path) 
+                                     A_COPY_path)
 
   # Update the WC (to r8), the mergeinfo on A_COPY should now have both
   # the local mod from the uncommitted merge (/A:3* --> /A:3) and the change

Modified: subversion/branches/svn-patch-improvements/subversion/tests/cmdline/upgrade_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/cmdline/upgrade_tests.py?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/cmdline/upgrade_tests.py Tue Mar 30 20:57:53 2010
@@ -141,6 +141,23 @@ def basic_upgrade(sbox):
   expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
   run_and_verify_status_no_server(sbox.wc_dir, expected_status)
 
+def upgrade_with_externals(sbox):
+  "upgrade with externals"
+
+  # Create wc from tarfile, uses the same structure of the wc as the tests
+  # in externals_tests.py.
+  replace_sbox_with_tarfile(sbox, 'upgrade_with_externals.tar.bz2')
+
+  # Attempt to use the working copy, this should give an error
+  expected_stderr = wc_is_too_old_regex
+  svntest.actions.run_and_verify_svn(None, None, expected_stderr,
+                                     'info', sbox.wc_dir)
+  # Now upgrade the working copy
+  svntest.actions.run_and_verify_svn(None, None, [],
+                                     'upgrade', sbox.wc_dir)
+
+  # Actually check the format number of the upgraded working copy
+  check_format(sbox, get_current_format())
 
 def upgrade_1_5_body(sbox, subcommand):
   replace_sbox_with_tarfile(sbox, 'upgrade_1_5.tar.bz2')
@@ -262,8 +279,8 @@ def basic_upgrade_1_0(sbox):
   # Now check the contents of the working copy
   # #### This working copy is not just a basic tree,
   #      fix with the right data once we get here
-  expected_status = svntest.wc.State(sbox.wc_dir, 
-    { 
+  expected_status = svntest.wc.State(sbox.wc_dir,
+    {
       '' : Item(status='  ', wc_rev=7),
       'B'                 : Item(status='  ', wc_rev='7'),
       'B/mu'              : Item(status='  ', wc_rev='7'),
@@ -328,6 +345,7 @@ def basic_upgrade_1_0(sbox):
 # list all tests here, starting with None:
 test_list = [ None,
               basic_upgrade,
+              upgrade_with_externals,
               upgrade_1_5,
               update_1_5,
               logs_left_1_5,

Propchange: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_client/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Mar 30 20:57:53 2010
@@ -1,3 +1,4 @@
 .libs
 client-test
 *.lo
+test-patch*

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_client/client-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_client/client-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_client/client-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_client/client-test.c Tue Mar 30 20:57:53 2010
@@ -22,12 +22,17 @@
  */
 
 
+
+#include <limits.h>
 #include "svn_mergeinfo.h"
 #include "../../libsvn_client/mergeinfo.h"
 #include "svn_pools.h"
 #include "svn_client.h"
+#include "svn_repos.h"
+#include "svn_subst.h"
 
 #include "../svn_test.h"
+#include "../svn_test_fs.h"
 
 typedef struct {
   const char *path;
@@ -199,6 +204,171 @@ test_args_to_target_array(apr_pool_t *po
   return SVN_NO_ERROR;
 }
 
+
+/* A helper function for test_patch().
+ * It compares a patched or reject file against expected content.
+ * It also deletes the file if the check was successful. */
+static svn_error_t *
+check_patch_result(const char *path, const char **expected_lines,
+                   int num_expected_lines, apr_pool_t *pool)
+{
+  svn_stream_t *stream;
+  apr_pool_t *iterpool;
+  int i;
+
+  SVN_ERR(svn_stream_open_readonly(&stream, path, pool, pool));
+  i = 0;
+  iterpool = svn_pool_create(pool);
+  while (TRUE)
+    {
+      svn_boolean_t eof;
+      svn_stringbuf_t *line;
+
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(svn_stream_readline(stream, &line, APR_EOL_STR, &eof, pool));
+      if (i < num_expected_lines)
+        if (strcmp(expected_lines[i++], line->data) != 0)
+          return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                   "%s line %d didn't match the expected line "
+                                   "(strlen=%d vs strlen=%d)", path, i,
+                                   (int)strlen(expected_lines[i-1]),
+                                   (int)strlen(line->data));
+
+      if (eof)
+        break;
+    }
+  svn_pool_destroy(iterpool);
+
+  SVN_ERR_ASSERT(i == num_expected_lines);
+  SVN_ERR(svn_io_remove_file2(path, FALSE, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_patch(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;
+  apr_hash_t *patched_tempfiles;
+  apr_hash_t *reject_tempfiles;
+  const char *repos_url;
+  const char *wc_path;
+  const char *cwd;
+  svn_revnum_t committed_rev;
+  svn_opt_revision_t rev;
+  svn_opt_revision_t peg_rev;
+  svn_client_ctx_t *ctx;
+  apr_file_t *patch_file;
+  const char *patch_file_path;
+  const char *patched_tempfile_path;
+  const char *reject_tempfile_path;
+  const char *key;
+  int i;
+#define NL APR_EOL_STR
+#define UNIDIFF_LINES 7
+  const char *unidiff_patch[UNIDIFF_LINES] =  {
+    "Index: A/D/gamma" NL,
+    "===================================================================\n",
+    "--- A/D/gamma\t(revision 1)" NL,
+    "+++ A/D/gamma\t(working copy)" NL,
+    "@@ -1 +1 @@" NL,
+    "-This is really the file 'gamma'." NL,
+    "+It is really the file 'gamma'." NL
+  };
+#define EXPECTED_GAMMA_LINES 1
+  const char *expected_gamma[EXPECTED_GAMMA_LINES] = {
+    "This is the file 'gamma'."
+  };
+#define EXPECTED_GAMMA_REJECT_LINES 5
+  const char *expected_gamma_reject[EXPECTED_GAMMA_REJECT_LINES] = {
+    "--- A/D/gamma",
+    "+++ A/D/gamma",
+    "@@ -1,1 +1,1 @@",
+    "-This is really the file 'gamma'.",
+    "+It is really the file 'gamma'."
+  };
+
+  /* Create a filesytem and repository. */
+  SVN_ERR(svn_test__create_repos(&repos, "test-patch-repos",
+                                 opts, pool));
+  fs = svn_repos_fs(repos);
+
+  /* Prepare a txn to receive the greek tree. */
+  SVN_ERR(svn_fs_begin_txn2(&txn, fs, 0, 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, &committed_rev, txn, pool));
+
+  /* Check out the HEAD revision */
+  SVN_ERR(svn_dirent_get_absolute(&cwd, "", pool));
+
+  if (cwd[0] == '/')
+    repos_url = apr_pstrcat(pool, "file://", cwd,
+                            "/test-patch-repos", NULL);
+  else
+    /* On Windows CWD is always in "X:/..." style */
+    repos_url = apr_pstrcat(pool, "file:///", cwd,
+                            "/test-patch-repos", NULL);
+
+  repos_url = svn_uri_canonicalize(repos_url, pool);
+
+  /* Put wc inside an unversioned directory.  Checking out a 1.7 wc
+     directly inside a 1.6 wc doesn't work reliably, an intervening
+     unversioned directory prevents the problems. */
+  wc_path = svn_dirent_join(cwd, "test-patch", pool);
+  SVN_ERR(svn_io_make_dir_recursively(wc_path, pool));
+  svn_test_add_dir_cleanup(wc_path);
+
+  wc_path = svn_dirent_join(wc_path, "test-patch-wc", pool);
+  SVN_ERR(svn_io_remove_dir2(wc_path, TRUE, NULL, NULL, pool));
+  rev.kind = svn_opt_revision_head;
+  peg_rev.kind = svn_opt_revision_unspecified;
+  SVN_ERR(svn_client_create_context(&ctx, pool));
+  SVN_ERR(svn_client_checkout3(NULL, repos_url, wc_path,
+                               &peg_rev, &rev, svn_depth_infinity,
+                               TRUE, FALSE, ctx, pool));
+
+  /* Create the patch file. */
+  patch_file_path = svn_dirent_join_many(pool, cwd,
+                                         "test-patch", "test-patch.diff", NULL);
+  SVN_ERR(svn_io_file_open(&patch_file, patch_file_path,
+                           (APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE),
+                           APR_OS_DEFAULT, pool));
+  for (i = 0; i < UNIDIFF_LINES; i++)
+    {
+      apr_size_t len = strlen(unidiff_patch[i]);
+      SVN_ERR(svn_io_file_write(patch_file, unidiff_patch[i], &len, pool));
+      SVN_ERR_ASSERT(len == strlen(unidiff_patch[i]));
+    }
+  SVN_ERR(svn_io_file_flush_to_disk(patch_file, pool));
+
+  /* Apply the patch. */
+  SVN_ERR(svn_client_patch(patch_file_path, wc_path, FALSE, 0, FALSE,
+                           NULL, NULL, &patched_tempfiles, &reject_tempfiles,
+                           ctx, pool, pool));
+  SVN_ERR(svn_io_file_close(patch_file, pool));
+
+  SVN_ERR_ASSERT(apr_hash_count(patched_tempfiles) == 1);
+  key = "A/D/gamma";
+  patched_tempfile_path = apr_hash_get(patched_tempfiles, key,
+                                       APR_HASH_KEY_STRING);
+  SVN_ERR(check_patch_result(patched_tempfile_path, expected_gamma,
+                             EXPECTED_GAMMA_LINES, pool));
+  SVN_ERR_ASSERT(apr_hash_count(reject_tempfiles) == 1);
+  key = "A/D/gamma";
+  reject_tempfile_path = apr_hash_get(reject_tempfiles, key,
+                                     APR_HASH_KEY_STRING);
+  SVN_ERR(check_patch_result(reject_tempfile_path, expected_gamma_reject,
+                             EXPECTED_GAMMA_REJECT_LINES, pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* ========================================================================== */
 
 struct svn_test_descriptor_t test_funcs[] =
@@ -208,5 +378,6 @@ struct svn_test_descriptor_t test_funcs[
                    "test svn_client__elide_mergeinfo_catalog"),
     SVN_TEST_PASS2(test_args_to_target_array,
                    "test svn_client_args_to_target_array"),
+    SVN_TEST_OPTS_PASS(test_patch, "test svn_client_patch"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_diff/diff-diff3-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_diff/diff-diff3-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_diff/diff-diff3-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_diff/diff-diff3-test.c Tue Mar 30 20:57:53 2010
@@ -567,20 +567,20 @@ test_two_way_unified(apr_pool_t *pool)
 
   SVN_ERR(two_way_diff("foo5d", "bar5d",
                        "Aa\r\n"
-					   "\r\n"
+                       "\r\n"
                        "Bb\r\n"
-					   "\r\n"
+                       "\r\n"
                        "Cc\r\n"
-					   "\r\n",
+                       "\r\n",
 
                        "Aa\n"
-					   "\n"
+                       "\n"
                        "Bb\n"
-					   "\n"
+                       "\n"
                        "Cc\n"
-					   "\n",
+                       "\n",
 
-					   "",
+                       "",
                        diff_opts, pool));
   diff_opts->ignore_eol_style = FALSE;
 

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_diff/parse-diff-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_diff/parse-diff-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_diff/parse-diff-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_diff/parse-diff-test.c Tue Mar 30 20:57:53 2010
@@ -25,7 +25,6 @@
 #include "../svn_test.h"
 
 #include "svn_diff.h"
-#include "private/svn_diff_private.h"
 #include "svn_pools.h"
 #include "svn_utf.h"
 
@@ -101,8 +100,8 @@ test_parse_unidiff(apr_pool_t *pool)
 
       /* We have two patches with one hunk each.
        * Parse the first patch. */
-      SVN_ERR(svn_diff__parse_next_patch(&patch, patch_file, reverse,
-                                         iterpool, iterpool));
+      SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file, reverse,
+                                        iterpool, iterpool));
       SVN_ERR_ASSERT(patch);
       SVN_ERR_ASSERT(! strcmp(patch->old_filename, "A/C/gamma"));
       SVN_ERR_ASSERT(! strcmp(patch->new_filename, "A/C/gamma"));
@@ -144,7 +143,7 @@ test_parse_unidiff(apr_pool_t *pool)
       SVN_ERR_ASSERT(buf->len == 0);
 
       /* Parse the second patch. */
-      SVN_ERR(svn_diff__parse_next_patch(&patch, patch_file, reverse, pool, pool));
+      SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file, reverse, pool, pool));
       SVN_ERR_ASSERT(patch);
       if (reverse)
         {

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_fs_base/changes-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_fs_base/changes-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_fs_base/changes-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_fs_base/changes-test.c Tue Mar 30 20:57:53 2010
@@ -698,6 +698,204 @@ changes_fetch_ordering(const svn_test_op
 }
 
 
+static svn_error_t *
+changes_bad_sequences(const svn_test_opts_t *opts,
+                      apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  apr_pool_t *subpool = svn_pool_create(pool);
+  svn_error_t *err;
+
+  /* Create a new fs and repos */
+  SVN_ERR(svn_test__create_bdb_fs
+          (&fs, "test-repo-changes-bad-sequences", opts,
+           pool));
+
+  /* Test changes bogus because a path's node-rev-ID changed
+     unexpectedly. */
+  svn_pool_clear(subpool);
+  {
+    static const char *bogus_changes[][6]
+         /* KEY   PATH   NODEREVID  KIND       TEXT PROP */
+      = { { "x",  "/foo",  "1.0.0",  "add",     0 ,  0  },
+          { "x",  "/foo",  "1.0.0",  "modify",  0 , "1" },
+          { "x",  "/foo",  "2.0.0",  "modify", "1", "1" } };
+    int num_changes = sizeof(bogus_changes) / sizeof(const char *) / 6;
+    struct changes_args args;
+    int i;
+
+    for (i = 0; i < num_changes; i++)
+      {
+        change_t change;
+
+        /* Set up the current change item. */
+        change.path = bogus_changes[i][1];
+        change.noderev_id = svn_fs_parse_id(bogus_changes[i][2],
+                                            strlen(bogus_changes[i][2]),
+                                            subpool);
+        change.kind = string_to_kind(bogus_changes[i][3]);
+        change.text_mod = bogus_changes[i][4] ? 1 : 0;
+        change.prop_mod = bogus_changes[i][5] ? 1 : 0;
+
+        /* Set up transaction baton. */
+        args.fs = fs;
+        args.key = "x";
+        args.change = &change;
+
+        /* Write new changes to the changes table. */
+        SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_add, &args,
+                                       TRUE, subpool));
+      }
+
+    /* Now read 'em back, looking for an error. */
+    args.fs = fs;
+    args.key = "x";
+    err = svn_fs_base__retry_txn(args.fs, txn_body_changes_fetch, &args,
+                                 TRUE, subpool);
+    if (!err)
+      {
+        return svn_error_create(SVN_ERR_TEST_FAILED, 0,
+                                "Expected SVN_ERR_FS_CORRUPT, got no error.");
+      }
+    else if (err->apr_err != SVN_ERR_FS_CORRUPT)
+      {
+        return svn_error_create(SVN_ERR_TEST_FAILED, err,
+                                "Expected SVN_ERR_FS_CORRUPT, got a different error.");
+      }
+    else
+      {
+        svn_error_clear(err);
+      }
+
+    /* Post-test cleanup. */
+    SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_delete, &args,
+                                   TRUE, subpool));
+  }
+
+  /* Test changes bogus because there's a change other than an
+     add-type changes on a deleted path. */
+  svn_pool_clear(subpool);
+  {
+    static const char *bogus_changes[][6]
+         /* KEY   PATH   NODEREVID  KIND       TEXT PROP */
+      = { { "x",  "/foo",  "1.0.0",  "delete",  0 ,  0  },
+          { "x",  "/foo",  "1.0.0",  "modify", "1",  0  } };
+    int num_changes = sizeof(bogus_changes) / sizeof(const char *) / 6;
+    struct changes_args args;
+    int i;
+
+    for (i = 0; i < num_changes; i++)
+      {
+        change_t change;
+
+        /* Set up the current change item. */
+        change.path = bogus_changes[i][1];
+        change.noderev_id = svn_fs_parse_id(bogus_changes[i][2],
+                                            strlen(bogus_changes[i][2]),
+                                            subpool);
+        change.kind = string_to_kind(bogus_changes[i][3]);
+        change.text_mod = bogus_changes[i][4] ? 1 : 0;
+        change.prop_mod = bogus_changes[i][5] ? 1 : 0;
+
+        /* Set up transaction baton. */
+        args.fs = fs;
+        args.key = "x";
+        args.change = &change;
+
+        /* Write new changes to the changes table. */
+        SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_add, &args,
+                                       TRUE, subpool));
+      }
+
+    /* Now read 'em back, looking for an error. */
+    args.fs = fs;
+    args.key = "x";
+    err = svn_fs_base__retry_txn(args.fs, txn_body_changes_fetch, &args,
+                                 TRUE, subpool);
+    if (!err)
+      {
+        return svn_error_create(SVN_ERR_TEST_FAILED, 0,
+                                "Expected SVN_ERR_FS_CORRUPT, got no error.");
+      }
+    else if (err->apr_err != SVN_ERR_FS_CORRUPT)
+      {
+        return svn_error_create(SVN_ERR_TEST_FAILED, err,
+                                "Expected SVN_ERR_FS_CORRUPT, got a different error.");
+      }
+    else
+      {
+        svn_error_clear(err);
+      }
+
+    /* Post-test cleanup. */
+    SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_delete, &args,
+                                   TRUE, subpool));
+  }
+
+  /* Test changes bogus because there's an add on a path that's got
+     previous non-delete changes on it. */
+  svn_pool_clear(subpool);
+  {
+    static const char *bogus_changes[][6]
+         /* KEY   PATH   NODEREVID  KIND       TEXT PROP */
+      = { { "x",  "/foo",  "1.0.0",  "modify", "1",  0  },
+          { "x",  "/foo",  "1.0.0",  "add",    "1",  0  } };
+    int num_changes = sizeof(bogus_changes) / sizeof(const char *) / 6;
+    struct changes_args args;
+    int i;
+
+    for (i = 0; i < num_changes; i++)
+      {
+        change_t change;
+
+        /* Set up the current change item. */
+        change.path = bogus_changes[i][1];
+        change.noderev_id = svn_fs_parse_id(bogus_changes[i][2],
+                                            strlen(bogus_changes[i][2]),
+                                            subpool);
+        change.kind = string_to_kind(bogus_changes[i][3]);
+        change.text_mod = bogus_changes[i][4] ? 1 : 0;
+        change.prop_mod = bogus_changes[i][5] ? 1 : 0;
+
+        /* Set up transaction baton. */
+        args.fs = fs;
+        args.key = "x";
+        args.change = &change;
+
+        /* Write new changes to the changes table. */
+        SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_add, &args,
+                                       TRUE, subpool));
+      }
+
+    /* Now read 'em back, looking for an error. */
+    args.fs = fs;
+    args.key = "x";
+    err = svn_fs_base__retry_txn(args.fs, txn_body_changes_fetch, &args,
+                                 TRUE, subpool);
+    if (!err)
+      {
+        return svn_error_create(SVN_ERR_TEST_FAILED, 0,
+                                "Expected SVN_ERR_FS_CORRUPT, got no error.");
+      }
+    else if (err->apr_err != SVN_ERR_FS_CORRUPT)
+      {
+        return svn_error_create(SVN_ERR_TEST_FAILED, err,
+                                "Expected SVN_ERR_FS_CORRUPT, got a different error.");
+      }
+    else
+      {
+        svn_error_clear(err);
+      }
+
+    /* Post-test cleanup. */
+    SVN_ERR(svn_fs_base__retry_txn(args.fs, txn_body_changes_delete, &args,
+                                   TRUE, subpool));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+
 
 /* The test table.  */
 
@@ -714,5 +912,7 @@ struct svn_test_descriptor_t test_funcs[
                        "fetch compressed changes from the changes table"),
     SVN_TEST_OPTS_PASS(changes_fetch_ordering,
                        "verify ordered-ness of fetched compressed changes"),
+    SVN_TEST_OPTS_PASS(changes_bad_sequences,
+                       "verify that bad change sequences raise errors"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_fs_fs/fs-pack-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_fs_fs/fs-pack-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_fs_fs/fs-pack-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_fs_fs/fs-pack-test.c Tue Mar 30 20:57:53 2010
@@ -380,7 +380,7 @@ get_set_revprop_packed_fs(const svn_test
 
   /* Try to get revprop for revision 0. */
   SVN_ERR(svn_fs_revision_prop(&prop_value, fs, 0, SVN_PROP_REVISION_AUTHOR, pool));
-  
+
   /* Try to change revprop for revision 0. */
   SVN_ERR(svn_fs_change_rev_prop(fs, 0, SVN_PROP_REVISION_AUTHOR,
                                  svn_string_create("tweaked-author", pool), pool));

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_repos/repos-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_repos/repos-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_repos/repos-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_repos/repos-test.c Tue Mar 30 20:57:53 2010
@@ -2152,13 +2152,12 @@ prop_validation_commit_with_revprop(cons
                    APR_HASH_KEY_STRING,
                    svn_string_create("plato", pool));
     }
-  else
-    if (strcmp(prop_key, SVN_PROP_REVISION_LOG) != 0)
-      {
-        apr_hash_set(revprop_table, SVN_PROP_REVISION_LOG,
-                     APR_HASH_KEY_STRING,
-                     svn_string_create("revision log", pool));
-      }
+  else if (strcmp(prop_key, SVN_PROP_REVISION_LOG) != 0)
+    {
+      apr_hash_set(revprop_table, SVN_PROP_REVISION_LOG,
+                   APR_HASH_KEY_STRING,
+                   svn_string_create("revision log", pool));
+    }
 
   /* Make an arbitrary change and commit using above values... */
 
@@ -2213,12 +2212,11 @@ prop_validation(const svn_test_opts_t *o
     return svn_error_create(SVN_ERR_TEST_FAILED, err,
                             "Failed to reject a log with invalid "
                             "UTF-8");
-  else
-    if (err->apr_err != SVN_ERR_BAD_PROPERTY_VALUE)
-      return svn_error_create(SVN_ERR_TEST_FAILED, err,
-                              "Expected SVN_ERR_BAD_PROPERTY_VALUE for "
-                              "a log with invalid UTF-8, "
-                              "got another error.");
+  else if (err->apr_err != SVN_ERR_BAD_PROPERTY_VALUE)
+    return svn_error_create(SVN_ERR_TEST_FAILED, err,
+                            "Expected SVN_ERR_BAD_PROPERTY_VALUE for "
+                            "a log with invalid UTF-8, "
+                            "got another error.");
   svn_error_clear(err);
 
 
@@ -2233,12 +2231,11 @@ prop_validation(const svn_test_opts_t *o
     return svn_error_create(SVN_ERR_TEST_FAILED, err,
                             "Failed to reject a log with inconsistent "
                             "line ending style");
-  else
-    if (err->apr_err != SVN_ERR_BAD_PROPERTY_VALUE)
-      return svn_error_create(SVN_ERR_TEST_FAILED, err,
-                              "Expected SVN_ERR_BAD_PROPERTY_VALUE for "
-                              "a log with inconsistent line ending style, "
-                              "got another error.");
+  else if (err->apr_err != SVN_ERR_BAD_PROPERTY_VALUE)
+    return svn_error_create(SVN_ERR_TEST_FAILED, err,
+                            "Expected SVN_ERR_BAD_PROPERTY_VALUE for "
+                            "a log with inconsistent line ending style, "
+                            "got another error.");
   svn_error_clear(err);
 
 

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/dirent_uri-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/dirent_uri-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/dirent_uri-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/dirent_uri-test.c Tue Mar 30 20:57:53 2010
@@ -1227,6 +1227,9 @@ test_uri_is_canonical(apr_pool_t *pool)
     { "http://hst/",           FALSE },
     { "http://HST/",           FALSE },
     { "http://HST/FOO/BaR",    FALSE },
+    { "http://hst/foo/./bar",  FALSE },
+    { "hTTp://hst/foo/bar",   FALSE },
+    { "http://hst/foo/bar/",   FALSE },
     { "svn+ssh://jens@10.0.1.1", TRUE },
     { "svn+ssh://j.raNDom@HST/BaR", FALSE },
     { "svn+SSH://j.random:jRaY@HST/BaR", FALSE },

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/mergeinfo-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/mergeinfo-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/mergeinfo-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/mergeinfo-test.c Tue Mar 30 20:57:53 2010
@@ -159,7 +159,7 @@ static const char * const mergeinfo_path
     "/patch-common::netasq-bpf.c",
     "/patch-common_netasq-bpf.c:",
     "/:patch:common:netasq:bpf.c",
-    
+
     "/trunk",
     "/trunk",
     "/trunk",
@@ -382,7 +382,7 @@ range_to_string(svn_merge_range_t *range
    verified (e.g. "svn_rangelist_intersect"), while TYPE is a word
    describing what the ranges being examined represent. */
 static svn_error_t *
-verify_ranges_match(apr_array_header_t *actual_rangelist,
+verify_ranges_match(const apr_array_header_t *actual_rangelist,
                     svn_merge_range_t *expected_ranges, int nbr_expected,
                     const char *func_verified, const char *type,
                     apr_pool_t *pool)
@@ -479,21 +479,68 @@ static svn_error_t *
 test_rangelist_intersect(apr_pool_t *pool)
 {
   apr_array_header_t *rangelist1, *rangelist2, *intersection;
-  svn_merge_range_t expected_intersection[] =
-    { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE}, {30, 32, TRUE},
+
+  /* Expected intersection when considering inheritance. */
+  svn_merge_range_t intersection_consider_inheritance[] =
+    { {0, 1, TRUE}, {11, 12, TRUE}, {30, 32, FALSE}, {39, 42, TRUE} };
+
+  /* Expected intersection when ignoring inheritance. */
+  svn_merge_range_t intersection_ignore_inheritance[] =
+    { {0, 1, TRUE}, {2, 4, TRUE}, {11, 12, TRUE}, {30, 32, FALSE},
       {39, 42, TRUE} };
 
-  SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16,30-32,40-42", pool));
-  SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4,7,9,11-12,31-34,38-44",
+  SVN_ERR(svn_mergeinfo_parse(&info1, "/trunk: 1-6,12-16,30-32*,40-42", pool));
+  SVN_ERR(svn_mergeinfo_parse(&info2, "/trunk: 1,3-4*,7,9,11-12,31-34*,38-44",
                               pool));
   rangelist1 = apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING);
   rangelist2 = apr_hash_get(info2, "/trunk", APR_HASH_KEY_STRING);
 
+  /* Check the intersection while considering inheritance twice, reversing
+     the order of the rangelist arguments on the second call to
+     svn_rangelist_intersection.  The order *should* have no effect on
+     the result -- see http://svn.haxx.se/dev/archive-2010-03/0351.shtml.
+
+     '3-4*' has different inheritance than '1-6', so no intersection is
+     expected.  '30-32*' and '31-34*' have the same inheritance, so intersect
+     at '31-32*'.  Per the svn_rangelist_intersect API, since both ranges
+     are non-inheritable, so is the result. */
   SVN_ERR(svn_rangelist_intersect(&intersection, rangelist1, rangelist2,
                                   TRUE, pool));
 
-  return verify_ranges_match(intersection, expected_intersection, 5,
-                             "svn_rangelist_intersect", "intersect", pool);
+  SVN_ERR(verify_ranges_match(intersection,
+                              intersection_consider_inheritance,
+                              4, "svn_rangelist_intersect", "intersect",
+                              pool));
+
+  SVN_ERR(svn_rangelist_intersect(&intersection, rangelist2, rangelist1,
+                                  TRUE, pool));
+
+  SVN_ERR(verify_ranges_match(intersection,
+                              intersection_consider_inheritance,
+                              4, "svn_rangelist_intersect", "intersect",
+                              pool));
+
+  /* Check the intersection while ignoring inheritance.  The one difference
+     from when we consider inheritance is that '3-4*' and '1-6' now intersect,
+     since we don't care about inheritability, just the start and end ranges.
+     Per the svn_rangelist_intersect API, since only one range is
+     non-inheritable the result is inheritable. */
+  SVN_ERR(svn_rangelist_intersect(&intersection, rangelist1, rangelist2,
+                                  FALSE, pool));
+
+  SVN_ERR(verify_ranges_match(intersection,
+                              intersection_ignore_inheritance,
+                              5, "svn_rangelist_intersect", "intersect",
+                              pool));
+
+  SVN_ERR(svn_rangelist_intersect(&intersection, rangelist2, rangelist1,
+                                  FALSE, pool));
+
+  SVN_ERR(verify_ranges_match(intersection,
+                              intersection_ignore_inheritance,
+                              5, "svn_rangelist_intersect", "intersect",
+                              pool));
+  return SVN_NO_ERROR;
 }
 
 static svn_error_t *
@@ -880,7 +927,8 @@ test_remove_rangelist(apr_pool_t *pool)
 /* Random number seed. */
 static apr_uint32_t random_rev_array_seed;
 
-/* Fill 3/4 of the array with 1s. */
+/* Set a random 3/4-ish of the elements of array REVS[RANDOM_REV_ARRAY_LENGTH]
+ * to TRUE and the rest to FALSE. */
 static void
 randomly_fill_rev_array(svn_boolean_t *revs)
 {
@@ -892,6 +940,8 @@ randomly_fill_rev_array(svn_boolean_t *r
     }
 }
 
+/* Set *RANGELIST to a rangelist representing the revisions that are marked
+ * with TRUE in the array REVS[RANDOM_REV_ARRAY_LENGTH]. */
 static svn_error_t *
 rev_array_to_rangelist(apr_array_header_t **rangelist,
                        svn_boolean_t *revs,
@@ -946,6 +996,9 @@ test_rangelist_remove_randomly(apr_pool_
 
       randomly_fill_rev_array(first_revs);
       randomly_fill_rev_array(second_revs);
+      /* There is no change numbered "r0" */
+      first_revs[0] = FALSE;
+      second_revs[0] = FALSE;
       for (j = 0; j < RANDOM_REV_ARRAY_LENGTH; j++)
         expected_revs[j] = second_revs[j] && !first_revs[j];
 
@@ -1001,6 +1054,9 @@ test_rangelist_intersect_randomly(apr_po
 
       randomly_fill_rev_array(first_revs);
       randomly_fill_rev_array(second_revs);
+      /* There is no change numbered "r0" */
+      first_revs[0] = FALSE;
+      second_revs[0] = FALSE;
       for (j = 0; j < RANDOM_REV_ARRAY_LENGTH; j++)
         expected_revs[j] = second_revs[j] && first_revs[j];
 
@@ -1098,7 +1154,7 @@ test_mergeinfo_to_string(apr_pool_t *poo
                APR_HASH_KEY_STRING,
                apr_hash_get(info1, "/trunk", APR_HASH_KEY_STRING));
   SVN_ERR(svn_mergeinfo_to_string(&output, info2, pool));
-  
+
   if (svn_string_compare(expected, output) != TRUE)
     return fail(pool, "Mergeinfo string not what we expected");
 

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/stream-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/stream-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/stream-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_subr/stream-test.c Tue Mar 30 20:57:53 2010
@@ -266,20 +266,20 @@ test_stream_range(apr_pool_t *pool)
 
     /* Even when requesting more data than contained in the range,
      * we should only receive data from the range. */
-    len = strlen(now) + strlen(after);
-
     for (i = 0; i < 2; i++)
       {
-        /* Read the range. */
+        /* Try to read from "Now", up to and past the end of the range. */
+        len = strlen(now) + 1;
         SVN_ERR(svn_stream_read(stream, buf, &len));
-        if (len > strlen(now))
+        if (len != strlen(now))
           return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
-                                   "Read past range");
+                                   "Read past (or not all of) range");
         if (strcmp(buf, now))
           return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
                                    "Unexpected data");
 
-        /* Reading past the end of the range should be impossible. */
+        /* Try to read from the end of the range - should be impossible. */
+        len = 1;
         SVN_ERR(svn_stream_read(stream, buf, &len));
         if (len != 0)
           return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_wc/db-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_wc/db-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_wc/db-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_wc/db-test.c Tue Mar 30 20:57:53 2010
@@ -649,10 +649,6 @@ validate_node(svn_wc__db_t *db,
   value = apr_hash_get(props, "p999", APR_HASH_KEY_STRING);
   SVN_TEST_ASSERT(value != NULL && strcmp(value->data, "v1") == 0);
 
-  if (status == svn_wc__db_status_normal)
-    SVN_ERR(svn_wc__db_temp_op_set_pristine_props(db, path, props, FALSE,
-                                                  scratch_pool));
-
   return SVN_NO_ERROR;
 }
 
@@ -1328,6 +1324,11 @@ test_upgrading_to_f15(apr_pool_t *pool)
 static int
 detect_work_item(const svn_skel_t *work_item)
 {
+  /* Test work items are a list with one integer atom as operation */
+  if (!work_item->children)
+    return -1;
+  work_item = work_item->children;
+
   if (!work_item->is_atom || work_item->len != 1)
     return -1;
   return work_item->data[0] - '0';
@@ -1347,13 +1348,16 @@ test_work_queue(apr_pool_t *pool)
                       svn_wc__db_openmode_readwrite, pool));
 
   /* Create three work items.  */
-  work_item = svn_skel__str_atom("0", pool);
+  work_item = svn_skel__make_empty_list(pool);
+  svn_skel__prepend_int(0, work_item, pool);
   SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, pool));
 
-  work_item = svn_skel__str_atom("1", pool);
+  work_item = svn_skel__make_empty_list(pool);
+  svn_skel__prepend_int(1, work_item, pool);
   SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, pool));
 
-  work_item = svn_skel__str_atom("2", pool);
+  work_item = svn_skel__make_empty_list(pool);
+  svn_skel__prepend_int(2, work_item, pool);
   SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, pool));
 
   while (TRUE)

Modified: subversion/branches/svn-patch-improvements/subversion/tests/libsvn_wc/tree-conflict-data-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/subversion/tests/libsvn_wc/tree-conflict-data-test.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/subversion/tests/libsvn_wc/tree-conflict-data-test.c (original)
+++ subversion/branches/svn-patch-improvements/subversion/tests/libsvn_wc/tree-conflict-data-test.c Tue Mar 30 20:57:53 2010
@@ -74,7 +74,7 @@ test_read_tree_conflict(apr_pool_t *pool
                                       pool));
 
   hi = apr_hash_first(pool, conflicts);
-  conflict = svn_apr_hash_index_val(hi);
+  conflict = svn__apr_hash_index_val(hi);
 
   if ((conflict->node_kind != exp_conflict->node_kind) ||
       (conflict->action    != exp_conflict->action) ||
@@ -120,7 +120,7 @@ test_read_2_tree_conflicts(apr_pool_t *p
                                       pool));
 
   hi = apr_hash_first(pool, conflicts);
-  conflict1 = svn_apr_hash_index_val(hi);
+  conflict1 = svn__apr_hash_index_val(hi);
   if ((conflict1->node_kind != exp_conflict1->node_kind) ||
       (conflict1->action    != exp_conflict1->action) ||
       (conflict1->reason    != exp_conflict1->reason) ||
@@ -129,7 +129,7 @@ test_read_2_tree_conflicts(apr_pool_t *p
     return fail(pool, "Tree conflict struct #1 has bad data");
 
   hi = apr_hash_next(hi);
-  conflict2 = svn_apr_hash_index_val(hi);
+  conflict2 = svn__apr_hash_index_val(hi);
   if ((conflict2->node_kind != exp_conflict2->node_kind) ||
       (conflict2->action    != exp_conflict2->action) ||
       (conflict2->reason    != exp_conflict2->reason) ||

Modified: subversion/branches/svn-patch-improvements/tools/dev/analyze-svnlogs.py
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/tools/dev/analyze-svnlogs.py?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/tools/dev/analyze-svnlogs.py (original)
+++ subversion/branches/svn-patch-improvements/tools/dev/analyze-svnlogs.py Tue Mar 30 20:57:53 2010
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 #
 #
 # Licensed to the Apache Software Foundation (ASF) under one

Modified: subversion/branches/svn-patch-improvements/tools/dev/unix-build/Makefile.svn
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/tools/dev/unix-build/Makefile.svn?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/svn-patch-improvements/tools/dev/unix-build/Makefile.svn Tue Mar 30 20:57:53 2010
@@ -31,6 +31,7 @@
 ENABLE_PYTHON_BINDINGS ?= yes
 ENABLE_RUBY_BINDINGS ?= yes
 ENABLE_PERL_BINDINGS ?= yes
+ENABLE_JAVA_BINDINGS ?= no # they don't build with thread-less APR...
 
 PWD		= $(shell pwd)
 
@@ -614,8 +615,21 @@ else
 BDB_FLAG=db.h:$(PREFIX)/bdb/include:$(PREFIX)/bdb/lib:db-$(BDB_MAJOR_VER)
 endif
 
+ifeq ($(ENABLE_JAVA_BINDINGS),yes)
+	JAVAHL_FLAG=--enable-javahl=yes --with-jdk --with-jikes=no \
+		--with-junit=$(PWD)/junit.jar
+else
+	JAVAHL_FLAG=--enable-javahl=no
+endif
+
 # configure svn
 $(SVN_OBJDIR)/.configured: $(SVN_OBJDIR)/.retrieved
+	@if [ $(ENABLE_JAVA_BINDINGS) = yes ]; then \
+		if [ ! -e $(PWD)/junit.jar ]; then \
+			echo "Please provide $(PWD)/junit.jar"; \
+			exit 1; \
+		fi; \
+	fi
 	cd $(SVN_SRCDIR) && ./autogen.sh
 	cd $(svn_builddir) && \
 		env LDFLAGS="-L$(PREFIX)/neon/lib -L$(PREFIX)/apr/lib" \
@@ -634,7 +648,8 @@ $(SVN_OBJDIR)/.configured: $(SVN_OBJDIR)
 			--with-berkeley-db="$(BDB_FLAG)" \
 			--with-sasl="no" \
 			--with-ruby-sitedir="$(SVN_PREFIX)/lib/ruby/site_ruby" \
-			--disable-mod-activation
+			--disable-mod-activation \
+			$(JAVAHL_FLAG)
 	touch $@
 
 # compile svn
@@ -662,6 +677,10 @@ $(SVN_OBJDIR)/.bindings-compiled: $(SVN_
 		cd $(svn_builddir) \
 			&& make swig-pl; \
 	fi
+	if [ $(ENABLE_JAVA_BINDINGS) = yes ]; then \
+		cd $(svn_builddir) \
+			&& make javahl; \
+	fi
 	touch $@
 
 $(SVN_OBJDIR)/.bindings-installed: $(SVN_OBJDIR)/.bindings-compiled
@@ -680,6 +699,10 @@ $(SVN_OBJDIR)/.bindings-installed: $(SVN
 		  && perl Makefile.PL PREFIX="$(SVN_PREFIX)" \
 		  && make install; \
 	fi
+	if [ $(ENABLE_JAVA_BINDINGS) = yes ]; then \
+		cd $(svn_builddir) \
+			&& make install-javahl; \
+	fi
 	touch $@
 
 # run svn regression tests
@@ -786,8 +809,9 @@ svn-check-svn:
 	cd $(svn_builddir) && make check FS_TYPE=bdb BASE_URL=svn://127.0.0.1
 	$(SVNSERVE_STOP_CMD)
 
-.PHONY: svn-check-swig-pl svn-check-swig-py svn-check-swig-rb
-svn-check-swig: svn-check-swig-pl svn-check-swig-py svn-check-swig-rb
+.PHONY: svn-check-swig-pl svn-check-swig-py svn-check-swig-rb svn-check-javahl
+svn-check-bindings: svn-check-swig-pl svn-check-swig-py svn-check-swig-rb \
+	svn-check-javahl
 
 RUBYLIB=$(SVN_PREFIX)/lib/ruby/site_ruby$(shell grep \
 	^svn_cv_ruby_sitedir_archsuffix $(svn_builddir)/config.log | \
@@ -803,5 +827,9 @@ svn-check-swig-rb:
 		env RUBYLIB=$(RUBYLIB) \
 		LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) \
 		ruby run-test.rb --verbose=verbose
+svn-check-javahl:
+	cd $(svn_builddir) && \
+		env LD_LIBRARY_PATH=$(LD_LIBRARY_PATH) \
+		make check-javahl
 
-svn-check: svn-check-local svn-check-svn svn-check-neon svn-check-serf svn-check-swig
+svn-check: svn-check-local svn-check-svn svn-check-neon svn-check-serf svn-check-bindings

Modified: subversion/branches/svn-patch-improvements/tools/dist/construct-rolling-environment.sh
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/tools/dist/construct-rolling-environment.sh?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/tools/dist/construct-rolling-environment.sh (original)
+++ subversion/branches/svn-patch-improvements/tools/dist/construct-rolling-environment.sh Tue Mar 30 20:57:53 2010
@@ -29,7 +29,7 @@ APR=apr-1.3.8
 APR_UTIL=apr-util-1.3.9
 NEON=neon-0.29.0
 SERF=serf-0.3.0
-ZLIB=zlib-1.2.3
+ZLIB=zlib-1.2.4
 SQLITE_VERSION=3.6.20
 SQLITE=sqlite-amalgamation-$SQLITE_VERSION
 

Modified: subversion/branches/svn-patch-improvements/tools/dist/dist.sh
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/tools/dist/dist.sh?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/tools/dist/dist.sh (original)
+++ subversion/branches/svn-patch-improvements/tools/dist/dist.sh Tue Mar 30 20:57:53 2010
@@ -238,7 +238,12 @@ rm -rf "$DISTPATH/contrib"
 rm -rf "$DISTPATH/packages"
 
 # Check for a recent enough Python
-PYTHON="`$DISTPATH/build/find_python.sh`"
+# Instead of attempting to deal with various line ending issues, just export
+# the find_python script manually.
+${svn:-svn} export -q -r "$REVISION"  \
+     "http://svn.apache.org/repos/asf/subversion/$REPOS_PATH/build/find_python.sh" \
+     --username none --password none "$DIST_SANDBOX/find_python.sh"
+PYTHON="`$DIST_SANDBOX/find_python.sh`"
 if test -z "$PYTHON"; then
   echo "Python 2.4 or later is required to run dist.sh"
   echo "If you have a suitable Python installed, but not on the"

Modified: subversion/branches/svn-patch-improvements/tools/server-side/svn-rep-sharing-stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-patch-improvements/tools/server-side/svn-rep-sharing-stats.c?rev=929279&r1=929278&r2=929279&view=diff
==============================================================================
--- subversion/branches/svn-patch-improvements/tools/server-side/svn-rep-sharing-stats.c (original)
+++ subversion/branches/svn-patch-improvements/tools/server-side/svn-rep-sharing-stats.c Tue Mar 30 20:57:53 2010
@@ -275,8 +275,8 @@ process_one_revision(svn_fs_t *fs,
 
       node_revision_t *node_rev;
 
-      path = svn_apr_hash_index_key(hi);
-      change = svn_apr_hash_index_val(hi);
+      path = svn__apr_hash_index_key(hi);
+      change = svn__apr_hash_index_val(hi);
       if (! quiet)
         SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
                                     "processing r%ld:%s\n", revnum, path));
@@ -334,8 +334,8 @@ pretty_print(const char *name,
 
       SVN_ERR(cancel_func(NULL));
 
-      key = svn_apr_hash_index_key(hi);
-      value = svn_apr_hash_index_val(hi);
+      key = svn__apr_hash_index_key(hi);
+      value = svn__apr_hash_index_val(hi);
       SVN_ERR(svn_cmdline_printf(scratch_pool, "%s %" APR_UINT64_T_FMT " %s\n",
                                  name, value->refcount,
                                  svn_checksum_to_cstring_display(