| #!/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 cStringIO import StringIO |
| import shutil |
| import svnmerge |
| import stat |
| import atexit |
| import getopt |
| |
| # True/False constants are Python 2.2+ |
| try: |
| True, False |
| except NameError: |
| True, False = 1, 0 |
| |
| 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 = "dir" |
| 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_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) |
| |
| 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") |
| |
| 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") |
| |
| 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) |
| |
| 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]) |
| |
| def test_union(self): |
| 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") |
| |
| 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): |
| out = StringIO() |
| sys.stdout = sys.stderr = out |
| try: |
| try: |
| # Clear svnmerge's internal cache before running any |
| # commands. |
| svnmerge._cache_svninfo = {} |
| |
| 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="no integration info") # accepted |
| self.svnmerge("-l avail", |
| error=True, |
| match="no integration info") # accepted |
| self.svnmerge("-r123 merge", |
| error=True, |
| match="no integration info") # accepted |
| self.svnmerge("-s -v -r92481 merge", |
| error=True, |
| match="no integration info") # accepted |
| self.svnmerge("--log merge", |
| error=True, |
| match="option --log not recognized") |
| self.svnmerge("--diff foobar", error=True, match="foobar") |
| |
| # This requires gnu_getopt support to be parsed |
| if hasattr(getopt, "gnu_getopt"): |
| self.svnmerge("-r123 merge . --log", |
| error=True, |
| match="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) |
| |
| class TestCase_TestRepo(TestCase_SvnMerge): |
| def setUp(self): |
| 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 = "file://" + self.template_repo_path.replace("\\", "/") |
| |
| self.test_repo_path = os.path.join(test_path, "repo") |
| self.test_repo_url = "file://" + self.test_repo_path.replace("\\", "/") |
| |
| 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 command_dict(self): |
| return dict(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() |
| 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"]) |
| return out[0].strip() |
| |
| def testNoWc(self): |
| os.mkdir("foo") |
| os.chdir("foo") |
| self.svnmerge("init", error=True, match="working dir") |
| self.svnmerge("avail", error=True, match="working dir") |
| self.svnmerge("merge", error=True, match="working dir") |
| self.svnmerge("block", error=True, match="working dir") |
| self.svnmerge("unblock", error=True, match="working dir") |
| |
| def testCheckNoIntegrationInfo(self): |
| self.svnmerge("avail", error=True, match="no integration") |
| self.svnmerge("merge", error=True, match="no integration") |
| self.svnmerge("block", error=True, match="no integration") |
| self.svnmerge("unblock", error=True, match="no integration") |
| |
| 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="no available revisions") |
| |
| # Block phantom revisions |
| self.svnmerge("block -r8", error=True, match="no available revisions") |
| |
| # Block available revisions |
| self.svnmerge("block -r9", match="'svnmerge-blocked' set") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| # Check that the revision was blocked correctly |
| out = self.svnmerge("avail") |
| out = out.rstrip().split("\n") |
| self.assertEqual(out[-1].strip(), "10") |
| |
| # Block all remaining revisions |
| self.svnmerge("block", match="'svnmerge-blocked' set") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| # Check that all revisions were blocked correctly |
| out = self.svnmerge("avail") |
| out = out.rstrip().split("\n") |
| self.assertEqual(out[-1].strip(), "") |
| |
| # Unblock all revisions |
| self.svnmerge("unblock", match="'svnmerge-blocked' deleted") |
| self.launch("svn commit -F svnmerge-commit-message.txt", |
| match=r"Committed revision") |
| |
| # Check that all revisions are available |
| out = self.svnmerge("avail") |
| out = out.rstrip().split("\n") |
| self.assertEqual(out[-1].strip(), "9-10") |
| |
| def testBasic(self): |
| self.svnmerge("init") |
| p = self.getproperty() |
| self.assertEqual("/trunk:1-6", p) |
| |
| out = self.svnmerge("avail -v", match=r"phantom.*7-8") |
| out = out.rstrip().split("\n") |
| self.assertEqual(out[-1].strip(), "9-10") |
| |
| self.svnmerge("avail --log", match=r"| r7.*| r8") |
| self.svnmerge("avail --diff -r9", match="Index: test4") |
| |
| out = self.svnmerge("avail --log -r5") |
| self.assertEqual(out.strip(), "") |
| out = self.svnmerge("avail --diff -r5") |
| self.assertEqual(out.strip(), "") |
| |
| def testCommitFile(self): |
| self.svnmerge("init -vf commit-log.txt", match="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="clean") |
| self.svnmerge("init -F") |
| p = self.getproperty() |
| self.assertEqual("/trunk:1-6", p) |
| |
| def testCheckInitializeEverything(self): |
| self.svnmerge2(["init", self.test_repo_url + "/trunk"]) |
| p = self.getproperty() |
| r = svnmerge.get_svninfo(".")["Revision"] |
| self.assertEqual("/trunk:1-%d" % long(r), p) |
| |
| def testCheckNoCopyfrom(self): |
| os.chdir("..") |
| os.chdir("trunk") |
| self.svnmerge("init", error=True, match="no copyfrom") |
| |
| def tearDown(self): |
| os.chdir(self.cwd) |
| rmtree(self.test_path) |
| |
| 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 log.*-r8:9") |
| self.svnmerge("merge -F -vv -r8-9", match=r"svn log.*-r8:9") |
| self.svnmerge("avail -vv -r2", nonmatch=r"svn log") |
| |
| 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", 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") |
| |
| 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") |
| |
| self.svnmerge("avail -vv", match=r"15-16$") |
| self.svnmerge("merge -vv", match=r"merge -r 14:16") |
| p = self.getproperty() |
| self.assertEqual("/trunk:1-16", p) |
| |
| # There will be directory property conflict on 'test-branch' |
| # due to the attempted merge from trunk of the addition of the |
| # svnmerge-integrated property, which already exists in the |
| # branch since 'svnmerge.py init' was run in it. So just |
| # resolve it, as it currently has the correct value (only on |
| # svn 1.3.x, so do not execute a match assertion). |
| self.launch("svn resolved .") |
| |
| 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") |
| |
| # Ensure default is not to check for reflected revisions. |
| self.svnmerge("avail -vv", match=r"17-18$") |
| |
| # Now check reflected revision is excluded with --bidirectional flag. |
| self.svnmerge("avail -vv --bidirectional", match=r"18$") |
| |
| self.svnmerge("merge -vv --bidirectional", match=r"merge -r 17:18") |
| p = self.getproperty() |
| self.assertEqual("/branches/test-branch:1-18", p) |
| |
| 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", 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", 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", 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", 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 --head ../test-branch2", |
| match=r"merge -r 18:19") |
| p = self.getproperty() |
| self.assertEqual("/branches/test-branch:1-16 /branches/test-branch2:1-19", p) |
| |
| 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") |
| |
| # 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"20$") |
| |
| self.svnmerge("merge -vv --bidirectional", match=r"merge -r 17:20") |
| p = self.getproperty() |
| self.assertEqual("/trunk:1-20", p) |
| |
| 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() |