# Moovida - Home multimedia server
# Copyright (C) 2006-2009 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Moovida with Fluendo's plugins.
#
# The GPL part of Moovida is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Moovida" in the root directory of this distribution package
# for details on that license.

from twisted.trial import unittest
from elisa.core.utils import signal

import gc

class TestSignal(unittest.TestCase):

    def test_emit(self):
        """
        Create a signal, connect a function to it and emit it.
        """
        def test(number, text):
            self.assertEquals(number, 42)
            self.assertEquals(text, "boudiou")
            test.called = True

        test.called = False

        signal1 = signal.Signal('test-signal',int, object)
        signal1.connect(test)

        signal1.emit(42, "boudiou")
        self.assertEquals(test.called, True)

    def test_emit_with_argument(self):
        """
        Create a signal, connect a function with attributes and keywords to it
        and emit it.
        """

        def test(number, text, arg1, arg2, arg3, foo='bar', answer='no'):
            self.assertEquals(number, 42)
            self.assertEquals(text, 'pocahontas')
            self.assertEquals(arg1, 1)
            self.assertEquals(arg2, ['a', 'b', 3])
            self.assertEquals(arg3, '4')
            self.assertEquals(foo, 'barbar')
            # be sure that the signals keyword got used!
            self.assertEquals(answer, 'yes')
            test.called = True

        test.called = False

        args = (1, ['a', 'b', 3], '4')
        kw = {'foo':'barbar', # this one is used
              'answer':'maybe' # this one gets overwritten with value
              }
        signal1 = signal.Signal('test-signal', int, object, answer=str)
        signal1.connect(test, *args, **kw)

        signal1.emit(42, 'pocahontas', answer='yes')
        self.assertTrue(test.called)

    def test_wrong_argument(self):
        """
        test to emit the signal with wrong argument types
        """
        def test(number, text, foo=0):
            self.assertEquals(number, 42)
            self.assertEquals(text, "boudiou")
            self.assertEquals(foo, 0)
            test.called = True

        test.called = False

        signal1 = signal.Signal('test-signal', int, object, foo=int)
        signal1.connect(test)

        signal1.emit(42, "boudiou")
        self.assertEquals(test.called, True)

        # wrong keyword type
        self.assertRaises(signal.WrongArgument, signal1.emit, 42, "bar",
                          foo="bar")

        # wrong parameter type
        self.assertRaises(signal.WrongArgument, signal1.emit, '42', 'bar',
                          foo="bar")

    def test_non_callable(self):
        """
        test what happens if you try to connect a non callable
        """
        signal1 = signal.Signal('test-signal', int, object)
        self.assertRaises(TypeError, signal1.connect, object())

    def test_disconnect(self):
        """
        Test that a disconnected callback does not get triggered anymore
        """
        def test(number, text):
            self.assertEquals(number, 42)
            self.assertEquals(text, "boudiou")
            test.called = True

        test.called = False

        signal1 = signal.Signal('test-signal',int, object)
        signal1.connect(test)
        signal1.disconnect(test)

        signal1.emit(42, "boudiou")
        self.assertEquals(test.called, False)

    def test_refcounting(self):
        """
        test if the refcounting is not increasing by adding a callback to the
        signal
        """

        def method_to_call(self):
            print "I don't get called anyway :("
    
        # check before
        before = len(gc.get_referents(method_to_call))

        sign1 = signal.Signal('yay', int)
        sign1.connect(method_to_call)

        # after adding it
        after = len(gc.get_referents(method_to_call))
        self.assertEquals(before, after)



