~ubuntu-branches/ubuntu/lucid/ubuntuone-storage-protocol/lucid-security

« back to all changes in this revision

Viewing changes to contrib/mocker.py

  • Committer: Bazaar Package Importer
  • Author(s): Rodney Dawes
  • Date: 2009-08-26 12:00:00 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20090826120000-ob2uuyrh5f476c7y
Tags: 0.93.0-0ubuntu1
* New upstream release
* Update Standards-Version to 3.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
Copyright (c) 2007  Gustavo Niemeyer <gustavo@niemeyer.net>
 
3
 
 
4
Graceful platform for test doubles in Python (mocks, stubs, fakes, and dummies).
 
5
"""
 
6
import __builtin__
 
7
import tempfile
 
8
import unittest
 
9
import inspect
 
10
import shutil
 
11
import types
 
12
import sys
 
13
import os
 
14
import gc
 
15
 
 
16
 
 
17
if sys.version_info < (2, 4):
 
18
    from sets import Set as set # pragma: nocover
 
19
 
 
20
 
 
21
__all__ = ["Mocker", "expect", "IS", "CONTAINS", "IN", "MATCH",
 
22
           "ANY", "ARGS", "KWARGS"]
 
23
 
 
24
 
 
25
__author__ = "Gustavo Niemeyer <gustavo@niemeyer.net>"
 
26
__license__ = "PSF License"
 
27
__version__ = "0.10.1"
 
28
 
 
29
 
 
30
ERROR_PREFIX = "[Mocker] "
 
31
 
 
32
 
 
33
# --------------------------------------------------------------------
 
34
# Exceptions
 
35
 
 
36
class MatchError(AssertionError):
 
37
    """Raised when an unknown expression is seen in playback mode."""
 
38
 
 
39
 
 
40
# --------------------------------------------------------------------
 
41
# Helper for chained-style calling.
 
42
 
 
43
class expect(object):
 
44
    """This is a simple helper that allows a different call-style.
 
45
 
 
46
    With this class one can comfortably do chaining of calls to the
 
47
    mocker object responsible by the object being handled. For instance::
 
48
 
 
49
        expect(obj.attr).result(3).count(1, 2)
 
50
 
 
51
    Is the same as::
 
52
 
 
53
        obj.attr
 
54
        mocker.result(3)
 
55
        mocker.count(1, 2)
 
56
 
 
57
    """
 
58
 
 
59
    def __init__(self, mock, attr=None):
 
60
        self._mock = mock
 
61
        self._attr = attr
 
62
 
 
63
    def __getattr__(self, attr):
 
64
        return self.__class__(self._mock, attr)
 
65
 
 
66
    def __call__(self, *args, **kwargs):
 
67
        getattr(self._mock.__mocker__, self._attr)(*args, **kwargs)
 
68
        return self
 
69
 
 
70
 
 
71
# --------------------------------------------------------------------
 
72
# Extensions to Python's unittest.
 
73
 
 
74
class MockerTestCase(unittest.TestCase):
 
75
    """unittest.TestCase subclass with Mocker support.
 
76
 
 
77
    @ivar mocker: The mocker instance.
 
78
 
 
79
    This is a convenience only.  Mocker may easily be used with the
 
80
    standard C{unittest.TestCase} class if wanted.
 
81
 
 
82
    Test methods have a Mocker instance available on C{self.mocker}.
 
83
    At the end of each test method, expectations of the mocker will
 
84
    be verified, and any requested changes made to the environment
 
85
    will be restored.
 
86
 
 
87
    In addition to the integration with Mocker, this class provides
 
88
    a few additional helper methods.
 
89
    """
 
90
 
 
91
    expect = expect
 
92
 
 
93
    def __init__(self, methodName="runTest"):
 
94
        # So here is the trick: we take the real test method, wrap it on
 
95
        # a function that do the job we have to do, and insert it in the
 
96
        # *instance* dictionary, so that getattr() will return our
 
97
        # replacement rather than the class method.
 
98
        test_method = getattr(self, methodName, None)
 
99
        if test_method is not None:
 
100
            def test_method_wrapper():
 
101
                try:
 
102
                    result = test_method()
 
103
                except:
 
104
                    raise
 
105
                else:
 
106
                    if (self.mocker.is_recording() and
 
107
                        self.mocker.get_events()):
 
108
                        raise RuntimeError("Mocker must be put in replay "
 
109
                                           "mode with self.mocker.replay()")
 
110
                    if (hasattr(result, "addCallback") and
 
111
                        hasattr(result, "addErrback")):
 
112
                        def verify(result):
 
113
                            self.mocker.verify()
 
114
                            return result
 
115
                        result.addCallback(verify)
 
116
                    else:
 
117
                        self.mocker.verify()
 
118
                        self.mocker.restore()
 
119
                    return result
 
120
            # Copy all attributes from the original method..
 
121
            for attr in dir(test_method):
 
122
                # .. unless they're present in our wrapper already.
 
123
                if not hasattr(test_method_wrapper, attr) or attr == "__doc__":
 
124
                    setattr(test_method_wrapper, attr,
 
125
                            getattr(test_method, attr))
 
126
            setattr(self, methodName, test_method_wrapper)
 
127
 
 
128
        # We could overload run() normally, but other well-known testing
 
129
        # frameworks do it as well, and some of them won't call the super,
 
130
        # which might mean that cleanup wouldn't happen.  With that in mind,
 
131
        # we make integration easier by using the following trick.
 
132
        run_method = self.run
 
133
        def run_wrapper(*args, **kwargs):
 
134
            try:
 
135
                return run_method(*args, **kwargs)
 
136
            finally:
 
137
                self.__cleanup()
 
138
        self.run = run_wrapper
 
139
 
 
140
        self.mocker = Mocker()
 
141
 
 
142
        self.__cleanup_funcs = []
 
143
        self.__cleanup_paths = []
 
144
 
 
145
        super(MockerTestCase, self).__init__(methodName)
 
146
 
 
147
    def __cleanup(self):
 
148
        for path in self.__cleanup_paths:
 
149
            if os.path.isfile(path):
 
150
                os.unlink(path)
 
151
            elif os.path.isdir(path):
 
152
                shutil.rmtree(path)
 
153
        self.mocker.reset()
 
154
        for func, args, kwargs in self.__cleanup_funcs:
 
155
            func(*args, **kwargs)
 
156
 
 
157
    def addCleanup(self, func, *args, **kwargs):
 
158
        self.__cleanup_funcs.append((func, args, kwargs))
 
159
 
 
160
    def makeFile(self, content=None, suffix="", prefix="tmp", basename=None,
 
161
                 dirname=None, path=None):
 
162
        """Create a temporary file and return the path to it.
 
163
 
 
164
        @param content: Initial content for the file.
 
165
        @param suffix: Suffix to be given to the file's basename.
 
166
        @param prefix: Prefix to be given to the file's basename.
 
167
        @param basename: Full basename for the file.
 
168
        @param dirname: Put file inside this directory.
 
169
 
 
170
        The file is removed after the test runs.
 
171
        """
 
172
        if path is not None:
 
173
            self.__cleanup_paths.append(path)
 
174
        elif basename is not None:
 
175
            if dirname is None:
 
176
                dirname = tempfile.mkdtemp()
 
177
                self.__cleanup_paths.append(dirname)
 
178
            path = os.path.join(dirname, basename)
 
179
        else:
 
180
            fd, path = tempfile.mkstemp(suffix, prefix, dirname)
 
181
            self.__cleanup_paths.append(path)
 
182
            os.close(fd)
 
183
            if content is None:
 
184
                os.unlink(path)
 
185
        if content is not None:
 
186
            file = open(path, "w")
 
187
            file.write(content)
 
188
            file.close()
 
189
        return path
 
190
 
 
191
    def makeDir(self, suffix="", prefix="tmp", dirname=None, path=None):
 
192
        """Create a temporary directory and return the path to it.
 
193
 
 
194
        @param suffix: Suffix to be given to the file's basename.
 
195
        @param prefix: Prefix to be given to the file's basename.
 
196
        @param dirname: Put directory inside this parent directory.
 
197
 
 
198
        The directory is removed after the test runs.
 
199
        """
 
200
        if path is not None:
 
201
            os.makedirs(path)
 
202
        else:
 
203
            path = tempfile.mkdtemp(suffix, prefix, dirname)
 
204
        self.__cleanup_paths.append(path)
 
205
        return path
 
206
 
 
207
    def failUnlessIs(self, first, second, msg=None):
 
208
        """Assert that C{first} is the same object as C{second}."""
 
209
        if first is not second:
 
210
            raise self.failureException(msg or "%r is not %r" % (first, second))
 
211
 
 
212
    def failIfIs(self, first, second, msg=None):
 
213
        """Assert that C{first} is not the same object as C{second}."""
 
214
        if first is second:
 
215
            raise self.failureException(msg or "%r is %r" % (first, second))
 
216
 
 
217
    def failUnlessIn(self, first, second, msg=None):
 
218
        """Assert that C{first} is contained in C{second}."""
 
219
        if first not in second:
 
220
            raise self.failureException(msg or "%r not in %r" % (first, second))
 
221
 
 
222
    def failUnlessStartsWith(self, first, second, msg=None):
 
223
        """Assert that C{first} starts with C{second}."""
 
224
        if first[:len(second)] != second:
 
225
            raise self.failureException(msg or "%r doesn't start with %r" %
 
226
                                               (first, second))
 
227
 
 
228
    def failIfStartsWith(self, first, second, msg=None):
 
229
        """Assert that C{first} doesn't start with C{second}."""
 
230
        if first[:len(second)] == second:
 
231
            raise self.failureException(msg or "%r starts with %r" %
 
232
                                               (first, second))
 
233
 
 
234
    def failUnlessEndsWith(self, first, second, msg=None):
 
235
        """Assert that C{first} starts with C{second}."""
 
236
        if first[len(first)-len(second):] != second:
 
237
            raise self.failureException(msg or "%r doesn't end with %r" %
 
238
                                               (first, second))
 
239
 
 
240
    def failIfEndsWith(self, first, second, msg=None):
 
241
        """Assert that C{first} doesn't start with C{second}."""
 
242
        if first[len(first)-len(second):] == second:
 
243
            raise self.failureException(msg or "%r ends with %r" %
 
244
                                               (first, second))
 
245
 
 
246
    def failIfIn(self, first, second, msg=None):
 
247
        """Assert that C{first} is not contained in C{second}."""
 
248
        if first in second:
 
249
            raise self.failureException(msg or "%r in %r" % (first, second))
 
250
 
 
251
    def failUnlessApproximates(self, first, second, tolerance, msg=None):
 
252
        """Assert that C{first} is near C{second} by at most C{tolerance}."""
 
253
        if abs(first - second) > tolerance:
 
254
            raise self.failureException(msg or "abs(%r - %r) > %r" %
 
255
                                        (first, second, tolerance))
 
256
 
 
257
    def failIfApproximates(self, first, second, tolerance, msg=None):
 
258
        """Assert that C{first} is far from C{second} by at least C{tolerance}.
 
259
        """
 
260
        if abs(first - second) <= tolerance:
 
261
            raise self.failureException(msg or "abs(%r - %r) <= %r" %
 
262
                                        (first, second, tolerance))
 
263
 
 
264
    def failUnlessMethodsMatch(self, first, second):
 
265
        """Assert that public methods in C{first} are present in C{second}.
 
266
 
 
267
        This method asserts that all public methods found in C{first} are also
 
268
        present in C{second} and accept the same arguments.  C{first} may
 
269
        have its own private methods, though, and may not have all methods
 
270
        found in C{second}.  Note that if a private method in C{first} matches
 
271
        the name of one in C{second}, their specification is still compared.
 
272
 
 
273
        This is useful to verify if a fake or stub class have the same API as
 
274
        the real class being simulated.
 
275
        """
 
276
        first_methods = dict(inspect.getmembers(first, inspect.ismethod))
 
277
        second_methods = dict(inspect.getmembers(second, inspect.ismethod))
 
278
        for name, first_method in first_methods.iteritems():
 
279
            first_argspec = inspect.getargspec(first_method)
 
280
            first_formatted = inspect.formatargspec(*first_argspec)
 
281
 
 
282
            second_method = second_methods.get(name)
 
283
            if second_method is None:
 
284
                if name[:1] == "_":
 
285
                    continue # First may have its own private methods.
 
286
                raise self.failureException("%s.%s%s not present in %s" %
 
287
                    (first.__name__, name, first_formatted, second.__name__))
 
288
 
 
289
            second_argspec = inspect.getargspec(second_method)
 
290
            if first_argspec != second_argspec:
 
291
                second_formatted = inspect.formatargspec(*second_argspec)
 
292
                raise self.failureException("%s.%s%s != %s.%s%s" %
 
293
                    (first.__name__, name, first_formatted,
 
294
                     second.__name__, name, second_formatted))
 
295
 
 
296
 
 
297
    assertIs = failUnlessIs
 
298
    assertIsNot = failIfIs
 
299
    assertIn = failUnlessIn
 
300
    assertNotIn = failIfIn
 
301
    assertStartsWith = failUnlessStartsWith
 
302
    assertNotStartsWith = failIfStartsWith
 
303
    assertEndsWith = failUnlessEndsWith
 
304
    assertNotEndsWith = failIfEndsWith
 
305
    assertApproximates = failUnlessApproximates
 
306
    assertNotApproximates = failIfApproximates
 
307
    assertMethodsMatch = failUnlessMethodsMatch
 
308
 
 
309
    # The following are missing in Python < 2.4.
 
310
    assertTrue = unittest.TestCase.failUnless
 
311
    assertFalse = unittest.TestCase.failIf
 
312
 
 
313
    # The following is provided for compatibility with Twisted's trial.
 
314
    assertIdentical = assertIs
 
315
    assertNotIdentical = assertIsNot
 
316
    failUnlessIdentical = failUnlessIs
 
317
    failIfIdentical = failIfIs
 
318
 
 
319
 
 
320
# --------------------------------------------------------------------
 
321
# Mocker.
 
322
 
 
323
class classinstancemethod(object):
 
324
 
 
325
    def __init__(self, method):
 
326
        self.method = method
 
327
 
 
328
    def __get__(self, obj, cls=None):
 
329
        def bound_method(*args, **kwargs):
 
330
            return self.method(cls, obj, *args, **kwargs)
 
331
        return bound_method
 
332
 
 
333
 
 
334
class MockerBase(object):
 
335
    """Controller of mock objects.
 
336
 
 
337
    A mocker instance is used to command recording and replay of
 
338
    expectations on any number of mock objects.
 
339
 
 
340
    Expectations should be expressed for the mock object while in
 
341
    record mode (the initial one) by using the mock object itself,
 
342
    and using the mocker (and/or C{expect()} as a helper) to define
 
343
    additional behavior for each event.  For instance::
 
344
 
 
345
        mock = mocker.mock()
 
346
        mock.hello()
 
347
        mocker.result("Hi!")
 
348
        mocker.replay()
 
349
        assert mock.hello() == "Hi!"
 
350
        mock.restore()
 
351
        mock.verify()
 
352
 
 
353
    In this short excerpt a mock object is being created, then an
 
354
    expectation of a call to the C{hello()} method was recorded, and
 
355
    when called the method should return the value C{10}.  Then, the
 
356
    mocker is put in replay mode, and the expectation is satisfied by
 
357
    calling the C{hello()} method, which indeed returns 10.  Finally,
 
358
    a call to the L{restore()} method is performed to undo any needed
 
359
    changes made in the environment, and the L{verify()} method is
 
360
    called to ensure that all defined expectations were met.
 
361
 
 
362
    The same logic can be expressed more elegantly using the
 
363
    C{with mocker:} statement, as follows::
 
364
 
 
365
        mock = mocker.mock()
 
366
        mock.hello()
 
367
        mocker.result("Hi!")
 
368
        with mocker:
 
369
            assert mock.hello() == "Hi!"
 
370
 
 
371
    Also, the MockerTestCase class, which integrates the mocker on
 
372
    a unittest.TestCase subclass, may be used to reduce the overhead
 
373
    of controlling the mocker.  A test could be written as follows::
 
374
 
 
375
        class SampleTest(MockerTestCase):
 
376
 
 
377
            def test_hello(self):
 
378
                mock = self.mocker.mock()
 
379
                mock.hello()
 
380
                self.mocker.result("Hi!")
 
381
                self.mocker.replay()
 
382
                self.assertEquals(mock.hello(), "Hi!")
 
383
    """
 
384
 
 
385
    _recorders = []
 
386
 
 
387
    # For convenience only.
 
388
    on = expect
 
389
 
 
390
    class __metaclass__(type):
 
391
        def __init__(self, name, bases, dict):
 
392
            # Make independent lists on each subclass, inheriting from parent.
 
393
            self._recorders = list(getattr(self, "_recorders", ()))
 
394
 
 
395
    def __init__(self):
 
396
        self._recorders = self._recorders[:]
 
397
        self._events = []
 
398
        self._recording = True
 
399
        self._ordering = False
 
400
        self._last_orderer = None
 
401
 
 
402
    def is_recording(self):
 
403
        """Return True if in recording mode, False if in replay mode.
 
404
 
 
405
        Recording is the initial state.
 
406
        """
 
407
        return self._recording
 
408
 
 
409
    def replay(self):
 
410
        """Change to replay mode, where recorded events are reproduced.
 
411
 
 
412
        If already in replay mode, the mocker will be restored, with all
 
413
        expectations reset, and then put again in replay mode.
 
414
 
 
415
        An alternative and more comfortable way to replay changes is
 
416
        using the 'with' statement, as follows::
 
417
 
 
418
            mocker = Mocker()
 
419
            <record events>
 
420
            with mocker:
 
421
                <reproduce events>
 
422
 
 
423
        The 'with' statement will automatically put mocker in replay
 
424
        mode, and will also verify if all events were correctly reproduced
 
425
        at the end (using L{verify()}), and also restore any changes done
 
426
        in the environment (with L{restore()}).
 
427
 
 
428
        Also check the MockerTestCase class, which integrates the
 
429
        unittest.TestCase class with mocker.
 
430
        """
 
431
        if not self._recording:
 
432
            for event in self._events:
 
433
                event.restore()
 
434
        else:
 
435
            self._recording = False
 
436
        for event in self._events:
 
437
            event.replay()
 
438
 
 
439
    def restore(self):
 
440
        """Restore changes in the environment, and return to recording mode.
 
441
 
 
442
        This should always be called after the test is complete (succeeding
 
443
        or not).  There are ways to call this method automatically on
 
444
        completion (e.g. using a C{with mocker:} statement, or using the
 
445
        L{MockerTestCase} class.
 
446
        """
 
447
        if not self._recording:
 
448
            self._recording = True
 
449
            for event in self._events:
 
450
                event.restore()
 
451
 
 
452
    def reset(self):
 
453
        """Reset the mocker state.
 
454
 
 
455
        This will restore environment changes, if currently in replay
 
456
        mode, and then remove all events previously recorded.
 
457
        """
 
458
        if not self._recording:
 
459
            self.restore()
 
460
        self.unorder()
 
461
        del self._events[:]
 
462
 
 
463
    def get_events(self):
 
464
        """Return all recorded events."""
 
465
        return self._events[:]
 
466
 
 
467
    def add_event(self, event):
 
468
        """Add an event.
 
469
 
 
470
        This method is used internally by the implementation, and
 
471
        shouldn't be needed on normal mocker usage.
 
472
        """
 
473
        self._events.append(event)
 
474
        if self._ordering:
 
475
            orderer = event.add_task(Orderer(event.path))
 
476
            if self._last_orderer:
 
477
                orderer.add_dependency(self._last_orderer)
 
478
            self._last_orderer = orderer
 
479
        return event
 
480
 
 
481
    def verify(self):
 
482
        """Check if all expectations were met, and raise AssertionError if not.
 
483
 
 
484
        The exception message will include a nice description of which
 
485
        expectations were not met, and why.
 
486
        """
 
487
        errors = []
 
488
        for event in self._events:
 
489
            try:
 
490
                event.verify()
 
491
            except AssertionError, e:
 
492
                error = str(e)
 
493
                if not error:
 
494
                    raise RuntimeError("Empty error message from %r"
 
495
                                       % event)
 
496
                errors.append(error)
 
497
        if errors:
 
498
            message = [ERROR_PREFIX + "Unmet expectations:", ""]
 
499
            for error in errors:
 
500
                lines = error.splitlines()
 
501
                message.append("=> " + lines.pop(0))
 
502
                message.extend([" " + line for line in lines])
 
503
                message.append("")
 
504
            raise AssertionError(os.linesep.join(message))
 
505
 
 
506
    def mock(self, spec_and_type=None, spec=None, type=None,
 
507
             name=None, count=True):
 
508
        """Return a new mock object.
 
509
 
 
510
        @param spec_and_type: Handy positional argument which sets both
 
511
                     spec and type.
 
512
        @param spec: Method calls will be checked for correctness against
 
513
                     the given class.
 
514
        @param type: If set, the Mock's __class__ attribute will return
 
515
                     the given type.  This will make C{isinstance()} calls
 
516
                     on the object work.
 
517
        @param name: Name for the mock object, used in the representation of
 
518
                     expressions.  The name is rarely needed, as it's usually
 
519
                     guessed correctly from the variable name used.
 
520
        @param count: If set to false, expressions may be executed any number
 
521
                     of times, unless an expectation is explicitly set using
 
522
                     the L{count()} method.  By default, expressions are
 
523
                     expected once.
 
524
        """
 
525
        if spec_and_type is not None:
 
526
            spec = type = spec_and_type
 
527
        return Mock(self, spec=spec, type=type, name=name, count=count)
 
528
 
 
529
    def proxy(self, object, spec=True, type=True, name=None, count=True,
 
530
              passthrough=True):
 
531
        """Return a new mock object which proxies to the given object.
 
532
 
 
533
        Proxies are useful when only part of the behavior of an object
 
534
        is to be mocked.  Unknown expressions may be passed through to
 
535
        the real implementation implicitly (if the C{passthrough} argument
 
536
        is True), or explicitly (using the L{passthrough()} method
 
537
        on the event).
 
538
 
 
539
        @param object: Real object to be proxied, and replaced by the mock
 
540
                       on replay mode.  It may also be an "import path",
 
541
                       such as C{"time.time"}, in which case the object
 
542
                       will be the C{time} function from the C{time} module.
 
543
        @param spec: Method calls will be checked for correctness against
 
544
                     the given object, which may be a class or an instance
 
545
                     where attributes will be looked up.  Defaults to the
 
546
                     the C{object} parameter.  May be set to None explicitly,
 
547
                     in which case spec checking is disabled.  Checks may
 
548
                     also be disabled explicitly on a per-event basis with
 
549
                     the L{nospec()} method.
 
550
        @param type: If set, the Mock's __class__ attribute will return
 
551
                     the given type.  This will make C{isinstance()} calls
 
552
                     on the object work.  Defaults to the type of the
 
553
                     C{object} parameter.  May be set to None explicitly.
 
554
        @param name: Name for the mock object, used in the representation of
 
555
                     expressions.  The name is rarely needed, as it's usually
 
556
                     guessed correctly from the variable name used.
 
557
        @param count: If set to false, expressions may be executed any number
 
558
                     of times, unless an expectation is explicitly set using
 
559
                     the L{count()} method.  By default, expressions are
 
560
                     expected once.
 
561
        @param passthrough: If set to False, passthrough of actions on the
 
562
                            proxy to the real object will only happen when
 
563
                            explicitly requested via the L{passthrough()}
 
564
                            method.
 
565
        """
 
566
        if isinstance(object, basestring):
 
567
            if name is None:
 
568
                name = object
 
569
            import_stack = object.split(".")
 
570
            attr_stack = []
 
571
            while import_stack:
 
572
                module_path = ".".join(import_stack)
 
573
                try:
 
574
                    object = __import__(module_path, {}, {}, [""])
 
575
                except ImportError:
 
576
                    attr_stack.insert(0, import_stack.pop())
 
577
                    if not import_stack:
 
578
                        raise
 
579
                    continue
 
580
                else:
 
581
                    for attr in attr_stack:
 
582
                        object = getattr(object, attr)
 
583
                    break
 
584
        if spec is True:
 
585
            spec = object
 
586
        if type is True:
 
587
            type = __builtin__.type(object)
 
588
        return Mock(self, spec=spec, type=type, object=object,
 
589
                    name=name, count=count, passthrough=passthrough)
 
590
 
 
591
    def replace(self, object, spec=True, type=True, name=None, count=True,
 
592
                passthrough=True):
 
593
        """Create a proxy, and replace the original object with the mock.
 
594
 
 
595
        On replay, the original object will be replaced by the returned
 
596
        proxy in all dictionaries found in the running interpreter via
 
597
        the garbage collecting system.  This should cover module
 
598
        namespaces, class namespaces, instance namespaces, and so on.
 
599
 
 
600
        @param object: Real object to be proxied, and replaced by the mock
 
601
                       on replay mode.  It may also be an "import path",
 
602
                       such as C{"time.time"}, in which case the object
 
603
                       will be the C{time} function from the C{time} module.
 
604
        @param spec: Method calls will be checked for correctness against
 
605
                     the given object, which may be a class or an instance
 
606
                     where attributes will be looked up.  Defaults to the
 
607
                     the C{object} parameter.  May be set to None explicitly,
 
608
                     in which case spec checking is disabled.  Checks may
 
609
                     also be disabled explicitly on a per-event basis with
 
610
                     the L{nospec()} method.
 
611
        @param type: If set, the Mock's __class__ attribute will return
 
612
                     the given type.  This will make C{isinstance()} calls
 
613
                     on the object work.  Defaults to the type of the
 
614
                     C{object} parameter.  May be set to None explicitly.
 
615
        @param name: Name for the mock object, used in the representation of
 
616
                     expressions.  The name is rarely needed, as it's usually
 
617
                     guessed correctly from the variable name used.
 
618
        @param passthrough: If set to False, passthrough of actions on the
 
619
                            proxy to the real object will only happen when
 
620
                            explicitly requested via the L{passthrough()}
 
621
                            method.
 
622
        """
 
623
        mock = self.proxy(object, spec, type, name, count, passthrough)
 
624
        event = self._get_replay_restore_event()
 
625
        event.add_task(ProxyReplacer(mock))
 
626
        return mock
 
627
 
 
628
    def patch(self, object, spec=True):
 
629
        """Patch an existing object to reproduce recorded events.
 
630
 
 
631
        @param object: Class or instance to be patched.
 
632
        @param spec: Method calls will be checked for correctness against
 
633
                     the given object, which may be a class or an instance
 
634
                     where attributes will be looked up.  Defaults to the
 
635
                     the C{object} parameter.  May be set to None explicitly,
 
636
                     in which case spec checking is disabled.  Checks may
 
637
                     also be disabled explicitly on a per-event basis with
 
638
                     the L{nospec()} method.
 
639
 
 
640
        The result of this method is still a mock object, which can be
 
641
        used like any other mock object to record events.  The difference
 
642
        is that when the mocker is put on replay mode, the *real* object
 
643
        will be modified to behave according to recorded expectations.
 
644
 
 
645
        Patching works in individual instances, and also in classes.
 
646
        When an instance is patched, recorded events will only be
 
647
        considered on this specific instance, and other instances should
 
648
        behave normally.  When a class is patched, the reproduction of
 
649
        events will be considered on any instance of this class once
 
650
        created (collectively).
 
651
 
 
652
        Observe that, unlike with proxies which catch only events done
 
653
        through the mock object, *all* accesses to recorded expectations
 
654
        will be considered;  even these coming from the object itself
 
655
        (e.g. C{self.hello()} is considered if this method was patched).
 
656
        While this is a very powerful feature, and many times the reason
 
657
        to use patches in the first place, it's important to keep this
 
658
        behavior in mind.
 
659
 
 
660
        Patching of the original object only takes place when the mocker
 
661
        is put on replay mode, and the patched object will be restored
 
662
        to its original state once the L{restore()} method is called
 
663
        (explicitly, or implicitly with alternative conventions, such as
 
664
        a C{with mocker:} block, or a MockerTestCase class).
 
665
        """
 
666
        if spec is True:
 
667
            spec = object
 
668
        patcher = Patcher()
 
669
        event = self._get_replay_restore_event()
 
670
        event.add_task(patcher)
 
671
        mock = Mock(self, object=object, patcher=patcher,
 
672
                    passthrough=True, spec=spec)
 
673
        patcher.patch_attr(object, '__mocker_mock__', mock)
 
674
        return mock
 
675
 
 
676
    def act(self, path):
 
677
        """This is called by mock objects whenever something happens to them.
 
678
 
 
679
        This method is part of the implementation between the mocker
 
680
        and mock objects.
 
681
        """
 
682
        if self._recording:
 
683
            event = self.add_event(Event(path))
 
684
            for recorder in self._recorders:
 
685
                recorder(self, event)
 
686
            return Mock(self, path)
 
687
        else:
 
688
            # First run events that may run, then run unsatisfied events, then
 
689
            # ones not previously run. We put the index in the ordering tuple
 
690
            # instead of the actual event because we want a stable sort
 
691
            # (ordering between 2 events is undefined).
 
692
            events = self._events
 
693
            order = [(events[i].satisfied()*2 + events[i].has_run(), i)
 
694
                     for i in range(len(events))]
 
695
            order.sort()
 
696
            postponed = None
 
697
            for weight, i in order:
 
698
                event = events[i]
 
699
                if event.matches(path):
 
700
                    if event.may_run(path):
 
701
                        return event.run(path)
 
702
                    elif postponed is None:
 
703
                        postponed = event
 
704
            if postponed is not None:
 
705
                return postponed.run(path)
 
706
            raise MatchError(ERROR_PREFIX + "Unexpected expression: %s" % path)
 
707
 
 
708
    def get_recorders(cls, self):
 
709
        """Return recorders associated with this mocker class or instance.
 
710
 
 
711
        This method may be called on mocker instances and also on mocker
 
712
        classes.  See the L{add_recorder()} method for more information.
 
713
        """
 
714
        return (self or cls)._recorders[:]
 
715
    get_recorders = classinstancemethod(get_recorders)
 
716
 
 
717
    def add_recorder(cls, self, recorder):
 
718
        """Add a recorder to this mocker class or instance.
 
719
 
 
720
        @param recorder: Callable accepting C{(mocker, event)} as parameters.
 
721
 
 
722
        This is part of the implementation of mocker.
 
723
 
 
724
        All registered recorders are called for translating events that
 
725
        happen during recording into expectations to be met once the state
 
726
        is switched to replay mode.
 
727
 
 
728
        This method may be called on mocker instances and also on mocker
 
729
        classes.  When called on a class, the recorder will be used by
 
730
        all instances, and also inherited on subclassing.  When called on
 
731
        instances, the recorder is added only to the given instance.
 
732
        """
 
733
        (self or cls)._recorders.append(recorder)
 
734
        return recorder
 
735
    add_recorder = classinstancemethod(add_recorder)
 
736
 
 
737
    def remove_recorder(cls, self, recorder):
 
738
        """Remove the given recorder from this mocker class or instance.
 
739
 
 
740
        This method may be called on mocker classes and also on mocker
 
741
        instances.  See the L{add_recorder()} method for more information.
 
742
        """
 
743
        (self or cls)._recorders.remove(recorder)
 
744
    remove_recorder = classinstancemethod(remove_recorder)
 
745
 
 
746
    def result(self, value):
 
747
        """Make the last recorded event return the given value on replay.
 
748
        
 
749
        @param value: Object to be returned when the event is replayed.
 
750
        """
 
751
        self.call(lambda *args, **kwargs: value)
 
752
 
 
753
    def generate(self, sequence):
 
754
        """Last recorded event will return a generator with the given sequence.
 
755
 
 
756
        @param sequence: Sequence of values to be generated.
 
757
        """
 
758
        def generate(*args, **kwargs):
 
759
            for value in sequence:
 
760
                yield value
 
761
        self.call(generate)
 
762
 
 
763
    def throw(self, exception):
 
764
        """Make the last recorded event raise the given exception on replay.
 
765
 
 
766
        @param exception: Class or instance of exception to be raised.
 
767
        """
 
768
        def raise_exception(*args, **kwargs):
 
769
            raise exception
 
770
        self.call(raise_exception)
 
771
 
 
772
    def call(self, func):
 
773
        """Make the last recorded event cause the given function to be called.
 
774
 
 
775
        @param func: Function to be called.
 
776
 
 
777
        The result of the function will be used as the event result.
 
778
        """
 
779
        self._events[-1].add_task(FunctionRunner(func))
 
780
 
 
781
    def count(self, min, max=False):
 
782
        """Last recorded event must be replayed between min and max times.
 
783
 
 
784
        @param min: Minimum number of times that the event must happen.
 
785
        @param max: Maximum number of times that the event must happen.  If
 
786
                    not given, it defaults to the same value of the C{min}
 
787
                    parameter.  If set to None, there is no upper limit, and
 
788
                    the expectation is met as long as it happens at least
 
789
                    C{min} times.
 
790
        """
 
791
        event = self._events[-1]
 
792
        for task in event.get_tasks():
 
793
            if isinstance(task, RunCounter):
 
794
                event.remove_task(task)
 
795
        event.add_task(RunCounter(min, max))
 
796
 
 
797
    def is_ordering(self):
 
798
        """Return true if all events are being ordered.
 
799
 
 
800
        See the L{order()} method.
 
801
        """
 
802
        return self._ordering
 
803
 
 
804
    def unorder(self):
 
805
        """Disable the ordered mode.
 
806
        
 
807
        See the L{order()} method for more information.
 
808
        """
 
809
        self._ordering = False
 
810
        self._last_orderer = None
 
811
 
 
812
    def order(self, *path_holders):
 
813
        """Create an expectation of order between two or more events.
 
814
 
 
815
        @param path_holders: Objects returned as the result of recorded events.
 
816
 
 
817
        By default, mocker won't force events to happen precisely in
 
818
        the order they were recorded.  Calling this method will change
 
819
        this behavior so that events will only match if reproduced in
 
820
        the correct order.
 
821
 
 
822
        There are two ways in which this method may be used.  Which one
 
823
        is used in a given occasion depends only on convenience.
 
824
 
 
825
        If no arguments are passed, the mocker will be put in a mode where
 
826
        all the recorded events following the method call will only be met
 
827
        if they happen in order.  When that's used, the mocker may be put
 
828
        back in unordered mode by calling the L{unorder()} method, or by
 
829
        using a 'with' block, like so::
 
830
 
 
831
            with mocker.ordered():
 
832
                <record events>
 
833
 
 
834
        In this case, only expressions in <record events> will be ordered,
 
835
        and the mocker will be back in unordered mode after the 'with' block.
 
836
 
 
837
        The second way to use it is by specifying precisely which events
 
838
        should be ordered.  As an example::
 
839
 
 
840
            mock = mocker.mock()
 
841
            expr1 = mock.hello()
 
842
            expr2 = mock.world
 
843
            expr3 = mock.x.y.z
 
844
            mocker.order(expr1, expr2, expr3)
 
845
 
 
846
        This method of ordering only works when the expression returns
 
847
        another object.
 
848
 
 
849
        Also check the L{after()} and L{before()} methods, which are
 
850
        alternative ways to perform this.
 
851
        """
 
852
        if not path_holders:
 
853
            self._ordering = True
 
854
            return OrderedContext(self)
 
855
 
 
856
        last_orderer = None
 
857
        for path_holder in path_holders:
 
858
            if type(path_holder) is Path:
 
859
                path = path_holder
 
860
            else:
 
861
                path = path_holder.__mocker_path__
 
862
            for event in self._events:
 
863
                if event.path is path:
 
864
                    for task in event.get_tasks():
 
865
                        if isinstance(task, Orderer):
 
866
                            orderer = task
 
867
                            break
 
868
                    else:
 
869
                        orderer = Orderer(path)
 
870
                        event.add_task(orderer)
 
871
                    if last_orderer:
 
872
                        orderer.add_dependency(last_orderer)
 
873
                    last_orderer = orderer
 
874
                    break
 
875
 
 
876
    def after(self, *path_holders):
 
877
        """Last recorded event must happen after events referred to.
 
878
 
 
879
        @param path_holders: Objects returned as the result of recorded events
 
880
                             which should happen before the last recorded event
 
881
 
 
882
        As an example, the idiom::
 
883
 
 
884
            expect(mock.x).after(mock.y, mock.z)
 
885
 
 
886
        is an alternative way to say::
 
887
 
 
888
            expr_x = mock.x
 
889
            expr_y = mock.y
 
890
            expr_z = mock.z
 
891
            mocker.order(expr_y, expr_x)
 
892
            mocker.order(expr_z, expr_x)
 
893
 
 
894
        See L{order()} for more information.
 
895
        """
 
896
        last_path = self._events[-1].path
 
897
        for path_holder in path_holders:
 
898
            self.order(path_holder, last_path)
 
899
 
 
900
    def before(self, *path_holders):
 
901
        """Last recorded event must happen before events referred to.
 
902
 
 
903
        @param path_holders: Objects returned as the result of recorded events
 
904
                             which should happen after the last recorded event
 
905
 
 
906
        As an example, the idiom::
 
907
 
 
908
            expect(mock.x).before(mock.y, mock.z)
 
909
 
 
910
        is an alternative way to say::
 
911
 
 
912
            expr_x = mock.x
 
913
            expr_y = mock.y
 
914
            expr_z = mock.z
 
915
            mocker.order(expr_x, expr_y)
 
916
            mocker.order(expr_x, expr_z)
 
917
 
 
918
        See L{order()} for more information.
 
919
        """
 
920
        last_path = self._events[-1].path
 
921
        for path_holder in path_holders:
 
922
            self.order(last_path, path_holder)
 
923
 
 
924
    def nospec(self):
 
925
        """Don't check method specification of real object on last event.
 
926
 
 
927
        By default, when using a mock created as the result of a call to
 
928
        L{proxy()}, L{replace()}, and C{patch()}, or when passing the spec
 
929
        attribute to the L{mock()} method, method calls on the given object
 
930
        are checked for correctness against the specification of the real
 
931
        object (or the explicitly provided spec).
 
932
 
 
933
        This method will disable that check specifically for the last
 
934
        recorded event.
 
935
        """
 
936
        event = self._events[-1]
 
937
        for task in event.get_tasks():
 
938
            if isinstance(task, SpecChecker):
 
939
                event.remove_task(task)
 
940
 
 
941
    def passthrough(self, result_callback=None):
 
942
        """Make the last recorded event run on the real object once seen.
 
943
 
 
944
        @param result_callback: If given, this function will be called with
 
945
            the result of the *real* method call as the only argument.
 
946
 
 
947
        This can only be used on proxies, as returned by the L{proxy()}
 
948
        and L{replace()} methods, or on mocks representing patched objects,
 
949
        as returned by the L{patch()} method.
 
950
        """
 
951
        event = self._events[-1]
 
952
        if event.path.root_object is None:
 
953
            raise TypeError("Mock object isn't a proxy")
 
954
        event.add_task(PathExecuter(result_callback))
 
955
 
 
956
    def __enter__(self):
 
957
        """Enter in a 'with' context.  This will run replay()."""
 
958
        self.replay()
 
959
        return self
 
960
 
 
961
    def __exit__(self, type, value, traceback):
 
962
        """Exit from a 'with' context.
 
963
 
 
964
        This will run restore() at all times, but will only run verify()
 
965
        if the 'with' block itself hasn't raised an exception.  Exceptions
 
966
        in that block are never swallowed.
 
967
        """
 
968
        self.restore()
 
969
        if type is None:
 
970
            self.verify()
 
971
        return False
 
972
 
 
973
    def _get_replay_restore_event(self):
 
974
        """Return unique L{ReplayRestoreEvent}, creating if needed.
 
975
 
 
976
        Some tasks only want to replay/restore.  When that's the case,
 
977
        they shouldn't act on other events during replay.  Also, they
 
978
        can all be put in a single event when that's the case.  Thus,
 
979
        we add a single L{ReplayRestoreEvent} as the first element of
 
980
        the list.
 
981
        """
 
982
        if not self._events or type(self._events[0]) != ReplayRestoreEvent:
 
983
            self._events.insert(0, ReplayRestoreEvent())
 
984
        return self._events[0]
 
985
 
 
986
 
 
987
class OrderedContext(object):
 
988
 
 
989
    def __init__(self, mocker):
 
990
        self._mocker = mocker
 
991
 
 
992
    def __enter__(self):
 
993
        return None
 
994
 
 
995
    def __exit__(self, type, value, traceback):
 
996
        self._mocker.unorder()
 
997
 
 
998
 
 
999
class Mocker(MockerBase):
 
1000
    __doc__ = MockerBase.__doc__
 
1001
 
 
1002
# Decorator to add recorders on the standard Mocker class.
 
1003
recorder = Mocker.add_recorder
 
1004
 
 
1005
 
 
1006
# --------------------------------------------------------------------
 
1007
# Mock object.
 
1008
 
 
1009
class Mock(object):
 
1010
 
 
1011
    def __init__(self, mocker, path=None, name=None, spec=None, type=None,
 
1012
                 object=None, passthrough=False, patcher=None, count=True):
 
1013
        self.__mocker__ = mocker
 
1014
        self.__mocker_path__ = path or Path(self, object)
 
1015
        self.__mocker_name__ = name
 
1016
        self.__mocker_spec__ = spec
 
1017
        self.__mocker_object__ = object
 
1018
        self.__mocker_passthrough__ = passthrough
 
1019
        self.__mocker_patcher__ = patcher
 
1020
        self.__mocker_replace__ = False
 
1021
        self.__mocker_type__ = type
 
1022
        self.__mocker_count__ = count
 
1023
 
 
1024
    def __mocker_act__(self, kind, args=(), kwargs={}, object=None):
 
1025
        if self.__mocker_name__ is None:
 
1026
            self.__mocker_name__ = find_object_name(self, 2)
 
1027
        action = Action(kind, args, kwargs, self.__mocker_path__)
 
1028
        path = self.__mocker_path__ + action
 
1029
        if object is not None:
 
1030
            path.root_object = object
 
1031
        try:
 
1032
            return self.__mocker__.act(path)
 
1033
        except MatchError, exception:
 
1034
            root_mock = path.root_mock
 
1035
            if (path.root_object is not None and
 
1036
                root_mock.__mocker_passthrough__):
 
1037
                return path.execute(path.root_object)
 
1038
            # Reinstantiate to show raise statement on traceback, and
 
1039
            # also to make the traceback shown shorter.
 
1040
            raise MatchError(str(exception))
 
1041
        except AssertionError, e:
 
1042
            lines = str(e).splitlines()
 
1043
            message = [ERROR_PREFIX + "Unmet expectation:", ""]
 
1044
            message.append("=> " + lines.pop(0))
 
1045
            message.extend([" " + line for line in lines])
 
1046
            message.append("")
 
1047
            raise AssertionError(os.linesep.join(message))
 
1048
 
 
1049
    def __getattribute__(self, name):
 
1050
        if name.startswith("__mocker_"):
 
1051
            return super(Mock, self).__getattribute__(name)
 
1052
        if name == "__class__":
 
1053
            if self.__mocker__.is_recording() or self.__mocker_type__ is None:
 
1054
                return type(self)
 
1055
            return self.__mocker_type__
 
1056
        return self.__mocker_act__("getattr", (name,))
 
1057
 
 
1058
    def __setattr__(self, name, value):
 
1059
        if name.startswith("__mocker_"):
 
1060
            return super(Mock, self).__setattr__(name, value)
 
1061
        return self.__mocker_act__("setattr", (name, value))
 
1062
 
 
1063
    def __delattr__(self, name):
 
1064
        return self.__mocker_act__("delattr", (name,))
 
1065
 
 
1066
    def __call__(self, *args, **kwargs):
 
1067
        return self.__mocker_act__("call", args, kwargs)
 
1068
 
 
1069
    def __contains__(self, value):
 
1070
        return self.__mocker_act__("contains", (value,))
 
1071
 
 
1072
    def __getitem__(self, key):
 
1073
        return self.__mocker_act__("getitem", (key,))
 
1074
 
 
1075
    def __setitem__(self, key, value):
 
1076
        return self.__mocker_act__("setitem", (key, value))
 
1077
 
 
1078
    def __delitem__(self, key):
 
1079
        return self.__mocker_act__("delitem", (key,))
 
1080
 
 
1081
    def __len__(self):
 
1082
        # MatchError is turned on an AttributeError so that list() and
 
1083
        # friends act properly when trying to get length hints on
 
1084
        # something that doesn't offer them.
 
1085
        try:
 
1086
            result = self.__mocker_act__("len")
 
1087
        except MatchError, e:
 
1088
            raise AttributeError(str(e))
 
1089
        if type(result) is Mock:
 
1090
            return 0
 
1091
        return result
 
1092
 
 
1093
    def __nonzero__(self):
 
1094
        try:
 
1095
            return self.__mocker_act__("nonzero")
 
1096
        except MatchError, e:
 
1097
            return True
 
1098
 
 
1099
    def __iter__(self):
 
1100
        # XXX On py3k, when next() becomes __next__(), we'll be able
 
1101
        #     to return the mock itself because it will be considered
 
1102
        #     an iterator (we'll be mocking __next__ as well, which we
 
1103
        #     can't now).
 
1104
        result = self.__mocker_act__("iter")
 
1105
        if type(result) is Mock:
 
1106
            return iter([])
 
1107
        return result
 
1108
 
 
1109
    # When adding a new action kind here, also add support for it on
 
1110
    # Action.execute() and Path.__str__().
 
1111
 
 
1112
 
 
1113
def find_object_name(obj, depth=0):
 
1114
    """Try to detect how the object is named on a previous scope."""
 
1115
    try:
 
1116
        frame = sys._getframe(depth+1)
 
1117
    except:
 
1118
        return None
 
1119
    for name, frame_obj in frame.f_locals.iteritems():
 
1120
        if frame_obj is obj:
 
1121
            return name
 
1122
    self = frame.f_locals.get("self")
 
1123
    if self is not None:
 
1124
        try:
 
1125
            items = list(self.__dict__.iteritems())
 
1126
        except:
 
1127
            pass
 
1128
        else:
 
1129
            for name, self_obj in items:
 
1130
                if self_obj is obj:
 
1131
                    return name
 
1132
    return None
 
1133
 
 
1134
 
 
1135
# --------------------------------------------------------------------
 
1136
# Action and path.
 
1137
 
 
1138
class Action(object):
 
1139
 
 
1140
    def __init__(self, kind, args, kwargs, path=None):
 
1141
        self.kind = kind
 
1142
        self.args = args
 
1143
        self.kwargs = kwargs
 
1144
        self.path = path
 
1145
        self._execute_cache = {}
 
1146
 
 
1147
    def __repr__(self):
 
1148
        if self.path is None:
 
1149
            return "Action(%r, %r, %r)" % (self.kind, self.args, self.kwargs)
 
1150
        return "Action(%r, %r, %r, %r)" % \
 
1151
               (self.kind, self.args, self.kwargs, self.path)
 
1152
 
 
1153
    def __eq__(self, other):
 
1154
        return (self.kind == other.kind and
 
1155
                self.args == other.args and
 
1156
                self.kwargs == other.kwargs)
 
1157
 
 
1158
    def __ne__(self, other):
 
1159
        return not self.__eq__(other)
 
1160
 
 
1161
    def matches(self, other):
 
1162
        return (self.kind == other.kind and
 
1163
                match_params(self.args, self.kwargs, other.args, other.kwargs))
 
1164
 
 
1165
    def execute(self, object):
 
1166
        # This caching scheme may fail if the object gets deallocated before
 
1167
        # the action, as the id might get reused.  It's somewhat easy to fix
 
1168
        # that with a weakref callback.  For our uses, though, the object
 
1169
        # should never get deallocated before the action itself, so we'll
 
1170
        # just keep it simple.
 
1171
        if id(object) in self._execute_cache:
 
1172
            return self._execute_cache[id(object)]
 
1173
        execute = getattr(object, "__mocker_execute__", None)
 
1174
        if execute is not None:
 
1175
            result = execute(self, object)
 
1176
        else:
 
1177
            kind = self.kind
 
1178
            if kind == "getattr":
 
1179
                result = getattr(object, self.args[0])
 
1180
            elif kind == "setattr":
 
1181
                result = setattr(object, self.args[0], self.args[1])
 
1182
            elif kind == "delattr":
 
1183
                result = delattr(object, self.args[0])
 
1184
            elif kind == "call":
 
1185
                result = object(*self.args, **self.kwargs)
 
1186
            elif kind == "contains":
 
1187
                result = self.args[0] in object
 
1188
            elif kind == "getitem":
 
1189
                result = object[self.args[0]]
 
1190
            elif kind == "setitem":
 
1191
                result = object[self.args[0]] = self.args[1]
 
1192
            elif kind == "delitem":
 
1193
                del object[self.args[0]]
 
1194
                result = None
 
1195
            elif kind == "len":
 
1196
                result = len(object)
 
1197
            elif kind == "nonzero":
 
1198
                result = bool(object)
 
1199
            elif kind == "iter":
 
1200
                result = iter(object)
 
1201
            else:
 
1202
                raise RuntimeError("Don't know how to execute %r kind." % kind)
 
1203
        self._execute_cache[id(object)] = result
 
1204
        return result
 
1205
 
 
1206
 
 
1207
class Path(object):
 
1208
 
 
1209
    def __init__(self, root_mock, root_object=None, actions=()):
 
1210
        self.root_mock = root_mock
 
1211
        self.root_object = root_object
 
1212
        self.actions = tuple(actions)
 
1213
        self.__mocker_replace__ = False
 
1214
 
 
1215
    def parent_path(self):
 
1216
        if not self.actions:
 
1217
            return None
 
1218
        return self.actions[-1].path
 
1219
    parent_path = property(parent_path)
 
1220
 
 
1221
    def __add__(self, action):
 
1222
        """Return a new path which includes the given action at the end."""
 
1223
        return self.__class__(self.root_mock, self.root_object,
 
1224
                              self.actions + (action,))
 
1225
 
 
1226
    def __eq__(self, other):
 
1227
        """Verify if the two paths are equal.
 
1228
        
 
1229
        Two paths are equal if they refer to the same mock object, and
 
1230
        have the actions with equal kind, args and kwargs.
 
1231
        """
 
1232
        if (self.root_mock is not other.root_mock or
 
1233
            self.root_object is not other.root_object or
 
1234
            len(self.actions) != len(other.actions)):
 
1235
            return False
 
1236
        for action, other_action in zip(self.actions, other.actions):
 
1237
            if action != other_action:
 
1238
                return False
 
1239
        return True
 
1240
 
 
1241
    def matches(self, other):
 
1242
        """Verify if the two paths are equivalent.
 
1243
        
 
1244
        Two paths are equal if they refer to the same mock object, and
 
1245
        have the same actions performed on them.
 
1246
        """
 
1247
        if (self.root_mock is not other.root_mock or
 
1248
            len(self.actions) != len(other.actions)):
 
1249
            return False
 
1250
        for action, other_action in zip(self.actions, other.actions):
 
1251
            if not action.matches(other_action):
 
1252
                return False
 
1253
        return True
 
1254
 
 
1255
    def execute(self, object):
 
1256
        """Execute all actions sequentially on object, and return result.
 
1257
        """
 
1258
        for action in self.actions:
 
1259
            object = action.execute(object)
 
1260
        return object
 
1261
 
 
1262
    def __str__(self):
 
1263
        """Transform the path into a nice string such as obj.x.y('z')."""
 
1264
        result = self.root_mock.__mocker_name__ or "<mock>"
 
1265
        for action in self.actions:
 
1266
            if action.kind == "getattr":
 
1267
                result = "%s.%s" % (result, action.args[0])
 
1268
            elif action.kind == "setattr":
 
1269
                result = "%s.%s = %r" % (result, action.args[0], action.args[1])
 
1270
            elif action.kind == "delattr":
 
1271
                result = "del %s.%s" % (result, action.args[0])
 
1272
            elif action.kind == "call":
 
1273
                args = [repr(x) for x in action.args]
 
1274
                items = list(action.kwargs.iteritems())
 
1275
                items.sort()
 
1276
                for pair in items:
 
1277
                    args.append("%s=%r" % pair)
 
1278
                result = "%s(%s)" % (result, ", ".join(args))
 
1279
            elif action.kind == "contains":
 
1280
                result = "%r in %s" % (action.args[0], result)
 
1281
            elif action.kind == "getitem":
 
1282
                result = "%s[%r]" % (result, action.args[0])
 
1283
            elif action.kind == "setitem":
 
1284
                result = "%s[%r] = %r" % (result, action.args[0],
 
1285
                                          action.args[1])
 
1286
            elif action.kind == "delitem":
 
1287
                result = "del %s[%r]" % (result, action.args[0])
 
1288
            elif action.kind == "len":
 
1289
                result = "len(%s)" % result
 
1290
            elif action.kind == "nonzero":
 
1291
                result = "bool(%s)" % result
 
1292
            elif action.kind == "iter":
 
1293
                result = "iter(%s)" % result
 
1294
            else:
 
1295
                raise RuntimeError("Don't know how to format kind %r" %
 
1296
                                   action.kind)
 
1297
        return result
 
1298
 
 
1299
 
 
1300
class SpecialArgument(object):
 
1301
    """Base for special arguments for matching parameters."""
 
1302
 
 
1303
    def __init__(self, object=None):
 
1304
        self.object = object
 
1305
 
 
1306
    def __repr__(self):
 
1307
        if self.object is None:
 
1308
            return self.__class__.__name__
 
1309
        else:
 
1310
            return "%s(%r)" % (self.__class__.__name__, self.object)
 
1311
 
 
1312
    def matches(self, other):
 
1313
        return True
 
1314
 
 
1315
    def __eq__(self, other):
 
1316
        return type(other) == type(self) and self.object == other.object
 
1317
 
 
1318
 
 
1319
class ANY(SpecialArgument):
 
1320
    """Matches any single argument."""
 
1321
 
 
1322
ANY = ANY()
 
1323
 
 
1324
 
 
1325
class ARGS(SpecialArgument):
 
1326
    """Matches zero or more positional arguments."""
 
1327
 
 
1328
ARGS = ARGS()
 
1329
 
 
1330
 
 
1331
class KWARGS(SpecialArgument):
 
1332
    """Matches zero or more keyword arguments."""
 
1333
 
 
1334
KWARGS = KWARGS()
 
1335
 
 
1336
 
 
1337
class IS(SpecialArgument):
 
1338
 
 
1339
    def matches(self, other):
 
1340
        return self.object is other
 
1341
 
 
1342
    def __eq__(self, other):
 
1343
        return type(other) == type(self) and self.object is other.object
 
1344
 
 
1345
 
 
1346
class CONTAINS(SpecialArgument):
 
1347
 
 
1348
    def matches(self, other):
 
1349
        try:
 
1350
            other.__contains__
 
1351
        except AttributeError:
 
1352
            try:
 
1353
                iter(other)
 
1354
            except TypeError:
 
1355
                # If an object can't be iterated, and has no __contains__
 
1356
                # hook, it'd blow up on the test below.  We test this in
 
1357
                # advance to prevent catching more errors than we really
 
1358
                # want.
 
1359
                return False
 
1360
        return self.object in other
 
1361
 
 
1362
 
 
1363
class IN(SpecialArgument):
 
1364
 
 
1365
    def matches(self, other):
 
1366
        return other in self.object
 
1367
 
 
1368
 
 
1369
class MATCH(SpecialArgument):
 
1370
 
 
1371
    def matches(self, other):
 
1372
        return bool(self.object(other))
 
1373
 
 
1374
    def __eq__(self, other):
 
1375
        return type(other) == type(self) and self.object is other.object
 
1376
 
 
1377
 
 
1378
def match_params(args1, kwargs1, args2, kwargs2):
 
1379
    """Match the two sets of parameters, considering special parameters."""
 
1380
 
 
1381
    has_args = ARGS in args1
 
1382
    has_kwargs = KWARGS in args1
 
1383
 
 
1384
    if has_kwargs:
 
1385
        args1 = [arg1 for arg1 in args1 if arg1 is not KWARGS]
 
1386
    elif len(kwargs1) != len(kwargs2):
 
1387
        return False
 
1388
 
 
1389
    if not has_args and len(args1) != len(args2):
 
1390
        return False
 
1391
 
 
1392
    # Either we have the same number of kwargs, or unknown keywords are
 
1393
    # accepted (KWARGS was used), so check just the ones in kwargs1.
 
1394
    for key, arg1 in kwargs1.iteritems():
 
1395
        if key not in kwargs2:
 
1396
            return False
 
1397
        arg2 = kwargs2[key]
 
1398
        if isinstance(arg1, SpecialArgument):
 
1399
            if not arg1.matches(arg2):
 
1400
                return False
 
1401
        elif arg1 != arg2:
 
1402
            return False
 
1403
 
 
1404
    # Keywords match.  Now either we have the same number of
 
1405
    # arguments, or ARGS was used.  If ARGS wasn't used, arguments
 
1406
    # must match one-on-one necessarily.
 
1407
    if not has_args:
 
1408
        for arg1, arg2 in zip(args1, args2):
 
1409
            if isinstance(arg1, SpecialArgument):
 
1410
                if not arg1.matches(arg2):
 
1411
                    return False
 
1412
            elif arg1 != arg2:
 
1413
                return False
 
1414
        return True
 
1415
 
 
1416
    # Easy choice. Keywords are matching, and anything on args is accepted.
 
1417
    if (ARGS,) == args1:
 
1418
        return True
 
1419
 
 
1420
    # We have something different there. If we don't have positional
 
1421
    # arguments on the original call, it can't match.
 
1422
    if not args2:
 
1423
        # Unless we have just several ARGS (which is bizarre, but..).
 
1424
        for arg1 in args1:
 
1425
            if arg1 is not ARGS:
 
1426
                return False
 
1427
        return True
 
1428
 
 
1429
    # Ok, all bets are lost.  We have to actually do the more expensive
 
1430
    # matching.  This is an algorithm based on the idea of the Levenshtein
 
1431
    # Distance between two strings, but heavily hacked for this purpose.
 
1432
    args2l = len(args2)
 
1433
    if args1[0] is ARGS:
 
1434
        args1 = args1[1:]
 
1435
        array = [0]*args2l
 
1436
    else:
 
1437
        array = [1]*args2l
 
1438
    for i in range(len(args1)):
 
1439
        last = array[0]
 
1440
        if args1[i] is ARGS:
 
1441
            for j in range(1, args2l):
 
1442
                last, array[j] = array[j], min(array[j-1], array[j], last)
 
1443
        else:
 
1444
            array[0] = i or int(args1[i] != args2[0])
 
1445
            for j in range(1, args2l):
 
1446
                last, array[j] = array[j], last or int(args1[i] != args2[j])
 
1447
        if 0 not in array:
 
1448
            return False
 
1449
    if array[-1] != 0:
 
1450
        return False
 
1451
    return True
 
1452
 
 
1453
 
 
1454
# --------------------------------------------------------------------
 
1455
# Event and task base.
 
1456
 
 
1457
class Event(object):
 
1458
    """Aggregation of tasks that keep track of a recorded action.
 
1459
 
 
1460
    An event represents something that may or may not happen while the
 
1461
    mocked environment is running, such as an attribute access, or a
 
1462
    method call.  The event is composed of several tasks that are
 
1463
    orchestrated together to create a composed meaning for the event,
 
1464
    including for which actions it should be run, what happens when it
 
1465
    runs, and what's the expectations about the actions run.
 
1466
    """
 
1467
 
 
1468
    def __init__(self, path=None):
 
1469
        self.path = path
 
1470
        self._tasks = []
 
1471
        self._has_run = False
 
1472
 
 
1473
    def add_task(self, task):
 
1474
        """Add a new task to this taks."""
 
1475
        self._tasks.append(task)
 
1476
        return task
 
1477
 
 
1478
    def remove_task(self, task):
 
1479
        self._tasks.remove(task)
 
1480
 
 
1481
    def get_tasks(self):
 
1482
        return self._tasks[:]
 
1483
 
 
1484
    def matches(self, path):
 
1485
        """Return true if *all* tasks match the given path."""
 
1486
        for task in self._tasks:
 
1487
            if not task.matches(path):
 
1488
                return False
 
1489
        return bool(self._tasks)
 
1490
 
 
1491
    def has_run(self):
 
1492
        return self._has_run
 
1493
 
 
1494
    def may_run(self, path):
 
1495
        """Verify if any task would certainly raise an error if run.
 
1496
 
 
1497
        This will call the C{may_run()} method on each task and return
 
1498
        false if any of them returns false.
 
1499
        """
 
1500
        for task in self._tasks:
 
1501
            if not task.may_run(path):
 
1502
                return False
 
1503
        return True
 
1504
 
 
1505
    def run(self, path):
 
1506
        """Run all tasks with the given action.
 
1507
 
 
1508
        @param path: The path of the expression run.
 
1509
 
 
1510
        Running an event means running all of its tasks individually and in
 
1511
        order.  An event should only ever be run if all of its tasks claim to
 
1512
        match the given action.
 
1513
 
 
1514
        The result of this method will be the last result of a task
 
1515
        which isn't None, or None if they're all None.
 
1516
        """
 
1517
        self._has_run = True
 
1518
        result = None
 
1519
        errors = []
 
1520
        for task in self._tasks:
 
1521
            try:
 
1522
                task_result = task.run(path)
 
1523
            except AssertionError, e:
 
1524
                error = str(e)
 
1525
                if not error:
 
1526
                    raise RuntimeError("Empty error message from %r" % task)
 
1527
                errors.append(error)
 
1528
            else:
 
1529
                if task_result is not None:
 
1530
                    result = task_result
 
1531
        if errors:
 
1532
            message = [str(self.path)]
 
1533
            if str(path) != message[0]:
 
1534
                message.append("- Run: %s" % path)
 
1535
            for error in errors:
 
1536
                lines = error.splitlines()
 
1537
                message.append("- " + lines.pop(0))
 
1538
                message.extend(["  " + line for line in lines])
 
1539
            raise AssertionError(os.linesep.join(message))
 
1540
        return result
 
1541
 
 
1542
    def satisfied(self):
 
1543
        """Return true if all tasks are satisfied.
 
1544
 
 
1545
        Being satisfied means that there are no unmet expectations.
 
1546
        """
 
1547
        for task in self._tasks:
 
1548
            try:
 
1549
                task.verify()
 
1550
            except AssertionError:
 
1551
                return False
 
1552
        return True
 
1553
 
 
1554
    def verify(self):
 
1555
        """Run verify on all tasks.
 
1556
 
 
1557
        The verify method is supposed to raise an AssertionError if the
 
1558
        task has unmet expectations, with a one-line explanation about
 
1559
        why this item is unmet.  This method should be safe to be called
 
1560
        multiple times without side effects.
 
1561
        """
 
1562
        errors = []
 
1563
        for task in self._tasks:
 
1564
            try:
 
1565
                task.verify()
 
1566
            except AssertionError, e:
 
1567
                error = str(e)
 
1568
                if not error:
 
1569
                    raise RuntimeError("Empty error message from %r" % task)
 
1570
                errors.append(error)
 
1571
        if errors:
 
1572
            message = [str(self.path)]
 
1573
            for error in errors:
 
1574
                lines = error.splitlines()
 
1575
                message.append("- " + lines.pop(0))
 
1576
                message.extend(["  " + line for line in lines])
 
1577
            raise AssertionError(os.linesep.join(message))
 
1578
 
 
1579
    def replay(self):
 
1580
        """Put all tasks in replay mode."""
 
1581
        self._has_run = False
 
1582
        for task in self._tasks:
 
1583
            task.replay()
 
1584
 
 
1585
    def restore(self):
 
1586
        """Restore the state of all tasks."""
 
1587
        for task in self._tasks:
 
1588
            task.restore()
 
1589
 
 
1590
 
 
1591
class ReplayRestoreEvent(Event):
 
1592
    """Helper event for tasks which need replay/restore but shouldn't match."""
 
1593
 
 
1594
    def matches(self, path):
 
1595
        return False
 
1596
 
 
1597
 
 
1598
class Task(object):
 
1599
    """Element used to track one specific aspect on an event.
 
1600
 
 
1601
    A task is responsible for adding any kind of logic to an event.
 
1602
    Examples of that are counting the number of times the event was
 
1603
    made, verifying parameters if any, and so on.
 
1604
    """
 
1605
 
 
1606
    def matches(self, path):
 
1607
        """Return true if the task is supposed to be run for the given path.
 
1608
        """
 
1609
        return True
 
1610
 
 
1611
    def may_run(self, path):
 
1612
        """Return false if running this task would certainly raise an error."""
 
1613
        return True
 
1614
 
 
1615
    def run(self, path):
 
1616
        """Perform the task item, considering that the given action happened.
 
1617
        """
 
1618
 
 
1619
    def verify(self):
 
1620
        """Raise AssertionError if expectations for this item are unmet.
 
1621
 
 
1622
        The verify method is supposed to raise an AssertionError if the
 
1623
        task has unmet expectations, with a one-line explanation about
 
1624
        why this item is unmet.  This method should be safe to be called
 
1625
        multiple times without side effects.
 
1626
        """
 
1627
 
 
1628
    def replay(self):
 
1629
        """Put the task in replay mode.
 
1630
 
 
1631
        Any expectations of the task should be reset.
 
1632
        """
 
1633
 
 
1634
    def restore(self):
 
1635
        """Restore any environmental changes made by the task.
 
1636
 
 
1637
        Verify should continue to work after this is called.
 
1638
        """
 
1639
 
 
1640
 
 
1641
# --------------------------------------------------------------------
 
1642
# Task implementations.
 
1643
 
 
1644
class OnRestoreCaller(Task):
 
1645
    """Call a given callback when restoring."""
 
1646
 
 
1647
    def __init__(self, callback):
 
1648
        self._callback = callback
 
1649
 
 
1650
    def restore(self):
 
1651
        self._callback()
 
1652
 
 
1653
 
 
1654
class PathMatcher(Task):
 
1655
    """Match the action path against a given path."""
 
1656
 
 
1657
    def __init__(self, path):
 
1658
        self.path = path
 
1659
 
 
1660
    def matches(self, path):
 
1661
        return self.path.matches(path)
 
1662
 
 
1663
def path_matcher_recorder(mocker, event):
 
1664
    event.add_task(PathMatcher(event.path))
 
1665
 
 
1666
Mocker.add_recorder(path_matcher_recorder)
 
1667
 
 
1668
 
 
1669
class RunCounter(Task):
 
1670
    """Task which verifies if the number of runs are within given boundaries.
 
1671
    """
 
1672
 
 
1673
    def __init__(self, min, max=False):
 
1674
        self.min = min
 
1675
        if max is None:
 
1676
            self.max = sys.maxint
 
1677
        elif max is False:
 
1678
            self.max = min
 
1679
        else:
 
1680
            self.max = max
 
1681
        self._runs = 0
 
1682
 
 
1683
    def replay(self):
 
1684
        self._runs = 0
 
1685
 
 
1686
    def may_run(self, path):
 
1687
        return self._runs < self.max
 
1688
 
 
1689
    def run(self, path):
 
1690
        self._runs += 1
 
1691
        if self._runs > self.max:
 
1692
            self.verify()
 
1693
 
 
1694
    def verify(self):
 
1695
        if not self.min <= self._runs <= self.max:
 
1696
            if self._runs < self.min:
 
1697
                raise AssertionError("Performed fewer times than expected.")
 
1698
            raise AssertionError("Performed more times than expected.")
 
1699
 
 
1700
 
 
1701
class ImplicitRunCounter(RunCounter):
 
1702
    """RunCounter inserted by default on any event.
 
1703
 
 
1704
    This is a way to differentiate explicitly added counters and
 
1705
    implicit ones.
 
1706
    """
 
1707
 
 
1708
def run_counter_recorder(mocker, event):
 
1709
    """Any event may be repeated once, unless disabled by default."""
 
1710
    if event.path.root_mock.__mocker_count__:
 
1711
        event.add_task(ImplicitRunCounter(1))
 
1712
 
 
1713
Mocker.add_recorder(run_counter_recorder)
 
1714
 
 
1715
def run_counter_removal_recorder(mocker, event):
 
1716
    """
 
1717
    Events created by getattr actions which lead to other events
 
1718
    may be repeated any number of times. For that, we remove implicit
 
1719
    run counters of any getattr actions leading to the current one.
 
1720
    """
 
1721
    parent_path = event.path.parent_path
 
1722
    for event in mocker.get_events()[::-1]:
 
1723
        if (event.path is parent_path and
 
1724
            event.path.actions[-1].kind == "getattr"):
 
1725
            for task in event.get_tasks():
 
1726
                if type(task) is ImplicitRunCounter:
 
1727
                    event.remove_task(task)
 
1728
 
 
1729
Mocker.add_recorder(run_counter_removal_recorder)
 
1730
 
 
1731
 
 
1732
class MockReturner(Task):
 
1733
    """Return a mock based on the action path."""
 
1734
 
 
1735
    def __init__(self, mocker):
 
1736
        self.mocker = mocker
 
1737
 
 
1738
    def run(self, path):
 
1739
        return Mock(self.mocker, path)
 
1740
 
 
1741
def mock_returner_recorder(mocker, event):
 
1742
    """Events that lead to other events must return mock objects."""
 
1743
    parent_path = event.path.parent_path
 
1744
    for event in mocker.get_events():
 
1745
        if event.path is parent_path:
 
1746
            for task in event.get_tasks():
 
1747
                if isinstance(task, MockReturner):
 
1748
                    break
 
1749
            else:
 
1750
                event.add_task(MockReturner(mocker))
 
1751
            break
 
1752
 
 
1753
Mocker.add_recorder(mock_returner_recorder)
 
1754
 
 
1755
 
 
1756
class FunctionRunner(Task):
 
1757
    """Task that runs a function everything it's run.
 
1758
 
 
1759
    Arguments of the last action in the path are passed to the function,
 
1760
    and the function result is also returned.
 
1761
    """
 
1762
 
 
1763
    def __init__(self, func):
 
1764
        self._func = func
 
1765
 
 
1766
    def run(self, path):
 
1767
        action = path.actions[-1]
 
1768
        return self._func(*action.args, **action.kwargs)
 
1769
 
 
1770
 
 
1771
class PathExecuter(Task):
 
1772
    """Task that executes a path in the real object, and returns the result."""
 
1773
 
 
1774
    def __init__(self, result_callback=None):
 
1775
        self._result_callback = result_callback
 
1776
 
 
1777
    def get_result_callback(self):
 
1778
        return self._result_callback
 
1779
 
 
1780
    def run(self, path):
 
1781
        result = path.execute(path.root_object)
 
1782
        if self._result_callback is not None:
 
1783
            self._result_callback(result)
 
1784
        return result
 
1785
 
 
1786
 
 
1787
class Orderer(Task):
 
1788
    """Task to establish an order relation between two events.
 
1789
 
 
1790
    An orderer task will only match once all its dependencies have
 
1791
    been run.
 
1792
    """
 
1793
 
 
1794
    def __init__(self, path):
 
1795
        self.path = path
 
1796
        self._run = False 
 
1797
        self._dependencies = []
 
1798
 
 
1799
    def replay(self):
 
1800
        self._run = False
 
1801
 
 
1802
    def has_run(self):
 
1803
        return self._run
 
1804
 
 
1805
    def may_run(self, path):
 
1806
        for dependency in self._dependencies:
 
1807
            if not dependency.has_run():
 
1808
                return False
 
1809
        return True
 
1810
 
 
1811
    def run(self, path):
 
1812
        for dependency in self._dependencies:
 
1813
            if not dependency.has_run():
 
1814
                raise AssertionError("Should be after: %s" % dependency.path)
 
1815
        self._run = True
 
1816
 
 
1817
    def add_dependency(self, orderer):
 
1818
        self._dependencies.append(orderer)
 
1819
 
 
1820
    def get_dependencies(self):
 
1821
        return self._dependencies
 
1822
 
 
1823
 
 
1824
class SpecChecker(Task):
 
1825
    """Task to check if arguments of the last action conform to a real method.
 
1826
    """
 
1827
 
 
1828
    def __init__(self, method):
 
1829
        self._method = method
 
1830
        self._unsupported = False
 
1831
 
 
1832
        if method:
 
1833
            try:
 
1834
                self._args, self._varargs, self._varkwargs, self._defaults = \
 
1835
                    inspect.getargspec(method)
 
1836
            except TypeError:
 
1837
                self._unsupported = True
 
1838
            else:
 
1839
                if self._defaults is None:
 
1840
                    self._defaults = ()
 
1841
                if type(method) is type(self.run):
 
1842
                    self._args = self._args[1:]
 
1843
 
 
1844
    def get_method(self):
 
1845
        return self._method
 
1846
 
 
1847
    def _raise(self, message):
 
1848
        spec = inspect.formatargspec(self._args, self._varargs,
 
1849
                                     self._varkwargs, self._defaults)
 
1850
        raise AssertionError("Specification is %s%s: %s" %
 
1851
                             (self._method.__name__, spec, message))
 
1852
 
 
1853
    def verify(self):
 
1854
        if not self._method:
 
1855
            raise AssertionError("Method not found in real specification")
 
1856
 
 
1857
    def may_run(self, path):
 
1858
        try:
 
1859
            self.run(path)
 
1860
        except AssertionError:
 
1861
            return False
 
1862
        return True
 
1863
 
 
1864
    def run(self, path):
 
1865
        if not self._method:
 
1866
            raise AssertionError("Method not found in real specification")
 
1867
        if self._unsupported:
 
1868
            return # Can't check it. Happens with builtin functions. :-(
 
1869
        action = path.actions[-1]
 
1870
        obtained_len = len(action.args)
 
1871
        obtained_kwargs = action.kwargs.copy()
 
1872
        nodefaults_len = len(self._args) - len(self._defaults)
 
1873
        for i, name in enumerate(self._args):
 
1874
            if i < obtained_len and name in action.kwargs:
 
1875
                self._raise("%r provided twice" % name)
 
1876
            if (i >= obtained_len and i < nodefaults_len and
 
1877
                name not in action.kwargs):
 
1878
                self._raise("%r not provided" % name)
 
1879
            obtained_kwargs.pop(name, None)
 
1880
        if obtained_len > len(self._args) and not self._varargs:
 
1881
            self._raise("too many args provided")
 
1882
        if obtained_kwargs and not self._varkwargs:
 
1883
            self._raise("unknown kwargs: %s" % ", ".join(obtained_kwargs))
 
1884
 
 
1885
def spec_checker_recorder(mocker, event):
 
1886
    spec = event.path.root_mock.__mocker_spec__
 
1887
    if spec:
 
1888
        actions = event.path.actions
 
1889
        if len(actions) == 1:
 
1890
            if actions[0].kind == "call":
 
1891
                method = getattr(spec, "__call__", None)
 
1892
                event.add_task(SpecChecker(method))
 
1893
        elif len(actions) == 2:
 
1894
            if actions[0].kind == "getattr" and actions[1].kind == "call":
 
1895
                method = getattr(spec, actions[0].args[0], None)
 
1896
                event.add_task(SpecChecker(method))
 
1897
 
 
1898
Mocker.add_recorder(spec_checker_recorder)
 
1899
 
 
1900
 
 
1901
class ProxyReplacer(Task):
 
1902
    """Task which installs and deinstalls proxy mocks.
 
1903
 
 
1904
    This task will replace a real object by a mock in all dictionaries
 
1905
    found in the running interpreter via the garbage collecting system.
 
1906
    """
 
1907
 
 
1908
    def __init__(self, mock):
 
1909
        self.mock = mock
 
1910
        self.__mocker_replace__ = False
 
1911
 
 
1912
    def replay(self):
 
1913
        global_replace(self.mock.__mocker_object__, self.mock)
 
1914
 
 
1915
    def restore(self):
 
1916
        global_replace(self.mock, self.mock.__mocker_object__)
 
1917
 
 
1918
 
 
1919
def global_replace(remove, install):
 
1920
    """Replace object 'remove' with object 'install' on all dictionaries."""
 
1921
    for referrer in gc.get_referrers(remove):
 
1922
        if (type(referrer) is dict and
 
1923
            referrer.get("__mocker_replace__", True)):
 
1924
            for key, value in list(referrer.iteritems()):
 
1925
                if value is remove:
 
1926
                    referrer[key] = install
 
1927
 
 
1928
 
 
1929
class Undefined(object):
 
1930
 
 
1931
    def __repr__(self):
 
1932
        return "Undefined"
 
1933
 
 
1934
Undefined = Undefined()
 
1935
 
 
1936
 
 
1937
class Patcher(Task):
 
1938
 
 
1939
    def __init__(self):
 
1940
        super(Patcher, self).__init__()
 
1941
        self._monitored = {} # {kind: {id(object): object}}
 
1942
        self._patched = {}
 
1943
 
 
1944
    def is_monitoring(self, obj, kind):
 
1945
        monitored = self._monitored.get(kind)
 
1946
        if monitored:
 
1947
            if id(obj) in monitored:
 
1948
                return True
 
1949
            cls = type(obj)
 
1950
            if issubclass(cls, type):
 
1951
                cls = obj
 
1952
            bases = set([id(base) for base in cls.__mro__])
 
1953
            bases.intersection_update(monitored)
 
1954
            return bool(bases)
 
1955
        return False
 
1956
 
 
1957
    def monitor(self, obj, kind):
 
1958
        if kind not in self._monitored:
 
1959
            self._monitored[kind] = {}
 
1960
        self._monitored[kind][id(obj)] = obj
 
1961
 
 
1962
    def patch_attr(self, obj, attr, value):
 
1963
        original = obj.__dict__.get(attr, Undefined)
 
1964
        self._patched[id(obj), attr] = obj, attr, original
 
1965
        setattr(obj, attr, value)
 
1966
 
 
1967
    def get_unpatched_attr(self, obj, attr):
 
1968
        cls = type(obj)
 
1969
        if issubclass(cls, type):
 
1970
            cls = obj
 
1971
        result = Undefined
 
1972
        for mro_cls in cls.__mro__:
 
1973
            key = (id(mro_cls), attr)
 
1974
            if key in self._patched:
 
1975
                result = self._patched[key][2]
 
1976
                if result is not Undefined:
 
1977
                    break
 
1978
            elif attr in mro_cls.__dict__:
 
1979
                result = mro_cls.__dict__.get(attr, Undefined)
 
1980
                break
 
1981
        if isinstance(result, object) and hasattr(type(result), "__get__"):
 
1982
            if cls is obj:
 
1983
                obj = None
 
1984
            return result.__get__(obj, cls)
 
1985
        return result
 
1986
 
 
1987
    def _get_kind_attr(self, kind):
 
1988
        if kind == "getattr":
 
1989
            return "__getattribute__"
 
1990
        return "__%s__" % kind
 
1991
 
 
1992
    def replay(self):
 
1993
        for kind in self._monitored:
 
1994
            attr = self._get_kind_attr(kind)
 
1995
            seen = set()
 
1996
            for obj in self._monitored[kind].itervalues():
 
1997
                cls = type(obj)
 
1998
                if issubclass(cls, type):
 
1999
                    cls = obj
 
2000
                if cls not in seen:
 
2001
                    seen.add(cls)
 
2002
                    unpatched = getattr(cls, attr, Undefined)
 
2003
                    self.patch_attr(cls, attr,
 
2004
                                    PatchedMethod(kind, unpatched,
 
2005
                                                  self.is_monitoring))
 
2006
                    self.patch_attr(cls, "__mocker_execute__",
 
2007
                                    self.execute)
 
2008
 
 
2009
    def restore(self):
 
2010
        for obj, attr, original in self._patched.itervalues():
 
2011
            if original is Undefined:
 
2012
                delattr(obj, attr)
 
2013
            else:
 
2014
                setattr(obj, attr, original)
 
2015
        self._patched.clear()
 
2016
 
 
2017
    def execute(self, action, object):
 
2018
        attr = self._get_kind_attr(action.kind)
 
2019
        unpatched = self.get_unpatched_attr(object, attr)
 
2020
        try:
 
2021
            return unpatched(*action.args, **action.kwargs)
 
2022
        except AttributeError:
 
2023
            type, value, traceback = sys.exc_info()
 
2024
            if action.kind == "getattr":
 
2025
                # The normal behavior of Python is to try __getattribute__,
 
2026
                # and if it raises AttributeError, try __getattr__.   We've
 
2027
                # tried the unpatched __getattribute__ above, and we'll now
 
2028
                # try __getattr__.
 
2029
                try:
 
2030
                    __getattr__ = unpatched("__getattr__")
 
2031
                except AttributeError:
 
2032
                    pass
 
2033
                else:
 
2034
                    return __getattr__(*action.args, **action.kwargs)
 
2035
            raise type, value, traceback
 
2036
 
 
2037
 
 
2038
class PatchedMethod(object):
 
2039
 
 
2040
    def __init__(self, kind, unpatched, is_monitoring):
 
2041
        self._kind = kind
 
2042
        self._unpatched = unpatched
 
2043
        self._is_monitoring = is_monitoring
 
2044
 
 
2045
    def __get__(self, obj, cls=None):
 
2046
        object = obj or cls
 
2047
        if not self._is_monitoring(object, self._kind):
 
2048
            return self._unpatched.__get__(obj, cls)
 
2049
        def method(*args, **kwargs):
 
2050
            if self._kind == "getattr" and args[0].startswith("__mocker_"):
 
2051
                return self._unpatched.__get__(obj, cls)(args[0])
 
2052
            mock = object.__mocker_mock__
 
2053
            return mock.__mocker_act__(self._kind, args, kwargs, object)
 
2054
        return method
 
2055
 
 
2056
    def __call__(self, obj, *args, **kwargs):
 
2057
        # At least with __getattribute__, Python seems to use *both* the
 
2058
        # descriptor API and also call the class attribute directly.  It
 
2059
        # looks like an interpreter bug, or at least an undocumented
 
2060
        # inconsistency.
 
2061
        return self.__get__(obj)(*args, **kwargs)
 
2062
 
 
2063
 
 
2064
def patcher_recorder(mocker, event):
 
2065
    mock = event.path.root_mock
 
2066
    if mock.__mocker_patcher__ and len(event.path.actions) == 1:
 
2067
        patcher = mock.__mocker_patcher__
 
2068
        patcher.monitor(mock.__mocker_object__, event.path.actions[0].kind)
 
2069
 
 
2070
Mocker.add_recorder(patcher_recorder)