????
Current Path : /proc/328295/root/usr/share/doc/subversion-1.6.11/ |
Current File : //proc/328295/root/usr/share/doc/subversion-1.6.11/svnmerge_test.py |
#!/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>") 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, (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_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 cache before running any # commands. svnmerge._cache_svninfo = {} svnmerge._cache_reporoot = {} ret = svnmerge.main(args) except SystemExit, 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, (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 testOptionOrder(self): """Make sure you can intermix command name, arguments and options in any order.""" 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") 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() 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() self.assert_(re.search("/branches/testYYY-branch:1-\d+? /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 branch2", match=r"merge --force -r 18:19") p = self.getproperty() self.assertEqual("/branches/test-branch:1-16 /branches/test-branch2:1-19", 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 occured.""" # 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)) 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()