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', False, 'import miniglm\n'), (11, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (16, 'miniglm.add', 'miniglm.add', False, 'import miniglm\n'), (17, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (22, 'miniglm.sub', 'miniglm.sub', False, 'import miniglm\n'), (23, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (28, 'miniglm.sub', 'miniglm.sub', False, 'import miniglm\n'), (29, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (34, 'miniglm.mul', 'miniglm.mul', False, 'import miniglm\n'), (35, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (40, 'miniglm.mul', 'miniglm.mul', False, 'import miniglm\n'), (41, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (46, 'miniglm.cross', 'miniglm.cross', False, 'import miniglm\n'), (47, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (52, 'miniglm.dot', 'miniglm.dot', False, 'import miniglm\n'), (53, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (57, 'miniglm.dot', 'miniglm.dot', False, 'import miniglm\n'), (58, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (62, 'miniglm.mix', 'miniglm.mix', False, 'import miniglm\n'), (63, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (68, 'miniglm.mix', 'miniglm.mix', False, 'import miniglm\n'), (69, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (75, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (81, 'miniglm.split', 'miniglm.split', False, 'import miniglm\n'), (82, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (83, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (88, 'miniglm.rotate', 'miniglm.rotate', False, 'import miniglm\n'), (93, 'miniglm.rotate', 'miniglm.rotate', False, 'import miniglm\n'), (98, 'miniglm.rotate', 'miniglm.rotate', False, 'import miniglm\n'), (103, 'miniglm.norm', 'miniglm.norm', False, 'import miniglm\n'), (105, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (110, 'miniglm.norm', 'miniglm.norm', False, 'import miniglm\n'), (112, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (122, 'miniglm.norm', 'miniglm.norm', False, 'import miniglm\n'), (141, 'miniglm.swizzle', 'miniglm.swizzle', False, 'import miniglm\n'), (142, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (146, 'miniglm.swizzle', 'miniglm.swizzle', False, 'import miniglm\n'), (147, 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', True, 'import numpy as np\n'), (73, 'miniglm.norm', 'miniglm.norm', False, 'import miniglm\n'), (123, 'miniglm.det', 'miniglm.det', False, 'import miniglm\n'), (124, 'miniglm.cross', 'miniglm.cross', False, 'import miniglm\n'), (125, 'miniglm.dot', 'miniglm.dot', False, 'import miniglm\n'), (126, 'miniglm.dot', 'miniglm.dot', False, 'import miniglm\n'), (127, 'miniglm.dot', 'miniglm.dot', False, 'import miniglm\n'), (134, 'miniglm.cast', 'miniglm.cast', False, 'import miniglm\n'), (135, 'miniglm.cast', 'miniglm.cast', False, 'import miniglm\n'), (151, 'miniglm.pack', 'miniglm.pack', False, 'import miniglm\n'), (151, 'struct.pack', 'struct.pack', False, 'import struct\n'), (156, 'miniglm.pack', 'miniglm.pack', False, 'import miniglm\n'), (156, 'struct.pack', 'struct.pack', False, 'import struct\n'), (161, 'miniglm.pack', 'miniglm.pack', False, 'import miniglm\n'), (161, 'struct.pack', 'struct.pack', False, 'import struct\n'), (166, 'miniglm.pack', 'miniglm.pack', False, 'import miniglm\n'), (166, 'struct.pack', 'struct.pack', False, 'import struct\n'), (136, 'miniglm.cast', 'miniglm.cast', False, 'import miniglm\n'), (137, 'miniglm.cast', 'miniglm.cast', False, 'import miniglm\n'), (89, 'numpy.sqrt', 'np.sqrt', True, 'import numpy as np\n'), (89, 'numpy.sqrt', 'np.sqrt', True, 'import numpy as np\n'), (94, 'numpy.sqrt', 'np.sqrt', True, 'import numpy as np\n'), (94, 'numpy.sqrt', 'np.sqrt', True, 'import numpy as np\n'), (99, 'numpy.sqrt', 'np.sqrt', True, 'import numpy as np\n'), (99, 'numpy.sqrt', 'np.sqrt', True, 'import numpy as np\n')]