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