You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2013/02/23 02:25:44 UTC
svn commit: r1449262 [21/25] - in /subversion/branches/ev2-export: ./ build/
build/ac-macros/ build/generator/ build/generator/swig/
build/generator/templates/ build/win32/
contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ notes/
note...
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/stat_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/stat_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/stat_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/stat_tests.py Sat Feb 23 01:25:38 2013
@@ -1073,9 +1073,7 @@ def status_add_plus_conflict(sbox):
"? " + sbox.ospath('trunk/file.merge-right.r5') + "\n",
"? " + sbox.ospath('trunk/file.working') + "\n",
"C + " + sbox.ospath('trunk/file') + "\n",
- "Summary of conflicts:\n",
- " Text conflicts: 1\n",
- ]
+ ] + svntest.main.summary_of_conflicts(text_conflicts=1)
if svntest.main.server_has_mergeinfo():
lines.append(" M " + sbox.ospath('trunk') + "\n")
@@ -1745,9 +1743,7 @@ def status_with_tree_conflicts(sbox):
" > local file delete, incoming file edit upon update\n",
"! C %s\n" % tau,
" > local file delete, incoming file delete upon update\n",
- "Summary of conflicts:\n",
- " Tree conflicts: 3\n",
- ])
+ ] + svntest.main.summary_of_conflicts(tree_conflicts=3))
svntest.actions.run_and_verify_svn(None,
expected,
@@ -1763,10 +1759,7 @@ def status_with_tree_conflicts(sbox):
" > local file edit, incoming file delete upon update\n",
"! C %s\n" % tau,
" > local file delete, incoming file delete upon update\n",
- "Summary of conflicts:\n",
- " Tree conflicts: 3\n",
- ])
-
+ ] + svntest.main.summary_of_conflicts(tree_conflicts=3))
svntest.actions.run_and_verify_svn(None,
expected,
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svnadmin_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svnadmin_tests.py Sat Feb 23 01:25:38 2013
@@ -551,10 +551,10 @@ def verify_windows_paths_in_repos(sbox):
# unfortunately, FSFS needs to do more checks than BDB resulting in
# different progress output
- if svntest.main.is_fs_type_fsfs:
+ if svntest.main.is_fs_type_fsfs():
svntest.verify.compare_and_display_lines(
"Error while running 'svnadmin verify'.",
- 'STDERR', ["* Verifying global structure ...\n",
+ 'STDERR', ["* Verifying repository metadata ...\n",
"* Verified revision 0.\n",
"* Verified revision 1.\n",
"* Verified revision 2.\n"], errput)
@@ -1499,44 +1499,31 @@ def test_lslocks_and_rmlocks(sbox):
[], "lock", "-m", "Locking files",
iota_url, lambda_url)
- expected_output_list = [
- "Path: /A/B/lambda",
+ def expected_output_list(path):
+ return [
+ "Path: " + path,
"UUID Token: opaquelocktoken",
"Owner: jrandom",
"Created:",
"Expires:",
"Comment \(1 line\):",
"Locking files",
- "Path: /iota",
- "UUID Token: opaquelocktoken.*",
"\n", # empty line
]
# List all locks
exit_code, output, errput = svntest.main.run_svnadmin("lslocks",
sbox.repo_dir)
-
if errput:
raise SVNUnexpectedStderr(errput)
svntest.verify.verify_exit_code(None, exit_code, 0)
- try:
- expected_output = svntest.verify.UnorderedRegexOutput(expected_output_list)
- svntest.verify.compare_and_display_lines('lslocks output mismatch',
- 'output',
- expected_output, output)
- except:
- # Usually both locks have the same timestamp but if the clock
- # ticks between creating the two locks then the timestamps will
- # differ. When the output has two identical "Created" lines
- # UnorderedRegexOutput must have one matching regex, when the
- # output has two different "Created" lines UnorderedRegexOutput
- # must have two regex.
- expected_output_list.append("Created:.*")
- expected_output = svntest.verify.UnorderedRegexOutput(expected_output_list)
- svntest.verify.compare_and_display_lines('lslocks output mismatch',
- 'output',
- expected_output, output)
+ expected_output = svntest.verify.UnorderedRegexListOutput(
+ expected_output_list('/A/B/lambda') +
+ expected_output_list('/iota'))
+ svntest.verify.compare_and_display_lines('lslocks output mismatch',
+ 'output',
+ expected_output, output)
# List lock in path /A
exit_code, output, errput = svntest.main.run_svnadmin("lslocks",
@@ -1545,18 +1532,10 @@ def test_lslocks_and_rmlocks(sbox):
if errput:
raise SVNUnexpectedStderr(errput)
- expected_output = svntest.verify.UnorderedRegexOutput([
- "Path: /A/B/lambda",
- "UUID Token: opaquelocktoken",
- "Owner: jrandom",
- "Created:",
- "Expires:",
- "Comment \(1 line\):",
- "Locking files",
- "\n", # empty line
- ])
-
- svntest.verify.compare_and_display_lines('message', 'label',
+ expected_output = svntest.verify.RegexListOutput(
+ expected_output_list('/A/B/lambda'))
+ svntest.verify.compare_and_display_lines('lslocks output mismatch',
+ 'output',
expected_output, output)
svntest.verify.verify_exit_code(None, exit_code, 0)
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svnlook_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svnlook_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svnlook_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svnlook_tests.py Sat Feb 23 01:25:38 2013
@@ -32,6 +32,7 @@ logger = logging.getLogger()
# Our testing module
import svntest
+from prop_tests import binary_mime_type_on_text_file_warning
# (abbreviation)
Skip = svntest.testcase.Skip_deco
@@ -578,7 +579,8 @@ def diff_binary(sbox):
# Set A/mu to a binary mime-type, tweak its text, and commit.
mu_path = os.path.join(wc_dir, 'A', 'mu')
svntest.main.file_append(mu_path, 'new appended text for mu')
- svntest.main.run_svn(None, 'propset', 'svn:mime-type',
+ svntest.main.run_svn(binary_mime_type_on_text_file_warning,
+ 'propset', 'svn:mime-type',
'application/octet-stream', mu_path)
svntest.main.run_svn(None, 'ci', '-m', 'log msg', mu_path)
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svnrdump_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svnrdump_tests.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svnrdump_tests.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svnrdump_tests.py Sat Feb 23 01:25:38 2013
@@ -138,12 +138,16 @@ def run_dump_test(sbox, dumpfile_name, e
if not l.startswith('Text-delta-base-md5')]
svnrdump_dumpfile = [l for l in svnrdump_dumpfile
if not l.startswith('Text-delta-base-md5')]
+ svnadmin_dumpfile = [l for l in svnadmin_dumpfile
+ if not mismatched_headers_re.match(l)]
+ svnrdump_dumpfile = [l for l in svnrdump_dumpfile
+ if not mismatched_headers_re.match(l)]
svnadmin_dumpfile = svntest.verify.UnorderedOutput(svnadmin_dumpfile)
svntest.verify.compare_and_display_lines(
"Dump files", "DUMP", svnadmin_dumpfile, svnrdump_dumpfile,
- None, mismatched_headers_re)
+ None)
else:
compare_repos_dumps(sbox, svnadmin_dumpfile)
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svntest/actions.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svntest/actions.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svntest/actions.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svntest/actions.py Sat Feb 23 01:25:38 2013
@@ -40,6 +40,9 @@ from svntest import Failure
logger = logging.getLogger()
+# (abbreviation)
+Item = svntest.wc.StateItem
+
def _log_tree_state(msg, actual, subtree=""):
if subtree:
subtree += os.sep
@@ -86,16 +89,10 @@ def setup_pristine_greek_repository():
# import the greek tree, using l:foo/p:bar
### todo: svn should not be prompting for auth info when using
### repositories with no auth/auth requirements
- exit_code, output, errput = main.run_svn(None, 'import', '-m',
- 'Log message for revision 1.',
- main.greek_dump_dir,
- main.pristine_greek_repos_url)
-
- # check for any errors from the import
- if len(errput):
- display_lines("Errors during initial 'svn import':",
- 'STDERR', None, errput)
- sys.exit(1)
+ _, output, _ = main.run_svn(None, 'import', '-m',
+ 'Log message for revision 1.',
+ main.greek_dump_dir,
+ main.pristine_greek_repos_url)
# verify the printed output of 'svn import'.
lastline = output.pop().strip()
@@ -424,6 +421,22 @@ def expected_noop_update_output(rev):
% (rev),
"no-op update")
+def run_and_verify_svnauthz(message, expected_stdout, expected_stderr,
+ expected_exit, compat_mode, *varargs):
+ """Run svnauthz command and check its output and exit code.
+ If COMPAT_MODE is True then run the command in pre-1.8
+ compatibility mode"""
+
+ if compat_mode:
+ exit_code, out, err = main.run_svnauthz_validate(*varargs)
+ else:
+ exit_code, out, err = main.run_svnauthz(*varargs)
+
+ verify.verify_outputs("Unexpected output", out, err,
+ expected_stdout, expected_stderr)
+ verify.verify_exit_code(message, exit_code, expected_exit)
+ return exit_code, out, err
+
######################################################################
# Subversion Actions
#
@@ -1116,7 +1129,7 @@ def run_and_verify_merge(dir, rev1, rev2
for x in out_dry:
logger.warn(x)
logger.warn("The full merge output:")
- for x in out:
+ for x in merge_diff_out:
logger.warn(x)
logger.warn("=============================================================")
raise main.SVNUnmatchedError
@@ -1445,47 +1458,50 @@ def run_and_verify_commit(wc_dir_name, o
# This function always passes '-q' to the status command, which
# suppresses the printing of any unversioned or nonexistent items.
-def run_and_verify_status(wc_dir_name, output_tree,
+def run_and_verify_status(wc_dir_name, status_tree,
singleton_handler_a = None,
a_baton = None,
singleton_handler_b = None,
b_baton = None):
"""Run 'status' on WC_DIR_NAME and compare it with the
- expected OUTPUT_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will
+ expected STATUS_TREE. SINGLETON_HANDLER_A and SINGLETON_HANDLER_B will
be passed to tree.compare_trees - see that function's doc string for
more details.
Returns on success, raises on failure."""
- if isinstance(output_tree, wc.State):
- output_state = output_tree
- output_tree = output_tree.old_tree()
- else:
- output_state = None
-
exit_code, output, errput = main.run_svn(None, 'status', '-v', '-u', '-q',
wc_dir_name)
- actual = tree.build_tree_from_status(output, wc_dir_name=wc_dir_name)
+ actual_status = svntest.wc.State.from_status(output)
# Verify actual output against expected output.
- try:
- tree.compare_trees("status", actual, output_tree,
- singleton_handler_a, a_baton,
- singleton_handler_b, b_baton)
- except tree.SVNTreeError:
- verify.display_trees(None, 'STATUS OUTPUT TREE', output_tree, actual)
- _log_tree_state("ACTUAL STATUS TREE:", actual, wc_dir_name)
- raise
+ if isinstance(status_tree, wc.State):
+ try:
+ status_tree.compare_and_display('status', actual_status)
+ except tree.SVNTreeError:
+ _log_tree_state("ACTUAL STATUS TREE:", actual_status.old_tree(),
+ wc_dir_name)
+ raise
+ else:
+ actual_status = actual_status.old_tree()
+ try:
+ tree.compare_trees("status", actual_status, status_tree,
+ singleton_handler_a, a_baton,
+ singleton_handler_b, b_baton)
+ except tree.SVNTreeError:
+ verify.display_trees(None, 'STATUS OUTPUT TREE', status_tree, actual_status)
+ _log_tree_state("ACTUAL STATUS TREE:", actual_status, wc_dir_name)
+ raise
# if we have an output State, and we can/are-allowed to create an
# entries-based State, then compare the two.
- if output_state:
- entries_state = wc.State.from_entries(wc_dir_name)
- if entries_state:
- tweaked = output_state.copy()
+ if isinstance(status_tree, wc.State):
+ actual_entries = wc.State.from_entries(wc_dir_name)
+ if actual_entries:
+ tweaked = status_tree.copy()
tweaked.tweak_for_entries_compare()
try:
- tweaked.compare_and_display('entries', entries_state)
+ tweaked.compare_and_display('entries', actual_entries)
except tree.SVNTreeUnequal:
### do something more
raise
@@ -1498,20 +1514,27 @@ def run_and_verify_unquiet_status(wc_dir
expected STATUS_TREE.
Returns on success, raises on failure."""
- if isinstance(status_tree, wc.State):
- status_tree = status_tree.old_tree()
-
exit_code, output, errput = main.run_svn(None, 'status', '-v',
'-u', wc_dir_name)
- actual = tree.build_tree_from_status(output, wc_dir_name=wc_dir_name)
+ actual_status = svntest.wc.State.from_status(output)
# Verify actual output against expected output.
- try:
- tree.compare_trees("UNQUIET STATUS", actual, status_tree)
- except tree.SVNTreeError:
- _log_tree_state("ACTUAL UNQUIET STATUS TREE:", actual, wc_dir_name)
- raise
+ if isinstance(status_tree, wc.State):
+ try:
+ status_tree.compare_and_display('unquiet status', actual_status)
+ except tree.SVNTreeError:
+ _log_tree_state("ACTUAL STATUS TREE:",
+ actual_status.normalize().old_tree(), wc_dir_name)
+ raise
+ else:
+ actual_status = actual_status.old_tree()
+ try:
+ tree.compare_trees("UNQUIET STATUS", actual_status, status_tree)
+ except tree.SVNTreeError:
+ _log_tree_state("ACTUAL UNQUIET STATUS TREE:", actual_status,
+ wc_dir_name)
+ raise
def run_and_verify_status_xml(expected_entries = [],
*args):
@@ -2197,980 +2220,3 @@ def build_greek_tree_conflicts(sbox):
run_and_verify_svn(None, verify.AnyOutput, [], 'update', wc_dir)
-def make_deep_trees(base):
- """Helper function for deep trees conflicts. Create a set of trees,
- each in its own "container" dir. Any conflicts can be tested separately
- in each container.
- """
- j = os.path.join
- # Create the container dirs.
- F = j(base, 'F')
- D = j(base, 'D')
- DF = j(base, 'DF')
- DD = j(base, 'DD')
- DDF = j(base, 'DDF')
- DDD = j(base, 'DDD')
- os.makedirs(F)
- os.makedirs(j(D, 'D1'))
- os.makedirs(j(DF, 'D1'))
- os.makedirs(j(DD, 'D1', 'D2'))
- os.makedirs(j(DDF, 'D1', 'D2'))
- os.makedirs(j(DDD, 'D1', 'D2', 'D3'))
-
- # Create their files.
- alpha = j(F, 'alpha')
- beta = j(DF, 'D1', 'beta')
- gamma = j(DDF, 'D1', 'D2', 'gamma')
- main.file_append(alpha, "This is the file 'alpha'.\n")
- main.file_append(beta, "This is the file 'beta'.\n")
- main.file_append(gamma, "This is the file 'gamma'.\n")
-
-
-def add_deep_trees(sbox, base_dir_name):
- """Prepare a "deep_trees" within a given directory.
-
- The directory <sbox.wc_dir>/<base_dir_name> is created and a deep_tree
- is created within. The items are only added, a commit has to be
- called separately, if needed.
-
- <base_dir_name> will thus be a container for the set of containers
- mentioned in make_deep_trees().
- """
- j = os.path.join
- base = j(sbox.wc_dir, base_dir_name)
- make_deep_trees(base)
- main.run_svn(None, 'add', base)
-
-
-Item = wc.StateItem
-
-# initial deep trees state
-deep_trees_virginal_state = wc.State('', {
- 'F' : Item(),
- 'F/alpha' : Item("This is the file 'alpha'.\n"),
- 'D' : Item(),
- 'D/D1' : Item(),
- 'DF' : Item(),
- 'DF/D1' : Item(),
- 'DF/D1/beta' : Item("This is the file 'beta'.\n"),
- 'DD' : Item(),
- 'DD/D1' : Item(),
- 'DD/D1/D2' : Item(),
- 'DDF' : Item(),
- 'DDF/D1' : Item(),
- 'DDF/D1/D2' : Item(),
- 'DDF/D1/D2/gamma' : Item("This is the file 'gamma'.\n"),
- 'DDD' : Item(),
- 'DDD/D1' : Item(),
- 'DDD/D1/D2' : Item(),
- 'DDD/D1/D2/D3' : Item(),
- })
-
-
-# Many actions on deep trees and their resulting states...
-
-def deep_trees_leaf_edit(base):
- """Helper function for deep trees test cases. Append text to files,
- create new files in empty directories, and change leaf node properties."""
- j = os.path.join
- F = j(base, 'F', 'alpha')
- DF = j(base, 'DF', 'D1', 'beta')
- DDF = j(base, 'DDF', 'D1', 'D2', 'gamma')
- main.file_append(F, "More text for file alpha.\n")
- main.file_append(DF, "More text for file beta.\n")
- main.file_append(DDF, "More text for file gamma.\n")
- run_and_verify_svn(None, verify.AnyOutput, [],
- 'propset', 'prop1', '1', F, DF, DDF)
-
- D = j(base, 'D', 'D1')
- DD = j(base, 'DD', 'D1', 'D2')
- DDD = j(base, 'DDD', 'D1', 'D2', 'D3')
- run_and_verify_svn(None, verify.AnyOutput, [],
- 'propset', 'prop1', '1', D, DD, DDD)
- D = j(base, 'D', 'D1', 'delta')
- DD = j(base, 'DD', 'D1', 'D2', 'epsilon')
- DDD = j(base, 'DDD', 'D1', 'D2', 'D3', 'zeta')
- main.file_append(D, "This is the file 'delta'.\n")
- main.file_append(DD, "This is the file 'epsilon'.\n")
- main.file_append(DDD, "This is the file 'zeta'.\n")
- run_and_verify_svn(None, verify.AnyOutput, [],
- 'add', D, DD, DDD)
-
-# deep trees state after a call to deep_trees_leaf_edit
-deep_trees_after_leaf_edit = wc.State('', {
- 'F' : Item(),
- 'F/alpha' : Item("This is the file 'alpha'.\nMore text for file alpha.\n"),
- 'D' : Item(),
- 'D/D1' : Item(),
- 'D/D1/delta' : Item("This is the file 'delta'.\n"),
- 'DF' : Item(),
- 'DF/D1' : Item(),
- 'DF/D1/beta' : Item("This is the file 'beta'.\nMore text for file beta.\n"),
- 'DD' : Item(),
- 'DD/D1' : Item(),
- 'DD/D1/D2' : Item(),
- 'DD/D1/D2/epsilon' : Item("This is the file 'epsilon'.\n"),
- 'DDF' : Item(),
- 'DDF/D1' : Item(),
- 'DDF/D1/D2' : Item(),
- 'DDF/D1/D2/gamma' : Item("This is the file 'gamma'.\nMore text for file gamma.\n"),
- 'DDD' : Item(),
- 'DDD/D1' : Item(),
- 'DDD/D1/D2' : Item(),
- 'DDD/D1/D2/D3' : Item(),
- 'DDD/D1/D2/D3/zeta' : Item("This is the file 'zeta'.\n"),
- })
-
-
-def deep_trees_leaf_del(base):
- """Helper function for deep trees test cases. Delete files and empty
- dirs."""
- j = os.path.join
- F = j(base, 'F', 'alpha')
- D = j(base, 'D', 'D1')
- DF = j(base, 'DF', 'D1', 'beta')
- DD = j(base, 'DD', 'D1', 'D2')
- DDF = j(base, 'DDF', 'D1', 'D2', 'gamma')
- DDD = j(base, 'DDD', 'D1', 'D2', 'D3')
- main.run_svn(None, 'rm', F, D, DF, DD, DDF, DDD)
-
-# deep trees state after a call to deep_trees_leaf_del
-deep_trees_after_leaf_del = wc.State('', {
- 'F' : Item(),
- 'D' : Item(),
- 'DF' : Item(),
- 'DF/D1' : Item(),
- 'DD' : Item(),
- 'DD/D1' : Item(),
- 'DDF' : Item(),
- 'DDF/D1' : Item(),
- 'DDF/D1/D2' : Item(),
- 'DDD' : Item(),
- 'DDD/D1' : Item(),
- 'DDD/D1/D2' : Item(),
- })
-
-# deep trees state after a call to deep_trees_leaf_del with no commit
-def deep_trees_after_leaf_del_no_ci(wc_dir):
- if svntest.main.wc_is_singledb(wc_dir):
- return deep_trees_after_leaf_del
- else:
- return deep_trees_empty_dirs
-
-
-def deep_trees_tree_del(base):
- """Helper function for deep trees test cases. Delete top-level dirs."""
- j = os.path.join
- F = j(base, 'F', 'alpha')
- D = j(base, 'D', 'D1')
- DF = j(base, 'DF', 'D1')
- DD = j(base, 'DD', 'D1')
- DDF = j(base, 'DDF', 'D1')
- DDD = j(base, 'DDD', 'D1')
- main.run_svn(None, 'rm', F, D, DF, DD, DDF, DDD)
-
-def deep_trees_rmtree(base):
- """Helper function for deep trees test cases. Delete top-level dirs
- with rmtree instead of svn del."""
- j = os.path.join
- F = j(base, 'F', 'alpha')
- D = j(base, 'D', 'D1')
- DF = j(base, 'DF', 'D1')
- DD = j(base, 'DD', 'D1')
- DDF = j(base, 'DDF', 'D1')
- DDD = j(base, 'DDD', 'D1')
- os.unlink(F)
- main.safe_rmtree(D)
- main.safe_rmtree(DF)
- main.safe_rmtree(DD)
- main.safe_rmtree(DDF)
- main.safe_rmtree(DDD)
-
-# deep trees state after a call to deep_trees_tree_del
-deep_trees_after_tree_del = wc.State('', {
- 'F' : Item(),
- 'D' : Item(),
- 'DF' : Item(),
- 'DD' : Item(),
- 'DDF' : Item(),
- 'DDD' : Item(),
- })
-
-# deep trees state without any files
-deep_trees_empty_dirs = wc.State('', {
- 'F' : Item(),
- 'D' : Item(),
- 'D/D1' : Item(),
- 'DF' : Item(),
- 'DF/D1' : Item(),
- 'DD' : Item(),
- 'DD/D1' : Item(),
- 'DD/D1/D2' : Item(),
- 'DDF' : Item(),
- 'DDF/D1' : Item(),
- 'DDF/D1/D2' : Item(),
- 'DDD' : Item(),
- 'DDD/D1' : Item(),
- 'DDD/D1/D2' : Item(),
- 'DDD/D1/D2/D3' : Item(),
- })
-
-# deep trees state after a call to deep_trees_tree_del with no commit
-def deep_trees_after_tree_del_no_ci(wc_dir):
- if svntest.main.wc_is_singledb(wc_dir):
- return deep_trees_after_tree_del
- else:
- return deep_trees_empty_dirs
-
-def deep_trees_tree_del_repos(base):
- """Helper function for deep trees test cases. Delete top-level dirs,
- directly in the repository."""
- j = '/'.join
- F = j([base, 'F', 'alpha'])
- D = j([base, 'D', 'D1'])
- DF = j([base, 'DF', 'D1'])
- DD = j([base, 'DD', 'D1'])
- DDF = j([base, 'DDF', 'D1'])
- DDD = j([base, 'DDD', 'D1'])
- main.run_svn(None, 'mkdir', '-m', '', F, D, DF, DD, DDF, DDD)
-
-# Expected merge/update/switch output.
-
-deep_trees_conflict_output = wc.State('', {
- 'F/alpha' : Item(status=' ', treeconflict='C'),
- 'D/D1' : Item(status=' ', treeconflict='C'),
- 'DF/D1' : Item(status=' ', treeconflict='C'),
- 'DD/D1' : Item(status=' ', treeconflict='C'),
- 'DDF/D1' : Item(status=' ', treeconflict='C'),
- 'DDD/D1' : Item(status=' ', treeconflict='C'),
- })
-
-deep_trees_conflict_output_skipped = wc.State('', {
- 'D/D1' : Item(verb='Skipped'),
- 'F/alpha' : Item(verb='Skipped'),
- 'DD/D1' : Item(verb='Skipped'),
- 'DF/D1' : Item(verb='Skipped'),
- 'DDD/D1' : Item(verb='Skipped'),
- 'DDF/D1' : Item(verb='Skipped'),
- })
-
-# Expected status output after merge/update/switch.
-
-deep_trees_status_local_tree_del = wc.State('', {
- '' : Item(status=' ', wc_rev=3),
- 'D' : Item(status=' ', wc_rev=3),
- 'D/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
- 'DD' : Item(status=' ', wc_rev=3),
- 'DD/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
- 'DD/D1/D2' : Item(status='D ', wc_rev=2),
- 'DDD' : Item(status=' ', wc_rev=3),
- 'DDD/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
- 'DDD/D1/D2' : Item(status='D ', wc_rev=2),
- 'DDD/D1/D2/D3' : Item(status='D ', wc_rev=2),
- 'DDF' : Item(status=' ', wc_rev=3),
- 'DDF/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
- 'DDF/D1/D2' : Item(status='D ', wc_rev=2),
- 'DDF/D1/D2/gamma' : Item(status='D ', wc_rev=2),
- 'DF' : Item(status=' ', wc_rev=3),
- 'DF/D1' : Item(status='D ', wc_rev=2, treeconflict='C'),
- 'DF/D1/beta' : Item(status='D ', wc_rev=2),
- 'F' : Item(status=' ', wc_rev=3),
- 'F/alpha' : Item(status='D ', wc_rev=2, treeconflict='C'),
- })
-
-deep_trees_status_local_leaf_edit = wc.State('', {
- '' : Item(status=' ', wc_rev=3),
- 'D' : Item(status=' ', wc_rev=3),
- 'D/D1' : Item(status=' M', wc_rev=2, treeconflict='C'),
- 'D/D1/delta' : Item(status='A ', wc_rev=0),
- 'DD' : Item(status=' ', wc_rev=3),
- 'DD/D1' : Item(status=' ', wc_rev=2, treeconflict='C'),
- 'DD/D1/D2' : Item(status=' M', wc_rev=2),
- 'DD/D1/D2/epsilon' : Item(status='A ', wc_rev=0),
- 'DDD' : Item(status=' ', wc_rev=3),
- 'DDD/D1' : Item(status=' ', wc_rev=2, treeconflict='C'),
- 'DDD/D1/D2' : Item(status=' ', wc_rev=2),
- 'DDD/D1/D2/D3' : Item(status=' M', wc_rev=2),
- 'DDD/D1/D2/D3/zeta' : Item(status='A ', wc_rev=0),
- 'DDF' : Item(status=' ', wc_rev=3),
- 'DDF/D1' : Item(status=' ', wc_rev=2, treeconflict='C'),
- 'DDF/D1/D2' : Item(status=' ', wc_rev=2),
- 'DDF/D1/D2/gamma' : Item(status='MM', wc_rev=2),
- 'DF' : Item(status=' ', wc_rev=3),
- 'DF/D1' : Item(status=' ', wc_rev=2, treeconflict='C'),
- 'DF/D1/beta' : Item(status='MM', wc_rev=2),
- 'F' : Item(status=' ', wc_rev=3),
- 'F/alpha' : Item(status='MM', wc_rev=2, treeconflict='C'),
- })
-
-
-class DeepTreesTestCase:
- """Describes one tree-conflicts test case.
- See deep_trees_run_tests_scheme_for_update(), ..._switch(), ..._merge().
-
- The name field is the subdirectory name in which the test should be run.
-
- The local_action and incoming_action are the functions to run
- to construct the local changes and incoming changes, respectively.
- See deep_trees_leaf_edit, deep_trees_tree_del, etc.
-
- The expected_* and error_re_string arguments are described in functions
- run_and_verify_[update|switch|merge]
- except expected_info, which is a dict that has path keys with values
- that are dicts as passed to run_and_verify_info():
- expected_info = {
- 'F/alpha' : {
- 'Revision' : '3',
- 'Tree conflict' :
- '^local delete, incoming edit upon update'
- + ' Source left: .file.*/F/alpha@2'
- + ' Source right: .file.*/F/alpha@3$',
- },
- 'DF/D1' : {
- 'Tree conflict' :
- '^local delete, incoming edit upon update'
- + ' Source left: .dir.*/DF/D1@2'
- + ' Source right: .dir.*/DF/D1@3$',
- },
- ...
- }
-
- Note: expected_skip is only used in merge, i.e. using
- deep_trees_run_tests_scheme_for_merge.
- """
-
- def __init__(self, name, local_action, incoming_action,
- expected_output = None, expected_disk = None,
- expected_status = None, expected_skip = None,
- error_re_string = None,
- commit_block_string = ".*remains in conflict.*",
- expected_info = None):
- self.name = name
- self.local_action = local_action
- self.incoming_action = incoming_action
- self.expected_output = expected_output
- self.expected_disk = expected_disk
- self.expected_status = expected_status
- self.expected_skip = expected_skip
- self.error_re_string = error_re_string
- self.commit_block_string = commit_block_string
- self.expected_info = expected_info
-
-
-
-def deep_trees_run_tests_scheme_for_update(sbox, greater_scheme):
- """
- Runs a given list of tests for conflicts occuring at an update operation.
-
- This function wants to save time and perform a number of different
- test cases using just a single repository and performing just one commit
- for all test cases instead of one for each test case.
-
- 1) Each test case is initialized in a separate subdir. Each subdir
- again contains one set of "deep_trees", being separate container
- dirs for different depths of trees (F, D, DF, DD, DDF, DDD).
-
- 2) A commit is performed across all test cases and depths.
- (our initial state, -r2)
-
- 3) In each test case subdir (e.g. "local_tree_del_incoming_leaf_edit"),
- its *incoming* action is performed (e.g. "deep_trees_leaf_edit"), in
- each of the different depth trees (F, D, DF, ... DDD).
-
- 4) A commit is performed across all test cases and depths:
- our "incoming" state is "stored away in the repository for now",
- -r3.
-
- 5) All test case dirs and contained deep_trees are time-warped
- (updated) back to -r2, the initial state containing deep_trees.
-
- 6) In each test case subdir (e.g. "local_tree_del_incoming_leaf_edit"),
- its *local* action is performed (e.g. "deep_trees_leaf_del"), in
- each of the different depth trees (F, D, DF, ... DDD).
-
- 7) An update to -r3 is performed across all test cases and depths.
- This causes tree-conflicts between the "local" state in the working
- copy and the "incoming" state from the repository, -r3.
-
- 8) A commit is performed in each separate container, to verify
- that each tree-conflict indeed blocks a commit.
-
- The sbox parameter is just the sbox passed to a test function. No need
- to call sbox.build(), since it is called (once) within this function.
-
- The "table" greater_scheme models all of the different test cases
- that should be run using a single repository.
-
- greater_scheme is a list of DeepTreesTestCase items, which define complete
- test setups, so that they can be performed as described above.
- """
-
- j = os.path.join
-
- if not sbox.is_built():
- sbox.build()
- wc_dir = sbox.wc_dir
-
-
- # 1) create directories
-
- for test_case in greater_scheme:
- try:
- add_deep_trees(sbox, test_case.name)
- except:
- logger.warn("ERROR IN: Tests scheme for update: "
- + "while setting up deep trees in '%s'", test_case.name)
- raise
-
-
- # 2) commit initial state
-
- main.run_svn(None, 'commit', '-m', 'initial state', wc_dir)
-
-
- # 3) apply incoming changes
-
- for test_case in greater_scheme:
- try:
- test_case.incoming_action(j(sbox.wc_dir, test_case.name))
- except:
- logger.warn("ERROR IN: Tests scheme for update: "
- + "while performing incoming action in '%s'", test_case.name)
- raise
-
-
- # 4) commit incoming changes
-
- main.run_svn(None, 'commit', '-m', 'incoming changes', wc_dir)
-
-
- # 5) time-warp back to -r2
-
- main.run_svn(None, 'update', '-r2', wc_dir)
-
-
- # 6) apply local changes
-
- for test_case in greater_scheme:
- try:
- test_case.local_action(j(wc_dir, test_case.name))
- except:
- logger.warn("ERROR IN: Tests scheme for update: "
- + "while performing local action in '%s'", test_case.name)
- raise
-
-
- # 7) update to -r3, conflicting with incoming changes.
- # A lot of different things are expected.
- # Do separate update operations for each test case.
-
- for test_case in greater_scheme:
- try:
- base = j(wc_dir, test_case.name)
-
- x_out = test_case.expected_output
- if x_out != None:
- x_out = x_out.copy()
- x_out.wc_dir = base
-
- x_disk = test_case.expected_disk
-
- x_status = test_case.expected_status
- if x_status != None:
- x_status.copy()
- x_status.wc_dir = base
-
- run_and_verify_update(base, x_out, x_disk, None,
- error_re_string = test_case.error_re_string)
- if x_status:
- run_and_verify_unquiet_status(base, x_status)
-
- x_info = test_case.expected_info or {}
- for path in x_info:
- run_and_verify_info([x_info[path]], j(base, path))
-
- except:
- logger.warn("ERROR IN: Tests scheme for update: "
- + "while verifying in '%s'", test_case.name)
- raise
-
-
- # 8) Verify that commit fails.
-
- for test_case in greater_scheme:
- try:
- base = j(wc_dir, test_case.name)
-
- x_status = test_case.expected_status
- if x_status != None:
- x_status.copy()
- x_status.wc_dir = base
-
- run_and_verify_commit(base, None, x_status,
- test_case.commit_block_string,
- base)
- except:
- logger.warn("ERROR IN: Tests scheme for update: "
- + "while checking commit-blocking in '%s'", test_case.name)
- raise
-
-
-
-def deep_trees_skipping_on_update(sbox, test_case, skip_paths,
- chdir_skip_paths):
- """
- Create tree conflicts, then update again, expecting the existing tree
- conflicts to be skipped.
- SKIP_PATHS is a list of paths, relative to the "base dir", for which
- "update" on the "base dir" should report as skipped.
- CHDIR_SKIP_PATHS is a list of (target-path, skipped-path) pairs for which
- an update of "target-path" (relative to the "base dir") should result in
- "skipped-path" (relative to "target-path") being reported as skipped.
- """
-
- """FURTHER_ACTION is a function that will make a further modification to
- each target, this being the modification that we expect to be skipped. The
- function takes the "base dir" (the WC path to the test case directory) as
- its only argument."""
- further_action = deep_trees_tree_del_repos
-
- j = os.path.join
- wc_dir = sbox.wc_dir
- base = j(wc_dir, test_case.name)
-
- # Initialize: generate conflicts. (We do not check anything here.)
- setup_case = DeepTreesTestCase(test_case.name,
- test_case.local_action,
- test_case.incoming_action,
- None,
- None,
- None)
- deep_trees_run_tests_scheme_for_update(sbox, [setup_case])
-
- # Make a further change to each target in the repository so there is a new
- # revision to update to. (This is r4.)
- further_action(sbox.repo_url + '/' + test_case.name)
-
- # Update whole working copy, expecting the nodes still in conflict to be
- # skipped.
-
- x_out = test_case.expected_output
- if x_out != None:
- x_out = x_out.copy()
- x_out.wc_dir = base
-
- x_disk = test_case.expected_disk
-
- x_status = test_case.expected_status
- if x_status != None:
- x_status = x_status.copy()
- x_status.wc_dir = base
- # Account for nodes that were updated by further_action
- x_status.tweak('', 'D', 'F', 'DD', 'DF', 'DDD', 'DDF', wc_rev=4)
-
- run_and_verify_update(base, x_out, x_disk, None,
- error_re_string = test_case.error_re_string)
-
- run_and_verify_unquiet_status(base, x_status)
-
- # Try to update each in-conflict subtree. Expect a 'Skipped' output for
- # each, and the WC status to be unchanged.
- for path in skip_paths:
- run_and_verify_update(j(base, path),
- wc.State(base, {path : Item(verb='Skipped')}),
- None, None)
-
- run_and_verify_unquiet_status(base, x_status)
-
- # Try to update each in-conflict subtree. Expect a 'Skipped' output for
- # each, and the WC status to be unchanged.
- # This time, cd to the subdir before updating it.
- was_cwd = os.getcwd()
- for path, skipped in chdir_skip_paths:
- if isinstance(skipped, list):
- expected_skip = {}
- for p in skipped:
- expected_skip[p] = Item(verb='Skipped')
- else:
- expected_skip = {skipped : Item(verb='Skipped')}
- p = j(base, path)
- run_and_verify_update(p,
- wc.State(p, expected_skip),
- None, None)
- os.chdir(was_cwd)
-
- run_and_verify_unquiet_status(base, x_status)
-
- # Verify that commit still fails.
- for path, skipped in chdir_skip_paths:
-
- run_and_verify_commit(j(base, path), None, None,
- test_case.commit_block_string,
- base)
-
- run_and_verify_unquiet_status(base, x_status)
-
-
-def deep_trees_run_tests_scheme_for_switch(sbox, greater_scheme):
- """
- Runs a given list of tests for conflicts occuring at a switch operation.
-
- This function wants to save time and perform a number of different
- test cases using just a single repository and performing just one commit
- for all test cases instead of one for each test case.
-
- 1) Each test case is initialized in a separate subdir. Each subdir
- again contains two subdirs: one "local" and one "incoming" for
- the switch operation. These contain a set of deep_trees each.
-
- 2) A commit is performed across all test cases and depths.
- (our initial state, -r2)
-
- 3) In each test case subdir's incoming subdir, the
- incoming actions are performed.
-
- 4) A commit is performed across all test cases and depths. (-r3)
-
- 5) In each test case subdir's local subdir, the local actions are
- performed. They remain uncommitted in the working copy.
-
- 6) In each test case subdir's local dir, a switch is performed to its
- corresponding incoming dir.
- This causes conflicts between the "local" state in the working
- copy and the "incoming" state from the incoming subdir (still -r3).
-
- 7) A commit is performed in each separate container, to verify
- that each tree-conflict indeed blocks a commit.
-
- The sbox parameter is just the sbox passed to a test function. No need
- to call sbox.build(), since it is called (once) within this function.
-
- The "table" greater_scheme models all of the different test cases
- that should be run using a single repository.
-
- greater_scheme is a list of DeepTreesTestCase items, which define complete
- test setups, so that they can be performed as described above.
- """
-
- j = os.path.join
-
- if not sbox.is_built():
- sbox.build()
- wc_dir = sbox.wc_dir
-
-
- # 1) Create directories.
-
- for test_case in greater_scheme:
- try:
- base = j(sbox.wc_dir, test_case.name)
- os.makedirs(base)
- make_deep_trees(j(base, "local"))
- make_deep_trees(j(base, "incoming"))
- main.run_svn(None, 'add', base)
- except:
- logger.warn("ERROR IN: Tests scheme for switch: "
- + "while setting up deep trees in '%s'", test_case.name)
- raise
-
-
- # 2) Commit initial state (-r2).
-
- main.run_svn(None, 'commit', '-m', 'initial state', wc_dir)
-
-
- # 3) Apply incoming changes
-
- for test_case in greater_scheme:
- try:
- test_case.incoming_action(j(sbox.wc_dir, test_case.name, "incoming"))
- except:
- logger.warn("ERROR IN: Tests scheme for switch: "
- + "while performing incoming action in '%s'", test_case.name)
- raise
-
-
- # 4) Commit all changes (-r3).
-
- main.run_svn(None, 'commit', '-m', 'incoming changes', wc_dir)
-
-
- # 5) Apply local changes in their according subdirs.
-
- for test_case in greater_scheme:
- try:
- test_case.local_action(j(sbox.wc_dir, test_case.name, "local"))
- except:
- logger.warn("ERROR IN: Tests scheme for switch: "
- + "while performing local action in '%s'", test_case.name)
- raise
-
-
- # 6) switch the local dir to the incoming url, conflicting with incoming
- # changes. A lot of different things are expected.
- # Do separate switch operations for each test case.
-
- for test_case in greater_scheme:
- try:
- local = j(wc_dir, test_case.name, "local")
- incoming = sbox.repo_url + "/" + test_case.name + "/incoming"
-
- x_out = test_case.expected_output
- if x_out != None:
- x_out = x_out.copy()
- x_out.wc_dir = local
-
- x_disk = test_case.expected_disk
-
- x_status = test_case.expected_status
- if x_status != None:
- x_status.copy()
- x_status.wc_dir = local
-
- run_and_verify_switch(local, local, incoming, x_out, x_disk, None,
- test_case.error_re_string, None, None, None,
- None, False, '--ignore-ancestry')
- run_and_verify_unquiet_status(local, x_status)
-
- x_info = test_case.expected_info or {}
- for path in x_info:
- run_and_verify_info([x_info[path]], j(local, path))
- except:
- logger.warn("ERROR IN: Tests scheme for switch: "
- + "while verifying in '%s'", test_case.name)
- raise
-
-
- # 7) Verify that commit fails.
-
- for test_case in greater_scheme:
- try:
- local = j(wc_dir, test_case.name, 'local')
-
- x_status = test_case.expected_status
- if x_status != None:
- x_status.copy()
- x_status.wc_dir = local
-
- run_and_verify_commit(local, None, x_status,
- test_case.commit_block_string,
- local)
- except:
- logger.warn("ERROR IN: Tests scheme for switch: "
- + "while checking commit-blocking in '%s'", test_case.name)
- raise
-
-
-def deep_trees_run_tests_scheme_for_merge(sbox, greater_scheme,
- do_commit_local_changes,
- do_commit_conflicts=True,
- ignore_ancestry=False):
- """
- Runs a given list of tests for conflicts occuring at a merge operation.
-
- This function wants to save time and perform a number of different
- test cases using just a single repository and performing just one commit
- for all test cases instead of one for each test case.
-
- 1) Each test case is initialized in a separate subdir. Each subdir
- initially contains another subdir, called "incoming", which
- contains a set of deep_trees.
-
- 2) A commit is performed across all test cases and depths.
- (a pre-initial state)
-
- 3) In each test case subdir, the "incoming" subdir is copied to "local",
- via the `svn copy' command. Each test case's subdir now has two sub-
- dirs: "local" and "incoming", initial states for the merge operation.
-
- 4) An update is performed across all test cases and depths, so that the
- copies made in 3) are pulled into the wc.
-
- 5) In each test case's "incoming" subdir, the incoming action is
- performed.
-
- 6) A commit is performed across all test cases and depths, to commit
- the incoming changes.
- If do_commit_local_changes is True, this becomes step 7 (swap steps).
-
- 7) In each test case's "local" subdir, the local_action is performed.
- If do_commit_local_changes is True, this becomes step 6 (swap steps).
- Then, in effect, the local changes are committed as well.
-
- 8) In each test case subdir, the "incoming" subdir is merged into the
- "local" subdir. If ignore_ancestry is True, then the merge is done
- with the --ignore-ancestry option, so mergeinfo is neither considered
- nor recorded. This causes conflicts between the "local" state in the
- working copy and the "incoming" state from the incoming subdir.
-
- 9) If do_commit_conflicts is True, then a commit is performed in each
- separate container, to verify that each tree-conflict indeed blocks
- a commit.
-
- The sbox parameter is just the sbox passed to a test function. No need
- to call sbox.build(), since it is called (once) within this function.
-
- The "table" greater_scheme models all of the different test cases
- that should be run using a single repository.
-
- greater_scheme is a list of DeepTreesTestCase items, which define complete
- test setups, so that they can be performed as described above.
- """
-
- j = os.path.join
-
- if not sbox.is_built():
- sbox.build()
- wc_dir = sbox.wc_dir
-
- # 1) Create directories.
- for test_case in greater_scheme:
- try:
- base = j(sbox.wc_dir, test_case.name)
- os.makedirs(base)
- make_deep_trees(j(base, "incoming"))
- main.run_svn(None, 'add', base)
- except:
- logger.warn("ERROR IN: Tests scheme for merge: "
- + "while setting up deep trees in '%s'", test_case.name)
- raise
-
-
- # 2) Commit pre-initial state (-r2).
-
- main.run_svn(None, 'commit', '-m', 'pre-initial state', wc_dir)
-
-
- # 3) Copy "incoming" to "local".
-
- for test_case in greater_scheme:
- try:
- base_url = sbox.repo_url + "/" + test_case.name
- incoming_url = base_url + "/incoming"
- local_url = base_url + "/local"
- main.run_svn(None, 'cp', incoming_url, local_url, '-m',
- 'copy incoming to local')
- except:
- logger.warn("ERROR IN: Tests scheme for merge: "
- + "while copying deep trees in '%s'", test_case.name)
- raise
-
- # 4) Update to load all of the "/local" subdirs into the working copies.
-
- try:
- main.run_svn(None, 'up', sbox.wc_dir)
- except:
- logger.warn("ERROR IN: Tests scheme for merge: "
- + "while updating local subdirs")
- raise
-
-
- # 5) Perform incoming actions
-
- for test_case in greater_scheme:
- try:
- test_case.incoming_action(j(sbox.wc_dir, test_case.name, "incoming"))
- except:
- logger.warn("ERROR IN: Tests scheme for merge: "
- + "while performing incoming action in '%s'", test_case.name)
- raise
-
-
- # 6) or 7) Commit all incoming actions
-
- if not do_commit_local_changes:
- try:
- main.run_svn(None, 'ci', '-m', 'Committing incoming actions',
- sbox.wc_dir)
- except:
- logger.warn("ERROR IN: Tests scheme for merge: "
- + "while committing incoming actions")
- raise
-
-
- # 7) or 6) Perform all local actions.
-
- for test_case in greater_scheme:
- try:
- test_case.local_action(j(sbox.wc_dir, test_case.name, "local"))
- except:
- logger.warn("ERROR IN: Tests scheme for merge: "
- + "while performing local action in '%s'", test_case.name)
- raise
-
-
- # 6) or 7) Commit all incoming actions
-
- if do_commit_local_changes:
- try:
- main.run_svn(None, 'ci', '-m', 'Committing incoming and local actions',
- sbox.wc_dir)
- except:
- logger.warn("ERROR IN: Tests scheme for merge: "
- + "while committing incoming and local actions")
- raise
-
-
- # 8) Merge all "incoming" subdirs to their respective "local" subdirs.
- # This creates conflicts between the local changes in the "local" wc
- # subdirs and the incoming states committed in the "incoming" subdirs.
-
- for test_case in greater_scheme:
- try:
- local = j(sbox.wc_dir, test_case.name, "local")
- incoming = sbox.repo_url + "/" + test_case.name + "/incoming"
-
- x_out = test_case.expected_output
- if x_out != None:
- x_out = x_out.copy()
- x_out.wc_dir = local
-
- x_disk = test_case.expected_disk
-
- x_status = test_case.expected_status
- if x_status != None:
- x_status.copy()
- x_status.wc_dir = local
-
- x_skip = test_case.expected_skip
- if x_skip != None:
- x_skip.copy()
- x_skip.wc_dir = local
-
- varargs = (local,)
- if ignore_ancestry:
- varargs = varargs + ('--ignore-ancestry',)
-
- run_and_verify_merge(local, None, None, incoming, None,
- x_out, None, None, x_disk, None, x_skip,
- test_case.error_re_string,
- None, None, None, None,
- False, False, *varargs)
- run_and_verify_unquiet_status(local, x_status)
- except:
- logger.warn("ERROR IN: Tests scheme for merge: "
- + "while verifying in '%s'", test_case.name)
- raise
-
-
- # 9) Verify that commit fails.
-
- if do_commit_conflicts:
- for test_case in greater_scheme:
- try:
- local = j(wc_dir, test_case.name, 'local')
-
- x_status = test_case.expected_status
- if x_status != None:
- x_status.copy()
- x_status.wc_dir = local
-
- run_and_verify_commit(local, None, x_status,
- test_case.commit_block_string,
- local)
- except:
- logger.warn("ERROR IN: Tests scheme for merge: "
- + "while checking commit-blocking in '%s'", test_case.name)
- raise
-
-
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svntest/main.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svntest/main.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svntest/main.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svntest/main.py Sat Feb 23 01:25:38 2013
@@ -157,6 +157,15 @@ atomic_ra_revprop_change_binary = os.pat
wc_lock_tester_binary = os.path.abspath('../libsvn_wc/wc-lock-tester' + _exe)
wc_incomplete_tester_binary = os.path.abspath('../libsvn_wc/wc-incomplete-tester' + _exe)
+######################################################################
+# The location of svnauthz binary, relative to the only scripts that
+# import this file right now (they live in ../).
+# Use --tools to overide these defaults.
+svnauthz_binary = os.path.abspath('../../../tools/server-side/svnauthz' + _exe)
+svnauthz_validate_binary = os.path.abspath(
+ '../../../tools/server-side/svnauthz-validate' + _exe
+)
+
# Location to the pristine repository, will be calculated from test_area_url
# when we know what the user specified for --url.
pristine_greek_repos_url = None
@@ -703,6 +712,16 @@ def run_svnmucc(*varargs):
return run_command(svnmucc_binary, 1, True,
*(_with_auth(_with_config_dir(varargs))))
+def run_svnauthz(*varargs):
+ """Run svnauthz with VARARGS, returns exit code as int; stdout, stderr
+ as list of lines (including line terminators)."""
+ return run_command(svnauthz_binary, 1, False, *varargs)
+
+def run_svnauthz_validate(*varargs):
+ """Run svnauthz-validate with VARARGS, returns exit code as int; stdout,
+ stderr as list of lines (including line terminators)."""
+ return run_command(svnauthz_validate_binary, 1, False, *varargs)
+
def run_entriesdump(path):
"""Run the entries-dump helper, returning a dict of Entry objects."""
# use spawn_process rather than run_command to avoid copying all the data
@@ -727,6 +746,23 @@ def run_entriesdump_subdirs(path):
0, False, None, '--subdirs', path)
return map(lambda line: line.strip(), filter_dbg(stdout_lines))
+def run_entriesdump_tree(path):
+ """Run the entries-dump helper, returning a dict of a dict of Entry objects."""
+ # use spawn_process rather than run_command to avoid copying all the data
+ # to stdout in verbose mode.
+ exit_code, stdout_lines, stderr_lines = spawn_process(entriesdump_binary,
+ 0, False, None,
+ '--tree-dump', path)
+ if exit_code or stderr_lines:
+ ### report on this? or continue to just skip it?
+ return None
+
+ class Entry(object):
+ pass
+ dirs = { }
+ exec(''.join(filter_dbg(stdout_lines)))
+ return dirs
+
def run_atomic_ra_revprop_change(url, revision, propname, skel, want_error):
"""Run the atomic-ra-revprop-change helper, returning its exit code, stdout,
and stderr. For HTTP, default HTTP library is used."""
@@ -1029,6 +1065,19 @@ def write_restrictive_svnserve_conf(repo
fp.write("password-db = passwd\n")
fp.close()
+def write_restrictive_svnserve_conf_with_groups(repo_dir,
+ anon_access="none"):
+ "Create a restrictive configuration with groups stored in a separate file."
+
+ fp = open(get_svnserve_conf_file_path(repo_dir), 'w')
+ fp.write("[general]\nanon-access = %s\nauth-access = write\n"
+ "authz-db = authz\ngroups-db = groups\n" % anon_access)
+ if options.enable_sasl:
+ fp.write("realm = svntest\n[sasl]\nuse-sasl = true\n");
+ else:
+ fp.write("password-db = passwd\n")
+ fp.close()
+
# Warning: because mod_dav_svn uses one shared authz file for all
# repositories, you *cannot* use write_authz_file in any test that
# might be run in parallel.
@@ -1064,6 +1113,18 @@ an appropriate list of mappings.
fp.write("[%s%s]\n%s\n" % (prefix, p, r))
fp.close()
+# See the warning about parallel test execution in write_authz_file
+# method description.
+def write_groups_file(sbox, groups):
+ """Write a groups file to SBOX, appropriate for the RA method used,
+with group contents set to GROUPS."""
+ fp = open(sbox.groups_file, 'w')
+ fp.write("[groups]\n")
+ if groups:
+ for p, r in groups.items():
+ fp.write("%s = %s\n" % (p, r))
+ fp.close()
+
def use_editor(func):
os.environ['SVN_EDITOR'] = svneditor_script
os.environ['SVN_MERGE'] = svneditor_script
@@ -1125,6 +1186,26 @@ def merge_notify_line(revstart=None, rev
return "--- Merging %sr%ld through r%ld into '%s':\n" \
% (from_foreign_phrase, revstart, revend, target_re)
+def summary_of_conflicts(text_conflicts=0, prop_conflicts=0,
+ tree_conflicts=0, skipped_paths=0):
+ """Return a list of lines corresponding to the summary of conflicts and
+ skipped paths that is printed by merge and update and switch. If all
+ parameters are zero, return an empty list.
+ """
+ lines = []
+ if text_conflicts or prop_conflicts or tree_conflicts or skipped_paths:
+ lines.append("Summary of conflicts:\n")
+ if text_conflicts:
+ lines.append(" Text conflicts: %d\n" % text_conflicts)
+ if prop_conflicts:
+ lines.append(" Property conflicts: %d\n" % prop_conflicts)
+ if tree_conflicts:
+ lines.append(" Tree conflicts: %d\n" % tree_conflicts)
+ if skipped_paths:
+ lines.append(" Skipped paths: %d\n" % skipped_paths)
+
+ return lines
+
def make_log_msg():
"Conjure up a log message based on the calling test."
@@ -1643,6 +1724,8 @@ def _create_parser():
help='Path to SSL server certificate.')
parser.add_option('--http-proxy', action='store',
help='Use the HTTP Proxy at hostname:port.')
+ parser.add_option('--tools-bin', action='store', dest='tools_bin',
+ help='Use the svn tools installed in this path')
# most of the defaults are None, but some are other values, set them here
parser.set_defaults(
@@ -1783,6 +1866,8 @@ def execute_tests(test_list, serial_only
global svndumpfilter_binary
global svnversion_binary
global svnmucc_binary
+ global svnauthz_binary
+ global svnauthz_validate_binary
global options
if test_name:
@@ -1900,6 +1985,11 @@ def execute_tests(test_list, serial_only
svnversion_binary = os.path.join(options.svn_bin, 'svnversion' + _exe)
svnmucc_binary = os.path.join(options.svn_bin, 'svnmucc' + _exe)
+ if options.tools_bin:
+ svnauthz_binary = os.path.join(options.tools_bin, 'svnauthz' + _exe)
+ svnauthz_validate_binary = os.path.join(options.tools_bin,
+ 'svnauthz-validate' + _exe)
+
######################################################################
# Cleanup: if a previous run crashed or interrupted the python
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svntest/sandbox.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svntest/sandbox.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svntest/sandbox.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svntest/sandbox.py Sat Feb 23 01:25:38 2013
@@ -37,6 +37,7 @@ class Sandbox:
a test to operate within."""
dependents = None
+ tmp_dir = None
def __init__(self, module, idx):
self.test_paths = []
@@ -45,10 +46,6 @@ class Sandbox:
# This flag is set to True by build() and returned by is_built()
self._is_built = False
- # Create an empty directory for temporary files
- self.tmp_dir = self.add_wc_path('tmp', remove=True)
- os.mkdir(self.tmp_dir)
-
def _set_name(self, name, read_only=False):
"""A convenience method for renaming a sandbox, useful when
working with multiple repositories in the same unit test."""
@@ -78,12 +75,14 @@ class Sandbox:
tmp_authz_file = os.path.join(svntest.main.work_dir, "authz-" + self.name)
open(tmp_authz_file, 'w').write("[/]\n* = rw\n")
shutil.move(tmp_authz_file, self.authz_file)
+ self.groups_file = os.path.join(svntest.main.work_dir, "groups")
# For svnserve tests we have a per-repository authz file, and it
# doesn't need to be there in order for things to work, so we don't
# have any default contents.
elif self.repo_url.startswith("svn"):
self.authz_file = os.path.join(self.repo_dir, "conf", "authz")
+ self.groups_file = os.path.join(self.repo_dir, "conf", "groups")
def clone_dependent(self, copy_wc=False):
"""A convenience method for creating a near-duplicate of this
@@ -157,6 +156,11 @@ class Sandbox:
"""Get a stable name for a temporary file that will be removed after
running the test"""
+ if not self.tmp_dir:
+ # Create an empty directory for temporary files
+ self.tmp_dir = self.add_wc_path('tmp', remove=True)
+ os.mkdir(self.tmp_dir)
+
self.tempname_offs = self.tempname_offs + 1
return os.path.join(self.tmp_dir, '%s-%s' % (prefix, self.tempname_offs))
@@ -189,6 +193,12 @@ class Sandbox:
path WC_DIR if supplied."""
return [self.ospath(rp, wc_dir) for rp in relpaths]
+ def path(self, relpath, wc_dir=None):
+ """Return RELPATH converted to an path relative to the WC dir
+ of this sbox, or relative to WC_DIR if supplied, but always
+ using '/' as directory separator."""
+ return self.ospath(relpath, wc_dir=wc_dir).replace(os.path.sep, '/')
+
def redirected_root_url(self, temporary=False):
"""If TEMPORARY is set, return the URL which should be configured
to temporarily redirect to the root of this repository;
@@ -231,8 +241,8 @@ class Sandbox:
target = self.ospath(target)
if message is None:
message = svntest.main.make_log_msg()
- svntest.main.run_svn(False, 'commit', '-m', message,
- target)
+ svntest.actions.run_and_verify_commit(self.wc_dir, None, None, [],
+ '-m', message, target)
def simple_rm(self, *targets):
"""Schedule TARGETS for deletion.
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svntest/tree.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svntest/tree.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svntest/tree.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svntest/tree.py Sat Feb 23 01:25:38 2013
@@ -838,11 +838,10 @@ def build_tree_from_commit(lines):
# IFF columns non-empty.
#
-def build_tree_from_status(lines, wc_dir_name=None):
+def build_tree_from_status(lines):
"Return a tree derived by parsing the output LINES from 'st -vuq'."
- return svntest.wc.State.from_status(lines,
- wc_dir_name=wc_dir_name).old_tree()
+ return svntest.wc.State.from_status(lines).old_tree()
# Parse merge "skipped" output
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svntest/verify.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svntest/verify.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svntest/verify.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svntest/verify.py Sat Feb 23 01:25:38 2013
@@ -96,129 +96,72 @@ def createExpectedOutput(expected, outpu
raise SVNIncorrectDatatype("Unexpected type for '%s' data" % output_type)
return expected
-class ExpectedOutput:
- """Contains expected output, and performs comparisons."""
+class ExpectedOutput(object):
+ """Matches an ordered list of lines.
- is_regex = False
- is_unordered = False
+ If MATCH_ALL is True, the expected lines must match all the actual
+ lines, one-to-one, in the same order. If MATCH_ALL is False, the
+ expected lines must match a subset of the actual lines, one-to-one,
+ in the same order, ignoring any other actual lines among the
+ matching ones.
+ """
- 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
- expected strings will be matched with the actual strings, one-to-one, in
- the same order. If False, they will be matched with a subset of the
- actual strings, one-to-one, in the same order, ignoring any other actual
- strings among the matching ones."""
- self.output = output
+ def __init__(self, expected, match_all=True):
+ """Initialize the expected output to EXPECTED which is a string, or
+ a list of strings.
+ """
+ assert expected is not None
+ self.expected = expected
self.match_all = match_all
def __str__(self):
- return str(self.output)
+ return str(self.expected)
def __cmp__(self, other):
- raise Exception('badness')
-
- def matches(self, other, except_re=None):
- """Return whether SELF.output matches OTHER (which may be a list
- of newline-terminated lines, or a single string). Either value
- may be None."""
- if self.output is None:
- expected = []
- else:
- expected = self.output
- if other is None:
- actual = []
- else:
- actual = other
+ raise TypeError("ExpectedOutput does not implement direct comparison; "
+ "see the 'matches()' method")
- if not isinstance(actual, list):
- actual = [actual]
+ def matches(self, actual):
+ """Return whether SELF matches ACTUAL (which may be a list
+ of newline-terminated lines, or a single string).
+ """
+ assert actual is not None
+ expected = self.expected
if not isinstance(expected, list):
expected = [expected]
+ if not isinstance(actual, list):
+ actual = [actual]
- if except_re:
- return self.matches_except(expected, actual, except_re)
- else:
- return self.is_equivalent_list(expected, actual)
-
- def matches_except(self, expected, actual, except_re):
- "Return whether EXPECTED and ACTUAL match except for except_re."
- if not self.is_regex:
- i_expected = 0
- i_actual = 0
- while i_expected < len(expected) and i_actual < len(actual):
- if re.match(except_re, actual[i_actual]):
- i_actual += 1
- elif re.match(except_re, expected[i_expected]):
- i_expected += 1
- elif expected[i_expected] == actual[i_actual]:
- i_expected += 1
- i_actual += 1
- else:
- return False
- if i_expected == len(expected) and i_actual == len(actual):
- return True
- return False
- else:
- raise Exception("is_regex and except_re are mutually exclusive")
-
- def is_equivalent_list(self, expected, actual):
- "Return whether EXPECTED and ACTUAL are equivalent."
- if not self.is_regex:
- if self.match_all:
- # The EXPECTED lines must match the ACTUAL lines, one-to-one, in
- # the same order.
- 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:
- 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
+ return expected == actual
+ i_expected = 0
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):
+ if expected[i_expected] == actual_line:
+ i_expected += 1
+ if i_expected == len(expected):
return True
-
- return all_lines_match_re
+ return False
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,
- self.is_regex, self.is_unordered)
+ """Show the differences between the expected and ACTUAL lines. Print
+ MESSAGE unless it is None, the expected lines, the ACTUAL lines,
+ and a diff, all labeled with LABEL.
+ """
+ display_lines(message, self.expected, actual, label, label)
+ display_lines_diff(self.expected, actual, label, label)
class AnyOutput(ExpectedOutput):
+ """Matches any non-empty output.
+ """
+
def __init__(self):
- ExpectedOutput.__init__(self, None, False)
+ ExpectedOutput.__init__(self, [], False)
+
+ def matches(self, actual):
+ assert actual is not None
- def is_equivalent_list(self, ignored, actual):
if len(actual) == 0:
# No actual output. No match.
return False
@@ -237,60 +180,162 @@ class AnyOutput(ExpectedOutput):
class RegexOutput(ExpectedOutput):
- is_regex = True
+ """Matches a single regular expression.
+ If MATCH_ALL is true, every actual line must match the RE. If
+ MATCH_ALL is false, at least one actual line must match the RE. In
+ any case, there must be at least one line of actual output.
+ """
-class UnorderedOutput(ExpectedOutput):
- """Marks unordered output, and performs comparisons."""
+ def __init__(self, expected, match_all=True):
+ "EXPECTED is a regular expression string."
+ assert isinstance(expected, str)
+ ExpectedOutput.__init__(self, expected, match_all)
+ self.expected_re = re.compile(expected)
- is_unordered = True
+ def matches(self, actual):
+ assert actual is not None
- def __cmp__(self, other):
- raise Exception('badness')
+ if not isinstance(actual, list):
+ actual = [actual]
+
+ # If a regex was provided assume that we require some actual output.
+ # Fail if we don't have any.
+ if len(actual) == 0:
+ return False
+
+ if self.match_all:
+ return all(self.expected_re.match(line) for line in actual)
+ else:
+ return any(self.expected_re.match(line) for line in actual)
+
+ def display_differences(self, message, label, actual):
+ display_lines(message, self.expected, actual, label + ' (regexp)', label)
+
+
+class RegexListOutput(ExpectedOutput):
+ """Matches an ordered list of regular expressions.
+
+ If MATCH_ALL is True, the expressions must match all the actual
+ lines, one-to-one, in the same order. If MATCH_ALL is False, the
+ expressions must match a subset of the actual lines, one-to-one, in
+ the same order, ignoring any other actual lines among the matching
+ ones.
- def matches_except(self, expected, actual, except_re):
- assert type(actual) == type([]) # ### if this trips: fix it!
- return self.is_equivalent_list([l for l in expected if not except_re.match(l)],
- [l for l in actual if not except_re.match(l)])
+ In any case, there must be at least one line of actual output.
+ """
- def is_equivalent_list(self, expected, actual):
- "Disregard the order of ACTUAL lines during comparison."
+ def __init__(self, expected, match_all=True):
+ "EXPECTED is a list of regular expression strings."
+ assert isinstance(expected, list) and expected != []
+ ExpectedOutput.__init__(self, expected, match_all)
+ self.expected_res = [re.compile(e) for e in expected]
- e_set = set(expected)
- a_set = set(actual)
+ def matches(self, actual):
+ assert actual is not None
+ if not isinstance(actual, list):
+ actual = [actual]
if self.match_all:
- if len(e_set) != len(a_set):
- return False
- 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
+ return (len(self.expected_res) == len(actual) and
+ all(e.match(a) for e, a in zip(self.expected_res, actual)))
+
+ i_expected = 0
+ for actual_line in actual:
+ if self.expected_res[i_expected].match(actual_line):
+ i_expected += 1
+ if i_expected == len(self.expected_res):
+ return True
+ return False
+
+ def display_differences(self, message, label, actual):
+ display_lines(message, self.expected, actual, label + ' (regexp)', label)
+
+
+class UnorderedOutput(ExpectedOutput):
+ """Matches an unordered list of lines.
+
+ The expected lines must match all the actual lines, one-to-one, in
+ any order.
+ """
+
+ def __init__(self, expected):
+ assert isinstance(expected, list)
+ ExpectedOutput.__init__(self, expected)
+
+ def matches(self, actual):
+ if not isinstance(actual, list):
+ actual = [actual]
+
+ return sorted(self.expected) == sorted(actual)
+
+ def display_differences(self, message, label, actual):
+ display_lines(message, self.expected, actual, label + ' (unordered)', label)
+ display_lines_diff(self.expected, actual, label + ' (unordered)', label)
+
- # All expected lines must be in the output.
- return e_set == a_set
+class UnorderedRegexListOutput(ExpectedOutput):
+ """Matches an unordered list of regular expressions.
+
+ The expressions must match all the actual lines, one-to-one, in any
+ order.
+
+ Note: This can give a false negative result (no match) when there is
+ an actual line that matches multiple expressions and a different
+ actual line that matches some but not all of those same
+ expressions. The implementation matches each expression in turn to
+ the first unmatched actual line that it can match, and does not try
+ all the permutations when there are multiple possible matches.
+ """
+
+ def __init__(self, expected):
+ assert isinstance(expected, list)
+ ExpectedOutput.__init__(self, expected)
+
+ def matches(self, actual):
+ assert actual is not None
+ if not isinstance(actual, list):
+ actual = [actual]
- 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
+ if len(self.expected) != len(actual):
return False
+ for e in self.expected:
+ expect_re = re.compile(e)
+ for actual_line in actual:
+ if expect_re.match(actual_line):
+ actual.remove(actual_line)
+ break
+ else:
+ # One of the regexes was not found
+ return False
+ return True
+
+ def display_differences(self, message, label, actual):
+ display_lines(message, self.expected, actual,
+ label + ' (regexp) (unordered)', label)
- # If any of the expected lines are in the output, then we match.
- return len(e_set.intersection(a_set)) > 0
+class AlternateOutput(ExpectedOutput):
+ """Matches any one of a list of ExpectedOutput instances.
+ """
+
+ def __init__(self, expected, match_all=True):
+ "EXPECTED is a list of ExpectedOutput instances."
+ assert isinstance(expected, list) and expected != []
+ assert all(isinstance(e, ExpectedOutput) for e in expected)
+ ExpectedOutput.__init__(self, expected)
+
+ def matches(self, actual):
+ assert actual is not None
+ for e in self.expected:
+ if e.matches(actual):
+ return True
+ return False
-class UnorderedRegexOutput(UnorderedOutput, RegexOutput):
- is_regex = True
- is_unordered = True
+ def display_differences(self, message, label, actual):
+ # For now, just display differences against the first alternative.
+ e = self.expected[0]
+ e.display_differences(message, label, actual)
######################################################################
@@ -308,55 +353,59 @@ def display_trees(message, label, expect
svntest.tree.dump_tree(actual)
-def display_lines(message, label, expected, actual, expected_is_regexp=None,
- expected_is_unordered=None):
+def display_lines_diff(expected, actual, expected_label, actual_label):
+ """Print a unified diff between EXPECTED (labeled with EXPECTED_LABEL)
+ and ACTUAL (labeled with ACTUAL_LABEL).
+ Each of EXPECTED and ACTUAL is a string or a list of strings.
+ """
+ if not isinstance(expected, list):
+ expected = [expected]
+ if not isinstance(actual, list):
+ actual = [actual]
+ logger.warn('DIFF ' + expected_label + ':')
+ for x in unified_diff(expected, actual,
+ fromfile='EXPECTED ' + expected_label,
+ tofile='ACTUAL ' + actual_label):
+ logger.warn('| ' + x.rstrip())
+
+def display_lines(message, expected, actual,
+ expected_label, actual_label=None):
"""Print MESSAGE, unless it is None, then print EXPECTED (labeled
- with LABEL) followed by ACTUAL (also labeled with LABEL).
- Both EXPECTED and ACTUAL may be strings or lists of strings."""
+ with EXPECTED_LABEL) followed by ACTUAL (labeled with ACTUAL_LABEL).
+ Each of EXPECTED and ACTUAL is a string or a list of strings.
+ """
if message is not None:
logger.warn(message)
+
+ if type(expected) is str:
+ expected = [expected]
+ if type(actual) is str:
+ actual = [actual]
+ if actual_label is None:
+ actual_label = expected_label
if expected is not None:
- output = 'EXPECTED %s' % label
- if expected_is_regexp:
- output += ' (regexp)'
- expected = [expected + '\n']
- if expected_is_unordered:
- output += ' (unordered)'
- output += ':'
- logger.warn(output)
+ logger.warn('EXPECTED %s:', expected_label)
for x in expected:
- sys.stdout.write(x)
+ logger.warn('| ' + x.rstrip())
if actual is not None:
- logger.warn('ACTUAL %s:', label)
+ logger.warn('ACTUAL %s:', actual_label)
for x in actual:
- sys.stdout.write(x)
-
- # Additionally print unified diff
- if not expected_is_regexp:
- logger.warn('DIFF ' + ' '.join(output.split(' ')[1:]))
-
- if type(expected) is str:
- expected = [expected]
-
- if type(actual) is str:
- actual = [actual]
-
- for x in unified_diff(expected, actual,
- fromfile="EXPECTED %s" % label,
- tofile="ACTUAL %s" % label):
- sys.stdout.write(x)
+ logger.warn('| ' + x.rstrip())
def compare_and_display_lines(message, label, expected, actual,
- raisable=None, except_re=None):
+ raisable=None):
"""Compare two sets of output lines, and print them if they differ,
preceded by MESSAGE iff not None. EXPECTED may be an instance of
- ExpectedOutput (and if not, it is wrapped as such). RAISABLE is an
+ ExpectedOutput (and if not, it is wrapped as such). ACTUAL may be a
+ list of newline-terminated lines, or a single string. RAISABLE is an
exception class, an instance of which is thrown if ACTUAL doesn't
match EXPECTED."""
if raisable is None:
raisable = svntest.main.SVNLineUnequal
### It'd be nicer to use createExpectedOutput() here, but its
### semantics don't match all current consumers of this function.
+ assert expected is not None
+ assert actual is not None
if not isinstance(expected, ExpectedOutput):
expected = ExpectedOutput(expected)
@@ -364,7 +413,7 @@ def compare_and_display_lines(message, l
actual = [actual]
actual = svntest.main.filter_dbg(actual)
- if not expected.matches(actual, except_re):
+ if not expected.matches(actual):
expected.display_differences(message, label, actual)
raise raisable
@@ -402,8 +451,7 @@ def verify_exit_code(message, actual, ex
not None) and raise an exception."""
if expected != actual:
- display_lines(message, "Exit Code",
- str(expected) + '\n', str(actual) + '\n')
+ display_lines(message, str(expected), str(actual), "Exit Code")
raise raisable
# A simple dump file parser. While sufficient for the current
Modified: subversion/branches/ev2-export/subversion/tests/cmdline/svntest/wc.py
URL: http://svn.apache.org/viewvc/subversion/branches/ev2-export/subversion/tests/cmdline/svntest/wc.py?rev=1449262&r1=1449261&r2=1449262&view=diff
==============================================================================
--- subversion/branches/ev2-export/subversion/tests/cmdline/svntest/wc.py (original)
+++ subversion/branches/ev2-export/subversion/tests/cmdline/svntest/wc.py Sat Feb 23 01:25:38 2013
@@ -261,11 +261,22 @@ class State:
base = to_relpath(os.path.normpath(self.wc_dir))
- # TODO: We should probably normalize the paths in moved_from and moved_to.
-
desc = dict([(repos_join(base, path), item)
for path, item in self.desc.items()])
+ for path, item in desc.copy().items():
+ if item.moved_from or item.moved_to:
+ i = item.copy()
+
+ if i.moved_from:
+ i.moved_from = to_relpath(os.path.normpath(
+ repos_join(base, i.moved_from)))
+ if i.moved_to:
+ i.moved_to = to_relpath(os.path.normpath(
+ repos_join(base, i.moved_to)))
+
+ desc[path] = i
+
return State('', desc)
def compare(self, other):
@@ -337,7 +348,8 @@ class State:
if item.status:
# If this is an unversioned tree-conflict, remove it.
# These are only in their parents' THIS_DIR, they don't have entries.
- if item.status[0] in '!?' and item.treeconflict == 'C':
+ if item.status[0] in '!?' and item.treeconflict == 'C' and \
+ item.entry_status is None:
del self.desc[path]
# Normal externals are not stored in the parent wc, drop the root
# and everything in these working copies
@@ -422,7 +434,7 @@ class State:
return not self.__eq__(other)
@classmethod
- def from_status(cls, lines, wc_dir_name=None):
+ def from_status(cls, lines):
"""Create a State object from 'svn status' output."""
def not_space(value):
@@ -444,21 +456,12 @@ class State:
if ex_match:
if ex_match.group('moved_from'):
path = ex_match.group('moved_from')
- if wc_dir_name and path.startswith(wc_dir_name + os.path.sep):
- path = path[len(wc_dir_name) + 1:]
-
last.tweak(moved_from = to_relpath(path))
elif ex_match.group('moved_to'):
path = ex_match.group('moved_to')
- if wc_dir_name and path.startswith(wc_dir_name + os.path.sep):
- path = path[len(wc_dir_name) + 1:]
-
last.tweak(moved_to = to_relpath(path))
elif ex_match.group('swapped_with'):
path = ex_match.group('swapped_with')
- if wc_dir_name and path.startswith(wc_dir_name + os.path.sep):
- path = path[len(wc_dir_name) + 1:]
-
last.tweak(moved_to = to_relpath(path))
last.tweak(moved_from = to_relpath(path))
@@ -471,6 +474,8 @@ class State:
prev_treeconflict = None
path = to_relpath(match.group('path'))
+ if path == '.':
+ path = ''
if path in desc:
prev_status = desc[path].status
prev_treeconflict = desc[path].treeconflict
@@ -663,21 +668,14 @@ class State:
desc = { }
dot_svn = svntest.main.get_admin_name()
- for dirpath in svntest.main.run_entriesdump_subdirs(base):
-
- if base == '.' and dirpath != '.':
- dirpath = '.' + os.path.sep + dirpath
+ dump_data = svntest.main.run_entriesdump_tree(base)
- entries = svntest.main.run_entriesdump(dirpath)
- if entries is None:
- continue
+ if not dump_data:
+ # Probably 'svn status' run on an actual only node
+ # ### Improve!
+ return cls('', desc)
- if dirpath == '.':
- parent = ''
- elif dirpath.startswith('.' + os.sep):
- parent = to_relpath(dirpath[2:])
- else:
- parent = to_relpath(dirpath)
+ for parent, entries in sorted(dump_data.items()):
parent_url = entries[''].url
@@ -796,15 +794,14 @@ class StateItem:
if not isinstance(other, StateItem):
return False
v_self = dict([(k, v) for k, v in vars(self).items()
- if not k.startswith('_')])
+ if not k.startswith('_') and not k.startswith('entry_')])
v_other = dict([(k, v) for k, v in vars(other).items()
- if not k.startswith('_')])
- if self.treeconflict is None:
- v_other = v_other.copy()
- v_other['treeconflict'] = None
- if other.treeconflict is None:
- v_self = v_self.copy()
- v_self['treeconflict'] = None
+ if not k.startswith('_') and not k.startswith('entry_')])
+
+ if self.wc_rev == '0' and self.status == 'A ':
+ v_self['wc_rev'] = '-'
+ if other.wc_rev == '0' and other.status == 'A ':
+ v_other['wc_rev'] = '-'
return v_self == v_other
def __ne__(self, other):