| #!/usr/bin/env python |
| # |
| # trans_tests.py: testing eol conversion and keyword substitution |
| # |
| # 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 os, re, logging, sys |
| |
| logger = logging.getLogger() |
| |
| # Our testing module |
| import svntest |
| from svntest import wc |
| |
| # (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 |
| |
| |
| ###################################################################### |
| # THINGS TO TEST |
| # |
| # *** Perhaps something like commit_tests.py:make_standard_slew_of_changes |
| # is in order here in this file as well. *** |
| # |
| # status level 1: |
| # enable translation, status |
| # (now throw local text mods into the picture) |
| # |
| # commit level 1: |
| # enable translation, commit |
| # (now throw local text mods into the picture) |
| # |
| # checkout: |
| # checkout stuff with translation enabled |
| # |
| # status level 2: |
| # disable translation, status |
| # change newline conversion to different style, status |
| # (now throw local text mods into the picture) |
| # |
| # commit level 2: |
| # disable translation, commit |
| # change newline conversion to different style, commit |
| # (now throw local text mods into the picture) |
| # (now throw local text mods with tortured line endings into the picture) |
| # |
| # update: |
| # update files from disabled translation to enabled translation |
| # update files from enabled translation to disabled translation |
| # update files with newline conversion style changes |
| # (now throw local text mods into the picture) |
| # (now throw conflicting local property mods into the picture) |
| # |
| #### |
| |
| |
| |
| # Paths that the tests test. |
| author_rev_unexp_path = '' |
| author_rev_exp_path = '' |
| bogus_keywords_path = '' |
| embd_author_rev_unexp_path = '' |
| embd_author_rev_exp_path = '' |
| embd_bogus_keywords_path = '' |
| |
| def check_keywords(actual_kw, expected_kw, name): |
| """A Helper function to compare two keyword lists""" |
| |
| if len(actual_kw) != len(expected_kw): |
| logger.warn("Keyword lists are different by size") |
| raise svntest.Failure |
| |
| for i in range(0,len(actual_kw)): |
| if actual_kw[i] != expected_kw[i]: |
| logger.warn('%s item %s, Expected: %s', name, i, expected_kw[i][:-1]) |
| logger.warn('%s item %s, Got: %s', name, i, actual_kw[i][:-1]) |
| raise svntest.Failure |
| |
| def setup_working_copy(wc_dir, value_len): |
| """Setup a standard test working copy, then create (but do not add) |
| various files for testing translation.""" |
| |
| global author_rev_unexp_path |
| global author_rev_exp_path |
| global url_unexp_path |
| global url_exp_path |
| global id_unexp_path |
| global id_exp_path |
| global header_unexp_path |
| global header_exp_path |
| global bogus_keywords_path |
| global embd_author_rev_unexp_path |
| global embd_author_rev_exp_path |
| global embd_bogus_keywords_path |
| global fixed_length_keywords_path |
| global id_with_space_path |
| global id_exp_with_dollar_path |
| |
| # NOTE: Only using author and revision keywords in tests for now, |
| # since they return predictable substitutions. |
| |
| # Unexpanded, expanded, and bogus keywords; sometimes as the only |
| # content of the files, sometimes embedded in non-keyword content. |
| author_rev_unexp_path = os.path.join(wc_dir, 'author_rev_unexp') |
| author_rev_exp_path = os.path.join(wc_dir, 'author_rev_exp') |
| url_unexp_path = os.path.join(wc_dir, 'url_unexp') |
| url_exp_path = os.path.join(wc_dir, 'url_exp') |
| id_unexp_path = os.path.join(wc_dir, 'id_unexp') |
| id_exp_path = os.path.join(wc_dir, 'id_exp') |
| header_unexp_path = os.path.join(wc_dir, 'header_unexp') |
| header_exp_path = os.path.join(wc_dir, 'header_exp') |
| bogus_keywords_path = os.path.join(wc_dir, 'bogus_keywords') |
| embd_author_rev_unexp_path = os.path.join(wc_dir, 'embd_author_rev_unexp') |
| embd_author_rev_exp_path = os.path.join(wc_dir, 'embd_author_rev_exp') |
| embd_bogus_keywords_path = os.path.join(wc_dir, 'embd_bogus_keywords') |
| fixed_length_keywords_path = os.path.join(wc_dir, 'fixed_length_keywords') |
| id_with_space_path = os.path.join(wc_dir, 'id with space') |
| id_exp_with_dollar_path = os.path.join(wc_dir, 'id_exp with_$_sign') |
| |
| svntest.main.file_append(author_rev_unexp_path, "$Author$\n$Rev$") |
| svntest.main.file_append(author_rev_exp_path, "$Author: blah $\n$Rev: 0 $") |
| svntest.main.file_append(url_unexp_path, "$URL$") |
| svntest.main.file_append(url_exp_path, "$URL: blah $") |
| svntest.main.file_append(id_unexp_path, "$Id$") |
| svntest.main.file_append(id_exp_path, "$Id: blah $") |
| svntest.main.file_append(header_unexp_path, "$Header$") |
| svntest.main.file_append(header_exp_path, "$Header: blah $") |
| svntest.main.file_append(bogus_keywords_path, "$Arthur$\n$Rev0$") |
| svntest.main.file_append(embd_author_rev_unexp_path, |
| "one\nfish\n$Author$ two fish\n red $Rev$\n fish") |
| svntest.main.file_append(embd_author_rev_exp_path, |
| "blue $Author: blah $ fish$Rev: 0 $\nI fish") |
| svntest.main.file_append(embd_bogus_keywords_path, |
| "you fish $Arthur$then\n we$Rev0$ \n\nchew fish") |
| |
| keyword_test_targets = [ |
| # User tries to shoot him or herself on the foot |
| "$URL::$\n", |
| "$URL:: $\n", |
| "$URL:: $\n", |
| # Following are valid entries |
| "$URL:: $\n", |
| "$URL:: %s $\n" % (' ' * (value_len-1)), |
| "$URL:: %s $\n" % (' ' * value_len), |
| # Check we will clean the truncate marker when the value fits exactly |
| "$URL:: %s#$\n" % ('a' * value_len), |
| "$URL:: %s $\n" % (' ' * (value_len+1)), |
| # These are syntactically wrong |
| "$URL::x%s $\n" % (' ' * value_len), |
| "$URL:: %sx$\n" % (' ' * value_len), |
| "$URL::x%sx$\n" % (' ' * value_len) |
| ] |
| |
| for i in keyword_test_targets: |
| svntest.main.file_append(fixed_length_keywords_path, i) |
| |
| svntest.main.file_append(id_with_space_path, "$Id$") |
| svntest.main.file_append(id_exp_with_dollar_path, |
| "$Id: id_exp with_$_sign 1 2006-06-10 11:10:00Z jrandom $") |
| |
| |
| ### Helper functions for setting/removing properties |
| |
| # Set the property keyword for PATH. Turn on all possible keywords. |
| ### todo: Later, take list of keywords to set. |
| def keywords_on(path): |
| svntest.actions.run_and_verify_svn(None, [], 'propset', |
| "svn:keywords", |
| "Author Rev Date URL Id Header", |
| path) |
| |
| # Delete property NAME from versioned PATH in the working copy. |
| ### todo: Later, take list of keywords to remove from the propval? |
| def keywords_off(path): |
| svntest.actions.run_and_verify_svn(None, [], 'propdel', |
| "svn:keywords", path) |
| |
| |
| ###################################################################### |
| # Tests |
| # |
| # Each test must return on success or raise on failure. |
| |
| #---------------------------------------------------------------------- |
| |
| ### This test is know to fail when Subversion is built in very deep |
| ### directory structures, caused by SVN_KEYWORD_MAX_LEN being defined |
| ### as 255. |
| def keywords_from_birth(sbox): |
| "commit new files with keywords active from birth" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| canonical_repo_url = svntest.main.canonicalize_url(sbox.repo_url) |
| if canonical_repo_url[-1:] != '/': |
| url_expand_test_data = canonical_repo_url + '/fixed_length_keywords' |
| else: |
| url_expand_test_data = canonical_repo_url + 'fixed_length_keywords' |
| |
| setup_working_copy(wc_dir, len(url_expand_test_data)) |
| |
| # Add all the files |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.add({ |
| 'author_rev_unexp' : Item(status='A ', wc_rev=0), |
| 'author_rev_exp' : Item(status='A ', wc_rev=0), |
| 'url_unexp' : Item(status='A ', wc_rev=0), |
| 'url_exp' : Item(status='A ', wc_rev=0), |
| 'id_unexp' : Item(status='A ', wc_rev=0), |
| 'id_exp' : Item(status='A ', wc_rev=0), |
| 'header_unexp' : Item(status='A ', wc_rev=0), |
| 'header_exp' : Item(status='A ', wc_rev=0), |
| 'bogus_keywords' : Item(status='A ', wc_rev=0), |
| 'embd_author_rev_unexp' : Item(status='A ', wc_rev=0), |
| 'embd_author_rev_exp' : Item(status='A ', wc_rev=0), |
| 'embd_bogus_keywords' : Item(status='A ', wc_rev=0), |
| 'fixed_length_keywords' : Item(status='A ', wc_rev=0), |
| 'id with space' : Item(status='A ', wc_rev=0), |
| 'id_exp with_$_sign' : Item(status='A ', wc_rev=0), |
| }) |
| |
| svntest.main.run_svn(None, 'add', author_rev_unexp_path) |
| svntest.main.run_svn(None, 'add', author_rev_exp_path) |
| svntest.main.run_svn(None, 'add', url_unexp_path) |
| svntest.main.run_svn(None, 'add', url_exp_path) |
| svntest.main.run_svn(None, 'add', id_unexp_path) |
| svntest.main.run_svn(None, 'add', id_exp_path) |
| svntest.main.run_svn(None, 'add', header_unexp_path) |
| svntest.main.run_svn(None, 'add', header_exp_path) |
| svntest.main.run_svn(None, 'add', bogus_keywords_path) |
| svntest.main.run_svn(None, 'add', embd_author_rev_unexp_path) |
| svntest.main.run_svn(None, 'add', embd_author_rev_exp_path) |
| svntest.main.run_svn(None, 'add', embd_bogus_keywords_path) |
| svntest.main.run_svn(None, 'add', fixed_length_keywords_path) |
| svntest.main.run_svn(None, 'add', id_with_space_path) |
| svntest.main.run_svn(None, 'add', id_exp_with_dollar_path) |
| |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # Add the keyword properties. |
| keywords_on(author_rev_unexp_path) |
| keywords_on(url_unexp_path) |
| keywords_on(url_exp_path) |
| keywords_on(id_unexp_path) |
| keywords_on(id_exp_path) |
| keywords_on(header_unexp_path) |
| keywords_on(header_exp_path) |
| keywords_on(embd_author_rev_exp_path) |
| keywords_on(fixed_length_keywords_path) |
| keywords_on(id_with_space_path) |
| keywords_on(id_exp_with_dollar_path) |
| |
| # Commit. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'author_rev_unexp' : Item(verb='Adding'), |
| 'author_rev_exp' : Item(verb='Adding'), |
| 'url_unexp' : Item(verb='Adding'), |
| 'url_exp' : Item(verb='Adding'), |
| 'id_unexp' : Item(verb='Adding'), |
| 'id_exp' : Item(verb='Adding'), |
| 'header_unexp' : Item(verb='Adding'), |
| 'header_exp' : Item(verb='Adding'), |
| 'bogus_keywords' : Item(verb='Adding'), |
| 'embd_author_rev_unexp' : Item(verb='Adding'), |
| 'embd_author_rev_exp' : Item(verb='Adding'), |
| 'embd_bogus_keywords' : Item(verb='Adding'), |
| 'fixed_length_keywords' : Item(verb='Adding'), |
| 'id with space' : Item(verb='Adding'), |
| 'id_exp with_$_sign' : Item(verb='Adding'), |
| }) |
| |
| svntest.actions.run_and_verify_commit(wc_dir, expected_output, |
| None) |
| |
| # Make sure the unexpanded URL keyword got expanded correctly. |
| fp = open(url_unexp_path, 'r') |
| lines = fp.readlines() |
| if not ((len(lines) == 1) |
| and (re.match("\$URL: (http|https|file|svn|svn\\+ssh)://", |
| lines[0]))): |
| logger.warn("URL expansion failed for %s", url_unexp_path) |
| raise svntest.Failure |
| fp.close() |
| |
| # Make sure the preexpanded URL keyword got reexpanded correctly. |
| fp = open(url_exp_path, 'r') |
| lines = fp.readlines() |
| if not ((len(lines) == 1) |
| and (re.match("\$URL: (http|https|file|svn|svn\\+ssh)://", |
| lines[0]))): |
| logger.warn("URL expansion failed for %s", url_exp_path) |
| raise svntest.Failure |
| fp.close() |
| |
| # Make sure the unexpanded Id keyword got expanded correctly. |
| fp = open(id_unexp_path, 'r') |
| lines = fp.readlines() |
| if not ((len(lines) == 1) |
| and (re.match("\$Id: id_unexp", lines[0]))): |
| logger.warn("Id expansion failed for %s", id_exp_path) |
| raise svntest.Failure |
| fp.close() |
| |
| # Make sure the preexpanded Id keyword got reexpanded correctly. |
| fp = open(id_exp_path, 'r') |
| lines = fp.readlines() |
| if not ((len(lines) == 1) |
| and (re.match("\$Id: id_exp", lines[0]))): |
| logger.warn("Id expansion failed for %s", id_exp_path) |
| raise svntest.Failure |
| fp.close() |
| |
| # Make sure the unexpanded Header keyword got expanded correctly. |
| fp = open(header_unexp_path, 'r') |
| lines = fp.readlines() |
| if not ((len(lines) == 1) |
| and (re.match("\$Header: (https?|file|svn|svn\\+ssh)://.* jrandom", |
| lines[0]))): |
| logger.warn("Header expansion failed for %s", header_unexp_path) |
| raise svntest.Failure |
| fp.close() |
| |
| # Make sure the preexpanded Header keyword got reexpanded correctly. |
| fp = open(header_exp_path, 'r') |
| lines = fp.readlines() |
| if not ((len(lines) == 1) |
| and (re.match("\$Header: (https?|file|svn|svn\\+ssh)://.* jrandom", |
| lines[0]))): |
| logger.warn("Header expansion failed for %s", header_exp_path) |
| raise svntest.Failure |
| fp.close() |
| |
| # Check fixed length keywords. |
| kw_workingcopy = [ |
| '$URL::$\n', |
| '$URL:: $\n', |
| '$URL:: $\n', |
| '$URL:: %s#$\n' % url_expand_test_data[0:1], |
| '$URL:: %s#$\n' % url_expand_test_data[:-1], |
| '$URL:: %s $\n' % url_expand_test_data, |
| '$URL:: %s $\n' % url_expand_test_data, |
| '$URL:: %s $\n'% url_expand_test_data, |
| '$URL::x%s $\n' % (' ' * len(url_expand_test_data)), |
| '$URL:: %sx$\n' % (' ' * len(url_expand_test_data)), |
| '$URL::x%sx$\n' % (' ' * len(url_expand_test_data)) |
| ] |
| |
| fp = open(fixed_length_keywords_path, 'r') |
| actual_workingcopy_kw = fp.readlines() |
| fp.close() |
| check_keywords(actual_workingcopy_kw, kw_workingcopy, "working copy") |
| |
| # Check text base for fixed length keywords. |
| kw_textbase = [ |
| '$URL::$\n', |
| '$URL:: $\n', |
| '$URL:: $\n', |
| '$URL:: $\n', |
| '$URL:: %s $\n' % (' ' * len(url_expand_test_data[:-1])), |
| '$URL:: %s $\n' % (' ' * len(url_expand_test_data)), |
| '$URL:: %s $\n' % (' ' * len(url_expand_test_data)), |
| '$URL:: %s $\n'% (' ' * len(url_expand_test_data)), |
| '$URL::x%s $\n' % (' ' * len(url_expand_test_data)), |
| '$URL:: %sx$\n' % (' ' * len(url_expand_test_data)), |
| '$URL::x%sx$\n' % (' ' * len(url_expand_test_data)) |
| ] |
| |
| fp = open(svntest.wc.text_base_path(fixed_length_keywords_path), 'r') |
| actual_textbase_kw = fp.readlines() |
| fp.close() |
| check_keywords(actual_textbase_kw, kw_textbase, "text base") |
| |
| # Check the Id keyword for filename with spaces. |
| fp = open(id_with_space_path, 'r') |
| lines = fp.readlines() |
| if not ((len(lines) == 1) |
| and (re.match("\$Id: .*id with space", lines[0]))): |
| logger.warn("Id expansion failed for %s", id_with_space_path) |
| raise svntest.Failure |
| fp.close() |
| |
| # Check the Id keyword for filename with_$_signs. |
| fp = open(id_exp_with_dollar_path, 'r') |
| lines = fp.readlines() |
| if not ((len(lines) == 1) |
| and (re.match("\$Id: .*id_exp with_\$_sign [^$]* jrandom \$", |
| lines[0]))): |
| logger.warn("Id expansion failed for %s", id_exp_with_dollar_path) |
| |
| raise svntest.Failure |
| fp.close() |
| |
| #---------------------------------------------------------------------- |
| |
| #def enable_translation(sbox): |
| # "enable translation, check status, commit" |
| |
| # TODO: Turn on newline conversion and/or keyword substitution for all |
| # sorts of files, with and without local mods, and verify that |
| # status shows the right stuff. The, commit those mods. |
| |
| #---------------------------------------------------------------------- |
| |
| #def checkout_translated(): |
| # "checkout files that have translation enabled" |
| |
| # TODO: Checkout a tree which contains files with translation |
| # enabled. |
| |
| #---------------------------------------------------------------------- |
| |
| #def disable_translation(): |
| # "disable translation, check status, commit" |
| |
| # TODO: Disable translation on files which have had it enabled, |
| # with and without local mods, check status, and commit. |
| |
| #---------------------------------------------------------------------- |
| |
| # Regression test for bug discovered by Vladmir Prus <ghost@cs.msu.csu>. |
| # This is a slight rewrite of his test, to use the run_and_verify_* API. |
| # This is for issue #631. |
| |
| @Issue(631) |
| def update_modified_with_translation(sbox): |
| "update modified file with eol-style 'native'" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # Replace contents of rho and set eol translation to 'native' |
| rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho') |
| svntest.main.file_write(rho_path, "1\n2\n3\n4\n5\n6\n7\n8\n9\n") |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', 'svn:eol-style', 'native', |
| rho_path) |
| |
| # Create expected output and status trees of a commit. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A/D/G/rho' : Item(verb='Sending'), |
| }) |
| |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| # rho has props |
| expected_status.tweak('A/D/G/rho', wc_rev=2, status=' ') |
| |
| # Commit revision 2: it has the new rho. |
| svntest.actions.run_and_verify_commit(wc_dir, |
| expected_output, |
| expected_status, |
| [], rho_path) |
| |
| # Change rho again |
| svntest.main.file_write(rho_path, "1\n2\n3\n4\n4.5\n5\n6\n7\n8\n9\n") |
| |
| # Commit revision 3 |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('A/D/G/rho', wc_rev=3, status=' ') |
| |
| svntest.actions.run_and_verify_commit(wc_dir, |
| expected_output, |
| expected_status, |
| [], rho_path) |
| |
| # Locally modify rho again. |
| svntest.main.file_write(rho_path, "1\n2\n3\n4\n4.5\n5\n6\n7\n8\n9\n10\n") |
| |
| # Prepare trees for an update to rev 1. |
| expected_output = svntest.wc.State(wc_dir, { |
| 'A/D/G/rho' : Item(status='CU'), |
| }) |
| |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('A/D/G/rho', |
| contents="\n".join(["<<<<<<< .mine", |
| "1", |
| "2", |
| "3", |
| "4", |
| "4.5", |
| "5", |
| "6", |
| "7", |
| "8", |
| "9", |
| "10", |
| "||||||| .r3", |
| "1", |
| "2", |
| "3", |
| "4", |
| "4.5", |
| "5", |
| "6", |
| "7", |
| "8", |
| "9", |
| "=======", |
| "This is the file 'rho'.", |
| ">>>>>>> .r1", |
| ""])) |
| |
| # Updating back to revision 1 should not error; the merge should |
| # work, with eol-translation turned on. |
| extra_files = ['rho.r1', 'rho.r3', 'rho.mine'] |
| svntest.actions.run_and_verify_update(wc_dir, |
| expected_output, |
| expected_disk, |
| None, |
| [], False, |
| '-r', '1', wc_dir, |
| extra_files=extra_files) |
| |
| |
| #---------------------------------------------------------------------- |
| |
| # Regression test for issue #1085, whereby setting the eol-style to a |
| # fixed platform-incorrect value on a file whose line endings are |
| # platform-correct causes repository insanity (the eol-style prop |
| # claims one line ending style, the file is in another). This test |
| # assumes that this can be testing by verifying that a) new file |
| # contents are transmitted to the server during commit, and b) that |
| # after the commit, the file and its text-base have been changed to |
| # have the new line-ending style. |
| @Issue(1085) |
| def eol_change_is_text_mod(sbox): |
| "committing eol-style change forces text send" |
| |
| sbox.build() |
| |
| wc_dir = sbox.wc_dir |
| |
| # add a new file to the working copy. |
| foo_path = os.path.join(wc_dir, 'foo') |
| f = open(foo_path, 'wb') |
| if svntest.main.windows: |
| f.write(b"1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n") |
| else: |
| f.write(b"1\n2\n3\n4\n5\n6\n7\n8\n9\n") |
| f.close() |
| |
| # commit the file |
| svntest.actions.run_and_verify_svn(None, [], 'add', foo_path) |
| svntest.actions.run_and_verify_svn(None, [], |
| 'ci', '-m', 'log msg', |
| foo_path) |
| |
| if svntest.main.windows: |
| svntest.actions.run_and_verify_svn(None, [], 'propset', |
| 'svn:eol-style', 'LF', foo_path) |
| else: |
| svntest.actions.run_and_verify_svn(None, [], 'propset', |
| 'svn:eol-style', 'CRLF', foo_path) |
| |
| # check 1: did new contents get transmitted? |
| expected_output = ["Sending " + foo_path + "\n", |
| "Transmitting file data .done\n", |
| "Committing transaction...\n", |
| "Committed revision 3.\n"] |
| svntest.actions.run_and_verify_svn(expected_output, [], |
| 'ci', '-m', 'log msg', foo_path) |
| |
| # check 2: do the files have the right contents now? |
| contents = open(foo_path, 'rb').read() |
| if svntest.main.windows: |
| if contents != b"1\n2\n3\n4\n5\n6\n7\n8\n9\n": |
| raise svntest.Failure |
| else: |
| if contents != b"1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n": |
| raise svntest.Failure |
| |
| foo_base_path = svntest.wc.text_base_path(foo_path) |
| base_contents = open(foo_base_path, 'rb').read() |
| if contents != base_contents: |
| raise svntest.Failure |
| |
| #---------------------------------------------------------------------- |
| # Regression test for issue #1151. A single file in a directory |
| # didn't get keywords expanded on checkout. |
| @Issue(1151) |
| def keyword_expanded_on_checkout(sbox): |
| "keyword expansion for lone file in directory" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| # The bug didn't occur if there were multiple files in the |
| # directory, so setup an empty directory. |
| Z_path = os.path.join(wc_dir, 'Z') |
| svntest.actions.run_and_verify_svn(None, [], 'mkdir', Z_path) |
| |
| # Add the file that has the keyword to be expanded |
| url_path = os.path.join(Z_path, 'url') |
| svntest.main.file_append(url_path, "$URL$") |
| svntest.actions.run_and_verify_svn(None, [], 'add', url_path) |
| keywords_on(url_path) |
| |
| svntest.actions.run_and_verify_svn(None, [], |
| 'ci', '-m', 'log msg', wc_dir) |
| |
| other_wc_dir = sbox.add_wc_path('other') |
| other_url_path = os.path.join(other_wc_dir, 'Z', 'url') |
| svntest.actions.run_and_verify_svn(None, [], 'checkout', |
| sbox.repo_url, |
| other_wc_dir) |
| |
| # Check keyword got expanded (and thus the mkdir, add, ps, commit |
| # etc. worked) |
| fp = open(other_url_path, 'r') |
| lines = fp.readlines() |
| if not ((len(lines) == 1) |
| and (re.match("\$URL: (http|https|file|svn|svn\\+ssh)://", |
| lines[0]))): |
| logger.warn("URL expansion failed for %s", other_url_path) |
| raise svntest.Failure |
| fp.close() |
| |
| |
| #---------------------------------------------------------------------- |
| def cat_keyword_expansion(sbox): |
| "keyword expanded on cat" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| mu_path = os.path.join(wc_dir, 'A', 'mu') |
| lambda_path = os.path.join(wc_dir, 'A', 'B', 'lambda') |
| |
| # Set up A/mu to do $Rev$ keyword expansion |
| svntest.main.file_append(mu_path , "$Rev$\n$Author$") |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', 'svn:keywords', 'Rev Author', |
| mu_path) |
| |
| expected_output = 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) |
| |
| # Change the author to value which will get truncated on expansion |
| full_author = "x" * 400 |
| key_author = "x" * 244 |
| svntest.actions.enable_revprop_changes(sbox.repo_dir) |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', '--revprop', '-r2', |
| 'svn:author', full_author, |
| sbox.wc_dir) |
| svntest.actions.run_and_verify_svn([ full_author ], [], |
| 'propget', '--revprop', '-r2', |
| 'svn:author', '--no-newline', |
| sbox.wc_dir) |
| |
| # Make another commit so that the last changed revision for A/mu is |
| # not HEAD. |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', 'foo', 'bar', lambda_path) |
| expected_output = wc.State(wc_dir, { |
| 'A/B/lambda' : Item(verb='Sending'), |
| }) |
| expected_status.tweak('A/B/lambda', wc_rev=3) |
| svntest.actions.run_and_verify_commit(wc_dir, |
| expected_output, expected_status) |
| |
| # At one stage the keywords were expanded to values for the requested |
| # revision, not to those committed revision |
| svntest.actions.run_and_verify_svn([ "This is the file 'mu'.\n", |
| "$Rev: 2 $\n", |
| "$Author: " + key_author + " $"], [], |
| 'cat', '-r', 'HEAD', mu_path) |
| |
| |
| #---------------------------------------------------------------------- |
| def copy_propset_commit(sbox): |
| "copy, propset svn:eol-style, commit" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| mu_path = os.path.join(wc_dir, 'A', 'mu') |
| mu2_path = os.path.join(wc_dir, 'A', 'mu2') |
| |
| # Copy and propset |
| svntest.actions.run_and_verify_svn(None, [], 'copy', mu_path, mu2_path) |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', 'svn:eol-style', 'native', |
| mu2_path) |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.add({ |
| 'A/mu2' : Item(status='A ', wc_rev='-', copied='+') |
| }) |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # Commit, at one stage this dumped core |
| expected_output = wc.State(wc_dir, { |
| 'A/mu2' : Item(verb='Adding'), |
| }) |
| expected_status.tweak('A/mu2', status=' ', wc_rev=2, copied=None) |
| svntest.actions.run_and_verify_commit(wc_dir, |
| expected_output, expected_status) |
| |
| #---------------------------------------------------------------------- |
| # Create a greek tree, commit a keyword into one file, |
| # then commit a keyword property (i.e., turn on keywords), then |
| # try to check out head somewhere else. |
| # This should not cause seg fault |
| def propset_commit_checkout_nocrash(sbox): |
| "propset, commit, check out into another wc" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| mu_path = os.path.join(wc_dir, 'A', 'mu') |
| |
| # Put a keyword in A/mu, commit |
| svntest.main.file_append(mu_path, "$Rev$") |
| expected_output = 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) |
| |
| # Set property to do keyword expansion on A/mu, commit. |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', 'svn:keywords', 'Rev', mu_path) |
| expected_output = 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=3) |
| svntest.actions.run_and_verify_commit(wc_dir, |
| expected_output, expected_status) |
| |
| # Check out into another wc dir |
| other_wc_dir = sbox.add_wc_path('other') |
| mu_other_path = os.path.join(other_wc_dir, 'A', 'mu') |
| |
| svntest.actions.run_and_verify_svn(None, [], 'checkout', |
| sbox.repo_url, |
| other_wc_dir) |
| |
| mu_other_contents = open(mu_other_path).read() |
| if mu_other_contents != "This is the file 'mu'.\n$Rev: 3 $": |
| logger.warn("'%s' does not have the expected contents", mu_other_path) |
| raise svntest.Failure |
| |
| |
| #---------------------------------------------------------------------- |
| # Add the keyword property to a file, svn revert the file |
| # This should not display any error message |
| def propset_revert_noerror(sbox): |
| "propset, revert" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| mu_path = os.path.join(wc_dir, 'A', 'mu') |
| |
| # Set the Rev keyword for the mu file |
| # could use the keywords_on()/keywords_off() functions to |
| # set/del all svn:keywords |
| svntest.actions.run_and_verify_svn(None, [], |
| 'propset', 'svn:keywords', 'Rev', mu_path) |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| expected_status.tweak('A/mu', status=' M') |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| # Revert the propset |
| svntest.actions.run_and_verify_svn(None, [], 'revert', mu_path) |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 1) |
| svntest.actions.run_and_verify_status(wc_dir, expected_status) |
| |
| |
| def props_only_file_update(sbox): |
| "retranslation occurs on a props-only update" |
| |
| sbox.build() |
| wc_dir = sbox.wc_dir |
| |
| iota_path = os.path.join(wc_dir, 'iota') |
| content = ["This is the file 'iota'.\n", |
| "$Author$\n", |
| ] |
| content_expanded = ["This is the file 'iota'.\n", |
| "$Author: jrandom $\n", |
| ] |
| |
| # Create r2 with iota's contents and svn:keywords modified |
| with open(iota_path, 'w') as f: |
| f.writelines(content) |
| svntest.main.run_svn(None, 'propset', 'svn:keywords', 'Author', iota_path) |
| |
| expected_output = 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) |
| |
| # Create r3 that drops svn:keywords |
| |
| # put the content back to its untranslated form |
| with open(iota_path, 'w') as f: |
| f.writelines(content) |
| |
| svntest.main.run_svn(None, 'propdel', 'svn:keywords', iota_path) |
| |
| expected_status.tweak('iota', wc_rev=3) |
| |
| svntest.actions.run_and_verify_commit(wc_dir, |
| expected_output, |
| expected_status) |
| |
| # Now, go back to r2. iota should have the Author keyword expanded. |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('iota', contents=''.join(content_expanded)) |
| |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 2) |
| |
| svntest.actions.run_and_verify_update(wc_dir, |
| None, None, expected_status, |
| [], False, |
| wc_dir, '-r', '2') |
| |
| if open(iota_path).read() != ''.join(content_expanded): |
| raise svntest.Failure("$Author$ is not expanded in 'iota'") |
| |
| # Update to r3. this should retranslate iota, dropping the keyword expansion |
| expected_disk = svntest.main.greek_state.copy() |
| expected_disk.tweak('iota', contents=''.join(content)) |
| |
| expected_status = svntest.actions.get_virginal_state(wc_dir, 3) |
| |
| svntest.actions.run_and_verify_update(wc_dir, |
| None, expected_disk, expected_status) |
| |
| if open(iota_path).read() != ''.join(content): |
| raise svntest.Failure("$Author$ is not contracted in 'iota'") |
| |
| # We used to leave some temporary files around. Make sure that we don't. |
| temps = os.listdir(os.path.join(wc_dir, svntest.main.get_admin_name(), 'tmp')) |
| if os.path.exists(os.path.join(wc_dir, svntest.main.get_admin_name(), |
| 'tmp', 'props')): |
| temps.remove('prop-base') |
| temps.remove('props') |
| if temps: |
| logger.warn('Temporary files leftover: %s', (', '.join(temps),)) |
| raise svntest.Failure |
| |
| @XFail() |
| @Issues(4327) |
| def autoprops_inconsistent_eol(sbox): |
| "able to handle inconsistent eols on add" |
| |
| sbox.build(read_only = True) |
| wc_dir = sbox.wc_dir |
| |
| text = 'line with NL\n' + \ |
| 'line with CR\r' + \ |
| 'line with CRLF\r\n' + \ |
| 'line with LFCR (or is that not a line? ;-)\n\r' |
| |
| # Compensate for python smartness |
| if sys.platform == 'win32': |
| expected_text = text.replace('\r\n', '\n') |
| else: |
| expected_text = text |
| |
| sbox.simple_add_text(text, 'add.c') |
| sbox.simple_add_text(text, 'add-force.c') |
| |
| svntest.actions.run_and_verify_svn(None, '.*inconsistent newlines.*', |
| 'ps', 'svn:eol-style', 'native', |
| sbox.ospath('add.c')) |
| |
| svntest.actions.run_and_verify_svn(None, [], |
| 'ps', 'svn:eol-style', 'native', '--force', |
| sbox.ospath('add.c')) |
| |
| expected_disk = svntest.main.greek_state.copy() |
| |
| expected_disk.add({ |
| 'add-force.c' : Item(contents=expected_text), |
| 'add.c' : Item(contents=expected_text), |
| }) |
| |
| # Verify that both add and add-force haven't been changed |
| svntest.actions.verify_disk(wc_dir, expected_disk) |
| |
| sbox.simple_propset('svn:auto-props', '*.c = svn:eol-style=native', '') |
| |
| |
| svntest.main.file_write(sbox.ospath('auto.c'), text, mode='wb') |
| |
| expected_output = ['A %s\n' % sbox.ospath('auto.c')] |
| |
| # Fails with svn: E200009: File '.*auto.c' has inconsistent newlines |
| svntest.actions.run_and_verify_svn(expected_output, |
| [], 'add', sbox.ospath('auto.c')) |
| |
| @XFail() |
| @Issues(4327) |
| def autoprops_inconsistent_mime(sbox): |
| "able to handle inconsistent mime on add" |
| |
| sbox.build(read_only = True) |
| |
| sbox.simple_propset('svn:auto-props', |
| '*.c = svn:eol-style=native\n' |
| 'c.* = svn:mime-type=application/octet-stream', '') |
| |
| sbox.simple_append('c.iota.c', '') |
| |
| expected_output = ['A %s\n' % sbox.ospath('c.iota.c')] |
| |
| # Fails with svn: E200009: File '.*c.iota.c' has binary mime type property |
| svntest.actions.run_and_verify_svn(expected_output, |
| [], 'add', sbox.ospath('c.iota.c')) |
| |
| |
| ######################################################################## |
| # Run the tests |
| |
| |
| # list all tests here, starting with None: |
| test_list = [ None, |
| keywords_from_birth, |
| # enable_translation, |
| # checkout_translated, |
| # disable_translation, |
| update_modified_with_translation, |
| eol_change_is_text_mod, |
| keyword_expanded_on_checkout, |
| cat_keyword_expansion, |
| copy_propset_commit, |
| propset_commit_checkout_nocrash, |
| propset_revert_noerror, |
| props_only_file_update, |
| autoprops_inconsistent_eol, |
| autoprops_inconsistent_mime, |
| ] |
| |
| if __name__ == '__main__': |
| svntest.main.run_tests(test_list) |
| # NOTREACHED |
| |
| |
| ### End of file. |