diff tests/test_util.py @ 1106:5cb6c95e0283 stable

Merge default and stable so I can do stable releases again.
author Augie Fackler <raf@durin42.com>
date Tue, 11 Feb 2014 12:48:49 -0500
parents 4a92eb1484ba
children a22d4972e01f
line wrap: on
line diff
--- a/tests/test_util.py
+++ b/tests/test_util.py
@@ -22,10 +22,16 @@ from mercurial import dispatch as dispat
 from mercurial import hg
 from mercurial import i18n
 from mercurial import node
+from mercurial import scmutil
 from mercurial import ui
 from mercurial import util
 from mercurial import extensions
 
+try:
+    from mercurial import obsolete
+except ImportError:
+    obsolete = None
+
 try:
     SkipTest = unittest.SkipTest
 except AttributeError:
@@ -100,6 +106,87 @@ subdir = {'truncatedhistory.svndump': '/
           'non_ascii_path_2.svndump': '/b%C3%B8b',
           'subdir_is_file_prefix.svndump': '/flaf',
           }
+# map defining the layouts of the fixtures we can use with custom layout
+# these are really popular layouts, so I gave them names
+trunk_only = {
+    'default': 'trunk',
+    }
+trunk_dev_branch = {
+    'default': 'trunk',
+    'dev_branch': 'branches/dev_branch',
+    }
+custom = {
+    'addspecial.svndump': {
+        'default': 'trunk',
+        'foo': 'branches/foo',
+        },
+    'binaryfiles.svndump': trunk_only,
+    'branch_create_with_dir_delete.svndump': trunk_dev_branch,
+    'branch_delete_parent_dir.svndump': trunk_dev_branch,
+    'branchmap.svndump': {
+        'default': 'trunk',
+        'badname': 'branches/badname',
+        'feature': 'branches/feature',
+        },
+    'branch_prop_edit.svndump': trunk_dev_branch,
+    'branch_rename_to_trunk.svndump': {
+        'default': 'trunk',
+        'dev_branch': 'branches/dev_branch',
+        'old_trunk': 'branches/old_trunk',
+        },
+    'copies.svndump': trunk_only,
+    'copybeforeclose.svndump': {
+        'default': 'trunk',
+        'test': 'branches/test'
+        },
+    'delentries.svndump': trunk_only,
+    'delete_restore_trunk.svndump': trunk_only,
+    'empty_dir_in_trunk_not_repo_root.svndump': trunk_only,
+    'executebit.svndump': trunk_only,
+    'filecase.svndump': trunk_only,
+    'file_not_in_trunk_root.svndump': trunk_only,
+    'project_name_with_space.svndump': trunk_dev_branch,
+    'pushrenames.svndump': trunk_only,
+    'rename_branch_parent_dir.svndump': trunk_dev_branch,
+    'renamedproject.svndump': {
+        'default': 'trunk',
+        'branch': 'branches/branch',
+        },
+    'renames.svndump': {
+        'default': 'trunk',
+        'branch1': 'branches/branch1',
+        },
+    'replace_branch_with_branch.svndump': {
+        'default': 'trunk',
+        'branch1': 'branches/branch1',
+        'branch2': 'branches/branch2',
+        },
+    'replace_trunk_with_branch.svndump': {
+        'default': 'trunk',
+        'test': 'branches/test',
+        },
+    'revert.svndump': trunk_only,
+    'siblingbranchfix.svndump': {
+        'default': 'trunk',
+        'wrongbranch': 'branches/wrongbranch',
+        },
+    'simple_branch.svndump': {
+        'default': 'trunk',
+        'the_branch': 'branches/the_branch',
+        },
+    'spaces-in-path.svndump': trunk_dev_branch,
+    'symlinks.svndump': trunk_only,
+    'truncatedhistory.svndump': trunk_only,
+    'unorderedbranch.svndump': {
+        'default': 'trunk',
+        'branch': 'branches/branch',
+        },
+    'unrelatedbranch.svndump': {
+        'default': 'trunk',
+        'branch1': 'branches/branch1',
+        'branch2': 'branches/branch2',
+        },
+}
 
 FIXTURES = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                         'fixtures')
@@ -110,6 +197,16 @@ def getlocalpeer(repo):
         localrepo = repo
     return localrepo
 
+def repolen(repo):
+    """Naively calculate the amount of available revisions in a repository.
+
+    this is usually equal to len(repo) -- except in the face of
+    obsolete revisions.
+    """
+    # kind of nasty way of calculating the length, but fortunately,
+    # our test repositories tend to be rather small
+    return len([r for r in repo])
+
 def _makeskip(name, message):
     if SkipTest:
         def skip(*args, **kwargs):
@@ -144,6 +241,18 @@ def requiresoption(option):
         raise TypeError('requiresoption takes a string argument')
     return decorator
 
+def requiresreplay(method):
+    '''Skip a test in stupid mode.'''
+    def test(self, *args, **kwargs):
+        if self.stupid:
+            if SkipTest:
+                raise SkipTest("test requires replay mode")
+        else:
+            return method(self, *args, **kwargs)
+
+    test.__name__ = method.__name__
+    return test
+
 def filtermanifest(manifest):
     return [f for f in manifest if f not in util.ignoredfiles]
 
@@ -170,7 +279,7 @@ def testui(stupid=False, layout='auto', 
 
 def dispatch(cmd):
     cmd = getattr(dispatchmod, 'request', lambda x: x)(cmd)
-    dispatchmod.dispatch(cmd)
+    return dispatchmod.dispatch(cmd)
 
 def rmtree(path):
     # Read-only files cannot be removed under Windows
@@ -240,9 +349,93 @@ def svnpropget(repo_path, path, prop, re
         raise Exception('svn ls failed on %s: %r' % (path, stderr))
     return stdout.strip()
 
+
+def _obsolete_wrap(cls, name):
+    origfunc = getattr(cls, name)
+
+    if not name.startswith('test_') or not origfunc:
+        return
+
+    if not obsolete:
+        wrapper = _makeskip(name, 'obsolete not available')
+    else:
+        def wrapper(self, *args, **opts):
+            self.assertFalse(obsolete._enabled, 'obsolete was already active')
+
+            obsolete._enabled = True
+
+            try:
+                    origfunc(self, *args, **opts)
+                    self.assertTrue(obsolete._enabled, 'obsolete remains active')
+            finally:
+                obsolete._enabled = False
+
+    if not wrapper:
+        return
+
+    wrapper.__name__ = name + ' obsolete'
+    wrapper.__module__ = origfunc.__module__
+
+    if origfunc.__doc__:
+        firstline = origfunc.__doc__.strip().splitlines()[0]
+        wrapper.__doc__ = firstline + ' (obsolete)'
+
+    assert getattr(cls, wrapper.__name__, None) is None
+
+    setattr(cls, wrapper.__name__, wrapper)
+
+
+def _stupid_wrap(cls, name):
+    origfunc = getattr(cls, name)
+
+    if not name.startswith('test_') or not origfunc:
+        return
+
+    def wrapper(self, *args, **opts):
+        self.assertFalse(self.stupid, 'stupid mode was already active')
+
+        self.stupid = True
+
+        try:
+            origfunc(self, *args, **opts)
+        finally:
+            self.stupid = False
+
+    wrapper.__name__ = name + ' stupid'
+    wrapper.__module__ = origfunc.__module__
+
+    if origfunc.__doc__:
+        firstline = origfunc.__doc__.strip().splitlines()[0]
+        wrapper.__doc__ = firstline + ' (stupid)'
+
+    assert getattr(cls, wrapper.__name__, None) is None
+
+    setattr(cls, wrapper.__name__, wrapper)
+
+class TestMeta(type):
+    def __init__(cls, *args, **opts):
+        if cls.obsolete_mode_tests:
+            for origname in dir(cls):
+                _obsolete_wrap(cls, origname)
+
+        if cls.stupid_mode_tests:
+            for origname in dir(cls):
+                _stupid_wrap(cls, origname)
+
+        return super(TestMeta, cls).__init__(*args, **opts)
+
 class TestBase(unittest.TestCase):
+    __metaclass__ = TestMeta
+
+    obsolete_mode_tests = False
+    stupid_mode_tests = False
+
+    stupid = False
+
     def setUp(self):
         _verify_our_modules()
+        if 'hgsubversion' in sys.modules:
+            sys.modules['hgext_hgsubversion'] = sys.modules['hgsubversion']
 
         # the Python 2.7 default of 640 is obnoxiously low
         self.maxDiff = 4096
@@ -256,9 +449,12 @@ class TestBase(unittest.TestCase):
         self.oldwd = os.getcwd()
         self.tmpdir = tempfile.mkdtemp(
             'svnwrap_test', dir=os.environ.get('HGSUBVERSION_TEST_TEMP', None))
+        os.chdir(self.tmpdir)
         self.hgrc = os.path.join(self.tmpdir, '.hgrc')
         os.environ['HGRCPATH'] = self.hgrc
+        scmutil._rcpath = None
         rc = open(self.hgrc, 'w')
+        rc.write('[ui]\nusername=test-user\n')
         for l in '[extensions]', 'hgsubversion=':
             print >> rc, l
 
@@ -279,8 +475,11 @@ class TestBase(unittest.TestCase):
         setattr(ui.ui, self.patch[0].func_name, self.patch[1])
 
     def setup_svn_config(self, config):
-        with open(self.config_dir + '/config', 'w') as c:
+        c = open(self.config_dir + '/config', 'w')
+        try:
             c.write(config)
+        finally:
+            c.close()
 
     def _makerepopath(self):
         self.repocount += 1
@@ -299,8 +498,8 @@ class TestBase(unittest.TestCase):
 
         _verify_our_modules()
 
-    def ui(self, stupid=False, layout='auto'):
-        return testui(stupid, layout)
+    def ui(self, layout='auto'):
+        return testui(self.stupid, layout)
 
     def load_svndump(self, fixture_name):
         '''Loads an svnadmin dump into a fresh repo. Return the svn repo
@@ -333,7 +532,7 @@ class TestBase(unittest.TestCase):
             tarball.extract(entry, path)
         return path
 
-    def fetch(self, repo_path, subdir=None, stupid=False, layout='auto',
+    def fetch(self, repo_path, subdir=None, layout='auto',
             startrev=0, externals=None, noupdate=True, dest=None, rev=None,
             config=None):
         if layout == 'single':
@@ -352,7 +551,7 @@ class TestBase(unittest.TestCase):
             fileurl(projectpath),
             self.wc_path,
             ]
-        if stupid:
+        if self.stupid:
             cmd.append('--stupid')
         if noupdate:
             cmd.append('--noupdate')
@@ -364,7 +563,8 @@ class TestBase(unittest.TestCase):
         for k,v in reversed(sorted(config.iteritems())):
             cmd[:0] = ['--config', '%s=%s' % (k, v)]
 
-        dispatch(cmd)
+        r = dispatch(cmd)
+        assert not r, 'fetch of %s failed' % projectpath
 
         return hg.repository(testui(), self.wc_path)
 
@@ -409,11 +609,11 @@ class TestBase(unittest.TestCase):
     def repo(self):
         return hg.repository(testui(), self.wc_path)
 
-    def pushrevisions(self, stupid=False, expected_extra_back=0):
-        before = len(self.repo)
-        self.repo.ui.setconfig('hgsubversion', 'stupid', str(stupid))
+    def pushrevisions(self, expected_extra_back=0):
+        before = repolen(self.repo)
+        self.repo.ui.setconfig('hgsubversion', 'stupid', str(self.stupid))
         res = commands.push(self.repo.ui, self.repo)
-        after = len(self.repo)
+        after = repolen(self.repo)
         self.assertEqual(expected_extra_back, after - before)
         return res
 
@@ -530,7 +730,7 @@ class TestBase(unittest.TestCase):
         extensions.loadall(_ui)
         graphlog = extensions.find('graphlog')
         templ = """\
-changeset: {rev}:{node|short}
+changeset: {rev}:{node|short} (r{svnrev})
 branch:    {branches}
 tags:      {tags}
 summary:   {desc|firstline}
@@ -543,4 +743,3 @@ files:     {files}
 
     def draw(self, repo):
         sys.stdout.write(self.getgraph(repo))
-