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