Translated tests for Quaternion
This commit is contained in:
parent
cd5e841ebd
commit
b8b3005cb2
@ -23,6 +23,7 @@ add_executable(Tests
|
|||||||
Vector2.cpp
|
Vector2.cpp
|
||||||
Vector3.cpp
|
Vector3.cpp
|
||||||
Vector4.cpp
|
Vector4.cpp
|
||||||
|
Quaternion.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(Tests Eule)
|
target_link_libraries(Tests Eule)
|
||||||
|
@ -1,44 +1,32 @@
|
|||||||
#include "CppUnitTest.h"
|
#include "Catch2.h"
|
||||||
#include "../Eule/Quaternion.h"
|
#include <Eule/Quaternion.h>
|
||||||
#include "../Eule/Math.h"
|
#include <Eule/Math.h>
|
||||||
#include "../_TestingUtilities/HandyMacros.h"
|
#include "../_TestingUtilities/HandyMacros.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
|
||||||
using namespace Eule;
|
using namespace Eule;
|
||||||
|
|
||||||
namespace TransformRelated
|
namespace {
|
||||||
|
static std::mt19937 rng = std::mt19937((std::random_device())());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests that if constructed with the default constructor, that all values are 0 (but w should be 1)
|
||||||
|
TEST_CASE(__FILE__"/Default_Constructor_All_0", "[Quaternion]")
|
||||||
{
|
{
|
||||||
TEST_CLASS(_Quaternion)
|
const Quaternion q;
|
||||||
{
|
REQUIRE(Vector4d(0, 0, 0, 1) == q.GetRawValues());
|
||||||
private:
|
|
||||||
std::mt19937 rng;
|
|
||||||
|
|
||||||
public:
|
|
||||||
// Constructor
|
|
||||||
_Quaternion()
|
|
||||||
{
|
|
||||||
rng = std::mt19937((std::random_device())());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests that if constructed with the default constructor, that all values are 0 (but w should be 1)
|
|
||||||
TEST_METHOD(Default_Constructor_All_0)
|
|
||||||
{
|
|
||||||
Quaternion q;
|
|
||||||
Assert::IsTrue(Vector4d(0, 0, 0, 1) == q.GetRawValues());
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that getting and setting raw values works
|
// Tests that getting and setting raw values works
|
||||||
TEST_METHOD(Can_Set_Get_Raw_Values)
|
TEST_CASE(__FILE__"/Can_Set_Get_Raw_Values", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Test 1000 times
|
// Test 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
Vector4d v(
|
const Vector4d v(
|
||||||
rng() % 90,
|
rng() % 90,
|
||||||
rng() % 90,
|
rng() % 90,
|
||||||
rng() % 90,
|
rng() % 90,
|
||||||
@ -48,165 +36,164 @@ namespace TransformRelated
|
|||||||
Quaternion q(Vector4d(0, 0, 0, 0)); // Garbage values
|
Quaternion q(Vector4d(0, 0, 0, 0)); // Garbage values
|
||||||
|
|
||||||
q.SetRawValues(v);
|
q.SetRawValues(v);
|
||||||
Assert::IsTrue(v.Similar(q.GetRawValues()));
|
REQUIRE(v.Similar(q.GetRawValues()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that retreiving euler angles (without gimbal lock) results in the same values as put in
|
// Tests that retrieving euler angles (without gimbal lock) results in the same values as put in
|
||||||
TEST_METHOD(To_Euler_From_Euler)
|
TEST_CASE(__FILE__"/To_Euler_From_Euler", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Test 1000 times
|
// Test 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
// Create vector
|
// Create vector
|
||||||
Vector3d eul(
|
const Vector3d eul(
|
||||||
rng() % 90,
|
rng() % 90,
|
||||||
rng() % 90,
|
rng() % 90,
|
||||||
rng() % 90
|
rng() % 90
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create quaternion from vector
|
// Create quaternion from vector
|
||||||
Quaternion q(eul);
|
const Quaternion q(eul);
|
||||||
|
|
||||||
// Create debug output
|
// Create debug output
|
||||||
std::wstringstream wss;
|
INFO('\n'
|
||||||
wss << std::endl
|
<< "Actual vals: " << q.ToEulerAngles() << '\n'
|
||||||
<< "Actual vals: " << q.ToEulerAngles() << std::endl
|
<< "Target vals: " << eul << '\n'
|
||||||
<< "Target vals: " << eul << std::endl;
|
);
|
||||||
|
|
||||||
// Assertion
|
// Assertion
|
||||||
Assert::IsTrue(eul.Similar(q.ToEulerAngles()), wss.str().c_str());
|
REQUIRE(eul.Similar(q.ToEulerAngles()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that adding angles (0,0,0) does not modify the quaternion
|
// Tests that adding angles (0,0,0) does not modify the quaternion
|
||||||
TEST_METHOD(Add_Angles_0_Does_Nothing)
|
TEST_CASE(__FILE__"/Add_Angles_0_Does_Nothing", "[Quaternion]")
|
||||||
{
|
{
|
||||||
Quaternion a(Vector3d(0, -45, 45));
|
const Quaternion a(Vector3d(0, -45, 45));
|
||||||
Quaternion b(Vector3d(0, 0, 0));
|
const Quaternion b(Vector3d(0, 0, 0));
|
||||||
|
|
||||||
Assert::IsTrue(Vector3d(0, -45, 45).Similar((a * b).ToEulerAngles()));
|
REQUIRE(Vector3d(0, -45, 45).Similar((a * b).ToEulerAngles()));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that subtracting angles (0,0,0) does not modify the quaternion
|
// Tests that subtracting angles (0,0,0) does not modify the quaternion
|
||||||
TEST_METHOD(Sub_Angles_0_Does_Nothing)
|
TEST_CASE(__FILE__"/Sub_Angles_0_Does_Nothing", "[Quaternion]")
|
||||||
{
|
{
|
||||||
Quaternion a(Vector3d(0, -45, 45));
|
const Quaternion a(Vector3d(0, -45, 45));
|
||||||
Quaternion b(Vector3d(0, 0, 0));
|
const Quaternion b(Vector3d(0, 0, 0));
|
||||||
|
|
||||||
Assert::IsTrue(Vector3d(0, -45, 45).Similar((a / b).ToEulerAngles()));
|
REQUIRE(Vector3d(0, -45, 45).Similar((a / b).ToEulerAngles()));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that subtracting by itself always returns (0,0,0)
|
// Tests that subtracting by itself always returns (0,0,0)
|
||||||
TEST_METHOD(Sub_Itself_Is_0)
|
TEST_CASE(__FILE__"/Sub_Itself_Is_0", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Run test 100 times
|
// Run test 100 times
|
||||||
for (std::size_t i = 0; i < 100; i++)
|
for (std::size_t i = 0; i < 100; i++)
|
||||||
{
|
{
|
||||||
Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE));
|
const Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE));
|
||||||
Assert::IsTrue(Vector3d(0,0,0).Similar((a / a).ToEulerAngles()));
|
REQUIRE(Vector3d(0,0,0).Similar((a / a).ToEulerAngles()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that rotating a vector is equal to multiplying it with the inverted rotation matrix
|
// Tests that rotating a vector is equal to multiplying it with the inverted rotation matrix
|
||||||
TEST_METHOD(RotateVector_Equal_to_RotationMatrix)
|
TEST_CASE(__FILE__"/RotateVector_Equal_to_RotationMatrix", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Run test 1000 times
|
// Run test 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE));
|
const Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE));
|
||||||
|
|
||||||
Vector3d point(32, 19, -14);
|
const Vector3d point(32, 19, -14);
|
||||||
|
|
||||||
// Generate debug output
|
// Generate debug output
|
||||||
std::wstringstream ss;
|
INFO((point * a.ToRotationMatrix()) << '\n' << "===" << (a * point) << '\n');
|
||||||
ss << (point * a.ToRotationMatrix()) << std::endl << L"===" << (a * point) << std::endl;
|
|
||||||
|
|
||||||
Assert::IsTrue((point * a.ToRotationMatrix()).Similar(a * point), ss.str().c_str());
|
REQUIRE((point * a.ToRotationMatrix()).Similar(a * point));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that a *= b will result in the exact same outcome as a = a * b
|
// Tests that a *= b will result in the exact same outcome as a = a * b
|
||||||
TEST_METHOD(MultiplyEquals_Operator_Same_Result_As_Multiply_Operator)
|
TEST_CASE(__FILE__"/MultiplyEquals_Operator_Same_Result_As_Multiply_Operator", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Run tests 1000 times
|
// Run tests 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
||||||
Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
const Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
||||||
|
|
||||||
// Exercise
|
// Exercise
|
||||||
Quaternion ref = a * b;
|
Quaternion ref = a * b;
|
||||||
a *= b;
|
a *= b;
|
||||||
|
|
||||||
// Verify
|
// Verify
|
||||||
Assert::IsTrue(a.GetRawValues().Similar(ref.GetRawValues()));
|
REQUIRE(a.GetRawValues().Similar(ref.GetRawValues()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that a /= b will result in the exact same outcome as a = a / b
|
// Tests that a /= b will result in the exact same outcome as a = a / b
|
||||||
TEST_METHOD(DivideEquals_Operator_Same_Result_As_Divide_Operator)
|
TEST_CASE(__FILE__"/DivideEquals_Operator_Same_Result_As_Divide_Operator", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Run tests 1000 times
|
// Run tests 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
||||||
Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
const Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
|
||||||
|
|
||||||
// Exercise
|
// Exercise
|
||||||
Quaternion ref = a / b;
|
Quaternion ref = a / b;
|
||||||
a /= b;
|
a /= b;
|
||||||
|
|
||||||
// Verify
|
// Verify
|
||||||
Assert::IsTrue(a.GetRawValues().Similar(ref.GetRawValues()));
|
REQUIRE(a.GetRawValues().Similar(ref.GetRawValues()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests basic equals comparison -> true
|
// Tests basic equals comparison -> true
|
||||||
TEST_METHOD(Basic_EqualsComparison_True)
|
TEST_CASE(__FILE__"/Basic_EqualsComparison_True", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Run tests 1000 times
|
// Run tests 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
Vector3d e(rng() % 360, rng() % 360, rng() % 360);
|
const Vector3d e(rng() % 360, rng() % 360, rng() % 360);
|
||||||
Quaternion a(e);
|
const Quaternion a(e);
|
||||||
Quaternion b(e);
|
const Quaternion b(e);
|
||||||
|
|
||||||
// Exercise and verify
|
// Exercise and verify
|
||||||
Assert::IsTrue(a == b);
|
REQUIRE(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests basic equals comparison -> true
|
// Tests basic equals comparison -> true
|
||||||
TEST_METHOD(Basic_EqualsComparison_False)
|
TEST_CASE(__FILE__"/Basic_EqualsComparison_False", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Run tests 1000 times
|
// Run tests 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
|
const Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
|
||||||
Vector3d be(rng() % 360, rng() % 360, rng() % 360);
|
const Vector3d be(rng() % 360, rng() % 360, rng() % 360);
|
||||||
|
|
||||||
// Abort if both vectors are equal
|
// Abort if both vectors are equal
|
||||||
if (ae == be)
|
if (ae == be)
|
||||||
@ -215,79 +202,79 @@ namespace TransformRelated
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Quaternion a(ae);
|
const Quaternion a(ae);
|
||||||
Quaternion b(be);
|
const Quaternion b(be);
|
||||||
|
|
||||||
// Exercise and verify
|
// Exercise and verify
|
||||||
Assert::IsFalse(a == b);
|
REQUIRE_FALSE(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests that different euler angles return true, if the angle is the same.
|
// Tests that different euler angles return true, if the angle is the same.
|
||||||
// Like [30, -10, 59] == [390, 350, 419]
|
// Like [30, -10, 59] == [390, 350, 419]
|
||||||
TEST_METHOD(Equals_Comparison_Same_Rotation_Different_EulerAngles)
|
TEST_CASE(__FILE__"/Equals_Comparison_Same_Rotation_Different_EulerAngles", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Run tests 1000 times
|
// Run tests 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
// Create random rotation
|
// Create random rotation
|
||||||
Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
|
const Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
|
||||||
|
|
||||||
// add or subtract a random multiple of 360
|
// add or subtract a random multiple of 360
|
||||||
#define keep_rot_change_values (360.0 * (double)(rng() % 20) * ((rng()%2) ? 1.0 : -1.0))
|
#define keep_rot_change_values (360.0 * (double)(rng() % 20) * ((rng()%2) ? 1.0 : -1.0))
|
||||||
Vector3d be(ae.x + keep_rot_change_values, ae.y + keep_rot_change_values, ae.z + keep_rot_change_values);
|
const Vector3d be(ae.x + keep_rot_change_values, ae.y + keep_rot_change_values, ae.z + keep_rot_change_values);
|
||||||
#undef keep_rot_change_values
|
#undef keep_rot_change_values
|
||||||
|
|
||||||
// Create quaternions
|
// Create quaternions
|
||||||
Quaternion a(ae);
|
const Quaternion a(ae);
|
||||||
Quaternion b(be);
|
const Quaternion b(be);
|
||||||
|
|
||||||
// Exercise & Verify
|
// Exercise & Verify
|
||||||
// Create debug output
|
// Create debug output
|
||||||
|
|
||||||
std::wstringstream wss;
|
INFO("ae: " << ae << '\n'
|
||||||
wss << "ae: " << ae << std::endl
|
<< "be: " << be << '\n'
|
||||||
<< "be: " << be << std::endl
|
<< "a: " << a << '\n'
|
||||||
<< "a: " << a << std::endl
|
<< "b: " << b << '\n'
|
||||||
<< "b: " << b << std::endl;
|
);
|
||||||
|
|
||||||
// Assertion
|
// Assertion
|
||||||
Assert::IsTrue(a == b, wss.str().c_str());
|
REQUIRE(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests basic not-equals comparison -> false
|
// Tests basic not-equals comparison -> false
|
||||||
TEST_METHOD(Basic_NotEqualsComparison_False)
|
TEST_CASE(__FILE__"/Basic_NotEqualsComparison_False", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Run tests 1000 times
|
// Run tests 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
Vector3d e(rng() % 360, rng() % 360, rng() % 360);
|
const Vector3d e(rng() % 360, rng() % 360, rng() % 360);
|
||||||
Quaternion a(e);
|
const Quaternion a(e);
|
||||||
Quaternion b(e);
|
const Quaternion b(e);
|
||||||
|
|
||||||
// Exercise and verify
|
// Exercise and verify
|
||||||
Assert::IsFalse(a != b);
|
REQUIRE_FALSE(a != b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests basic not-equals comparison -> true
|
// Tests basic not-equals comparison -> true
|
||||||
TEST_METHOD(Basic_NotEqualsComparison_True)
|
TEST_CASE(__FILE__"/Basic_NotEqualsComparison_True", "[Quaternion]")
|
||||||
{
|
{
|
||||||
// Run tests 1000 times
|
// Run tests 1000 times
|
||||||
for (std::size_t i = 0; i < 1000; i++)
|
for (std::size_t i = 0; i < 1000; i++)
|
||||||
{
|
{
|
||||||
// Setup
|
// Setup
|
||||||
Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
|
const Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
|
||||||
Vector3d be(rng() % 360, rng() % 360, rng() % 360);
|
const Vector3d be(rng() % 360, rng() % 360, rng() % 360);
|
||||||
|
|
||||||
// Abort if both vectors are equal
|
// Abort if both vectors are equal
|
||||||
if (ae == be)
|
if (ae == be)
|
||||||
@ -296,14 +283,12 @@ namespace TransformRelated
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Quaternion a(ae);
|
const Quaternion a(ae);
|
||||||
Quaternion b(be);
|
const Quaternion b(be);
|
||||||
|
|
||||||
// Exercise and verify
|
// Exercise and verify
|
||||||
Assert::IsTrue(a != b);
|
REQUIRE(a != b);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user