You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by as...@apache.org on 2012/11/24 21:29:48 UTC

svn commit: r1413258 [28/33] - in /subversion/branches/compressed-pristines: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/emacs/ contrib/server-side/fsfsfixer/ notes/ notes/directory-index/ subversion/ subv...

Added: subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_automatic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_automatic_tests.py?rev=1413258&view=auto
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_automatic_tests.py (added)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_automatic_tests.py Sat Nov 24 20:29:11 2012
@@ -0,0 +1,1022 @@
+#!/usr/bin/env python
+#
+#  merge_automatic_tests.py:  testing "automatic merge" scenarios
+#
+#  Subversion is a tool for revision control.
+#  See http://subversion.apache.org for more information.
+#
+# ====================================================================
+#    Licensed to the Apache Software Foundation (ASF) under one
+#    or more contributor license agreements.  See the NOTICE file
+#    distributed with this work for additional information
+#    regarding copyright ownership.  The ASF licenses this file
+#    to you under the Apache License, Version 2.0 (the
+#    "License"); you may not use this file except in compliance
+#    with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing,
+#    software distributed under the License is distributed on an
+#    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#    KIND, either express or implied.  See the License for the
+#    specific language governing permissions and limitations
+#    under the License.
+######################################################################
+
+# General modules
+import shutil, sys, re, os
+import time
+
+# Our testing module
+import svntest
+from svntest import main, wc, verify, actions
+
+# (abbreviation)
+Item = wc.StateItem
+Skip = svntest.testcase.Skip_deco
+SkipUnless = svntest.testcase.SkipUnless_deco
+XFail = svntest.testcase.XFail_deco
+Issues = svntest.testcase.Issues_deco
+Issue = svntest.testcase.Issue_deco
+Wimp = svntest.testcase.Wimp_deco
+
+from svntest.main import SVN_PROP_MERGEINFO
+from svntest.main import server_has_mergeinfo
+from merge_tests import local_path
+from merge_tests import expected_merge_output
+from merge_tests import svn_merge
+from merge_tests import set_up_branch
+
+#----------------------------------------------------------------------
+
+# Merging scenarios to test
+#
+#   Merge once
+#
+#     A (--?---
+#       (    \
+#     B (--?--x
+#
+#   Merge twice in same direction
+#
+#     A (--o-----?---
+#       (    \     \
+#     B (--o--x--?--x
+#
+#   Merge to and fro
+#
+#     A (--o-----?--x
+#       (    \     /
+#     B (--o--x--?---
+#
+#     A (--o-----o-----?--x
+#       (    \     \     /
+#     B (--o--x--o--x--?---
+#
+#     A (--o-----o--x--?--x
+#       (    \     /     /
+#     B (--o--x--o-----?---
+#
+#     A (--o-----o--x--?---
+#       (    \     /     \
+#     B (--o--x--o-----?--x
+#
+#   Merge with cherry-picks
+#
+#     Cherry1, fwd
+#     A (--o-----o-[o]----o---
+#       (    \        \     \
+#     B (--o--x--?-----c-----x
+#
+#     Cherry2, fwd
+#     A (--o-----?-----c--o---
+#       (    \        /     \
+#     B (--o--x--o-[o]-------x
+#
+#     Cherry3, fwd
+#     A (--o-----?-------c--o----
+#       (    \_____     /     \
+#       (          \   /       \
+#     B (--o--o-[o]-x-/---------x
+#                 \__/
+#
+#     Cherry1, back
+#     A (--o-----o-[o]-------x
+#       (    \        \     /
+#     B (--o--x--?-----c--o---
+#
+#     Cherry2, back
+#     A (--o-----?-----c-----x
+#       (    \        /     /
+#     B (--o--x--o-[o]----o---
+#
+#     Cherry3, back
+#     A (--o-----?-------c------x
+#       (    \_____     /      /
+#       (          \   /      /
+#     B (--o--o-[o]-x-/-----o----
+#                 \__/
+#
+#   Criss-cross merge
+#
+#     A (--o--?--x--?----
+#       (    \ /     \
+#       (     X       \
+#       (    / \       \
+#     B (--o--?--x--?---x
+#
+#   Subtree mergeinfo
+#
+#     subtree to, fro
+#     A (--o-o-o-o---------x
+#       ( \         \     /
+#       (  \         \   /
+#     B (   o--o------s--
+#
+#     merge to, reverse cherry subtree to, merge to
+#     A (--o-o-o-o------------------
+#       ( \         \        \     \
+#       (  \         \        \     \
+#     B (   o--o------x-------rcs----x
+#
+#   Sparse WC
+#
+#     ...
+#
+#   Mixed-rev WC
+#
+#     ...
+#
+#
+# Key to diagrams:
+#
+#   o   - an original change
+#   ?   - an original change or no-op (test both)
+#   x   - a branch root merge
+#   c   - a cherry-pick merge
+#   [o] - source range of a cherry-pick merge
+#   s   - a subtree merge
+#   r   - reverse merge
+
+
+########################################################################
+
+def assert_equal(a, b):
+  """Assert that two generic Python objects are equal.  If not, raise an
+     exception giving their values.  Rationale:  During debugging, it's
+     easier to see what's wrong if we see the values rather than just
+     an indication that the assertion failed."""
+  if a != b:
+    raise Exception("assert_equal failed: a = (%s), b = (%s)" % (a, b))
+
+def logical_changes_in_branch(sbox, branch):
+  """Return the set of logical changes that are actually in branch BRANCH
+     (at its current working version), by examining the state of the
+     branch files and directories rather than its mergeinfo.
+
+     Each logical change is described by its branch and revision number
+     as a string such as 'A1'."""
+  changes = set()
+  for propname in sbox.simple_proplist(branch + '/D').keys():
+    if propname.startswith('prop-'):
+      changes.add(propname[5:])
+  return changes
+
+def get_mergeinfo_change(sbox, target):
+  """Return a list of revision numbers representing the mergeinfo change
+  on TARGET (working version against base).  Non-recursive."""
+  exit, out, err = actions.run_and_verify_svn(None, None, [],
+                                              'diff', '--depth=empty',
+                                              sbox.ospath(target))
+  merged_revs = []
+  for line in out:
+    match = re.match(r'   Merged /(\w+):r(.*)', line)
+    if match:
+      for r_range in match.group(2).split(','):
+        if '-' in r_range:
+          r_start, r_end = r_range.split('-')
+        else:
+          r_start = r_end = r_range
+        merged_revs += range(int(r_start), int(r_end) + 1)
+  return merged_revs
+
+def get_3ways_from_output(output):
+  """Scan the list of lines OUTPUT for indications of 3-way merges.
+     Return a list of (base, source-right) tuples."""
+  ### Problem: test suite strips debugging output within run_and_verify_...()
+  ### so we don't see it here.  And relying on debug output is a temporary
+  ### measure only.  Better to access svn_client_find_automatic_merge()
+  ### directly, via bindings?
+
+  merges = []
+  for line in output:
+    print "## " + line,
+    # Extract "A1" from a line like "DBG: merge.c:11336: base  svn://.../A@1"
+    match = re.search(r'merge\.c:.* base .* /(\w+)@([0-9-]+)', line)
+    if match:
+      base = match.group(1) + match.group(2)
+    match = re.search(r'merge\.c:.* right.* /(\w+)@([0-9-]+)', line)
+    if match:
+      right = match.group(1) + match.group(2)
+      assert base is not None
+      merges.append((base, right))
+      base = None
+  return merges
+
+def make_branches(sbox):
+  """Make branches A and B."""
+  sbox.build()
+  sbox.simple_copy('A', 'B')
+  sbox.simple_commit()
+  os.chdir(sbox.wc_dir)
+  sbox.wc_dir = ''
+
+def modify_branch(sbox, branch, number, conflicting=False):
+  """Commit a modification to branch BRANCH. The actual modification depends
+     on NUMBER.  If CONFLICTING=True, the change will be of a kind that
+     conflicts with any other change that has CONFLICTING=True.  We don't
+     modify (properties on) the branch root node itself, to make it easier
+     for the tests to distinguish mergeinfo changes from these mods."""
+  uniq = branch + str(number)  # something like 'A1' or 'B2'
+  if conflicting:
+    sbox.simple_propset('conflict', uniq, branch + '/C')
+  else:
+    # Make some changes.  We add a property, which we will read later in
+    # logical_changes_in_branch() to check that the correct logical
+    # changes were merged.  We add a file, so that we will notice if
+    # Subversion tries to merge this same logical change into a branch
+    # that already has it (it will raise a tree conflict).
+    sbox.simple_propset('prop-' + uniq, uniq, branch + '/D')
+    sbox.simple_copy(branch + '/mu', branch + '/mu-' + uniq)
+  sbox.simple_commit()
+
+def expected_automatic_merge_output(target, expect_3ways):
+  """Calculate the expected output."""
+
+  # (This is rather specific to the current implementation.)
+
+  # Match a notification for each rev-range.
+  if expect_3ways:
+    rev_ranges = []
+    for base, right in expect_3ways:
+      if base[0] == right[0]:
+        base_rev = int(base[1:])
+        right_rev = int(right[1:])
+        rev_ranges += [(base_rev + 1, right_rev)];
+  else:
+    rev_ranges = None
+
+  # Match any content modifications; but not of the root of the branch
+  # because we don't intentionally modify the branch root node in most
+  # tests and we don't want to accidentally overlook a mergeinfo change.
+  lines = ["(A |D |[UG] | [UG]|[UG][UG])   " + target + os.path.sep + ".*\n"]
+
+  # Match mergeinfo changes.  (### Subtrees are not yet supported here.)
+  lines += [" [UG]   " + target + "\n"]
+
+  # At the moment, the automatic merge code sometimes says 'Merging
+  # differences between repository URLs' and sometimes 'Merging r3 through
+  # r5', but it's not trivial to predict which, so expect either form.
+  lines += ["--- Merging .* into '%s':\n" % (target,),
+            "--- Recording mergeinfo for merge .* into '%s':\n" % (target,)]
+
+  return expected_merge_output(rev_ranges, lines, target=target)
+
+def automatic_merge(sbox, source, target, args=[],
+                    expect_changes=None, expect_mi=None, expect_3ways=None):
+  """Do a complete, automatic merge from path SOURCE to path TARGET, and
+  commit.  Verify the output and that there is no error.
+  ### TODO: Verify the changes made.
+
+  ARGS are additional arguments passed to svn merge."""
+
+  source = local_path(source)
+  target = local_path(target)
+
+  # First, update the WC target because mixed-rev is not fully supported.
+  sbox.simple_update(target)
+
+  before_changes = logical_changes_in_branch(sbox, target)
+
+  exp_out = expected_automatic_merge_output(target, expect_3ways)
+  exit, out, err = svntest.actions.run_and_verify_svn(None, exp_out, [],
+                                     'merge',
+                                     '^/' + source, target,
+                                     *args)
+
+  if expect_changes is not None:
+    after_changes = logical_changes_in_branch(sbox, target)
+    merged_changes = after_changes - before_changes
+    assert_equal(merged_changes, set(expect_changes))
+    reversed_changes = before_changes - after_changes
+    assert_equal(reversed_changes, set())
+
+  if expect_mi is not None:
+    actual_mi_change = get_mergeinfo_change(sbox, target)
+    assert_equal(actual_mi_change, expect_mi)
+
+  if expect_3ways is not None:
+    ### actual_3ways = get_3ways_from_output(out)
+    ### assert_equal(actual_3ways, expect_3ways)
+    pass
+
+  sbox.simple_commit()
+
+def three_way_merge(base_node, source_right_node):
+  return (base_node, source_right_node)
+
+def three_way_merge_no_op(base_node, source_right_node):
+  return (base_node, source_right_node)
+
+def cherry_pick(sbox, rev, source, target):
+  """Cherry-pick merge revision REV from branch SOURCE to branch TARGET
+  (both WC-relative paths), and commit."""
+  sbox.simple_update(target)
+  svn_merge(rev, source, target)
+  sbox.simple_commit()
+
+no_op_commit__n = 0
+def no_op_commit(sbox):
+  """Commit a new revision that does not affect the branches under test."""
+
+  global no_op_commit__n
+  sbox.simple_propset('foo', str(no_op_commit__n), 'iota')
+  no_op_commit__n += 1
+  sbox.simple_commit('iota')
+
+
+#----------------------------------------------------------------------
+
+def init_mod_merge_mod(sbox, mod_6, mod_7):
+  """Modify both branches, merge A -> B, optionally modify again.
+     MOD_6 is True to modify A in r6, MOD_7 is True to modify B in r7,
+     otherwise make no-op commits for r6 and/or r7."""
+
+  #   A (--o------?-
+  #     (     \
+  #   B (---o--x---?
+  #     2  34  5  67
+
+  make_branches(sbox)
+  modify_branch(sbox, 'A', 3)
+  modify_branch(sbox, 'B', 4)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A3'],
+                  expect_mi=[2, 3, 4],
+                  expect_3ways=[three_way_merge('A1', 'A4')])
+
+  if mod_6:
+    modify_branch(sbox, 'A', 6)
+  else:
+    no_op_commit(sbox)  # r6
+
+  if mod_7:
+    modify_branch(sbox, 'B', 7)
+  else:
+    no_op_commit(sbox)  # r7
+
+########################################################################
+
+# Merge once
+
+@SkipUnless(server_has_mergeinfo)
+def merge_once_1(sbox):
+  """merge_once_1"""
+
+  #   A (------
+  #     (    \
+  #   B (-----x
+  #     2 34  5
+
+  make_branches(sbox)
+  no_op_commit(sbox)  # r3
+  no_op_commit(sbox)  # r4
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=[],
+                  expect_mi=[2, 3, 4],
+                  expect_3ways=[three_way_merge_no_op('A1', 'A4')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_once_2(sbox):
+  """merge_once_2"""
+
+  #   A (-o----
+  #     (    \
+  #   B (-----x
+  #     2 34  5
+
+  make_branches(sbox)
+  modify_branch(sbox, 'A', 3)
+  no_op_commit(sbox)  # r4
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A3'],
+                  expect_mi=[2, 3, 4],
+                  expect_3ways=[three_way_merge('A1', 'A4')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_once_3(sbox):
+  """merge_once_3"""
+
+  #   A (------
+  #     (    \
+  #   B (--o--x
+  #     2 34  5
+
+  make_branches(sbox)
+  no_op_commit(sbox)  # r3
+  modify_branch(sbox, 'B', 4)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=[],
+                  expect_mi=[2, 3, 4],
+                  expect_3ways=[three_way_merge_no_op('A1', 'A4')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_once_4(sbox):
+  """merge_once_4"""
+
+  #   A (-o----
+  #     (    \
+  #   B (--o--x
+  #     2 34  5
+
+  make_branches(sbox)
+  modify_branch(sbox, 'A', 3)
+  modify_branch(sbox, 'B', 4)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A3'],
+                  expect_mi=[2, 3, 4],
+                  expect_3ways=[three_way_merge('A1', 'A4')])
+
+#----------------------------------------------------------------------
+
+# Merge twice in same direction
+
+@SkipUnless(server_has_mergeinfo)
+def merge_twice_same_direction_1(sbox):
+  """merge_twice_same_direction_1"""
+
+  #   A (--o-----------
+  #     (     \      \
+  #   B (---o--x------x
+  #     2  34  5  67  8
+
+  init_mod_merge_mod(sbox, mod_6=False, mod_7=False)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=[],
+                  expect_mi=[5, 6, 7],
+                  expect_3ways=[three_way_merge_no_op('A4', 'A7')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_twice_same_direction_2(sbox):
+  """merge_twice_same_direction_2"""
+
+  #   A (--o------o----
+  #     (     \      \
+  #   B (---o--x---o--x
+  #     2  34  5  67  8
+
+  init_mod_merge_mod(sbox, mod_6=True, mod_7=True)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A6'],
+                  expect_mi=[5, 6, 7],
+                  expect_3ways=[three_way_merge('A4', 'A7')])
+
+#----------------------------------------------------------------------
+
+#   Merge to and fro
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_1_1(sbox):
+  """merge_to_and_fro_1_1"""
+
+  #   A (--o----------x
+  #     (     \      /
+  #   B (---o--x-------
+  #     2  34  5  67  8
+
+  init_mod_merge_mod(sbox, mod_6=False, mod_7=False)
+
+  automatic_merge(sbox, 'B', 'A',
+                  expect_changes=['B4'],
+                  expect_mi=[2, 3, 4, 5, 6, 7],
+                  expect_3ways=[three_way_merge('A4', 'B7')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_1_2(sbox):
+  """merge_to_and_fro_1_2"""
+
+  #   A (--o------o---x
+  #     (     \      /
+  #   B (---o--x---o---
+  #     2  34  5  67  8
+
+  init_mod_merge_mod(sbox, mod_6=True, mod_7=True)
+
+  automatic_merge(sbox, 'B', 'A',
+                  expect_changes=['B4', 'B7'],
+                  expect_mi=[2, 3, 4, 5, 6, 7],
+                  expect_3ways=[three_way_merge('A4', 'B7')])
+
+def init_merge_to_and_fro_2(sbox, mod_9, mod_10):
+  """Set up branches A and B for the merge_to_and_fro_2 scenarios.
+     MOD_9 is True to modify A in r9, MOD_10 is True to modify B in r10,
+     otherwise make no-op commits for r9 and/or r10."""
+
+  #   A (--o------o------?-
+  #     (     \      \
+  #   B (---o--x---o--x---?
+  #     2  34  5  67  8--90
+
+  init_mod_merge_mod(sbox, mod_6=True, mod_7=True)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A6'],
+                  expect_mi=[5, 6, 7],
+                  expect_3ways=[three_way_merge('A4', 'A7')])
+
+  if mod_9:
+    modify_branch(sbox, 'A', 9)
+  else:
+    no_op_commit(sbox)  # r9
+
+  if mod_10:
+    modify_branch(sbox, 'B', 10)
+  else:
+    no_op_commit(sbox)  # r10
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_2_1(sbox):
+  """merge_to_and_fro_2_1"""
+
+  #   A (--o------o----------x
+  #     (     \      \      /
+  #   B (---o--x---o--x-------
+  #     2  34  5  67  8  90  1
+
+  init_merge_to_and_fro_2(sbox, mod_9=False, mod_10=False)
+
+  automatic_merge(sbox, 'B', 'A',
+                  expect_changes=['B4', 'B7'],
+                  expect_mi=[2, 3, 4, 5, 6, 7, 8, 9, 10],
+                  expect_3ways=[three_way_merge('A7', 'B10')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_2_2(sbox):
+  """merge_to_and_fro_2_2"""
+
+  #   A (--o------o------o---x
+  #     (     \      \      /
+  #   B (---o--x---o--x---o---
+  #     2  34  5  67  8  90  1
+
+  init_merge_to_and_fro_2(sbox, mod_9=True, mod_10=True)
+
+  automatic_merge(sbox, 'B', 'A',
+                  expect_changes=['B4', 'B7', 'B10'],
+                  expect_mi=[2, 3, 4, 5, 6, 7, 8, 9, 10],
+                  expect_3ways=[three_way_merge('A7', 'B10')])
+
+def init_merge_to_and_fro_3(sbox, mod_9, mod_10):
+  """Set up branches A and B for the merge_to_and_fro_3/4 scenarios.
+     MOD_9 is True to modify A in r9, MOD_10 is True to modify B in r10,
+     otherwise make no-op commits for r9 and/or r10."""
+
+  #   A (--o------o---x--?-
+  #     (     \      /
+  #   B (---o--x---o------?
+  #     2  34  5  67  8  90
+
+  init_mod_merge_mod(sbox, mod_6=True, mod_7=True)
+
+  automatic_merge(sbox, 'B', 'A',
+                  expect_changes=['B4', 'B7'],
+                  expect_mi=[2, 3, 4, 5, 6, 7],
+                  expect_3ways=[three_way_merge('A4', 'B7')])
+
+  if mod_9:
+    modify_branch(sbox, 'A', 9)
+  else:
+    no_op_commit(sbox)  # r9
+
+  if mod_10:
+    modify_branch(sbox, 'B', 10)
+  else:
+    no_op_commit(sbox)  # r10
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_3_1(sbox):
+  """merge_to_and_fro_3_1"""
+
+  #   A (--o------o---x------x
+  #     (     \      /      /
+  #   B (---o--x---o----------
+  #     2  34  5  67  8  90  1
+
+  init_merge_to_and_fro_3(sbox, mod_9=False, mod_10=False)
+
+  automatic_merge(sbox, 'B', 'A',
+                  expect_changes=[],
+                  expect_mi=[8, 9, 10],
+                  expect_3ways=[three_way_merge_no_op('B7', 'B10')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_3_2(sbox):
+  """merge_to_and_fro_3_2"""
+
+  #   A (--o------o---x--o---x
+  #     (     \      /      /
+  #   B (---o--x---o------o---
+  #     2  34  5  67  8  90  1
+
+  init_merge_to_and_fro_3(sbox, mod_9=True, mod_10=True)
+
+  automatic_merge(sbox, 'B', 'A',
+                  expect_changes=['B10'],
+                  expect_mi=[8, 9, 10],
+                  expect_3ways=[three_way_merge('B7', 'B10')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_4_1(sbox):
+  """merge_to_and_fro_4_1"""
+
+  #   A (--o------o---x-------
+  #     (     \      /      \
+  #   B (---o--x---o---------x
+  #     2  34  5  67  8  90  1
+
+  init_merge_to_and_fro_3(sbox, mod_9=False, mod_10=False)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A6'],
+                  expect_mi=[5, 6, 7, 8, 9, 10],
+                  expect_3ways=[three_way_merge_no_op('B7', 'A10')])
+
+@SkipUnless(server_has_mergeinfo)
+def merge_to_and_fro_4_2(sbox):
+  """merge_to_and_fro_4_2"""
+
+  #   A (--o------o---x--o----
+  #     (     \      /      \
+  #   B (---o--x---o------o--x
+  #     2  34  5  67  8  90  1
+
+  init_merge_to_and_fro_3(sbox, mod_9=True, mod_10=True)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A6', 'A9'],
+                  expect_mi=[5, 6, 7, 8, 9, 10],
+                  expect_3ways=[three_way_merge('B7', 'A10')])
+
+#----------------------------------------------------------------------
+
+# Cherry-pick scenarios
+
+@SkipUnless(server_has_mergeinfo)
+def cherry1_fwd(sbox):
+  """cherry1_fwd"""
+
+  #   A (--o------o--[o]----o---
+  #     (     \         \     \
+  #   B (---o--x---------c-----x
+  #     2  34  5  67  8  9  0  1
+
+  init_mod_merge_mod(sbox, mod_6=True, mod_7=False)
+  modify_branch(sbox, 'A', 8)
+  cherry_pick(sbox, 8, 'A', 'B')
+  modify_branch(sbox, 'A', 10)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A6', 'A10'],  # and NOT A8
+                  expect_mi=[5, 6, 7, 9, 10],
+                  expect_3ways=[three_way_merge('A4', 'A7'),
+                                three_way_merge('A8', 'A10')])
+
+@SkipUnless(server_has_mergeinfo)
+@XFail()
+def cherry2_fwd(sbox):
+  """cherry2_fwd"""
+
+  #   A (--o-------------c--o---
+  #     (     \         /     \
+  #   B (---o--x---o-[o]-------x
+  #     2  34  5  67  8  9  0  1
+
+  init_mod_merge_mod(sbox, mod_6=False, mod_7=True)
+  modify_branch(sbox, 'B', 8)
+  cherry_pick(sbox, 8, 'B', 'A')
+  modify_branch(sbox, 'A', 10)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A10'],  # and NOT A9
+                  expect_mi=[5, 6, 7, 8, 9, 10],
+                  expect_3ways=[three_way_merge('A9', 'A10')])
+
+@SkipUnless(server_has_mergeinfo)
+@XFail()
+def cherry3_fwd(sbox):
+  """cherry3_fwd"""
+
+  #   A (--o--------------c--o----
+  #     (          \     /     \
+  #     (           \   /       \
+  #   B (---o--o-[o]-x-/---------x
+  #               \__/
+  #     2  34  5  6  7    8  9   0
+
+  make_branches(sbox)
+  modify_branch(sbox, 'A', 3)
+  modify_branch(sbox, 'B', 4)
+  modify_branch(sbox, 'B', 5)
+  modify_branch(sbox, 'B', 6)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A3'],
+                  expect_mi=[2, 3, 4, 5, 6],
+                  expect_3ways=[three_way_merge('A1', 'A6')])
+
+  cherry_pick(sbox, 6, 'B', 'A')
+  modify_branch(sbox, 'A', 9)
+
+  automatic_merge(sbox, 'A', 'B',
+                  expect_changes=['A9'],  # and NOT A8
+                  expect_mi=[7, 8, 9],
+                  expect_3ways=[three_way_merge('A8', 'A9')])
+
+#----------------------------------------------------------------------
+# Automatic merges ignore subtree mergeinfo during reintegrate.
+@SkipUnless(server_has_mergeinfo)
+@XFail()
+def subtree_to_and_fro(sbox):
+  "reintegrate considers source subtree mergeinfo"
+
+#     A (--o-o-o-o---------x
+#       ( \         \     /
+#       (  \         \   /
+#     B (   o--o------s--
+
+  # Some paths we'll care about.
+  A_COPY_gamma_path = sbox.ospath('A_COPY/D/gamma')
+  psi_path = sbox.ospath('A/D/H/psi')
+  A_COPY_D_path = sbox.ospath('A_COPY/D')
+  A_path = sbox.ospath('A')
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # Setup a simple 'trunk & branch': Copy ^/A to ^/A_COPY in r2 and then
+  # make a few edits under A in r3-6:
+  wc_disk, wc_status = set_up_branch(sbox)
+
+  # r7 - Edit a file on the branch.
+  svntest.main.file_write(A_COPY_gamma_path, "Branch edit to 'gamma'.\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir,
+                                     '-m', 'Edit a file on our branch')
+
+  # r8 - Do a subtree sync merge from ^/A/D to A_COPY/D.
+  # Note that among other things this changes A_COPY/D/H/psi.
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+                                     sbox.repo_url + '/A/D', A_COPY_D_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir,
+                                     '-m', 'Automatic subtree merge')
+
+  # r9 - Make an edit to A/D/H/psi.
+  svntest.main.file_write(psi_path, "Trunk Edit to 'psi'.\n")
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir,
+                                     '-m', 'Edit a file on our trunk')
+
+  # Now reintegrate ^/A_COPY back to A.  To the automatic merge code the
+  # subtree merge to A_COPY/D just looks like any other branch edit, it is
+  # not considered a merge.  So the changes which exist on A/D and were
+  # merged to A_COPY/D, are merged *back* to A, resulting in a conflict:
+  #
+  #   C:\SVN\src-trunk\Debug\subversion\tests\cmdline\svn-test-work\
+  #     working_copies\merge_automatic_tests-18>svn merge ^^/A_COPY A
+  #   DBG: merge.c:11461: base on source: file:///C:/SVN/src-trunk/Debug/
+  #     subversion/tests/cmdline/svn-test-work/repositories/
+  #     merge_automatic_tests-18/A@1
+  #   DBG: merge.c:11462: base on target: file:///C:/SVN/src-trunk/Debug/
+  #     subversion/tests/cmdline/svn-test-work/repositories/
+  #     merge_automatic_tests-18/A@1
+  #   DBG: merge.c:11567: yca   file:///C:/SVN/src-trunk/Debug/subversion/
+  #     tests/cmdline/svn-test-work/repositories/merge_automatic_tests-18/A@1
+  #   DBG: merge.c:11568: base  file:///C:/SVN/src-trunk/Debug/subversion/
+  #     tests/cmdline/svn-test-work/repositories/merge_automatic_tests-18/A@1
+  #   DBG: merge.c:11571: right file:///C:/SVN/src-trunk/Debug/subversion/
+  #     tests/cmdline/svn-test-work/repositories/merge_automatic_tests-18/
+  #     A_COPY@8
+  #   Conflict discovered in file 'A\D\H\psi'.
+  #   Select: (p) postpone, (df) diff-full, (e) edit,
+  #           (mc) mine-conflict, (tc) theirs-conflict,
+  #           (s) show all options: p
+  #   --- Merging r2 through r9 into 'A':
+  #   C    A\D\H\psi
+  #   U    A\D\gamma
+  #   --- Recording mergeinfo for merge of r2 through r9 into 'A':
+  #    U   A
+  #   Summary of conflicts:
+  #     Text conflicts: 1
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  exit_code, out, err = svntest.actions.run_and_verify_svn(
+    None, [], svntest.verify.AnyOutput,
+    'merge', sbox.repo_url + '/A_COPY', A_path)
+
+  # The 'old' merge produced a warning that reintegrate could not be used.
+  # Not claiming this is perfect, but it's better(?) than a conflict:
+  svntest.verify.verify_outputs("Automatic Reintegrate failed, but not "
+                                "in the way expected",
+                                err, None,
+                                "(svn: E195016: Reintegrate can only be used if "
+                                "revisions 2 through 9 were previously "
+                                "merged from .*/A to the reintegrate source, "
+                                "but this is not the case:\n)"
+                                "|(  A_COPY\n)"
+                                "|(    Missing ranges: /A:5\n)"
+                                "|(\n)"
+                                "|(.*apr_err.*)", # In case of debug build
+                                None,
+                                True) # Match *all* lines of stdout  
+
+#----------------------------------------------------------------------
+# Automatic merges ignore subtree mergeinfo gaps older than the last rev
+# synced to the target root.
+@SkipUnless(server_has_mergeinfo)
+def merge_to_reverse_cherry_subtree_to_merge_to(sbox):
+  "sync merge considers target subtree mergeinfo"
+
+  #   A (--o-o-o-o------------------
+  #     ( \         \        \     \
+  #     (  \         \        \     \
+  #   B (   o--o------x-------rc-----x
+
+  # Some paths we'll care about.
+  A_COPY_path = sbox.ospath('A_COPY')
+  A_COPY_B_path = sbox.ospath('A_COPY/B')
+  A_COPY_beta_path = sbox.ospath('A_COPY/B/E/beta')
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # Setup a simple 'trunk & branch': Copy ^/A to ^/A_COPY in r2 and then
+  # make a few edits under A in r3-6:
+  wc_disk, wc_status = set_up_branch(sbox)
+
+  # Sync merge ^/A to A_COPY, then reverse merge r5 from ^/A/B to A_COPY/B.
+  # This results in mergeinfo on the target which makes it appear that the
+  # branch is synced up to r6, but the subtree mergeinfo on A_COPY/B reveals
+  # that r5 has not been merged to that subtree:
+  #
+  #   Properties on 'A_COPY':
+  #     svn:mergeinfo
+  #       /A:2-6
+  #   Properties on 'A_COPY\B':
+  #     svn:mergeinfo
+  #       /A/B:2-4,6
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+                                     sbox.repo_url + '/A', A_COPY_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge', '-c-5',
+                                     sbox.repo_url + '/A/B',
+                                     A_COPY_B_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', wc_dir, '-m',
+                                     'sync merge and reverse subtree merge')
+
+  # Try an automatic sync merge from ^/A to A_COPY.  Revision 5 should be
+  # merged to A_COPY/B as its subtree mergeinfo reveals that rev is missing,
+  # like so:
+  # 
+  #   >svn merge ^/A A_COPY
+  #   --- Merging r5 into 'A_COPY\B':
+  #   U    A_COPY\B\E\beta
+  #   --- Recording mergeinfo for merge of r5 through r7 into 'A_COPY':
+  #    U   A_COPY
+  #   --- Recording mergeinfo for merge of r5 through r7 into 'A_COPY\B':
+  #    U   A_COPY\B
+  #   --- Eliding mergeinfo from 'A_COPY\B':
+  #    U   A_COPY\B
+  #
+  # But the merge ignores the subtree mergeinfo and considers
+  # only the mergeinfo on the target itself (and thus is a no-op but for
+  # the mergeinfo change on the root of the merge target):
+  #
+  #   >svn merge ^/A A_COPY
+  #   --- Recording mergeinfo for merge of r7 into 'A_COPY':
+  #    U   A_COPY
+  #
+  #   >svn diff
+  #   Index: A_COPY
+  #   ===================================================================
+  #   --- A_COPY      (revision 7)
+  #   +++ A_COPY      (working copy)
+  #
+  #   Property changes on: A_COPY
+  #   ___________________________________________________________________
+  #   Modified: svn:mergeinfo
+  #      Merged /A:r7
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  expected_output = wc.State(A_COPY_path, {
+    'B/E/beta'   : Item(status='U '),
+    })
+  expected_mergeinfo_output = wc.State(A_COPY_path, {
+    ''  : Item(status=' U'),
+    'B' : Item(status=' U'),
+    })
+  expected_elision_output = wc.State(A_COPY_path, {
+    'B' : Item(status=' U'),
+    })
+  expected_status = wc.State(A_COPY_path, {
+    ''           : Item(status=' M'),
+    'B'          : Item(status=' M'),
+    'mu'         : Item(status='  '),
+    'B/E'        : Item(status='  '),
+    'B/E/alpha'  : Item(status='  '),
+    'B/E/beta'   : Item(status='M '),
+    'B/lambda'   : Item(status='  '),
+    'B/F'        : Item(status='  '),
+    'C'          : Item(status='  '),
+    'D'          : Item(status='  '),
+    'D/G'        : Item(status='  '),
+    'D/G/pi'     : Item(status='  '),
+    'D/G/rho'    : Item(status='  '),
+    'D/G/tau'    : Item(status='  '),
+    'D/gamma'    : Item(status='  '),
+    'D/H'        : Item(status='  '),
+    'D/H/chi'    : Item(status='  '),
+    'D/H/psi'    : Item(status='  '),
+    'D/H/omega'  : Item(status='  '),
+    })
+  expected_status.tweak(wc_rev='7')
+  expected_disk = wc.State('', {
+    ''           : Item(props={SVN_PROP_MERGEINFO : '/A:2-7'}),
+    'B'          : Item(),
+    'mu'         : Item("This is the file 'mu'.\n"),
+    'B/E'        : Item(),
+    'B/E/alpha'  : Item("This is the file 'alpha'.\n"),
+    'B/E/beta'   : Item("New content"),
+    'B/lambda'   : Item("This is the file 'lambda'.\n"),
+    'B/F'        : Item(),
+    'C'          : Item(),
+    'D'          : Item(),
+    'D/G'        : Item(),
+    'D/G/pi'     : Item("This is the file 'pi'.\n"),
+    'D/G/rho'    : Item("New content"),
+    'D/G/tau'    : Item("This is the file 'tau'.\n"),
+    'D/gamma'    : Item("This is the file 'gamma'.\n"),
+    'D/H'        : Item(),
+    'D/H/chi'    : Item("This is the file 'chi'.\n"),
+    'D/H/psi'    : Item("New content"),
+    'D/H/omega'  : Item("New content"),
+    })
+  expected_skip = wc.State(A_COPY_path, { })
+  svntest.actions.run_and_verify_merge(A_COPY_path, None, None,
+                                       sbox.repo_url + '/A', None,
+                                       expected_output,
+                                       expected_mergeinfo_output,
+                                       expected_elision_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, None, None, None,
+                                       None, 1, 0, A_COPY_path)
+
+########################################################################
+# Run the tests
+
+
+# list all tests here, starting with None:
+test_list = [ None,
+              merge_once_1,
+              merge_once_2,
+              merge_once_3,
+              merge_once_4,
+              merge_twice_same_direction_1,
+              merge_twice_same_direction_2,
+              merge_to_and_fro_1_1,
+              merge_to_and_fro_1_2,
+              merge_to_and_fro_2_1,
+              merge_to_and_fro_2_2,
+              merge_to_and_fro_3_1,
+              merge_to_and_fro_3_2,
+              merge_to_and_fro_4_1,
+              merge_to_and_fro_4_2,
+              cherry1_fwd,
+              cherry2_fwd,
+              cherry3_fwd,
+              subtree_to_and_fro,
+              merge_to_reverse_cherry_subtree_to_merge_to,
+             ]
+
+if __name__ == '__main__':
+  svntest.main.run_tests(test_list)
+  # NOTREACHED
+
+
+### End of file.

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tests.py Sat Nov 24 20:29:11 2012
@@ -5799,14 +5799,14 @@ def merge_to_path_with_switched_children
   expected_mergeinfo_output = wc.State(A_COPY_D_path, {
     ''      : Item(status=' G'),
     'H'     : Item(status=' G'),
-    'H/psi' : Item(status=' G')
+    'H/psi' : Item(status=' U')
     })
   expected_elision_output = wc.State(A_COPY_D_path, {
     })
   expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5,6*'})
   expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'})
   expected_disk_D.tweak('H/psi', contents="New content",
-                        props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5,8'})
+                        props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5'})
   expected_status_D.tweak('H/psi', status='MM')
   svntest.actions.run_and_verify_merge(A_COPY_D_path, '4', '5',
                                        sbox.repo_url + '/A/D', None,
@@ -5869,7 +5869,7 @@ def merge_to_path_with_switched_children
     'D/H'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'}),
     'D/H/chi'   : Item("This is the file 'chi'.\n"),
     'D/H/psi'   : Item("New content",
-                       props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5,8'}),
+                       props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5'}),
     'D/H/omega' : Item("New content"),
     })
   expected_skip = wc.State(A_COPY_path, { })
@@ -17826,6 +17826,60 @@ def merge_with_added_subtrees_with_merge
                                        None, None, None, None,
                                        None, 1, 0)
 
+#----------------------------------------------------------------------
+@SkipUnless(server_has_mergeinfo)
+def merge_with_externals_with_mergeinfo(sbox):
+  "merge with externals with mergeinfo"
+
+  # Some paths we'll care about.
+  A_path = sbox.ospath('A')
+  A_COPY_path = sbox.ospath('A_COPY')
+  file_external_path = sbox.ospath('A/file-external')
+  mu_COPY_path = sbox.ospath('A_COPY/mu')
+  mu_path = sbox.ospath('A/mu')
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # Make a branch of ^/A and then make a few edits under A in r3-6:
+  wc_disk, wc_status = set_up_branch(sbox)
+
+  svntest.main.file_write(mu_COPY_path, "branch edit")
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'file edit on the branch', wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+
+  # Create a file external under 'A' and set some bogus mergeinfo
+  # on it (the fact that this mergeinfo is bogus has no bearing on
+  # this test).
+  svntest.actions.run_and_verify_svn(None, None, [], 'propset',
+                                     'svn:externals',
+                                     '^/iota file-external', A_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'set file external', wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [], 'up', wc_dir)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ps', SVN_PROP_MERGEINFO,
+                                     "/bogus-mergeinfo:5", file_external_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'set mergeinfo on file external',
+                                     file_external_path)
+
+  # Sync merge ^/A to A_COPY and then reintegrate A_COPY back to A.
+  svntest.actions.run_and_verify_svn(None, None, [], 'merge',
+                                     sbox.repo_url + '/A', A_COPY_path)
+  svntest.actions.run_and_verify_svn(None, None, [], 'ci', '-m',
+                                     'sync merge', wc_dir)
+  # This was segfaulting, see
+  # http://svn.haxx.se/dev/archive-2012-10/0364.shtml
+  svntest.actions.run_and_verify_svn(
+    None,
+    expected_merge_output(None,
+                          ['U    ' + mu_path + '\n',
+                           ' U   ' + A_path  + '\n'],
+                          two_url=True),
+    [], 'merge', '--reintegrate', sbox.repo_url + '/A_COPY',
+    A_path)
+
 ########################################################################
 # Run the tests
 
@@ -17961,6 +18015,7 @@ test_list = [ None,
               reverse_merge_with_rename,
               merge_adds_then_deletes_subtree,
               merge_with_added_subtrees_with_mergeinfo,
+              merge_with_externals_with_mergeinfo,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tree_conflict_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tree_conflict_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/merge_tree_conflict_tests.py Sat Nov 24 20:29:11 2012
@@ -1671,7 +1671,6 @@ def merge_replace_setup(sbox):
 
 #----------------------------------------------------------------------
 # ra_serf causes duplicate notifications with this test:
-@XFail(svntest.main.is_ra_type_dav_serf)
 @Issue(3802)
 def merge_replace_causes_tree_conflict(sbox):
   "replace vs. edit tree-conflicts"

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/mergeinfo_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/mergeinfo_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/mergeinfo_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/mergeinfo_tests.py Sat Nov 24 20:29:11 2012
@@ -72,7 +72,8 @@ def no_mergeinfo(sbox):
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
                                            [],
                                            sbox.repo_url + '/A',
-                                           sbox.repo_url + '/A2')
+                                           sbox.repo_url + '/A2',
+                                           "--show-revs=merged")
 
 def mergeinfo(sbox):
   "'mergeinfo' on a path with mergeinfo"
@@ -94,7 +95,8 @@ def mergeinfo(sbox):
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
                                            ['3'],
                                            sbox.repo_url + '/A',
-                                           sbox.ospath('A2'))
+                                           sbox.ospath('A2'),
+                                           "--show-revs=merged")
 
 @SkipUnless(server_has_mergeinfo)
 def explicit_mergeinfo_source(sbox):
@@ -132,13 +134,17 @@ def explicit_mergeinfo_source(sbox):
 
   # Check using each of our recorded merge sources (as paths and URLs).
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
-                                           ['2', '4'], url(B2), path(B))
+                                           ['2', '4'], url(B2), path(B),
+                                           "--show-revs=merged")
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
-                                           ['2', '4'], path(B2), path(B))
+                                           ['2', '4'], path(B2), path(B),
+                                           "--show-revs=merged")
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
-                                           ['3', '5'], url(B3), path(B))
+                                           ['3', '5'], url(B3), path(B),
+                                           "--show-revs=merged")
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
-                                           ['3', '5'], path(B3), path(B))
+                                           ['3', '5'], path(B3), path(B),
+                                           "--show-revs=merged")
 
 @SkipUnless(server_has_mergeinfo)
 def mergeinfo_non_source(sbox):
@@ -162,7 +168,8 @@ def mergeinfo_non_source(sbox):
 
   # Check on a source we haven't "merged" from.
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
-                                           [], H2_url, H_path)
+                                           [], H2_url, H_path,
+                                           "--show-revs=merged")
 
 #----------------------------------------------------------------------
 # Issue #3138
@@ -238,7 +245,8 @@ def non_inheritable_mergeinfo(sbox):
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
                                            ['4','6*'],
                                            sbox.repo_url + '/A',
-                                           A_COPY_path)
+                                           A_COPY_path,
+                                           '--show-revs', 'merged')
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
                                            ['3','5','6*'],
                                            sbox.repo_url + '/A',
@@ -249,7 +257,8 @@ def non_inheritable_mergeinfo(sbox):
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
                                            ['4'],
                                            sbox.repo_url + '/A/D',
-                                           D_COPY_path)
+                                           D_COPY_path,
+                                           '--show-revs', 'merged')
   svntest.actions.run_and_verify_mergeinfo(adjust_error_for_server_version(""),
                                            ['3','6'],
                                            sbox.repo_url + '/A/D',

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/patch_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/patch_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/patch_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/patch_tests.py Sat Nov 24 20:29:11 2012
@@ -3997,24 +3997,57 @@ def patch_target_no_eol_at_eof(sbox):
 
   patch_file_path = make_patch_path(sbox)
   iota_path = sbox.ospath('iota')
+  mu_path = sbox.ospath('A/mu')
 
   iota_contents = [
     "This is the file iota."
   ]
 
+  mu_contents = [
+    "context\n",
+    "context\n",
+    "context\n",
+    "context\n",
+    "This is the file mu.\n",
+    "context\n",
+    "context\n",
+    "context\n",
+    "context", # no newline at end of file
+  ]
+
   svntest.main.file_write(iota_path, ''.join(iota_contents))
+  svntest.main.file_write(mu_path, ''.join(mu_contents))
   expected_output = svntest.wc.State(wc_dir, {
     'iota'  : Item(verb='Sending'),
+    'A/mu'  : Item(verb='Sending'),
     })
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
   expected_status.tweak('iota', wc_rev=2)
+  expected_status.tweak('A/mu', wc_rev=2)
   svntest.actions.run_and_verify_commit(wc_dir, expected_output,
                                         expected_status, None, wc_dir)
   unidiff_patch = [
-    "--- iota\t(revision 1)\n",
+    "Index: A/mu\n",
+    "===================================================================\n",
+    "--- A/mu\t(revision 2)\n",
+    "+++ A/mu\t(working copy)\n",
+    "@@ -2,8 +2,8 @@ context\n",
+    " context\n",
+    " context\n",
+    " context\n",
+    "-This is the file mu.\n",
+    "+It is really the file mu.\n",
+    " context\n",
+    " context\n",
+    " context\n",
+    " context\n",
+    "\\ No newline at end of file\n",
+    "Index: iota\n",
+    "===================================================================\n",
+    "--- iota\t(revision 2)\n",
     "+++ iota\t(working copy)\n",
-    "@@ -1,7 +1,7 @@\n",
-    "-This is the file iota.\n"
+    "@@ -1 +1 @@\n",
+    "-This is the file iota.\n",
     "\\ No newline at end of file\n",
     "+It is really the file 'iota'.\n",
     "\\ No newline at end of file\n",
@@ -4025,15 +4058,29 @@ def patch_target_no_eol_at_eof(sbox):
   iota_contents = [
     "It is really the file 'iota'."
   ]
+  mu_contents = [
+    "context\n",
+    "context\n",
+    "context\n",
+    "context\n",
+    "It is really the file mu.\n",
+    "context\n",
+    "context\n",
+    "context\n",
+    "context", # no newline at end of file
+  ]
   expected_output = [
+    'U         %s\n' % sbox.ospath('A/mu'),
     'U         %s\n' % sbox.ospath('iota'),
   ]
 
   expected_disk = svntest.main.greek_state.copy()
   expected_disk.tweak('iota', contents=''.join(iota_contents))
+  expected_disk.tweak('A/mu', contents=''.join(mu_contents))
 
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
   expected_status.tweak('iota', status='M ', wc_rev=2)
+  expected_status.tweak('A/mu', status='M ', wc_rev=2)
 
   expected_skip = wc.State('', { })
 
@@ -4099,6 +4146,61 @@ def patch_add_and_delete(sbox):
                                        1, # check-props
                                        1) # dry-run
 
+
+def patch_git_with_index_line(sbox):
+  "apply git patch with 'index' line"
+
+  sbox.build(read_only = True)
+  wc_dir = sbox.wc_dir
+  patch_file_path = make_patch_path(sbox)
+
+  unidiff_patch = [
+    "diff --git a/src/tools/ConsoleRunner/hi.txt b/src/tools/ConsoleRunner/hi.txt\n",
+    "new file mode 100644\n",
+    "index 0000000..c82a38f\n",
+    "--- /dev/null\n",
+    "+++ b/src/tools/ConsoleRunner/hi.txt\n",
+    "@@ -0,0 +1 @@\n",
+    "+hihihihihihi\n",
+    "\ No newline at end of file\n",
+  ]
+
+  svntest.main.file_write(patch_file_path, ''.join(unidiff_patch))
+
+  expected_output = [
+    'A         %s\n' % sbox.ospath('src'),
+    'A         %s\n' % sbox.ospath('src/tools'),
+    'A         %s\n' % sbox.ospath('src/tools/ConsoleRunner'),
+    'A         %s\n' % sbox.ospath('src/tools/ConsoleRunner/hi.txt'),
+  ]
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+  expected_status.add({
+      'src/'                            : Item(status='A ', wc_rev=0),
+      'src/tools'                       : Item(status='A ', wc_rev=0),
+      'src/tools/ConsoleRunner/'        : Item(status='A ', wc_rev=0),
+      'src/tools/ConsoleRunner/hi.txt'  : Item(status='A ', wc_rev=0),
+  })
+
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({'src'                            : Item(),
+                     'src/tools'                      : Item(),
+                     'src/tools/ConsoleRunner'        : Item(),
+                     'src/tools/ConsoleRunner/hi.txt' :
+                        Item(contents="hihihihihihi")
+                   })
+
+  expected_skip = wc.State('', { })
+
+  svntest.actions.run_and_verify_patch(wc_dir, os.path.abspath(patch_file_path),
+                                       expected_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, # expected err
+                                       1, # check-props
+                                       1) # dry-run
+
 ########################################################################
 #Run the tests
 
@@ -4143,6 +4245,7 @@ test_list = [ None,
               patch_delete_and_skip,
               patch_target_no_eol_at_eof,
               patch_add_and_delete,
+              patch_git_with_index_line,
             ]
 
 if __name__ == '__main__':

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/prop_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/prop_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/prop_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/prop_tests.py Sat Nov 24 20:29:11 2012
@@ -33,6 +33,8 @@ logger = logging.getLogger()
 import svntest
 
 from svntest.main import SVN_PROP_MERGEINFO
+from svntest.main import SVN_PROP_INHERITABLE_IGNORES
+from svntest import wc
 
 # (abbreviation)
 Skip = svntest.testcase.Skip_deco
@@ -2047,7 +2049,7 @@ def atomic_over_ra(sbox):
   sbox.build(create_wc=False)
   repo_url = sbox.repo_url
 
-  # From this point on, similar to ../libsvn_fs-fs-test.c:revision_props().
+  # From this point on, similar to ../libsvn_fs/fs-test.c:revision_props().
   s1 = "violet"
   s2 = "wrong value"
 
@@ -2507,6 +2509,167 @@ def pristine_props_listed(sbox):
   svntest.actions.run_and_verify_svn(None, expected_output, [],
                                      'proplist', '-R', wc_dir, '-r', 'BASE')
 
+def create_inherited_ignores_config(config_dir):
+  "create config stuffs for inherited ignores tests"
+
+  # contents of the file 'config'
+  config_contents = '''\
+[miscellany]
+global-ignores = *.boo *.goo
+'''
+
+  svntest.main.create_config_dir(config_dir, config_contents)
+
+def inheritable_ignores(sbox):
+  "inheritable ignores with svn:ignores and config"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  tmp_dir = os.path.abspath(svntest.main.temp_dir)
+  config_dir = os.path.join(tmp_dir, 'autoprops_config_' + sbox.name)
+  create_inherited_ignores_config(config_dir)
+
+  sbox.simple_propset(SVN_PROP_INHERITABLE_IGNORES, '*.doo', 'A/B')
+  sbox.simple_propset(SVN_PROP_INHERITABLE_IGNORES, '*.moo', 'A/D')
+  sbox.simple_propset('svn:ignore', '*.foo', 'A/B/E')
+  sbox.simple_commit()
+
+  # Some directories and files that should be added because they don't
+  # match any applicable ignores.
+  X_dir_path = os.path.join(wc_dir, 'ADD-ME-DIR-X')
+  Y_dir_path = os.path.join(wc_dir, 'A', 'ADD-ME-DIR-Y.doo')
+  Z_dir_path = os.path.join(wc_dir, 'A', 'D', 'G', 'ADD-ME-DIR-Z.doo')
+  os.mkdir(X_dir_path)
+  os.mkdir(Y_dir_path)
+  os.mkdir(Z_dir_path)
+
+  # Some directories and files that should be ignored when adding
+  # because they match an ignore pattern (unless of course they are
+  # the direct target of an add, which we always add).
+  boo_dir_path = os.path.join(wc_dir, 'IGNORE-ME-DIR.boo')
+  goo_dir_path = os.path.join(wc_dir, 'IGNORE-ME-DIR.boo', 'IGNORE-ME-DIR.goo')
+  doo_dir_path = os.path.join(wc_dir, 'A', 'B', 'IGNORE-ME-DIR.doo')
+  moo_dir_path = os.path.join(wc_dir, 'A', 'D', 'IGNORE-ME-DIR.moo')
+  foo_dir_path = os.path.join(wc_dir, 'A', 'B', 'E', 'IGNORE-ME-DIR.foo')
+  os.mkdir(boo_dir_path)
+  os.mkdir(goo_dir_path)
+  os.mkdir(doo_dir_path)
+  os.mkdir(moo_dir_path)
+  os.mkdir(foo_dir_path)
+  boo_file_path = sbox.ospath('ADD-ME-DIR-X/ignore-me-file.boo')
+  goo_file_path = sbox.ospath('A/D/G/ignore-me-file.goo')
+  doo_file_path = sbox.ospath('A/B/IGNORE-ME-DIR.doo/ignore-me-file.doo')
+  doo_file2_path = sbox.ospath('A/B/E/ignore-me-file.doo')
+  moo_file_path = sbox.ospath('A/D/ignore-me-file.moo')
+  foo_file_path = sbox.ospath('A/B/E/ignore-me-file.foo')
+  svntest.main.file_write(boo_file_path, 'I should not be versioned!\n')
+  svntest.main.file_write(goo_file_path, 'I should not be versioned!\n')
+  svntest.main.file_write(doo_file_path, 'I should not be versioned!\n')
+  svntest.main.file_write(doo_file2_path, 'I should not be versioned!\n')
+  svntest.main.file_write(moo_file_path, 'I should not be versioned!\n')
+  svntest.main.file_write(foo_file_path, 'I should not be versioned!\n')
+
+  # Some directories and files that don't match any ignore pattern
+  # but are located within a subtree that does match and so shouldn't
+  # be added.
+  roo_file_path = sbox.ospath('A/B/IGNORE-ME-DIR.doo/ignore-me-file.roo')
+  svntest.main.file_write(roo_file_path, 'I should not be versioned!\n')
+
+  # Check (non-verbose) status with the custom config. We should only see
+  # the three unversioned directories which don't match any of the ignore
+  # patterns and aren't proper subtrees of an unversioned or ignored
+  # subtree.
+  expected_output = svntest.verify.UnorderedOutput(
+    ['?       ' + X_dir_path + '\n',
+     '?       ' + Y_dir_path + '\n',
+     '?       ' + Z_dir_path + '\n',])
+  svntest.actions.run_and_verify_svn(None, expected_output, [], 'st',
+                                     '--config-dir', config_dir, wc_dir)
+
+  # Check status without the custom config.
+  # Should be the same as above except the *.boo and *.goo paths
+  # now show up as unversioned '?'.
+  expected_output = svntest.verify.UnorderedOutput(
+    ['?       ' + X_dir_path    + '\n',
+     '?       ' + Y_dir_path    + '\n',
+     '?       ' + Z_dir_path    + '\n',
+     '?       ' + boo_dir_path  + '\n',
+     '?       ' + goo_file_path + '\n',])
+  svntest.actions.run_and_verify_svn(None, expected_output, [], 'st', wc_dir)
+
+  # Check status with the custom config and --no-ignore.
+  expected_output = svntest.verify.UnorderedOutput(
+    ['?       ' + X_dir_path     + '\n',
+     '?       ' + Y_dir_path     + '\n',
+     '?       ' + Z_dir_path     + '\n',
+     'I       ' + boo_dir_path   + '\n',
+     'I       ' + doo_dir_path   + '\n',
+     'I       ' + doo_file2_path + '\n',
+     'I       ' + moo_dir_path   + '\n',
+     'I       ' + foo_dir_path   + '\n',
+     'I       ' + goo_file_path  + '\n',
+     'I       ' + moo_file_path  + '\n',
+     'I       ' + foo_file_path  + '\n',])
+  svntest.actions.run_and_verify_svn(None, expected_output, [], 'st',
+                                     '--config-dir', config_dir,
+                                     '--no-ignore', wc_dir)
+
+  # Check status without the custom config and --no-ignore.
+  # Should be the same as above except the *.boo and *.goo paths
+  # are reported as unversioned '?' rather than ignored 'I'.
+  expected_output = svntest.verify.UnorderedOutput(
+    ['?       ' + X_dir_path     + '\n',
+     '?       ' + Y_dir_path     + '\n',
+     '?       ' + Z_dir_path     + '\n',
+     '?       ' + boo_dir_path   + '\n',
+     'I       ' + doo_dir_path   + '\n',
+     'I       ' + doo_file2_path + '\n',
+     'I       ' + moo_dir_path   + '\n',
+     'I       ' + foo_dir_path   + '\n',
+     '?       ' + goo_file_path  + '\n',
+     'I       ' + moo_file_path  + '\n',
+     'I       ' + foo_file_path  + '\n',])
+  svntest.actions.run_and_verify_svn(None, expected_output, [], 'st',
+                                     '--no-ignore', wc_dir)
+
+  # Perform the add with the --force flag, targeting the root of the WC.
+  ### Note: You have to be inside the working copy or else Subversion
+  ### will think you're trying to add the working copy to its parent
+  ### directory, and will (possibly, if the parent directory isn't
+  ### versioned) fail -- see also schedule_tests.py 11 "'svn add'
+  ### should traverse already-versioned dirs"
+  saved_wd = os.getcwd()
+  os.chdir(sbox.wc_dir)
+  expected = svntest.verify.UnorderedOutput(
+    ['A         ' + 'ADD-ME-DIR-X\n',
+     'A         ' + os.path.join('A', 'ADD-ME-DIR-Y.doo') + '\n',
+     'A         ' + os.path.join('A', 'D', 'G', 'ADD-ME-DIR-Z.doo') + '\n'])
+  svntest.actions.run_and_verify_svn("Adds in spite of ignores", expected,
+                                     [], 'add', '.', '--force',
+                                     '--config-dir', config_dir)
+  os.chdir(saved_wd)
+
+  # Now revert and try the add with the --no-ignore flag, only the
+  # svn:inheritable-ignores should be enforced.
+  svntest.actions.run_and_verify_svn(None, None, [], 'revert', wc_dir, '-R')
+  saved_wd = os.getcwd()
+  os.chdir(sbox.wc_dir)
+  expected = svntest.verify.UnorderedOutput(
+    ['A         ' + 'ADD-ME-DIR-X\n',
+     'A         ' + os.path.join('A', 'ADD-ME-DIR-Y.doo') + '\n',
+     'A         ' + os.path.join('A', 'D', 'G', 'ADD-ME-DIR-Z.doo') + '\n',
+     'A         ' + os.path.join('ADD-ME-DIR-X', 'ignore-me-file.boo') + '\n',
+     'A         ' + 'IGNORE-ME-DIR.boo' + '\n',
+     'A         ' + os.path.join('IGNORE-ME-DIR.boo',
+                                 'IGNORE-ME-DIR.goo') + '\n',
+     'A         ' + os.path.join('A', 'B', 'E', 'IGNORE-ME-DIR.foo') + '\n',
+     'A         ' + os.path.join('A', 'B', 'E', 'ignore-me-file.foo') + '\n',
+     'A         ' + os.path.join('A', 'D', 'G', 'ignore-me-file.goo') + '\n'])
+  svntest.actions.run_and_verify_svn("Adds in spite of ignores", expected,
+                                     [], 'add', '.', '--force','--no-ignore',
+                                     '--config-dir', config_dir)
+
 ########################################################################
 # Run the tests
 
@@ -2549,6 +2712,7 @@ test_list = [ None,
               propget_redirection,
               file_matching_dir_prop_reject,
               pristine_props_listed,
+              inheritable_ignores,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/resolve_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/resolve_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/resolve_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/resolve_tests.py Sat Nov 24 20:29:11 2012
@@ -25,7 +25,7 @@
 ######################################################################
 
 # General modules
-import shutil, sys, re, os
+import shutil, sys, re, os, stat
 import time
 
 # Our testing module
@@ -106,7 +106,6 @@ def automatic_conflict_resolution(sbox):
 # Test for issue #3707 'property conflicts not handled correctly by
 # svn resolve'.
 @Issue(3707)
-@XFail()
 def prop_conflict_resolution(sbox):
   "resolving prop conflicts"
 
@@ -225,8 +224,8 @@ def prop_conflict_resolution(sbox):
   #   2) 'A/mu' - An incoming prop edit on a local prop modification.
   #   3) 'A/D/gamma' - An local, non-conflicted prop edit
   #
-  # This currently fails because svn resolve --accept=[theirs-conflict |
-  # theirs-full] removes the conflicts, but doesn't install 'their' version
+  # Previously this failed because svn resolve --accept=[theirs-conflict |
+  # theirs-full] removed the conflicts, but didn't install 'their' version
   # of the conflicted properties.
   do_prop_conflicting_up_and_resolve('mine-full',
                                      ['local_edit\n'],
@@ -244,6 +243,35 @@ def prop_conflict_resolution(sbox):
                                      [], # Prop deleted
                                      ['incoming-conflict\n'])
 
+@SkipUnless(svntest.main.is_posix_os)
+def auto_resolve_executable_file(sbox):
+  "resolve file with executable bit set"
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # Mark iota as executable
+  sbox.simple_propset("svn:executable", '*', 'iota')
+  sbox.simple_commit() # r2
+
+  # Make a change to iota in r3
+  svntest.main.file_write(sbox.ospath('iota'), "boo\n")
+  sbox.simple_commit() # r3
+
+  # Update back to r2, and tweak iota to provoke a text conflict
+  sbox.simple_update(revision=2)
+  svntest.main.file_write(sbox.ospath('iota'), "bzzt\n")
+
+  # Get permission bits of iota
+  mode = os.stat(sbox.ospath('iota'))[stat.ST_MODE]
+
+  # Update back to r3, and auto-resolve the text conflict.
+  svntest.main.run_svn(False, 'update', wc_dir, '--accept', 'theirs-full')
+
+  # permission bits of iota should be unaffected
+  if mode != os.stat(sbox.ospath('iota'))[stat.ST_MODE]:
+    raise svntest.Failure
+
+
 ########################################################################
 # Run the tests
 
@@ -251,6 +279,7 @@ def prop_conflict_resolution(sbox):
 test_list = [ None,
               automatic_conflict_resolution,
               prop_conflict_resolution,
+              auto_resolve_executable_file,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/schedule_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/schedule_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/schedule_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/schedule_tests.py Sat Nov 24 20:29:11 2012
@@ -563,6 +563,7 @@ def status_add_deleted_directory(sbox):
 # Regression test for issue #939:
 # Recursive 'svn add' should still traverse already-versioned dirs.
 @Issue(939)
+@Issue(4241)
 def add_recursive_already_versioned(sbox):
   "'svn add' should traverse already-versioned dirs"
 
@@ -592,8 +593,8 @@ def add_recursive_already_versioned(sbox
   ### or else Subversion will think you're trying to add the working copy
   ### to its parent directory, and will (possibly, if the parent directory
   ### isn't versioned) fail.
-  #svntest.main.run_svn(None, 'add', '--force', wc_dir)
-  #svntest.actions.run_and_verify_status(wc_dir, expected_status)
+  svntest.main.run_svn(None, 'add', '--force', wc_dir)
+  svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
   # Now revert, and do the adds again from inside the working copy.
   svntest.main.run_svn(None, 'revert', '--recursive', wc_dir)

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/special_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/special_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/special_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/special_tests.py Sat Nov 24 20:29:11 2012
@@ -759,7 +759,6 @@ def symlink_destination_change(sbox):
 # (disk and metadata).
 @Issue(3884)
 @SkipUnless(svntest.main.is_posix_os)
-@XFail()
 def merge_foreign_symlink(sbox):
   "merge symlink-add from foreign repos"
 
@@ -790,7 +789,7 @@ def merge_foreign_symlink(sbox):
   # Verify special status.
   expected_disk = svntest.main.greek_state.copy()
   expected_disk.add({
-    'A/zeta': Item(props={ 'svn:special': '*' })
+    'A/zeta': Item(contents="link target", props={ 'svn:special': '*' })
   })
   svntest.actions.verify_disk(sbox.ospath(''), expected_disk, True)
 
@@ -820,7 +819,7 @@ def symlink_to_wc_basic(sbox):
   wc_uuid = svntest.actions.get_wc_uuid(wc_dir)
   expected_info = [{
       'Path' : re.escape(os.path.join(symlink_path)),
-      'Working Copy Root Path' : re.escape(os.path.abspath(symlink_path)),
+      'Working Copy Root Path' : re.escape(os.path.abspath(wc_dir)),
       'Repository Root' : sbox.repo_url,
       'Repository UUID' : wc_uuid,
       'Revision' : '1',
@@ -829,7 +828,7 @@ def symlink_to_wc_basic(sbox):
   }, {
       'Name' : 'iota',
       'Path' : re.escape(os.path.join(symlink_path, 'iota')),
-      'Working Copy Root Path' : re.escape(os.path.abspath(symlink_path)),
+      'Working Copy Root Path' : re.escape(os.path.abspath(wc_dir)),
       'Repository Root' : sbox.repo_url,
       'Repository UUID' : wc_uuid,
       'Revision' : '1',

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/stat_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/stat_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/stat_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/stat_tests.py Sat Nov 24 20:29:11 2012
@@ -986,25 +986,19 @@ def status_ignored_dir(sbox):
 
 #----------------------------------------------------------------------
 
-@Issue(2030)
-def status_unversioned_dir(sbox):
-  "status on unversioned dir"
-  sbox.build(read_only = True, create_wc = False)
-  dir = sbox.wc_dir
-  svntest.main.safe_rmtree(sbox.wc_dir)
-  os.mkdir(dir)
-
-  # Depending on whether you run the tests below a working copy
-  # or not, the error message might either be something like
-  # svn: warning: W155007: '...copies/stat_tests-19' is not a working copy
-  # or
-  # svn: warning: W155010: The node '...copies/stat_tests-19' was not found.
+def status_unversioned_dir_in_wc(sbox):
+  "status on unversioned dir in working copy"
+  sbox.build(read_only = True)
 
-  expected_err = "svn: warning: W1550(07|10): .*'.*(/|\\\\)" + \
-                 os.path.basename(dir) + \
-                 "' (is not a working copy|was not found)"
+  # Create two unversioned directories within the test working copy
+  path = sbox.ospath('1/2')
+  os.makedirs(path)
+
+  expected_err = "svn: warning: (W155007|W155010): .*'.*(/|\\\\)" + \
+                 os.path.basename(path) + \
+                 "' was not found"
   svntest.actions.run_and_verify_svn2(None, [], expected_err, 0,
-                                      "status", dir, dir)
+                                      "status", path)
 
 #----------------------------------------------------------------------
 
@@ -1883,14 +1877,6 @@ def status_nested_wc_old_format(sbox):
   os.chdir(wc_dir)
   svntest.actions.run_and_verify_svn(None, [ "?       subdir\n" ], [], 'st')
 
-########################################################################
-# Run the tests
-
-
-def simple_lock(sbox, relpath):
-  path = os.path.join(sbox.wc_dir, relpath)
-  svntest.actions.run_and_verify_svn(None, None, [], 'lock', path)
-
 #----------------------------------------------------------------------
 # Regression test for issue #3855 "status doesn't show 'K' on a locked
 # deleted node".
@@ -1902,7 +1888,8 @@ def status_locked_deleted(sbox):
   iota_path = sbox.ospath('iota')
 
   sbox.simple_rm('iota')
-  simple_lock(sbox, 'iota')
+  svntest.actions.run_and_verify_svn(None, None, [], 'lock',
+                                     os.path.join(sbox.wc_dir, 'iota'))
   svntest.actions.run_and_verify_svn(None, ['D    K  %s\n' % iota_path], [],
                                      'status', iota_path)
 
@@ -2036,6 +2023,19 @@ def status_not_present(sbox):
                                      sbox.ospath('A/mu'),
                                      sbox.ospath('no-file'))
 
+# Skip this test is a .svn dir exists in the root directory
+@Skip(lambda: os.path.exists("/%s" % svntest.main.get_admin_name())) 
+def status_unversioned_dir(sbox):
+  "status on unversioned dir"
+  sbox.build(read_only = True, create_wc = False)
+
+  # Run svn status on "/", which we assume exists and isn't a WC.
+  # This should work on UNIX-like systems and Windows systems
+  expected_err = "svn: warning: W1550(07|10): .*'.*(/|\\\\)" + \
+                 "' is not a working copy"
+  svntest.actions.run_and_verify_svn2(None, [], expected_err, 0,
+                                      "status", "/")
+
 ########################################################################
 # Run the tests
 
@@ -2060,7 +2060,7 @@ test_list = [ None,
               missing_dir_in_anchor,
               status_in_xml,
               status_ignored_dir,
-              status_unversioned_dir,
+              status_unversioned_dir_in_wc,
               status_missing_dir,
               status_nonrecursive_update_different_cwd,
               status_add_plus_conflict,
@@ -2080,6 +2080,7 @@ test_list = [ None,
               wclock_status,
               modified_modulo_translation,
               status_not_present,
+              status_unversioned_dir,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svnadmin_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svnadmin_tests.py Sat Nov 24 20:29:11 2012
@@ -78,6 +78,12 @@ def check_hotcopy_fsfs(src, dst):
                                 "source" % src_dirent)
       # Compare all files in this directory
       for src_file in src_files:
+        # Exclude temporary files
+        if src_file == 'rev-prop-atomicsShm':
+          continue
+        if src_file == 'rev-prop-atomicsMutex':
+          continue
+
         src_path = os.path.join(src_dirpath, src_file)
         dst_path = os.path.join(dst_dirpath, src_file)
         if not os.path.isfile(dst_path):
@@ -1824,7 +1830,8 @@ def mergeinfo_race(sbox):
 @Issue(4213)
 def recover_old(sbox):
   "recover --pre-1.4-compatible"
-  sbox.build(create_wc=False)
+  svntest.main.safe_rmtree(sbox.repo_dir, 1)
+  svntest.main.create_repos(sbox.repo_dir, minor_version=0)
   svntest.main.run_svnadmin("recover", sbox.repo_dir)
 
 

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svndumpfilter_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svndumpfilter_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svndumpfilter_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svndumpfilter_tests.py Sat Nov 24 20:29:11 2012
@@ -679,6 +679,33 @@ def accepts_deltas(sbox):
 
   
 
+@Issue(4234)
+def dumpfilter_targets_expect_leading_slash_prefixes(sbox):
+  "dumpfilter targets expect leading '/' in prefixes"
+  ## See http://subversion.tigris.org/issues/show_bug.cgi?id=4234. ##
+
+  test_create(sbox)
+
+  dumpfile_location = os.path.join(os.path.dirname(sys.argv[0]),
+                                   'svndumpfilter_tests_data',
+                                   'greek_tree.dump')
+  dumpfile = open(dumpfile_location).read()
+
+  (fd, targets_file) = tempfile.mkstemp(dir=svntest.main.temp_dir)
+  try:
+    targets = open(targets_file, 'w')
+
+    # Removing the leading slash in path prefixes should work.
+    targets.write('A/D/H\n')
+    targets.write('A/D/G\n')
+    targets.close()
+    _simple_dumpfilter_test(sbox, dumpfile,
+                            'exclude', '/A/B/E', '--targets', targets_file)
+  finally:
+    os.close(fd)
+    os.remove(targets_file)
+
+
 ########################################################################
 # Run the tests
 
@@ -693,6 +720,7 @@ test_list = [ None,
               dropped_but_not_renumbered_empty_revs,
               match_empty_prefix,
               accepts_deltas,
+              dumpfilter_targets_expect_leading_slash_prefixes,
               ]
 
 if __name__ == '__main__':

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svnlook_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svnlook_tests.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svnlook_tests.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svnlook_tests.py Sat Nov 24 20:29:11 2012
@@ -698,9 +698,14 @@ fp.close()"""
                     'bogus_rev_val\n',
                     '  bogus_prop\n',
                     '  svn:log\n', '  svn:author\n',
-                    #  internal property, not really expected
-                    '  svn:check-locks\n',
-                    '  bogus_rev_prop\n', '  svn:date\n']
+                    '  svn:check-locks\n', # internal prop, not really expected
+                    '  bogus_rev_prop\n',
+                    '  svn:date\n',
+                    '  svn:txn-client-compat-version\n',
+                    ]
+  # ra_dav and ra_svn add the user-agent ephemeral property
+  if svntest.main.is_ra_type_dav() or svntest.main.is_ra_type_svn():
+    expected_data.append('  svn:txn-user-agent\n')
   verify_logfile(logfilepath, svntest.verify.UnorderedOutput(expected_data))
 
 def property_delete(sbox):

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/actions.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/actions.py Sat Nov 24 20:29:11 2012
@@ -35,7 +35,7 @@ else:
   from cStringIO import StringIO
 
 import svntest
-from svntest import main, verify, tree, wc
+from svntest import main, verify, tree, wc, sandbox
 from svntest import Failure
 
 logger = logging.getLogger()
@@ -1573,6 +1573,90 @@ def run_and_verify_status_xml(expected_e
           pprint.pformat(expected_entries).splitlines(),
           pprint.pformat(actual_entries).splitlines())))
 
+def run_and_verify_inherited_prop_xml(path_or_url,
+                                      expected_inherited_props,
+                                      expected_explicit_props,
+                                      propname=None,
+                                      peg_rev=None,
+                                      *args):
+  """If PROPNAME is None, then call run_and_verify_svn with proplist -v --xml
+  --show-inherited-props on PATH_OR_URL, otherwise call run_and_verify_svn
+  with propget PROPNAME --xml --show-inherited-props.
+
+  PATH_OR_URL is pegged at PEG_REV if the latter is not None.  If PEG_REV
+  is none, then PATH_OR_URL is pegged at HEAD if a url.
+
+  EXPECTED_INHERITED_PROPS is a (possibly empty) dict mapping working copy
+  paths or URLs to dicts of inherited properties. EXPECTED_EXPLICIT_PROPS is
+  a (possibly empty) dict of the explicit properties expected on PATH_OR_URL.
+
+  Returns on success, raises on failure if EXPECTED_INHERITED_PROPS or
+  EXPECTED_EXPLICIT_PROPS don't match the results of proplist/propget.
+  """
+
+  if peg_rev is None:
+    if sandbox.is_url(path_or_url):
+      path_or_url = path_or_url + '@HEAD'
+  else:
+    path_or_url = path_or_url + '@' + str(peg_rev)
+
+  if (propname):
+    exit_code, output, errput = svntest.actions.run_and_verify_svn(
+      None, None, [], 'propget', propname, '--xml',
+      '--show-inherited-props', path_or_url, *args)
+  else:
+    exit_code, output, errput = svntest.actions.run_and_verify_svn(
+      None, None, [], 'proplist', '-v', '--xml', '--show-inherited-props',
+      path_or_url, *args)
+
+  if len(errput) > 0:
+    raise Failure
+
+  # Props inherited from within the WC are keyed on absolute paths.
+  expected_iprops = {}
+  for x in expected_inherited_props:
+    if sandbox.is_url(x):
+      expected_iprops[x] = expected_inherited_props[x]    
+    else:
+      expected_iprops[os.path.abspath(x)] = expected_inherited_props[x]
+
+  actual_iprops = {}
+  actual_explicit_props = {}
+
+  doc = parseString(''.join(output))
+  targets = doc.getElementsByTagName('target')
+  for t in targets:
+
+    # Create actual inherited props.
+    iprops = t.getElementsByTagName('inherited_property')
+
+    if len(iprops) > 0:
+      actual_iprops[t.getAttribute('path')]={}
+
+    for i in iprops:
+      actual_iprops[t.getAttribute('path')][i.getAttribute('name')] = \
+        i.firstChild.nodeValue
+
+    # Create actual explicit props.
+    xprops = t.getElementsByTagName('property')
+
+    for x in xprops:
+      actual_explicit_props[x.getAttribute('name')] = x.firstChild.nodeValue
+
+  if expected_explicit_props != actual_explicit_props:
+    raise svntest.Failure(
+      'Actual and expected explicit props do not match\n' +
+      '\n'.join(difflib.ndiff(
+      pprint.pformat(expected_explicit_props).splitlines(),
+      pprint.pformat(actual_explicit_props).splitlines())))
+
+  if expected_iprops != actual_iprops:
+    raise svntest.Failure(
+      'Actual and expected inherited props do not match\n' +
+      '\n'.join(difflib.ndiff(
+      pprint.pformat(expected_iprops).splitlines(),
+      pprint.pformat(actual_iprops).splitlines())))
+
 def run_and_verify_diff_summarize_xml(error_re_string = [],
                                       expected_prefix = None,
                                       expected_paths = [],

Modified: subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/main.py?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/compressed-pristines/subversion/tests/cmdline/svntest/main.py Sat Nov 24 20:29:11 2012
@@ -174,6 +174,12 @@ work_dir = "svn-test-work"
 # Constant for the merge info property.
 SVN_PROP_MERGEINFO = "svn:mergeinfo"
 
+# Constant for the inheritabled auto-props property.
+SVN_PROP_INHERITABLE_AUTOPROPS = "svn:inheritable-auto-props"
+
+# Constant for the inheritabled ignores property.
+SVN_PROP_INHERITABLE_IGNORES = "svn:inheritable-ignores"
+
 # Where we want all the repositories and working copies to live.
 # Each test will have its own!
 general_repo_dir = os.path.join(work_dir, "repositories")
@@ -952,12 +958,16 @@ def copy_repos(src_path, dst_path, head_
 
   dump_re = re.compile(r'^\* Dumped revision (\d+)\.\r?$')
   expect_revision = 0
+  dump_failed = False
   for dump_line in dump_stderr:
     match = dump_re.match(dump_line)
     if not match or match.group(1) != str(expect_revision):
       logger.warn('ERROR:  dump failed: %s', dump_line.strip())
-      raise SVNRepositoryCopyFailure
-    expect_revision += 1
+      dump_failed = True
+    else:
+      expect_revision += 1
+  if dump_failed:
+    raise SVNRepositoryCopyFailure
   if expect_revision != head_revision + 1:
     logger.warn('ERROR:  dump failed; did not see revision %s', head_revision)
     raise SVNRepositoryCopyFailure
@@ -1229,10 +1239,12 @@ class TestSpawningThread(threading.Threa
   """A thread that runs test cases in their own processes.
   Receives test numbers to run from the queue, and saves results into
   the results field."""
-  def __init__(self, queue):
+  def __init__(self, queue, progress_func, tests_total):
     threading.Thread.__init__(self)
     self.queue = queue
     self.results = []
+    self.progress_func = progress_func
+    self.tests_total = tests_total
 
   def run(self):
     while True:
@@ -1243,6 +1255,11 @@ class TestSpawningThread(threading.Threa
 
       self.run_one(next_index)
 
+      # signal progress
+      if self.progress_func:
+        self.progress_func(self.tests_total - self.queue.qsize(),
+                           self.tests_total)
+
   def run_one(self, index):
     command = os.path.abspath(sys.argv[0])
 
@@ -1292,7 +1309,8 @@ class TestRunner:
 
   def list(self, milestones_dict=None):
     """Print test doc strings.  MILESTONES_DICT is an optional mapping
-    of issue numbers to target milestones."""
+    of issue numbers to an list containing target milestones and who
+    the issue is assigned to."""
     if options.mode_filter.upper() == 'ALL' \
        or options.mode_filter.upper() == self.pred.list_mode().upper() \
        or (options.mode_filter.upper() == 'PASS' \
@@ -1302,6 +1320,7 @@ class TestRunner:
       if self.pred.issues:
         if not options.milestone_filter or milestones_dict is None:
           issues = self.pred.issues
+          tail += " [%s]" % ','.join(['#%s' % str(i) for i in issues])
         else: # Limit listing by requested target milestone(s).
           filter_issues = []
           matches_filter = False
@@ -1310,13 +1329,16 @@ class TestRunner:
           # If any one of them matches the MILESTONE_FILTER then we'll print
           # them all.
           for issue in self.pred.issues:
-            # A safe starting assumption.
+            # Some safe starting assumptions.
             milestone = 'unknown'
+            assigned_to = 'unknown'
             if milestones_dict:
               if milestones_dict.has_key(str(issue)):
-                milestone = milestones_dict[str(issue)]
+                milestone = milestones_dict[str(issue)][0]
+                assigned_to = milestones_dict[str(issue)][1]
 
-            filter_issues.append(str(issue) + '(' + milestone + ')')
+            filter_issues.append(
+              str(issue) + '(' + milestone + '/' + assigned_to + ')')
             pattern = re.compile(options.milestone_filter)
             if pattern.match(milestone):
               matches_filter = True
@@ -1324,9 +1346,12 @@ class TestRunner:
           # Did at least one of the associated issues meet our filter?
           if matches_filter:
             issues = filter_issues
-
-        tail += " [%s]" % ','.join(['#%s' % str(i) for i in issues])
-
+          # Wrap the issue#/target-milestone/assigned-to string
+          # to the next line and add a line break to enhance
+          # readability.
+          tail += "\n               %s" % '\n               '.join(
+            ['#%s' % str(i) for i in issues])
+          tail += '\n'
       # If there is no filter or this test made if through
       # the filter then print it!
       if options.milestone_filter is None or len(issues):
@@ -1499,7 +1524,8 @@ def _internal_run_tests(test_list, testn
     for num in testnums:
       number_queue.put(num)
 
-    threads = [ TestSpawningThread(number_queue) for i in range(parallel) ]
+    threads = [ TestSpawningThread(number_queue, progress_func,
+                                   len(testnums)) for i in range(parallel) ]
     for t in threads:
       t.start()
 
@@ -1512,10 +1538,6 @@ def _internal_run_tests(test_list, testn
       results += t.results
     results.sort()
 
-    # signal some kind of progress
-    if progress_func:
-      progress_func(len(testnums), len(testnums))
-
     # terminate the line of dots
     print("")
 
@@ -1666,7 +1688,12 @@ def run_tests(test_list, serial_only = F
 
   sys.exit(execute_tests(test_list, serial_only))
 
-def get_target_milestones_for_issues(issue_numbers):
+def get_issue_details(issue_numbers):
+  """For each issue number in ISSUE_NUMBERS query the issue
+     tracker and determine what the target milestone is and
+     who the issue is assigned to.  Return this information
+     as a dictionary mapping issue numbers to a list
+     [target_milestone, assigned_to]"""
   xml_url = "http://subversion.tigris.org/issues/xml.cgi?id="
   issue_dict = {}
 
@@ -1694,14 +1721,17 @@ def get_target_milestones_for_issues(iss
     xmldoc = xml.dom.minidom.parse(issue_xml_f)
     issue_xml_f.close()
 
-    # Get the target milestone for each issue.
+    # For each issue: Get the target milestone and who
+    #                 the issue is assigned to.
     issue_element = xmldoc.getElementsByTagName('issue')
     for i in issue_element:
       issue_id_element = i.getElementsByTagName('issue_id')
       issue_id = issue_id_element[0].childNodes[0].nodeValue
       milestone_element = i.getElementsByTagName('target_milestone')
       milestone = milestone_element[0].childNodes[0].nodeValue
-      issue_dict[issue_id] = milestone
+      assignment_element = i.getElementsByTagName('assigned_to')
+      assignment = assignment_element[0].childNodes[0].nodeValue
+      issue_dict[issue_id] = [milestone, assignment]
   except:
     print "ERROR: Unable to parse target milestones from issue tracker"
     raise
@@ -1894,10 +1924,13 @@ def execute_tests(test_list, serial_only
                 options.mode_filter.upper() == test_mode or
                 (options.mode_filter.upper() == 'PASS' and test_mode == '')):
               issues_dict[issue]=issue
-      milestones_dict = get_target_milestones_for_issues(issues_dict.keys())
+      milestones_dict = get_issue_details(issues_dict.keys())
+
+    header = "Test #  Mode   Test Description\n"
+    if options.milestone_filter:
+      header += "               Issue#(Target Mileston/Assigned To)\n"
+    header += "------  -----  ----------------"
 
-    header = "Test #  Mode   Test Description\n" \
-             "------  -----  ----------------"
     printed_header = False
     for testnum in testnums:
       test_mode = TestRunner(test_list[testnum], testnum).get_mode().upper()