import unittest

from turbogears.decorator import *
from turbogears import testutil


def d1(func):
    def call(func, *args, **kw):
        return func(*args, **kw)
    return call
d1 = decorator(d1)

def d2(func):
    def call(func, *args, **kw):
        return func(*args, **kw)
    return call
d2 = decorator(d2)

def d3(func):
    func.baz2 = 2
    def call(func, *args, **kw):
        return func(*args, **kw)
    return call
d3 = decorator(d3)

def foo(a, b):
    return a+b
foo.baz1 = 1

bar = foo

foo = d1(foo)
foo = d2(foo)
foo = d3(foo)

def addn(n):
    def entangle(func):
        def call(func, *args, **kw):
            return func(*args, **kw) + n
        return call
    return decorator(entangle)

[addn(11)]
def py23(a):
    return a

[compose(addn(1), addn(2))]
def composed(a):
    return a

def weakener():
    def entangle(func):
        def call(func, *args, **kw):
            return len(args)
        return call
    return weak_signature_decorator(entangle)

[weakener()]
def weakling():
    pass

def sig_changer():
    def entangle(func):
        def call(func, a, b):
            return func(b)
        return call
    return decorator(entangle, (["a", "b"], None, None, None))

[sig_changer()]
def new_sig(a):
    return a

def simple(func, *args, **kw):
    return func(*args, **kw) + 1
simple = simple_decorator(simple)

def simple_weakener(func, *args, **kw):
     return len(args)
simple_weakener = simple_weak_signature_decorator(simple_weakener)

def simple_weakling():
    pass
simple_weakling = simple_weakener(simple_weakling)

def simple_adder1(a):
    return a
simple_adder1 = simple(simple_adder1)

class TestDecorator(unittest.TestCase):

    def test_preservation(self):
        for key, value in bar.__dict__.iteritems():
            self.failUnless(key in foo.__dict__)
            self.failUnless(value == foo.__dict__[key])
        self.failUnless(bar.__name__ == foo.__name__)
        self.failUnless(bar.__module__ == foo.__module__)
        self.failUnless(bar.__doc__ == foo.__doc__)

    def test_eq(self):
        self.failUnless(func_id(foo) == func_id(bar))
        self.failUnless(func_eq(foo, bar))
        self.failUnless(bar == func_original(foo))
        self.failUnless(bar is func_original(foo))

    def test_history(self):
        self.failUnless(len(func_composition(foo)) == 4)
        self.failUnless(func_composition(foo)[:-1] ==
                        func_composition(func_composition(foo)[-2]))

    def test_23compatibility(self):
        self.failUnless(py23(2)==13)

    def test_attributes(self):
        self.failUnless(foo.baz1==1)
        self.failUnless(foo.baz2==2)

    def test_composition(self):
        self.failUnless(addn(3)(py23)(2)==16)
        self.failUnless(composed(1)==4, composed(1))
        self.failUnless(composed.__name__ == "composed")

    def test_signature(self):
        self.failUnless(make_weak_signature(bar)[1:3]==(
                        "_decorator__varargs", "_decorator__kwargs"))
        self.failUnless(weakling(1,2)==2)
        self.failUnless(new_sig(1,2)==2)

    def test_simple_decorators(self):
        self.failUnless(simple_adder1(1)==2)
        self.failUnless(simple_weakling(1,2)==2)
