OLD | NEW |
| (Empty) |
1 # Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 # Use of this source code is governed by a BSD-style license that can be | |
3 # found in the LICENSE file. | |
4 | |
5 """Manages stubs in an simple and efficient way. | |
6 | |
7 Original source: | |
8 https://chromium.googlesource.com/chromium/tools/depot_tools.git/ \ | |
9 +/master/testing_support/auto_stub.py | |
10 """ | |
11 | |
12 import inspect | |
13 import unittest | |
14 | |
15 | |
16 class OrderedDict(object): | |
17 """Incomplete and inefficient implementation of collections.OrderedDict.""" | |
18 def __init__(self): | |
19 self._keys = [] | |
20 | |
21 def setdefault(self, key, value): | |
22 try: | |
23 self._getindex(key) | |
24 except KeyError: | |
25 self._keys.append((key, value)) | |
26 return self[key] | |
27 | |
28 def _getindex(self, key): | |
29 for i, v in enumerate(self._keys): | |
30 if v[0] == key: | |
31 return i | |
32 raise KeyError(key) | |
33 | |
34 def __getitem__(self, key): | |
35 return self._keys[self._getindex(key)][1] | |
36 | |
37 def iteritems(self): | |
38 for i in self._keys: | |
39 yield i | |
40 | |
41 | |
42 class AutoStubMixIn(object): | |
43 """Automatically restores stubbed functions on unit test teardDown. | |
44 | |
45 It's an extremely lightweight mocking class that doesn't require bookeeping. | |
46 """ | |
47 _saved = None | |
48 | |
49 def mock(self, obj, member, mock): | |
50 self._saved = self._saved or OrderedDict() | |
51 old_value = self._saved.setdefault( | |
52 obj, OrderedDict()).setdefault(member, getattr(obj, member)) | |
53 setattr(obj, member, mock) | |
54 return old_value | |
55 | |
56 def tearDown(self): | |
57 """Restore all the mocked members.""" | |
58 if self._saved: | |
59 for obj, items in self._saved.iteritems(): | |
60 for member, previous_value in items.iteritems(): | |
61 setattr(obj, member, previous_value) | |
62 | |
63 | |
64 class SimpleMock(object): | |
65 """Really simple manual class mock.""" | |
66 def __init__(self, unit_test): | |
67 """Do not call __init__ if you want to use the global call list to detect | |
68 ordering across different instances. | |
69 """ | |
70 self.calls = [] | |
71 self.unit_test = unit_test | |
72 self.assertEqual = unit_test.assertEqual | |
73 | |
74 def pop_calls(self): | |
75 """Returns the list of calls up to date. | |
76 | |
77 Good to do self.assertEqual(expected, mock.pop_calls()). | |
78 """ | |
79 calls = self.calls | |
80 self.calls = [] | |
81 return calls | |
82 | |
83 def check_calls(self, expected): | |
84 self.assertEqual(expected, self.pop_calls()) | |
85 | |
86 def _register_call(self, *args, **kwargs): | |
87 """Registers the name of the caller function.""" | |
88 caller_name = kwargs.pop('caller_name', None) or inspect.stack()[1][3] | |
89 str_args = ', '.join(repr(arg) for arg in args) | |
90 str_kwargs = ', '.join('%s=%r' % (k, v) for k, v in kwargs.iteritems()) | |
91 self.calls.append('%s(%s)' % ( | |
92 caller_name, ', '.join(filter(None, [str_args, str_kwargs])))) | |
93 | |
94 | |
95 class TestCase(unittest.TestCase, AutoStubMixIn): | |
96 """Adds python 2.7 functionality.""" | |
97 | |
98 def tearDown(self): | |
99 AutoStubMixIn.tearDown(self) | |
100 unittest.TestCase.tearDown(self) | |
101 | |
102 def has_failed(self): | |
103 """Returns True if the test has failed.""" | |
104 if hasattr(self, '_exc_info'): | |
105 # Only present in python <= 2.6 | |
106 # pylint: disable=E1101 | |
107 return bool(self._exc_info()[0]) | |
108 | |
109 # Only present in python >= 2.7 | |
110 # pylint: disable=E1101 | |
111 return not self._resultForDoCleanups.wasSuccessful() | |
112 | |
113 def assertIs(self, expr1, expr2, msg=None): | |
114 if hasattr(super(TestCase, self), 'assertIs'): | |
115 return super(TestCase, self).assertIs(expr1, expr2, msg) | |
116 if expr1 is not expr2: | |
117 self.fail(msg or '%r is not %r' % (expr1, expr2)) | |
118 | |
119 def assertIsNot(self, expr1, expr2, msg=None): | |
120 if hasattr(super(TestCase, self), 'assertIsNot'): | |
121 return super(TestCase, self).assertIsNot(expr1, expr2, msg) | |
122 if expr1 is expr2: | |
123 self.fail(msg or 'unexpectedly identical: %r' % expr1) | |
124 | |
125 def assertIn(self, expr1, expr2, msg=None): | |
126 if hasattr(super(TestCase, self), 'assertIn'): | |
127 return super(TestCase, self).assertIn(expr1, expr2, msg) | |
128 if expr1 not in expr2: | |
129 self.fail(msg or '%r not in %r' % (expr1, expr2)) | |
130 | |
131 def assertLess(self, a, b, msg=None): | |
132 if hasattr(super(TestCase, self), 'assertLess'): | |
133 return super(TestCase, self).assertLess(a, b, msg) | |
134 if not a < b: | |
135 self.fail(msg or '%r not less than %r' % (a, b)) | |
OLD | NEW |