pax_global_header00006660000000000000000000000064130131560260014507gustar00rootroot0000000000000052 comment=4d16ff6b55694d6060dfd3fe772f77a3f3c9f005 python-pyforge-1.3.0/000077500000000000000000000000001301315602600145025ustar00rootroot00000000000000python-pyforge-1.3.0/.gitignore000066400000000000000000000004121301315602600164670ustar00rootroot00000000000000#### Python *.py[co] # Packages *.egg *.egg-info dist build eggs parts bin develop-eggs .installed.cfg # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox #### Eclipse *.pydevproject .project .metadata #### Emacs \#*\# .#* MANIFEST .env python-pyforge-1.3.0/.travis.yml000066400000000000000000000006401301315602600166130ustar00rootroot00000000000000language: python sudo: false python: - '2.7' - '3.3' - '3.4' - '3.5' install: - pip install . - pip install nose script: nosetests deploy: provider: pypi user: vmalloc password: secure: dLHV+qi3Pgd61dyDDIGBO7dauuZ3hS/0guZNwkLy2g/4eSzNKcUDXDxBeYYLiduZhRPEdAkAM5pirjc0FCBJUxdrncuNOsvIphRh/DhM9aEpiaiTuGBoOyxF2UPAfJwfvIjkSbdAGjeIuTK1aCAtXkijYHmCKnAjRTRmgRgBW2g= on: tags: true repo: vmalloc/pyforge python-pyforge-1.3.0/LICENSE000066400000000000000000000027661301315602600155220ustar00rootroot00000000000000# Copyright (c) 2010, Rotem Yaari # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of organization nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY Rotem Yaari ''AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL Rotem Yaari BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. python-pyforge-1.3.0/Makefile000066400000000000000000000003111301315602600161350ustar00rootroot00000000000000default: test test: env .env/bin/nosetests -x env: .env/.up-to-date .env/.up-to-date: setup.py Makefile python -m virtualenv .env .env/bin/pip install -e . .env/bin/pip install nose touch $@ python-pyforge-1.3.0/README.rst000066400000000000000000000432051301315602600161750ustar00rootroot00000000000000.. image:: https://secure.travis-ci.org/vmalloc/pyforge.png What is it? =========== Forge is a mocking library for Python. It draws most of its inspiration from Mox (http://code.google.com/p/pymox). It is aimed to be simple, but still feature-rich, and provide maximum flexibility for unit testing using the mock approach. Running Forge's Acceptance Suite ================================ All of Forge's acceptance tests are in the tests/ directory under the root. They require either unittest2 or the built-in unittest module (2.7/3.2 and above). Running the tests is recommended with the *nosetests* script, but in case you don't have it, the *run_tests* script can be used instead. Installation ============ Installing forge is pretty much the same as most of the packages you already know :: python setup.py install Usage ===== Basics ------ Forge mostly creates mock objects and function stubs, but in a variety of flavors. Using Forge always starts with creating a "Mock Manager", with the *Forge* class:: >>> from forge import Forge >>> forge_manager = Forge() There shouldn't be a real reason for keeping more than one forge manager. What it is typically used for is creating mocks:: >>> class SomeClass(object): ... def f(self, a, b, c): ... pass >>> mock = forge_manager.create_mock(SomeClass) >>> mock Mock tests usually act in a record-replay manner. You record what you expect your mock to do, and then replay it, while Forge tracks what happens and makes sure it is correct:: >>> forge_manager.is_recording() True >>> mock.f(1, 2, 3) # doctest: +ELLIPSIS <...> >>> mock.f(3, 4, 5) # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> forge_manager.is_recording() False >>> forge_manager.is_replaying() True >>> mock.f(1, 2, 3) >>> mock.f(3, 4, 5) >>> forge_manager.verify() # this verifies no more calls are expected To start over working from scratch, you can always perform:: >>> forge_manager.reset() Just like classes yield mocks, regular functions yield stubs, through the use of *Forge.create_function_stub*:: >>> def some_func(a, b, c): ... pass >>> stub = forge_manager.create_function_stub(some_func) As methods and functions are recorded, their signature is verified against the recorded calls. Upon replay the call must match the original call, so you shouldn't worry too much about accidents concerning the function signature. To promote niceness, two context managers provide syntactic sugar that structure the test code: >>> with forge_manager.record_context(): ... mock.f(1, 2, 3) # doctest: +ELLIPSIS ... mock.f(3, 4, 5) # doctest: +ELLIPSIS <...> >>> with forge_manager.verified_replay_context(): ... mock.f(1, 2, 3) # doctest: +ELLIPSIS ... mock.f(3, 4, 5) # doctest: +ELLIPSIS Failures and Unexpected Events ------------------------------ Whenever an event occurs that was not expected, an exception is raised, explaining what happend:: >>> stub = forge_manager.create_function_stub(some_func) >>> stub(1, 2, 3) # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> stub(1, 2, 4) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... UnexpectedCall: Unexpected function called! (Expected: +, Got: -) - some_func(a=1, b=2, c=4) ? ^ + some_func(a=1, b=2, c=3) ? ^ >>> forge_manager.reset() In some cases this is sufficient, but in case you want a bit more info as to where the calls were recorded and replayed, you can turn on debug info:: >>> forge_manager.debug.enable() >>> stub = forge_manager.create_function_stub(some_func) >>> stub(1, 2, 3) # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> stub(1, 2, 4) # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... UnexpectedCall: Unexpected function called! (Expected: +, Got: -) Recorded from ... Replayed from ... - some_func(a=1, b=2, c=4) ? ^ + some_func(a=1, b=2, c=3) ? ^ >>> forge_manager.reset() >>> forge_manager.debug.disable() Since sometimes this is a very common pattern, you can also turn on debugging through environment variables, by setting the FORGE_DEBUG environment variable to anything when running your tests. Expecting Attribute Setting --------------------------- Setting attributes for mock object is allowed only during record mode. By default, attributes set during replay will trigger an exception. However, in some cases you want to *expect* an attribute being set at some point of the replay. Due to the hackish nature of the Forge setattr/getattr mechanism, the way to do this is with a dedicated API through the __forge__ handle: >>> mock = forge_manager.create_mock(SomeClass) >>> mock.__forge__.expect_setattr("length", 20) # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> mock.length = 20 >>> forge_manager.verify() >>> forge_manager.reset() You can also set mock object to ignore attribute setting (thus allow all setattrs regardless of nature). This is not recommended, but might sometimes be useful:: >>> mock.__forge__.enable_setattr_during_replay() >>> forge_manager.replay() >>> mock.a = 2 # works! >>> forge_manager.reset() If you want to simulate a *mock structure*, that is, an object with attributes which are in turn other objects, you can use the *create_mock_with_attrs* API. This is especially concise if you create a shortcut for it: >>> class A(object): pass >>> class B(object): pass >>> class C(object): pass >>> MOCK = forge_manager.create_mock_with_attrs >>> result = MOCK(A, b=MOCK(B, c=MOCK(C))) >>> result.b.c # doctest: +ELLIPSIS Actions ------- When expecting a call on a stub, you can control what happens *when* the call takes place. Supported cases are: - controlling the return value:: my_stub(1, 2, 3).and_return(666) - calling another function (no arguments):: my_stub(1, 2, 3).and_call(callback) - calling another function with certain arguments/keyword arguments:: my_stub(1, 2, 3).and_call(callback, args=(100, 200), kwargs={'some_arg':20}) - calling another function (with the arguments of the call):: my_stub(1, 2, 3).and_call_with_args(callback) - raising an exception (happens after all callbacks are fired):: my_stub(1, 2, 3).and_raise(MyException()) Comparators ----------- If you don't know the exact value that the argument to a function is going to get, you sometimes have to use predicates to help you distinguish valid cases from invalid ones. For starters we'll mention that mock objects will only compare 'true' to themselves, so you shouldn't worry about any funky business as far as mock comparison goes. To complete the picture, if you want to assert all sorts of checks on the arguments you are recording, you can use comparators. For instance, the following doesn't care about which argument is passed to 'name', as long as it is a string:: my_stub(name=IsA(basestring)) Many comparators exist in Forge: * ``Is(x)``: compares true only if the argument is *x* * ``IsA(type)``: compares true only if the argument is of type *type* * ``RegexpMatches(regexp, [flags])``: compares true only if the argument is a string, and matches *regexp* * ``Func(f)``: compares true only if *f* returns True for the argument * ``IsAlmost(value, [places])``: compares true only if the argument is almost identical to *value*, by *places* digits after the floating point * ``Contains(element)``: compares true only if *element* exists in the argument * ``StrContains(substring)``: compares true only if *substring* exists in the argument, and the argument is a string * ``HasKeyValue(key, value)``: compares true only if the argument has *key* as a key, whose value is *value* * ``HasAttributeValue(attr, value)``: same as HasKeyValue, but for attributes * ``Anything()``: always compares true * ``And(...), Or(...), Not(c)``: and, or and a negator for other comparators Replacing Methods and Functions with Stubs ------------------------------------------ Forge includes a mechanism for installing (and later removing) stubs instead of ordinary methods and functions:: >>> import time >>> forge_manager.replace(time, "time") # doctest: +ELLIPSIS <...> >>> time.time().and_return(2) 2 >>> forge_manager.replay() >>> time.time() 2 >>> forge_manager.verify() >>> forge_manager.restore_all_replacements() >>> forge_manager.reset() This also works, of course, on methods: >>> class MyClass(object): ... def f(self): ... self.g() ... def g(self): ... raise NotImplementedError() >>> instance = MyClass() >>> forge_manager.replace(instance, "g") # doctest: +ELLIPSIS <...> >>> instance.g() # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> instance.f() >>> forge_manager.verify() >>> forge_manager.restore_all_replacements() >>> forge_manager.reset() One can also use the same install mechanism to set a custom value and have it restored along with all stubs:: >>> class SomeClass(object): ... x = 2 >>> forge_manager.replace_with(SomeClass, "x", 3) 3 >>> SomeClass.x 3 >>> forge_manager.restore_all_replacements() >>> SomeClass.x 2 Replacing is also supported within a context, restoring the installed stub upon exit from the context:: >>> with forge_manager.replacing_context(SomeClass, "x"): ... pass Ordering -------- By default, forge verifies that the order in which calls are made in practice is the same as the record flow. You can, however, control it and create groups in which order does not matter:: >>> class SomeClass(object): ... def func(self, arg): ... pass >>> mock = forge_manager.create_mock(SomeClass) >>> mock.func(1) # doctest: +ELLIPSIS <...> >>> mock.func(2) # doctest: +ELLIPSIS <...> >>> mock.func(3) # doctest: +ELLIPSIS ... # so far order must be kept <...> >>> with forge_manager.any_order(): # doctest: +ELLIPSIS ... mock.func(4) ... mock.func(5) <...> <...> >>> mock.func(6) # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> mock.func(1) >>> mock.func(2) >>> mock.func(3) >>> mock.func(5) # ok! >>> mock.func(4) # also ok! >>> mock.func(6) >>> forge_manager.verify() >>> forge_manager.reset() You can always nest ordering groups, by using *ordered*, *any_order* and *interleaved_order* (see below) :: >>> with forge_manager.any_order(): # doctest: +ELLIPSIS ... mock.func(4) ... with forge_manager.ordered(): ... mock.func(5) ... mock.func(6) ... mock.func(7) <...> <...> <...> <...> In the example above, func(5) and func(6) will be asserted to occur in this specific order, but the group can appear anywhere among func(4) and func(7). >>> forge_manager.replay() >>> for i in (5, 6, 7, 4): ... _ = mock.func(i) >>> forge_manager.verify() >>> forge_manager.reset() In the context of nested ordering groups, the *interleaved* ordering may come in handy when working with coroutines/greenlets:: >>> class SomeClass(object): ... def foo(self, arg): ... pass ... def bar(self, arg): ... pass >>> mock = forge_manager.create_mock(SomeClass) >>> with forge_manager.interleaved_order(): # doctest: +ELLIPSIS ... with forge_manager.ordered(): ... mock.foo(1) ... mock.foo(2) ... with forge_manager.ordered(): ... mock.bar(1) ... mock.bar(2) <...> <...> <...> <...> >>> forge_manager.replay() >>> mock.foo(1) >>> mock.bar(1) >>> mock.foo(2) >>> mock.bar(2) >>> forge_manager.verify() >>> forge_manager.reset() The expectation above will work with following sequence as well: >>> with forge_manager.interleaved_order(): # doctest: +ELLIPSIS ... with forge_manager.ordered(): ... mock.foo(1) ... mock.foo(2) ... with forge_manager.ordered(): ... mock.bar(1) ... mock.bar(2) <...> <...> <...> <...> >>> forge_manager.replay() >>> mock.bar(1) >>> mock.bar(2) >>> mock.foo(1) >>> mock.foo(2) >>> forge_manager.verify() >>> forge_manager.reset() Whenever -------- Sometimes you intend for a function to be called zero or more times, regardless of timing, and return a certain value (or raise an exception). There are ugly ways to do this:: >>> class MyObj(object): ... def f(self): ... pass >>> m = forge_manager.create_mock(MyObj) >>> m.f = lambda: 2 # yuck! And of course the downside is that: * the fact that f exists doesn't get verified. Also its signature is not verified with this method. * lambda's are ugly, and it gets nastier when you want to use exceptions. *whenever()* to the rescue - it is a method that can be called on expected methods, causing the call to be accepted, signature checked and acted upon. However, unlike regular recordings, it expects the call 0 or more times, at any point - so it achieves the same effect:: >>> m = forge_manager.create_mock(MyObj) >>> m.f().whenever().and_return(2) 2 >>> forge_manager.replay() >>> m.f() 2 >>> m.f() 2 >>> forge_manager.verify() >>> forge_manager.reset() Multiple *whenever()* recordings can be specified with different parameters, which results in a form of "pattern matching" for the requested calls (each call signature will result in a different return value). An alternative syntax exists for *whenever()* for easier readability:: >>> class Obj(object): ... def f(self, value): ... pass >>> m = forge_manager.create_mock(Obj) >>> m.f.when(2).then_return(3) 3 >>> forge_manager.replay() >>> m.f(2) 3 >>> forge_manager.verify() >>> forge_manager.reset() .. note:: whenever() calls always apply to the ordering group in which they were recorded. This means that once an order group is cleared, all of the *whenever*s recorded in it are automatically "forgotten", and will no longer be accepted on replay. Wildcard Mocks -------------- Although not recommended, sometimes you just want a mock that accepts anything during record, and just verifies that you stick to it in replay. This is useful for prototyping an interface that doesn't exist yet. This is done in Forge by using *wildcard mocks*:: >>> mock = forge_manager.create_wildcard_mock() >>> mock <> >>> stub = forge_manager.create_wildcard_function_stub() >>> stub >'> >>> mock.f() # doctest: +ELLIPSIS <...> >>> mock.g(1, 2, 3, d=4) # doctest: +ELLIPSIS <...> >>> stub() # doctest: +ELLIPSIS <...> >>> stub(1, 2, 3, d=4) # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> mock.f() >>> mock.g(1, 2, 3, d=4) >>> stub() >>> stub(1, 2, 3, d=4) >>> forge_manager.reset() Class Mocks ----------- Sometimes you would like to simulate the behavior of a class, and not an object. Forge allows to do this with the *create_class_mock* API:: >>> class MyClass(object): ... def __init__(self, a, b, c): ... pass ... def regular_method(self): ... pass ... @classmethod ... def some_class_method(cls): ... pass ... @staticmethod ... def some_static_method(): ... pass >>> class_mock = forge_manager.create_class_mock(MyClass) >>> class_mock >>> class_mock.regular_method() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): SignatureException: ... >>> class_mock.some_class_method() # doctest: +ELLIPSIS <...> >>> class_mock.some_static_method() # doctest: +ELLIPSIS <...> >>> fake_new_instance = forge_manager.create_mock(MyClass) >>> class_mock(1, 2, 3).and_return(fake_new_instance) # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> class_mock.some_class_method() >>> class_mock.some_static_method() >>> assert class_mock(1, 2, 3) is fake_new_instance >>> forge_manager.verify() >>> forge_manager.reset() Hybrid Mocks ------------ Suppose you have a class like the following:: >>> class File(object): ... def __init__(self, filename): ... self.f = open(filename, "rb") ... def read(self, size): ... raise NotImplementedError() ... def log(self, buffer): ... raise NotImplementedError() ... def read_and_log(self, size): ... data = self.read(size) ... self.log(data) ... return data Now, suppose you want to write a test for read_and_log, while mimicking the behavior of read() and log(). This is quite common, because sometimes methods in your classes have lots of side effects which are hard to plumb during test writing. One easy approach would be to create a File object and to replace read() and log() with stubs (see above). This is fine, but the problem is with the class construction, which opens a file for reading. In some cases, constructors (especially in legacy code to which you add tests) do lots of things that are hard to stub, or that are likely to change thus breaking any stubbing work you might install. For this case Forge has hybrid mocks:: >>> mock = forge_manager.create_hybrid_mock(File) >>> mock.read(20).and_return("data") # doctest: +ELLIPSIS '...' >>> mock.log("data") # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> assert mock.read_and_log(20) == "data" >>> forge_manager.verify() >>> forge_manager.reset() Hybrid mocks are, well, hybrid. They behave as regular mocks during record, but calling any method during replay that hasn't been recorded will invoke the original method on the mock, thus testing it in an isolated environment. A class equivalent also exists:: >>> class SomeClass(object): ... def __init__(self, parameter): ... raise NotImplementedError() ... @classmethod ... def constructor(cls): ... return cls(1) >>> mock = forge_manager.create_hybrid_class_mock(SomeClass) >>> expected_return_value = forge_manager.create_sentinel() >>> mock(1).and_return(expected_return_value) # doctest: +ELLIPSIS <...> >>> forge_manager.replay() >>> got_return_value = mock.constructor() >>> got_return_value is expected_return_value True python-pyforge-1.3.0/forge/000077500000000000000000000000001301315602600156045ustar00rootroot00000000000000python-pyforge-1.3.0/forge/__init__.py000066400000000000000000000002361301315602600177160ustar00rootroot00000000000000from .comparators import * from .forge import Forge from .exceptions import * from .forge_test_case import ForgeTestCase from .__version__ import __version__ python-pyforge-1.3.0/forge/__version__.py000066400000000000000000000000261301315602600204350ustar00rootroot00000000000000__version__ = "1.3.0" python-pyforge-1.3.0/forge/attribute_manager.py000066400000000000000000000021201301315602600216460ustar00rootroot00000000000000from collections import defaultdict from sentinels import NOTHING class AttributeManager(object): def __init__(self, forge): super(AttributeManager, self).__init__() self.forge = forge self._record_attributes = defaultdict(dict) self._replay_attributes = defaultdict(dict) def set_attribute(self, mock, attr, value): d = self._replay_attributes if self.forge.is_replaying() else self._record_attributes d[mock.__forge__.id][attr] = value def get_attribute(self, mock, attr): returned = self._get_attribute(mock, attr, self._replay_attributes) if returned is NOTHING: returned = self._get_attribute(mock, attr, self._record_attributes) return returned def _get_attribute(self, mock, attr, attr_dict): return attr_dict[mock.__forge__.id].get(attr, NOTHING) def reset_replay_attributes(self): self._replay_attributes.clear() def has_attribute(self, mock, attr): return attr in self._record_attributes[mock.__forge__.id] or attr in self._replay_attributes[mock.__forge__.id] python-pyforge-1.3.0/forge/bound_signature_adapter.py000066400000000000000000000014521301315602600230500ustar00rootroot00000000000000from .exceptions import SignatureException class BoundSignatureAdapter(object): def __init__(self, signature, obj): super(BoundSignatureAdapter, self).__init__() if signature.is_bound_method(): raise SignatureException("%s is already bound!" % self.stub) self._signature = signature self._obj = obj def is_bound(self): return True def get_normalized_args(self, args, kwargs): new_args = [self._obj] new_args.extend(args) returned = self._signature.get_normalized_args(new_args, kwargs) returned.pop(self._get_self_arg_name()) return returned def _get_self_arg_name(self): arg_names = list(self._signature.get_arg_names()) if arg_names: return arg_names[0] return 0 python-pyforge-1.3.0/forge/caller_info.py000066400000000000000000000017351301315602600204410ustar00rootroot00000000000000import sys class CallerInfo(object): def __init__(self, file_name, line_number, function_name): super(CallerInfo, self).__init__() self.file_name = file_name self.line_number = line_number self.function_name = function_name def __repr__(self): return "%s:%s::%s" % (self.file_name, self.line_number, self.function_name) @classmethod def from_caller(cls, level=1, _frame_getter=sys._getframe): """ @param level: how many calls above this one is to be retrieved (1 is the caller to this function) """ frame = _frame_getter(level + 1) try: returned = cls(file_name=frame.f_code.co_filename, line_number=frame.f_lineno, function_name=frame.f_code.co_name) finally: #necessary to prevent memory leaks, just in case __del__ #pops up some day del frame return returned python-pyforge-1.3.0/forge/class_mock.py000066400000000000000000000012061301315602600202730ustar00rootroot00000000000000from .class_mock_handle import ClassMockHandle from .mock_object import MockObject class ClassMockObject(MockObject): def __init__(self, forge, mocked_class, behave_as_instance, hybrid): super(ClassMockObject, self).__init__() self.__forge__ = ClassMockHandle(forge, self, mocked_class, behave_as_instance, hybrid) def __getattribute__(self, name): if name == '__class__': if self.__forge__.behaves_as_instance: return self.__forge__.mocked_class return type(self.__forge__.mocked_class) else: return super(ClassMockObject, self).__getattribute__(name) python-pyforge-1.3.0/forge/class_mock_handle.py000066400000000000000000000130771301315602600216170ustar00rootroot00000000000000import types import functools from sentinels import NOTHING from types import FunctionType from types import MethodType from types import BuiltinMethodType from .dtypes import MethodDescriptorType from .exceptions import InvalidEntryPoint from .exceptions import CannotMockFunctions from .signature import FunctionSignature from .mock_handle import MockHandle from .python3_compat import build_unbound_instance_method, IS_PY3 class ClassMockHandle(MockHandle): def __init__(self, forge, mock, mocked_class, behave_as_instance, hybrid): super(ClassMockHandle, self).__init__(forge, mock, behave_as_instance) self._assert_is_not_function(mocked_class) self.mocked_class = mocked_class self._hybrid = hybrid def _describe(self): desc = self._get_class_description() type_str = 'Mock' if self.behaves_as_instance else 'Class mock' return "<%s of %r>" % (type_str, desc) def _get_class_description(self): return getattr(self.mocked_class, '__name__', '?') def _assert_is_not_function(self, mocked_class): if type(mocked_class) in (types.FunctionType, types.MethodType, types.BuiltinFunctionType): raise CannotMockFunctions("Cannot mock functions as classes. Use create_function_stub instead.") def _has_method(self, name): return hasattr(self.mocked_class, name) def _get_real_function(self, name): returned = self._get_real_method(name) if IS_PY3: if hasattr(returned, '__func__'): return returned.__func__ return returned return returned.__func__ def _get_real_method(self, name): if name == '__call__' and not self.behaves_as_instance: return self._get_constructor_method() return getattr(self.mocked_class, name, NOTHING) def _get_constructor_method(self): returned = getattr(self.mocked_class, "__init__", object.__init__) if type(returned) is type(object.__init__) and returned.__objclass__ is object: # in some cases where the class doesn't have a constructor, # simulate an empty ctor... fake_constructor = lambda self: None fake_constructor.__name__ = "__init__" returned = build_unbound_instance_method(fake_constructor, self.mocked_class) return returned def _check_unrecorded_method_getting(self, name): pass # unrecorded methods can be obtained, but not called... def _check_getting_method_stub_without_recorded_calls(self, name, stub): pass # also ok def has_nonmethod_class_member(self, name): value = getattr(self.mocked_class, name, NOTHING) if value is NOTHING: return False return type(value) not in (FunctionType, MethodType, BuiltinMethodType, MethodDescriptorType) def get_nonmethod_class_member(self, name): return getattr(self.mocked_class, name) def get_method(self, name): if self._hybrid: if self.forge.is_replaying() and not self.forge.stubs.has_initialized_method_stub(self.mock, name): return self._build_hybrid_method(name) return super(ClassMockHandle, self).get_method(name) def _build_hybrid_method(self, name): real_method = self._get_real_method(name) if not self._can_use_as_entry_point(name, real_method): raise InvalidEntryPoint("%s is not a method that can be used as a hybrid entry pont" % (name,)) return functools.partial(self._get_real_function(name), self._build_hybrid_self_arg(real_method)) def _build_hybrid_self_arg(self, method): sig = FunctionSignature(method) if sig.is_class_method() and self.behaves_as_instance: return self.mocked_class return self.mock def _can_use_as_entry_point(self, name, method): if self._is_static_method(name): return False sig = FunctionSignature(method) if (sig.is_bound_method() and not sig.is_class_method()) and not self.behaves_as_instance: return False return True def _check_special_method_call(self, name, args, kwargs): if name == '__call__': if self.behaves_as_instance and not self.is_callable(): raise TypeError("%s instance is not callable!" % (self.mocked_class,)) else: if not self.has_method(name): raise TypeError("%s instance has no attribute %r" % (self.mocked_class, name)) def is_callable(self): if not hasattr(self.mocked_class, "__call__"): return False call_method = self.mocked_class.__call__ if getattr(call_method, "__objclass__", None) is type(self.mocked_class): return False if getattr(call_method, "__self__", None) is not None: #__call__ is already bound, for some reason return False return True def _is_binding_needed(self, name, method_stub): if not method_stub.__forge__.is_bound(): if name == '__call__' and not self.behaves_as_instance: # constructors are normally bound... return True, NOTHING if method_stub.__forge__.signature.is_class_method(): return True, self.mocked_class if self._is_static_method(name): return False, None if self.behaves_as_instance and not method_stub.__forge__.signature.is_bound_method(): return True, self.mock return False, None def _is_static_method(self, method_name): return isinstance(self.mocked_class.__dict__.get(method_name, None), staticmethod) python-pyforge-1.3.0/forge/comparators.py000066400000000000000000000105231301315602600205110ustar00rootroot00000000000000import re from .python3_compat import basestring class Comparator(object): def equals(self, other): raise NotImplementedError() def __eq__(self, other): return self.equals(other) def __ne__(self, other): return not (self == other) def __repr__(self): return "" % (type(self).__name__) class Is(Comparator): def __init__(self, obj): super(Is, self).__init__() self._obj = obj def equals(self, other): return self._obj is other def __repr__(self): return "" % (self._obj, id(self._obj)) class IsA(Comparator): def __init__(self, klass): super(IsA, self).__init__() self._class = klass def equals(self, other): try: return isinstance(other, self._class) except TypeError: return self._class is type(other) def __repr__(self): return "" % (self._class,) class RegexpMatches(Comparator): def __init__(self, regexp, flags=0): super(RegexpMatches, self).__init__() self._regexp = regexp self._flags = flags def equals(self, other): if not isinstance(other, basestring): return False return re.match(self._regexp, other, self._flags) def __repr__(self): return "" % (self._regexp,) class RegexpSearches(Comparator): def __init__(self, regexp, flags=0): super(RegexpSearches, self).__init__() self._regexp = regexp self._flags = flags def equals(self, other): if not isinstance(other, basestring): return False return re.search(self._regexp, other, self._flags) def __repr__(self): return "" % (self._regexp,) class Func(Comparator): def __init__(self, func): super(Func, self).__init__() self._func = func def equals(self, other): return self._func(other) def __repr__(self): return "" % (self._func,) class IsAlmost(Comparator): def __init__(self, value, places=7): super(IsAlmost, self).__init__() self._value = value self._places = places def equals(self, other): try: return round(self._value - other, self._places) == 0 except TypeError: return False class Contains(Comparator): def __init__(self, *objs): super(Contains, self).__init__() self._objs = objs def equals(self, other): try: return all(obj in other for obj in self._objs) except TypeError: return False class HasKeyValue(Comparator): def __init__(self, key, value): super(HasKeyValue, self).__init__() self._key = key self._value = value def equals(self, other): try: return other[self._key] == self._value except TypeError: return False except KeyError: return False class HasAttributeValue(Comparator): def __init__(self, attr, value): super(HasAttributeValue, self).__init__() self._attr = attr self._value = value def equals(self, other): try: return getattr(other, self._attr) == self._value except TypeError: return False except AttributeError: return False class Anything(Comparator): def equals(self, other): return True class And(Comparator): def __init__(self, *comparators): super(And, self).__init__() if not comparators: raise TypeError("At least one comparator must be specified for And()") self.comparators = comparators def equals(self, other): return all(c.equals(other) for c in self.comparators) StrContains = lambda *xs: And(IsA(basestring), Contains(*xs)) class Or(Comparator): def __init__(self, *comparators): super(Or, self).__init__() if not comparators: raise TypeError("At least one comparator must be specified for Or()") self.comparators = comparators def equals(self, other): return any(c.equals(other) for c in self.comparators) class Not(Comparator): def __init__(self, comparator): super(Not, self).__init__() self.comparator = comparator def equals(self, other): return not self.comparator.equals(other) python-pyforge-1.3.0/forge/constants.py000066400000000000000000000000461301315602600201720ustar00rootroot00000000000000WILDCARD_DESCRIPTION = "<>" python-pyforge-1.3.0/forge/debug.py000066400000000000000000000012661301315602600172510ustar00rootroot00000000000000import os from .caller_info import CallerInfo def _get_none_caller_info(level): return None class ForgeDebug(object): def __init__(self, forge): super(ForgeDebug, self).__init__() if 'FORGE_DEBUG' in os.environ: self.enable() else: self.disable() def disable(self): self._enabled = False self._current_caller_info_getter = _get_none_caller_info def enable(self): self._enabled = True self._current_caller_info_getter = CallerInfo.from_caller def is_enabled(self): return self._enabled def get_caller_info(self, level=1): return self._current_caller_info_getter(level + 1) python-pyforge-1.3.0/forge/dtypes.py000066400000000000000000000004051301315602600174650ustar00rootroot00000000000000from .constants import WILDCARD_DESCRIPTION WILDCARD_FUNCTION = lambda *args, **kwargs: None WILDCARD_FUNCTION.__name__ = WILDCARD_DESCRIPTION # unfortunately there doesn't appear to be another way of getting # this type MethodDescriptorType = type(dict.get) python-pyforge-1.3.0/forge/exceptions.py000066400000000000000000000066771301315602600203570ustar00rootroot00000000000000from difflib import Differ from .queued_object import QueuedObject class ForgeException(Exception): pass class SignatureException(ForgeException): pass class InvalidKeywordArgument(SignatureException): pass class FunctionCannotBeBound(SignatureException): pass class ConflictingActions(ForgeException): pass class MockObjectUnhashable(ForgeException): pass class CannotMockException(ForgeException): pass class CannotMockFunctions(CannotMockException): pass UNEXPECTED_FUNCTION_CALLED_STR = "Unexpected function called!" UNEXPECTED_SETATTR_STR = "Unexpected attribute set!" DIFF_DESCRIPTION_STR = "(Expected: +, Got: -)" class UnexpectedEvent(ForgeException, AssertionError): def __init__(self, expected, got): super(UnexpectedEvent, self).__init__() self.expected = expected self.got = got def __str__(self): returned = self._getTitle() returned += " %s\n" % DIFF_DESCRIPTION_STR debug_info = self._get_debug_info() if debug_info: returned += debug_info returned += self._get_diff_string() return returned def _get_debug_info(self): returned = "" returned += self._get_expected_caller_infos() returned += self._get_got_caller_infos() return returned def _get_expected_caller_infos(self): return self._get_caller_infos("Recorded", self.expected) def _get_got_caller_infos(self): return self._get_caller_infos("Replayed", self.got) def _get_caller_infos(self, verb, list_or_single): if not isinstance(list_or_single, list): list_or_single = [list_or_single] returned = "" for option in list_or_single: if option and option.caller_info: returned += "%s from %s\n" % (verb, option.caller_info) return returned def _get_diff_string(self): got_string = self._get_got_string() expected_string = self._get_expected_string() if got_string == expected_string: return "- %s\n+ %s" % (expected_string, got_string) diff = Differ().compare( [self._get_got_string()], [self._get_expected_string()], ) return "\n".join(line.strip() for line in diff) def _get_expected_string(self): return self._get_description_string(self.expected) def _get_got_string(self): return self._get_description_string(self.got) def _get_description_string(self, x): if isinstance(x, list): if len(x) == 1: x = x[0] elif len(x) == 0: x = None if x is None: return "<< None >>" if not isinstance(x, QueuedObject): return str(x) return x.describe() class UnexpectedCall(UnexpectedEvent): @classmethod def _getTitle(cls): return UNEXPECTED_FUNCTION_CALLED_STR class UnexpectedSetattr(UnexpectedEvent): @classmethod def _getTitle(cls): return UNEXPECTED_SETATTR_STR class ExpectedEventsNotFound(ForgeException, AssertionError): def __init__(self, events): super(ExpectedEventsNotFound, self).__init__() if type(events) is not list: raise ValueError("Expected events must be a list") self.events = events def __str__(self): return "Expected events not found:\n%s" % "\n".join(map(str, self.events)) class InvalidEntryPoint(ForgeException): pass python-pyforge-1.3.0/forge/forge.py000066400000000000000000000072151301315602600172650ustar00rootroot00000000000000import itertools import time from contextlib import contextmanager from .python3_compat import iteritems from .stub import FunctionStub from .queue import ForgeQueue from .class_mock import ClassMockObject from .wildcard_mock_object import WildcardMockObject from .replacer import Replacer from .stub_manager import StubManager from .attribute_manager import AttributeManager from .sentinel import Sentinel from .dtypes import WILDCARD_FUNCTION from .debug import ForgeDebug class Forge(object): def __init__(self): super(Forge, self).__init__() self.replacer = Replacer(self) self.attributes = AttributeManager(self) self.reset() self._id_allocator = itertools.count() self.debug = ForgeDebug(self) def get_new_handle_id(self): return next(self._id_allocator) def is_replaying(self): return self._is_replaying def is_recording(self): return not self.is_replaying() def replay(self): self._is_replaying = True def reset(self): self._is_replaying = False self.session_id = time.time() self.queue = ForgeQueue(self) self.stubs = StubManager(self) self.attributes.reset_replay_attributes() @contextmanager def record_context(self): assert self.is_recording() yield @contextmanager def verified_replay_context(self): self.replay() yield self.verify() self.reset() def verify(self): self.queue.verify() def create_function_stub(self, func, name=None): return FunctionStub(self, func, name=name) def create_wildcard_function_stub(self, name=None): return self.create_function_stub(WILDCARD_FUNCTION, name=name) def create_method_stub(self, method, name=None): return FunctionStub(self, method, name=name) def create_mock(self, mocked_class): return ClassMockObject(self, mocked_class, behave_as_instance=True, hybrid=False) def create_hybrid_mock(self, mocked_class): return ClassMockObject(self, mocked_class, behave_as_instance=True, hybrid=True) def create_class_mock(self, mocked_class): return ClassMockObject(self, mocked_class, behave_as_instance=False, hybrid=False) def create_hybrid_class_mock(self, mocked_class): return ClassMockObject(self, mocked_class, behave_as_instance=False, hybrid=True) def create_wildcard_mock(self, name=None): return WildcardMockObject(self, name=name) # arguments decorated to avoid conflicts with attrs def create_sentinel(__forge__self, __forge__name=None, **attrs): return Sentinel(__forge__name, **attrs) def create_mock_with_attrs(self, mocked_class, **attrs): returned = self.create_mock(mocked_class) for attr, value in iteritems(attrs): setattr(returned, attr, value) return returned def replace(self, obj, attr_name): return self.replacer.replace(obj, attr_name) def replacing_context(self, obj, attr_name): return self.replacer.replacing_context(obj, attr_name) def replace_many(self, obj, *attr_names): return [self.replace(obj, attr_name) for attr_name in attr_names] def replace_with(self, obj, attr_name, replacement): return self.replacer.replace_with(obj, attr_name, replacement) def restore_all_replacements(self): self.replacer.restore_all() def any_order(self): return self.queue.get_any_order_group_context() def ordered(self): return self.queue.get_ordered_group_context() def interleaved_order(self): return self.queue.get_interleaved_group_context() group = ordered python-pyforge-1.3.0/forge/forge_test_case.py000066400000000000000000000006521301315602600213150ustar00rootroot00000000000000try: from unittest2 import TestCase except ImportError: from unittest import TestCase from .forge import Forge class ForgeTestCase(TestCase): def setUp(self): super(ForgeTestCase, self).setUp() self.forge = Forge() def tearDown(self): try: self.forge.verify() finally: self.forge.restore_all_replacements() super(ForgeTestCase, self).tearDown() python-pyforge-1.3.0/forge/function_call.py000066400000000000000000000050771301315602600210070ustar00rootroot00000000000000from numbers import Number from sentinels import NOTHING from .exceptions import ConflictingActions from .queued_object import QueuedObject class FunctionCall(QueuedObject): def __init__(self, target, args, kwargs, caller_info): super(FunctionCall, self).__init__(caller_info) self.target = target self.args = target.__forge__.signature.get_normalized_args(args, kwargs) self._call_funcs = [] self._call_funcs_with_args = [] self._return_value = NOTHING self._raised_exception = NOTHING def matches(self, call): if not isinstance(call, FunctionCall): return False return self.target is call.target and self.args == call.args def describe(self): return "%s(%s)" % ( self.target.__forge__.describe(), self._get_argument_string(), ) def _get_argument_string(self): positional_args = sorted(k for k in self.args if isinstance(k, Number)) keyword_args = sorted(k for k in self.args if not isinstance(k, Number)) args = [repr(self.args[arg_index]) for arg_index in positional_args] args.extend("%s=%r" % (arg_name, self.args[arg_name]) for arg_name in keyword_args) return ", ".join(args) def whenever(self): self.target.__forge__.forge.queue.allow_whenever(self) return self def and_call(self, func, args=(), kwargs=None): if kwargs is None: kwargs = {} self._call_funcs.append((func, list(args), kwargs)) return self then_call = and_call def and_call_with_args(self, func): self._call_funcs_with_args.append(func) return self then_call_with_args = and_call_with_args def and_raise(self, exc): if self._return_value is not NOTHING: raise ConflictingActions() self._raised_exception = exc return exc then_raise = and_raise def and_return(self, rv): if self._raised_exception is not NOTHING: raise ConflictingActions() self._return_value = rv return rv then_return = and_return def do_side_effects(self, args, kwargs): for call_func, args, kwargs in self._call_funcs: call_func(*args, **kwargs) for call_func in self._call_funcs_with_args: call_func(*args, **kwargs) if self._raised_exception is not NOTHING: raise self._raised_exception def get_return_value(self): if self._return_value is not NOTHING: return self._return_value return None python-pyforge-1.3.0/forge/handle.py000066400000000000000000000007561301315602600174210ustar00rootroot00000000000000class ForgeHandle(object): def __init__(self, forge): super(ForgeHandle, self).__init__() self.id = forge.get_new_handle_id() self.forge = forge self._forced_description = None def describe(self): if self._forced_description is not None: return self._forced_description return self._describe() def _describe(self): raise NotImplementedError() def set_description(self, d): self._forced_description = d python-pyforge-1.3.0/forge/mock_handle.py000066400000000000000000000104561301315602600204300ustar00rootroot00000000000000from .handle import ForgeHandle class MockHandle(ForgeHandle): def __init__(self, forge, mock, behave_as_instance=True): super(MockHandle, self).__init__(forge) self.mock = mock self.behaves_as_instance = behave_as_instance self._attributes = {} self._is_hashable = False self._is_setattr_enabled_in_replay = False def is_hashable(self): return self._is_hashable def enable_hashing(self): self._is_hashable = True def disable_hashing(self): self._is_hashable = False def enable_setattr_during_replay(self): self._is_setattr_enabled_in_replay = True def disable_setattr_during_replay(self): self._is_setattr_enabled_in_replay = False def is_setattr_enabled_in_replay(self): return self._is_setattr_enabled_in_replay def has_attribute(self, attr): return False def get_attribute(self, attr): if self.forge.attributes.has_attribute(self.mock, attr): return self.forge.attributes.get_attribute(self.mock, attr) if self.has_nonmethod_class_member(attr): return self.get_nonmethod_class_member(attr) if self.has_method(attr): return self.get_method(attr) raise AttributeError("%s has no attribute %r" % (self.mock, attr)) def set_attribute(self, attr, value, caller_info): if self.forge.is_recording() or self.is_setattr_enabled_in_replay(): self._set_attribute(attr, value) else: self._set_attribute_during_replay(attr, value, caller_info) def expect_setattr(self, attr, value): return self.forge.queue.push_setattr(self.mock, attr, value, caller_info=self.forge.debug.get_caller_info()) def _set_attribute_during_replay(self, attr, value, caller_info): self.forge.queue.pop_matching_setattr(self.mock, attr, value, caller_info) self._set_attribute(attr, value) def _set_attribute(self, attr, value): self.forge.attributes.set_attribute(self.mock, attr, value) def has_method(self, attr): return self.forge.stubs.has_initialized_method_stub(self.mock, attr) or self._has_method(attr) def _has_method(self, name): raise NotImplementedError() def has_nonmethod_class_member(self, name): raise NotImplementedError() def get_nonmethod_class_member(self, name): raise NotImplementedError() def get_method(self, name): returned = self.forge.stubs.get_initialized_method_stub_or_none(self.mock, name) if returned is None: real_method = self._get_real_method(name) if not self.forge.is_recording(): self._check_unrecorded_method_getting(name) returned = self._construct_stub(name, real_method) self._bind_if_needed(name, returned) self.forge.stubs.add_initialized_method_stub(self.mock, name, returned) self._set_method_description(returned, name) elif self.forge.is_replaying() and not returned.__forge__.has_recorded_calls(): self._check_getting_method_stub_without_recorded_calls(name, returned) return returned def _set_method_description(self, method, name): method.__forge__.set_description("%s.%s" % ( self.describe(), name )) def _construct_stub(self, name, real_method): return self.forge.create_method_stub(real_method) def _check_unrecorded_method_getting(self, name): raise NotImplementedError() def _check_getting_method_stub_without_recorded_calls(self, name, stub): raise NotImplementedError() def _get_real_method(self, name): raise NotImplementedError() def handle_special_method_call(self, name, args, kwargs, caller_info): self._check_special_method_call(name, args, kwargs) return self.get_method(name).__forge__.handle_call(args, kwargs, caller_info) def _check_special_method_call(self, name, args, kwargs): raise NotImplementedError() def is_callable(self): raise NotImplementedError() def _bind_if_needed(self, name, method_stub): bind_needed, bind_target = self._is_binding_needed(name, method_stub) if bind_needed: method_stub.__forge__.bind(bind_target) def _is_binding_needed(self, name, method_stub): raise NotImplementedError() python-pyforge-1.3.0/forge/mock_object.py000066400000000000000000000036341301315602600204430ustar00rootroot00000000000000from .exceptions import MockObjectUnhashable from .exceptions import UnexpectedEvent class MockObject(object): def __repr__(self): return self.__forge__.describe() def __getattr__(self, attr): return self.__forge__.get_attribute(attr) def __setattr__(self, attr, value): if attr == '__forge__': self.__dict__[attr] = value else: self.__forge__.set_attribute(attr, value, caller_info=self.__forge__.forge.debug.get_caller_info()) def __hash__(self): if not self.__forge__.is_hashable(): raise MockObjectUnhashable("%s is not hashable!" % (self,)) return id(self) def __nonzero__(self): try: return self.__forge__.handle_special_method_call('__nonzero__', (), {}, caller_info=self.__forge__.forge.debug.get_caller_info()) except TypeError: return True def __bool__(self): return self.__nonzero__() def __exit__(self, *args): if self.__forge__.forge.is_replaying() and isinstance(args[1], UnexpectedEvent): return return self.__forge__.handle_special_method_call('__exit__', args, {}, caller_info=self.__forge__.forge.debug.get_caller_info()) def _get_special_method_placeholder(name): def placeholder(self, *args, **kwargs): caller_info = self.__forge__.forge.debug.get_caller_info() return self.__forge__.handle_special_method_call(name, args, kwargs, caller_info=caller_info) placeholder.__name__ = name return placeholder for special_method_name in [ '__delitem__', '__getitem__', '__len__', '__setitem__', '__iter__', '__call__', '__contains__', '__enter__', ]: setattr(MockObject, special_method_name, _get_special_method_placeholder(special_method_name)) python-pyforge-1.3.0/forge/python3_compat.py000066400000000000000000000014761301315602600211350ustar00rootroot00000000000000import types import itertools import platform import inspect IS_PY3 = (platform.python_version() >= '3') if IS_PY3: iteritems = dict.items xrange = range basestring = str def getargspec(x): return inspect.getfullargspec(x)[:4] else: iteritems = dict.iteritems from __builtin__ import xrange, basestring getargspec = inspect.getargspec def izip(*args, **kwargs): if IS_PY3: return zip(*args, **kwargs) return itertools.izip(*args, **kwargs) def build_instance_method(function, instance, cls): if IS_PY3: return types.MethodType(function, instance) return types.MethodType(function, instance, cls) def build_unbound_instance_method(function, cls): if IS_PY3: return types.MethodType(function, cls) return types.MethodType(function, None, cls) python-pyforge-1.3.0/forge/queue.py000066400000000000000000000076351301315602600173150ustar00rootroot00000000000000import sys import traceback import logging from contextlib import contextmanager from .function_call import FunctionCall from .setattr import Setattr from .exceptions import UnexpectedCall, UnexpectedSetattr, ExpectedEventsNotFound from .queued_node import QueuedNode from .queued_group import OrderedGroup, AnyOrderGroup, InterleavedGroup _logger = logging.getLogger("pyforge") class WheneverDecorator(QueuedNode): def __init__(self, obj): super(WheneverDecorator, self).__init__() self.obj = obj def get_expected(self): return [] def get_available(self): return [self.obj] def pop_matching(self, queue_object): return self.obj if self.obj.matches(queue_object) else None def __len__(self): return len(self.obj) def __repr__(self): return "" % (repr(self.obj),) class ForgeQueue(object): def __init__(self, forge): super(ForgeQueue, self).__init__() self._root_group = OrderedGroup() self._recording_group = self._root_group self._forge = forge def get_expected(self): return self._root_group.get_expected() def get_available(self): return self._root_group.get_available() def is_empty(self): return not self._root_group.get_expected() def __len__(self): return len(self._root_group) def clear(self): self._root_group = OrderedGroup() self._recording_group = self._root_group def allow_whenever(self, queued_object): queued_object.get_parent().discard_child(queued_object) self._recording_group.push_out_of_band(WheneverDecorator(queued_object)) def push_call(self, target, args, kwargs, caller_info): return self._push(FunctionCall(target, args, kwargs, caller_info)) def push_setattr(self, target, name, value, caller_info): return self._push(Setattr(target, name, value, caller_info)) def pop_matching_call(self, target, args, kwargs, caller_info): return self._pop_matching(FunctionCall(target, args, kwargs, caller_info), UnexpectedCall) def pop_matching_setattr(self, target, name, value, caller_info): return self._pop_matching(Setattr(target, name, value, caller_info), UnexpectedSetattr) def _push(self, queued_object): return self._recording_group.push(queued_object) def _pop_matching(self, queued_object, unexpected_class): popped = self._root_group.pop_matching(queued_object) if popped is None: self._log_exception_context() raise unexpected_class(self.get_available(), queued_object) return popped def _log_exception_context(self): exc_type, exc_value, exc_tb = sys.exc_info() if exc_value is not None: _logger.debug("In exception context:\n%s\n%s: %s", "".join(traceback.format_tb(exc_tb)), exc_type.__name__, exc_value) @contextmanager def _get_group_context(self, group_class): group = group_class() try: self._recording_group.push(group) self._recording_group = group yield finally: parent = group.get_parent() if group.is_empty(): parent.discard_child(group) self._recording_group = parent def get_any_order_group_context(self): return self._get_group_context(AnyOrderGroup) def get_ordered_group_context(self): return self._get_group_context(OrderedGroup) def get_interleaved_group_context(self): return self._get_group_context(InterleavedGroup) def verify(self): expected_events = self._root_group.get_expected() if expected_events: raise ExpectedEventsNotFound(expected_events) def __repr__(self): return "ForgeQueue(_root_group =%s, _recording_group=)" % (id(self._root_group), repr(self._root_group), id(self._recording_group)) python-pyforge-1.3.0/forge/queued_group.py000066400000000000000000000107631301315602600206710ustar00rootroot00000000000000from itertools import chain from .queued_node import QueuedNodeParent class QueuedGroup(QueuedNodeParent): def __init__(self, parent_group=None): super(QueuedGroup, self).__init__() self._parent_group = parent_group self._collection = [] self._out_of_band_collection = [] def is_empty(self): return not self.get_expected() and not self.get_available() def get_expected(self): return list(chain.from_iterable(obj.get_expected() for obj in self.iter_expected_or_available_children())) def get_available(self): return list(chain.from_iterable(obj.get_available() for obj in self.iter_expected_or_available_children())) def iter_expected_or_available_children(self): raise NotImplementedError() # pragma: no cover def push(self, obj): self._collection.append(obj) obj.set_parent(self) return obj def push_out_of_band(self, obj): self._out_of_band_collection.append(obj) obj.set_parent(self) return obj def pop_matching(self, queued_object): result = self._pop_matching_by_strategy(queued_object) if result is None: result = self.pop_matching_out_of_band(queued_object) if result and self.get_parent() and not self.get_expected(): self.get_parent().discard_child(self) return result def pop_matching_out_of_band(self, queued_object): for obj in self._out_of_band_collection: result = obj.pop_matching(queued_object) if result: return result return None def discard_child(self, queued_object): for collection in (self._collection, self._out_of_band_collection): for index, obj in enumerate(collection): if obj is queued_object: collection.pop(index) return def __len__(self): return sum(len(obj) for obj in chain(self._collection, self._out_of_band_collection)) def __repr__(self): return "%s (%s, out_of_band=%s)" % (type(self).__name__, id(self), repr(self._collection), repr(self._out_of_band_collection)) class OrderedGroup(QueuedGroup): def iter_expected_or_available_children(self): return chain(self._collection[:1], self._out_of_band_collection) def _pop_matching_by_strategy(self, queued_object): return self._collection[0].pop_matching(queued_object) if self._collection else None class AnyOrderGroup(QueuedGroup): def __init__(self, parent_group=None): super(AnyOrderGroup, self).__init__(parent_group) self._current_child = None def iter_expected_or_available_children(self): return chain(self._collection, self._out_of_band_collection) def discard_child(self, queued_object): returned = super(AnyOrderGroup, self).discard_child(queued_object) if queued_object is self._current_child: self._current_child = None return returned def _pop_matching_by_strategy(self, queued_object): if self._current_child: return self._current_child.pop_matching(queued_object) else: for obj in self._collection: # Save the current child so if it removes itself we won't set it as as the current child anymore. self._current_child = obj try: result = obj.pop_matching(queued_object) except: self._current_child = None raise if result is not None: return result self._current_child = None return None def __repr__(self): return "%s (_current_child id=%s, %s, out_of_band=%s)" % (type(self).__name__, id(self), id(self._current_child), repr(self._collection), repr(self._out_of_band_collection)) class InterleavedGroup(QueuedGroup): def iter_expected_or_available_children(self): return chain(self._collection, self._out_of_band_collection) def _pop_matching_by_strategy(self, queued_object): for obj in self._collection: result = obj.pop_matching(queued_object) if result is not None: return result return None def __repr__(self): return "%s (%s, out_of_band=%s)" % (type(self).__name__, id(self), repr(self._collection), repr(self._out_of_band_collection)) python-pyforge-1.3.0/forge/queued_node.py000066400000000000000000000020571301315602600204570ustar00rootroot00000000000000class QueuedNode(object): """Base class for all nodes in the call tree. A node may be an actual call or attribute set/get, in this case this is a leaf node, or a call group (ordered, unordered, etc.), in that case it's a branch node.""" def __init__(self): super(QueuedNode, self).__init__() self._parent = None def get_parent(self): return self._parent def set_parent(self, parent): self._parent = parent def get_expected(self): return [self] def get_available(self): return [self] def pop_matching(self, queue_object): """Provide the node with the opportunity to remove queue_object from its subtree. Usually called after a call to matches(queue_object) as been made. Returns the matching queued object or None if not found.""" raise NotImplementedError() # pragma: no cover class QueuedNodeParent(QueuedNode): """Base class for all non-leaf nodes.""" def discard_child(self, child): raise NotImplementedError() # pragma: no cover python-pyforge-1.3.0/forge/queued_object.py000066400000000000000000000015011301315602600207710ustar00rootroot00000000000000from .queued_node import QueuedNode class QueuedObject(QueuedNode): """Base object for all leafs in the call tree.""" def __init__(self, caller_info): super(QueuedObject, self).__init__() self.caller_info = caller_info def matches(self, queue_object): """Returns True if the object matches queue_object. Implemented by derived classes.""" raise NotImplementedError() # pragma: no cover def describe(self): raise NotImplementedError() # pragma: no cover def __repr__(self): return "<%s>" % self.describe() def __len__(self): return 1 def pop_matching(self, queue_object): if not self.matches(queue_object): return None if self.get_parent(): self.get_parent().discard_child(self) return self python-pyforge-1.3.0/forge/replacer.py000066400000000000000000000065761301315602600177710ustar00rootroot00000000000000from contextlib import contextmanager from types import ModuleType from .utils import is_class from .utils import is_function from .utils import is_bound_method class Replacer(object): def __init__(self, forge): super(Replacer, self).__init__() self.forge = forge self._stubs = [] def replace(self, obj, attr_name): return self._replace(obj, attr_name).stub def _replace(self, obj, attr_name): replaced = getattr(obj, attr_name) replacement = self._get_replacement(replaced) self._set_replacement_description(replacement, obj, attr_name) return self._replace_with(obj, attr_name, replacement) @contextmanager def replacing_context(self, obj, attr_name): installed = self._replace(obj, attr_name) try: yield None finally: installed.restore() def _get_replacement(self, replaced): if is_class(replaced): return self.forge.create_class_mock(replaced) if is_function(replaced): return self.forge.create_function_stub(replaced) if is_bound_method(replaced): return self.forge.create_method_stub(replaced) return self.forge.create_mock(self._get_class(replaced)) def _get_class(self, obj): return getattr(obj, "__class__", type(obj)) def _set_replacement_description(self, replacement, obj, attr_name): if isinstance(obj, ModuleType): obj_name = obj.__name__ else: obj_name = "<%s instance>" % (type(obj).__name__,) replacement.__forge__.set_description("%s.%s" % (obj_name, attr_name)) def _replace_object_method_with_stub(self, obj, method_name): return self.replace_with(obj, method_name, self.forge.create_method_stub(getattr(obj, method_name))) def _replace_module_function_with_stub(self, module, function_name): return self.replace_with(module, function_name, self.forge.create_function_stub(getattr(module, function_name))) def replace_with(self, obj, attr_name, stub): self._replace_with(obj, attr_name, stub) return stub def _replace_with(self, obj, attr_name, stub): installed = InstalledStub(obj, attr_name, stub) self._stubs.append(installed) setattr(obj, attr_name, stub) return installed def restore_all(self): while self._stubs: installed = self._stubs.pop(-1) installed.restore() class InstalledStub(object): def __init__(self, obj, method_name, stub): super(InstalledStub, self).__init__() self.obj = obj self.method_name = method_name self.restorer = self._get_restorer(obj, method_name) self.stub = stub def restore(self): self.restorer.restore() def _get_restorer(self, obj, method_name): orig = obj.__dict__.get(method_name) if orig is None: orig = getattr(obj, method_name) return SimpleRestorer(obj, method_name, orig) class Restorer(object): def __init__(self, obj, method_name, orig): super(Restorer, self).__init__() self.obj, self.method_name = obj, method_name self.orig = orig def restore(self): raise NotImplementedError() class SimpleRestorer(Restorer): def restore(self): setattr(self.obj, self.method_name, self.orig) python-pyforge-1.3.0/forge/sentinel.py000066400000000000000000000006731301315602600200050ustar00rootroot00000000000000from .python3_compat import iteritems class Sentinel(object): def __init__(self, __forge__name=None, **attrs): super(Sentinel, self).__init__() self.__forge__name = __forge__name for attr, value in iteritems(attrs): setattr(self, attr, value) def __repr__(self): name = self.__forge__name if name is None: name = "0x%x" % id(self) return "" % name python-pyforge-1.3.0/forge/setattr.py000066400000000000000000000010641301315602600176450ustar00rootroot00000000000000from .queued_object import QueuedObject class Setattr(QueuedObject): def __init__(self, target, name, value, caller_info): super(Setattr, self).__init__(caller_info) self.target = target self.name = name self.value = value def matches(self, other): if not isinstance(other, Setattr): return False return other.target is self.target and other.name == self.name and other.value == self.value def describe(self): return "setattr(%r, %r, %r)" % (self.target, self.name, self.value) python-pyforge-1.3.0/forge/signature.py000066400000000000000000000107201301315602600201570ustar00rootroot00000000000000import copy import itertools from .python3_compat import izip, iteritems, basestring, getargspec from .exceptions import SignatureException, InvalidKeywordArgument from .utils import is_bound_method from .utils import is_class_method from numbers import Number from sentinels import NOTHING class Argument(object): def __init__(self, name, default=NOTHING): super(Argument, self).__init__() self.name = name self.default = default def has_default(self): return self.default is not NOTHING class FunctionSignature(object): def __init__(self, func): super(FunctionSignature, self).__init__() self.func = func self.func_name = func.__name__ self._build_arguments() def is_bound_method(self): return is_bound_method(self.func) def is_class_method(self): return is_class_method(self.func) def _iter_args_and_defaults(self, args, defaults): defaults = [] if defaults is None else defaults filled_defaults = itertools.chain(itertools.repeat(NOTHING, len(args) - len(defaults)), defaults) return izip(args, filled_defaults) def _build_arguments(self): self._args = [] try: args, varargs_name, kwargs_name, defaults = getargspec(self.func)[:4] except TypeError: args = [] varargs_name = 'args' kwargs_name = 'kwargs' defaults = [] for arg_name, default in self._iter_args_and_defaults(args, defaults): self._args.append(Argument(arg_name, default)) self._varargs_name = varargs_name self._kwargs_name = kwargs_name def get_args(self): return itertools.islice(self._args, 1 if self.is_bound_method() else 0, None) def get_num_args(self): returned = len(self._args) if self.is_bound_method(): returned = max(0, returned - 1) return returned def get_self_arg_name(self): if self.is_bound_method() and len(self._args) > 0: return self._args[0].name return None def get_arg_names(self): return (arg.name for arg in self.get_args()) def has_variable_args(self): return self._varargs_name is not None def has_variable_kwargs(self): return self._kwargs_name is not None def get_normalized_args(self, args, kwargs): returned = {} self._update_normalized_positional_args(returned, args) self._update_normalized_kwargs(returned, kwargs) self._check_missing_arguments(returned) self._check_unknown_arguments(returned) return returned def _update_normalized_positional_args(self, returned, args): argument_names = list(self.get_arg_names()) argument_names.extend(range(len(args) - self.get_num_args())) for arg_name, given_arg in zip(argument_names, args): returned[arg_name] = given_arg def _update_normalized_kwargs(self, returned, kwargs): for arg_name, arg in iteritems(kwargs): if not isinstance(arg_name, basestring): raise InvalidKeywordArgument("Invalid keyword argument %r" % (arg_name,)) if arg_name in returned: raise SignatureException("%s is given more than once to %s" % (arg_name, self.func_name)) returned[arg_name] = arg def _check_missing_arguments(self, args_dict): required_arguments = set(arg.name for arg in self.get_args() if not arg.has_default()) missing_arguments = required_arguments - set(args_dict) if missing_arguments: raise SignatureException("The following arguments were not specified: %s" % ",".join(map(repr, missing_arguments))) def _check_unknown_arguments(self, args_dict): positional_arg_count = len([arg_name for arg_name in args_dict if isinstance(arg_name, Number)]) num_args = self.get_num_args() if positional_arg_count and not self.has_variable_args(): raise SignatureException("%s receives %s positional arguments (%s specified)" % (self.func_name, num_args, num_args + positional_arg_count)) unknown = set(arg for arg in args_dict if not isinstance(arg, Number)) - set(self.get_arg_names()) if unknown and not self.has_variable_kwargs(): raise SignatureException("%s received unknown argument(s): %s" % (self.func_name, ",".join(unknown))) def copy(self): returned = copy.copy(self) returned._args = copy.deepcopy(returned._args) return returned python-pyforge-1.3.0/forge/stub.py000066400000000000000000000022161301315602600171340ustar00rootroot00000000000000import functools from .stub_handle import StubHandle from .dtypes import WILDCARD_FUNCTION class FunctionStub(object): def __init__(self, forge, original, name=None): super(FunctionStub, self).__init__() self.__forge__ = StubHandle(forge, self, original, name=name) self.__name__ = original.__name__ if name is None else name self.__doc__ = original.__doc__ def __call__(*args, **kwargs): self = args[0] caller_info = self.__forge__.forge.debug.get_caller_info() return self.__forge__.handle_call(args[1:], kwargs, caller_info=caller_info) def __repr__(self): call_count_msg = "" if self.__forge__.call_count: call_count_msg += " (already called %s times)" % (self.__forge__.call_count,) return '' % (self.__forge__.describe(), call_count_msg) def __getattribute__(self, name): if name == "when" and self.__forge__.forge.is_recording(): return functools.partial(_when, self) return super(FunctionStub, self).__getattribute__(name) def _when(__func, *args, **kwargs): return __func(*args, **kwargs).whenever() python-pyforge-1.3.0/forge/stub_handle.py000066400000000000000000000040671301315602600204550ustar00rootroot00000000000000from .handle import ForgeHandle from .signature import FunctionSignature from .bound_signature_adapter import BoundSignatureAdapter class StubHandle(ForgeHandle): def __init__(self, forge, stub, original, name=None): super(StubHandle, self).__init__(forge) self.stub = stub self.name = name self.original = original self.signature = FunctionSignature(self.original) self._call_count = 0 self._call_count_session_id = 0 @property def call_count(self): if self.forge.session_id == self._call_count_session_id: return self._call_count return 0 def _describe(self): if self.name is not None: return self.name return self.original.__name__ def bind(self, obj): self.signature = BoundSignatureAdapter(self.signature, obj) def is_bound(self): return self.signature.is_bound_method() def handle_call(self, args, kwargs, caller_info): if self.forge.is_recording(): returned = self._handle_recorded_call(args, kwargs, caller_info) self.forge.stubs.mark_stub_recorded(self.stub) return returned else: return self._handle_replay_call(args, kwargs, caller_info) def _handle_recorded_call(self, args, kwargs, caller_info): return self.forge.queue.push_call(self.stub, args, kwargs, caller_info) def _handle_replay_call(self, args, kwargs, caller_info): expected_call = self.forge.queue.pop_matching_call(self.stub, args, kwargs, caller_info) return_value = expected_call.get_return_value() self._increment_call_count() #might raise... expected_call.do_side_effects(args, kwargs) return return_value def _increment_call_count(self): if self._call_count_session_id != self.forge.session_id: self._call_count_session_id = self.forge.session_id self._call_count = 0 self._call_count += 1 def has_recorded_calls(self): return self.forge.stubs.was_stub_recorded(self.stub) python-pyforge-1.3.0/forge/stub_manager.py000066400000000000000000000016051301315602600206270ustar00rootroot00000000000000from collections import defaultdict class StubManager(object): def __init__(self, forge): super(StubManager, self).__init__() self._initialized_method_stubs = defaultdict(dict) self._recorded_method_stubs = set() def get_initialized_method_stub_or_none(self, mock, method_name): return self._initialized_method_stubs[mock.__forge__.id].get(method_name, None) def add_initialized_method_stub(self, mock, method_name, method): self._initialized_method_stubs[mock.__forge__.id][method_name] = method def has_initialized_method_stub(self, mock, method_name): return self.get_initialized_method_stub_or_none(mock, method_name) is not None def mark_stub_recorded(self, stub): self._recorded_method_stubs.add(stub.__forge__.id) def was_stub_recorded(self, stub): return stub.__forge__.id in self._recorded_method_stubs python-pyforge-1.3.0/forge/utils.py000066400000000000000000000016401301315602600173170ustar00rootroot00000000000000from types import * from .python3_compat import xrange, IS_PY3 def renumerate(collection): for index in xrange(len(collection) - 1, -1, -1): yield (index, collection[index]) ### object predicates def is_bound_method(obj): return isinstance(obj, MethodType) and obj.__self__ is not None def is_function(obj): return isinstance(obj, FunctionType) or isinstance(obj, BuiltinFunctionType) def is_class(obj): return isinstance(obj, type) or (not IS_PY3 and isinstance(obj, ClassType)) def is_class_method(obj): if not is_bound_method(obj): return False return is_class(obj.__self__) ### some useful shortcuts class EXPECTING(object): def __init__(self, mock): self.mock = mock def __setattr__(self, attr, value): if attr == 'mock': super(EXPECTING, self).__setattr__(attr, value) else: self.mock.__forge__.expect_setattr(attr, value) python-pyforge-1.3.0/forge/wildcard_mock_handle.py000066400000000000000000000023271301315602600222770ustar00rootroot00000000000000from .mock_handle import MockHandle from .constants import WILDCARD_DESCRIPTION from .dtypes import WILDCARD_FUNCTION class WildcardMockHandle(MockHandle): def __init__(self, forge, mock, name=None): super(WildcardMockHandle, self).__init__(forge, mock) self.__name__ = name def _has_method(self, name): return True def _describe(self): if self.__name__: return "<>" % self.__name__ else: return WILDCARD_DESCRIPTION def _get_real_method(self, name): return WILDCARD_FUNCTION def _construct_stub(self, name, real_method): return self.forge.create_method_stub(real_method, name=name) def _check_unrecorded_method_getting(self, name): self._raise_attribute_error(name) def _check_getting_method_stub_without_recorded_calls(self, name, stub): self._raise_attribute_error(name) def _raise_attribute_error(self, name): raise AttributeError("%s has no attribute %s" % (self.mock, name)) def has_nonmethod_class_member(self, name): return False def _check_special_method_call(self, *_, **__): pass def _is_binding_needed(self, name, stub): return False, None python-pyforge-1.3.0/forge/wildcard_mock_object.py000066400000000000000000000005421301315602600223070ustar00rootroot00000000000000from .mock_object import MockObject from .wildcard_mock_handle import WildcardMockHandle class WildcardMockObject(MockObject): def __init__(self, forge, name=None): super(WildcardMockObject, self).__init__() self.__forge__ = WildcardMockHandle(forge, self, name=name) def __repr__(self): return self.__forge__.describe() python-pyforge-1.3.0/setup.py000066400000000000000000000023161301315602600162160ustar00rootroot00000000000000import os import platform from setuptools import setup, find_packages with open(os.path.join(os.path.dirname(__file__), "forge", "__version__.py")) as version_file: exec(version_file.read()) _INSTALL_REQUIREMENTS = ['sentinels>=0.0.4'] if platform.python_version_tuple() < ('2', '7'): _INSTALL_REQUIREMENTS.append('unittest2') setup(name="pyforge", classifiers = [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Software Development :: Testing", ], description="Python mocking framework", license="BSD", author="Rotem Yaari", author_email="vmalloc@gmail.com", url="http://github.com/vmalloc/pyforge", version=__version__, install_requires=_INSTALL_REQUIREMENTS, packages=find_packages(exclude=["tests"]) ) python-pyforge-1.3.0/tests/000077500000000000000000000000001301315602600156445ustar00rootroot00000000000000python-pyforge-1.3.0/tests/__init__.py000066400000000000000000000000001301315602600177430ustar00rootroot00000000000000python-pyforge-1.3.0/tests/test__actions.py000066400000000000000000000061121301315602600210540ustar00rootroot00000000000000from .ut_utils import ForgeTestCase from .ut_utils import Checkpoint from forge import ConflictingActions from sentinels import NOTHING class ActionsTest(ForgeTestCase): def setUp(self): super(ActionsTest, self).setUp() self.stub = self.forge.create_function_stub(lambda *args, **kwargs: None) def test__return_value(self): rv = self.stub(1, 2, 3).and_return(666) self.assertEquals(rv, 666) self.forge.replay() self.assertEquals(666, self.stub(1, 2, 3)) self.assertNoMoreCalls() self.forge.verify() def test__raised_exception(self): raised = Exception() rv = self.stub(1, 2, 3).and_raise(raised) self.assertIs(rv, raised) self.forge.replay() with self.assertRaises(Exception) as caught: self.stub(1, 2, 3) self.assertIs(caught.exception, raised) self.assertNoMoreCalls() self.forge.verify() def test__conflicting_actions(self): expected_call = self.stub(1, 2, 3) expected_call.and_return(2) with self.assertRaises(ConflictingActions): expected_call.and_raise(Exception()) #conflict should not affect existing expectations self.assertEquals(expected_call._return_value, 2) self.assertIs(expected_call._raised_exception, NOTHING) expected_call = self.stub(1, 2, 3) exc = Exception() expected_call.and_raise(exc) with self.assertRaises(ConflictingActions): expected_call.and_return(2) #conflict should not affect existing expectations self.assertIs(expected_call._return_value, NOTHING) self.assertIs(expected_call._raised_exception, exc) self.forge.reset() def test__and_call(self): return_value = 666 cp = Checkpoint() rv = self.stub(1, 2, 3).and_call(cp.trigger).and_return(return_value) self.assertEquals(rv, return_value) self.forge.replay() rv = self.stub(1, 2, 3) self.assertEquals(rv, return_value) self.assertTrue(cp.called) def test__and_call__specify_args_kwargs(self): return_value = 666 cp = Checkpoint() def callback(a, b, c, d): self.assertEquals((a, b, c, d), (1, 2, 3, 4)) cp.trigger() rv = self.stub(1, 2, 3).and_call(callback, args=(1, 2, 3), kwargs=dict(d=4)).and_return(return_value) self.assertEquals(rv, return_value) self.forge.replay() rv = self.stub(1, 2, 3) self.assertEquals(rv, return_value) self.assertTrue(cp.called) def test__and_call_with_args(self): return_value = 666 cp = Checkpoint() def trigger(*args, **kwargs): self.assertEquals(args, (1, 2, 3)) self.assertEquals(kwargs, dict(d=4)) cp.trigger() rv = self.stub(1, 2, 3, d=4).and_call_with_args(trigger).and_return(return_value) self.assertEquals(rv, return_value) self.forge.replay() rv = self.stub(1, 2, 3, d=4) self.assertEquals(rv, return_value) self.assertTrue(cp.called) python-pyforge-1.3.0/tests/test__calling_mock_instance_methods.py000066400000000000000000000046651301315602600254600ustar00rootroot00000000000000import functools from .ut_utils import ForgeTestCase from .ut_utils import Method, ClassMethod, StaticMethod from .ut_utils import build_old_style_class from .ut_utils import build_new_style_class from .ut_utils import resets_forge_at_end from forge import SignatureException METHODS = [ Method('method(self, a, b, c)'), ClassMethod('class_method(cls, a, b, c)'), StaticMethod('static_method(a, b, c)'), Method('without_self()'), Method('with_varargs_self(*args)'), Method('__len__(self)'), ] MockedNewStyleClass = build_new_style_class(METHODS) MockedOldStyleClass = build_old_style_class(METHODS) def for_each_mock(func): @functools.wraps(func) def newfunc(self, *args, **kwargs): for obj in self.mocks: func(self, obj, *args, **kwargs) return newfunc class MockInstanceMethodTest(ForgeTestCase): def setUp(self): super(MockInstanceMethodTest, self).setUp() self.newstyle_mock = self.forge.create_mock(MockedNewStyleClass) self.oldstyle_mock = self.forge.create_mock(MockedOldStyleClass) self.mocks = [self.newstyle_mock, self.oldstyle_mock] def test__calling_methods(self): self._test__recording_and_calling('method') def test__calling_class_methods(self): self._test__recording_and_calling('class_method') def test__calling_static_methods(self): self._test__recording_and_calling('static_method') def test__calling_methods_with_varargs_self(self): self._test__recording_and_calling('with_varargs_self') def test__calling_method_without_self(self): for mock in self.mocks: with self.assertRaises(SignatureException): mock.without_self() @for_each_mock def test__static_method_signature_checking(self, obj): with self.assertRaises(SignatureException): obj.static_method(1, 2) with self.assertRaises(SignatureException): obj.static_method() @for_each_mock def test__class_method_signature_checking(self, obj): with self.assertRaises(SignatureException): obj.class_method(1, 2, 3, 4) with self.assertRaises(SignatureException): obj.class_method() @for_each_mock @resets_forge_at_end def _test__recording_and_calling(self, obj, method_name): method = getattr(obj, method_name) method(1, 2, 3) self.forge.replay() method(1, 2, 3) self.forge.verify() python-pyforge-1.3.0/tests/test__class_mocks.py000066400000000000000000000144511301315602600217220ustar00rootroot00000000000000from .ut_utils import * from forge import SignatureException METHODS = [ ClassMethod('class_method(cls, a, b, c, d=5)'), StaticMethod('static_method(a, b, c, d=5)'), Method('regular_method(self, a, b, c, d=5)'), ] class _ClassMockTest(ForgeTestCase): def setUp(self): super(_ClassMockTest, self).setUp() factory = self._get_class_factory() methods = self._get_methods() self.mocked_class = factory(methods) self.mock = self.forge.create_class_mock(self.mocked_class) def tearDown(self): self.forge.verify() self.assertNoMoreCalls() super(_ClassMockTest, self).tearDown() class _OldStyleTest(object): def _get_class_factory(self): return build_old_style_class class _NewStyleTest(object): def _get_class_factory(Self): return build_new_style_class class _BasicClassMockTest(_ClassMockTest): def _get_methods(self): return METHODS def test__isinstance(self): self.assertFalse(isinstance(self.mock, self.mocked_class)) self.assertTrue(isinstance(self.mock, type(self.mocked_class))) def test__class_methods_can_be_called(self): self.mock.class_method(1, 2, 3) self.forge.replay() self.mock.class_method(1, 2, 3) def test__static_methods_can_be_called(self): self.mock.static_method(1, 2, 3) self.forge.replay() self.mock.static_method(1, 2, 3) def test__class_and_static_methods_signature_checks(self): for meth in (self.mock.class_method, self.mock.static_method): with self.assertRaises(SignatureException): meth() with self.assertRaises(SignatureException): meth(1, 2, 3, 4, 5) with self.assertRaises(SignatureException): meth(1, 2, 3, e=5) def test__regular_methods_calling(self): fake_self = object() with self.assertRaises(SignatureException): self.mock.regular_method(1, 2, 3) self.mock.regular_method(fake_self, 1, 2, 3) self.mock.regular_method(fake_self, 1, 2, 3, d=19) self.forge.replay() self.mock.regular_method(fake_self, 1, 2, 3) self.mock.regular_method(fake_self, 1, 2, 3, d=19) def test__regular_methods_calling_signature_check(self): with self.assertRaises(SignatureException): self.mock.regular_method(1, 2, 3) with self.assertRaises(SignatureException): self.mock.regular_method() with self.assertRaises(SignatureException): self.mock.regular_method(1, 2) with self.assertRaises(SignatureException): self.mock.regular_method(d=10) class OldStyleBasicTest(_BasicClassMockTest, _OldStyleTest): pass class NewStyleBasicTest(_BasicClassMockTest, _NewStyleTest): pass class ClassMockConstructionTest(ForgeTestCase): def tearDown(self): self.forge.verify() self.assertNoMoreCalls() super(ClassMockConstructionTest, self).tearDown() def test__empty_constructor_new_style(self): class MyClass(object): def __init__(self): pass self._test__empty_construction(MyClass) def test__empty_constructor_old_style(self): class MyClass: def __init__(self): pass self._test__empty_construction(MyClass) def test__no_constructor_new_style(self): class MyClass(object): pass self._test__empty_construction(MyClass) def test__no_constructor_old_style(self): class MyClass: pass self._test__empty_construction(MyClass) def _test__empty_construction(self, cls): mock = self.forge.create_class_mock(cls) with self.assertRaises(SignatureException): mock(1, 2, 3) with self.assertRaises(SignatureException): mock(1) result = self.forge.create_mock(cls) mock().and_return(result) self.forge.replay() self.assertIs(result, mock()) def test__construction_new_style(self): class MyClass(object): def __init__(self, a, b, c, d=4): pass self._test__construction(MyClass) def test__construction_old_style(self): class MyClass: def __init__(self, a, b, c, d=4): pass self._test__construction(MyClass) def test__construction_inheritence_new_style(self): class MyClass(object): def __init__(self, a, b, c, d=4): pass class MyClass2(MyClass): pass self._test__construction(MyClass2) def test__construction_inheritence_old_style(self): class MyClass: def __init__(self, a, b, c, d=4): pass class MyClass2(MyClass): pass self._test__construction(MyClass2) def test__construction_with_call_operator_new_style(self): class MyClass(object): def __init__(self, a, b, c, d=4): pass def __call__(self, a, b): pass self._test__construction(MyClass) def test__construction_with_call_operator_old_style(self): class MyClass: def __init__(self, a, b, c, d=4): pass def __call__(self, a, b): pass self._test__construction(MyClass) def _test__construction(self, cls): mock = self.forge.create_class_mock(cls) with self.assertRaises(SignatureException): mock() with self.assertRaises(SignatureException): mock(1, 2) with self.assertRaises(SignatureException): mock(1, e=100) result_1 = self.forge.create_mock(cls) mock(1, 2, 3).and_return(result_1) result_2 = self.forge.create_mock(cls) mock(1, 2, 3, 4).and_return(result_2) self.forge.replay() self.assertIs(result_1, mock(1, 2, 3)) self.assertIs(result_2, mock(1, 2, 3, 4)) def test__construction_only_kwarg(self): class MyClass(object): def __init__(self, a=None, b=None, c=None): pass mock = self.forge.create_class_mock(MyClass) expected = self.forge.create_mock(MyClass) mock(b=2).and_return(expected) self.forge.replay() returned = mock(b=2) self.assertIs(returned, expected) python-pyforge-1.3.0/tests/test__comparators.py000066400000000000000000000143341301315602600217530ustar00rootroot00000000000000import itertools import re from .ut_utils import TestCase, BinaryObjectClass from forge.comparators import * from forge.python3_compat import IS_PY3, basestring class Compared(object): def __eq__(self): raise NotImplementedError() def __ne__(self): raise NotImplementedError() class _ComparatorTest(TestCase): def test__valid_equality(self): for a, b in self._get_equal_pairs(): self.assertTrue(a == b) def test__invalid_equality(self): for a, b in self._get_unequal_pairs(): self.assertFalse(a == b) def test__valid_inequality(self): for a, b in self._get_unequal_pairs(): self.assertTrue(a != b) def test__invalid_inequality(self): for a, b in self._get_equal_pairs(): self.assertFalse(a != b) def test__representation(self): for a, _ in itertools.chain(self._get_equal_pairs(), self._get_unequal_pairs()): self.assertIsInstance(a, Comparator) self.assertIsInstance(str(a), basestring) self.assertEquals(str(a), repr(a)) class IsTest(_ComparatorTest): def _get_equal_pairs(self): c = Compared() yield Is(c), c def _get_unequal_pairs(self): c = Compared() yield Is(c), Compared() yield Is(c), 2 class IsATest(_ComparatorTest): def _get_equal_pairs(self): c = Compared() yield IsA(Compared), c yield IsA(basestring), "hey" yield IsA(type(BinaryObjectClass())), BinaryObjectClass() def _get_unequal_pairs(self): yield IsA(Compared), "hey" yield IsA(basestring), Compared() yield IsA(type(BinaryObjectClass())), object() yield IsA(BinaryObjectClass), BinaryObjectClass yield IsA(BinaryObjectClass()), BinaryObjectClass() class RegexpMatchesTest(_ComparatorTest): def _get_equal_pairs(self): yield RegexpMatches(".+"), "hey" yield RegexpMatches(r"hey \S+"), "hey there" yield RegexpMatches(r"hello", re.I), "hEllO" def _get_unequal_pairs(self): yield RegexpMatches(r"hello \S+"), "hey there" yield RegexpMatches(r"hello"), 2 class FuncTest(_ComparatorTest): def _get_equal_pairs(self): obj = object() yield Func(lambda o: o is obj), obj yield Func(lambda o: True), None def _get_unequal_pairs(self): obj = object() for other in (None, 2, "hello"): yield Func(lambda o: o is obj), other yield Func(lambda o: False), "hello" class IsAlmostTest(_ComparatorTest): def _get_equal_pairs(self): yield IsAlmost(3, 3), 3.0002 yield IsAlmost(3), 3.00000002 def _get_unequal_pairs(self): yield IsAlmost(3, 3), 3.02 yield IsAlmost(3), 3.02 yield IsAlmost(3), "hey" class ContainsTest(_ComparatorTest): def _get_equal_pairs(self): yield Contains("a"), "laugh" yield Contains("bl"), "able" yield Contains(2), [1, 2, 3] yield Contains("hey"), ["hey", "there"] yield Contains("a", "b"), "abcdefg" yield Contains("a", "b"), ["a", "b"] def _get_unequal_pairs(self): yield Contains("a"), "hello" yield Contains("bla"), object() yield Contains(2), [1, 3, 5] yield Contains("hey"), ["hello", "world"] yield Contains("a", "b"), "a" yield Contains("a", "b"), "b" yield Contains("a", "b", "d"), ["a", "b"] class StrContainsTest(_ComparatorTest): def _get_equal_pairs(self): yield StrContains("a"), "laugh" yield StrContains("bl"), "able" yield StrContains("a", "b"), "able" def _get_unequal_pairs(self): yield StrContains("hey"), ["hey", "there"] yield StrContains("a"), "hello" yield StrContains("bla"), object() yield StrContains(2), [1, 2, 3] yield StrContains(2), [1, 3, 5] yield StrContains("hey"), ["hello", "world"] yield StrContains("a", "b"), "a" yield StrContains("a", "b"), ["a", "b"] class HasKeyValueTest(_ComparatorTest): def _get_equal_pairs(self): yield HasKeyValue('a', 1), dict(a=1, b=2) yield HasKeyValue(1, 2), [0, 2, 0, 0] def _get_unequal_pairs(self): yield HasKeyValue('a', 1), {} yield HasKeyValue('a', 1), dict(a=2) yield HasKeyValue('a', 1), [] yield HasKeyValue('a', 1), object() yield HasKeyValue(0, 1), [0, 0, 0] class HasAttributeValueTest(_ComparatorTest): class Object(object): a = 2 b = 3 def _get_equal_pairs(self): Object = self.Object yield HasAttributeValue('a', 2), Object yield HasAttributeValue('b', 3), Object() def _get_unequal_pairs(self): Object = self.Object for obj in (Object, Object()): yield HasAttributeValue('a', 3), obj yield HasAttributeValue('bla', 2), Object() yield HasAttributeValue('bloop', 2), dict(bloop=2) class AnythingTest(_ComparatorTest): def _get_equal_pairs(self): yield Anything(), object yield Anything(), object() yield Anything(), 2 yield Anything(), "bla" yield Anything(), Anything() def _get_unequal_pairs(self): return () class AndTest(_ComparatorTest): def _get_equal_pairs(self): yield And(IsA(basestring), Contains('a')), "Boa" yield And(IsA(basestring), Contains('a'), Contains('g')), "Bga" yield And(IsA(int)), 2 def _get_unequal_pairs(self): yield And(IsA(basestring), Contains('a')), 2 yield And(IsA(basestring), Contains('a'), Contains('g')), "Boa" yield And(IsA(int)), "a" def test__empty_and(self): with self.assertRaises(TypeError): And() class OrTest(_ComparatorTest): def _get_equal_pairs(self): yield Or(IsA(basestring), IsA(int)), "a" yield Or(Anything(), IsA(basestring)), 2 yield Or(IsA(basestring), Anything()), 2 def _get_unequal_pairs(self): yield Or(IsA(basestring), IsA(int)), 2.0 def test__empty_or(self): with self.assertRaises(TypeError): Or() class NotTest(_ComparatorTest): def _get_equal_pairs(self): yield Not(IsA(int)), "a" def _get_unequal_pairs(self): yield Not(Anything()), 2 yield Not(Anything()), object() python-pyforge-1.3.0/tests/test__context_managers.py000066400000000000000000000072751301315602600227700ustar00rootroot00000000000000import types from .ut_utils import ForgeTestCase from forge import UnexpectedCall from forge import UnexpectedSetattr from forge.python3_compat import IS_PY3 class ContextManager(object): def __enter__(self): raise NotImplementedError() def __exit__(self, t, v, tb): raise NotImplementedError() class ContextManagerTest(ForgeTestCase): def setUp(self): super(ContextManagerTest, self).setUp() self.obj = self.forge.create_mock(ContextManager) self.checkpoint = self.forge.create_function_stub(lambda: None) def tearDown(self): self.assertTrue(self.forge.queue.is_empty()) self.forge.verify() super(ContextManagerTest, self).tearDown() def test__expecting_context(self): with self.obj: self.checkpoint() self.forge.replay() with self.obj: self.checkpoint() def test__expecting_context_with_exception_inside(self): with self.obj: self.checkpoint() my_exception = Exception() self.forge.replay() with self.assertRaises(UnexpectedCall) as caught: with self.obj: raise my_exception caught = caught.exception self.assertEquals(len(caught.expected), 1) self.assertIs(caught.expected[0].target, self.checkpoint) self.assertIsSameMethod(caught.got.target.__forge__.original, ContextManager.__exit__) self.assertIs(caught.got.args['t'], Exception) self.assertIs(caught.got.args['v'], my_exception) self.assertIsNotNone(caught.got.args['tb']) self.assertEquals(len(self.forge.queue), 2) self.forge.reset() def test__expecting_context_with_unexpected_call_inside(self): stub = self.forge.create_function_stub(lambda arg: None) with self.obj: stub(1) self.forge.replay() with self.assertRaises(UnexpectedCall) as caught: with self.obj: stub(2) caught = caught.exception self.assertEquals(len(caught.expected), 1) self.assertIs(caught.expected[0].target, stub) self.assertIs(caught.got.target, stub) self.assertIs(caught.expected[0].args['arg'], 1) self.assertIs(caught.got.args['arg'], 2) self.assertEquals(len(self.forge.queue), 2) self.forge.reset() def test__expecting_context_with_unexpected_setattr_inside(self): with self.obj: pass self.forge.replay() with self.assertRaises(UnexpectedSetattr) as caught: with self.obj: self.obj.a = 2 caught = caught.exception self.assertEquals(len(caught.expected), 1) self.assertIs(caught.expected[0].target, self.obj.__forge__.get_attribute('__exit__')) self.assertEquals(len(caught.expected[0].args), 3) self.assertTrue(all(x is None for x in caught.expected[0].args.values())) self.assertIs(caught.got.target, self.obj) self.assertEquals(caught.got.name, 'a') self.assertEquals(caught.got.value, 2) self.assertEquals(len(self.forge.queue), 1) self.forge.reset() def test__enter_returning_value(self): self.obj.__enter__().and_return(2) self.checkpoint() self.obj.__exit__(None, None, None) self.forge.replay() with self.obj as value: self.checkpoint() self.assertEquals(value, 2) def assertIsSameMethod(self, a, b): if IS_PY3: if not isinstance(a, types.FunctionType): a = a.__func__ if not isinstance(b, types.FunctionType): b = b.__func__ return a is b return a.__func__ is b.__func__ python-pyforge-1.3.0/tests/test__create_mock_with_attrs.py000066400000000000000000000016671301315602600241520ustar00rootroot00000000000000from .ut_utils import ForgeTestCase from forge.class_mock import ClassMockObject class A(object): pass class B(object): pass class C: pass class D(object): pass class E(object): pass class AttrMockTest(ForgeTestCase): def test__create_mock_with_attrs(self): M = self.forge.create_mock_with_attrs result = M(A, b=M(B, c=M(C, d=M(D)), e=M(E), ) ) self.assertIsInstanceMockOf(result, A) self.assertIsInstanceMockOf(result.b, B) self.assertIsInstanceMockOf(result.b.c, C) self.assertIsInstanceMockOf(result.b.c.d, D) self.assertIsInstanceMockOf(result.b.e, E) def assertIsInstanceMockOf(self, obj, cls): self.assertIsInstance(obj, ClassMockObject) self.assertTrue(obj.__forge__.behaves_as_instance) self.assertIs(obj.__forge__.mocked_class, cls) python-pyforge-1.3.0/tests/test__error_readability.py000066400000000000000000000134771301315602600231320ustar00rootroot00000000000000import sys from difflib import Differ from types import ModuleType from contextlib import contextmanager from .ut_utils import ForgeTestCase from forge import UnexpectedCall, UnexpectedSetattr class ErrorClarityTest(ForgeTestCase): pass from forge.exceptions import UNEXPECTED_FUNCTION_CALLED_STR from forge.exceptions import UNEXPECTED_SETATTR_STR from forge.exceptions import DIFF_DESCRIPTION_STR class ErrorsInRegularStubs(ForgeTestCase): def setUp(self): super(ErrorsInRegularStubs, self).setUp() def some_function(a, b, c): raise NotImplementedError() self.stub = self.forge.create_function_stub(some_function) class SomeClass(object): def method(self, a, b, c): raise NotImplementedError() def __call__(self, a, b, c): raise NotImplementedError() @classmethod def class_method(cls, a, b, c): raise NotImplementedError() self.mock = self.forge.create_mock(SomeClass) self.obj = SomeClass() self.forge.replace(self.obj, "method") self.class_mock = self.forge.create_class_mock(SomeClass) def tearDown(self): # ForgeTestCase makes sure no more calls are active etc.... self.forge.reset() super(ErrorsInRegularStubs, self).tearDown() def test__function_error_clarity(self): self.stub(1, 2, 3) self.forge.replay() with self.assertUnexpectedCommonCase('some_function'): self.stub(1, 2, 4) def test__function_error_clarity_no_expected(self): self.forge.replay() with self.assertUnexpectedEvent("<< None >>", "some_function(a=1, b=2, c=4)"): self.stub(1, 2, 4) def test__method_clarity(self): self.mock.method(1, 2, 3) self.forge.replay() with self.assertUnexpectedCommonCase(".method"): self.mock.method(1, 2, 4) def test__method_of_object_with_different_name_for_self(self): class SomeClass(object): def method(not_self, a, b, c): raise NotImplementedError() mock = self.forge.create_mock(SomeClass) mock.method(1, 2, 3) self.forge.replay() with self.assertUnexpectedCommonCase(".method"): mock.method(1, 2, 4) def test__class_method_clarity(self): self.mock.class_method(1, 2, 3) self.forge.replay() with self.assertUnexpectedCommonCase(".class_method"): self.mock.class_method(1, 2, 4) def test__object_calling_clarity(self): self.mock(1, 2, 3) self.forge.replay() with self.assertUnexpectedCommonCase(".__call__"): self.mock(1, 2, 4) def test__replaced_method_clarity(self): self.obj.method(1, 2, 3) self.forge.replay() with self.assertUnexpectedCommonCase('.method'): self.obj.method(1, 2, 4) def test__replaced_module_clarity(self): module_name = 'some_module_name' module = ModuleType(module_name) def f(a, b, c): raise NotImplementedError() module.f = f self.forge.replace(module, 'f') module.f(1, 2, 3) self.forge.replay() with self.assertUnexpectedCommonCase('%s.f' % module_name): module.f(1, 2, 4) def test__debug_info(self): self.forge.debug.enable() record_lineno = self._get_lineno() + 1 self.stub(1, 2, 3) self.forge.replay() file_name = __file__ if file_name.endswith(".pyc"): file_name = file_name[:-1] replay_lineno = self._get_lineno() + 5 prologue = "Recorded from %s:%s::test__debug_info" % (file_name, record_lineno) prologue += "\nReplayed from %s:%s::test__debug_info" % (file_name, replay_lineno) with self.assertUnexpectedCommonCase('some_function', prologue=prologue): self.stub(1, 2, 4) def _get_lineno(self): return sys._getframe(1).f_lineno def test__setattr_clarity(self): self.mock.__forge__.expect_setattr('a', 2) self.forge.replay() with self.assertUnexpectedEvent("setattr(%s, 'a', 2)" % self.mock, "setattr(%s, 'a', 3)" % self.mock, message=UNEXPECTED_SETATTR_STR, cls=UnexpectedSetattr): self.mock.a = 3 def test__identical_expectations_clarity(self): wc1 = self.forge.create_wildcard_function_stub() wc2 = self.forge.create_wildcard_function_stub() wc1() self.forge.replay() with self.assertRaises(UnexpectedCall) as caught: wc2() self.assertMultiLineEqual(str(caught.exception), """%s %s - <>() + <>()""" % (UNEXPECTED_FUNCTION_CALLED_STR, DIFF_DESCRIPTION_STR)) def assertUnexpectedCommonCase(self, function_name, prologue=None): return self.assertUnexpectedEvent('%s(a=1, b=2, c=3)' % function_name, '%s(a=1, b=2, c=4)' % function_name, prologue=prologue) @contextmanager def assertUnexpectedEvent(self, expected, found, prologue=None, cls=UnexpectedCall, message=UNEXPECTED_FUNCTION_CALLED_STR): diff_str = "%s %s\n" % (message, DIFF_DESCRIPTION_STR) if prologue: diff_str += prologue diff_str += "\n" diff_str += "\n".join(map(str.strip, Differ().compare([found], [expected]))) with self.assertRaises(cls) as caught: yield None self.assertMultiLineEqual(str(caught.exception), diff_str) python-pyforge-1.3.0/tests/test__forge.py000066400000000000000000000035251301315602600205230ustar00rootroot00000000000000from .ut_utils import TestCase from .ut_utils import Checkpoint from forge import Forge from forge.exceptions import ExpectedEventsNotFound class ForgeTest(TestCase): def setUp(self): super(ForgeTest, self).setUp() self.forge = Forge() def assertRecording(self): self.assertFalse(self.forge.is_replaying()) self.assertTrue(self.forge.is_recording()) def assertReplaying(self): self.assertTrue(self.forge.is_replaying()) self.assertFalse(self.forge.is_recording()) def test__replaying(self): self.assertRecording() self.forge.replay() self.assertReplaying() self.forge.verify() self.assertReplaying() def test__reset(self): self.test__replaying() self.forge.queue._queue = [1, 2, 3, 4] self.forge.reset() self.assertRecording() self.assertTrue(self.forge.queue.is_empty()) def test__verified_replay_context(self): self.assertRecording() check_verify = Checkpoint() check_reset = Checkpoint() self.forge.verify = check_verify.trigger def _fake_reset(): self.assertTrue(check_verify.called) check_reset.trigger() self.forge.reset = _fake_reset with self.forge.verified_replay_context(): self.assertReplaying() self.assertFalse(check_verify.called) self.assertFalse(check_reset.called) self.assertTrue(check_reset.called) self.assertTrue(check_verify.called) # we don't assertRecording, since we stubbed out reset def test__verified_replay_context_checks_no_more_calls(self): expected_call = self.forge.create_wildcard_function_stub()(1, 2, 3) with self.assertRaises(ExpectedEventsNotFound): with self.forge.verified_replay_context(): pass python-pyforge-1.3.0/tests/test__forge_debug.py000066400000000000000000000017751301315602600216760ustar00rootroot00000000000000import os from .ut_utils import TestCase from forge import Forge from forge.caller_info import CallerInfo class ForgeDebugTest(TestCase): def assertDebugOff(self, forge): self.assertFalse(forge.debug.is_enabled()) self.assertIsNone(forge.debug.get_caller_info()) def assertDebugOn(self, forge): self.assertTrue(forge.debug.is_enabled()) self.assertIsInstance(forge.debug.get_caller_info(), CallerInfo) def test__debug_states(self): f = Forge() self.assertDebugOff(f) f.debug.enable() self.assertDebugOn(f) f.debug.disable() self.assertDebugOff(f) def test__debug_disable_enable(self): prev_value = os.environ.get('FORGE_DEBUG', None) os.environ['FORGE_DEBUG'] = "1" try: f = Forge() self.assertDebugOn(f) finally: if prev_value is None: os.environ.pop('FORGE_DEBUG') else: os.environ['FORGE_DEBUG'] = prev_value python-pyforge-1.3.0/tests/test__function_stubs.py000066400000000000000000000044231301315602600224640ustar00rootroot00000000000000from numbers import Number from .ut_utils import ForgeTestCase from forge.stub import FunctionStub from forge.stub_handle import StubHandle from forge.python3_compat import IS_PY3 if IS_PY3: from urllib.request import urlopen else: from urllib2 import urlopen def some_function(): "some doc" raise NotImplementedError() class FunctionStubbingTest(ForgeTestCase): def test__stubbing_urlopen(self): # known bug in python 3 urlopen_stub = self.forge.create_function_stub(urlopen) urlopen_stub("url").and_return(666) self.forge.replay() self.assertEquals(urlopen_stub("url"), 666) class FunctionStubAttributesTest(ForgeTestCase): def setUp(self): super(FunctionStubAttributesTest, self).setUp() self.stub = self.forge.create_function_stub(some_function) def test__name(self): self.assertEquals(self.stub.__name__, some_function.__name__) def test__specific_name(self): stub = self.forge.create_function_stub(some_function, name='other_name') self.assertEquals(stub.__name__, 'other_name') def test__doc(self): self.assertEquals(self.stub.__doc__, some_function.__doc__) def test__stub_id(self): self.assertIsInstance(self.stub.__forge__.id, Number) def test__str_repr(self): self.assertIn('some_function', str(self.stub)) self.assertIn('some_function', repr(self.stub)) def test__forge_handle(self): stub = FunctionStub(self.forge, some_function) self.assertIs(stub.__forge__.original, some_function) self.assertIs(stub.__forge__.signature.func, some_function) self.assertIsInstance(stub.__forge__, StubHandle) self.assertIs(stub.__forge__.stub, stub) self.assertIs(stub.__forge__.forge, self.forge) def test__stub_record_marker(self): stub = FunctionStub(self.forge, some_function) self.assertFalse(stub.__forge__.has_recorded_calls()) stub() self.assertTrue(stub.__forge__.has_recorded_calls()) self.forge.replay() stub() self.assertTrue(stub.__forge__.has_recorded_calls()) self.forge.verify() self.assertTrue(stub.__forge__.has_recorded_calls()) self.forge.reset() self.assertFalse(stub.__forge__.has_recorded_calls()) python-pyforge-1.3.0/tests/test__hybrid_mock.py000066400000000000000000000054741301315602600217200ustar00rootroot00000000000000from .ut_utils import ForgeTestCase from forge import InvalidEntryPoint class TestedClass(object): def entry_point(self): self.f() self.g(1, 2, 3) self.h(a=1, b=2) self.class_method() self.static_method() def set_value(self): self.value = 2 def f(self): raise NotImplementedError() @classmethod def class_method(self): pass @staticmethod def static_method(): pass def g(self, a, b, c): raise NotImplementedError() def h(self, a, b): raise NotImplementedError() @classmethod def class_method_entry_point(cls): return cls @staticmethod def static_method_entry_point(arg): pass class HybridMockTest(ForgeTestCase): def tearDown(self): self.forge.verify() self.assertNoMoreCalls() super(HybridMockTest, self).tearDown() def test__hybrid_mock(self): hm = self.forge.create_hybrid_mock(TestedClass) # these will be stubbed hm.f() hm.g(1, 2, 3) hm.h(1, 2) hm.class_method() hm.static_method() self.forge.replay() hm.entry_point() self.forge.verify() def test__can_call_class_methods(self): hm = self.forge.create_hybrid_mock(TestedClass) self.forge.replay() rv = hm.class_method_entry_point() # the 'cls' argument should be the class itself self.assertIs(rv, TestedClass) def test__can_call_class_methods_on_class_mocks(self): hm = self.forge.create_hybrid_class_mock(TestedClass) self.forge.replay() rv = hm.class_method_entry_point() # for class mocks, the 'cls' argument should be the mock! self.assertIs(rv, hm) def test__cannot_call_static_methods(self): hm = self.forge.create_hybrid_mock(TestedClass) self.forge.replay() with self.assertRaises(InvalidEntryPoint): hm.static_method_entry_point() def test__hybrid_mocks_setting_values(self): hm = self.forge.create_hybrid_mock(TestedClass) hm.__forge__.enable_setattr_during_replay() self.forge.replay() hm.set_value() self.assertEquals(hm.value, 2) class ClassWithClassmethodConstructor(object): def __init__(self, a, b, c): pass @classmethod def constructor(cls, a, b, c): return cls(a, b, c) class HybridClassMockTest(ForgeTestCase): def setUp(self): super(HybridClassMockTest, self).setUp() self.mock = self.forge.create_hybrid_class_mock(ClassWithClassmethodConstructor) def test__expecting_construction(self): expected = self.mock(1, 2, 3).and_return(self.forge.create_mock(ClassWithClassmethodConstructor)) self.forge.replay() got = self.mock.constructor(1, 2, 3) self.assertIs(expected, got) python-pyforge-1.3.0/tests/test__interleaved.py000066400000000000000000000041461301315602600217230ustar00rootroot00000000000000import random from .ut_utils import ForgeTestCase from forge.exceptions import UnexpectedCall class Obj(object): def f(self, a, b, c): raise NotImplementedError() # pragma: no cover def g(self, value): raise NotImplementedError() # pragma: no cover class InterleavedTest(ForgeTestCase): def setUp(self): super(InterleavedTest, self).setUp() # make tests deterministic and reproducible... random.seed(0) self.obj = self.forge.create_mock(Obj) def test__interleaved__single_collection(self): with self.forge.interleaved_order(): self.obj.f(1, 2, 3).and_return(2) self.obj.f(2, 3, 4).and_return(3) self.forge.replay() self.assertEquals(self.obj.f(1, 2, 3), 2) with self.assertRaises(UnexpectedCall): self.obj.f(1, 2, 4) self.assertEquals(self.obj.f(2, 3, 4), 3) def test__interleaved__two_ordered_nested(self): with self.forge.interleaved_order(): with self.forge.ordered(): self.obj.f(1, 1, 1).and_return(11) self.obj.f(1, 1, 2).and_return(12) self.obj.f(1, 1, 3).and_return(13) with self.forge.ordered(): self.obj.f(1, 2, 1).and_return(21) self.obj.f(1, 2, 2).and_return(22) self.obj.f(1, 2, 3).and_return(23) self.forge.replay() parallels = [ [((1, 1, 1), 11), ((1, 1, 2), 12), ((1, 1, 3), 13)], [((1, 2, 1), 21), ((1, 2, 2), 22), ((1, 2, 3), 23)] ] while parallels: random.shuffle(parallels) thread = parallels[0] if len(thread) > 1: # try to skip one call... with self.assertRaises(UnexpectedCall): self.obj.f(*thread[1][0]) args, ret = thread.pop(0) self.assertEquals(self.obj.f(*args), ret) if not thread: parallels.pop(0) def test__interleaved__zero_context(self): with self.forge.interleaved_order(): pass self.forge.replay() python-pyforge-1.3.0/tests/test__mock_attributes.py000066400000000000000000000116611301315602600226200ustar00rootroot00000000000000from .ut_utils import ForgeTestCase from forge import UnexpectedSetattr from forge import ExpectedEventsNotFound from contextlib import contextmanager class MockedClass(object): class_variable = 2 def some_method(self): pass class MockAttributesTest(ForgeTestCase): def setUp(self): super(MockAttributesTest, self).setUp() self.obj = self.forge.create_mock(MockedClass) def tearDown(self): self.forge.verify() self.assertNoMoreCalls() super(MockAttributesTest, self).tearDown() def test__setting_mock_object_attributes(self): attr_value = self.obj.a = object() self.assertIs(self.obj.a, attr_value) self.forge.replay() self.assertIs(self.obj.a, attr_value) self.forge.reset() self.assertEquals(self.obj.a, attr_value) def test__setting_mock_object_attributes_during_replay(self): self.forge.replay() with self.assertUnexpectedSetattr(self.obj, "a", 2): self.obj.a = 2 with self.assertRaises(AttributeError): self.obj.a self.forge.reset() with self.assertRaises(AttributeError): self.obj.a def test__setting_mock_object_attributes_during_replay_enabled_explicitly(self): self.obj.__forge__.enable_setattr_during_replay() self.forge.replay() self.obj.a = 2 self.assertEquals(self.obj.a, 2) self.forge.reset() with self.assertRaises(AttributeError): self.obj.a def test__setting_mock_object_attributes_during_replay_enabled_explicitly_and_disabled_again(self): self.obj.__forge__.enable_setattr_during_replay() self.obj.__forge__.disable_setattr_during_replay() self.test__setting_mock_object_attributes_during_replay() def test__setting_mock_object_attributes_during_replay_even_if_set_during_record(self): self.obj.a = 2 self.forge.replay() with self.assertUnexpectedSetattr(self.obj, "a", 2): self.obj.a = 2 with self.assertUnexpectedSetattr(self.obj, "a", 3): self.obj.a = 3 self.assertNoMoreCalls() self.assertEquals(self.obj.a, 2) self.forge.reset() self.assertEquals(self.obj.a, 2) def test__getattr_of_nonexisting_attr_during_replay(self): self.forge.replay() with self.assertRaises(AttributeError): self.obj.nonexisting_attr with self.assertRaises(AttributeError): # a private case of the above, just making a point self.obj.nonexisting_method() def test__getattr_of_real_methods_during_replay(self): self.forge.replay() self.obj.some_method def test__getattr_of_class_variables_during_record(self): self.assertEquals(self.obj.class_variable, MockedClass.class_variable) def test__getattr_of_class_variables_during_replay(self): self.forge.replay() self.assertEquals(self.obj.class_variable, MockedClass.class_variable) def test__setattr_of_class_variables_during_record(self): self.obj.class_variable = 300 self.assertEquals(self.obj.class_variable, 300) self.forge.replay() self.assertEquals(self.obj.class_variable, 300) def test__setattr_of_class_variables_during_replay(self): self.forge.replay() with self.assertUnexpectedSetattr(self.obj, "class_variable", 300): self.obj.class_variable = 300 def test__expect_setattr(self): self.obj.__forge__.expect_setattr("a", 666) self.forge.replay() with self.assertRaises(AttributeError): self.obj.a self.obj.a = 666 self.assertEquals(self.obj.a, 666) def test__expect_setattr_previous_value(self): self.obj.a = 1 self.assertEquals(self.obj.a, 1) self.obj.__forge__.expect_setattr("a", 2) self.assertEquals(self.obj.a, 1) self.forge.replay() self.assertEquals(self.obj.a, 1) self.obj.a = 2 self.assertEquals(self.obj.a, 2) self.assertNoMoreCalls() self.forge.reset() self.assertEquals(self.obj.a, 1) def test__expect_setattr_not_happening(self): self.obj.__forge__.expect_setattr("a", 666) self.forge.replay() with self.assertRaises(ExpectedEventsNotFound) as caught: self.forge.verify() self.assertEquals(len(caught.exception.events), 1) self.assertIs(caught.exception.events[0].target, self.obj) self.assertEquals(caught.exception.events[0].name, "a") self.assertEquals(caught.exception.events[0].value, 666) self.forge.reset() @contextmanager def assertUnexpectedSetattr(self, target, name, value): with self.assertRaises(UnexpectedSetattr) as caught: yield None exception = caught.exception self.assertIs(exception.got.target, target) self.assertEquals(exception.got.name, name) self.assertEquals(exception.got.value, value) python-pyforge-1.3.0/tests/test__mocking_instances.py000066400000000000000000000070111301315602600231110ustar00rootroot00000000000000from numbers import Number from .ut_utils import ForgeTestCase from forge.mock_handle import MockHandle from forge import SignatureException from forge import MockObjectUnhashable from forge import CannotMockFunctions class MockedClass(object): def some_method(self): raise NotImplementedError() class MockingTest(ForgeTestCase): def setUp(self): super(MockingTest, self).setUp() self.obj = self.forge.create_mock(MockedClass) def test__mock_hashability(self): self._assert_mock_not_hashable(self.obj) self.obj.__forge__.enable_hashing() self.assertEquals(id(self.obj), hash(self.obj)) self.obj.__forge__.disable_hashing() self._assert_mock_not_hashable(self.obj) def _assert_mock_not_hashable(self, obj): with self.assertRaises(MockObjectUnhashable): hash(obj) def test__mock_object_has_mock_handle(self): self.assertIsInstance(self.obj.__forge__, MockHandle) self.assertIs(self.obj.__forge__.forge, self.forge) self.assertIs(self.obj.__forge__.mock, self.obj) self.assertIs(self.obj.__forge__.mocked_class, MockedClass) self.assertIsInstance(self.obj.__forge__.id, Number) def test__class_attribute(self): self.assertIs(self.obj.__class__, MockedClass) self.assertIsInstance(self.obj, MockedClass) self.assertIsNot(type(self.obj), MockedClass) def test__equality(self): self.assertTrue(self.obj == self.obj) self.assertFalse(self.obj == 2) self.assertFalse(self.obj == self.forge.create_mock(MockedClass)) def test__inequality(self): self.assertFalse(self.obj != self.obj) self.assertTrue(self.obj != 2) self.assertTrue(self.obj != self.forge.create_mock(MockedClass)) class MockingCornerCasesTest(ForgeTestCase): def tearDown(self): self.forge.verify() self.assertNoMoreCalls() super(MockingCornerCasesTest, self).tearDown() def _test__calling_method_cannot_be_called_bound(self, cls): m = self.forge.create_mock(cls) #obtaining the method is ok method = m.invalid_method with self.assertRaises(SignatureException): #calling it is not ok method() def test__calling_new_style_method_cannot_be_called_bound(self): class NewStyleClass(object): def invalid_method(): raise NotImplementedError() self._test__calling_method_cannot_be_called_bound(NewStyleClass) def test__calling_old_style_method_cannot_be_called_bound(self): class OldStyleClass: def invalid_method(): raise NotImplementedError() self._test__calling_method_cannot_be_called_bound(OldStyleClass) def test__mocking_with_method_placeholders(self): mock = self.forge.create_mock(dict) mock.get(2, 3).and_return(4) mock[6].and_return(7) with self.assertRaises(AttributeError): mock.gettt self.forge.replay() self.assertEquals(mock.get(2, 3), 4) self.assertEquals(mock[6], 7) class InvalidMockingTest(ForgeTestCase): def test__cannot_mock_functions(self): for invalid_target in self._get_function_variants(): with self.assertRaises(CannotMockFunctions): self.forge.create_mock(invalid_target) def _get_function_variants(self): yield lambda *args: None yield self._get_function_variants def some_function(): pass yield some_function yield isinstance python-pyforge-1.3.0/tests/test__readme.py000066400000000000000000000006441301315602600206550ustar00rootroot00000000000000from .ut_utils import TestCase import os import doctest class ReadmeTest(TestCase): def test__readme_file(self): readme_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "README.rst")) self.assertTrue(os.path.exists(readme_path)) result = doctest.testfile(readme_path, module_relative=False) self.assertEquals(result.failed, 0, "%s tests failed!" % result.failed) python-pyforge-1.3.0/tests/test__record_replay.py000066400000000000000000000101021301315602600222400ustar00rootroot00000000000000from forge import UnexpectedCall, ExpectedEventsNotFound, SignatureException from .ut_utils import ForgeTestCase class RecordReplayTest(ForgeTestCase): def setUp(self): super(RecordReplayTest, self).setUp() def some_function(a, b, c): raise NotImplementedError() self.stub = self.forge.create_function_stub(some_function) def tearDown(self): self.assertNoMoreCalls() super(RecordReplayTest, self).tearDown() def test__record_replay_valid(self): self.stub(1, 2, 3) self.forge.replay() self.stub(1, 2, 3) self.forge.verify() def test__call_counts(self): for i in range(2): self.stub(1, 2, 3) self.stub(1, 2, 3) self.assertEquals(self.stub.__forge__.call_count, 0) self.forge.replay() self.stub(1, 2, 3) self.assertEquals(self.stub.__forge__.call_count, 1) self.stub(1, 2, 3) self.assertEquals(self.stub.__forge__.call_count, 2) self.assertIn("2 times", str(self.stub)) self.forge.reset() self.assertEquals(self.stub.__forge__.call_count, 0) def test__record_replay_different_not_equal_value(self): self.stub(1, 2, 3) self.forge.replay() with self.assertRaises(UnexpectedCall) as caught: self.stub(1, 2, 6) exc = caught.exception self.assertEquals(len(exc.expected), 1) self.assertEquals(exc.expected[0].args, dict(a=1, b=2, c=3)) self.assertEquals(exc.got.args, dict(a=1, b=2, c=6)) self.assertExpectedNotMet([self.stub]) def test__record_replay_different_more_args(self): self.stub(1, 2, 3) self.forge.replay() with self.assertRaises(SignatureException): self.stub(1, 2, 3, 4, 5) self.assertExpectedNotMet([self.stub]) def test__record_replay_different_less_args(self): self.stub(1, 2, 3) self.forge.replay() with self.assertRaises(SignatureException): self.stub() self.assertExpectedNotMet([self.stub]) def test__record_replay_no_actual_call(self): self.stub(1, 2, 3) self.forge.replay() self.assertExpectedNotMet([self.stub]) def test__replay_queue_empty(self): self.stub(1, 2, 3) self.forge.replay() self.stub(1, 2, 3) with self.assertRaises(UnexpectedCall) as caught: self.stub(1, 2, 3) self.assertEquals(caught.exception.expected, []) self.assertIs(caught.exception.got.target, self.stub) self.assertNoMoreCalls() self.forge.verify() def test__naming_stubs(self): def some_other_function(): raise NotImplementedError() stub2 = self.forge.create_function_stub(some_other_function) self.stub(1, 2, 3) self.forge.replay() with self.assertRaises(UnexpectedCall) as caught: stub2() exc = caught.exception for r in (str, repr): self.assertIn('some_function', r(exc.expected)) self.assertIn('some_other_function', r(exc.got)) self.assertIn('some_function', str(exc)) self.assertIn('some_other_function', str(exc)) self.forge.reset() def test__record_self_argument(self): def some_func(bla, self, bla2): pass stub = self.forge.create_function_stub(some_func) stub(bla=1, self=2, bla2=3) stub(1, 2, 3) self.forge.replay() stub(bla=1, self=2, bla2=3) stub(1, 2, 3) def assertExpectedNotMet(self, stubs): self.assertGreater(len(stubs), 0) with self.assertRaises(ExpectedEventsNotFound) as caught: self.forge.verify() self.assertEquals(len(caught.exception.events), len(stubs)) expected = self.forge.queue.get_expected() for stub, exception_call in zip(stubs, caught.exception.events): expected_call = expected.pop() self.assertIs(expected_call, exception_call) self.assertIs(expected_call.target, stub) self.assertEquals(len(expected), 0) self.forge.queue.clear() python-pyforge-1.3.0/tests/test__record_replay_ordering.py000066400000000000000000000174541301315602600241520ustar00rootroot00000000000000from .ut_utils import ForgeTestCase from forge import UnexpectedCall, ExpectedEventsNotFound from forge.python3_compat import basestring import random class OrderingTest(ForgeTestCase): def setUp(self): super(OrderingTest, self).setUp() self.stub = self.forge.create_function_stub(lambda arg: None) class StrictOrderingTest(OrderingTest): def test__strict_ordering(self): self.stub(1) self.stub(2) self.forge.replay() with self.assertRaises(UnexpectedCall) as caught: self.stub(2) self.assertIs(caught.exception.got.target, self.stub) self.assertEquals(len(caught.exception.expected), 1) self.assertIs(caught.exception.expected[0].target, self.stub) self.forge.reset() class EmptyGroupTest(OrderingTest): def test__empty_group_with_initial_ordered(self): self._test__empty_group(True, True, True) self._test__empty_group(True, True, False) def test__empty_group_with_initial_unordered(self): self._test__empty_group(True, False, True) self._test__empty_group(True, False, False) def test__empty_group_without_initial_ordered(self): self._test__empty_group(False, True, True) self._test__empty_group(False, True, False) def test__empty_group_without_initial_unordered(self): self._test__empty_group(False, False, True) self._test__empty_group(False, False, False) def _test__empty_group(self, with_initial_recording, ordered, success): if with_initial_recording: self.stub(0) if ordered: context = self.forge.ordered else: context = self.forge.any_order with context(): pass self.stub(1) self.stub(2) self.forge.replay() if with_initial_recording: self.stub(0) if success: self.stub(1) self.stub(2) self.forge.verify() else: with self.assertRaises(UnexpectedCall): self.stub(2) self.forge.reset() class OrderGroupsTest(OrderingTest): def setUp(self): super(OrderGroupsTest, self).setUp() with self.forge.any_order(): self.stub(0) self.stub(1) self.stub(2) self.stub(3) with self.forge.any_order(): self.stub(4) self.stub(5) self.forge.replay() def test__as_recorded(self): for i in range(6): self.stub(i) self.forge.verify() def test__not_as_recorded(self): self.stub(1) self.stub(0) self.stub(2) self.stub(3) self.stub(5) self.stub(4) self.forge.verify() # class EmptyGroupTest(OrderingTest): # def test__empty_ordered_group(self): # self._test__empty_group(self.forge.ordered) # def test__empty_unordered_group(self): # self._test__empty_group(self.forge.any_order) # def _test__empty_group(self, context): # with context(): # pass # self.stub(1) # self.forge.replay() # self.stub(1) # self.forge.verify() class OrderingGroupExceptionFormatting(OrderingTest): def test__unexpected_call(self): with self.forge.any_order(): self.stub(1) self.stub(2) self.stub(3) self.forge.replay() with self.assertRaises(UnexpectedCall) as caught: self.stub(4) self.assertIsInstance(caught.exception.expected, list) self.assertIsInstance(str(caught.exception), basestring) self.assertIsInstance(repr(caught.exception), basestring) self.forge.reset() class OrderedOrderedGroupTest(OrderingTest): def test__ordered_ordered(self): self.stub(0) self.stub(1) with self.forge.ordered(): self.stub(2) self.stub(3) self.stub(4) self.forge.replay() for i in range(5): self.stub(i) self.forge.verify() def test__ordered_ordered__unexpected(self): self.stub(0) with self.forge.ordered(): self.stub(1) self.stub(2) self.stub(3) self.forge.replay() self.stub(0) with self.assertRaises(UnexpectedCall) as caught: self.stub(2) self.assertIsInstance(caught.exception.expected, list) self.assertIsInstance(str(caught.exception), basestring) self.assertIsInstance(repr(caught.exception), basestring) self.forge.reset() class OrderedAnyOrderGroupTest(OrderingTest): def setUp(self): super(OrderedAnyOrderGroupTest, self).setUp() self.stub(0) with self.forge.any_order(): self.stub(1) self.stub(2) with self.forge.ordered(): self.stub('a') self.stub('b') self.stub(3) self.stub(4) self.forge.replay() def test__as_recorded(self): for n in (0, 1, 2, 'a', 'b', 3, 4): self.stub(n) self.forge.verify() def test__not_as_recorded(self): for n in (0, 'a', 'b', 1, 2, 3, 4): self.stub(n) self.forge.verify() def test__not_as_recorded_2(self): for n in (0, 3, 1, 'a', 'b', 2, 4): self.stub(n) self.forge.verify() def test__not_as_recorded_3(self): for n in (0, 'a', 'b', 2, 3, 1, 4): self.stub(n) self.forge.verify() def test__break_inner_ordered__unexpected(self): for n in (0, 1, 'a'): self.stub(n) with self.assertRaises(UnexpectedCall) as caught: self.stub(2) self.assertIsInstance(caught.exception.expected, list) self.assertIsInstance(str(caught.exception), basestring) self.assertIsInstance(repr(caught.exception), basestring) self.forge.reset() class OrderedAnyOrder2GroupTest(OrderingTest): def setUp(self): super(OrderedAnyOrder2GroupTest, self).setUp() self.stub(0) with self.forge.any_order(): self.stub(1) self.stub(2) with self.forge.ordered(): self.stub('a') self.stub('b') self.stub(3) with self.forge.ordered(): self.stub('c') self.stub('d') self.stub(4) self.forge.replay() def test__as_recorded(self): for n in (0, 1, 2, 'a', 'b', 3, 'c', 'd', 4): self.stub(n) self.forge.verify() def test__not_as_recorded(self): for n in (0, 'c', 'd', 1, 'a', 'b', 2, 3, 4): self.stub(n) self.forge.verify() def test__break_inner_ordered__unexpected(self): for n in (0, 1, 'c', 'd'): self.stub(n) with self.assertRaises(UnexpectedCall) as caught: self.stub('b') self.assertIsInstance(caught.exception.expected, list) self.assertIsInstance(str(caught.exception), basestring) self.assertIsInstance(repr(caught.exception), basestring) self.forge.reset() class OrderedAnyOrderOrderedGroupTest(OrderingTest): def setUp(self): super(OrderedAnyOrderOrderedGroupTest, self).setUp() self.stub(0) with self.forge.any_order(): self.stub(1) self.stub(2) with self.forge.ordered(): self.stub('a') with self.forge.any_order(): self.stub('!') self.stub('@') self.stub('b') self.stub(3) self.stub(4) self.forge.replay() def test__as_recorded(self): for n in (0, 1, 2, 'a', '!', '@', 'b', 3, 4): self.stub(n) self.forge.verify() def test__not_as_recorded(self): for n in (0, 'a', '@', '!', 'b', 3, 2, 1, 4): self.stub(n) self.forge.verify() python-pyforge-1.3.0/tests/test__replacing.py000066400000000000000000000202621301315602600213620ustar00rootroot00000000000000import os import time import types from .ut_utils import ForgeTestCase, BinaryObjectClass from forge.stub import FunctionStub from forge.class_mock import ClassMockObject from forge.python3_compat import IS_PY3 orig_time_sleep = time.sleep orig_os_path_join = os.path.join class NewStyleClass(object): def method(self, a, b, c): raise NotImplementedError() @property def some_property(self): return 2 orig_newstyle_method = NewStyleClass.method orig_newstyle_property = NewStyleClass.some_property class OldStyleClass: def method(self, a, b, c): raise NotImplementedError() @property def some_property(self): return 2 orig_oldstyle_method = OldStyleClass.method orig_oldstyle_property = OldStyleClass.some_property class StubbingObjectsTest(ForgeTestCase): def _test__stubbing_object(self, obj): expected = obj.method returned = self.forge.replace(obj, 'method') self.assertIsInstance(obj.method, FunctionStub) self.assertIs(returned, obj.method) self.assertIs(obj.method.__forge__.original.__func__, expected.__func__) self.assertIs(obj.method.__forge__.signature.func.__func__, expected.__func__) self.assertTrue(obj.method.__forge__.is_bound()) self.forge.restore_all_replacements() self.assertIs(obj.method.__func__, expected.__func__) def test__stubbing_new_style_objects(self): self._test__stubbing_object(NewStyleClass()) def test__stubbing_old_style_objects(self): self._test__stubbing_object(OldStyleClass()) class StubbedNewStyleClass(object): @classmethod def class_method(cls, a, b, c): raise NotImplementedError() @staticmethod def static_method(a, b, c): raise NotImplementedError() assert 'class_method' in dir(StubbedNewStyleClass) class StubbedOldStyleClass: @classmethod def class_method(cls, a, b, c): raise NotImplementedError() @staticmethod def static_method(a, b, c): raise NotImplementedError() class StubbingClassMethodTest(ForgeTestCase): def test__stubbing_class_methods(self): for cls in (StubbedNewStyleClass, StubbedOldStyleClass): self._test__stubbing_class_methods(cls, 'class_method', False) def test__stubbing_static_methods(self): for cls in (StubbedNewStyleClass, StubbedOldStyleClass): self._test__stubbing_class_methods(cls, 'static_method', True) def _test__stubbing_class_methods(self, cls, name, is_static): orig = getattr(cls, name) self.forge.replace(cls, name) func = getattr(cls, name) self.assertIsInstance(func, FunctionStub) func(1, 2, 3) self.forge.replay() func = getattr(cls, name) func(1, 2, 3) self.forge.verify() self.forge.reset() self.forge.restore_all_replacements() func = getattr(cls, name) if is_static: self.assertIsInstance(func, types.FunctionType) self.assertIsInstance(cls.__dict__[name], staticmethod) self.assertIs(func, orig) else: self.assertIsInstance(cls.class_method, types.MethodType) self.assertIsInstance(cls.__dict__[name], classmethod) #classmethods are re-computed on every fetch self.assertIsNot(func, orig) self.assertIs(cls.class_method.__self__, cls) self.assertIs(cls.class_method.__func__, orig.__func__) class StubbingModulesTest(ForgeTestCase): def test__stub_c_function(self): self.forge.replace(time, "sleep") self.assertIsInstance(time.sleep, FunctionStub) expected_result = 666 time.sleep(10).and_return(expected_result) self.forge.replay() self.assertEquals(time.sleep(10), expected_result) self.forge.restore_all_replacements() self.assertIs(time.sleep, orig_time_sleep) def test__stub_module_functions(self): self.forge.replace(os.path, "join") self.assertIsInstance(os.path.join, FunctionStub) self.assertFalse(os.path.join.__forge__.signature.has_variable_kwargs()) self.assertTrue(os.path.join.__forge__.signature.has_variable_args()) return_path = "return_path" os.path.join("a", "b", "c").and_return(return_path) self.forge.replay() self.assertEquals(return_path, os.path.join("a", "b", "c")) self.forge.verify() self.forge.restore_all_replacements() self.assertIs(os.path.join, orig_os_path_join) class ReplacingTest(ForgeTestCase): def test__replacing_simple_attributes(self): s = self.forge.create_sentinel() s.a = 2 self.forge.replace_with(s, "a", 3) self.assertEquals(s.a, 3) self.forge.restore_all_replacements() self.assertEquals(s.a, 2) def test__replacing_properties__new_style(self): self._test__replacing_properties(NewStyleClass, orig_newstyle_property) def test__replacing_properties__old_style(self): self._test__replacing_properties(OldStyleClass, orig_oldstyle_property) def _test__replacing_properties(self, cls, orig): self.forge.replace_with(cls, "some_property", 3) self.assertEquals(cls.some_property, 3) self.assertEquals(cls().some_property, 3) self.forge.restore_all_replacements() self.assertIs(cls.some_property, orig) self.assertIs(cls().some_property, 2) class NonFunctionStubbingTest(ForgeTestCase): def setUp(self): super(NonFunctionStubbingTest, self).setUp() self.x = self.forge.create_sentinel() def test__replacing_new_style_class_objects(self): class MyClass(object): pass self._test__replacing_objects(MyClass(), MyClass) def test__replacing_old_style_class_objects(self): class MyClass: pass self._test__replacing_objects(MyClass(), MyClass) def test__replacing_builtin_objects(self): self._test__replacing_objects(BinaryObjectClass(), type(BinaryObjectClass())) def _test__replacing_objects(self, obj, cls): orig = self.x.obj = obj self.forge.replace(self.x, 'obj') self.assertIsInstance(self.x.obj, ClassMockObject) self.assertTrue(self.x.obj.__forge__.behaves_as_instance) self.assertIs(self.x.obj.__forge__.mocked_class, cls) self.forge.restore_all_replacements() self.assertIs(self.x.obj, orig) def test__replacing_new_style_classes(self): class MyClass(object): pass self._test__replacing_classes(MyClass) def test__stubbing_old_new_style_classes(self): class MyClass: pass self._test__replacing_classes(MyClass) def _test__replacing_classes(self, cls): self.x.cls = cls self.forge.replace(self.x, 'cls') self.assertIsInstance(self.x.cls, ClassMockObject) self.assertIs(self.x.cls.__forge__.mocked_class, cls) self.assertFalse(self.x.cls.__forge__.behaves_as_instance) self.forge.restore_all_replacements() self.assertIs(self.x.cls, cls) class MultipleStubbingTest(ForgeTestCase): def test__multiple_stubbing(self): self.forge.replace(self.forge, "replace") some_object = self.forge.create_sentinel() expected_results = [ self.forge.replace(some_object, x).and_return(object()) for x in ["a", "b", "c"] ] self.forge.replay() returned = self.forge.replace_many(some_object, "a", "b", "c") self.assertEquals(returned, expected_results) self.forge.restore_all_replacements() self.forge.verify() self.assertNoMoreCalls() self.forge.reset() class ReplaceContextTest(ForgeTestCase): def test__replace_context(self): some_object = self.forge.create_sentinel() orig = some_object.attr = self.forge.create_sentinel() other = some_object.other_attr = self.forge.create_sentinel() self.forge.replace(some_object, "other_attr") with self.forge.replacing_context(some_object, "attr"): self.assertIsNot(some_object.other_attr, other) self.assertIsNot(some_object.attr, orig) self.assertIsNot(some_object.other_attr, other) self.assertIs(some_object.attr, orig) python-pyforge-1.3.0/tests/test__sentinels.py000066400000000000000000000013521301315602600214210ustar00rootroot00000000000000from .ut_utils import ForgeTestCase class SentinelTest(ForgeTestCase): def test__sentinel_equality(self): s1 = self.forge.create_sentinel() s2 = self.forge.create_sentinel() self.assertNotEqual(s1, s2) self.assertEqual(s1, s1) self.assertEqual(s2, s2) def test__sentinel_name(self): s1 = self.forge.create_sentinel('s1') self.assertIn('s1', str(s1)) self.assertIn('s1', repr(s1)) def test__sentinal_attrs(self): s = self.forge.create_sentinel('name1', a=2, b=3, name='name2') self.assertEquals(s.a, 2) self.assertEquals(s.b, 3) for s in (str(s), repr(s)): self.assertIn('name1', s) self.assertNotIn('name2', s) python-pyforge-1.3.0/tests/test__signature_checking_during_record.py000066400000000000000000000057701301315602600261670ustar00rootroot00000000000000from .ut_utils import ForgeTestCase from forge import SignatureException class call(object): def __init__(self, *args, **kwargs): self.func = args[0] self.args = args[1:] self.kwargs = kwargs class SignatureCheckingTest(ForgeTestCase): def test__good_record(self): for good_call in self._iterate_valid_calls(): stub = self.forge.create_function_stub(good_call.func) self.assertTrue(self.forge.is_recording()) stub(*good_call.args, **good_call.kwargs) self.forge.replay() stub(*good_call.args, **good_call.kwargs) self.forge.verify() self.forge.reset() def test__signature_checking_on_record(self): for invalid_call in self._iterate_invalid_calls(): stub = self.forge.create_function_stub(invalid_call.func) self.assertTrue(self.forge.is_recording()) with self.assertRaises(SignatureException): stub(*invalid_call.args, **invalid_call.kwargs) def _iterate_valid_calls(self): def f(): raise NotImplementedError() yield call(f) def f(a, b, c): raise NotImplementedError() yield call(f, 1, 2, 3) yield call(f, a=1, b=2, c=3) yield call(f, 1, 2, c=3) def f(a, b, c=2): raise NotImplementedError() yield call(f, 1, 2, 3) yield call(f, a=1, b=2, c=3) yield call(f, 1, 2) def f(a, b, c=2, *args): raise NotImplementedError() yield call(f, 1, 2, 3) yield call(f, 1, 2, 3, 4, 5) yield call(f, 1, 2, c=5) def f(a, b, c=2, **kwargs): raise NotImplementedError() yield call(f, 1, 2, 3) yield call(f, 1, 2, 3, d=5) yield call(f, 1, 2, c=2, d=5) def f(a, b, c=2, *args, **kwags): raise NotImplementedError() yield call(f, 1, 2, 3, 4, 5) yield call(f, 1, 2, 3, 4, 5, d=5, e=8) def _iterate_invalid_calls(self): def f(): raise NotImplementedError() yield call(f, 2) yield call(f, c=3) def f(a, b, c): raise NotImplementedError() yield call(f) yield call(f, 1) yield call(f, 1, 2) yield call(f, 1, 2, 3, 4) yield call(f, 1, c=3) def f(a, b, c=2): raise NotImplementedError() yield call(f) yield call(f, 1) yield call(f, 1, 2, 3, 4) yield call(f, c=5) yield call(f, 1, c=5) def f(a, b, c=2, *args): raise NotImplementedError() yield call(f, 1, 2, d=5) yield call(f, 1, 2, 3, c=5) yield call(f, 1, 2, a=1) def f(a, b, c=2, **kwargs): raise NotImplementedError() yield call(f, 1, 2, 3, c=5) yield call(f, 1, 2, 3, 4) yield call(f, 1, c=2, d=5) def f(a, b, c=2, *args, **kwags): raise NotImplementedError() yield call(f, 1) yield call(f, 1, 2, 3, 4, 5, c=4) python-pyforge-1.3.0/tests/test__signature_object.py000066400000000000000000000135161301315602600227510ustar00rootroot00000000000000import time from .ut_utils import TestCase from forge.signature import FunctionSignature from forge.exceptions import SignatureException, InvalidKeywordArgument, FunctionCannotBeBound # no named tuples for python 2.5 compliance... class ExpectedArg(object): def __init__(self, name, has_default, default=None): self.name = name self.has_default = has_default self.default = default class SignatureTest(TestCase): def _assert_argument_names(self, sig, names): self.assertEquals([arg.name for arg in sig._args], names) def _test_function_signature(self, func, expected_signature, has_varargs=False, has_varkwargs=False ): sig = FunctionSignature(func) self.assertEquals(len(expected_signature), len(sig._args)) self.assertEquals(len(expected_signature), sig.get_num_args()) for expected_arg, arg in zip(expected_signature, sig._args): if isinstance(expected_arg, tuple): expected_arg = ExpectedArg(*expected_arg) self.assertEquals(expected_arg.name, arg.name) self.assertEquals(expected_arg.has_default, arg.has_default()) if expected_arg.has_default: self.assertEquals(expected_arg.default, arg.default) self.assertEquals(sig.has_variable_kwargs(), has_varkwargs) self.assertEquals(sig.has_variable_args(), has_varargs) def test__simple_functions(self): def f(a, b, c): pass self._test_function_signature(f, [('a', False), ('b', False), ('c', False)]) def test__kwargs(self): def f(a, b, c=2): pass def f_args(a, b, c=2, *args): pass def f_kwargs(a, b, c=2, **kwargs): pass def f_args_kwargs(a, b, c=2, *args, **kwargs): pass lambda_args_kwargs = lambda a, b, c=2, *args, **kwargs: None sig = [('a', False), ('b', False), ('c', True, 2)] self._test_function_signature(f, sig) self._test_function_signature(f_args, sig, has_varargs=True) self._test_function_signature(f_kwargs, sig, has_varkwargs=True) self._test_function_signature(f_args_kwargs, sig, has_varargs=True, has_varkwargs=True) self._test_function_signature(lambda_args_kwargs, sig, has_varargs=True, has_varkwargs=True) def test__normalizing_kwargs_with_numbers(self): # this is supported in python, but interferes with the arg-normalizing logic sig = FunctionSignature(lambda *args, **kwargs: None) with self.assertRaises(InvalidKeywordArgument): sig.get_normalized_args((), {1:2}) def test__is_method_and_is_bound(self): def f(): raise NotImplementedError() def f_with_self_arg(self): raise NotImplementedError() self.assertFalse(FunctionSignature(f_with_self_arg).is_bound_method()) self.assertFalse(FunctionSignature(f).is_bound_method()) self.assertFalse(FunctionSignature(f_with_self_arg)._args[0].has_default()) class SomeClass(object): def f_without_self(): raise NotImplementedError() def f(self): raise NotImplementedError() def f_with_args(self, a, b, c): raise NotImplementedError() def f_with_first_argument_not_self(bla): raise NotImplementedError() class SomeOldStyleClass: def f_without_self(): raise NotImplementedError() def f(self): raise NotImplementedError() def f_with_args(self, a, b, c): raise NotImplementedError() def f_with_first_argument_not_self(bla): raise NotImplementedError() for cls in (SomeClass, SomeOldStyleClass): self.assertFalse(FunctionSignature(cls.f).is_bound_method()) self.assertFalse(FunctionSignature(cls.f_with_args).is_bound_method()) self.assertFalse(FunctionSignature(cls.f_with_first_argument_not_self).is_bound_method()) self.assertTrue(FunctionSignature(cls().f).is_bound_method()) self.assertTrue(FunctionSignature(cls().f_with_args).is_bound_method()) self.assertTrue(FunctionSignature(cls().f_with_first_argument_not_self).is_bound_method()) def test__is_class_method(self): class New(object): @classmethod def class_method(cls): raise NotImplementedError() def regular_method(self): raise NotImplementedError() class Old(object): @classmethod def class_method(cls): raise NotImplementedError() def regular_method(self): raise NotImplementedError() self.assertTrue(FunctionSignature(New.class_method).is_class_method()) self.assertTrue(FunctionSignature(Old.class_method).is_class_method()) self.assertFalse(FunctionSignature(New.regular_method).is_class_method()) self.assertFalse(FunctionSignature(Old.regular_method).is_class_method()) def test__copy(self): f = FunctionSignature(lambda a, b: 2) f2 = f.copy() self.assertIsNot(f, f2) self.assertIsNot(f._args, f2._args) class BinaryFunctionSignatureTest(TestCase): def test__binary_global_function(self): sig = FunctionSignature(time.time) self.assertEquals(sig._args, []) self.assertTrue(sig.has_variable_args()) self.assertTrue(sig.has_variable_kwargs()) def test__object_method_placeholders(self): class SomeObject(object): pass sig = FunctionSignature(SomeObject.__ge__) python-pyforge-1.3.0/tests/test__special_methods.py000066400000000000000000000142311301315602600225600ustar00rootroot00000000000000from .ut_utils import BinaryObjectClass from functools import partial from .ut_utils import ForgeTestCase from .ut_utils import build_new_style_class from .ut_utils import build_old_style_class from .ut_utils import Method from forge import UnexpectedCall from forge.python3_compat import IS_PY3 class _SpecialMethodsTest(ForgeTestCase): def setUp(self): super(_SpecialMethodsTest, self).setUp() self.obj = self.forge.create_mock(self.CTOR([ Method("__len__(self)"), Method("__setitem__(self, item, value)"), Method("__getitem__(self, item)"), Method('__delitem__(self, item)'), Method('__iter__(self)'), Method('__call__(self, a, b, c)'), Method('__contains__(self, item)'), Method('__nonzero__(self)'), Method('__bool__(self)'), ])) def tearDown(self): self.forge.verify() self.assertNoMoreCalls() super(_SpecialMethodsTest, self).tearDown() def test__len(self): self.obj.__len__().and_return(2) self.forge.replay() self.assertEquals(len(self.obj), 2) def test__setitem_explicit(self): self.obj.__setitem__('a', 'b') self.forge.replay() self.obj['a'] = 'b' def test__setitem_implicit(self): self.obj['a'] = 'b' self.forge.replay() self.obj['a'] = 'b' def test__setitem_mismatch(self): self.obj['a'] = 'b' self.forge.replay() with self.assertRaises(UnexpectedCall): self.obj['a'] = 'c' self.assertEquals(len(self.forge.queue), 1) self.forge.reset() def test__getitem_explicit(self): self.obj.__getitem__(2).and_return(3) self.forge.replay() self.assertEquals(self.obj[2], 3) def test__getitem_implicit(self): self.obj[2].and_return(3) self.forge.replay() self.assertEquals(self.obj[2], 3) def test__getitem_mismatch(self): self.obj[2].and_return(3) self.forge.replay() with self.assertRaises(UnexpectedCall): self.obj[3] self.assertEquals(len(self.forge.queue), 1) self.forge.reset() def test__delitem_explicit(self): self.obj.__delitem__(2) self.forge.replay() del self.obj[2] def test__delitem_implicit(self): del self.obj[2] self.forge.replay() del self.obj[2] def test__delitem_mismatch(self): del self.obj[2] self.forge.replay() with self.assertRaises(UnexpectedCall): del self.obj[3] self.assertEquals(len(self.forge.queue), 1) self.forge.reset() def test__iter(self): expected_result = [1, 3, 4, 5] self.obj.__iter__().and_return(iter(expected_result)) self.forge.replay() l = [x for x in self.obj] self.assertEquals(l, expected_result) def test__call(self): self.obj(1, 2, c=3).and_return(5) self.forge.replay() self.assertEquals(self.obj(1, 2, c=3), 5) def test__call_mismatch(self): self.obj(1, 2, c=3).and_return(5) self.forge.replay() with self.assertRaises(UnexpectedCall): self.obj(1, 2, c=4) self.assertEquals(len(self.forge.queue), 1) self.forge.reset() def test__contains_explicit(self): self.obj.__contains__(2).and_return(True) self.obj.__contains__(2).and_return(False) self.forge.replay() self.assertTrue(2 in self.obj) self.assertFalse(2 in self.obj) def test__contains_mismatch(self): self.obj.__contains__(2).and_return(True) self.forge.replay() with self.assertRaises(UnexpectedCall): 3 in self.obj self.assertEquals(len(self.forge.queue), 1) self.forge.reset() def test__boolean(self): if IS_PY3: self.obj.__bool__().and_return(False) else: self.obj.__nonzero__().and_return(False) self.forge.replay() self.assertFalse(self.obj) class NewStyleSpecialMethodsTest(_SpecialMethodsTest): CTOR = staticmethod(build_new_style_class) class OldStyleSpecialMethodsTest(_SpecialMethodsTest): CTOR = staticmethod(build_old_style_class) class _SpecialMethodAbsenceTest(ForgeTestCase): def tearDown(self): self.forge.verify() self.assertNoMoreCalls() super(_SpecialMethodAbsenceTest, self).tearDown() def test__special_method_absence(self): for statement in self._get_invalid_statements(): with self.assertRaises(TypeError): exec(statement) def test__boolean(self): self.assertTrue(self.obj) def _get_invalid_statements(self): return [ 'len(self.obj)', 'self.obj.__setitem__(1, 2)', 'self.obj[1] = 2', 'self.obj.__getitem__(1)', 'self.obj[1]', 'del self.obj[1]', 'self.obj.__delitem__(1)', 'list(self.obj)', 'iter(self.obj)', 'self.obj(1, 2, 3)', 'self.obj()', '3 in self.obj' ] class NewStyleSpecialMethodsAbsenceTest(_SpecialMethodAbsenceTest): def setUp(self): super(NewStyleSpecialMethodsAbsenceTest, self).setUp() self.obj = self.forge.create_mock(build_new_style_class()) class OldStyleSpecialMethodsAbsenceTest(_SpecialMethodAbsenceTest): def setUp(self): super(OldStyleSpecialMethodsAbsenceTest, self).setUp() self.obj = self.forge.create_mock(build_old_style_class()) class CallCornerCasesTest(ForgeTestCase): def test__callable_metaclass(self): class Object(object): class __metaclass__(type): def __call__(self, a, b, c): return 2 obj = self.forge.create_mock(Object) with self.assertRaises(TypeError): obj(1, 2, 3) def test__non_callable_binary_classes(self): obj = self.forge.create_mock(type(BinaryObjectClass())) with self.assertRaises(TypeError): obj(1, 2, 3) def test__callable_binary_classes(self): obj = self.forge.create_mock(partial) obj(1, 2, 3) self.forge.replay() obj(1, 2, 3) python-pyforge-1.3.0/tests/test__utils.py000066400000000000000000000012361301315602600205560ustar00rootroot00000000000000from .ut_utils import TestCase, ForgeTestCase from forge.utils import renumerate, EXPECTING from forge.class_mock_handle import ClassMockHandle class RenumerateTest(TestCase): def test__simple_usage(self): self.assertEquals(list(renumerate(range(5))), [(4, 4), (3, 3), (2, 2), (1, 1), (0, 0)]) class EXPECTING_Test(ForgeTestCase): def test(self): mocked = self.forge.create_wildcard_mock() handle = self.forge.create_mock(ClassMockHandle) mocked.__forge__ = handle handle.expect_setattr("foo", "bar") with self.forge.verified_replay_context(): EXPECTING(mocked).foo = "bar" python-pyforge-1.3.0/tests/test__whenever.py000066400000000000000000000077771301315602600212610ustar00rootroot00000000000000import random from .ut_utils import ForgeTestCase from forge.exceptions import UnexpectedCall class Obj(object): def f(self, a, b, c): raise NotImplementedError() # pragma: no cover def g(self, value): raise NotImplementedError() # pragma: no cover class WheneverTest(ForgeTestCase): def setUp(self): super(WheneverTest, self).setUp() self.obj = self.forge.create_mock(Obj) def test__whenever_verifies_arguments(self): self.obj.f(1, 2, 3).whenever().and_return(2) self.forge.replay() self.assertEquals(self.obj.f(1, 2, 3), 2) with self.assertRaises(UnexpectedCall): self.obj.f(1, 2, 4) self.assertEquals(self.obj.f(1, 2, 3), 2) def test__whenever_accepts_zero_times(self): self.obj.f(1, 2, 3).whenever().and_return(2) self.forge.replay() def test__whenever_and_raise(self): e = Exception() self.obj.f(1, 2, 3).whenever().and_raise(e) self.forge.replay() with self.assertRaises(Exception) as caught: self.obj.f(1, 2, 3) self.assertIs(caught.exception, e) def test__whenever_with_multiple_groups(self): call = self.obj.f(1, 2, 3) self.obj.f(1, 1, 1).and_return(1) with self.forge.any_order(): self.obj.f(2, 2, 2).and_return(2) self.obj.f(3, 3, 3).and_return(3) call.whenever().and_return("hey") self.forge.replay() for i in range(3): self.assertEquals("hey", self.obj.f(1, 2, 3)) self.assertEquals(1, self.obj.f(1, 1, 1)) self.assertEquals("hey", self.obj.f(1, 2, 3)) self.assertEquals(2, self.obj.f(2, 2, 2)) self.assertEquals(3, self.obj.f(3, 3, 3)) self.assertEquals("hey", self.obj.f(1, 2, 3)) def test__whenever_patterns(self): values = list(range(10)) for value in values: self.obj.g(value).whenever().and_return(value*2) self.forge.replay() for i in range(3): random.shuffle(values) for value in values: self.assertEquals(self.obj.g(value), value * 2) with self.assertRaises(UnexpectedCall): self.obj.g(max(values)+1) def test__whenever_when_syntax(self): self.obj.g.when(1).then_return(2) self.forge.replay() self.assertEquals(self.obj.g(1), 2) self.assertEquals(self.obj.g(1), 2) self.assertEquals(self.obj.g(1), 2) with self.assertRaises(UnexpectedCall): self.obj.g(2) def test__whenever_when_syntax_disabled_in_replay(self): self.forge.replay() self.obj.g # make sure the stub exists with self.assertRaises(AttributeError): self.obj.g.when def test__whenever_when_syntax_in_group(self): with self.forge.ordered(): self.obj.f(1, 2, 3).and_return(42) self.obj.g.when(1).then_return(2) with self.forge.ordered(): self.obj.f(3, 2, 1).and_return(24) self.obj.g.when(1).then_return(3) self.forge.replay() self.assertEquals(self.obj.g(1), 2) self.assertEquals(self.obj.g(1), 2) self.assertEquals(self.obj.f(1, 2, 3), 42) self.assertEquals(self.obj.g(1), 3) self.assertEquals(self.obj.g(1), 3) self.assertEquals(self.obj.f(3, 2, 1), 24) def test__whenever_applies_only_in_group(self): result = object() with self.forge.ordered(): self.obj.f(1, 1, 1) with self.forge.any_order(): self.obj.g(1).whenever().and_return(result) self.obj.f(2, 2, 2) self.obj.f(3, 3, 3) self.forge.replay() with self.assertRaises(UnexpectedCall): self.obj.g(1) self.obj.f(1, 1, 1) self.assertIs(result, self.obj.g(1)) self.obj.f(2, 2, 2) with self.assertRaises(UnexpectedCall): # once f(2, 2, 2) is called, the group is cleared and the whenever() no longer applies self.obj.g(1) self.obj.f(3, 3, 3) python-pyforge-1.3.0/tests/test__wildcards.py000066400000000000000000000057031301315602600213750ustar00rootroot00000000000000from .ut_utils import ForgeTestCase from forge import UnexpectedSetattr from forge.python3_compat import xrange class WildcardTest(ForgeTestCase): def tearDown(self): self.forge.verify() self.assertNoMoreCalls() super(WildcardTest, self).tearDown() def test__wildcard_functions(self): wcf = self.forge.create_wildcard_function_stub() self._do_all_sorts_of_calls(wcf) self.forge.replay() self._do_all_sorts_of_calls(wcf) def _do_all_sorts_of_calls(self, func): func(1, 2, 3) func(1, 2) func() func(a=2) func(1, 2, a=2, d=3) def test__wildcard_record_replay(self): wc = self.forge.create_wildcard_mock() wc.f(1, 2, 3) wc.g(1, 2, 3, d=4) self.forge.replay() wc.f(1, 2, 3) wc.g(1, 2, 3, d=4) def test__wildcard_function_names(self): wc = self.forge.create_wildcard_function_stub('some_name') self.assertIn('some_name', str(wc)) self.assertIn('some_name', repr(wc)) def test__wildcard_access_to_unrecorded_methods(self): wc = self.forge.create_wildcard_mock() self.forge.replay() with self.assertRaises(AttributeError): wc.f def test__wildcard_access_to_unrecorded_methods_getattr_in_record(self): wc = self.forge.create_wildcard_mock() wc.f # no call! self.forge.replay() with self.assertRaises(AttributeError): wc.f # todo: this shouldn't be ok... to be solved when setattr expectations are added def test__setattr_forbidden(self): wc = self.forge.create_wildcard_mock() wc.a = 2 self.forge.replay() self.assertEquals(wc.a, 2) with self.assertRaises(UnexpectedSetattr): wc.a = 2 with self.assertRaises(UnexpectedSetattr): wc.a = 3 with self.assertRaises(UnexpectedSetattr): wc.b = 3 def test__expect_setattr(self): wc = self.forge.create_wildcard_mock() wc.__forge__.expect_setattr("a", 2) self.forge.replay() wc.a = 2 self.assertEquals(wc.a, 2) def test__repr(self): name = 'some_name' wc = self.forge.create_wildcard_mock(name) self.assertIn(name, str(wc)) self.assertIn(name, repr(wc)) def test__method_repr(self): wc = self.forge.create_wildcard_mock() m = wc.method_with_specific_name self.assertTrue("method_with_specific_name" in repr(m)) self.assertTrue("method_with_specific_name" in str(m)) def test__special_methods_ok(self): wc = self.forge.create_wildcard_mock() f = self.forge.create_wildcard_function_stub() with wc: f() wc.__len__().and_return(666) wc.__iter__().and_return(iter(xrange(10))) self.forge.replay() with wc: f() self.assertEquals(len(wc), 666) self.assertEquals([x for x in wc], list(range(10))) python-pyforge-1.3.0/tests/ut_utils/000077500000000000000000000000001301315602600175145ustar00rootroot00000000000000python-pyforge-1.3.0/tests/ut_utils/__init__.py000066400000000000000000000047521301315602600216350ustar00rootroot00000000000000from functools import wraps import sys import types import platform from forge import Forge from forge.python3_compat import IS_PY3 try: import unittest2 as unittest except ImportError: import unittest class TestCase(unittest.TestCase): pass if IS_PY3: from io import BytesIO as BinaryObjectClass assert not hasattr(sys.modules[BinaryObjectClass.__module__], "__file__") else: from cStringIO import StringIO as BinaryObjectClass class ForgeTestCase(TestCase): def setUp(self): super(ForgeTestCase, self).setUp() self.forge = Forge() def tearDown(self): self.assertNoMoreCalls() self.forge.verify() self.forge.restore_all_replacements() self.forge.reset() super(ForgeTestCase, self).tearDown() def assertNoMoreCalls(self): expected = self.forge.queue.get_expected() self.assertEquals(len(expected), 0, "len=%d != 0, expected_events=%s, queue=%s" % (len(expected), repr(expected), repr(self.forge.queue))) class Method(object): def __init__(self, signature_string): self.signature_string = signature_string self.function = self._to_function() self.name = self.function.__name__ def get_function(self): return self.function def _to_function(self): code = """def %s: raise NotImplementedError()""" % self.signature_string d = {} exec(code, {}, d) if len(d) != 1: raise RuntimeError("More than one function created") [returned] = d.values() return returned class ClassMethod(Method): def get_function(self): return classmethod(super(ClassMethod, self).get_function()) class StaticMethod(Method): def get_function(self): return staticmethod(super(StaticMethod, self).get_function()) def build_new_style_class(methods=()): return type('NewStyleClass', (object,), _get_class_dict(methods)) def build_old_style_class(methods=()): if IS_PY3: return build_new_style_class(methods) return types.ClassType('OldStyleClass', (), _get_class_dict(methods)) def _get_class_dict(methods): return dict((method.name, method.get_function()) for method in methods) def resets_forge_at_end(func): @wraps(func) def new_func(self, *args, **kwargs): func(self, *args, **kwargs) self.assertNoMoreCalls() self.forge.reset() return new_func class Checkpoint(object): called = False def trigger(self): self.called = True python-pyforge-1.3.0/tox.ini000066400000000000000000000001651301315602600160170ustar00rootroot00000000000000[tox] envlist = py27,py33,py34,py35 [testenv] deps=nose commands=nosetests [testenv:py26] deps=unittest2 nose