summaryrefslogtreecommitdiff
path: root/bzrlib/tests/fixtures.py
diff options
context:
space:
mode:
Diffstat (limited to 'bzrlib/tests/fixtures.py')
-rw-r--r--bzrlib/tests/fixtures.py160
1 files changed, 160 insertions, 0 deletions
diff --git a/bzrlib/tests/fixtures.py b/bzrlib/tests/fixtures.py
new file mode 100644
index 0000000..33591d9
--- /dev/null
+++ b/bzrlib/tests/fixtures.py
@@ -0,0 +1,160 @@
+# Copyright (C) 2010 Canonical Ltd
+#
+# 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
+
+
+"""Fixtures that can be used within tests.
+
+Fixtures can be created during a test as a way to separate out creation of
+objects to test. Fixture objects can hold some state so that different
+objects created during a test instance can be related. Normally a fixture
+should live only for the duration of a single test, and its tearDown method
+should be passed to `addCleanup` on the test.
+"""
+
+
+import itertools
+
+
+def generate_unicode_names():
+ """Generate a sequence of arbitrary unique unicode names.
+
+ By default they are not representable in ascii.
+
+ >>> gen = generate_unicode_names()
+ >>> n1 = gen.next()
+ >>> n2 = gen.next()
+ >>> type(n1)
+ <type 'unicode'>
+ >>> n1 == n2
+ False
+ >>> n1.encode('ascii', 'replace') == n1
+ False
+ """
+ # include a mathematical symbol unlikely to be in 8-bit encodings
+ return (u"\N{SINE WAVE}%d" % x for x in itertools.count())
+
+
+interesting_encodings = [
+ ('iso-8859-1', False),
+ ('ascii', False),
+ ('cp850', False),
+ ('utf-8', True),
+ ('ucs-2', True),
+ ]
+
+
+def generate_unicode_encodings(universal_encoding=None):
+ """Return a generator of unicode encoding names.
+
+ These can be passed to Python encode/decode/etc.
+
+ :param universal_encoding: True/False/None tristate to say whether the
+ generated encodings either can or cannot encode all unicode
+ strings.
+
+ >>> n1 = generate_unicode_names().next()
+ >>> enc = generate_unicode_encodings(universal_encoding=True).next()
+ >>> enc2 = generate_unicode_encodings(universal_encoding=False).next()
+ >>> n1.encode(enc).decode(enc) == n1
+ True
+ >>> try:
+ ... n1.encode(enc2).decode(enc2)
+ ... except UnicodeError:
+ ... print 'fail'
+ fail
+ """
+ # TODO: check they're supported on this platform?
+ if universal_encoding is not None:
+ e = [n for (n, u) in interesting_encodings if u == universal_encoding]
+ else:
+ e = [n for (n, u) in interesting_encodings]
+ return itertools.cycle(iter(e))
+
+
+class RecordingContextManager(object):
+ """A context manager that records."""
+
+ def __init__(self):
+ self._calls = []
+
+ def __enter__(self):
+ self._calls.append('__enter__')
+ return self # This is bound to the 'as' clause in a with statement.
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self._calls.append('__exit__')
+ return False # propogate exceptions.
+
+
+def build_branch_with_non_ancestral_rev(branch_builder):
+ """Builds a branch with a rev not in the ancestry of the tip.
+
+ This is the revision graph::
+
+ rev-2
+ |
+ rev-1
+ |
+ (null)
+
+ The branch tip is 'rev-1'. 'rev-2' is present in the branch's repository,
+ but is not part of rev-1's ancestry.
+
+ :param branch_builder: A BranchBuilder (e.g. from
+ TestCaseWithMemoryTransport.make_branch_builder).
+ :returns: the new branch
+ """
+ # Make a sequence of two commits
+ branch_builder.build_commit(message="Rev 1", rev_id='rev-1')
+ branch_builder.build_commit(message="Rev 2", rev_id='rev-2')
+ # Move the branch tip back to the first commit
+ source = branch_builder.get_branch()
+ source.set_last_revision_info(1, 'rev-1')
+ return source
+
+
+def make_branch_and_populated_tree(testcase):
+ """Make a simple branch and tree.
+
+ The tree holds some added but uncommitted files.
+ """
+ # TODO: Either accept or return the names of the files, so the caller
+ # doesn't need to be bound to the particular files created? -- mbp
+ # 20110705
+ tree = testcase.make_branch_and_tree('t')
+ testcase.build_tree_contents([('t/hello', 'hello world')])
+ tree.add(['hello'], ['hello-id'])
+ return tree
+
+
+class TimeoutFixture(object):
+ """Kill a test with sigalarm if it runs too long.
+
+ Only works on Unix at present.
+ """
+
+ def __init__(self, timeout_secs):
+ import signal
+ self.timeout_secs = timeout_secs
+ self.alarm_fn = getattr(signal, 'alarm', None)
+
+ def setUp(self):
+ if self.alarm_fn is not None:
+ self.alarm_fn(self.timeout_secs)
+
+ def cleanUp(self):
+ if self.alarm_fn is not None:
+ self.alarm_fn(0)