diff options
Diffstat (limited to 'subversion/tests/cmdline/shelf_tests.py')
-rwxr-xr-x | subversion/tests/cmdline/shelf_tests.py | 1012 |
1 files changed, 1012 insertions, 0 deletions
diff --git a/subversion/tests/cmdline/shelf_tests.py b/subversion/tests/cmdline/shelf_tests.py new file mode 100755 index 0000000..fe6108a --- /dev/null +++ b/subversion/tests/cmdline/shelf_tests.py @@ -0,0 +1,1012 @@ +#!/usr/bin/env python +# +# shelf_tests.py: testing shelving +# +# 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, stat, re, os, logging + +logger = logging.getLogger() + +# Our testing module +import svntest +from svntest import wc +from svntest.verify import make_diff_header, make_no_diff_deleted_header, \ + make_git_diff_header, make_diff_prop_header, \ + make_diff_prop_val, make_diff_prop_deleted, \ + make_diff_prop_added, make_diff_prop_modified + +# (abbreviation) +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 +Item = wc.StateItem + +#---------------------------------------------------------------------- + +def state_from_status(wc_dir, + v=True, u=True, q=True): + opts = () + if v: + opts += ('-v',) + if u: + opts += ('-u',) + if q: + opts += ('-q',) + _, output, _ = svntest.main.run_svn(None, 'status', wc_dir, *opts) + return svntest.wc.State.from_status(output, wc_dir) + +def get_wc_state(wc_dir): + """Return a description of the WC state. Include as much info as shelving + should be capable of restoring. + """ + return (state_from_status(wc_dir), + svntest.wc.State.from_wc(wc_dir, load_props=True), + ) + +def check_wc_state(wc_dir, expected): + """Check a description of the WC state. Include as much info as shelving + should be capable of restoring. + """ + expect_st, expect_wc = expected + actual_st, actual_wc = get_wc_state(wc_dir) + + # Verify actual status against expected status. + try: + expect_st.compare_and_display('status', actual_st) + except svntest.tree.SVNTreeError: + svntest.actions._log_tree_state("EXPECT STATUS TREE:", expect_st.old_tree(), + wc_dir) + svntest.actions._log_tree_state("ACTUAL STATUS TREE:", actual_st.old_tree(), + wc_dir) + raise + + # Verify actual WC against expected WC. + try: + expect_wc.compare_and_display('status', actual_wc) + except svntest.tree.SVNTreeError: + svntest.actions._log_tree_state("EXPECT WC TREE:", expect_wc.old_tree(), + wc_dir) + svntest.actions._log_tree_state("ACTUAL WC TREE:", actual_wc.old_tree(), + wc_dir) + raise + +def shelve_unshelve_verify(sbox, modifier, cannot_shelve=False): + """Round-trip: shelve; verify all changes are reverted; + unshelve; verify all changes are restored. + """ + + wc_dir = sbox.wc_dir + virginal_state = get_wc_state(wc_dir) + + # Make some changes to the working copy + modifier(sbox) + + # Save the modified state + modified_state = get_wc_state(wc_dir) + + if cannot_shelve: + svntest.actions.run_and_verify_svn(None, '.* could not be shelved.*', + 'x-shelve', 'foo') + return + + # Shelve; check there are no longer any modifications + svntest.actions.run_and_verify_svn(None, [], + 'x-shelve', 'foo') + check_wc_state(wc_dir, virginal_state) + + # List; ensure the shelf is listed + expected_output = svntest.verify.RegexListOutput( + [r'foo\s*version \d+.*', + r' ', + ]) + svntest.actions.run_and_verify_svn(expected_output, [], 'x-shelves') + + # Unshelve; check the original modifications are here again + svntest.actions.run_and_verify_svn(None, [], + 'x-unshelve', 'foo') + check_wc_state(wc_dir, modified_state) + +#---------------------------------------------------------------------- + +def shelve_unshelve(sbox, modifier, cannot_shelve=False): + """Round-trip: build 'sbox'; apply changes by calling 'modifier(sbox)'; + shelve and unshelve; verify changes are fully reverted and restored. + """ + + if not sbox.is_built(): + sbox.build() + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '' + + shelve_unshelve_verify(sbox, modifier, cannot_shelve) + + os.chdir(was_cwd) + +###################################################################### +# Tests +# +# Each test must return on success or raise on failure. + +def shelve_text_mods(sbox): + "shelve text mods" + + def modifier(sbox): + sbox.simple_append('A/mu', 'appended mu text') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_prop_changes(sbox): + "shelve prop changes" + + def modifier(sbox): + sbox.simple_propset('p', 'v', 'A') + sbox.simple_propset('p', 'v', 'A/mu') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_adds(sbox): + "shelve adds" + + def modifier(sbox): + sbox.simple_add_text('A new file\n', 'A/new') + sbox.simple_add_text('A new file\n', 'A/new2') + sbox.simple_propset('p', 'v', 'A/new2') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +@Issue(4709) +def shelve_deletes(sbox): + "shelve deletes" + + def modifier(sbox): + sbox.simple_rm('A/mu') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_replace(sbox): + "shelve replace" + + def modifier(sbox): + sbox.simple_rm('A/mu') + sbox.simple_add_text('Replacement\n', 'A/mu') + sbox.simple_propset('p', 'v', 'A/mu') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_empty_adds(sbox): + "shelve empty adds" + sbox.build(empty=True) + + def modifier(sbox): + sbox.simple_add_text('', 'empty') + sbox.simple_add_text('', 'empty-with-prop') + sbox.simple_propset('p', 'v', 'empty-with-prop') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_empty_deletes(sbox): + "shelve empty deletes" + sbox.build(empty=True) + sbox.simple_add_text('', 'empty') + sbox.simple_add_text('', 'empty-with-prop') + sbox.simple_propset('p', 'v', 'empty-with-prop') + sbox.simple_commit() + + def modifier(sbox): + sbox.simple_rm('empty', 'empty-with-prop') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_from_inner_path(sbox): + "shelve from inner path" + + def modifier(sbox): + sbox.simple_append('A/mu', 'appended mu text') + + sbox.build() + was_cwd = os.getcwd() + os.chdir(sbox.ospath('A')) + sbox.wc_dir = '..' + + shelve_unshelve_verify(sbox, modifier) + + os.chdir(was_cwd) + +#---------------------------------------------------------------------- + +def save_revert_restore(sbox, modifier1, modifier2): + "Save 2 checkpoints; revert; restore 1st" + + sbox.build() + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '' + wc_dir = '' + + initial_state = get_wc_state(wc_dir) + + # Make some changes to the working copy + modifier1(sbox) + + # Remember the modified state + modified_state1 = get_wc_state(wc_dir) + + # Save a checkpoint; check nothing changed + svntest.actions.run_and_verify_svn(None, [], + 'x-shelf-save', 'foo') + check_wc_state(wc_dir, modified_state1) + + # Modify again; remember the state; save a checkpoint + modifier2(sbox) + modified_state2 = get_wc_state(wc_dir) + svntest.actions.run_and_verify_svn(None, [], + 'x-shelf-save', 'foo') + check_wc_state(wc_dir, modified_state2) + + # Revert + svntest.actions.run_and_verify_svn(None, [], + 'revert', '-R', '.') + check_wc_state(wc_dir, initial_state) + + # Restore; check the original modifications are here again + svntest.actions.run_and_verify_svn(None, [], + 'x-unshelve', 'foo', '1') + check_wc_state(wc_dir, modified_state1) + + os.chdir(was_cwd) + +#---------------------------------------------------------------------- + +def checkpoint_basic(sbox): + "checkpoint basic" + + def modifier1(sbox): + sbox.simple_append('A/mu', 'appended mu text\n') + + def modifier2(sbox): + sbox.simple_append('iota', 'appended iota text\n') + sbox.simple_append('A/mu', 'appended another line\n') + + save_revert_restore(sbox, modifier1, modifier2) + +#---------------------------------------------------------------------- + +@Issue(3747) +def shelve_mergeinfo(sbox): + "shelve mergeinfo" + + def modifier(sbox): + sbox.simple_propset('svn:mergeinfo', '/trunk/A:1-3,10', 'A') + sbox.simple_propset('svn:mergeinfo', '/trunk/A/mu:1-3,10', 'A/mu') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def unshelve_refuses_if_conflicts(sbox): + "unshelve refuses if conflicts" + + def modifier1(sbox): + sbox.simple_append('alpha', 'A-mod1\nB\nC\nD\n', truncate=True) + sbox.simple_append('beta', 'A-mod1\nB\nC\nD\n', truncate=True) + + def modifier2(sbox): + sbox.simple_append('beta', 'A-mod2\nB\nC\nD\n', truncate=True) + + sbox.build(empty=True) + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '' + wc_dir = '' + + sbox.simple_add_text('A\nB\nC\nD\n', 'alpha') + sbox.simple_add_text('A\nB\nC\nD\n', 'beta') + sbox.simple_commit() + initial_state = get_wc_state(wc_dir) + + # Make initial mods; remember this modified state + modifier1(sbox) + modified_state1 = get_wc_state(wc_dir) + assert modified_state1 != initial_state + + # Shelve; check there are no longer any local mods + svntest.actions.run_and_verify_svn(None, [], + 'x-shelve', 'foo') + check_wc_state(wc_dir, initial_state) + + # Make a different local mod that will conflict with the shelf + modifier2(sbox) + modified_state2 = get_wc_state(wc_dir) + + # Try to unshelve; check it fails with an error about a conflict + svntest.actions.run_and_verify_svn(None, '.*[Cc]onflict.*', + 'x-unshelve', 'foo') + # Check nothing changed in the attempt + check_wc_state(wc_dir, modified_state2) + +#---------------------------------------------------------------------- + +def shelve_binary_file_mod(sbox): + "shelve binary file mod" + + sbox.build(empty=True) + + existing_files = ['A/B/existing'] + mod_files = ['bin', 'A/B/bin'] + + sbox.simple_mkdir('A', 'A/B') + for f in existing_files + mod_files: + sbox.simple_add_text('\0\1\2\3\4\5', f) + sbox.simple_commit() + + def modifier(sbox): + for f in mod_files: + sbox.simple_append(f, '\6\5\4\3\2\1\0', truncate=True) + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_binary_file_add(sbox): + "shelve binary file add" + + sbox.build(empty=True) + + existing_files = ['A/B/existing'] + mod_files = ['bin', 'A/B/bin'] + + sbox.simple_mkdir('A', 'A/B') + for f in existing_files: + sbox.simple_add_text('\0\1\2\3\4\5', f) + sbox.simple_commit() + + def modifier(sbox): + for f in mod_files: + sbox.simple_add_text('\0\1\2\3\4\5', f) + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_binary_file_del(sbox): + "shelve binary file del" + + sbox.build(empty=True) + + existing_files = ['A/B/existing'] + mod_files = ['bin', 'A/B/bin'] + + sbox.simple_mkdir('A', 'A/B') + for f in existing_files + mod_files: + sbox.simple_add_text('\0\1\2\3\4\5', f) + sbox.simple_commit() + + def modifier(sbox): + for f in mod_files: + sbox.simple_rm(f) + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_binary_file_replace(sbox): + "shelve binary file replace" + + sbox.build(empty=True) + + existing_files = ['A/B/existing'] + mod_files = ['bin', 'A/B/bin'] + + sbox.simple_mkdir('A', 'A/B') + for f in existing_files + mod_files: + sbox.simple_add_text('\0\1\2\3\4\5', f) + sbox.simple_commit() + + def modifier(sbox): + for f in mod_files: + sbox.simple_rm(f) + sbox.simple_add_text('\6\5\4\3\2\1\0', f) + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_with_log_message(sbox): + "shelve with log message" + + sbox.build(empty=True) + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '' + + sbox.simple_add_text('New file', 'f') + log_message = 'Log message for foo' + svntest.actions.run_and_verify_svn(None, [], + 'x-shelve', 'foo', '-m', log_message) + expected_output = svntest.verify.RegexListOutput( + ['foo .*', + ' ' + log_message + ]) + svntest.actions.run_and_verify_svn(expected_output, [], + 'x-shelf-list') + + os.chdir(was_cwd) + +#---------------------------------------------------------------------- + +def run_and_verify_status(wc_dir_name, status_tree, changelists=[]): + """Run 'status' on WC_DIR_NAME and compare it with the + expected STATUS_TREE. + Returns on success, raises on failure.""" + + if not isinstance(status_tree, wc.State): + raise TypeError('wc.State tree expected') + + cl_opts = ('--cl=' + cl for cl in changelists) + exit_code, output, errput = svntest.main.run_svn(None, 'status', '-q', + wc_dir_name, *cl_opts) + + actual_status = svntest.wc.State.from_status(output, wc_dir=wc_dir_name) + + # Verify actual output against expected output. + try: + status_tree.compare_and_display('status', actual_status) + except svntest.tree.SVNTreeError: + svntest.actions._log_tree_state("ACTUAL STATUS TREE:", actual_status.old_tree(), + wc_dir_name) + raise + +def run_and_verify_shelf_status(wc_dir, expected_status, shelf): + run_and_verify_status(wc_dir, expected_status, + changelists=['svn:shelf:' + shelf]) + +def shelf_status(sbox): + "shelf status" + + sbox.build() + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '' + + sbox.simple_add_text('New file', 'f') + sbox.simple_append('iota', 'New text') + sbox.simple_propset('p', 'v', 'A/mu') + sbox.simple_rm('A/B/lambda') + # Not yet supported: + #sbox.simple_rm('A/B/E') + expected_status = state_from_status(sbox.wc_dir, v=False, u=False, q=False) + run_and_verify_status(sbox.wc_dir, expected_status) + + svntest.actions.run_and_verify_svn(None, [], + 'x-shelve', 'foo') + run_and_verify_shelf_status(sbox.wc_dir, expected_status, shelf='foo') + + os.chdir(was_cwd) + +#---------------------------------------------------------------------- + +@XFail() +def shelve_mkdir(sbox): + "shelve mkdir" + + sbox.build() + + def modifier(sbox): + sbox.simple_mkdir('D', 'D/D2') + sbox.simple_propset('p', 'v', 'D', 'D/D2') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_rmdir(sbox): + "shelve rmdir" + + sbox.build() + sbox.simple_propset('p', 'v', 'A/C') + sbox.simple_commit() + + def modifier(sbox): + sbox.simple_rm('A/C', 'A/D/G') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +@XFail() +def shelve_replace_dir(sbox): + "shelve replace dir" + + sbox.build() + sbox.simple_propset('p', 'v', 'A/C') + sbox.simple_commit() + + def modifier(sbox): + sbox.simple_rm('A/C', 'A/D/G') + sbox.simple_mkdir('A/C', 'A/C/D2') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_file_copy(sbox): + "shelve file copy" + + sbox.build() + + def modifier(sbox): + sbox.simple_copy('iota', 'A/ii') + sbox.simple_propset('p', 'v', 'A/ii') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def shelve_dir_copy(sbox): + "shelve dir copy" + + sbox.build() + + def modifier(sbox): + sbox.simple_copy('A/B', 'BB') + sbox.simple_propset('p', 'v', 'BB') + + shelve_unshelve(sbox, modifier) + +#---------------------------------------------------------------------- + +def list_shelves(sbox): + "list_shelves" + + sbox.build() + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '' + + # an empty list + svntest.actions.run_and_verify_svn([], [], + 'x-shelf-list', '-q') + + # make two shelves + sbox.simple_append('A/mu', 'appended mu text') + svntest.actions.run_and_verify_svn(None, [], + 'x-shelf-save', 'foo') + sbox.simple_append('A/mu', 'appended more text') + svntest.actions.run_and_verify_svn(None, [], + 'x-shelf-save', 'foo', '-m', 'log msg') + svntest.actions.run_and_verify_svn(None, [], + 'x-shelf-save', 'bar', '-m', 'log msg') + + # We don't check for time-ordering of the shelves. If we want to do so, we + # would need to sleep for timestamps to differ, between creating them. + + # a quiet list + expected_out = svntest.verify.UnorderedRegexListOutput(['foo', 'bar']) + svntest.actions.run_and_verify_svn(expected_out, [], + 'x-shelf-list', '-q') + + # a detailed list + expected_out = svntest.verify.UnorderedRegexListOutput(['foo .* 1 path.*', + ' log msg', + 'bar .* 1 path.*', + ' log msg']) + svntest.actions.run_and_verify_svn(expected_out, [], + 'x-shelf-list') + + os.chdir(was_cwd) + +#---------------------------------------------------------------------- + +def refuse_to_shelve_conflict(sbox): + "refuse to shelve conflict" + + sbox.build(empty=True) + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '' + + # create a conflict + sbox.simple_mkdir('topdir') + sbox.simple_commit() + sbox.simple_update() + svntest.actions.run_and_verify_svn( + None, [], + 'merge', '-c1', '.', '--ignore-ancestry', '--accept', 'postpone') + # check that we did create a conflict + svntest.actions.run_and_verify_svn( + None, 'svn: E155035:.*conflict.*', + 'merge', '-c1', '.', '--ignore-ancestry', '--accept', 'postpone') + + # attempt to shelve + expected_err = "svn: E155015: .* '.*topdir' remains in conflict" + svntest.actions.run_and_verify_svn(None, expected_err, + 'x-shelf-save', 'foo') + + os.chdir(was_cwd) + +#---------------------------------------------------------------------- + +def unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state): + """Run a test scenario in which 'unshelve' needs to merge some shelved + changes made by modifier1() with some committed changes made by + modifier2(). tweak_expected_state() must produce the expected WC state. + """ + sbox.build() + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '' + wc_dir = sbox.wc_dir + + setup(sbox) + sbox.simple_commit() + initial_state = get_wc_state(wc_dir) + + # Make some changes to the working copy + modifier1(sbox) + modified_state = get_wc_state(wc_dir) + + # Shelve; check there are no longer any modifications + svntest.actions.run_and_verify_svn(None, [], + 'x-shelve', 'foo') + check_wc_state(wc_dir, initial_state) + + # Make a different change, with which we shall merge + modifier2(sbox) + sbox.simple_commit() + modified_state[0].tweak('A/mu', wc_rev='3') + + # Unshelve; check the expected result of the merge + svntest.actions.run_and_verify_svn(None, [], + 'x-unshelve', 'foo') + tweak_expected_state(modified_state) + check_wc_state(wc_dir, modified_state) + + os.chdir(was_cwd) + +@XFail() +def unshelve_text_mod_merge(sbox): + "unshelve text mod merge" + + orig_contents='A\nB\nC\nD\nE\n' + mod1_contents='A\nBB\nC\nD\nE\n' + mod2_contents='A\nB\nC\nDD\nE\n' + merged_contents='A\nBB\nC\nDD\nE\n' + + def setup(sbox): + sbox.simple_append('A/mu', orig_contents, truncate=True) + + def modifier1(sbox): + sbox.simple_append('A/mu', mod1_contents, truncate=True) + + def modifier2(sbox): + sbox.simple_append('A/mu', mod2_contents, truncate=True) + + def tweak_expected_state(modified_state): + modified_state[1].tweak('A/mu', contents=merged_contents) + + unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) + +#---------------------------------------------------------------------- + +@XFail() +def unshelve_text_mod_conflict(sbox): + "unshelve text mod conflict" + + orig_contents='A\nB\nC\nD\nE\n' + mod1_contents='A\nBB\nC\nD\nE\n' + mod2_contents='A\nBCD\nC\nD\nE\n' + merged_contents = 'A\n<<<<<<< .working\nBCD\n||||||| .merge-left\nB\n=======\nBB\n>>>>>>> .merge-right\nC\nD\nE\n' + + def setup(sbox): + sbox.simple_append('A/mu', orig_contents, truncate=True) + + def modifier1(sbox): + sbox.simple_append('A/mu', mod1_contents, truncate=True) + + def modifier2(sbox): + sbox.simple_append('A/mu', mod2_contents, truncate=True) + + def tweak_expected_state(modified_state): + modified_state[0].tweak('A/mu', status='C ') + modified_state[1].tweak('A/mu', contents=merged_contents) + modified_state[1].add({ + 'A/mu.merge-left': Item(contents=orig_contents), + 'A/mu.merge-right': Item(contents=mod1_contents), + 'A/mu.working': Item(contents=mod2_contents), + }) + + unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) + +#---------------------------------------------------------------------- + +@XFail() +def unshelve_undeclared_binary_mod_conflict(sbox): + "unshelve undeclared binary mod conflict" + + orig_contents='\1\2\3\4\5' + mod1_contents='\1\2\2\3\4\5' + mod2_contents='\1\2\3\4\3\4\5' + merged_contents = '<<<<<<< .working\n' + mod2_contents + '||||||| .merge-left\n' + orig_contents + '=======\n' + mod1_contents + '>>>>>>> .merge-right\n' + + def setup(sbox): + sbox.simple_append('A/mu', orig_contents, truncate=True) + + def modifier1(sbox): + sbox.simple_append('A/mu', mod1_contents, truncate=True) + + def modifier2(sbox): + sbox.simple_append('A/mu', mod2_contents, truncate=True) + + def tweak_expected_state(modified_state): + modified_state[0].tweak('A/mu', status='C ') + modified_state[1].tweak('A/mu', contents=merged_contents) + modified_state[1].add({ + 'A/mu.merge-left': Item(contents=orig_contents), + 'A/mu.merge-right': Item(contents=mod1_contents), + 'A/mu.working': Item(contents=mod2_contents), + }) + + unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) + +#---------------------------------------------------------------------- + +@XFail() +def unshelve_binary_mod_conflict(sbox): + "unshelve binary mod conflict" + + orig_contents='\1\2\3\4\5' + mod1_contents='\1\2\2\3\4\5' + mod2_contents='\1\2\3\4\3\4\5' + + def setup(sbox): + sbox.simple_append('A/mu', orig_contents, truncate=True) + sbox.simple_propset('svn:mime-type', 'application/octet-stream', 'A/mu') + + def modifier1(sbox): + sbox.simple_append('A/mu', mod1_contents, truncate=True) + + def modifier2(sbox): + sbox.simple_append('A/mu', mod2_contents, truncate=True) + + def tweak_expected_state(modified_state): + modified_state[0].tweak('A/mu', status='C ') + modified_state[1].tweak('A/mu', contents=mod2_contents) + modified_state[1].add({ + 'A/mu.merge-left': Item(contents=orig_contents), + 'A/mu.merge-right': Item(contents=mod1_contents), + }) + + unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) + +#---------------------------------------------------------------------- + +def unshelve_text_prop_merge(sbox): + "unshelve text prop merge" + + def setup(sbox): + sbox.simple_propset('p1', 'v', 'A/mu') + sbox.simple_propset('p2', 'v', 'A/mu') + + def modifier1(sbox): + sbox.simple_propset('p1', 'changed', 'A/mu') + + def modifier2(sbox): + sbox.simple_propset('p2', 'changed', 'A/mu') + + def tweak_expected_state(wc_state): + wc_state[1].tweak('A/mu', props={'p1':'changed', + 'p2':'changed'}) + + unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) + +#---------------------------------------------------------------------- + +@XFail() +def unshelve_text_prop_conflict(sbox): + "unshelve text prop conflict" + + orig_contents='A' + mod1_contents='B' + mod2_contents='C' + merged_contents='C' + prej_contents='''Trying to change property 'p' +but the local property value conflicts with the incoming change. +<<<<<<< (local property value) +C||||||| (incoming 'changed from' value) +A======= +B>>>>>>> (incoming 'changed to' value) +''' + + def setup(sbox): + sbox.simple_propset('p', orig_contents, 'A/mu') + + def modifier1(sbox): + sbox.simple_propset('p', mod1_contents, 'A/mu') + + def modifier2(sbox): + sbox.simple_propset('p', mod2_contents, 'A/mu') + + def tweak_expected_state(wc_state): + wc_state[0].tweak('A/mu', status=' C') + wc_state[1].tweak('A/mu', props={'p':merged_contents}) + wc_state[1].add({ + 'A/mu.prej': Item(contents=prej_contents), + }) + + unshelve_with_merge(sbox, setup, modifier1, modifier2, tweak_expected_state) + +#---------------------------------------------------------------------- + +def run_and_verify_shelf_diff_summarize(output_tree, shelf, *args): + """Run 'svn shelf-diff --summarize' with the arguments *ARGS. + + The subcommand output will be verified against OUTPUT_TREE. Returns + on success, raises on failure. + """ + + if isinstance(output_tree, wc.State): + output_tree = output_tree.old_tree() + + exit_code, output, errput = svntest.actions.run_and_verify_svn( + None, [], + 'x-shelf-diff', '--summarize', shelf, *args) + + actual = svntest.tree.build_tree_from_diff_summarize(output) + + # Verify actual output against expected output. + try: + svntest.tree.compare_trees("output", actual, output_tree) + except svntest.tree.SVNTreeError: + svntest.verify.display_trees(None, 'DIFF OUTPUT TREE', output_tree, actual) + raise + +#---------------------------------------------------------------------- + +# Exercise a very basic case of shelf-diff. +def shelf_diff_simple(sbox): + "shelf diff simple" + + sbox.build() + was_cwd = os.getcwd() + os.chdir(sbox.wc_dir) + sbox.wc_dir = '' + wc_dir = sbox.wc_dir + + def setup(sbox): + sbox.simple_propset('p1', 'v', 'A/mu') + sbox.simple_propset('p2', 'v', 'A/mu') + + def modifier1(sbox): + sbox.simple_append('A/mu', 'New line.\n') + sbox.simple_propset('p1', 'changed', 'A/mu') + + setup(sbox) + sbox.simple_commit() + initial_state = get_wc_state(wc_dir) + + # Make some changes to the working copy + modifier1(sbox) + modified_state = get_wc_state(wc_dir) + + svntest.actions.run_and_verify_svn(None, [], + 'x-shelf-save', 'foo') + + # basic svn-style diff + expected_output = make_diff_header('A/mu', 'revision 2', 'working copy') + [ + "@@ -1 +1,2 @@\n", + " This is the file 'mu'.\n", + "+New line.\n", + ] + make_diff_prop_header('A/mu') \ + + make_diff_prop_modified('p1', 'v', 'changed') + svntest.actions.run_and_verify_svn(expected_output, [], + 'x-shelf-diff', 'foo') + + # basic summary diff + expected_diff = svntest.wc.State(wc_dir, { + 'A/mu': Item(status='MM'), + }) + run_and_verify_shelf_diff_summarize(expected_diff, 'foo') + +#---------------------------------------------------------------------- + +@XFail() +@Issue(4827) +def shelve_with_kw_translation(sbox): + "shelve with kw translation" + sbox.build(empty=True) + sbox.simple_add_text('$Rev$\n', 'file') + sbox.simple_propset('svn:keywords', 'rev', 'file') + sbox.simple_commit() + sbox.simple_update() + + def modifier(sbox): + sbox.simple_append('file', 'New line\n') + + shelve_unshelve(sbox, modifier) + + +######################################################################## +# Run the tests + +# list all tests here, starting with None: +test_list = [ None, + shelve_text_mods, + shelve_prop_changes, + shelve_adds, + shelve_deletes, + shelve_replace, + shelve_empty_adds, + shelve_empty_deletes, + shelve_from_inner_path, + checkpoint_basic, + shelve_mergeinfo, + unshelve_refuses_if_conflicts, + shelve_binary_file_mod, + shelve_binary_file_add, + shelve_binary_file_del, + shelve_binary_file_replace, + shelve_with_log_message, + shelf_status, + shelve_mkdir, + shelve_rmdir, + shelve_replace_dir, + shelve_file_copy, + shelve_dir_copy, + list_shelves, + refuse_to_shelve_conflict, + unshelve_text_mod_merge, + unshelve_text_mod_conflict, + unshelve_undeclared_binary_mod_conflict, + unshelve_binary_mod_conflict, + unshelve_text_prop_merge, + unshelve_text_prop_conflict, + shelf_diff_simple, + shelve_with_kw_translation, + ] + +if __name__ == '__main__': + svntest.main.run_tests(test_list) + # NOTREACHED + + +### End of file. |