1
# Copyright (C) 2010 Canonical Ltd
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18
"""Fixtures that can be used within tests.
20
Fixtures can be created during a test as a way to separate out creation of
21
objects to test. Fixture objects can hold some state so that different
22
objects created during a test instance can be related. Normally a fixture
23
should live only for the duration of a single test, and its tearDown method
24
should be passed to `addCleanup` on the test.
31
def generate_unicode_names():
32
"""Generate a sequence of arbitrary unique unicode names.
34
By default they are not representable in ascii.
36
>>> gen = generate_unicode_names()
43
>>> n1.encode('ascii', 'replace') == n1
46
# include a mathematical symbol unlikely to be in 8-bit encodings
47
return (u"\N{SINE WAVE}%d" % x for x in itertools.count())
50
interesting_encodings = [
51
('iso-8859-1', False),
59
def generate_unicode_encodings(universal_encoding=None):
60
"""Return a generator of unicode encoding names.
62
These can be passed to Python encode/decode/etc.
64
:param universal_encoding: True/False/None tristate to say whether the
65
generated encodings either can or cannot encode all unicode
68
>>> n1 = generate_unicode_names().next()
69
>>> enc = generate_unicode_encodings(universal_encoding=True).next()
70
>>> enc2 = generate_unicode_encodings(universal_encoding=False).next()
71
>>> n1.encode(enc).decode(enc) == n1
74
... n1.encode(enc2).decode(enc2)
75
... except UnicodeError:
79
# TODO: check they're supported on this platform?
80
if universal_encoding is not None:
81
e = [n for (n, u) in interesting_encodings if u == universal_encoding]
83
e = [n for (n, u) in interesting_encodings]
84
return itertools.cycle(iter(e))
87
class RecordingContextManager(object):
88
"""A context manager that records."""
94
self._calls.append('__enter__')
95
return self # This is bound to the 'as' clause in a with statement.
97
def __exit__(self, exc_type, exc_val, exc_tb):
98
self._calls.append('__exit__')
99
return False # propogate exceptions.
102
def build_branch_with_non_ancestral_rev(branch_builder):
103
"""Builds a branch with a rev not in the ancestry of the tip.
105
This is the revision graph::
113
The branch tip is 'rev-1'. 'rev-2' is present in the branch's repository,
114
but is not part of rev-1's ancestry.
116
:param branch_builder: A BranchBuilder (e.g. from
117
TestCaseWithMemoryTransport.make_branch_builder).
118
:returns: the new branch
120
# Make a sequence of two commits
121
branch_builder.build_commit(message="Rev 1", rev_id='rev-1')
122
branch_builder.build_commit(message="Rev 2", rev_id='rev-2')
123
# Move the branch tip back to the first commit
124
source = branch_builder.get_branch()
125
source.set_last_revision_info(1, 'rev-1')
129
def make_branch_and_populated_tree(testcase):
130
"""Make a simple branch and tree.
132
The tree holds some added but uncommitted files.
134
# TODO: Either accept or return the names of the files, so the caller
135
# doesn't need to be bound to the particular files created? -- mbp
137
tree = testcase.make_branch_and_tree('t')
138
testcase.build_tree_contents([('t/hello', 'hello world')])
139
tree.add(['hello'], ['hello-id'])
143
class TimeoutFixture(object):
144
"""Kill a test with sigalarm if it runs too long.
146
Only works on Unix at present.
149
def __init__(self, timeout_secs):
151
self.timeout_secs = timeout_secs
152
self.alarm_fn = getattr(signal, 'alarm', None)
155
if self.alarm_fn is not None:
156
self.alarm_fn(self.timeout_secs)
159
if self.alarm_fn is not None: