From 59f1164458f37582c75dcfbd3553aee43fbcc760 Mon Sep 17 00:00:00 2001 From: Leonetienne Date: Fri, 11 Feb 2022 13:40:22 +0100 Subject: [PATCH] Translated tests for Vector3 --- Test/CMakeLists.txt | 1 + Test/Math_Similar.cpp | 61 - Test/Matrix4x4.cpp | 1 - Test/Vector3.cpp | 3018 ++++++++++++++++++++--------------------- 4 files changed, 1472 insertions(+), 1609 deletions(-) delete mode 100644 Test/Math_Similar.cpp diff --git a/Test/CMakeLists.txt b/Test/CMakeLists.txt index 66a5156..2263cda 100644 --- a/Test/CMakeLists.txt +++ b/Test/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable(Tests Math__Min.cpp Math__Similar.cpp Matrix4x4.cpp + Vector3.cpp ) target_link_libraries(Tests Eule) diff --git a/Test/Math_Similar.cpp b/Test/Math_Similar.cpp deleted file mode 100644 index 2a6908b..0000000 --- a/Test/Math_Similar.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "CppUnitTest.h" -#include "../Eule/Math.h" - -using namespace Microsoft::VisualStudio::CppUnitTestFramework; -using namespace Eule; - -namespace _Math -{ - TEST_CLASS(_Similar) - { - public: - // Checks that the similar function works with an exact comparison -> true - TEST_METHOD(Exact_Comparison_True) - { - Assert::IsTrue(Math::Similar(100, 100, 0)); - return; - } - - // Checks that the similar function works with an exact comparison -> false - TEST_METHOD(Exact_Comparison_False) - { - Assert::IsFalse(Math::Similar(100, 100.001, 0)); - return; - } - - // Checks that the similar function works with an exact comparison -> false - TEST_METHOD(Exact_Comparison_False2) - { - Assert::IsFalse(Math::Similar(100, 99.999, 0)); - return; - } - - // Checks that the similar function works with a loose comparison -> true - TEST_METHOD(Loose_Comparison_True) - { - Assert::IsTrue(Math::Similar(100, 100.001, 0.01)); - return; - } - - // Checks that the similar function works with a loose comparison -> true - TEST_METHOD(Loose_Comparison_True2) - { - Assert::IsTrue(Math::Similar(100, 99.999, 0.01)); - return; - } - - // Checks that the similar function works with a loose comparison -> false - TEST_METHOD(Loose_Comparison_False) - { - Assert::IsFalse(Math::Similar(100, 100.1, 0.01)); - return; - } - - // Checks that the similar function works with a loose comparison -> false - TEST_METHOD(Loose_Comparison_False2) - { - Assert::IsFalse(Math::Similar(100, 99.9, 0.01)); - return; - } - }; -} diff --git a/Test/Matrix4x4.cpp b/Test/Matrix4x4.cpp index ab3f59e..a0d3a73 100644 --- a/Test/Matrix4x4.cpp +++ b/Test/Matrix4x4.cpp @@ -10,7 +10,6 @@ namespace { static std::mt19937 rng = std::mt19937((std::random_device())()); } - // Tests that a freshly created matrix is an identity matrix TEST_CASE(__FILE__"/New_Matrix_Is_Identity", "[Matrix4x4]") { diff --git a/Test/Vector3.cpp b/Test/Vector3.cpp index 32d9d2b..72dcd98 100644 --- a/Test/Vector3.cpp +++ b/Test/Vector3.cpp @@ -1,1553 +1,1477 @@ -#include "CppUnitTest.h" -#include "../Eule/Vector3.h" -#include "../Eule/Math.h" +#include "Catch2.h" +#include +#include #include "../_TestingUtilities/HandyMacros.h" #include -#include -using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Eule; -namespace Vectors -{ - TEST_CLASS(_Vector3) - { - private: - std::mt19937 rng; - - public: - // Constructor - _Vector3() - { - rng = std::mt19937((std::random_device())()); - return; - } - - // Tests if all values are 0 after initialization via default constructor - TEST_METHOD(New_Vector_All_0) - { - Vector3d v3; - - Assert::AreEqual(0.0, v3.x); - Assert::AreEqual(0.0, v3.y); - Assert::AreEqual(0.0, v3.z); - - return; - } - - // Tests if values can be set via the constructor - TEST_METHOD(Can_Set_Values_Constructor) - { - Vector3d v3(69, 32, 16); - - Assert::AreEqual(69.0, v3.x); - Assert::AreEqual(32.0, v3.y); - Assert::AreEqual(16.0, v3.z); - - return; - } - - // Tests if values can be set via letters - TEST_METHOD(Can_Set_Values_Letters) - { - Vector3d v3; - v3.x = 69; - v3.y = 32; - v3.z = 16; - - Assert::AreEqual(69.0, v3.x); - Assert::AreEqual(32.0, v3.y); - Assert::AreEqual(16.0, v3.z); - - return; - } - - // Tests if values can be set via array descriptors - TEST_METHOD(Can_Set_Values_ArrayDescriptor) - { - Vector3d v3; - v3[0] = 69; - v3[1] = 32; - v3[2] = 16; - - Assert::AreEqual(69.0, v3.x); - Assert::AreEqual(32.0, v3.y); - Assert::AreEqual(16.0, v3.z); - - return; - } - - // Tests if values can be set via an initializer list - TEST_METHOD(Can_Set_Values_InitializerList) - { - Vector3d v3 = { 69, 32, 16 }; - - Assert::AreEqual(69.0, v3.x); - Assert::AreEqual(32.0, v3.y); - Assert::AreEqual(16.0, v3.z); - - return; - } - - // Tests for vectors copied via the copy constructor to have the same values - TEST_METHOD(Copy_Constructor_Same_Values) - { - Vector3d a(69, 32, 16); - Vector3d b(a); - - Assert::AreEqual(a.x, b.x); - Assert::AreEqual(a.y, b.y); - Assert::AreEqual(a.z, b.z); - - return; - } - - // Tests for vectors copied via the equals operator to have the same values - TEST_METHOD(Operator_Equals_Same_Values) - { - Vector3d a(69, 32, 16); - Vector3d b = a; - - Assert::AreEqual(a.x, b.x); - Assert::AreEqual(a.y, b.y); - Assert::AreEqual(a.z, b.z); - - return; - } - - // Tests for vectors copied via the copy constructor to be modifyable without modifying the original object - TEST_METHOD(Copy_Constructor_Independent) - { - Vector3d a(69, 32, 16); - Vector3d b(a); - - b.x = 169; - b.y = 132; - b.z = 116; - - Assert::AreEqual(69.0, a.x); - Assert::AreEqual(32.0, a.y); - Assert::AreEqual(16.0, a.z); - - Assert::AreEqual(169.0, b.x); - Assert::AreEqual(132.0, b.y); - Assert::AreEqual(116.0, b.z); - - return; - } - - // Tests for vectors copied via the equals operator to be modifyable without modifying the original object - TEST_METHOD(Operator_Equals_Independent) - { - Vector3d a(69, 32, 16); - Vector3d b = a; - - b.x = 169; - b.y = 132; - b.z = 116; - - Assert::AreEqual(69.0, a.x); - Assert::AreEqual(32.0, a.y); - Assert::AreEqual(16.0, a.z); - - Assert::AreEqual(169.0, b.x); - Assert::AreEqual(132.0, b.y); - Assert::AreEqual(116.0, b.z); - - return; - } - - // Tests if the dot product between two vectors angled 90 degrees from one another is 0. It should by definition be 0! - // Dot products are commutative, so we'll check both directions. - // This test tests all possible 90 degree setups with 1000x random lengths - TEST_METHOD(DotProduct_90deg) - { - // Test 1000 times - for (std::size_t i = 0; i < 100; i++) - { - // The length of the vectors should not matter. Only the angle should. - // Let's test that! - Vector3d a = Vector3d(1, 0, 0) * (rng() % 6969 + 1.0); - Vector3d b = Vector3d(0, 1, 0) * (rng() % 6969 + 1.0); - - std::wstringstream wss; - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::AreEqual(0.0, a.DotProduct(b), wss.str().c_str()); - Assert::AreEqual(0.0, b.DotProduct(a), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(0, 1, 0) * (rng() % 6969 + 1.0); - b = Vector3d(1, 0, 0) * (rng() % 6969 + 1.0); - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::AreEqual(0.0, a.DotProduct(b), wss.str().c_str()); - Assert::AreEqual(0.0, b.DotProduct(a), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(0, 1, 0) * (rng() % 6969 + 1.0); - b = Vector3d(0, 0, 1) * (rng() % 6969 + 1.0); - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::AreEqual(0.0, a.DotProduct(b), wss.str().c_str()); - Assert::AreEqual(0.0, b.DotProduct(a), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(0, 0, 1) * (rng() % 6969 + 1.0); - b = Vector3d(0, 1, 0) * (rng() % 6969 + 1.0); - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::AreEqual(0.0, a.DotProduct(b), wss.str().c_str()); - Assert::AreEqual(0.0, b.DotProduct(a), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(1, 0, 0) * (rng() % 6969 + 1.0); - b = Vector3d(0, 0, 1) * (rng() % 6969 + 1.0); - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::AreEqual(0.0, a.DotProduct(b), wss.str().c_str()); - Assert::AreEqual(0.0, b.DotProduct(a), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(0, 0, 1) * (rng() % 6969 + 1.0); - b = Vector3d(1, 0, 0) * (rng() % 6969 + 1.0); - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::AreEqual(0.0, a.DotProduct(b), wss.str().c_str()); - Assert::AreEqual(0.0, b.DotProduct(a), wss.str().c_str()); - } - - return; - } - - // Test if the dot product is positive for two vectors angled less than 90 degrees from another - // Dot products are commutative, so we'll check both directions. - TEST_METHOD(DotProduct_LessThan90deg) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - // The length of the vectors should not matter. Only the angle should. - // Let's test that! - Vector3d a = Vector3d(1, 1.0 / (rng() % 100), 69) * (rng() % 6969 + 1.0); // Don't allow the scalar to become 0 - Vector3d b = Vector3d(1.0 / (rng() % 100), 1, 69) * (rng() % 6969 + 1.0); - - - std::wstringstream wss; - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::IsTrue(a.DotProduct(b) > 0, wss.str().c_str()); - Assert::IsTrue(b.DotProduct(a) > 0, wss.str().c_str()); - } - - return; - } - - // Test if the dot product is negative for two vectors angled greater than 90 degrees from another - // Dot products are commutative, so we'll check both directions. - TEST_METHOD(DotProduct_GreaterThan90deg) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - // The length of the vectors should not matter. Only the angle should. - // Let's test that! - Vector3d a = Vector3d(1, -1.0 / (rng() % 100), 69) * (rng() % 6969 + 1.0); // Don't allow the scalar to become 0 - Vector3d b = Vector3d(-1.0 / (rng() % 100), 1, -69) * (rng() % 6969 + 1.0); - - std::wstringstream wss; - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::IsTrue(a.DotProduct(b) < 0, wss.str().c_str()); - Assert::IsTrue(b.DotProduct(a) < 0, wss.str().c_str()); - } - - return; - } - - // Tests that the dot product is correct for a known value - TEST_METHOD(DotProduct_Oracle) - { - // Setup - Vector3d a(-99, 199, -32); - Vector3d b(18, -1, -21); - - // Exercise - const double dot = a.DotProduct(b); - - // Verify - Assert::AreEqual(-1309.0, dot); - - return; - } - - // Quick and dirty check if the useless int-method is working - TEST_METHOD(DotProduct_Dirty_Int) - { - Vector3i a; - Vector3i b; - std::wstringstream wss; - - // 90 deg - a = { 0, 10, 0 }; - b = { 10, 0, 0 }; - wss.str(L""); - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::AreEqual(0.0, a.DotProduct(b), wss.str().c_str()); - Assert::AreEqual(0.0, b.DotProduct(a), wss.str().c_str()); - - // < 90 deg - a = { 7, 10, 10 }; - b = { 10, 1, 10 }; - wss.str(L""); - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::IsTrue(a.DotProduct(b) > 0.0, wss.str().c_str()); - Assert::IsTrue(b.DotProduct(a) > 0.0, wss.str().c_str()); - - // > 90 deg - a = { -3, 10, -10 }; - b = { 10, -4, 10 }; - wss.str(L""); - wss << a << L" DOT " << b << L" = " << a.DotProduct(b) << std::endl; - Assert::IsTrue(a.DotProduct(b) < 0.0, wss.str().c_str()); - Assert::IsTrue(b.DotProduct(a) < 0.0, wss.str().c_str()); - - return; - } - - // Tests for the cross product between the same vector being 0 - TEST_METHOD(CrossProduct_Same_Vector_Is_0) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = LARGE_RAND_DOUBLE; - double y = LARGE_RAND_DOUBLE; - double z = LARGE_RAND_DOUBLE; - - Vector3d a(x, y, z); - - std::wstringstream wss; - wss << a << L" CROSS " << a << L" = " << a.CrossProduct(a) << std::endl; - Assert::IsTrue(Vector3d(0,0,0) == a.CrossProduct(a), wss.str().c_str()); - } - - return; - } - - // Tests for the cross product between opposite vectors being 0 - TEST_METHOD(CrossProduct_Opposite_Vector_Is_0) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = LARGE_RAND_DOUBLE; - double y = LARGE_RAND_DOUBLE; - double z = LARGE_RAND_DOUBLE; - - Vector3d a(x, y, z); - Vector3d b(-x, -y, -z); - - std::wstringstream wss; - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, 0, 0) == a.CrossProduct(b), wss.str().c_str()); - } - - return; - } - - // Tests for known values - TEST_METHOD(CrossProduct_KnownValues) - { - Vector3d a; - Vector3d b; - - std::wstringstream wss; - - wss.str(L""); - a = Vector3d(1, 0, 0); - b = Vector3d(0, 0, 1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -1, 0) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(-1, 0, 0); - b = Vector3d(0, 0, -1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -1, 0) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(1, 0, 0); - b = Vector3d(0, 0, -1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, 1, 0) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(1, 0, 0); - b = Vector3d(0, 1, 0); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, 0, 1) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(1, 0, 0); - b = Vector3d(1, 0, 1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -1, 0) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(1, 0, 0); - b = Vector3d(1, 1, 1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -1, 1) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3d(3, -1, -3); - b = Vector3d(-1, 1, 3); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -6, 2) == a.CrossProduct(b), wss.str().c_str()); - - return; - } - - // Tests for known values, but with int vectors - TEST_METHOD(CrossProduct_KnownValues_Int) - { - Vector3i a; - Vector3i b; - - std::wstringstream wss; - - wss.str(L""); - a = Vector3i(1, 0, 0); - b = Vector3i(0, 0, 1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -1, 0) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3i(-1, 0, 0); - b = Vector3i(0, 0, -1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -1, 0) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3i(1, 0, 0); - b = Vector3i(0, 0, -1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, 1, 0) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3i(1, 0, 0); - b = Vector3i(0, 1, 0); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, 0, 1) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3i(1, 0, 0); - b = Vector3i(1, 0, 1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -1, 0) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3i(1, 0, 0); - b = Vector3i(1, 1, 1); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -1, 1) == a.CrossProduct(b), wss.str().c_str()); - - wss.str(L""); - a = Vector3i(3, -1, -3); - b = Vector3i(-1, 1, 3); - wss << a << L" CROSS " << b << L" = " << a.CrossProduct(b) << std::endl; - Assert::IsTrue(Vector3d(0, -6, 2) == a.CrossProduct(b), wss.str().c_str()); - - return; - } - - // Tests the SqrMagnitude method to work as expected with random numbers - TEST_METHOD(SqrMagnitude) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = (double)(rng() % 1000) - 500.0; // Too large numbers would get unaccurate decimals when using intrinsics. - double y = (double)(rng() % 1000) - 500.0; - double z = (double)(rng() % 1000) - 500.0; - double expected = x*x + y*y + z*z; - - Assert::IsTrue(Math::Similar(expected, Vector3d(x, y, z).SqrMagnitude())); - } - - return; - } - - // Tests the SqrMagnitude method to work as expected with random numbers, but with an int-vector - TEST_METHOD(SqrMagnitude_Int) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - int x = LARGE_RAND_INT; - int y = LARGE_RAND_INT; - int z = LARGE_RAND_INT; - int expected = x*x + y*y + z*z; - - Assert::AreEqual((double)expected, Vector3i(x, y, z).SqrMagnitude()); - } - - return; - } - - // Tests for the length of the vector (0,0,0) being 0 - TEST_METHOD(Magnitude_Is_0_On_Vec0) - { - Assert::AreEqual(0.0, Vector3d(0, 0, 0).Magnitude()); - return; - } - - // Tests for a vector of a known length to actually return that - TEST_METHOD(Magnitude_One_Axis_X) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = (double)(rng() % 1000) - 500.0; // Too large numbers would get unaccurate decimals when using intrinsics. - Vector3d vec(x, 0, 0); - - std::wstringstream wss; - wss << std::endl << std::setprecision(20) - << "Actual: " << vec.Magnitude() << std::endl - << "Expected: " << x << std::endl; - Assert::IsTrue(Math::Similar(abs(x), vec.Magnitude()), wss.str().c_str()); - } - - return; - } - - // Tests for a vector of a known length to actually return that - TEST_METHOD(Magnitude_One_Axis_Y) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double y = (double)(rng() % 1000) - 500.0; // Too large numbers would get unaccurate decimals when using intrinsics. - Vector3d vec(0, y, 0); - - std::wstringstream wss; - wss << std::endl << std::setprecision(20) - << "Actual: " << vec.Magnitude() << std::endl - << "Expected: " << y << std::endl; - Assert::IsTrue(Math::Similar(abs(y), vec.Magnitude()), wss.str().c_str()); - } - - return; - } - - // Tests for a vector of a known length to actually return that - TEST_METHOD(Magnitude_One_Axis_Z) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double z = (double)(rng() % 1000) - 500.0; // Too large numbers would get unaccurate decimals when using intrinsics. - Vector3d vec(0, 0, z); - - std::wstringstream wss; - wss << std::endl << std::setprecision(20) - << "Actual: " << vec.Magnitude() << std::endl - << "Expected: " << z << std::endl; - Assert::IsTrue(Math::Similar(abs(z), vec.Magnitude()), wss.str().c_str()); - } - - return; - } - - // Tests for a known result - TEST_METHOD(Magnitude) - { - // Ya'll got more of 'dem digits? - Assert::AreEqual(426.14786166306174663986894302070140838623046875, Vector3d(69, -420, 21).Magnitude()); - return; - } - - // Tests for expected lerp result 0.00 - TEST_METHOD(Lerp_000) - { - Vector3d a(100, 1000, 10); - Vector3d b(200, 4000, 100); - Vector3d res = a.Lerp(b, 0.00); - - std::wstringstream wss; - wss << res; - Assert::IsTrue(a == res, wss.str().c_str()); - return; - } - - // Tests for expected lerp result 0.25 - TEST_METHOD(Lerp_025) - { - Vector3d a(100, 1000, 10); - Vector3d b(200, 4000, 100); - Vector3d res = a.Lerp(b, 0.25); - - std::wstringstream wss; - wss << res; - Assert::IsTrue(Vector3d(125, 1750, 32.5) == res, wss.str().c_str()); - return; - } - - // Tests for expected lerp result 0.50 - TEST_METHOD(Lerp_050) - { - Vector3d a(100, 1000, 10); - Vector3d b(200, 4000, 100); - Vector3d res = a.Lerp(b, 0.50); - - std::wstringstream wss; - wss << res; - Assert::IsTrue(Vector3d(150, 2500, 55) == res, wss.str().c_str()); - return; - } - - // Tests for expected lerp result 0.75 - TEST_METHOD(Lerp_075) - { - Vector3d a(100, 1000, 10); - Vector3d b(200, 4000, 100); - Vector3d res = a.Lerp(b, 0.75); - - std::wstringstream wss; - wss << res; - Assert::IsTrue(Vector3d(175, 3250, 77.5) == res, wss.str().c_str()); - return; - } - - // Tests for expected lerp result 1.00 - TEST_METHOD(Lerp_100) - { - Vector3d a(100, 1000, 10); - Vector3d b(200, 4000, 100); - Vector3d res = a.Lerp(b, 1.00); - - std::wstringstream wss; - wss << res; - Assert::IsTrue(b == res, wss.str().c_str()); - return; - } - - // Tests lerpself - TEST_METHOD(LerpSelf) - { - Vector3d a(100, 1000, 10); - Vector3d b(200, 4000, 100); - - a.LerpSelf(b, 0.75); - - std::wstringstream wss; - wss << a; - Assert::IsTrue(Vector3d(175, 3250, 77.5) == a, wss.str().c_str()); - return; - } - - // Tests if an input vector of length 0 is handled correctly by the normalize method - TEST_METHOD(Normalize_Length_Before_Is_0) - { - Vector3d vec(0, 0, 0); - vec.NormalizeSelf(); - Assert::AreEqual(0.0, vec.Magnitude()); - return; - } - - // Tests for any normalized vector to be of length 1 - TEST_METHOD(Normalize_Length_Is_1) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = LARGE_RAND_DOUBLE; - double y = LARGE_RAND_DOUBLE; - double z = LARGE_RAND_DOUBLE; - - Vector3d vec(x, y, z); - - // Prevent a vector of length 0 going in - if (vec.SqrMagnitude() == 0) - vec.x++; - - std::wstringstream wss; - wss << vec; - Assert::IsTrue(Math::Similar(vec.Normalize().Magnitude(), 1.0), wss.str().c_str()); // Account for floating point inaccuracy - } - - return; - } - - // Tests the normalize method with known values - TEST_METHOD(Normalize_Oracle) - { - // Setup - Vector3d v(3.2, -5.3, 9.88); - - // Exercise - v.NormalizeSelf(); - - // Verify - Vector3d expected(0.27445384355, -0.45456417839, 0.84737624198); - Assert::IsTrue(v.Similar(expected)); - } - - // Tests for a normalized vector to still point in the exact same direction - TEST_METHOD(Normalize_Direction_Stays_Unaffected) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = LARGE_RAND_DOUBLE; - double y = LARGE_RAND_DOUBLE; - double z = LARGE_RAND_DOUBLE; - if (x == 0) x++; - if (y == 0) y++; - if (z == 0) z++; - - Vector3d vec(x, y, z); - - Vector3d vec_n(x, y, z); - vec_n = vec_n.Normalize(); - - std::wstringstream wss; - wss << vec << L" | " << vec_n; - - // Both vectors should still point in the same direction! - Assert::IsTrue( - (vec.DotProduct(vec_n) > 0) && // Roughly same direction - (Math::Similar(vec_n.CrossProduct(vec).Magnitude(), 0.0)), // Both vectors align - wss.str().c_str()); - } - return; - } - - // Kinda dumb method, but ok lol - // DON'T NORMALIZE INT-VECTORS WHAT IS WRONG WITH YOU - TEST_METHOD(Normalized_Int_Vector_Is_0) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - int x = LARGE_RAND_INT; - int y = LARGE_RAND_INT; - int z = LARGE_RAND_INT; - - Vector3i vec(x, y, z); - - vec.NormalizeSelf(); - - std::wstringstream wss; - wss << vec; - Assert::AreEqual(0.0, vec.Magnitude(), wss.str().c_str()); - } - } - - // Tests that NormalizeSelf() results in the same as Normalize() - TEST_METHOD(NormalizeSelf_IsSameAs_Normalize) - { - // Run test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - Vector3d vec(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE); - - Vector3d nVec = vec.Normalize(); - vec.NormalizeSelf(); - - Assert::IsTrue(nVec == vec); - } - - return; - } - - // Tests for the VectorScale() method to work - TEST_METHOD(VectorScale) - { - // Run test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - const double ax = LARGE_RAND_DOUBLE; - const double ay = LARGE_RAND_DOUBLE; - const double az = LARGE_RAND_DOUBLE; - const double bx = LARGE_RAND_DOUBLE; - const double by = LARGE_RAND_DOUBLE; - const double bz = LARGE_RAND_DOUBLE; - - Vector3d a(ax, ay, az); - Vector3d b(bx, by, bz); - - Vector3d target( - ax * bx, - ay * by, - az * bz - ); - - Assert::IsTrue(a.VectorScale(b) == target); - } - - return; - } - - // Tests for operator- (unary) to work - TEST_METHOD(Operator_Unary_Negative) - { - Vector3d v(29, -5, 35); - - Assert::IsTrue(Vector3d(-29, 5, -35) == -v); - - return; - } - - // Tests for operator+ to work as expected - TEST_METHOD(Operator_Add) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double ax = LARGE_RAND_DOUBLE; - double ay = LARGE_RAND_DOUBLE; - double az = LARGE_RAND_DOUBLE; - double bx = LARGE_RAND_DOUBLE; - double by = LARGE_RAND_DOUBLE; - double bz = LARGE_RAND_DOUBLE; - - Vector3d a(ax, ay, az); - Vector3d b(bx, by, bz); - - Assert::IsTrue(Vector3d(ax + bx, ay + by, az + bz) == a + b); - } - - return; - } - - // Tests for operator+= to work as expected - TEST_METHOD(Operator_Add_Equals) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double ax = LARGE_RAND_DOUBLE; - double ay = LARGE_RAND_DOUBLE; - double az = LARGE_RAND_DOUBLE; - double bx = LARGE_RAND_DOUBLE; - double by = LARGE_RAND_DOUBLE; - double bz = LARGE_RAND_DOUBLE; - - Vector3d a(ax, ay, az); - a += Vector3d(bx, by, bz); - - Assert::IsTrue(Vector3d(ax + bx, ay + by, az + bz) == a); - } - - return; - } - - // Tests for operator- to work as expected - TEST_METHOD(Operator_Sub) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double ax = LARGE_RAND_DOUBLE; - double ay = LARGE_RAND_DOUBLE; - double az = LARGE_RAND_DOUBLE; - double bx = LARGE_RAND_DOUBLE; - double by = LARGE_RAND_DOUBLE; - double bz = LARGE_RAND_DOUBLE; - - Vector3d a(ax, ay, az); - Vector3d b(bx, by, bz); - - Assert::IsTrue(Vector3d(ax - bx, ay - by, az - bz) == a - b); - } - - return; - } - - // Tests for operator-= to work as expected - TEST_METHOD(Operator_Sub_Equals) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double ax = LARGE_RAND_DOUBLE; - double ay = LARGE_RAND_DOUBLE; - double az = LARGE_RAND_DOUBLE; - double bx = LARGE_RAND_DOUBLE; - double by = LARGE_RAND_DOUBLE; - double bz = LARGE_RAND_DOUBLE; - - Vector3d a(ax, ay, az); - a -= Vector3d(bx, by, bz); - - Assert::IsTrue(Vector3d(ax - bx, ay - by, az - bz) == a); - } - - return; - } - - // Tests for operator* to work as expected - TEST_METHOD(Operator_Mult) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = LARGE_RAND_DOUBLE; - double y = LARGE_RAND_DOUBLE; - double z = LARGE_RAND_DOUBLE; - double scalar = LARGE_RAND_DOUBLE; - - Vector3d a(x, y, z); - - Assert::IsTrue(Vector3d(x * scalar, y * scalar, z * scalar) == a * scalar); - } - - return; - } - - // Tests for operator*= to work as expected - TEST_METHOD(Operator_Mult_Equals) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = LARGE_RAND_DOUBLE; - double y = LARGE_RAND_DOUBLE; - double z = LARGE_RAND_DOUBLE; - double scalar = LARGE_RAND_DOUBLE; - - Vector3d a(x, y, z); - a *= scalar; - - Assert::IsTrue(Vector3d(x * scalar, y * scalar, z * scalar) == a); - } - - return; - } - - // Tests for operator/ to work as expected - TEST_METHOD(Operator_Div) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = LARGE_RAND_DOUBLE; - double y = LARGE_RAND_DOUBLE; - double z = LARGE_RAND_DOUBLE; - double scalar = LARGE_RAND_DOUBLE; - - Vector3d a(x, y, z); - - Assert::IsTrue(Vector3d(x / scalar, y / scalar, z / scalar) == a / scalar); - } - - return; - } - - // Tests for operator/= to work as expected - TEST_METHOD(Operator_Div_Equals) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - double x = LARGE_RAND_DOUBLE; - double y = LARGE_RAND_DOUBLE; - double z = LARGE_RAND_DOUBLE; - double scalar = LARGE_RAND_DOUBLE; - - Vector3d a(x, y, z); - a /= scalar; - - Assert::IsTrue(Vector3d(x / scalar, y / scalar, z / scalar) == a); - } - - return; - } - - // Tests for operator== to work as expected - TEST_METHOD(Operator_Equals) - { - // Test 1000 times - for (std::size_t i = 0; i < 10000; i++) - { - double ax = (rng() % 10) - 5; - double ay = (rng() % 10) - 5; - double az = (rng() % 10) - 5; - double bx = (rng() % 10) - 5; - double by = (rng() % 10) - 5; - double bz = (rng() % 10) - 5; - - Vector3d a(ax, ay, az); - Vector3d b(bx, by, bz); - - Assert::IsTrue( - ((ax == bx) && (ay == by) && (az == bz)) == - (a == b) - ); - } - - return; - } - - // Tests for operator!= to work as expected - TEST_METHOD(Operator_Not_Equals) - { - // Test 1000 times - for (std::size_t i = 0; i < 10000; i++) - { - double ax = (rng() % 10) - 5; - double ay = (rng() % 10) - 5; - double az = (rng() % 10) - 5; - double bx = (rng() % 10) - 5; - double by = (rng() % 10) - 5; - double bz = (rng() % 10) - 5; - - Vector3d a(ax, ay, az); - Vector3d b(bx, by, bz); - - Assert::IsTrue( - ((ax != bx) || (ay != by) || (az != bz)) == - (a != b) - ); - } - - return; - } - - // Tests for matrix multiplication working regarding rotation - TEST_METHOD(MatrixMult_Rotate_Yaw) - { - // Create vector - Vector3d vec(69, 32, 16); - Vector3d originalVec = vec; - - // Create 90deg yaw rotation matrix (Y) - Matrix4x4 mat; - mat[0] = { 0, 0, 1, 0 }; - mat[1] = { 0, 1, 0, 0 }; - mat[2] = { -1, 0, 0, 0 }; - - // Rotate vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << L"Rot #1 " << vec; - Assert::IsTrue(Vector3d(16, 32, -69) == vec, wss.str().c_str()); - - // Rotate again! - vec *= mat; - wss.str(L""); - wss << L"Rot #2 " << vec; - Assert::IsTrue(Vector3d(-69, 32, -16) == vec, wss.str().c_str()); - - // Rotate again! - vec *= mat; - wss.str(L""); - wss << L"Rot #3 " << vec; - Assert::IsTrue(Vector3d(-16, 32, 69) == vec, wss.str().c_str()); - - // Rotate by 90 deg a last time, having completed a 360° rotation. - vec *= mat; - wss.str(L""); - wss << L"Rot #4 " << vec; - Assert::IsTrue(originalVec == vec, wss.str().c_str()); - - return; - } - - // Tests for matrix multiplication working regarding rotation - TEST_METHOD(MatrixMult_Rotate_Roll) - { - // Create vector - Vector3d vec(69, 32, 16); - Vector3d originalVec = vec; - - // Create 90deg roll rotation matrix (Z) - Matrix4x4 mat; - mat[0] = { 0, -1, 0, 0 }; - mat[1] = { 1, 0, 0, 0 }; - mat[2] = { 0, 0, 1, 0 }; - - // Rotate vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << L"Rot #1 " << vec; - Assert::IsTrue(Vector3d(-32, 69, 16) == vec, wss.str().c_str()); - - // Rotate again! - vec *= mat; - wss.str(L""); - wss << L"Rot #2 " << vec; - Assert::IsTrue(Vector3d(-69, -32, 16) == vec, wss.str().c_str()); - - // Rotate again! - vec *= mat; - wss.str(L""); - wss << L"Rot #3 " << vec; - Assert::IsTrue(Vector3d(32, -69, 16) == vec, wss.str().c_str()); - - // Rotate by 90 deg a last time, having completed a 360° rotation. - vec *= mat; - wss.str(L""); - wss << L"Rot #4 " << vec; - Assert::IsTrue(originalVec == vec, wss.str().c_str()); - - return; - } - - // Tests for matrix multiplication working regarding rotation - TEST_METHOD(MatrixMult_Rotate_Pitch) - { - // Create vector - Vector3d vec(69, 32, 16); - Vector3d originalVec = vec; - - // Create 90deg pitch rotation matrix (X) - Matrix4x4 mat; - mat[0] = { 1, 0, 0, 0 }; - mat[1] = { 0, 0, -1, 0 }; - mat[2] = { 0, 1, 0, 0 }; - - // Rotate vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << L"Rot #1 " << vec; - Assert::IsTrue(Vector3d(69, -16, 32) == vec, wss.str().c_str()); - - // Rotate again! - vec *= mat; - wss.str(L""); - wss << L"Rot #2 " << vec; - Assert::IsTrue(Vector3d(69, -32, -16) == vec, wss.str().c_str()); - - // Rotate again! - vec *= mat; - wss.str(L""); - wss << L"Rot #3 " << vec; - Assert::IsTrue(Vector3d(69, 16, -32) == vec, wss.str().c_str()); - - // Rotate by 90 deg a last time, having completed a 360° rotation. - vec *= mat; - wss.str(L""); - wss << L"Rot #4 " << vec; - Assert::IsTrue(originalVec == vec, wss.str().c_str()); - - return; - } - - // Tests if rotating a vector (1,1,1) by (45,45,45) eulers works - TEST_METHOD(MatrixMult_Rotate_Unit_Combined) - { - // Create vector - Vector3d vec(1, 1, 1); - - // Create rotation matrix - Matrix4x4 mat; - mat[0] = { 0.5, -0.1465, 0.8535, 0 }; - mat[1] = { 0.5, 0.8535, -0.1465, 0 }; - mat[2] = { -0.7072, 0.5, 0.5, 0 }; - - // Rotate vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue( - Math::Similar(vec.x, 1.207, 0.001) && - Math::Similar(vec.y, 1.207, 0.001) && - Math::Similar(vec.z, 0.2928, 0.001), - wss.str().c_str()); - - return; - } - - // Tests if rotating a vector (69,32,16) by (45,45,45) eulers works - TEST_METHOD(MatrixMult_Rotate_HalfUnit_Combined) - { - // Create vector - Vector3d vec(69, 32, 16); - - // Create rotation matrix - Matrix4x4 mat; - mat[0] = { 0.5, -0.1465, 0.8535, 0 }; - mat[1] = { 0.5, 0.8535, -0.1465, 0 }; - mat[2] = { -0.7072, 0.5, 0.5, 0 }; - - // Rotate vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue( - Math::Similar(vec.x, 43.468, 0.001) && - Math::Similar(vec.y, 59.468, 0.001) && - Math::Similar(vec.z, -24.7968, 0.001), - wss.str().c_str()); - - return; - } - - // Tests if rotating a vector (69,32,16) by (45,45,45) eulers works - TEST_METHOD(MatrixMult_Rotate_Combined) - { - // Create vector - Vector3d vec(69, 32, 16); - - // Create rotation matrix - Matrix4x4 mat; - mat[0] = { -0.1639, -0.9837, -0.0755, 0 }; - mat[1] = { 0.128, -0.097, 0.987, 0 }; - mat[2] = { -0.9782, 0.152, 0.1417, 0 }; - - // Rotate vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue( - Math::Similar(vec.x, -43.9955, 0.001) && - Math::Similar(vec.y, 21.52, 0.001) && - Math::Similar(vec.z, -60.3646, 0.001), - wss.str().c_str()); - - return; - } - - // Tests if matrix scaling works ( x axis only ) - TEST_METHOD(MatrixMult_Scale_X) - { - // Create vector - Vector3d vec(5, 6, 7); - - // Create scaling matrix - Matrix4x4 mat; - mat[0] = { 3, 0, 0, 0 }; - mat[1] = { 0, 1, 0, 0 }; - mat[2] = { 0, 0, 1, 0 }; - - // Scale vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue(Vector3d(15, 6, 7) == vec, wss.str().c_str()); - - return; - } - - // Tests if matrix scaling works ( y axis only ) - TEST_METHOD(MatrixMult_Scale_Y) - { - // Create vector - Vector3d vec(5, 6, 7); - - // Create scaling matrix - Matrix4x4 mat; - mat[0] = { 1, 0, 0, 0 }; - mat[1] = { 0, 3, 0, 0 }; - mat[2] = { 0, 0, 1, 0 }; - - // Scale vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue(Vector3d(5, 18, 7) == vec, wss.str().c_str()); - - return; - } - - // Tests if matrix scaling works ( z axis only ) - TEST_METHOD(MatrixMult_Scale_Z) - { - // Create vector - Vector3d vec(5, 6, 7); - - // Create scaling matrix - Matrix4x4 mat; - mat[0] = { 1, 0, 0, 0 }; - mat[1] = { 0, 1, 0, 0 }; - mat[2] = { 0, 0, 3, 0 }; - - // Scale vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue(Vector3d(5, 6, 21) == vec, wss.str().c_str()); - - return; - } - - // Tests if matrix scaling works ( all axes ) - TEST_METHOD(MatrixMult_Scale_Combined) - { - // Create vector - Vector3d vec(5, 6, 7); - - // Create scaling matrix - Matrix4x4 mat; - mat[0] = { 4, 0, 0, 0 }; - mat[1] = { 0, 5, 0, 0 }; - mat[2] = { 0, 0, 8, 0 }; - - // Scale vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue(Vector3d(20, 30, 56) == vec, wss.str().c_str()); - - return; - } - - // Tests if translation via matrix multiplication works - TEST_METHOD(MatrixMult_Translation) - { - // Create vector - Vector3d vec(5, 6, 7); - - // Create scaling matrix - Matrix4x4 mat; - mat[0] = { 1, 0, 0, 155 }; - mat[1] = { 0, 1, 0, -23 }; - mat[2] = { 0, 0, 1, 333 }; - - // Translate vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue(Vector3d(160, -17, 340) == vec, wss.str().c_str()); - - return; - } - - // Tests the multiplication operator (*) with a simple matrix. All other tests used the * operator (without the '=') - TEST_METHOD(MatrixMult_Not_Using_MultEqualsOperator) - { - // Create vector - Vector3d vec(5.1, 6.4, 7.99); - - // Create scaling and translation matrix - Matrix4x4 mat; - mat[0] = { 3.8, 0, 0, -5.1 }; - mat[1] = { 0, -1.5, 0, 15.2 }; - mat[2] = { 0, 0, 3.01, 19.9 }; - - // Transform vector - vec = vec * mat; - - // Did we succeed? - Vector3d expected( - 5.1 * 3.8 - 5.1, - 6.4 * -1.5 + 15.2, - 7.99 * 3.01 + 19.9 - ); - - std::wstringstream wss; - wss << std::endl; - wss << "Expected: " << expected << std::endl; - wss << "Actual: " << vec; - - Assert::IsTrue(expected == vec, wss.str().c_str()); - - return; - } - - // A simple matrix multiplication tested on an int vector - TEST_METHOD(MatrixMult_Dirty_Int_Check) - { - // Create vector - Vector3i vec(5, 6, 7); - - // Create scaling and translation matrix - Matrix4x4 mat; - mat[0] = { 3, 0, 0, -5 }; - mat[1] = { 0, -1, 0, 15 }; - mat[2] = { 0, 0, 3, 20 }; - - // Transform vector - vec *= mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue(Vector3i( - 5*3 + -5, - 6*-1 + 15, - 7*3 + 20 - ) == vec, wss.str().c_str()); - - return; - } - - // Tests the multiplication operator (*) with a simple matrix. All other tests used the * operator (without the '=') - TEST_METHOD(MatrixMult_Dirty_Int_Check_Not_Using_MultEqualsOperator) - { - // Create vector - Vector3i vec(5, 6, 7); - - // Create scaling and translation matrix - Matrix4x4 mat; - mat[0] = { 3, 0, 0, -5 }; - mat[1] = { 0, -1, 0, 15 }; - mat[2] = { 0, 0, 3, 20 }; - - // Scale vector - vec = vec * mat; - - // Did we succeed? - std::wstringstream wss; - wss << vec; - Assert::IsTrue(Vector3i( - 5 * 3 + -5, - 6 * -1 + 15, - 7 * 3 + 20 - ) == vec, wss.str().c_str()); - - return; - } - - //This tests the multiplication equals operator (*=) procedurally - TEST_METHOD(MatrixMult_Equals_Procedural) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - // Generate parameters - double initialX = LARGE_RAND_DOUBLE; - double initialY = LARGE_RAND_DOUBLE; - double initialZ = LARGE_RAND_DOUBLE; - double scaleX = LARGE_RAND_DOUBLE; - double scaleY = LARGE_RAND_DOUBLE; - double scaleZ = LARGE_RAND_DOUBLE; - double transX = LARGE_RAND_DOUBLE; - double transY = LARGE_RAND_DOUBLE; - double transZ = LARGE_RAND_DOUBLE; - - // Create vector - Vector3d vec(initialX, initialY, initialZ); - - // Create matrix - Matrix4x4 mat; - mat[0] = { scaleX, 0, 0, transX }; - mat[1] = { 0, scaleY, 0, transY }; - mat[2] = { 0, 0, scaleZ, transZ }; - mat[3] = { 0, 0, 0, 0 }; - - // Create expected vector - Vector3d expected( - initialX * scaleX + transX, - initialY * scaleY + transY, - initialZ * scaleZ + transZ - ); - - // Transform vector - vec *= mat; - - // Compare - Assert::IsTrue(vec == expected); - } - - return; - } - - //This tests the multiplication operator (*) procedurally - TEST_METHOD(MatrixMult_Procedural) - { - // Test 1000 times - for (std::size_t i = 0; i < 1000; i++) - { - // Generate parameters - double initialX = LARGE_RAND_DOUBLE; - double initialY = LARGE_RAND_DOUBLE; - double initialZ = LARGE_RAND_DOUBLE; - double scaleX = LARGE_RAND_DOUBLE; - double scaleY = LARGE_RAND_DOUBLE; - double scaleZ = LARGE_RAND_DOUBLE; - double transX = LARGE_RAND_DOUBLE; - double transY = LARGE_RAND_DOUBLE; - double transZ = LARGE_RAND_DOUBLE; - - // Create vector - Vector3d vec(initialX, initialY, initialZ); - - // Create matrix - Matrix4x4 mat; - mat[0] = { scaleX, 0, 0, transX }; - mat[1] = { 0, scaleY, 0, transY }; - mat[2] = { 0, 0, scaleZ, transZ }; - mat[3] = { 0, 0, 0, 0 }; - - // Create expected vector - Vector3d expected( - initialX * scaleX + transX, - initialY * scaleY + transY, - initialZ * scaleZ + transZ - ); - - // Transform vector - vec = vec * mat; - - // Compare - Assert::IsTrue(vec == expected); - } - - return; - } - - // Tests loose comparison via Vector3d::Similar -> true - TEST_METHOD(Similar_True) - { - Assert::IsTrue( - Vector3d(0.00000000000000000000001, -6.6666666666666666666666666666, 9.9999999999999999999999999999).Similar( - Vector3d(0, -6.666666667, 10) - )); - return; - } - - // Tests loose comparison via Vector3d::Similar -> false - TEST_METHOD(Similar_False) - { - Assert::IsFalse( - Vector3d(0.00000000000000000000001, -6.6666666666666666666666666666, 9.9999999999999999999999999999).Similar( - Vector3d(0.1, -6.7, 10.1) - )); - return; - } - - // Tests that the move constructor works - TEST_METHOD(Move_Constructor) - { - Vector3d a(1,2,3); - Vector3d b(std::move(a)); - - Assert::AreEqual(b.x, 1.0); - Assert::AreEqual(b.y, 2.0); - Assert::AreEqual(b.z, 3.0); - - return; - } - - // Tests that the move operator works - TEST_METHOD(Move_Operator) - { - Vector3d a(1, 2, 3); - Vector3d b = std::move(a); - - Assert::AreEqual(b.x, 1.0); - Assert::AreEqual(b.y, 2.0); - Assert::AreEqual(b.z, 3.0); - - return; - } - }; +namespace { + static std::mt19937 rng = std::mt19937((std::random_device())()); +} + + +// Tests if all values are 0 after initialization via default constructor +TEST_CASE(__FILE__"/New_Vector_All_0", "[Vector3]") +{ + Vector3d v3; + + REQUIRE(0.0 == v3.x); + REQUIRE(0.0 == v3.y); + REQUIRE(0.0 == v3.z); + + return; +} + +// Tests if values can be set via the constructor +TEST_CASE(__FILE__"/Can_Set_Values_Constructor", "[Vector3]") +{ + Vector3d v3(69, 32, 16); + + REQUIRE(69. == v3.x); + REQUIRE(32. == v3.y); + REQUIRE(16. == v3.z); + + return; +} + +// Tests if values can be set via letters +TEST_CASE(__FILE__"/Can_Set_Values_Letters", "[Vector3]") +{ + Vector3d v3; + v3.x = 69; + v3.y = 32; + v3.z = 16; + + REQUIRE(69. == v3.x); + REQUIRE(32. == v3.y); + REQUIRE(16. == v3.z); + + return; +} + +// Tests if values can be set via array descriptors +TEST_CASE(__FILE__"/Can_Set_Values_ArrayDescriptor", "[Vector3]") +{ + Vector3d v3; + v3[0] = 69; + v3[1] = 32; + v3[2] = 16; + + REQUIRE(69. == v3.x); + REQUIRE(32. == v3.y); + REQUIRE(16. == v3.z); + + return; +} + +// Tests if values can be set via an initializer list +TEST_CASE(__FILE__"/Can_Set_Values_InitializerList", "[Vector3]") +{ + Vector3d v3 = { 69, 32, 16 }; + + REQUIRE(69. == v3.x); + REQUIRE(32. == v3.y); + REQUIRE(16. == v3.z); + + return; +} + +// Tests for vectors copied via the copy constructor to have the same values +TEST_CASE(__FILE__"/Copy_Constructor_Same_Values", "[Vector3]") +{ + Vector3d a(69, 32, 16); + Vector3d b(a); + + REQUIRE(a.x == b.x); + REQUIRE(a.y == b.y); + REQUIRE(a.z == b.z); + + return; +} + +// Tests for vectors copied via the equals operator to have the same values +TEST_CASE(__FILE__"/Operator_Equals_Same_Values", "[Vector3]") +{ + Vector3d a(69, 32, 16); + Vector3d b = a; + + REQUIRE(a.x == b.x); + REQUIRE(a.y == b.y); + REQUIRE(a.z == b.z); + + return; +} + +// Tests for vectors copied via the copy constructor to be modifyable without modifying the original object +TEST_CASE(__FILE__"/Copy_Constructor_Independent", "[Vector3]") +{ + Vector3d a(69, 32, 16); + Vector3d b(a); + + b.x = 169; + b.y = 132; + b.z = 116; + + REQUIRE(69.0 == a.x); + REQUIRE(32.0 == a.y); + REQUIRE(16.0 == a.z); + + REQUIRE(169 == b.x); + REQUIRE(132 == b.y); + REQUIRE(116 == b.z); + + return; +} + +// Tests for vectors copied via the equals operator to be modifyable without modifying the original object +TEST_CASE(__FILE__"/Operator_Equals_Independent", "[Vector3]") +{ + Vector3d a(69, 32, 16); + Vector3d b = a; + + b.x = 169; + b.y = 132; + b.z = 116; + + REQUIRE(69.0 == a.x); + REQUIRE(32.0 == a.y); + REQUIRE(16.0 == a.z); + + REQUIRE(169 == b.x); + REQUIRE(132 == b.y); + REQUIRE(116 == b.z); + + return; +} + +// Tests if the dot product between two vectors angled 90 degrees from one another is 0. It should by definition be 0! +// Dot products are commutative, so we'll check both directions. +// This test tests all possible 90 degree setups with 1000x random lengths +TEST_CASE(__FILE__"/DotProduct_90deg", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 100; i++) + { + // The length of the vectors should not matter. Only the angle should. + // Let's test that! + Vector3d a = Vector3d(1, 0, 0) * (rng() % 6969 + 1.0); + Vector3d b = Vector3d(0, 1, 0) * (rng() % 6969 + 1.0); + + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(0.0 == a.DotProduct(b)); + REQUIRE(0.0 == b.DotProduct(a)); + + a = Vector3d(0, 1, 0) * (rng() % 6969 + 1.0); + b = Vector3d(1, 0, 0) * (rng() % 6969 + 1.0); + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(0.0 == a.DotProduct(b)); + REQUIRE(0.0 == b.DotProduct(a)); + + a = Vector3d(0, 1, 0) * (rng() % 6969 + 1.0); + b = Vector3d(0, 0, 1) * (rng() % 6969 + 1.0); + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(0.0 == a.DotProduct(b)); + REQUIRE(0.0 == b.DotProduct(a)); + + a = Vector3d(0, 0, 1) * (rng() % 6969 + 1.0); + b = Vector3d(0, 1, 0) * (rng() % 6969 + 1.0); + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(0.0 == a.DotProduct(b)); + REQUIRE(0.0 == b.DotProduct(a)); + + a = Vector3d(1, 0, 0) * (rng() % 6969 + 1.0); + b = Vector3d(0, 0, 1) * (rng() % 6969 + 1.0); + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(0.0 == a.DotProduct(b)); + REQUIRE(0.0 == b.DotProduct(a)); + + a = Vector3d(0, 0, 1) * (rng() % 6969 + 1.0); + b = Vector3d(1, 0, 0) * (rng() % 6969 + 1.0); + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(0.0 == a.DotProduct(b)); + REQUIRE(0.0 == b.DotProduct(a)); + } + + return; +} + +// Test if the dot product is positive for two vectors angled less than 90 degrees from another +// Dot products are commutative, so we'll check both directions. +TEST_CASE(__FILE__"/DotProduct_LessThan90deg", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + // The length of the vectors should not matter. Only the angle should. + // Let's test that! + Vector3d a = Vector3d(1, 1.0 / (rng() % 100), 69) * (rng() % 6969 + 1.0); // Don't allow the scalar to become 0 + Vector3d b = Vector3d(1.0 / (rng() % 100), 1, 69) * (rng() % 6969 + 1.0); + + + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(a.DotProduct(b) > 0); + REQUIRE(b.DotProduct(a) > 0); + } + + return; +} + +// Test if the dot product is negative for two vectors angled greater than 90 degrees from another +// Dot products are commutative, so we'll check both directions. +TEST_CASE(__FILE__"/DotProduct_GreaterThan90deg", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + // The length of the vectors should not matter. Only the angle should. + // Let's test that! + Vector3d a = Vector3d(1, -1.0 / (rng() % 100), 69) * (rng() % 6969 + 1.0); // Don't allow the scalar to become 0 + Vector3d b = Vector3d(-1.0 / (rng() % 100), 1, -69) * (rng() % 6969 + 1.0); + + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(a.DotProduct(b) < 0); + REQUIRE(b.DotProduct(a) < 0); + } + + return; +} + +// Tests that the dot product is correct for a known value +TEST_CASE(__FILE__"/DotProduct_Oracle", "[Vector3]") +{ + // Setup + Vector3d a(-99, 199, -32); + Vector3d b(18, -1, -21); + + // Exercise + const double dot = a.DotProduct(b); + + // Verify + REQUIRE(-1309.0 == dot); + + return; +} + +// Quick and dirty check if the useless int-method is working +TEST_CASE(__FILE__"/DotProduct_Dirty_Int", "[Vector3]") +{ + Vector3i a; + Vector3i b; + + // 90 deg + a = { 0, 10, 0 }; + b = { 10, 0, 0 }; + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(0.0 == a.DotProduct(b)); + REQUIRE(0.0 == b.DotProduct(a)); + + // < 90 deg + a = { 7, 10, 10 }; + b = { 10, 1, 10 }; + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(a.DotProduct(b) > 0.0); + REQUIRE(b.DotProduct(a) > 0.0); + + // > 90 deg + a = { -3, 10, -10 }; + b = { 10, -4, 10 }; + INFO(a << " DOT " << b << " = " << a.DotProduct(b) << '\n'); + REQUIRE(a.DotProduct(b) < 0.0); + REQUIRE(b.DotProduct(a) < 0.0); + + return; +} + +// Tests for the cross product between the same vector being 0 +TEST_CASE(__FILE__"/CrossProduct_Same_Vector_Is_0", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + double x = LARGE_RAND_DOUBLE; + double y = LARGE_RAND_DOUBLE; + double z = LARGE_RAND_DOUBLE; + + Vector3d a(x, y, z); + + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0,0,0) == a.CrossProduct(a)); + } + + return; +} + +// Tests for the cross product between opposite vectors being 0 +TEST_CASE(__FILE__"/CrossProduct_Opposite_Vector_Is_0", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + double x = LARGE_RAND_DOUBLE; + double y = LARGE_RAND_DOUBLE; + double z = LARGE_RAND_DOUBLE; + + Vector3d a(x, y, z); + Vector3d b(-x, -y, -z); + + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, 0, 0) == a.CrossProduct(b)); + } + + return; +} + +// Tests for known values +TEST_CASE(__FILE__"/CrossProduct_KnownValues", "[Vector3]") +{ + Vector3d a; + Vector3d b; + + a = Vector3d(1, 0, 0); + b = Vector3d(0, 0, 1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -1, 0) == a.CrossProduct(b)); + + a = Vector3d(-1, 0, 0); + b = Vector3d(0, 0, -1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -1, 0) == a.CrossProduct(b)); + + a = Vector3d(1, 0, 0); + b = Vector3d(0, 0, -1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, 1, 0) == a.CrossProduct(b)); + + a = Vector3d(1, 0, 0); + b = Vector3d(0, 1, 0); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, 0, 1) == a.CrossProduct(b)); + + a = Vector3d(1, 0, 0); + b = Vector3d(1, 0, 1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -1, 0) == a.CrossProduct(b)); + + a = Vector3d(1, 0, 0); + b = Vector3d(1, 1, 1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -1, 1) == a.CrossProduct(b)); + + a = Vector3d(3, -1, -3); + b = Vector3d(-1, 1, 3); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -6, 2) == a.CrossProduct(b)); + + return; +} + +// Tests for known values, but with int vectors +TEST_CASE(__FILE__"/CrossProduct_KnownValues_Int", "[Vector3]") +{ + Vector3i a; + Vector3i b; + + a = Vector3i(1, 0, 0); + b = Vector3i(0, 0, 1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -1, 0) == a.CrossProduct(b)); + + a = Vector3i(-1, 0, 0); + b = Vector3i(0, 0, -1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -1, 0) == a.CrossProduct(b)); + + a = Vector3i(1, 0, 0); + b = Vector3i(0, 0, -1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, 1, 0) == a.CrossProduct(b)); + + a = Vector3i(1, 0, 0); + b = Vector3i(0, 1, 0); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, 0, 1) == a.CrossProduct(b)); + + a = Vector3i(1, 0, 0); + b = Vector3i(1, 0, 1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -1, 0) == a.CrossProduct(b)); + + a = Vector3i(1, 0, 0); + b = Vector3i(1, 1, 1); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -1, 1) == a.CrossProduct(b)); + + a = Vector3i(3, -1, -3); + b = Vector3i(-1, 1, 3); + INFO(a << L" CROSS " << a << L" = " << a.CrossProduct(a) << '\n'); + REQUIRE(Vector3d(0, -6, 2) == a.CrossProduct(b)); + + return; +} + +// Tests the SqrMagnitude method to work as expected with random numbers +TEST_CASE(__FILE__"/SqrMagnitude", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + double x = (double)(rng() % 1000) - 500.0; // Too large numbers would get inaccurate decimals when using intrinsics. + double y = (double)(rng() % 1000) - 500.0; + double z = (double)(rng() % 1000) - 500.0; + double expected = x*x + y*y + z*z; + + REQUIRE(Math::Similar(expected, Vector3d(x, y, z).SqrMagnitude())); + } + + return; +} + +// Tests the SqrMagnitude method to work as expected with random numbers, but with an int-vector +TEST_CASE(__FILE__"/SqrMagnitude_Int", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const int x = LARGE_RAND_INT; + const int y = LARGE_RAND_INT; + const int z = LARGE_RAND_INT; + const int expected = x*x + y*y + z*z; + + REQUIRE(expected == Vector3i(x, y, z).SqrMagnitude()); + } + + return; +} + +// Tests for the length of the vector (0,0,0) being 0 +TEST_CASE(__FILE__"/Magnitude_Is_0_On_Vec0", "[Vector3]") +{ + REQUIRE(0.0 == Vector3d(0, 0, 0).Magnitude()); + return; +} + +// Tests for a vector of a known length to actually return that +TEST_CASE(__FILE__"/Magnitude_One_Axis_X", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + double x = (double)(rng() % 1000) - 500.0; // Too large numbers would get inaccurate decimals when using intrinsics. + Vector3d vec(x, 0, 0); + + INFO('\n' + << "Actual: " << vec.Magnitude() << '\n' + << "Expected: " << x << '\n' + ); + REQUIRE(Math::Similar(abs(x), vec.Magnitude())); + } + + return; +} + +// Tests for a vector of a known length to actually return that +TEST_CASE(__FILE__"/Magnitude_One_Axis_Y", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + double y = (double)(rng() % 1000) - 500.0; // Too large numbers would get inaccurate decimals when using intrinsics. + Vector3d vec(0, y, 0); + + INFO('\n' + << "Actual: " << vec.Magnitude() << '\n' + << "Expected: " << y << '\n' + ); + REQUIRE(Math::Similar(abs(y), vec.Magnitude())); + } + + return; +} + +// Tests for a vector of a known length to actually return that +TEST_CASE(__FILE__"/Magnitude_One_Axis_Z", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + double z = (double)(rng() % 1000) - 500.0; // Too large numbers would get inaccurate decimals when using intrinsics. + Vector3d vec(0, 0, z); + + INFO('\n' + << "Actual: " << vec.Magnitude() << '\n' + << "Expected: " << z << '\n' + ); + REQUIRE(Math::Similar(abs(z), vec.Magnitude())); + } + + return; +} + +// Tests for a known result +TEST_CASE(__FILE__"/Magnitude", "[Vector3]") +{ + // Ya'll got more of 'dem digits? + REQUIRE(426.14786166306174663986894302070140838623046875 == Vector3d(69, -420, 21).Magnitude()); + return; +} + +// Tests for expected lerp result 0.00 +TEST_CASE(__FILE__"/Lerp_000", "[Vector3]") +{ + Vector3d a(100, 1000, 10); + Vector3d b(200, 4000, 100); + Vector3d res = a.Lerp(b, 0.00); + + INFO(res); + REQUIRE(a == res); + return; +} + +// Tests for expected lerp result 0.25 +TEST_CASE(__FILE__"/Lerp_025", "[Vector3]") +{ + Vector3d a(100, 1000, 10); + Vector3d b(200, 4000, 100); + Vector3d res = a.Lerp(b, 0.25); + + INFO(res); + REQUIRE(Vector3d(125, 1750, 32.5) == res); + return; +} + +// Tests for expected lerp result 0.50 +TEST_CASE(__FILE__"/Lerp_050", "[Vector3]") +{ + Vector3d a(100, 1000, 10); + Vector3d b(200, 4000, 100); + Vector3d res = a.Lerp(b, 0.50); + + INFO(res); + REQUIRE(Vector3d(150, 2500, 55) == res); + return; +} + +// Tests for expected lerp result 0.75 +TEST_CASE(__FILE__"/Lerp_075", "[Vector3]") +{ + Vector3d a(100, 1000, 10); + Vector3d b(200, 4000, 100); + Vector3d res = a.Lerp(b, 0.75); + + INFO(res); + REQUIRE(Vector3d(175, 3250, 77.5) == res); + return; +} + +// Tests for expected lerp result 1.00 +TEST_CASE(__FILE__"/Lerp_100", "[Vector3]") +{ + Vector3d a(100, 1000, 10); + Vector3d b(200, 4000, 100); + Vector3d res = a.Lerp(b, 1.00); + + INFO(res); + REQUIRE(b == res); + return; +} + +// Tests lerpself +TEST_CASE(__FILE__"/LerpSelf", "[Vector3]") +{ + Vector3d a(100, 1000, 10); + Vector3d b(200, 4000, 100); + + a.LerpSelf(b, 0.75); + + INFO(a); + REQUIRE(Vector3d(175, 3250, 77.5) == a); + return; +} + +// Tests if an input vector of length 0 is handled correctly by the normalize method +TEST_CASE(__FILE__"/Normalize_Length_Before_Is_0", "[Vector3]") +{ + Vector3d vec(0, 0, 0); + vec.NormalizeSelf(); + REQUIRE(0.0 == vec.Magnitude()); + return; +} + +// Tests for any normalized vector to be of length 1 +TEST_CASE(__FILE__"/Normalize_Length_Is_1", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + double x = LARGE_RAND_DOUBLE; + double y = LARGE_RAND_DOUBLE; + double z = LARGE_RAND_DOUBLE; + + Vector3d vec(x, y, z); + + // Prevent a vector of length 0 going in + if (vec.SqrMagnitude() == 0) + vec.x++; + + std::wstringstream wss; + wss << vec; + REQUIRE(Math::Similar(vec.Normalize().Magnitude(), 1.0)); // Account for floating point inaccuracy + } + + return; +} + +// Tests the normalize method with known values +TEST_CASE(__FILE__"/Normalize_Oracle", "[Vector3]") +{ + // Setup + Vector3d v(3.2, -5.3, 9.88); + + // Exercise + v.NormalizeSelf(); + + // Verify + Vector3d expected(0.27445384355, -0.45456417839, 0.84737624198); + REQUIRE(v.Similar(expected)); +} + +// Tests for a normalized vector to still point in the exact same direction +TEST_CASE(__FILE__"/Normalize_Direction_Stays_Unaffected", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + double x = LARGE_RAND_DOUBLE; + double y = LARGE_RAND_DOUBLE; + double z = LARGE_RAND_DOUBLE; + if (x == 0) x++; + if (y == 0) y++; + if (z == 0) z++; + + Vector3d vec(x, y, z); + + Vector3d vec_n(x, y, z); + vec_n = vec_n.Normalize(); + + INFO(vec << L" | " << vec_n); + + // Both vectors should still point in the same direction! + REQUIRE(( + (vec.DotProduct(vec_n) > 0) && // Roughly same direction + (Math::Similar(vec_n.CrossProduct(vec).Magnitude(), 0.0)) // Both vectors align + )); + } + return; +} + +// Kinda dumb method, but ok lol +// DON'T NORMALIZE INT-VECTORS WHAT IS WRONG WITH YOU +TEST_CASE(__FILE__"/Normalized_Int_Vector_Is_0", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const int x = LARGE_RAND_INT; + const int y = LARGE_RAND_INT; + const int z = LARGE_RAND_INT; + + Vector3i vec(x, y, z); + + vec.NormalizeSelf(); + + INFO(vec); + REQUIRE(0.0 == vec.Magnitude()); + } +} + +// Tests that NormalizeSelf() results in the same as Normalize() +TEST_CASE(__FILE__"/NormalizeSelf_IsSameAs_Normalize", "[Vector3]") +{ + // Run test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + Vector3d vec(LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE, LARGE_RAND_DOUBLE); + + Vector3d nVec = vec.Normalize(); + vec.NormalizeSelf(); + + REQUIRE(nVec == vec); + } + + return; +} + +// Tests for the VectorScale() method to work +TEST_CASE(__FILE__"/VectorScale", "[Vector3]") +{ + // Run test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const double ax = LARGE_RAND_DOUBLE; + const double ay = LARGE_RAND_DOUBLE; + const double az = LARGE_RAND_DOUBLE; + const double bx = LARGE_RAND_DOUBLE; + const double by = LARGE_RAND_DOUBLE; + const double bz = LARGE_RAND_DOUBLE; + + const Vector3d a(ax, ay, az); + const Vector3d b(bx, by, bz); + + Vector3d target( + ax * bx, + ay * by, + az * bz + ); + + REQUIRE(a.VectorScale(b) == target); + } + + return; +} + +// Tests for operator- (unary) to work +TEST_CASE(__FILE__"/Operator_Unary_Negative", "[Vector3]") +{ + const Vector3d v(29, -5, 35); + + REQUIRE(Vector3d(-29, 5, -35) == -v); + + return; +} + +// Tests for operator+ to work as expected +TEST_CASE(__FILE__"/Operator_Add", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const double ax = LARGE_RAND_DOUBLE; + const double ay = LARGE_RAND_DOUBLE; + const double az = LARGE_RAND_DOUBLE; + const double bx = LARGE_RAND_DOUBLE; + const double by = LARGE_RAND_DOUBLE; + const double bz = LARGE_RAND_DOUBLE; + + const Vector3d a(ax, ay, az); + const Vector3d b(bx, by, bz); + + REQUIRE(Vector3d(ax + bx, ay + by, az + bz) == a + b); + } + + return; +} + +// Tests for operator+= to work as expected +TEST_CASE(__FILE__"/Operator_Add_Equals", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const double ax = LARGE_RAND_DOUBLE; + const double ay = LARGE_RAND_DOUBLE; + const double az = LARGE_RAND_DOUBLE; + const double bx = LARGE_RAND_DOUBLE; + const double by = LARGE_RAND_DOUBLE; + const double bz = LARGE_RAND_DOUBLE; + + Vector3d a(ax, ay, az); + a += Vector3d(bx, by, bz); + + REQUIRE(Vector3d(ax + bx, ay + by, az + bz) == a); + } + + return; +} + +// Tests for operator- to work as expected +TEST_CASE(__FILE__"/Operator_Sub", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const double ax = LARGE_RAND_DOUBLE; + const double ay = LARGE_RAND_DOUBLE; + const double az = LARGE_RAND_DOUBLE; + const double bx = LARGE_RAND_DOUBLE; + const double by = LARGE_RAND_DOUBLE; + const double bz = LARGE_RAND_DOUBLE; + + const Vector3d a(ax, ay, az); + const Vector3d b(bx, by, bz); + + REQUIRE(Vector3d(ax - bx, ay - by, az - bz) == a - b); + } + + return; +} + +// Tests for operator-= to work as expected +TEST_CASE(__FILE__"/Operator_Sub_Equals", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const double ax = LARGE_RAND_DOUBLE; + const double ay = LARGE_RAND_DOUBLE; + const double az = LARGE_RAND_DOUBLE; + const double bx = LARGE_RAND_DOUBLE; + const double by = LARGE_RAND_DOUBLE; + const double bz = LARGE_RAND_DOUBLE; + + Vector3d a(ax, ay, az); + a -= Vector3d(bx, by, bz); + + REQUIRE(Vector3d(ax - bx, ay - by, az - bz) == a); + } + + return; +} + +// Tests for operator* to work as expected +TEST_CASE(__FILE__"/Operator_Mult", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const double x = LARGE_RAND_DOUBLE; + const double y = LARGE_RAND_DOUBLE; + const double z = LARGE_RAND_DOUBLE; + const double scalar = LARGE_RAND_DOUBLE; + + const Vector3d a(x, y, z); + + REQUIRE(Vector3d(x * scalar, y * scalar, z * scalar) == a * scalar); + } + + return; +} + +// Tests for operator*= to work as expected +TEST_CASE(__FILE__"/Operator_Mult_Equals", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const double x = LARGE_RAND_DOUBLE; + const double y = LARGE_RAND_DOUBLE; + const double z = LARGE_RAND_DOUBLE; + const double scalar = LARGE_RAND_DOUBLE; + + Vector3d a(x, y, z); + a *= scalar; + + REQUIRE(Vector3d(x * scalar, y * scalar, z * scalar) == a); + } + + return; +} + +// Tests for operator/ to work as expected +TEST_CASE(__FILE__"/Operator_Div", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const double x = LARGE_RAND_DOUBLE; + const double y = LARGE_RAND_DOUBLE; + const double z = LARGE_RAND_DOUBLE; + const double scalar = LARGE_RAND_DOUBLE; + + const Vector3d a(x, y, z); + + REQUIRE(Vector3d(x / scalar, y / scalar, z / scalar) == a / scalar); + } + + return; +} + +// Tests for operator/= to work as expected +TEST_CASE(__FILE__"/Operator_Div_Equals", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + const double x = LARGE_RAND_DOUBLE; + const double y = LARGE_RAND_DOUBLE; + const double z = LARGE_RAND_DOUBLE; + const double scalar = LARGE_RAND_DOUBLE; + + Vector3d a(x, y, z); + a /= scalar; + + REQUIRE(Vector3d(x / scalar, y / scalar, z / scalar) == a); + } + + return; +} + +// Tests for operator== to work as expected +TEST_CASE(__FILE__"/Operator_Equals", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 10000; i++) + { + const double ax = (rng() % 10) - 5; + const double ay = (rng() % 10) - 5; + const double az = (rng() % 10) - 5; + const double bx = (rng() % 10) - 5; + const double by = (rng() % 10) - 5; + const double bz = (rng() % 10) - 5; + + const Vector3d a(ax, ay, az); + const Vector3d b(bx, by, bz); + + REQUIRE( + ((ax == bx) && (ay == by) && (az == bz)) == + (a == b) + ); + } + + return; +} + +// Tests for operator!= to work as expected +TEST_CASE(__FILE__"/Operator_Not_Equals", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 10000; i++) + { + double ax = (rng() % 10) - 5; + double ay = (rng() % 10) - 5; + double az = (rng() % 10) - 5; + double bx = (rng() % 10) - 5; + double by = (rng() % 10) - 5; + double bz = (rng() % 10) - 5; + + Vector3d a(ax, ay, az); + Vector3d b(bx, by, bz); + + REQUIRE( + ((ax != bx) || (ay != by) || (az != bz)) == + (a != b) + ); + } + + return; +} + +// Tests for matrix multiplication working regarding rotation +TEST_CASE(__FILE__"/MatrixMult_Rotate_Yaw", "[Vector3]") +{ + // Create vector + Vector3d vec(69, 32, 16); + Vector3d originalVec = vec; + + // Create 90deg yaw rotation matrix (Y) + Matrix4x4 mat; + mat[0] = { 0, 0, 1, 0 }; + mat[1] = { 0, 1, 0, 0 }; + mat[2] = { -1, 0, 0, 0 }; + + // Rotate vector + vec *= mat; + + // Did we succeed? + INFO("Rot #1 " << vec); + REQUIRE(Vector3d(16, 32, -69) == vec); + + // Rotate again! + vec *= mat; + INFO("Rot #2 " << vec); + REQUIRE(Vector3d(-69, 32, -16) == vec); + + // Rotate again! + vec *= mat; + INFO("Rot #3 " << vec); + REQUIRE(Vector3d(-16, 32, 69) == vec); + + // Rotate by 90 deg a last time, having completed a 360� rotation. + vec *= mat; + INFO("Rot #4 " << vec); + REQUIRE(originalVec == vec); + + return; +} + +// Tests for matrix multiplication working regarding rotation +TEST_CASE(__FILE__"/MatrixMult_Rotate_Roll", "[Vector3]") +{ + // Create vector + Vector3d vec(69, 32, 16); + Vector3d originalVec = vec; + + // Create 90deg roll rotation matrix (Z) + Matrix4x4 mat; + mat[0] = { 0, -1, 0, 0 }; + mat[1] = { 1, 0, 0, 0 }; + mat[2] = { 0, 0, 1, 0 }; + + // Rotate vector + vec *= mat; + + // Did we succeed? + INFO("Rot #1 " << vec); + REQUIRE(Vector3d(-32, 69, 16) == vec); + + // Rotate again! + vec *= mat; + INFO("Rot #2 " << vec); + REQUIRE(Vector3d(-69, -32, 16) == vec); + + // Rotate again! + vec *= mat; + INFO("Rot #3 " << vec); + REQUIRE(Vector3d(32, -69, 16) == vec); + + // Rotate by 90 deg a last time, having completed a 360� rotation. + vec *= mat; + INFO("Rot #4 " << vec); + REQUIRE(originalVec == vec); + + return; +} + +// Tests for matrix multiplication working regarding rotation +TEST_CASE(__FILE__"/MatrixMult_Rotate_Pitch", "[Vector3]") +{ + // Create vector + Vector3d vec(69, 32, 16); + Vector3d originalVec = vec; + + // Create 90deg pitch rotation matrix (X) + Matrix4x4 mat; + mat[0] = { 1, 0, 0, 0 }; + mat[1] = { 0, 0, -1, 0 }; + mat[2] = { 0, 1, 0, 0 }; + + // Rotate vector + vec *= mat; + + // Did we succeed? + INFO("Rot #1 " << vec); + REQUIRE(Vector3d(69, -16, 32) == vec); + + // Rotate again! + vec *= mat; + INFO("Rot #2 " << vec); + REQUIRE(Vector3d(69, -32, -16) == vec); + + // Rotate again! + vec *= mat; + INFO("Rot #3 " << vec); + REQUIRE(Vector3d(69, 16, -32) == vec); + + // Rotate by 90 deg a last time, having completed a 360� rotation. + vec *= mat; + INFO("Rot #4 " << vec); + REQUIRE(originalVec == vec); + + return; +} + +// Tests if rotating a vector (1,1,1) by (45,45,45) eulers works +TEST_CASE(__FILE__"/MatrixMult_Rotate_Unit_Combined", "[Vector3]") +{ + // Create vector + Vector3d vec(1, 1, 1); + + // Create rotation matrix + Matrix4x4 mat; + mat[0] = { 0.5, -0.1465, 0.8535, 0 }; + mat[1] = { 0.5, 0.8535, -0.1465, 0 }; + mat[2] = { -0.7072, 0.5, 0.5, 0 }; + + // Rotate vector + vec *= mat; + + // Did we succeed? + INFO(vec); + REQUIRE(( + Math::Similar(vec.x, 1.207, 0.001) && + Math::Similar(vec.y, 1.207, 0.001) && + Math::Similar(vec.z, 0.2928, 0.001) + )); + + return; +} + +// Tests if rotating a vector (69,32,16) by (45,45,45) eulers works +TEST_CASE(__FILE__"/MatrixMult_Rotate_HalfUnit_Combined", "[Vector3]") +{ + // Create vector + Vector3d vec(69, 32, 16); + + // Create rotation matrix + Matrix4x4 mat; + mat[0] = { 0.5, -0.1465, 0.8535, 0 }; + mat[1] = { 0.5, 0.8535, -0.1465, 0 }; + mat[2] = { -0.7072, 0.5, 0.5, 0 }; + + // Rotate vector + vec *= mat; + + // Did we succeed? + INFO(vec); + REQUIRE(( + Math::Similar(vec.x, 43.468, 0.001) && + Math::Similar(vec.y, 59.468, 0.001) && + Math::Similar(vec.z, -24.7968, 0.001) + )); + + return; +} + +// Tests if rotating a vector (69,32,16) by (45,45,45) eulers works +TEST_CASE(__FILE__"/MatrixMult_Rotate_Combined", "[Vector3]") +{ + // Create vector + Vector3d vec(69, 32, 16); + + // Create rotation matrix + Matrix4x4 mat; + mat[0] = { -0.1639, -0.9837, -0.0755, 0 }; + mat[1] = { 0.128, -0.097, 0.987, 0 }; + mat[2] = { -0.9782, 0.152, 0.1417, 0 }; + + // Rotate vector + vec *= mat; + + // Did we succeed? + INFO(vec); + REQUIRE(( + Math::Similar(vec.x, -43.9955, 0.001) && + Math::Similar(vec.y, 21.52, 0.001) && + Math::Similar(vec.z, -60.3646, 0.001) + )); + + return; +} + +// Tests if matrix scaling works ( x axis only ) +TEST_CASE(__FILE__"/MatrixMult_Scale_X", "[Vector3]") +{ + // Create vector + Vector3d vec(5, 6, 7); + + // Create scaling matrix + Matrix4x4 mat; + mat[0] = { 3, 0, 0, 0 }; + mat[1] = { 0, 1, 0, 0 }; + mat[2] = { 0, 0, 1, 0 }; + + // Scale vector + vec *= mat; + + // Did we succeed? + INFO(vec); + REQUIRE(Vector3d(15, 6, 7) == vec); + + return; +} + +// Tests if matrix scaling works ( y axis only ) +TEST_CASE(__FILE__"/MatrixMult_Scale_Y", "[Vector3]") +{ + // Create vector + Vector3d vec(5, 6, 7); + + // Create scaling matrix + Matrix4x4 mat; + mat[0] = { 1, 0, 0, 0 }; + mat[1] = { 0, 3, 0, 0 }; + mat[2] = { 0, 0, 1, 0 }; + + // Scale vector + vec *= mat; + + // Did we succeed? + INFO(vec); + REQUIRE(Vector3d(5, 18, 7) == vec); + + return; +} + +// Tests if matrix scaling works ( z axis only ) +TEST_CASE(__FILE__"/MatrixMult_Scale_Z", "[Vector3]") +{ + // Create vector + Vector3d vec(5, 6, 7); + + // Create scaling matrix + Matrix4x4 mat; + mat[0] = { 1, 0, 0, 0 }; + mat[1] = { 0, 1, 0, 0 }; + mat[2] = { 0, 0, 3, 0 }; + + // Scale vector + vec *= mat; + + // Did we succeed? + INFO(vec); + REQUIRE(Vector3d(5, 6, 21) == vec); + + return; +} + +// Tests if matrix scaling works ( all axes ) +TEST_CASE(__FILE__"/MatrixMult_Scale_Combined", "[Vector3]") +{ + // Create vector + Vector3d vec(5, 6, 7); + + // Create scaling matrix + Matrix4x4 mat; + mat[0] = { 4, 0, 0, 0 }; + mat[1] = { 0, 5, 0, 0 }; + mat[2] = { 0, 0, 8, 0 }; + + // Scale vector + vec *= mat; + + // Did we succeed? + INFO(vec); + REQUIRE(Vector3d(20, 30, 56) == vec); + + return; +} + +// Tests if translation via matrix multiplication works +TEST_CASE(__FILE__"/MatrixMult_Translation", "[Vector3]") +{ + // Create vector + Vector3d vec(5, 6, 7); + + // Create scaling matrix + Matrix4x4 mat; + mat[0] = { 1, 0, 0, 155 }; + mat[1] = { 0, 1, 0, -23 }; + mat[2] = { 0, 0, 1, 333 }; + + // Translate vector + vec *= mat; + + // Did we succeed? + INFO(vec); + REQUIRE(Vector3d(160, -17, 340) == vec); + + return; +} + +// Tests the multiplication operator (*) with a simple matrix. All other tests used the * operator (without the '=') +TEST_CASE(__FILE__"/MatrixMult_Not_Using_MultEqualsOperator", "[Vector3]") +{ + // Create vector + Vector3d vec(5.1, 6.4, 7.99); + + // Create scaling and translation matrix + Matrix4x4 mat; + mat[0] = { 3.8, 0, 0, -5.1 }; + mat[1] = { 0, -1.5, 0, 15.2 }; + mat[2] = { 0, 0, 3.01, 19.9 }; + + // Transform vector + vec = vec * mat; + + // Did we succeed? + Vector3d expected( + 5.1 * 3.8 - 5.1, + 6.4 * -1.5 + 15.2, + 7.99 * 3.01 + 19.9 + ); + + INFO('\n' + << "Expected: " << expected << '\n' + << "Actual: " << vec + ); + + REQUIRE(expected == vec); + + return; +} + +// A simple matrix multiplication tested on an int vector +TEST_CASE(__FILE__"/MatrixMult_Dirty_Int_Check", "[Vector3]") +{ + // Create vector + Vector3i vec(5, 6, 7); + + // Create scaling and translation matrix + Matrix4x4 mat; + mat[0] = { 3, 0, 0, -5 }; + mat[1] = { 0, -1, 0, 15 }; + mat[2] = { 0, 0, 3, 20 }; + + // Transform vector + vec *= mat; + + // Did we succeed? + INFO(vec); + REQUIRE(Vector3i( + 5*3 + -5, + 6*-1 + 15, + 7*3 + 20 + ) == vec); + + return; +} + +// Tests the multiplication operator (*) with a simple matrix. All other tests used the * operator (without the '=') +TEST_CASE(__FILE__"/MatrixMult_Dirty_Int_Check_Not_Using_MultEqualsOperator", "[Vector3]") +{ + // Create vector + Vector3i vec(5, 6, 7); + + // Create scaling and translation matrix + Matrix4x4 mat; + mat[0] = { 3, 0, 0, -5 }; + mat[1] = { 0, -1, 0, 15 }; + mat[2] = { 0, 0, 3, 20 }; + + // Scale vector + vec = vec * mat; + + // Did we succeed? + INFO(vec); + REQUIRE(Vector3i( + 5 * 3 + -5, + 6 * -1 + 15, + 7 * 3 + 20 + ) == vec); + + return; +} + +//This tests the multiplication equals operator (*=) procedurally +TEST_CASE(__FILE__"/MatrixMult_Equals_Procedural", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + // Generate parameters + const double initialX = LARGE_RAND_DOUBLE; + const double initialY = LARGE_RAND_DOUBLE; + const double initialZ = LARGE_RAND_DOUBLE; + const double scaleX = LARGE_RAND_DOUBLE; + const double scaleY = LARGE_RAND_DOUBLE; + const double scaleZ = LARGE_RAND_DOUBLE; + const double transX = LARGE_RAND_DOUBLE; + const double transY = LARGE_RAND_DOUBLE; + const double transZ = LARGE_RAND_DOUBLE; + + // Create vector + Vector3d vec(initialX, initialY, initialZ); + + // Create matrix + Matrix4x4 mat; + mat[0] = { scaleX, 0, 0, transX }; + mat[1] = { 0, scaleY, 0, transY }; + mat[2] = { 0, 0, scaleZ, transZ }; + mat[3] = { 0, 0, 0, 0 }; + + // Create expected vector + Vector3d expected( + initialX * scaleX + transX, + initialY * scaleY + transY, + initialZ * scaleZ + transZ + ); + + // Transform vector + vec *= mat; + + // Compare + REQUIRE(vec == expected); + } + + return; +} + +//This tests the multiplication operator (*) procedurally +TEST_CASE(__FILE__"/MatrixMult_Procedural", "[Vector3]") +{ + // Test 1000 times + for (std::size_t i = 0; i < 1000; i++) + { + // Generate parameters + const double initialX = LARGE_RAND_DOUBLE; + const double initialY = LARGE_RAND_DOUBLE; + const double initialZ = LARGE_RAND_DOUBLE; + const double scaleX = LARGE_RAND_DOUBLE; + const double scaleY = LARGE_RAND_DOUBLE; + const double scaleZ = LARGE_RAND_DOUBLE; + const double transX = LARGE_RAND_DOUBLE; + const double transY = LARGE_RAND_DOUBLE; + const double transZ = LARGE_RAND_DOUBLE; + + // Create vector + Vector3d vec(initialX, initialY, initialZ); + + // Create matrix + Matrix4x4 mat; + mat[0] = { scaleX, 0, 0, transX }; + mat[1] = { 0, scaleY, 0, transY }; + mat[2] = { 0, 0, scaleZ, transZ }; + mat[3] = { 0, 0, 0, 0 }; + + // Create expected vector + Vector3d expected( + initialX * scaleX + transX, + initialY * scaleY + transY, + initialZ * scaleZ + transZ + ); + + // Transform vector + vec = vec * mat; + + // Compare + REQUIRE(vec == expected); + } + + return; +} + +// Tests loose comparison via Vector3d::Similar -> true +TEST_CASE(__FILE__"/Similar_True", "[Vector3]") +{ + REQUIRE( + Vector3d(0.00000000000000000000001, -6.6666666666666666666666666666, 9.9999999999999999999999999999).Similar( + Vector3d(0, -6.666666667, 10) + )); + return; +} + +// Tests loose comparison via Vector3d::Similar -> false +TEST_CASE(__FILE__"/Similar_False", "[Vector3]") +{ + REQUIRE_FALSE( + Vector3d(0.00000000000000000000001, -6.6666666666666666666666666666, 9.9999999999999999999999999999).Similar( + Vector3d(0.1, -6.7, 10.1) + )); + return; +} + +// Tests that the move constructor works +TEST_CASE(__FILE__"/Move_Constructor", "[Vector3]") +{ + Vector3d a(1,2,3); + Vector3d b(std::move(a)); + + REQUIRE(b.x == 1.0); + REQUIRE(b.y == 2.0); + REQUIRE(b.z == 3.0); + + return; +} + +// Tests that the move operator works +TEST_CASE(__FILE__"/Move_Operator", "[Vector3]") +{ + Vector3d a(1, 2, 3); + Vector3d b = std::move(a); + + REQUIRE(b.x == 1.0); + REQUIRE(b.y == 2.0); + REQUIRE(b.z == 3.0); + + return; }