Skip to content

Commit

Permalink
Improving unit test coverage for Math functions (#1380)
Browse files Browse the repository at this point in the history
  • Loading branch information
jrouwe authored Dec 6, 2024
1 parent e0e434f commit c10d9b2
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Jolt/Math/Math.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ JPH_INLINE constexpr T Sign(T inV)
template <typename T>
constexpr bool IsPowerOf2(T inV)
{
return (inV & (inV - 1)) == 0;
return inV > 0 && (inV & (inV - 1)) == 0;
}

/// Align inV up to the next inAlignment bytes
Expand Down
1 change: 1 addition & 0 deletions UnitTests/Math/BVec16Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ TEST_SUITE("BVec16Tests")
CHECK(v != BVec16(1, 2, 3, 4, 5, 6, 7, 8, 10, 9, 11, 12, 13, 14, 15, 16));

// Check element modification
CHECK(const_cast<const BVec16 &>(v)[15] == 16); // Check const operator
v[15] = 17;
CHECK(v[15] == 17);
CHECK(v == BVec16(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17));
Expand Down
79 changes: 79 additions & 0 deletions UnitTests/Math/DMat44Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@

#include "UnitTestFramework.h"
#include <Jolt/Math/DMat44.h>
#include <Jolt/Core/StringTools.h>

TEST_SUITE("DMat44Tests")
{
TEST_CASE("TestDMat44Zero")
{
DMat44 zero = DMat44::sZero();

CHECK(zero == DMat44(Vec4(0, 0, 0, 0), Vec4(0, 0, 0, 0), Vec4(0, 0, 0, 0), DVec3(0, 0, 0)));
CHECK(zero.GetAxisX() == Vec3::sZero());
CHECK(zero.GetAxisY() == Vec3::sZero());
CHECK(zero.GetAxisZ() == Vec3::sZero());
Expand All @@ -22,6 +24,12 @@ TEST_SUITE("DMat44Tests")
DMat44 identity = DMat44::sIdentity();

CHECK(identity == DMat44(Vec4(1, 0, 0, 0), Vec4(0, 1, 0, 0), Vec4(0, 0, 1, 0), DVec3(0, 0, 0)));

// Check non-equality
CHECK(identity != DMat44(Vec4(0, 0, 0, 0), Vec4(0, 1, 0, 0), Vec4(0, 0, 1, 0), DVec3(0, 0, 0)));
CHECK(identity != DMat44(Vec4(1, 0, 0, 0), Vec4(0, 0, 0, 0), Vec4(0, 0, 1, 0), DVec3(0, 0, 0)));
CHECK(identity != DMat44(Vec4(1, 0, 0, 0), Vec4(0, 1, 0, 0), Vec4(0, 0, 0, 0), DVec3(0, 0, 0)));
CHECK(identity != DMat44(Vec4(1, 0, 0, 0), Vec4(0, 1, 0, 0), Vec4(0, 0, 1, 0), DVec3(1, 0, 0)));
}

TEST_CASE("TestDMat44Construct")
Expand Down Expand Up @@ -61,6 +69,23 @@ TEST_SUITE("DMat44Tests")
CHECK(mat == DMat44(Vec4(17, 18, 19, 20), Vec4(21, 22, 23, 24), Vec4(25, 26, 27, 28), DVec3(13, 14, 15)));
}

TEST_CASE("TestDMat44Rotation")
{
Quat q = Quat::sRotation(Vec3(1, 1, 1).Normalized(), 0.2f * JPH_PI);
CHECK(DMat44::sRotation(q).ToMat44() == Mat44::sRotation(q));
}

TEST_CASE("TestDMat44Translation")
{
CHECK(DMat44::sTranslation(DVec3(1, 2, 3)) == DMat44(Vec4(1, 0, 0, 0), Vec4(0, 1, 0, 0), Vec4(0, 0, 1, 0), DVec3(1, 2, 3)));
}

TEST_CASE("TestDMat44RotationTranslation")
{
Quat q = Quat::sRotation(Vec3(1, 1, 1).Normalized(), 0.2f * JPH_PI);
CHECK(DMat44::sRotationTranslation(q, DVec3(1, 2, 3)).ToMat44() == Mat44::sRotationTranslation(q, Vec3(1, 2, 3)));
}

TEST_CASE("TestDMat44MultiplyMat44")
{
DMat44 mat(Vec4(1, 2, 3, 0), Vec4(5, 6, 7, 0), Vec4(9, 10, 11, 0), DVec3(13, 14, 15));
Expand Down Expand Up @@ -164,4 +189,58 @@ TEST_SUITE("DMat44Tests")
CHECK_APPROX_EQUAL(rotation_translation, m2);
CHECK_APPROX_EQUAL(scale, scale_out);
}

TEST_CASE("TestDMat44ToMat44")
{
DMat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), DVec3(13, 14, 15));
CHECK(mat.ToMat44() == Mat44(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 1)));
}

TEST_CASE("TestDMat44Column")
{
DMat44 mat = DMat44::sZero();
mat.SetColumn4(0, Vec4(1, 2, 3, 4));
CHECK(mat.GetColumn4(0) == Vec4(1, 2, 3, 4));
mat.SetColumn3(0, Vec3(5, 6, 7));
CHECK(mat.GetColumn3(0) == Vec3(5, 6, 7));
CHECK(mat.GetColumn4(0) == Vec4(5, 6, 7, 0));

mat.SetAxisX(Vec3(8, 9, 10));
mat.SetAxisY(Vec3(11, 12, 13));
mat.SetAxisZ(Vec3(14, 15, 16));
mat.SetTranslation(DVec3(17, 18, 19));
CHECK(mat.GetAxisX() == Vec3(8, 9, 10));
CHECK(mat.GetAxisY() == Vec3(11, 12, 13));
CHECK(mat.GetAxisZ() == Vec3(14, 15, 16));
CHECK(mat.GetTranslation() == DVec3(17, 18, 19));
}

TEST_CASE("TestDMat44Transposed")
{
DMat44 mat(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), DVec3(13, 14, 15));
Mat44 result = mat.Transposed3x3();
CHECK(result == Mat44(Vec4(1, 5, 9, 0), Vec4(2, 6, 10, 0), Vec4(3, 7, 11, 0), Vec4(0, 0, 0, 1)));
}

TEST_CASE("TestDMat44GetQuaternion")
{
Quat rot = Quat::sRotation(Vec3(1, 1, 1).Normalized(), 0.2f * JPH_PI);
DMat44 mat = DMat44::sRotation(rot);
CHECK_APPROX_EQUAL(mat.GetQuaternion(), rot);
}

TEST_CASE("TestDMat44PrePostTranslated")
{
DMat44 m(Vec4(2, 3, 4, 0), Vec4(5, 6, 7, 0), Vec4(8, 9, 10, 0), DVec3(11, 12, 13));
DVec3 v(14, 15, 16);

CHECK(m.PreTranslated(v) == m * DMat44::sTranslation(v));
CHECK(m.PostTranslated(v) == DMat44::sTranslation(v) * m);
}

TEST_CASE("TestDMat44ConvertToString")
{
DMat44 v(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), DVec3(13, 14, 15));
CHECK(ConvertToString(v) == "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15");
}
}
24 changes: 24 additions & 0 deletions UnitTests/Math/DVec3Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "UnitTestFramework.h"
#include <Jolt/Math/DVec3.h>
#include <Jolt/Core/StringTools.h>

TEST_SUITE("DVec3Tests")
{
Expand All @@ -16,6 +17,13 @@ TEST_SUITE("DVec3Tests")
CHECK(v.GetZ() == 0);
}

TEST_CASE("TestDVec3Axis")
{
CHECK(DVec3::sAxisX() == DVec3(1, 0, 0));
CHECK(DVec3::sAxisY() == DVec3(0, 1, 0));
CHECK(DVec3::sAxisZ() == DVec3(0, 0, 1));
}

TEST_CASE("TestVec3NaN")
{
DVec3 v = DVec3::sNaN();
Expand Down Expand Up @@ -56,6 +64,16 @@ TEST_SUITE("DVec3Tests")
v.SetComponent(1, 5);
v.SetComponent(2, 6);
CHECK(v == DVec3(4, 5, 6));

// Set the components again
v.SetX(7);
v.SetY(8);
v.SetZ(9);
CHECK(v == DVec3(7, 8, 9));

// Set all components
v.Set(10, 11, 12);
CHECK(v == DVec3(10, 11, 12));
}

TEST_CASE("TestVec4ToDVec3")
Expand Down Expand Up @@ -281,4 +299,10 @@ TEST_SUITE("DVec3Tests")
CHECK(DVec3(1.2345, -6.7891, 0).GetSign() == DVec3(1, -1, 1));
CHECK(DVec3(0, 2.3456, -7.8912).GetSign() == DVec3(1, 1, -1));
}

TEST_CASE("TestDVec3ConvertToString")
{
DVec3 v(1, 2, 3);
CHECK(ConvertToString(v) == "1, 2, 3");
}
}
46 changes: 46 additions & 0 deletions UnitTests/Math/Mat44Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "UnitTestFramework.h"
#include <Jolt/Math/Mat44.h>
#include <Jolt/Core/StringTools.h>

TEST_SUITE("Mat44Tests")
{
Expand All @@ -16,6 +17,38 @@ TEST_SUITE("Mat44Tests")
CHECK(zero(row, col) == 0.0f);
}

TEST_CASE("TestMat44Column")
{
Mat44 mat = Mat44::sZero();
mat.SetColumn4(0, Vec4(1, 2, 3, 4));
CHECK(mat.GetColumn4(0) == Vec4(1, 2, 3, 4));
mat.SetColumn3(0, Vec3(5, 6, 7));
CHECK(mat.GetColumn3(0) == Vec3(5, 6, 7));
CHECK(mat.GetColumn4(0) == Vec4(5, 6, 7, 0));

mat.SetAxisX(Vec3(8, 9, 10));
mat.SetAxisY(Vec3(11, 12, 13));
mat.SetAxisZ(Vec3(14, 15, 16));
mat.SetTranslation(Vec3(17, 18, 19));
CHECK(mat.GetAxisX() == Vec3(8, 9, 10));
CHECK(mat.GetAxisY() == Vec3(11, 12, 13));
CHECK(mat.GetAxisZ() == Vec3(14, 15, 16));
CHECK(mat.GetTranslation() == Vec3(17, 18, 19));

mat.SetDiagonal3(Vec3(20, 21, 22));
CHECK(mat.GetDiagonal3() == Vec3(20, 21, 22));
CHECK(mat.GetAxisX() == Vec3(20, 9, 10));
CHECK(mat.GetAxisY() == Vec3(11, 21, 13));
CHECK(mat.GetAxisZ() == Vec3(14, 15, 22));

mat.SetDiagonal4(Vec4(23, 24, 25, 26));
CHECK(mat.GetDiagonal4() == Vec4(23, 24, 25, 26));
CHECK(mat.GetAxisX() == Vec3(23, 9, 10));
CHECK(mat.GetAxisY() == Vec3(11, 24, 13));
CHECK(mat.GetAxisZ() == Vec3(14, 15, 25));
CHECK(mat.GetColumn4(3) == Vec4(17, 18, 19, 26));
}

TEST_CASE("TestMat44NaN")
{
Mat44 nan = Mat44::sNaN();
Expand Down Expand Up @@ -521,4 +554,17 @@ TEST_SUITE("Mat44Tests")
CHECK_APPROX_EQUAL(m2.GetAxisX().Cross(m2.GetAxisY()).Dot(m2.GetAxisZ()), 1.0f); // Check perpendicular
CHECK_APPROX_EQUAL(scale, scale_out, 0.05f); // Scale may change a bit
}

TEST_CASE("TestDMat44GetQuaternion")
{
Quat rot = Quat::sRotation(Vec3(1, 1, 1).Normalized(), 0.2f * JPH_PI);
Mat44 mat = Mat44::sRotation(rot);
CHECK_APPROX_EQUAL(mat.GetQuaternion(), rot);
}

TEST_CASE("TestDMat44ConvertToString")
{
Mat44 v(Vec4(1, 2, 3, 4), Vec4(5, 6, 7, 8), Vec4(9, 10, 11, 12), Vec4(13, 14, 15, 16));
CHECK(ConvertToString(v) == "1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16");
}
}
28 changes: 28 additions & 0 deletions UnitTests/Math/MathTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,32 @@ TEST_SUITE("Mat44Tests")
CHECK(GetNextPowerOf2(0x8000000U - 1) == 0x8000000U);
CHECK(GetNextPowerOf2(0x8000000U) == 0x8000000U);
}

TEST_CASE("TestCenterAngleAroundZero")
{
for (int i = 0; i < 10; i += 2)
{
CHECK_APPROX_EQUAL(CenterAngleAroundZero(i * JPH_PI), 0, 1.0e-5f);
CHECK_APPROX_EQUAL(CenterAngleAroundZero((0.5f + i) * JPH_PI), 0.5f * JPH_PI, 1.0e-5f);
CHECK_APPROX_EQUAL(CenterAngleAroundZero((1.5f + i) * JPH_PI), -0.5f * JPH_PI, 1.0e-5f);
CHECK_APPROX_EQUAL(CenterAngleAroundZero(-(0.5f + i) * JPH_PI), -0.5f * JPH_PI, 1.0e-5f);
CHECK_APPROX_EQUAL(CenterAngleAroundZero(-(1.5f + i) * JPH_PI), 0.5f * JPH_PI, 1.0e-5f);
CHECK_APPROX_EQUAL(CenterAngleAroundZero(-(0.99f + i) * JPH_PI), -0.99f * JPH_PI, 1.0e-5f);
CHECK_APPROX_EQUAL(CenterAngleAroundZero((0.99f + i) * JPH_PI), 0.99f * JPH_PI, 1.0e-5f);
}
}

TEST_CASE("TestIsPowerOf2")
{
for (int i = 0; i < 63; ++i)
CHECK(IsPowerOf2(uint64(1) << 1));
CHECK(!IsPowerOf2(-2));
CHECK(!IsPowerOf2(0));
CHECK(!IsPowerOf2(3));
CHECK(!IsPowerOf2(5));
CHECK(!IsPowerOf2(15));
CHECK(!IsPowerOf2(17));
CHECK(!IsPowerOf2(65535));
CHECK(!IsPowerOf2(65537));
}
}
37 changes: 37 additions & 0 deletions UnitTests/Math/QuatTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "UnitTestFramework.h"
#include <Jolt/Math/Mat44.h>
#include <Jolt/Math/Quat.h>
#include <Jolt/Core/StringTools.h>
#include <random>

TEST_SUITE("QuatTests")
Expand Down Expand Up @@ -64,6 +65,16 @@ TEST_SUITE("QuatTests")
CHECK(Quat(1, 2, 3, 4) * 5.0f == Quat(5, 10, 15, 20));
CHECK(5.0f * Quat(1, 2, 3, 4) == Quat(5, 10, 15, 20));
CHECK(Quat(2, 4, 6, 8) / 2.0f == Quat(1, 2, 3, 4));

Quat v(1, 2, 3, 4);
v += Quat(5, 6, 7, 8);
CHECK(v == Quat(6, 8, 10, 12));
v -= Quat(4, 3, 2, 1);
CHECK(v == Quat(2, 5, 8, 11));
v *= 2.0f;
CHECK(v == Quat(4, 10, 16, 22));
v /= 2.0f;
CHECK(v == Quat(2, 5, 8, 11));
}

TEST_CASE("TestQuatPerpendicular")
Expand Down Expand Up @@ -342,6 +353,8 @@ TEST_SUITE("QuatTests")
CHECK_APPROX_EQUAL(twist2, q2);
Quat swing2 = twist2.Inversed() * swing1;
CHECK_APPROX_EQUAL(swing2, Quat::sIdentity());

CHECK(Quat::sZero().GetTwist(Vec3::sAxisX()) == Quat::sIdentity());
}

TEST_CASE("TestQuatGetRotationAngle")
Expand Down Expand Up @@ -449,4 +462,28 @@ TEST_SUITE("QuatTests")
CHECK_APPROX_EQUAL(v2t, v1t, 1.0e-5f);
}
}

TEST_CASE("TestQuatConvertToString")
{
Quat v(1, 2, 3, 4);
CHECK(ConvertToString(v) == "1, 2, 3, 4");
}

TEST_CASE("TestQuatLERP")
{
Quat v1(1, 2, 3, 4);
Quat v2(5, 6, 7, 8);
CHECK(v1.LERP(v2, 0.25f) == Quat(2, 3, 4, 5));
}

TEST_CASE("TestQuatSLERP")
{
Quat v1 = Quat::sIdentity();
Quat v2 = Quat::sRotation(Vec3::sAxisX(), 0.99f * JPH_PI);
CHECK_APPROX_EQUAL(v1.SLERP(v2, 0.25f), Quat::sRotation(Vec3::sAxisX(), 0.25f * 0.99f * JPH_PI));

// Check that we ignore the sign
Quat v3 = Quat(1, 2, 3, 4).Normalized();
CHECK_APPROX_EQUAL(v3.SLERP(-v3, 0.5f), v3);
}
}
17 changes: 17 additions & 0 deletions UnitTests/Math/UVec4Tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// SPDX-License-Identifier: MIT

#include "UnitTestFramework.h"
#include <Jolt/Core/StringTools.h>

TEST_SUITE("UVec4Tests")
{
Expand All @@ -25,6 +26,16 @@ TEST_SUITE("UVec4Tests")
CHECK(v != UVec4(1, 2, 4, 3));
}

TEST_CASE("TestUVec4Components")
{
UVec4 v(1, 2, 3, 4);
v.SetX(5);
v.SetY(6);
v.SetZ(7);
v.SetW(8);
CHECK(v == UVec4(5, 6, 7, 8));
}

TEST_CASE("TestUVec4LoadStoreInt4")
{
alignas(16) uint32 i4[] = { 1, 2, 3, 4 };
Expand Down Expand Up @@ -544,4 +555,10 @@ TEST_SUITE("UVec4Tests")
CHECK(UVec4::sSort4True(UVec4(0x00000000U, 0xffffffffU, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(2, 3, 4, 4));
CHECK(UVec4::sSort4True(UVec4(0xffffffffU, 0xffffffffU, 0xffffffffU, 0xffffffffU), UVec4(1, 2, 3, 4)) == UVec4(1, 2, 3, 4));
}

TEST_CASE("TestUVec4ConvertToString")
{
UVec4 v(1, 2, 3, 4);
CHECK(ConvertToString(v) == "1, 2, 3, 4");
}
}
Loading

0 comments on commit c10d9b2

Please sign in to comment.