#!/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 shelf3_enabled(): v = os.getenv('SVN_EXPERIMENTAL_COMMANDS') return v is not None and v.find('shelf3') >= 0 #---------------------------------------------------------------------- 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') # Diff; ensure something comes out and it doesn't crash svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], 'x-shelf-diff', 'foo') svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], 'x-shelf-diff', '--summarize', 'foo') # 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. @SkipUnless(shelf3_enabled) def shelve_text_mods(sbox): "shelve text mods" def modifier(sbox): sbox.simple_append('A/mu', 'appended mu text') shelve_unshelve(sbox, modifier) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) @SkipUnless(shelf3_enabled) def shelve_deletes(sbox): "shelve deletes" def modifier(sbox): sbox.simple_rm('A/mu') shelve_unshelve(sbox, modifier) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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]) @SkipUnless(shelf3_enabled) 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() @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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() @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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() @SkipUnless(shelf3_enabled) 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() @SkipUnless(shelf3_enabled) 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() @SkipUnless(shelf3_enabled) 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() @SkipUnless(shelf3_enabled) 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) #---------------------------------------------------------------------- @SkipUnless(shelf3_enabled) 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() @SkipUnless(shelf3_enabled) 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. @SkipUnless(shelf3_enabled) 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_rm('A/B/lambda') sbox.simple_add_text('This is a new file.\n', 'A/B/new') 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/B/lambda', 'revision 2', 'nonexistent') + [ "@@ -1 +0,0 @@\n", "-This is the file 'lambda'.\n" ] expected_output += make_diff_header('A/B/new', 'nonexistent', 'working copy') + [ "@@ -0,0 +1 @@\n", "+This is a new file.\n" ] 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/B/lambda': Item(status='D '), 'A/B/new': Item(status='A '), 'A/mu': Item(status='MM'), }) run_and_verify_shelf_diff_summarize(expected_diff, 'foo') #---------------------------------------------------------------------- @XFail() @Issue(4827) @SkipUnless(shelf3_enabled) 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.