~bzr-pqm/bzr/bzr.dev

5177.1.1 by Vincent Ladeuil
Manually assign docstrings to command objects, so that they work with python -OO
1
# Copyright (C) 2006-2010 Canonical Ltd
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
2
#
1185.70.5 by Martin Pool
Pass through wrapped function name and docstrign
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1185.70.5 by Martin Pool
Pass through wrapped function name and docstrign
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.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1185.70.5 by Martin Pool
Pass through wrapped function name and docstrign
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
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
1185.70.5 by Martin Pool
Pass through wrapped function name and docstrign
16
17
18
"""Tests for decorator functions"""
19
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
20
import inspect
21
22
from bzrlib import decorators
1185.70.5 by Martin Pool
Pass through wrapped function name and docstrign
23
from bzrlib.tests import TestCase
24
25
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
26
class SampleUnlockError(Exception):
27
    pass
28
29
30
def create_decorator_sample(style, unlock_error=None):
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
31
    """Create a DecoratorSample object, using specific lock operators.
1185.70.5 by Martin Pool
Pass through wrapped function name and docstrign
32
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
33
    :param style: The type of lock decorators to use (fast/pretty/None)
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
34
    :param unlock_error: If specified, an error to raise from unlock.
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
35
    :return: An instantiated DecoratorSample object.
1185.70.5 by Martin Pool
Pass through wrapped function name and docstrign
36
    """
37
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
38
    if style is None:
39
        # Default
40
        needs_read_lock = decorators.needs_read_lock
41
        needs_write_lock = decorators.needs_write_lock
42
    elif style == 'pretty':
43
        needs_read_lock = decorators._pretty_needs_read_lock
44
        needs_write_lock = decorators._pretty_needs_write_lock
45
    else:
46
        needs_read_lock = decorators._fast_needs_read_lock
47
        needs_write_lock = decorators._fast_needs_write_lock
48
49
    class DecoratorSample(object):
50
        """Sample class that uses decorators.
51
52
        Log when requests go through lock_read()/unlock() or
53
        lock_write()/unlock.
54
        """
55
56
        def __init__(self):
57
            self.actions = []
58
59
        def lock_read(self):
60
            self.actions.append('lock_read')
61
62
        def lock_write(self):
63
            self.actions.append('lock_write')
64
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
65
        @decorators.only_raises(SampleUnlockError)
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
66
        def unlock(self):
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
67
            if unlock_error:
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
68
                self.actions.append('unlock_fail')
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
69
                raise unlock_error
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
70
            else:
71
                self.actions.append('unlock')
72
73
        @needs_read_lock
74
        def frob(self):
75
            """Frob the sample object"""
76
            self.actions.append('frob')
77
            return 'newbie'
78
79
        @needs_write_lock
80
        def bank(self, bar, biz=None):
81
            """Bank the sample, but using bar and biz."""
82
            self.actions.append(('bank', bar, biz))
83
            return (bar, biz)
84
85
        @needs_read_lock
86
        def fail_during_read(self):
87
            self.actions.append('fail_during_read')
88
            raise TypeError('during read')
89
90
        @needs_write_lock
91
        def fail_during_write(self):
92
            self.actions.append('fail_during_write')
93
            raise TypeError('during write')
94
95
    return DecoratorSample()
96
97
98
class TestDecoratorActions(TestCase):
99
100
    _decorator_style = None # default
101
102
    def test_read_lock_locks_and_unlocks(self):
103
        sam = create_decorator_sample(self._decorator_style)
104
        self.assertEqual('newbie', sam.frob())
105
        self.assertEqual(['lock_read', 'frob', 'unlock'], sam.actions)
106
107
    def test_write_lock_locks_and_unlocks(self):
108
        sam = create_decorator_sample(self._decorator_style)
109
        self.assertEqual(('bar', 'bing'), sam.bank('bar', biz='bing'))
110
        self.assertEqual(['lock_write', ('bank', 'bar', 'bing'), 'unlock'],
111
                         sam.actions)
112
113
    def test_read_lock_unlocks_during_failure(self):
114
        sam = create_decorator_sample(self._decorator_style)
115
        self.assertRaises(TypeError, sam.fail_during_read)
116
        self.assertEqual(['lock_read', 'fail_during_read', 'unlock'],
117
                         sam.actions)
118
119
    def test_write_lock_unlocks_during_failure(self):
120
        sam = create_decorator_sample(self._decorator_style)
121
        self.assertRaises(TypeError, sam.fail_during_write)
122
        self.assertEqual(['lock_write', 'fail_during_write', 'unlock'],
123
                         sam.actions)
124
125
    def test_read_lock_raises_original_error(self):
126
        sam = create_decorator_sample(self._decorator_style,
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
127
                                      unlock_error=SampleUnlockError())
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
128
        self.assertRaises(TypeError, sam.fail_during_read)
129
        self.assertEqual(['lock_read', 'fail_during_read', 'unlock_fail'],
130
                         sam.actions)
131
132
    def test_write_lock_raises_original_error(self):
133
        sam = create_decorator_sample(self._decorator_style,
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
134
                                      unlock_error=SampleUnlockError())
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
135
        self.assertRaises(TypeError, sam.fail_during_write)
136
        self.assertEqual(['lock_write', 'fail_during_write', 'unlock_fail'],
137
                         sam.actions)
138
139
    def test_read_lock_raises_unlock_error(self):
140
        sam = create_decorator_sample(self._decorator_style,
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
141
                                      unlock_error=SampleUnlockError())
142
        self.assertRaises(SampleUnlockError, sam.frob)
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
143
        self.assertEqual(['lock_read', 'frob', 'unlock_fail'], sam.actions)
144
145
    def test_write_lock_raises_unlock_error(self):
146
        sam = create_decorator_sample(self._decorator_style,
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
147
                                      unlock_error=SampleUnlockError())
148
        self.assertRaises(SampleUnlockError, sam.bank, 'bar', biz='bing')
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
149
        self.assertEqual(['lock_write', ('bank', 'bar', 'bing'),
150
                          'unlock_fail'], sam.actions)
151
152
153
class TestFastDecoratorActions(TestDecoratorActions):
154
155
    _decorator_style = 'fast'
156
157
158
class TestPrettyDecoratorActions(TestDecoratorActions):
159
160
    _decorator_style = 'pretty'
1185.70.5 by Martin Pool
Pass through wrapped function name and docstrign
161
162
163
class TestDecoratorDocs(TestCase):
164
    """Test method decorators"""
165
166
    def test_read_lock_passthrough(self):
167
        """@needs_read_lock exposes underlying name and doc."""
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
168
        sam = create_decorator_sample(None)
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
169
        self.assertEqual('frob', sam.frob.__name__)
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
170
        self.assertDocstring('Frob the sample object', sam.frob)
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
171
172
    def test_write_lock_passthrough(self):
173
        """@needs_write_lock exposes underlying name and doc."""
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
174
        sam = create_decorator_sample(None)
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
175
        self.assertEqual('bank', sam.bank.__name__)
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
176
        self.assertDocstring('Bank the sample, but using bar and biz.',
177
                             sam.bank)
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
178
179
    def test_argument_passthrough(self):
180
        """Test that arguments get passed around properly."""
3316.3.2 by John Arbash Meinel
Finish fix for bug #125784. need_read/write_lock decorators should attempt to raise an original exception.
181
        sam = create_decorator_sample(None)
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
182
        sam.bank('1', biz='2')
183
        self.assertEqual(['lock_write',
184
                          ('bank', '1', '2'),
185
                          'unlock',
186
                         ], sam.actions)
187
188
189
class TestPrettyDecorators(TestCase):
190
    """Test that pretty decorators generate nice looking wrappers."""
191
192
    def get_formatted_args(self, func):
193
        """Return a nicely formatted string for the arguments to a function.
194
195
        This generates something like "(foo, bar=None)".
196
        """
197
        return inspect.formatargspec(*inspect.getargspec(func))
198
199
    def test__pretty_needs_read_lock(self):
200
        """Test that _pretty_needs_read_lock generates a nice wrapper."""
201
202
        @decorators._pretty_needs_read_lock
203
        def my_function(foo, bar, baz=None, biz=1):
204
            """Just a function that supplies several arguments."""
205
206
        self.assertEqual('my_function', my_function.__name__)
207
        self.assertEqual('my_function_read_locked',
208
                         my_function.func_code.co_name)
209
        self.assertEqual('(foo, bar, baz=None, biz=1)',
210
                         self.get_formatted_args(my_function))
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
211
        self.assertDocstring(
212
            'Just a function that supplies several arguments.', my_function)
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
213
214
    def test__fast_needs_read_lock(self):
215
        """Test the output of _fast_needs_read_lock."""
216
217
        @decorators._fast_needs_read_lock
218
        def my_function(foo, bar, baz=None, biz=1):
219
            """Just a function that supplies several arguments."""
220
221
        self.assertEqual('my_function', my_function.__name__)
222
        self.assertEqual('read_locked', my_function.func_code.co_name)
223
        self.assertEqual('(self, *args, **kwargs)',
224
                         self.get_formatted_args(my_function))
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
225
        self.assertDocstring(
226
            'Just a function that supplies several arguments.', my_function)
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
227
228
    def test__pretty_needs_write_lock(self):
229
        """Test that _pretty_needs_write_lock generates a nice wrapper."""
230
231
        @decorators._pretty_needs_write_lock
232
        def my_function(foo, bar, baz=None, biz=1):
233
            """Just a function that supplies several arguments."""
234
235
        self.assertEqual('my_function', my_function.__name__)
236
        self.assertEqual('my_function_write_locked',
237
                         my_function.func_code.co_name)
238
        self.assertEqual('(foo, bar, baz=None, biz=1)',
239
                         self.get_formatted_args(my_function))
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
240
        self.assertDocstring(
241
            'Just a function that supplies several arguments.', my_function)
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
242
243
    def test__fast_needs_write_lock(self):
244
        """Test the output of _fast_needs_write_lock."""
245
246
        @decorators._fast_needs_write_lock
247
        def my_function(foo, bar, baz=None, biz=1):
248
            """Just a function that supplies several arguments."""
249
250
        self.assertEqual('my_function', my_function.__name__)
251
        self.assertEqual('write_locked', my_function.func_code.co_name)
252
        self.assertEqual('(self, *args, **kwargs)',
253
                         self.get_formatted_args(my_function))
5131.2.1 by Martin
Permit bzrlib to run under python -OO by explictly assigning to __doc__ for user-visible docstrings
254
        self.assertDocstring(
255
            'Just a function that supplies several arguments.', my_function)
2230.2.4 by John Arbash Meinel
Add tests that decorators generate useful wrappers.
256
257
    def test_use_decorators(self):
258
        """Test that you can switch the type of the decorators."""
259
        cur_read = decorators.needs_read_lock
260
        cur_write = decorators.needs_write_lock
261
        try:
262
            decorators.use_fast_decorators()
263
            self.assertIs(decorators._fast_needs_read_lock,
264
                          decorators.needs_read_lock)
265
            self.assertIs(decorators._fast_needs_write_lock,
266
                          decorators.needs_write_lock)
267
268
            decorators.use_pretty_decorators()
269
            self.assertIs(decorators._pretty_needs_read_lock,
270
                          decorators.needs_read_lock)
271
            self.assertIs(decorators._pretty_needs_write_lock,
272
                          decorators.needs_write_lock)
273
274
            # One more switch to make sure it wasn't just good luck that the
275
            # functions pointed to the correct version
276
            decorators.use_fast_decorators()
277
            self.assertIs(decorators._fast_needs_read_lock,
278
                          decorators.needs_read_lock)
279
            self.assertIs(decorators._fast_needs_write_lock,
280
                          decorators.needs_write_lock)
281
        finally:
282
            decorators.needs_read_lock = cur_read
283
            decorators.needs_write_lock = cur_write
4634.62.2 by Andrew Bennetts
Update test_decorators, add docstring.
284
285
286
class TestOnlyRaisesDecorator(TestCase):
287
288
    def raise_ZeroDivisionError(self):
289
        1/0
290
        
291
    def test_raises_approved_error(self):
292
        decorator = decorators.only_raises(ZeroDivisionError)
293
        decorated_meth = decorator(self.raise_ZeroDivisionError)
294
        self.assertRaises(ZeroDivisionError, decorated_meth)
295
296
    def test_quietly_logs_unapproved_errors(self):
297
        decorator = decorators.only_raises(IOError)
298
        decorated_meth = decorator(self.raise_ZeroDivisionError)
299
        self.assertLogsError(ZeroDivisionError, decorated_meth)
300
        
301