xref: /aosp_15_r20/external/protobuf/python/mox.py (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker#!/usr/bin/python2.4
2*1b3f573fSAndroid Build Coastguard Worker#
3*1b3f573fSAndroid Build Coastguard Worker# Copyright 2008 Google Inc.
4*1b3f573fSAndroid Build Coastguard Worker#
5*1b3f573fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
6*1b3f573fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
7*1b3f573fSAndroid Build Coastguard Worker# You may obtain a copy of the License at
8*1b3f573fSAndroid Build Coastguard Worker#
9*1b3f573fSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
10*1b3f573fSAndroid Build Coastguard Worker#
11*1b3f573fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
12*1b3f573fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
13*1b3f573fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*1b3f573fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
15*1b3f573fSAndroid Build Coastguard Worker# limitations under the License.
16*1b3f573fSAndroid Build Coastguard Worker
17*1b3f573fSAndroid Build Coastguard Worker# This file is used for testing.  The original is at:
18*1b3f573fSAndroid Build Coastguard Worker#   http://code.google.com/p/pymox/
19*1b3f573fSAndroid Build Coastguard Worker
20*1b3f573fSAndroid Build Coastguard Worker"""Mox, an object-mocking framework for Python.
21*1b3f573fSAndroid Build Coastguard Worker
22*1b3f573fSAndroid Build Coastguard WorkerMox works in the record-replay-verify paradigm.  When you first create
23*1b3f573fSAndroid Build Coastguard Workera mock object, it is in record mode.  You then programmatically set
24*1b3f573fSAndroid Build Coastguard Workerthe expected behavior of the mock object (what methods are to be
25*1b3f573fSAndroid Build Coastguard Workercalled on it, with what parameters, what they should return, and in
26*1b3f573fSAndroid Build Coastguard Workerwhat order).
27*1b3f573fSAndroid Build Coastguard Worker
28*1b3f573fSAndroid Build Coastguard WorkerOnce you have set up the expected mock behavior, you put it in replay
29*1b3f573fSAndroid Build Coastguard Workermode.  Now the mock responds to method calls just as you told it to.
30*1b3f573fSAndroid Build Coastguard WorkerIf an unexpected method (or an expected method with unexpected
31*1b3f573fSAndroid Build Coastguard Workerparameters) is called, then an exception will be raised.
32*1b3f573fSAndroid Build Coastguard Worker
33*1b3f573fSAndroid Build Coastguard WorkerOnce you are done interacting with the mock, you need to verify that
34*1b3f573fSAndroid Build Coastguard Workerall the expected interactions occurred.  (Maybe your code exited
35*1b3f573fSAndroid Build Coastguard Workerprematurely without calling some cleanup method!)  The verify phase
36*1b3f573fSAndroid Build Coastguard Workerensures that every expected method was called; otherwise, an exception
37*1b3f573fSAndroid Build Coastguard Workerwill be raised.
38*1b3f573fSAndroid Build Coastguard Worker
39*1b3f573fSAndroid Build Coastguard WorkerSuggested usage / workflow:
40*1b3f573fSAndroid Build Coastguard Worker
41*1b3f573fSAndroid Build Coastguard Worker  # Create Mox factory
42*1b3f573fSAndroid Build Coastguard Worker  my_mox = Mox()
43*1b3f573fSAndroid Build Coastguard Worker
44*1b3f573fSAndroid Build Coastguard Worker  # Create a mock data access object
45*1b3f573fSAndroid Build Coastguard Worker  mock_dao = my_mox.CreateMock(DAOClass)
46*1b3f573fSAndroid Build Coastguard Worker
47*1b3f573fSAndroid Build Coastguard Worker  # Set up expected behavior
48*1b3f573fSAndroid Build Coastguard Worker  mock_dao.RetrievePersonWithIdentifier('1').AndReturn(person)
49*1b3f573fSAndroid Build Coastguard Worker  mock_dao.DeletePerson(person)
50*1b3f573fSAndroid Build Coastguard Worker
51*1b3f573fSAndroid Build Coastguard Worker  # Put mocks in replay mode
52*1b3f573fSAndroid Build Coastguard Worker  my_mox.ReplayAll()
53*1b3f573fSAndroid Build Coastguard Worker
54*1b3f573fSAndroid Build Coastguard Worker  # Inject mock object and run test
55*1b3f573fSAndroid Build Coastguard Worker  controller.SetDao(mock_dao)
56*1b3f573fSAndroid Build Coastguard Worker  controller.DeletePersonById('1')
57*1b3f573fSAndroid Build Coastguard Worker
58*1b3f573fSAndroid Build Coastguard Worker  # Verify all methods were called as expected
59*1b3f573fSAndroid Build Coastguard Worker  my_mox.VerifyAll()
60*1b3f573fSAndroid Build Coastguard Worker"""
61*1b3f573fSAndroid Build Coastguard Worker
62*1b3f573fSAndroid Build Coastguard Workerfrom collections import deque
63*1b3f573fSAndroid Build Coastguard Workerimport re
64*1b3f573fSAndroid Build Coastguard Workerimport types
65*1b3f573fSAndroid Build Coastguard Workerimport unittest
66*1b3f573fSAndroid Build Coastguard Worker
67*1b3f573fSAndroid Build Coastguard Workerimport stubout
68*1b3f573fSAndroid Build Coastguard Worker
69*1b3f573fSAndroid Build Coastguard Workerclass Error(AssertionError):
70*1b3f573fSAndroid Build Coastguard Worker  """Base exception for this module."""
71*1b3f573fSAndroid Build Coastguard Worker
72*1b3f573fSAndroid Build Coastguard Worker  pass
73*1b3f573fSAndroid Build Coastguard Worker
74*1b3f573fSAndroid Build Coastguard Worker
75*1b3f573fSAndroid Build Coastguard Workerclass ExpectedMethodCallsError(Error):
76*1b3f573fSAndroid Build Coastguard Worker  """Raised when Verify() is called before all expected methods have been called
77*1b3f573fSAndroid Build Coastguard Worker  """
78*1b3f573fSAndroid Build Coastguard Worker
79*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, expected_methods):
80*1b3f573fSAndroid Build Coastguard Worker    """Init exception.
81*1b3f573fSAndroid Build Coastguard Worker
82*1b3f573fSAndroid Build Coastguard Worker    Args:
83*1b3f573fSAndroid Build Coastguard Worker      # expected_methods: A sequence of MockMethod objects that should have been
84*1b3f573fSAndroid Build Coastguard Worker      #   called.
85*1b3f573fSAndroid Build Coastguard Worker      expected_methods: [MockMethod]
86*1b3f573fSAndroid Build Coastguard Worker
87*1b3f573fSAndroid Build Coastguard Worker    Raises:
88*1b3f573fSAndroid Build Coastguard Worker      ValueError: if expected_methods contains no methods.
89*1b3f573fSAndroid Build Coastguard Worker    """
90*1b3f573fSAndroid Build Coastguard Worker
91*1b3f573fSAndroid Build Coastguard Worker    if not expected_methods:
92*1b3f573fSAndroid Build Coastguard Worker      raise ValueError("There must be at least one expected method")
93*1b3f573fSAndroid Build Coastguard Worker    Error.__init__(self)
94*1b3f573fSAndroid Build Coastguard Worker    self._expected_methods = expected_methods
95*1b3f573fSAndroid Build Coastguard Worker
96*1b3f573fSAndroid Build Coastguard Worker  def __str__(self):
97*1b3f573fSAndroid Build Coastguard Worker    calls = "\n".join(["%3d.  %s" % (i, m)
98*1b3f573fSAndroid Build Coastguard Worker                       for i, m in enumerate(self._expected_methods)])
99*1b3f573fSAndroid Build Coastguard Worker    return "Verify: Expected methods never called:\n%s" % (calls,)
100*1b3f573fSAndroid Build Coastguard Worker
101*1b3f573fSAndroid Build Coastguard Worker
102*1b3f573fSAndroid Build Coastguard Workerclass UnexpectedMethodCallError(Error):
103*1b3f573fSAndroid Build Coastguard Worker  """Raised when an unexpected method is called.
104*1b3f573fSAndroid Build Coastguard Worker
105*1b3f573fSAndroid Build Coastguard Worker  This can occur if a method is called with incorrect parameters, or out of the
106*1b3f573fSAndroid Build Coastguard Worker  specified order.
107*1b3f573fSAndroid Build Coastguard Worker  """
108*1b3f573fSAndroid Build Coastguard Worker
109*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, unexpected_method, expected):
110*1b3f573fSAndroid Build Coastguard Worker    """Init exception.
111*1b3f573fSAndroid Build Coastguard Worker
112*1b3f573fSAndroid Build Coastguard Worker    Args:
113*1b3f573fSAndroid Build Coastguard Worker      # unexpected_method: MockMethod that was called but was not at the head of
114*1b3f573fSAndroid Build Coastguard Worker      #   the expected_method queue.
115*1b3f573fSAndroid Build Coastguard Worker      # expected: MockMethod or UnorderedGroup the method should have
116*1b3f573fSAndroid Build Coastguard Worker      #   been in.
117*1b3f573fSAndroid Build Coastguard Worker      unexpected_method: MockMethod
118*1b3f573fSAndroid Build Coastguard Worker      expected: MockMethod or UnorderedGroup
119*1b3f573fSAndroid Build Coastguard Worker    """
120*1b3f573fSAndroid Build Coastguard Worker
121*1b3f573fSAndroid Build Coastguard Worker    Error.__init__(self)
122*1b3f573fSAndroid Build Coastguard Worker    self._unexpected_method = unexpected_method
123*1b3f573fSAndroid Build Coastguard Worker    self._expected = expected
124*1b3f573fSAndroid Build Coastguard Worker
125*1b3f573fSAndroid Build Coastguard Worker  def __str__(self):
126*1b3f573fSAndroid Build Coastguard Worker    return "Unexpected method call: %s.  Expecting: %s" % \
127*1b3f573fSAndroid Build Coastguard Worker      (self._unexpected_method, self._expected)
128*1b3f573fSAndroid Build Coastguard Worker
129*1b3f573fSAndroid Build Coastguard Worker
130*1b3f573fSAndroid Build Coastguard Workerclass UnknownMethodCallError(Error):
131*1b3f573fSAndroid Build Coastguard Worker  """Raised if an unknown method is requested of the mock object."""
132*1b3f573fSAndroid Build Coastguard Worker
133*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, unknown_method_name):
134*1b3f573fSAndroid Build Coastguard Worker    """Init exception.
135*1b3f573fSAndroid Build Coastguard Worker
136*1b3f573fSAndroid Build Coastguard Worker    Args:
137*1b3f573fSAndroid Build Coastguard Worker      # unknown_method_name: Method call that is not part of the mocked class's
138*1b3f573fSAndroid Build Coastguard Worker      #   public interface.
139*1b3f573fSAndroid Build Coastguard Worker      unknown_method_name: str
140*1b3f573fSAndroid Build Coastguard Worker    """
141*1b3f573fSAndroid Build Coastguard Worker
142*1b3f573fSAndroid Build Coastguard Worker    Error.__init__(self)
143*1b3f573fSAndroid Build Coastguard Worker    self._unknown_method_name = unknown_method_name
144*1b3f573fSAndroid Build Coastguard Worker
145*1b3f573fSAndroid Build Coastguard Worker  def __str__(self):
146*1b3f573fSAndroid Build Coastguard Worker    return "Method called is not a member of the object: %s" % \
147*1b3f573fSAndroid Build Coastguard Worker      self._unknown_method_name
148*1b3f573fSAndroid Build Coastguard Worker
149*1b3f573fSAndroid Build Coastguard Worker
150*1b3f573fSAndroid Build Coastguard Workerclass Mox(object):
151*1b3f573fSAndroid Build Coastguard Worker  """Mox: a factory for creating mock objects."""
152*1b3f573fSAndroid Build Coastguard Worker
153*1b3f573fSAndroid Build Coastguard Worker  # A list of types that should be stubbed out with MockObjects (as
154*1b3f573fSAndroid Build Coastguard Worker  # opposed to MockAnythings).
155*1b3f573fSAndroid Build Coastguard Worker  _USE_MOCK_OBJECT = [types.ClassType, types.InstanceType, types.ModuleType,
156*1b3f573fSAndroid Build Coastguard Worker                      types.ObjectType, types.TypeType]
157*1b3f573fSAndroid Build Coastguard Worker
158*1b3f573fSAndroid Build Coastguard Worker  def __init__(self):
159*1b3f573fSAndroid Build Coastguard Worker    """Initialize a new Mox."""
160*1b3f573fSAndroid Build Coastguard Worker
161*1b3f573fSAndroid Build Coastguard Worker    self._mock_objects = []
162*1b3f573fSAndroid Build Coastguard Worker    self.stubs = stubout.StubOutForTesting()
163*1b3f573fSAndroid Build Coastguard Worker
164*1b3f573fSAndroid Build Coastguard Worker  def CreateMock(self, class_to_mock):
165*1b3f573fSAndroid Build Coastguard Worker    """Create a new mock object.
166*1b3f573fSAndroid Build Coastguard Worker
167*1b3f573fSAndroid Build Coastguard Worker    Args:
168*1b3f573fSAndroid Build Coastguard Worker      # class_to_mock: the class to be mocked
169*1b3f573fSAndroid Build Coastguard Worker      class_to_mock: class
170*1b3f573fSAndroid Build Coastguard Worker
171*1b3f573fSAndroid Build Coastguard Worker    Returns:
172*1b3f573fSAndroid Build Coastguard Worker      MockObject that can be used as the class_to_mock would be.
173*1b3f573fSAndroid Build Coastguard Worker    """
174*1b3f573fSAndroid Build Coastguard Worker
175*1b3f573fSAndroid Build Coastguard Worker    new_mock = MockObject(class_to_mock)
176*1b3f573fSAndroid Build Coastguard Worker    self._mock_objects.append(new_mock)
177*1b3f573fSAndroid Build Coastguard Worker    return new_mock
178*1b3f573fSAndroid Build Coastguard Worker
179*1b3f573fSAndroid Build Coastguard Worker  def CreateMockAnything(self):
180*1b3f573fSAndroid Build Coastguard Worker    """Create a mock that will accept any method calls.
181*1b3f573fSAndroid Build Coastguard Worker
182*1b3f573fSAndroid Build Coastguard Worker    This does not enforce an interface.
183*1b3f573fSAndroid Build Coastguard Worker    """
184*1b3f573fSAndroid Build Coastguard Worker
185*1b3f573fSAndroid Build Coastguard Worker    new_mock = MockAnything()
186*1b3f573fSAndroid Build Coastguard Worker    self._mock_objects.append(new_mock)
187*1b3f573fSAndroid Build Coastguard Worker    return new_mock
188*1b3f573fSAndroid Build Coastguard Worker
189*1b3f573fSAndroid Build Coastguard Worker  def ReplayAll(self):
190*1b3f573fSAndroid Build Coastguard Worker    """Set all mock objects to replay mode."""
191*1b3f573fSAndroid Build Coastguard Worker
192*1b3f573fSAndroid Build Coastguard Worker    for mock_obj in self._mock_objects:
193*1b3f573fSAndroid Build Coastguard Worker      mock_obj._Replay()
194*1b3f573fSAndroid Build Coastguard Worker
195*1b3f573fSAndroid Build Coastguard Worker
196*1b3f573fSAndroid Build Coastguard Worker  def VerifyAll(self):
197*1b3f573fSAndroid Build Coastguard Worker    """Call verify on all mock objects created."""
198*1b3f573fSAndroid Build Coastguard Worker
199*1b3f573fSAndroid Build Coastguard Worker    for mock_obj in self._mock_objects:
200*1b3f573fSAndroid Build Coastguard Worker      mock_obj._Verify()
201*1b3f573fSAndroid Build Coastguard Worker
202*1b3f573fSAndroid Build Coastguard Worker  def ResetAll(self):
203*1b3f573fSAndroid Build Coastguard Worker    """Call reset on all mock objects.  This does not unset stubs."""
204*1b3f573fSAndroid Build Coastguard Worker
205*1b3f573fSAndroid Build Coastguard Worker    for mock_obj in self._mock_objects:
206*1b3f573fSAndroid Build Coastguard Worker      mock_obj._Reset()
207*1b3f573fSAndroid Build Coastguard Worker
208*1b3f573fSAndroid Build Coastguard Worker  def StubOutWithMock(self, obj, attr_name, use_mock_anything=False):
209*1b3f573fSAndroid Build Coastguard Worker    """Replace a method, attribute, etc. with a Mock.
210*1b3f573fSAndroid Build Coastguard Worker
211*1b3f573fSAndroid Build Coastguard Worker    This will replace a class or module with a MockObject, and everything else
212*1b3f573fSAndroid Build Coastguard Worker    (method, function, etc) with a MockAnything.  This can be overridden to
213*1b3f573fSAndroid Build Coastguard Worker    always use a MockAnything by setting use_mock_anything to True.
214*1b3f573fSAndroid Build Coastguard Worker
215*1b3f573fSAndroid Build Coastguard Worker    Args:
216*1b3f573fSAndroid Build Coastguard Worker      obj: A Python object (class, module, instance, callable).
217*1b3f573fSAndroid Build Coastguard Worker      attr_name: str.  The name of the attribute to replace with a mock.
218*1b3f573fSAndroid Build Coastguard Worker      use_mock_anything: bool. True if a MockAnything should be used regardless
219*1b3f573fSAndroid Build Coastguard Worker        of the type of attribute.
220*1b3f573fSAndroid Build Coastguard Worker    """
221*1b3f573fSAndroid Build Coastguard Worker
222*1b3f573fSAndroid Build Coastguard Worker    attr_to_replace = getattr(obj, attr_name)
223*1b3f573fSAndroid Build Coastguard Worker    if type(attr_to_replace) in self._USE_MOCK_OBJECT and not use_mock_anything:
224*1b3f573fSAndroid Build Coastguard Worker      stub = self.CreateMock(attr_to_replace)
225*1b3f573fSAndroid Build Coastguard Worker    else:
226*1b3f573fSAndroid Build Coastguard Worker      stub = self.CreateMockAnything()
227*1b3f573fSAndroid Build Coastguard Worker
228*1b3f573fSAndroid Build Coastguard Worker    self.stubs.Set(obj, attr_name, stub)
229*1b3f573fSAndroid Build Coastguard Worker
230*1b3f573fSAndroid Build Coastguard Worker  def UnsetStubs(self):
231*1b3f573fSAndroid Build Coastguard Worker    """Restore stubs to their original state."""
232*1b3f573fSAndroid Build Coastguard Worker
233*1b3f573fSAndroid Build Coastguard Worker    self.stubs.UnsetAll()
234*1b3f573fSAndroid Build Coastguard Worker
235*1b3f573fSAndroid Build Coastguard Workerdef Replay(*args):
236*1b3f573fSAndroid Build Coastguard Worker  """Put mocks into Replay mode.
237*1b3f573fSAndroid Build Coastguard Worker
238*1b3f573fSAndroid Build Coastguard Worker  Args:
239*1b3f573fSAndroid Build Coastguard Worker    # args is any number of mocks to put into replay mode.
240*1b3f573fSAndroid Build Coastguard Worker  """
241*1b3f573fSAndroid Build Coastguard Worker
242*1b3f573fSAndroid Build Coastguard Worker  for mock in args:
243*1b3f573fSAndroid Build Coastguard Worker    mock._Replay()
244*1b3f573fSAndroid Build Coastguard Worker
245*1b3f573fSAndroid Build Coastguard Worker
246*1b3f573fSAndroid Build Coastguard Workerdef Verify(*args):
247*1b3f573fSAndroid Build Coastguard Worker  """Verify mocks.
248*1b3f573fSAndroid Build Coastguard Worker
249*1b3f573fSAndroid Build Coastguard Worker  Args:
250*1b3f573fSAndroid Build Coastguard Worker    # args is any number of mocks to be verified.
251*1b3f573fSAndroid Build Coastguard Worker  """
252*1b3f573fSAndroid Build Coastguard Worker
253*1b3f573fSAndroid Build Coastguard Worker  for mock in args:
254*1b3f573fSAndroid Build Coastguard Worker    mock._Verify()
255*1b3f573fSAndroid Build Coastguard Worker
256*1b3f573fSAndroid Build Coastguard Worker
257*1b3f573fSAndroid Build Coastguard Workerdef Reset(*args):
258*1b3f573fSAndroid Build Coastguard Worker  """Reset mocks.
259*1b3f573fSAndroid Build Coastguard Worker
260*1b3f573fSAndroid Build Coastguard Worker  Args:
261*1b3f573fSAndroid Build Coastguard Worker    # args is any number of mocks to be reset.
262*1b3f573fSAndroid Build Coastguard Worker  """
263*1b3f573fSAndroid Build Coastguard Worker
264*1b3f573fSAndroid Build Coastguard Worker  for mock in args:
265*1b3f573fSAndroid Build Coastguard Worker    mock._Reset()
266*1b3f573fSAndroid Build Coastguard Worker
267*1b3f573fSAndroid Build Coastguard Worker
268*1b3f573fSAndroid Build Coastguard Workerclass MockAnything:
269*1b3f573fSAndroid Build Coastguard Worker  """A mock that can be used to mock anything.
270*1b3f573fSAndroid Build Coastguard Worker
271*1b3f573fSAndroid Build Coastguard Worker  This is helpful for mocking classes that do not provide a public interface.
272*1b3f573fSAndroid Build Coastguard Worker  """
273*1b3f573fSAndroid Build Coastguard Worker
274*1b3f573fSAndroid Build Coastguard Worker  def __init__(self):
275*1b3f573fSAndroid Build Coastguard Worker    """ """
276*1b3f573fSAndroid Build Coastguard Worker    self._Reset()
277*1b3f573fSAndroid Build Coastguard Worker
278*1b3f573fSAndroid Build Coastguard Worker  def __getattr__(self, method_name):
279*1b3f573fSAndroid Build Coastguard Worker    """Intercept method calls on this object.
280*1b3f573fSAndroid Build Coastguard Worker
281*1b3f573fSAndroid Build Coastguard Worker     A new MockMethod is returned that is aware of the MockAnything's
282*1b3f573fSAndroid Build Coastguard Worker     state (record or replay).  The call will be recorded or replayed
283*1b3f573fSAndroid Build Coastguard Worker     by the MockMethod's __call__.
284*1b3f573fSAndroid Build Coastguard Worker
285*1b3f573fSAndroid Build Coastguard Worker    Args:
286*1b3f573fSAndroid Build Coastguard Worker      # method name: the name of the method being called.
287*1b3f573fSAndroid Build Coastguard Worker      method_name: str
288*1b3f573fSAndroid Build Coastguard Worker
289*1b3f573fSAndroid Build Coastguard Worker    Returns:
290*1b3f573fSAndroid Build Coastguard Worker      A new MockMethod aware of MockAnything's state (record or replay).
291*1b3f573fSAndroid Build Coastguard Worker    """
292*1b3f573fSAndroid Build Coastguard Worker
293*1b3f573fSAndroid Build Coastguard Worker    return self._CreateMockMethod(method_name)
294*1b3f573fSAndroid Build Coastguard Worker
295*1b3f573fSAndroid Build Coastguard Worker  def _CreateMockMethod(self, method_name):
296*1b3f573fSAndroid Build Coastguard Worker    """Create a new mock method call and return it.
297*1b3f573fSAndroid Build Coastguard Worker
298*1b3f573fSAndroid Build Coastguard Worker    Args:
299*1b3f573fSAndroid Build Coastguard Worker      # method name: the name of the method being called.
300*1b3f573fSAndroid Build Coastguard Worker      method_name: str
301*1b3f573fSAndroid Build Coastguard Worker
302*1b3f573fSAndroid Build Coastguard Worker    Returns:
303*1b3f573fSAndroid Build Coastguard Worker      A new MockMethod aware of MockAnything's state (record or replay).
304*1b3f573fSAndroid Build Coastguard Worker    """
305*1b3f573fSAndroid Build Coastguard Worker
306*1b3f573fSAndroid Build Coastguard Worker    return MockMethod(method_name, self._expected_calls_queue,
307*1b3f573fSAndroid Build Coastguard Worker                      self._replay_mode)
308*1b3f573fSAndroid Build Coastguard Worker
309*1b3f573fSAndroid Build Coastguard Worker  def __nonzero__(self):
310*1b3f573fSAndroid Build Coastguard Worker    """Return 1 for nonzero so the mock can be used as a conditional."""
311*1b3f573fSAndroid Build Coastguard Worker
312*1b3f573fSAndroid Build Coastguard Worker    return 1
313*1b3f573fSAndroid Build Coastguard Worker
314*1b3f573fSAndroid Build Coastguard Worker  def __eq__(self, rhs):
315*1b3f573fSAndroid Build Coastguard Worker    """Provide custom logic to compare objects."""
316*1b3f573fSAndroid Build Coastguard Worker
317*1b3f573fSAndroid Build Coastguard Worker    return (isinstance(rhs, MockAnything) and
318*1b3f573fSAndroid Build Coastguard Worker            self._replay_mode == rhs._replay_mode and
319*1b3f573fSAndroid Build Coastguard Worker            self._expected_calls_queue == rhs._expected_calls_queue)
320*1b3f573fSAndroid Build Coastguard Worker
321*1b3f573fSAndroid Build Coastguard Worker  def __ne__(self, rhs):
322*1b3f573fSAndroid Build Coastguard Worker    """Provide custom logic to compare objects."""
323*1b3f573fSAndroid Build Coastguard Worker
324*1b3f573fSAndroid Build Coastguard Worker    return not self == rhs
325*1b3f573fSAndroid Build Coastguard Worker
326*1b3f573fSAndroid Build Coastguard Worker  def _Replay(self):
327*1b3f573fSAndroid Build Coastguard Worker    """Start replaying expected method calls."""
328*1b3f573fSAndroid Build Coastguard Worker
329*1b3f573fSAndroid Build Coastguard Worker    self._replay_mode = True
330*1b3f573fSAndroid Build Coastguard Worker
331*1b3f573fSAndroid Build Coastguard Worker  def _Verify(self):
332*1b3f573fSAndroid Build Coastguard Worker    """Verify that all of the expected calls have been made.
333*1b3f573fSAndroid Build Coastguard Worker
334*1b3f573fSAndroid Build Coastguard Worker    Raises:
335*1b3f573fSAndroid Build Coastguard Worker      ExpectedMethodCallsError: if there are still more method calls in the
336*1b3f573fSAndroid Build Coastguard Worker        expected queue.
337*1b3f573fSAndroid Build Coastguard Worker    """
338*1b3f573fSAndroid Build Coastguard Worker
339*1b3f573fSAndroid Build Coastguard Worker    # If the list of expected calls is not empty, raise an exception
340*1b3f573fSAndroid Build Coastguard Worker    if self._expected_calls_queue:
341*1b3f573fSAndroid Build Coastguard Worker      # The last MultipleTimesGroup is not popped from the queue.
342*1b3f573fSAndroid Build Coastguard Worker      if (len(self._expected_calls_queue) == 1 and
343*1b3f573fSAndroid Build Coastguard Worker          isinstance(self._expected_calls_queue[0], MultipleTimesGroup) and
344*1b3f573fSAndroid Build Coastguard Worker          self._expected_calls_queue[0].IsSatisfied()):
345*1b3f573fSAndroid Build Coastguard Worker        pass
346*1b3f573fSAndroid Build Coastguard Worker      else:
347*1b3f573fSAndroid Build Coastguard Worker        raise ExpectedMethodCallsError(self._expected_calls_queue)
348*1b3f573fSAndroid Build Coastguard Worker
349*1b3f573fSAndroid Build Coastguard Worker  def _Reset(self):
350*1b3f573fSAndroid Build Coastguard Worker    """Reset the state of this mock to record mode with an empty queue."""
351*1b3f573fSAndroid Build Coastguard Worker
352*1b3f573fSAndroid Build Coastguard Worker    # Maintain a list of method calls we are expecting
353*1b3f573fSAndroid Build Coastguard Worker    self._expected_calls_queue = deque()
354*1b3f573fSAndroid Build Coastguard Worker
355*1b3f573fSAndroid Build Coastguard Worker    # Make sure we are in setup mode, not replay mode
356*1b3f573fSAndroid Build Coastguard Worker    self._replay_mode = False
357*1b3f573fSAndroid Build Coastguard Worker
358*1b3f573fSAndroid Build Coastguard Worker
359*1b3f573fSAndroid Build Coastguard Workerclass MockObject(MockAnything, object):
360*1b3f573fSAndroid Build Coastguard Worker  """A mock object that simulates the public/protected interface of a class."""
361*1b3f573fSAndroid Build Coastguard Worker
362*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, class_to_mock):
363*1b3f573fSAndroid Build Coastguard Worker    """Initialize a mock object.
364*1b3f573fSAndroid Build Coastguard Worker
365*1b3f573fSAndroid Build Coastguard Worker    This determines the methods and properties of the class and stores them.
366*1b3f573fSAndroid Build Coastguard Worker
367*1b3f573fSAndroid Build Coastguard Worker    Args:
368*1b3f573fSAndroid Build Coastguard Worker      # class_to_mock: class to be mocked
369*1b3f573fSAndroid Build Coastguard Worker      class_to_mock: class
370*1b3f573fSAndroid Build Coastguard Worker    """
371*1b3f573fSAndroid Build Coastguard Worker
372*1b3f573fSAndroid Build Coastguard Worker    # This is used to hack around the mixin/inheritance of MockAnything, which
373*1b3f573fSAndroid Build Coastguard Worker    # is not a proper object (it can be anything. :-)
374*1b3f573fSAndroid Build Coastguard Worker    MockAnything.__dict__['__init__'](self)
375*1b3f573fSAndroid Build Coastguard Worker
376*1b3f573fSAndroid Build Coastguard Worker    # Get a list of all the public and special methods we should mock.
377*1b3f573fSAndroid Build Coastguard Worker    self._known_methods = set()
378*1b3f573fSAndroid Build Coastguard Worker    self._known_vars = set()
379*1b3f573fSAndroid Build Coastguard Worker    self._class_to_mock = class_to_mock
380*1b3f573fSAndroid Build Coastguard Worker    for method in dir(class_to_mock):
381*1b3f573fSAndroid Build Coastguard Worker      if callable(getattr(class_to_mock, method)):
382*1b3f573fSAndroid Build Coastguard Worker        self._known_methods.add(method)
383*1b3f573fSAndroid Build Coastguard Worker      else:
384*1b3f573fSAndroid Build Coastguard Worker        self._known_vars.add(method)
385*1b3f573fSAndroid Build Coastguard Worker
386*1b3f573fSAndroid Build Coastguard Worker  def __getattr__(self, name):
387*1b3f573fSAndroid Build Coastguard Worker    """Intercept attribute request on this object.
388*1b3f573fSAndroid Build Coastguard Worker
389*1b3f573fSAndroid Build Coastguard Worker    If the attribute is a public class variable, it will be returned and not
390*1b3f573fSAndroid Build Coastguard Worker    recorded as a call.
391*1b3f573fSAndroid Build Coastguard Worker
392*1b3f573fSAndroid Build Coastguard Worker    If the attribute is not a variable, it is handled like a method
393*1b3f573fSAndroid Build Coastguard Worker    call. The method name is checked against the set of mockable
394*1b3f573fSAndroid Build Coastguard Worker    methods, and a new MockMethod is returned that is aware of the
395*1b3f573fSAndroid Build Coastguard Worker    MockObject's state (record or replay).  The call will be recorded
396*1b3f573fSAndroid Build Coastguard Worker    or replayed by the MockMethod's __call__.
397*1b3f573fSAndroid Build Coastguard Worker
398*1b3f573fSAndroid Build Coastguard Worker    Args:
399*1b3f573fSAndroid Build Coastguard Worker      # name: the name of the attribute being requested.
400*1b3f573fSAndroid Build Coastguard Worker      name: str
401*1b3f573fSAndroid Build Coastguard Worker
402*1b3f573fSAndroid Build Coastguard Worker    Returns:
403*1b3f573fSAndroid Build Coastguard Worker      Either a class variable or a new MockMethod that is aware of the state
404*1b3f573fSAndroid Build Coastguard Worker      of the mock (record or replay).
405*1b3f573fSAndroid Build Coastguard Worker
406*1b3f573fSAndroid Build Coastguard Worker    Raises:
407*1b3f573fSAndroid Build Coastguard Worker      UnknownMethodCallError if the MockObject does not mock the requested
408*1b3f573fSAndroid Build Coastguard Worker          method.
409*1b3f573fSAndroid Build Coastguard Worker    """
410*1b3f573fSAndroid Build Coastguard Worker
411*1b3f573fSAndroid Build Coastguard Worker    if name in self._known_vars:
412*1b3f573fSAndroid Build Coastguard Worker      return getattr(self._class_to_mock, name)
413*1b3f573fSAndroid Build Coastguard Worker
414*1b3f573fSAndroid Build Coastguard Worker    if name in self._known_methods:
415*1b3f573fSAndroid Build Coastguard Worker      return self._CreateMockMethod(name)
416*1b3f573fSAndroid Build Coastguard Worker
417*1b3f573fSAndroid Build Coastguard Worker    raise UnknownMethodCallError(name)
418*1b3f573fSAndroid Build Coastguard Worker
419*1b3f573fSAndroid Build Coastguard Worker  def __eq__(self, rhs):
420*1b3f573fSAndroid Build Coastguard Worker    """Provide custom logic to compare objects."""
421*1b3f573fSAndroid Build Coastguard Worker
422*1b3f573fSAndroid Build Coastguard Worker    return (isinstance(rhs, MockObject) and
423*1b3f573fSAndroid Build Coastguard Worker            self._class_to_mock == rhs._class_to_mock and
424*1b3f573fSAndroid Build Coastguard Worker            self._replay_mode == rhs._replay_mode and
425*1b3f573fSAndroid Build Coastguard Worker            self._expected_calls_queue == rhs._expected_calls_queue)
426*1b3f573fSAndroid Build Coastguard Worker
427*1b3f573fSAndroid Build Coastguard Worker  def __setitem__(self, key, value):
428*1b3f573fSAndroid Build Coastguard Worker    """Provide custom logic for mocking classes that support item assignment.
429*1b3f573fSAndroid Build Coastguard Worker
430*1b3f573fSAndroid Build Coastguard Worker    Args:
431*1b3f573fSAndroid Build Coastguard Worker      key: Key to set the value for.
432*1b3f573fSAndroid Build Coastguard Worker      value: Value to set.
433*1b3f573fSAndroid Build Coastguard Worker
434*1b3f573fSAndroid Build Coastguard Worker    Returns:
435*1b3f573fSAndroid Build Coastguard Worker      Expected return value in replay mode.  A MockMethod object for the
436*1b3f573fSAndroid Build Coastguard Worker      __setitem__ method that has already been called if not in replay mode.
437*1b3f573fSAndroid Build Coastguard Worker
438*1b3f573fSAndroid Build Coastguard Worker    Raises:
439*1b3f573fSAndroid Build Coastguard Worker      TypeError if the underlying class does not support item assignment.
440*1b3f573fSAndroid Build Coastguard Worker      UnexpectedMethodCallError if the object does not expect the call to
441*1b3f573fSAndroid Build Coastguard Worker        __setitem__.
442*1b3f573fSAndroid Build Coastguard Worker
443*1b3f573fSAndroid Build Coastguard Worker    """
444*1b3f573fSAndroid Build Coastguard Worker    setitem = self._class_to_mock.__dict__.get('__setitem__', None)
445*1b3f573fSAndroid Build Coastguard Worker
446*1b3f573fSAndroid Build Coastguard Worker    # Verify the class supports item assignment.
447*1b3f573fSAndroid Build Coastguard Worker    if setitem is None:
448*1b3f573fSAndroid Build Coastguard Worker      raise TypeError('object does not support item assignment')
449*1b3f573fSAndroid Build Coastguard Worker
450*1b3f573fSAndroid Build Coastguard Worker    # If we are in replay mode then simply call the mock __setitem__ method.
451*1b3f573fSAndroid Build Coastguard Worker    if self._replay_mode:
452*1b3f573fSAndroid Build Coastguard Worker      return MockMethod('__setitem__', self._expected_calls_queue,
453*1b3f573fSAndroid Build Coastguard Worker                        self._replay_mode)(key, value)
454*1b3f573fSAndroid Build Coastguard Worker
455*1b3f573fSAndroid Build Coastguard Worker
456*1b3f573fSAndroid Build Coastguard Worker    # Otherwise, create a mock method __setitem__.
457*1b3f573fSAndroid Build Coastguard Worker    return self._CreateMockMethod('__setitem__')(key, value)
458*1b3f573fSAndroid Build Coastguard Worker
459*1b3f573fSAndroid Build Coastguard Worker  def __getitem__(self, key):
460*1b3f573fSAndroid Build Coastguard Worker    """Provide custom logic for mocking classes that are subscriptable.
461*1b3f573fSAndroid Build Coastguard Worker
462*1b3f573fSAndroid Build Coastguard Worker    Args:
463*1b3f573fSAndroid Build Coastguard Worker      key: Key to return the value for.
464*1b3f573fSAndroid Build Coastguard Worker
465*1b3f573fSAndroid Build Coastguard Worker    Returns:
466*1b3f573fSAndroid Build Coastguard Worker      Expected return value in replay mode.  A MockMethod object for the
467*1b3f573fSAndroid Build Coastguard Worker      __getitem__ method that has already been called if not in replay mode.
468*1b3f573fSAndroid Build Coastguard Worker
469*1b3f573fSAndroid Build Coastguard Worker    Raises:
470*1b3f573fSAndroid Build Coastguard Worker      TypeError if the underlying class is not subscriptable.
471*1b3f573fSAndroid Build Coastguard Worker      UnexpectedMethodCallError if the object does not expect the call to
472*1b3f573fSAndroid Build Coastguard Worker        __setitem__.
473*1b3f573fSAndroid Build Coastguard Worker
474*1b3f573fSAndroid Build Coastguard Worker    """
475*1b3f573fSAndroid Build Coastguard Worker    getitem = self._class_to_mock.__dict__.get('__getitem__', None)
476*1b3f573fSAndroid Build Coastguard Worker
477*1b3f573fSAndroid Build Coastguard Worker    # Verify the class supports item assignment.
478*1b3f573fSAndroid Build Coastguard Worker    if getitem is None:
479*1b3f573fSAndroid Build Coastguard Worker      raise TypeError('unsubscriptable object')
480*1b3f573fSAndroid Build Coastguard Worker
481*1b3f573fSAndroid Build Coastguard Worker    # If we are in replay mode then simply call the mock __getitem__ method.
482*1b3f573fSAndroid Build Coastguard Worker    if self._replay_mode:
483*1b3f573fSAndroid Build Coastguard Worker      return MockMethod('__getitem__', self._expected_calls_queue,
484*1b3f573fSAndroid Build Coastguard Worker                        self._replay_mode)(key)
485*1b3f573fSAndroid Build Coastguard Worker
486*1b3f573fSAndroid Build Coastguard Worker
487*1b3f573fSAndroid Build Coastguard Worker    # Otherwise, create a mock method __getitem__.
488*1b3f573fSAndroid Build Coastguard Worker    return self._CreateMockMethod('__getitem__')(key)
489*1b3f573fSAndroid Build Coastguard Worker
490*1b3f573fSAndroid Build Coastguard Worker  def __call__(self, *params, **named_params):
491*1b3f573fSAndroid Build Coastguard Worker    """Provide custom logic for mocking classes that are callable."""
492*1b3f573fSAndroid Build Coastguard Worker
493*1b3f573fSAndroid Build Coastguard Worker    # Verify the class we are mocking is callable
494*1b3f573fSAndroid Build Coastguard Worker    callable = self._class_to_mock.__dict__.get('__call__', None)
495*1b3f573fSAndroid Build Coastguard Worker    if callable is None:
496*1b3f573fSAndroid Build Coastguard Worker      raise TypeError('Not callable')
497*1b3f573fSAndroid Build Coastguard Worker
498*1b3f573fSAndroid Build Coastguard Worker    # Because the call is happening directly on this object instead of a method,
499*1b3f573fSAndroid Build Coastguard Worker    # the call on the mock method is made right here
500*1b3f573fSAndroid Build Coastguard Worker    mock_method = self._CreateMockMethod('__call__')
501*1b3f573fSAndroid Build Coastguard Worker    return mock_method(*params, **named_params)
502*1b3f573fSAndroid Build Coastguard Worker
503*1b3f573fSAndroid Build Coastguard Worker  @property
504*1b3f573fSAndroid Build Coastguard Worker  def __class__(self):
505*1b3f573fSAndroid Build Coastguard Worker    """Return the class that is being mocked."""
506*1b3f573fSAndroid Build Coastguard Worker
507*1b3f573fSAndroid Build Coastguard Worker    return self._class_to_mock
508*1b3f573fSAndroid Build Coastguard Worker
509*1b3f573fSAndroid Build Coastguard Worker
510*1b3f573fSAndroid Build Coastguard Workerclass MockMethod(object):
511*1b3f573fSAndroid Build Coastguard Worker  """Callable mock method.
512*1b3f573fSAndroid Build Coastguard Worker
513*1b3f573fSAndroid Build Coastguard Worker  A MockMethod should act exactly like the method it mocks, accepting parameters
514*1b3f573fSAndroid Build Coastguard Worker  and returning a value, or throwing an exception (as specified).  When this
515*1b3f573fSAndroid Build Coastguard Worker  method is called, it can optionally verify whether the called method (name and
516*1b3f573fSAndroid Build Coastguard Worker  signature) matches the expected method.
517*1b3f573fSAndroid Build Coastguard Worker  """
518*1b3f573fSAndroid Build Coastguard Worker
519*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, method_name, call_queue, replay_mode):
520*1b3f573fSAndroid Build Coastguard Worker    """Construct a new mock method.
521*1b3f573fSAndroid Build Coastguard Worker
522*1b3f573fSAndroid Build Coastguard Worker    Args:
523*1b3f573fSAndroid Build Coastguard Worker      # method_name: the name of the method
524*1b3f573fSAndroid Build Coastguard Worker      # call_queue: deque of calls, verify this call against the head, or add
525*1b3f573fSAndroid Build Coastguard Worker      #     this call to the queue.
526*1b3f573fSAndroid Build Coastguard Worker      # replay_mode: False if we are recording, True if we are verifying calls
527*1b3f573fSAndroid Build Coastguard Worker      #     against the call queue.
528*1b3f573fSAndroid Build Coastguard Worker      method_name: str
529*1b3f573fSAndroid Build Coastguard Worker      call_queue: list or deque
530*1b3f573fSAndroid Build Coastguard Worker      replay_mode: bool
531*1b3f573fSAndroid Build Coastguard Worker    """
532*1b3f573fSAndroid Build Coastguard Worker
533*1b3f573fSAndroid Build Coastguard Worker    self._name = method_name
534*1b3f573fSAndroid Build Coastguard Worker    self._call_queue = call_queue
535*1b3f573fSAndroid Build Coastguard Worker    if not isinstance(call_queue, deque):
536*1b3f573fSAndroid Build Coastguard Worker      self._call_queue = deque(self._call_queue)
537*1b3f573fSAndroid Build Coastguard Worker    self._replay_mode = replay_mode
538*1b3f573fSAndroid Build Coastguard Worker
539*1b3f573fSAndroid Build Coastguard Worker    self._params = None
540*1b3f573fSAndroid Build Coastguard Worker    self._named_params = None
541*1b3f573fSAndroid Build Coastguard Worker    self._return_value = None
542*1b3f573fSAndroid Build Coastguard Worker    self._exception = None
543*1b3f573fSAndroid Build Coastguard Worker    self._side_effects = None
544*1b3f573fSAndroid Build Coastguard Worker
545*1b3f573fSAndroid Build Coastguard Worker  def __call__(self, *params, **named_params):
546*1b3f573fSAndroid Build Coastguard Worker    """Log parameters and return the specified return value.
547*1b3f573fSAndroid Build Coastguard Worker
548*1b3f573fSAndroid Build Coastguard Worker    If the Mock(Anything/Object) associated with this call is in record mode,
549*1b3f573fSAndroid Build Coastguard Worker    this MockMethod will be pushed onto the expected call queue.  If the mock
550*1b3f573fSAndroid Build Coastguard Worker    is in replay mode, this will pop a MockMethod off the top of the queue and
551*1b3f573fSAndroid Build Coastguard Worker    verify this call is equal to the expected call.
552*1b3f573fSAndroid Build Coastguard Worker
553*1b3f573fSAndroid Build Coastguard Worker    Raises:
554*1b3f573fSAndroid Build Coastguard Worker      UnexpectedMethodCall if this call is supposed to match an expected method
555*1b3f573fSAndroid Build Coastguard Worker        call and it does not.
556*1b3f573fSAndroid Build Coastguard Worker    """
557*1b3f573fSAndroid Build Coastguard Worker
558*1b3f573fSAndroid Build Coastguard Worker    self._params = params
559*1b3f573fSAndroid Build Coastguard Worker    self._named_params = named_params
560*1b3f573fSAndroid Build Coastguard Worker
561*1b3f573fSAndroid Build Coastguard Worker    if not self._replay_mode:
562*1b3f573fSAndroid Build Coastguard Worker      self._call_queue.append(self)
563*1b3f573fSAndroid Build Coastguard Worker      return self
564*1b3f573fSAndroid Build Coastguard Worker
565*1b3f573fSAndroid Build Coastguard Worker    expected_method = self._VerifyMethodCall()
566*1b3f573fSAndroid Build Coastguard Worker
567*1b3f573fSAndroid Build Coastguard Worker    if expected_method._side_effects:
568*1b3f573fSAndroid Build Coastguard Worker      expected_method._side_effects(*params, **named_params)
569*1b3f573fSAndroid Build Coastguard Worker
570*1b3f573fSAndroid Build Coastguard Worker    if expected_method._exception:
571*1b3f573fSAndroid Build Coastguard Worker      raise expected_method._exception
572*1b3f573fSAndroid Build Coastguard Worker
573*1b3f573fSAndroid Build Coastguard Worker    return expected_method._return_value
574*1b3f573fSAndroid Build Coastguard Worker
575*1b3f573fSAndroid Build Coastguard Worker  def __getattr__(self, name):
576*1b3f573fSAndroid Build Coastguard Worker    """Raise an AttributeError with a helpful message."""
577*1b3f573fSAndroid Build Coastguard Worker
578*1b3f573fSAndroid Build Coastguard Worker    raise AttributeError('MockMethod has no attribute "%s". '
579*1b3f573fSAndroid Build Coastguard Worker        'Did you remember to put your mocks in replay mode?' % name)
580*1b3f573fSAndroid Build Coastguard Worker
581*1b3f573fSAndroid Build Coastguard Worker  def _PopNextMethod(self):
582*1b3f573fSAndroid Build Coastguard Worker    """Pop the next method from our call queue."""
583*1b3f573fSAndroid Build Coastguard Worker    try:
584*1b3f573fSAndroid Build Coastguard Worker      return self._call_queue.popleft()
585*1b3f573fSAndroid Build Coastguard Worker    except IndexError:
586*1b3f573fSAndroid Build Coastguard Worker      raise UnexpectedMethodCallError(self, None)
587*1b3f573fSAndroid Build Coastguard Worker
588*1b3f573fSAndroid Build Coastguard Worker  def _VerifyMethodCall(self):
589*1b3f573fSAndroid Build Coastguard Worker    """Verify the called method is expected.
590*1b3f573fSAndroid Build Coastguard Worker
591*1b3f573fSAndroid Build Coastguard Worker    This can be an ordered method, or part of an unordered set.
592*1b3f573fSAndroid Build Coastguard Worker
593*1b3f573fSAndroid Build Coastguard Worker    Returns:
594*1b3f573fSAndroid Build Coastguard Worker      The expected mock method.
595*1b3f573fSAndroid Build Coastguard Worker
596*1b3f573fSAndroid Build Coastguard Worker    Raises:
597*1b3f573fSAndroid Build Coastguard Worker      UnexpectedMethodCall if the method called was not expected.
598*1b3f573fSAndroid Build Coastguard Worker    """
599*1b3f573fSAndroid Build Coastguard Worker
600*1b3f573fSAndroid Build Coastguard Worker    expected = self._PopNextMethod()
601*1b3f573fSAndroid Build Coastguard Worker
602*1b3f573fSAndroid Build Coastguard Worker    # Loop here, because we might have a MethodGroup followed by another
603*1b3f573fSAndroid Build Coastguard Worker    # group.
604*1b3f573fSAndroid Build Coastguard Worker    while isinstance(expected, MethodGroup):
605*1b3f573fSAndroid Build Coastguard Worker      expected, method = expected.MethodCalled(self)
606*1b3f573fSAndroid Build Coastguard Worker      if method is not None:
607*1b3f573fSAndroid Build Coastguard Worker        return method
608*1b3f573fSAndroid Build Coastguard Worker
609*1b3f573fSAndroid Build Coastguard Worker    # This is a mock method, so just check equality.
610*1b3f573fSAndroid Build Coastguard Worker    if expected != self:
611*1b3f573fSAndroid Build Coastguard Worker      raise UnexpectedMethodCallError(self, expected)
612*1b3f573fSAndroid Build Coastguard Worker
613*1b3f573fSAndroid Build Coastguard Worker    return expected
614*1b3f573fSAndroid Build Coastguard Worker
615*1b3f573fSAndroid Build Coastguard Worker  def __str__(self):
616*1b3f573fSAndroid Build Coastguard Worker    params = ', '.join(
617*1b3f573fSAndroid Build Coastguard Worker        [repr(p) for p in self._params or []] +
618*1b3f573fSAndroid Build Coastguard Worker        ['%s=%r' % x for x in sorted((self._named_params or {}).items())])
619*1b3f573fSAndroid Build Coastguard Worker    desc = "%s(%s) -> %r" % (self._name, params, self._return_value)
620*1b3f573fSAndroid Build Coastguard Worker    return desc
621*1b3f573fSAndroid Build Coastguard Worker
622*1b3f573fSAndroid Build Coastguard Worker  def __eq__(self, rhs):
623*1b3f573fSAndroid Build Coastguard Worker    """Test whether this MockMethod is equivalent to another MockMethod.
624*1b3f573fSAndroid Build Coastguard Worker
625*1b3f573fSAndroid Build Coastguard Worker    Args:
626*1b3f573fSAndroid Build Coastguard Worker      # rhs: the right hand side of the test
627*1b3f573fSAndroid Build Coastguard Worker      rhs: MockMethod
628*1b3f573fSAndroid Build Coastguard Worker    """
629*1b3f573fSAndroid Build Coastguard Worker
630*1b3f573fSAndroid Build Coastguard Worker    return (isinstance(rhs, MockMethod) and
631*1b3f573fSAndroid Build Coastguard Worker            self._name == rhs._name and
632*1b3f573fSAndroid Build Coastguard Worker            self._params == rhs._params and
633*1b3f573fSAndroid Build Coastguard Worker            self._named_params == rhs._named_params)
634*1b3f573fSAndroid Build Coastguard Worker
635*1b3f573fSAndroid Build Coastguard Worker  def __ne__(self, rhs):
636*1b3f573fSAndroid Build Coastguard Worker    """Test whether this MockMethod is not equivalent to another MockMethod.
637*1b3f573fSAndroid Build Coastguard Worker
638*1b3f573fSAndroid Build Coastguard Worker    Args:
639*1b3f573fSAndroid Build Coastguard Worker      # rhs: the right hand side of the test
640*1b3f573fSAndroid Build Coastguard Worker      rhs: MockMethod
641*1b3f573fSAndroid Build Coastguard Worker    """
642*1b3f573fSAndroid Build Coastguard Worker
643*1b3f573fSAndroid Build Coastguard Worker    return not self == rhs
644*1b3f573fSAndroid Build Coastguard Worker
645*1b3f573fSAndroid Build Coastguard Worker  def GetPossibleGroup(self):
646*1b3f573fSAndroid Build Coastguard Worker    """Returns a possible group from the end of the call queue or None if no
647*1b3f573fSAndroid Build Coastguard Worker    other methods are on the stack.
648*1b3f573fSAndroid Build Coastguard Worker    """
649*1b3f573fSAndroid Build Coastguard Worker
650*1b3f573fSAndroid Build Coastguard Worker    # Remove this method from the tail of the queue so we can add it to a group.
651*1b3f573fSAndroid Build Coastguard Worker    this_method = self._call_queue.pop()
652*1b3f573fSAndroid Build Coastguard Worker    assert this_method == self
653*1b3f573fSAndroid Build Coastguard Worker
654*1b3f573fSAndroid Build Coastguard Worker    # Determine if the tail of the queue is a group, or just a regular ordered
655*1b3f573fSAndroid Build Coastguard Worker    # mock method.
656*1b3f573fSAndroid Build Coastguard Worker    group = None
657*1b3f573fSAndroid Build Coastguard Worker    try:
658*1b3f573fSAndroid Build Coastguard Worker      group = self._call_queue[-1]
659*1b3f573fSAndroid Build Coastguard Worker    except IndexError:
660*1b3f573fSAndroid Build Coastguard Worker      pass
661*1b3f573fSAndroid Build Coastguard Worker
662*1b3f573fSAndroid Build Coastguard Worker    return group
663*1b3f573fSAndroid Build Coastguard Worker
664*1b3f573fSAndroid Build Coastguard Worker  def _CheckAndCreateNewGroup(self, group_name, group_class):
665*1b3f573fSAndroid Build Coastguard Worker    """Checks if the last method (a possible group) is an instance of our
666*1b3f573fSAndroid Build Coastguard Worker    group_class. Adds the current method to this group or creates a new one.
667*1b3f573fSAndroid Build Coastguard Worker
668*1b3f573fSAndroid Build Coastguard Worker    Args:
669*1b3f573fSAndroid Build Coastguard Worker
670*1b3f573fSAndroid Build Coastguard Worker      group_name: the name of the group.
671*1b3f573fSAndroid Build Coastguard Worker      group_class: the class used to create instance of this new group
672*1b3f573fSAndroid Build Coastguard Worker    """
673*1b3f573fSAndroid Build Coastguard Worker    group = self.GetPossibleGroup()
674*1b3f573fSAndroid Build Coastguard Worker
675*1b3f573fSAndroid Build Coastguard Worker    # If this is a group, and it is the correct group, add the method.
676*1b3f573fSAndroid Build Coastguard Worker    if isinstance(group, group_class) and group.group_name() == group_name:
677*1b3f573fSAndroid Build Coastguard Worker      group.AddMethod(self)
678*1b3f573fSAndroid Build Coastguard Worker      return self
679*1b3f573fSAndroid Build Coastguard Worker
680*1b3f573fSAndroid Build Coastguard Worker    # Create a new group and add the method.
681*1b3f573fSAndroid Build Coastguard Worker    new_group = group_class(group_name)
682*1b3f573fSAndroid Build Coastguard Worker    new_group.AddMethod(self)
683*1b3f573fSAndroid Build Coastguard Worker    self._call_queue.append(new_group)
684*1b3f573fSAndroid Build Coastguard Worker    return self
685*1b3f573fSAndroid Build Coastguard Worker
686*1b3f573fSAndroid Build Coastguard Worker  def InAnyOrder(self, group_name="default"):
687*1b3f573fSAndroid Build Coastguard Worker    """Move this method into a group of unordered calls.
688*1b3f573fSAndroid Build Coastguard Worker
689*1b3f573fSAndroid Build Coastguard Worker    A group of unordered calls must be defined together, and must be executed
690*1b3f573fSAndroid Build Coastguard Worker    in full before the next expected method can be called.  There can be
691*1b3f573fSAndroid Build Coastguard Worker    multiple groups that are expected serially, if they are given
692*1b3f573fSAndroid Build Coastguard Worker    different group names.  The same group name can be reused if there is a
693*1b3f573fSAndroid Build Coastguard Worker    standard method call, or a group with a different name, spliced between
694*1b3f573fSAndroid Build Coastguard Worker    usages.
695*1b3f573fSAndroid Build Coastguard Worker
696*1b3f573fSAndroid Build Coastguard Worker    Args:
697*1b3f573fSAndroid Build Coastguard Worker      group_name: the name of the unordered group.
698*1b3f573fSAndroid Build Coastguard Worker
699*1b3f573fSAndroid Build Coastguard Worker    Returns:
700*1b3f573fSAndroid Build Coastguard Worker      self
701*1b3f573fSAndroid Build Coastguard Worker    """
702*1b3f573fSAndroid Build Coastguard Worker    return self._CheckAndCreateNewGroup(group_name, UnorderedGroup)
703*1b3f573fSAndroid Build Coastguard Worker
704*1b3f573fSAndroid Build Coastguard Worker  def MultipleTimes(self, group_name="default"):
705*1b3f573fSAndroid Build Coastguard Worker    """Move this method into group of calls which may be called multiple times.
706*1b3f573fSAndroid Build Coastguard Worker
707*1b3f573fSAndroid Build Coastguard Worker    A group of repeating calls must be defined together, and must be executed in
708*1b3f573fSAndroid Build Coastguard Worker    full before the next expected method can be called.
709*1b3f573fSAndroid Build Coastguard Worker
710*1b3f573fSAndroid Build Coastguard Worker    Args:
711*1b3f573fSAndroid Build Coastguard Worker      group_name: the name of the unordered group.
712*1b3f573fSAndroid Build Coastguard Worker
713*1b3f573fSAndroid Build Coastguard Worker    Returns:
714*1b3f573fSAndroid Build Coastguard Worker      self
715*1b3f573fSAndroid Build Coastguard Worker    """
716*1b3f573fSAndroid Build Coastguard Worker    return self._CheckAndCreateNewGroup(group_name, MultipleTimesGroup)
717*1b3f573fSAndroid Build Coastguard Worker
718*1b3f573fSAndroid Build Coastguard Worker  def AndReturn(self, return_value):
719*1b3f573fSAndroid Build Coastguard Worker    """Set the value to return when this method is called.
720*1b3f573fSAndroid Build Coastguard Worker
721*1b3f573fSAndroid Build Coastguard Worker    Args:
722*1b3f573fSAndroid Build Coastguard Worker      # return_value can be anything.
723*1b3f573fSAndroid Build Coastguard Worker    """
724*1b3f573fSAndroid Build Coastguard Worker
725*1b3f573fSAndroid Build Coastguard Worker    self._return_value = return_value
726*1b3f573fSAndroid Build Coastguard Worker    return return_value
727*1b3f573fSAndroid Build Coastguard Worker
728*1b3f573fSAndroid Build Coastguard Worker  def AndRaise(self, exception):
729*1b3f573fSAndroid Build Coastguard Worker    """Set the exception to raise when this method is called.
730*1b3f573fSAndroid Build Coastguard Worker
731*1b3f573fSAndroid Build Coastguard Worker    Args:
732*1b3f573fSAndroid Build Coastguard Worker      # exception: the exception to raise when this method is called.
733*1b3f573fSAndroid Build Coastguard Worker      exception: Exception
734*1b3f573fSAndroid Build Coastguard Worker    """
735*1b3f573fSAndroid Build Coastguard Worker
736*1b3f573fSAndroid Build Coastguard Worker    self._exception = exception
737*1b3f573fSAndroid Build Coastguard Worker
738*1b3f573fSAndroid Build Coastguard Worker  def WithSideEffects(self, side_effects):
739*1b3f573fSAndroid Build Coastguard Worker    """Set the side effects that are simulated when this method is called.
740*1b3f573fSAndroid Build Coastguard Worker
741*1b3f573fSAndroid Build Coastguard Worker    Args:
742*1b3f573fSAndroid Build Coastguard Worker      side_effects: A callable which modifies the parameters or other relevant
743*1b3f573fSAndroid Build Coastguard Worker        state which a given test case depends on.
744*1b3f573fSAndroid Build Coastguard Worker
745*1b3f573fSAndroid Build Coastguard Worker    Returns:
746*1b3f573fSAndroid Build Coastguard Worker      Self for chaining with AndReturn and AndRaise.
747*1b3f573fSAndroid Build Coastguard Worker    """
748*1b3f573fSAndroid Build Coastguard Worker    self._side_effects = side_effects
749*1b3f573fSAndroid Build Coastguard Worker    return self
750*1b3f573fSAndroid Build Coastguard Worker
751*1b3f573fSAndroid Build Coastguard Workerclass Comparator:
752*1b3f573fSAndroid Build Coastguard Worker  """Base class for all Mox comparators.
753*1b3f573fSAndroid Build Coastguard Worker
754*1b3f573fSAndroid Build Coastguard Worker  A Comparator can be used as a parameter to a mocked method when the exact
755*1b3f573fSAndroid Build Coastguard Worker  value is not known.  For example, the code you are testing might build up a
756*1b3f573fSAndroid Build Coastguard Worker  long SQL string that is passed to your mock DAO. You're only interested that
757*1b3f573fSAndroid Build Coastguard Worker  the IN clause contains the proper primary keys, so you can set your mock
758*1b3f573fSAndroid Build Coastguard Worker  up as follows:
759*1b3f573fSAndroid Build Coastguard Worker
760*1b3f573fSAndroid Build Coastguard Worker  mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result)
761*1b3f573fSAndroid Build Coastguard Worker
762*1b3f573fSAndroid Build Coastguard Worker  Now whatever query is passed in must contain the string 'IN (1, 2, 4, 5)'.
763*1b3f573fSAndroid Build Coastguard Worker
764*1b3f573fSAndroid Build Coastguard Worker  A Comparator may replace one or more parameters, for example:
765*1b3f573fSAndroid Build Coastguard Worker  # return at most 10 rows
766*1b3f573fSAndroid Build Coastguard Worker  mock_dao.RunQuery(StrContains('SELECT'), 10)
767*1b3f573fSAndroid Build Coastguard Worker
768*1b3f573fSAndroid Build Coastguard Worker  or
769*1b3f573fSAndroid Build Coastguard Worker
770*1b3f573fSAndroid Build Coastguard Worker  # Return some non-deterministic number of rows
771*1b3f573fSAndroid Build Coastguard Worker  mock_dao.RunQuery(StrContains('SELECT'), IsA(int))
772*1b3f573fSAndroid Build Coastguard Worker  """
773*1b3f573fSAndroid Build Coastguard Worker
774*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
775*1b3f573fSAndroid Build Coastguard Worker    """Special equals method that all comparators must implement.
776*1b3f573fSAndroid Build Coastguard Worker
777*1b3f573fSAndroid Build Coastguard Worker    Args:
778*1b3f573fSAndroid Build Coastguard Worker      rhs: any python object
779*1b3f573fSAndroid Build Coastguard Worker    """
780*1b3f573fSAndroid Build Coastguard Worker
781*1b3f573fSAndroid Build Coastguard Worker    raise NotImplementedError('method must be implemented by a subclass.')
782*1b3f573fSAndroid Build Coastguard Worker
783*1b3f573fSAndroid Build Coastguard Worker  def __eq__(self, rhs):
784*1b3f573fSAndroid Build Coastguard Worker    return self.equals(rhs)
785*1b3f573fSAndroid Build Coastguard Worker
786*1b3f573fSAndroid Build Coastguard Worker  def __ne__(self, rhs):
787*1b3f573fSAndroid Build Coastguard Worker    return not self.equals(rhs)
788*1b3f573fSAndroid Build Coastguard Worker
789*1b3f573fSAndroid Build Coastguard Worker
790*1b3f573fSAndroid Build Coastguard Workerclass IsA(Comparator):
791*1b3f573fSAndroid Build Coastguard Worker  """This class wraps a basic Python type or class.  It is used to verify
792*1b3f573fSAndroid Build Coastguard Worker  that a parameter is of the given type or class.
793*1b3f573fSAndroid Build Coastguard Worker
794*1b3f573fSAndroid Build Coastguard Worker  Example:
795*1b3f573fSAndroid Build Coastguard Worker  mock_dao.Connect(IsA(DbConnectInfo))
796*1b3f573fSAndroid Build Coastguard Worker  """
797*1b3f573fSAndroid Build Coastguard Worker
798*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, class_name):
799*1b3f573fSAndroid Build Coastguard Worker    """Initialize IsA
800*1b3f573fSAndroid Build Coastguard Worker
801*1b3f573fSAndroid Build Coastguard Worker    Args:
802*1b3f573fSAndroid Build Coastguard Worker      class_name: basic python type or a class
803*1b3f573fSAndroid Build Coastguard Worker    """
804*1b3f573fSAndroid Build Coastguard Worker
805*1b3f573fSAndroid Build Coastguard Worker    self._class_name = class_name
806*1b3f573fSAndroid Build Coastguard Worker
807*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
808*1b3f573fSAndroid Build Coastguard Worker    """Check to see if the RHS is an instance of class_name.
809*1b3f573fSAndroid Build Coastguard Worker
810*1b3f573fSAndroid Build Coastguard Worker    Args:
811*1b3f573fSAndroid Build Coastguard Worker      # rhs: the right hand side of the test
812*1b3f573fSAndroid Build Coastguard Worker      rhs: object
813*1b3f573fSAndroid Build Coastguard Worker
814*1b3f573fSAndroid Build Coastguard Worker    Returns:
815*1b3f573fSAndroid Build Coastguard Worker      bool
816*1b3f573fSAndroid Build Coastguard Worker    """
817*1b3f573fSAndroid Build Coastguard Worker
818*1b3f573fSAndroid Build Coastguard Worker    try:
819*1b3f573fSAndroid Build Coastguard Worker      return isinstance(rhs, self._class_name)
820*1b3f573fSAndroid Build Coastguard Worker    except TypeError:
821*1b3f573fSAndroid Build Coastguard Worker      # Check raw types if there was a type error.  This is helpful for
822*1b3f573fSAndroid Build Coastguard Worker      # things like cStringIO.StringIO.
823*1b3f573fSAndroid Build Coastguard Worker      return type(rhs) == type(self._class_name)
824*1b3f573fSAndroid Build Coastguard Worker
825*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
826*1b3f573fSAndroid Build Coastguard Worker    return str(self._class_name)
827*1b3f573fSAndroid Build Coastguard Worker
828*1b3f573fSAndroid Build Coastguard Workerclass IsAlmost(Comparator):
829*1b3f573fSAndroid Build Coastguard Worker  """Comparison class used to check whether a parameter is nearly equal
830*1b3f573fSAndroid Build Coastguard Worker  to a given value.  Generally useful for floating point numbers.
831*1b3f573fSAndroid Build Coastguard Worker
832*1b3f573fSAndroid Build Coastguard Worker  Example mock_dao.SetTimeout((IsAlmost(3.9)))
833*1b3f573fSAndroid Build Coastguard Worker  """
834*1b3f573fSAndroid Build Coastguard Worker
835*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, float_value, places=7):
836*1b3f573fSAndroid Build Coastguard Worker    """Initialize IsAlmost.
837*1b3f573fSAndroid Build Coastguard Worker
838*1b3f573fSAndroid Build Coastguard Worker    Args:
839*1b3f573fSAndroid Build Coastguard Worker      float_value: The value for making the comparison.
840*1b3f573fSAndroid Build Coastguard Worker      places: The number of decimal places to round to.
841*1b3f573fSAndroid Build Coastguard Worker    """
842*1b3f573fSAndroid Build Coastguard Worker
843*1b3f573fSAndroid Build Coastguard Worker    self._float_value = float_value
844*1b3f573fSAndroid Build Coastguard Worker    self._places = places
845*1b3f573fSAndroid Build Coastguard Worker
846*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
847*1b3f573fSAndroid Build Coastguard Worker    """Check to see if RHS is almost equal to float_value
848*1b3f573fSAndroid Build Coastguard Worker
849*1b3f573fSAndroid Build Coastguard Worker    Args:
850*1b3f573fSAndroid Build Coastguard Worker      rhs: the value to compare to float_value
851*1b3f573fSAndroid Build Coastguard Worker
852*1b3f573fSAndroid Build Coastguard Worker    Returns:
853*1b3f573fSAndroid Build Coastguard Worker      bool
854*1b3f573fSAndroid Build Coastguard Worker    """
855*1b3f573fSAndroid Build Coastguard Worker
856*1b3f573fSAndroid Build Coastguard Worker    try:
857*1b3f573fSAndroid Build Coastguard Worker      return round(rhs-self._float_value, self._places) == 0
858*1b3f573fSAndroid Build Coastguard Worker    except TypeError:
859*1b3f573fSAndroid Build Coastguard Worker      # This is probably because either float_value or rhs is not a number.
860*1b3f573fSAndroid Build Coastguard Worker      return False
861*1b3f573fSAndroid Build Coastguard Worker
862*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
863*1b3f573fSAndroid Build Coastguard Worker    return str(self._float_value)
864*1b3f573fSAndroid Build Coastguard Worker
865*1b3f573fSAndroid Build Coastguard Workerclass StrContains(Comparator):
866*1b3f573fSAndroid Build Coastguard Worker  """Comparison class used to check whether a substring exists in a
867*1b3f573fSAndroid Build Coastguard Worker  string parameter.  This can be useful in mocking a database with SQL
868*1b3f573fSAndroid Build Coastguard Worker  passed in as a string parameter, for example.
869*1b3f573fSAndroid Build Coastguard Worker
870*1b3f573fSAndroid Build Coastguard Worker  Example:
871*1b3f573fSAndroid Build Coastguard Worker  mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result)
872*1b3f573fSAndroid Build Coastguard Worker  """
873*1b3f573fSAndroid Build Coastguard Worker
874*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, search_string):
875*1b3f573fSAndroid Build Coastguard Worker    """Initialize.
876*1b3f573fSAndroid Build Coastguard Worker
877*1b3f573fSAndroid Build Coastguard Worker    Args:
878*1b3f573fSAndroid Build Coastguard Worker      # search_string: the string you are searching for
879*1b3f573fSAndroid Build Coastguard Worker      search_string: str
880*1b3f573fSAndroid Build Coastguard Worker    """
881*1b3f573fSAndroid Build Coastguard Worker
882*1b3f573fSAndroid Build Coastguard Worker    self._search_string = search_string
883*1b3f573fSAndroid Build Coastguard Worker
884*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
885*1b3f573fSAndroid Build Coastguard Worker    """Check to see if the search_string is contained in the rhs string.
886*1b3f573fSAndroid Build Coastguard Worker
887*1b3f573fSAndroid Build Coastguard Worker    Args:
888*1b3f573fSAndroid Build Coastguard Worker      # rhs: the right hand side of the test
889*1b3f573fSAndroid Build Coastguard Worker      rhs: object
890*1b3f573fSAndroid Build Coastguard Worker
891*1b3f573fSAndroid Build Coastguard Worker    Returns:
892*1b3f573fSAndroid Build Coastguard Worker      bool
893*1b3f573fSAndroid Build Coastguard Worker    """
894*1b3f573fSAndroid Build Coastguard Worker
895*1b3f573fSAndroid Build Coastguard Worker    try:
896*1b3f573fSAndroid Build Coastguard Worker      return rhs.find(self._search_string) > -1
897*1b3f573fSAndroid Build Coastguard Worker    except Exception:
898*1b3f573fSAndroid Build Coastguard Worker      return False
899*1b3f573fSAndroid Build Coastguard Worker
900*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
901*1b3f573fSAndroid Build Coastguard Worker    return '<str containing \'%s\'>' % self._search_string
902*1b3f573fSAndroid Build Coastguard Worker
903*1b3f573fSAndroid Build Coastguard Worker
904*1b3f573fSAndroid Build Coastguard Workerclass Regex(Comparator):
905*1b3f573fSAndroid Build Coastguard Worker  """Checks if a string matches a regular expression.
906*1b3f573fSAndroid Build Coastguard Worker
907*1b3f573fSAndroid Build Coastguard Worker  This uses a given regular expression to determine equality.
908*1b3f573fSAndroid Build Coastguard Worker  """
909*1b3f573fSAndroid Build Coastguard Worker
910*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, pattern, flags=0):
911*1b3f573fSAndroid Build Coastguard Worker    """Initialize.
912*1b3f573fSAndroid Build Coastguard Worker
913*1b3f573fSAndroid Build Coastguard Worker    Args:
914*1b3f573fSAndroid Build Coastguard Worker      # pattern is the regular expression to search for
915*1b3f573fSAndroid Build Coastguard Worker      pattern: str
916*1b3f573fSAndroid Build Coastguard Worker      # flags passed to re.compile function as the second argument
917*1b3f573fSAndroid Build Coastguard Worker      flags: int
918*1b3f573fSAndroid Build Coastguard Worker    """
919*1b3f573fSAndroid Build Coastguard Worker
920*1b3f573fSAndroid Build Coastguard Worker    self.regex = re.compile(pattern, flags=flags)
921*1b3f573fSAndroid Build Coastguard Worker
922*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
923*1b3f573fSAndroid Build Coastguard Worker    """Check to see if rhs matches regular expression pattern.
924*1b3f573fSAndroid Build Coastguard Worker
925*1b3f573fSAndroid Build Coastguard Worker    Returns:
926*1b3f573fSAndroid Build Coastguard Worker      bool
927*1b3f573fSAndroid Build Coastguard Worker    """
928*1b3f573fSAndroid Build Coastguard Worker
929*1b3f573fSAndroid Build Coastguard Worker    return self.regex.search(rhs) is not None
930*1b3f573fSAndroid Build Coastguard Worker
931*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
932*1b3f573fSAndroid Build Coastguard Worker    s = '<regular expression \'%s\'' % self.regex.pattern
933*1b3f573fSAndroid Build Coastguard Worker    if self.regex.flags:
934*1b3f573fSAndroid Build Coastguard Worker      s += ', flags=%d' % self.regex.flags
935*1b3f573fSAndroid Build Coastguard Worker    s += '>'
936*1b3f573fSAndroid Build Coastguard Worker    return s
937*1b3f573fSAndroid Build Coastguard Worker
938*1b3f573fSAndroid Build Coastguard Worker
939*1b3f573fSAndroid Build Coastguard Workerclass In(Comparator):
940*1b3f573fSAndroid Build Coastguard Worker  """Checks whether an item (or key) is in a list (or dict) parameter.
941*1b3f573fSAndroid Build Coastguard Worker
942*1b3f573fSAndroid Build Coastguard Worker  Example:
943*1b3f573fSAndroid Build Coastguard Worker  mock_dao.GetUsersInfo(In('expectedUserName')).AndReturn(mock_result)
944*1b3f573fSAndroid Build Coastguard Worker  """
945*1b3f573fSAndroid Build Coastguard Worker
946*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, key):
947*1b3f573fSAndroid Build Coastguard Worker    """Initialize.
948*1b3f573fSAndroid Build Coastguard Worker
949*1b3f573fSAndroid Build Coastguard Worker    Args:
950*1b3f573fSAndroid Build Coastguard Worker      # key is any thing that could be in a list or a key in a dict
951*1b3f573fSAndroid Build Coastguard Worker    """
952*1b3f573fSAndroid Build Coastguard Worker
953*1b3f573fSAndroid Build Coastguard Worker    self._key = key
954*1b3f573fSAndroid Build Coastguard Worker
955*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
956*1b3f573fSAndroid Build Coastguard Worker    """Check to see whether key is in rhs.
957*1b3f573fSAndroid Build Coastguard Worker
958*1b3f573fSAndroid Build Coastguard Worker    Args:
959*1b3f573fSAndroid Build Coastguard Worker      rhs: dict
960*1b3f573fSAndroid Build Coastguard Worker
961*1b3f573fSAndroid Build Coastguard Worker    Returns:
962*1b3f573fSAndroid Build Coastguard Worker      bool
963*1b3f573fSAndroid Build Coastguard Worker    """
964*1b3f573fSAndroid Build Coastguard Worker
965*1b3f573fSAndroid Build Coastguard Worker    return self._key in rhs
966*1b3f573fSAndroid Build Coastguard Worker
967*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
968*1b3f573fSAndroid Build Coastguard Worker    return '<sequence or map containing \'%s\'>' % self._key
969*1b3f573fSAndroid Build Coastguard Worker
970*1b3f573fSAndroid Build Coastguard Worker
971*1b3f573fSAndroid Build Coastguard Workerclass ContainsKeyValue(Comparator):
972*1b3f573fSAndroid Build Coastguard Worker  """Checks whether a key/value pair is in a dict parameter.
973*1b3f573fSAndroid Build Coastguard Worker
974*1b3f573fSAndroid Build Coastguard Worker  Example:
975*1b3f573fSAndroid Build Coastguard Worker  mock_dao.UpdateUsers(ContainsKeyValue('stevepm', stevepm_user_info))
976*1b3f573fSAndroid Build Coastguard Worker  """
977*1b3f573fSAndroid Build Coastguard Worker
978*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, key, value):
979*1b3f573fSAndroid Build Coastguard Worker    """Initialize.
980*1b3f573fSAndroid Build Coastguard Worker
981*1b3f573fSAndroid Build Coastguard Worker    Args:
982*1b3f573fSAndroid Build Coastguard Worker      # key: a key in a dict
983*1b3f573fSAndroid Build Coastguard Worker      # value: the corresponding value
984*1b3f573fSAndroid Build Coastguard Worker    """
985*1b3f573fSAndroid Build Coastguard Worker
986*1b3f573fSAndroid Build Coastguard Worker    self._key = key
987*1b3f573fSAndroid Build Coastguard Worker    self._value = value
988*1b3f573fSAndroid Build Coastguard Worker
989*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
990*1b3f573fSAndroid Build Coastguard Worker    """Check whether the given key/value pair is in the rhs dict.
991*1b3f573fSAndroid Build Coastguard Worker
992*1b3f573fSAndroid Build Coastguard Worker    Returns:
993*1b3f573fSAndroid Build Coastguard Worker      bool
994*1b3f573fSAndroid Build Coastguard Worker    """
995*1b3f573fSAndroid Build Coastguard Worker
996*1b3f573fSAndroid Build Coastguard Worker    try:
997*1b3f573fSAndroid Build Coastguard Worker      return rhs[self._key] == self._value
998*1b3f573fSAndroid Build Coastguard Worker    except Exception:
999*1b3f573fSAndroid Build Coastguard Worker      return False
1000*1b3f573fSAndroid Build Coastguard Worker
1001*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
1002*1b3f573fSAndroid Build Coastguard Worker    return '<map containing the entry \'%s: %s\'>' % (self._key, self._value)
1003*1b3f573fSAndroid Build Coastguard Worker
1004*1b3f573fSAndroid Build Coastguard Worker
1005*1b3f573fSAndroid Build Coastguard Workerclass SameElementsAs(Comparator):
1006*1b3f573fSAndroid Build Coastguard Worker  """Checks whether iterables contain the same elements (ignoring order).
1007*1b3f573fSAndroid Build Coastguard Worker
1008*1b3f573fSAndroid Build Coastguard Worker  Example:
1009*1b3f573fSAndroid Build Coastguard Worker  mock_dao.ProcessUsers(SameElementsAs('stevepm', 'salomaki'))
1010*1b3f573fSAndroid Build Coastguard Worker  """
1011*1b3f573fSAndroid Build Coastguard Worker
1012*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, expected_seq):
1013*1b3f573fSAndroid Build Coastguard Worker    """Initialize.
1014*1b3f573fSAndroid Build Coastguard Worker
1015*1b3f573fSAndroid Build Coastguard Worker    Args:
1016*1b3f573fSAndroid Build Coastguard Worker      expected_seq: a sequence
1017*1b3f573fSAndroid Build Coastguard Worker    """
1018*1b3f573fSAndroid Build Coastguard Worker
1019*1b3f573fSAndroid Build Coastguard Worker    self._expected_seq = expected_seq
1020*1b3f573fSAndroid Build Coastguard Worker
1021*1b3f573fSAndroid Build Coastguard Worker  def equals(self, actual_seq):
1022*1b3f573fSAndroid Build Coastguard Worker    """Check to see whether actual_seq has same elements as expected_seq.
1023*1b3f573fSAndroid Build Coastguard Worker
1024*1b3f573fSAndroid Build Coastguard Worker    Args:
1025*1b3f573fSAndroid Build Coastguard Worker      actual_seq: sequence
1026*1b3f573fSAndroid Build Coastguard Worker
1027*1b3f573fSAndroid Build Coastguard Worker    Returns:
1028*1b3f573fSAndroid Build Coastguard Worker      bool
1029*1b3f573fSAndroid Build Coastguard Worker    """
1030*1b3f573fSAndroid Build Coastguard Worker
1031*1b3f573fSAndroid Build Coastguard Worker    try:
1032*1b3f573fSAndroid Build Coastguard Worker      expected = dict([(element, None) for element in self._expected_seq])
1033*1b3f573fSAndroid Build Coastguard Worker      actual = dict([(element, None) for element in actual_seq])
1034*1b3f573fSAndroid Build Coastguard Worker    except TypeError:
1035*1b3f573fSAndroid Build Coastguard Worker      # Fall back to slower list-compare if any of the objects are unhashable.
1036*1b3f573fSAndroid Build Coastguard Worker      expected = list(self._expected_seq)
1037*1b3f573fSAndroid Build Coastguard Worker      actual = list(actual_seq)
1038*1b3f573fSAndroid Build Coastguard Worker      expected.sort()
1039*1b3f573fSAndroid Build Coastguard Worker      actual.sort()
1040*1b3f573fSAndroid Build Coastguard Worker    return expected == actual
1041*1b3f573fSAndroid Build Coastguard Worker
1042*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
1043*1b3f573fSAndroid Build Coastguard Worker    return '<sequence with same elements as \'%s\'>' % self._expected_seq
1044*1b3f573fSAndroid Build Coastguard Worker
1045*1b3f573fSAndroid Build Coastguard Worker
1046*1b3f573fSAndroid Build Coastguard Workerclass And(Comparator):
1047*1b3f573fSAndroid Build Coastguard Worker  """Evaluates one or more Comparators on RHS and returns an AND of the results.
1048*1b3f573fSAndroid Build Coastguard Worker  """
1049*1b3f573fSAndroid Build Coastguard Worker
1050*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, *args):
1051*1b3f573fSAndroid Build Coastguard Worker    """Initialize.
1052*1b3f573fSAndroid Build Coastguard Worker
1053*1b3f573fSAndroid Build Coastguard Worker    Args:
1054*1b3f573fSAndroid Build Coastguard Worker      *args: One or more Comparator
1055*1b3f573fSAndroid Build Coastguard Worker    """
1056*1b3f573fSAndroid Build Coastguard Worker
1057*1b3f573fSAndroid Build Coastguard Worker    self._comparators = args
1058*1b3f573fSAndroid Build Coastguard Worker
1059*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
1060*1b3f573fSAndroid Build Coastguard Worker    """Checks whether all Comparators are equal to rhs.
1061*1b3f573fSAndroid Build Coastguard Worker
1062*1b3f573fSAndroid Build Coastguard Worker    Args:
1063*1b3f573fSAndroid Build Coastguard Worker      # rhs: can be anything
1064*1b3f573fSAndroid Build Coastguard Worker
1065*1b3f573fSAndroid Build Coastguard Worker    Returns:
1066*1b3f573fSAndroid Build Coastguard Worker      bool
1067*1b3f573fSAndroid Build Coastguard Worker    """
1068*1b3f573fSAndroid Build Coastguard Worker
1069*1b3f573fSAndroid Build Coastguard Worker    for comparator in self._comparators:
1070*1b3f573fSAndroid Build Coastguard Worker      if not comparator.equals(rhs):
1071*1b3f573fSAndroid Build Coastguard Worker        return False
1072*1b3f573fSAndroid Build Coastguard Worker
1073*1b3f573fSAndroid Build Coastguard Worker    return True
1074*1b3f573fSAndroid Build Coastguard Worker
1075*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
1076*1b3f573fSAndroid Build Coastguard Worker    return '<AND %s>' % str(self._comparators)
1077*1b3f573fSAndroid Build Coastguard Worker
1078*1b3f573fSAndroid Build Coastguard Worker
1079*1b3f573fSAndroid Build Coastguard Workerclass Or(Comparator):
1080*1b3f573fSAndroid Build Coastguard Worker  """Evaluates one or more Comparators on RHS and returns an OR of the results.
1081*1b3f573fSAndroid Build Coastguard Worker  """
1082*1b3f573fSAndroid Build Coastguard Worker
1083*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, *args):
1084*1b3f573fSAndroid Build Coastguard Worker    """Initialize.
1085*1b3f573fSAndroid Build Coastguard Worker
1086*1b3f573fSAndroid Build Coastguard Worker    Args:
1087*1b3f573fSAndroid Build Coastguard Worker      *args: One or more Mox comparators
1088*1b3f573fSAndroid Build Coastguard Worker    """
1089*1b3f573fSAndroid Build Coastguard Worker
1090*1b3f573fSAndroid Build Coastguard Worker    self._comparators = args
1091*1b3f573fSAndroid Build Coastguard Worker
1092*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
1093*1b3f573fSAndroid Build Coastguard Worker    """Checks whether any Comparator is equal to rhs.
1094*1b3f573fSAndroid Build Coastguard Worker
1095*1b3f573fSAndroid Build Coastguard Worker    Args:
1096*1b3f573fSAndroid Build Coastguard Worker      # rhs: can be anything
1097*1b3f573fSAndroid Build Coastguard Worker
1098*1b3f573fSAndroid Build Coastguard Worker    Returns:
1099*1b3f573fSAndroid Build Coastguard Worker      bool
1100*1b3f573fSAndroid Build Coastguard Worker    """
1101*1b3f573fSAndroid Build Coastguard Worker
1102*1b3f573fSAndroid Build Coastguard Worker    for comparator in self._comparators:
1103*1b3f573fSAndroid Build Coastguard Worker      if comparator.equals(rhs):
1104*1b3f573fSAndroid Build Coastguard Worker        return True
1105*1b3f573fSAndroid Build Coastguard Worker
1106*1b3f573fSAndroid Build Coastguard Worker    return False
1107*1b3f573fSAndroid Build Coastguard Worker
1108*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
1109*1b3f573fSAndroid Build Coastguard Worker    return '<OR %s>' % str(self._comparators)
1110*1b3f573fSAndroid Build Coastguard Worker
1111*1b3f573fSAndroid Build Coastguard Worker
1112*1b3f573fSAndroid Build Coastguard Workerclass Func(Comparator):
1113*1b3f573fSAndroid Build Coastguard Worker  """Call a function that should verify the parameter passed in is correct.
1114*1b3f573fSAndroid Build Coastguard Worker
1115*1b3f573fSAndroid Build Coastguard Worker  You may need the ability to perform more advanced operations on the parameter
1116*1b3f573fSAndroid Build Coastguard Worker  in order to validate it.  You can use this to have a callable validate any
1117*1b3f573fSAndroid Build Coastguard Worker  parameter. The callable should return either True or False.
1118*1b3f573fSAndroid Build Coastguard Worker
1119*1b3f573fSAndroid Build Coastguard Worker
1120*1b3f573fSAndroid Build Coastguard Worker  Example:
1121*1b3f573fSAndroid Build Coastguard Worker
1122*1b3f573fSAndroid Build Coastguard Worker  def myParamValidator(param):
1123*1b3f573fSAndroid Build Coastguard Worker    # Advanced logic here
1124*1b3f573fSAndroid Build Coastguard Worker    return True
1125*1b3f573fSAndroid Build Coastguard Worker
1126*1b3f573fSAndroid Build Coastguard Worker  mock_dao.DoSomething(Func(myParamValidator), true)
1127*1b3f573fSAndroid Build Coastguard Worker  """
1128*1b3f573fSAndroid Build Coastguard Worker
1129*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, func):
1130*1b3f573fSAndroid Build Coastguard Worker    """Initialize.
1131*1b3f573fSAndroid Build Coastguard Worker
1132*1b3f573fSAndroid Build Coastguard Worker    Args:
1133*1b3f573fSAndroid Build Coastguard Worker      func: callable that takes one parameter and returns a bool
1134*1b3f573fSAndroid Build Coastguard Worker    """
1135*1b3f573fSAndroid Build Coastguard Worker
1136*1b3f573fSAndroid Build Coastguard Worker    self._func = func
1137*1b3f573fSAndroid Build Coastguard Worker
1138*1b3f573fSAndroid Build Coastguard Worker  def equals(self, rhs):
1139*1b3f573fSAndroid Build Coastguard Worker    """Test whether rhs passes the function test.
1140*1b3f573fSAndroid Build Coastguard Worker
1141*1b3f573fSAndroid Build Coastguard Worker    rhs is passed into func.
1142*1b3f573fSAndroid Build Coastguard Worker
1143*1b3f573fSAndroid Build Coastguard Worker    Args:
1144*1b3f573fSAndroid Build Coastguard Worker      rhs: any python object
1145*1b3f573fSAndroid Build Coastguard Worker
1146*1b3f573fSAndroid Build Coastguard Worker    Returns:
1147*1b3f573fSAndroid Build Coastguard Worker      the result of func(rhs)
1148*1b3f573fSAndroid Build Coastguard Worker    """
1149*1b3f573fSAndroid Build Coastguard Worker
1150*1b3f573fSAndroid Build Coastguard Worker    return self._func(rhs)
1151*1b3f573fSAndroid Build Coastguard Worker
1152*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
1153*1b3f573fSAndroid Build Coastguard Worker    return str(self._func)
1154*1b3f573fSAndroid Build Coastguard Worker
1155*1b3f573fSAndroid Build Coastguard Worker
1156*1b3f573fSAndroid Build Coastguard Workerclass IgnoreArg(Comparator):
1157*1b3f573fSAndroid Build Coastguard Worker  """Ignore an argument.
1158*1b3f573fSAndroid Build Coastguard Worker
1159*1b3f573fSAndroid Build Coastguard Worker  This can be used when we don't care about an argument of a method call.
1160*1b3f573fSAndroid Build Coastguard Worker
1161*1b3f573fSAndroid Build Coastguard Worker  Example:
1162*1b3f573fSAndroid Build Coastguard Worker  # Check if CastMagic is called with 3 as first arg and 'disappear' as third.
1163*1b3f573fSAndroid Build Coastguard Worker  mymock.CastMagic(3, IgnoreArg(), 'disappear')
1164*1b3f573fSAndroid Build Coastguard Worker  """
1165*1b3f573fSAndroid Build Coastguard Worker
1166*1b3f573fSAndroid Build Coastguard Worker  def equals(self, unused_rhs):
1167*1b3f573fSAndroid Build Coastguard Worker    """Ignores arguments and returns True.
1168*1b3f573fSAndroid Build Coastguard Worker
1169*1b3f573fSAndroid Build Coastguard Worker    Args:
1170*1b3f573fSAndroid Build Coastguard Worker      unused_rhs: any python object
1171*1b3f573fSAndroid Build Coastguard Worker
1172*1b3f573fSAndroid Build Coastguard Worker    Returns:
1173*1b3f573fSAndroid Build Coastguard Worker      always returns True
1174*1b3f573fSAndroid Build Coastguard Worker    """
1175*1b3f573fSAndroid Build Coastguard Worker
1176*1b3f573fSAndroid Build Coastguard Worker    return True
1177*1b3f573fSAndroid Build Coastguard Worker
1178*1b3f573fSAndroid Build Coastguard Worker  def __repr__(self):
1179*1b3f573fSAndroid Build Coastguard Worker    return '<IgnoreArg>'
1180*1b3f573fSAndroid Build Coastguard Worker
1181*1b3f573fSAndroid Build Coastguard Worker
1182*1b3f573fSAndroid Build Coastguard Workerclass MethodGroup(object):
1183*1b3f573fSAndroid Build Coastguard Worker  """Base class containing common behaviour for MethodGroups."""
1184*1b3f573fSAndroid Build Coastguard Worker
1185*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, group_name):
1186*1b3f573fSAndroid Build Coastguard Worker    self._group_name = group_name
1187*1b3f573fSAndroid Build Coastguard Worker
1188*1b3f573fSAndroid Build Coastguard Worker  def group_name(self):
1189*1b3f573fSAndroid Build Coastguard Worker    return self._group_name
1190*1b3f573fSAndroid Build Coastguard Worker
1191*1b3f573fSAndroid Build Coastguard Worker  def __str__(self):
1192*1b3f573fSAndroid Build Coastguard Worker    return '<%s "%s">' % (self.__class__.__name__, self._group_name)
1193*1b3f573fSAndroid Build Coastguard Worker
1194*1b3f573fSAndroid Build Coastguard Worker  def AddMethod(self, mock_method):
1195*1b3f573fSAndroid Build Coastguard Worker    raise NotImplementedError
1196*1b3f573fSAndroid Build Coastguard Worker
1197*1b3f573fSAndroid Build Coastguard Worker  def MethodCalled(self, mock_method):
1198*1b3f573fSAndroid Build Coastguard Worker    raise NotImplementedError
1199*1b3f573fSAndroid Build Coastguard Worker
1200*1b3f573fSAndroid Build Coastguard Worker  def IsSatisfied(self):
1201*1b3f573fSAndroid Build Coastguard Worker    raise NotImplementedError
1202*1b3f573fSAndroid Build Coastguard Worker
1203*1b3f573fSAndroid Build Coastguard Workerclass UnorderedGroup(MethodGroup):
1204*1b3f573fSAndroid Build Coastguard Worker  """UnorderedGroup holds a set of method calls that may occur in any order.
1205*1b3f573fSAndroid Build Coastguard Worker
1206*1b3f573fSAndroid Build Coastguard Worker  This construct is helpful for non-deterministic events, such as iterating
1207*1b3f573fSAndroid Build Coastguard Worker  over the keys of a dict.
1208*1b3f573fSAndroid Build Coastguard Worker  """
1209*1b3f573fSAndroid Build Coastguard Worker
1210*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, group_name):
1211*1b3f573fSAndroid Build Coastguard Worker    super(UnorderedGroup, self).__init__(group_name)
1212*1b3f573fSAndroid Build Coastguard Worker    self._methods = []
1213*1b3f573fSAndroid Build Coastguard Worker
1214*1b3f573fSAndroid Build Coastguard Worker  def AddMethod(self, mock_method):
1215*1b3f573fSAndroid Build Coastguard Worker    """Add a method to this group.
1216*1b3f573fSAndroid Build Coastguard Worker
1217*1b3f573fSAndroid Build Coastguard Worker    Args:
1218*1b3f573fSAndroid Build Coastguard Worker      mock_method: A mock method to be added to this group.
1219*1b3f573fSAndroid Build Coastguard Worker    """
1220*1b3f573fSAndroid Build Coastguard Worker
1221*1b3f573fSAndroid Build Coastguard Worker    self._methods.append(mock_method)
1222*1b3f573fSAndroid Build Coastguard Worker
1223*1b3f573fSAndroid Build Coastguard Worker  def MethodCalled(self, mock_method):
1224*1b3f573fSAndroid Build Coastguard Worker    """Remove a method call from the group.
1225*1b3f573fSAndroid Build Coastguard Worker
1226*1b3f573fSAndroid Build Coastguard Worker    If the method is not in the set, an UnexpectedMethodCallError will be
1227*1b3f573fSAndroid Build Coastguard Worker    raised.
1228*1b3f573fSAndroid Build Coastguard Worker
1229*1b3f573fSAndroid Build Coastguard Worker    Args:
1230*1b3f573fSAndroid Build Coastguard Worker      mock_method: a mock method that should be equal to a method in the group.
1231*1b3f573fSAndroid Build Coastguard Worker
1232*1b3f573fSAndroid Build Coastguard Worker    Returns:
1233*1b3f573fSAndroid Build Coastguard Worker      The mock method from the group
1234*1b3f573fSAndroid Build Coastguard Worker
1235*1b3f573fSAndroid Build Coastguard Worker    Raises:
1236*1b3f573fSAndroid Build Coastguard Worker      UnexpectedMethodCallError if the mock_method was not in the group.
1237*1b3f573fSAndroid Build Coastguard Worker    """
1238*1b3f573fSAndroid Build Coastguard Worker
1239*1b3f573fSAndroid Build Coastguard Worker    # Check to see if this method exists, and if so, remove it from the set
1240*1b3f573fSAndroid Build Coastguard Worker    # and return it.
1241*1b3f573fSAndroid Build Coastguard Worker    for method in self._methods:
1242*1b3f573fSAndroid Build Coastguard Worker      if method == mock_method:
1243*1b3f573fSAndroid Build Coastguard Worker        # Remove the called mock_method instead of the method in the group.
1244*1b3f573fSAndroid Build Coastguard Worker        # The called method will match any comparators when equality is checked
1245*1b3f573fSAndroid Build Coastguard Worker        # during removal.  The method in the group could pass a comparator to
1246*1b3f573fSAndroid Build Coastguard Worker        # another comparator during the equality check.
1247*1b3f573fSAndroid Build Coastguard Worker        self._methods.remove(mock_method)
1248*1b3f573fSAndroid Build Coastguard Worker
1249*1b3f573fSAndroid Build Coastguard Worker        # If this group is not empty, put it back at the head of the queue.
1250*1b3f573fSAndroid Build Coastguard Worker        if not self.IsSatisfied():
1251*1b3f573fSAndroid Build Coastguard Worker          mock_method._call_queue.appendleft(self)
1252*1b3f573fSAndroid Build Coastguard Worker
1253*1b3f573fSAndroid Build Coastguard Worker        return self, method
1254*1b3f573fSAndroid Build Coastguard Worker
1255*1b3f573fSAndroid Build Coastguard Worker    raise UnexpectedMethodCallError(mock_method, self)
1256*1b3f573fSAndroid Build Coastguard Worker
1257*1b3f573fSAndroid Build Coastguard Worker  def IsSatisfied(self):
1258*1b3f573fSAndroid Build Coastguard Worker    """Return True if there are not any methods in this group."""
1259*1b3f573fSAndroid Build Coastguard Worker
1260*1b3f573fSAndroid Build Coastguard Worker    return len(self._methods) == 0
1261*1b3f573fSAndroid Build Coastguard Worker
1262*1b3f573fSAndroid Build Coastguard Worker
1263*1b3f573fSAndroid Build Coastguard Workerclass MultipleTimesGroup(MethodGroup):
1264*1b3f573fSAndroid Build Coastguard Worker  """MultipleTimesGroup holds methods that may be called any number of times.
1265*1b3f573fSAndroid Build Coastguard Worker
1266*1b3f573fSAndroid Build Coastguard Worker  Note: Each method must be called at least once.
1267*1b3f573fSAndroid Build Coastguard Worker
1268*1b3f573fSAndroid Build Coastguard Worker  This is helpful, if you don't know or care how many times a method is called.
1269*1b3f573fSAndroid Build Coastguard Worker  """
1270*1b3f573fSAndroid Build Coastguard Worker
1271*1b3f573fSAndroid Build Coastguard Worker  def __init__(self, group_name):
1272*1b3f573fSAndroid Build Coastguard Worker    super(MultipleTimesGroup, self).__init__(group_name)
1273*1b3f573fSAndroid Build Coastguard Worker    self._methods = set()
1274*1b3f573fSAndroid Build Coastguard Worker    self._methods_called = set()
1275*1b3f573fSAndroid Build Coastguard Worker
1276*1b3f573fSAndroid Build Coastguard Worker  def AddMethod(self, mock_method):
1277*1b3f573fSAndroid Build Coastguard Worker    """Add a method to this group.
1278*1b3f573fSAndroid Build Coastguard Worker
1279*1b3f573fSAndroid Build Coastguard Worker    Args:
1280*1b3f573fSAndroid Build Coastguard Worker      mock_method: A mock method to be added to this group.
1281*1b3f573fSAndroid Build Coastguard Worker    """
1282*1b3f573fSAndroid Build Coastguard Worker
1283*1b3f573fSAndroid Build Coastguard Worker    self._methods.add(mock_method)
1284*1b3f573fSAndroid Build Coastguard Worker
1285*1b3f573fSAndroid Build Coastguard Worker  def MethodCalled(self, mock_method):
1286*1b3f573fSAndroid Build Coastguard Worker    """Remove a method call from the group.
1287*1b3f573fSAndroid Build Coastguard Worker
1288*1b3f573fSAndroid Build Coastguard Worker    If the method is not in the set, an UnexpectedMethodCallError will be
1289*1b3f573fSAndroid Build Coastguard Worker    raised.
1290*1b3f573fSAndroid Build Coastguard Worker
1291*1b3f573fSAndroid Build Coastguard Worker    Args:
1292*1b3f573fSAndroid Build Coastguard Worker      mock_method: a mock method that should be equal to a method in the group.
1293*1b3f573fSAndroid Build Coastguard Worker
1294*1b3f573fSAndroid Build Coastguard Worker    Returns:
1295*1b3f573fSAndroid Build Coastguard Worker      The mock method from the group
1296*1b3f573fSAndroid Build Coastguard Worker
1297*1b3f573fSAndroid Build Coastguard Worker    Raises:
1298*1b3f573fSAndroid Build Coastguard Worker      UnexpectedMethodCallError if the mock_method was not in the group.
1299*1b3f573fSAndroid Build Coastguard Worker    """
1300*1b3f573fSAndroid Build Coastguard Worker
1301*1b3f573fSAndroid Build Coastguard Worker    # Check to see if this method exists, and if so add it to the set of
1302*1b3f573fSAndroid Build Coastguard Worker    # called methods.
1303*1b3f573fSAndroid Build Coastguard Worker
1304*1b3f573fSAndroid Build Coastguard Worker    for method in self._methods:
1305*1b3f573fSAndroid Build Coastguard Worker      if method == mock_method:
1306*1b3f573fSAndroid Build Coastguard Worker        self._methods_called.add(mock_method)
1307*1b3f573fSAndroid Build Coastguard Worker        # Always put this group back on top of the queue, because we don't know
1308*1b3f573fSAndroid Build Coastguard Worker        # when we are done.
1309*1b3f573fSAndroid Build Coastguard Worker        mock_method._call_queue.appendleft(self)
1310*1b3f573fSAndroid Build Coastguard Worker        return self, method
1311*1b3f573fSAndroid Build Coastguard Worker
1312*1b3f573fSAndroid Build Coastguard Worker    if self.IsSatisfied():
1313*1b3f573fSAndroid Build Coastguard Worker      next_method = mock_method._PopNextMethod();
1314*1b3f573fSAndroid Build Coastguard Worker      return next_method, None
1315*1b3f573fSAndroid Build Coastguard Worker    else:
1316*1b3f573fSAndroid Build Coastguard Worker      raise UnexpectedMethodCallError(mock_method, self)
1317*1b3f573fSAndroid Build Coastguard Worker
1318*1b3f573fSAndroid Build Coastguard Worker  def IsSatisfied(self):
1319*1b3f573fSAndroid Build Coastguard Worker    """Return True if all methods in this group are called at least once."""
1320*1b3f573fSAndroid Build Coastguard Worker    # NOTE(psycho): We can't use the simple set difference here because we want
1321*1b3f573fSAndroid Build Coastguard Worker    # to match different parameters which are considered the same e.g. IsA(str)
1322*1b3f573fSAndroid Build Coastguard Worker    # and some string. This solution is O(n^2) but n should be small.
1323*1b3f573fSAndroid Build Coastguard Worker    tmp = self._methods.copy()
1324*1b3f573fSAndroid Build Coastguard Worker    for called in self._methods_called:
1325*1b3f573fSAndroid Build Coastguard Worker      for expected in tmp:
1326*1b3f573fSAndroid Build Coastguard Worker        if called == expected:
1327*1b3f573fSAndroid Build Coastguard Worker          tmp.remove(expected)
1328*1b3f573fSAndroid Build Coastguard Worker          if not tmp:
1329*1b3f573fSAndroid Build Coastguard Worker            return True
1330*1b3f573fSAndroid Build Coastguard Worker          break
1331*1b3f573fSAndroid Build Coastguard Worker    return False
1332*1b3f573fSAndroid Build Coastguard Worker
1333*1b3f573fSAndroid Build Coastguard Worker
1334*1b3f573fSAndroid Build Coastguard Workerclass MoxMetaTestBase(type):
1335*1b3f573fSAndroid Build Coastguard Worker  """Metaclass to add mox cleanup and verification to every test.
1336*1b3f573fSAndroid Build Coastguard Worker
1337*1b3f573fSAndroid Build Coastguard Worker  As the mox unit testing class is being constructed (MoxTestBase or a
1338*1b3f573fSAndroid Build Coastguard Worker  subclass), this metaclass will modify all test functions to call the
1339*1b3f573fSAndroid Build Coastguard Worker  CleanUpMox method of the test class after they finish. This means that
1340*1b3f573fSAndroid Build Coastguard Worker  unstubbing and verifying will happen for every test with no additional code,
1341*1b3f573fSAndroid Build Coastguard Worker  and any failures will result in test failures as opposed to errors.
1342*1b3f573fSAndroid Build Coastguard Worker  """
1343*1b3f573fSAndroid Build Coastguard Worker
1344*1b3f573fSAndroid Build Coastguard Worker  def __init__(cls, name, bases, d):
1345*1b3f573fSAndroid Build Coastguard Worker    type.__init__(cls, name, bases, d)
1346*1b3f573fSAndroid Build Coastguard Worker
1347*1b3f573fSAndroid Build Coastguard Worker    # also get all the attributes from the base classes to account
1348*1b3f573fSAndroid Build Coastguard Worker    # for a case when test class is not the immediate child of MoxTestBase
1349*1b3f573fSAndroid Build Coastguard Worker    for base in bases:
1350*1b3f573fSAndroid Build Coastguard Worker      for attr_name in dir(base):
1351*1b3f573fSAndroid Build Coastguard Worker        d[attr_name] = getattr(base, attr_name)
1352*1b3f573fSAndroid Build Coastguard Worker
1353*1b3f573fSAndroid Build Coastguard Worker    for func_name, func in d.items():
1354*1b3f573fSAndroid Build Coastguard Worker      if func_name.startswith('test') and callable(func):
1355*1b3f573fSAndroid Build Coastguard Worker        setattr(cls, func_name, MoxMetaTestBase.CleanUpTest(cls, func))
1356*1b3f573fSAndroid Build Coastguard Worker
1357*1b3f573fSAndroid Build Coastguard Worker  @staticmethod
1358*1b3f573fSAndroid Build Coastguard Worker  def CleanUpTest(cls, func):
1359*1b3f573fSAndroid Build Coastguard Worker    """Adds Mox cleanup code to any MoxTestBase method.
1360*1b3f573fSAndroid Build Coastguard Worker
1361*1b3f573fSAndroid Build Coastguard Worker    Always unsets stubs after a test. Will verify all mocks for tests that
1362*1b3f573fSAndroid Build Coastguard Worker    otherwise pass.
1363*1b3f573fSAndroid Build Coastguard Worker
1364*1b3f573fSAndroid Build Coastguard Worker    Args:
1365*1b3f573fSAndroid Build Coastguard Worker      cls: MoxTestBase or subclass; the class whose test method we are altering.
1366*1b3f573fSAndroid Build Coastguard Worker      func: method; the method of the MoxTestBase test class we wish to alter.
1367*1b3f573fSAndroid Build Coastguard Worker
1368*1b3f573fSAndroid Build Coastguard Worker    Returns:
1369*1b3f573fSAndroid Build Coastguard Worker      The modified method.
1370*1b3f573fSAndroid Build Coastguard Worker    """
1371*1b3f573fSAndroid Build Coastguard Worker    def new_method(self, *args, **kwargs):
1372*1b3f573fSAndroid Build Coastguard Worker      mox_obj = getattr(self, 'mox', None)
1373*1b3f573fSAndroid Build Coastguard Worker      cleanup_mox = False
1374*1b3f573fSAndroid Build Coastguard Worker      if mox_obj and isinstance(mox_obj, Mox):
1375*1b3f573fSAndroid Build Coastguard Worker        cleanup_mox = True
1376*1b3f573fSAndroid Build Coastguard Worker      try:
1377*1b3f573fSAndroid Build Coastguard Worker        func(self, *args, **kwargs)
1378*1b3f573fSAndroid Build Coastguard Worker      finally:
1379*1b3f573fSAndroid Build Coastguard Worker        if cleanup_mox:
1380*1b3f573fSAndroid Build Coastguard Worker          mox_obj.UnsetStubs()
1381*1b3f573fSAndroid Build Coastguard Worker      if cleanup_mox:
1382*1b3f573fSAndroid Build Coastguard Worker        mox_obj.VerifyAll()
1383*1b3f573fSAndroid Build Coastguard Worker    new_method.__name__ = func.__name__
1384*1b3f573fSAndroid Build Coastguard Worker    new_method.__doc__ = func.__doc__
1385*1b3f573fSAndroid Build Coastguard Worker    new_method.__module__ = func.__module__
1386*1b3f573fSAndroid Build Coastguard Worker    return new_method
1387*1b3f573fSAndroid Build Coastguard Worker
1388*1b3f573fSAndroid Build Coastguard Worker
1389*1b3f573fSAndroid Build Coastguard Workerclass MoxTestBase(unittest.TestCase):
1390*1b3f573fSAndroid Build Coastguard Worker  """Convenience test class to make stubbing easier.
1391*1b3f573fSAndroid Build Coastguard Worker
1392*1b3f573fSAndroid Build Coastguard Worker  Sets up a "mox" attribute which is an instance of Mox - any mox tests will
1393*1b3f573fSAndroid Build Coastguard Worker  want this. Also automatically unsets any stubs and verifies that all mock
1394*1b3f573fSAndroid Build Coastguard Worker  methods have been called at the end of each test, eliminating boilerplate
1395*1b3f573fSAndroid Build Coastguard Worker  code.
1396*1b3f573fSAndroid Build Coastguard Worker  """
1397*1b3f573fSAndroid Build Coastguard Worker
1398*1b3f573fSAndroid Build Coastguard Worker  __metaclass__ = MoxMetaTestBase
1399*1b3f573fSAndroid Build Coastguard Worker
1400*1b3f573fSAndroid Build Coastguard Worker  def setUp(self):
1401*1b3f573fSAndroid Build Coastguard Worker    self.mox = Mox()
1402