text: import unittest
  import numpy as np
  from math import pi
  from quaternion_calc import Quaternion
  
  cos_x = lambda x: np.cos(x)
  sin_x = lambda x: np.sin(x)
  
  class TestQuaternion(unittest.TestCase):
          def test_init(self):
              xin = np.array([1,2,3,4])
              q_0 = Quaternion(1,2,3,4)
              q_1 = Quaternion.from_array(xin)
              self.assertIsInstance(q_1, Quaternion)
              self.assertEqual(q_0, q_1)
              #check rounding
              q_2 = Quaternion(*np.array([1e-16, 0,0, 1-1e-16]))
              q_3 = Quaternion(0,0,0,1)
              self.assertEqual(q_2, q_3)
  
          def test_properties(self):
              xin = np.array([1,2,3,4])
              q = Quaternion(*xin)
              q_conj = Quaternion(1, -2,-3,-4)
              self.assertEqual(q.conjugate, q_conj)
              q_norm = 5.477225575051661
              self.assertEqual(q.norm, q_norm)
              self.assertEqual(q.normalized, q/q_norm)
  
  
          def test_mul(self):
              x = Quaternion(1,2,3,4)
              y = Quaternion(3,4,5,6)
              z = Quaternion(3,6,7,8)
              self.assertEqual(y*x*z, Quaternion(-434.0, -288.0, -254.0, -268.0))
              self.assertEqual(x*y*z, Quaternion(-434.0, -208.0, -222.0, -356.0))
  
          def test_rotation(self):
              v1 = np.array([1,1,1])
              #rotate about the x-axis 90 degrees
              matrix_x90 = np.array([[1,0,0], [0, cos_x(pi/2), -sin_x(pi/2)], [0, sin_x(pi/2), cos_x(pi/2)]])
              #rotate about the y-axis 90 degrees
              matrix_y90 = np.array([[ cos_x(pi/2), 0, sin_x(pi/2)],[0,1,0] , [-sin_x(pi/2), 0, cos_x(pi/2)]])
              #rotate about the z-axis 90 degrees
              matrix_z90 = np.array([[cos_x(pi/2), -sin_x(pi/2), 0], [sin_x(pi/2), cos_x(pi/2), 0],[0, 0,1]])
              matrix_xyz90 = np.matmul(np.matmul(matrix_x90, matrix_y90), matrix_z90)
              quat_x = Quaternion.from_matrix(matrix_x90)
              quat_y = Quaternion.from_matrix(matrix_y90)
              quat_z = Quaternion.from_matrix(matrix_z90)
              #compose rotations
              quat_xyz = Quaternion.from_matrix(matrix_xyz90)
              v1_x = quat_x.rotate_vector(v1)
              #check x-rotation
              np.testing.assert_allclose(v1_x, np.matmul(matrix_x90, v1))
              v1_xy = quat_y.rotate_vector(v1_x)
              #check y-rotation
              np.testing.assert_allclose(v1_xy, np.matmul(matrix_y90, v1_x))
              v1_xyz = quat_z.rotate_vector(v1_xy)
              #check z-rotation
              np.testing.assert_allclose(v1_xyz, np.matmul(matrix_z90, v1_xy))
              v1_xyz_1 = quat_xyz.rotate_vector(v1)
              #check rotation composition works
              np.testing.assert_allclose(v1_xyz_1, np.matmul(matrix_xyz90, v1))
              quat_xyz_1 = quat_x*quat_y*quat_z
              v1_xyz_2 = quat_xyz_1.rotate_vector(v1)
              np.testing.assert_allclose(v1_xyz_2, np.matmul(matrix_xyz90, v1))
  
  
  
  if __name__ == '__main__':
      unittest.main()
  