diff --git a/.gitignore b/.gitignore deleted file mode 100644 index f7f355f..0000000 --- a/.gitignore +++ /dev/null @@ -1,70 +0,0 @@ -*.py[co] - -# Packages -*.egg* -dist -build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -.coverage -.tox -.stestr/ - -#Translations -*.mo - -# virtualenv -.venv - -#Mr Developer -.mr.developer.cfg - -# https://github.com/h5bp/html5-boilerplate/blob/master/.gitignore -# Numerous always-ignore extensions -*.diff -*.err -*.orig -*.log -*.rej -*.swo -*.swp -*.vi -*~ - -# OS or Editor folders -.DS_Store -Thumbs.db -.cache -.project -.settings -.tmproj -nbproject -*.sublime-project -*.sublime-workspace -*.komodoproject -.komodotools - -# Folders to ignore -.hg -.svn -.CVS -intermediate -publish -.idea - -# PyDev -.pydevproject - -# pbr -AUTHORS -ChangeLog diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 6a6d090..0000000 --- a/.mailmap +++ /dev/null @@ -1 +0,0 @@ -Przemysław Gajda diff --git a/.stestr.conf b/.stestr.conf deleted file mode 100644 index 8e9a540..0000000 --- a/.stestr.conf +++ /dev/null @@ -1,4 +0,0 @@ -[DEFAULT] -test_path=./mox3/tests -top_dir=./ - diff --git a/.zuul.yaml b/.zuul.yaml deleted file mode 100644 index db37fa5..0000000 --- a/.zuul.yaml +++ /dev/null @@ -1,7 +0,0 @@ -- project: - templates: - - check-requirements - - openstack-lower-constraints-jobs - - openstack-python3-victoria-jobs - - periodic-stable-jobs - - publish-openstack-docs-pti diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index b2538df..0000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,17 +0,0 @@ -If you would like to contribute to the development of OpenStack, -you must follow the steps in the "If you're a developer, start here" -section of this page: - - https://docs.openstack.org/infra/manual/developers.html - -Once those steps have been completed, changes to OpenStack -should be submitted for review via the Gerrit tool, following -the workflow documented at: - - https://docs.openstack.org/infra/manual/developers.html#development-workflow - -Pull requests submitted through GitHub will be ignored. - -Bugs should be filed on Launchpad, not GitHub: - - https://bugs.launchpad.net/python-mox3 diff --git a/COPYING.txt b/COPYING.txt deleted file mode 100644 index d645695..0000000 --- a/COPYING.txt +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index c978a52..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,6 +0,0 @@ -include AUTHORS -include ChangeLog -exclude .gitignore -exclude .gitreview - -global-exclude *.pyc diff --git a/README.rst b/README.rst index d946e11..86e34d6 100644 --- a/README.rst +++ b/README.rst @@ -1,64 +1,10 @@ -========================================= -Mox3 - Mock object framework for Python 3 -========================================= +This project is no longer maintained. -.. image:: https://governance.openstack.org/tc/badges/mox3.svg - :target: https://governance.openstack.org/tc/reference/tags/index.html +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". -Mox3 is an unofficial port of the Google mox framework -(http://code.google.com/p/pymox/) to Python 3. It was meant to be as compatible -with mox as possible, but small enhancements have been made. The library was -tested on Python version 3.2, 2.7 and 2.6. - -Use at your own risk ;) - -To install: - - $ python setup.py install - -Running Tests -------------- -The testing system is based on a combination of tox and testr. The canonical -approach to running tests is to simply run the command `tox`. This will -create virtual environments, populate them with depenedencies and run all of -the tests that OpenStack CI systems run. Behind the scenes, tox is running -`testr run --parallel`, but is set up such that you can supply any additional -testr arguments that are needed to tox. For example, you can run: -`tox -- --analyze-isolation` to cause tox to tell testr to add ---analyze-isolation to its argument list. - -It is also possible to run the tests inside of a virtual environment -you have created, or it is possible that you have all of the dependencies -installed locally already. In this case, you can interact with the testr -command directly. Running `testr run` will run the entire test suite. `testr -run --parallel` will run it in parallel (this is the default incantation tox -uses.) More information about testr can be found at: -https://wiki.openstack.org/wiki/Testr - -Basic Usage ------------ - -The basic usage of mox3 is the same as with mox, but the initial import should -be made from the mox3 module: - - from mox3 import mox - -To learn how to use mox3 you may check the documentation of the original mox -framework: - - http://code.google.com/p/pymox/wiki/MoxDocumentation - -Original Copyright ------------------- - -Mox is Copyright 2008 Google Inc, and licensed under the Apache -License, Version 2.0; see the file COPYING.txt for details. If you would -like to help us improve Mox, join the group. - -OpenStack Fork --------------- - -* Free software: Apache license -* Documentation: https://docs.openstack.org/mox3/latest/ -* Source: https://opendev.org/openstack/mox3 -* Bugs: https://bugs.launchpad.net/python-mox3 +For any further questions, please email +openstack-discuss@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 54e9611..0000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,68 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import sys - -sys.path.insert(0, os.path.abspath('../..')) -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', 'openstackdocstheme'] - -# openstackdocstheme options -openstackdocs_repo_name = 'openstack/mox3' -openstackdocs_bug_project = 'python-mox3' -openstackdocs_auto_name = False -openstackdocs_bug_tag = '' - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# Add any paths that contain templates here, relative to this directory. -# templates_path = [] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'mox3' -copyright = u'OpenStack Foundation' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'native' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -html_theme = 'openstackdocs' -html_static_path = ['static'] - -# Output file base name for HTML help builder. -htmlhelp_basename = '%sdoc' % project - -git_cmd = "git log --pretty=format:'%ad, commit %h' --date=local -n1" -html_last_updated_fmt = os.popen(git_cmd).read() - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', - '%s.tex' % project, - '%s Documentation' % project, - 'OpenStack Foundation', 'manual'), -] diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst deleted file mode 100644 index 3d4ceb4..0000000 --- a/doc/source/contributor/index.rst +++ /dev/null @@ -1,5 +0,0 @@ -============ -Contributing -============ - -.. include:: ../../../CONTRIBUTING.rst diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index 7170ee4..0000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,21 +0,0 @@ -mox3 -==== - -A fork of mox with Python 3 support. - -Contents -======== - -.. toctree:: - :maxdepth: 2 - - user/index - contributor/index - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` - diff --git a/doc/source/static/.placeholder b/doc/source/static/.placeholder deleted file mode 100644 index e69de29..0000000 diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst deleted file mode 100644 index e4a3ad5..0000000 --- a/doc/source/user/index.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../../README.rst diff --git a/lower-constraints.txt b/lower-constraints.txt deleted file mode 100644 index 44fdecc..0000000 --- a/lower-constraints.txt +++ /dev/null @@ -1,30 +0,0 @@ -alabaster==0.7.10 -Babel==2.3.4 -coverage==4.0 -docutils==0.11 -dulwich==0.15.0 -extras==1.0.0 -fixtures==3.0.0 -flake8==2.5.5 -imagesize==0.7.1 -Jinja2==2.10 -linecache2==1.0.0 -MarkupSafe==1.0 -mccabe==0.4.0 -openstackdocstheme==2.2.1 -pbr==2.0.0 -pep8==1.7.1 -pyflakes==1.0.0 -Pygments==2.2.0 -python-mimeparse==1.6.0 -python-subunit==1.0.0 -pytz==2013.6 -requests==2.14.2 -six==1.10.0 -snowballstemmer==1.2.1 -Sphinx==2.2.0 -sphinxcontrib-websupport==1.0.1 -stestr==2.0.0 -testtools==2.2.0 -traceback2==1.4.0 -unittest2==1.1.0 diff --git a/mox3/__init__.py b/mox3/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mox3/fixture.py b/mox3/fixture.py deleted file mode 100644 index 5d7c35b..0000000 --- a/mox3/fixture.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import fixtures -from mox3 import mox -from mox3 import stubout - - -class MoxStubout(fixtures.Fixture): - """Deal with code around mox and stubout as a fixture.""" - - def setUp(self): - super(MoxStubout, self).setUp() - self.mox = mox.Mox() - self.stubs = stubout.StubOutForTesting() - self.addCleanup(self.mox.UnsetStubs) - self.addCleanup(self.stubs.UnsetAll) - self.addCleanup(self.stubs.SmartUnsetAll) - self.addCleanup(self.mox.VerifyAll) diff --git a/mox3/mox.py b/mox3/mox.py deleted file mode 100644 index 21e3535..0000000 --- a/mox3/mox.py +++ /dev/null @@ -1,2170 +0,0 @@ -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This is a fork of the pymox library intended to work with Python 3. -# The file was modified by quermit@gmail.com and dawid.fatyga@gmail.com - -"""Mox, an object-mocking framework for Python. - -Mox works in the record-replay-verify paradigm. When you first create -a mock object, it is in record mode. You then programmatically set -the expected behavior of the mock object (what methods are to be -called on it, with what parameters, what they should return, and in -what order). - -Once you have set up the expected mock behavior, you put it in replay -mode. Now the mock responds to method calls just as you told it to. -If an unexpected method (or an expected method with unexpected -parameters) is called, then an exception will be raised. - -Once you are done interacting with the mock, you need to verify that -all the expected interactions occured. (Maybe your code exited -prematurely without calling some cleanup method!) The verify phase -ensures that every expected method was called; otherwise, an exception -will be raised. - -WARNING! Mock objects created by Mox are not thread-safe. If you are -call a mock in multiple threads, it should be guarded by a mutex. - -TODO(stevepm): Add the option to make mocks thread-safe! - -Suggested usage / workflow: - - # Create Mox factory - my_mox = Mox() - - # Create a mock data access object - mock_dao = my_mox.CreateMock(DAOClass) - - # Set up expected behavior - mock_dao.RetrievePersonWithIdentifier('1').AndReturn(person) - mock_dao.DeletePerson(person) - - # Put mocks in replay mode - my_mox.ReplayAll() - - # Inject mock object and run test - controller.SetDao(mock_dao) - controller.DeletePersonById('1') - - # Verify all methods were called as expected - my_mox.VerifyAll() -""" - -import collections -import difflib -import inspect -import re -import types -import unittest - -from mox3 import stubout - - -class Error(AssertionError): - """Base exception for this module.""" - - pass - - -class ExpectedMethodCallsError(Error): - """Raised when an expected method wasn't called. - - This can occur if Verify() is called before all expected methods have been - called. - """ - - def __init__(self, expected_methods): - """Init exception. - - Args: - # expected_methods: A sequence of MockMethod objects that should - # have been called. - expected_methods: [MockMethod] - - Raises: - ValueError: if expected_methods contains no methods. - """ - - if not expected_methods: - raise ValueError("There must be at least one expected method") - Error.__init__(self) - self._expected_methods = expected_methods - - def __str__(self): - calls = "\n".join(["%3d. %s" % (i, m) - for i, m in enumerate(self._expected_methods)]) - return "Verify: Expected methods never called:\n%s" % (calls,) - - -class UnexpectedMethodCallError(Error): - """Raised when an unexpected method is called. - - This can occur if a method is called with incorrect parameters, or out of - the specified order. - """ - - def __init__(self, unexpected_method, expected): - """Init exception. - - Args: - # unexpected_method: MockMethod that was called but was not at the - # head of the expected_method queue. - # expected: MockMethod or UnorderedGroup the method should have - # been in. - unexpected_method: MockMethod - expected: MockMethod or UnorderedGroup - """ - - Error.__init__(self) - if expected is None: - self._str = "Unexpected method call %s" % (unexpected_method,) - else: - differ = difflib.Differ() - diff = differ.compare(str(unexpected_method).splitlines(True), - str(expected).splitlines(True)) - self._str = ("Unexpected method call." - " unexpected:- expected:+\n%s" - % ("\n".join(line.rstrip() for line in diff),)) - - def __str__(self): - return self._str - - -class UnknownMethodCallError(Error): - """Raised if an unknown method is requested of the mock object.""" - - def __init__(self, unknown_method_name): - """Init exception. - - Args: - # unknown_method_name: Method call that is not part of the mocked - # class's public interface. - unknown_method_name: str - """ - - Error.__init__(self) - self._unknown_method_name = unknown_method_name - - def __str__(self): - return ("Method called is not a member of the object: %s" % - self._unknown_method_name) - - -class PrivateAttributeError(Error): - """Raised if a MockObject is passed a private additional attribute name.""" - - def __init__(self, attr): - Error.__init__(self) - self._attr = attr - - def __str__(self): - return ("Attribute '%s' is private and should not be available" - "in a mock object." % self._attr) - - -class ExpectedMockCreationError(Error): - """Raised if mocks should have been created by StubOutClassWithMocks.""" - - def __init__(self, expected_mocks): - """Init exception. - - Args: - # expected_mocks: A sequence of MockObjects that should have been - # created - - Raises: - ValueError: if expected_mocks contains no methods. - """ - - if not expected_mocks: - raise ValueError("There must be at least one expected method") - Error.__init__(self) - self._expected_mocks = expected_mocks - - def __str__(self): - mocks = "\n".join(["%3d. %s" % (i, m) - for i, m in enumerate(self._expected_mocks)]) - return "Verify: Expected mocks never created:\n%s" % (mocks,) - - -class UnexpectedMockCreationError(Error): - """Raised if too many mocks were created by StubOutClassWithMocks.""" - - def __init__(self, instance, *params, **named_params): - """Init exception. - - Args: - # instance: the type of obejct that was created - # params: parameters given during instantiation - # named_params: named parameters given during instantiation - """ - - Error.__init__(self) - self._instance = instance - self._params = params - self._named_params = named_params - - def __str__(self): - args = ", ".join(["%s" % v for i, v in enumerate(self._params)]) - error = "Unexpected mock creation: %s(%s" % (self._instance, args) - - if self._named_params: - error += ", " + ", ".join(["%s=%s" % (k, v) for k, v in - self._named_params.items()]) - - error += ")" - return error - - -class Mox(object): - """Mox: a factory for creating mock objects.""" - - # A list of types that should be stubbed out with MockObjects (as - # opposed to MockAnythings). - _USE_MOCK_OBJECT = [types.FunctionType, types.ModuleType, types.MethodType] - - def __init__(self): - """Initialize a new Mox.""" - - self._mock_objects = [] - self.stubs = stubout.StubOutForTesting() - - def CreateMock(self, class_to_mock, attrs=None, bounded_to=None): - """Create a new mock object. - - Args: - # class_to_mock: the class to be mocked - class_to_mock: class - attrs: dict of attribute names to values that will be - set on the mock object. Only public attributes may be set. - bounded_to: optionally, when class_to_mock is not a class, - it points to a real class object, to which - attribute is bound - - Returns: - MockObject that can be used as the class_to_mock would be. - """ - if attrs is None: - attrs = {} - new_mock = MockObject(class_to_mock, attrs=attrs, - class_to_bind=bounded_to) - self._mock_objects.append(new_mock) - return new_mock - - def CreateMockAnything(self, description=None): - """Create a mock that will accept any method calls. - - This does not enforce an interface. - - Args: - description: str. Optionally, a descriptive name for the mock object - being created, for debugging output purposes. - """ - new_mock = MockAnything(description=description) - self._mock_objects.append(new_mock) - return new_mock - - def ReplayAll(self): - """Set all mock objects to replay mode.""" - - for mock_obj in self._mock_objects: - mock_obj._Replay() - - def VerifyAll(self): - """Call verify on all mock objects created.""" - - for mock_obj in self._mock_objects: - mock_obj._Verify() - - def ResetAll(self): - """Call reset on all mock objects. This does not unset stubs.""" - - for mock_obj in self._mock_objects: - mock_obj._Reset() - - def StubOutWithMock(self, obj, attr_name, use_mock_anything=False): - """Replace a method, attribute, etc. with a Mock. - - This will replace a class or module with a MockObject, and everything - else (method, function, etc) with a MockAnything. This can be - overridden to always use a MockAnything by setting use_mock_anything - to True. - - Args: - obj: A Python object (class, module, instance, callable). - attr_name: str. The name of the attribute to replace with a mock. - use_mock_anything: bool. True if a MockAnything should be used - regardless of the type of attribute. - """ - - if inspect.isclass(obj): - class_to_bind = obj - else: - class_to_bind = None - - attr_to_replace = getattr(obj, attr_name) - attr_type = type(attr_to_replace) - - if attr_type == MockAnything or attr_type == MockObject: - raise TypeError('Cannot mock a MockAnything! Did you remember to ' - 'call UnsetStubs in your previous test?') - - type_check = ( - attr_type in self._USE_MOCK_OBJECT or - inspect.isclass(attr_to_replace) or - isinstance(attr_to_replace, object)) - if type_check and not use_mock_anything: - stub = self.CreateMock(attr_to_replace, bounded_to=class_to_bind) - else: - stub = self.CreateMockAnything( - description='Stub for %s' % attr_to_replace) - stub.__name__ = attr_name - - self.stubs.Set(obj, attr_name, stub) - - def StubOutClassWithMocks(self, obj, attr_name): - """Replace a class with a "mock factory" that will create mock objects. - - This is useful if the code-under-test directly instantiates - dependencies. Previously some boilder plate was necessary to - create a mock that would act as a factory. Using - StubOutClassWithMocks, once you've stubbed out the class you may - use the stubbed class as you would any other mock created by mox: - during the record phase, new mock instances will be created, and - during replay, the recorded mocks will be returned. - - In replay mode - - # Example using StubOutWithMock (the old, clunky way): - - mock1 = mox.CreateMock(my_import.FooClass) - mock2 = mox.CreateMock(my_import.FooClass) - foo_factory = mox.StubOutWithMock(my_import, 'FooClass', - use_mock_anything=True) - foo_factory(1, 2).AndReturn(mock1) - foo_factory(9, 10).AndReturn(mock2) - mox.ReplayAll() - - my_import.FooClass(1, 2) # Returns mock1 again. - my_import.FooClass(9, 10) # Returns mock2 again. - mox.VerifyAll() - - # Example using StubOutClassWithMocks: - - mox.StubOutClassWithMocks(my_import, 'FooClass') - mock1 = my_import.FooClass(1, 2) # Returns a new mock of FooClass - mock2 = my_import.FooClass(9, 10) # Returns another mock instance - mox.ReplayAll() - - my_import.FooClass(1, 2) # Returns mock1 again. - my_import.FooClass(9, 10) # Returns mock2 again. - mox.VerifyAll() - """ - attr_to_replace = getattr(obj, attr_name) - attr_type = type(attr_to_replace) - - if attr_type == MockAnything or attr_type == MockObject: - raise TypeError('Cannot mock a MockAnything! Did you remember to ' - 'call UnsetStubs in your previous test?') - - if not inspect.isclass(attr_to_replace): - raise TypeError('Given attr is not a Class. Use StubOutWithMock.') - - factory = _MockObjectFactory(attr_to_replace, self) - self._mock_objects.append(factory) - self.stubs.Set(obj, attr_name, factory) - - def UnsetStubs(self): - """Restore stubs to their original state.""" - - self.stubs.UnsetAll() - - -def Replay(*args): - """Put mocks into Replay mode. - - Args: - # args is any number of mocks to put into replay mode. - """ - - for mock in args: - mock._Replay() - - -def Verify(*args): - """Verify mocks. - - Args: - # args is any number of mocks to be verified. - """ - - for mock in args: - mock._Verify() - - -def Reset(*args): - """Reset mocks. - - Args: - # args is any number of mocks to be reset. - """ - - for mock in args: - mock._Reset() - - -class MockAnything(object): - """A mock that can be used to mock anything. - - This is helpful for mocking classes that do not provide a public interface. - """ - - def __init__(self, description=None): - """Initialize a new MockAnything. - - Args: - description: str. Optionally, a descriptive name for the mock - object being created, for debugging output purposes. - """ - self._description = description - self._Reset() - - def __repr__(self): - if self._description: - return '' % self._description - else: - return '' - - def __getattr__(self, method_name): - """Intercept method calls on this object. - - A new MockMethod is returned that is aware of the MockAnything's - state (record or replay). The call will be recorded or replayed - by the MockMethod's __call__. - - Args: - # method name: the name of the method being called. - method_name: str - - Returns: - A new MockMethod aware of MockAnything's state (record or replay). - """ - if method_name == '__dir__': - return self.__class__.__dir__.__get__(self, self.__class__) - - return self._CreateMockMethod(method_name) - - def __str__(self): - return self._CreateMockMethod('__str__')() - - def __call__(self, *args, **kwargs): - return self._CreateMockMethod('__call__')(*args, **kwargs) - - def __getitem__(self, i): - return self._CreateMockMethod('__getitem__')(i) - - def _CreateMockMethod(self, method_name, method_to_mock=None, - class_to_bind=object): - """Create a new mock method call and return it. - - Args: - # method_name: the name of the method being called. - # method_to_mock: The actual method being mocked, used for - # introspection. - # class_to_bind: Class to which method is bounded - # (object by default) - method_name: str - method_to_mock: a method object - - Returns: - A new MockMethod aware of MockAnything's state (record or replay). - """ - - return MockMethod(method_name, self._expected_calls_queue, - self._replay_mode, method_to_mock=method_to_mock, - description=self._description, - class_to_bind=class_to_bind) - - def __nonzero__(self): - """Return 1 for nonzero so the mock can be used as a conditional.""" - - return 1 - - def __bool__(self): - """Return True for nonzero so the mock can be used as a conditional.""" - return True - - def __eq__(self, rhs): - """Provide custom logic to compare objects.""" - - return (isinstance(rhs, MockAnything) and - self._replay_mode == rhs._replay_mode and - self._expected_calls_queue == rhs._expected_calls_queue) - - def __ne__(self, rhs): - """Provide custom logic to compare objects.""" - - return not self == rhs - - def _Replay(self): - """Start replaying expected method calls.""" - - self._replay_mode = True - - def _Verify(self): - """Verify that all of the expected calls have been made. - - Raises: - ExpectedMethodCallsError: if there are still more method calls in - the expected queue. - """ - - # If the list of expected calls is not empty, raise an exception - if self._expected_calls_queue: - # The last MultipleTimesGroup is not popped from the queue. - if (len(self._expected_calls_queue) == 1 and - isinstance(self._expected_calls_queue[0], - MultipleTimesGroup) and - self._expected_calls_queue[0].IsSatisfied()): - pass - else: - raise ExpectedMethodCallsError(self._expected_calls_queue) - - def _Reset(self): - """Reset the state of this mock to record mode with an empty queue.""" - - # Maintain a list of method calls we are expecting - self._expected_calls_queue = collections.deque() - - # Make sure we are in setup mode, not replay mode - self._replay_mode = False - - -class MockObject(MockAnything): - """Mock object that simulates the public/protected interface of a class.""" - - def __init__(self, class_to_mock, attrs=None, class_to_bind=None): - """Initialize a mock object. - - Determines the methods and properties of the class and stores them. - - Args: - # class_to_mock: class to be mocked - class_to_mock: class - attrs: dict of attribute names to values that will be set on the - mock object. Only public attributes may be set. - class_to_bind: optionally, when class_to_mock is not a class at - all, it points to a real class - - Raises: - PrivateAttributeError: if a supplied attribute is not public. - ValueError: if an attribute would mask an existing method. - """ - if attrs is None: - attrs = {} - - # Used to hack around the mixin/inheritance of MockAnything, which - # is not a proper object (it can be anything. :-) - MockAnything.__dict__['__init__'](self) - - # Get a list of all the public and special methods we should mock. - self._known_methods = set() - self._known_vars = set() - self._class_to_mock = class_to_mock - - if inspect.isclass(class_to_mock): - self._class_to_bind = self._class_to_mock - else: - self._class_to_bind = class_to_bind - - try: - if inspect.isclass(self._class_to_mock): - self._description = class_to_mock.__name__ - else: - self._description = type(class_to_mock).__name__ - except Exception: - pass - - for method in dir(class_to_mock): - attr = getattr(class_to_mock, method) - if callable(attr): - self._known_methods.add(method) - elif not (type(attr) is property): - # treating properties as class vars makes little sense. - self._known_vars.add(method) - - # Set additional attributes at instantiation time; this is quicker - # than manually setting attributes that are normally created in - # __init__. - for attr, value in attrs.items(): - if attr.startswith("_"): - raise PrivateAttributeError(attr) - elif attr in self._known_methods: - raise ValueError("'%s' is a method of '%s' objects." % (attr, - class_to_mock)) - else: - setattr(self, attr, value) - - def _CreateMockMethod(self, *args, **kwargs): - """Overridden to provide self._class_to_mock to class_to_bind.""" - kwargs.setdefault("class_to_bind", self._class_to_bind) - return super(MockObject, self)._CreateMockMethod(*args, **kwargs) - - def __getattr__(self, name): - """Intercept attribute request on this object. - - If the attribute is a public class variable, it will be returned and - not recorded as a call. - - If the attribute is not a variable, it is handled like a method - call. The method name is checked against the set of mockable - methods, and a new MockMethod is returned that is aware of the - MockObject's state (record or replay). The call will be recorded - or replayed by the MockMethod's __call__. - - Args: - # name: the name of the attribute being requested. - name: str - - Returns: - Either a class variable or a new MockMethod that is aware of the - state of the mock (record or replay). - - Raises: - UnknownMethodCallError if the MockObject does not mock the - requested method. - """ - - if name in self._known_vars: - return getattr(self._class_to_mock, name) - - if name in self._known_methods: - return self._CreateMockMethod( - name, - method_to_mock=getattr(self._class_to_mock, name)) - - raise UnknownMethodCallError(name) - - def __eq__(self, rhs): - """Provide custom logic to compare objects.""" - - return (isinstance(rhs, MockObject) and - self._class_to_mock == rhs._class_to_mock and - self._replay_mode == rhs._replay_mode and - self._expected_calls_queue == rhs._expected_calls_queue) - - def __setitem__(self, key, value): - """Custom logic for mocking classes that support item assignment. - - Args: - key: Key to set the value for. - value: Value to set. - - Returns: - Expected return value in replay mode. A MockMethod object for the - __setitem__ method that has already been called if not in replay - mode. - - Raises: - TypeError if the underlying class does not support item assignment. - UnexpectedMethodCallError if the object does not expect the call to - __setitem__. - - """ - # Verify the class supports item assignment. - if '__setitem__' not in dir(self._class_to_mock): - raise TypeError('object does not support item assignment') - - # If we are in replay mode then simply call the mock __setitem__ method - if self._replay_mode: - return MockMethod('__setitem__', self._expected_calls_queue, - self._replay_mode)(key, value) - - # Otherwise, create a mock method __setitem__. - return self._CreateMockMethod('__setitem__')(key, value) - - def __getitem__(self, key): - """Provide custom logic for mocking classes that are subscriptable. - - Args: - key: Key to return the value for. - - Returns: - Expected return value in replay mode. A MockMethod object for the - __getitem__ method that has already been called if not in replay - mode. - - Raises: - TypeError if the underlying class is not subscriptable. - UnexpectedMethodCallError if the object does not expect the call to - __getitem__. - - """ - # Verify the class supports item assignment. - if '__getitem__' not in dir(self._class_to_mock): - raise TypeError('unsubscriptable object') - - # If we are in replay mode then simply call the mock __getitem__ method - if self._replay_mode: - return MockMethod('__getitem__', self._expected_calls_queue, - self._replay_mode)(key) - - # Otherwise, create a mock method __getitem__. - return self._CreateMockMethod('__getitem__')(key) - - def __iter__(self): - """Provide custom logic for mocking classes that are iterable. - - Returns: - Expected return value in replay mode. A MockMethod object for the - __iter__ method that has already been called if not in replay mode. - - Raises: - TypeError if the underlying class is not iterable. - UnexpectedMethodCallError if the object does not expect the call to - __iter__. - - """ - methods = dir(self._class_to_mock) - - # Verify the class supports iteration. - if '__iter__' not in methods: - # If it doesn't have iter method and we are in replay method, - # then try to iterate using subscripts. - if '__getitem__' not in methods or not self._replay_mode: - raise TypeError('not iterable object') - else: - results = [] - index = 0 - try: - while True: - results.append(self[index]) - index += 1 - except IndexError: - return iter(results) - - # If we are in replay mode then simply call the mock __iter__ method. - if self._replay_mode: - return MockMethod('__iter__', self._expected_calls_queue, - self._replay_mode)() - - # Otherwise, create a mock method __iter__. - return self._CreateMockMethod('__iter__')() - - def __contains__(self, key): - """Provide custom logic for mocking classes that contain items. - - Args: - key: Key to look in container for. - - Returns: - Expected return value in replay mode. A MockMethod object for the - __contains__ method that has already been called if not in replay - mode. - - Raises: - TypeError if the underlying class does not implement __contains__ - UnexpectedMethodCaller if the object does not expect the call to - __contains__. - - """ - contains = self._class_to_mock.__dict__.get('__contains__', None) - - if contains is None: - raise TypeError('unsubscriptable object') - - if self._replay_mode: - return MockMethod('__contains__', self._expected_calls_queue, - self._replay_mode)(key) - - return self._CreateMockMethod('__contains__')(key) - - def __call__(self, *params, **named_params): - """Provide custom logic for mocking classes that are callable.""" - - # Verify the class we are mocking is callable. - is_callable = hasattr(self._class_to_mock, '__call__') - if not is_callable: - raise TypeError('Not callable') - - # Because the call is happening directly on this object instead of - # a method, the call on the mock method is made right here - - # If we are mocking a Function, then use the function, and not the - # __call__ method - method = None - if type(self._class_to_mock) in (types.FunctionType, types.MethodType): - method = self._class_to_mock - else: - method = getattr(self._class_to_mock, '__call__') - mock_method = self._CreateMockMethod('__call__', method_to_mock=method) - - return mock_method(*params, **named_params) - - @property - def __name__(self): - """Return the name that is being mocked.""" - return self._description - - # TODO(dejw): this property stopped to work after I introduced changes with - # binding classes. Fortunately I found a solution in the form of - # __getattribute__ method below, but this issue should be investigated - @property - def __class__(self): - return self._class_to_mock - - def __dir__(self): - """Return only attributes of a class to mock.""" - return dir(self._class_to_mock) - - def __getattribute__(self, name): - """Return _class_to_mock on __class__ attribute.""" - if name == "__class__": - return super(MockObject, self).__getattribute__("_class_to_mock") - - return super(MockObject, self).__getattribute__(name) - - -class _MockObjectFactory(MockObject): - """A MockObjectFactory creates mocks and verifies __init__ params. - - A MockObjectFactory removes the boiler plate code that was previously - necessary to stub out direction instantiation of a class. - - The MockObjectFactory creates new MockObjects when called and verifies the - __init__ params are correct when in record mode. When replaying, - existing mocks are returned, and the __init__ params are verified. - - See StubOutWithMock vs StubOutClassWithMocks for more detail. - """ - - def __init__(self, class_to_mock, mox_instance): - MockObject.__init__(self, class_to_mock) - self._mox = mox_instance - self._instance_queue = collections.deque() - - def __call__(self, *params, **named_params): - """Instantiate and record that a new mock has been created.""" - - method = getattr(self._class_to_mock, '__init__') - mock_method = self._CreateMockMethod('__init__', method_to_mock=method) - # Note: calling mock_method() is deferred in order to catch the - # empty instance_queue first. - - if self._replay_mode: - if not self._instance_queue: - raise UnexpectedMockCreationError(self._class_to_mock, *params, - **named_params) - - mock_method(*params, **named_params) - - return self._instance_queue.pop() - else: - mock_method(*params, **named_params) - - instance = self._mox.CreateMock(self._class_to_mock) - self._instance_queue.appendleft(instance) - return instance - - def _Verify(self): - """Verify that all mocks have been created.""" - if self._instance_queue: - raise ExpectedMockCreationError(self._instance_queue) - super(_MockObjectFactory, self)._Verify() - - -class MethodSignatureChecker(object): - """Ensures that methods are called correctly.""" - - _NEEDED, _DEFAULT, _GIVEN = range(3) - - def __init__(self, method, class_to_bind=None): - """Creates a checker. - - Args: - # method: A method to check. - # class_to_bind: optionally, a class used to type check first - # method parameter, only used with unbound methods - method: function - class_to_bind: type or None - - Raises: - ValueError: method could not be inspected, so checks aren't - possible. Some methods and functions like built-ins - can't be inspected. - """ - try: - self._args, varargs, varkw, defaults = inspect.getargspec(method) - except TypeError: - raise ValueError('Could not get argument specification for %r' - % (method,)) - if (inspect.ismethod(method) or class_to_bind or ( - hasattr(self, '_args') and len(self._args) > 0 and - self._args[0] == 'self')): - self._args = self._args[1:] # Skip 'self'. - self._method = method - self._instance = None # May contain the instance this is bound to. - self._instance = getattr(method, "__self__", None) - - # _bounded_to determines whether the method is bound or not - if self._instance: - self._bounded_to = self._instance.__class__ - else: - self._bounded_to = class_to_bind or getattr(method, "im_class", - None) - - self._has_varargs = varargs is not None - self._has_varkw = varkw is not None - if defaults is None: - self._required_args = self._args - self._default_args = [] - else: - self._required_args = self._args[:-len(defaults)] - self._default_args = self._args[-len(defaults):] - - def _RecordArgumentGiven(self, arg_name, arg_status): - """Mark an argument as being given. - - Args: - # arg_name: The name of the argument to mark in arg_status. - # arg_status: Maps argument names to one of - # _NEEDED, _DEFAULT, _GIVEN. - arg_name: string - arg_status: dict - - Raises: - AttributeError: arg_name is already marked as _GIVEN. - """ - if arg_status.get(arg_name, None) == MethodSignatureChecker._GIVEN: - raise AttributeError('%s provided more than once' % (arg_name,)) - arg_status[arg_name] = MethodSignatureChecker._GIVEN - - def Check(self, params, named_params): - """Ensures that the parameters used while recording a call are valid. - - Args: - # params: A list of positional parameters. - # named_params: A dict of named parameters. - params: list - named_params: dict - - Raises: - AttributeError: the given parameters don't work with the given - method. - """ - arg_status = dict((a, MethodSignatureChecker._NEEDED) - for a in self._required_args) - for arg in self._default_args: - arg_status[arg] = MethodSignatureChecker._DEFAULT - - # WARNING: Suspect hack ahead. - # - # Check to see if this is an unbound method, where the instance - # should be bound as the first argument. We try to determine if - # the first argument (param[0]) is an instance of the class, or it - # is equivalent to the class (used to account for Comparators). - # - # NOTE: If a Func() comparator is used, and the signature is not - # correct, this will cause extra executions of the function. - if inspect.ismethod(self._method) or self._bounded_to: - # The extra param accounts for the bound instance. - if len(params) > len(self._required_args): - expected = self._bounded_to - - # Check if the param is an instance of the expected class, - # or check equality (useful for checking Comparators). - - # This is a hack to work around the fact that the first - # parameter can be a Comparator, and the comparison may raise - # an exception during this comparison, which is OK. - try: - param_equality = (params[0] == expected) - except Exception: - param_equality = False - - if isinstance(params[0], expected) or param_equality: - params = params[1:] - # If the IsA() comparator is being used, we need to check the - # inverse of the usual case - that the given instance is a - # subclass of the expected class. For example, the code under - # test does late binding to a subclass. - elif (isinstance(params[0], IsA) and - params[0]._IsSubClass(expected)): - params = params[1:] - - # Check that each positional param is valid. - for i in range(len(params)): - try: - arg_name = self._args[i] - except IndexError: - if not self._has_varargs: - raise AttributeError( - '%s does not take %d or more positional ' - 'arguments' % (self._method.__name__, i)) - else: - self._RecordArgumentGiven(arg_name, arg_status) - - # Check each keyword argument. - for arg_name in named_params: - if arg_name not in arg_status and not self._has_varkw: - raise AttributeError('%s is not expecting keyword argument %s' - % (self._method.__name__, arg_name)) - self._RecordArgumentGiven(arg_name, arg_status) - - # Ensure all the required arguments have been given. - still_needed = [k for k, v in arg_status.items() - if v == MethodSignatureChecker._NEEDED] - if still_needed: - raise AttributeError('No values given for arguments: %s' - % (' '.join(sorted(still_needed)))) - - -class MockMethod(object): - """Callable mock method. - - A MockMethod should act exactly like the method it mocks, accepting - parameters and returning a value, or throwing an exception (as specified). - When this method is called, it can optionally verify whether the called - method (name and signature) matches the expected method. - """ - - def __init__(self, method_name, call_queue, replay_mode, - method_to_mock=None, description=None, class_to_bind=None): - """Construct a new mock method. - - Args: - # method_name: the name of the method - # call_queue: deque of calls, verify this call against the head, - # or add this call to the queue. - # replay_mode: False if we are recording, True if we are verifying - # calls against the call queue. - # method_to_mock: The actual method being mocked, used for - # introspection. - # description: optionally, a descriptive name for this method. - # Typically this is equal to the descriptive name of - # the method's class. - # class_to_bind: optionally, a class that is used for unbound - # methods (or functions in Python3) to which method - # is bound, in order not to loose binding - # information. If given, it will be used for - # checking the type of first method parameter - method_name: str - call_queue: list or deque - replay_mode: bool - method_to_mock: a method object - description: str or None - class_to_bind: type or None - """ - - self._name = method_name - self.__name__ = method_name - self._call_queue = call_queue - if not isinstance(call_queue, collections.deque): - self._call_queue = collections.deque(self._call_queue) - self._replay_mode = replay_mode - self._description = description - - self._params = None - self._named_params = None - self._return_value = None - self._exception = None - self._side_effects = None - - try: - self._checker = MethodSignatureChecker(method_to_mock, - class_to_bind=class_to_bind) - except ValueError: - self._checker = None - - def __call__(self, *params, **named_params): - """Log parameters and return the specified return value. - - If the Mock(Anything/Object) associated with this call is in record - mode, this MockMethod will be pushed onto the expected call queue. - If the mock is in replay mode, this will pop a MockMethod off the - top of the queue and verify this call is equal to the expected call. - - Raises: - UnexpectedMethodCall if this call is supposed to match an expected - method call and it does not. - """ - - self._params = params - self._named_params = named_params - - if not self._replay_mode: - if self._checker is not None: - self._checker.Check(params, named_params) - self._call_queue.append(self) - return self - - expected_method = self._VerifyMethodCall() - - if expected_method._side_effects: - result = expected_method._side_effects(*params, **named_params) - if expected_method._return_value is None: - expected_method._return_value = result - - if expected_method._exception: - raise expected_method._exception - - return expected_method._return_value - - def __getattr__(self, name): - """Raise an AttributeError with a helpful message.""" - - raise AttributeError( - 'MockMethod has no attribute "%s". ' - 'Did you remember to put your mocks in replay mode?' % name) - - def __iter__(self): - """Raise a TypeError with a helpful message.""" - raise TypeError( - 'MockMethod cannot be iterated. ' - 'Did you remember to put your mocks in replay mode?') - - def next(self): - """Raise a TypeError with a helpful message.""" - raise TypeError( - 'MockMethod cannot be iterated. ' - 'Did you remember to put your mocks in replay mode?') - - def __next__(self): - """Raise a TypeError with a helpful message.""" - raise TypeError( - 'MockMethod cannot be iterated. ' - 'Did you remember to put your mocks in replay mode?') - - def _PopNextMethod(self): - """Pop the next method from our call queue.""" - try: - return self._call_queue.popleft() - except IndexError: - raise UnexpectedMethodCallError(self, None) - - def _VerifyMethodCall(self): - """Verify the called method is expected. - - This can be an ordered method, or part of an unordered set. - - Returns: - The expected mock method. - - Raises: - UnexpectedMethodCall if the method called was not expected. - """ - - expected = self._PopNextMethod() - - # Loop here, because we might have a MethodGroup followed by another - # group. - while isinstance(expected, MethodGroup): - expected, method = expected.MethodCalled(self) - if method is not None: - return method - - # This is a mock method, so just check equality. - if expected != self: - raise UnexpectedMethodCallError(self, expected) - - return expected - - def __str__(self): - params = ', '.join( - [repr(p) for p in self._params or []] + - ['%s=%r' % x for x in sorted((self._named_params or {}).items())]) - full_desc = "%s(%s) -> %r" % (self._name, params, self._return_value) - if self._description: - full_desc = "%s.%s" % (self._description, full_desc) - return full_desc - - def __hash__(self): - return id(self) - - def __eq__(self, rhs): - """Test whether this MockMethod is equivalent to another MockMethod. - - Args: - # rhs: the right hand side of the test - rhs: MockMethod - """ - - return (isinstance(rhs, MockMethod) and - self._name == rhs._name and - self._params == rhs._params and - self._named_params == rhs._named_params) - - def __ne__(self, rhs): - """Test if this MockMethod is not equivalent to another MockMethod. - - Args: - # rhs: the right hand side of the test - rhs: MockMethod - """ - - return not self == rhs - - def GetPossibleGroup(self): - """Returns a possible group from the end of the call queue. - - Return None if no other methods are on the stack. - """ - - # Remove this method from the tail of the queue so we can add it - # to a group. - this_method = self._call_queue.pop() - assert this_method == self - - # Determine if the tail of the queue is a group, or just a regular - # ordered mock method. - group = None - try: - group = self._call_queue[-1] - except IndexError: - pass - - return group - - def _CheckAndCreateNewGroup(self, group_name, group_class): - """Checks if the last method (a possible group) is an instance of our - group_class. Adds the current method to this group or creates a - new one. - - Args: - - group_name: the name of the group. - group_class: the class used to create instance of this new group - """ - group = self.GetPossibleGroup() - - # If this is a group, and it is the correct group, add the method. - if isinstance(group, group_class) and group.group_name() == group_name: - group.AddMethod(self) - return self - - # Create a new group and add the method. - new_group = group_class(group_name) - new_group.AddMethod(self) - self._call_queue.append(new_group) - return self - - def InAnyOrder(self, group_name="default"): - """Move this method into a group of unordered calls. - - A group of unordered calls must be defined together, and must be - executed in full before the next expected method can be called. - There can be multiple groups that are expected serially, if they are - given different group names. The same group name can be reused if there - is a standard method call, or a group with a different name, spliced - between usages. - - Args: - group_name: the name of the unordered group. - - Returns: - self - """ - return self._CheckAndCreateNewGroup(group_name, UnorderedGroup) - - def MultipleTimes(self, group_name="default"): - """Move method into group of calls which may be called multiple times. - - A group of repeating calls must be defined together, and must be - executed in full before the next expected method can be called. - - Args: - group_name: the name of the unordered group. - - Returns: - self - """ - return self._CheckAndCreateNewGroup(group_name, MultipleTimesGroup) - - def AndReturn(self, return_value): - """Set the value to return when this method is called. - - Args: - # return_value can be anything. - """ - - self._return_value = return_value - return return_value - - def AndRaise(self, exception): - """Set the exception to raise when this method is called. - - Args: - # exception: the exception to raise when this method is called. - exception: Exception - """ - - self._exception = exception - - def WithSideEffects(self, side_effects): - """Set the side effects that are simulated when this method is called. - - Args: - side_effects: A callable which modifies the parameters or other - relevant state which a given test case depends on. - - Returns: - Self for chaining with AndReturn and AndRaise. - """ - self._side_effects = side_effects - return self - - -class Comparator: - """Base class for all Mox comparators. - - A Comparator can be used as a parameter to a mocked method when the exact - value is not known. For example, the code you are testing might build up - a long SQL string that is passed to your mock DAO. You're only interested - that the IN clause contains the proper primary keys, so you can set your - mock up as follows: - - mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result) - - Now whatever query is passed in must contain the string 'IN (1, 2, 4, 5)'. - - A Comparator may replace one or more parameters, for example: - # return at most 10 rows - mock_dao.RunQuery(StrContains('SELECT'), 10) - - or - - # Return some non-deterministic number of rows - mock_dao.RunQuery(StrContains('SELECT'), IsA(int)) - """ - - def equals(self, rhs): - """Special equals method that all comparators must implement. - - Args: - rhs: any python object - """ - - raise NotImplementedError('method must be implemented by a subclass.') - - def __eq__(self, rhs): - return self.equals(rhs) - - def __ne__(self, rhs): - return not self.equals(rhs) - - -class Is(Comparator): - """Comparison class used to check identity, instead of equality.""" - - def __init__(self, obj): - self._obj = obj - - def equals(self, rhs): - return rhs is self._obj - - def __repr__(self): - return "" % (self._obj, id(self._obj)) - - -class IsA(Comparator): - """This class wraps a basic Python type or class. It is used to verify - that a parameter is of the given type or class. - - Example: - mock_dao.Connect(IsA(DbConnectInfo)) - """ - - def __init__(self, class_name): - """Initialize IsA - - Args: - class_name: basic python type or a class - """ - - self._class_name = class_name - - def equals(self, rhs): - """Check to see if the RHS is an instance of class_name. - - Args: - # rhs: the right hand side of the test - rhs: object - - Returns: - bool - """ - - try: - return isinstance(rhs, self._class_name) - except TypeError: - # Check raw types if there was a type error. This is helpful for - # things like cStringIO.StringIO. - return type(rhs) == type(self._class_name) - - def _IsSubClass(self, clazz): - """Check to see if the IsA comparators class is a subclass of clazz. - - Args: - # clazz: a class object - - Returns: - bool - """ - - try: - return issubclass(self._class_name, clazz) - except TypeError: - # Check raw types if there was a type error. This is helpful for - # things like cStringIO.StringIO. - return type(clazz) == type(self._class_name) - - def __repr__(self): - return 'mox.IsA(%s) ' % str(self._class_name) - - -class IsAlmost(Comparator): - """Comparison class used to check whether a parameter is nearly equal - to a given value. Generally useful for floating point numbers. - - Example mock_dao.SetTimeout((IsAlmost(3.9))) - """ - - def __init__(self, float_value, places=7): - """Initialize IsAlmost. - - Args: - float_value: The value for making the comparison. - places: The number of decimal places to round to. - """ - - self._float_value = float_value - self._places = places - - def equals(self, rhs): - """Check to see if RHS is almost equal to float_value - - Args: - rhs: the value to compare to float_value - - Returns: - bool - """ - - try: - return round(rhs - self._float_value, self._places) == 0 - except Exception: - # Probably because either float_value or rhs is not a number. - return False - - def __repr__(self): - return str(self._float_value) - - -class StrContains(Comparator): - """Comparison class used to check whether a substring exists in a - string parameter. This can be useful in mocking a database with SQL - passed in as a string parameter, for example. - - Example: - mock_dao.RunQuery(StrContains('IN (1, 2, 4, 5)')).AndReturn(mock_result) - """ - - def __init__(self, search_string): - """Initialize. - - Args: - # search_string: the string you are searching for - search_string: str - """ - - self._search_string = search_string - - def equals(self, rhs): - """Check to see if the search_string is contained in the rhs string. - - Args: - # rhs: the right hand side of the test - rhs: object - - Returns: - bool - """ - - try: - return rhs.find(self._search_string) > -1 - except Exception: - return False - - def __repr__(self): - return '' % self._search_string - - -class Regex(Comparator): - """Checks if a string matches a regular expression. - - This uses a given regular expression to determine equality. - """ - - def __init__(self, pattern, flags=0): - """Initialize. - - Args: - # pattern is the regular expression to search for - pattern: str - # flags passed to re.compile function as the second argument - flags: int - """ - self.flags = flags - self.regex = re.compile(pattern, flags=flags) - - def equals(self, rhs): - """Check to see if rhs matches regular expression pattern. - - Returns: - bool - """ - - try: - return self.regex.search(rhs) is not None - except Exception: - return False - - def __repr__(self): - s = '' % str(self._key) - - -class Not(Comparator): - """Checks whether a predicates is False. - - Example: - mock_dao.UpdateUsers(Not(ContainsKeyValue('stevepm', - stevepm_user_info))) - """ - - def __init__(self, predicate): - """Initialize. - - Args: - # predicate: a Comparator instance. - """ - - assert isinstance(predicate, Comparator), ("predicate %r must be a" - " Comparator." % predicate) - self._predicate = predicate - - def equals(self, rhs): - """Check to see whether the predicate is False. - - Args: - rhs: A value that will be given in argument of the predicate. - - Returns: - bool - """ - - try: - return not self._predicate.equals(rhs) - except Exception: - return False - - def __repr__(self): - return '' % self._predicate - - -class ContainsKeyValue(Comparator): - """Checks whether a key/value pair is in a dict parameter. - - Example: - mock_dao.UpdateUsers(ContainsKeyValue('stevepm', stevepm_user_info)) - """ - - def __init__(self, key, value): - """Initialize. - - Args: - # key: a key in a dict - # value: the corresponding value - """ - - self._key = key - self._value = value - - def equals(self, rhs): - """Check whether the given key/value pair is in the rhs dict. - - Returns: - bool - """ - - try: - return rhs[self._key] == self._value - except Exception: - return False - - def __repr__(self): - return '' % (str(self._key), - str(self._value)) - - -class ContainsAttributeValue(Comparator): - """Checks whether passed parameter contains attributes with a given value. - - Example: - mock_dao.UpdateSomething(ContainsAttribute('stevepm', stevepm_user_info)) - """ - - def __init__(self, key, value): - """Initialize. - - Args: - # key: an attribute name of an object - # value: the corresponding value - """ - - self._key = key - self._value = value - - def equals(self, rhs): - """Check if the given attribute has a matching value in the rhs object. - - Returns: - bool - """ - - try: - return getattr(rhs, self._key) == self._value - except Exception: - return False - - -class SameElementsAs(Comparator): - """Checks whether sequences contain the same elements (ignoring order). - - Example: - mock_dao.ProcessUsers(SameElementsAs('stevepm', 'salomaki')) - """ - - def __init__(self, expected_seq): - """Initialize. - - Args: - expected_seq: a sequence - """ - # Store in case expected_seq is an iterator. - self._expected_list = list(expected_seq) - - def equals(self, actual_seq): - """Check to see whether actual_seq has same elements as expected_seq. - - Args: - actual_seq: sequence - - Returns: - bool - """ - try: - # Store in case actual_seq is an iterator. We potentially iterate - # twice: once to make the dict, once in the list fallback. - actual_list = list(actual_seq) - except TypeError: - # actual_seq cannot be read as a sequence. - # - # This happens because Mox uses __eq__ both to check object - # equality (in MethodSignatureChecker) and to invoke Comparators. - return False - - try: - return set(self._expected_list) == set(actual_list) - except TypeError: - # Fall back to slower list-compare if any of the objects - # are unhashable. - if len(self._expected_list) != len(actual_list): - return False - for el in actual_list: - if el not in self._expected_list: - return False - return True - - def __repr__(self): - return '' % self._expected_list - - -class And(Comparator): - """Evaluates one or more Comparators on RHS, returns an AND of the results. - """ - - def __init__(self, *args): - """Initialize. - - Args: - *args: One or more Comparator - """ - - self._comparators = args - - def equals(self, rhs): - """Checks whether all Comparators are equal to rhs. - - Args: - # rhs: can be anything - - Returns: - bool - """ - - for comparator in self._comparators: - if not comparator.equals(rhs): - return False - - return True - - def __repr__(self): - return '' % str(self._comparators) - - -class Or(Comparator): - """Evaluates one or more Comparators on RHS; returns OR of the results.""" - - def __init__(self, *args): - """Initialize. - - Args: - *args: One or more Mox comparators - """ - - self._comparators = args - - def equals(self, rhs): - """Checks whether any Comparator is equal to rhs. - - Args: - # rhs: can be anything - - Returns: - bool - """ - - for comparator in self._comparators: - if comparator.equals(rhs): - return True - - return False - - def __repr__(self): - return '' % str(self._comparators) - - -class Func(Comparator): - """Call a function that should verify the parameter passed in is correct. - - You may need the ability to perform more advanced operations on the - parameter in order to validate it. You can use this to have a callable - validate any parameter. The callable should return either True or False. - - - Example: - - def myParamValidator(param): - # Advanced logic here - return True - - mock_dao.DoSomething(Func(myParamValidator), true) - """ - - def __init__(self, func): - """Initialize. - - Args: - func: callable that takes one parameter and returns a bool - """ - - self._func = func - - def equals(self, rhs): - """Test whether rhs passes the function test. - - rhs is passed into func. - - Args: - rhs: any python object - - Returns: - the result of func(rhs) - """ - - return self._func(rhs) - - def __repr__(self): - return str(self._func) - - -class IgnoreArg(Comparator): - """Ignore an argument. - - This can be used when we don't care about an argument of a method call. - - Example: - # Check if CastMagic is called with 3 as first arg and - # 'disappear' as third. - mymock.CastMagic(3, IgnoreArg(), 'disappear') - """ - - def equals(self, unused_rhs): - """Ignores arguments and returns True. - - Args: - unused_rhs: any python object - - Returns: - always returns True - """ - - return True - - def __repr__(self): - return '' - - -class Value(Comparator): - """Compares argument against a remembered value. - - To be used in conjunction with Remember comparator. See Remember() - for example. - """ - - def __init__(self): - self._value = None - self._has_value = False - - def store_value(self, rhs): - self._value = rhs - self._has_value = True - - def equals(self, rhs): - if not self._has_value: - return False - else: - return rhs == self._value - - def __repr__(self): - if self._has_value: - return "" % self._value - else: - return "" - - -class Remember(Comparator): - """Remembers the argument to a value store. - - To be used in conjunction with Value comparator. - - Example: - # Remember the argument for one method call. - users_list = Value() - mock_dao.ProcessUsers(Remember(users_list)) - - # Check argument against remembered value. - mock_dao.ReportUsers(users_list) - """ - - def __init__(self, value_store): - if not isinstance(value_store, Value): - raise TypeError( - "value_store is not an instance of the Value class") - self._value_store = value_store - - def equals(self, rhs): - self._value_store.store_value(rhs) - return True - - def __repr__(self): - return "" % id(self._value_store) - - -class MethodGroup(object): - """Base class containing common behaviour for MethodGroups.""" - - def __init__(self, group_name): - self._group_name = group_name - - def group_name(self): - return self._group_name - - def __str__(self): - return '<%s "%s">' % (self.__class__.__name__, self._group_name) - - def AddMethod(self, mock_method): - raise NotImplementedError - - def MethodCalled(self, mock_method): - raise NotImplementedError - - def IsSatisfied(self): - raise NotImplementedError - - -class UnorderedGroup(MethodGroup): - """UnorderedGroup holds a set of method calls that may occur in any order. - - This construct is helpful for non-deterministic events, such as iterating - over the keys of a dict. - """ - - def __init__(self, group_name): - super(UnorderedGroup, self).__init__(group_name) - self._methods = [] - - def __str__(self): - return '%s "%s" pending calls:\n%s' % ( - self.__class__.__name__, - self._group_name, - "\n".join(str(method) for method in self._methods)) - - def AddMethod(self, mock_method): - """Add a method to this group. - - Args: - mock_method: A mock method to be added to this group. - """ - - self._methods.append(mock_method) - - def MethodCalled(self, mock_method): - """Remove a method call from the group. - - If the method is not in the set, an UnexpectedMethodCallError will be - raised. - - Args: - mock_method: a mock method that should be equal to a method in the - group. - - Returns: - The mock method from the group - - Raises: - UnexpectedMethodCallError if the mock_method was not in the group. - """ - - # Check to see if this method exists, and if so, remove it from the set - # and return it. - for method in self._methods: - if method == mock_method: - # Remove the called mock_method instead of the method in the - # group. The called method will match any comparators when - # equality is checked during removal. The method in the group - # could pass a comparator to another comparator during the - # equality check. - self._methods.remove(mock_method) - - # If group is not empty, put it back at the head of the queue. - if not self.IsSatisfied(): - mock_method._call_queue.appendleft(self) - - return self, method - - raise UnexpectedMethodCallError(mock_method, self) - - def IsSatisfied(self): - """Return True if there are not any methods in this group.""" - - return len(self._methods) == 0 - - -class MultipleTimesGroup(MethodGroup): - """MultipleTimesGroup holds methods that may be called any number of times. - - Note: Each method must be called at least once. - - This is helpful, if you don't know or care how many times a method is - called. - """ - - def __init__(self, group_name): - super(MultipleTimesGroup, self).__init__(group_name) - self._methods = set() - self._methods_left = set() - - def AddMethod(self, mock_method): - """Add a method to this group. - - Args: - mock_method: A mock method to be added to this group. - """ - - self._methods.add(mock_method) - self._methods_left.add(mock_method) - - def MethodCalled(self, mock_method): - """Remove a method call from the group. - - If the method is not in the set, an UnexpectedMethodCallError will be - raised. - - Args: - mock_method: a mock method that should be equal to a method in the - group. - - Returns: - The mock method from the group - - Raises: - UnexpectedMethodCallError if the mock_method was not in the group. - """ - - # Check to see if this method exists, and if so add it to the set of - # called methods. - for method in self._methods: - if method == mock_method: - self._methods_left.discard(method) - # Always put this group back on top of the queue, - # because we don't know when we are done. - mock_method._call_queue.appendleft(self) - return self, method - - if self.IsSatisfied(): - next_method = mock_method._PopNextMethod() - return next_method, None - else: - raise UnexpectedMethodCallError(mock_method, self) - - def IsSatisfied(self): - """Return True if all methods in group are called at least once.""" - return len(self._methods_left) == 0 - - -class MoxMetaTestBase(type): - """Metaclass to add mox cleanup and verification to every test. - - As the mox unit testing class is being constructed (MoxTestBase or a - subclass), this metaclass will modify all test functions to call the - CleanUpMox method of the test class after they finish. This means that - unstubbing and verifying will happen for every test with no additional - code, and any failures will result in test failures as opposed to errors. - """ - - def __init__(cls, name, bases, d): - type.__init__(cls, name, bases, d) - - # also get all the attributes from the base classes to account - # for a case when test class is not the immediate child of MoxTestBase - for base in bases: - for attr_name in dir(base): - if attr_name not in d: - d[attr_name] = getattr(base, attr_name) - - for func_name, func in d.items(): - if func_name.startswith('test') and callable(func): - - setattr(cls, func_name, MoxMetaTestBase.CleanUpTest(cls, func)) - - @staticmethod - def CleanUpTest(cls, func): - """Adds Mox cleanup code to any MoxTestBase method. - - Always unsets stubs after a test. Will verify all mocks for tests that - otherwise pass. - - Args: - cls: MoxTestBase or subclass; the class whose method we are - altering. - func: method; the method of the MoxTestBase test class we wish to - alter. - - Returns: - The modified method. - """ - def new_method(self, *args, **kwargs): - mox_obj = getattr(self, 'mox', None) - stubout_obj = getattr(self, 'stubs', None) - cleanup_mox = False - cleanup_stubout = False - if mox_obj and isinstance(mox_obj, Mox): - cleanup_mox = True - if stubout_obj and isinstance(stubout_obj, - stubout.StubOutForTesting): - cleanup_stubout = True - try: - func(self, *args, **kwargs) - finally: - if cleanup_mox: - mox_obj.UnsetStubs() - if cleanup_stubout: - stubout_obj.UnsetAll() - stubout_obj.SmartUnsetAll() - if cleanup_mox: - mox_obj.VerifyAll() - new_method.__name__ = func.__name__ - new_method.__doc__ = func.__doc__ - new_method.__module__ = func.__module__ - return new_method - - -_MoxTestBase = MoxMetaTestBase('_MoxTestBase', (unittest.TestCase, ), {}) - - -class MoxTestBase(_MoxTestBase): - """Convenience test class to make stubbing easier. - - Sets up a "mox" attribute which is an instance of Mox (any mox tests will - want this), and a "stubs" attribute that is an instance of - StubOutForTesting (needed at times). Also automatically unsets any stubs - and verifies that all mock methods have been called at the end of each - test, eliminating boilerplate code. - """ - - def setUp(self): - super(MoxTestBase, self).setUp() - self.mox = Mox() - self.stubs = stubout.StubOutForTesting() diff --git a/mox3/stubout.py b/mox3/stubout.py deleted file mode 100644 index 4773771..0000000 --- a/mox3/stubout.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This is a fork of the pymox library intended to work with Python 3. -# The file was modified by quermit@gmail.com and dawid.fatyga@gmail.com - -import inspect - - -class StubOutForTesting(object): - """Sample Usage: - - You want os.path.exists() to always return true during testing. - - stubs = StubOutForTesting() - stubs.Set(os.path, 'exists', lambda x: 1) - ... - stubs.UnsetAll() - - The above changes os.path.exists into a lambda that returns 1. Once - the ... part of the code finishes, the UnsetAll() looks up the old value - of os.path.exists and restores it. - - """ - def __init__(self): - self.cache = [] - self.stubs = [] - - def __del__(self): - self.SmartUnsetAll() - self.UnsetAll() - - def SmartSet(self, obj, attr_name, new_attr): - """Replace obj.attr_name with new_attr. - - This method is smart and works at the module, class, and instance level - while preserving proper inheritance. It will not stub out C types - however unless that has been explicitly allowed by the type. - - This method supports the case where attr_name is a staticmethod or a - classmethod of obj. - - Notes: - - If obj is an instance, then it is its class that will actually be - stubbed. Note that the method Set() does not do that: if obj is - an instance, it (and not its class) will be stubbed. - - The stubbing is using the builtin getattr and setattr. So, the - __get__ and __set__ will be called when stubbing (TODO: A better - idea would probably be to manipulate obj.__dict__ instead of - getattr() and setattr()). - - Raises AttributeError if the attribute cannot be found. - """ - if (inspect.ismodule(obj) or - (not inspect.isclass(obj) and attr_name in obj.__dict__)): - orig_obj = obj - orig_attr = getattr(obj, attr_name) - - else: - if not inspect.isclass(obj): - mro = list(inspect.getmro(obj.__class__)) - else: - mro = list(inspect.getmro(obj)) - - mro.reverse() - - orig_attr = None - - for cls in mro: - try: - orig_obj = cls - orig_attr = getattr(obj, attr_name) - except AttributeError: - continue - - if orig_attr is None: - raise AttributeError("Attribute not found.") - - # Calling getattr() on a staticmethod transforms it to a 'normal' - # function. We need to ensure that we put it back as a staticmethod. - old_attribute = obj.__dict__.get(attr_name) - if (old_attribute is not None and - isinstance(old_attribute, staticmethod)): - orig_attr = staticmethod(orig_attr) - - self.stubs.append((orig_obj, attr_name, orig_attr)) - setattr(orig_obj, attr_name, new_attr) - - def SmartUnsetAll(self): - """Reverses all the SmartSet() calls. - - Restores things to their original definition. Its okay to call - SmartUnsetAll() repeatedly, as later calls have no effect if no - SmartSet() calls have been made. - """ - self.stubs.reverse() - - for args in self.stubs: - setattr(*args) - - self.stubs = [] - - def Set(self, parent, child_name, new_child): - """Replace child_name's old definition with new_child. - - Replace definiion in the context of the given parent. The parent could - be a module when the child is a function at module scope. Or the parent - could be a class when a class' method is being replaced. The named - child is set to new_child, while the prior definition is saved away - for later, when UnsetAll() is called. - - This method supports the case where child_name is a staticmethod or a - classmethod of parent. - """ - old_child = getattr(parent, child_name) - - old_attribute = parent.__dict__.get(child_name) - if old_attribute is not None: - if isinstance(old_attribute, staticmethod): - old_child = staticmethod(old_child) - elif isinstance(old_attribute, classmethod): - old_child = classmethod(old_child.__func__) - - self.cache.append((parent, old_child, child_name)) - setattr(parent, child_name, new_child) - - def UnsetAll(self): - """Reverses all the Set() calls. - - Restores things to their original definition. Its okay to call - UnsetAll() repeatedly, as later calls have no effect if no Set() - calls have been made. - """ - # Undo calls to Set() in reverse order, in case Set() was called on the - # same arguments repeatedly (want the original call to be last one - # undone) - self.cache.reverse() - - for (parent, old_child, child_name) in self.cache: - setattr(parent, child_name, old_child) - self.cache = [] diff --git a/mox3/tests/__init__.py b/mox3/tests/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/mox3/tests/mox_helper.py b/mox3/tests/mox_helper.py deleted file mode 100644 index 67843a9..0000000 --- a/mox3/tests/mox_helper.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# -# This is a fork of the pymox library intended to work with Python 3. -# The file was modified by quermit@gmail.com and dawid.fatyga@gmail.com - -"""A very basic test class derived from mox.MoxTestBase, used by test_mox.py. - -The class defined in this module is used to test the features of -MoxTestBase and is not intended to be a standalone test. It needs to -be in a separate module, because otherwise the tests in this class -(which should not all pass) would be executed as part of the -test_mox.py test suite. - -See test_mox.MoxTestBaseTest for how this class is actually used. -""" - -import os - -from mox3 import mox - - -class ExampleMoxTestMixin(object): - """Mix-in class for mox test case class. - - It stubs out the same function as one of the test methods in - the example test case. Both tests must pass as meta class wraps - test methods in all base classes. - """ - - def testStat(self): - self.mox.StubOutWithMock(os, 'stat') - os.stat(self.DIR_PATH) - self.mox.ReplayAll() - os.stat(self.DIR_PATH) - - -class ExampleMoxTest(mox.MoxTestBase, ExampleMoxTestMixin): - - DIR_PATH = '/path/to/some/directory' - - def testSuccess(self): - self.mox.StubOutWithMock(os, 'listdir') - os.listdir(self.DIR_PATH) - self.mox.ReplayAll() - os.listdir(self.DIR_PATH) - - def testExpectedNotCalled(self): - self.mox.StubOutWithMock(os, 'listdir') - os.listdir(self.DIR_PATH) - self.mox.ReplayAll() - - def testUnexpectedCall(self): - self.mox.StubOutWithMock(os, 'listdir') - os.listdir(self.DIR_PATH) - self.mox.ReplayAll() - os.listdir('/path/to/some/other/directory') - os.listdir(self.DIR_PATH) - - def testFailure(self): - self.assertTrue(False) - - def testStatOther(self): - self.mox.StubOutWithMock(os, 'stat') - os.stat(self.DIR_PATH) - self.mox.ReplayAll() - os.stat(self.DIR_PATH) - - def testHasStubs(self): - listdir_list = [] - - def MockListdir(directory): - listdir_list.append(directory) - - self.stubs.Set(os, 'listdir', MockListdir) - os.listdir(self.DIR_PATH) - self.assertEqual([self.DIR_PATH], listdir_list) - - -class TestClassFromAnotherModule(object): - - def __init__(self): - return None - - def Value(self): - return 'Not mock' - - -class ChildClassFromAnotherModule(TestClassFromAnotherModule): - """A child class of TestClassFromAnotherModule. - - Used to test stubbing out unbound methods, where child classes - are eventually bound. - """ - - def __init__(self): - TestClassFromAnotherModule.__init__(self) - - -class CallableClass(object): - - def __init__(self, one, two, nine=None): - pass - - def __call__(self, one): - return 'Not mock' - - def Value(self): - return 'Not mock' - - -def MyTestFunction(one, two, nine=None): - pass - - -class ExampleClass(object): - def __init__(self, foo='bar'): - pass - - def TestMethod(self, one, two, nine=None): - pass - - def NamedParams(self, ignore, foo='bar', baz='qux'): - pass - - def SpecialArgs(self, *args, **kwargs): - pass - - -# This class is used to test stubbing out __init__ of a parent class. -class ChildExampleClass(ExampleClass): - def __init__(self): - ExampleClass.__init__(self) diff --git a/mox3/tests/stubout_helper.py b/mox3/tests/stubout_helper.py deleted file mode 100644 index 7a6b266..0000000 --- a/mox3/tests/stubout_helper.py +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This is a fork of the pymox library intended to work with Python 3. -# The file was modified by quermit@gmail.com and dawid.fatyga@gmail.com - - -def SampleFunction(): - raise Exception('I should never be called!') diff --git a/mox3/tests/test_mox.py b/mox3/tests/test_mox.py deleted file mode 100644 index a1ddb18..0000000 --- a/mox3/tests/test_mox.py +++ /dev/null @@ -1,2394 +0,0 @@ -# Unit tests for Mox. -# -# Copyright 2008 Google Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This is a fork of the pymox library intended to work with Python 3. -# The file was modified by quermit@gmail.com and dawid.fatyga@gmail.com - -import io -import re - -from mox3 import mox -from mox3.tests import mox_helper - -import testtools - - -OS_LISTDIR = mox_helper.os.listdir - - -class ExpectedMethodCallsErrorTest(testtools.TestCase): - """Test creation and string conversion of ExpectedMethodCallsError.""" - - def testAtLeastOneMethod(self): - self.assertRaises(ValueError, mox.ExpectedMethodCallsError, []) - - def testOneError(self): - method = mox.MockMethod("testMethod", [], False) - method(1, 2).AndReturn('output') - e = mox.ExpectedMethodCallsError([method]) - self.assertEqual( - "Verify: Expected methods never called:\n" - " 0. testMethod(1, 2) -> 'output'", - str(e)) - - def testManyErrors(self): - method1 = mox.MockMethod("testMethod", [], False) - method1(1, 2).AndReturn('output') - method2 = mox.MockMethod("testMethod", [], False) - method2(a=1, b=2, c="only named") - method3 = mox.MockMethod("testMethod2", [], False) - method3().AndReturn(44) - method4 = mox.MockMethod("testMethod", [], False) - method4(1, 2).AndReturn('output') - e = mox.ExpectedMethodCallsError([method1, method2, method3, method4]) - self.assertEqual( - "Verify: Expected methods never called:\n" - " 0. testMethod(1, 2) -> 'output'\n" - " 1. testMethod(a=1, b=2, c='only named') -> None\n" - " 2. testMethod2() -> 44\n" - " 3. testMethod(1, 2) -> 'output'", - str(e)) - - -class OrTest(testtools.TestCase): - """Test Or correctly chains Comparators.""" - - def testValidOr(self): - """Or should be True if either Comparator returns True.""" - self.assertTrue(mox.Or(mox.IsA(dict), mox.IsA(str)) == {}) - self.assertTrue(mox.Or(mox.IsA(dict), mox.IsA(str)) == 'test') - self.assertTrue(mox.Or(mox.IsA(str), mox.IsA(str)) == 'test') - - def testInvalidOr(self): - """Or should be False if both Comparators return False.""" - self.assertFalse(mox.Or(mox.IsA(dict), mox.IsA(str)) == 0) - - -class AndTest(testtools.TestCase): - """Test And correctly chains Comparators.""" - - def testValidAnd(self): - """And should be True if both Comparators return True.""" - self.assertTrue(mox.And(mox.IsA(str), mox.IsA(str)) == '1') - - def testClauseOneFails(self): - """And should be False if the first Comparator returns False.""" - - self.assertFalse(mox.And(mox.IsA(dict), mox.IsA(str)) == '1') - - def testAdvancedUsage(self): - """And should work with other Comparators. - - Note: this test is reliant on In and ContainsKeyValue. - """ - test_dict = {"mock": "obj", "testing": "isCOOL"} - self.assertTrue(mox.And(mox.In("testing"), - mox.ContainsKeyValue("mock", "obj")) == test_dict) - - def testAdvancedUsageFails(self): - """Note: this test is reliant on In and ContainsKeyValue.""" - test_dict = {"mock": "obj", "testing": "isCOOL"} - self.assertFalse(mox.And(mox.In("NOTFOUND"), - mox.ContainsKeyValue("mock", "obj")) == test_dict) - - -class FuncTest(testtools.TestCase): - """Test Func correctly evaluates based upon true-false return.""" - - def testFuncTrueFalseEvaluation(self): - """Should return True if the validating function returns True.""" - - def equals_one(x): - return x == 1 - - def always_none(x): - return None - - self.assertTrue(mox.Func(equals_one) == 1) - self.assertFalse(mox.Func(equals_one) == 0) - - self.assertFalse(mox.Func(always_none) == 1) - self.assertFalse(mox.Func(always_none) == 0) - self.assertFalse(mox.Func(always_none) is None) - - def testFuncExceptionPropagation(self): - """Exceptions within the validating function should propagate.""" - class TestException(Exception): - pass - - def raiseExceptionOnNotOne(value): - if value != 1: - raise TestException - else: - return True - - self.assertTrue(mox.Func(raiseExceptionOnNotOne) == 1) - self.assertRaises( - TestException, mox.Func(raiseExceptionOnNotOne).__eq__, 2) - - -class SameElementsAsTest(testtools.TestCase): - """SameElementsAs correctly identifies sequences with same elements.""" - - def testSortedLists(self): - """Should return True if two lists are exactly equal.""" - self.assertTrue(mox.SameElementsAs([1, 2.0, 'c']) == [1, 2.0, 'c']) - - def testUnsortedLists(self): - """Should return True if lists are unequal but have same elements.""" - self.assertTrue(mox.SameElementsAs([1, 2.0, 'c']) == [2.0, 'c', 1]) - - def testUnhashableLists(self): - """Should return True if lists have the same unhashable elements.""" - self.assertTrue(mox.SameElementsAs([{'a': 1}, {2: 'b'}]) == - [{2: 'b'}, {'a': 1}]) - - def testEmptyLists(self): - """Should return True for two empty lists.""" - self.assertTrue(mox.SameElementsAs([]) == []) - - def testUnequalLists(self): - """Should return False if the lists are not equal.""" - self.assertFalse(mox.SameElementsAs([1, 2.0, 'c']) == [2.0, 'c']) - - def testUnequalUnhashableLists(self): - """Should return False if lists with unhashable items are unequal.""" - self.assertFalse(mox.SameElementsAs( - [{'a': 1}, {2: 'b'}]) == [{2: 'b'}]) - - def testActualIsNotASequence(self): - """Should return False if the actual object is not a sequence.""" - self.assertFalse(mox.SameElementsAs([1]) == object()) - - def testOneUnhashableObjectInActual(self): - """Store the entire iterator for a correct comparison. - - In a previous version of SameElementsAs, iteration stopped when an - unhashable object was encountered and then was restarted, so the actual - list appeared smaller than it was. - """ - self.assertFalse(mox.SameElementsAs([1, 2]) == iter([{}, 1, 2])) - - -class ContainsKeyValueTest(testtools.TestCase): - """Test ContainsKeyValue correctly identifies key/value pairs in a dict. - """ - - def testValidPair(self): - """Should return True if the key value is in the dict.""" - self.assertTrue(mox.ContainsKeyValue("key", 1) == {"key": 1}) - - def testInvalidValue(self): - """Should return False if the value is not correct.""" - self.assertFalse(mox.ContainsKeyValue("key", 1) == {"key": 2}) - - def testInvalidKey(self): - """Should return False if they key is not in the dict.""" - self.assertFalse(mox.ContainsKeyValue("qux", 1) == {"key": 2}) - - -class ContainsAttributeValueTest(testtools.TestCase): - """Test ContainsAttributeValue identifies properties in an object.""" - - def setUp(self): - """Create an object to test with.""" - - class TestObject(object): - key = 1 - - super(ContainsAttributeValueTest, self).setUp() - self.test_object = TestObject() - - def testValidPair(self): - """Return True if the object has the key attribute that matches.""" - self.assertTrue(mox.ContainsAttributeValue("key", 1) == - self.test_object) - - def testInvalidValue(self): - """Should return False if the value is not correct.""" - self.assertFalse(mox.ContainsKeyValue("key", 2) == self.test_object) - - def testInvalidKey(self): - """Should return False if they the object doesn't have the property.""" - self.assertFalse(mox.ContainsKeyValue("qux", 1) == self.test_object) - - -class InTest(testtools.TestCase): - """Test In correctly identifies a key in a list/dict.""" - - def testItemInList(self): - """Should return True if the item is in the list.""" - self.assertTrue(mox.In(1) == [1, 2, 3]) - - def testKeyInDict(self): - """Should return True if the item is a key in a dict.""" - self.assertTrue(mox.In("test") == {"test": "module"}) - - def testItemInTuple(self): - """Should return True if the item is in the list.""" - self.assertTrue(mox.In(1) == (1, 2, 3)) - - def testTupleInTupleOfTuples(self): - self.assertTrue(mox.In((1, 2, 3)) == ((1, 2, 3), (1, 2))) - - def testItemNotInList(self): - self.assertFalse(mox.In(1) == [2, 3]) - - def testTupleNotInTupleOfTuples(self): - self.assertFalse(mox.In((1, 2)) == ((1, 2, 3), (4, 5))) - - -class NotTest(testtools.TestCase): - """Test Not correctly identifies False predicates.""" - - def testItemInList(self): - """Should return True if the item is NOT in the list.""" - self.assertTrue(mox.Not(mox.In(42)) == [1, 2, 3]) - - def testKeyInDict(self): - """Should return True if the item is NOT a key in a dict.""" - self.assertTrue(mox.Not(mox.In("foo")) == {"key": 42}) - - def testInvalidKeyWithNot(self): - """Should return False if they key is NOT in the dict.""" - self.assertTrue(mox.Not(mox.ContainsKeyValue("qux", 1)) == {"key": 2}) - - -class StrContainsTest(testtools.TestCase): - """Test StrContains checks for substring occurrence of a parameter.""" - - def testValidSubstringAtStart(self): - """Should return True if substring is at the start of the string.""" - self.assertTrue(mox.StrContains("hello") == "hello world") - - def testValidSubstringInMiddle(self): - """Should return True if substring is in the middle of the string.""" - self.assertTrue(mox.StrContains("lo wo") == "hello world") - - def testValidSubstringAtEnd(self): - """Should return True if the substring is at the end of the string.""" - self.assertTrue(mox.StrContains("ld") == "hello world") - - def testInvaildSubstring(self): - """Should return False if the substring is not in the string.""" - self.assertFalse(mox.StrContains("AAA") == "hello world") - - def testMultipleMatches(self): - """Should return True if there are multiple occurrences of substring""" - self.assertTrue(mox.StrContains("abc") == "ababcabcabcababc") - - -class RegexTest(testtools.TestCase): - """Test Regex correctly matches regular expressions.""" - - def testIdentifyBadSyntaxDuringInit(self): - """The user should know immediately if a regex has bad syntax.""" - self.assertRaises(re.error, mox.Regex, '(a|b') - - def testPatternInMiddle(self): - """Return True if the pattern matches at the middle of the string. - - This ensures that re.search is used (instead of re.find). - """ - self.assertTrue(mox.Regex(r"a\s+b") == "x y z a b c") - - def testNonMatchPattern(self): - """Should return False if the pattern does not match the string.""" - self.assertFalse(mox.Regex(r"a\s+b") == "x y z") - - def testFlagsPassedCorrectly(self): - """Should return True as we pass IGNORECASE flag.""" - self.assertTrue(mox.Regex(r"A", re.IGNORECASE) == "a") - - def testReprWithoutFlags(self): - """repr should return the regular expression pattern.""" - self.assertTrue( - repr(mox.Regex(r"a\s+b")) == "") - - def testReprWithFlags(self): - """repr should return the regular expression pattern and flags.""" - self.assertTrue(repr(mox.Regex(r"a\s+b", flags=2)) == - "") - - -class IsTest(testtools.TestCase): - """Verify Is correctly checks equality based upon identity, not value.""" - - class AlwaysComparesTrue(object): - def __eq__(self, other): - return True - - def __cmp__(self, other): - return 0 - - def __ne__(self, other): - return False - - def testEqualityValid(self): - o1 = self.AlwaysComparesTrue() - self.assertTrue(mox.Is(o1), o1) - - def testEqualityInvalid(self): - o1 = self.AlwaysComparesTrue() - o2 = self.AlwaysComparesTrue() - self.assertTrue(o1 == o2) - # but... - self.assertFalse(mox.Is(o1) == o2) - - def testInequalityValid(self): - o1 = self.AlwaysComparesTrue() - o2 = self.AlwaysComparesTrue() - self.assertTrue(mox.Is(o1) != o2) - - def testInequalityInvalid(self): - o1 = self.AlwaysComparesTrue() - self.assertFalse(mox.Is(o1) != o1) - - def testEqualityInListValid(self): - o1 = self.AlwaysComparesTrue() - o2 = self.AlwaysComparesTrue() - isa_list = [mox.Is(o1), mox.Is(o2)] - str_list = [o1, o2] - self.assertTrue(isa_list == str_list) - - def testEquailtyInListInvalid(self): - o1 = self.AlwaysComparesTrue() - o2 = self.AlwaysComparesTrue() - isa_list = [mox.Is(o1), mox.Is(o2)] - mixed_list = [o2, o1] - self.assertFalse(isa_list == mixed_list) - - -class IsATest(testtools.TestCase): - """Verify IsA correctly checks equality based upon class type not value.""" - - def testEqualityValid(self): - """Verify that == correctly identifies objects of the same type.""" - self.assertTrue(mox.IsA(str) == 'test') - - def testEqualityInvalid(self): - """Verify that == correctly identifies objects of different types.""" - self.assertFalse(mox.IsA(str) == 10) - - def testInequalityValid(self): - """Verify that != identifies objects of different type.""" - self.assertTrue(mox.IsA(str) != 10) - - def testInequalityInvalid(self): - """Verify that != correctly identifies objects of the same type.""" - self.assertFalse(mox.IsA(str) != "test") - - def testEqualityInListValid(self): - """Verify list contents are properly compared.""" - isa_list = [mox.IsA(str), mox.IsA(str)] - str_list = ["abc", "def"] - self.assertTrue(isa_list == str_list) - - def testEquailtyInListInvalid(self): - """Verify list contents are properly compared.""" - isa_list = [mox.IsA(str), mox.IsA(str)] - mixed_list = ["abc", 123] - self.assertFalse(isa_list == mixed_list) - - def testSpecialTypes(self): - """Verify that IsA can handle objects like io.StringIO.""" - isA = mox.IsA(io.StringIO()) - stringIO = io.StringIO() - self.assertTrue(isA == stringIO) - - -class IsAlmostTest(testtools.TestCase): - """Verify IsAlmost correctly checks equality of floating point numbers.""" - - def testEqualityValid(self): - """Verify that == correctly identifies nearly equivalent floats.""" - self.assertEqual(mox.IsAlmost(1.8999999999), 1.9) - - def testEqualityInvalid(self): - """Verify that == correctly identifies non-equivalent floats.""" - self.assertNotEqual(mox.IsAlmost(1.899), 1.9) - - def testEqualityWithPlaces(self): - """Verify that specifying places has the desired effect.""" - self.assertNotEqual(mox.IsAlmost(1.899), 1.9) - self.assertEqual(mox.IsAlmost(1.899, places=2), 1.9) - - def testNonNumericTypes(self): - """Verify that IsAlmost handles non-numeric types properly.""" - - self.assertNotEqual(mox.IsAlmost(1.8999999999), '1.9') - self.assertNotEqual(mox.IsAlmost('1.8999999999'), 1.9) - self.assertNotEqual(mox.IsAlmost('1.8999999999'), '1.9') - - -class ValueRememberTest(testtools.TestCase): - """Verify comparing argument against remembered value.""" - - def testValueEquals(self): - """Verify that value will compare to stored value.""" - value = mox.Value() - value.store_value('hello world') - self.assertEqual(value, 'hello world') - - def testNoValue(self): - """Verify that uninitialized value does not compare to empty values.""" - value = mox.Value() - self.assertNotEqual(value, None) - self.assertNotEqual(value, False) - self.assertNotEqual(value, 0) - self.assertNotEqual(value, '') - self.assertNotEqual(value, ()) - self.assertNotEqual(value, []) - self.assertNotEqual(value, {}) - self.assertNotEqual(value, object()) - self.assertNotEqual(value, set()) - - def testRememberValue(self): - """Verify that comparing against remember will store argument.""" - value = mox.Value() - remember = mox.Remember(value) - self.assertNotEqual(value, 'hello world') # value not yet stored. - self.assertEqual(remember, 'hello world') # store value here. - self.assertEqual(value, 'hello world') # compare against stored value. - - -class MockMethodTest(testtools.TestCase): - """Test class to verify that the MockMethod class is working correctly.""" - - def setUp(self): - super(MockMethodTest, self).setUp() - self.expected_method = mox.MockMethod( - "testMethod", [], False)(['original']) - self.mock_method = mox.MockMethod( - "testMethod", [self.expected_method], True) - - def testNameAttribute(self): - """Should provide a __name__ attribute.""" - self.assertEqual('testMethod', self.mock_method.__name__) - - def testAndReturnNoneByDefault(self): - """Should return None by default.""" - return_value = self.mock_method(['original']) - self.assertTrue(return_value is None) - - def testAndReturnValue(self): - """Should return a specificed return value.""" - expected_return_value = "test" - self.expected_method.AndReturn(expected_return_value) - return_value = self.mock_method(['original']) - self.assertTrue(return_value == expected_return_value) - - def testAndRaiseException(self): - """Should raise a specified exception.""" - class TestException(Exception): - pass - - expected_exception = TestException('test exception') - self.expected_method.AndRaise(expected_exception) - self.assertRaises(TestException, self.mock_method, ['original']) - - def testWithSideEffects(self): - """Should call state modifier.""" - local_list = ['original'] - - def modifier(mutable_list): - self.assertTrue(local_list is mutable_list) - mutable_list[0] = 'mutation' - - self.expected_method.WithSideEffects(modifier).AndReturn(1) - self.mock_method(local_list) - self.assertEqual('mutation', local_list[0]) - - def testWithReturningSideEffects(self): - """Should call state modifier and propagate its return value.""" - local_list = ['original'] - expected_return = 'expected_return' - - def modifier_with_return(mutable_list): - self.assertTrue(local_list is mutable_list) - mutable_list[0] = 'mutation' - return expected_return - - self.expected_method.WithSideEffects(modifier_with_return) - actual_return = self.mock_method(local_list) - self.assertEqual('mutation', local_list[0]) - self.assertEqual(expected_return, actual_return) - - def testWithReturningSideEffectsWithAndReturn(self): - """Should call state modifier and ignore its return value.""" - local_list = ['original'] - expected_return = 'expected_return' - unexpected_return = 'unexpected_return' - - def modifier_with_return(mutable_list): - self.assertTrue(local_list is mutable_list) - mutable_list[0] = 'mutation' - return unexpected_return - - self.expected_method.WithSideEffects(modifier_with_return).AndReturn( - expected_return) - actual_return = self.mock_method(local_list) - self.assertEqual('mutation', local_list[0]) - self.assertEqual(expected_return, actual_return) - - def testEqualityNoParamsEqual(self): - """Methods with the same name and without params should be equal.""" - expected_method = mox.MockMethod("testMethod", [], False) - self.assertEqual(self.mock_method, expected_method) - - def testEqualityNoParamsNotEqual(self): - """Methods with different names without params should not be equal.""" - expected_method = mox.MockMethod("otherMethod", [], False) - self.assertNotEqual(self.mock_method, expected_method) - - def testEqualityParamsEqual(self): - """Methods with the same name and parameters should be equal.""" - params = [1, 2, 3] - expected_method = mox.MockMethod("testMethod", [], False) - expected_method._params = params - - self.mock_method._params = params - self.assertEqual(self.mock_method, expected_method) - - def testEqualityParamsNotEqual(self): - """Methods with same name and different params should not be equal.""" - expected_method = mox.MockMethod("testMethod", [], False) - expected_method._params = [1, 2, 3] - - self.mock_method._params = ['a', 'b', 'c'] - self.assertNotEqual(self.mock_method, expected_method) - - def testEqualityNamedParamsEqual(self): - """Methods with the same name and same named params should be equal.""" - named_params = {"input1": "test", "input2": "params"} - expected_method = mox.MockMethod("testMethod", [], False) - expected_method._named_params = named_params - - self.mock_method._named_params = named_params - self.assertEqual(self.mock_method, expected_method) - - def testEqualityNamedParamsNotEqual(self): - """Methods with same name and diffnamed params should not be equal.""" - expected_method = mox.MockMethod("testMethod", [], False) - expected_method._named_params = {"input1": "test", "input2": "params"} - - self.mock_method._named_params = { - "input1": "test2", "input2": "params2"} - self.assertNotEqual(self.mock_method, expected_method) - - def testEqualityWrongType(self): - """Method should not be equal to an object of a different type.""" - self.assertNotEqual(self.mock_method, "string?") - - def testObjectEquality(self): - """Equality of objects should work without a Comparator""" - instA = TestClass() - instB = TestClass() - - params = [instA, ] - expected_method = mox.MockMethod("testMethod", [], False) - expected_method._params = params - - self.mock_method._params = [instB, ] - self.assertEqual(self.mock_method, expected_method) - - def testStrConversion(self): - method = mox.MockMethod("f", [], False) - method(1, 2, "st", n1=8, n2="st2") - self.assertEqual(str(method), - ("f(1, 2, 'st', n1=8, n2='st2') -> None")) - - method = mox.MockMethod("testMethod", [], False) - method(1, 2, "only positional") - self.assertEqual(str(method), - "testMethod(1, 2, 'only positional') -> None") - - method = mox.MockMethod("testMethod", [], False) - method(a=1, b=2, c="only named") - self.assertEqual(str(method), - "testMethod(a=1, b=2, c='only named') -> None") - - method = mox.MockMethod("testMethod", [], False) - method() - self.assertEqual(str(method), "testMethod() -> None") - - method = mox.MockMethod("testMethod", [], False) - method(x="only 1 parameter") - self.assertEqual(str(method), - "testMethod(x='only 1 parameter') -> None") - - method = mox.MockMethod("testMethod", [], False) - method().AndReturn('return_value') - self.assertEqual(str(method), "testMethod() -> 'return_value'") - - method = mox.MockMethod("testMethod", [], False) - method().AndReturn(('a', {1: 2})) - self.assertEqual(str(method), "testMethod() -> ('a', {1: 2})") - - -class MockAnythingTest(testtools.TestCase): - """Verify that the MockAnything class works as expected.""" - - def setUp(self): - super(MockAnythingTest, self).setUp() - self.mock_object = mox.MockAnything() - - def testRepr(self): - """Calling repr on a MockAnything instance must work.""" - self.assertEqual('', repr(self.mock_object)) - - def testCanMockStr(self): - self.mock_object.__str__().AndReturn("foo") - self.mock_object._Replay() - actual = str(self.mock_object) - self.mock_object._Verify() - self.assertEqual("foo", actual) - - def testSetupMode(self): - """Verify the mock will accept any call.""" - self.mock_object.NonsenseCall() - self.assertTrue(len(self.mock_object._expected_calls_queue) == 1) - - def testReplayWithExpectedCall(self): - """Verify the mock replays method calls as expected.""" - self.mock_object.ValidCall() # setup method call - self.mock_object._Replay() # start replay mode - self.mock_object.ValidCall() # make method call - - def testReplayWithUnexpectedCall(self): - """Unexpected method calls should raise UnexpectedMethodCallError.""" - self.mock_object.ValidCall() # setup method call - self.mock_object._Replay() # start replay mode - self.assertRaises(mox.UnexpectedMethodCallError, - self.mock_object.OtherValidCall) - - def testVerifyWithCompleteReplay(self): - """Verify should not raise an exception for a valid replay.""" - self.mock_object.ValidCall() # setup method call - self.mock_object._Replay() # start replay mode - self.mock_object.ValidCall() # make method call - self.mock_object._Verify() - - def testVerifyWithIncompleteReplay(self): - """Verify should raise an exception if the replay was not complete.""" - self.mock_object.ValidCall() # setup method call - self.mock_object._Replay() # start replay mode - # ValidCall() is never made - self.assertRaises( - mox.ExpectedMethodCallsError, self.mock_object._Verify) - - def testSpecialClassMethod(self): - """Verify should not raise exception when special methods are used.""" - self.mock_object[1].AndReturn(True) - self.mock_object._Replay() - returned_val = self.mock_object[1] - self.assertTrue(returned_val) - self.mock_object._Verify() - - def testNonzero(self): - """You should be able to use the mock object in an if.""" - self.mock_object._Replay() - if self.mock_object: - pass - - def testNotNone(self): - """Mock should be comparable to None.""" - self.mock_object._Replay() - if self.mock_object is not None: - pass - - if self.mock_object is None: - pass - - def testEquals(self): - """A mock should be able to compare itself to another object.""" - self.mock_object._Replay() - self.assertEqual(self.mock_object, self.mock_object) - - def testEqualsMockFailure(self): - """Verify equals identifies unequal objects.""" - self.mock_object.SillyCall() - self.mock_object._Replay() - self.assertNotEqual(self.mock_object, mox.MockAnything()) - - def testEqualsInstanceFailure(self): - """Verify equals identifies that objects are different instances.""" - self.mock_object._Replay() - self.assertNotEqual(self.mock_object, TestClass()) - - def testNotEquals(self): - """Verify not equals works.""" - self.mock_object._Replay() - self.assertFalse(self.mock_object != self.mock_object) - - def testNestedMockCallsRecordedSerially(self): - """Test that nested calls work when recorded serially.""" - self.mock_object.CallInner().AndReturn(1) - self.mock_object.CallOuter(1) - self.mock_object._Replay() - - self.mock_object.CallOuter(self.mock_object.CallInner()) - - self.mock_object._Verify() - - def testNestedMockCallsRecordedNested(self): - """Test that nested cals work when recorded in a nested fashion.""" - self.mock_object.CallOuter(self.mock_object.CallInner().AndReturn(1)) - self.mock_object._Replay() - - self.mock_object.CallOuter(self.mock_object.CallInner()) - - self.mock_object._Verify() - - def testIsCallable(self): - """Test that MockAnything can even mock a simple callable. - - This is handy for "stubbing out" a method in a module with a mock, and - verifying that it was called. - """ - self.mock_object().AndReturn('mox0rd') - self.mock_object._Replay() - - self.assertEqual('mox0rd', self.mock_object()) - - self.mock_object._Verify() - - def testIsReprable(self): - """Test that MockAnythings can be repr'd without causing a failure.""" - self.assertIn('MockAnything', repr(self.mock_object)) - - -class MethodCheckerTest(testtools.TestCase): - """Tests MockMethod's use of MethodChecker method.""" - - def testNoParameters(self): - method = mox.MockMethod('NoParameters', [], False, - CheckCallTestClass.NoParameters, - class_to_bind=CheckCallTestClass) - method() - self.assertRaises(AttributeError, method, 1) - self.assertRaises(AttributeError, method, 1, 2) - self.assertRaises(AttributeError, method, a=1) - self.assertRaises(AttributeError, method, 1, b=2) - - def testOneParameter(self): - method = mox.MockMethod('OneParameter', [], False, - CheckCallTestClass.OneParameter, - class_to_bind=CheckCallTestClass) - self.assertRaises(AttributeError, method) - method(1) - method(a=1) - self.assertRaises(AttributeError, method, b=1) - self.assertRaises(AttributeError, method, 1, 2) - self.assertRaises(AttributeError, method, 1, a=2) - self.assertRaises(AttributeError, method, 1, b=2) - - def testTwoParameters(self): - method = mox.MockMethod('TwoParameters', [], False, - CheckCallTestClass.TwoParameters, - class_to_bind=CheckCallTestClass) - self.assertRaises(AttributeError, method) - self.assertRaises(AttributeError, method, 1) - self.assertRaises(AttributeError, method, a=1) - self.assertRaises(AttributeError, method, b=1) - method(1, 2) - method(1, b=2) - method(a=1, b=2) - method(b=2, a=1) - self.assertRaises(AttributeError, method, b=2, c=3) - self.assertRaises(AttributeError, method, a=1, b=2, c=3) - self.assertRaises(AttributeError, method, 1, 2, 3) - self.assertRaises(AttributeError, method, 1, 2, 3, 4) - self.assertRaises(AttributeError, method, 3, a=1, b=2) - - def testOneDefaultValue(self): - method = mox.MockMethod('OneDefaultValue', [], False, - CheckCallTestClass.OneDefaultValue, - class_to_bind=CheckCallTestClass) - method() - method(1) - method(a=1) - self.assertRaises(AttributeError, method, b=1) - self.assertRaises(AttributeError, method, 1, 2) - self.assertRaises(AttributeError, method, 1, a=2) - self.assertRaises(AttributeError, method, 1, b=2) - - def testTwoDefaultValues(self): - method = mox.MockMethod('TwoDefaultValues', [], False, - CheckCallTestClass.TwoDefaultValues, - class_to_bind=CheckCallTestClass) - self.assertRaises(AttributeError, method) - self.assertRaises(AttributeError, method, c=3) - self.assertRaises(AttributeError, method, 1) - self.assertRaises(AttributeError, method, 1, d=4) - self.assertRaises(AttributeError, method, 1, d=4, c=3) - method(1, 2) - method(a=1, b=2) - method(1, 2, 3) - method(1, 2, 3, 4) - method(1, 2, c=3) - method(1, 2, c=3, d=4) - method(1, 2, d=4, c=3) - method(d=4, c=3, a=1, b=2) - self.assertRaises(AttributeError, method, 1, 2, 3, 4, 5) - self.assertRaises(AttributeError, method, 1, 2, e=9) - self.assertRaises(AttributeError, method, a=1, b=2, e=9) - - def testArgs(self): - method = mox.MockMethod('Args', [], False, CheckCallTestClass.Args, - class_to_bind=CheckCallTestClass) - self.assertRaises(AttributeError, method) - self.assertRaises(AttributeError, method, 1) - method(1, 2) - method(a=1, b=2) - method(1, 2, 3) - method(1, 2, 3, 4) - self.assertRaises(AttributeError, method, 1, 2, a=3) - self.assertRaises(AttributeError, method, 1, 2, c=3) - - def testKwargs(self): - method = mox.MockMethod('Kwargs', [], False, CheckCallTestClass.Kwargs, - class_to_bind=CheckCallTestClass) - self.assertRaises(AttributeError, method) - method(1) - method(1, 2) - method(a=1, b=2) - method(b=2, a=1) - self.assertRaises(AttributeError, method, 1, 2, 3) - self.assertRaises(AttributeError, method, 1, 2, a=3) - method(1, 2, c=3) - method(a=1, b=2, c=3) - method(c=3, a=1, b=2) - method(a=1, b=2, c=3, d=4) - self.assertRaises(AttributeError, method, 1, 2, 3, 4) - - def testArgsAndKwargs(self): - method = mox.MockMethod('ArgsAndKwargs', [], False, - CheckCallTestClass.ArgsAndKwargs, - class_to_bind=CheckCallTestClass) - self.assertRaises(AttributeError, method) - method(1) - method(1, 2) - method(1, 2, 3) - method(a=1) - method(1, b=2) - self.assertRaises(AttributeError, method, 1, a=2) - method(b=2, a=1) - method(c=3, b=2, a=1) - method(1, 2, c=3) - - -class CheckCallTestClass(object): - def NoParameters(self): - pass - - def OneParameter(self, a): - pass - - def TwoParameters(self, a, b): - pass - - def OneDefaultValue(self, a=1): - pass - - def TwoDefaultValues(self, a, b, c=1, d=2): - pass - - def Args(self, a, b, *args): - pass - - def Kwargs(self, a, b=2, **kwargs): - pass - - def ArgsAndKwargs(self, a, *args, **kwargs): - pass - - -class MockObjectTest(testtools.TestCase): - """Verify that the MockObject class works as exepcted.""" - - def setUp(self): - super(MockObjectTest, self).setUp() - self.mock_object = mox.MockObject(TestClass) - - def testSetupModeWithValidCall(self): - """Verify the mock object properly mocks a basic method call.""" - self.mock_object.ValidCall() - self.assertTrue(len(self.mock_object._expected_calls_queue) == 1) - - def testSetupModeWithInvalidCall(self): - """Rase UnknownMethodCallError for a non-member method call. - """ - # Note: assertRaises does not catch exceptions thrown by MockObject's - # __getattr__ - try: - self.mock_object.InvalidCall() - self.fail("No exception thrown, expected UnknownMethodCallError") - except mox.UnknownMethodCallError: - pass - except Exception: - self.fail("Wrong exception type thrown," - " expected UnknownMethodCallError") - - def testReplayWithInvalidCall(self): - """Rase UnknownMethodCallError for a non-member method call. - """ - self.mock_object.ValidCall() # setup method call - self.mock_object._Replay() # start replay mode - # Note: assertRaises does not catch exceptions thrown by MockObject's - # __getattr__ - try: - self.mock_object.InvalidCall() - self.fail("No exception thrown, expected UnknownMethodCallError") - except mox.UnknownMethodCallError: - pass - except Exception: - self.fail("Wrong exception type thrown," - " expected UnknownMethodCallError") - - def testIsInstance(self): - """Mock should be able to pass as an instance of the mocked class.""" - self.assertTrue(isinstance(self.mock_object, TestClass)) - - def testFindValidMethods(self): - """Mock should be able to mock all public methods.""" - self.assertIn('ValidCall', self.mock_object._known_methods) - self.assertIn('OtherValidCall', self.mock_object._known_methods) - self.assertIn('MyClassMethod', self.mock_object._known_methods) - self.assertIn('MyStaticMethod', self.mock_object._known_methods) - self.assertIn('_ProtectedCall', self.mock_object._known_methods) - self.assertNotIn('__PrivateCall', self.mock_object._known_methods) - self.assertIn( - '_TestClass__PrivateCall', self.mock_object._known_methods) - - def testFindsSuperclassMethods(self): - """Mock should be able to mock superclasses methods.""" - self.mock_object = mox.MockObject(ChildClass) - self.assertIn('ValidCall', self.mock_object._known_methods) - self.assertIn('OtherValidCall', self.mock_object._known_methods) - self.assertIn('MyClassMethod', self.mock_object._known_methods) - self.assertIn('ChildValidCall', self.mock_object._known_methods) - - def testAccessClassVariables(self): - """Class variables should be accessible through the mock.""" - self.assertIn('SOME_CLASS_VAR', self.mock_object._known_vars) - self.assertIn('_PROTECTED_CLASS_VAR', self.mock_object._known_vars) - self.assertEqual('test_value', self.mock_object.SOME_CLASS_VAR) - - def testEquals(self): - """A mock should be able to compare itself to another object.""" - self.mock_object._Replay() - self.assertEqual(self.mock_object, self.mock_object) - - def testEqualsMockFailure(self): - """Verify equals identifies unequal objects.""" - self.mock_object.ValidCall() - self.mock_object._Replay() - self.assertNotEqual(self.mock_object, mox.MockObject(TestClass)) - - def testEqualsInstanceFailure(self): - """Verify equals identifies that objects are different instances.""" - self.mock_object._Replay() - self.assertNotEqual(self.mock_object, TestClass()) - - def testNotEquals(self): - """Verify not equals works.""" - self.mock_object._Replay() - self.assertFalse(self.mock_object != self.mock_object) - - def testMockSetItem_ExpectedSetItem_Success(self): - """Test that __setitem__() gets mocked in Dummy. - - In this test, _Verify() succeeds. - """ - dummy = mox.MockObject(TestClass) - dummy['X'] = 'Y' - - dummy._Replay() - - dummy['X'] = 'Y' - - dummy._Verify() - - def testMockSetItem_ExpectedSetItem_NoSuccess(self): - """Test that __setitem__() gets mocked in Dummy. - - In this test, _Verify() fails. - """ - dummy = mox.MockObject(TestClass) - dummy['X'] = 'Y' - - dummy._Replay() - - # NOT doing dummy['X'] = 'Y' - - self.assertRaises(mox.ExpectedMethodCallsError, dummy._Verify) - - def testMockSetItem_ExpectedNoSetItem_Success(self): - """Test that __setitem__() gets mocked in Dummy.""" - dummy = mox.MockObject(TestClass) - # NOT doing dummy['X'] = 'Y' - - dummy._Replay() - - def call(): - dummy['X'] = 'Y' - - self.assertRaises(mox.UnexpectedMethodCallError, call) - - def testMockSetItem_ExpectedNoSetItem_NoSuccess(self): - """Test that __setitem__() gets mocked in Dummy. - - In this test, _Verify() fails. - """ - dummy = mox.MockObject(TestClass) - # NOT doing dummy['X'] = 'Y' - - dummy._Replay() - - # NOT doing dummy['X'] = 'Y' - - dummy._Verify() - - def testMockSetItem_ExpectedSetItem_NonmatchingParameters(self): - """Test that __setitem__() fails if other parameters are expected.""" - dummy = mox.MockObject(TestClass) - dummy['X'] = 'Y' - - dummy._Replay() - - def call(): - dummy['wrong'] = 'Y' - - self.assertRaises(mox.UnexpectedMethodCallError, call) - - dummy._Verify() - - def testMockSetItem_WithSubClassOfNewStyleClass(self): - class NewStyleTestClass(object): - def __init__(self): - self.my_dict = {} - - def __setitem__(self, key, value): - self.my_dict[key], value - - class TestSubClass(NewStyleTestClass): - pass - - dummy = mox.MockObject(TestSubClass) - dummy[1] = 2 - dummy._Replay() - dummy[1] = 2 - dummy._Verify() - - def testMockGetItem_ExpectedGetItem_Success(self): - """Test that __getitem__() gets mocked in Dummy. - - In this test, _Verify() succeeds. - """ - dummy = mox.MockObject(TestClass) - dummy['X'].AndReturn('value') - - dummy._Replay() - - self.assertEqual(dummy['X'], 'value') - - dummy._Verify() - - def testMockGetItem_ExpectedGetItem_NoSuccess(self): - """Test that __getitem__() gets mocked in Dummy. - - In this test, _Verify() fails. - """ - dummy = mox.MockObject(TestClass) - dummy['X'].AndReturn('value') - - dummy._Replay() - - # NOT doing dummy['X'] - - self.assertRaises(mox.ExpectedMethodCallsError, dummy._Verify) - - def testMockGetItem_ExpectedNoGetItem_NoSuccess(self): - """Test that __getitem__() gets mocked in Dummy.""" - dummy = mox.MockObject(TestClass) - # NOT doing dummy['X'] - - dummy._Replay() - - def call(): - return dummy['X'] - - self.assertRaises(mox.UnexpectedMethodCallError, call) - - def testMockGetItem_ExpectedGetItem_NonmatchingParameters(self): - """Test that __getitem__() fails if other parameters are expected.""" - dummy = mox.MockObject(TestClass) - dummy['X'].AndReturn('value') - - dummy._Replay() - - def call(): - return dummy['wrong'] - - self.assertRaises(mox.UnexpectedMethodCallError, call) - - dummy._Verify() - - def testMockGetItem_WithSubClassOfNewStyleClass(self): - class NewStyleTestClass(object): - def __getitem__(self, key): - return {1: '1', 2: '2'}[key] - - class TestSubClass(NewStyleTestClass): - pass - - dummy = mox.MockObject(TestSubClass) - dummy[1].AndReturn('3') - - dummy._Replay() - self.assertEqual('3', dummy.__getitem__(1)) - dummy._Verify() - - def testMockIter_ExpectedIter_Success(self): - """Test that __iter__() gets mocked in Dummy. - - In this test, _Verify() succeeds. - """ - dummy = mox.MockObject(TestClass) - iter(dummy).AndReturn(iter(['X', 'Y'])) - - dummy._Replay() - - self.assertEqual([x for x in dummy], ['X', 'Y']) - - dummy._Verify() - - def testMockContains_ExpectedContains_Success(self): - """Test that __contains__ gets mocked in Dummy. - - In this test, _Verify() succeeds. - """ - dummy = mox.MockObject(TestClass) - dummy.__contains__('X').AndReturn(True) - - dummy._Replay() - - self.assertIn('X', dummy) - - dummy._Verify() - - def testMockContains_ExpectedContains_NoSuccess(self): - """Test that __contains__() gets mocked in Dummy. - - In this test, _Verify() fails. - """ - dummy = mox.MockObject(TestClass) - dummy.__contains__('X').AndReturn('True') - - dummy._Replay() - - # NOT doing 'X' in dummy - - self.assertRaises(mox.ExpectedMethodCallsError, dummy._Verify) - - def testMockContains_ExpectedContains_NonmatchingParameter(self): - """Test that __contains__ fails if other parameters are expected.""" - dummy = mox.MockObject(TestClass) - dummy.__contains__('X').AndReturn(True) - - dummy._Replay() - - def call(): - return 'Y' in dummy - - self.assertRaises(mox.UnexpectedMethodCallError, call) - - dummy._Verify() - - def testMockIter_ExpectedIter_NoSuccess(self): - """Test that __iter__() gets mocked in Dummy. - - In this test, _Verify() fails. - """ - dummy = mox.MockObject(TestClass) - iter(dummy).AndReturn(iter(['X', 'Y'])) - - dummy._Replay() - - # NOT doing self.assertEqual([x for x in dummy], ['X', 'Y']) - - self.assertRaises(mox.ExpectedMethodCallsError, dummy._Verify) - - def testMockIter_ExpectedNoIter_NoSuccess(self): - """Test that __iter__() gets mocked in Dummy.""" - dummy = mox.MockObject(TestClass) - # NOT doing iter(dummy) - - dummy._Replay() - - def call(): - return [x for x in dummy] - self.assertRaises(mox.UnexpectedMethodCallError, call) - - def testMockIter_ExpectedGetItem_Success(self): - """Test that __iter__() gets mocked in Dummy using getitem.""" - dummy = mox.MockObject(SubscribtableNonIterableClass) - dummy[0].AndReturn('a') - dummy[1].AndReturn('b') - dummy[2].AndRaise(IndexError) - - dummy._Replay() - self.assertEqual(['a', 'b'], [x for x in dummy]) - dummy._Verify() - - def testMockIter_ExpectedNoGetItem_NoSuccess(self): - """Test that __iter__() gets mocked in Dummy using getitem.""" - dummy = mox.MockObject(SubscribtableNonIterableClass) - # NOT doing dummy[index] - - dummy._Replay() - self.assertRaises(mox.UnexpectedMethodCallError, - lambda: [x for x in dummy]) - - def testMockGetIter_WithSubClassOfNewStyleClass(self): - class NewStyleTestClass(object): - def __iter__(self): - return iter([1, 2, 3]) - - class TestSubClass(NewStyleTestClass): - pass - - dummy = mox.MockObject(TestSubClass) - iter(dummy).AndReturn(iter(['a', 'b'])) - dummy._Replay() - self.assertEqual(['a', 'b'], [x for x in dummy]) - dummy._Verify() - - def testInstantiationWithAdditionalAttributes(self): - mock_object = mox.MockObject(TestClass, attrs={"attr1": "value"}) - self.assertEqual(mock_object.attr1, "value") - - def testCantOverrideMethodsWithAttributes(self): - self.assertRaises(ValueError, mox.MockObject, TestClass, - attrs={"ValidCall": "value"}) - - def testCantMockNonPublicAttributes(self): - self.assertRaises(mox.PrivateAttributeError, mox.MockObject, TestClass, - attrs={"_protected": "value"}) - self.assertRaises(mox.PrivateAttributeError, mox.MockObject, TestClass, - attrs={"__private": "value"}) - - -class MoxTest(testtools.TestCase): - """Verify Mox works correctly.""" - - def setUp(self): - super(MoxTest, self).setUp() - self.mox = mox.Mox() - - def testCreateObject(self): - """Mox should create a mock object.""" - self.mox.CreateMock(TestClass) - - def testVerifyObjectWithCompleteReplay(self): - """Mox should replay and verify all objects it created.""" - mock_obj = self.mox.CreateMock(TestClass) - mock_obj.ValidCall() - mock_obj.ValidCallWithArgs(mox.IsA(TestClass)) - self.mox.ReplayAll() - mock_obj.ValidCall() - mock_obj.ValidCallWithArgs(TestClass("some_value")) - self.mox.VerifyAll() - - def testVerifyObjectWithIncompleteReplay(self): - """Mox should raise an exception if a mock didn't replay completely.""" - mock_obj = self.mox.CreateMock(TestClass) - mock_obj.ValidCall() - self.mox.ReplayAll() - # ValidCall() is never made - self.assertRaises(mox.ExpectedMethodCallsError, self.mox.VerifyAll) - - def testEntireWorkflow(self): - """Test the whole work flow.""" - mock_obj = self.mox.CreateMock(TestClass) - mock_obj.ValidCall().AndReturn("yes") - self.mox.ReplayAll() - - ret_val = mock_obj.ValidCall() - self.assertEqual("yes", ret_val) - self.mox.VerifyAll() - - def testSignatureMatchingWithComparatorAsFirstArg(self): - """Test that the first argument can be a comparator.""" - - def VerifyLen(val): - """This will raise an exception when not given a list. - - This exception will be raised when trying to infer/validate the - method signature. - """ - return len(val) != 1 - - mock_obj = self.mox.CreateMock(TestClass) - # This intentionally does not name the 'nine' param so it triggers - # deeper inspection. - mock_obj.MethodWithArgs(mox.Func(VerifyLen), mox.IgnoreArg(), None) - self.mox.ReplayAll() - - mock_obj.MethodWithArgs([1, 2], "foo", None) - - self.mox.VerifyAll() - - def testCallableObject(self): - """Test recording calls to a callable object works.""" - mock_obj = self.mox.CreateMock(CallableClass) - mock_obj("foo").AndReturn("qux") - self.mox.ReplayAll() - - ret_val = mock_obj("foo") - self.assertEqual("qux", ret_val) - self.mox.VerifyAll() - - def testInheritedCallableObject(self): - """Recording calls to an object inheriting from a callable object.""" - mock_obj = self.mox.CreateMock(InheritsFromCallable) - mock_obj("foo").AndReturn("qux") - self.mox.ReplayAll() - - ret_val = mock_obj("foo") - self.assertEqual("qux", ret_val) - self.mox.VerifyAll() - - def testCallOnNonCallableObject(self): - """Test that you cannot call a non-callable object.""" - mock_obj = self.mox.CreateMock("string is not callable") - self.assertRaises(TypeError, mock_obj) - - def testCallableObjectWithBadCall(self): - """Test verifying calls to a callable object works.""" - mock_obj = self.mox.CreateMock(CallableClass) - mock_obj("foo").AndReturn("qux") - self.mox.ReplayAll() - - self.assertRaises(mox.UnexpectedMethodCallError, mock_obj, "ZOOBAZ") - - def testCallableObjectVerifiesSignature(self): - mock_obj = self.mox.CreateMock(CallableClass) - # Too many arguments - self.assertRaises(AttributeError, mock_obj, "foo", "bar") - - def testUnorderedGroup(self): - """Test that using one unordered group works.""" - mock_obj = self.mox.CreateMockAnything() - mock_obj.Method(1).InAnyOrder() - mock_obj.Method(2).InAnyOrder() - self.mox.ReplayAll() - - mock_obj.Method(2) - mock_obj.Method(1) - - self.mox.VerifyAll() - - def testUnorderedGroupsInline(self): - """Unordered groups should work in the context of ordered calls.""" - mock_obj = self.mox.CreateMockAnything() - mock_obj.Open() - mock_obj.Method(1).InAnyOrder() - mock_obj.Method(2).InAnyOrder() - mock_obj.Close() - self.mox.ReplayAll() - - mock_obj.Open() - mock_obj.Method(2) - mock_obj.Method(1) - mock_obj.Close() - - self.mox.VerifyAll() - - def testMultipleUnorderdGroups(self): - """Multiple unoreded groups should work.""" - mock_obj = self.mox.CreateMockAnything() - mock_obj.Method(1).InAnyOrder() - mock_obj.Method(2).InAnyOrder() - mock_obj.Foo().InAnyOrder('group2') - mock_obj.Bar().InAnyOrder('group2') - self.mox.ReplayAll() - - mock_obj.Method(2) - mock_obj.Method(1) - mock_obj.Bar() - mock_obj.Foo() - - self.mox.VerifyAll() - - def testMultipleUnorderdGroupsOutOfOrder(self): - """Multiple unordered groups should maintain external order""" - mock_obj = self.mox.CreateMockAnything() - mock_obj.Method(1).InAnyOrder() - mock_obj.Method(2).InAnyOrder() - mock_obj.Foo().InAnyOrder('group2') - mock_obj.Bar().InAnyOrder('group2') - self.mox.ReplayAll() - - mock_obj.Method(2) - self.assertRaises(mox.UnexpectedMethodCallError, mock_obj.Bar) - - def testUnorderedGroupWithReturnValue(self): - """Unordered groups should work with return values.""" - mock_obj = self.mox.CreateMockAnything() - mock_obj.Open() - mock_obj.Method(1).InAnyOrder().AndReturn(9) - mock_obj.Method(2).InAnyOrder().AndReturn(10) - mock_obj.Close() - self.mox.ReplayAll() - - mock_obj.Open() - actual_two = mock_obj.Method(2) - actual_one = mock_obj.Method(1) - mock_obj.Close() - - self.assertEqual(9, actual_one) - self.assertEqual(10, actual_two) - - self.mox.VerifyAll() - - def testUnorderedGroupWithComparator(self): - """Unordered groups should work with comparators.""" - - def VerifyOne(cmd): - if not isinstance(cmd, str): - self.fail('Unexpected type passed to comparator: ' + str(cmd)) - return cmd == 'test' - - def VerifyTwo(cmd): - return True - - mock_obj = self.mox.CreateMockAnything() - mock_obj.Foo(['test'], mox.Func(VerifyOne), bar=1).InAnyOrder().\ - AndReturn('yes test') - mock_obj.Foo(['test'], mox.Func(VerifyTwo), bar=1).InAnyOrder().\ - AndReturn('anything') - - self.mox.ReplayAll() - - mock_obj.Foo(['test'], 'anything', bar=1) - mock_obj.Foo(['test'], 'test', bar=1) - - self.mox.VerifyAll() - - def testMultipleTimes(self): - """Test if MultipleTimesGroup works.""" - mock_obj = self.mox.CreateMockAnything() - mock_obj.Method(1).MultipleTimes().AndReturn(9) - mock_obj.Method(2).AndReturn(10) - mock_obj.Method(3).MultipleTimes().AndReturn(42) - self.mox.ReplayAll() - - actual_one = mock_obj.Method(1) - second_one = mock_obj.Method(1) # This tests MultipleTimes. - actual_two = mock_obj.Method(2) - actual_three = mock_obj.Method(3) - mock_obj.Method(3) - mock_obj.Method(3) - - self.mox.VerifyAll() - - self.assertEqual(9, actual_one) - # Repeated calls should return same number. - self.assertEqual(9, second_one) - self.assertEqual(10, actual_two) - self.assertEqual(42, actual_three) - - def testMultipleTimesUsingIsAParameter(self): - """Test if MultipleTimesGroup works with a IsA parameter.""" - mock_obj = self.mox.CreateMockAnything() - mock_obj.Open() - mock_obj.Method(mox.IsA(str)).MultipleTimes("IsA").AndReturn(9) - mock_obj.Close() - self.mox.ReplayAll() - - mock_obj.Open() - actual_one = mock_obj.Method("1") - second_one = mock_obj.Method("2") # This tests MultipleTimes. - mock_obj.Close() - - self.mox.VerifyAll() - - self.assertEqual(9, actual_one) - # Repeated calls should return same number. - self.assertEqual(9, second_one) - - def testMutlipleTimesUsingFunc(self): - """Test that the Func is not evaluated more times than necessary. - - If a Func() has side effects, it can cause a passing test to fail. - """ - - self.counter = 0 - - def MyFunc(actual_str): - """Increment the counter if actual_str == 'foo'.""" - if actual_str == 'foo': - self.counter += 1 - return True - - mock_obj = self.mox.CreateMockAnything() - mock_obj.Open() - mock_obj.Method(mox.Func(MyFunc)).MultipleTimes() - mock_obj.Close() - self.mox.ReplayAll() - - mock_obj.Open() - mock_obj.Method('foo') - mock_obj.Method('foo') - mock_obj.Method('not-foo') - mock_obj.Close() - - self.mox.VerifyAll() - - self.assertEqual(2, self.counter) - - def testMultipleTimesThreeMethods(self): - """Test if MultipleTimesGroup works with three or more methods.""" - mock_obj = self.mox.CreateMockAnything() - mock_obj.Open() - mock_obj.Method(1).MultipleTimes().AndReturn(9) - mock_obj.Method(2).MultipleTimes().AndReturn(8) - mock_obj.Method(3).MultipleTimes().AndReturn(7) - mock_obj.Method(4).AndReturn(10) - mock_obj.Close() - self.mox.ReplayAll() - - mock_obj.Open() - actual_three = mock_obj.Method(3) - mock_obj.Method(1) - actual_two = mock_obj.Method(2) - mock_obj.Method(3) - actual_one = mock_obj.Method(1) - actual_four = mock_obj.Method(4) - mock_obj.Close() - - self.assertEqual(9, actual_one) - self.assertEqual(8, actual_two) - self.assertEqual(7, actual_three) - self.assertEqual(10, actual_four) - - self.mox.VerifyAll() - - def testMultipleTimesMissingOne(self): - """Test if MultipleTimesGroup fails if one method is missing.""" - mock_obj = self.mox.CreateMockAnything() - mock_obj.Open() - mock_obj.Method(1).MultipleTimes().AndReturn(9) - mock_obj.Method(2).MultipleTimes().AndReturn(8) - mock_obj.Method(3).MultipleTimes().AndReturn(7) - mock_obj.Method(4).AndReturn(10) - mock_obj.Close() - self.mox.ReplayAll() - - mock_obj.Open() - mock_obj.Method(3) - mock_obj.Method(2) - mock_obj.Method(3) - mock_obj.Method(3) - mock_obj.Method(2) - - self.assertRaises(mox.UnexpectedMethodCallError, mock_obj.Method, 4) - - def testMultipleTimesTwoGroups(self): - """Test if MultipleTimesGroup works with a group after a - MultipleTimesGroup. - """ - mock_obj = self.mox.CreateMockAnything() - mock_obj.Open() - mock_obj.Method(1).MultipleTimes().AndReturn(9) - mock_obj.Method(3).MultipleTimes("nr2").AndReturn(42) - mock_obj.Close() - self.mox.ReplayAll() - - mock_obj.Open() - actual_one = mock_obj.Method(1) - mock_obj.Method(1) - actual_three = mock_obj.Method(3) - mock_obj.Method(3) - mock_obj.Close() - - self.assertEqual(9, actual_one) - self.assertEqual(42, actual_three) - - self.mox.VerifyAll() - - def testMultipleTimesTwoGroupsFailure(self): - """Test if MultipleTimesGroup fails with a group after a - MultipleTimesGroup. - """ - mock_obj = self.mox.CreateMockAnything() - mock_obj.Open() - mock_obj.Method(1).MultipleTimes().AndReturn(9) - mock_obj.Method(3).MultipleTimes("nr2").AndReturn(42) - mock_obj.Close() - self.mox.ReplayAll() - - mock_obj.Open() - mock_obj.Method(1) - mock_obj.Method(1) - mock_obj.Method(3) - - self.assertRaises(mox.UnexpectedMethodCallError, mock_obj.Method, 1) - - def testWithSideEffects(self): - """Test side effect operations actually modify their target objects.""" - def modifier(mutable_list): - mutable_list[0] = 'mutated' - mock_obj = self.mox.CreateMockAnything() - mock_obj.ConfigureInOutParameter( - ['original']).WithSideEffects(modifier) - mock_obj.WorkWithParameter(['mutated']) - self.mox.ReplayAll() - - local_list = ['original'] - mock_obj.ConfigureInOutParameter(local_list) - mock_obj.WorkWithParameter(local_list) - - self.mox.VerifyAll() - - def testWithSideEffectsException(self): - """Test side effect operations actually modify their target objects.""" - class TestException(Exception): - pass - - def modifier(mutable_list): - mutable_list[0] = 'mutated' - mock_obj = self.mox.CreateMockAnything() - method = mock_obj.ConfigureInOutParameter(['original']) - method.WithSideEffects(modifier).AndRaise(TestException('exception')) - mock_obj.WorkWithParameter(['mutated']) - self.mox.ReplayAll() - - local_list = ['original'] - self.assertRaises(TestException, - mock_obj.ConfigureInOutParameter, - local_list) - mock_obj.WorkWithParameter(local_list) - - self.mox.VerifyAll() - - def testStubOutMethod(self): - """Test that a method is replaced with a MockObject.""" - test_obj = TestClass() - method_type = type(test_obj.OtherValidCall) - # Replace OtherValidCall with a mock. - self.mox.StubOutWithMock(test_obj, 'OtherValidCall') - self.assertTrue(isinstance(test_obj.OtherValidCall, mox.MockObject)) - self.assertFalse(type(test_obj.OtherValidCall) is method_type) - - test_obj.OtherValidCall().AndReturn('foo') - self.mox.ReplayAll() - - actual = test_obj.OtherValidCall() - - self.mox.VerifyAll() - self.mox.UnsetStubs() - self.assertEqual('foo', actual) - self.assertTrue(type(test_obj.OtherValidCall) is method_type) - - def testStubOutMethod_Unbound_Comparator(self): - instance = TestClass() - self.mox.StubOutWithMock(TestClass, 'OtherValidCall') - - TestClass.OtherValidCall(mox.IgnoreArg()).AndReturn('foo') - self.mox.ReplayAll() - - actual = TestClass.OtherValidCall(instance) - - self.mox.VerifyAll() - self.mox.UnsetStubs() - self.assertEqual('foo', actual) - - def testStubOutMethod_Unbound_Subclass_Comparator(self): - self.mox.StubOutWithMock( - mox_helper.TestClassFromAnotherModule, 'Value') - mox_helper.TestClassFromAnotherModule.Value( - mox.IsA(mox_helper.ChildClassFromAnotherModule)).AndReturn('foo') - self.mox.ReplayAll() - - instance = mox_helper.ChildClassFromAnotherModule() - actual = mox_helper.TestClassFromAnotherModule.Value(instance) - - self.mox.VerifyAll() - self.mox.UnsetStubs() - self.assertEqual('foo', actual) - - def testStubOuMethod_Unbound_WithOptionalParams(self): - self.mox = mox.Mox() - self.mox.StubOutWithMock(TestClass, 'OptionalArgs') - TestClass.OptionalArgs(mox.IgnoreArg(), foo=2) - self.mox.ReplayAll() - - t = TestClass() - TestClass.OptionalArgs(t, foo=2) - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def testStubOutMethod_Unbound_ActualInstance(self): - instance = TestClass() - self.mox.StubOutWithMock(TestClass, 'OtherValidCall') - - TestClass.OtherValidCall(instance).AndReturn('foo') - self.mox.ReplayAll() - - actual = TestClass.OtherValidCall(instance) - - self.mox.VerifyAll() - self.mox.UnsetStubs() - self.assertEqual('foo', actual) - - def testStubOutMethod_Unbound_DifferentInstance(self): - instance = TestClass() - self.mox.StubOutWithMock(TestClass, 'OtherValidCall') - - TestClass.OtherValidCall(instance).AndReturn('foo') - self.mox.ReplayAll() - - # This should fail, since the instances are different - self.assertRaises(mox.UnexpectedMethodCallError, - TestClass.OtherValidCall, "wrong self") - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def testStubOutMethod_Unbound_NamedUsingPositional(self): - """Check positional parameters can be matched to keyword arguments.""" - self.mox.StubOutWithMock(mox_helper.ExampleClass, 'NamedParams') - instance = mox_helper.ExampleClass() - mox_helper.ExampleClass.NamedParams(instance, 'foo', baz=None) - self.mox.ReplayAll() - - mox_helper.ExampleClass.NamedParams(instance, 'foo', baz=None) - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def testStubOutMethod_Unbound_NamedUsingPositional_SomePositional(self): - """Check positional parameters can be matched to keyword arguments.""" - self.mox.StubOutWithMock(mox_helper.ExampleClass, 'TestMethod') - instance = mox_helper.ExampleClass() - mox_helper.ExampleClass.TestMethod(instance, 'one', 'two', 'nine') - self.mox.ReplayAll() - - mox_helper.ExampleClass.TestMethod(instance, 'one', 'two', 'nine') - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def testStubOutMethod_Unbound_SpecialArgs(self): - self.mox.StubOutWithMock(mox_helper.ExampleClass, 'SpecialArgs') - instance = mox_helper.ExampleClass() - mox_helper.ExampleClass.SpecialArgs(instance, 'foo', None, bar='bar') - self.mox.ReplayAll() - - mox_helper.ExampleClass.SpecialArgs(instance, 'foo', None, bar='bar') - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def testStubOutMethod_Bound_SimpleTest(self): - t = self.mox.CreateMock(TestClass) - - t.MethodWithArgs(mox.IgnoreArg(), mox.IgnoreArg()).AndReturn('foo') - self.mox.ReplayAll() - - actual = t.MethodWithArgs(None, None) - - self.mox.VerifyAll() - self.mox.UnsetStubs() - self.assertEqual('foo', actual) - - def testStubOutMethod_Bound_NamedUsingPositional(self): - """Check positional parameters can be matched to keyword arguments.""" - self.mox.StubOutWithMock(mox_helper.ExampleClass, 'NamedParams') - instance = mox_helper.ExampleClass() - instance.NamedParams('foo', baz=None) - self.mox.ReplayAll() - - instance.NamedParams('foo', baz=None) - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def testStubOutMethod_Bound_NamedUsingPositional_SomePositional(self): - """Check positional parameters can be matched to keyword arguments.""" - self.mox.StubOutWithMock(mox_helper.ExampleClass, 'TestMethod') - instance = mox_helper.ExampleClass() - instance.TestMethod(instance, 'one', 'two', 'nine') - self.mox.ReplayAll() - - instance.TestMethod(instance, 'one', 'two', 'nine') - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def testStubOutMethod_Bound_SpecialArgs(self): - self.mox.StubOutWithMock(mox_helper.ExampleClass, 'SpecialArgs') - instance = mox_helper.ExampleClass() - instance.SpecialArgs(instance, 'foo', None, bar='bar') - self.mox.ReplayAll() - - instance.SpecialArgs(instance, 'foo', None, bar='bar') - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def testStubOutMethod_Func_PropgatesExceptions(self): - """Errors in Func comparator should propagate to the calling method.""" - class TestException(Exception): - pass - - def raiseExceptionOnNotOne(value): - if value == 1: - return True - else: - raise TestException - - test_obj = TestClass() - self.mox.StubOutWithMock(test_obj, 'MethodWithArgs') - test_obj.MethodWithArgs( - mox.IgnoreArg(), mox.Func(raiseExceptionOnNotOne)).AndReturn(1) - test_obj.MethodWithArgs( - mox.IgnoreArg(), mox.Func(raiseExceptionOnNotOne)).AndReturn(1) - self.mox.ReplayAll() - - self.assertEqual(test_obj.MethodWithArgs('ignored', 1), 1) - self.assertRaises(TestException, - test_obj.MethodWithArgs, 'ignored', 2) - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - def testStubOut_SignatureMatching_init_(self): - self.mox.StubOutWithMock(mox_helper.ExampleClass, '__init__') - mox_helper.ExampleClass.__init__(mox.IgnoreArg()) - self.mox.ReplayAll() - - # Create an instance of a child class, which calls the parent - # __init__ - mox_helper.ChildExampleClass() - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - # FIXME(dhellmann): Skip this test until someone can debug why it - # fails on python 3.4. - - def testStubOutClass_OldStyle(self): - """Test a mocked class whose __init__ returns a Mock.""" - self.mox.StubOutWithMock(mox_helper, 'TestClassFromAnotherModule') - self.assertTrue(isinstance(mox_helper.TestClassFromAnotherModule, - mox.MockObject)) - - mock_instance = self.mox.CreateMock( - mox_helper.TestClassFromAnotherModule) - mox_helper.TestClassFromAnotherModule().AndReturn(mock_instance) - mock_instance.Value().AndReturn('mock instance') - - self.mox.ReplayAll() - - a_mock = mox_helper.TestClassFromAnotherModule() - actual = a_mock.Value() - - self.mox.VerifyAll() - self.mox.UnsetStubs() - self.assertEqual('mock instance', actual) - - def testStubOutClass(self): - self.mox.StubOutClassWithMocks(mox_helper, 'CallableClass') - - # Instance one - mock_one = mox_helper.CallableClass(1, 2) - mock_one.Value().AndReturn('mock') - - # Instance two - mock_two = mox_helper.CallableClass(8, 9) - mock_two('one').AndReturn('called mock') - - self.mox.ReplayAll() - - one = mox_helper.CallableClass(1, 2) - actual_one = one.Value() - - two = mox_helper.CallableClass(8, 9) - actual_two = two('one') - - self.mox.VerifyAll() - self.mox.UnsetStubs() - - # Verify the correct mocks were returned - self.assertEqual(mock_one, one) - self.assertEqual(mock_two, two) - - # Verify - self.assertEqual('mock', actual_one) - self.assertEqual('called mock', actual_two) - - def testStubOutClass_NotAClass(self): - self.assertRaises(TypeError, self.mox.StubOutClassWithMocks, - mox_helper, 'MyTestFunction') - - def testStubOutClassNotEnoughCreated(self): - self.mox.StubOutClassWithMocks(mox_helper, 'CallableClass') - - mox_helper.CallableClass(1, 2) - mox_helper.CallableClass(8, 9) - - self.mox.ReplayAll() - mox_helper.CallableClass(1, 2) - - self.assertRaises(mox.ExpectedMockCreationError, self.mox.VerifyAll) - self.mox.UnsetStubs() - - def testStubOutClassWrongSignature(self): - self.mox.StubOutClassWithMocks(mox_helper, 'CallableClass') - - self.assertRaises(AttributeError, mox_helper.CallableClass) - - self.mox.UnsetStubs() - - def testStubOutClassWrongParameters(self): - self.mox.StubOutClassWithMocks(mox_helper, 'CallableClass') - - mox_helper.CallableClass(1, 2) - - self.mox.ReplayAll() - - self.assertRaises(mox.UnexpectedMethodCallError, - mox_helper.CallableClass, 8, 9) - self.mox.UnsetStubs() - - def testStubOutClassTooManyCreated(self): - self.mox.StubOutClassWithMocks(mox_helper, 'CallableClass') - - mox_helper.CallableClass(1, 2) - - self.mox.ReplayAll() - mox_helper.CallableClass(1, 2) - self.assertRaises(mox.UnexpectedMockCreationError, - mox_helper.CallableClass, 8, 9) - - self.mox.UnsetStubs() - - def testWarnsUserIfMockingMock(self): - """Test that user is warned if they try to stub out a MockAnything.""" - self.mox.StubOutWithMock(TestClass, 'MyStaticMethod') - self.assertRaises(TypeError, self.mox.StubOutWithMock, TestClass, - 'MyStaticMethod') - - def testStubOutFirstClassMethodVerifiesSignature(self): - self.mox.StubOutWithMock(mox_helper, 'MyTestFunction') - - # Wrong number of arguments - self.assertRaises(AttributeError, mox_helper.MyTestFunction, 1) - self.mox.UnsetStubs() - - def _testMethodSignatureVerification(self, stubClass): - # If stubClass is true, the test is run against an a stubbed out class, - # else the test is run against a stubbed out instance. - if stubClass: - self.mox.StubOutWithMock(mox_helper.ExampleClass, "TestMethod") - obj = mox_helper.ExampleClass() - else: - obj = mox_helper.ExampleClass() - self.mox.StubOutWithMock(mox_helper.ExampleClass, "TestMethod") - self.assertRaises(AttributeError, obj.TestMethod) - self.assertRaises(AttributeError, obj.TestMethod, 1) - self.assertRaises(AttributeError, obj.TestMethod, nine=2) - obj.TestMethod(1, 2) - obj.TestMethod(1, 2, 3) - obj.TestMethod(1, 2, nine=3) - self.assertRaises(AttributeError, obj.TestMethod, 1, 2, 3, 4) - self.mox.UnsetStubs() - - def testStubOutClassMethodVerifiesSignature(self): - self._testMethodSignatureVerification(stubClass=True) - - def testStubOutObjectMethodVerifiesSignature(self): - self._testMethodSignatureVerification(stubClass=False) - - def testStubOutObject(self): - """Test than object is replaced with a Mock.""" - - class Foo(object): - def __init__(self): - self.obj = TestClass() - - foo = Foo() - self.mox.StubOutWithMock(foo, "obj") - self.assertTrue(isinstance(foo.obj, mox.MockObject)) - foo.obj.ValidCall() - self.mox.ReplayAll() - - foo.obj.ValidCall() - - self.mox.VerifyAll() - self.mox.UnsetStubs() - self.assertFalse(isinstance(foo.obj, mox.MockObject)) - - def testForgotReplayHelpfulMessage(self): - """If there is an AttributeError on a MockMethod, give helpful msg.""" - foo = self.mox.CreateMockAnything() - bar = self.mox.CreateMockAnything() - foo.GetBar().AndReturn(bar) - bar.ShowMeTheMoney() - # Forgot to replay! - try: - foo.GetBar().ShowMeTheMoney() - except AttributeError as e: - self.assertEqual( - 'MockMethod has no attribute "ShowMeTheMoney". ' - 'Did you remember to put your mocks in replay mode?', str(e)) - - -class ReplayTest(testtools.TestCase): - """Verify Replay works properly.""" - - def testReplay(self): - """Replay should put objects into replay mode.""" - mock_obj = mox.MockObject(TestClass) - self.assertFalse(mock_obj._replay_mode) - mox.Replay(mock_obj) - self.assertTrue(mock_obj._replay_mode) - - -class MoxTestBaseTest(testtools.TestCase): - """Verify that all tests in class derived from MoxTestBase are wrapped.""" - - def setUp(self): - super(MoxTestBaseTest, self).setUp() - self.mox = mox.Mox() - self.addCleanup(self.mox.UnsetStubs) - self.test_mox = mox.Mox() - self.addCleanup(self.test_mox.UnsetStubs) - self.test_stubs = mox.stubout.StubOutForTesting() - self.addCleanup(self.test_stubs.UnsetAll) - self.addCleanup(self.test_stubs.SmartUnsetAll) - self.result = testtools.TestResult() - - def _setUpTestClass(self): - """Replacement for setUp in the test class instance. - - Assigns a mox.Mox instance as the mox attribute of the test instance. - Replacement Mox instance is under our control before setUp is called - in the test class instance. - """ - self.test.mox = self.test_mox - self.test.stubs = self.test_stubs - - def _CreateTest(self, test_name): - """Create a test from our example mox class. - - The created test instance is assigned to this instances test attribute. - """ - self.test = mox_helper.ExampleMoxTest(test_name) - self.mox.stubs.Set(self.test, 'setUp', self._setUpTestClass) - - def _VerifySuccess(self): - """Run the checks to confirm test method completed successfully.""" - self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs') - self.mox.StubOutWithMock(self.test_mox, 'VerifyAll') - self.mox.StubOutWithMock(self.test_stubs, 'UnsetAll') - self.mox.StubOutWithMock(self.test_stubs, 'SmartUnsetAll') - self.test_mox.UnsetStubs() - self.test_mox.VerifyAll() - self.test_stubs.UnsetAll() - self.test_stubs.SmartUnsetAll() - self.mox.ReplayAll() - self.test.run(result=self.result) - self.assertTrue(self.result.wasSuccessful()) - self.mox.VerifyAll() - self.mox.UnsetStubs() # Needed to call the real VerifyAll() below. - self.test_mox.VerifyAll() - - def testSuccess(self): - """Successful test method execution test.""" - self._CreateTest('testSuccess') - self._VerifySuccess() - - def testSuccessNoMocks(self): - """testSuccess() unsets all the mocks. Vverify they've been unset.""" - self._CreateTest('testSuccess') - self.test.run(result=self.result) - self.assertTrue(self.result.wasSuccessful()) - self.assertEqual(OS_LISTDIR, mox_helper.os.listdir) - - def testStubs(self): - """Test that "self.stubs" is provided as is useful.""" - self._CreateTest('testHasStubs') - self._VerifySuccess() - - def testStubsNoMocks(self): - """Let testHasStubs() unset the stubs by itself.""" - self._CreateTest('testHasStubs') - self.test.run(result=self.result) - self.assertTrue(self.result.wasSuccessful()) - self.assertEqual(OS_LISTDIR, mox_helper.os.listdir) - - def testExpectedNotCalled(self): - """Stubbed out method is not called.""" - self._CreateTest('testExpectedNotCalled') - self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs') - self.mox.StubOutWithMock(self.test_stubs, 'UnsetAll') - self.mox.StubOutWithMock(self.test_stubs, 'SmartUnsetAll') - # Don't stub out VerifyAll - that's what causes the test to fail - self.test_mox.UnsetStubs() - self.test_stubs.UnsetAll() - self.test_stubs.SmartUnsetAll() - self.mox.ReplayAll() - self.test.run(result=self.result) - self.assertFalse(self.result.wasSuccessful()) - self.mox.VerifyAll() - - def testExpectedNotCalledNoMocks(self): - """Let testExpectedNotCalled() unset all the mocks by itself.""" - self._CreateTest('testExpectedNotCalled') - self.test.run(result=self.result) - self.assertFalse(self.result.wasSuccessful()) - self.assertEqual(OS_LISTDIR, mox_helper.os.listdir) - - def testUnexpectedCall(self): - """Stubbed out method is called with unexpected arguments.""" - self._CreateTest('testUnexpectedCall') - self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs') - self.mox.StubOutWithMock(self.test_stubs, 'UnsetAll') - self.mox.StubOutWithMock(self.test_stubs, 'SmartUnsetAll') - # Ensure no calls are made to VerifyAll() - self.mox.StubOutWithMock(self.test_mox, 'VerifyAll') - self.test_mox.UnsetStubs() - self.test_stubs.UnsetAll() - self.test_stubs.SmartUnsetAll() - self.mox.ReplayAll() - self.test.run(result=self.result) - self.assertFalse(self.result.wasSuccessful()) - self.mox.VerifyAll() - - def testFailure(self): - """Failing assertion in test method.""" - self._CreateTest('testFailure') - self.mox.StubOutWithMock(self.test_mox, 'UnsetStubs') - self.mox.StubOutWithMock(self.test_stubs, 'UnsetAll') - self.mox.StubOutWithMock(self.test_stubs, 'SmartUnsetAll') - # Ensure no calls are made to VerifyAll() - self.mox.StubOutWithMock(self.test_mox, 'VerifyAll') - self.test_mox.UnsetStubs() - self.test_stubs.UnsetAll() - self.test_stubs.SmartUnsetAll() - self.mox.ReplayAll() - self.test.run(result=self.result) - self.assertFalse(self.result.wasSuccessful()) - self.mox.VerifyAll() - - def testMixin(self): - """Run test from mix-in test class, ensure it passes.""" - self._CreateTest('testStat') - self._VerifySuccess() - - def testMixinAgain(self): - """Run same test as above but from the current test class. - - Ensures metaclass properly wrapped test methods from all base classes. - If unsetting of stubs doesn't happen, this will fail. - """ - self._CreateTest('testStatOther') - self._VerifySuccess() - - -class VerifyTest(testtools.TestCase): - """Verify Verify works properly.""" - - def testVerify(self): - """Verify should be called for all objects. - - Should throw an exception because the expected behavior did not occur. - """ - mock_obj = mox.MockObject(TestClass) - mock_obj.ValidCall() - mock_obj._Replay() - self.assertRaises(mox.ExpectedMethodCallsError, mox.Verify, mock_obj) - - -class ResetTest(testtools.TestCase): - """Verify Reset works properly.""" - - def testReset(self): - """Should empty all queues and put mocks in record mode.""" - mock_obj = mox.MockObject(TestClass) - mock_obj.ValidCall() - self.assertFalse(mock_obj._replay_mode) - mock_obj._Replay() - self.assertTrue(mock_obj._replay_mode) - self.assertEqual(1, len(mock_obj._expected_calls_queue)) - - mox.Reset(mock_obj) - self.assertFalse(mock_obj._replay_mode) - self.assertEqual(0, len(mock_obj._expected_calls_queue)) - - -class MyTestCase(testtools.TestCase): - """Simulate the use of a fake wrapper around Python's unittest library.""" - - def setUp(self): - super(MyTestCase, self).setUp() - self.critical_variable = 42 - self.another_critical_variable = 42 - - def testMethodOverride(self): - """Should be properly overridden in a derived class.""" - self.assertEqual(42, self.another_critical_variable) - self.another_critical_variable += 1 - - -class MoxTestBaseMultipleInheritanceTest(mox.MoxTestBase, MyTestCase): - """Test that multiple inheritance can be used with MoxTestBase.""" - - def setUp(self): - super(MoxTestBaseMultipleInheritanceTest, self).setUp() - self.another_critical_variable = 99 - - def testMultipleInheritance(self): - """Should be able to access members created by all parent setUp().""" - self.assertTrue(isinstance(self.mox, mox.Mox)) - self.assertEqual(42, self.critical_variable) - - def testMethodOverride(self): - """Should run before MyTestCase.testMethodOverride.""" - self.assertEqual(99, self.another_critical_variable) - self.another_critical_variable = 42 - super(MoxTestBaseMultipleInheritanceTest, self).testMethodOverride() - self.assertEqual(43, self.another_critical_variable) - - -class MoxTestDontMockProperties(MoxTestBaseTest): - def testPropertiesArentMocked(self): - mock_class = self.mox.CreateMock(ClassWithProperties) - self.assertRaises(mox.UnknownMethodCallError, - lambda: mock_class.prop_attr) - - -class TestClass(object): - """This class is used only for testing the mock framework.""" - - SOME_CLASS_VAR = "test_value" - _PROTECTED_CLASS_VAR = "protected value" - - def __init__(self, ivar=None): - self.__ivar = ivar - - def __eq__(self, rhs): - return self.__ivar == rhs - - def __ne__(self, rhs): - return not self.__eq__(rhs) - - def ValidCall(self): - pass - - def MethodWithArgs(self, one, two, nine=None): - pass - - def OtherValidCall(self): - pass - - def OptionalArgs(self, foo='boom'): - pass - - def ValidCallWithArgs(self, *args, **kwargs): - pass - - @classmethod - def MyClassMethod(cls): - pass - - @staticmethod - def MyStaticMethod(): - pass - - def _ProtectedCall(self): - pass - - def __PrivateCall(self): - pass - - def __DoNotMock(self): - pass - - def __getitem__(self, key): - """Return the value for key.""" - return self.d[key] - - def __setitem__(self, key, value): - """Set the value for key to value.""" - self.d[key] = value - - def __contains__(self, key): - """Returns True if d contains the key.""" - return key in self.d - - def __iter__(self): - pass - - -class ChildClass(TestClass): - """This inherits from TestClass.""" - def __init__(self): - TestClass.__init__(self) - - def ChildValidCall(self): - pass - - -class CallableClass(object): - """This class is callable, and that should be mockable!""" - - def __init__(self): - pass - - def __call__(self, param): - return param - - -class ClassWithProperties(object): - def setter_attr(self, value): - pass - - def getter_attr(self): - pass - - prop_attr = property(getter_attr, setter_attr) - - -class SubscribtableNonIterableClass(object): - def __getitem__(self, index): - raise IndexError - - -class InheritsFromCallable(CallableClass): - """This class should be mockable; it inherits from a callable class.""" - - pass - - -if __name__ == '__main__': - testtools.main() diff --git a/mox3/tests/test_stubout.py b/mox3/tests/test_stubout.py deleted file mode 100644 index 4a04170..0000000 --- a/mox3/tests/test_stubout.py +++ /dev/null @@ -1,49 +0,0 @@ -# Unit tests for stubout. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# -# This is a fork of the pymox library intended to work with Python 3. -# The file was modified by quermit@gmail.com and dawid.fatyga@gmail.com - -import fixtures -import testtools - -from mox3 import mox -from mox3 import stubout -from mox3.tests import stubout_helper - - -class StubOutForTestingTest(testtools.TestCase): - def setUp(self): - super(StubOutForTestingTest, self).setUp() - self.mox = mox.Mox() - self.useFixture(fixtures.MonkeyPatch( - 'mox3.tests.stubout_helper.SampleFunction', - stubout_helper.SampleFunction)) - - def testSmartSetOnModule(self): - mock_function = self.mox.CreateMockAnything() - mock_function() - - stubber = stubout.StubOutForTesting() - stubber.SmartSet(stubout_helper, 'SampleFunction', mock_function) - - self.mox.ReplayAll() - - stubout_helper.SampleFunction() - - self.mox.VerifyAll() - - -if __name__ == '__main__': - testtools.main() diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 64fc8f9..0000000 --- a/requirements.txt +++ /dev/null @@ -1,6 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -pbr!=2.1.0,>=2.0.0 # Apache-2.0 - -fixtures>=3.0.0 # Apache-2.0/BSD diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 4b920c9..0000000 --- a/setup.cfg +++ /dev/null @@ -1,29 +0,0 @@ -[metadata] -name = mox3 -summary = Mock object framework for Python -description-file = - README.rst -author = OpenStack -author-email = openstack-discuss@lists.openstack.org -home-page = https://docs.openstack.org/mox3/latest/ -python-requires = >=3.6 -classifiers = - Environment :: OpenStack - Programming Language :: Python - License :: OSI Approved :: Apache Software License - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.6 - Programming Language :: Python :: 3.7 - Programming Language :: Python :: 3.8 - Operating System :: OS Independent - Development Status :: 4 - Beta - Intended Audience :: Developers - Topic :: Software Development :: Testing - -[files] -packages = - mox3 - -[global] -setup-hooks = - pbr.hooks.setup_hook diff --git a/setup.py b/setup.py deleted file mode 100644 index 566d844..0000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or -# implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 8a1f912..0000000 --- a/test-requirements.txt +++ /dev/null @@ -1,16 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -# this file lists dependencies required for the testing of heat - -coverage!=4.4,>=4.0 # Apache-2.0 -python-subunit>=1.0.0 # Apache-2.0/BSD -stestr>=2.0.0 # Apache-2.0 -testtools>=2.2.0 # MIT - -six>=1.10.0 # MIT - -# this is required for the docs build jobs -sphinx>=2.2.0,!=2.1.0 # BSD -openstackdocstheme>=2.2.1 # Apache-2.0 - diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 366fac3..0000000 --- a/tox.ini +++ /dev/null @@ -1,36 +0,0 @@ -[tox] -minversion = 3.1.1 -envlist = py38,pep8 -ignore_basepython_conflict = True - -[testenv] -basepython = python3 -deps = - -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = stestr run --slowest {posargs} - -[testenv:docs] -commands = - rm -rf doc/build/html doc/build/doctrees - sphinx-build -W --keep-going -b html -d doc/build/doctrees doc/source doc/build/html - -[testenv:pep8] -deps = - flake8<2.7.0,>=2.6.0 -commands = flake8 - -[testenv:venv] -commands = {posargs} - -[flake8] -show-source = true -ignore = E721 -exclude=.git,.tox,dist,doc,*openstack/common*,*lib/python*,*egg - -[testenv:lower-constraints] -deps = - -c{toxinidir}/lower-constraints.txt - -r{toxinidir}/test-requirements.txt - -r{toxinidir}/requirements.txt