from mathlib import calc_math as m
import unittest


class add_test(unittest.TestCase):
    def test_add_positive(self):
        self.assertEqual(m.add(1, 1), 2)
        self.assertEqual(m.add(10, 0), 10)
        self.assertEqual(m.add(123456, 1), 123457)

    def test_add_negative(self):
        self.assertEqual(m.add(-1, -1), -2)
        self.assertEqual(m.add(-10, 0), -10)
        self.assertEqual(m.add(-123456, -1), -123457)

    def test_add_mix(self):
        self.assertEqual(m.add(-1, 1), 0)
        self.assertEqual(m.add(-10, 5), -5)
        self.assertEqual(m.add(-123456, 1), -123455)

    def test_add_float(self):
        self.assertAlmostEqual(m.add(1.1, 1.1), 2.2)
        self.assertAlmostEqual(m.add(5.321, 3.8467), 9.1677)
        self.assertAlmostEqual(m.add(-1.0, 1.1), 0.1)
        self.assertAlmostEqual(m.add(-5.54, -3.892), -9.432)


class array_sum_test(unittest.TestCase):
    def test_array_sum_positive(self):
        self.assertEqual(m.array_sum([1, 2, 3]), 6)
        self.assertEqual(m.array_sum([10, 20, 354]), 384)
        self.assertEqual(m.array_sum([0]), 0)
        self.assertEqual(m.array_sum([]), 0)

    def test_array_sum_negative(self):
        self.assertEqual(m.array_sum([-10, -5]), -15)
        self.assertEqual(m.array_sum([-300, -250]), -550)

    def test_array_sum_mix(self):
        self.assertEqual(m.array_sum([-1, 2, -3, 4]), 2)
        self.assertEqual(m.array_sum([-1, -2, 40]), 37)
        self.assertEqual(m.array_sum([1, 2, -40]), -37)

    def test_array_sum_float(self):
        self.assertAlmostEqual(m.array_sum([1.2, 2, 3]), 6.2)
        self.assertAlmostEqual(m.array_sum([-1.2, 2, 3]), 3.8)
        self.assertAlmostEqual(m.array_sum([-1.2, 3.874, -13.245]), -10.571)


class sub_test(unittest.TestCase):
    def test_sub_positive(self):
        self.assertEqual(m.sub(1, 1), 0)
        self.assertEqual(m.sub(10, 0), 10)
        self.assertEqual(m.sub(123456, 1), 123455)

    def test_sub_negative(self):
        self.assertEqual(m.sub(-1, -1), 0)
        self.assertEqual(m.sub(-10, 0), -10)
        self.assertEqual(m.sub(-123456, -1), -123455)

    def test_sub_mix(self):
        self.assertEqual(m.sub(-1, 1), -2)
        self.assertEqual(m.sub(-10, 5), -15)
        self.assertEqual(m.sub(-123456, 1), -123457)

    def test_sub_float(self):
        self.assertAlmostEqual(m.sub(1.1, 1.1), 0.0)
        self.assertAlmostEqual(m.sub(5.321, 3.8467), 1.4743)
        self.assertAlmostEqual(m.sub(-1.0, 1.1), -2.1)
        self.assertAlmostEqual(m.sub(-5.54, -3.892), -1.648)


class abs_val_test(unittest.TestCase):
    def test_abs_val_positive(self):
        self.assertEqual(m.abs_val(10), 10)
        self.assertEqual(m.abs_val(0), 0)
        self.assertEqual(m.abs_val(300), 300)
        self.assertEqual(m.abs_val(2503421), 2503421)

    def test_abs_val_negative(self):
        self.assertEqual(m.abs_val(-10), 10)
        self.assertEqual(m.abs_val(-300), 300)
        self.assertEqual(m.abs_val(-2503421), 2503421)


class mul_test(unittest.TestCase):
    def test_mul_zero(self):
        self.assertEqual(m.mul(10, 0), 0)
        self.assertEqual(m.mul(-10, 0), 0)
        self.assertEqual(m.mul(0, 0), 0)
        self.assertEqual(m.mul(545635675, 0), 0)

    def test_mul_positive(self):
        self.assertEqual(m.mul(1, 2), 2)
        self.assertEqual(m.mul(10, 2), 20)
        self.assertEqual(m.mul(345, 32), 11040)

    def test_mul_negative(self):
        self.assertEqual(m.mul(-1, -2), 2)
        self.assertEqual(m.mul(-10, -2), 20)
        self.assertEqual(m.mul(-345, -32), 11040)

    def test_mul_mix(self):
        self.assertEqual(m.mul(1, -2), -2)
        self.assertEqual(m.mul(10, -2), -20)
        self.assertEqual(m.mul(345, -32), -11040)

    def test_mul_float(self):
        self.assertAlmostEqual(m.mul(1.0, 2.3), 2.3)
        self.assertAlmostEqual(m.mul(1.5, 2.336), 3.504)
        self.assertAlmostEqual(m.mul(1.5, -2.336), -3.504)
        self.assertAlmostEqual(m.mul(0.5, -2.336), -1.168)


class div_test(unittest.TestCase):
    def test_div_zero(self):
        self.assertRaises(ZeroDivisionError, m.div, 1, 0)
        self.assertRaises(ZeroDivisionError, m.div, -1, 0)
        self.assertRaises(ZeroDivisionError, m.div, 436246, 0)

    def test_div_positive(self):
        self.assertAlmostEqual(m.div(10, 1), 10)
        self.assertAlmostEqual(m.div(10, 2), 5)
        self.assertAlmostEqual(m.div(5, 2), 2.5)

    def test_div_negative(self):
        self.assertAlmostEqual(m.div(-10, -1), 10)
        self.assertAlmostEqual(m.div(-10, -2), 5)
        self.assertAlmostEqual(m.div(-5, -2), 2.5)

    def test_div_mix(self):
        self.assertAlmostEqual(m.div(10, -1), -10)
        self.assertAlmostEqual(m.div(10, -2), -5)
        self.assertAlmostEqual(m.div(5, -2), -2.5)

    def test_div_float(self):
        self.assertAlmostEqual(m.div(15.9505, 4.37), 3.65)
        self.assertAlmostEqual(m.div(-15.9505, 4.37), -3.65)
        self.assertAlmostEqual(m.div(10, 0.01), 1000)

    def test_div_remainder(self):
        self.assertAlmostEqual(m.div(5, 2, -1)[0], 2)
        self.assertAlmostEqual(m.div(5, 2, -1)[1], 1)
        self.assertAlmostEqual(m.div(-1.5, 0.2, -1)[0], -7)
        self.assertAlmostEqual(m.div(-1.5, 0.2, -1)[1], -0.1)


class factor_test(unittest.TestCase):
    def test_factor_positive(self):
        self.assertEqual(m.factor(0), 1)
        self.assertEqual(m.factor(1), 1)
        self.assertEqual(m.factor(2), 2)
        self.assertEqual(m.factor(3), 6)
        self.assertEqual(m.factor(7), 5040)
        self.assertRaises(OverflowError, m.factor, 1000000)

    def test_factor_negative(self):
        self.assertRaises(ValueError, m.factor, -1)
        self.assertRaises(ValueError, m.factor, -5)

    def test_factor_float(self):
        self.assertRaises(ValueError, m.factor, -5.4)


class exp_test(unittest.TestCase):
    def test_exp_zero(self):
        self.assertEqual(m.exp(1, 0), 1)
        self.assertEqual(m.exp(-1, 0), 1)
        self.assertEqual(m.exp(43244234, 0), 1)

    def test_exp_positive(self):
        self.assertEqual(m.exp(1, 30), 1)
        self.assertEqual(m.exp(2, 2), 4)
        self.assertEqual(m.exp(3, 5), 243)

    def test_exp_negative(self):
        self.assertEqual(m.exp(-1, 2), 1)
        self.assertEqual(m.exp(-1, 3), -1)
        self.assertEqual(m.exp(-3, 5), -243)
        self.assertEqual(m.exp(-3, 6), 729)

    def test_exp_negative_exponent(self):
        self.assertRaises(ValueError, m.exp, 10, -1)
        self.assertRaises(ValueError, m.exp, -10, -1)

    def test_exp_float_exponent(self):
        self.assertRaises(ValueError, m.exp, -10, -1.5)


class rad_test(unittest.TestCase):
    def test_rad_zero(self):
        self.assertRaises(ValueError, m.rad, 1, 0)
        self.assertRaises(ValueError, m.rad, 30, 0)
        self.assertRaises(ValueError, m.rad, -30, 0)

    def test_rad_positive(self):
        self.assertEqual(m.rad(4, 2), 2)
        self.assertEqual(m.rad(8, 3), 2)
        self.assertEqual(m.rad(16, 4), 2)

    def test_rad_negative(self):
        self.assertEqual(m.rad(-8, 3), -2)
        self.assertEqual(m.rad(-27, 3), -3)
        self.assertRaises(ValueError, m.rad, -8, 2)
        self.assertRaises(ValueError, m.rad, -16, 4)

    def test_rad_negative_exponent(self):
        self.assertRaises(ValueError, m.exp, 10, -1)
        self.assertRaises(ValueError, m.exp, -10, -1)

    def test_rad_float_exponent(self):
        self.assertRaises(ValueError, m.exp, -10, -1.5)


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