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, 10, 10, 55), 'miniglm.add', 'miniglm.add', ({(10, 22, 10, 37): '(1.0, 2.0, 3.0)', (10, 39, 10, 54): '(1.5, 1.8, 1.2)'}, {}), '((1.0, 2.0, 3.0), (1.5, 1.8, 1.2))', False, 'import miniglm\n'), ((11, 4, 11, 56), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(11, 35, 11, 38): 'res', (11, 40, 11, 55): '(2.5, 3.8, 4.2)'}, {}), '(res, (2.5, 3.8, 4.2))', True, 'import numpy as np\n'), ((16, 10, 16, 43), 'miniglm.add', 'miniglm.add', ({(16, 22, 16, 37): '(1.0, 2.0, 3.0)', (16, 39, 16, 42): '0.5'}, {}), '((1.0, 2.0, 3.0), 0.5)', False, 'import miniglm\n'), ((17, 4, 17, 56), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(17, 35, 17, 38): 'res', (17, 40, 17, 55): '(1.5, 2.5, 3.5)'}, {}), '(res, (1.5, 2.5, 3.5))', True, 'import numpy as np\n'), ((22, 10, 22, 55), 'miniglm.sub', 'miniglm.sub', ({(22, 22, 22, 37): '(5.0, 6.0, 7.0)', (22, 39, 22, 54): '(1.5, 1.8, 1.2)'}, {}), '((5.0, 6.0, 7.0), (1.5, 1.8, 1.2))', False, 'import miniglm\n'), ((23, 4, 23, 56), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(23, 35, 23, 38): 'res', (23, 40, 23, 55): '(3.5, 4.2, 5.8)'}, {}), '(res, (3.5, 4.2, 5.8))', True, 'import numpy as np\n'), ((28, 10, 28, 43), 'miniglm.sub', 'miniglm.sub', ({(28, 22, 28, 37): '(5.0, 6.0, 7.0)', (28, 39, 28, 42): '1.5'}, {}), '((5.0, 6.0, 7.0), 1.5)', False, 'import miniglm\n'), ((29, 4, 29, 56), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(29, 35, 29, 38): 'res', (29, 40, 29, 55): '(3.5, 4.5, 5.5)'}, {}), '(res, (3.5, 4.5, 5.5))', True, 'import numpy as np\n'), ((34, 10, 34, 55), 'miniglm.mul', 'miniglm.mul', ({(34, 22, 34, 37): '(5.0, 6.0, 7.0)', (34, 39, 34, 54): '(1.5, 1.8, 1.2)'}, {}), '((5.0, 6.0, 7.0), (1.5, 1.8, 1.2))', False, 'import miniglm\n'), ((35, 4, 35, 57), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(35, 35, 35, 38): 'res', (35, 40, 35, 56): '(7.5, 10.8, 8.4)'}, {}), '(res, (7.5, 10.8, 8.4))', True, 'import numpy as np\n'), ((40, 10, 40, 43), 'miniglm.mul', 'miniglm.mul', ({(40, 22, 40, 37): '(1.0, 2.0, 3.0)', (40, 39, 40, 42): '2.0'}, {}), '((1.0, 2.0, 3.0), 2.0)', False, 'import miniglm\n'), ((41, 4, 41, 56), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(41, 35, 41, 38): 'res', (41, 40, 41, 55): '(2.0, 4.0, 6.0)'}, {}), '(res, (2.0, 4.0, 6.0))', True, 'import numpy as np\n'), ((46, 10, 46, 58), 'miniglm.cross', 'miniglm.cross', ({(46, 24, 46, 39): '(2.0, 3.5, 7.1)', (46, 41, 46, 57): '(0.2, 10.0, 3.3)'}, {}), '((2.0, 3.5, 7.1), (0.2, 10.0, 3.3))', False, 'import miniglm\n'), ((47, 4, 47, 62), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(47, 35, 47, 38): 'res', (47, 40, 47, 61): '(-59.45, -5.18, 19.3)'}, {}), '(res, (-59.45, -5.18, 19.3))', True, 'import numpy as np\n'), ((52, 10, 52, 56), 'miniglm.dot', 'miniglm.dot', ({(52, 22, 52, 37): '(2.0, 3.5, 7.1)', (52, 39, 52, 55): '(0.2, 10.0, 3.3)'}, {}), '((2.0, 3.5, 7.1), (0.2, 10.0, 3.3))', False, 'import miniglm\n'), ((53, 4, 53, 46), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(53, 35, 53, 38): 'res', (53, 40, 53, 45): '(58.83)'}, {}), '(res, 58.83)', True, 'import numpy as np\n'), ((57, 10, 57, 56), 'miniglm.dot', 'miniglm.dot', ({(57, 22, 57, 37): '(2.0, 3.5, 7.1)', (57, 39, 57, 55): '(0.2, 10.0, 3.3)'}, {}), '((2.0, 3.5, 7.1), (0.2, 10.0, 3.3))', False, 'import miniglm\n'), ((58, 4, 58, 46), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(58, 35, 58, 38): 'res', (58, 40, 58, 45): '(58.83)'}, {}), '(res, 58.83)', True, 'import numpy as np\n'), ((62, 10, 62, 60), 'miniglm.mix', 'miniglm.mix', ({(62, 22, 62, 37): '(2.5, 3.4, 4.6)', (62, 39, 62, 54): '(7.2, 1.1, 3.2)', (62, 56, 62, 59): '0.2'}, {}), '((2.5, 3.4, 4.6), (7.2, 1.1, 3.2), 0.2)', False, 'import miniglm\n'), ((63, 4, 63, 59), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(63, 35, 63, 38): 'res', (63, 40, 63, 58): '(3.44, 2.94, 4.32)'}, {}), '(res, (3.44, 2.94, 4.32))', True, 'import numpy as np\n'), ((68, 10, 68, 36), 'miniglm.mix', 'miniglm.mix', ({(68, 22, 68, 25): '1.0', (68, 27, 68, 30): '3.0', (68, 32, 68, 35): '0.5'}, {}), '(1.0, 3.0, 0.5)', False, 'import miniglm\n'), ((69, 4, 69, 44), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(69, 35, 69, 38): 'res', (69, 40, 69, 43): '(2.0)'}, {}), '(res, 2.0)', True, 'import numpy as np\n'), ((75, 4, 75, 49), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(75, 35, 75, 38): 'res', (75, 40, 75, 48): 'expected'}, {}), '(res, expected)', True, 'import numpy as np\n'), ((81, 18, 81, 37), 'miniglm.split', 'miniglm.split', ({(81, 32, 81, 36): 'quat'}, {}), '(quat)', False, 'import miniglm\n'), ((82, 4, 82, 59), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(82, 35, 82, 40): 'angle', (82, 42, 82, 58): '(miniglm.pi / 3.0)'}, {}), '(angle, miniglm.pi / 3.0)', True, 'import numpy as np\n'), ((83, 4, 83, 60), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(83, 35, 83, 39): 'axis', (83, 41, 83, 59): '(0.48, 0.6, 0.64)'}, {}), '(axis, (0.48, 0.6, 0.64))', True, 'import numpy as np\n'), ((88, 10, 88, 59), 'miniglm.rotate', 'miniglm.rotate', ({(88, 25, 88, 41): 'miniglm.pi / 2.0', (88, 43, 88, 58): '(1.0, 0.0, 0.0)'}, {}), '(miniglm.pi / 2.0, (1.0, 0.0, 0.0))', False, 'import miniglm\n'), ((93, 10, 93, 59), 'miniglm.rotate', 'miniglm.rotate', ({(93, 25, 93, 41): 'miniglm.pi / 2.0', (93, 43, 93, 58): '(0.0, 1.0, 0.0)'}, {}), '(miniglm.pi / 2.0, (0.0, 1.0, 0.0))', False, 'import miniglm\n'), ((98, 10, 98, 59), 'miniglm.rotate', 'miniglm.rotate', ({(98, 25, 98, 41): 'miniglm.pi / 2.0', (98, 43, 98, 58): '(0.0, 0.0, 1.0)'}, {}), '(miniglm.pi / 2.0, (0.0, 0.0, 1.0))', False, 'import miniglm\n'), ((103, 10, 103, 42), 'miniglm.norm', 'miniglm.norm', ({(103, 23, 103, 41): '(48.0, 60.0, 64.0)'}, {}), '((48.0, 60.0, 64.0))', False, 'import miniglm\n'), ((105, 4, 105, 49), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(105, 35, 105, 38): 'res', (105, 40, 105, 48): 'expected'}, {}), '(res, expected)', True, 'import numpy as np\n'), ((110, 10, 110, 44), 'miniglm.norm', 'miniglm.norm', ({(110, 23, 110, 43): '(2.0, 4.0, 8.0, 4.0)'}, {}), '((2.0, 4.0, 8.0, 4.0))', False, 'import miniglm\n'), ((112, 4, 112, 49), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(112, 35, 112, 38): 'res', (112, 40, 112, 48): 'expected'}, {}), '(res, expected)', True, 'import numpy as np\n'), ((122, 10, 122, 27), 'miniglm.norm', 'miniglm.norm', ({(122, 23, 122, 26): 'mat'}, {}), '(mat)', False, 'import miniglm\n'), ((141, 10, 141, 49), 'miniglm.swizzle', 'miniglm.swizzle', ({(141, 26, 141, 41): '(1.0, 2.0, 3.0)', (141, 43, 141, 48): '"""yxz"""'}, {}), "((1.0, 2.0, 3.0), 'yxz')", False, 'import miniglm\n'), ((142, 4, 142, 56), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(142, 35, 142, 38): 'res', (142, 40, 142, 55): '(2.0, 1.0, 3.0)'}, {}), '(res, (2.0, 1.0, 3.0))', True, 'import numpy as np\n'), ((146, 10, 146, 55), 'miniglm.swizzle', 'miniglm.swizzle', ({(146, 26, 146, 46): '(0.1, 0.7, 0.5, 0.5)', (146, 48, 146, 54): '"""wxyz"""'}, {}), "((0.1, 0.7, 0.5, 0.5), 'wxyz')", False, 'import miniglm\n'), ((147, 4, 147, 61), 'numpy.testing.assert_almost_equal', 'np.testing.assert_almost_equal', ({(147, 35, 147, 38): 'res', (147, 40, 147, 60): '(0.5, 0.1, 0.7, 0.5)'}, {}), '(res, (0.5, 0.1, 0.7, 0.5))', True, 'import numpy as np\n'), ((73, 43, 73, 75), 'miniglm.norm', 'miniglm.norm', ({(73, 56, 73, 74): '(0.48, 0.6, 0.64)'}, {}), '((0.48, 0.6, 0.64))', False, 'import miniglm\n'), ((123, 35, 123, 51), 'miniglm.det', 'miniglm.det', ({(123, 47, 123, 50): 'res'}, {}), '(res)', False, 'import miniglm\n'), ((124, 35, 124, 68), 'miniglm.cross', 'miniglm.cross', ({(124, 49, 124, 57): 'res[0:3]', (124, 59, 124, 67): 'res[3:6]'}, {}), '(res[0:3], res[3:6])', False, 'import miniglm\n'), ((125, 35, 125, 66), 'miniglm.dot', 'miniglm.dot', ({(125, 47, 125, 55): 'res[0:3]', (125, 57, 125, 65): 'res[3:6]'}, {}), '(res[0:3], res[3:6])', False, 'import miniglm\n'), ((126, 35, 126, 66), 'miniglm.dot', 'miniglm.dot', ({(126, 47, 126, 55): 'res[3:6]', (126, 57, 126, 65): 'res[6:9]'}, {}), '(res[3:6], res[6:9])', False, 'import miniglm\n'), ((127, 35, 127, 66), 'miniglm.dot', 'miniglm.dot', ({(127, 47, 127, 55): 'res[0:3]', (127, 57, 127, 65): 'res[6:9]'}, {}), '(res[0:3], res[6:9])', False, 'import miniglm\n'), ((134, 35, 134, 53), 'miniglm.cast', 'miniglm.cast', ({(134, 48, 134, 52): 'quat'}, {}), '(quat)', False, 'import miniglm\n'), ((135, 35, 135, 52), 'miniglm.cast', 'miniglm.cast', ({(135, 48, 135, 51): 'mat'}, {}), '(mat)', False, 'import miniglm\n'), ((151, 11, 151, 29), 'miniglm.pack', 'miniglm.pack', ({(151, 24, 151, 28): '(1.75)'}, {}), '(1.75)', False, 'import miniglm\n'), ((151, 33, 151, 55), 'struct.pack', 'struct.pack', ({(151, 45, 151, 48): '"""f"""', (151, 50, 151, 54): '(1.75)'}, {}), "('f', 1.75)", False, 'import struct\n'), ((156, 11, 156, 28), 'miniglm.pack', 'miniglm.pack', ({(156, 24, 156, 27): 'vec'}, {}), '(vec)', False, 'import miniglm\n'), ((156, 32, 156, 56), 'struct.pack', 'struct.pack', ({(156, 44, 156, 49): '"""fff"""', (156, 51, 156, 55): '*vec'}, {}), "('fff', *vec)", False, 'import struct\n'), ((161, 11, 161, 29), 'miniglm.pack', 'miniglm.pack', ({(161, 24, 161, 28): 'quat'}, {}), '(quat)', False, 'import miniglm\n'), ((161, 33, 161, 59), 'struct.pack', 'struct.pack', ({(161, 45, 161, 51): '"""ffff"""', (161, 53, 161, 58): '*quat'}, {}), "('ffff', *quat)", False, 'import struct\n'), ((166, 11, 166, 28), 'miniglm.pack', 'miniglm.pack', ({(166, 24, 166, 27): 'mat'}, {}), '(mat)', False, 'import miniglm\n'), ((166, 32, 166, 62), 'struct.pack', 'struct.pack', ({(166, 44, 166, 55): '"""fffffffff"""', (166, 57, 166, 61): '*mat'}, {}), "('fffffffff', *mat)", False, 'import struct\n'), ((136, 48, 136, 66), 'miniglm.cast', 'miniglm.cast', ({(136, 61, 136, 65): 'quat'}, {}), '(quat)', False, 'import miniglm\n'), ((137, 48, 137, 65), 'miniglm.cast', 'miniglm.cast', ({(137, 61, 137, 64): 'mat'}, {}), '(mat)', False, 'import miniglm\n'), ((89, 41, 89, 53), 'numpy.sqrt', 'np.sqrt', ({(89, 49, 89, 52): '(2.0)'}, {}), '(2.0)', True, 'import numpy as np\n'), ((89, 71, 89, 83), 'numpy.sqrt', 'np.sqrt', ({(89, 79, 89, 82): '(2.0)'}, {}), '(2.0)', True, 'import numpy as np\n'), ((94, 46, 94, 58), 'numpy.sqrt', 'np.sqrt', ({(94, 54, 94, 57): '(2.0)'}, {}), '(2.0)', True, 'import numpy as np\n'), ((94, 71, 94, 83), 'numpy.sqrt', 'np.sqrt', ({(94, 79, 94, 82): '(2.0)'}, {}), '(2.0)', True, 'import numpy as np\n'), ((99, 51, 99, 63), 'numpy.sqrt', 'np.sqrt', ({(99, 59, 99, 62): '(2.0)'}, {}), '(2.0)', True, 'import numpy as np\n'), ((99, 71, 99, 83), 'numpy.sqrt', 'np.sqrt', ({(99, 79, 99, 82): '(2.0)'}, {}), '(2.0)', True, 'import numpy as np\n')]