import struct

import numpy as np
import pytest

import miniglm


def test_add_vec_vec():
    res = miniglm.add((1.0, 2.0, 3.0), (1.5, 1.8, 1.2))
    np.testing.assert_almost_equal(res, (2.5, 3.8, 4.2))
    assert type(res) is tuple


def test_add_vec_scalar():
    res = miniglm.add((1.0, 2.0, 3.0), 0.5)
    np.testing.assert_almost_equal(res, (1.5, 2.5, 3.5))
    assert type(res) is tuple


def test_sub_vec_vec():
    res = miniglm.sub((5.0, 6.0, 7.0), (1.5, 1.8, 1.2))
    np.testing.assert_almost_equal(res, (3.5, 4.2, 5.8))
    assert type(res) is tuple


def test_sub_vec_scalar():
    res = miniglm.sub((5.0, 6.0, 7.0), 1.5)
    np.testing.assert_almost_equal(res, (3.5, 4.5, 5.5))
    assert type(res) is tuple


def test_mul_vec_vec():
    res = miniglm.mul((5.0, 6.0, 7.0), (1.5, 1.8, 1.2))
    np.testing.assert_almost_equal(res, (7.5, 10.8, 8.4))
    assert type(res) is tuple


def test_mul_vec_scalar():
    res = miniglm.mul((1.0, 2.0, 3.0), 2.0)
    np.testing.assert_almost_equal(res, (2.0, 4.0, 6.0))
    assert type(res) is tuple


def test_cross():
    res = miniglm.cross((2.0, 3.5, 7.1), (0.2, 10.0, 3.3))
    np.testing.assert_almost_equal(res, (-59.45, -5.18, 19.3))
    assert type(res) is tuple


def test_dot_vec():
    res = miniglm.dot((2.0, 3.5, 7.1), (0.2, 10.0, 3.3))
    np.testing.assert_almost_equal(res, 58.83)


def test_dot_quat():
    res = miniglm.dot((2.0, 3.5, 7.1), (0.2, 10.0, 3.3))
    np.testing.assert_almost_equal(res, 58.83)


def test_mix_vec():
    res = miniglm.mix((2.5, 3.4, 4.6), (7.2, 1.1, 3.2), 0.2)
    np.testing.assert_almost_equal(res, (3.44, 2.94, 4.32))
    assert type(res) is tuple


def test_mix_scalar():
    res = miniglm.mix(1.0, 3.0, 0.5)
    np.testing.assert_almost_equal(res, 2.0)


def test_rotate():
    res = miniglm.rotate(miniglm.pi / 3.0, miniglm.norm((0.48, 0.60, 0.64)))
    expected = (0.24, 0.3, 0.32, 0.8660254037844387)
    np.testing.assert_almost_equal(res, expected)
    assert type(res) is tuple


def test_split_quat():
    quat = (0.24, 0.3, 0.32, 0.8660254037844387)
    angle, axis = miniglm.split(quat)
    np.testing.assert_almost_equal(angle, miniglm.pi / 3.0)
    np.testing.assert_almost_equal(axis, (0.48, 0.60, 0.64))
    assert type(axis) is tuple


def test_rotate_x_90_deg():
    res = miniglm.rotate(miniglm.pi / 2.0, (1.0, 0.0, 0.0))
    np.testing.assert_almost_equal(res, (np.sqrt(2.0) / 2.0, 0.0, 0.0, np.sqrt(2.0) / 2.0))


def test_rotate_y_90_deg():
    res = miniglm.rotate(miniglm.pi / 2.0, (0.0, 1.0, 0.0))
    np.testing.assert_almost_equal(res, (0.0, np.sqrt(2.0) / 2.0, 0.0, np.sqrt(2.0) / 2.0))


def test_rotate_z_90_deg():
    res = miniglm.rotate(miniglm.pi / 2.0, (0.0, 0.0, 1.0))
    np.testing.assert_almost_equal(res, (0.0, 0.0, np.sqrt(2.0) / 2.0, np.sqrt(2.0) / 2.0))


def test_norm_vec():
    res = miniglm.norm((48.0, 60.0, 64.0))
    expected = (0.48, 0.60, 0.64)
    np.testing.assert_almost_equal(res, expected)
    assert type(res) is tuple


def test_norm_quat():
    res = miniglm.norm((2.0, 4.0, 8.0, 4.0))
    expected = (0.2, 0.4, 0.8, 0.4)
    np.testing.assert_almost_equal(res, expected)
    assert type(res) is tuple


def test_norm_mat():
    mat = (
        0.074, 0.962, -0.259,
        -0.518, 0.259, 0.814,
        0.851, 0.074, 0.518,
    )
    res = miniglm.norm(mat)
    np.testing.assert_almost_equal(miniglm.det(res), 1.0)
    np.testing.assert_almost_equal(miniglm.cross(res[0:3], res[3:6]), res[6:9])
    np.testing.assert_almost_equal(miniglm.dot(res[0:3], res[3:6]), 0.0)
    np.testing.assert_almost_equal(miniglm.dot(res[3:6], res[6:9]), 0.0)
    np.testing.assert_almost_equal(miniglm.dot(res[0:3], res[6:9]), 0.0)
    assert type(res) is tuple


def test_cast():
    quat = (0.2, 0.4, 0.8, 0.4)
    mat = (-0.6, 0.8, 0.0, -0.48, -0.36, 0.8, 0.64, 0.48, 0.6)
    np.testing.assert_almost_equal(miniglm.cast(quat), mat)
    np.testing.assert_almost_equal(miniglm.cast(mat), quat)
    np.testing.assert_almost_equal(miniglm.cast(miniglm.cast(quat)), quat)
    np.testing.assert_almost_equal(miniglm.cast(miniglm.cast(mat)), mat)


def test_swizzle_vec():
    res = miniglm.swizzle((1.0, 2.0, 3.0), 'yxz')
    np.testing.assert_almost_equal(res, (2.0, 1.0, 3.0))


def test_swizzle_quat():
    res = miniglm.swizzle((0.1, 0.7, 0.5, 0.5), 'wxyz')
    np.testing.assert_almost_equal(res, (0.5, 0.1, 0.7, 0.5))


def test_pack_scalar():
    assert miniglm.pack(1.75) == struct.pack('f', 1.75)


def test_pack_vec():
    vec = (1.0, 2.0, 3.0)
    assert miniglm.pack(vec) == struct.pack('fff', *vec)


def test_pack_quat():
    quat = (0.1, 0.7, 0.5, 0.5)
    assert miniglm.pack(quat) == struct.pack('ffff', *quat)


def test_pack_mat():
    mat = (1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
    assert miniglm.pack(mat) == struct.pack('fffffffff', *mat)

[(10, 'miniglm.add', 'miniglm.add', (['(1.0, 2.0, 3.0)', '(1.5, 1.8, 1.2)'], {}), False, 'import miniglm\n'), (11, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(2.5, 3.8, 4.2)'], {}), True, 'import numpy as np\n'), (16, 'miniglm.add', 'miniglm.add', (['(1.0, 2.0, 3.0)', '(0.5)'], {}), False, 'import miniglm\n'), (17, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(1.5, 2.5, 3.5)'], {}), True, 'import numpy as np\n'), (22, 'miniglm.sub', 'miniglm.sub', (['(5.0, 6.0, 7.0)', '(1.5, 1.8, 1.2)'], {}), False, 'import miniglm\n'), (23, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(3.5, 4.2, 5.8)'], {}), True, 'import numpy as np\n'), (28, 'miniglm.sub', 'miniglm.sub', (['(5.0, 6.0, 7.0)', '(1.5)'], {}), False, 'import miniglm\n'), (29, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(3.5, 4.5, 5.5)'], {}), True, 'import numpy as np\n'), (34, 'miniglm.mul', 'miniglm.mul', (['(5.0, 6.0, 7.0)', '(1.5, 1.8, 1.2)'], {}), False, 'import miniglm\n'), (35, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(7.5, 10.8, 8.4)'], {}), True, 'import numpy as np\n'), (40, 'miniglm.mul', 'miniglm.mul', (['(1.0, 2.0, 3.0)', '(2.0)'], {}), False, 'import miniglm\n'), (41, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(2.0, 4.0, 6.0)'], {}), True, 'import numpy as np\n'), (46, 'miniglm.cross', 'miniglm.cross', (['(2.0, 3.5, 7.1)', '(0.2, 10.0, 3.3)'], {}), False, 'import miniglm\n'), (47, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(-59.45, -5.18, 19.3)'], {}), True, 'import numpy as np\n'), (52, 'miniglm.dot', 'miniglm.dot', (['(2.0, 3.5, 7.1)', '(0.2, 10.0, 3.3)'], {}), False, 'import miniglm\n'), (53, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(58.83)'], {}), True, 'import numpy as np\n'), (57, 'miniglm.dot', 'miniglm.dot', (['(2.0, 3.5, 7.1)', '(0.2, 10.0, 3.3)'], {}), False, 'import miniglm\n'), (58, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(58.83)'], {}), True, 'import numpy as np\n'), (62, 'miniglm.mix', 'miniglm.mix', (['(2.5, 3.4, 4.6)', '(7.2, 1.1, 3.2)', '(0.2)'], {}), False, 'import miniglm\n'), (63, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(3.44, 2.94, 4.32)'], {}), True, 'import numpy as np\n'), (68, 'miniglm.mix', 'miniglm.mix', (['(1.0)', '(3.0)', '(0.5)'], {}), False, 'import miniglm\n'), (69, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(2.0)'], {}), True, 'import numpy as np\n'), (75, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', 'expected'], {}), True, 'import numpy as np\n'), (81, 'miniglm.split', 'miniglm.split', (['quat'], {}), False, 'import miniglm\n'), (82, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['angle', '(miniglm.pi / 3.0)'], {}), True, 'import numpy as np\n'), (83, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['axis', '(0.48, 0.6, 0.64)'], {}), True, 'import numpy as np\n'), (88, 'miniglm.rotate', 'miniglm.rotate', (['(miniglm.pi / 2.0)', '(1.0, 0.0, 0.0)'], {}), False, 'import miniglm\n'), (93, 'miniglm.rotate', 'miniglm.rotate', (['(miniglm.pi / 2.0)', '(0.0, 1.0, 0.0)'], {}), False, 'import miniglm\n'), (98, 'miniglm.rotate', 'miniglm.rotate', (['(miniglm.pi / 2.0)', '(0.0, 0.0, 1.0)'], {}), False, 'import miniglm\n'), (103, 'miniglm.norm', 'miniglm.norm', (['(48.0, 60.0, 64.0)'], {}), False, 'import miniglm\n'), (105, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', 'expected'], {}), True, 'import numpy as np\n'), (110, 'miniglm.norm', 'miniglm.norm', (['(2.0, 4.0, 8.0, 4.0)'], {}), False, 'import miniglm\n'), (112, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', 'expected'], {}), True, 'import numpy as np\n'), (122, 'miniglm.norm', 'miniglm.norm', (['mat'], {}), False, 'import miniglm\n'), (141, 'miniglm.swizzle', 'miniglm.swizzle', (['(1.0, 2.0, 3.0)', '"""yxz"""'], {}), False, 'import miniglm\n'), (142, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(2.0, 1.0, 3.0)'], {}), True, 'import numpy as np\n'), (146, 'miniglm.swizzle', 'miniglm.swizzle', (['(0.1, 0.7, 0.5, 0.5)', '"""wxyz"""'], {}), False, 'import miniglm\n'), (147, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', (['res', '(0.5, 0.1, 0.7, 0.5)'], {}), True, 'import numpy as np\n'), (73, 'miniglm.norm', 'miniglm.norm', (['(0.48, 0.6, 0.64)'], {}), False, 'import miniglm\n'), (123, 'miniglm.det', 'miniglm.det', (['res'], {}), False, 'import miniglm\n'), (124, 'miniglm.cross', 'miniglm.cross', (['res[0:3]', 'res[3:6]'], {}), False, 'import miniglm\n'), (125, 'miniglm.dot', 'miniglm.dot', (['res[0:3]', 'res[3:6]'], {}), False, 'import miniglm\n'), (126, 'miniglm.dot', 'miniglm.dot', (['res[3:6]', 'res[6:9]'], {}), False, 'import miniglm\n'), (127, 'miniglm.dot', 'miniglm.dot', (['res[0:3]', 'res[6:9]'], {}), False, 'import miniglm\n'), (134, 'miniglm.cast', 'miniglm.cast', (['quat'], {}), False, 'import miniglm\n'), (135, 'miniglm.cast', 'miniglm.cast', (['mat'], {}), False, 'import miniglm\n'), (151, 'miniglm.pack', 'miniglm.pack', (['(1.75)'], {}), False, 'import miniglm\n'), (151, 'struct.pack', 'struct.pack', (['"""f"""', '(1.75)'], {}), False, 'import struct\n'), (156, 'miniglm.pack', 'miniglm.pack', (['vec'], {}), False, 'import miniglm\n'), (156, 'struct.pack', 'struct.pack', (['"""fff"""', '*vec'], {}), False, 'import struct\n'), (161, 'miniglm.pack', 'miniglm.pack', (['quat'], {}), False, 'import miniglm\n'), (161, 'struct.pack', 'struct.pack', (['"""ffff"""', '*quat'], {}), False, 'import struct\n'), (166, 'miniglm.pack', 'miniglm.pack', (['mat'], {}), False, 'import miniglm\n'), (166, 'struct.pack', 'struct.pack', (['"""fffffffff"""', '*mat'], {}), False, 'import struct\n'), (136, 'miniglm.cast', 'miniglm.cast', (['quat'], {}), False, 'import miniglm\n'), (137, 'miniglm.cast', 'miniglm.cast', (['mat'], {}), False, 'import miniglm\n'), (89, 'numpy.sqrt', 'np.sqrt', (['(2.0)'], {}), True, 'import numpy as np\n'), (89, 'numpy.sqrt', 'np.sqrt', (['(2.0)'], {}), True, 'import numpy as np\n'), (94, 'numpy.sqrt', 'np.sqrt', (['(2.0)'], {}), True, 'import numpy as np\n'), (94, 'numpy.sqrt', 'np.sqrt', (['(2.0)'], {}), True, 'import numpy as np\n'), (99, 'numpy.sqrt', 'np.sqrt', (['(2.0)'], {}), True, 'import numpy as np\n'), (99, 'numpy.sqrt', 'np.sqrt', (['(2.0)'], {}), True, 'import numpy as np\n')]