import unittest
try:
    from .lib_misc import is_palindrome_integer
    from .lib_misc import is_palindrome_string
    from .lib_misc import get_digits_reversed
    from .lib_misc import get_item_counts
    from .lib_misc import product
    from .lib_misc import triangle_numbers
    from .lib_misc import even, odd
    from .lib_misc import collatz_sequence
    from .lib_misc import collatz_sequence_length
    from .lib_misc import factorial
    from .lib_misc import proper_divisors, sum_proper_divisors
    from .lib_misc import permutations
    from .lib_misc import gcd
except ModuleNotFoundError:
    from lib_misc import is_palindrome_integer
    from lib_misc import is_palindrome_string
    from lib_misc import get_digits_reversed
    from lib_misc import get_item_counts
    from lib_misc import product
    from lib_misc import triangle_numbers
    from lib_misc import even, odd
    from lib_misc import collatz_sequence
    from lib_misc import collatz_sequence_length
    from lib_misc import factorial
    from lib_misc import proper_divisors, sum_proper_divisors
    from lib_misc import permutations
    from lib_misc import gcd


class TestPrimeMethods(unittest.TestCase):

    def test_is_palindrome_integer(self):
        self.assertEqual(is_palindrome_integer(2), True)
        self.assertEqual(is_palindrome_integer(888), True)
        self.assertEqual(is_palindrome_integer(9009), True)
        self.assertEqual(is_palindrome_integer(23), False)
        self.assertEqual(is_palindrome_integer(9008), False)

    def test_is_palindrome_string(self):
        self.assertEqual(is_palindrome_string(2), True)
        self.assertEqual(is_palindrome_string(888), True)
        self.assertEqual(is_palindrome_string(9009), True)
        self.assertEqual(is_palindrome_string(23), False)
        self.assertEqual(is_palindrome_string(9008), False)

    def test_get_digits_reversed(self):
        self.assertEqual(get_digits_reversed(3), [3])
        self.assertEqual(get_digits_reversed(1234), [4, 3, 2, 1])
        self.assertEqual(get_digits_reversed(1000), [0, 0, 0, 1])

    def test_get_item_counts(self):
        self.assertEqual(get_item_counts([]), {})
        self.assertEqual(get_item_counts([1, 1, 3]), {1: 2, 3: 1})

    def test_product(self):
        self.assertEqual(product([2, 4, 8]), 64)
        self.assertEqual(product([]), 1)

    def test_triangle_numbers(self):
        f = triangle_numbers()
        self.assertEqual(next(f), 1)
        self.assertEqual(next(f), 3)
        self.assertEqual(next(f), 6)
        self.assertEqual(next(f), 10)
        self.assertEqual(next(f), 15)
        self.assertEqual(next(f), 21)

    def test_even_odd(self):
        self.assertTrue(odd(3))
        self.assertTrue(even(4))
        self.assertFalse(even(3))
        self.assertFalse(odd(4))

    def test_collatz(self):
        self.assertEqual(collatz_sequence(13),
                         [13, 40, 20, 10, 5, 16, 8, 4, 2, 1])
        self.assertEqual(collatz_sequence_length(13), 10)

    def test_factorial(self):
        self.assertEqual(factorial(1), 1)
        self.assertEqual(factorial(3), 6)
        self.assertEqual(factorial(10), 3628800)

    def test_proper_divisors(self):
        self.assertEqual(proper_divisors(0), [])
        self.assertEqual(proper_divisors(1), [])
        self.assertEqual(proper_divisors(2), [1])
        self.assertEqual(proper_divisors(4), [1, 2])
        self.assertEqual(proper_divisors(220), [
                         1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110])

    def test_sum_proper_divisors(self):
        self.assertEqual(sum_proper_divisors(0), 0)
        self.assertEqual(sum_proper_divisors(1), 0)
        self.assertEqual(sum_proper_divisors(2), 1)
        self.assertEqual(sum_proper_divisors(3), 1)
        self.assertEqual(sum_proper_divisors(220), 284)
        self.assertEqual(sum_proper_divisors(284), 220)

    def test_permutations(self):
        from itertools import permutations as std_permutations
        test_list = []
        p1 = list(map(tuple, permutations(test_list)))
        p2 = list(std_permutations(test_list))
        self.assertEqual(p1, p2)

        test_list = [1]
        p1 = list(map(tuple, permutations(test_list)))
        p2 = list(std_permutations(test_list))
        self.assertEqual(p1, p2)

        test_list = [1, 2, 3]
        p1 = list(map(tuple, permutations(test_list)))
        p2 = list(std_permutations(test_list))
        self.assertEqual(p1, p2)

        test_list = [1, 2, 3, 4, 5, 6]
        p1 = list(map(tuple, permutations(test_list)))
        p2 = list(std_permutations(test_list))
        self.assertEqual(p1, p2)

        test_list = "abc"
        p1 = list(map(tuple, permutations(test_list)))
        p2 = list(std_permutations(test_list))
        self.assertEqual(p1, p2)

    def test_gcd(self):
        self.assertEqual(gcd(3, 2), 1)
        self.assertEqual(gcd(15, 6), 3)
        self.assertEqual(gcd(6, 15), 3)


if __name__ == '__main__':
    unittest.main()
