~bzr-pqm/bzr/bzr.dev

5311.4.1 by Robert Collins
Polish and adjust news for Martin's output_encoding branch.
1
# Copyright (C) 2010 Canonical Ltd
5230.1.1 by Martin Pool
Add a simple bzrlib.tests.fixtures
2
#
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.
7
#
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.
12
#
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
16
17
18
"""Fixtures that can be used within tests.
19
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
5230.2.1 by Martin Pool
Change simple fixtures to be generators of names and unicode encodings.
23
should live only for the duration of a single test, and its tearDown method
24
should be passed to `addCleanup` on the test.
5230.1.1 by Martin Pool
Add a simple bzrlib.tests.fixtures
25
"""
26
27
5230.2.1 by Martin Pool
Change simple fixtures to be generators of names and unicode encodings.
28
import itertools
29
30
31
def generate_unicode_names():
32
    """Generate a sequence of arbitrary unique unicode names.
33
    
34
    By default they are not representable in ascii.
35
    
36
    >>> gen = generate_unicode_names()
37
    >>> n1 = gen.next()
38
    >>> n2 = gen.next()
39
    >>> type(n1)
40
    <type 'unicode'>
41
    >>> n1 == n2
42
    False
43
    >>> n1.encode('ascii', 'replace') == n1
44
    False
45
    """
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())
48
49
50
interesting_encodings = [
51
    ('iso-8859-1', False),
52
    ('ascii', False),
53
    ('cp850', False),
54
    ('utf-8', True),
55
    ('ucs-2', True),
56
    ]
57
58
59
def generate_unicode_encodings(universal_encoding=None):
60
    """Return a generator of unicode encoding names.
61
62
    These can be passed to Python encode/decode/etc.
63
    
64
    :param universal_encoding: True/False/None tristate to say whether the
65
        generated encodings either can or cannot encode all unicode 
66
        strings.
67
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
72
    True
73
    >>> try:
74
    ...   n1.encode(enc2).decode(enc2)
75
    ... except UnicodeError:
76
    ...   print 'fail'
77
    fail
78
    """
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]
82
    else:
83
        e = [n for (n, u) in interesting_encodings]
84
    return itertools.cycle(iter(e))
5320.2.5 by Robert Collins
Make bzrlib startup use a trace context manager.
85
86
87
class RecordingContextManager(object):
88
    """A context manager that records."""
89
90
    def __init__(self):
91
        self._calls = []
92
93
    def __enter__(self):
94
        self._calls.append('__enter__')
95
        return self # This is bound to the 'as' clause in a with statement.
96
97
    def __exit__(self, exc_type, exc_val, exc_tb):
98
        self._calls.append('__exit__')
99
        return False # propogate exceptions.
5651.5.1 by Andrew Bennetts
Make 'bzr reconfigure --unstacked' fetch tagged revisions too. (#401646)
100
101
5651.5.2 by Andrew Bennetts
Simplify new fixture slightly, and other test tweaks.
102
def build_branch_with_non_ancestral_rev(branch_builder):
103
    """Builds a branch with a rev not in the ancestry of the tip.
5651.5.1 by Andrew Bennetts
Make 'bzr reconfigure --unstacked' fetch tagged revisions too. (#401646)
104
105
    This is the revision graph::
106
107
      rev-2
108
        |
109
      rev-1
110
        |
111
      (null)
112
5651.5.2 by Andrew Bennetts
Simplify new fixture slightly, and other test tweaks.
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.
5651.5.1 by Andrew Bennetts
Make 'bzr reconfigure --unstacked' fetch tagged revisions too. (#401646)
115
116
    :param branch_builder: A BranchBuilder (e.g. from
117
        TestCaseWithMemoryTransport.make_branch_builder).
5651.5.2 by Andrew Bennetts
Simplify new fixture slightly, and other test tweaks.
118
    :returns: the new branch
5651.5.1 by Andrew Bennetts
Make 'bzr reconfigure --unstacked' fetch tagged revisions too. (#401646)
119
    """
5651.5.2 by Andrew Bennetts
Simplify new fixture slightly, and other test tweaks.
120
    # Make a sequence of two commits
5651.5.1 by Andrew Bennetts
Make 'bzr reconfigure --unstacked' fetch tagged revisions too. (#401646)
121
    branch_builder.build_commit(message="Rev 1", rev_id='rev-1')
5651.5.2 by Andrew Bennetts
Simplify new fixture slightly, and other test tweaks.
122
    branch_builder.build_commit(message="Rev 2", rev_id='rev-2')
123
    # Move the branch tip back to the first commit
5651.5.1 by Andrew Bennetts
Make 'bzr reconfigure --unstacked' fetch tagged revisions too. (#401646)
124
    source = branch_builder.get_branch()
125
    source.set_last_revision_info(1, 'rev-1')
126
    return source
127
6006.3.1 by Martin Pool
Start adding ContentFilterTree
128
129
def make_branch_and_populated_tree(testcase):
130
    """Make a simple branch and tree.
131
132
    The tree holds some added but uncommitted files.
133
    """
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
136
    # 20110705
137
    tree = testcase.make_branch_and_tree('t')
138
    testcase.build_tree_contents([('t/hello', 'hello world')])
139
    tree.add(['hello'], ['hello-id'])
140
    return tree
6319.1.1 by Martin Pool
Add selftest.timeout option, defaulting to 600
141
142
143
class TimeoutFixture(object):
144
    """Kill a test with sigalarm if it runs too long.
145
    
6319.1.5 by Martin Pool
Slight cleanup of TimeoutFixture
146
    Only works on Unix at present.
6319.1.1 by Martin Pool
Add selftest.timeout option, defaulting to 600
147
    """
148
149
    def __init__(self, timeout_secs):
6319.1.5 by Martin Pool
Slight cleanup of TimeoutFixture
150
        import signal
6319.1.1 by Martin Pool
Add selftest.timeout option, defaulting to 600
151
        self.timeout_secs = timeout_secs
6319.1.5 by Martin Pool
Slight cleanup of TimeoutFixture
152
        self.alarm_fn = getattr(signal, 'alarm', None)
6319.1.1 by Martin Pool
Add selftest.timeout option, defaulting to 600
153
154
    def setUp(self):
6319.1.5 by Martin Pool
Slight cleanup of TimeoutFixture
155
        if self.alarm_fn is not None:
156
            self.alarm_fn(self.timeout_secs)
6319.1.1 by Martin Pool
Add selftest.timeout option, defaulting to 600
157
158
    def cleanUp(self):
6319.1.5 by Martin Pool
Slight cleanup of TimeoutFixture
159
        if self.alarm_fn is not None:
160
            self.alarm_fn(0)