15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#!/usr/bin/python2.4 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright 2008 Google Inc. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Licensed under the Apache License, Version 2.0 (the "License"); 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# you may not use this file except in compliance with the License. 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# You may obtain a copy of the License at 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# http://www.apache.org/licenses/LICENSE-2.0 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Unless required by applicable law or agreed to in writing, software 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# distributed under the License is distributed on an "AS IS" BASIS, 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# See the License for the specific language governing permissions and 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# limitations under the License. 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# This file is used for testing. The original is at: 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# http://code.google.com/p/pymox/ 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""Mox, an object-mocking framework for Python. 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Mox works in the record-replay-verify paradigm. When you first create 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)a mock object, it is in record mode. You then programmatically set 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)the expected behavior of the mock object (what methods are to be 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)called on it, with what parameters, what they should return, and in 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)what order). 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Once you have set up the expected mock behavior, you put it in replay 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)mode. Now the mock responds to method calls just as you told it to. 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)If an unexpected method (or an expected method with unexpected 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)parameters) is called, then an exception will be raised. 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Once you are done interacting with the mock, you need to verify that 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)all the expected interactions occured. (Maybe your code exited 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)prematurely without calling some cleanup method!) The verify phase 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ensures that every expected method was called; otherwise, an exception 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)will be raised. 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)Suggested usage / workflow: 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Create Mox factory 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) my_mox = Mox() 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Create a mock data access object 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao = my_mox.CreateMock(DAOClass) 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Set up expected behavior 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.RetrievePersonWithIdentifier('1').AndReturn(person) 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.DeletePerson(person) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Put mocks in replay mode 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) my_mox.ReplayAll() 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Inject mock object and run test 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller.SetDao(mock_dao) 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) controller.DeletePersonById('1') 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Verify all methods were called as expected 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) my_mox.VerifyAll() 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)""" 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)from collections import deque 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import re 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import types 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import unittest 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import stubout 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Error(AssertionError): 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Base exception for this module.""" 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ExpectedMethodCallsError(Error): 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Raised when Verify() is called before all expected methods have been called 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, expected_methods): 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Init exception. 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # expected_methods: A sequence of MockMethod objects that should have been 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # called. 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_methods: [MockMethod] 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ValueError: if expected_methods contains no methods. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not expected_methods: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise ValueError("There must be at least one expected method") 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error.__init__(self) 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._expected_methods = expected_methods 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __str__(self): 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) calls = "\n".join(["%3d. %s" % (i, m) 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for i, m in enumerate(self._expected_methods)]) 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "Verify: Expected methods never called:\n%s" % (calls,) 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UnexpectedMethodCallError(Error): 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Raised when an unexpected method is called. 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This can occur if a method is called with incorrect parameters, or out of the 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) specified order. 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, unexpected_method, expected): 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Init exception. 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # unexpected_method: MockMethod that was called but was not at the head of 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # the expected_method queue. 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # expected: MockMethod or UnorderedGroup the method should have 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # been in. 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unexpected_method: MockMethod 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected: MockMethod or UnorderedGroup 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error.__init__(self) 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._unexpected_method = unexpected_method 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._expected = expected 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __str__(self): 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "Unexpected method call: %s. Expecting: %s" % \ 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (self._unexpected_method, self._expected) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UnknownMethodCallError(Error): 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Raised if an unknown method is requested of the mock object.""" 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, unknown_method_name): 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Init exception. 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # unknown_method_name: Method call that is not part of the mocked class's 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # public interface. 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unknown_method_name: str 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Error.__init__(self) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._unknown_method_name = unknown_method_name 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __str__(self): 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "Method called is not a member of the object: %s" % \ 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._unknown_method_name 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Mox(object): 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Mox: a factory for creating mock objects.""" 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # A list of types that should be stubbed out with MockObjects (as 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # opposed to MockAnythings). 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _USE_MOCK_OBJECT = [types.ClassType, types.InstanceType, types.ModuleType, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) types.ObjectType, types.TypeType] 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize a new Mox.""" 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._mock_objects = [] 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.stubs = stubout.StubOutForTesting() 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CreateMock(self, class_to_mock): 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Create a new mock object. 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # class_to_mock: the class to be mocked 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class_to_mock: class 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockObject that can be used as the class_to_mock would be. 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_mock = MockObject(class_to_mock) 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._mock_objects.append(new_mock) 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new_mock 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CreateMockAnything(self): 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Create a mock that will accept any method calls. 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This does not enforce an interface. 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_mock = MockAnything() 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._mock_objects.append(new_mock) 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new_mock 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ReplayAll(self): 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Set all mock objects to replay mode.""" 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for mock_obj in self._mock_objects: 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_obj._Replay() 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def VerifyAll(self): 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Call verify on all mock objects created.""" 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for mock_obj in self._mock_objects: 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_obj._Verify() 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def ResetAll(self): 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Call reset on all mock objects. This does not unset stubs.""" 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for mock_obj in self._mock_objects: 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_obj._Reset() 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def StubOutWithMock(self, obj, attr_name, use_mock_anything=False): 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Replace a method, attribute, etc. with a Mock. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This will replace a class or module with a MockObject, and everything else 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (method, function, etc) with a MockAnything. This can be overridden to 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) always use a MockAnything by setting use_mock_anything to True. 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) obj: A Python object (class, module, instance, callable). 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attr_name: str. The name of the attribute to replace with a mock. 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) use_mock_anything: bool. True if a MockAnything should be used regardless 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) of the type of attribute. 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) attr_to_replace = getattr(obj, attr_name) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if type(attr_to_replace) in self._USE_MOCK_OBJECT and not use_mock_anything: 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stub = self.CreateMock(attr_to_replace) 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) stub = self.CreateMockAnything() 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.stubs.Set(obj, attr_name, stub) 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def UnsetStubs(self): 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Restore stubs to their original state.""" 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.stubs.UnsetAll() 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Replay(*args): 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Put mocks into Replay mode. 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # args is any number of mocks to put into replay mode. 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for mock in args: 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock._Replay() 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Verify(*args): 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Verify mocks. 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # args is any number of mocks to be verified. 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for mock in args: 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock._Verify() 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def Reset(*args): 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Reset mocks. 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # args is any number of mocks to be reset. 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for mock in args: 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock._Reset() 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockAnything: 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A mock that can be used to mock anything. 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This is helpful for mocking classes that do not provide a public interface. 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self): 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ """ 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._Reset() 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __getattr__(self, method_name): 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Intercept method calls on this object. 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A new MockMethod is returned that is aware of the MockAnything's 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state (record or replay). The call will be recorded or replayed 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) by the MockMethod's __call__. 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # method name: the name of the method being called. 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) method_name: str 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A new MockMethod aware of MockAnything's state (record or replay). 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._CreateMockMethod(method_name) 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _CreateMockMethod(self, method_name): 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Create a new mock method call and return it. 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # method name: the name of the method being called. 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) method_name: str 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A new MockMethod aware of MockAnything's state (record or replay). 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MockMethod(method_name, self._expected_calls_queue, 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._replay_mode) 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __nonzero__(self): 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Return 1 for nonzero so the mock can be used as a conditional.""" 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 1 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __eq__(self, rhs): 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Provide custom logic to compare objects.""" 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (isinstance(rhs, MockAnything) and 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._replay_mode == rhs._replay_mode and 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._expected_calls_queue == rhs._expected_calls_queue) 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __ne__(self, rhs): 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Provide custom logic to compare objects.""" 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return not self == rhs 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _Replay(self): 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Start replaying expected method calls.""" 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._replay_mode = True 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _Verify(self): 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Verify that all of the expected calls have been made. 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ExpectedMethodCallsError: if there are still more method calls in the 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected queue. 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If the list of expected calls is not empty, raise an exception 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self._expected_calls_queue: 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The last MultipleTimesGroup is not popped from the queue. 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (len(self._expected_calls_queue) == 1 and 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) isinstance(self._expected_calls_queue[0], MultipleTimesGroup) and 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._expected_calls_queue[0].IsSatisfied()): 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise ExpectedMethodCallsError(self._expected_calls_queue) 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _Reset(self): 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Reset the state of this mock to record mode with an empty queue.""" 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Maintain a list of method calls we are expecting 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._expected_calls_queue = deque() 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Make sure we are in setup mode, not replay mode 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._replay_mode = False 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockObject(MockAnything, object): 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """A mock object that simulates the public/protected interface of a class.""" 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, class_to_mock): 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize a mock object. 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This determines the methods and properties of the class and stores them. 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # class_to_mock: class to be mocked 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class_to_mock: class 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # This is used to hack around the mixin/inheritance of MockAnything, which 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # is not a proper object (it can be anything. :-) 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockAnything.__dict__['__init__'](self) 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Get a list of all the public and special methods we should mock. 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._known_methods = set() 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._known_vars = set() 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._class_to_mock = class_to_mock 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for method in dir(class_to_mock): 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if callable(getattr(class_to_mock, method)): 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._known_methods.add(method) 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._known_vars.add(method) 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __getattr__(self, name): 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Intercept attribute request on this object. 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If the attribute is a public class variable, it will be returned and not 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) recorded as a call. 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If the attribute is not a variable, it is handled like a method 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) call. The method name is checked against the set of mockable 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) methods, and a new MockMethod is returned that is aware of the 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) MockObject's state (record or replay). The call will be recorded 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) or replayed by the MockMethod's __call__. 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # name: the name of the attribute being requested. 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) name: str 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Either a class variable or a new MockMethod that is aware of the state 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) of the mock (record or replay). 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnknownMethodCallError if the MockObject does not mock the requested 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) method. 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if name in self._known_vars: 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return getattr(self._class_to_mock, name) 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if name in self._known_methods: 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._CreateMockMethod(name) 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise UnknownMethodCallError(name) 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __eq__(self, rhs): 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Provide custom logic to compare objects.""" 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (isinstance(rhs, MockObject) and 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._class_to_mock == rhs._class_to_mock and 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._replay_mode == rhs._replay_mode and 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._expected_calls_queue == rhs._expected_calls_queue) 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __setitem__(self, key, value): 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Provide custom logic for mocking classes that support item assignment. 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key: Key to set the value for. 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value: Value to set. 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Expected return value in replay mode. A MockMethod object for the 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __setitem__ method that has already been called if not in replay mode. 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeError if the underlying class does not support item assignment. 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnexpectedMethodCallError if the object does not expect the call to 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __setitem__. 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setitem = self._class_to_mock.__dict__.get('__setitem__', None) 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Verify the class supports item assignment. 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if setitem is None: 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise TypeError('object does not support item assignment') 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If we are in replay mode then simply call the mock __setitem__ method. 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self._replay_mode: 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MockMethod('__setitem__', self._expected_calls_queue, 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._replay_mode)(key, value) 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Otherwise, create a mock method __setitem__. 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._CreateMockMethod('__setitem__')(key, value) 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __getitem__(self, key): 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Provide custom logic for mocking classes that are subscriptable. 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) key: Key to return the value for. 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Expected return value in replay mode. A MockMethod object for the 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __getitem__ method that has already been called if not in replay mode. 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) TypeError if the underlying class is not subscriptable. 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnexpectedMethodCallError if the object does not expect the call to 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __setitem__. 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) getitem = self._class_to_mock.__dict__.get('__getitem__', None) 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Verify the class supports item assignment. 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if getitem is None: 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise TypeError('unsubscriptable object') 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If we are in replay mode then simply call the mock __getitem__ method. 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self._replay_mode: 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return MockMethod('__getitem__', self._expected_calls_queue, 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._replay_mode)(key) 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Otherwise, create a mock method __getitem__. 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._CreateMockMethod('__getitem__')(key) 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __call__(self, *params, **named_params): 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Provide custom logic for mocking classes that are callable.""" 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Verify the class we are mocking is callable 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) callable = self._class_to_mock.__dict__.get('__call__', None) 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if callable is None: 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise TypeError('Not callable') 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Because the call is happening directly on this object instead of a method, 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # the call on the mock method is made right here 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_method = self._CreateMockMethod('__call__') 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return mock_method(*params, **named_params) 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @property 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __class__(self): 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Return the class that is being mocked.""" 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._class_to_mock 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MockMethod(object): 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Callable mock method. 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A MockMethod should act exactly like the method it mocks, accepting parameters 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) and returning a value, or throwing an exception (as specified). When this 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) method is called, it can optionally verify whether the called method (name and 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) signature) matches the expected method. 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, method_name, call_queue, replay_mode): 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Construct a new mock method. 5215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # method_name: the name of the method 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # call_queue: deque of calls, verify this call against the head, or add 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # this call to the queue. 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # replay_mode: False if we are recording, True if we are verifying calls 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # against the call queue. 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) method_name: str 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) call_queue: list or deque 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) replay_mode: bool 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._name = method_name 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._call_queue = call_queue 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not isinstance(call_queue, deque): 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._call_queue = deque(self._call_queue) 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._replay_mode = replay_mode 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._params = None 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._named_params = None 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._return_value = None 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._exception = None 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._side_effects = None 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __call__(self, *params, **named_params): 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Log parameters and return the specified return value. 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If the Mock(Anything/Object) associated with this call is in record mode, 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this MockMethod will be pushed onto the expected call queue. If the mock 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is in replay mode, this will pop a MockMethod off the top of the queue and 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) verify this call is equal to the expected call. 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnexpectedMethodCall if this call is supposed to match an expected method 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) call and it does not. 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._params = params 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._named_params = named_params 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self._replay_mode: 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._call_queue.append(self) 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_method = self._VerifyMethodCall() 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if expected_method._side_effects: 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_method._side_effects(*params, **named_params) 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if expected_method._exception: 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise expected_method._exception 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return expected_method._return_value 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __getattr__(self, name): 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Raise an AttributeError with a helpful message.""" 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise AttributeError('MockMethod has no attribute "%s". ' 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 'Did you remember to put your mocks in replay mode?' % name) 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _PopNextMethod(self): 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Pop the next method from our call queue.""" 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._call_queue.popleft() 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except IndexError: 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise UnexpectedMethodCallError(self, None) 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _VerifyMethodCall(self): 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Verify the called method is expected. 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This can be an ordered method, or part of an unordered set. 5925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The expected mock method. 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnexpectedMethodCall if the method called was not expected. 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected = self._PopNextMethod() 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Loop here, because we might have a MethodGroup followed by another 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # group. 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while isinstance(expected, MethodGroup): 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected, method = expected.MethodCalled(self) 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if method is not None: 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return method 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # This is a mock method, so just check equality. 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if expected != self: 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise UnexpectedMethodCallError(self, expected) 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return expected 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __str__(self): 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) params = ', '.join( 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) [repr(p) for p in self._params or []] + 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ['%s=%r' % x for x in sorted((self._named_params or {}).items())]) 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) desc = "%s(%s) -> %r" % (self._name, params, self._return_value) 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return desc 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __eq__(self, rhs): 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Test whether this MockMethod is equivalent to another MockMethod. 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # rhs: the right hand side of the test 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rhs: MockMethod 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return (isinstance(rhs, MockMethod) and 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._name == rhs._name and 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._params == rhs._params and 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._named_params == rhs._named_params) 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __ne__(self, rhs): 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Test whether this MockMethod is not equivalent to another MockMethod. 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # rhs: the right hand side of the test 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rhs: MockMethod 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return not self == rhs 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def GetPossibleGroup(self): 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Returns a possible group from the end of the call queue or None if no 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) other methods are on the stack. 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Remove this method from the tail of the queue so we can add it to a group. 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) this_method = self._call_queue.pop() 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) assert this_method == self 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Determine if the tail of the queue is a group, or just a regular ordered 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # mock method. 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group = None 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group = self._call_queue[-1] 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except IndexError: 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pass 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return group 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def _CheckAndCreateNewGroup(self, group_name, group_class): 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Checks if the last method (a possible group) is an instance of our 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group_class. Adds the current method to this group or creates a new one. 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group_name: the name of the group. 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group_class: the class used to create instance of this new group 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group = self.GetPossibleGroup() 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If this is a group, and it is the correct group, add the method. 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if isinstance(group, group_class) and group.group_name() == group_name: 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group.AddMethod(self) 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Create a new group and add the method. 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_group = group_class(group_name) 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_group.AddMethod(self) 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._call_queue.append(new_group) 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def InAnyOrder(self, group_name="default"): 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Move this method into a group of unordered calls. 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A group of unordered calls must be defined together, and must be executed 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in full before the next expected method can be called. There can be 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) multiple groups that are expected serially, if they are given 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) different group names. The same group name can be reused if there is a 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) standard method call, or a group with a different name, spliced between 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) usages. 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group_name: the name of the unordered group. 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._CheckAndCreateNewGroup(group_name, UnorderedGroup) 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def MultipleTimes(self, group_name="default"): 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Move this method into group of calls which may be called multiple times. 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A group of repeating calls must be defined together, and must be executed in 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) full before the next expected mehtod can be called. 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) group_name: the name of the unordered group. 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._CheckAndCreateNewGroup(group_name, MultipleTimesGroup) 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AndReturn(self, return_value): 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Set the value to return when this method is called. 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # return_value can be anything. 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._return_value = return_value 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return return_value 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AndRaise(self, exception): 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Set the exception to raise when this method is called. 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # exception: the exception to raise when this method is called. 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) exception: Exception 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._exception = exception 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def WithSideEffects(self, side_effects): 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Set the side effects that are simulated when this method is called. 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) side_effects: A callable which modifies the parameters or other relevant 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) state which a given test case depends on. 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Self for chaining with AndReturn and AndRaise. 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._side_effects = side_effects 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Comparator: 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Base class for all Mox comparators. 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A Comparator can be used as a parameter to a mocked method when the exact 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value is not known. For example, the code you are testing might build up a 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) long SQL string that is passed to your mock DAO. You're only interested that 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the IN clause contains the proper primary keys, so you can set your mock 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) up as follows: 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result) 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Now whatever query is passed in must contain the string 'IN (1, 2, 4, 5)'. 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) A Comparator may replace one or more parameters, for example: 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # return at most 10 rows 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.RunQuery(StrContains('SELECT'), 10) 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) or 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Return some non-deterministic number of rows 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.RunQuery(StrContains('SELECT'), IsA(int)) 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Special equals method that all comparators must implement. 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rhs: any python object 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError, 'method must be implemented by a subclass.' 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __eq__(self, rhs): 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.equals(rhs) 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __ne__(self, rhs): 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return not self.equals(rhs) 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IsA(Comparator): 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """This class wraps a basic Python type or class. It is used to verify 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) that a parameter is of the given type or class. 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.Connect(IsA(DbConnectInfo)) 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, class_name): 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize IsA 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) class_name: basic python type or a class 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._class_name = class_name 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Check to see if the RHS is an instance of class_name. 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # rhs: the right hand side of the test 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rhs: object 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return isinstance(rhs, self._class_name) 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except TypeError: 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check raw types if there was a type error. This is helpful for 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # things like cStringIO.StringIO. 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return type(rhs) == type(self._class_name) 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return str(self._class_name) 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IsAlmost(Comparator): 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Comparison class used to check whether a parameter is nearly equal 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) to a given value. Generally useful for floating point numbers. 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example mock_dao.SetTimeout((IsAlmost(3.9))) 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, float_value, places=7): 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize IsAlmost. 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) float_value: The value for making the comparison. 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) places: The number of decimal places to round to. 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._float_value = float_value 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._places = places 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Check to see if RHS is almost equal to float_value 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rhs: the value to compare to float_value 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return round(rhs-self._float_value, self._places) == 0 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except TypeError: 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # This is probably because either float_value or rhs is not a number. 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return str(self._float_value) 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class StrContains(Comparator): 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Comparison class used to check whether a substring exists in a 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) string parameter. This can be useful in mocking a database with SQL 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) passed in as a string parameter, for example. 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result) 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, search_string): 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize. 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # search_string: the string you are searching for 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) search_string: str 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._search_string = search_string 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Check to see if the search_string is contained in the rhs string. 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # rhs: the right hand side of the test 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rhs: object 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rhs.find(self._search_string) > -1 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception: 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '<str containing \'%s\'>' % self._search_string 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Regex(Comparator): 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Checks if a string matches a regular expression. 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This uses a given regular expression to determine equality. 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, pattern, flags=0): 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize. 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # pattern is the regular expression to search for 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pattern: str 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # flags passed to re.compile function as the second argument 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) flags: int 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.regex = re.compile(pattern, flags=flags) 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Check to see if rhs matches regular expression pattern. 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self.regex.search(rhs) is not None 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s = '<regular expression \'%s\'' % self.regex.pattern 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.regex.flags: 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s += ', flags=%d' % self.regex.flags 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) s += '>' 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return s 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class In(Comparator): 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Checks whether an item (or key) is in a list (or dict) parameter. 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.GetUsersInfo(In('expectedUserName')).AndReturn(mock_result) 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, key): 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize. 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # key is any thing that could be in a list or a key in a dict 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._key = key 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Check to see whether key is in rhs. 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rhs: dict 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._key in rhs 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '<sequence or map containing \'%s\'>' % self._key 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ContainsKeyValue(Comparator): 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Checks whether a key/value pair is in a dict parameter. 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.UpdateUsers(ContainsKeyValue('stevepm', stevepm_user_info)) 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, key, value): 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize. 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # key: a key in a dict 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # value: the corresponding value 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._key = key 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._value = value 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Check whether the given key/value pair is in the rhs dict. 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return rhs[self._key] == self._value 9985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except Exception: 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '<map containing the entry \'%s: %s\'>' % (self._key, self._value) 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class SameElementsAs(Comparator): 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Checks whether iterables contain the same elements (ignoring order). 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.ProcessUsers(SameElementsAs('stevepm', 'salomaki')) 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, expected_seq): 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize. 10145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected_seq: a sequence 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._expected_seq = expected_seq 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, actual_seq): 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Check to see whether actual_seq has same elements as expected_seq. 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) actual_seq: sequence 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected = dict([(element, None) for element in self._expected_seq]) 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) actual = dict([(element, None) for element in actual_seq]) 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) except TypeError: 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Fall back to slower list-compare if any of the objects are unhashable. 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected = list(self._expected_seq) 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) actual = list(actual_seq) 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) expected.sort() 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) actual.sort() 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return expected == actual 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '<sequence with same elements as \'%s\'>' % self._expected_seq 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class And(Comparator): 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Evaluates one or more Comparators on RHS and returns an AND of the results. 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, *args): 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize. 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *args: One or more Comparator 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._comparators = args 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Checks whether all Comparators are equal to rhs. 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # rhs: can be anything 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for comparator in self._comparators: 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not comparator.equals(rhs): 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '<AND %s>' % str(self._comparators) 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Or(Comparator): 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Evaluates one or more Comparators on RHS and returns an OR of the results. 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, *args): 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize. 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *args: One or more Mox comparators 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._comparators = args 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Checks whether any Comparator is equal to rhs. 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # rhs: can be anything 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for comparator in self._comparators: 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if comparator.equals(rhs): 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '<OR %s>' % str(self._comparators) 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class Func(Comparator): 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Call a function that should verify the parameter passed in is correct. 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) You may need the ability to perform more advanced operations on the parameter 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) in order to validate it. You can use this to have a callable validate any 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parameter. The callable should return either True or False. 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def myParamValidator(param): 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Advanced logic here 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_dao.DoSomething(Func(myParamValidator), true) 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, func): 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Initialize. 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) func: callable that takes one parameter and returns a bool 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._func = func 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, rhs): 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Test whether rhs passes the function test. 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rhs is passed into func. 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) rhs: any python object 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) the result of func(rhs) 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._func(rhs) 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return str(self._func) 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class IgnoreArg(Comparator): 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Ignore an argument. 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This can be used when we don't care about an argument of a method call. 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Example: 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check if CastMagic is called with 3 as first arg and 'disappear' as third. 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mymock.CastMagic(3, IgnoreArg(), 'disappear') 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def equals(self, unused_rhs): 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Ignores arguments and returns True. 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unused_rhs: any python object 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) always returns True 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __repr__(self): 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '<IgnoreArg>' 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MethodGroup(object): 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Base class containing common behaviour for MethodGroups.""" 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, group_name): 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._group_name = group_name 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def group_name(self): 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self._group_name 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __str__(self): 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return '<%s "%s">' % (self.__class__.__name__, self._group_name) 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AddMethod(self, mock_method): 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def MethodCalled(self, mock_method): 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def IsSatisfied(self): 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise NotImplementedError 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UnorderedGroup(MethodGroup): 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """UnorderedGroup holds a set of method calls that may occur in any order. 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This construct is helpful for non-deterministic events, such as iterating 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) over the keys of a dict. 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, group_name): 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) super(UnorderedGroup, self).__init__(group_name) 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._methods = [] 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AddMethod(self, mock_method): 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Add a method to this group. 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_method: A mock method to be added to this group. 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._methods.append(mock_method) 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def MethodCalled(self, mock_method): 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Remove a method call from the group. 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If the method is not in the set, an UnexpectedMethodCallError will be 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raised. 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_method: a mock method that should be equal to a method in the group. 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The mock method from the group 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnexpectedMethodCallError if the mock_method was not in the group. 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check to see if this method exists, and if so, remove it from the set 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # and return it. 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for method in self._methods: 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if method == mock_method: 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Remove the called mock_method instead of the method in the group. 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # The called method will match any comparators when equality is checked 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # during removal. The method in the group could pass a comparator to 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # another comparator during the equality check. 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._methods.remove(mock_method) 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # If this group is not empty, put it back at the head of the queue. 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not self.IsSatisfied(): 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_method._call_queue.appendleft(self) 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self, method 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise UnexpectedMethodCallError(mock_method, self) 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def IsSatisfied(self): 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Return True if there are not any methods in this group.""" 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return len(self._methods) == 0 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MultipleTimesGroup(MethodGroup): 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """MultipleTimesGroup holds methods that may be called any number of times. 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Note: Each method must be called at least once. 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) This is helpful, if you don't know or care how many times a method is called. 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(self, group_name): 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) super(MultipleTimesGroup, self).__init__(group_name) 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._methods = set() 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._methods_called = set() 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def AddMethod(self, mock_method): 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Add a method to this group. 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_method: A mock method to be added to this group. 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._methods.add(mock_method) 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def MethodCalled(self, mock_method): 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Remove a method call from the group. 12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) If the method is not in the set, an UnexpectedMethodCallError will be 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raised. 12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_method: a mock method that should be equal to a method in the group. 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The mock method from the group 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Raises: 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) UnexpectedMethodCallError if the mock_method was not in the group. 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Check to see if this method exists, and if so add it to the set of 13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # called methods. 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for method in self._methods: 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if method == mock_method: 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self._methods_called.add(mock_method) 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # Always put this group back on top of the queue, because we don't know 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # when we are done. 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mock_method._call_queue.appendleft(self) 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return self, method 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if self.IsSatisfied(): 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) next_method = mock_method._PopNextMethod(); 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return next_method, None 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else: 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) raise UnexpectedMethodCallError(mock_method, self) 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def IsSatisfied(self): 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Return True if all methods in this group are called at least once.""" 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # NOTE(psycho): We can't use the simple set difference here because we want 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # to match different parameters which are considered the same e.g. IsA(str) 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # and some string. This solution is O(n^2) but n should be small. 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tmp = self._methods.copy() 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for called in self._methods_called: 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for expected in tmp: 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if called == expected: 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) tmp.remove(expected) 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if not tmp: 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return True 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return False 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MoxMetaTestBase(type): 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Metaclass to add mox cleanup and verification to every test. 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) As the mox unit testing class is being constructed (MoxTestBase or a 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) subclass), this metaclass will modify all test functions to call the 13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CleanUpMox method of the test class after they finish. This means that 13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) unstubbing and verifying will happen for every test with no additional code, 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) and any failures will result in test failures as opposed to errors. 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def __init__(cls, name, bases, d): 13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) type.__init__(cls, name, bases, d) 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # also get all the attributes from the base classes to account 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) # for a case when test class is not the immediate child of MoxTestBase 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for base in bases: 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for attr_name in dir(base): 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) d[attr_name] = getattr(base, attr_name) 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for func_name, func in d.items(): 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if func_name.startswith('test') and callable(func): 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) setattr(cls, func_name, MoxMetaTestBase.CleanUpTest(cls, func)) 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) @staticmethod 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def CleanUpTest(cls, func): 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Adds Mox cleanup code to any MoxTestBase method. 13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Always unsets stubs after a test. Will verify all mocks for tests that 13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) otherwise pass. 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Args: 13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cls: MoxTestBase or subclass; the class whose test method we are altering. 13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) func: method; the method of the MoxTestBase test class we wish to alter. 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Returns: 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) The modified method. 13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def new_method(self, *args, **kwargs): 13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mox_obj = getattr(self, 'mox', None) 13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cleanup_mox = False 13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if mox_obj and isinstance(mox_obj, Mox): 13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) cleanup_mox = True 13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) try: 13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) func(self, *args, **kwargs) 13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) finally: 13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if cleanup_mox: 13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mox_obj.UnsetStubs() 13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if cleanup_mox: 13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) mox_obj.VerifyAll() 13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_method.__name__ = func.__name__ 13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_method.__doc__ = func.__doc__ 13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) new_method.__module__ = func.__module__ 13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return new_method 13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class MoxTestBase(unittest.TestCase): 13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """Convenience test class to make stubbing easier. 13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) Sets up a "mox" attribute which is an instance of Mox - any mox tests will 13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) want this. Also automatically unsets any stubs and verifies that all mock 13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) methods have been called at the end of each test, eliminating boilerplate 13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) code. 13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) """ 13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __metaclass__ = MoxMetaTestBase 13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) def setUp(self): 14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) self.mox = Mox() 1402