~mandel/ubuntu-sso-client/pinned-certs

« back to all changes in this revision

Viewing changes to mocker.py

  • Committer: natalia.bidart at canonical
  • Date: 2010-06-08 11:54:48 UTC
  • Revision ID: natalia.bidart@canonical.com-20100608115448-aqeiwm4ki1nljaw1
Built correct structure.

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
            result = self.__mocker_act__("nonzero")
 
1096
        except MatchError, e:
 
1097
            return True
 
1098
        if type(result) is Mock:
 
1099
            return True
 
1100
        return result
 
1101
 
 
1102
    def __iter__(self):
 
1103
        # XXX On py3k, when next() becomes __next__(), we'll be able
 
1104
        #     to return the mock itself because it will be considered
 
1105
        #     an iterator (we'll be mocking __next__ as well, which we
 
1106
        #     can't now).
 
1107
        result = self.__mocker_act__("iter")
 
1108
        if type(result) is Mock:
 
1109
            return iter([])
 
1110
        return result
 
1111
 
 
1112
    # When adding a new action kind here, also add support for it on
 
1113
    # Action.execute() and Path.__str__().
 
1114
 
 
1115
 
 
1116
def find_object_name(obj, depth=0):
 
1117
    """Try to detect how the object is named on a previous scope."""
 
1118
    try:
 
1119
        frame = sys._getframe(depth+1)
 
1120
    except:
 
1121
        return None
 
1122
    for name, frame_obj in frame.f_locals.iteritems():
 
1123
        if frame_obj is obj:
 
1124
            return name
 
1125
    self = frame.f_locals.get("self")
 
1126
    if self is not None:
 
1127
        try:
 
1128
            items = list(self.__dict__.iteritems())
 
1129
        except:
 
1130
            pass
 
1131
        else:
 
1132
            for name, self_obj in items:
 
1133
                if self_obj is obj:
 
1134
                    return name
 
1135
    return None
 
1136
 
 
1137
 
 
1138
# --------------------------------------------------------------------
 
1139
# Action and path.
 
1140
 
 
1141
class Action(object):
 
1142
 
 
1143
    def __init__(self, kind, args, kwargs, path=None):
 
1144
        self.kind = kind
 
1145
        self.args = args
 
1146
        self.kwargs = kwargs
 
1147
        self.path = path
 
1148
        self._execute_cache = {}
 
1149
 
 
1150
    def __repr__(self):
 
1151
        if self.path is None:
 
1152
            return "Action(%r, %r, %r)" % (self.kind, self.args, self.kwargs)
 
1153
        return "Action(%r, %r, %r, %r)" % \
 
1154
               (self.kind, self.args, self.kwargs, self.path)
 
1155
 
 
1156
    def __eq__(self, other):
 
1157
        return (self.kind == other.kind and
 
1158
                self.args == other.args and
 
1159
                self.kwargs == other.kwargs)
 
1160
 
 
1161
    def __ne__(self, other):
 
1162
        return not self.__eq__(other)
 
1163
 
 
1164
    def matches(self, other):
 
1165
        return (self.kind == other.kind and
 
1166
                match_params(self.args, self.kwargs, other.args, other.kwargs))
 
1167
 
 
1168
    def execute(self, object):
 
1169
        # This caching scheme may fail if the object gets deallocated before
 
1170
        # the action, as the id might get reused.  It's somewhat easy to fix
 
1171
        # that with a weakref callback.  For our uses, though, the object
 
1172
        # should never get deallocated before the action itself, so we'll
 
1173
        # just keep it simple.
 
1174
        if id(object) in self._execute_cache:
 
1175
            return self._execute_cache[id(object)]
 
1176
        execute = getattr(object, "__mocker_execute__", None)
 
1177
        if execute is not None:
 
1178
            result = execute(self, object)
 
1179
        else:
 
1180
            kind = self.kind
 
1181
            if kind == "getattr":
 
1182
                result = getattr(object, self.args[0])
 
1183
            elif kind == "setattr":
 
1184
                result = setattr(object, self.args[0], self.args[1])
 
1185
            elif kind == "delattr":
 
1186
                result = delattr(object, self.args[0])
 
1187
            elif kind == "call":
 
1188
                result = object(*self.args, **self.kwargs)
 
1189
            elif kind == "contains":
 
1190
                result = self.args[0] in object
 
1191
            elif kind == "getitem":
 
1192
                result = object[self.args[0]]
 
1193
            elif kind == "setitem":
 
1194
                result = object[self.args[0]] = self.args[1]
 
1195
            elif kind == "delitem":
 
1196
                del object[self.args[0]]
 
1197
                result = None
 
1198
            elif kind == "len":
 
1199
                result = len(object)
 
1200
            elif kind == "nonzero":
 
1201
                result = bool(object)
 
1202
            elif kind == "iter":
 
1203
                result = iter(object)
 
1204
            else:
 
1205
                raise RuntimeError("Don't know how to execute %r kind." % kind)
 
1206
        self._execute_cache[id(object)] = result
 
1207
        return result
 
1208
 
 
1209
 
 
1210
class Path(object):
 
1211
 
 
1212
    def __init__(self, root_mock, root_object=None, actions=()):
 
1213
        self.root_mock = root_mock
 
1214
        self.root_object = root_object
 
1215
        self.actions = tuple(actions)
 
1216
        self.__mocker_replace__ = False
 
1217
 
 
1218
    def parent_path(self):
 
1219
        if not self.actions:
 
1220
            return None
 
1221
        return self.actions[-1].path
 
1222
    parent_path = property(parent_path)
 
1223
 
 
1224
    def __add__(self, action):
 
1225
        """Return a new path which includes the given action at the end."""
 
1226
        return self.__class__(self.root_mock, self.root_object,
 
1227
                              self.actions + (action,))
 
1228
 
 
1229
    def __eq__(self, other):
 
1230
        """Verify if the two paths are equal.
 
1231
        
 
1232
        Two paths are equal if they refer to the same mock object, and
 
1233
        have the actions with equal kind, args and kwargs.
 
1234
        """
 
1235
        if (self.root_mock is not other.root_mock or
 
1236
            self.root_object is not other.root_object or
 
1237
            len(self.actions) != len(other.actions)):
 
1238
            return False
 
1239
        for action, other_action in zip(self.actions, other.actions):
 
1240
            if action != other_action:
 
1241
                return False
 
1242
        return True
 
1243
 
 
1244
    def matches(self, other):
 
1245
        """Verify if the two paths are equivalent.
 
1246
        
 
1247
        Two paths are equal if they refer to the same mock object, and
 
1248
        have the same actions performed on them.
 
1249
        """
 
1250
        if (self.root_mock is not other.root_mock or
 
1251
            len(self.actions) != len(other.actions)):
 
1252
            return False
 
1253
        for action, other_action in zip(self.actions, other.actions):
 
1254
            if not action.matches(other_action):
 
1255
                return False
 
1256
        return True
 
1257
 
 
1258
    def execute(self, object):
 
1259
        """Execute all actions sequentially on object, and return result.
 
1260
        """
 
1261
        for action in self.actions:
 
1262
            object = action.execute(object)
 
1263
        return object
 
1264
 
 
1265
    def __str__(self):
 
1266
        """Transform the path into a nice string such as obj.x.y('z')."""
 
1267
        result = self.root_mock.__mocker_name__ or "<mock>"
 
1268
        for action in self.actions:
 
1269
            if action.kind == "getattr":
 
1270
                result = "%s.%s" % (result, action.args[0])
 
1271
            elif action.kind == "setattr":
 
1272
                result = "%s.%s = %r" % (result, action.args[0], action.args[1])
 
1273
            elif action.kind == "delattr":
 
1274
                result = "del %s.%s" % (result, action.args[0])
 
1275
            elif action.kind == "call":
 
1276
                args = [repr(x) for x in action.args]
 
1277
                items = list(action.kwargs.iteritems())
 
1278
                items.sort()
 
1279
                for pair in items:
 
1280
                    args.append("%s=%r" % pair)
 
1281
                result = "%s(%s)" % (result, ", ".join(args))
 
1282
            elif action.kind == "contains":
 
1283
                result = "%r in %s" % (action.args[0], result)
 
1284
            elif action.kind == "getitem":
 
1285
                result = "%s[%r]" % (result, action.args[0])
 
1286
            elif action.kind == "setitem":
 
1287
                result = "%s[%r] = %r" % (result, action.args[0],
 
1288
                                          action.args[1])
 
1289
            elif action.kind == "delitem":
 
1290
                result = "del %s[%r]" % (result, action.args[0])
 
1291
            elif action.kind == "len":
 
1292
                result = "len(%s)" % result
 
1293
            elif action.kind == "nonzero":
 
1294
                result = "bool(%s)" % result
 
1295
            elif action.kind == "iter":
 
1296
                result = "iter(%s)" % result
 
1297
            else:
 
1298
                raise RuntimeError("Don't know how to format kind %r" %
 
1299
                                   action.kind)
 
1300
        return result
 
1301
 
 
1302
 
 
1303
class SpecialArgument(object):
 
1304
    """Base for special arguments for matching parameters."""
 
1305
 
 
1306
    def __init__(self, object=None):
 
1307
        self.object = object
 
1308
 
 
1309
    def __repr__(self):
 
1310
        if self.object is None:
 
1311
            return self.__class__.__name__
 
1312
        else:
 
1313
            return "%s(%r)" % (self.__class__.__name__, self.object)
 
1314
 
 
1315
    def matches(self, other):
 
1316
        return True
 
1317
 
 
1318
    def __eq__(self, other):
 
1319
        return type(other) == type(self) and self.object == other.object
 
1320
 
 
1321
 
 
1322
class ANY(SpecialArgument):
 
1323
    """Matches any single argument."""
 
1324
 
 
1325
ANY = ANY()
 
1326
 
 
1327
 
 
1328
class ARGS(SpecialArgument):
 
1329
    """Matches zero or more positional arguments."""
 
1330
 
 
1331
ARGS = ARGS()
 
1332
 
 
1333
 
 
1334
class KWARGS(SpecialArgument):
 
1335
    """Matches zero or more keyword arguments."""
 
1336
 
 
1337
KWARGS = KWARGS()
 
1338
 
 
1339
 
 
1340
class IS(SpecialArgument):
 
1341
 
 
1342
    def matches(self, other):
 
1343
        return self.object is other
 
1344
 
 
1345
    def __eq__(self, other):
 
1346
        return type(other) == type(self) and self.object is other.object
 
1347
 
 
1348
 
 
1349
class CONTAINS(SpecialArgument):
 
1350
 
 
1351
    def matches(self, other):
 
1352
        try:
 
1353
            other.__contains__
 
1354
        except AttributeError:
 
1355
            try:
 
1356
                iter(other)
 
1357
            except TypeError:
 
1358
                # If an object can't be iterated, and has no __contains__
 
1359
                # hook, it'd blow up on the test below.  We test this in
 
1360
                # advance to prevent catching more errors than we really
 
1361
                # want.
 
1362
                return False
 
1363
        return self.object in other
 
1364
 
 
1365
 
 
1366
class IN(SpecialArgument):
 
1367
 
 
1368
    def matches(self, other):
 
1369
        return other in self.object
 
1370
 
 
1371
 
 
1372
class MATCH(SpecialArgument):
 
1373
 
 
1374
    def matches(self, other):
 
1375
        return bool(self.object(other))
 
1376
 
 
1377
    def __eq__(self, other):
 
1378
        return type(other) == type(self) and self.object is other.object
 
1379
 
 
1380
 
 
1381
def match_params(args1, kwargs1, args2, kwargs2):
 
1382
    """Match the two sets of parameters, considering special parameters."""
 
1383
 
 
1384
    has_args = ARGS in args1
 
1385
    has_kwargs = KWARGS in args1
 
1386
 
 
1387
    if has_kwargs:
 
1388
        args1 = [arg1 for arg1 in args1 if arg1 is not KWARGS]
 
1389
    elif len(kwargs1) != len(kwargs2):
 
1390
        return False
 
1391
 
 
1392
    if not has_args and len(args1) != len(args2):
 
1393
        return False
 
1394
 
 
1395
    # Either we have the same number of kwargs, or unknown keywords are
 
1396
    # accepted (KWARGS was used), so check just the ones in kwargs1.
 
1397
    for key, arg1 in kwargs1.iteritems():
 
1398
        if key not in kwargs2:
 
1399
            return False
 
1400
        arg2 = kwargs2[key]
 
1401
        if isinstance(arg1, SpecialArgument):
 
1402
            if not arg1.matches(arg2):
 
1403
                return False
 
1404
        elif arg1 != arg2:
 
1405
            return False
 
1406
 
 
1407
    # Keywords match.  Now either we have the same number of
 
1408
    # arguments, or ARGS was used.  If ARGS wasn't used, arguments
 
1409
    # must match one-on-one necessarily.
 
1410
    if not has_args:
 
1411
        for arg1, arg2 in zip(args1, args2):
 
1412
            if isinstance(arg1, SpecialArgument):
 
1413
                if not arg1.matches(arg2):
 
1414
                    return False
 
1415
            elif arg1 != arg2:
 
1416
                return False
 
1417
        return True
 
1418
 
 
1419
    # Easy choice. Keywords are matching, and anything on args is accepted.
 
1420
    if (ARGS,) == args1:
 
1421
        return True
 
1422
 
 
1423
    # We have something different there. If we don't have positional
 
1424
    # arguments on the original call, it can't match.
 
1425
    if not args2:
 
1426
        # Unless we have just several ARGS (which is bizarre, but..).
 
1427
        for arg1 in args1:
 
1428
            if arg1 is not ARGS:
 
1429
                return False
 
1430
        return True
 
1431
 
 
1432
    # Ok, all bets are lost.  We have to actually do the more expensive
 
1433
    # matching.  This is an algorithm based on the idea of the Levenshtein
 
1434
    # Distance between two strings, but heavily hacked for this purpose.
 
1435
    args2l = len(args2)
 
1436
    if args1[0] is ARGS:
 
1437
        args1 = args1[1:]
 
1438
        array = [0]*args2l
 
1439
    else:
 
1440
        array = [1]*args2l
 
1441
    for i in range(len(args1)):
 
1442
        last = array[0]
 
1443
        if args1[i] is ARGS:
 
1444
            for j in range(1, args2l):
 
1445
                last, array[j] = array[j], min(array[j-1], array[j], last)
 
1446
        else:
 
1447
            array[0] = i or int(args1[i] != args2[0])
 
1448
            for j in range(1, args2l):
 
1449
                last, array[j] = array[j], last or int(args1[i] != args2[j])
 
1450
        if 0 not in array:
 
1451
            return False
 
1452
    if array[-1] != 0:
 
1453
        return False
 
1454
    return True
 
1455
 
 
1456
 
 
1457
# --------------------------------------------------------------------
 
1458
# Event and task base.
 
1459
 
 
1460
class Event(object):
 
1461
    """Aggregation of tasks that keep track of a recorded action.
 
1462
 
 
1463
    An event represents something that may or may not happen while the
 
1464
    mocked environment is running, such as an attribute access, or a
 
1465
    method call.  The event is composed of several tasks that are
 
1466
    orchestrated together to create a composed meaning for the event,
 
1467
    including for which actions it should be run, what happens when it
 
1468
    runs, and what's the expectations about the actions run.
 
1469
    """
 
1470
 
 
1471
    def __init__(self, path=None):
 
1472
        self.path = path
 
1473
        self._tasks = []
 
1474
        self._has_run = False
 
1475
 
 
1476
    def add_task(self, task):
 
1477
        """Add a new task to this taks."""
 
1478
        self._tasks.append(task)
 
1479
        return task
 
1480
 
 
1481
    def remove_task(self, task):
 
1482
        self._tasks.remove(task)
 
1483
 
 
1484
    def get_tasks(self):
 
1485
        return self._tasks[:]
 
1486
 
 
1487
    def matches(self, path):
 
1488
        """Return true if *all* tasks match the given path."""
 
1489
        for task in self._tasks:
 
1490
            if not task.matches(path):
 
1491
                return False
 
1492
        return bool(self._tasks)
 
1493
 
 
1494
    def has_run(self):
 
1495
        return self._has_run
 
1496
 
 
1497
    def may_run(self, path):
 
1498
        """Verify if any task would certainly raise an error if run.
 
1499
 
 
1500
        This will call the C{may_run()} method on each task and return
 
1501
        false if any of them returns false.
 
1502
        """
 
1503
        for task in self._tasks:
 
1504
            if not task.may_run(path):
 
1505
                return False
 
1506
        return True
 
1507
 
 
1508
    def run(self, path):
 
1509
        """Run all tasks with the given action.
 
1510
 
 
1511
        @param path: The path of the expression run.
 
1512
 
 
1513
        Running an event means running all of its tasks individually and in
 
1514
        order.  An event should only ever be run if all of its tasks claim to
 
1515
        match the given action.
 
1516
 
 
1517
        The result of this method will be the last result of a task
 
1518
        which isn't None, or None if they're all None.
 
1519
        """
 
1520
        self._has_run = True
 
1521
        result = None
 
1522
        errors = []
 
1523
        for task in self._tasks:
 
1524
            try:
 
1525
                task_result = task.run(path)
 
1526
            except AssertionError, e:
 
1527
                error = str(e)
 
1528
                if not error:
 
1529
                    raise RuntimeError("Empty error message from %r" % task)
 
1530
                errors.append(error)
 
1531
            else:
 
1532
                if task_result is not None:
 
1533
                    result = task_result
 
1534
        if errors:
 
1535
            message = [str(self.path)]
 
1536
            if str(path) != message[0]:
 
1537
                message.append("- Run: %s" % path)
 
1538
            for error in errors:
 
1539
                lines = error.splitlines()
 
1540
                message.append("- " + lines.pop(0))
 
1541
                message.extend(["  " + line for line in lines])
 
1542
            raise AssertionError(os.linesep.join(message))
 
1543
        return result
 
1544
 
 
1545
    def satisfied(self):
 
1546
        """Return true if all tasks are satisfied.
 
1547
 
 
1548
        Being satisfied means that there are no unmet expectations.
 
1549
        """
 
1550
        for task in self._tasks:
 
1551
            try:
 
1552
                task.verify()
 
1553
            except AssertionError:
 
1554
                return False
 
1555
        return True
 
1556
 
 
1557
    def verify(self):
 
1558
        """Run verify on all tasks.
 
1559
 
 
1560
        The verify method is supposed to raise an AssertionError if the
 
1561
        task has unmet expectations, with a one-line explanation about
 
1562
        why this item is unmet.  This method should be safe to be called
 
1563
        multiple times without side effects.
 
1564
        """
 
1565
        errors = []
 
1566
        for task in self._tasks:
 
1567
            try:
 
1568
                task.verify()
 
1569
            except AssertionError, e:
 
1570
                error = str(e)
 
1571
                if not error:
 
1572
                    raise RuntimeError("Empty error message from %r" % task)
 
1573
                errors.append(error)
 
1574
        if errors:
 
1575
            message = [str(self.path)]
 
1576
            for error in errors:
 
1577
                lines = error.splitlines()
 
1578
                message.append("- " + lines.pop(0))
 
1579
                message.extend(["  " + line for line in lines])
 
1580
            raise AssertionError(os.linesep.join(message))
 
1581
 
 
1582
    def replay(self):
 
1583
        """Put all tasks in replay mode."""
 
1584
        self._has_run = False
 
1585
        for task in self._tasks:
 
1586
            task.replay()
 
1587
 
 
1588
    def restore(self):
 
1589
        """Restore the state of all tasks."""
 
1590
        for task in self._tasks:
 
1591
            task.restore()
 
1592
 
 
1593
 
 
1594
class ReplayRestoreEvent(Event):
 
1595
    """Helper event for tasks which need replay/restore but shouldn't match."""
 
1596
 
 
1597
    def matches(self, path):
 
1598
        return False
 
1599
 
 
1600
 
 
1601
class Task(object):
 
1602
    """Element used to track one specific aspect on an event.
 
1603
 
 
1604
    A task is responsible for adding any kind of logic to an event.
 
1605
    Examples of that are counting the number of times the event was
 
1606
    made, verifying parameters if any, and so on.
 
1607
    """
 
1608
 
 
1609
    def matches(self, path):
 
1610
        """Return true if the task is supposed to be run for the given path.
 
1611
        """
 
1612
        return True
 
1613
 
 
1614
    def may_run(self, path):
 
1615
        """Return false if running this task would certainly raise an error."""
 
1616
        return True
 
1617
 
 
1618
    def run(self, path):
 
1619
        """Perform the task item, considering that the given action happened.
 
1620
        """
 
1621
 
 
1622
    def verify(self):
 
1623
        """Raise AssertionError if expectations for this item are unmet.
 
1624
 
 
1625
        The verify method is supposed to raise an AssertionError if the
 
1626
        task has unmet expectations, with a one-line explanation about
 
1627
        why this item is unmet.  This method should be safe to be called
 
1628
        multiple times without side effects.
 
1629
        """
 
1630
 
 
1631
    def replay(self):
 
1632
        """Put the task in replay mode.
 
1633
 
 
1634
        Any expectations of the task should be reset.
 
1635
        """
 
1636
 
 
1637
    def restore(self):
 
1638
        """Restore any environmental changes made by the task.
 
1639
 
 
1640
        Verify should continue to work after this is called.
 
1641
        """
 
1642
 
 
1643
 
 
1644
# --------------------------------------------------------------------
 
1645
# Task implementations.
 
1646
 
 
1647
class OnRestoreCaller(Task):
 
1648
    """Call a given callback when restoring."""
 
1649
 
 
1650
    def __init__(self, callback):
 
1651
        self._callback = callback
 
1652
 
 
1653
    def restore(self):
 
1654
        self._callback()
 
1655
 
 
1656
 
 
1657
class PathMatcher(Task):
 
1658
    """Match the action path against a given path."""
 
1659
 
 
1660
    def __init__(self, path):
 
1661
        self.path = path
 
1662
 
 
1663
    def matches(self, path):
 
1664
        return self.path.matches(path)
 
1665
 
 
1666
def path_matcher_recorder(mocker, event):
 
1667
    event.add_task(PathMatcher(event.path))
 
1668
 
 
1669
Mocker.add_recorder(path_matcher_recorder)
 
1670
 
 
1671
 
 
1672
class RunCounter(Task):
 
1673
    """Task which verifies if the number of runs are within given boundaries.
 
1674
    """
 
1675
 
 
1676
    def __init__(self, min, max=False):
 
1677
        self.min = min
 
1678
        if max is None:
 
1679
            self.max = sys.maxint
 
1680
        elif max is False:
 
1681
            self.max = min
 
1682
        else:
 
1683
            self.max = max
 
1684
        self._runs = 0
 
1685
 
 
1686
    def replay(self):
 
1687
        self._runs = 0
 
1688
 
 
1689
    def may_run(self, path):
 
1690
        return self._runs < self.max
 
1691
 
 
1692
    def run(self, path):
 
1693
        self._runs += 1
 
1694
        if self._runs > self.max:
 
1695
            self.verify()
 
1696
 
 
1697
    def verify(self):
 
1698
        if not self.min <= self._runs <= self.max:
 
1699
            if self._runs < self.min:
 
1700
                raise AssertionError("Performed fewer times than expected.")
 
1701
            raise AssertionError("Performed more times than expected.")
 
1702
 
 
1703
 
 
1704
class ImplicitRunCounter(RunCounter):
 
1705
    """RunCounter inserted by default on any event.
 
1706
 
 
1707
    This is a way to differentiate explicitly added counters and
 
1708
    implicit ones.
 
1709
    """
 
1710
 
 
1711
def run_counter_recorder(mocker, event):
 
1712
    """Any event may be repeated once, unless disabled by default."""
 
1713
    if event.path.root_mock.__mocker_count__:
 
1714
        event.add_task(ImplicitRunCounter(1))
 
1715
 
 
1716
Mocker.add_recorder(run_counter_recorder)
 
1717
 
 
1718
def run_counter_removal_recorder(mocker, event):
 
1719
    """
 
1720
    Events created by getattr actions which lead to other events
 
1721
    may be repeated any number of times. For that, we remove implicit
 
1722
    run counters of any getattr actions leading to the current one.
 
1723
    """
 
1724
    parent_path = event.path.parent_path
 
1725
    for event in mocker.get_events()[::-1]:
 
1726
        if (event.path is parent_path and
 
1727
            event.path.actions[-1].kind == "getattr"):
 
1728
            for task in event.get_tasks():
 
1729
                if type(task) is ImplicitRunCounter:
 
1730
                    event.remove_task(task)
 
1731
 
 
1732
Mocker.add_recorder(run_counter_removal_recorder)
 
1733
 
 
1734
 
 
1735
class MockReturner(Task):
 
1736
    """Return a mock based on the action path."""
 
1737
 
 
1738
    def __init__(self, mocker):
 
1739
        self.mocker = mocker
 
1740
 
 
1741
    def run(self, path):
 
1742
        return Mock(self.mocker, path)
 
1743
 
 
1744
def mock_returner_recorder(mocker, event):
 
1745
    """Events that lead to other events must return mock objects."""
 
1746
    parent_path = event.path.parent_path
 
1747
    for event in mocker.get_events():
 
1748
        if event.path is parent_path:
 
1749
            for task in event.get_tasks():
 
1750
                if isinstance(task, MockReturner):
 
1751
                    break
 
1752
            else:
 
1753
                event.add_task(MockReturner(mocker))
 
1754
            break
 
1755
 
 
1756
Mocker.add_recorder(mock_returner_recorder)
 
1757
 
 
1758
 
 
1759
class FunctionRunner(Task):
 
1760
    """Task that runs a function everything it's run.
 
1761
 
 
1762
    Arguments of the last action in the path are passed to the function,
 
1763
    and the function result is also returned.
 
1764
    """
 
1765
 
 
1766
    def __init__(self, func):
 
1767
        self._func = func
 
1768
 
 
1769
    def run(self, path):
 
1770
        action = path.actions[-1]
 
1771
        return self._func(*action.args, **action.kwargs)
 
1772
 
 
1773
 
 
1774
class PathExecuter(Task):
 
1775
    """Task that executes a path in the real object, and returns the result."""
 
1776
 
 
1777
    def __init__(self, result_callback=None):
 
1778
        self._result_callback = result_callback
 
1779
 
 
1780
    def get_result_callback(self):
 
1781
        return self._result_callback
 
1782
 
 
1783
    def run(self, path):
 
1784
        result = path.execute(path.root_object)
 
1785
        if self._result_callback is not None:
 
1786
            self._result_callback(result)
 
1787
        return result
 
1788
 
 
1789
 
 
1790
class Orderer(Task):
 
1791
    """Task to establish an order relation between two events.
 
1792
 
 
1793
    An orderer task will only match once all its dependencies have
 
1794
    been run.
 
1795
    """
 
1796
 
 
1797
    def __init__(self, path):
 
1798
        self.path = path
 
1799
        self._run = False 
 
1800
        self._dependencies = []
 
1801
 
 
1802
    def replay(self):
 
1803
        self._run = False
 
1804
 
 
1805
    def has_run(self):
 
1806
        return self._run
 
1807
 
 
1808
    def may_run(self, path):
 
1809
        for dependency in self._dependencies:
 
1810
            if not dependency.has_run():
 
1811
                return False
 
1812
        return True
 
1813
 
 
1814
    def run(self, path):
 
1815
        for dependency in self._dependencies:
 
1816
            if not dependency.has_run():
 
1817
                raise AssertionError("Should be after: %s" % dependency.path)
 
1818
        self._run = True
 
1819
 
 
1820
    def add_dependency(self, orderer):
 
1821
        self._dependencies.append(orderer)
 
1822
 
 
1823
    def get_dependencies(self):
 
1824
        return self._dependencies
 
1825
 
 
1826
 
 
1827
class SpecChecker(Task):
 
1828
    """Task to check if arguments of the last action conform to a real method.
 
1829
    """
 
1830
 
 
1831
    def __init__(self, method):
 
1832
        self._method = method
 
1833
        self._unsupported = False
 
1834
 
 
1835
        if method:
 
1836
            try:
 
1837
                self._args, self._varargs, self._varkwargs, self._defaults = \
 
1838
                    inspect.getargspec(method)
 
1839
            except TypeError:
 
1840
                self._unsupported = True
 
1841
            else:
 
1842
                if self._defaults is None:
 
1843
                    self._defaults = ()
 
1844
                if type(method) is type(self.run):
 
1845
                    self._args = self._args[1:]
 
1846
 
 
1847
    def get_method(self):
 
1848
        return self._method
 
1849
 
 
1850
    def _raise(self, message):
 
1851
        spec = inspect.formatargspec(self._args, self._varargs,
 
1852
                                     self._varkwargs, self._defaults)
 
1853
        raise AssertionError("Specification is %s%s: %s" %
 
1854
                             (self._method.__name__, spec, message))
 
1855
 
 
1856
    def verify(self):
 
1857
        if not self._method:
 
1858
            raise AssertionError("Method not found in real specification")
 
1859
 
 
1860
    def may_run(self, path):
 
1861
        try:
 
1862
            self.run(path)
 
1863
        except AssertionError:
 
1864
            return False
 
1865
        return True
 
1866
 
 
1867
    def run(self, path):
 
1868
        if not self._method:
 
1869
            raise AssertionError("Method not found in real specification")
 
1870
        if self._unsupported:
 
1871
            return # Can't check it. Happens with builtin functions. :-(
 
1872
        action = path.actions[-1]
 
1873
        obtained_len = len(action.args)
 
1874
        obtained_kwargs = action.kwargs.copy()
 
1875
        nodefaults_len = len(self._args) - len(self._defaults)
 
1876
        for i, name in enumerate(self._args):
 
1877
            if i < obtained_len and name in action.kwargs:
 
1878
                self._raise("%r provided twice" % name)
 
1879
            if (i >= obtained_len and i < nodefaults_len and
 
1880
                name not in action.kwargs):
 
1881
                self._raise("%r not provided" % name)
 
1882
            obtained_kwargs.pop(name, None)
 
1883
        if obtained_len > len(self._args) and not self._varargs:
 
1884
            self._raise("too many args provided")
 
1885
        if obtained_kwargs and not self._varkwargs:
 
1886
            self._raise("unknown kwargs: %s" % ", ".join(obtained_kwargs))
 
1887
 
 
1888
def spec_checker_recorder(mocker, event):
 
1889
    spec = event.path.root_mock.__mocker_spec__
 
1890
    if spec:
 
1891
        actions = event.path.actions
 
1892
        if len(actions) == 1:
 
1893
            if actions[0].kind == "call":
 
1894
                method = getattr(spec, "__call__", None)
 
1895
                event.add_task(SpecChecker(method))
 
1896
        elif len(actions) == 2:
 
1897
            if actions[0].kind == "getattr" and actions[1].kind == "call":
 
1898
                method = getattr(spec, actions[0].args[0], None)
 
1899
                event.add_task(SpecChecker(method))
 
1900
 
 
1901
Mocker.add_recorder(spec_checker_recorder)
 
1902
 
 
1903
 
 
1904
class ProxyReplacer(Task):
 
1905
    """Task which installs and deinstalls proxy mocks.
 
1906
 
 
1907
    This task will replace a real object by a mock in all dictionaries
 
1908
    found in the running interpreter via the garbage collecting system.
 
1909
    """
 
1910
 
 
1911
    def __init__(self, mock):
 
1912
        self.mock = mock
 
1913
        self.__mocker_replace__ = False
 
1914
 
 
1915
    def replay(self):
 
1916
        global_replace(self.mock.__mocker_object__, self.mock)
 
1917
 
 
1918
    def restore(self):
 
1919
        global_replace(self.mock, self.mock.__mocker_object__)
 
1920
 
 
1921
 
 
1922
def global_replace(remove, install):
 
1923
    """Replace object 'remove' with object 'install' on all dictionaries."""
 
1924
    for referrer in gc.get_referrers(remove):
 
1925
        if (type(referrer) is dict and
 
1926
            referrer.get("__mocker_replace__", True)):
 
1927
            for key, value in list(referrer.iteritems()):
 
1928
                if value is remove:
 
1929
                    referrer[key] = install
 
1930
 
 
1931
 
 
1932
class Undefined(object):
 
1933
 
 
1934
    def __repr__(self):
 
1935
        return "Undefined"
 
1936
 
 
1937
Undefined = Undefined()
 
1938
 
 
1939
 
 
1940
class Patcher(Task):
 
1941
 
 
1942
    def __init__(self):
 
1943
        super(Patcher, self).__init__()
 
1944
        self._monitored = {} # {kind: {id(object): object}}
 
1945
        self._patched = {}
 
1946
 
 
1947
    def is_monitoring(self, obj, kind):
 
1948
        monitored = self._monitored.get(kind)
 
1949
        if monitored:
 
1950
            if id(obj) in monitored:
 
1951
                return True
 
1952
            cls = type(obj)
 
1953
            if issubclass(cls, type):
 
1954
                cls = obj
 
1955
            bases = set([id(base) for base in cls.__mro__])
 
1956
            bases.intersection_update(monitored)
 
1957
            return bool(bases)
 
1958
        return False
 
1959
 
 
1960
    def monitor(self, obj, kind):
 
1961
        if kind not in self._monitored:
 
1962
            self._monitored[kind] = {}
 
1963
        self._monitored[kind][id(obj)] = obj
 
1964
 
 
1965
    def patch_attr(self, obj, attr, value):
 
1966
        original = obj.__dict__.get(attr, Undefined)
 
1967
        self._patched[id(obj), attr] = obj, attr, original
 
1968
        setattr(obj, attr, value)
 
1969
 
 
1970
    def get_unpatched_attr(self, obj, attr):
 
1971
        cls = type(obj)
 
1972
        if issubclass(cls, type):
 
1973
            cls = obj
 
1974
        result = Undefined
 
1975
        for mro_cls in cls.__mro__:
 
1976
            key = (id(mro_cls), attr)
 
1977
            if key in self._patched:
 
1978
                result = self._patched[key][2]
 
1979
                if result is not Undefined:
 
1980
                    break
 
1981
            elif attr in mro_cls.__dict__:
 
1982
                result = mro_cls.__dict__.get(attr, Undefined)
 
1983
                break
 
1984
        if isinstance(result, object) and hasattr(type(result), "__get__"):
 
1985
            if cls is obj:
 
1986
                obj = None
 
1987
            return result.__get__(obj, cls)
 
1988
        return result
 
1989
 
 
1990
    def _get_kind_attr(self, kind):
 
1991
        if kind == "getattr":
 
1992
            return "__getattribute__"
 
1993
        return "__%s__" % kind
 
1994
 
 
1995
    def replay(self):
 
1996
        for kind in self._monitored:
 
1997
            attr = self._get_kind_attr(kind)
 
1998
            seen = set()
 
1999
            for obj in self._monitored[kind].itervalues():
 
2000
                cls = type(obj)
 
2001
                if issubclass(cls, type):
 
2002
                    cls = obj
 
2003
                if cls not in seen:
 
2004
                    seen.add(cls)
 
2005
                    unpatched = getattr(cls, attr, Undefined)
 
2006
                    self.patch_attr(cls, attr,
 
2007
                                    PatchedMethod(kind, unpatched,
 
2008
                                                  self.is_monitoring))
 
2009
                    self.patch_attr(cls, "__mocker_execute__",
 
2010
                                    self.execute)
 
2011
 
 
2012
    def restore(self):
 
2013
        for obj, attr, original in self._patched.itervalues():
 
2014
            if original is Undefined:
 
2015
                delattr(obj, attr)
 
2016
            else:
 
2017
                setattr(obj, attr, original)
 
2018
        self._patched.clear()
 
2019
 
 
2020
    def execute(self, action, object):
 
2021
        attr = self._get_kind_attr(action.kind)
 
2022
        unpatched = self.get_unpatched_attr(object, attr)
 
2023
        try:
 
2024
            return unpatched(*action.args, **action.kwargs)
 
2025
        except AttributeError:
 
2026
            type, value, traceback = sys.exc_info()
 
2027
            if action.kind == "getattr":
 
2028
                # The normal behavior of Python is to try __getattribute__,
 
2029
                # and if it raises AttributeError, try __getattr__.   We've
 
2030
                # tried the unpatched __getattribute__ above, and we'll now
 
2031
                # try __getattr__.
 
2032
                try:
 
2033
                    __getattr__ = unpatched("__getattr__")
 
2034
                except AttributeError:
 
2035
                    pass
 
2036
                else:
 
2037
                    return __getattr__(*action.args, **action.kwargs)
 
2038
            raise type, value, traceback
 
2039
 
 
2040
 
 
2041
class PatchedMethod(object):
 
2042
 
 
2043
    def __init__(self, kind, unpatched, is_monitoring):
 
2044
        self._kind = kind
 
2045
        self._unpatched = unpatched
 
2046
        self._is_monitoring = is_monitoring
 
2047
 
 
2048
    def __get__(self, obj, cls=None):
 
2049
        object = obj or cls
 
2050
        if not self._is_monitoring(object, self._kind):
 
2051
            return self._unpatched.__get__(obj, cls)
 
2052
        def method(*args, **kwargs):
 
2053
            if self._kind == "getattr" and args[0].startswith("__mocker_"):
 
2054
                return self._unpatched.__get__(obj, cls)(args[0])
 
2055
            mock = object.__mocker_mock__
 
2056
            return mock.__mocker_act__(self._kind, args, kwargs, object)
 
2057
        return method
 
2058
 
 
2059
    def __call__(self, obj, *args, **kwargs):
 
2060
        # At least with __getattribute__, Python seems to use *both* the
 
2061
        # descriptor API and also call the class attribute directly.  It
 
2062
        # looks like an interpreter bug, or at least an undocumented
 
2063
        # inconsistency.
 
2064
        return self.__get__(obj)(*args, **kwargs)
 
2065
 
 
2066
 
 
2067
def patcher_recorder(mocker, event):
 
2068
    mock = event.path.root_mock
 
2069
    if mock.__mocker_patcher__ and len(event.path.actions) == 1:
 
2070
        patcher = mock.__mocker_patcher__
 
2071
        patcher.monitor(mock.__mocker_object__, event.path.actions[0].kind)
 
2072
 
 
2073
Mocker.add_recorder(patcher_recorder)