from .samples import my_func, _my_private_func, MyClass
from ...utils.predicates import func_class_name_is_in, func_class_name_is_not_in, func_name_is_in, func_name_is_not_in, func_is_public
from django.test import SimpleTestCase


class PredicatesTest(SimpleTestCase):

    def __test_func_class_name_is_in(self, negation: bool = False):
        """ teste func_class_name_is_in et func_class_name_is_not_in """

        func = func_class_name_is_not_in if negation else func_class_name_is_in
        result = negation is not True

        own_name = self.__class__.__name__
        MainType = MyClass
        main_type = MainType(11)
        main_type_name = MainType.__name__
        SubType = MyClass.MySubClass
        sub_type = SubType(13)
        sub_type_name = SubType.__name__

        def local_func(a: int, b: int):
            return a + b

        # fonction native : None
        self.assertEqual(func(str.__name__)(str.join), False)

        # fonction locale : None
        self.assertEqual(func(own_name)(local_func), False)

        # méthodes
        predicate = func(main_type_name)
        self.assertEqual(predicate(MainType.class_met), result)
        self.assertEqual(predicate(MainType.static_met), result)
        self.assertEqual(predicate(main_type.std_met), result)
        self.assertEqual(predicate(SubType.sub_class_met), not result)
        self.assertEqual(predicate(SubType.sub_static_met), not result)
        self.assertEqual(predicate(sub_type.sub_std_met), not result)

        predicate = func(sub_type_name)
        self.assertEqual(predicate(MainType.class_met), not result)
        self.assertEqual(predicate(MainType.static_met), not result)
        self.assertEqual(predicate(main_type.std_met), not result)
        self.assertEqual(predicate(SubType.sub_class_met), result)
        self.assertEqual(predicate(SubType.sub_static_met), result)
        self.assertEqual(predicate(sub_type.sub_std_met), result)

    def __test_func_name_is_in(self, negation: bool = False):
        """ teste func_name_is_in et func_name_is_not_in """

        func = func_name_is_not_in if negation else func_name_is_in
        result = negation is not True

        MainType = MyClass
        main_type = MainType(11)
        SubType = MyClass.MySubClass
        sub_type = SubType(13)

        def local_func(a: int, b: int):
            return a + b

        # fonction native
        self.assertEqual(func('join')(str.join), result)
        self.assertEqual(func('other', 'join')(str.join), result)

        # autre fonction, fonction locale
        self.assertEqual(func('local_func')(local_func), result)
        self.assertEqual(func('other', 'local_func')(local_func), result)
        self.assertEqual(func('my_func')(my_func), result)
        self.assertEqual(func('other', 'my_func')(my_func), result)


        # méthodes
        predicate = func('class_met', 'std_met', 'sub_static_met')
        self.assertEqual(predicate(MainType.class_met), result)
        self.assertEqual(predicate(MainType.static_met), not result)
        self.assertEqual(predicate(main_type.std_met), result)
        self.assertEqual(predicate(SubType.sub_class_met), not result)
        self.assertEqual(predicate(SubType.sub_static_met), result)
        self.assertEqual(predicate(sub_type.sub_std_met), not result)

        predicate = func('static_met', 'sub_class_met', 'sub_std_met')
        self.assertEqual(predicate(MainType.class_met), not result)
        self.assertEqual(predicate(MainType.static_met), result)
        self.assertEqual(predicate(main_type.std_met), not result)
        self.assertEqual(predicate(SubType.sub_class_met), result)
        self.assertEqual(predicate(SubType.sub_static_met), not result)
        self.assertEqual(predicate(sub_type.sub_std_met), result)


    def test_func_class_name_is_in(self):
        self.__test_func_class_name_is_in()

    def test_func_class_name_is_not_in(self):
        self.__test_func_class_name_is_in(negation=True)

    def test_func_name_is_in(self):
        self.__test_func_name_is_in()

    def test_func_name_is_not_in(self):
        self.__test_func_name_is_in(negation=True)

    def test_func_is_public(self):
        MainType = MyClass
        main_type = MainType(11)
        SubType = MyClass.MySubClass
        sub_type = SubType(13)

        def local_func(a: int, b: int):
            return a + b

        # fonction native
        self.assertEqual(func_is_public(str.join), True)

        # autre fonction, fonction locale
        self.assertEqual(func_is_public(local_func), True)
        self.assertEqual(func_is_public(my_func), True)
        self.assertEqual(func_is_public(_my_private_func), False)

        # méthodes
        self.assertEqual(func_is_public(MainType._protected_met), False)
        self.assertEqual(func_is_public(MainType.class_met), True)
        self.assertEqual(func_is_public(MainType.static_met), True)
        self.assertEqual(func_is_public(main_type.std_met), True)
        self.assertEqual(func_is_public(SubType.sub_class_met), True)
        self.assertEqual(func_is_public(SubType.sub_static_met), True)
        self.assertEqual(func_is_public(sub_type.sub_std_met), True)
