~juju/ubuntu/quantal/juju/0.6

« back to all changes in this revision

Viewing changes to juju/lib/mocker.py

  • Committer: Package Import Robot
  • Author(s): Clint Byrum
  • Date: 2011-09-28 09:42:32 UTC
  • Revision ID: package-import@ubuntu.com-20110928094232-o1yozyv3nw3ejymz
Tags: upstream-0.5+bzr361
ImportĀ upstreamĀ versionĀ 0.5+bzr361

Show diffs side-by-side

added added

removed removed

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