#!/usr/bin/env python
# -*- coding: utf-8 -*-
# --------------------------------------------------------------------
# The MIT License (MIT)
#
# Copyright (c) 2014 Jonathan Labéjof <jonathan.labejof@gmail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
# --------------------------------------------------------------------
from unittest import main
from b3j0f.utils.ut import UTCase
from six import PY3, PY2
from ..joinpoint import (
Joinpoint,
is_intercepted, get_intercepted,
_apply_interception, _unapply_interception,
_get_function, find_ctx, super_method
)
from types import MethodType, FunctionType
from inspect import isclass
[docs]class SuperMethodTest(UTCase):
"""
Test super method function.
"""
def _test_class(self, BaseTest):
class Test(BaseTest):
pass
class FinalTest(Test):
pass
finaltest = FinalTest()
super_elt, super_ctx = super_method(name='test', ctx=finaltest)
self.assertIs(
super_elt.__func__ if PY2 else super_elt,
FinalTest.test.__func__ if PY2 else FinalTest.test
)
self.assertIs(super_ctx, FinalTest)
super_elt, super_ctx = super_method(name='test', ctx=FinalTest)
self.assertIs(
super_elt.__func__ if PY2 else super_elt,
Test.test.__func__ if PY2 else Test.test
)
self.assertIs(super_ctx, Test)
super_elt, super_ctx = super_method(name='test', ctx=Test)
self.assertIs(
super_elt.__func__ if PY2 else super_elt,
BaseTest.test.__func__ if PY2 else BaseTest.test
)
self.assertIs(super_ctx, BaseTest)
super_elt, super_ctx = super_method(name='test', ctx=BaseTest)
self.assertIs(super_elt, None)
self.assertIs(super_ctx, None)
[docs] def test_namespace(self):
class BaseTest:
def test(self):
pass
self._test_class(BaseTest)
[docs] def test_class(self):
class BaseTest(object):
def test(self):
pass
self._test_class(BaseTest)
[docs]class FindCTXTest(UTCase):
"""
Test find_ctx function.
"""
[docs] def test_none(self):
ctx = find_ctx(None)
self.assertIsNone(ctx)
[docs] def test_class_method(self):
ctx = find_ctx(FindCTXTest.test_class_method)
if PY2:
self.assertIs(ctx, FindCTXTest)
elif PY3:
self.assertIsNone(ctx)
else:
raise NotImplementedError('Not implemented for python < 2 or > 3')
[docs] def test_instance_method(self):
ctx = find_ctx(self.test_instance_method)
self.assertIs(ctx, self)
[docs] def test_function(self):
def test():
pass
ctx = find_ctx(test)
self.assertIsNone(ctx)
[docs] def test_namespace(self):
class A:
pass
ctx = find_ctx(A)
self.assertIs(ctx, A)
[docs] def test_class(self):
class A(object):
pass
ctx = find_ctx(A)
self.assertIs(ctx, A)
[docs]class JoinpointProceedingTest(UTCase):
"""
Test to apply joinpoint poincut on any kinf of elements and parameters.
"""
[docs] def setUp(self):
"""
Create a default joinpoint with self joinpoint_proceeding such as the
only one advice and an integer count attribute equals 0.
"""
self.joinpoint = Joinpoint(advices=[self.joinpoint_proceeding])
self.count = 0
[docs] def joinpoint_proceeding(self, jp):
"""
Base joinpoint proceeding which increments self count and return the
proceeding result.
:param Joinpoint jp: joinpoint to proceed.
:return: joinpoint proceeding.
"""
self.count += 1
result = jp.proceed()
self.count += 2
return result
def _test_joinpoint_proceeding(
self,
target, ctx=None, expected_result=None, elt=None,
args=(), kwargs={}
):
"""
Do a serie of tests on joinpoint proceeding related to input target.
All targets may return result if not None, or themself.
:param callable target: callable target to intercept.
:param expected_result: target call result.
:param elt: element to call if not None.
:param args: target call var args.
:param kwargs: target call keywords.
"""
# check init context
self.assertEqual(self.count, 0)
# start to apply pointcut on joinpoint
self.joinpoint.set_target(target, ctx=ctx)
# update target with interception
jp_interception = self.joinpoint._interception
# call target
result = jp_interception(*args, **kwargs)
# compare result with target
if expected_result is None and not isclass(target):
expected_result = JoinpointProceedingTest
self.assertEqual(result, expected_result)
# compare count with before and after interception
self.assertEqual(self.count, 3)
# do the test a second time
result = jp_interception(*args, **kwargs)
# compare result with interception
self.assertEqual(result, expected_result)
# compare count with before and after interception
self.assertEqual(self.count, 6)
[docs] def test_namespace(self):
"""
Test to intercept a namespace.
"""
class Test:
pass
self._test_joinpoint_proceeding(
target=Test, ctx=Test, args=[Test()]
)
[docs] def test_instance_method(self):
"""
Test to intercept a method
"""
class Test(object):
def test(self):
return JoinpointProceedingTest
test = Test()
self._test_joinpoint_proceeding(test.test)
[docs] def test_builtin(self):
"""
Test to intercept a builtin.
"""
self._test_joinpoint_proceeding(max, expected_result=3, args=[2, 3])
[docs] def test_function(self):
"""
Test to intercept a function.
"""
def test():
return JoinpointProceedingTest
self._test_joinpoint_proceeding(test)
[docs] def test_function_params(self):
"""
Test to intercept a function with params.
"""
def test(a, b):
return JoinpointProceedingTest
self._test_joinpoint_proceeding(test, args=[1, 2])
[docs] def test_function_default_params(self):
"""
Test to intercept a function with default params.
"""
def test(a, b=None):
return JoinpointProceedingTest
self._test_joinpoint_proceeding(test, kwargs={'a': 1})
[docs] def test_function_closure(self):
"""
Test to intercept a function with closure.
"""
closure = 1
def test():
return closure
self._test_joinpoint_proceeding(test, expected_result=closure)
[docs] def test_function_args(self):
"""
Test to intercept a function with var args.
"""
def test(*args):
return JoinpointProceedingTest
self._test_joinpoint_proceeding(test)
[docs] def test_function_args_params(self):
"""
Test to intercept a function with var args and params.
"""
def test(a, b=1, *args):
return JoinpointProceedingTest
self._test_joinpoint_proceeding(test, args=[1])
[docs] def test_function_args_params_closure(self):
"""
Test to intercept a function with var args and params an closure.
"""
closure = 0
def test(a, b=1, *args):
return closure
self._test_joinpoint_proceeding(
test, args=[2], expected_result=closure)
[docs] def test_function_kwargs(self):
"""
Test to intercept a function with kwargs.
"""
def test(**kwargs):
return JoinpointProceedingTest
self._test_joinpoint_proceeding(test)
[docs] def test_function_kwargs_params(self):
"""
Test to intercept a function with kwargs and params.
"""
def test(a, b=1, **kwargs):
return JoinpointProceedingTest
self._test_joinpoint_proceeding(test, kwargs={'a': 1})
[docs] def test_function_kwargs_params_closure(self):
"""
Test to intercept a function with kwargs and params.
"""
closure = 0
def test(a, b=1, **kwargs):
return closure
self._test_joinpoint_proceeding(test, expected_result=0, args=[1])
[docs] def test_function_args_kwargs(self):
"""
Test to intercept a function with var args and kwargs.
"""
def test(*args, **kwargs):
return JoinpointProceedingTest
self._test_joinpoint_proceeding(test)
[docs] def test_function_args_kwargs_params(self):
"""
Test to intercept a function with var args, kwargs and params.
"""
def test(a, b=1, *args, **kwargs):
return JoinpointProceedingTest
self._test_joinpoint_proceeding(test, args=[1])
[docs] def test_function_args_kwargs_params_closure(self):
"""
Test to intercept a function with var args, kwargs, params and closure.
"""
closure = 0
def test(a, b=1, *args, **kwargs):
return closure
self._test_joinpoint_proceeding(
test, args=[1], expected_result=closure)
[docs]class JoinpointTest(UTCase):
[docs] def setUp(self):
self.count = 0
def a():
self.count += 1
return self.count
self.joinpoint = Joinpoint(target=a, advices=[])
[docs] def test_execution(self):
result = self.joinpoint.start()
self.assertEqual(result, 1)
[docs] def test_execution_twice(self):
result = self.joinpoint.start()
self.assertEqual(result, 1)
result = self.joinpoint.start()
self.assertEqual(result, 2)
[docs] def test_add_advices(self):
def advice(joinpoint):
proceed = joinpoint.proceed()
return proceed, 3
self.joinpoint._advices = [advice]
result = self.joinpoint.start()
self.assertEqual(result, (1, 3))
result = self.joinpoint.start()
self.assertEqual(result, (2, 3))
[docs]class GetFunctionTest(UTCase):
[docs] def test_class(self):
class A(object):
pass
func = _get_function(A)
self.assertEqual(func, A.__init__)
[docs] def test_namespace(self):
class A:
pass
func = _get_function(A)
to_compare = A.__init__
if PY2:
to_compare = to_compare.__func__
self.assertEqual(func, to_compare)
[docs] def test_builtin(self):
_max = _get_function(max)
self.assertIs(_max, max)
[docs] def test_method(self):
class A:
def method(self):
pass
func = _get_function(A.method)
_func = A.method if PY3 else A.method.__func__
self.assertIs(func, _func)
[docs] def test_instancemethod(self):
class A:
def method(self):
pass
a = A()
func = _get_function(a.method)
self.assertIs(func, a.method.__func__)
_func = A.method if PY3 else A.method.__func__
self.assertIs(func, _func)
[docs] def test_function(self):
def function():
pass
func = _get_function(function)
self.assertIs(func, function)
[docs] def test_call(self):
class A:
def __call__(self):
pass
a = A()
func = _get_function(a)
self.assertEqual(func, a.__call__.__func__)
[docs]class ApplyInterceptionTest(UTCase):
[docs] def test_function(self):
def function():
pass
__code__ = function.__code__
self.assertFalse(is_intercepted(function))
self.assertEqual(get_intercepted(function), (None, None))
interception, intercepted, ctx = _apply_interception(
function, lambda x: None)
self.assertTrue(isinstance(interception, FunctionType))
self.assertIs(interception, function)
self.assertEqual(get_intercepted(interception), (intercepted, ctx))
self.assertTrue(is_intercepted(interception))
self.assertIsNot(interception.__code__, __code__)
self.assertIs(intercepted.__code__, __code__)
_unapply_interception(function)
self.assertFalse(is_intercepted(function))
self.assertIs(interception, function)
self.assertIs(function.__code__, __code__)
self.assertEqual(get_intercepted(function), (None, None))
[docs] def test_method(self):
class A(object):
def method(self):
pass
self.assertEqual(get_intercepted(A.method), (None, None))
self.assertFalse(is_intercepted(A.method))
interception_fn = lambda: None
interception, intercepted, ctx = _apply_interception(
target=A.method,
interception_fn=interception_fn,
ctx=A)
joinpoint_type = FunctionType if PY3 else MethodType
self.assertTrue(isinstance(interception, joinpoint_type))
self.assertTrue(is_intercepted(A.method))
self.assertEqual(interception, A.method)
self.assertEqual((intercepted, ctx), get_intercepted(A.method))
_unapply_interception(target=A.method, ctx=A)
self.assertFalse(is_intercepted(A.method))
self.assertEqual(get_intercepted(A.method), (None, None))
[docs] def test_class_container(self):
class A(object):
def method(self):
pass
class B(A):
pass
self.assertEqual(A.method, B.method)
_apply_interception(
target=B.method,
interception_fn=lambda: None,
ctx=B)
self.assertNotEqual(A.method, B.method)
_unapply_interception(
target=B.method, ctx=B)
self.assertEqual(A.method, B.method)
[docs] def test_instance(self):
class A(object):
def method(self):
pass
class B(A):
pass
a = A()
b = B()
self.assertEqual(a.__dict__, b.__dict__)
_apply_interception(
target=b.method,
interception_fn=lambda: None)
self.assertNotEqual(a.__dict__, b.__dict__)
_unapply_interception(target=b.method)
self.assertEqual(a.__dict__, b.__dict__)
[docs] def test_builtin(self):
function = min
self.assertEqual(get_intercepted(min), (None, None))
self.assertFalse(is_intercepted(min))
interception, intercepted, ctx = _apply_interception(min, lambda: None)
self.assertTrue(isinstance(interception, FunctionType))
self.assertTrue(is_intercepted(min))
self.assertIs(interception, min)
self.assertIsNot(min, function)
self.assertEqual(get_intercepted(min), (intercepted, None))
_unapply_interception(interception)
self.assertFalse(is_intercepted(min))
self.assertIsNot(interception, min)
self.assertIs(min, function)
self.assertEqual(get_intercepted(min), (None, None))
[docs] def test_inheritance(self):
"""
Test interception in an inheritance context.
"""
def new_test():
def test():
pass
return test
def test():
pass
class Test0(object):
def test(self):
pass
class Test1(Test0):
pass
class Test2(Test1):
def test(self):
pass
test0 = Test0()
test1 = Test1()
test1.test = test
test2 = Test2()
# check for inherited method
_apply_interception(Test1.test, ctx=Test1, interception_fn=new_test())
self.assertFalse(is_intercepted(Test0.test))
self.assertTrue(is_intercepted(Test1.test))
self.assertFalse(is_intercepted(Test2.test))
self.assertFalse(is_intercepted(test0.test))
self.assertFalse(is_intercepted(test1.test))
self.assertFalse(is_intercepted(test2.test))
# check for base method
_apply_interception(Test0.test, ctx=Test0, interception_fn=new_test())
self.assertTrue(is_intercepted(Test0.test))
self.assertTrue(is_intercepted(Test1.test))
self.assertIsNot(_get_function(Test0.test), _get_function(Test1.test))
self.assertIsNot(Test0.test.__dict__, Test1.test.__dict__)
self.assertFalse(is_intercepted(Test2.test))
self.assertTrue(is_intercepted(test0.test))
self.assertIs(_get_function(Test0.test), _get_function(test0.test))
self.assertFalse(is_intercepted(test1.test))
self.assertFalse(is_intercepted(test2.test))
# check for overriden method
_apply_interception(Test2.test, ctx=Test2, interception_fn=new_test())
self.assertTrue(is_intercepted(Test0.test))
self.assertTrue(is_intercepted(Test1.test))
self.assertIsNot(_get_function(Test0.test), _get_function(Test1.test))
self.assertIsNot(Test0.test.__dict__, Test1.test.__dict__)
self.assertTrue(is_intercepted(Test2.test))
self.assertIsNot(_get_function(Test1.test), _get_function(Test2.test))
self.assertIsNot(Test1.test.__dict__, Test2.test.__dict__)
self.assertTrue(is_intercepted(test0.test))
self.assertIs(_get_function(Test0.test), _get_function(test0.test))
self.assertFalse(is_intercepted(test1.test))
self.assertTrue(is_intercepted(test2.test))
self.assertIs(_get_function(Test2.test), _get_function(test2.test))
# check for inherited instance method
_apply_interception(test0.test, interception_fn=new_test())
self.assertTrue(is_intercepted(Test0.test))
self.assertTrue(is_intercepted(Test1.test))
self.assertIsNot(_get_function(Test0.test), _get_function(Test1.test))
self.assertIsNot(Test0.test.__dict__, Test1.test.__dict__)
self.assertTrue(is_intercepted(Test2.test))
self.assertIsNot(_get_function(Test1.test), _get_function(Test2.test))
self.assertIsNot(Test1.test.__dict__, Test2.test.__dict__)
self.assertTrue(is_intercepted(test0.test))
self.assertIsNot(_get_function(Test0.test), _get_function(test0.test))
self.assertIsNot(test0.test.__dict__, Test0.test.__dict__)
self.assertFalse(is_intercepted(test1.test))
self.assertTrue(is_intercepted(test2.test))
self.assertIs(_get_function(Test2.test), _get_function(test2.test))
# check for overriden instance method
_apply_interception(test1.test, interception_fn=new_test())
self.assertTrue(is_intercepted(Test0.test))
self.assertTrue(is_intercepted(Test1.test))
self.assertIsNot(_get_function(Test0.test), _get_function(Test1.test))
self.assertIsNot(Test0.test.__dict__, Test1.test.__dict__)
self.assertTrue(is_intercepted(Test2.test))
self.assertIsNot(_get_function(Test1.test), _get_function(Test2.test))
self.assertIsNot(Test1.test.__dict__, Test2.test.__dict__)
self.assertTrue(is_intercepted(test0.test))
self.assertIsNot(_get_function(Test0.test), _get_function(test0.test))
self.assertIsNot(test0.test.__dict__, Test0.test.__dict__)
self.assertTrue(is_intercepted(test1.test))
self.assertIsNot(_get_function(Test1.test), _get_function(test1.test))
self.assertIsNot(test1.test.__dict__, Test1.test.__dict__)
self.assertTrue(is_intercepted(test2.test))
self.assertIs(_get_function(Test2.test), _get_function(test2.test))
# check to unapply base class method
_unapply_interception(Test0.test, ctx=Test0)
self.assertFalse(is_intercepted(Test0.test))
self.assertTrue(is_intercepted(Test1.test))
self.assertIsNot(_get_function(Test0.test), _get_function(Test1.test))
self.assertIsNot(Test0.test.__dict__, Test1.test.__dict__)
self.assertTrue(is_intercepted(Test2.test))
self.assertIsNot(_get_function(Test1.test), _get_function(Test2.test))
self.assertIsNot(Test1.test.__dict__, Test2.test.__dict__)
self.assertTrue(is_intercepted(test0.test))
self.assertIsNot(_get_function(Test0.test), _get_function(test0.test))
self.assertIsNot(test0.test.__dict__, Test0.test.__dict__)
self.assertTrue(is_intercepted(test1.test))
self.assertIsNot(_get_function(Test1.test), _get_function(test1.test))
self.assertIsNot(test1.test.__dict__, Test1.test.__dict__)
self.assertTrue(is_intercepted(test2.test))
self.assertIs(_get_function(Test2.test), _get_function(test2.test))
# check to unapply overriden method
_unapply_interception(Test2.test, ctx=Test2)
self.assertFalse(is_intercepted(Test0.test))
self.assertTrue(is_intercepted(Test1.test))
self.assertIsNot(_get_function(Test0.test), _get_function(Test1.test))
self.assertIsNot(Test0.test.__dict__, Test1.test.__dict__)
self.assertFalse(is_intercepted(Test2.test))
self.assertIsNot(_get_function(Test1.test), _get_function(Test2.test))
self.assertIsNot(Test1.test.__dict__, Test2.test.__dict__)
self.assertTrue(is_intercepted(test0.test))
self.assertIsNot(_get_function(Test0.test), _get_function(test0.test))
self.assertIsNot(test0.test.__dict__, Test0.test.__dict__)
self.assertTrue(is_intercepted(test1.test))
self.assertIsNot(_get_function(Test1.test), _get_function(test1.test))
self.assertIsNot(test1.test.__dict__, Test1.test.__dict__)
self.assertFalse(is_intercepted(test2.test))
_unapply_interception(test0.test)
self.assertFalse(is_intercepted(test0.test))
# check to unapply a method class which is overriden by an instance
_unapply_interception(Test1.test, ctx=Test1)
self.assertFalse(is_intercepted(Test1.test))
self.assertTrue(is_intercepted(test1.test))
# check to unapply an instance method
_unapply_interception(test1.test)
self.assertFalse(is_intercepted(test1.test))
if __name__ == '__main__':
main()