| #!/usr/bin/env python |
| # -*- coding: utf-8 -*- |
| # Copyright (c) 2005, Giovanni Bajo |
| # All rights reserved. |
| # |
| # This program is free software; you can redistribute it and/or |
| # modify it under the terms of the GNU General Public License |
| # as published by the Free Software Foundation; either version 2 |
| # of the License, or (at your option) any later version. |
| # |
| # This program is distributed in the hope that it will be useful, |
| # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| # GNU General Public License for more details. |
| # |
| # You should have received a copy of the GNU General Public License |
| # along with this program; if not, write to the Free Software |
| # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
| import sys, os |
| import types |
| import re |
| import unittest |
| from StringIO import StringIO |
| import shutil |
| import svnmerge |
| import stat |
| import atexit |
| import getopt |
| import locale |
| |
| #### |
| # IMPORTANT NOTE TO TEST AUTHORS |
| # |
| # Any quoted strings inside the arguments of the parameter "cmd" must |
| # be enclosed in double-, not single-quotes, so that the command parser |
| # knows to keep them together. For example, do not write this: |
| # launch("svn ci -m 'log comment'") # BAD |
| # ...but one of these: |
| # launch('svn ci -m "log comment"') # GOOD |
| # launch("svn ci -m \"log comment\"") # GOOD, but why? |
| # Otherwise, you get an error saying |
| # '<path>/comment' is not under version control |
| # ...when running the tests on Windows. |
| #### |
| |
| # True/False constants are Python 2.2+ |
| try: |
| True, False |
| except NameError: |
| True, False = 1, 0 |
| |
| class StringIOWithEncoding(StringIO): |
| def __init__(self): |
| StringIO.__init__(self) |
| self.encoding = sys.stdout.encoding |
| |
| class TestCase_kwextract(unittest.TestCase): |
| def test_basic(self): |
| self.assertEqual(svnmerge.kwextract("$Rev: 134 rasky $"), "134 rasky") |
| self.assertEqual(svnmerge.kwextract("$Date: 2005-09-25 13:45 CET+1$"), |
| "2005-09-25 13:45 CET+1") |
| |
| def test_failure(self): |
| self.assertEqual(svnmerge.kwextract("$Rev: $"), "<unknown>") |
| self.assertEqual(svnmerge.kwextract("$Date$"), "<unknown>") |
| |
| def reset_svnmerge(): |
| svnmerge.opts = svnmerge.default_opts.copy() |
| svnmerge._cache_svninfo = {} |
| svnmerge._cache_reporoot = {} |
| svnmerge.PathIdentifier.locobjs = {} |
| svnmerge.PathIdentifier.repo_hints = {} |
| |
| class TestCase_launch(unittest.TestCase): |
| if os.name == "nt": |
| cmd = "attrib" |
| else: |
| cmd = "ls" |
| |
| def test_basic(self): |
| out = svnmerge.launch(self.cmd) |
| self.assert_(out) |
| for o in out: |
| self.assertEqual(o[-1], "\n") |
| |
| def test_failure(self): |
| self.assertRaises(svnmerge.LaunchError, svnmerge.launch, self.cmd*10) |
| |
| def test_failurecode(self): |
| try: |
| svnmerge.launch(self.cmd*10) |
| except svnmerge.LaunchError as (ret, cmd, out): |
| self.assertNotEqual(ret, 0) |
| self.assertNotEqual(ret, None) |
| self.assert_(out) |
| self.assertEqual(cmd, self.cmd*10) |
| else: |
| self.fail("svnmerge.launch did not cause a LaunchError as expected") |
| |
| class TestCase_PrefixLines(unittest.TestCase): |
| def test_basic(self): |
| self.assertEqual("zz\n", svnmerge.prefix_lines("zz", "\n")) |
| self.assertEqual("zzfoo\n", svnmerge.prefix_lines("zz", "foo\n")) |
| self.assertEqual("zzfoo\nzzbar\n", svnmerge.prefix_lines("zz", "foo\nbar\n")) |
| self.assertEqual("zz\nzzfoo\n", svnmerge.prefix_lines("zz", "\nfoo\n")) |
| self.assertEqual("zz\nzzfoo\nzzbar\n", svnmerge.prefix_lines("zz", "\nfoo\nbar\n")) |
| |
| class TestCase_RevisionSet(unittest.TestCase): |
| def test_constr_string(self): |
| rs = svnmerge.RevisionSet("10- 15, 12-48,2 ") |
| self.assert_(17 in rs) |
| self.assert_(2 in rs) |
| self.assert_(9 not in rs) |
| |
| rs = svnmerge.RevisionSet("10: 15, 12:48,2 ") |
| self.assert_(17 in rs) |
| self.assert_(2 in rs) |
| self.assert_(9 not in rs) |
| |
| def test_constr_dict(self): |
| rs = svnmerge.RevisionSet({18:1, 24:1, 25:1, 43:1}) |
| self.assert_(24 in rs) |
| self.assert_(18 in rs) |
| self.assert_(44 not in rs) |
| |
| def test_constr_error(self): |
| self.assertRaises(ValueError, svnmerge.RevisionSet, "10-12-15") |
| self.assertRaises(ValueError, svnmerge.RevisionSet, "10;12-15") |
| self.assertRaises(ValueError, svnmerge.RevisionSet, "10,foo,3-15") |
| |
| self.assertRaises(ValueError, svnmerge.RevisionSet, "10:12:15") |
| self.assertRaises(ValueError, svnmerge.RevisionSet, "10;12:15") |
| self.assertRaises(ValueError, svnmerge.RevisionSet, "10,foo,3:15") |
| |
| def test_normalized(self): |
| rs = svnmerge.RevisionSet("8-15,16-18, 4-6, 9, 18, 1-1, 3-3") |
| self.assertEqual(rs.normalized(), [(1,1), (3,6), (8,18)]) |
| self.assertEqual(str(rs), "1,3-6,8-18") |
| |
| rs = svnmerge.RevisionSet("8:15,16:18, 4:6, 9, 18, 1:1, 3:3") |
| self.assertEqual(rs.normalized(), [(1,1), (3,6), (8,18)]) |
| self.assertEqual(str(rs), "1,3-6,8-18") |
| |
| def test_sorted(self): |
| "Test the sorted() function of the RevisionSet class." |
| rs = svnmerge.RevisionSet("8-15,16-18, 4-6, 9, 18, 1-1, 3-3") |
| self.assertEqual(rs.sorted(), [1, 3, 4, 5, 6, 8, 9, 10, 11, |
| 12, 13, 14, 15, 16, 17, 18]) |
| |
| rs = svnmerge.RevisionSet("8:15,16:18, 4:6, 9, 18, 1:1, 3:3") |
| self.assertEqual(rs.sorted(), [1, 3, 4, 5, 6, 8, 9, 10, 11, |
| 12, 13, 14, 15, 16, 17, 18]) |
| |
| def test_length(self): |
| rs = svnmerge.RevisionSet("3-8") |
| self.assertEqual(len(rs), 6) |
| rs = svnmerge.RevisionSet("3-8,4-10") |
| self.assertEqual(len(rs), 8) |
| rs = svnmerge.RevisionSet("1,3,5") |
| self.assertEqual(len(rs), 3) |
| |
| rs = svnmerge.RevisionSet("3:8") |
| self.assertEqual(len(rs), 6) |
| rs = svnmerge.RevisionSet("3:8,4:10") |
| self.assertEqual(len(rs), 8) |
| rs = svnmerge.RevisionSet("1,3,5") |
| self.assertEqual(len(rs), 3) |
| |
| def test_iter(self): |
| try: |
| iter |
| except NameError: |
| pass |
| else: |
| rs = svnmerge.RevisionSet("4-13,1-5,34,20-22,18-21") |
| self.assertEqual(list(iter(rs)), range(1,14)+range(18,23)+[34]) |
| |
| rs = svnmerge.RevisionSet("4:13,1:5,34,20:22,18:21") |
| self.assertEqual(list(iter(rs)), range(1,14)+range(18,23)+[34]) |
| |
| def test_union(self): |
| rs = svnmerge.RevisionSet("3-8,4-10") | svnmerge.RevisionSet("7-14,1") |
| self.assertEqual(str(rs), "1,3-14") |
| |
| rs = svnmerge.RevisionSet("3:8,4:10") | svnmerge.RevisionSet("7:14,1") |
| self.assertEqual(str(rs), "1,3-14") |
| |
| def test_subtraction(self): |
| rs = svnmerge.RevisionSet("3-8,4-10") - svnmerge.RevisionSet("7-14,1") |
| self.assertEqual(str(rs), "3-6") |
| |
| rs = svnmerge.RevisionSet("3:8,4:10") - svnmerge.RevisionSet("7:14,1") |
| self.assertEqual(str(rs), "3-6") |
| |
| def test_constr_empty(self): |
| rs = svnmerge.RevisionSet("") |
| self.assertEqual(str(rs), "") |
| |
| class TestCase_PathIdentifier(unittest.TestCase): |
| rrp = "/trunk/contrib/client-side/svnmerge" |
| uuid = "65390229-12b7-0310-b90b-f21a5aa7ec8e" |
| uuidrl = 'uuid://'+uuid+rrp |
| url= "http://svn.apache.org/repos/asf/subversion/trunk/contrib/client-side/svnmerge" |
| ext = "uuid://65390229-12b7-0310-b90b-f21a5aa7ec8e/trunk/contrib/client-side/svnmerge" |
| def try_pathid(self, rrp, uuid, url, ext, expected_str, expected_formats): |
| l = svnmerge.PathIdentifier(rrp, uuid, url, ext) |
| self.assertEqual(str(l), expected_str, |
| "str() gave '%s' instead of '%s'" % (str(l), expected_str)) |
| for k, v in expected_formats.items(): |
| self.assertEqual(l.format(k), v, |
| "format('%s') gave '%s' instead of '%s'" % (k, l.format(k), v)) |
| reset_svnmerge() |
| |
| def test_PathIdentifier_just_path(self): |
| self.try_pathid(self.rrp, None, None, None, |
| self.rrp, { 'path' : self.rrp }) |
| |
| def test_PathIdentifier_uuid(self): |
| self.try_pathid(self.rrp, self.uuid, None, None, |
| self.uuidrl, { 'path' : self.rrp, 'uuid' : self.uuidrl }) |
| |
| def test_PathIdentifier_url(self): |
| self.try_pathid(self.rrp, None, self.url, None, |
| self.url, { 'path' : self.rrp, 'url' : self.url }) |
| |
| def test_PathIdentifier_prefer_url(self): |
| self.try_pathid(self.rrp, self.uuid, self.url, None, |
| self.url, { 'path' : self.rrp, 'url' : self.url, 'uuid' : self.uuidrl }) |
| |
| def test_PathIdentifier_external_form(self): |
| self.try_pathid(self.rrp, self.uuid, self.url, self.ext, |
| self.ext, { 'path' : self.rrp, 'url' : self.url, 'uuid' : self.uuidrl }) |
| |
| class TestCase_MinimalMergeIntervals(unittest.TestCase): |
| def test_basic(self): |
| rs = svnmerge.RevisionSet("4-8,12,18,24") |
| phantom = svnmerge.RevisionSet("8-11,13-16,19-23") |
| revs = svnmerge.minimal_merge_intervals(rs, phantom) |
| self.assertEqual(revs, [(4,12), (18,24)]) |
| |
| class TestCase_SvnMerge(unittest.TestCase): |
| def svnmerge(self, cmds, *args, **kwargs): |
| return self.svnmerge2(cmds.split(), *args, **kwargs) |
| |
| def svnmerge2(self, args, error=False, match=None, nonmatch=None): |
| # svnmerge's get_commit_log method needs the "encoding" method of |
| # sys.stdout, which is not provided by StringIO |
| out = StringIOWithEncoding() |
| sys.stdout = sys.stderr = out |
| try: |
| try: |
| # Clear svnmerge's internal caches before running any |
| # commands. |
| reset_svnmerge() |
| |
| ret = svnmerge.main(args) |
| except SystemExit as e: |
| ret = e.code |
| finally: |
| sys.stdout = sys.__stdout__ |
| sys.stderr = sys.__stderr__ |
| |
| if ret is None: |
| ret = 0 |
| |
| if error: |
| self.assertNotEqual(ret, 0, |
| "svnmerge did not fail, with this output:\n%s" % out.getvalue()) |
| else: |
| self.assertEqual(ret, 0, |
| "svnmerge failed, with this output:\n%s" % out.getvalue()) |
| |
| if match is not None: |
| self.assert_(re.search(match, out.getvalue()), |
| "pattern %r not found in output:\n%s" % (match, out.getvalue())) |
| if nonmatch is not None: |
| self.assert_(not re.search(nonmatch, out.getvalue()), |
| "pattern %r found in output:\n%s" % (nonmatch, out.getvalue())) |
| |
| return out.getvalue() |
| |
| def _parseoutput(self, ret, out, error=False, match=None, nonmatch=None): |
| if error: |
| self.assertNotEqual(ret, |
| 0, |
| "svnmerge did not fail, with this output:\n%s" % out) |
| else: |
| self.assertEqual(ret, |
| 0, |
| "svnmerge failed, with this output:\n%s" % out) |
| |
| if match is not None: |
| self.assert_(re.search(match, out), |
| "pattern %r not found in output:\n%s" % (match, out)) |
| |
| if nonmatch is not None: |
| self.assert_(not re.search(nonmatch, out), |
| "pattern %r found in output:\n%s" % (nonmatch, out)) |
| |
| return out |
| |
| def launch(self, cmd, **kwargs): |
| try: |
| out = svnmerge.launch(cmd, split_lines=False) |
| except svnmerge.LaunchError as (ret, cmd, out): |
| return self._parseoutput(ret, out, **kwargs) |
| return self._parseoutput(0, out, **kwargs) |
| |
| class TestCase_CommandLineOptions(TestCase_SvnMerge): |
| def test_empty(self): |
| self.svnmerge("") |
| |
| def test_help_commands(self): |
| self.svnmerge("help") |
| self.svnmerge("--help") |
| self.svnmerge("-h") |
| for cmd in svnmerge.command_table.keys(): |
| self.svnmerge("help %s" % cmd) |
| self.svnmerge("%s --help" % cmd) |
| self.svnmerge("%s -h" % cmd) |
| |
| def test_wrong_commands(self): |
| self.svnmerge("asijdoiasjd", error=True) |
| self.svnmerge("help asijdoiasjd", error=True) |
| |
| def test_wrong_option(self): |
| self.svnmerge("--asdsad", error=True) |
| self.svnmerge("help --asdsad", error=True) |
| self.svnmerge("init --asdsad", error=True) |
| self.svnmerge("--asdsad init", error=True) |
| |
| def test_version(self): |
| out = self.svnmerge("--version") |
| self.assert_(out.find("Giovanni Bajo") >= 0) |
| out = self.svnmerge("-V") |
| self.assert_(out.find("Giovanni Bajo") >= 0) |
| out = self.svnmerge("init -V") |
| self.assert_(out.find("Giovanni Bajo") >= 0) |
| |
| def temp_path(): |
| try: |
| return os.environ["TEMP"] |
| except KeyError: |
| pass |
| if os.name == "posix": |
| return "/tmp" |
| return "." |
| |
| def rmtree(path): |
| def onerror(func, path, excinfo): |
| if func in [os.remove, os.rmdir]: |
| if os.path.exists(path): |
| os.chmod(path, stat.S_IWRITE) |
| func(path) |
| |
| if os.path.isdir(path): |
| shutil.rmtree(path, onerror=onerror) |
| |
| def get_template_path(): |
| p = os.path.join(temp_path(), "__svnmerge_test_template") |
| return os.path.abspath(p) |
| |
| def get_test_path(): |
| p = os.path.join(temp_path(), "__svnmerge_test") |
| return os.path.abspath(p) |
| |
| def abspath_to_url(path): |
| assert path == os.path.abspath(path) |
| path = path.replace("\\", "/") |
| if path[0] != '/': |
| path = '/' + path |
| return "file://" + path |
| |
| class TestCase_TestRepo(TestCase_SvnMerge): |
| def setUp(self): |
| """Creates a working copy of a branch at r13 with the |
| following structure, containing revisions (3-6, 13): |
| |
| test-branch/ |
| test1 |
| test2 |
| test3 |
| |
| ...from a repository with the following structure: |
| |
| Path Created rev |
| ---- ----------- |
| / 0 |
| trunk/ 3 |
| test1 4 |
| test2 5 |
| test3 6 |
| test4 9 |
| test5 10 |
| branches/ 1 |
| testYYY-branch/ 11 (renamed from testXXX-branch in 12) |
| test1 4 |
| test2 5 |
| test3 6 |
| test-branch/ 13 (copied from trunk@6) |
| test1 4 |
| test2 5 |
| test3 6 |
| tags/ 2 |
| """ |
| self.cwd = os.getcwd() |
| reset_svnmerge() |
| |
| test_path = get_test_path() |
| template_path = get_template_path() |
| |
| self.template_path = template_path |
| self.test_path = test_path |
| |
| self.template_repo_path = os.path.join(template_path, "repo") |
| self.template_repo_url = abspath_to_url(self.template_repo_path) |
| |
| self.test_repo_path = os.path.join(test_path, "repo") |
| self.test_repo_url = abspath_to_url(self.test_repo_path) |
| |
| if not os.path.isdir(template_path): |
| rmtree(template_path) |
| os.makedirs(template_path) |
| os.chdir(template_path) |
| |
| self.multilaunch(""" |
| svnadmin create --fs-type fsfs %(TEMPLATE_REPO_PATH)s |
| svn mkdir -m "create /branches" %(TEMPLATE_REPO_URL)s/branches |
| svn mkdir -m "create /tags" %(TEMPLATE_REPO_URL)s/tags |
| svn mkdir -m "create /trunk" %(TEMPLATE_REPO_URL)s/trunk |
| svn co %(TEMPLATE_REPO_URL)s/trunk trunk |
| """) |
| |
| os.chdir("trunk") |
| open("test1", "w").write("test 1") |
| open("test2", "w").write("test 2") |
| open("test3", "w").write("test 3") |
| open("test4", "w").write("test 4") |
| open("test5", "w").write("test 5") |
| |
| self.multilaunch(""" |
| svn add test1 |
| svn ci -m "add test1" |
| svn add test2 |
| svn ci -m "add test2" |
| svn add test3 |
| svn ci -m "add test3" |
| svn mkdir -m "create /foobar" %(TEMPLATE_REPO_URL)s/foobar |
| svn rm -m "remove /foobar" %(TEMPLATE_REPO_URL)s/foobar |
| svn add test4 |
| svn ci -m "add test4" |
| svn add test5 |
| svn ci -m "add test5" |
| svn cp -r6 -m "create branch" %(TEMPLATE_REPO_URL)s/trunk %(TEMPLATE_REPO_URL)s/branches/testXXX-branch |
| svn mv -m "rename branch" %(TEMPLATE_REPO_URL)s/branches/testXXX-branch %(TEMPLATE_REPO_URL)s/branches/testYYY-branch |
| svn cp -r6 -m "create branch" %(TEMPLATE_REPO_URL)s/trunk %(TEMPLATE_REPO_URL)s/branches/test-branch |
| """) |
| |
| os.chdir("..") |
| |
| self.launch("svn co %(TEMPLATE_REPO_URL)s/branches/test-branch") |
| |
| os.chdir(self.cwd) |
| |
| rmtree(self.test_path) |
| shutil.copytree(self.template_path, self.test_path) |
| os.chdir(self.test_path) |
| |
| # Relocate the test working copies from using the template |
| # repository to the test repository so the template repository |
| # is not affected by commits. |
| self.launch("svn switch --relocate %(TEMPLATE_REPO_URL)s %(TEST_REPO_URL)s trunk test-branch") |
| |
| os.chdir("test-branch") |
| |
| # Always remove the template directory when the tests have |
| # completed. |
| atexit.register(lambda: rmtree(template_path)) |
| |
| def tearDown(self): |
| os.chdir(self.cwd) |
| rmtree(self.test_path) |
| |
| def command_dict(self): |
| return { |
| "TEMPLATE_PATH": self.template_path, |
| "TEMPLATE_REPO_PATH": self.template_repo_path, |
| "TEMPLATE_REPO_URL": self.template_repo_url, |
| "TEST_PATH": self.test_path, |
| "TEST_REPO_PATH": self.test_repo_path, |
| "TEST_REPO_URL": self.test_repo_url, |
| } |
| |
| def launch(self, cmd, *args, **kwargs): |
| cmd = cmd % self.command_dict() |
| return TestCase_SvnMerge.launch(self, cmd, *args, **kwargs) |
| |
| def multilaunch(self, cmds): |
| for cmd in cmds.split("\n"): |
| cmd = cmd.strip() |
| if len(cmd) > 0: |
| svnmerge.launch(cmd % self.command_dict()) |
| |
| def revert(self): |
| self.multilaunch("svn revert -R .") |
| |
| def getproperty(self): |
| out = svnmerge.launch("svn pg %s ." % svnmerge.opts["prop"]) |
| if len(out) == 0: |
| return None |
| else: |
| return out[0].strip() |
| |
| def getBlockedProperty(self): |
| out = svnmerge.launch("svn pg %s ." % svnmerge.opts["block-prop"]) |
| if len(out) == 0: |
| return None |
| else: |
| return out[0].strip() |
| |
| def testNoWc(self): |
| os.mkdir("foo") |
| os.chdir("foo") |
| self.svnmerge("init", error=True, match=r"working dir") |
| self.svnmerge("avail", error=True, match=r"working dir") |
| self.svnmerge("integrated", error=True, match=r"working dir") |
| self.svnmerge("merge", error=True, match=r"working dir") |
| self.svnmerge("block", error=True, match=r"working dir") |
| self.svnmerge("unblock", error=True, match=r"working dir") |
| |
| def testCheckNoIntegrationInfo(self): |
| self.svnmerge("avail", error=True, match=r"no integration") |
| self.svnmerge("integrated", error=True, match=r"no integration") |
| self.svnmerge("merge", error=True, match=r"no integration") |
| self.svnmerge("block", error=True, match=r"no integration") |
| self.svnmerge("unblock", error=True, match=r"no integration") |
| |
| def testSelfReferentialInit(self): |
| self.svnmerge2(["init", self.test_repo_url + "/branches/test-branch"], |
| error=True, match=r"cannot init integration source") |
| |
| def testAvailURL(self): |
| # Initialize svnmerge |
| self.svnmerge("init") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| self.svnmerge("avail %s/branches/test-branch" % self.test_repo_url, match=r"\A9-10$") |
| |
| def testBlocked(self): |
| |
| # Initialize svnmerge |
| self.svnmerge("init") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| # Block revisions that have already been merged |
| self.svnmerge("block -r5", error=True, match=r"no available revisions") |
| |
| # Block phantom revisions |
| self.svnmerge("block -r8", error=True, match=r"no available revisions") |
| |
| # Block available revisions |
| self.svnmerge("block -r9", match=r"'svnmerge-blocked' set") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| # Check that the revision is still available |
| self.svnmerge("avail", match=r"\A10$") |
| |
| # Check that the revision was blocked correctly |
| self.svnmerge("avail -B", match=r"\A9$") |
| |
| # Check that both revisions are available with avail -A |
| self.svnmerge("avail -A", match=r"\A9-10$") |
| |
| # Block all remaining revisions |
| self.svnmerge("block", match=r"'svnmerge-blocked' set") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| # Check that all revisions were blocked correctly |
| self.svnmerge("avail -B", match=r"\A9-10$") |
| |
| # Check that all revisions are available using avail -A |
| self.svnmerge("avail -A", match=r"\A9-10$") |
| |
| # Check that no revisions are available, now that they have |
| # been blocked |
| self.svnmerge("avail", match=r"\A\Z") |
| |
| # Unblock all revisions |
| self.svnmerge("unblock", match=r"'svnmerge-blocked' deleted") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| # Check that all revisions are available |
| self.svnmerge("avail", match=r"\A9-10$") |
| self.svnmerge("avail -A", match=r"\A9-10$") |
| |
| # Check that no revisions are blocked |
| self.svnmerge("avail -B", match=r"\A$") |
| |
| def testTransitiveMerge(self): |
| """ |
| Test a merge of a change from testYYY-branch -> test-branch -> trunk |
| """ |
| os.chdir("..") |
| self.launch("svn co %(TEST_REPO_URL)s/branches/testYYY-branch testYYY-branch") |
| |
| os.chdir("trunk") |
| self.launch("svn up") |
| self.svnmerge("init ../test-branch") |
| self.launch('svn ci -m "init test-branch -> trunk"', |
| match=r"Committed revision 14") |
| |
| os.chdir("../test-branch") |
| self.svnmerge("init -r 1-6 ../testYYY-branch") |
| self.launch('svn ci -m "init testYYY-branch -> test-branch"', |
| match=r"Committed revision 15") |
| |
| os.chdir("../testYYY-branch") |
| open("test6", "w").write("test6") |
| self.launch("svn add test6") |
| self.launch('svn ci -m "add test6"', |
| match=r"Committed revision 16") |
| |
| os.chdir("../test-branch") |
| self.svnmerge("merge -r 16") |
| self.launch('svn ci -m "merge r16"', |
| match=r"Committed revision 17") |
| |
| #os.chdir("../test-branch") |
| open("test5", "w").write("test5") |
| self.launch("svn add test5") |
| self.launch('svn ci -m "add test5"', |
| match=r"Committed revision 18") |
| |
| os.chdir("../trunk") |
| self.svnmerge("block -r 18") |
| self.launch('svn ci -m "block r18"', |
| match=r"Committed revision 19") |
| |
| #os.chdir("../trunk") |
| out = self.svnmerge("merge -r 17") |
| |
| self.launch('svn ci -m "merge r17 from test-branch"', |
| match=r"Committed revision 20") |
| |
| p = self.getproperty() |
| self.assertEqual(p, '/branches/test-branch:1-13,17') |
| p = self.getBlockedProperty() |
| self.assertEqual(p, '/branches/test-branch:18') |
| |
| def testTransitiveMergeWithBlock(self): |
| """ |
| Test a merge of a change from testYYY-branch -> test-branch -> trunk |
| """ |
| os.chdir("..") |
| self.launch("svn co %(TEST_REPO_URL)s/branches/testYYY-branch testYYY-branch") |
| |
| os.chdir("trunk") |
| self.launch("svn up") |
| self.svnmerge("init ../test-branch") |
| self.launch('svn ci -m "init test-branch -> trunk"', |
| match=r"Committed revision 14") |
| |
| os.chdir("../test-branch") |
| self.svnmerge("init -r 1-6 ../testYYY-branch") |
| self.launch('svn ci -m "init testYYY-branch -> test-branch"', |
| match=r"Committed revision 15") |
| |
| os.chdir("../testYYY-branch") |
| open("test4", "w").write("test4") |
| self.launch("svn add test4") |
| self.launch('svn ci -m "add test4"', |
| match=r"Committed revision 16") |
| |
| os.chdir("../test-branch") |
| self.svnmerge("block -r 16") |
| self.launch('svn ci -m "block r16"', |
| match=r"Committed revision 17") |
| |
| #os.chdir("../test-branch") |
| open("test5", "w").write("test5") |
| self.launch("svn add test5") |
| self.launch('svn ci -m "add test5"', |
| match=r"Committed revision 18") |
| |
| os.chdir("../trunk") |
| self.svnmerge("block -r 18") |
| self.launch('svn ci -m "block r18"', |
| match=r"Committed revision 19") |
| |
| #os.chdir("../trunk") |
| self.svnmerge("merge -r 17") |
| self.launch('svn ci -m "merge r17 from test-branch"', |
| match=r"Committed revision 20") |
| |
| p = self.getproperty() |
| self.assertEqual(p, '/branches/test-branch:1-13,17') |
| p = self.getBlockedProperty() |
| self.assertEqual(p, '/branches/test-branch:18') |
| |
| def testBasic(self): |
| self.svnmerge("init") |
| p = self.getproperty() |
| self.assertEqual("/trunk:1-6", p) |
| |
| self.svnmerge("avail", match=r"\A9-10$") |
| self.svnmerge("avail -v", match=r"phantom.*7-8") |
| |
| self.svnmerge("avail -B", match=r"\A$") |
| self.svnmerge("avail -A", match=r"\A9-10$") |
| |
| self.svnmerge("avail --log", match=r"| r7.*| r8") |
| self.svnmerge("avail --diff -r9", match=r"Index: test4") |
| |
| self.svnmerge("avail --log -r5", match=r"\A\Z") |
| self.svnmerge("avail --diff -r5", match=r"\A\Z") |
| |
| self.svnmerge("integrated", match=r"^3-6$") |
| self.svnmerge("integrated --log -r5", match=r"| r5 ") |
| self.svnmerge("integrated --diff -r5", match=r"Index: test2") |
| |
| def test_log_msg_suggest(self): |
| self.svnmerge("init -vf commit-log.txt", match=r"wrote commit message") |
| self.assert_(os.path.exists("commit-log.txt")) |
| os.remove("commit-log.txt") |
| |
| def testInitForce(self): |
| open("test1", "a").write("foo") |
| self.svnmerge("init", error=True, match=r"clean") |
| self.svnmerge("init -F") |
| p = self.getproperty() |
| self.assertEqual("/trunk:1-6", p) |
| |
| def testUninit(self): |
| """Test that uninit works, for both merged and blocked revisions.""" |
| os.chdir("..") |
| self.launch("svn co %(TEST_REPO_URL)s/branches/testYYY-branch testYYY-branch") |
| |
| os.chdir("trunk") |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 13") |
| self.svnmerge2(["init", "-r1-13", |
| self.test_repo_url + "/branches/test-branch"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 14") |
| |
| self.svnmerge2(["init", self.test_repo_url + "/branches/testYYY-branch"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 15") |
| |
| # Create changes on test-branch that we can block |
| os.chdir("..") |
| os.chdir("test-branch") |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 15") |
| |
| open("test1", "w").write("test 1-changed_on_test-branch") |
| |
| self.launch("svn commit -m \"Change to test1 on test-branch\"", |
| match=r"Committed revision 16") |
| |
| # Create changes on testYYY-branch that we can block |
| os.chdir("..") |
| os.chdir("testYYY-branch") |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 16") |
| |
| open("test2", "w").write("test 2-changed_on_testYYY-branch") |
| |
| self.launch("svn commit -m \"Change to test2 on testYYY-branch\"", |
| match=r"Committed revision 17") |
| |
| # Block changes from both branches on the trunk |
| os.chdir("..") |
| os.chdir("trunk") |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 17") |
| self.svnmerge("block -S testYYY-branch", match=r"'svnmerge-blocked' set") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 18") |
| |
| self.svnmerge("block -S test-branch", match=r"'svnmerge-blocked' set") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 19") |
| |
| # Do the uninit |
| self.svnmerge2(["uninit", "--source", self.test_repo_url + "/branches/testYYY-branch"]) |
| |
| # Check that the merged property for testYYY-branch was removed, but |
| # not for test-branch |
| pmerged = self.getproperty() |
| self.assertEqual("/branches/test-branch:1-13", pmerged) |
| |
| # Check that the blocked property for testYYY-branch was removed, but |
| # not for test-branch |
| pblocked = self.getBlockedProperty() |
| self.assertEqual("/branches/test-branch:16", pblocked) |
| |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 20") |
| |
| self.svnmerge2(["uninit", "--source", self.test_repo_url + "/branches/test-branch"]) |
| |
| # Check that the merged and blocked properties for test-branch have been removed too |
| pmerged = self.getproperty() |
| self.assertEqual(None, pmerged) |
| |
| pblocked = self.getBlockedProperty() |
| self.assertEqual(None, pblocked) |
| |
| def testUninitForce(self): |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| self.svnmerge2(["init", self.test_repo_url + "/branches/testYYY-branch"]) |
| |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| p = self.getproperty() |
| # properties come back in arbitrary order, so search for them individually |
| self.assertTrue(re.search("/branches/testYYY-branch:1-\d+?", p)) |
| self.assertTrue(re.search("/trunk:1-\d+?", p)) |
| |
| open("test1", "a").write("foo") |
| |
| self.svnmerge("uninit --source " + self.test_repo_url + "/branches/testYYY-branch", |
| error=True, match=r"clean") |
| |
| self.svnmerge("uninit -F --source " + self.test_repo_url + "/branches/testYYY-branch") |
| p = self.getproperty() |
| self.assert_(re.search("^/trunk:1-\d+", p)) |
| |
| def testCheckNoCopyfrom(self): |
| os.chdir("..") |
| os.chdir("trunk") |
| self.svnmerge("init", error=True, match=r"no copyfrom") |
| |
| def testInitScenarios(self): |
| """ Run various scenarios w/ svnmerge.py init and verify |
| the default values that are set as the integrated |
| revisions.""" |
| |
| # Run init with branch as merge source and trunk as merge target |
| os.chdir("..") |
| os.chdir("trunk") |
| self.svnmerge("init ../test-branch") |
| # Verify range ends at rev in which branch was created |
| self.launch("svn proplist -v", match=r":1-13") |
| self.revert() |
| |
| # Run init with TRUNK as merge source and BRANCH as merge target |
| os.chdir("..") |
| os.chdir("test-branch") |
| self.svnmerge("init ../trunk") |
| # Verify range ends at rev of trunk which was copied to create branch |
| self.launch("svn proplist -v", match=r":1-6") |
| self.revert() |
| |
| # Same thing, but with no explicit parameter (should work implicitly) |
| self.svnmerge("init") |
| # Verify range ends at rev of trunk which was copied to create branch |
| self.launch("svn proplist -v", match=r":1-6") |
| self.revert() |
| |
| # Run init with TRUNK as merge src, & any other branch which is not |
| # a copy of trunk (or the source from which trunk was copied) |
| # as the merge target. |
| os.chdir("../trunk") |
| os.chdir("..") |
| self.launch('svn mkdir -m "create /other" %(TEST_REPO_URL)s/other') # creates r14 |
| self.launch("svn co %(TEST_REPO_URL)s/other") |
| os.chdir("other") |
| self.svnmerge("init ../trunk") |
| # Verify integrated range ends with merge source's latest rev as of |
| # the time of initialization: |
| self.launch("svn proplist -v", match=r":1-14") |
| self.revert() |
| |
| # Run init w/ explicit parms; verify them |
| self.svnmerge("init -r 1-999 ../trunk") |
| self.launch("svn proplist -v", match=r":1-999") |
| |
| def testTrimmedAvailMerge(self): |
| """Check that both avail and merge do not search for phantom revs too hard.""" |
| self.svnmerge("init") |
| self.svnmerge("avail -vv -r8-9", match=r"svn --non-interactive log.*-r8:9") |
| self.svnmerge("merge -F -vv -r8-9", match=r"svn --non-interactive log.*-r8:9") |
| self.svnmerge("avail -vv -r2", nonmatch=r"svn log") |
| self.svnmerge("integrated", match=r"^3-6,8-9$") |
| |
| def testMergeRecordOnly(self): |
| """Check that flagging revisions as manually merged works.""" |
| self.svnmerge("init") |
| self.svnmerge("avail -vv -r9", match=r"svn --non-interactive log.*-r9:9") |
| self.svnmerge("merge --record-only -F -vv -r9", |
| nonmatch=r"svn merge -r 8:9") |
| self.svnmerge("avail -r9", match=r"\A$") |
| self.svnmerge("integrated", match=r"^3-6,9$") |
| self.svnmerge("integrated -r9", match=r"^9$") |
| |
| def testBidirectionalMerges(self): |
| """Check that reflected revisions are recognized properly for bidirectional merges.""" |
| |
| os.chdir("..") |
| os.chdir("test-branch") |
| |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| os.chdir("..") |
| os.chdir("trunk") |
| |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 14") |
| self.svnmerge2(["init", "-r1-14", |
| self.test_repo_url + "/branches/test-branch"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 15") |
| os.remove("svnmerge-commit-message.txt") |
| |
| open("test1", "w").write("test 1-changed_on_trunk") |
| |
| self.launch("svn commit -m \"Change to test1 on trunk\"", |
| match=r"Committed revision 16") |
| |
| self.svnmerge("integrated", match=r"^13-14$") |
| |
| os.chdir("..") |
| os.chdir("test-branch") |
| |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 16") |
| |
| # test-branch was copied from trunk's r6. So non-phantom revs |
| # since that point should still be available to merge from |
| # trunk to test-branch: |
| self.svnmerge("avail -vv", match=r"\n9-10,16$") |
| self.svnmerge("merge -vv", match=r"svn --non-interactive merge --force -r 15:16") |
| p = self.getproperty() |
| self.assertEqual("/trunk:1-16", p) |
| self.svnmerge("integrated", match=r"^3-16$") |
| |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 17") |
| os.remove("svnmerge-commit-message.txt") |
| |
| open("test1", "w").write("test 1-changed_on_branch_after_merge_from_trunk") |
| |
| self.launch("svn commit -m \"Change to test1 on branch\"", |
| match=r"Committed revision 18") |
| |
| os.chdir("..") |
| os.chdir("trunk") |
| |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 18") |
| |
| # Check reflected revision is excluded with --bidirectional |
| self.svnmerge("avail -vv --bidirectional", match=r"\n18$") |
| |
| # and without --bidirectional. |
| self.svnmerge("avail -vv", match=r"\n18$") |
| |
| self.svnmerge("merge -vv", match=r"svn --non-interactive merge --force -r 17:18") |
| p = self.getproperty() |
| self.assertEqual("/branches/test-branch:1-18", p) |
| |
| self.svnmerge("integrated", match=r"^13-18$") |
| |
| def testBidirectionalMergesMultiBranch(self): |
| """Check that merges from a second branch are not considered reflected for other branches.""" |
| |
| os.chdir("..") |
| |
| self.multilaunch(""" |
| svn cp -m "Create test-branch2" %(TEST_REPO_URL)s/trunk %(TEST_REPO_URL)s/branches/test-branch2 |
| svn co %(TEST_REPO_URL)s/branches/test-branch2 test-branch2 |
| """) |
| |
| os.chdir("test-branch") |
| |
| self.svnmerge2(["init", "-r1-13", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 15") |
| os.remove("svnmerge-commit-message.txt") |
| |
| os.chdir("..") |
| os.chdir("test-branch2") |
| |
| self.svnmerge2(["init", "-r1-14", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 16") |
| os.remove("svnmerge-commit-message.txt") |
| |
| os.chdir("..") |
| os.chdir("trunk") |
| |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 16") |
| |
| self.svnmerge2(["init", "-r1-16", |
| self.test_repo_url + "/branches/test-branch"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 17") |
| os.remove("svnmerge-commit-message.txt") |
| self.svnmerge2(["init", "-r1-17", |
| self.test_repo_url + "/branches/test-branch2"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 18") |
| os.remove("svnmerge-commit-message.txt") |
| |
| os.chdir("..") |
| os.chdir("test-branch2") |
| |
| open("test1", "w").write("test 1-changed_on_branch2") |
| |
| self.launch("svn commit -m \"Change to test1 on branch2\"", |
| match=r"Committed revision 19") |
| |
| os.chdir("..") |
| os.chdir("trunk") |
| |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 19") |
| |
| # Merge into trunk |
| self.svnmerge("merge -vv -S /branches/test-branch2", |
| match=r"merge --force -r 18:19") |
| p = self.getproperty() |
| |
| # allow properties to come back in arbitrary order |
| self.assertTrue(re.search("/branches/test-branch2:1-19", p)) |
| self.assertTrue(re.search("/branches/test-branch:1-16", p)) |
| |
| self.svnmerge("integrated -S branch2", match=r"^14-19$") |
| self.svnmerge("integrated -S ../test-branch", match=r"^13-16$") |
| |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 20") |
| os.remove("svnmerge-commit-message.txt") |
| |
| os.chdir("..") |
| os.chdir("test-branch") |
| |
| # Not using switch, so must update to get latest repository rev. |
| self.launch("svn update", match=r"At revision 20") |
| |
| # Initialized revs should not be available for merge |
| self.svnmerge("avail -v", match=r"initialized.*17-18") |
| |
| # Latest revision on trunk which was merged from test-branch2 |
| # should be available for test-branch with --bidirectional flag. |
| self.svnmerge("avail -vv --bidirectional", match=r"merged are:\n20$") |
| |
| # and also without the --bidirectional flag. |
| self.svnmerge("avail -vv", match=r"merged are:\n20$") |
| |
| self.svnmerge("merge -vv", match=r"merge --force -r 19:20") |
| p = self.getproperty() |
| self.assertEqual("/trunk:1-20", p) |
| |
| self.svnmerge("integrated", match=r"^3-20$") |
| |
| def testRollbackWithoutInit(self): |
| """Rollback should error out if invoked prior to init""" |
| |
| self.svnmerge("rollback -vv -S ../trunk", |
| error = True, |
| match = r"no integration info available for path") |
| |
| def testRollbackOutsidePossibleRange(self): |
| """`svnmerge rollback' should error out if range contains revisions prior to |
| SOURCE creation date.""" |
| |
| # Initialize svnmerge |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| expected_error = r"""Specified revision range falls out of the rollback range.""" |
| self.svnmerge("rollback -vv -S ../trunk -r 2-14", |
| error = True, |
| match = expected_error) |
| |
| def testRollbackWithoutRevisionOpt(self): |
| """`svnmerge rollback' should error out if -r option is not given""" |
| |
| # Initialize svnmerge |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| self.svnmerge("rollback -vv -S ../trunk", |
| error = True, |
| match = r"The '-r' option is mandatory for rollback") |
| |
| def testInitAndRollbackRecordOnly(self): |
| """Init svnmerge, modify source head, merge, rollback --record-only.""" |
| |
| # Initialize svnmerge |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| # Rollback record-only |
| expected_output = r"property 'svnmerge-integrated' set on '.'" |
| detested_output = r""" |
| D test2 |
| D test3""" |
| self.svnmerge("rollback -vv --record-only -S ../trunk -r5-7", |
| match = expected_output, |
| nonmatch = detested_output) |
| |
| def testInitAndRollback(self): |
| """Init svnmerge, modify source head, merge, rollback.""" |
| |
| # Initialize svnmerge |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| # Svnmerge rollback r5-7 |
| expected_output = "D\s+test2\s+D\s+test3" |
| self.svnmerge("rollback -vv -S ../trunk -r5-7", |
| match = expected_output) |
| |
| def testMergeAndRollbackEmptyRevisionRange(self): |
| """Init svnmerge, modify source head, merge, rollback where no merge |
| occurred.""" |
| |
| # Initialize svnmerge |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| # Make changes to trunk |
| os.chdir("../trunk") |
| open("newfile", "w").close() |
| self.launch("svn add newfile") |
| self.launch('svn commit -m "Adding newfile"', match=r"Committed revision 15") |
| open("anothernewfile", "w").close() |
| self.launch("svn add anothernewfile") |
| self.launch('svn commit -m "Adding anothernewfile"', match=r"Committed revision 16") |
| |
| # Svnmerge block r15,16 |
| os.chdir("../test-branch") |
| self.launch("svn up ..", |
| error = False) |
| self.svnmerge("block -r 15,16 -S ../trunk") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 17") |
| self.svnmerge("merge -S ../trunk") |
| self.launch("svn commit -F svnmerge-commit-message.txt") |
| |
| # Svnmerge rollback r15-16 |
| self.svnmerge("rollback -vv -S ../trunk -r15-16", |
| error = False, |
| match = r"Nothing to rollback in revision range r15-16") |
| |
| def testMergeAndRollback(self): |
| """Init svnmerge, modify source head, merge, rollback.""" |
| |
| # Initialize svnmerge |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| # Make changes to trunk |
| os.chdir("../trunk") |
| open("newfile", "w").close() |
| self.launch("svn add newfile") |
| self.launch('svn commit -m "Adding newfile"', match=r"Committed revision 15") |
| |
| # Svnmerge merge r15 |
| os.chdir("../test-branch") |
| self.svnmerge("merge -r 15 -S ../trunk") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 16") |
| |
| # Svnmerge rollback r15 |
| self.svnmerge("rollback -vv -S ../trunk -r15", |
| match = r"-r 15:14") |
| |
| def testBlockMergeAndRollback(self): |
| """Init svnmerge, block, modify head, merge, rollback.""" |
| |
| # Initialize svnmerge |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| # Make changes to trunk |
| os.chdir("../trunk") |
| open("newfile", "w").close() |
| self.launch("svn add newfile") |
| self.launch('svn commit -m "Adding newfile"', match=r"Committed revision 15") |
| open("anothernewfile", "w").close() |
| self.launch("svn add anothernewfile") |
| self.launch('svn commit -m "Adding anothernewfile"', match=r"Committed revision 16") |
| |
| # Svnmerge block r16, merge r15 |
| os.chdir("../test-branch") |
| self.launch("svn up ..", |
| error = False) |
| self.svnmerge("block -r 16 -S ../trunk") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 17") |
| self.svnmerge("merge -S ../trunk", |
| nonmatch = r"A anothernewfile", |
| match = r"A newfile") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 18") |
| |
| # Svnmerge rollback revision range 15-18 (in effect only 15,17) |
| self.svnmerge("rollback -vv -S ../trunk -r15-18", |
| nonmatch = r"D anothernewfile") |
| |
| def testMergeWithPotentialPropertyConflict(self): |
| """Init branch B, merge changes from branch A to branch B, |
| init branch C, and attempt a merge of changes from branch B to |
| branch C.""" |
| |
| # Initialize merge info for test-branch. |
| self.svnmerge2(["init", "-r 3-6", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| # Make a change to trunk. |
| os.chdir("../trunk") |
| open("newfile", "w").close() |
| self.launch("svn add newfile") |
| self.launch('svn commit -m "Adding newfile"', |
| match=r"Committed revision 15") |
| |
| # Merge a change from trunk to test-branch. |
| os.chdir("../test-branch") |
| self.svnmerge("merge -r 15 -S ../trunk") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 16") |
| |
| # Get a WC for testYYY-branch. |
| os.chdir("..") |
| self.launch("svn co %s/branches/testYYY-branch" % self.test_repo_url) |
| os.chdir("testYYY-branch") |
| |
| # Initialize merge info for testYYY-branch. |
| self.svnmerge2(["init", "-r 13", |
| self.test_repo_url + "/branches/test-branch"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 17") |
| os.remove("svnmerge-commit-message.txt") |
| |
| ### FIXME: Unfortunately, we're getting a conflict for the |
| ### merge info property in the following svnmerge invocation |
| ### due to Subversion's (reasonable) lack of property value |
| ### merging (which isn't possible without knowing a property's |
| ### MIME type) |
| |
| # Attempt a merge of changes from test-branch to |
| # testYYY-branch. |
| self.svnmerge("merge -r 16 -S ../test-branch") |
| try: |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision 18") |
| except AssertionError: |
| self.assert_(os.path.isfile("dir_conflicts.prej")) |
| |
| def testCommitMessageEncoding(self): |
| """Init svnmerge, modify source head and commit with a message |
| containing non-ASCII caracters, merge, commit, and verify the commit |
| message was correctly encoded.""" |
| |
| # Initialize svnmerge |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match = r"Committed revision 14") |
| os.remove("svnmerge-commit-message.txt") |
| |
| commit_msg = u"adição no repositório" |
| input_encoding = locale.getdefaultlocale()[1] |
| output_encoding = sys.stdout.encoding |
| |
| # Create a file |
| os.chdir("../trunk") |
| open("newfile", "w").close() |
| |
| # Create a message containing non-ASCII caracters. The message will be |
| # kept inside a file, so we don't need to worry about Python or the OS |
| # converting the command line before it's sent to svn |
| msg_file = open('msg.txt', 'w') |
| msg_file.write(commit_msg.encode(input_encoding)) |
| msg_file.close() |
| |
| # Add the file and commit with the message above |
| self.launch("svn add newfile") |
| self.launch('svn commit -F msg.txt', match="Committed revision 15") |
| os.remove('msg.txt') |
| # Check the message was properly encoded by svn (this will currently |
| # only work if the user config file does not override log-encoding) |
| self.launch('svn log -r 15', match=commit_msg.encode(output_encoding)) |
| |
| # Merge changes into the branch commiting with the message provided by |
| # svnmerge |
| os.chdir("../test-branch") |
| self.svnmerge("merge") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match="Committed revision 16") |
| # The procedure above should have not misencoded the message |
| self.launch('svn log -r 16', match=commit_msg.encode(output_encoding)) |
| |
| |
| def test_pathid_fns(self): |
| # (see also TestCase_pathid_fns for tests that don't need a repos) |
| os.chdir("..") |
| self.assertEqual(svnmerge.pathid_to_url( "/branches/testYYY-branch", "./trunk"), |
| "%s/branches/testYYY-branch" % self.test_repo_url) |
| |
| self.assertTrue( |
| svnmerge.equivalent_pathids("/branches/testYYY-branch", |
| "/branches/testYYY-branch", |
| "./trunk")) |
| |
| self.assertFalse( |
| svnmerge.equivalent_pathids("/branches/test-branch", |
| "/branches/testYYY-branch", |
| "./trunk")) |
| |
| def test_invalid_url(self): |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) # warm up svnmerge |
| self.assertEqual(svnmerge.get_svninfo("file://foo/bar"), {}) |
| |
| def test_dict_from_revlist_prop(self): |
| locdict = svnmerge.dict_from_revlist_prop("/trunk:1-10 uuid://65390229-12b7-0310-b90b-f21a5aa7ec8e/branches/foo:20-30") |
| for k, v in locdict.items(): |
| if str(k) == '/trunk': |
| self.assertEqual(str(v), '1-10') |
| elif str(k) == 'uuid://65390229-12b7-0310-b90b-f21a5aa7ec8e/branches/foo': |
| self.assertEqual(str(v), '20-30') |
| else: |
| self.fail("Unknown pathid '%s'" % k) |
| |
| def test_pathid_fns(self): |
| os.chdir("..") |
| |
| # run svnmerge once to get things rolling |
| self.svnmerge("init", error=True) |
| |
| branch = svnmerge.PathIdentifier.from_target("test-branch") |
| trunk = svnmerge.PathIdentifier.from_target("trunk") |
| yy = svnmerge.PathIdentifier.from_target("%s/branches/testYYY-branch" % self.test_repo_url) |
| branchurl = svnmerge.PathIdentifier.from_target("%s/branches/test-branch" % self.test_repo_url) |
| trunkurl = svnmerge.PathIdentifier.from_target("%s/trunk" % self.test_repo_url) |
| |
| self.assertTrue(branchurl == branch) |
| self.assertFalse(branchurl != branch) |
| self.assertTrue(trunkurl == trunk) |
| self.assertTrue(yy != trunk) |
| |
| def test_PathIdentifier_hint_url(self): |
| os.chdir("..") |
| # prime the cache with our repo URL |
| svnmerge.PathIdentifier.hint(self.test_repo_url + '/trunk') |
| expected = svnmerge.PathIdentifier.locobjs['/trunk'] |
| |
| # and then we should get the same pathid for all of these |
| self.assertEqual(expected, svnmerge.PathIdentifier.from_target('trunk')) |
| self.assertEqual(expected, svnmerge.PathIdentifier.from_target(self.test_repo_url + '/trunk')) |
| |
| def test_is_pathid(self): |
| os.chdir("..") |
| l = svnmerge.PathIdentifier.from_target('trunk') |
| self.assertTrue(svnmerge.is_pathid(l)) |
| |
| def testOptionOrder(self): |
| """Make sure you can intermix command name, arguments and options in any order.""" |
| # this is under TestCase_TestRepo because it assumes that '.' is a svn working dir |
| self.svnmerge("--log avail", |
| error=True, |
| match=r"no integration info") # accepted |
| self.svnmerge("-l avail", |
| error=True, |
| match=r"no integration info") # accepted |
| self.svnmerge("-r123 merge", |
| error=True, |
| match=r"no integration info") # accepted |
| self.svnmerge("-s -v -r92481 merge", |
| error=True, |
| match=r"no integration info") # accepted |
| self.svnmerge("--log merge", |
| error=True, |
| match=r"option --log not recognized") |
| self.svnmerge("--diff foobar", error=True, match=r"foobar") |
| |
| # This requires gnu_getopt support to be parsed |
| if hasattr(getopt, "gnu_getopt"): |
| self.svnmerge("-r123 merge . --log", |
| error=True, |
| match=r"option --log not recognized") |
| |
| if __name__ == "__main__": |
| # If an existing template repository and working copy for testing |
| # exists, then always remove it. This prevents any problems if |
| # this test suite is modified and there exists an older template |
| # directory that may be used. This will also prevent problems if |
| # in a previous run of this script, the template was being created |
| # when the script was canceled, leaving it in an inconsistent |
| # state. |
| template_path = get_template_path() |
| if os.path.exists(template_path): |
| rmtree(template_path) |
| |
| unittest.main() |