Translated tests for Quaternion

This commit is contained in:
Leonetienne 2022-02-11 14:47:33 +01:00
parent cd5e841ebd
commit b8b3005cb2
2 changed files with 288 additions and 302 deletions

View File

@ -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)

View File

@ -1,309 +1,294 @@
#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())());
TEST_CLASS(_Quaternion) }
{
private: // Tests that if constructed with the default constructor, that all values are 0 (but w should be 1)
std::mt19937 rng; TEST_CASE(__FILE__"/Default_Constructor_All_0", "[Quaternion]")
{
public: const Quaternion q;
// Constructor REQUIRE(Vector4d(0, 0, 0, 1) == q.GetRawValues());
_Quaternion()
{ return;
rng = std::mt19937((std::random_device())()); }
return;
} // Tests that getting and setting raw values works
TEST_CASE(__FILE__"/Can_Set_Get_Raw_Values", "[Quaternion]")
// Tests that if constructed with the default constructor, that all values are 0 (but w should be 1) {
TEST_METHOD(Default_Constructor_All_0) // Test 1000 times
{ for (std::size_t i = 0; i < 1000; i++)
Quaternion q; {
Assert::IsTrue(Vector4d(0, 0, 0, 1) == q.GetRawValues()); const Vector4d v(
rng() % 90,
return; rng() % 90,
} rng() % 90,
rng() % 90
// Tests that getting and setting raw values works );
TEST_METHOD(Can_Set_Get_Raw_Values)
{ Quaternion q(Vector4d(0, 0, 0, 0)); // Garbage values
// Test 1000 times
for (std::size_t i = 0; i < 1000; i++) q.SetRawValues(v);
{ REQUIRE(v.Similar(q.GetRawValues()));
Vector4d v( }
rng() % 90,
rng() % 90, return;
rng() % 90, }
rng() % 90
); // Tests that retrieving euler angles (without gimbal lock) results in the same values as put in
TEST_CASE(__FILE__"/To_Euler_From_Euler", "[Quaternion]")
Quaternion q(Vector4d(0, 0, 0, 0)); // Garbage values {
// Test 1000 times
q.SetRawValues(v); for (std::size_t i = 0; i < 1000; i++)
Assert::IsTrue(v.Similar(q.GetRawValues())); {
} // Create vector
const Vector3d eul(
return; rng() % 90,
} rng() % 90,
rng() % 90
// Tests that retreiving euler angles (without gimbal lock) results in the same values as put in );
TEST_METHOD(To_Euler_From_Euler)
{ // Create quaternion from vector
// Test 1000 times const Quaternion q(eul);
for (std::size_t i = 0; i < 1000; i++)
{ // Create debug output
// Create vector INFO('\n'
Vector3d eul( << "Actual vals: " << q.ToEulerAngles() << '\n'
rng() % 90, << "Target vals: " << eul << '\n'
rng() % 90, );
rng() % 90
); // Assertion
REQUIRE(eul.Similar(q.ToEulerAngles()));
// Create quaternion from vector }
Quaternion q(eul);
return;
// Create debug output }
std::wstringstream wss;
wss << std::endl // Tests that adding angles (0,0,0) does not modify the quaternion
<< "Actual vals: " << q.ToEulerAngles() << std::endl TEST_CASE(__FILE__"/Add_Angles_0_Does_Nothing", "[Quaternion]")
<< "Target vals: " << eul << std::endl; {
const Quaternion a(Vector3d(0, -45, 45));
// Assertion const Quaternion b(Vector3d(0, 0, 0));
Assert::IsTrue(eul.Similar(q.ToEulerAngles()), wss.str().c_str());
} REQUIRE(Vector3d(0, -45, 45).Similar((a * b).ToEulerAngles()));
return; return;
} }
// Tests that adding angles (0,0,0) does not modify the quaternion // Tests that subtracting angles (0,0,0) does not modify the quaternion
TEST_METHOD(Add_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 angles (0,0,0) does not modify the quaternion // Tests that subtracting by itself always returns (0,0,0)
TEST_METHOD(Sub_Angles_0_Does_Nothing) TEST_CASE(__FILE__"/Sub_Itself_Is_0", "[Quaternion]")
{ {
Quaternion a(Vector3d(0, -45, 45)); // Run test 100 times
Quaternion b(Vector3d(0, 0, 0)); for (std::size_t i = 0; i < 100; i++)
{
Assert::IsTrue(Vector3d(0, -45, 45).Similar((a / b).ToEulerAngles())); const Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE));
REQUIRE(Vector3d(0,0,0).Similar((a / a).ToEulerAngles()));
return; }
}
return;
// Tests that subtracting by itself always returns (0,0,0) }
TEST_METHOD(Sub_Itself_Is_0)
{ // Tests that rotating a vector is equal to multiplying it with the inverted rotation matrix
// Run test 100 times TEST_CASE(__FILE__"/RotateVector_Equal_to_RotationMatrix", "[Quaternion]")
for (std::size_t i = 0; i < 100; i++) {
{ // Run test 1000 times
Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE)); for (std::size_t i = 0; i < 1000; i++)
Assert::IsTrue(Vector3d(0,0,0).Similar((a / a).ToEulerAngles())); {
} const Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE));
return; const Vector3d point(32, 19, -14);
}
// Generate debug output
// Tests that rotating a vector is equal to multiplying it with the inverted rotation matrix INFO((point * a.ToRotationMatrix()) << '\n' << "===" << (a * point) << '\n');
TEST_METHOD(RotateVector_Equal_to_RotationMatrix)
{ REQUIRE((point * a.ToRotationMatrix()).Similar(a * point));
// Run test 1000 times }
for (std::size_t i = 0; i < 1000; i++)
{ return;
Quaternion a(Vector3d(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE)); }
Vector3d point(32, 19, -14); // Tests that a *= b will result in the exact same outcome as a = a * b
TEST_CASE(__FILE__"/MultiplyEquals_Operator_Same_Result_As_Multiply_Operator", "[Quaternion]")
// Generate debug output {
std::wstringstream ss; // Run tests 1000 times
ss << (point * a.ToRotationMatrix()) << std::endl << L"===" << (a * point) << std::endl; for (std::size_t i = 0; i < 1000; i++)
{
Assert::IsTrue((point * a.ToRotationMatrix()).Similar(a * point), ss.str().c_str()); // Setup
} Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360));
const Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
return;
} // Exercise
Quaternion ref = a * b;
// Tests that a *= b will result in the exact same outcome as a = a * b a *= b;
TEST_METHOD(MultiplyEquals_Operator_Same_Result_As_Multiply_Operator)
{ // Verify
// Run tests 1000 times REQUIRE(a.GetRawValues().Similar(ref.GetRawValues()));
for (std::size_t i = 0; i < 1000; i++) }
{
// Setup return;
Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360)); }
Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
// Tests that a /= b will result in the exact same outcome as a = a / b
// Exercise TEST_CASE(__FILE__"/DivideEquals_Operator_Same_Result_As_Divide_Operator", "[Quaternion]")
Quaternion ref = a * b; {
a *= b; // Run tests 1000 times
for (std::size_t i = 0; i < 1000; i++)
// Verify {
Assert::IsTrue(a.GetRawValues().Similar(ref.GetRawValues())); // Setup
} Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360));
const Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
return;
} // Exercise
Quaternion ref = a / b;
// Tests that a /= b will result in the exact same outcome as a = a / b a /= b;
TEST_METHOD(DivideEquals_Operator_Same_Result_As_Divide_Operator)
{ // Verify
// Run tests 1000 times REQUIRE(a.GetRawValues().Similar(ref.GetRawValues()));
for (std::size_t i = 0; i < 1000; i++) }
{
// Setup return;
Quaternion a(Vector3d(rng() % 360, rng() % 360, rng() % 360)); }
Quaternion b(Vector3d(rng() % 360, rng() % 360, rng() % 360));
// Tests basic equals comparison -> true
// Exercise TEST_CASE(__FILE__"/Basic_EqualsComparison_True", "[Quaternion]")
Quaternion ref = a / b; {
a /= b; // Run tests 1000 times
for (std::size_t i = 0; i < 1000; i++)
// Verify {
Assert::IsTrue(a.GetRawValues().Similar(ref.GetRawValues())); // Setup
} const Vector3d e(rng() % 360, rng() % 360, rng() % 360);
const Quaternion a(e);
return; const Quaternion b(e);
}
// Exercise and verify
// Tests basic equals comparison -> true REQUIRE(a == b);
TEST_METHOD(Basic_EqualsComparison_True) }
{
// Run tests 1000 times return;
for (std::size_t i = 0; i < 1000; i++) }
{
// Setup // Tests basic equals comparison -> true
Vector3d e(rng() % 360, rng() % 360, rng() % 360); TEST_CASE(__FILE__"/Basic_EqualsComparison_False", "[Quaternion]")
Quaternion a(e); {
Quaternion b(e); // Run tests 1000 times
for (std::size_t i = 0; i < 1000; i++)
// Exercise and verify {
Assert::IsTrue(a == b); // Setup
} const Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
const Vector3d be(rng() % 360, rng() % 360, rng() % 360);
return;
} // Abort if both vectors are equal
if (ae == be)
// Tests basic equals comparison -> true {
TEST_METHOD(Basic_EqualsComparison_False) i--;
{ continue;
// Run tests 1000 times }
for (std::size_t i = 0; i < 1000; i++)
{ const Quaternion a(ae);
// Setup const Quaternion b(be);
Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
Vector3d be(rng() % 360, rng() % 360, rng() % 360); // Exercise and verify
REQUIRE_FALSE(a == b);
// Abort if both vectors are equal }
if (ae == be)
{ return;
i--; }
continue;
} // Tests that different euler angles return true, if the angle is the same.
// Like [30, -10, 59] == [390, 350, 419]
Quaternion a(ae); TEST_CASE(__FILE__"/Equals_Comparison_Same_Rotation_Different_EulerAngles", "[Quaternion]")
Quaternion b(be); {
// Run tests 1000 times
// Exercise and verify for (std::size_t i = 0; i < 1000; i++)
Assert::IsFalse(a == b); {
} // Setup
// Create random rotation
return; const Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
}
// add or subtract a random multiple of 360
// Tests that different euler angles return true, if the angle is the same. #define keep_rot_change_values (360.0 * (double)(rng() % 20) * ((rng()%2) ? 1.0 : -1.0))
// Like [30, -10, 59] == [390, 350, 419] const Vector3d be(ae.x + keep_rot_change_values, ae.y + keep_rot_change_values, ae.z + keep_rot_change_values);
TEST_METHOD(Equals_Comparison_Same_Rotation_Different_EulerAngles) #undef keep_rot_change_values
{
// Run tests 1000 times // Create quaternions
for (std::size_t i = 0; i < 1000; i++) const Quaternion a(ae);
{ const Quaternion b(be);
// Setup
// Create random rotation // Exercise & Verify
Vector3d ae(rng() % 360, rng() % 360, rng() % 360); // Create debug output
// add or subtract a random multiple of 360 INFO("ae: " << ae << '\n'
#define keep_rot_change_values (360.0 * (double)(rng() % 20) * ((rng()%2) ? 1.0 : -1.0)) << "be: " << be << '\n'
Vector3d be(ae.x + keep_rot_change_values, ae.y + keep_rot_change_values, ae.z + keep_rot_change_values); << "a: " << a << '\n'
#undef keep_rot_change_values << "b: " << b << '\n'
);
// Create quaternions
Quaternion a(ae); // Assertion
Quaternion b(be); REQUIRE(a == b);
}
// Exercise & Verify
// Create debug output return;
}
std::wstringstream wss;
wss << "ae: " << ae << std::endl // Tests basic not-equals comparison -> false
<< "be: " << be << std::endl TEST_CASE(__FILE__"/Basic_NotEqualsComparison_False", "[Quaternion]")
<< "a: " << a << std::endl {
<< "b: " << b << std::endl; // Run tests 1000 times
for (std::size_t i = 0; i < 1000; i++)
// Assertion {
Assert::IsTrue(a == b, wss.str().c_str()); // Setup
} const Vector3d e(rng() % 360, rng() % 360, rng() % 360);
const Quaternion a(e);
return; const Quaternion b(e);
}
// Exercise and verify
// Tests basic not-equals comparison -> false REQUIRE_FALSE(a != b);
TEST_METHOD(Basic_NotEqualsComparison_False) }
{
// Run tests 1000 times return;
for (std::size_t i = 0; i < 1000; i++) }
{
// Setup // Tests basic not-equals comparison -> true
Vector3d e(rng() % 360, rng() % 360, rng() % 360); TEST_CASE(__FILE__"/Basic_NotEqualsComparison_True", "[Quaternion]")
Quaternion a(e); {
Quaternion b(e); // Run tests 1000 times
for (std::size_t i = 0; i < 1000; i++)
// Exercise and verify {
Assert::IsFalse(a != b); // Setup
} const Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
const Vector3d be(rng() % 360, rng() % 360, rng() % 360);
return;
} // Abort if both vectors are equal
if (ae == be)
// Tests basic not-equals comparison -> true {
TEST_METHOD(Basic_NotEqualsComparison_True) i--;
{ continue;
// Run tests 1000 times }
for (std::size_t i = 0; i < 1000; i++)
{ const Quaternion a(ae);
// Setup const Quaternion b(be);
Vector3d ae(rng() % 360, rng() % 360, rng() % 360);
Vector3d be(rng() % 360, rng() % 360, rng() % 360); // Exercise and verify
REQUIRE(a != b);
// Abort if both vectors are equal }
if (ae == be)
{ return;
i--;
continue;
}
Quaternion a(ae);
Quaternion b(be);
// Exercise and verify
Assert::IsTrue(a != b);
}
return;
}
};
} }