Modified: subversion/branches/swig-py3/subversion/tests/cmdline/revert_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/revert_tests.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/revert_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/revert_tests.py Mon Jul 8 15:19:03 2019 @@ -46,6 +46,23 @@ Item = svntest.wc.StateItem ###################################################################### # Helpers +def expected_output_revert(reverted_paths, skipped_paths=[]): + return svntest.verify.UnorderedRegexListOutput( + ["Reverted '%s'\n" % re.escape(path) for path in reverted_paths] + + ["Skipped '%s'.*\n" % re.escape(path) for path in skipped_paths]) + +def run_and_verify_revert(targets, options=[], + reverted_paths=None, skipped_paths=[]): + """Run 'svn revert OPTIONS TARGETS'. Verify that the printed output matches + REVERTED_PATHS and SKIPPED_PATHS. If REVERTED_PATHS is None, it defaults + to TARGETS. + """ + if reverted_paths is None: + reverted_paths = targets + expected_output = expected_output_revert(reverted_paths, skipped_paths) + svntest.actions.run_and_verify_svn(expected_output, [], + *(['revert'] + options + targets)) + def revert_replacement_with_props(sbox, wc_copy): """Helper implementing the core of revert_{repos,wc}_to_wc_replace_with_props(). @@ -129,9 +146,7 @@ def revert_replacement_with_props(sbox, svntest.actions.run_and_verify_status(wc_dir, expected_status) expected_status.tweak('A/D/G/rho', status=' ', copied=None, wc_rev='2') - expected_output = ["Reverted '" + rho_path + "'\n"] - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', '-R', wc_dir) + run_and_verify_revert([wc_dir], ['-R'], [rho_path]) svntest.actions.run_and_verify_status(wc_dir, expected_status) # Check disk status @@ -356,8 +371,7 @@ def revert_replaced_file_without_props(s svntest.actions.run_and_verify_status(wc_dir, expected_status) # revert file1 - svntest.actions.run_and_verify_svn(["Reverted '" + file1_path + "'\n"], - [], 'revert', file1_path) + run_and_verify_revert([file1_path]) # test that file1 really was reverted expected_status.tweak('file1', status=' ', wc_rev=2) @@ -402,10 +416,7 @@ def revert_moved_file(sbox): actions.run_and_verify_unquiet_status(wc_dir, expected_status) # svn revert iota - expected_stdout = ["Reverted '" + iota + "'\n"] - - actions.run_and_verify_svn2(expected_stdout, [], 0, 'revert', - iota) + run_and_verify_revert([iota]) # svn st expected_status.tweak('iota', status=' ', moved_to=None) @@ -644,9 +655,7 @@ def revert_propset__dir(sbox): wc_dir = sbox.wc_dir a_path = os.path.join(wc_dir, 'A') svntest.main.run_svn(None, 'propset', 'foo', 'x', a_path) - expected_output = re.escape("Reverted '" + a_path + "'") - svntest.actions.run_and_verify_svn(expected_output, [], "revert", - a_path) + run_and_verify_revert([a_path]) def revert_propset__file(sbox): "revert a simple propset on a file" @@ -655,9 +664,7 @@ def revert_propset__file(sbox): wc_dir = sbox.wc_dir iota_path = os.path.join(wc_dir, 'iota') svntest.main.run_svn(None, 'propset', 'foo', 'x', iota_path) - expected_output = re.escape("Reverted '" + iota_path + "'") - svntest.actions.run_and_verify_svn(expected_output, [], "revert", - iota_path) + run_and_verify_revert([iota_path]) def revert_propdel__dir(sbox): "revert a simple propdel on a dir" @@ -669,9 +676,7 @@ def revert_propdel__dir(sbox): svntest.main.run_svn(None, 'commit', '-m', 'ps', a_path) svntest.main.run_svn(None, 'propdel', 'foo', a_path) - expected_output = re.escape("Reverted '" + a_path + "'") - svntest.actions.run_and_verify_svn(expected_output, [], "revert", - a_path) + run_and_verify_revert([a_path]) def revert_propdel__file(sbox): "revert a simple propdel on a file" @@ -683,9 +688,7 @@ def revert_propdel__file(sbox): svntest.main.run_svn(None, 'commit', '-m', 'ps', iota_path) svntest.main.run_svn(None, 'propdel', 'foo', iota_path) - expected_output = re.escape("Reverted '" + iota_path + "'") - svntest.actions.run_and_verify_svn(expected_output, [], "revert", - iota_path) + run_and_verify_revert([iota_path]) def revert_replaced_with_history_file_1(sbox): "revert a committed replace-with-history == no-op" @@ -776,9 +779,7 @@ def status_of_missing_dir_after_revert(s A_D_G_path = os.path.join(wc_dir, "A", "D", "G") svntest.actions.run_and_verify_svn(None, [], "rm", A_D_G_path) - expected_output = re.escape("Reverted '" + A_D_G_path + "'") - svntest.actions.run_and_verify_svn(expected_output, [], "revert", - A_D_G_path) + run_and_verify_revert([A_D_G_path]) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/D/G/rho', 'A/D/G/pi', 'A/D/G/tau', @@ -877,11 +878,7 @@ def status_of_missing_dir_after_revert_r revert_paths = [G_path] + [os.path.join(G_path, child) for child in ['alpha', 'beta', 'pi', 'rho', 'tau']] - expected_output = svntest.verify.UnorderedOutput([ - "Reverted '%s'\n" % path for path in revert_paths]) - - svntest.actions.run_and_verify_svn(expected_output, [], "revert", "-R", - G_path) + run_and_verify_revert([G_path], ["-R"], revert_paths) svntest.actions.run_and_verify_svn([], [], "status", wc_dir) @@ -947,12 +944,6 @@ def revert_tree_conflicts_in_updated_fil G2_tau = os.path.join(G2, 'tau') # Expectations - expected_output = svntest.verify.UnorderedOutput( - ["Reverted '%s'\n" % G_pi, - "Reverted '%s'\n" % G_rho, - "Reverted '%s'\n" % G_tau, - ]) - expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.tweak('A/D/G/pi', status=' ') expected_status.remove('A/D/G/rho') @@ -965,23 +956,15 @@ def revert_tree_conflicts_in_updated_fil expected_disk.remove('A/D/G/tau') # Revert individually in wc - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', G_pi, G_rho, G_tau) + run_and_verify_revert([G_pi, G_rho, G_tau]) svntest.actions.run_and_verify_status(wc_dir, expected_status) svntest.actions.verify_disk(wc_dir, expected_disk) # Expectations - expected_output = svntest.verify.UnorderedOutput( - ["Reverted '%s'\n" % G2_pi, - "Reverted '%s'\n" % G2_rho, - "Reverted '%s'\n" % G2_tau, - ]) - expected_status.wc_dir = wc_dir_2 # Revert recursively in wc 2 - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', '-R', G2) + run_and_verify_revert([G2], ['-R'], [G2_pi, G2_rho, G2_tau]) svntest.actions.run_and_verify_status(wc_dir_2, expected_status) svntest.actions.verify_disk(wc_dir_2, expected_disk) @@ -1049,9 +1032,7 @@ def revert_child_of_copy(sbox): svntest.actions.run_and_verify_status(wc_dir, expected_status) # First revert removes text change, child is still copied - expected_output = ["Reverted '%s'\n" % sbox.ospath('A/B/E2/beta')] - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', sbox.ospath('A/B/E2/beta')) + run_and_verify_revert(sbox.ospaths(['A/B/E2/beta'])) expected_status.tweak('A/B/E2/beta', status=' ') svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1074,9 +1055,7 @@ def revert_non_recusive_after_delete(sbo svntest.actions.run_and_verify_status(wc_dir, expected_status) # This appears to work but gets the op-depth wrong - expected_output = ["Reverted '%s'\n" % sbox.ospath('A/B')] - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', sbox.ospath('A/B')) + run_and_verify_revert(sbox.ospaths(['A/B'])) expected_status.tweak('A/B', status=' ') svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1086,9 +1065,7 @@ def revert_non_recusive_after_delete(sbo svntest.actions.run_and_verify_status(wc_dir, expected_status) # Since the op-depth was wrong A/B/E erroneously remains deleted - expected_output = ["Reverted '%s'\n" % sbox.ospath('A/B/E')] - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', sbox.ospath('A/B/E')) + run_and_verify_revert(sbox.ospaths(['A/B/E'])) expected_status.tweak('A/B/E', status=' ') svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1134,17 +1111,13 @@ def revert_permissions_only(sbox): os.chmod(sbox.ospath('A/B/E/alpha'), svntest.main.S_ALL_READ) # read-only is_readonly(sbox.ospath('A/B/E/alpha')) - expected_output = ["Reverted '%s'\n" % sbox.ospath('A/B/E/alpha')] - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', sbox.ospath('A/B/E/alpha')) + run_and_verify_revert(sbox.ospaths(['A/B/E/alpha'])) is_writable(sbox.ospath('A/B/E/alpha')) if svntest.main.is_posix_os(): os.chmod(sbox.ospath('A/B/E/beta'), svntest.main.S_ALL_RWX) # executable is_executable(sbox.ospath('A/B/E/beta')) - expected_output = ["Reverted '%s'\n" % sbox.ospath('A/B/E/beta')] - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', sbox.ospath('A/B/E/beta')) + run_and_verify_revert(sbox.ospaths(['A/B/E/beta'])) is_non_executable(sbox.ospath('A/B/E/beta')) svntest.actions.run_and_verify_svn(None, [], @@ -1167,17 +1140,13 @@ def revert_permissions_only(sbox): os.chmod(sbox.ospath('A/B/E/alpha'), svntest.main.S_ALL_RW) # not read-only is_writable(sbox.ospath('A/B/E/alpha')) - expected_output = ["Reverted '%s'\n" % sbox.ospath('A/B/E/alpha')] - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', sbox.ospath('A/B/E/alpha')) + run_and_verify_revert(sbox.ospaths(['A/B/E/alpha'])) is_readonly(sbox.ospath('A/B/E/alpha')) if svntest.main.is_posix_os(): os.chmod(sbox.ospath('A/B/E/beta'), svntest.main.S_ALL_RW) # not executable is_non_executable(sbox.ospath('A/B/E/beta')) - expected_output = ["Reverted '%s'\n" % sbox.ospath('A/B/E/beta')] - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', sbox.ospath('A/B/E/beta')) + run_and_verify_revert(sbox.ospaths(['A/B/E/beta'])) is_executable(sbox.ospath('A/B/E/beta')) # copied file is always writeable @@ -1212,14 +1181,8 @@ def revert_copy_depth_files(sbox): }) svntest.actions.run_and_verify_status(wc_dir, expected_status) - expected_output = svntest.verify.UnorderedOutput([ - "Reverted '%s'\n" % sbox.ospath(path) for path in ['A/B/E2', - 'A/B/E2/alpha', - 'A/B/E2/beta']]) - - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', '--depth', 'files', - sbox.ospath('A/B/E2')) + run_and_verify_revert(sbox.ospaths(['A/B/E2']), ['--depth', 'files'], + sbox.ospaths(['A/B/E2', 'A/B/E2/alpha', 'A/B/E2/beta'])) expected_status.remove('A/B/E2', 'A/B/E2/alpha', 'A/B/E2/beta') svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1242,12 +1205,8 @@ def revert_nested_add_depth_immediates(s }) svntest.actions.run_and_verify_status(wc_dir, expected_status) - expected_output = svntest.verify.UnorderedOutput([ - "Reverted '%s'\n" % sbox.ospath(path) for path in ['A/X', 'A/X/Y']]) - - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', '--depth', 'immediates', - sbox.ospath('A/X')) + run_and_verify_revert(sbox.ospaths(['A/X']), ['--depth', 'immediates'], + sbox.ospaths(['A/X', 'A/X/Y'])) expected_status.remove('A/X', 'A/X/Y') svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1299,9 +1258,7 @@ def revert_empty_actual(sbox): wc_dir = sbox.wc_dir # Non-recursive code path works - svntest.actions.run_and_verify_svn(["Reverted '%s'\n" % sbox.ospath('alpha')], - [], - 'revert', sbox.ospath('alpha')) + run_and_verify_revert(sbox.ospaths(['alpha'])) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1316,9 +1273,7 @@ def revert_empty_actual_recursive(sbox): # Recursive code path fails, the superfluous actual node suppresses the # notification - svntest.actions.run_and_verify_svn(["Reverted '%s'\n" % sbox.ospath('alpha')], - [], - 'revert', '-R', sbox.ospath('alpha')) + run_and_verify_revert(sbox.ospaths(['alpha']), ['-R']) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1433,7 +1388,7 @@ def revert_tree_conflicts_with_replaceme cd_and_status_u('A/D/H') # Revert everything (i.e., accept "theirs-full"). - svntest.actions.run_and_verify_revert([ + reverted_paths = [ wc('A/B/E'), wc('A/B/E/alpha'), # incoming & local wc('A/B/E/beta'), @@ -1450,7 +1405,8 @@ def revert_tree_conflicts_with_replaceme wc('A/D/H/loc_psi'), wc('A/D/gamma'), wc('A/mu'), - ], '-R', wc_dir) + ] + run_and_verify_revert([wc_dir], ['-R'], reverted_paths) # Remove a few unversioned files that revert left behind. os.remove(wc('A/B/E/loc_beta')) @@ -1511,10 +1467,7 @@ def revert_no_text_change_conflict(sbox) create_no_text_change_conflict(sbox) wc_dir = sbox.wc_dir - svntest.actions.run_and_verify_svn(["Reverted '%s'\n" - % sbox.ospath('A/B/E/alpha')], - [], - 'revert', sbox.ospath('A/B/E/alpha')) + run_and_verify_revert(sbox.ospaths(['A/B/E/alpha'])) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1526,10 +1479,7 @@ def revert_no_text_change_conflict_recur create_no_text_change_conflict(sbox) wc_dir = sbox.wc_dir - svntest.actions.run_and_verify_svn(["Reverted '%s'\n" - % sbox.ospath('A/B/E/alpha')], - [], - 'revert', '-R', wc_dir) + run_and_verify_revert(sbox.ospaths(['A/B/E/alpha']), ['-R']) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) svntest.actions.run_and_verify_status(wc_dir, expected_status) @@ -1560,13 +1510,8 @@ def revert_with_unversioned_targets(sbox f.write(psi_contents) # revert - expected_output = svntest.verify.UnorderedOutput([ - "Reverted '%s'\n" % sbox.ospath('A/D/H/chi'), - "Skipped '%s'\n" % sbox.ospath('A/D/H/delta'), - "Reverted '%s'\n" % sbox.ospath('A/D/H/psi'), - ]) - svntest.actions.run_and_verify_svn(expected_output, [], - 'revert', chi_path, delta_path, psi_path) + run_and_verify_revert([chi_path, delta_path, psi_path], [], + [chi_path, psi_path], [delta_path]) # verify status expected_status = svntest.actions.get_virginal_state(wc_dir, 1) @@ -1585,8 +1530,8 @@ def revert_with_unversioned_targets(sbox def revert_nonexistent(sbox): 'svn revert -R nonexistent' sbox.build(read_only=True) - svntest.actions.run_and_verify_svn('Skipped.*nonexistent', [], - 'revert', '-R', sbox.ospath('nonexistent')) + run_and_verify_revert(sbox.ospaths(['nonexistent']), ['-R'], + [], sbox.ospaths(['nonexistent'])) @Issue(4168) def revert_obstructing_wc(sbox): @@ -1641,6 +1586,33 @@ def revert_moved_dir_partial(sbox): sbox.simple_move('A', 'A_') svntest.actions.run_and_verify_svn(None, [], 'revert', sbox.ospath('A')) +@XFail() +@Issue(4798) +def revert_remove_added(sbox): + "revert_remove_added" + + sbox.build(empty=True, read_only=True) + + # We'll test the items named with a '1' as direct targets to 'revert', + # and items named with a '2' as items found by recursion. + sbox.simple_mkdir('D1', 'D2') + sbox.simple_add_text('This is a new file.', + 'D1/file', 'file1', + 'D2/file', 'file2') + + run_and_verify_revert(sbox.ospaths(['D1']), ['--remove-added', '-R'], + sbox.ospaths(['D1/file', 'D1'])) + assert(not os.path.exists(sbox.ospath('D1'))) + + run_and_verify_revert(sbox.ospaths(['file1']), ['--remove-added'], + sbox.ospaths(['file1'])) + assert(not os.path.exists(sbox.ospath('file1'))) + + run_and_verify_revert(sbox.ospaths(['.']), ['--remove-added', '-R'], + sbox.ospaths(['D2/file', 'D2', 'file2'])) + assert(not os.path.exists(sbox.ospath('file2'))) + assert(not os.path.exists(sbox.ospath('D2'))) + ######################################################################## # Run the tests @@ -1683,6 +1655,7 @@ test_list = [ None, revert_nonexistent, revert_obstructing_wc, revert_moved_dir_partial, + revert_remove_added, ] if __name__ == '__main__':
Modified: subversion/branches/swig-py3/subversion/tests/cmdline/shelf_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/shelf_tests.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/shelf_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/shelf_tests.py Mon Jul 8 15:19:03 2019 @@ -525,6 +525,7 @@ def shelf_status(sbox): #---------------------------------------------------------------------- +@XFail() def shelve_mkdir(sbox): "shelve mkdir" @@ -534,7 +535,7 @@ def shelve_mkdir(sbox): sbox.simple_mkdir('D', 'D/D2') sbox.simple_propset('p', 'v', 'D', 'D/D2') - shelve_unshelve(sbox, modifier, cannot_shelve=True) + shelve_unshelve(sbox, modifier) #---------------------------------------------------------------------- @@ -548,10 +549,11 @@ def shelve_rmdir(sbox): def modifier(sbox): sbox.simple_rm('A/C', 'A/D/G') - shelve_unshelve(sbox, modifier, cannot_shelve=True) + shelve_unshelve(sbox, modifier) #---------------------------------------------------------------------- +@XFail() def shelve_replace_dir(sbox): "shelve replace dir" @@ -563,7 +565,7 @@ def shelve_replace_dir(sbox): sbox.simple_rm('A/C', 'A/D/G') sbox.simple_mkdir('A/C', 'A/C/D2') - shelve_unshelve(sbox, modifier, cannot_shelve=True) + shelve_unshelve(sbox, modifier) #---------------------------------------------------------------------- @@ -576,7 +578,7 @@ def shelve_file_copy(sbox): sbox.simple_copy('iota', 'A/ii') sbox.simple_propset('p', 'v', 'A/ii') - shelve_unshelve(sbox, modifier, cannot_shelve=True) + shelve_unshelve(sbox, modifier) #---------------------------------------------------------------------- @@ -589,7 +591,7 @@ def shelve_dir_copy(sbox): sbox.simple_copy('A/B', 'BB') sbox.simple_propset('p', 'v', 'BB') - shelve_unshelve(sbox, modifier, cannot_shelve=True) + shelve_unshelve(sbox, modifier) #---------------------------------------------------------------------- @@ -643,31 +645,21 @@ def refuse_to_shelve_conflict(sbox): os.chdir(sbox.wc_dir) sbox.wc_dir = '' - # create a tree conflict victim at an unversioned path + # create a conflict sbox.simple_mkdir('topdir') sbox.simple_commit() - sbox.simple_mkdir('topdir/subdir') - sbox.simple_commit() - sbox.simple_update() - sbox.simple_rm('topdir') - sbox.simple_commit() sbox.simple_update() svntest.actions.run_and_verify_svn( None, [], - 'merge', '-c2', '.', '--ignore-ancestry', '--accept', 'postpone') + 'merge', '-c1', '.', '--ignore-ancestry', '--accept', 'postpone') + # check that we did create a conflict svntest.actions.run_and_verify_svn( - None, 'svn: E155015:.*existing.*conflict.*', + None, 'svn: E155035:.*conflict.*', 'merge', '-c1', '.', '--ignore-ancestry', '--accept', 'postpone') # attempt to shelve - expected_out = svntest.verify.RegexListOutput([ - r'--- .*', - r'--- .*', - r'\? C topdir', - r' > .*', - r' > not shelved']) - svntest.actions.run_and_verify_svn(expected_out, - '.* 1 path could not be shelved', + 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) @@ -711,6 +703,7 @@ def unshelve_with_merge(sbox, setup, mod os.chdir(was_cwd) +@XFail() def unshelve_text_mod_merge(sbox): "unshelve text mod merge" @@ -735,6 +728,7 @@ def unshelve_text_mod_merge(sbox): #---------------------------------------------------------------------- +@XFail() def unshelve_text_mod_conflict(sbox): "unshelve text mod conflict" @@ -765,6 +759,7 @@ def unshelve_text_mod_conflict(sbox): #---------------------------------------------------------------------- +@XFail() def unshelve_undeclared_binary_mod_conflict(sbox): "unshelve undeclared binary mod conflict" @@ -795,6 +790,7 @@ def unshelve_undeclared_binary_mod_confl #---------------------------------------------------------------------- +@XFail() def unshelve_binary_mod_conflict(sbox): "unshelve binary mod conflict" @@ -845,6 +841,7 @@ def unshelve_text_prop_merge(sbox): #---------------------------------------------------------------------- +@XFail() def unshelve_text_prop_conflict(sbox): "unshelve text prop conflict" Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svnadmin_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svnadmin_tests.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/svnadmin_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/svnadmin_tests.py Mon Jul 8 15:19:03 2019 @@ -3920,6 +3920,51 @@ def recover_prunes_rep_cache_when_disabl check_recover_prunes_rep_cache(sbox, enable_rep_sharing=False) +@Issue(4760) +def dump_include_copied_directory(sbox): + "include copied directory with nested nodes" + + sbox.build(create_wc=False) + + svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "copy", + sbox.repo_url + '/A/D', + sbox.repo_url + '/COPY', + "-m", "Create branch.") + + # Dump repository with only /COPY path included. + _, dump, _ = svntest.actions.run_and_verify_svnadmin(None, [], + 'dump', '-q', + '--include', '/COPY', + sbox.repo_dir) + + # Load repository from dump. + sbox2 = sbox.clone_dependent() + sbox2.build(create_wc=False, empty=True) + load_and_verify_dumpstream(sbox2, None, [], None, False, dump) + + # Check log. + expected_output = svntest.verify.RegexListOutput([ + '-+\\n', + 'r2\ .*\n', + # Only '/COPY' is added + re.escape('Changed paths:\n'), + re.escape(' A /COPY'), + re.escape(' A /COPY/G'), + re.escape(' A /COPY/G/pi'), + re.escape(' A /COPY/G/rho'), + re.escape(' A /COPY/G/tau'), + re.escape(' A /COPY/H'), + re.escape(' A /COPY/H/chi'), + re.escape(' A /COPY/H/omega'), + re.escape(' A /COPY/H/psi'), + re.escape(' A /COPY/gamma'), + '-+\\n', + 'r1\ .*\n', + '-+\\n' + ]) + svntest.actions.run_and_verify_svn(expected_output, [], + 'log', '-v', '-q', sbox2.repo_url) + ######################################################################## # Run the tests @@ -3997,6 +4042,7 @@ test_list = [ None, dump_no_canonicalize_svndate, recover_prunes_rep_cache_when_enabled, recover_prunes_rep_cache_when_disabled, + dump_include_copied_directory, ] if __name__ == '__main__': Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svnauthz_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svnauthz_tests.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/svnauthz_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/svnauthz_tests.py Mon Jul 8 15:19:03 2019 @@ -965,6 +965,36 @@ def svnauthz_inverted_selector_test(sbox os.remove(authz_path) +@Issues(4802, 4803) +def svnauthz_empty_group_test(sbox): + "test empty group definition" + + # build an authz file + authz_content = ("[groups]\n" + "group1 =\n" + "group2 = @group1\n" + "group3 = @group2, user\n" + + + "[A:/]\n" + "@group1 = rw\n" + "@group2 = rw\n" + "@group3 = r\n") + + (authz_fd, authz_path) = tempfile.mkstemp() + svntest.main.file_write(authz_path, authz_content) + + expected_stderr = svntest.verify.RegexOutput( + r".*warning: W220003:.*", match_all=False) + + svntest.actions.run_and_verify_svnauthz( + [], expected_stderr, 0, False, 'validate', authz_path) + + svntest.actions.run_and_verify_svnauthz( + 'r', expected_stderr, 0, False, 'accessof', + '--repository', 'A', '--username', 'user', authz_path) + + ######################################################################## # Run the tests @@ -984,6 +1014,7 @@ test_list = [ None, svnauthz_compat_mode_file_test, svnauthz_compat_mode_repo_test, svnauthz_inverted_selector_test, + svnauthz_empty_group_test, ] if __name__ == '__main__': Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svnserveautocheck.sh URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svnserveautocheck.sh?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/svnserveautocheck.sh (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/svnserveautocheck.sh Mon Jul 8 15:19:03 2019 @@ -74,6 +74,28 @@ fail() { exit 1 } +query() { + printf "%s" "$SCRIPT: $1 (y/n)? [$2] " + if [ -n "$BASH_VERSION" ]; then + read -n 1 -t 32 + else + # + prog=" +import select as s +import sys +import tty, termios +tty.setcbreak(sys.stdin.fileno(), termios.TCSANOW) +if s.select([sys.stdin.fileno()], [], [], 32)[0]: + sys.stdout.write(sys.stdin.read(1)) +" + stty_state=`stty -g` + REPLY=`$PYTHON -u -c "$prog" "$@"` + stty $stty_state + fi + echo + [ "${REPLY:-$2}" = 'y' ] +} + # Compute ABS_BUILDDIR and ABS_SRCDIR. if [ -x subversion/svn/svn ]; then # cwd is build tree root @@ -92,13 +114,21 @@ if [ ! -e $ABS_SRCDIR/subversion/include fail "Run this script from the root of Subversion's build tree!" fi +# Create a directory for the PID and log files. If you change this, also make +# sure to change the svn:ignore entry for it and "make check-clean". +SVNSERVE_ROOT="$ABS_BUILDDIR/subversion/tests/cmdline/svnserve-$(date '+%Y%m%d-%H%M%S')" +mkdir "$SVNSERVE_ROOT" \ + || fail "couldn't create temporary directory '$SVNSERVE_ROOT'" + # If you change this, also make sure to change the svn:ignore entry # for it and "make check-clean". -SVNSERVE_PID=$ABS_BUILDDIR/subversion/tests/svnserveautocheck.pid +SVNSERVE_PID=$SVNSERVE_ROOT/svnserve.pid +SVNSERVE_LOG=$SVNSERVE_ROOT/svnserve.log SERVER_CMD="$ABS_BUILDDIR/subversion/svnserve/svnserve" rm -f $SVNSERVE_PID +rm -f $SVNSERVE_LOG random_port() { if [ -n "$BASH_VERSION" ]; then @@ -140,6 +170,7 @@ fi --listen-host 127.0.0.1 \ --listen-port $SVNSERVE_PORT \ --pid-file $SVNSERVE_PID \ + --log-file $SVNSERVE_LOG \ $SVNSERVE_ARGS & BASE_URL=svn://127.0.0.1:$SVNSERVE_PORT @@ -155,5 +186,11 @@ else cd - > /dev/null fi +query 'Browse server log' n \ + && less "$SVNSERVE_LOG" + +query 'Delete svnserve root directory' y \ + && rm -fr "$SVNSERVE_ROOT/" + really_cleanup exit $r Modified: subversion/branches/swig-py3/subversion/tests/cmdline/svntest/main.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/svntest/main.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/svntest/main.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/svntest/main.py Mon Jul 8 15:19:03 2019 @@ -57,7 +57,7 @@ from svntest import Failure from svntest import Skip from svntest.wc import StateItem as Item -SVN_VER_MINOR = 12 +SVN_VER_MINOR = 13 ###################################################################### # Modified: subversion/branches/swig-py3/subversion/tests/cmdline/switch_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/switch_tests.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/switch_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/switch_tests.py Mon Jul 8 15:19:03 2019 @@ -2027,8 +2027,9 @@ def tolerate_local_mods(sbox): svntest.main.run_svn(None, 'add', L_path) sbox.simple_commit(message='Commit added folder') - # locally modified unversioned file + # locally modified versioned file svntest.main.file_write(LM_path, 'Locally modified file.\n', 'w+') + sbox.simple_add('A/L/local_mod') expected_output = svntest.wc.State(wc_dir, { 'A/L' : Item(status=' ', treeconflict='C'), @@ -2044,7 +2045,8 @@ def tolerate_local_mods(sbox): expected_status.tweak('', 'iota', wc_rev=1) expected_status.tweak('A', switched='S') expected_status.add({ - 'A/L' : Item(status='A ', copied='+', treeconflict='C', wc_rev='-') + 'A/L' : Item(status='A ', copied='+', treeconflict='C', wc_rev='-'), + 'A/L/local_mod' : Item(status='A ', wc_rev='-'), }) # Used to fail with locally modified or unversioned files Modified: subversion/branches/swig-py3/subversion/tests/cmdline/update_tests.py URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/cmdline/update_tests.py?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/cmdline/update_tests.py (original) +++ subversion/branches/swig-py3/subversion/tests/cmdline/update_tests.py Mon Jul 8 15:19:03 2019 @@ -6855,6 +6855,48 @@ def update_add_missing_local_add(sbox): sbox.simple_update() +# Verify that deleting an unmodified directory leaves behind any unversioned +# items on disk +def update_keeps_unversioned_items_in_deleted_dir(sbox): + "update keeps unversioned items in deleted dir" + sbox.build() + wc_dir = sbox.wc_dir + + sbox.simple_rm('A/D/G') + sbox.simple_commit() + + sbox.simple_update('', revision='1') + + os.mkdir(sbox.ospath('A/D/G/unversioned-dir')) + svntest.main.file_write(sbox.ospath('A/D/G/unversioned.txt'), + 'unversioned file', 'wb') + + expected_output = svntest.wc.State(wc_dir, { + 'A/D/G' : Item(status='D '), + }) + + expected_disk = svntest.main.greek_state.copy() + # The unversioned items should be left behind on disk + expected_disk.add({ + 'A/D/G/unversioned-dir' : Item(), + 'A/D/G/unversioned.txt' : Item('unversioned file'), + }) + expected_disk.remove('A/D/G/pi') + expected_disk.remove('A/D/G/rho') + expected_disk.remove('A/D/G/tau') + + expected_status = svntest.actions.get_virginal_state(wc_dir, 2) + expected_status.remove('A/D/G') + expected_status.remove('A/D/G/pi') + expected_status.remove('A/D/G/rho') + expected_status.remove('A/D/G/tau') + + svntest.actions.run_and_verify_update(wc_dir, + expected_output, + expected_disk, + expected_status, + [], True) + ####################################################################### # Run the tests @@ -6946,6 +6988,7 @@ test_list = [ None, missing_tmp_update, update_delete_switched, update_add_missing_local_add, + update_keeps_unversioned_items_in_deleted_dir, ] if __name__ == '__main__': Modified: subversion/branches/swig-py3/subversion/tests/libsvn_client/conflicts-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_client/conflicts-test.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_client/conflicts-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_client/conflicts-test.c Mon Jul 8 15:19:03 2019 @@ -6946,6 +6946,519 @@ test_merge_file_edit_move_vs_file_move_a return SVN_NO_ERROR; } +static svn_error_t * +create_dir_move_vs_dir_move_merge_conflict(svn_client_conflict_t **conflict, + svn_test__sandbox_t *b, + svn_client_ctx_t *ctx) +{ + svn_opt_revision_t opt_rev; + const char *branch_url; + apr_array_header_t *options; + svn_client_conflict_option_t *option; + apr_array_header_t *possible_moved_to_abspaths; + + /* Create a branch of node "A". */ + SVN_ERR(sbox_wc_copy(b, "A", "A2")); + SVN_ERR(sbox_wc_commit(b, "")); /* r2 */ + + /* Move a directory on trunk. */ + SVN_ERR(sbox_wc_move(b, "A/B", "A/B-moved")); + SVN_ERR(sbox_wc_commit(b, "")); /* r3 */ + + /* Edit a file in the moved directory on trunk. */ + SVN_ERR(sbox_file_write(b, "A/B-moved/E/alpha", + modified_file_content)); + SVN_ERR(sbox_wc_commit(b, "")); + + /* Move the same direcotry to a different location on the branch. */ + SVN_ERR(sbox_wc_move(b, "A2/B", "A2/B-also-moved")); + SVN_ERR(sbox_wc_commit(b, "")); + + /* Edit a file in the moved directory on the branch. */ + SVN_ERR(sbox_file_write(b, "A2/B-also-moved/lambda", + modified_file_content)); + SVN_ERR(sbox_wc_commit(b, "")); + + /* Merge branch to trunk. */ + SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM)); + branch_url = apr_pstrcat(b->pool, b->repos_url, "/A2", SVN_VA_NULL); + opt_rev.kind = svn_opt_revision_head; + opt_rev.value.number = SVN_INVALID_REVNUM; + SVN_ERR(svn_client_merge_peg5(branch_url, NULL, &opt_rev, + sbox_wc_path(b, "A"), + svn_depth_infinity, + FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, + NULL, ctx, b->pool)); + + SVN_ERR(svn_client_conflict_get(conflict, sbox_wc_path(b, "A/B"), + ctx, b->pool, b->pool)); + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + svn_client_conflict_option_incoming_delete_ignore, + svn_client_conflict_option_incoming_delete_accept, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(*conflict, ctx, expected_opts, + b->pool)); + } + + SVN_ERR(svn_client_conflict_tree_get_details(*conflict, ctx, b->pool)); + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + svn_client_conflict_option_both_moved_dir_merge, + svn_client_conflict_option_both_moved_dir_move_merge, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(*conflict, ctx, expected_opts, + b->pool)); + } + + SVN_ERR(svn_client_conflict_tree_get_resolution_options(&options, *conflict, + ctx, b->pool, + b->pool)); + option = svn_client_conflict_option_find_by_id( + options, svn_client_conflict_option_both_moved_dir_merge); + SVN_TEST_ASSERT(option != NULL); + SVN_ERR(svn_client_conflict_option_get_moved_to_abspath_candidates( + &possible_moved_to_abspaths, option, b->pool, b->pool)); + + /* The resolver finds two possible move destinations because both + * branches are checked out into the same working copy. + * + * Possible working copy destinations for moved-away 'A/B' are: + * (1): 'A/B-also-moved + * (2): 'A2/B-also-moved + * Only one destination can be a move; the others are copies. + */ + SVN_TEST_INT_ASSERT(possible_moved_to_abspaths->nelts, 2); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_abspaths, 0, const char *), + sbox_wc_path(b, "A/B-also-moved")); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_abspaths, 1, const char *), + sbox_wc_path(b, "A2/B-also-moved")); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_merge_dir_move_vs_dir_move(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b)); + svn_client_ctx_t *ctx; + svn_client_conflict_t *conflict; + svn_opt_revision_t opt_rev; + struct status_baton sb; + struct svn_client_status_t *status; + svn_stringbuf_t *buf; + + SVN_ERR(svn_test__sandbox_create(b, "merge_dir_move_vs_dir_move", + opts, pool)); + + SVN_ERR(sbox_add_and_commit_greek_tree(b)); /* r1 */ + + SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool)); + SVN_ERR(create_dir_move_vs_dir_move_merge_conflict(&conflict, b, ctx)); + + SVN_ERR(svn_client_conflict_tree_resolve_by_id( + conflict, + svn_client_conflict_option_both_moved_dir_merge, + ctx, b->pool)); + + /* The node "A/B" should not exist. */ + SVN_TEST_ASSERT_ERROR(svn_client_conflict_get(&conflict, + sbox_wc_path(b, "A/B"), + ctx, pool, pool), + SVN_ERR_WC_PATH_NOT_FOUND); + + /* The node "A/B-also-moved" should not exist. */ + SVN_TEST_ASSERT_ERROR(svn_client_conflict_get( + &conflict, + sbox_wc_path(b, "A/B-also-moved"), ctx, pool, pool), + SVN_ERR_WC_PATH_NOT_FOUND); + + /* Ensure that the merged directory has the expected status. */ + opt_rev.kind = svn_opt_revision_working; + sb.result_pool = b->pool; + SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, "A/B-moved"), + &opt_rev, svn_depth_unknown, TRUE, TRUE, + TRUE, TRUE, FALSE, TRUE, NULL, + status_func, &sb, b->pool)); + status = sb.status; + SVN_TEST_ASSERT(status->kind == svn_node_dir); + SVN_TEST_ASSERT(status->versioned); + SVN_TEST_ASSERT(!status->conflicted); + SVN_TEST_ASSERT(status->node_status == svn_wc_status_normal); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_normal); + SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none); + SVN_TEST_ASSERT(!status->copied); + SVN_TEST_ASSERT(!status->switched); + SVN_TEST_ASSERT(!status->file_external); + SVN_TEST_ASSERT(status->moved_from_abspath == NULL); + SVN_TEST_ASSERT(status->moved_to_abspath == NULL); + + /* Make sure the edited files have the expected content. */ + SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, "A/B-moved/lambda"), + pool)); + SVN_TEST_STRING_ASSERT(buf->data, modified_file_content); + SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, "A/B-moved/E/alpha"), + pool)); + SVN_TEST_STRING_ASSERT(buf->data, modified_file_content); + + return SVN_NO_ERROR; +} + +static svn_error_t * +test_merge_dir_move_vs_dir_move_accept_move(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b)); + svn_client_ctx_t *ctx; + svn_client_conflict_t *conflict; + svn_opt_revision_t opt_rev; + struct status_baton sb; + struct svn_client_status_t *status; + svn_stringbuf_t *buf; + + SVN_ERR(svn_test__sandbox_create(b, "merge_dir_move_vs_dir_move_accept_move", + opts, pool)); + + SVN_ERR(sbox_add_and_commit_greek_tree(b)); /* r1 */ + + SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool)); + SVN_ERR(create_dir_move_vs_dir_move_merge_conflict(&conflict, b, ctx)); + + SVN_ERR(svn_client_conflict_tree_resolve_by_id( + conflict, + svn_client_conflict_option_both_moved_dir_move_merge, + ctx, b->pool)); + + /* The node "A/B" should not exist. */ + SVN_TEST_ASSERT_ERROR(svn_client_conflict_get(&conflict, + sbox_wc_path(b, "A/B"), + ctx, pool, pool), + SVN_ERR_WC_PATH_NOT_FOUND); + + /* The node "A/B-moved" should be moved to A/B-also-moved. */ + opt_rev.kind = svn_opt_revision_working; + sb.result_pool = b->pool; + SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, "A/B-moved"), + &opt_rev, svn_depth_empty, TRUE, TRUE, + TRUE, TRUE, FALSE, TRUE, NULL, + status_func, &sb, b->pool)); + status = sb.status; + SVN_TEST_ASSERT(status->kind == svn_node_dir); + SVN_TEST_ASSERT(status->versioned); + SVN_TEST_ASSERT(!status->conflicted); + SVN_TEST_ASSERT(status->node_status == svn_wc_status_deleted); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_normal); + SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none); + SVN_TEST_ASSERT(!status->copied); + SVN_TEST_ASSERT(!status->switched); + SVN_TEST_ASSERT(!status->file_external); + SVN_TEST_ASSERT(status->moved_from_abspath == NULL); + SVN_TEST_STRING_ASSERT(status->moved_to_abspath, + sbox_wc_path(b, "A/B-also-moved")); + + /* Ensure that the merged directory has the expected status. */ + SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, "A/B-also-moved"), + &opt_rev, svn_depth_empty, TRUE, TRUE, + TRUE, TRUE, FALSE, TRUE, NULL, + status_func, &sb, b->pool)); + status = sb.status; + SVN_TEST_ASSERT(status->kind == svn_node_dir); + SVN_TEST_ASSERT(status->versioned); + SVN_TEST_ASSERT(!status->conflicted); + SVN_TEST_ASSERT(status->node_status == svn_wc_status_added); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_normal); + SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none); + SVN_TEST_ASSERT(status->copied); + SVN_TEST_ASSERT(!status->switched); + SVN_TEST_ASSERT(!status->file_external); + SVN_TEST_STRING_ASSERT(status->moved_from_abspath, + sbox_wc_path(b, "A/B-moved")); + SVN_TEST_ASSERT(status->moved_to_abspath == NULL); + + /* Make sure the edited files have the expected content. */ + SVN_ERR(svn_stringbuf_from_file2(&buf, + sbox_wc_path(b, "A/B-also-moved/lambda"), + pool)); + SVN_TEST_STRING_ASSERT(buf->data, modified_file_content); + SVN_ERR(svn_stringbuf_from_file2(&buf, + sbox_wc_path(b, "A/B-also-moved/E/alpha"), + pool)); + SVN_TEST_STRING_ASSERT(buf->data, modified_file_content); + + return SVN_NO_ERROR; +} + +static svn_error_t * +create_file_move_vs_file_move_update_conflict(svn_client_conflict_t **conflict, + svn_test__sandbox_t *b, + svn_client_ctx_t *ctx) +{ + apr_array_header_t *options; + svn_client_conflict_option_t *option; + apr_array_header_t *possible_moved_to_abspaths; + + /* Move a file. */ + SVN_ERR(sbox_wc_move(b, "A/mu", "A/mu-moved")); + + /* Edit moved file. */ + SVN_ERR(sbox_file_write(b, "A/mu-moved", modified_file_content)); + SVN_ERR(sbox_wc_commit(b, "")); + + /* Update back to r1, */ + SVN_ERR(sbox_wc_update(b, "", 1)); /* r2 */ + + /* Copy the file to test handling of ambiguous moves. */ + SVN_ERR(sbox_wc_copy(b, "A/mu", "A/mu-copied")); + + /* Move the same file to a different location. */ + SVN_ERR(sbox_wc_move(b, "A/mu", "A/mu-also-moved")); + + /* Edit moved file. */ + SVN_ERR(sbox_file_write(b, "A/mu-also-moved", + modified_file_in_working_copy_content)); + + /* Update to r2. */ + /* This should raise an "incoming delete vs local delete" tree conflict. */ + SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM)); + + SVN_ERR(svn_client_conflict_get(conflict, sbox_wc_path(b, "A/mu"), + ctx, b->pool, b->pool)); + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + svn_client_conflict_option_incoming_delete_ignore, + svn_client_conflict_option_incoming_delete_accept, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(*conflict, ctx, expected_opts, + b->pool)); + } + + SVN_ERR(svn_client_conflict_tree_get_details(*conflict, ctx, b->pool)); + { + svn_client_conflict_option_id_t expected_opts[] = { + svn_client_conflict_option_postpone, + svn_client_conflict_option_accept_current_wc_state, + svn_client_conflict_option_both_moved_file_merge, + svn_client_conflict_option_both_moved_file_move_merge, + -1 /* end of list */ + }; + SVN_ERR(assert_tree_conflict_options(*conflict, ctx, expected_opts, + b->pool)); + } + + /* Check possible move destinations for the file. */ + SVN_ERR(svn_client_conflict_tree_get_resolution_options(&options, *conflict, + ctx, b->pool, + b->pool)); + option = svn_client_conflict_option_find_by_id( + options, svn_client_conflict_option_both_moved_file_merge); + SVN_TEST_ASSERT(option != NULL); + + SVN_ERR(svn_client_conflict_option_get_moved_to_abspath_candidates( + &possible_moved_to_abspaths, option, b->pool, b->pool)); + + /* The resolver finds two possible destinations for the moved file: + * + * Possible working copy destinations for moved-away 'A/mu' are: + * (1): 'A/mu-also-moved' + * (2): 'A/mu-copied' + * Only one destination can be a move; the others are copies. + */ + SVN_TEST_INT_ASSERT(possible_moved_to_abspaths->nelts, 2); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_abspaths, 0, const char *), + sbox_wc_path(b, "A/mu-also-moved")); + SVN_TEST_STRING_ASSERT( + APR_ARRAY_IDX(possible_moved_to_abspaths, 1, const char *), + sbox_wc_path(b, "A/mu-copied")); + + return SVN_NO_ERROR; +} + + +static svn_error_t * +test_update_file_move_vs_file_move(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b)); + svn_client_ctx_t *ctx; + svn_client_conflict_t *conflict; + svn_opt_revision_t opt_rev; + struct status_baton sb; + struct svn_client_status_t *status; + svn_stringbuf_t *buf; + svn_node_kind_t kind; + char *conflicted_content; + + SVN_ERR(svn_test__sandbox_create(b, "update_file_move_vs_file_move", + opts, pool)); + + SVN_ERR(sbox_add_and_commit_greek_tree(b)); /* r1 */ + + SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool)); + SVN_ERR(create_file_move_vs_file_move_update_conflict(&conflict, b, ctx)); + + SVN_ERR(svn_client_conflict_tree_resolve_by_id( + conflict, + svn_client_conflict_option_both_moved_file_merge, + ctx, b->pool)); + + /* The node "A/mu" should no longer exist. */ + SVN_TEST_ASSERT_ERROR(svn_client_conflict_get( + &conflict, sbox_wc_path(b, "A/mu"), ctx, pool, pool), + SVN_ERR_WC_PATH_NOT_FOUND); + + /* The node "A/mu-moved" should now have moved to "A/mu-also-moved. */ + SVN_ERR(svn_io_check_path(sbox_wc_path(b, "A/mu"), &kind, b->pool)); + SVN_TEST_ASSERT(kind == svn_node_none); + opt_rev.kind = svn_opt_revision_working; + sb.result_pool = b->pool; + SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, "A/mu-moved"), + &opt_rev, svn_depth_unknown, TRUE, TRUE, + TRUE, TRUE, FALSE, TRUE, NULL, + status_func, &sb, b->pool)); + status = sb.status; + SVN_TEST_ASSERT(status->kind == svn_node_file); + SVN_TEST_ASSERT(status->versioned); + SVN_TEST_ASSERT(!status->conflicted); + SVN_TEST_ASSERT(status->node_status == svn_wc_status_deleted); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_normal); + SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none); + SVN_TEST_ASSERT(!status->copied); + SVN_TEST_ASSERT(!status->switched); + SVN_TEST_ASSERT(!status->file_external); + SVN_TEST_ASSERT(status->moved_from_abspath == NULL); + SVN_TEST_STRING_ASSERT(status->moved_to_abspath, + sbox_wc_path(b, "A/mu-also-moved")); + + /* Ensure that the merged file has the expected status. */ + opt_rev.kind = svn_opt_revision_working; + sb.result_pool = b->pool; + SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, "A/mu-also-moved"), + &opt_rev, svn_depth_unknown, TRUE, TRUE, + TRUE, TRUE, FALSE, TRUE, NULL, + status_func, &sb, b->pool)); + status = sb.status; + SVN_TEST_ASSERT(status->kind == svn_node_file); + SVN_TEST_ASSERT(status->versioned); + SVN_TEST_ASSERT(status->conflicted); + SVN_TEST_ASSERT(status->node_status == svn_wc_status_conflicted); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_conflicted); + SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none); + SVN_TEST_ASSERT(status->copied); + SVN_TEST_ASSERT(!status->switched); + SVN_TEST_ASSERT(!status->file_external); + SVN_TEST_STRING_ASSERT(status->moved_from_abspath, + sbox_wc_path(b, "A/mu-moved")); + SVN_TEST_ASSERT(status->moved_to_abspath == NULL); + + /* Ensure that the moved+merged file has the expected content. */ + SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, "A/mu-also-moved"), + b->pool)); + conflicted_content = apr_psprintf(b->pool, + "<<<<<<< .working\n" + "%s" + "||||||| .old\n" + "This is the file 'mu'.\n" + "=======\n" + "%s" + ">>>>>>> .new\n", + modified_file_in_working_copy_content, + modified_file_content); + SVN_TEST_STRING_ASSERT(buf->data, conflicted_content); + + return SVN_NO_ERROR; +} + +/* Same test case as above, but accept the incoming move. */ +static svn_error_t * +test_update_file_move_vs_file_move_accept_move(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b)); + svn_client_ctx_t *ctx; + svn_client_conflict_t *conflict; + svn_opt_revision_t opt_rev; + struct status_baton sb; + struct svn_client_status_t *status; + svn_stringbuf_t *buf; + char *conflicted_content; + + SVN_ERR(svn_test__sandbox_create(b, + "update_file_move_vs_file_move_accept_move", + opts, pool)); + + SVN_ERR(sbox_add_and_commit_greek_tree(b)); /* r1 */ + + SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool)); + SVN_ERR(create_file_move_vs_file_move_update_conflict(&conflict, b, ctx)); + + SVN_ERR(svn_client_conflict_tree_resolve_by_id( + conflict, + svn_client_conflict_option_both_moved_file_move_merge, + ctx, b->pool)); + + /* The node "A/mu" should no longer exist. */ + SVN_TEST_ASSERT_ERROR(svn_client_conflict_get( + &conflict, sbox_wc_path(b, "A/mu"), ctx, pool, pool), + SVN_ERR_WC_PATH_NOT_FOUND); + + /* The node "A/mu-also-moved" should not exist. */ + SVN_TEST_ASSERT_ERROR(svn_client_conflict_get( + &conflict, sbox_wc_path(b, "A/mu-also-moved"), ctx, + pool, pool), + SVN_ERR_WC_PATH_NOT_FOUND); + + /* Ensure that the merged file has the expected status. */ + opt_rev.kind = svn_opt_revision_working; + sb.result_pool = b->pool; + SVN_ERR(svn_client_status6(NULL, ctx, sbox_wc_path(b, "A/mu-moved"), + &opt_rev, svn_depth_unknown, TRUE, TRUE, + TRUE, TRUE, FALSE, TRUE, NULL, + status_func, &sb, b->pool)); + status = sb.status; + SVN_TEST_ASSERT(status->kind == svn_node_file); + SVN_TEST_ASSERT(status->versioned); + SVN_TEST_ASSERT(status->conflicted); + SVN_TEST_ASSERT(status->node_status == svn_wc_status_conflicted); + SVN_TEST_ASSERT(status->text_status == svn_wc_status_conflicted); + SVN_TEST_ASSERT(status->prop_status == svn_wc_status_none); + SVN_TEST_ASSERT(!status->copied); + SVN_TEST_ASSERT(!status->switched); + SVN_TEST_ASSERT(!status->file_external); + SVN_TEST_ASSERT(status->moved_from_abspath == NULL); + SVN_TEST_ASSERT(status->moved_to_abspath == NULL); + + /* Ensure that the moved+merged file has the expected content. */ + SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, "A/mu-moved"), + b->pool)); + conflicted_content = apr_psprintf(b->pool, + "<<<<<<< .working\n" /* ### labels need fixing */ + "%s" + "||||||| .old\n" + "This is the file 'mu'.\n" + "=======\n" + "%s" + ">>>>>>> .new\n", + modified_file_content, + modified_file_in_working_copy_content); + SVN_TEST_STRING_ASSERT(buf->data, conflicted_content); + + return SVN_NO_ERROR; +} + + /* ========================================================================== */ @@ -7066,6 +7579,14 @@ static struct svn_test_descriptor_t test "file move vs file edit-move during merge"), SVN_TEST_OPTS_PASS(test_merge_file_edit_move_vs_file_move_accept_move, "file edit-move vs file move merge accept move"), + SVN_TEST_OPTS_PASS(test_merge_dir_move_vs_dir_move, + "dir move vs dir move during merge"), + SVN_TEST_OPTS_PASS(test_merge_dir_move_vs_dir_move_accept_move, + "dir move vs dir move during merge accept move"), + SVN_TEST_OPTS_PASS(test_update_file_move_vs_file_move, + "file move vs file move during update"), + SVN_TEST_OPTS_PASS(test_update_file_move_vs_file_move_accept_move, + "file move vs file move during update accept move"), SVN_TEST_NULL }; Modified: subversion/branches/swig-py3/subversion/tests/libsvn_fs/fs-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_fs/fs-test.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_fs/fs-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_fs/fs-test.c Mon Jul 8 15:19:03 2019 @@ -7441,6 +7441,34 @@ test_closest_copy_file_replaced_with_dir return SVN_NO_ERROR; } +static svn_error_t * +test_unrecognized_ioctl(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_fs_t *fs; + svn_error_t *err; + svn_fs_ioctl_code_t code = {0}; + + SVN_ERR(svn_test__create_fs(&fs, "test-unrecognized-ioctl", opts, pool)); + + code.fs_type = "NON-EXISTING"; + code.code = 98765; + err = svn_fs_ioctl(fs, code, NULL, NULL, NULL, NULL, pool, pool); + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE); + + code.fs_type = "NON-EXISTING"; + code.code = 98765; + err = svn_fs_ioctl(NULL, code, NULL, NULL, NULL, NULL, pool, pool); + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_UNKNOWN_FS_TYPE); + + code.fs_type = opts->fs_type; + code.code = 98765; + err = svn_fs_ioctl(NULL, code, NULL, NULL, NULL, NULL, pool, pool); + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE); + + return SVN_NO_ERROR; +} + /* ------------------------------------------------------------------------ */ /* The test table. */ @@ -7587,6 +7615,8 @@ static struct svn_test_descriptor_t test "test issue SVN-4677 regression"), SVN_TEST_OPTS_PASS(test_closest_copy_file_replaced_with_dir, "svn_fs_closest_copy after replacing file with dir"), + SVN_TEST_OPTS_PASS(test_unrecognized_ioctl, + "test svn_fs_ioctl with unrecognized code"), SVN_TEST_NULL }; Modified: subversion/branches/swig-py3/subversion/tests/libsvn_fs/locks-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_fs/locks-test.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_fs/locks-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_fs/locks-test.c Mon Jul 8 15:19:03 2019 @@ -1089,6 +1089,9 @@ lock_cb_error(const svn_test_opts_t *opt return SVN_NO_ERROR; } +/* XXX NOTE: + This test will fail on most Unix-like systems when run as the + root user, because flock() will ignore file permissions. */ static svn_error_t * obtain_write_lock_failure(const svn_test_opts_t *opts, apr_pool_t *pool) Modified: subversion/branches/swig-py3/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c Mon Jul 8 15:19:03 2019 @@ -199,8 +199,10 @@ get_repo_stats(const svn_test_opts_t *op svn_repos_t *repos; svn_revnum_t rev; apr_size_t i; - svn_fs_fs__stats_t *stats; svn_fs_fs__extension_info_t *extension_info; + svn_fs_fs__ioctl_get_stats_input_t input = {0}; + svn_fs_fs__ioctl_get_stats_output_t *output; + const svn_fs_fs__stats_t *stats; /* Bail (with success) on known-untestable scenarios */ if (strcmp(opts->fs_type, "fsfs") != 0) @@ -211,8 +213,9 @@ get_repo_stats(const svn_test_opts_t *op SVN_ERR(create_greek_repo(&repos, &rev, opts, REPO_NAME, pool, pool)); /* Gather statistics info on that repo. */ - SVN_ERR(svn_fs_fs__get_stats(&stats, svn_repos_fs(repos), NULL, NULL, - NULL, NULL, pool, pool)); + SVN_ERR(svn_fs_ioctl(svn_repos_fs(repos), SVN_FS_FS__IOCTL_GET_STATS, + &input, (void**)&output, NULL, NULL, pool, pool)); + stats = output->stats; /* Check that the stats make sense. */ SVN_TEST_ASSERT(stats->total_size > 1000 && stats->total_size < 10000); @@ -324,6 +327,7 @@ dump_index(const svn_test_opts_t *opts, svn_repos_t *repos; svn_revnum_t rev; dump_baton_t baton; + svn_fs_fs__ioctl_dump_index_input_t input = {0}; /* Bail (with success) on known-untestable scenarios */ if (strcmp(opts->fs_type, "fsfs") != 0) @@ -342,8 +346,12 @@ dump_index(const svn_test_opts_t *opts, baton.offset = 0; baton.revision = rev; baton.numbers_seen = svn_bit_array__create(100, pool); - SVN_ERR(svn_fs_fs__dump_index(svn_repos_fs(repos), rev, dump_index_entry, - &baton, NULL, NULL, pool)); + + input.revision = rev; + input.callback_func = dump_index_entry; + input.callback_baton = &baton; + SVN_ERR(svn_fs_ioctl(svn_repos_fs(repos), SVN_FS_FS__IOCTL_DUMP_INDEX, + &input, NULL, NULL, NULL, pool, pool)); /* Check that we've got all data (20 noderevs + 20 reps + 1 changes list). */ SVN_TEST_ASSERT(baton.invocations == 41); @@ -377,6 +385,8 @@ load_index(const svn_test_opts_t *opts, apr_array_header_t *entries = apr_array_make(pool, 41, sizeof(void *)); apr_array_header_t *alt_entries = apr_array_make(pool, 1, sizeof(void *)); svn_fs_fs__p2l_entry_t entry; + svn_fs_fs__ioctl_dump_index_input_t dump_input = {0}; + svn_fs_fs__ioctl_load_index_input_t load_input = {0}; /* Bail (with success) on known-untestable scenarios */ if (strcmp(opts->fs_type, "fsfs") != 0) @@ -391,8 +401,11 @@ load_index(const svn_test_opts_t *opts, SVN_ERR(create_greek_repo(&repos, &rev, opts, REPO_NAME, pool, pool)); /* Read the original index contents for REV in ENTRIES. */ - SVN_ERR(svn_fs_fs__dump_index(svn_repos_fs(repos), rev, receive_index, - entries, NULL, NULL, pool)); + dump_input.revision = rev; + dump_input.callback_func = receive_index; + dump_input.callback_baton = entries; + SVN_ERR(svn_fs_ioctl(svn_repos_fs(repos), SVN_FS_FS__IOCTL_DUMP_INDEX, + &dump_input, NULL, NULL, NULL, pool, pool)); /* Replace it with an index that declares the whole revision contents as * "unused". */ @@ -404,14 +417,21 @@ load_index(const svn_test_opts_t *opts, entry.item.revision = SVN_INVALID_REVNUM; APR_ARRAY_PUSH(alt_entries, svn_fs_fs__p2l_entry_t *) = &entry; - SVN_ERR(svn_fs_fs__load_index(svn_repos_fs(repos), rev, alt_entries, pool)); + load_input.revision = rev; + load_input.entries = alt_entries; + SVN_ERR(svn_fs_ioctl(svn_repos_fs(repos), SVN_FS_FS__IOCTL_LOAD_INDEX, + &load_input, NULL, NULL, NULL, pool, pool)); + SVN_TEST_ASSERT_ERROR(svn_repos_verify_fs3(repos, rev, rev, FALSE, FALSE, NULL, NULL, NULL, NULL, NULL, NULL, pool), SVN_ERR_FS_INDEX_CORRUPTION); /* Restore the original index. */ - SVN_ERR(svn_fs_fs__load_index(svn_repos_fs(repos), rev, entries, pool)); + load_input.revision = rev; + load_input.entries = entries; + SVN_ERR(svn_fs_ioctl(svn_repos_fs(repos), SVN_FS_FS__IOCTL_LOAD_INDEX, + &load_input, NULL, NULL, NULL, pool, pool)); SVN_ERR(svn_repos_verify_fs3(repos, rev, rev, FALSE, FALSE, NULL, NULL, NULL, NULL, NULL, NULL, pool)); Modified: subversion/branches/swig-py3/subversion/tests/libsvn_ra/ra-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_ra/ra-test.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_ra/ra-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_ra/ra-test.c Mon Jul 8 15:19:03 2019 @@ -94,6 +94,41 @@ commit_changes(svn_ra_session_t *session return SVN_NO_ERROR; } +/* Commit two revisions: add 'B', then delete 'A' */ +static svn_error_t * +commit_two_changes(svn_ra_session_t *session, + apr_pool_t *pool) +{ + apr_hash_t *revprop_table = apr_hash_make(pool); + const svn_delta_editor_t *editor; + void *edit_baton; + void *root_baton, *dir_baton; + + /* mkdir B */ + SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton, + revprop_table, + NULL, NULL, NULL, TRUE, pool)); + SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, + pool, &root_baton)); + SVN_ERR(editor->add_directory("B", root_baton, NULL, SVN_INVALID_REVNUM, + pool, &dir_baton)); + SVN_ERR(editor->close_directory(dir_baton, pool)); + SVN_ERR(editor->close_directory(root_baton, pool)); + SVN_ERR(editor->close_edit(edit_baton, pool)); + + /* delete A */ + SVN_ERR(svn_ra_get_commit_editor3(session, &editor, &edit_baton, + revprop_table, + NULL, NULL, NULL, TRUE, pool)); + SVN_ERR(editor->open_root(edit_baton, SVN_INVALID_REVNUM, + pool, &root_baton)); + SVN_ERR(editor->delete_entry("A", SVN_INVALID_REVNUM, root_baton, pool)); + SVN_ERR(editor->close_directory(root_baton, pool)); + SVN_ERR(editor->close_edit(edit_baton, pool)); + + return SVN_NO_ERROR; +} + static svn_error_t * commit_tree(svn_ra_session_t *session, apr_pool_t *pool) @@ -1784,6 +1819,63 @@ commit_locked_file(const svn_test_opts_t return SVN_NO_ERROR; } +/* Cases of 'get-deleted-rev' that should return SVN_INVALID_REVNUM. */ +static svn_error_t * +test_get_deleted_rev_no_delete(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_ra_session_t *ra_session; + svn_revnum_t revision_deleted; + + SVN_ERR(make_and_open_repos(&ra_session, + "test-repo-get-deleted-rev-no-delete", opts, + pool)); + SVN_ERR(commit_changes(ra_session, pool)); + SVN_ERR(commit_two_changes(ra_session, pool)); + + /* expect 'no deletion' in the range up to r2, when it is deleted in r3 */ + /* This was failing over RA-SVN where the 'get-deleted-rev' wire command's + prototype cannot directly represent that result. A new enough client and + server collaborate on a work-around implemented using an error code. */ + SVN_ERR(svn_ra_get_deleted_rev(ra_session, "A", 1, 2, + &revision_deleted, pool)); + SVN_TEST_INT_ASSERT(revision_deleted, SVN_INVALID_REVNUM); + + /* this connection should still be open: a simple case should still work */ + SVN_ERR(svn_ra_get_deleted_rev(ra_session, "A", 1, 3, + &revision_deleted, pool)); + SVN_TEST_INT_ASSERT(revision_deleted, 3); + + return SVN_NO_ERROR; +} + +/* Cases of 'get-deleted-rev' that should return an error. */ +static svn_error_t * +test_get_deleted_rev_errors(const svn_test_opts_t *opts, + apr_pool_t *pool) +{ + svn_ra_session_t *ra_session; + svn_revnum_t revision_deleted; + svn_error_t *err; + + SVN_ERR(make_and_open_repos(&ra_session, + "test-repo-get-deleted-rev-errors", opts, pool)); + SVN_ERR(commit_changes(ra_session, pool)); + + /* expect an error when searching up to r3, when repository head is r1 */ + err = svn_ra_get_deleted_rev(ra_session, "A", 1, 3, &revision_deleted, pool); + + /* mod_dav_svn returns a generic error code for "500 Internal Server Error"; + * the other RA layers return the specific error code for "no such revision". + * We should make these consistent, but for now that's how it is. */ + if (opts->repos_url && strncmp(opts->repos_url, "http", 4) == 0) + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_RA_DAV_REQUEST_FAILED); + else + SVN_TEST_ASSERT_ERROR(err, SVN_ERR_FS_NO_SUCH_REVISION); + + return SVN_NO_ERROR; +} + /* The test table. */ @@ -1820,6 +1912,10 @@ static struct svn_test_descriptor_t test "check how last change applies to empty commit"), SVN_TEST_OPTS_PASS(commit_locked_file, "check commit editor for a locked file"), + SVN_TEST_OPTS_PASS(test_get_deleted_rev_no_delete, + "test get-deleted-rev no delete"), + SVN_TEST_OPTS_PASS(test_get_deleted_rev_errors, + "test get-deleted-rev errors"), SVN_TEST_NULL }; Modified: subversion/branches/swig-py3/subversion/tests/libsvn_repos/authz-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_repos/authz-test.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_repos/authz-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_repos/authz-test.c Mon Jul 8 15:19:03 2019 @@ -212,7 +212,7 @@ test_authz_parse(const svn_test_opts_t * APR_READ, APR_OS_DEFAULT, pool)); groups = svn_stream_from_aprfile2(groups_file, FALSE, pool); - SVN_ERR(svn_authz__parse(&authz, rules, groups, pool, pool)); + SVN_ERR(svn_authz__parse(&authz, rules, groups, NULL, NULL, pool, pool)); printf("Access check for ('%s', '%s')\n", check_user, check_repo); @@ -304,7 +304,7 @@ run_global_rights_tests(const char *cont svn_stringbuf_t *buffer = svn_stringbuf_create(contents, pool); svn_stream_t *stream = svn_stream_from_stringbuf(buffer, pool); - SVN_ERR(svn_repos_authz_parse(&authz, stream, NULL, pool)); + SVN_ERR(svn_repos_authz_parse2(&authz, stream, NULL, NULL, NULL, pool, pool)); for (; test_cases->repos; ++test_cases) { @@ -463,7 +463,7 @@ issue_4741_groups(apr_pool_t *pool) svn_authz_t *authz; svn_boolean_t access_granted; - SVN_ERR(svn_repos_authz_parse(&authz, stream, NULL, pool)); + SVN_ERR(svn_repos_authz_parse2(&authz, stream, NULL, NULL, NULL, pool, pool)); SVN_ERR(svn_repos_authz_check_access(authz, "repo", "/", "userA", svn_authz_write, &access_granted, @@ -500,7 +500,7 @@ reposful_reposless_stanzas_inherit(apr_p svn_authz_t *authz; svn_boolean_t access_granted; - SVN_ERR(svn_repos_authz_parse(&authz, stream, NULL, pool)); + SVN_ERR(svn_repos_authz_parse2(&authz, stream, NULL, NULL, NULL, pool, pool)); SVN_ERR(svn_repos_authz_check_access(authz, "project1", "/foo", "user1", svn_authz_write | svn_authz_recursive, Modified: subversion/branches/swig-py3/subversion/tests/libsvn_subr/dirent_uri-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_subr/dirent_uri-test.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_subr/dirent_uri-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_subr/dirent_uri-test.c Mon Jul 8 15:19:03 2019 @@ -36,6 +36,7 @@ #include "svn_pools.h" #include "svn_dirent_uri.h" +#include "private/svn_dirent_uri_private.h" #include "private/svn_fspath.h" #include "private/svn_cert.h" @@ -2331,11 +2332,12 @@ test_relpath_internal_style(apr_pool_t * for (i = 0; i < COUNT_OF(tests); i++) { - const char *internal = svn_relpath__internal_style(tests[i].path, pool); + const char *internal; + SVN_ERR(svn_relpath__make_internal(&internal, tests[i].path, pool, pool)); if (strcmp(internal, tests[i].result)) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, - "svn_relpath__internal_style(\"%s\") returned " + "svn_relpath__make_internal(\"%s\") returned " "\"%s\" expected \"%s\"", tests[i].path, internal, tests[i].result); } Modified: subversion/branches/swig-py3/subversion/tests/libsvn_subr/io-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_subr/io-test.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_subr/io-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_subr/io-test.c Mon Jul 8 15:19:03 2019 @@ -211,6 +211,38 @@ create_comparison_candidates(struct test return err; } +/* Create an on-disk tree with optional read-only attributes on some + files and/or directories. */ +static svn_error_t * +create_dir_tree(const char **dir_path, + const char *testname, + svn_boolean_t dir_readonly, + svn_boolean_t file_readonly, + apr_pool_t *pool) +{ + const char *test_dir_path; + const char *sub_dir_path; + const char *file_path; + + SVN_ERR(svn_test_make_sandbox_dir(&test_dir_path, testname, pool)); + + sub_dir_path = svn_dirent_join(test_dir_path, "dir", pool); + SVN_ERR(svn_io_dir_make(sub_dir_path, APR_OS_DEFAULT, pool)); + + file_path = svn_dirent_join(sub_dir_path, "file", pool); + SVN_ERR(svn_io_file_create_empty(file_path, pool)); + + if (file_readonly) + SVN_ERR(svn_io_set_file_read_only(file_path, FALSE, pool)); + + if (dir_readonly) + SVN_ERR(svn_io_set_file_read_only(sub_dir_path, FALSE, pool)); + + *dir_path = sub_dir_path; + return SVN_NO_ERROR; +} + + /* Functions to check the 2-way and 3-way file comparison functions. */ @@ -1147,6 +1179,56 @@ test_apr_trunc_workaround(apr_pool_t *po return SVN_NO_ERROR; } + +/* Issue #4806 */ +static svn_error_t * +test_rmtree_all_writable(apr_pool_t *pool) +{ + const char *dir_path = NULL; + + SVN_ERR(create_dir_tree(&dir_path, "test_rmtree_all_writable", + FALSE, FALSE, pool)); + SVN_ERR(svn_io_remove_dir2(dir_path, FALSE, NULL, NULL, pool)); + return SVN_NO_ERROR; +} + +/* Issue #4806 */ +static svn_error_t * +test_rmtree_file_readonly(apr_pool_t *pool) +{ + const char *dir_path = NULL; + + SVN_ERR(create_dir_tree(&dir_path, "test_rmtree_file_readonly", + FALSE, TRUE, pool)); + SVN_ERR(svn_io_remove_dir2(dir_path, FALSE, NULL, NULL, pool)); + return SVN_NO_ERROR; +} + +/* Issue #4806 */ +static svn_error_t * +test_rmtree_dir_readonly(apr_pool_t *pool) +{ + const char *dir_path = NULL; + + SVN_ERR(create_dir_tree(&dir_path, "test_rmtree_dir_readonly", + TRUE, FALSE, pool)); + SVN_ERR(svn_io_remove_dir2(dir_path, FALSE, NULL, NULL, pool)); + return SVN_NO_ERROR; +} + +/* Issue #4806 */ +static svn_error_t * +test_rmtree_all_readonly(apr_pool_t *pool) +{ + const char *dir_path = NULL; + + SVN_ERR(create_dir_tree(&dir_path, "test_rmtree_all_readonly", + TRUE, TRUE, pool)); + SVN_ERR(svn_io_remove_dir2(dir_path, FALSE, NULL, NULL, pool)); + return SVN_NO_ERROR; +} + + /* The test table. */ static int max_threads = 3; @@ -1184,6 +1266,14 @@ static struct svn_test_descriptor_t test "test svn_io_open_uniquely_named()"), SVN_TEST_PASS2(test_apr_trunc_workaround, "test workaround for APR in svn_io_file_trunc"), + SVN_TEST_PASS2(test_rmtree_all_writable, + "test svn_io_remove_dir2() with writable tree"), + SVN_TEST_PASS2(test_rmtree_file_readonly, + "test svn_io_remove_dir2() with read-only file"), + SVN_TEST_PASS2(test_rmtree_dir_readonly, + "test svn_io_remove_dir2() with read-only directory"), + SVN_TEST_PASS2(test_rmtree_all_readonly, + "test svn_io_remove_dir2() with read-only tree"), SVN_TEST_NULL }; Modified: subversion/branches/swig-py3/subversion/tests/libsvn_wc/wc-queries-test.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/subversion/tests/libsvn_wc/wc-queries-test.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/subversion/tests/libsvn_wc/wc-queries-test.c (original) +++ subversion/branches/swig-py3/subversion/tests/libsvn_wc/wc-queries-test.c Mon Jul 8 15:19:03 2019 @@ -100,6 +100,7 @@ static const int slow_statements[] = STMT_SELECT_UPDATE_MOVE_LIST, STMT_FIND_REPOS_PATH_IN_WC, STMT_SELECT_PRESENT_HIGHEST_WORKING_NODES_BY_BASENAME_AND_KIND, + STMT_SELECT_COPIES_OF_REPOS_RELPATH, /* Designed as slow to avoid penalty on other queries */ STMT_SELECT_UNREFERENCED_PRISTINES, @@ -266,6 +267,14 @@ struct explanation_item const char *compound_right; svn_boolean_t create_btree; + svn_boolean_t create_union; + svn_boolean_t union_all; + + svn_boolean_t merge; + + svn_boolean_t multi_index; + svn_boolean_t multi_index_or; + int expression_vars; int expected_rows; }; @@ -312,6 +321,18 @@ parse_explanation_item(struct explanatio item->table = apr_psprintf(result_pool, "SUBQUERY-%s", apr_strtok(NULL, " ", &last)); } + else if (MATCH_TOKEN(token, "CONSTANT")) + { + item->table = "sqlite_master"; /* not worth checking. + Just a lookup */ + token = apr_strtok(NULL, " ", &last); + if (!MATCH_TOKEN(token, "ROW")) + { + printf("DBG: Expected 'ROW', got '%s' in '%s'\n", + token, text); + return SVN_NO_ERROR; + } + } else { printf("DBG: Expected 'TABLE', got '%s' in '%s'\n", token, text); @@ -433,39 +454,44 @@ parse_explanation_item(struct explanatio /* Handling temporary table (E.g. UNION) */ token = apr_strtok(NULL, " ", &last); - if (!MATCH_TOKEN(token, "SUBQUERIES")) - { - printf("DBG: Expected 'SUBQUERIES', got '%s' in '%s'\n", token, - text); - return SVN_NO_ERROR; - } - - item->compound_left = apr_strtok(NULL, " ", &last); - token = apr_strtok(NULL, " ", &last); - - if (!MATCH_TOKEN(token, "AND")) - { - printf("DBG: Expected 'AND', got '%s' in '%s'\n", token, text); - return SVN_NO_ERROR; - } - - item->compound_right = apr_strtok(NULL, " ", &last); - - token = apr_strtok(NULL, " ", &last); - if (MATCH_TOKEN(token, "USING")) + if (MATCH_TOKEN(token, "SUBQUERIES")) { + item->compound_left = apr_strtok(NULL, " ", &last); token = apr_strtok(NULL, " ", &last); - if (!MATCH_TOKEN(token, "TEMP")) + + if (!MATCH_TOKEN(token, "AND")) { - printf("DBG: Expected 'TEMP', got '%s' in '%s'\n", token, text); + printf("DBG: Expected 'AND', got '%s' in '%s'\n", token, text); + return SVN_NO_ERROR; } + + item->compound_right = apr_strtok(NULL, " ", &last); + token = apr_strtok(NULL, " ", &last); - if (!MATCH_TOKEN(token, "B-TREE")) + if (MATCH_TOKEN(token, "USING")) { - printf("DBG: Expected 'B-TREE', got '%s' in '%s'\n", token, - text); + token = apr_strtok(NULL, " ", &last); + if (!MATCH_TOKEN(token, "TEMP")) + { + printf("DBG: Expected 'TEMP', got '%s' in '%s'\n", token, text); + } + token = apr_strtok(NULL, " ", &last); + if (!MATCH_TOKEN(token, "B-TREE")) + { + printf("DBG: Expected 'B-TREE', got '%s' in '%s'\n", token, + text); + } + item->create_btree = TRUE; } - item->create_btree = TRUE; + } + else if (MATCH_TOKEN(token, "QUERY")) + { + } + else + { + printf("DBG: Expected 'SUBQUERIES', got '%s' in '%s'\n", token, + text); + return SVN_NO_ERROR; } } else if (MATCH_TOKEN(item->operation, "USE")) @@ -474,6 +500,48 @@ parse_explanation_item(struct explanatio /* ### Need parsing */ item->create_btree = TRUE; } + else if (MATCH_TOKEN(item->operation, "UNION")) + { + item->create_union = TRUE; + + token = apr_strtok(NULL, " ", &last); + if (MATCH_TOKEN(token, "ALL")) + item->union_all = TRUE; + else + item->union_all = FALSE; + } + else if (MATCH_TOKEN(item->operation, "INDEX")) + { + + } + else if (MATCH_TOKEN(item->operation, "MULTI-INDEX")) + { + item->multi_index = TRUE; + token = apr_strtok(NULL, " ", &last); + if (MATCH_TOKEN(token, "OR")) + item->multi_index_or = TRUE; + } + else if (MATCH_TOKEN(item->operation, "MERGE")) + { + item->merge = TRUE; + } + else if (MATCH_TOKEN(item->operation, "LEFT") + || MATCH_TOKEN(item->operation, "RIGHT")) + { + } + else if (MATCH_TOKEN(item->operation, "CORRELATED")) + { + item->merge = TRUE; + } + else if (MATCH_TOKEN(item->operation, "CO-ROUTINE")) + { + } + else if (MATCH_TOKEN(item->operation, "SCALAR")) + { + } + else if (MATCH_TOKEN(item->operation, "LEFT-MOST")) + { + } else { printf("DBG: Unhandled sqlite operation '%s' in explanation\n", item->operation); @@ -670,7 +738,20 @@ test_query_expectations(apr_pool_t *scra || (item->expression_vars < 1)) && !is_result_table(item->table)) { - if (in_list(primary_key_statements, i)) + if (MATCH_TOKEN(item->table, "sqlite_master")) + { + /* The sqlite_master table does not have an index. + Query explanations that say 'SCAN TABLE sqlite_master' + will appear if SQLite was compiled with the option + SQLITE_ENABLE_STMT_SCANSTATUS, for queries such + as 'DROP TABLE foo', but the performance of such + statements is not our concern here. */ + + /* "Slow" statements do expect too see a warning, however. */ + if (is_slow_statement(i)) + warned = TRUE; + } + else if (in_list(primary_key_statements, i)) { /* Reported as primary key index usage in Sqlite 3.7, as table scan in 3.8+, while the execution plan is Modified: subversion/branches/swig-py3/tools/client-side/bash_completion URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/client-side/bash_completion?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/client-side/bash_completion (original) +++ subversion/branches/swig-py3/tools/client-side/bash_completion Mon Jul 8 15:19:03 2019 @@ -1139,7 +1139,7 @@ _svnadmin () # Possible expansions, without pure-prefix abbreviations such as "h". cmds='crashtest create delrevprop deltify dump dump-revprops freeze \ help hotcopy info list-dblogs list-unused-dblogs \ - load load-revprops lock lslocks lstxns pack recover rmlocks \ + load load-revprops lock lslocks lstxns pack recover rev-size rmlocks \ rmtxns setlog setrevprop setuuid unlock upgrade verify --version' if [[ $COMP_CWORD -eq 1 ]] ; then @@ -1211,6 +1211,9 @@ _svnadmin () recover) cmdOpts="--wait" ;; + rev-size) + cmdOpts="-r --revision -M --memory-cache-size -q --quiet" + ;; rmlocks) cmdOpts="-q --quiet" ;; Modified: subversion/branches/swig-py3/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c (original) +++ subversion/branches/swig-py3/tools/client-side/svn-mergeinfo-normalizer/svn-mergeinfo-normalizer.c Mon Jul 8 15:19:03 2019 @@ -566,7 +566,8 @@ sub_main(int *exit_code, int argc, const break; case opt_config_dir: SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); - opt_state.config_dir = svn_dirent_internal_style(utf8_opt_arg, pool); + SVN_ERR(svn_dirent_internal_style_safe(&opt_state.config_dir, NULL, + utf8_opt_arg, pool, pool)); break; case opt_config_options: if (!opt_state.config_options) Modified: subversion/branches/swig-py3/tools/client-side/svnconflict/svnconflict.c URL: http://svn.apache.org/viewvc/subversion/branches/swig-py3/tools/client-side/svnconflict/svnconflict.c?rev=1862754&r1=1862753&r2=1862754&view=diff ============================================================================== --- subversion/branches/swig-py3/tools/client-side/svnconflict/svnconflict.c (original) +++ subversion/branches/swig-py3/tools/client-side/svnconflict/svnconflict.c Mon Jul 8 15:19:03 2019 @@ -717,7 +717,8 @@ sub_main(int *exit_code, int argc, const break; case opt_config_dir: SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool)); - opt_state.config_dir = svn_dirent_internal_style(utf8_opt_arg, pool); + SVN_ERR(svn_dirent_internal_style_safe(&opt_state.config_dir, NULL, + utf8_opt_arg, pool, pool)); break; case opt_config_options: if (!opt_state.config_options)