#!/usr/bin/env python # -*- coding: utf-8 -*- # # diff_tests.py: some basic diff tests # # 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 sys, re, os, time, shutil, logging logger = logging.getLogger() # Our testing module import svntest from svntest import err, wc from prop_tests import binary_mime_type_on_text_file_warning from svntest.verify import make_diff_header, make_no_diff_deleted_header, \ 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 = svntest.wc.StateItem ###################################################################### # Generate expected output ###################################################################### # Diff output checker # # Looks for the correct filenames and a suitable number of +/- lines # depending on whether this is an addition, modification or deletion. def check_diff_output(diff_output, name, diff_type): "check diff output" # On Windows, diffs still display / rather than \ in paths if svntest.main.windows == 1: name = name.replace('\\', '/') i_re = re.compile('^Index:') d_re = re.compile('^Index: (\\./)?' + name) p_re = re.compile('^--- (\\./)?' + name) add_re = re.compile('^\\+') sub_re = re.compile('^-') i = 0 while i < len(diff_output) - 4: # identify a possible diff if (d_re.match(diff_output[i]) and p_re.match(diff_output[i+2])): # count lines added and deleted i += 4 add_lines = 0 sub_lines = 0 while i < len(diff_output) and not i_re.match(diff_output[i]): if add_re.match(diff_output[i][0]): add_lines += 1 if sub_re.match(diff_output[i][0]): sub_lines += 1 i += 1 #print "add:", add_lines #print "sub:", sub_lines # check if this looks like the right sort of diff if add_lines > 0 and sub_lines == 0 and diff_type == 'A': return 0 if sub_lines > 0 and add_lines == 0 and diff_type == 'D': return 0 if add_lines > 0 and sub_lines > 0 and diff_type == 'M': return 0 else: i += 1 # no suitable diff found return 1 def count_diff_output(diff_output): "count the number of file diffs in the output" i_re = re.compile('Index:') diff_count = 0 i = 0 while i < len(diff_output) - 4: if i_re.match(diff_output[i]): i += 4 diff_count += 1 else: i += 1 return diff_count def verify_expected_output(diff_output, expected): "verify given line exists in diff output" for line in diff_output: if line.find(expected) != -1: break else: raise svntest.Failure def verify_excluded_output(diff_output, excluded): "verify given line does not exist in diff output as diff line" for line in diff_output: if re.match("^(\\+|-)%s" % re.escape(excluded), line): logger.warn('Sought: %s' % excluded) logger.warn('Found: %s' % line) raise svntest.Failure def extract_diff_path(line): l2 = line[(line.find("(")+1):] l3 = l2[0:(l2.find(")"))] return l3 ###################################################################### # diff on a repository subset and check the output def diff_check_repo_subset(wc_dir, repo_subset, check_fn, do_diff_r): "diff and check for part of the repository" was_cwd = os.getcwd() os.chdir(wc_dir) exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', repo_subset) if check_fn(diff_output): return 1 if do_diff_r: exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', 'HEAD', repo_subset) if check_fn(diff_output): return 1 os.chdir(was_cwd) return 0 ###################################################################### # Changes makers and change checkers def update_a_file(): "update a file" svntest.main.file_write(os.path.join('A', 'B', 'E', 'alpha'), "new atext") # svntest.main.file_append(, "new atext") return 0 def check_update_a_file(diff_output): "check diff for update a file" return check_diff_output(diff_output, os.path.join('A', 'B', 'E', 'alpha'), 'M') def diff_check_update_a_file_repo_subset(wc_dir): "diff and check update a file for a repository subset" repo_subset = os.path.join('A', 'B') if diff_check_repo_subset(wc_dir, repo_subset, check_update_a_file, 1): return 1 repo_subset = os.path.join('A', 'B', 'E', 'alpha') if diff_check_repo_subset(wc_dir, repo_subset, check_update_a_file, 1): return 1 return 0 #---------------------------------------------------------------------- def add_a_file(): "add a file" svntest.main.file_append(os.path.join('A', 'B', 'E', 'theta'), "theta") svntest.main.run_svn(None, 'add', os.path.join('A', 'B', 'E', 'theta')) return 0 def check_add_a_file(diff_output): "check diff for add a file" return check_diff_output(diff_output, os.path.join('A', 'B', 'E', 'theta'), 'A') def check_add_a_file_reverse(diff_output): "check diff for add a file" return check_diff_output(diff_output, os.path.join('A', 'B', 'E', 'theta'), 'D') def diff_check_add_a_file_repo_subset(wc_dir): "diff and check add a file for a repository subset" repo_subset = os.path.join('A', 'B') if diff_check_repo_subset(wc_dir, repo_subset, check_add_a_file, 1): return 1 repo_subset = os.path.join('A', 'B', 'E', 'theta') ### TODO: diff -r HEAD doesn't work for added file if diff_check_repo_subset(wc_dir, repo_subset, check_add_a_file, 0): return 1 def update_added_file(): svntest.main.file_append(os.path.join('A', 'B', 'E', 'theta'), "net ttext") "update added file" return 0 def check_update_added_file(diff_output): "check diff for update of added file" return check_diff_output(diff_output, os.path.join('A', 'B', 'E', 'theta'), 'M') #---------------------------------------------------------------------- def add_a_file_in_a_subdir(): "add a file in a subdir" os.mkdir(os.path.join('A', 'B', 'T')) svntest.main.run_svn(None, 'add', os.path.join('A', 'B', 'T')) svntest.main.file_append(os.path.join('A', 'B', 'T', 'phi'), "phi") svntest.main.run_svn(None, 'add', os.path.join('A', 'B', 'T', 'phi')) return 0 def check_add_a_file_in_a_subdir(diff_output): "check diff for add a file in a subdir" return check_diff_output(diff_output, os.path.join('A', 'B', 'T', 'phi'), 'A') def check_add_a_file_in_a_subdir_reverse(diff_output): "check diff for add a file in a subdir" return check_diff_output(diff_output, os.path.join('A', 'B', 'T', 'phi'), 'D') def diff_check_add_a_file_in_a_subdir_repo_subset(wc_dir): "diff and check add a file in a subdir for a repository subset" repo_subset = os.path.join('A', 'B', 'T') ### TODO: diff -r HEAD doesn't work for added subdir if diff_check_repo_subset(wc_dir, repo_subset, check_add_a_file_in_a_subdir, 0): return 1 repo_subset = os.path.join('A', 'B', 'T', 'phi') ### TODO: diff -r HEAD doesn't work for added file in subdir if diff_check_repo_subset(wc_dir, repo_subset, check_add_a_file_in_a_subdir, 0): return 1 #---------------------------------------------------------------------- def replace_a_file(): "replace a file" svntest.main.run_svn(None, 'rm', os.path.join('A', 'D', 'G', 'rho')) svntest.main.file_append(os.path.join('A', 'D', 'G', 'rho'), "new rho") svntest.main.run_svn(None, 'add', os.path.join('A', 'D', 'G', 'rho')) return 0 def check_replace_a_file(diff_output): "check diff for replace a file" return check_diff_output(diff_output, os.path.join('A', 'D', 'G', 'rho'), 'M') #---------------------------------------------------------------------- def update_three_files(): "update three files" svntest.main.file_write(os.path.join('A', 'D', 'gamma'), "new gamma") svntest.main.file_write(os.path.join('A', 'D', 'G', 'tau'), "new tau") svntest.main.file_write(os.path.join('A', 'D', 'H', 'psi'), "new psi") return 0 def check_update_three_files(diff_output): "check update three files" if check_diff_output(diff_output, os.path.join('A', 'D', 'gamma'), 'M'): return 1 if check_diff_output(diff_output, os.path.join('A', 'D', 'G', 'tau'), 'M'): return 1 if check_diff_output(diff_output, os.path.join('A', 'D', 'H', 'psi'), 'M'): return 1 return 0 ###################################################################### # make a change, check the diff, commit the change, check the diff def change_diff_commit_diff(wc_dir, revision, change_fn, check_fn): "make a change, diff, commit, update and diff again" was_cwd = os.getcwd() os.chdir(wc_dir) svntest.main.run_svn(None, 'up', '-r', 'HEAD') change_fn() # diff without revision doesn't use an editor exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff') if check_fn(diff_output): raise svntest.Failure # diff with revision runs an editor exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', 'HEAD') if check_fn(diff_output): raise svntest.Failure svntest.main.run_svn(None, 'ci', '-m', 'log msg') svntest.main.run_svn(None, 'up') exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', revision) if check_fn(diff_output): raise svntest.Failure os.chdir(was_cwd) ###################################################################### # check the diff def just_diff(wc_dir, rev_check, check_fn): "update and check that the given diff is seen" was_cwd = os.getcwd() os.chdir(wc_dir) exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', rev_check) if check_fn(diff_output): raise svntest.Failure os.chdir(was_cwd) ###################################################################### # update, check the diff def update_diff(wc_dir, rev_up, rev_check, check_fn): "update and check that the given diff is seen" was_cwd = os.getcwd() os.chdir(wc_dir) svntest.main.run_svn(None, 'up', '-r', rev_up) os.chdir(was_cwd) just_diff(wc_dir, rev_check, check_fn) ###################################################################### # check a pure repository rev1:rev2 diff def repo_diff(wc_dir, rev1, rev2, check_fn): "check that the given pure repository diff is seen" was_cwd = os.getcwd() os.chdir(wc_dir) exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', repr(rev2) + ':' + repr(rev1)) if check_fn(diff_output): raise svntest.Failure os.chdir(was_cwd) ###################################################################### # Tests # # test 1 def diff_update_a_file(sbox): "update a file" sbox.build() change_diff_commit_diff(sbox.wc_dir, 1, update_a_file, check_update_a_file) # test 2 def diff_add_a_file(sbox): "add a file" sbox.build() change_diff_commit_diff(sbox.wc_dir, 1, add_a_file, check_add_a_file) #test 3 def diff_add_a_file_in_a_subdir(sbox): "add a file in an added directory" sbox.build() change_diff_commit_diff(sbox.wc_dir, 1, add_a_file_in_a_subdir, check_add_a_file_in_a_subdir) # test 4 def diff_replace_a_file(sbox): "replace a file with a file" sbox.build() change_diff_commit_diff(sbox.wc_dir, 1, replace_a_file, check_replace_a_file) # test 5 def diff_multiple_reverse(sbox): "multiple revisions diff'd forwards and backwards" sbox.build() wc_dir = sbox.wc_dir # rev 2 change_diff_commit_diff(wc_dir, 1, add_a_file, check_add_a_file) #rev 3 change_diff_commit_diff(wc_dir, 2, add_a_file_in_a_subdir, check_add_a_file_in_a_subdir) #rev 4 change_diff_commit_diff(wc_dir, 3, update_a_file, check_update_a_file) # check diffs both ways update_diff(wc_dir, 4, 1, check_update_a_file) just_diff(wc_dir, 1, check_add_a_file_in_a_subdir) just_diff(wc_dir, 1, check_add_a_file) update_diff(wc_dir, 1, 4, check_update_a_file) just_diff(wc_dir, 4, check_add_a_file_in_a_subdir_reverse) just_diff(wc_dir, 4, check_add_a_file_reverse) # check pure repository diffs repo_diff(wc_dir, 4, 1, check_update_a_file) repo_diff(wc_dir, 4, 1, check_add_a_file_in_a_subdir) repo_diff(wc_dir, 4, 1, check_add_a_file) repo_diff(wc_dir, 1, 4, check_update_a_file) repo_diff(wc_dir, 1, 4, check_add_a_file_in_a_subdir_reverse) repo_diff(wc_dir, 1, 4, check_add_a_file_reverse) # test 6 def diff_non_recursive(sbox): "non-recursive behaviour" sbox.build() wc_dir = sbox.wc_dir change_diff_commit_diff(wc_dir, 1, update_three_files, check_update_three_files) # The changes are in: ./A/D/gamma # ./A/D/G/tau # ./A/D/H/psi # When checking D recursively there are three changes. When checking # D non-recursively there is only one change. When checking G # recursively, there is only one change even though D is the anchor # full diff has three changes exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', sbox.ospath('A/D')) if count_diff_output(diff_output) != 3: raise svntest.Failure # non-recursive has one change exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', '-N', sbox.ospath('A/D')) if count_diff_output(diff_output) != 1: raise svntest.Failure # diffing a directory doesn't pick up other diffs in the anchor exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', sbox.ospath('A/D/G')) if count_diff_output(diff_output) != 1: raise svntest.Failure # test 7 def diff_repo_subset(sbox): "diff only part of the repository" sbox.build() wc_dir = sbox.wc_dir was_cwd = os.getcwd() os.chdir(wc_dir) update_a_file() add_a_file() add_a_file_in_a_subdir() os.chdir(was_cwd) if diff_check_update_a_file_repo_subset(wc_dir): raise svntest.Failure if diff_check_add_a_file_repo_subset(wc_dir): raise svntest.Failure if diff_check_add_a_file_in_a_subdir_repo_subset(wc_dir): raise svntest.Failure # test 8 def diff_non_version_controlled_file(sbox): "non version controlled files" sbox.build() wc_dir = sbox.wc_dir svntest.main.file_append(sbox.ospath('A/D/foo'), "a new file") svntest.actions.run_and_verify_svn(None, 'svn: E155010: .*foo\' was not found.', 'diff', sbox.ospath('A/D/foo')) # test 9 def diff_pure_repository_update_a_file(sbox): "pure repository diff update a file" sbox.build() wc_dir = sbox.wc_dir os.chdir(wc_dir) # rev 2 update_a_file() svntest.main.run_svn(None, 'ci', '-m', 'log msg') # rev 3 add_a_file_in_a_subdir() svntest.main.run_svn(None, 'ci', '-m', 'log msg') # rev 4 add_a_file() svntest.main.run_svn(None, 'ci', '-m', 'log msg') # rev 5 update_added_file() svntest.main.run_svn(None, 'ci', '-m', 'log msg') svntest.main.run_svn(None, 'up', '-r', '2') url = sbox.repo_url exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-c', '2', url) if check_update_a_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1:2') if check_update_a_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-c', '3', url) if check_add_a_file_in_a_subdir(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '2:3') if check_add_a_file_in_a_subdir(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-c', '5', url) if check_update_added_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '4:5') if check_update_added_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', 'head') if check_add_a_file_in_a_subdir_reverse(diff_output): raise svntest.Failure # test 10 def diff_only_property_change(sbox): "diff when property was changed but text was not" sbox.build() wc_dir = sbox.wc_dir expected_output = \ make_diff_header("iota", "revision 1", "revision 2") + \ make_diff_prop_header("iota") + \ make_diff_prop_added("svn:eol-style", "native") expected_reverse_output = \ make_diff_header("iota", "revision 2", "revision 1") + \ make_diff_prop_header("iota") + \ make_diff_prop_deleted("svn:eol-style", "native") expected_rev1_output = \ make_diff_header("iota", "revision 1", "working copy") + \ make_diff_prop_header("iota") + \ make_diff_prop_added("svn:eol-style", "native") os.chdir(sbox.wc_dir) svntest.actions.run_and_verify_svn(None, [], 'propset', 'svn:eol-style', 'native', 'iota') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'empty-msg') svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r', '1:2') svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-c', '2') svntest.actions.run_and_verify_svn(expected_reverse_output, [], 'diff', '-r', '2:1') svntest.actions.run_and_verify_svn(expected_reverse_output, [], 'diff', '-c', '-2') svntest.actions.run_and_verify_svn(expected_rev1_output, [], 'diff', '-r', '1') svntest.actions.run_and_verify_svn(expected_rev1_output, [], 'diff', '-r', 'PREV', 'iota') #---------------------------------------------------------------------- # Regression test for issue #1019: make sure we don't try to display # diffs when the file is marked as a binary type. This tests all 3 # uses of 'svn diff': wc-wc, wc-repos, repos-repos. @Issue(1019) def dont_diff_binary_file(sbox): "don't diff file marked as binary type" sbox.build() wc_dir = sbox.wc_dir # Add a binary file to the project. theta_contents = open(os.path.join(sys.path[0], "theta.bin"), 'rb').read() # Write PNG file data into 'A/theta'. theta_path = sbox.ospath('A/theta') svntest.main.file_write(theta_path, theta_contents, 'wb') svntest.main.run_svn(None, 'add', theta_path) # Created expected output tree for 'svn ci' expected_output = svntest.wc.State(wc_dir, { 'A/theta' : Item(verb='Adding (bin)'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'A/theta' : Item(status=' ', wc_rev=2), }) # Commit the new binary file, creating revision 2. svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # Update the whole working copy to HEAD (rev 2) expected_output = svntest.wc.State(wc_dir, {}) expected_disk = svntest.main.greek_state.copy() expected_disk.add({ 'A/theta' : Item(theta_contents, props={'svn:mime-type' : 'application/octet-stream'}), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'A/theta' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status, check_props=True) # Make a local mod to the binary file. svntest.main.file_append(theta_path, "some extra junk") # First diff use-case: plain old 'svn diff wc' will display any # local changes in the working copy. (diffing working # vs. text-base) re_nodisplay = re.compile('^Cannot display:') exit_code, stdout, stderr = svntest.main.run_svn(None, 'diff', wc_dir) for line in stdout: if (re_nodisplay.match(line)): break else: raise svntest.Failure # Second diff use-case: 'svn diff -r1 wc' compares the wc against a # the first revision in the repository. exit_code, stdout, stderr = svntest.main.run_svn(None, 'diff', '-r', '1', wc_dir) for line in stdout: if (re_nodisplay.match(line)): break else: raise svntest.Failure # Now commit the local mod, creating rev 3. expected_output = svntest.wc.State(wc_dir, { 'A/theta' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.add({ 'A/theta' : Item(status=' ', wc_rev=3), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # Third diff use-case: 'svn diff -r2:3 wc' will compare two # repository trees. exit_code, stdout, stderr = svntest.main.run_svn(None, 'diff', '-r', '2:3', wc_dir) for line in stdout: if (re_nodisplay.match(line)): break else: raise svntest.Failure def diff_nonextant_urls(sbox): "svn diff errors against a non-existent URL" sbox.build(create_wc = False) non_extant_url = sbox.repo_url + '/A/does_not_exist' extant_url = sbox.repo_url + '/A/mu' exit_code, diff_output, err_output = svntest.main.run_svn( 1, 'diff', '--old', non_extant_url, '--new', extant_url) for line in err_output: if re.search('was not found in the repository at revision', line): break else: raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn( 1, 'diff', '--old', extant_url, '--new', non_extant_url) for line in err_output: if re.search('was not found in the repository at revision', line): break else: raise svntest.Failure def diff_head_of_moved_file(sbox): "diff against the head of a moved file" sbox.build() mu_path = sbox.ospath('A/mu') new_mu_path = mu_path + '.new' svntest.main.run_svn(None, 'mv', mu_path, new_mu_path) # Modify the file to ensure that the diff is non-empty. svntest.main.file_append(new_mu_path, "\nActually, it's a new mu.") mu_new = sbox.ospath('A/mu.new').replace('\\','/') expected_output = [ 'Index: %s\n' % mu_new, '===================================================================\n', '--- %s\t(.../mu)\t(revision 1)\n' % mu_new, '+++ %s\t(.../mu.new)\t(working copy)\n' % mu_new, '@@ -1 +1,3 @@\n', ' This is the file \'mu\'.\n', '+\n', '+Actually, it\'s a new mu.\n', '\ No newline at end of file\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r', 'HEAD', new_mu_path) #---------------------------------------------------------------------- # Regression test for issue #977: make 'svn diff -r BASE:N' compare a # repository tree against the wc's text-bases, rather than the wc's # working files. This is a long test, which checks many variations. @Issue(977) def diff_base_to_repos(sbox): "diff text-bases against repository" sbox.build() wc_dir = sbox.wc_dir iota_path = sbox.ospath('iota') newfile_path = sbox.ospath('A/D/newfile') mu_path = sbox.ospath('A/mu') # Make changes to iota, commit r2, update to HEAD (r2). svntest.main.file_append(iota_path, "some rev2 iota text.\n") expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('iota', wc_rev=2) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) expected_output = svntest.wc.State(wc_dir, {}) expected_disk = svntest.main.greek_state.copy() expected_disk.tweak('iota', contents=\ "This is the file 'iota'.\nsome rev2 iota text.\n") expected_status = svntest.actions.get_virginal_state(wc_dir, 2) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) # Now make another local mod to iota. svntest.main.file_append(iota_path, "an iota local mod.\n") # If we run 'svn diff -r 1', we should see diffs that include *both* # the rev2 changes and local mods. That's because the working files # are being compared to the repository. exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', '1', wc_dir) # Makes diff output look the same on all platforms. def strip_eols(lines): return [x.replace("\r", "").replace("\n", "") for x in lines] expected_output_lines = make_diff_header(iota_path, "revision 1", "working copy") + [ "@@ -1 +1,3 @@\n", " This is the file 'iota'.\n", "+some rev2 iota text.\n", "+an iota local mod.\n"] if strip_eols(diff_output) != strip_eols(expected_output_lines): raise svntest.Failure # If we run 'svn diff -r BASE:1', we should see diffs that only show # the rev2 changes and NOT the local mods. That's because the # text-bases are being compared to the repository. exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', 'BASE:1', wc_dir) expected_output_lines = make_diff_header(iota_path, "working copy", "revision 1") + [ "@@ -1,2 +1 @@\n", " This is the file 'iota'.\n", "-some rev2 iota text.\n"] if strip_eols(diff_output) != strip_eols(expected_output_lines): raise svntest.Failure # But that's not all folks... no, no, we're just getting started # here! There are so many other tests to do. # For example, we just ran 'svn diff -rBASE:1'. The output should # look exactly the same as 'svn diff -r2:1'. (If you remove the # header commentary) exit_code, diff_output2, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', '2:1', wc_dir) diff_output[2:4] = [] diff_output2[2:4] = [] if (diff_output2 != diff_output): raise svntest.Failure # and similarly, does 'svn diff -r1:2' == 'svn diff -r1:BASE' ? exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', '1:2', wc_dir) exit_code, diff_output2, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', '1:BASE', wc_dir) diff_output[2:4] = [] diff_output2[2:4] = [] if (diff_output2 != diff_output): raise svntest.Failure # Now we schedule an addition and a deletion. svntest.main.file_append(newfile_path, "Contents of newfile\n") svntest.main.run_svn(None, 'add', newfile_path) svntest.main.run_svn(None, 'rm', mu_path) expected_output = svntest.actions.get_virginal_state(wc_dir, 2) expected_output.add({ 'A/D/newfile' : Item(status='A ', wc_rev=0), }) expected_output.tweak('A/mu', status='D ') expected_output.tweak('iota', status='M ') svntest.actions.run_and_verify_status(wc_dir, expected_output) # once again, verify that -r1:2 and -r1:BASE look the same, as do # -r2:1 and -rBASE:1. None of these diffs should mention the # scheduled addition or deletion. exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', '1:2', wc_dir) exit_code, diff_output2, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', '1:BASE', wc_dir) exit_code, diff_output3, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', '2:1', wc_dir) exit_code, diff_output4, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', 'BASE:1', wc_dir) diff_output[2:4] = [] diff_output2[2:4] = [] diff_output3[2:4] = [] diff_output4[2:4] = [] if (diff_output != diff_output2): raise svntest.Failure if (diff_output3 != diff_output4): raise svntest.Failure # Great! So far, so good. Now we commit our three changes (a local # mod, an addition, a deletion) and update to HEAD (r3). expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), 'A/mu' : Item(verb='Deleting'), 'A/D/newfile' : Item(verb='Adding') }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.tweak('iota', wc_rev=3) expected_status.remove('A/mu') expected_status.add({ 'A/D/newfile' : Item(status=' ', wc_rev=3), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) expected_output = svntest.wc.State(wc_dir, {}) expected_disk = svntest.main.greek_state.copy() expected_disk.tweak('iota', contents="This is the file 'iota'.\n" + \ "some rev2 iota text.\nan iota local mod.\n") expected_disk.add({'A/D/newfile' : Item("Contents of newfile\n")}) expected_disk.remove('A/mu') expected_status = svntest.actions.get_virginal_state(wc_dir, 3) expected_status.remove('A/mu') expected_status.add({ 'A/D/newfile' : Item(status=' ', wc_rev=3), }) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) # Now 'svn diff -r3:2' should == 'svn diff -rBASE:2', showing the # removal of changes to iota, the adding of mu, and deletion of newfile. exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', '3:2', wc_dir) exit_code, diff_output2, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', 'BASE:2', wc_dir) # to do the comparison, remove all output lines starting with +++ or --- re_infoline = re.compile('^(\+\+\+|---).*$') list1 = [] list2 = [] for line in diff_output: if not re_infoline.match(line): list1.append(line) for line in diff_output2: if not re_infoline.match(line): list2.append(line) # Two files in diff may be in any order. list1 = svntest.verify.UnorderedOutput(list1) svntest.verify.compare_and_display_lines('', '', list1, list2) #---------------------------------------------------------------------- # This is a simple regression test for issue #891, whereby ra_neon's # REPORT request would fail, because the object no longer exists in HEAD. @Issue(891) def diff_deleted_in_head(sbox): "repos-repos diff on item deleted from HEAD" sbox.build() wc_dir = sbox.wc_dir A_path = sbox.ospath('A') mu_path = sbox.ospath('A/mu') # Make a change to mu, commit r2, update. svntest.main.file_append(mu_path, "some rev2 mu text.\n") expected_output = svntest.wc.State(wc_dir, { 'A/mu' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('A/mu', wc_rev=2) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) expected_output = svntest.wc.State(wc_dir, {}) expected_disk = svntest.main.greek_state.copy() expected_disk.tweak('A/mu', contents="This is the file 'mu'.\nsome rev2 mu text.\n") expected_status = svntest.actions.get_virginal_state(wc_dir, 2) svntest.actions.run_and_verify_update(wc_dir, expected_output, expected_disk, expected_status) # Now delete the whole directory 'A', and commit as r3. svntest.main.run_svn(None, 'rm', A_path) expected_output = svntest.wc.State(wc_dir, { 'A' : Item(verb='Deleting'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.remove('A', 'A/B', 'A/B/E', 'A/B/E/beta', 'A/B/E/alpha', 'A/B/F', 'A/B/lambda', 'A/D', 'A/D/G', 'A/D/G/rho', 'A/D/G/pi', 'A/D/G/tau', 'A/D/H', 'A/D/H/psi', 'A/D/H/omega', 'A/D/H/chi', 'A/D/gamma', 'A/mu', 'A/C') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # Doing an 'svn diff -r1:2' on the URL of directory A should work, # especially over the DAV layer. the_url = sbox.repo_url + '/A' diff_output = svntest.actions.run_and_verify_svn(None, [], 'diff', '-r', '1:2', the_url + "@2") #---------------------------------------------------------------------- @Issue(2873) def diff_targets(sbox): "select diff targets" sbox.build() os.chdir(sbox.wc_dir) update_a_file() add_a_file() update_path = os.path.join('A', 'B', 'E', 'alpha') add_path = os.path.join('A', 'B', 'E', 'theta') parent_path = os.path.join('A', 'B', 'E') update_url = sbox.repo_url + '/A/B/E/alpha' parent_url = sbox.repo_url + '/A/B/E' exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', update_path, add_path) if check_update_a_file(diff_output) or check_add_a_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', update_path) if check_update_a_file(diff_output) or not check_add_a_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '--old', parent_path, 'alpha', 'theta') if check_update_a_file(diff_output) or check_add_a_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '--old', parent_path, 'theta') if not check_update_a_file(diff_output) or check_add_a_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn(None, 'ci', '-m', 'log msg') exit_code, diff_output, err_output = svntest.main.run_svn(1, 'diff', '-r1:2', update_path, add_path) if check_update_a_file(diff_output) or check_add_a_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn(1, 'diff', '-r1:2', add_path) if not check_update_a_file(diff_output) or check_add_a_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn( 1, 'diff', '-r1:2', '--old', parent_path, 'alpha', 'theta') if check_update_a_file(diff_output) or check_add_a_file(diff_output): raise svntest.Failure exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r1:2', '--old', parent_path, 'alpha') if check_update_a_file(diff_output) or not check_add_a_file(diff_output): raise svntest.Failure #---------------------------------------------------------------------- def diff_branches(sbox): "diff for branches" sbox.build() A_url = sbox.repo_url + '/A' A2_url = sbox.repo_url + '/A2' svntest.actions.run_and_verify_svn(None, [], 'cp', '-m', 'log msg', A_url, A2_url) svntest.actions.run_and_verify_svn(None, [], 'up', sbox.wc_dir) A_alpha = sbox.ospath('A/B/E/alpha') A2_alpha = sbox.ospath('A2/B/E/alpha') svntest.main.file_append(A_alpha, "\nfoo\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', sbox.wc_dir) svntest.main.file_append(A2_alpha, "\nbar\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', sbox.wc_dir) svntest.main.file_append(A_alpha, "zig\n") # Compare repository file on one branch against repository file on # another branch rel_path = os.path.join('B', 'E', 'alpha') exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '--old', A_url, '--new', A2_url, rel_path) verify_expected_output(diff_output, "-foo") verify_expected_output(diff_output, "+bar") # Same again but using whole branch exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '--old', A_url, '--new', A2_url) verify_expected_output(diff_output, "-foo") verify_expected_output(diff_output, "+bar") # Compare two repository files on different branches exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', A_url + '/B/E/alpha', A2_url + '/B/E/alpha') verify_expected_output(diff_output, "-foo") verify_expected_output(diff_output, "+bar") # Compare two versions of a file on a single branch exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', A_url + '/B/E/alpha@2', A_url + '/B/E/alpha@3') verify_expected_output(diff_output, "+foo") # Compare identical files on different branches exit_code, diff_output, err = svntest.actions.run_and_verify_svn( [], [], 'diff', A_url + '/B/E/alpha@2', A2_url + '/B/E/alpha@3') #---------------------------------------------------------------------- def diff_repos_and_wc(sbox): "diff between repos URLs and WC paths" sbox.build() A_url = sbox.repo_url + '/A' A2_url = sbox.repo_url + '/A2' svntest.actions.run_and_verify_svn(None, [], 'cp', '-m', 'log msg', A_url, A2_url) svntest.actions.run_and_verify_svn(None, [], 'up', sbox.wc_dir) A_alpha = sbox.ospath('A/B/E/alpha') A2_alpha = sbox.ospath('A2/B/E/alpha') svntest.main.file_append(A_alpha, "\nfoo\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', sbox.wc_dir) svntest.main.file_append(A2_alpha, "\nbar\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', sbox.wc_dir) svntest.main.file_append(A_alpha, "zig\n") # Compare working file on one branch against repository file on # another branch A_path = sbox.ospath('A') rel_path = os.path.join('B', 'E', 'alpha') exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '--old', A2_url, '--new', A_path, rel_path) verify_expected_output(diff_output, "-bar") verify_expected_output(diff_output, "+foo") verify_expected_output(diff_output, "+zig") # Same again but using whole branch exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '--old', A2_url, '--new', A_path) verify_expected_output(diff_output, "-bar") verify_expected_output(diff_output, "+foo") verify_expected_output(diff_output, "+zig") #---------------------------------------------------------------------- @Issue(1311) def diff_file_urls(sbox): "diff between two file URLs" sbox.build() iota_path = sbox.ospath('iota') iota_url = sbox.repo_url + '/iota' iota_copy_path = sbox.ospath('A/iota') iota_copy_url = sbox.repo_url + '/A/iota' iota_copy2_url = sbox.repo_url + '/A/iota2' # Put some different text into iota, and commit. os.remove(iota_path) svntest.main.file_append(iota_path, "foo\nbar\nsnafu\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', iota_path) # Now, copy the file elsewhere, twice. svntest.actions.run_and_verify_svn(None, [], 'cp', '-m', 'log msg', iota_url, iota_copy_url) svntest.actions.run_and_verify_svn(None, [], 'cp', '-m', 'log msg', iota_url, iota_copy2_url) # Update (to get the copies) svntest.actions.run_and_verify_svn(None, [], 'up', sbox.wc_dir) # Now, make edits to one of the copies of iota, and commit. os.remove(iota_copy_path) svntest.main.file_append(iota_copy_path, "foo\nsnafu\nabcdefg\nopqrstuv\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', iota_copy_path) # Finally, do a diff between the first and second copies of iota, # and verify that we got the expected lines. And then do it in reverse! exit_code, out, err = svntest.actions.run_and_verify_svn(None, [], 'diff', iota_copy_url, iota_copy2_url) verify_expected_output(out, "+bar") verify_expected_output(out, "-abcdefg") verify_expected_output(out, "-opqrstuv") exit_code, out, err = svntest.actions.run_and_verify_svn(None, [], 'diff', iota_copy2_url, iota_copy_url) verify_expected_output(out, "-bar") verify_expected_output(out, "+abcdefg") verify_expected_output(out, "+opqrstuv") #---------------------------------------------------------------------- def diff_prop_change_local_edit(sbox): "diff a property change plus a local edit" sbox.build() iota_path = sbox.ospath('iota') iota_url = sbox.repo_url + '/iota' # Change a property on iota, and commit. svntest.actions.run_and_verify_svn(None, [], 'propset', 'pname', 'pvalue', iota_path) svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', iota_path) # Make local edits to iota. svntest.main.file_append(iota_path, "\nMore text.\n") # diff r1:COMMITTED should show the property change but not the local edit. exit_code, out, err = svntest.actions.run_and_verify_svn(None, [], 'diff', '-r1:COMMITTED', iota_path) for line in out: if line.find("+More text.") != -1: raise svntest.Failure verify_expected_output(out, "+pvalue") # diff r1:BASE should show the property change but not the local edit. exit_code, out, err = svntest.actions.run_and_verify_svn(None, [], 'diff', '-r1:BASE', iota_path) for line in out: if line.find("+More text.") != -1: raise svntest.Failure # fails at r7481 verify_expected_output(out, "+pvalue") # fails at r7481 # diff r1:WC should show the local edit as well as the property change. exit_code, out, err = svntest.actions.run_and_verify_svn(None, [], 'diff', '-r1', iota_path) verify_expected_output(out, "+More text.") # fails at r7481 verify_expected_output(out, "+pvalue") #---------------------------------------------------------------------- def check_for_omitted_prefix_in_path_component(sbox): "check for omitted prefix in path component" sbox.build() svntest.actions.do_sleep_for_timestamps() prefix_path = sbox.ospath('prefix_mydir') svntest.actions.run_and_verify_svn(None, [], 'mkdir', prefix_path) other_prefix_path = sbox.ospath('prefix_other') svntest.actions.run_and_verify_svn(None, [], 'mkdir', other_prefix_path) svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', sbox.wc_dir) file_path = os.path.join(prefix_path, "test.txt") svntest.main.file_write(file_path, "Hello\nThere\nIota\n") svntest.actions.run_and_verify_svn(None, [], 'add', file_path) svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', sbox.wc_dir) prefix_url = sbox.repo_url + "/prefix_mydir" other_prefix_url = sbox.repo_url + "/prefix_other/mytag" svntest.actions.run_and_verify_svn(None, [], 'cp', '-m', 'log msg', prefix_url, other_prefix_url) svntest.main.file_write(file_path, "Hello\nWorld\nIota\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg', prefix_path) exit_code, out, err = svntest.actions.run_and_verify_svn(None, [], 'diff', prefix_url, other_prefix_url) src = extract_diff_path(out[2]) dest = extract_diff_path(out[3]) good_src = ".../prefix_mydir" good_dest = ".../prefix_other/mytag" if ((src != good_src) or (dest != good_dest)): logger.warn("src is '%s' instead of '%s' and dest is '%s' instead of '%s'" % (src, good_src, dest, good_dest)) raise svntest.Failure #---------------------------------------------------------------------- def diff_renamed_file(sbox): "diff a file that has been renamed" sbox.build() os.chdir(sbox.wc_dir) pi_path = os.path.join('A', 'D', 'G', 'pi') pi2_path = os.path.join('A', 'D', 'pi2') svntest.main.file_write(pi_path, "new pi") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg') svntest.main.file_append(pi_path, "even more pi") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg') svntest.main.run_svn(None, 'mv', pi_path, pi2_path) # Repos->WC diff of the file exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1', pi2_path) if check_diff_output(diff_output, pi2_path, 'M') : raise svntest.Failure # Repos->WC diff of the file showing copies as adds exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', '--show-copies-as-adds', pi2_path) if check_diff_output(diff_output, pi2_path, 'A') : raise svntest.Failure svntest.main.file_append(pi2_path, "new pi") # Repos->WC of the containing directory exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', os.path.join('A', 'D')) if check_diff_output(diff_output, pi_path, 'D') : raise svntest.Failure if check_diff_output(diff_output, pi2_path, 'M') : raise svntest.Failure # Repos->WC of the containing directory showing copies as adds exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', '--show-copies-as-adds', os.path.join('A', 'D')) if check_diff_output(diff_output, pi_path, 'D') : raise svntest.Failure if check_diff_output(diff_output, pi2_path, 'A') : raise svntest.Failure # WC->WC of the file exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', pi2_path) if check_diff_output(diff_output, pi2_path, 'M') : raise svntest.Failure # WC->WC of the file showing copies as adds exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '--show-copies-as-adds', pi2_path) if check_diff_output(diff_output, pi2_path, 'A') : raise svntest.Failure svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg') # Repos->WC diff of file after the rename exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1', pi2_path) if check_diff_output(diff_output, pi2_path, 'M') : raise svntest.Failure # Repos->WC diff of file after the rename. The local file is not # a copy anymore (it has schedule "normal"), so --show-copies-as-adds # should have no effect. exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', '--show-copies-as-adds', pi2_path) if check_diff_output(diff_output, pi2_path, 'M') : raise svntest.Failure # Repos->repos diff after the rename ### --show-copies-as-adds has no effect exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '2:3', pi2_path) if check_diff_output(diff_output, os.path.join('A', 'D', 'pi'), 'M') : raise svntest.Failure #---------------------------------------------------------------------- def diff_within_renamed_dir(sbox): "diff a file within a renamed directory" sbox.build() os.chdir(sbox.wc_dir) svntest.main.run_svn(None, 'mv', os.path.join('A', 'D', 'G'), os.path.join('A', 'D', 'I')) # svntest.main.run_svn(None, 'ci', '-m', 'log_msg') svntest.main.file_write(os.path.join('A', 'D', 'I', 'pi'), "new pi") # Check a repos->wc diff exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', os.path.join('A', 'D', 'I', 'pi')) if check_diff_output(diff_output, os.path.join('A', 'D', 'I', 'pi'), 'M') : raise svntest.Failure svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg') # Check repos->wc after commit exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', os.path.join('A', 'D', 'I', 'pi')) if check_diff_output(diff_output, os.path.join('A', 'D', 'I', 'pi'), 'M') : raise svntest.Failure # Test the diff while within the moved directory os.chdir(os.path.join('A','D','I')) exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1') if check_diff_output(diff_output, 'pi', 'M') : raise svntest.Failure # Test a repos->repos diff while within the moved directory exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1:2') if check_diff_output(diff_output, 'pi', 'M') : raise svntest.Failure #---------------------------------------------------------------------- def diff_prop_on_named_dir(sbox): "diff a prop change on a dir named explicitly" # Diff of a property change or addition should contain a "+" line. # Diff of a property change or deletion should contain a "-" line. # On a diff between repository revisions (not WC) of a dir named # explicitly, the "-" line was missing. (For a file, and for a dir # recursed into, the result was correct.) sbox.build() wc_dir = sbox.wc_dir os.chdir(sbox.wc_dir) svntest.actions.run_and_verify_svn(None, [], 'propset', 'p', 'v', 'A') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', '') svntest.actions.run_and_verify_svn(None, [], 'propdel', 'p', 'A') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', '') exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r2:3', 'A') # Check that the result contains a "-" line. verify_expected_output(diff_output, "-v") #---------------------------------------------------------------------- def diff_keywords(sbox): "ensure that diff won't show keywords" sbox.build() iota_path = sbox.ospath('iota') svntest.actions.run_and_verify_svn(None, [], 'ps', 'svn:keywords', 'Id Rev Date', iota_path) fp = open(iota_path, 'w') fp.write("$Date$\n") fp.write("$Id$\n") fp.write("$Rev$\n") fp.write("$Date::%s$\n" % (' ' * 80)) fp.write("$Id::%s$\n" % (' ' * 80)) fp.write("$Rev::%s$\n" % (' ' * 80)) fp.close() svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'keywords', sbox.wc_dir) svntest.main.file_append(iota_path, "bar\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'added bar', sbox.wc_dir) svntest.actions.run_and_verify_svn(None, [], 'up', sbox.wc_dir) exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', 'prev:head', sbox.wc_dir) verify_expected_output(diff_output, "+bar") verify_excluded_output(diff_output, "$Date:") verify_excluded_output(diff_output, "$Rev:") verify_excluded_output(diff_output, "$Id:") exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', 'head:prev', sbox.wc_dir) verify_expected_output(diff_output, "-bar") verify_excluded_output(diff_output, "$Date:") verify_excluded_output(diff_output, "$Rev:") verify_excluded_output(diff_output, "$Id:") # Check fixed length keywords will show up # when the length of keyword has changed fp = open(iota_path, 'w') fp.write("$Date$\n") fp.write("$Id$\n") fp.write("$Rev$\n") fp.write("$Date::%s$\n" % (' ' * 79)) fp.write("$Id::%s$\n" % (' ' * 79)) fp.write("$Rev::%s$\n" % (' ' * 79)) fp.close() svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'keywords 2', sbox.wc_dir) svntest.actions.run_and_verify_svn(None, [], 'up', sbox.wc_dir) exit_code, diff_output, err = svntest.actions.run_and_verify_svn( None, [], 'diff', '-r', 'prev:head', sbox.wc_dir) # these should show up verify_expected_output(diff_output, "+$Id:: ") verify_expected_output(diff_output, "-$Id:: ") verify_expected_output(diff_output, "-$Rev:: ") verify_expected_output(diff_output, "+$Rev:: ") verify_expected_output(diff_output, "-$Date:: ") verify_expected_output(diff_output, "+$Date:: ") # ... and these won't verify_excluded_output(diff_output, "$Date: ") verify_excluded_output(diff_output, "$Rev: ") verify_excluded_output(diff_output, "$Id: ") def diff_force(sbox): "show diffs for binary files" sbox.build() wc_dir = sbox.wc_dir iota_path = sbox.ospath('iota') # Append a line to iota and make it binary. svntest.main.file_append(iota_path, "new line") svntest.main.run_svn(binary_mime_type_on_text_file_warning, 'propset', 'svn:mime-type', 'application/octet-stream', iota_path) # Created expected output tree for 'svn ci' expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) # Create expected status tree expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'iota' : Item(status=' ', wc_rev=2), }) # Commit iota, creating revision 2. svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # Add another line, while keeping he file as binary. svntest.main.file_append(iota_path, "another line") # Commit creating rev 3. expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'iota' : Item(status=' ', wc_rev=3), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # Check that we get diff when the first, the second and both files # are marked as binary. First we'll use --force. Then we'll use # the configuration option 'diff-ignore-content-type'. re_nodisplay = re.compile('^Cannot display:') for opt in ['--force', '--config-option=config:miscellany:diff-ignore-content-type=yes']: for range in ['-r1:2', '-r2:1', '-r2:3']: exit_code, stdout, stderr = svntest.main.run_svn(None, 'diff', range, iota_path, opt) for line in stdout: if (re_nodisplay.match(line)): raise svntest.Failure #---------------------------------------------------------------------- # Regression test for issue #2333: Renaming a directory should produce # deletion and addition diffs for each included file. @Issue(2333) def diff_renamed_dir(sbox): "diff a renamed directory" sbox.build() os.chdir(sbox.wc_dir) svntest.main.run_svn(None, 'mv', os.path.join('A', 'D', 'G'), os.path.join('A', 'D', 'I')) # Check a wc->wc diff exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '--show-copies-as-adds', os.path.join('A', 'D')) if check_diff_output(diff_output, os.path.join('A', 'D', 'G', 'pi'), 'D') : raise svntest.Failure if check_diff_output(diff_output, os.path.join('A', 'D', 'I', 'pi'), 'A') : raise svntest.Failure # Check a repos->wc diff of the moved-here node before commit exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', '--show-copies-as-adds', os.path.join('A', 'D', 'I')) if check_diff_output(diff_output, os.path.join('A', 'D', 'I', 'pi'), 'A') : raise svntest.Failure # Check a repos->wc diff of the moved-away node before commit exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', os.path.join('A', 'D', 'G')) if check_diff_output(diff_output, os.path.join('A', 'D', 'G', 'pi'), 'D') : raise svntest.Failure # Commit svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log msg') # Check repos->wc after commit exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r', '1', os.path.join('A', 'D')) if check_diff_output(diff_output, os.path.join('A', 'D', 'G', 'pi'), 'D') : raise svntest.Failure if check_diff_output(diff_output, os.path.join('A', 'D', 'I', 'pi'), 'A') : raise svntest.Failure # Test a repos->repos diff after commit exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1:2') if check_diff_output(diff_output, os.path.join('A', 'D', 'G', 'pi'), 'D') : raise svntest.Failure if check_diff_output(diff_output, os.path.join('A', 'D', 'I', 'pi'), 'A') : raise svntest.Failure # repos->repos with explicit URL arg exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1:2', '^/A') if check_diff_output(diff_output, os.path.join('D', 'G', 'pi'), 'D') : raise svntest.Failure if check_diff_output(diff_output, os.path.join('D', 'I', 'pi'), 'A') : raise svntest.Failure # Go to the parent of the moved directory os.chdir(os.path.join('A','D')) # repos->wc diff in the parent exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1') if check_diff_output(diff_output, os.path.join('G', 'pi'), 'D') : raise svntest.Failure if check_diff_output(diff_output, os.path.join('I', 'pi'), 'A') : raise svntest.Failure # repos->repos diff in the parent exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1:2') if check_diff_output(diff_output, os.path.join('G', 'pi'), 'D') : raise svntest.Failure if check_diff_output(diff_output, os.path.join('I', 'pi'), 'A') : raise svntest.Failure # Go to the move target directory os.chdir('I') # repos->wc diff while within the moved directory (should be empty) exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1') if diff_output: raise svntest.Failure # repos->repos diff while within the moved directory (should be empty) exit_code, diff_output, err_output = svntest.main.run_svn(None, 'diff', '-r', '1:2') if diff_output: raise svntest.Failure #---------------------------------------------------------------------- def diff_property_changes_to_base(sbox): "diff to BASE with local property mods" sbox.build() wc_dir = sbox.wc_dir # Each of these returns an expected diff as a list of lines. def add_diff_A(r1, r2): return (make_diff_header("A", r1, r2) + make_diff_prop_header("A") + make_diff_prop_added("dirprop", "r2value")) def add_diff_iota(r1, r2): return (make_diff_header("iota", r1, r2) + make_diff_prop_header("iota") + make_diff_prop_added("fileprop", "r2value")) def del_diff_A(r1, r2): return (make_diff_header("A", r1, r2) + make_diff_prop_header("A") + make_diff_prop_deleted("dirprop", "r2value")) def del_diff_iota(r1, r2): return (make_diff_header("iota", r1, r2) + make_diff_prop_header("iota") + make_diff_prop_deleted("fileprop", "r2value")) # Each of these is an expected diff as a list of lines. expected_output_r1_r2 = (add_diff_A('revision 1', 'revision 2') + add_diff_iota('revision 1', 'revision 2')) expected_output_r2_r1 = (del_diff_A('revision 2', 'revision 1') + del_diff_iota('revision 2', 'revision 1')) expected_output_r1 = (add_diff_A('revision 1', 'working copy') + add_diff_iota('revision 1', 'working copy')) expected_output_base_r1 = (del_diff_A('working copy', 'revision 1') + del_diff_iota('working copy', 'revision 1')) os.chdir(sbox.wc_dir) svntest.actions.run_and_verify_svn(None, [], 'propset', 'fileprop', 'r2value', 'iota') svntest.actions.run_and_verify_svn(None, [], 'propset', 'dirprop', 'r2value', 'A') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'empty-msg') # Check that forward and reverse repos-repos diffs are as expected. expected = svntest.verify.UnorderedOutput(expected_output_r1_r2) svntest.actions.run_and_verify_svn(expected, [], 'diff', '-r', '1:2') expected = svntest.verify.UnorderedOutput(expected_output_r2_r1) svntest.actions.run_and_verify_svn(expected, [], 'diff', '-r', '2:1') # Now check repos->WORKING, repos->BASE, and BASE->repos. # (BASE is r1, and WORKING has no local mods, so this should produce # the same output as above). expected = svntest.verify.UnorderedOutput(expected_output_r1) svntest.actions.run_and_verify_svn(expected, [], 'diff', '-r', '1') svntest.actions.run_and_verify_svn(expected, [], 'diff', '-r', '1:BASE') expected = svntest.verify.UnorderedOutput(expected_output_base_r1) svntest.actions.run_and_verify_svn(expected, [], 'diff', '-r', 'BASE:1') # Modify some properties. svntest.actions.run_and_verify_svn(None, [], 'propset', 'fileprop', 'workingvalue', 'iota') svntest.actions.run_and_verify_svn(None, [], 'propset', 'dirprop', 'workingvalue', 'A') svntest.actions.run_and_verify_svn(None, [], 'propset', 'fileprop', 'workingvalue', 'A/mu') # Check that the earlier diffs against BASE are unaffected by the # presence of local mods (with the exception of diff header changes). expected = svntest.verify.UnorderedOutput(expected_output_r1) svntest.actions.run_and_verify_svn(expected, [], 'diff', '-r', '1:BASE') expected = svntest.verify.UnorderedOutput(expected_output_base_r1) svntest.actions.run_and_verify_svn(expected, [], 'diff', '-r', 'BASE:1') def diff_schedule_delete(sbox): "scheduled deleted" sbox.build() expected_output_r2_working = make_diff_header("foo", "revision 2", "nonexistent") + [ "@@ -1 +0,0 @@\n", "-xxx\n" ] expected_output_r2_base = make_diff_header("foo", "revision 2", "nonexistent") + [ "@@ -1 +0,0 @@\n", "-xxx\n", ] expected_output_base_r2 = make_diff_header("foo", "nonexistent", "revision 2") + [ "@@ -0,0 +1 @@\n", "+xxx\n", ] expected_output_r1_base = make_diff_header("foo", "nonexistent", "working copy") + [ "@@ -0,0 +1,2 @@\n", "+xxx\n", "+yyy\n" ] expected_output_base_r1 = make_diff_header("foo", "working copy", "nonexistent") + [ "@@ -1,2 +0,0 @@\n", "-xxx\n", "-yyy\n" ] expected_output_base_working = expected_output_base_r1[:] expected_output_base_working[2] = "--- foo\t(revision 3)\n" expected_output_base_working[3] = "+++ foo\t(nonexistent)\n" wc_dir = sbox.wc_dir os.chdir(wc_dir) svntest.main.file_append('foo', "xxx\n") svntest.main.run_svn(None, 'add', 'foo') svntest.main.run_svn(None, 'ci', '-m', 'log msg r2') svntest.main.file_append('foo', "yyy\n") svntest.main.run_svn(None, 'ci', '-m', 'log msg r3') # Update everyone's BASE to r3, and mark 'foo' as schedule-deleted. svntest.main.run_svn(None, 'up') svntest.main.run_svn(None, 'rm', 'foo') # A file marked as schedule-delete should act as if were not present # in WORKING, but diffs against BASE should remain unaffected. # 1. repos-wc diff: file not present in repos. svntest.actions.run_and_verify_svn([], [], 'diff', '-r', '1') svntest.actions.run_and_verify_svn(expected_output_r1_base, [], 'diff', '-r', '1:BASE') svntest.actions.run_and_verify_svn(expected_output_base_r1, [], 'diff', '-r', 'BASE:1') # 2. repos-wc diff: file present in repos. svntest.actions.run_and_verify_svn(expected_output_r2_working, [], 'diff', '-r', '2') svntest.actions.run_and_verify_svn(expected_output_r2_base, [], 'diff', '-r', '2:BASE') svntest.actions.run_and_verify_svn(expected_output_base_r2, [], 'diff', '-r', 'BASE:2') # 3. wc-wc diff. svntest.actions.run_and_verify_svn(expected_output_base_working, [], 'diff') #---------------------------------------------------------------------- def diff_mime_type_changes(sbox): "repos-wc diffs with local svn:mime-type prop mods" sbox.build() expected_output_r1_wc = make_diff_header("iota", "revision 1", "working copy") + [ "@@ -1 +1,2 @@\n", " This is the file 'iota'.\n", "+revision 2 text.\n" ] expected_output_wc_r1 = make_diff_header("iota", "working copy", "revision 1") + [ "@@ -1,2 +1 @@\n", " This is the file 'iota'.\n", "-revision 2 text.\n" ] os.chdir(sbox.wc_dir) # Append some text to iota (r2). svntest.main.file_append('iota', "revision 2 text.\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log_msg') # Check that forward and reverse repos-BASE diffs are as expected. svntest.actions.run_and_verify_svn(expected_output_r1_wc, [], 'diff', '-r', '1:BASE') svntest.actions.run_and_verify_svn(expected_output_wc_r1, [], 'diff', '-r', 'BASE:1') # Mark iota as a binary file in the working copy. svntest.actions.run_and_verify_svn2(None, binary_mime_type_on_text_file_warning, 0, 'propset', 'svn:mime-type', 'application/octet-stream', 'iota') # Check that the earlier diffs against BASE are unaffected by the # presence of local svn:mime-type property mods. svntest.actions.run_and_verify_svn(expected_output_r1_wc, [], 'diff', '-r', '1:BASE') svntest.actions.run_and_verify_svn(expected_output_wc_r1, [], 'diff', '-r', 'BASE:1') # Commit the change (r3) (so that BASE has the binary MIME type), then # mark iota as a text file again in the working copy. svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log_msg') svntest.actions.run_and_verify_svn(None, [], 'propdel', 'svn:mime-type', 'iota') # Now diffs against BASE will fail, but diffs against WORKNG should be # fine. svntest.actions.run_and_verify_svn(expected_output_r1_wc, [], 'diff', '-r', '1') #---------------------------------------------------------------------- # Test a repos-WORKING diff, with different versions of the same property # at repository, BASE, and WORKING. def diff_prop_change_local_propmod(sbox): "diff a property change plus a local prop edit" sbox.build() expected_output_r2_wc = \ make_diff_header("A", "revision 2", "working copy") + \ make_diff_prop_header("A") + \ make_diff_prop_modified("dirprop", "r2value", "workingvalue") + \ make_diff_prop_added("newdirprop", "newworkingvalue") + \ make_diff_header("iota", "revision 2", "working copy") + \ make_diff_prop_header("iota") + \ make_diff_prop_modified("fileprop", "r2value", "workingvalue") + \ make_diff_prop_added("newfileprop", "newworkingvalue") os.chdir(sbox.wc_dir) # Set a property on A/ and iota, and commit them (r2). svntest.actions.run_and_verify_svn(None, [], 'propset', 'dirprop', 'r2value', 'A') svntest.actions.run_and_verify_svn(None, [], 'propset', 'fileprop', 'r2value', 'iota') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log_msg') # Change the property values on A/ and iota, and commit them (r3). svntest.actions.run_and_verify_svn(None, [], 'propset', 'dirprop', 'r3value', 'A') svntest.actions.run_and_verify_svn(None, [], 'propset', 'fileprop', 'r3value', 'iota') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log_msg') # Finally, change the property values one last time. svntest.actions.run_and_verify_svn(None, [], 'propset', 'dirprop', 'workingvalue', 'A') svntest.actions.run_and_verify_svn(None, [], 'propset', 'fileprop', 'workingvalue', 'iota') # And also add some properties that only exist in WORKING. svntest.actions.run_and_verify_svn(None, [], 'propset', 'newdirprop', 'newworkingvalue', 'A') svntest.actions.run_and_verify_svn(None, [], 'propset', 'newfileprop', 'newworkingvalue', 'iota') # Now, if we diff r2 to WORKING, we've got three property values # to consider: r2value (in the repository), r3value (in BASE), and # workingvalue (in WORKING). # The diff should only show the r2->WORKING change. # # We also need to make sure that the 'new' (WORKING only) properties # are included in the output, since they won't be listed in a simple # BASE->r2 diff. expected = svntest.verify.UnorderedOutput(expected_output_r2_wc) svntest.actions.run_and_verify_svn(expected, [], 'diff', '-r', '2') #---------------------------------------------------------------------- # repos->wc and BASE->repos diffs that add files or directories with # properties should show the added properties. def diff_repos_wc_add_with_props(sbox): "repos-wc diff showing added entries with props" sbox.build() diff_foo = [ "@@ -0,0 +1 @@\n", "+content\n", ] + make_diff_prop_header("foo") + \ make_diff_prop_added("propname", "propvalue") diff_X = \ make_diff_prop_header("X") + \ make_diff_prop_added("propname", "propvalue") diff_X_bar = [ "@@ -0,0 +1 @@\n", "+content\n", ] + make_diff_prop_header("X/bar") + \ make_diff_prop_added("propname", "propvalue") diff_X_r1_base = make_diff_header("X", "nonexistent", "working copy") + diff_X diff_X_base_r3 = make_diff_header("X", "nonexistent", "revision 3") + diff_X diff_foo_r1_base = make_diff_header("foo", "nonexistent", "revision 3") + diff_foo diff_foo_base_r3 = make_diff_header("foo", "nonexistent", "revision 3") + diff_foo diff_X_bar_r1_base = make_diff_header("X/bar", "nonexistent", "revision 3") + diff_X_bar diff_X_bar_base_r3 = make_diff_header("X/bar", "nonexistent", "revision 3") + diff_X_bar expected_output_r1_base = svntest.verify.UnorderedOutput(diff_X_r1_base + diff_X_bar_r1_base + diff_foo_r1_base) expected_output_base_r3 = svntest.verify.UnorderedOutput(diff_foo_base_r3 + diff_X_bar_base_r3 + diff_X_base_r3) os.chdir(sbox.wc_dir) # Create directory X, file foo, and file X/bar, and commit them (r2). os.makedirs('X') svntest.main.file_append('foo', "content\n") svntest.main.file_append(os.path.join('X', 'bar'), "content\n") svntest.actions.run_and_verify_svn(None, [], 'add', 'X', 'foo') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log_msg') # Set a property on all three items, and commit them (r3). svntest.actions.run_and_verify_svn(None, [], 'propset', 'propname', 'propvalue', 'X', 'foo', os.path.join('X', 'bar')) svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log_msg') # Now, if we diff r1 to WORKING or BASE, we should see the content # addition for foo and X/bar, and property additions for all three. svntest.actions.run_and_verify_svn(expected_output_r1_base, [], 'diff', '-r', '1') svntest.actions.run_and_verify_svn(expected_output_r1_base, [], 'diff', '-r', '1:BASE') # Update the BASE and WORKING revisions to r1. svntest.actions.run_and_verify_svn(None, [], 'up', '-r', '1') # If we diff BASE to r3, we should see the same output as above. svntest.actions.run_and_verify_svn(expected_output_base_r3, [], 'diff', '-r', 'BASE:3') #---------------------------------------------------------------------- # repos-wc diffs on a non-recursively checked out wc that would normally # (if recursively checked out) include a directory that is not present in # the repos version should not segfault. def diff_nonrecursive_checkout_deleted_dir(sbox): "nonrecursive diff + deleted directories" sbox.build() url = sbox.repo_url A_url = url + '/A' A_prime_url = url + '/A_prime' svntest.main.run_svn(None, 'cp', '-m', 'log msg', A_url, A_prime_url) svntest.main.run_svn(None, 'mkdir', '-m', 'log msg', A_prime_url + '/Q') wc = sbox.add_wc_path('wc') svntest.main.run_svn(None, 'co', '-N', A_prime_url, wc) os.chdir(wc) # We don't particular care about the output here, just that it doesn't # segfault. svntest.main.run_svn(None, 'diff', '-r1') #---------------------------------------------------------------------- # repos->WORKING diffs that include directories with local mods that are # not present in the repos version should work as expected (and not, for # example, show an extraneous BASE->WORKING diff for the added directory # after the repos->WORKING output). def diff_repos_working_added_dir(sbox): "repos->WORKING diff showing added modifed dir" sbox.build() expected_output_r1_BASE = make_diff_header("X/bar", "nonexistent", "revision 2") + [ "@@ -0,0 +1 @@\n", "+content\n" ] expected_output_r1_WORKING = make_diff_header("X/bar", "nonexistent", "working copy") + [ "@@ -0,0 +1,2 @@\n", "+content\n", "+more content\n" ] os.chdir(sbox.wc_dir) # Create directory X and file X/bar, and commit them (r2). os.makedirs('X') svntest.main.file_append(os.path.join('X', 'bar'), "content\n") svntest.actions.run_and_verify_svn(None, [], 'add', 'X') svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'log_msg') # Make a local modification to X/bar. svntest.main.file_append(os.path.join('X', 'bar'), "more content\n") # Now, if we diff r1 to WORKING or BASE, we should see the content # addition for X/bar, and (for WORKING) the local modification. svntest.actions.run_and_verify_svn(expected_output_r1_BASE, [], 'diff', '-r', '1:BASE') svntest.actions.run_and_verify_svn(expected_output_r1_WORKING, [], 'diff', '-r', '1') #---------------------------------------------------------------------- # A base->repos diff of a moved file used to output an all-lines-deleted diff def diff_base_repos_moved(sbox): "base->repos diff of moved file" sbox.build() os.chdir(sbox.wc_dir) oldfile = 'iota' newfile = 'kappa' # Move, modify and commit a file svntest.main.run_svn(None, 'mv', oldfile, newfile) svntest.main.file_write(newfile, "new content\n") svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', '') # Check that a base->repos diff with copyfrom shows deleted and added lines. exit_code, out, err = svntest.actions.run_and_verify_svn( svntest.verify.AnyOutput, [], 'diff', '-rBASE:1', newfile) if check_diff_output(out, newfile, 'M'): raise svntest.Failure # Diff should recognise that the item's name has changed, and mention both # the current and the old name in parentheses, in the right order. if (out[2][:3] != '---' or out[2].find('kappa)') == -1 or out[3][:3] != '+++' or out[3].find('iota)') == -1): raise svntest.Failure #---------------------------------------------------------------------- # A diff of an added file within an added directory should work, and # shouldn't produce an error. def diff_added_subtree(sbox): "wc->repos diff of added subtree" sbox.build() os.chdir(sbox.wc_dir) # Roll the wc back to r0 (i.e. an empty wc). svntest.actions.run_and_verify_svn(None, [], 'up', '-r0') # We shouldn't get any errors when we request a diff showing the # addition of the greek tree. The diff contains additions of files # and directories with parents that don't currently exist in the wc, # which is what we're testing here. svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], 'diff', '-r', 'BASE:1') #---------------------------------------------------------------------- def basic_diff_summarize(sbox): "basic diff summarize" sbox.build() wc_dir = sbox.wc_dir p = sbox.ospath # Diff summarize of a newly added file expected_diff = svntest.wc.State(wc_dir, { 'iota': Item(status='A '), }) svntest.actions.run_and_verify_diff_summarize(expected_diff, p('iota'), '-c1') # Reverse summarize diff of a newly added file expected_diff = svntest.wc.State(wc_dir, { 'iota': Item(status='D '), }) svntest.actions.run_and_verify_diff_summarize(expected_diff, p('iota'), '-c-1') # Diff summarize of a newly added directory expected_diff = svntest.wc.State(wc_dir, { 'A/D': Item(status='A '), 'A/D/gamma': Item(status='A '), 'A/D/H': Item(status='A '), 'A/D/H/chi': Item(status='A '), 'A/D/H/psi': Item(status='A '), 'A/D/H/omega': Item(status='A '), 'A/D/G': Item(status='A '), 'A/D/G/pi': Item(status='A '), 'A/D/G/rho': Item(status='A '), 'A/D/G/tau': Item(status='A '), }) svntest.actions.run_and_verify_diff_summarize(expected_diff, p('A/D'), '-c1') # Reverse summarize diff of a newly added directory expected_diff = svntest.wc.State(wc_dir, { 'A/D': Item(status='D '), 'A/D/gamma': Item(status='D '), 'A/D/H': Item(status='D '), 'A/D/H/chi': Item(status='D '), 'A/D/H/psi': Item(status='D '), 'A/D/H/omega': Item(status='D '), 'A/D/G': Item(status='D '), 'A/D/G/pi': Item(status='D '), 'A/D/G/rho': Item(status='D '), 'A/D/G/tau': Item(status='D '), }) svntest.actions.run_and_verify_diff_summarize(expected_diff, p('A/D'), '-c-1') # Add props to some items that will be deleted, and commit. sbox.simple_propset('prop', 'val', 'A/C', 'A/D/gamma', 'A/D/H/chi') sbox.simple_commit() # r2 sbox.simple_update() # Content modification. svntest.main.file_append(p('A/mu'), 'new text\n') # Prop modification. sbox.simple_propset('prop', 'val', 'iota') # Both content and prop mods. svntest.main.file_append(p('A/D/G/tau'), 'new text\n') sbox.simple_propset('prop', 'val', 'A/D/G/tau') # File addition. svntest.main.file_append(p('newfile'), 'new text\n') svntest.main.file_append(p('newfile2'), 'new text\n') sbox.simple_add('newfile', 'newfile2') sbox.simple_propset('prop', 'val', 'newfile') # File deletion. sbox.simple_rm('A/B/lambda', 'A/D/gamma') # Directory addition. os.makedirs(p('P')) os.makedirs(p('Q/R')) svntest.main.file_append(p('Q/newfile'), 'new text\n') svntest.main.file_append(p('Q/R/newfile'), 'new text\n') sbox.simple_add('P', 'Q') sbox.simple_propset('prop', 'val', 'P', 'Q/newfile') # Directory deletion. sbox.simple_rm('A/D/H', 'A/C') # Commit, because diff-summarize handles repos-repos only. #svntest.main.run_svn(False, 'st', wc_dir) sbox.simple_commit() # r3 # Get the differences between two versions of a file. expected_diff = svntest.wc.State(wc_dir, { 'iota': Item(status=' M'), }) svntest.actions.run_and_verify_diff_summarize(expected_diff, p('iota'), '-c3') svntest.actions.run_and_verify_diff_summarize(expected_diff, p('iota'), '-c-3') # wc-wc diff summary for a directory. expected_diff = svntest.wc.State(wc_dir, { 'A/mu': Item(status='M '), 'iota': Item(status=' M'), 'A/D/G/tau': Item(status='MM'), 'newfile': Item(status='A '), 'newfile2': Item(status='A '), 'P': Item(status='A '), 'Q': Item(status='A '), 'Q/newfile': Item(status='A '), 'Q/R': Item(status='A '), 'Q/R/newfile': Item(status='A '), 'A/B/lambda': Item(status='D '), 'A/C': Item(status='D '), 'A/D/gamma': Item(status='D '), 'A/D/H': Item(status='D '), 'A/D/H/chi': Item(status='D '), 'A/D/H/psi': Item(status='D '), 'A/D/H/omega': Item(status='D '), }) expected_reverse_diff = svntest.wc.State(wc_dir, { 'A/mu': Item(status='M '), 'iota': Item(status=' M'), 'A/D/G/tau': Item(status='MM'), 'newfile': Item(status='D '), 'newfile2': Item(status='D '), 'P': Item(status='D '), 'Q': Item(status='D '), 'Q/newfile': Item(status='D '), 'Q/R': Item(status='D '), 'Q/R/newfile': Item(status='D '), 'A/B/lambda': Item(status='A '), 'A/C': Item(status='A '), 'A/D/gamma': Item(status='A '), 'A/D/H': Item(status='A '), 'A/D/H/chi': Item(status='A '), 'A/D/H/psi': Item(status='A '), 'A/D/H/omega': Item(status='A '), }) svntest.actions.run_and_verify_diff_summarize(expected_diff, wc_dir, '-c3') svntest.actions.run_and_verify_diff_summarize(expected_reverse_diff, wc_dir, '-c-3') # Get the differences between a deep newly added dir Issue(4421) expected_diff = svntest.wc.State(wc_dir, { 'Q/R' : Item(status='A '), 'Q/R/newfile' : Item(status='A '), }) expected_reverse_diff = svntest.wc.State(wc_dir, { 'Q/R' : Item(status='D '), 'Q/R/newfile' : Item(status='D '), }) svntest.actions.run_and_verify_diff_summarize(expected_diff, p('Q/R'), '-c3') svntest.actions.run_and_verify_diff_summarize(expected_reverse_diff, p('Q/R'), '-c-3') #---------------------------------------------------------------------- def diff_weird_author(sbox): "diff with svn:author that has < in it" sbox.build() svntest.actions.enable_revprop_changes(sbox.repo_dir) svntest.main.file_write(sbox.ospath('A/mu'), "new content\n") expected_output = svntest.wc.State(sbox.wc_dir, { 'A/mu': Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) expected_status.tweak("A/mu", wc_rev=2) svntest.actions.run_and_verify_commit(sbox.wc_dir, expected_output, expected_status) svntest.main.run_svn(None, "propset", "--revprop", "-r", "2", "svn:author", "J. Random ", sbox.repo_url) svntest.actions.run_and_verify_svn(["J. Random \n"], [], "pget", "--revprop", "-r" "2", "svn:author", sbox.repo_url) expected_output = make_diff_header("A/mu", "revision 1", "revision 2") + [ "@@ -1 +1 @@\n", "-This is the file 'mu'.\n", "+new content\n" ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r1:2', sbox.repo_url) # test for issue 2121, use -x -w option for ignoring whitespace during diff @Issue(2121) def diff_ignore_whitespace(sbox): "ignore whitespace when diffing" sbox.build() wc_dir = sbox.wc_dir file_name = "iota" file_path = os.path.join(wc_dir, file_name) svntest.main.file_write(file_path, "Aa\n" "Bb\n" "Cc\n") expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, None,) # only whitespace changes, should return no changes svntest.main.file_write(file_path, " A a \n" " B b \n" " C c \n") svntest.actions.run_and_verify_svn([], [], 'diff', '-x', '-w', file_path) # some changes + whitespace svntest.main.file_write(file_path, " A a \n" "Xxxx X\n" " Bb b \n" " C c \n") expected_output = make_diff_header(file_path, "revision 2", "working copy") + [ "@@ -1,3 +1,4 @@\n", " Aa\n", "-Bb\n", "+Xxxx X\n", "+ Bb b \n", " Cc\n" ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-x', '-w', file_path) def diff_ignore_eolstyle(sbox): "ignore eol styles when diffing" sbox.build() wc_dir = sbox.wc_dir file_name = "iota" file_path = os.path.join(wc_dir, file_name) svntest.main.file_write(file_path, "Aa\n" "Bb\n" "Cc\n") expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, None) # commit only eol changes svntest.main.file_write(file_path, "Aa\r" "Bb\r" "Cc") expected_output = make_diff_header(file_path, "revision 2", "working copy") + [ "@@ -1,3 +1,3 @@\n", " Aa\n", " Bb\n", "-Cc\n", "+Cc\n", "\ No newline at end of file\n" ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-x', '--ignore-eol-style', file_path) # test for issue 2600, diff revision of a file in a renamed folder @Issue(2600) def diff_in_renamed_folder(sbox): "diff a revision of a file in a renamed folder" sbox.build() wc_dir = sbox.wc_dir C_path = sbox.ospath('A/C') D_path = sbox.ospath('A/D') kappa_path = os.path.join(D_path, "C", "kappa") # add a new file to a renamed (moved in this case) folder. svntest.main.run_svn(None, 'mv', C_path, D_path) svntest.main.file_append(kappa_path, "this is file kappa.\n") svntest.main.run_svn(None, 'add', kappa_path) expected_output = svntest.wc.State(wc_dir, { 'A/C' : Item(verb='Deleting'), 'A/D/C' : Item(verb='Adding'), 'A/D/C/kappa' : Item(verb='Adding'), }) ### right now, we cannot denote that kappa is a local-add rather than a ### child of the A/D/C copy. thus, it appears in the status output as a ### (M)odified child. svntest.actions.run_and_verify_commit(wc_dir, expected_output, None) expected_output = svntest.wc.State(wc_dir, { 'A/D/C/kappa' : Item(verb='Sending'), }) # modify the file two times so we have something to diff. for i in range(3, 5): svntest.main.file_append(kappa_path, str(i) + "\n") svntest.actions.run_and_verify_commit(wc_dir, expected_output, None) expected_output = make_diff_header(kappa_path, "revision 3", "revision 4") + [ "@@ -1,2 +1,3 @@\n", " this is file kappa.\n", " 3\n", "+4\n" ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r3:4', kappa_path) def diff_with_depth(sbox): "test diffs at various depths" sbox.build() os.chdir(sbox.wc_dir) sbox.wc_dir = '' B_path = os.path.join('A', 'B') sbox.simple_propset('foo1', 'bar1', '.') sbox.simple_propset('foo2', 'bar2', 'iota') sbox.simple_propset('foo3', 'bar3', 'A') sbox.simple_propset('foo4', 'bar4', 'A/B') def create_expected_diffs(r1, r2): diff_dot = \ make_diff_header(".", r1, r2) + \ make_diff_prop_header(".") + \ make_diff_prop_added("foo1", "bar1") diff_iota = \ make_diff_header('iota', r1, r2) + \ make_diff_prop_header("iota") + \ make_diff_prop_added("foo2", "bar2") diff_A = \ make_diff_header('A', r1, r2) + \ make_diff_prop_header("A") + \ make_diff_prop_added("foo3", "bar3") diff_AB = \ make_diff_header(B_path, r1, r2) + \ make_diff_prop_header("A/B") + \ make_diff_prop_added("foo4", "bar4") expected = {} expected['empty'] = svntest.verify.UnorderedOutput(diff_dot) expected['files'] = svntest.verify.UnorderedOutput(diff_dot + diff_iota) expected['immediates'] = svntest.verify.UnorderedOutput(diff_dot + diff_iota + diff_A) expected['infinity'] = svntest.verify.UnorderedOutput(diff_dot + diff_iota + diff_A + diff_AB) return expected # Test wc-wc diff. expected_diffs = create_expected_diffs("revision 1", "working copy") for depth in ['empty', 'files', 'immediates', 'infinity']: svntest.actions.run_and_verify_svn(expected_diffs[depth], [], 'diff', '--depth', depth) # Commit the changes. svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', '') # Test repos-repos diff. expected_diffs = create_expected_diffs("revision 1", "revision 2") for depth in ['empty', 'files', 'immediates', 'infinity']: svntest.actions.run_and_verify_svn(expected_diffs[depth], [], 'diff', '-c2', '--depth', depth) def create_expected_repos_wc_diffs(): diff_AB = \ make_diff_header("A/B", "revision 2", "working copy") + \ make_diff_prop_header("A/B") + \ make_diff_prop_modified("foo4", "bar4", "baz4") diff_A = \ make_diff_header("A", "revision 2", "working copy") + \ make_diff_prop_header("A") + \ make_diff_prop_modified("foo3", "bar3", "baz3") diff_mu = \ make_diff_header("A/mu", "revision 2", "working copy") + [ "@@ -1 +1,2 @@\n", " This is the file 'mu'.\n", "+new text\n",] diff_iota = \ make_diff_header("iota", "revision 2", "working copy") + [ "@@ -1 +1,2 @@\n", " This is the file 'iota'.\n", "+new text\n", ] + make_diff_prop_header("iota") + \ make_diff_prop_modified("foo2", "bar2", "baz2") diff_dot = \ make_diff_header(".", "revision 2", "working copy") + \ make_diff_prop_header(".") + \ make_diff_prop_modified("foo1", "bar1", "baz1") expected = {} expected['empty'] = svntest.verify.UnorderedOutput(diff_dot) expected['files'] = svntest.verify.UnorderedOutput(diff_iota + diff_dot) expected['immediates'] = svntest.verify.UnorderedOutput(diff_A + diff_iota + diff_dot) expected['infinity'] = svntest.verify.UnorderedOutput(diff_AB + diff_A + diff_mu + diff_iota + diff_dot) return expected svntest.actions.run_and_verify_svn(None, [], 'up', '-r1') sbox.simple_propset('foo1', 'baz1', '.') sbox.simple_propset('foo2', 'baz2', 'iota') sbox.simple_propset('foo3', 'baz3', 'A') sbox.simple_propset('foo4', 'baz4', 'A/B') svntest.main.file_append(os.path.join('A', 'mu'), "new text\n") svntest.main.file_append('iota', "new text\n") # Test wc-repos diff. expected_diffs = create_expected_repos_wc_diffs() for depth in ['empty', 'files', 'immediates', 'infinity']: svntest.actions.run_and_verify_svn(expected_diffs[depth], [], 'diff', '-rHEAD', '--depth', depth) # test for issue 2920: ignore eol-style on empty lines @Issue(2920) def diff_ignore_eolstyle_empty_lines(sbox): "ignore eol styles when diffing empty lines" sbox.build() wc_dir = sbox.wc_dir file_name = "iota" file_path = os.path.join(wc_dir, file_name) svntest.main.file_write(file_path, "Aa\n" "\n" "Bb\n" "\n" "Cc\n") expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, None) # sleep to guarantee timestamp change time.sleep(1.1) # commit only eol changes svntest.main.file_write(file_path, "Aa\012" "\012" "Bb\r" "\r" "Cc\012", mode="wb") svntest.actions.run_and_verify_svn([], [], 'diff', '-x', '--ignore-eol-style', file_path) def diff_backward_repos_wc_copy(sbox): "backward repos->wc diff with copied file" sbox.build() wc_dir = sbox.wc_dir os.chdir(wc_dir) # copy a file mu_path = os.path.join('A', 'mu') mucp_path = os.path.join('A', 'mucopy') svntest.main.run_svn(None, 'cp', mu_path, mucp_path) # commit r2 and update back to r1 svntest.main.run_svn(None, 'ci', '-m', 'log msg') svntest.main.run_svn(None, 'up', '-r1') # diff r2 against working copy diff_repos_wc = make_diff_header("A/mucopy", "revision 2", "nonexistent") diff_repos_wc += [ "@@ -1 +0,0 @@\n", "-This is the file 'mu'.\n", ] svntest.actions.run_and_verify_svn(diff_repos_wc, [], 'diff', '-r' , '2') #---------------------------------------------------------------------- def diff_summarize_xml(sbox): "xml diff summarize" sbox.build() wc_dir = sbox.wc_dir # A content modification. svntest.main.file_append(sbox.ospath('A/mu'), "New mu content") # A prop modification. svntest.main.run_svn(None, "propset", "prop", "val", sbox.ospath('iota')) # Both content and prop mods. tau_path = sbox.ospath('A/D/G/tau') svntest.main.file_append(tau_path, "tautau") svntest.main.run_svn(None, "propset", "prop", "val", tau_path) # A file addition. newfile_path = sbox.ospath('newfile') svntest.main.file_append(newfile_path, 'newfile') svntest.main.run_svn(None, 'add', newfile_path) # A file deletion. svntest.main.run_svn(None, "delete", os.path.join(wc_dir, 'A', 'B', 'lambda')) # A directory addition svntest.main.run_svn(None, "mkdir", sbox.ospath('newdir')) expected_output = svntest.wc.State(wc_dir, { 'A/mu': Item(verb='Sending'), 'iota': Item(verb='Sending'), 'newfile': Item(verb='Adding'), 'A/D/G/tau': Item(verb='Sending'), 'A/B/lambda': Item(verb='Deleting'), 'newdir': Item(verb='Adding'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'newfile': Item(status=' ', wc_rev=2), 'newdir': Item(status=' ', wc_rev=2), }) expected_status.tweak("A/mu", "iota", "A/D/G/tau", "newfile", "newdir", wc_rev=2) expected_status.remove("A/B/lambda") # 3) Test working copy summarize paths = ['A/mu', 'iota', 'A/D/G/tau', 'newfile', 'A/B/lambda', 'newdir',] items = ['modified', 'none', 'modified', 'added', 'deleted', 'added',] kinds = ['file','file','file','file','file', 'dir',] props = ['none', 'modified', 'modified', 'none', 'none', 'none',] svntest.actions.run_and_verify_diff_summarize_xml( [], wc_dir, paths, items, props, kinds, wc_dir) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # 1) Test --xml without --summarize svntest.actions.run_and_verify_svn( None, ".*--xml' option only valid with '--summarize' option", 'diff', wc_dir, '--xml') # 2) Test --xml on invalid revision svntest.actions.run_and_verify_diff_summarize_xml( ".*No such revision 5555555", None, wc_dir, None, None, None, '-r0:5555555', wc_dir) # 4) Test --summarize --xml on -c2 paths_iota = ['iota',] items_iota = ['none',] kinds_iota = ['file',] props_iota = ['modified',] svntest.actions.run_and_verify_diff_summarize_xml( [], wc_dir, paths_iota, items_iota, props_iota, kinds_iota, '-c2', sbox.ospath('iota')) # 5) Test --summarize --xml on -r1:2 svntest.actions.run_and_verify_diff_summarize_xml( [], wc_dir, paths, items, props, kinds, '-r1:2', wc_dir) # 6) Same as test #5 but ran against a URL instead of a WC path svntest.actions.run_and_verify_diff_summarize_xml( [], sbox.repo_url, paths, items, props, kinds, '-r1:2', sbox.repo_url) def diff_file_depth_empty(sbox): "svn diff --depth=empty FILE_WITH_LOCAL_MODS" # The bug was that no diff output would be generated. Check that some is. sbox.build() iota_path = sbox.ospath('iota') svntest.main.file_append(iota_path, "new text in iota") exit_code, out, err = svntest.main.run_svn(None, 'diff', '--depth', 'empty', iota_path) if err: raise svntest.Failure if len(out) < 4: raise svntest.Failure # This used to abort with ra_serf. def diff_wrong_extension_type(sbox): "'svn diff -x wc -r#' should return error" sbox.build(read_only = True) svntest.actions.run_and_verify_svn([], err.INVALID_DIFF_OPTION, 'diff', '-x', sbox.wc_dir, '-r', '1') # Check the order of the arguments for an external diff tool def diff_external_diffcmd(sbox): "svn diff --diff-cmd provides the correct arguments" sbox.build(read_only = True) os.chdir(sbox.wc_dir) iota_path = 'iota' svntest.main.file_append(iota_path, "new text in iota") # Create a small diff mock object that prints its arguments to stdout. # (This path needs an explicit directory component to avoid searching.) diff_script_path = os.path.join('.', 'diff') # TODO: make the create function return the actual script name, and rename # it to something more generic. svntest.main.create_python_hook_script(diff_script_path, 'import sys\n' 'for arg in sys.argv[1:]:\n print(arg)\n') if sys.platform == 'win32': diff_script_path = "%s.bat" % diff_script_path expected_output = svntest.verify.ExpectedOutput([ "Index: iota\n", "===================================================================\n", "-u\n", "-L\n", "iota\t(revision 1)\n", "-L\n", "iota\t(working copy)\n", os.path.abspath(svntest.wc.text_base_path("iota")) + "\n", os.path.abspath("iota") + "\n"]) # Check that the output of diff corresponds with the expected arguments, # in the correct order. svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--diff-cmd', diff_script_path, iota_path) #---------------------------------------------------------------------- # Diffing an unrelated repository URL against working copy with # local modifications (i.e. not committed). This is issue #3295 (diff # local changes against arbitrary URL@REV ignores local add). # Helper def make_file_edit_del_add(dir): "make a file mod (M), a deletion (D) and an addition (A)." alpha = os.path.join(dir, 'B', 'E', 'alpha') beta = os.path.join(dir, 'B', 'E', 'beta') theta = os.path.join(dir, 'B', 'E', 'theta') # modify alpha, remove beta and add theta. svntest.main.file_append(alpha, "Edited file alpha.\n") svntest.main.run_svn(None, 'remove', beta) svntest.main.file_append(theta, "Created file theta.\n") svntest.main.run_svn(None, 'add', theta) @Issue(3295) def diff_url_against_local_mods(sbox): "diff URL against working copy with local mods" sbox.build() os.chdir(sbox.wc_dir) A = 'A' A_url = sbox.repo_url + '/A' # First, just make a copy. A2 = 'A2' A2_url = sbox.repo_url + '/A2' svntest.actions.run_and_verify_svn(None, [], 'cp', '-m', 'log msg', A_url, A2_url) svntest.actions.run_and_verify_svn(None, [], 'up') # In A, add, remove and change a file, and commit. make_file_edit_del_add(A) svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'committing A') # In A2, do the same changes but leave uncommitted. make_file_edit_del_add(A2) # Diff Path of A against working copy of A2. # Output using arbritrary diff handling should be empty. expected_output = [] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--old', A, '--new', A2) # Diff URL of A against working copy of A2. Output should be empty. expected_output = [] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--old', A_url, '--new', A2) #---------------------------------------------------------------------- # Diff against old revision of the parent directory of a removed and # locally re-added file. @Issue(3797) def diff_preexisting_rev_against_local_add(sbox): "diff -r1 of dir with removed-then-readded file" sbox.build() os.chdir(sbox.wc_dir) beta = os.path.join('A', 'B', 'E', 'beta') # remove svntest.main.run_svn(None, 'remove', beta) svntest.actions.run_and_verify_svn(None, [], 'ci', '-m', 'removing beta') # re-add, without committing svntest.main.file_append(beta, "Re-created file beta.\n") svntest.main.run_svn(None, 'add', beta) # diff against -r1, the diff should show both removal and re-addition exit_code, diff_output, err_output = svntest.main.run_svn( None, 'diff', '-r1', 'A') verify_expected_output(diff_output, "-This is the file 'beta'.") verify_expected_output(diff_output, "+Re-created file beta.") def diff_git_format_wc_wc(sbox): "create a diff in git unidiff format for wc-wc" sbox.build() wc_dir = sbox.wc_dir iota_path = sbox.ospath('iota') mu_path = sbox.ospath('A/mu') new_path = sbox.ospath('new') lambda_path = sbox.ospath('A/B/lambda') lambda_copied_path = sbox.ospath('A/B/lambda_copied') alpha_path = sbox.ospath('A/B/E/alpha') alpha_copied_path = sbox.ospath('A/B/E/alpha_copied') svntest.main.file_append(iota_path, "Changed 'iota'.\n") svntest.main.file_append(new_path, "This is the file 'new'.\n") svntest.main.run_svn(None, 'add', new_path) svntest.main.run_svn(None, 'rm', mu_path) svntest.main.run_svn(None, 'cp', lambda_path, lambda_copied_path) svntest.main.run_svn(None, 'cp', alpha_path, alpha_copied_path) svntest.main.file_append(alpha_copied_path, "This is a copy of 'alpha'.\n") ### We're not testing moved paths expected_output = make_git_diff_header( alpha_copied_path, "A/B/E/alpha_copied", "revision 1", "working copy", copyfrom_path="A/B/E/alpha", copyfrom_rev='1', cp=True, text_changes=True) + [ "@@ -1 +1,2 @@\n", " This is the file 'alpha'.\n", "+This is a copy of 'alpha'.\n", ] + make_git_diff_header(lambda_copied_path, "A/B/lambda_copied", "revision 1", "working copy", copyfrom_path="A/B/lambda", copyfrom_rev='1', cp=True, text_changes=False) \ + make_git_diff_header(mu_path, "A/mu", "revision 1", "nonexistent", delete=True) + [ "@@ -1 +0,0 @@\n", "-This is the file 'mu'.\n", ] + make_git_diff_header(iota_path, "iota", "revision 1", "working copy") + [ "@@ -1 +1,2 @@\n", " This is the file 'iota'.\n", "+Changed 'iota'.\n", ] + make_git_diff_header(new_path, "new", "nonexistent", "working copy", add=True) + [ "@@ -0,0 +1 @@\n", "+This is the file 'new'.\n", ] expected = expected_output svntest.actions.run_and_verify_svn(expected, [], 'diff', '--git', wc_dir) @Issue(4294) def diff_git_format_wc_wc_dir_mv(sbox): "create a diff in git unidff format for wc dir mv" sbox.build() wc_dir = sbox.wc_dir g_path = sbox.ospath('A/D/G') g2_path = sbox.ospath('A/D/G2') pi_path = sbox.ospath('A/D/G/pi') rho_path = sbox.ospath('A/D/G/rho') tau_path = sbox.ospath('A/D/G/tau') new_pi_path = sbox.ospath('A/D/G2/pi') new_rho_path = sbox.ospath('A/D/G2/rho') new_tau_path = sbox.ospath('A/D/G2/tau') svntest.main.run_svn(None, 'mv', g_path, g2_path) expected_output = make_git_diff_header(pi_path, "A/D/G/pi", "revision 1", "nonexistent", delete=True) \ + [ "@@ -1 +0,0 @@\n", "-This is the file 'pi'.\n" ] + make_git_diff_header(rho_path, "A/D/G/rho", "revision 1", "nonexistent", delete=True) \ + [ "@@ -1 +0,0 @@\n", "-This is the file 'rho'.\n" ] + make_git_diff_header(tau_path, "A/D/G/tau", "revision 1", "nonexistent", delete=True) \ + [ "@@ -1 +0,0 @@\n", "-This is the file 'tau'.\n" ] + make_git_diff_header(new_pi_path, "A/D/G2/pi", None, None, cp=True, copyfrom_path="A/D/G/pi", copyfrom_rev='1', text_changes=False) \ + make_git_diff_header(new_rho_path, "A/D/G2/rho", None, None, cp=True, copyfrom_path="A/D/G/rho", copyfrom_rev='1', text_changes=False) \ + make_git_diff_header(new_tau_path, "A/D/G2/tau", None, None, cp=True, copyfrom_path="A/D/G/tau", copyfrom_rev='1', text_changes=False) expected = expected_output svntest.actions.run_and_verify_svn(expected, [], 'diff', '--git', wc_dir) def diff_git_format_url_wc(sbox): "create a diff in git unidiff format for url-wc" sbox.build() wc_dir = sbox.wc_dir repo_url = sbox.repo_url iota_path = sbox.ospath('iota') mu_path = sbox.ospath('A/mu') new_path = sbox.ospath('new') svntest.main.file_append(iota_path, "Changed 'iota'.\n") svntest.main.file_append(new_path, "This is the file 'new'.\n") svntest.main.run_svn(None, 'add', new_path) svntest.main.run_svn(None, 'rm', mu_path) ### We're not testing copied or moved paths svntest.main.run_svn(None, 'commit', '-m', 'Committing changes', wc_dir) svntest.main.run_svn(None, 'up', wc_dir) expected_output = make_git_diff_header(new_path, "new", "nonexistent", "revision 2", add=True) + [ "@@ -0,0 +1 @@\n", "+This is the file 'new'.\n", ] + make_git_diff_header(mu_path, "A/mu", "revision 1", "nonexistent", delete=True) + [ "@@ -1 +0,0 @@\n", "-This is the file 'mu'.\n", ] + make_git_diff_header(iota_path, "iota", "revision 1", "working copy") + [ "@@ -1 +1,2 @@\n", " This is the file 'iota'.\n", "+Changed 'iota'.\n", ] expected = svntest.verify.UnorderedOutput(expected_output) svntest.actions.run_and_verify_svn(expected, [], 'diff', '--git', '--old', repo_url + '@1', '--new', wc_dir) def diff_git_format_url_url(sbox): "create a diff in git unidiff format for url-url" sbox.build() wc_dir = sbox.wc_dir repo_url = sbox.repo_url iota_path = sbox.ospath('iota') mu_path = sbox.ospath('A/mu') new_path = sbox.ospath('new') svntest.main.file_append(iota_path, "Changed 'iota'.\n") svntest.main.file_append(new_path, "This is the file 'new'.\n") svntest.main.run_svn(None, 'add', new_path) svntest.main.run_svn(None, 'rm', mu_path) ### We're not testing copied or moved paths. When we do, we will not be ### able to identify them as copies/moves until we have editor-v2. svntest.main.run_svn(None, 'commit', '-m', 'Committing changes', wc_dir) svntest.main.run_svn(None, 'up', wc_dir) expected_output = make_git_diff_header("A/mu", "A/mu", "revision 1", "nonexistent", delete=True) + [ "@@ -1 +0,0 @@\n", "-This is the file 'mu'.\n", ] + make_git_diff_header("new", "new", "nonexistent", "revision 2", add=True) + [ "@@ -0,0 +1 @@\n", "+This is the file 'new'.\n", ] + make_git_diff_header("iota", "iota", "revision 1", "revision 2") + [ "@@ -1 +1,2 @@\n", " This is the file 'iota'.\n", "+Changed 'iota'.\n", ] expected = svntest.verify.UnorderedOutput(expected_output) svntest.actions.run_and_verify_svn(expected, [], 'diff', '--git', '--old', repo_url + '@1', '--new', repo_url + '@2') # Regression test for an off-by-one error when printing intermediate context # lines. def diff_prop_missing_context(sbox): "diff for property has missing context" sbox.build() wc_dir = sbox.wc_dir iota_path = sbox.ospath('iota') prop_val = "".join([ "line 1\n", "line 2\n", "line 3\n", "line 4\n", "line 5\n", "line 6\n", "line 7\n", ]) svntest.main.run_svn(None, "propset", "prop", prop_val, iota_path) expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('iota', wc_rev=2) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) prop_val = "".join([ "line 3\n", "line 4\n", "line 5\n", "line 6\n", ]) svntest.main.run_svn(None, "propset", "prop", prop_val, iota_path) expected_output = make_diff_header(iota_path, 'revision 2', 'working copy') + \ make_diff_prop_header(iota_path) + [ "Modified: prop\n", "## -1,7 +1,4 ##\n", "-line 1\n", "-line 2\n", " line 3\n", " line 4\n", " line 5\n", " line 6\n", "-line 7\n", ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', iota_path) def diff_prop_multiple_hunks(sbox): "diff for property with multiple hunks" sbox.build() wc_dir = sbox.wc_dir iota_path = sbox.ospath('iota') prop_val = "".join([ "line 1\n", "line 2\n", "line 3\n", "line 4\n", "line 5\n", "line 6\n", "line 7\n", "line 8\n", "line 9\n", "line 10\n", "line 11\n", "line 12\n", "line 13\n", ]) svntest.main.run_svn(None, "propset", "prop", prop_val, iota_path) expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.tweak('iota', wc_rev=2) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) prop_val = "".join([ "line 1\n", "line 2\n", "line 3\n", "Add a line here\n", "line 4\n", "line 5\n", "line 6\n", "line 7\n", "line 8\n", "line 9\n", "line 10\n", "And add a line here\n", "line 11\n", "line 12\n", "line 13\n", ]) svntest.main.run_svn(None, "propset", "prop", prop_val, iota_path) expected_output = make_diff_header(iota_path, 'revision 2', 'working copy') + \ make_diff_prop_header(iota_path) + [ "Modified: prop\n", "## -1,6 +1,7 ##\n", " line 1\n", " line 2\n", " line 3\n", "+Add a line here\n", " line 4\n", " line 5\n", " line 6\n", "## -8,6 +9,7 ##\n", " line 8\n", " line 9\n", " line 10\n", "+And add a line here\n", " line 11\n", " line 12\n", " line 13\n", ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', iota_path) def diff_git_empty_files(sbox): "create a diff in git format for empty files" sbox.build() wc_dir = sbox.wc_dir iota_path = sbox.ospath('iota') new_path = sbox.ospath('new') svntest.main.file_write(iota_path, "") # Now commit the local mod, creating rev 2. expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'iota' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) svntest.main.file_write(new_path, "") svntest.main.run_svn(None, 'add', new_path) svntest.main.run_svn(None, 'rm', iota_path) expected_output = make_git_diff_header(new_path, "new", "nonexistent", "working copy", add=True, text_changes=False) + [ ] + make_git_diff_header(iota_path, "iota", "revision 2", "working copy", delete=True, text_changes=False) # Two files in diff may be in any order. expected_output = svntest.verify.UnorderedOutput(expected_output) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--git', wc_dir) def diff_git_with_props(sbox): "create a diff in git format showing prop changes" sbox.build() wc_dir = sbox.wc_dir iota_path = sbox.ospath('iota') new_path = sbox.ospath('new') svntest.main.file_write(iota_path, "") # Now commit the local mod, creating rev 2. expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'iota' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) svntest.main.file_write(new_path, "") svntest.main.run_svn(None, 'add', new_path) svntest.main.run_svn(None, 'propset', 'svn:eol-style', 'native', new_path) svntest.main.run_svn(None, 'propset', 'svn:keywords', 'Id', iota_path) expected_output = make_git_diff_header(new_path, "new", "nonexistent", "working copy", add=True, text_changes=False) + \ make_diff_prop_header("new") + \ make_diff_prop_added("svn:eol-style", "native") + \ make_git_diff_header(iota_path, "iota", "revision 2", "working copy", text_changes=False) + \ make_diff_prop_header("iota") + \ make_diff_prop_added("svn:keywords", "Id") # Files in diff may be in any order. expected_output = svntest.verify.UnorderedOutput(expected_output) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--git', wc_dir) @Issue(4010) def diff_correct_wc_base_revnum(sbox): "diff WC-WC shows the correct base rev num" sbox.build() wc_dir = sbox.wc_dir iota_path = sbox.ospath('iota') svntest.main.file_write(iota_path, "") # Commit a local mod, creating rev 2. expected_output = svntest.wc.State(wc_dir, { 'iota' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ 'iota' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) # Child's base is now 2; parent's is still 1. # Make a local mod. svntest.main.run_svn(None, 'propset', 'svn:keywords', 'Id', iota_path) expected_output = make_git_diff_header(iota_path, "iota", "revision 2", "working copy") + \ make_diff_prop_header("iota") + \ make_diff_prop_added("svn:keywords", "Id") # Diff the parent. svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--git', wc_dir) # The same again, but specifying the target explicitly. This should # give the same output. svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--git', iota_path) def diff_git_with_props_on_dir(sbox): "diff in git format showing prop changes on dir" sbox.build() wc_dir = sbox.wc_dir # Now commit the local mod, creating rev 2. expected_output = svntest.wc.State(wc_dir, { '.' : Item(verb='Sending'), 'A' : Item(verb='Sending'), }) expected_status = svntest.actions.get_virginal_state(wc_dir, 1) expected_status.add({ '' : Item(status=' ', wc_rev=2), }) expected_status.tweak('A', wc_rev=2) sbox.simple_propset('k','v', '', 'A') svntest.actions.run_and_verify_commit(wc_dir, expected_output, expected_status) was_cwd = os.getcwd() os.chdir(wc_dir) expected_output = make_git_diff_header("A", "A", "revision 1", "revision 2", add=False, text_changes=False) + \ make_diff_prop_header("A") + \ make_diff_prop_added("k", "v") + \ make_git_diff_header(".", "", "revision 1", "revision 2", add=False, text_changes=False) + \ make_diff_prop_header("") + \ make_diff_prop_added("k", "v") svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-c2', '--git') os.chdir(was_cwd) @Issue(3826) def diff_abs_localpath_from_wc_folder(sbox): "diff absolute localpath from wc folder" sbox.build(read_only = True) wc_dir = sbox.wc_dir A_path = sbox.ospath('A') B_abs_path = os.path.abspath(sbox.ospath('A/B')) os.chdir(os.path.abspath(A_path)) svntest.actions.run_and_verify_svn(None, [], 'diff', B_abs_path) @Issue(3449) def no_spurious_conflict(sbox): "no spurious conflict on update" sbox.build() wc_dir = sbox.wc_dir svntest.actions.do_sleep_for_timestamps() data_dir = os.path.join(os.path.dirname(sys.argv[0]), 'diff_tests_data') shutil.copyfile(os.path.join(data_dir, '3449_spurious_v1'), sbox.ospath('3449_spurious')) svntest.actions.run_and_verify_svn(None, [], 'add', sbox.ospath('3449_spurious')) sbox.simple_commit() shutil.copyfile(os.path.join(data_dir, '3449_spurious_v2'), sbox.ospath('3449_spurious')) sbox.simple_commit() shutil.copyfile(os.path.join(data_dir, '3449_spurious_v3'), sbox.ospath('3449_spurious')) sbox.simple_commit() svntest.actions.run_and_verify_svn(None, [], 'update', '-r2', wc_dir) svntest.actions.run_and_verify_svn(None, [], 'merge', '-c4', '^/', wc_dir) expected_status = svntest.actions.get_virginal_state(wc_dir, 2) expected_status.tweak('', status=' M') expected_status.add({ '3449_spurious' : Item(status='M ', wc_rev=2), }) svntest.actions.run_and_verify_status(wc_dir, expected_status) # This update produces a conflict in 1.6 svntest.actions.run_and_verify_svn(None, [], 'update', '--accept', 'postpone', wc_dir) expected_status.tweak(wc_rev=4) expected_status.tweak('3449_spurious', status=' ') svntest.actions.run_and_verify_status(wc_dir, expected_status) def diff_two_working_copies(sbox): "diff between two working copies" sbox.build() wc_dir = sbox.wc_dir # Create a pristine working copy that will remain mostly unchanged wc_dir_old = sbox.add_wc_path('old') svntest.main.run_svn(None, 'co', sbox.repo_url, wc_dir_old) # Add a property to A/B/F in the pristine working copy svntest.main.run_svn(None, 'propset', 'newprop', 'propval-old\n', os.path.join(wc_dir_old, 'A', 'B', 'F')) # Make changes to the first working copy: # removed nodes sbox.simple_rm('A/mu') sbox.simple_rm('A/D/H') # new nodes sbox.simple_mkdir('newdir') svntest.main.file_append(sbox.ospath('newdir/newfile'), 'new text\n') sbox.simple_add('newdir/newfile') sbox.simple_mkdir('newdir/newdir2') # should not show up in the diff # modified nodes sbox.simple_propset('newprop', 'propval', 'A/D') sbox.simple_propset('newprop', 'propval', 'A/D/gamma') svntest.main.file_append(sbox.ospath('A/B/lambda'), 'new text\n') # replaced nodes (files vs. directories) with property mods sbox.simple_rm('A/B/F') svntest.main.file_append(sbox.ospath('A/B/F'), 'new text\n') sbox.simple_add('A/B/F') sbox.simple_propset('newprop', 'propval-new\n', 'A/B/F') sbox.simple_rm('A/D/G/pi') sbox.simple_mkdir('A/D/G/pi') sbox.simple_propset('newprop', 'propval', 'A/D/G/pi') src_label = os.path.basename(wc_dir_old) dst_label = os.path.basename(wc_dir) expected_output = make_diff_header('newdir/newfile', 'nonexistent', 'working copy', src_label, dst_label) + [ "@@ -0,0 +1 @@\n", "+new text\n", ] + make_diff_header('A/mu', 'working copy', 'nonexistent', src_label, dst_label) + [ "@@ -1 +0,0 @@\n", "-This is the file 'mu'.\n", ] + make_diff_header('A/B/F', 'nonexistent', 'working copy', src_label, dst_label) + [ "@@ -0,0 +1 @@\n", "+new text\n", ] + make_diff_prop_header('A/B/F') + \ make_diff_prop_added("newprop", "propval-new\n") + \ make_diff_header('A/B/lambda', 'working copy', 'working copy', src_label, dst_label) + [ "@@ -1 +1,2 @@\n", " This is the file 'lambda'.\n", "+new text\n", ] + make_diff_header('A/D', 'working copy', 'working copy', src_label, dst_label) + \ make_diff_prop_header('A/D') + \ make_diff_prop_added("newprop", "propval") + \ make_diff_header('A/D/gamma', 'working copy', 'working copy', src_label, dst_label) + \ make_diff_prop_header('A/D/gamma') + \ make_diff_prop_added("newprop", "propval") + \ make_diff_header('A/D/G/pi', 'working copy', 'nonexistent', src_label, dst_label) + [ "@@ -1 +0,0 @@\n", "-This is the file 'pi'.\n", ] + make_diff_header('A/D/G/pi', 'nonexistent', 'working copy', src_label, dst_label) + \ make_diff_prop_header('A/D/G/pi') + \ make_diff_prop_added("newprop", "propval") + \ make_diff_header('A/D/H/chi', 'working copy', 'nonexistent', src_label, dst_label) + [ "@@ -1 +0,0 @@\n", "-This is the file 'chi'.\n", ] + make_diff_header('A/D/H/omega', 'working copy', 'nonexistent', src_label, dst_label) + [ "@@ -1 +0,0 @@\n", "-This is the file 'omega'.\n", ] + make_diff_header('A/D/H/psi', 'working copy', 'nonexistent', src_label, dst_label) + [ "@@ -1 +0,0 @@\n", "-This is the file 'psi'.\n", ] + make_diff_header('A/B/F', 'working copy', 'nonexistent', src_label, dst_label) + \ make_diff_prop_header('A/B/F') + \ make_diff_prop_deleted('newprop', 'propval-old\n') # Files in diff may be in any order. #### Not any more, but test order is wrong. expected_output = svntest.verify.UnorderedOutput(expected_output) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--old', wc_dir_old, '--new', wc_dir) def diff_deleted_url(sbox): "diff -cN of URL deleted in rN" sbox.build() wc_dir = sbox.wc_dir # remove A/D/H in r2 sbox.simple_rm("A/D/H") sbox.simple_commit() # A diff of r2 with target A/D/H should show the removed children expected_output = make_diff_header("chi", "revision 1", "nonexistent") + [ "@@ -1 +0,0 @@\n", "-This is the file 'chi'.\n", ] + make_diff_header("omega", "revision 1", "nonexistent") + [ "@@ -1 +0,0 @@\n", "-This is the file 'omega'.\n", ] + make_diff_header("psi", "revision 1", "nonexistent") + [ "@@ -1 +0,0 @@\n", "-This is the file 'psi'.\n", ] # Files in diff may be in any order. expected_output = svntest.verify.UnorderedOutput(expected_output) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-c2', sbox.repo_url + '/A/D/H') def diff_arbitrary_files_and_dirs(sbox): "diff arbitrary files and dirs" sbox.build() wc_dir = sbox.wc_dir # diff iota with A/mu expected_output = make_diff_header("iota", "working copy", "working copy", "iota", "A/mu") + [ "@@ -1 +1 @@\n", "-This is the file 'iota'.\n", "+This is the file 'mu'.\n" ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--old', sbox.ospath('iota'), '--new', sbox.ospath('A/mu')) # diff A/B/E with A/D expected_output = make_diff_header("G/pi", "nonexistent", "working copy", "B/E", "D") + [ "@@ -0,0 +1 @@\n", "+This is the file 'pi'.\n" ] + make_diff_header("G/rho", "nonexistent", "working copy", "B/E", "D") + [ "@@ -0,0 +1 @@\n", "+This is the file 'rho'.\n" ] + make_diff_header("G/tau", "nonexistent", "working copy", "B/E", "D") + [ "@@ -0,0 +1 @@\n", "+This is the file 'tau'.\n" ] + make_diff_header("H/chi", "nonexistent", "working copy", "B/E", "D") + [ "@@ -0,0 +1 @@\n", "+This is the file 'chi'.\n" ] + make_diff_header("H/omega", "nonexistent", "working copy", "B/E", "D") + [ "@@ -0,0 +1 @@\n", "+This is the file 'omega'.\n" ] + make_diff_header("H/psi", "nonexistent", "working copy", "B/E", "D") + [ "@@ -0,0 +1 @@\n", "+This is the file 'psi'.\n" ] + make_diff_header("alpha", "working copy", "nonexistent", "B/E", "D") + [ "@@ -1 +0,0 @@\n", "-This is the file 'alpha'.\n" ] + make_diff_header("beta", "working copy", "nonexistent", "B/E", "D") + [ "@@ -1 +0,0 @@\n", "-This is the file 'beta'.\n" ] + make_diff_header("gamma", "nonexistent", "working copy", "B/E", "D") + [ "@@ -0,0 +1 @@\n", "+This is the file 'gamma'.\n" ] # Files in diff may be in any order. expected_output = svntest.verify.UnorderedOutput(expected_output) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--old', sbox.ospath('A/B/E'), '--new', sbox.ospath('A/D')) def diff_properties_only(sbox): "diff --properties-only" sbox.build() wc_dir = sbox.wc_dir expected_output = \ make_diff_header("iota", "revision 1", "revision 2") + \ make_diff_prop_header("iota") + \ make_diff_prop_added("svn:eol-style", "native") expected_reverse_output = \ make_diff_header("iota", "revision 2", "revision 1") + \ make_diff_prop_header("iota") + \ make_diff_prop_deleted("svn:eol-style", "native") expected_rev1_output = \ make_diff_header("iota", "revision 1", "working copy") + \ make_diff_prop_header("iota") + \ make_diff_prop_added("svn:eol-style", "native") # Make a property change and a content change to 'iota' # Only the property change should be displayed by diff --properties-only sbox.simple_propset('svn:eol-style', 'native', 'iota') svntest.main.file_append(sbox.ospath('iota'), 'new text') sbox.simple_commit() # r2 svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--properties-only', '-r', '1:2', sbox.repo_url + '/iota') svntest.actions.run_and_verify_svn(expected_reverse_output, [], 'diff', '--properties-only', '-r', '2:1', sbox.repo_url + '/iota') os.chdir(wc_dir) svntest.actions.run_and_verify_svn(expected_rev1_output, [], 'diff', '--properties-only', '-r', '1', 'iota') svntest.actions.run_and_verify_svn(expected_rev1_output, [], 'diff', '--properties-only', '-r', 'PREV', 'iota') def diff_properties_no_newline(sbox): "diff props; check no-newline-at-end messages" sbox.build() old_cwd = os.getcwd() os.chdir(sbox.wc_dir) sbox.wc_dir = '' no_nl = "\\ No newline at end of property\n" propchange_header = "Modified: p.*\n" subtests = [ ('p1', 'val1', 'val2' ), ('p2', 'val1', 'val2\n'), ('p3', 'val1\n', 'val2' ), ('p4', 'val1\n', 'val2\n'), ] # The "before" state. for pname, old_val, new_val in subtests: sbox.simple_propset(pname, old_val, 'iota') sbox.simple_commit() # r2 # Test one change at a time. (Because, with multiple changes, the order # may not be predictable.) for pname, old_val, new_val in subtests: expected_output = \ make_diff_header("iota", "revision 2", "working copy") + \ make_diff_prop_header("iota") + \ make_diff_prop_modified(pname, old_val, new_val) sbox.simple_propset(pname, new_val, 'iota') svntest.actions.run_and_verify_svn(expected_output, [], 'diff') svntest.actions.run_and_verify_svn(None, [], 'revert', 'iota') os.chdir(old_cwd) def diff_arbitrary_same(sbox): "diff arbitrary files and dirs but same" sbox.build(read_only = True) sbox.simple_propset('k', 'v', 'A', 'A/mu', 'A/D/G/pi') svntest.main.file_write(sbox.ospath('A/mu'), "new mu") sbox.simple_copy('A', 'A2') svntest.actions.run_and_verify_svn([], [], 'diff', '--old', sbox.ospath('A'), '--new', sbox.ospath('A2')) svntest.actions.run_and_verify_svn([], [], 'diff', '--summarize', '--old', sbox.ospath('A'), '--new', sbox.ospath('A2')) def simple_ancestry(sbox): "diff some simple ancestry changes" sbox.build() sbox.simple_copy('A/B/E', 'A/B/E_copied') sbox.simple_copy('A/D/G/pi', 'A/D/G/pi-2') sbox.simple_copy('A/D/G/rho', 'A/D/G/rho-2') sbox.simple_rm('A/B/F', 'A/B/E', 'A/D/G/rho', 'A/D/G/tau') sbox.simple_add_text('new', 'new') line = '===================================================================\n' expected_output = svntest.verify.UnorderedOutput([ 'Index: %s (added)\n' % sbox.path('new'), line, 'Index: %s (deleted)\n' % sbox.path('A/B/E/alpha'), line, 'Index: %s (deleted)\n' % sbox.path('A/B/E/beta'), line, 'Index: %s (added)\n' % sbox.path('A/B/E_copied/beta'), line, 'Index: %s (added)\n' % sbox.path('A/B/E_copied/alpha'), line, 'Index: %s (added)\n' % sbox.path('A/D/G/pi-2'), line, 'Index: %s (deleted)\n' % sbox.path('A/D/G/rho'), line, 'Index: %s (added)\n' % sbox.path('A/D/G/rho-2'), line, 'Index: %s (deleted)\n' % sbox.path('A/D/G/tau'), line, ]) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', sbox.wc_dir, '-r', '1', '--notice-ancestry', '--no-diff-deleted', '--show-copies-as-adds', '--no-diff-added') # And try the same thing in reverse sbox.simple_commit() sbox.simple_update(revision=1) expected_output = svntest.verify.UnorderedOutput([ 'Index: %s (deleted)\n' % sbox.path('new'), line, 'Index: %s (added)\n' % sbox.path('A/B/E/alpha'), line, 'Index: %s (added)\n' % sbox.path('A/B/E/beta'), line, 'Index: %s (deleted)\n' % sbox.path('A/B/E_copied/beta'), line, 'Index: %s (deleted)\n' % sbox.path('A/B/E_copied/alpha'), line, 'Index: %s (deleted)\n' % sbox.path('A/D/G/pi-2'), line, 'Index: %s (added)\n' % sbox.path('A/D/G/rho'), line, 'Index: %s (deleted)\n' % sbox.path('A/D/G/rho-2'), line, 'Index: %s (added)\n' % sbox.path('A/D/G/tau'), line, ]) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', sbox.wc_dir, '-r', 'HEAD', '--notice-ancestry', '--no-diff-deleted', '--show-copies-as-adds', '--no-diff-added') # Now introduce a replacements and some delete-deletes sbox.simple_update() sbox.simple_mkdir('A/B/E') sbox.simple_add_text('New alpha', 'A/B/E/alpha') sbox.simple_add_text('New beta', 'A/B/E/beta') sbox.simple_add_text('New rho', 'A/D/G/rho') sbox.simple_add_text('New tau', 'A/D/G/tau') sbox.simple_rm('A/B/E_copied', 'A/D/G/pi-2', 'A/D/G/rho-2') expected_output = svntest.verify.UnorderedOutput([ 'Index: %s (added)\n' % sbox.path('new'), line, 'Index: %s (deleted)\n' % sbox.path('A/B/E/alpha'), line, 'Index: %s (deleted)\n' % sbox.path('A/B/E/beta'), line, 'Index: %s (added)\n' % sbox.path('A/B/E/alpha'), line, 'Index: %s (added)\n' % sbox.path('A/B/E/beta'), line, 'Index: %s (deleted)\n' % sbox.path('A/D/G/rho'), line, 'Index: %s (added)\n' % sbox.path('A/D/G/rho'), line, 'Index: %s (deleted)\n' % sbox.path('A/D/G/tau'), line, 'Index: %s (added)\n' % sbox.path('A/D/G/tau'), line, ]) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', sbox.wc_dir, '-r', '1', '--notice-ancestry', '--no-diff-deleted', '--show-copies-as-adds', '--no-diff-added') sbox.simple_commit() sbox.simple_update() svntest.actions.run_and_verify_svn(expected_output, [], 'diff', sbox.wc_dir, '-r', '1', '--notice-ancestry', '--no-diff-deleted', '--show-copies-as-adds', '--no-diff-added') def local_tree_replace(sbox): "diff a replaced tree" sbox.build() wc_dir = sbox.wc_dir sbox.simple_add_text('extra', 'A/B/F/extra') sbox.simple_commit() svntest.actions.run_and_verify_svn(None, [], 'rm', '--keep-local', sbox.ospath('A/B')) svntest.actions.run_and_verify_svn(None, [], 'add', sbox.ospath('A/B')) # And now check with ancestry line = '===================================================================\n' expected_output = svntest.verify.UnorderedOutput([ 'Index: %s (deleted)\n' % sbox.path('A/B/lambda'), line, 'Index: %s (deleted)\n' % sbox.path('A/B/E/alpha'), line, 'Index: %s (deleted)\n' % sbox.path('A/B/E/beta'), line, 'Index: %s (deleted)\n' % sbox.path('A/B/F/extra'), line, 'Index: %s (added)\n' % sbox.path('A/B/lambda'), line, 'Index: %s (added)\n' % sbox.path('A/B/E/alpha'), line, 'Index: %s (added)\n' % sbox.path('A/B/E/beta'), line, 'Index: %s (added)\n' % sbox.path('A/B/F/extra'), line, ]) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', wc_dir, '-r', '2', '--notice-ancestry', '--show-copies-as-adds', '--no-diff-added', '--no-diff-deleted') # Now create patches to verify the tree ordering patch = os.path.abspath(os.path.join(wc_dir, 'ancestry.patch')) cwd = os.getcwd() os.chdir(wc_dir) _, out, _ = svntest.actions.run_and_verify_svn(None, [], 'diff', '.', '-r', '2', '--notice-ancestry', '--show-copies-as-adds') svntest.main.file_append(patch, ''.join(out)) os.chdir(cwd) # And try to apply it svntest.actions.run_and_verify_svn(None, [], 'revert', '-R', wc_dir) expected_output = svntest.verify.UnorderedOutput([ 'D %s\n' % sbox.ospath('A/B/F/extra'), 'D %s\n' % sbox.ospath('A/B/F'), 'D %s\n' % sbox.ospath('A/B/E/beta'), 'D %s\n' % sbox.ospath('A/B/E/alpha'), 'D %s\n' % sbox.ospath('A/B/E'), 'D %s\n' % sbox.ospath('A/B/lambda'), 'D %s\n' % sbox.ospath('A/B'), 'A %s\n' % sbox.ospath('A/B'), 'A %s\n' % sbox.ospath('A/B/lambda'), 'A %s\n' % sbox.ospath('A/B/F'), 'A %s\n' % sbox.ospath('A/B/F/extra'), 'A %s\n' % sbox.ospath('A/B/E'), 'A %s\n' % sbox.ospath('A/B/E/beta'), 'A %s\n' % sbox.ospath('A/B/E/alpha'), ]) # And this currently fails because the ordering is broken, but also # because it hits an issue in 'svn patch' svntest.actions.run_and_verify_svn(expected_output, [], 'patch', patch, wc_dir) def diff_dir_replaced_by_file(sbox): "diff a directory replaced by a file" sbox.build() wc_dir = sbox.wc_dir sbox.simple_rm('A/B/E') sbox.simple_add_text('text', 'A/B/E') expected_output = [ 'Index: %s\n' % sbox.path('A/B/E/alpha'), '===================================================================\n', '--- %s\t(revision 1)\n' % sbox.path('A/B/E/alpha'), '+++ %s\t(nonexistent)\n' % sbox.path('A/B/E/alpha'), '@@ -1 +0,0 @@\n', '-This is the file \'alpha\'.\n', 'Index: %s\n' % sbox.path('A/B/E/beta'), '===================================================================\n', '--- %s\t(revision 1)\n' % sbox.path('A/B/E/beta'), '+++ %s\t(nonexistent)\n' % sbox.path('A/B/E/beta'), '@@ -1 +0,0 @@\n', '-This is the file \'beta\'.\n', 'Index: %s\n' % sbox.path('A/B/E'), '===================================================================\n', '--- %s\t(nonexistent)\n' % sbox.path('A/B/E'), '+++ %s\t(working copy)\n' % sbox.path('A/B/E'), '@@ -0,0 +1 @@\n', '+text\n', '\ No newline at end of file\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', wc_dir) def diff_dir_replaced_by_dir(sbox): "diff a directory replaced by a directory tree" sbox.build() wc_dir = sbox.wc_dir sbox.simple_rm('A/B/E') sbox.simple_mkdir('A/B/E') sbox.simple_propset('a', 'b\n', 'A/B/E') sbox.simple_add_text('New beta\n', 'A/B/E/beta') # First check with ancestry (Tree replace) expected_output = [ 'Index: %s\n' % sbox.path('A/B/E/alpha'), '===================================================================\n', '--- %s\t(revision 1)\n' % sbox.path('A/B/E/alpha'), '+++ %s\t(nonexistent)\n' % sbox.path('A/B/E/alpha'), '@@ -1 +0,0 @@\n', '-This is the file \'alpha\'.\n', 'Index: %s\n' % sbox.path('A/B/E/beta'), '===================================================================\n', '--- %s\t(revision 1)\n' % sbox.path('A/B/E/beta'), '+++ %s\t(nonexistent)\n' % sbox.path('A/B/E/beta'), '@@ -1 +0,0 @@\n', '-This is the file \'beta\'.\n', 'Index: %s\n' % sbox.path('A/B/E/beta'), '===================================================================\n', '--- %s\t(nonexistent)\n' % sbox.path('A/B/E/beta'), '+++ %s\t(working copy)\n' % sbox.path('A/B/E/beta'), '@@ -0,0 +1 @@\n', '+New beta\n', 'Index: %s\n' % sbox.path('A/B/E'), '===================================================================\n', '--- %s\t(nonexistent)\n' % sbox.path('A/B/E'), '+++ %s\t(working copy)\n' % sbox.path('A/B/E'), '\n', 'Property changes on: %s\n' % sbox.path('A/B/E'), '___________________________________________________________________\n', 'Added: a\n', '## -0,0 +1 ##\n', '+b\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--notice-ancestry', wc_dir) # And summarized. Currently produces directory adds after their children expected_output = svntest.verify.UnorderedOutput([ 'D %s\n' % sbox.ospath('A/B/E/alpha'), 'D %s\n' % sbox.ospath('A/B/E/beta'), 'D %s\n' % sbox.ospath('A/B/E'), 'A %s\n' % sbox.ospath('A/B/E'), 'A %s\n' % sbox.ospath('A/B/E/beta'), ]) svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--summarize', wc_dir, '--notice-ancestry') # And now without (file delete, change + properties) expected_output = [ 'Index: %s\n' % sbox.path('A/B/E/alpha'), '===================================================================\n', '--- %s\t(revision 1)\n' % sbox.path('A/B/E/alpha'), '+++ %s\t(nonexistent)\n' % sbox.path('A/B/E/alpha'), '@@ -1 +0,0 @@\n', '-This is the file \'alpha\'.\n', 'Index: %s\n' % sbox.path('A/B/E/beta'), '===================================================================\n', '--- %s\t(revision 1)\n' % sbox.path('A/B/E/beta'), '+++ %s\t(working copy)\n' % sbox.path('A/B/E/beta'), '@@ -1 +1 @@\n', '-This is the file \'beta\'.\n', '+New beta\n', 'Index: %s\n' % sbox.path('A/B/E'), '===================================================================\n', '--- %s\t(revision 1)\n' % sbox.path('A/B/E'), '+++ %s\t(working copy)\n' % sbox.path('A/B/E'), '\n', 'Property changes on: %s\n' % sbox.path('A/B/E'), '___________________________________________________________________\n', 'Added: a\n', '## -0,0 +1 ##\n', '+b\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', wc_dir) expected_output = [ 'D %s\n' % sbox.ospath('A/B/E/alpha'), 'M %s\n' % sbox.ospath('A/B/E/beta'), ' M %s\n' % sbox.ospath('A/B/E'), ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--summarize', wc_dir) @Issue(4366) def diff_repos_empty_file_addition(sbox): "repos diff of rev which adds empty file" sbox.build() wc_dir = sbox.wc_dir # Add and commit an empty file. svntest.main.file_append(sbox.ospath('newfile'), "") svntest.main.run_svn(None, 'add', sbox.ospath('newfile')) expected_output = svntest.wc.State(sbox.wc_dir, { 'newfile': Item(verb='Adding'), }) expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1) expected_status.add({ 'newfile' : Item(status=' ', wc_rev=2), }) svntest.actions.run_and_verify_commit(sbox.wc_dir, expected_output, expected_status) # Now diff the revision that added the empty file. expected_output = [ 'Index: newfile\n', '===================================================================\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-c', '2', sbox.repo_url) def diff_missing_tree_conflict_victim(sbox): "diff with missing tree-conflict victim in wc" sbox.build() wc_dir = sbox.wc_dir # Produce an 'incoming edit vs. local missing' tree conflict: # r2: edit iota and commit the change svntest.main.file_append(sbox.ospath('iota'), "This is a change to iota.\n") sbox.simple_propset('k', 'v', 'A/C') sbox.simple_commit() # now remove iota sbox.simple_rm('iota', 'A/C') sbox.simple_commit() # update to avoid mixed-rev wc warning sbox.simple_update() # merge r2 into wc and verify that a tree conflict is flagged on iota expected_output = wc.State(wc_dir, { 'iota' : Item(status=' ', treeconflict='C'), 'A/C' : Item(status=' ', treeconflict='C') }) expected_mergeinfo_output = wc.State(wc_dir, {}) expected_elision_output = wc.State(wc_dir, {}) expected_disk = svntest.main.greek_state.copy() expected_disk.remove('iota','A/C') expected_status = svntest.actions.get_virginal_state(wc_dir, 3) expected_status.tweak('iota', 'A/C', status='! ', treeconflict='C', wc_rev=None) expected_skip = wc.State('', { }) svntest.actions.run_and_verify_merge(wc_dir, '1', '2', sbox.repo_url, None, expected_output, expected_mergeinfo_output, expected_elision_output, expected_disk, expected_status, expected_skip, [], False, False, '--ignore-ancestry', wc_dir) # 'svn diff' should show no change for the working copy # This currently fails because svn errors out with a 'node not found' error expected_output = [ ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', wc_dir) @Issue(4396) def diff_local_missing_obstruction(sbox): "diff local missing and obstructed files" sbox.build(read_only=True) wc_dir = sbox.wc_dir os.unlink(sbox.ospath('iota')) os.unlink(sbox.ospath('A/mu')) os.mkdir(sbox.ospath('A/mu')) # Expect no output for missing and obstructed files expected_output = [ ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', wc_dir) sbox.simple_propset('K', 'V', 'iota', 'A/mu') sbox.simple_append('IotA', 'Content') # But do expect a proper property diff expected_output = [ 'Index: %s\n' % (sbox.path('A/mu'),), '===================================================================\n', '--- %s\t(revision 1)\n' % (sbox.path('A/mu'),), '+++ %s\t(working copy)\n' % (sbox.path('A/mu'),), '\n', 'Property changes on: %s\n' % (sbox.path('A/mu'),), '___________________________________________________________________\n', 'Added: K\n', '## -0,0 +1 ##\n', '+V\n', '\ No newline at end of property\n', 'Index: %s\n' % (sbox.path('iota'),), '===================================================================\n', '--- %s\t(revision 1)\n' % (sbox.path('iota'),), '+++ %s\t(working copy)\n' % (sbox.path('iota'),), '\n', 'Property changes on: %s\n' % (sbox.path('iota'),), '___________________________________________________________________\n', 'Added: K\n', '## -0,0 +1 ##\n', '+V\n', '\ No newline at end of property\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', wc_dir) # Create an external. This produces an error in 1.8.0. sbox.simple_propset('svn:externals', 'AA/BB ' + sbox.repo_url + '/A', '.') sbox.simple_update() svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], 'diff', wc_dir) @Issue(4444) def diff_move_inside_copy(sbox): "diff copied-along child that contains a moved file" sbox.build(read_only=True) wc_dir = sbox.wc_dir d_path = 'A/D' d_copy = 'A/D-copy' h_path = 'A/D-copy/H' chi_path = '%s/chi' % h_path chi_moved = '%s/chi-moved' % h_path sbox.simple_copy(d_path, d_copy) sbox.simple_move(chi_path, chi_moved) sbox.simple_append(chi_moved, 'a new line') # Bug: Diffing the copied-along parent directory asserts svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], 'diff', sbox.ospath(h_path)) @XFail() @Issue(4464) def diff_repo_wc_copies(sbox): "diff repo to wc of a copy" sbox.build() wc_dir = sbox.wc_dir iota_copy = sbox.ospath('iota_copy') iota_url = sbox.repo_url + '/iota' sbox.simple_copy('iota', 'iota_copy') expected_output = make_diff_header(iota_copy, "nonexistent", "working copy", iota_url, iota_copy) + [ "@@ -0,0 +1 @@\n", "+This is the file 'iota'.\n" ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--show-copies-as-adds', iota_url, iota_copy) @Issue(4460) def diff_repo_wc_file_props(sbox): "diff repo to wc file target with props" sbox.build() iota = sbox.ospath('iota') # add a mime-type and a line to iota to test the binary check sbox.simple_propset('svn:mime-type', 'text/plain', 'iota') sbox.simple_append('iota','second line\n') # test that we get the line and the property add expected_output = make_diff_header(iota, 'revision 1', 'working copy') + \ [ '@@ -1 +1,2 @@\n', " This is the file 'iota'.\n", "+second line\n", ] + \ make_diff_prop_header(iota) + \ make_diff_prop_added('svn:mime-type', 'text/plain') svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r1', iota) # reverse the diff, should get a property delete and line delete expected_output = make_diff_header(iota, 'working copy', 'revision 1') + \ [ '@@ -1,2 +1 @@\n', " This is the file 'iota'.\n", "-second line\n", ] + \ make_diff_prop_header(iota) + \ make_diff_prop_deleted('svn:mime-type', 'text/plain') svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '--old', iota, '--new', iota + '@1') # copy iota to test with --show-copies as adds sbox.simple_copy('iota', 'iota_copy') iota_copy = sbox.ospath('iota_copy') # test that we get all lines as added and the property added # TODO: We only test that this test doesn't error out because of Issue #4464 # if and when that issue is fixed this test should check output svntest.actions.run_and_verify_svn(None, [], 'diff', '--show-copies-as-adds', '-r1', iota_copy) # reverse the diff, should get all lines as a delete and no property # TODO: We only test that this test doesn't error out because of Issue #4464 # if and when that issue is fixed this test should check output svntest.actions.run_and_verify_svn(None, [], 'diff', '--show-copies-as-adds', '--old', iota_copy, '--new', iota + '@1') # revert and commit with the eol-style of LF and then update so # that we can see a change on either windows or *nix. sbox.simple_revert('iota', 'iota_copy') sbox.simple_propset('svn:eol-style', 'LF', 'iota') sbox.simple_commit() #r2 sbox.simple_update() # now that we have a LF file on disk switch to CRLF sbox.simple_propset('svn:eol-style', 'CRLF', 'iota') # test that not only the property but also the file changes # i.e. that the line endings substitution works if svntest.main.is_os_windows(): # test suite normalizes crlf output into just lf on Windows. # so we have to assume it worked because there is an add and # remove line with the same content. Fortunately, it doesn't # do this on *nix so we can be pretty sure that it works right. # TODO: Provide a way to handle this better crlf = '\n' else: crlf = '\r\n' expected_output = make_diff_header(iota, 'revision 1', 'working copy') + \ [ '@@ -1 +1 @@\n', "-This is the file 'iota'.\n", "+This is the file 'iota'." + crlf ] + \ make_diff_prop_header(iota) + \ make_diff_prop_added('svn:eol-style', 'CRLF') svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r1', iota) @Issue(4460) def diff_repo_repo_added_file_mime_type(sbox): "diff repo to repo added file with mime-type" sbox.build() wc_dir = sbox.wc_dir newfile = sbox.ospath('newfile') # add a file with a mime-type sbox.simple_append('newfile', "This is the file 'newfile'.\n") sbox.simple_add('newfile') sbox.simple_propset('svn:mime-type', 'text/plain', 'newfile') sbox.simple_commit() # r2 # try to diff across the addition expected_output = make_diff_header(newfile, 'nonexistent', 'revision 2') + \ [ '@@ -0,0 +1 @@\n', "+This is the file 'newfile'.\n" ] + \ make_diff_prop_header(newfile) + \ make_diff_prop_added('svn:mime-type', 'text/plain') svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r1:2', newfile) # reverse the diff to diff across a deletion expected_output = make_diff_header(newfile, 'revision 2', 'nonexistent') + \ [ '@@ -1 +0,0 @@\n', "-This is the file 'newfile'.\n", '\n', 'Property changes on: %s\n' % sbox.path('newfile'), '__________________________________________________' + '_________________\n', 'Deleted: svn:mime-type\n', '## -1 +0,0 ##\n', '-text/plain\n', '\ No newline at end of property\n'] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r2:1', newfile) def diff_switched_file(sbox): "diff a switched file against repository" sbox.build() svntest.actions.run_and_verify_svn(None, [], 'switch', sbox.repo_url + '/A/mu', sbox.ospath('iota'), '--ignore-ancestry') sbox.simple_append('iota', 'Mu????') # This diffs the file against its origin expected_output = [ 'Index: %s\n' % sbox.path('iota'), '===================================================================\n', '--- %s\t(.../A/mu)\t(revision 1)\n' % sbox.path('iota'), '+++ %s\t(.../iota)\t(working copy)\n' % sbox.path('iota'), '@@ -1 +1,2 @@\n', ' This is the file \'mu\'.\n', '+Mu????\n', '\ No newline at end of file\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r', '1', sbox.ospath('iota')) # And this undoes the switch for the diff expected_output = [ 'Index: %s\n' % sbox.path('iota'), '===================================================================\n', '--- %s\t(revision 1)\n' % sbox.path('iota'), '+++ %s\t(working copy)\n' % sbox.path('iota'), '@@ -1 +1,2 @@\n', '-This is the file \'iota\'.\n', '+This is the file \'mu\'.\n', '+Mu????\n', '\ No newline at end of file\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r', '1', sbox.ospath('')) def diff_parent_dir(sbox): "diff parent directory" sbox.build() wc_dir = sbox.wc_dir svntest.actions.run_and_verify_svnmucc(None, [], '-U', sbox.repo_url, '-m', 'Q', 'mkdir', 'A/ZZZ', 'propset', 'A', 'B', 'A/ZZZ') was_cwd = os.getcwd() os.chdir(os.path.join(wc_dir, 'A', 'B')) try: # This currently (1.8.9, 1.9.0 development) triggers an assertion failure # as a non canonical relpath ".." is used as diff target expected_output = [ 'Index: ../ZZZ\n', '===================================================================\n', '--- ../ZZZ (revision 2)\n', '+++ ../ZZZ (nonexistent)\n', '\n', 'Property changes on: ../ZZZ\n', '___________________________________________________________________\n', 'Deleted: A\n', '## -1 +0,0 ##\n', '-B\n', '\ No newline at end of property\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r', '2', '..') expected_output = [ 'Index: ../../A/ZZZ\n', '===================================================================\n', '--- ../../A/ZZZ (revision 2)\n', '+++ ../../A/ZZZ (nonexistent)\n', '\n', 'Property changes on: ../../A/ZZZ\n', '___________________________________________________________________\n', 'Deleted: A\n', '## -1 +0,0 ##\n', '-B\n', '\ No newline at end of property\n', ] svntest.actions.run_and_verify_svn(expected_output, [], 'diff', '-r', '2', '../..') finally: os.chdir(was_cwd) def diff_deleted_in_move_against_repos(sbox): "diff deleted in move against repository" sbox.build() sbox.simple_move('A/B', 'BB') sbox.simple_move('BB/E/alpha', 'BB/q') sbox.simple_rm('BB/E/beta') svntest.actions.run_and_verify_svn(None, [], 'mkdir', sbox.repo_url + '/BB/E', '--parents', '-m', 'Create dir') # OK. Local diff svntest.actions.run_and_verify_svn(None, [], 'diff', sbox.wc_dir) # OK. Walks nodes locally from wc-root, notices ancestry svntest.actions.run_and_verify_svn(None, [], 'diff', sbox.wc_dir, '-r1', '--notice-ancestry') # OK. Walks nodes locally from BB, notices ancestry svntest.actions.run_and_verify_svn(None, [], 'diff', sbox.wc_dir, '-r2', '--notice-ancestry') # OK. Walks nodes locally from wc-root svntest.actions.run_and_verify_svn(None, [], 'diff', sbox.wc_dir, '-r1') # Assertion. Walks nodes locally from BB. svntest.actions.run_and_verify_svn(None, [], 'diff', sbox.wc_dir, '-r2') def diff_replaced_moved(sbox): "diff against a replaced moved node" sbox.build(read_only=True) sbox.simple_move('A', 'AA') sbox.simple_rm('AA/B') sbox.simple_move('AA/D', 'AA/B') # Ok svntest.actions.run_and_verify_svn(None, [], 'diff', sbox.ospath('.'), '-r1') # Ok (rhuijben: Works through a hack assuming some BASE knowledge) svntest.actions.run_and_verify_svn(None, [], 'diff', sbox.ospath('AA'), '-r1') # Error (misses BASE node because the diff editor is driven incorrectly) svntest.actions.run_and_verify_svn(None, [], 'diff', sbox.ospath('AA/B'), '-r1') # Regression test for the fix in r1619380. Prior to this (and in releases # 1.8.0 through 1.8.10) a local diff incorrectly showed a copied dir's # properties as added, whereas it should show only the changes against the # copy-source. def diff_local_copied_dir(sbox): "local WC diff of copied dir" sbox.build() was_cwd = os.getcwd() os.chdir(sbox.wc_dir) sbox.wc_dir = '' try: sbox.simple_propset('p1', 'v1', 'A/C') sbox.simple_commit() # dir with no prop changes sbox.simple_copy('A/C', 'C2') # dir with prop changes sbox.simple_copy('A/C', 'C3') sbox.simple_propset('p2', 'v2', 'C3') expected_output_C2 = [] expected_output_C3 = [ 'Index: C3\n', '===================================================================\n', '--- C3 (revision 2)\n', '+++ C3 (working copy)\n', '\n', 'Property changes on: C3\n', '___________________________________________________________________\n', 'Added: p2\n', '## -0,0 +1 ##\n', '+v2\n', '\ No newline at end of property\n', ] svntest.actions.run_and_verify_svn(expected_output_C2, [], 'diff', 'C2') svntest.actions.run_and_verify_svn(expected_output_C3, [], 'diff', 'C3') finally: os.chdir(was_cwd) def diff_summarize_ignore_properties(sbox): "diff --summarize --ignore-properties" sbox.build() wc_dir = sbox.wc_dir # Make a property change and a content change to 'iota' sbox.simple_propset('svn:eol-style', 'native', 'iota') svntest.main.file_append(sbox.ospath('iota'), 'new text') # Make a property change to 'A/mu' sbox.simple_propset('svn:eol-style', 'native', 'A/mu') # Make a content change to 'A/B/lambda' svntest.main.file_append(sbox.ospath('A/B/lambda'), 'new text') # Add a file. svntest.main.file_write(sbox.ospath('new'), 'new text') sbox.simple_add('new') # Delete a file sbox.simple_rm('A/B/E/alpha') expected_diff = svntest.wc.State(wc_dir, { 'iota': Item(status='M '), 'new': Item(status='A '), 'A/B/lambda': Item(status='M '), 'A/B/E/alpha': Item(status='D '), }) svntest.actions.run_and_verify_diff_summarize(expected_diff, '--ignore-properties', sbox.wc_dir) # test with --xml, too paths = ['iota', 'new', 'A/B/lambda', 'A/B/E/alpha'] items = ['modified', 'added', 'modified', 'deleted' ] kinds = ['file','file', 'file', 'file'] props = ['none', 'none', 'none', 'none'] svntest.actions.run_and_verify_diff_summarize_xml( [], wc_dir, paths, items, props, kinds, wc_dir, '--ignore-properties') ######################################################################## #Run the tests # list all tests here, starting with None: test_list = [ None, diff_update_a_file, diff_add_a_file, diff_add_a_file_in_a_subdir, diff_replace_a_file, diff_multiple_reverse, diff_non_recursive, diff_repo_subset, diff_non_version_controlled_file, diff_pure_repository_update_a_file, diff_only_property_change, dont_diff_binary_file, diff_nonextant_urls, diff_head_of_moved_file, diff_base_to_repos, diff_deleted_in_head, diff_targets, diff_branches, diff_repos_and_wc, diff_file_urls, diff_prop_change_local_edit, check_for_omitted_prefix_in_path_component, diff_renamed_file, diff_within_renamed_dir, diff_prop_on_named_dir, diff_keywords, diff_force, diff_schedule_delete, diff_renamed_dir, diff_property_changes_to_base, diff_mime_type_changes, diff_prop_change_local_propmod, diff_repos_wc_add_with_props, diff_nonrecursive_checkout_deleted_dir, diff_repos_working_added_dir, diff_base_repos_moved, diff_added_subtree, basic_diff_summarize, diff_weird_author, diff_ignore_whitespace, diff_ignore_eolstyle, diff_in_renamed_folder, diff_with_depth, diff_ignore_eolstyle_empty_lines, diff_backward_repos_wc_copy, diff_summarize_xml, diff_file_depth_empty, diff_wrong_extension_type, diff_external_diffcmd, diff_url_against_local_mods, diff_preexisting_rev_against_local_add, diff_git_format_wc_wc, diff_git_format_url_wc, diff_git_format_url_url, diff_prop_missing_context, diff_prop_multiple_hunks, diff_git_empty_files, diff_git_with_props, diff_git_with_props_on_dir, diff_abs_localpath_from_wc_folder, no_spurious_conflict, diff_correct_wc_base_revnum, diff_two_working_copies, diff_deleted_url, diff_arbitrary_files_and_dirs, diff_properties_only, diff_properties_no_newline, diff_arbitrary_same, diff_git_format_wc_wc_dir_mv, simple_ancestry, local_tree_replace, diff_dir_replaced_by_file, diff_dir_replaced_by_dir, diff_repos_empty_file_addition, diff_missing_tree_conflict_victim, diff_local_missing_obstruction, diff_move_inside_copy, diff_repo_wc_copies, diff_repo_wc_file_props, diff_repo_repo_added_file_mime_type, diff_switched_file, diff_parent_dir, diff_deleted_in_move_against_repos, diff_replaced_moved, diff_local_copied_dir, diff_summarize_ignore_properties, ] if __name__ == '__main__': svntest.main.run_tests(test_list) # NOTREACHED ### End of file.