浏览代码

Merge pull request #3147 from malortie/add-tests-to-c-api-2

Added tests to C API missing functionalities in #3091
Kim Kulling 5 年之前
父节点
当前提交
c530635c03

+ 28 - 13
include/assimp/MathFunctions.h

@@ -55,36 +55,51 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 namespace Assimp {
 namespace Math {
 
-// TODO: use binary GCD for unsigned integers ....
-template < typename IntegerType >
-inline
-IntegerType gcd( IntegerType a, IntegerType b ) {
+/// @brief  Will return the greatest common divisor.
+/// @param  a   [in] Value a.
+/// @param  b   [in] Value b.
+/// @return The greatest common divisor.
+template <typename IntegerType>
+inline IntegerType gcd( IntegerType a, IntegerType b ) {
 	const IntegerType zero = (IntegerType)0;
 	while ( true ) {
-		if ( a == zero )
+		if ( a == zero ) {
 			return b;
+        }
 		b %= a;
 
-		if ( b == zero )
+		if ( b == zero ) {
 			return a;
+        }
 		a %= b;
 	}
 }
 
+/// @brief  Will return the greatest common divisor.
+/// @param  a   [in] Value a.
+/// @param  b   [in] Value b.
+/// @return The greatest common divisor.
 template < typename IntegerType >
-inline
-IntegerType lcm( IntegerType a, IntegerType b ) {
+inline IntegerType lcm( IntegerType a, IntegerType b ) {
 	const IntegerType t = gcd (a,b);
-	if (!t)
+	if (!t) {
         return t;
+    }
 	return a / t * b;
 }
-
+/// @brief  Will return the smallest epsilon-value for the requested type. 
+/// @return The numercical limit epsilon depending on its type.
 template<class T>
-inline
-T getEpsilon() {
+inline T getEpsilon() {
     return std::numeric_limits<T>::epsilon();
 }
 
+/// @brief  Will return the constant PI for the requested type.
+/// @return Pi
+template<class T>
+inline T PI() {
+    return static_cast<T>(3.14159265358979323846);
 }
-}
+
+} // namespace Math
+} // namespace Assimp

+ 8 - 0
test/CMakeLists.txt

@@ -61,6 +61,14 @@ SET( COMMON
   unit/utIssues.cpp
   unit/utAnim.cpp
   unit/AssimpAPITest.cpp
+  unit/AssimpAPITest_aiMatrix3x3.cpp
+  unit/AssimpAPITest_aiMatrix4x4.cpp
+  unit/AssimpAPITest_aiQuaternion.cpp
+  unit/AssimpAPITest_aiVector2D.cpp
+  unit/AssimpAPITest_aiVector3D.cpp
+  unit/MathTest.cpp
+  unit/MathTest.h
+  unit/RandomNumberGeneration.h
   unit/utBatchLoader.cpp
   unit/utDefaultIOStream.cpp
   unit/utFastAtof.cpp

+ 151 - 0
test/unit/AssimpAPITest_aiMatrix3x3.cpp

@@ -0,0 +1,151 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "UnitTestPCH.h"
+#include "MathTest.h"
+
+using namespace Assimp;
+
+class AssimpAPITest_aiMatrix3x3 : public AssimpMathTest {
+protected:
+    virtual void SetUp() {
+        result_c = result_cpp = aiMatrix3x3();
+    }
+
+    aiMatrix3x3 result_c, result_cpp;
+};
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiIdentityMatrix3Test) {
+    // Force a non-identity matrix.
+    result_c = aiMatrix3x3(0,0,0,0,0,0,0,0,0);
+    aiIdentityMatrix3(&result_c);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3FromMatrix4Test) {
+    const auto m = random_mat4();
+    result_cpp = aiMatrix3x3(m);
+    aiMatrix3FromMatrix4(&result_c, &m);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3FromQuaternionTest) {
+    const auto q = random_quat();
+    result_cpp = q.GetMatrix();
+    aiMatrix3FromQuaternion(&result_c, &q);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3AreEqualTest) {
+    result_c = result_cpp = random_mat3();
+    EXPECT_EQ(result_cpp == result_c,
+        (bool)aiMatrix3AreEqual(&result_cpp, &result_c));
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3AreEqualEpsilonTest) {
+    result_c = result_cpp = random_mat3();
+    EXPECT_EQ(result_cpp.Equal(result_c, Epsilon),
+        (bool)aiMatrix3AreEqualEpsilon(&result_cpp, &result_c, Epsilon));
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMultiplyMatrix3Test) {
+    const auto m = random_mat3();
+    result_c = result_cpp = random_mat3();
+    result_cpp *= m;
+    aiMultiplyMatrix3(&result_c, &m);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiTransposeMatrix3Test) {
+    result_c = result_cpp = random_mat3();
+    result_cpp.Transpose();
+    aiTransposeMatrix3(&result_c);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3InverseTest) {
+    // Use a predetermined matrix to prevent arbitrary
+    // cases where it could have a null determinant.
+    result_c = result_cpp = aiMatrix3x3(
+        5, 2, 7,
+        4, 6, 9,
+        1, 8, 3);
+    result_cpp.Inverse();
+    aiMatrix3Inverse(&result_c);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3DeterminantTest) {
+    result_c = result_cpp = random_mat3();
+    EXPECT_EQ(result_cpp.Determinant(),
+        aiMatrix3Determinant(&result_c));
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3RotationZTest) {
+    const float angle(RandPI.next());
+    aiMatrix3x3::RotationZ(angle, result_cpp);
+    aiMatrix3RotationZ(&result_c, angle);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3FromRotationAroundAxisTest) {
+    const float angle(RandPI.next());
+    const auto axis = random_unit_vec3();
+    aiMatrix3x3::Rotation(angle, axis, result_cpp);
+    aiMatrix3FromRotationAroundAxis(&result_c, &axis, angle);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3TranslationTest) {
+    const auto axis = random_vec2();
+    aiMatrix3x3::Translation(axis, result_cpp);
+    aiMatrix3Translation(&result_c, &axis);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix3x3, aiMatrix3FromToTest) {
+    // Use predetermined vectors to prevent running into division by zero.
+    const auto from = aiVector3D(1,2,1).Normalize(), to = aiVector3D(-1,1,1).Normalize();
+    aiMatrix3x3::FromToMatrix(from, to, result_cpp);
+    aiMatrix3FromTo(&result_c, &from, &to);
+    EXPECT_EQ(result_cpp, result_c);
+}

+ 259 - 0
test/unit/AssimpAPITest_aiMatrix4x4.cpp

@@ -0,0 +1,259 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "UnitTestPCH.h"
+#include "MathTest.h"
+
+using namespace Assimp;
+
+class AssimpAPITest_aiMatrix4x4 : public AssimpMathTest {
+protected:
+    virtual void SetUp() {
+        result_c = result_cpp = aiMatrix4x4();
+    }
+
+    /* Generates a predetermined transformation matrix to use
+       for the aiDecompose functions to prevent running into
+       division by zero. */
+    aiMatrix4x4 get_predetermined_transformation_matrix_for_decomposition() const {
+        aiMatrix4x4 t, r;
+        aiMatrix4x4::Translation(aiVector3D(14,-25,-8), t);
+        aiMatrix4x4::Rotation(Math::PI<float>() / 4.0f, aiVector3D(1).Normalize(), r);
+        return t * r;
+    }
+
+    aiMatrix4x4 result_c, result_cpp;
+};
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiIdentityMatrix4Test) {
+    // Force a non-identity matrix.
+    result_c = aiMatrix4x4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
+    aiIdentityMatrix4(&result_c);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromMatrix3Test) {
+    aiMatrix3x3 m = random_mat3();
+    result_cpp = aiMatrix4x4(m);
+    aiMatrix4FromMatrix3(&result_c, &m);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromScalingQuaternionPositionTest) {
+    const aiVector3D s = random_vec3();
+    const aiQuaternion q = random_quat();
+    const aiVector3D t = random_vec3();
+    result_cpp = aiMatrix4x4(s, q, t);
+    aiMatrix4FromScalingQuaternionPosition(&result_c, &s, &q, &t);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4AddTest) {
+    const aiMatrix4x4 temp = random_mat4();
+    result_c = result_cpp = random_mat4();
+    result_cpp = result_cpp + temp;
+    aiMatrix4Add(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4AreEqualTest) {
+    result_c = result_cpp = random_mat4();
+    EXPECT_EQ(result_cpp == result_c,
+        (bool)aiMatrix4AreEqual(&result_cpp, &result_c));
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4AreEqualEpsilonTest) {
+    result_c = result_cpp = random_mat4();
+    EXPECT_EQ(result_cpp.Equal(result_c, Epsilon),
+        (bool)aiMatrix4AreEqualEpsilon(&result_cpp, &result_c, Epsilon));
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMultiplyMatrix4Test) {
+    const auto m = random_mat4();
+    result_c = result_cpp = random_mat4();
+    result_cpp *= m;
+    aiMultiplyMatrix4(&result_c, &m);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiTransposeMatrix4Test) {
+    result_c = result_cpp = random_mat4();
+    result_cpp.Transpose();
+    aiTransposeMatrix4(&result_c);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4InverseTest) {
+    // Use a predetermined matrix to prevent arbitrary
+    // cases where it could have a null determinant.
+    result_c = result_cpp = aiMatrix4x4(
+        6, 10, 15, 3,
+        14, 2, 12, 8,
+        9, 13, 5, 16,
+        4, 7, 11, 1);
+    result_cpp.Inverse();
+    aiMatrix4Inverse(&result_c);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4DeterminantTest) {
+    result_c = result_cpp = random_mat4();
+    EXPECT_EQ(result_cpp.Determinant(),
+        aiMatrix4Determinant(&result_c));
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4IsIdentityTest) {
+    EXPECT_EQ(result_cpp.IsIdentity(),
+        (bool)aiMatrix4IsIdentity(&result_c));
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiDecomposeMatrixTest) {
+    aiVector3D scaling_c, scaling_cpp,
+        position_c, position_cpp;
+    aiQuaternion rotation_c, rotation_cpp;
+
+    result_c = result_cpp = get_predetermined_transformation_matrix_for_decomposition();
+    result_cpp.Decompose(scaling_cpp, rotation_cpp, position_cpp);
+    aiDecomposeMatrix(&result_c, &scaling_c, &rotation_c, &position_c);
+    EXPECT_EQ(scaling_cpp, scaling_c);
+    EXPECT_EQ(position_cpp, position_c);
+    EXPECT_EQ(rotation_cpp, rotation_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4DecomposeIntoScalingEulerAnglesPositionTest) {
+    aiVector3D scaling_c, scaling_cpp,
+        rotation_c, rotation_cpp,
+        position_c, position_cpp;
+
+    result_c = result_cpp = get_predetermined_transformation_matrix_for_decomposition();
+    result_cpp.Decompose(scaling_cpp, rotation_cpp, position_cpp);
+    aiMatrix4DecomposeIntoScalingEulerAnglesPosition(&result_c, &scaling_c, &rotation_c, &position_c);
+    EXPECT_EQ(scaling_cpp, scaling_c);
+    EXPECT_EQ(position_cpp, position_c);
+    EXPECT_EQ(rotation_cpp, rotation_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4DecomposeIntoScalingAxisAnglePositionTest) {
+    aiVector3D scaling_c, scaling_cpp,
+        axis_c, axis_cpp,
+        position_c, position_cpp;
+    float angle_c, angle_cpp;
+
+    result_c = result_cpp = get_predetermined_transformation_matrix_for_decomposition();
+    result_cpp.Decompose(scaling_cpp, axis_cpp, angle_cpp, position_cpp);
+    aiMatrix4DecomposeIntoScalingAxisAnglePosition(&result_c, &scaling_c, &axis_c, &angle_c, &position_c);
+    EXPECT_EQ(scaling_cpp, scaling_c);
+    EXPECT_EQ(axis_cpp, axis_c);
+    EXPECT_EQ(angle_cpp, angle_c);
+    EXPECT_EQ(position_cpp, position_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4DecomposeNoScalingTest) {
+    aiVector3D position_c, position_cpp;
+    aiQuaternion rotation_c, rotation_cpp;
+
+    result_c = result_cpp = get_predetermined_transformation_matrix_for_decomposition();
+    result_cpp.DecomposeNoScaling(rotation_cpp, position_cpp);
+    aiMatrix4DecomposeNoScaling(&result_c, &rotation_c, &position_c);
+    EXPECT_EQ(position_cpp, position_c);
+    EXPECT_EQ(rotation_cpp, rotation_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromEulerAnglesTest) {
+    const float x(RandPI.next()),
+        y(RandPI.next()),
+        z(RandPI.next());
+    result_cpp.FromEulerAnglesXYZ(x, y, z);
+    aiMatrix4FromEulerAngles(&result_c, x, y, z);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4RotationXTest) {
+    const float angle(RandPI.next());
+    aiMatrix4x4::RotationX(angle, result_cpp);
+    aiMatrix4RotationX(&result_c, angle);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4RotationYTest) {
+    const float angle(RandPI.next());
+    aiMatrix4x4::RotationY(angle, result_cpp);
+    aiMatrix4RotationY(&result_c, angle);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4RotationZTest) {
+    const float angle(RandPI.next());
+    aiMatrix4x4::RotationZ(angle, result_cpp);
+    aiMatrix4RotationZ(&result_c, angle);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromRotationAroundAxisTest) {
+    const float angle(RandPI.next());
+    const auto axis = random_unit_vec3();
+    aiMatrix4x4::Rotation(angle, axis, result_cpp);
+    aiMatrix4FromRotationAroundAxis(&result_c, &axis, angle);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4TranslationTest) {
+    const auto axis = random_vec3();
+    aiMatrix4x4::Translation(axis, result_cpp);
+    aiMatrix4Translation(&result_c, &axis);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4ScalingTest) {
+    const auto scaling = random_vec3();
+    aiMatrix4x4::Scaling(scaling, result_cpp);
+    aiMatrix4Scaling(&result_c, &scaling);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiMatrix4x4, aiMatrix4FromToTest) {
+    // Use predetermined vectors to prevent running into division by zero.
+    const auto from = aiVector3D(1,2,1).Normalize(), to = aiVector3D(-1,1,1).Normalize();
+    aiMatrix4x4::FromToMatrix(from, to, result_cpp);
+    aiMatrix4FromTo(&result_c, &from, &to);
+    EXPECT_EQ(result_cpp, result_c);
+}

+ 135 - 0
test/unit/AssimpAPITest_aiQuaternion.cpp

@@ -0,0 +1,135 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "UnitTestPCH.h"
+#include "MathTest.h"
+
+using namespace Assimp;
+
+class AssimpAPITest_aiQuaternion : public AssimpMathTest {
+protected:
+    virtual void SetUp() {
+        result_c = result_cpp = aiQuaternion();
+    }
+
+    aiQuaternion result_c, result_cpp;
+};
+
+TEST_F(AssimpAPITest_aiQuaternion, aiCreateQuaternionFromMatrixTest) {
+    // Use a predetermined transformation matrix
+    // to prevent running into division by zero.
+    aiMatrix3x3 m, r;
+    aiMatrix3x3::Translation(aiVector2D(14,-25), m);
+    aiMatrix3x3::RotationZ(Math::PI<float>() / 4.0f, r);
+    m = m * r;
+
+    result_cpp = aiQuaternion(m);
+    aiCreateQuaternionFromMatrix(&result_c, &m);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionFromEulerAnglesTest) {
+    const float x(RandPI.next()),
+        y(RandPI.next()),
+        z(RandPI.next());
+    result_cpp = aiQuaternion(x, y, z);
+    aiQuaternionFromEulerAngles(&result_c, x, y, z);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionFromAxisAngleTest) {
+    const float angle(RandPI.next());
+    const aiVector3D axis(random_unit_vec3());
+    result_cpp = aiQuaternion(axis, angle);
+    aiQuaternionFromAxisAngle(&result_c, &axis, angle);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionFromNormalizedQuaternionTest) {
+    const auto qvec3 = random_unit_vec3();
+    result_cpp = aiQuaternion(qvec3);
+    aiQuaternionFromNormalizedQuaternion(&result_c, &qvec3);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionAreEqualTest) {
+    result_c = result_cpp = random_quat();
+    EXPECT_EQ(result_cpp == result_c,
+        (bool)aiQuaternionAreEqual(&result_cpp, &result_c));
+}
+
+TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionAreEqualEpsilonTest) {
+    result_c = result_cpp = random_quat();
+    EXPECT_EQ(result_cpp.Equal(result_c, Epsilon),
+        (bool)aiQuaternionAreEqualEpsilon(&result_cpp, &result_c, Epsilon));
+}
+
+TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionNormalizeTest) {
+    result_c = result_cpp = random_quat();
+    aiQuaternionNormalize(&result_c);
+    EXPECT_EQ(result_cpp.Normalize(), result_c);
+}
+
+TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionConjugateTest) {
+    result_c = result_cpp = random_quat();
+    aiQuaternionConjugate(&result_c);
+    EXPECT_EQ(result_cpp.Conjugate(), result_c);
+}
+
+TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionMultiplyTest) {
+    const aiQuaternion temp = random_quat();
+    result_c = result_cpp = random_quat();
+    result_cpp = result_cpp * temp;
+    aiQuaternionMultiply(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiQuaternion, aiQuaternionInterpolateTest) {
+    // Use predetermined quaternions to prevent division by zero
+    // during slerp calculations.
+    const float INTERPOLATION(0.5f);
+    const auto q1 = aiQuaternion(aiVector3D(-1,1,1).Normalize(), Math::PI<float>() / 4.0f);
+    const auto q2 = aiQuaternion(aiVector3D(1,2,1).Normalize(), Math::PI<float>() / 2.0f);
+    aiQuaternion::Interpolate(result_cpp, q1, q2, INTERPOLATION);
+    aiQuaternionInterpolate(&result_c, &q1, &q2, INTERPOLATION);
+    EXPECT_EQ(result_cpp, result_c);
+}

+ 140 - 0
test/unit/AssimpAPITest_aiVector2D.cpp

@@ -0,0 +1,140 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "UnitTestPCH.h"
+#include "MathTest.h"
+
+using namespace Assimp;
+
+class AssimpAPITest_aiVector2D : public AssimpMathTest {
+protected:
+    virtual void SetUp() {
+        result_c = result_cpp = aiVector2D();
+        temp = random_vec2(); // Generates a random 2D vector != null vector.
+    }
+
+    aiVector2D result_c, result_cpp, temp;
+};
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2AreEqualTest) {
+    result_c = result_cpp = random_vec2();
+    EXPECT_EQ(result_cpp == result_c,
+        (bool)aiVector2AreEqual(&result_cpp, &result_c));
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2AreEqualEpsilonTest) {
+    result_c = result_cpp = random_vec2();
+    EXPECT_EQ(result_cpp.Equal(result_c, Epsilon),
+        (bool)aiVector2AreEqualEpsilon(&result_cpp, &result_c, Epsilon));
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2AddTest) {
+    result_c = result_cpp = random_vec2();
+    result_cpp += temp;
+    aiVector2Add(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2SubtractTest) {
+    result_c = result_cpp = random_vec2();
+    result_cpp -= temp;
+    aiVector2Subtract(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2ScaleTest) {
+    const float FACTOR = RandNonZero.next();
+    result_c = result_cpp = random_vec2();
+    result_cpp *= FACTOR;
+    aiVector2Scale(&result_c, FACTOR);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2SymMulTest) {
+    result_c = result_cpp = random_vec2();
+    result_cpp = result_cpp.SymMul(temp);
+    aiVector2SymMul(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2DivideByScalarTest) {
+    const float DIVISOR = RandNonZero.next();
+    result_c = result_cpp = random_vec2();
+    result_cpp /= DIVISOR;
+    aiVector2DivideByScalar(&result_c, DIVISOR);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2DivideByVectorTest) {
+    result_c = result_cpp = random_vec2();
+    result_cpp = result_cpp / temp;
+    aiVector2DivideByVector(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2LengthTest) {
+    result_c = result_cpp = random_vec2();
+    EXPECT_EQ(result_cpp.Length(), aiVector2Length(&result_c));
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2SquareLengthTest) {
+    result_c = result_cpp = random_vec2();
+    EXPECT_EQ(result_cpp.SquareLength(), aiVector2SquareLength(&result_c));
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2NegateTest) {
+    result_c = result_cpp = random_vec2();
+    aiVector2Negate(&result_c);
+    EXPECT_EQ(-result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2DotProductTest) {
+    result_c = result_cpp = random_vec2();
+    EXPECT_EQ(result_cpp * result_c,
+        aiVector2DotProduct(&result_cpp, &result_c));
+}
+
+TEST_F(AssimpAPITest_aiVector2D, aiVector2NormalizeTest) {
+    result_c = result_cpp = random_vec2();
+    aiVector2Normalize(&result_c);
+    EXPECT_EQ(result_cpp.Normalize(), result_c);
+}

+ 185 - 0
test/unit/AssimpAPITest_aiVector3D.cpp

@@ -0,0 +1,185 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "UnitTestPCH.h"
+#include "MathTest.h"
+
+using namespace Assimp;
+
+class AssimpAPITest_aiVector3D : public AssimpMathTest {
+protected:
+    virtual void SetUp() {
+        result_c = result_cpp = aiVector3D();
+        temp = random_vec3(); // Generates a random 3D vector != null vector.
+    }
+
+    aiVector3D result_c, result_cpp, temp;
+};
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3AreEqualTest) {
+    result_c = result_cpp = random_vec3();
+    EXPECT_EQ(result_cpp == result_c,
+        (bool)aiVector3AreEqual(&result_cpp, &result_c));
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3AreEqualEpsilonTest) {
+    result_c = result_cpp = random_vec3();
+    EXPECT_EQ(result_cpp.Equal(result_c, Epsilon),
+        (bool)aiVector3AreEqualEpsilon(&result_cpp, &result_c, Epsilon));
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3LessThanTest) {
+    result_c = result_cpp = random_vec3();
+    EXPECT_EQ(result_cpp < temp,
+        (bool)aiVector3LessThan(&result_c, &temp));
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3AddTest) {
+    result_c = result_cpp = random_vec3();
+    result_cpp += temp;
+    aiVector3Add(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3SubtractTest) {
+    result_c = result_cpp = random_vec3();
+    result_cpp -= temp;
+    aiVector3Subtract(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3ScaleTest) {
+    const float FACTOR = RandNonZero.next();
+    result_c = result_cpp = random_vec3();
+    result_cpp *= FACTOR;
+    aiVector3Scale(&result_c, FACTOR);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3SymMulTest) {
+    result_c = result_cpp = random_vec3();
+    result_cpp = result_cpp.SymMul(temp);
+    aiVector3SymMul(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3DivideByScalarTest) {
+    const float DIVISOR = RandNonZero.next();
+    result_c = result_cpp = random_vec3();
+    result_cpp /= DIVISOR;
+    aiVector3DivideByScalar(&result_c, DIVISOR);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3DivideByVectorTest) {
+    result_c = result_cpp = random_vec3();
+    result_cpp = result_cpp / temp;
+    aiVector3DivideByVector(&result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3LengthTest) {
+    result_c = result_cpp = random_vec3();
+    EXPECT_EQ(result_cpp.Length(), aiVector3Length(&result_c));
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3SquareLengthTest) {
+    result_c = result_cpp = random_vec3();
+    EXPECT_EQ(result_cpp.SquareLength(), aiVector3SquareLength(&result_c));
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3NegateTest) {
+    result_c = result_cpp = random_vec3();
+    aiVector3Negate(&result_c);
+    EXPECT_EQ(-result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3DotProductTest) {
+    result_c = result_cpp = random_vec3();
+    EXPECT_EQ(result_cpp * result_c,
+        aiVector3DotProduct(&result_cpp, &result_c));
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3CrossProductTest) {
+    result_c = result_cpp = random_vec3();
+    result_cpp = result_cpp ^ temp;
+    aiVector3CrossProduct(&result_c, &result_c, &temp);
+    EXPECT_EQ(result_cpp, result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3NormalizeTest) {
+    result_c = result_cpp = random_vec3();
+    aiVector3Normalize(&result_c);
+    EXPECT_EQ(result_cpp.Normalize(), result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3NormalizeSafeTest) {
+    result_c = result_cpp = random_vec3();
+    aiVector3NormalizeSafe(&result_c);
+    EXPECT_EQ(result_cpp.NormalizeSafe(), result_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiVector3RotateByQuaternionTest) {
+    aiVector3D v_c, v_cpp;
+    v_c = v_cpp = random_vec3();
+    const auto q = random_quat();
+    aiVector3RotateByQuaternion(&v_c, &q);
+    EXPECT_EQ(q.Rotate(v_cpp), v_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiTransformVecByMatrix3Test) {
+    const auto m = random_mat3();
+    aiVector3D v_c, v_cpp;
+    v_c = v_cpp = random_vec3();
+    v_cpp *= m;
+    aiTransformVecByMatrix3(&v_c, &m);
+    EXPECT_EQ(v_cpp, v_c);
+}
+
+TEST_F(AssimpAPITest_aiVector3D, aiTransformVecByMatrix4Test) {
+    const auto m = random_mat4();
+    aiVector3D v_c, v_cpp;
+    v_c = v_cpp = random_vec3();
+    v_cpp *= m;
+    aiTransformVecByMatrix4(&v_c, &m);
+    EXPECT_EQ(v_cpp, v_c);
+}

+ 56 - 0
test/unit/MathTest.cpp

@@ -0,0 +1,56 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+#include "MathTest.h"
+
+namespace Assimp {
+
+// Initialize epsilon value.
+const float AssimpMathTest::Epsilon = Math::getEpsilon<float>();
+
+// Initialize with an interval of [1,100].
+RandomUniformFloatGenerator AssimpMathTest::RandNonZero(1.0f, 100.0f);
+
+// Initialize with an interval of [-PI,PI] inclusively.
+RandomUniformFloatGenerator AssimpMathTest::RandPI(-Math::PI<float>(), Math::PI<float>());
+
+}

+ 103 - 0
test/unit/MathTest.h

@@ -0,0 +1,103 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#ifndef ASSIMP_MATH_TEST_H
+#define ASSIMP_MATH_TEST_H
+
+#include "UnitTestPCH.h"
+#include <assimp/types.h>
+#include "RandomNumberGeneration.h"
+
+namespace Assimp {
+
+/** Custom test class providing several math related utilities. */
+class AssimpMathTest : public ::testing::Test {
+public:
+    /** Return a random non-null 2D vector. */
+    inline static aiVector2D random_vec2() {
+        return aiVector2D(RandNonZero.next(), RandNonZero.next());
+    }
+
+    /** Return a random non-null 3D vector. */
+    inline static aiVector3D random_vec3() {
+        return aiVector3D(RandNonZero.next(), RandNonZero.next(),RandNonZero.next());
+    }
+
+    /** Return a random unit 3D vector. */
+    inline static aiVector3D random_unit_vec3() {
+        return random_vec3().NormalizeSafe();
+    }
+
+    /** Return a quaternion with random orientation and
+      * rotation angle around axis. */
+    inline static aiQuaternion random_quat() {
+        return aiQuaternion(random_unit_vec3(), RandPI.next());
+    }
+
+    /** Return a random non-null 3x3 matrix. */
+    inline static aiMatrix3x3 random_mat3() {
+        return aiMatrix3x3(
+            RandNonZero.next(), RandNonZero.next(),RandNonZero.next(),
+            RandNonZero.next(), RandNonZero.next(),RandNonZero.next(),
+            RandNonZero.next(), RandNonZero.next(),RandNonZero.next());
+    }
+
+    /** Return a random non-null 4x4 matrix. */
+    inline static aiMatrix4x4 random_mat4() {
+        return aiMatrix4x4(
+            RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), RandNonZero.next(),
+            RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), RandNonZero.next(),
+            RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), RandNonZero.next(),
+            RandNonZero.next(), RandNonZero.next(),RandNonZero.next(), RandNonZero.next());
+    }
+
+    /** Epsilon value to use in tests. */
+    static const float Epsilon;
+
+    /** Random number generators. */
+    static RandomUniformFloatGenerator RandNonZero, RandPI;
+};
+
+}
+
+#endif // ASSIMP_MATH_TEST_H

+ 82 - 0
test/unit/RandomNumberGeneration.h

@@ -0,0 +1,82 @@
+/*
+---------------------------------------------------------------------------
+Open Asset Import Library (assimp)
+---------------------------------------------------------------------------
+
+Copyright (c) 2006-2020, assimp team
+
+All rights reserved.
+
+Redistribution and use of this software in source and binary forms,
+with or without modification, are permitted provided that the following
+conditions are met:
+
+* Redistributions of source code must retain the above
+copyright notice, this list of conditions and the
+following disclaimer.
+
+* Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the
+following disclaimer in the documentation and/or other
+materials provided with the distribution.
+
+* Neither the name of the assimp team, nor the names of its
+contributors may be used to endorse or promote products
+derived from this software without specific prior
+written permission of the assimp team.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+---------------------------------------------------------------------------
+*/
+
+#ifndef ASSIMP_RANDOM_NUMBER_GENERATION_H
+#define ASSIMP_RANDOM_NUMBER_GENERATION_H
+
+#include <random>
+
+namespace Assimp {
+
+/** Helper class to use for generating pseudo-random
+ *  real numbers, with a uniform distribution. */
+template<typename T>
+class RandomUniformRealGenerator {
+public:
+    RandomUniformRealGenerator() :
+            dist_(),
+            rd_(), 
+            re_(rd_())  {
+        // empty
+    }
+    
+    RandomUniformRealGenerator(T min, T max) :
+            dist_(min, max),
+            rd_(),
+            re_(rd_())  {
+        // empty
+    }
+
+    inline T next() {
+        return dist_(re_);
+    }
+
+private:
+    std::uniform_real_distribution<T> dist_;
+    std::random_device rd_;
+    std::default_random_engine re_;
+};
+
+using RandomUniformFloatGenerator = RandomUniformRealGenerator<float>;
+
+}
+
+#endif // ASSIMP_RANDOM_NUMBER_GENERATION_H