Vec3/tests/unit_tests/vec_test.cpp

232 lines
6.8 KiB
C++
Raw Normal View History

2025-04-15 17:48:33 -04:00
#include "vec3.h"
#include <cmath>
#include <gtest/gtest.h>
#include <limits>
// Test fixture for Vec3 tests
class Vec3Test : public ::testing::Test {
protected:
// Test vectors that will be used across multiple tests
Vec3<int> intVec1, intVec2;
Vec3<float> floatVec1, floatVec2;
Vec3<double> doubleVec1, doubleVec2;
void SetUp() override {
// Initialize test vectors
intVec1 = {1, 2, 3};
intVec2 = {4, 5, 6};
floatVec1 = {1.5f, 2.5f, 3.5f};
floatVec2 = {4.5f, 5.5f, 6.5f};
doubleVec1 = {1.5, 2.5, 3.5};
doubleVec2 = {4.5, 5.5, 6.5};
}
};
// Test vector addition
TEST_F(Vec3Test, Addition) {
// Test integer vectors
auto intResult = intVec1 + intVec2;
EXPECT_EQ(intResult.x, 5);
EXPECT_EQ(intResult.y, 7);
EXPECT_EQ(intResult.z, 9);
// Test float vectors
auto floatResult = floatVec1 + floatVec2;
EXPECT_FLOAT_EQ(floatResult.x, 6.0f);
EXPECT_FLOAT_EQ(floatResult.y, 8.0f);
EXPECT_FLOAT_EQ(floatResult.z, 10.0f);
// Test double vectors
auto doubleResult = doubleVec1 + doubleVec2;
EXPECT_DOUBLE_EQ(doubleResult.x, 6.0);
EXPECT_DOUBLE_EQ(doubleResult.y, 8.0);
EXPECT_DOUBLE_EQ(doubleResult.z, 10.0);
}
// Test vector subtraction
TEST_F(Vec3Test, Subtraction) {
// Test integer vectors
auto intResult = intVec2 - intVec1;
EXPECT_EQ(intResult.x, 3);
EXPECT_EQ(intResult.y, 3);
EXPECT_EQ(intResult.z, 3);
// Test float vectors
auto floatResult = floatVec2 - floatVec1;
EXPECT_FLOAT_EQ(floatResult.x, 3.0f);
EXPECT_FLOAT_EQ(floatResult.y, 3.0f);
EXPECT_FLOAT_EQ(floatResult.z, 3.0f);
// Test double vectors
auto doubleResult = doubleVec2 - doubleVec1;
EXPECT_DOUBLE_EQ(doubleResult.x, 3.0);
EXPECT_DOUBLE_EQ(doubleResult.y, 3.0);
EXPECT_DOUBLE_EQ(doubleResult.z, 3.0);
}
// Test vector scaling
TEST_F(Vec3Test, Scale) {
// Test integer scaling
Vec3<int> intVecScaled = intVec1;
intVecScaled.scale(2);
EXPECT_EQ(intVecScaled.x, 2);
EXPECT_EQ(intVecScaled.y, 4);
EXPECT_EQ(intVecScaled.z, 6);
// Test float scaling
Vec3<float> floatVecScaled = floatVec1;
floatVecScaled.scale(2.0f);
EXPECT_FLOAT_EQ(floatVecScaled.x, 3.0f);
EXPECT_FLOAT_EQ(floatVecScaled.y, 5.0f);
EXPECT_FLOAT_EQ(floatVecScaled.z, 7.0f);
// Test double scaling
Vec3<double> doubleVecScaled = doubleVec1;
doubleVecScaled.scale(2.0);
EXPECT_DOUBLE_EQ(doubleVecScaled.x, 3.0);
EXPECT_DOUBLE_EQ(doubleVecScaled.y, 5.0);
EXPECT_DOUBLE_EQ(doubleVecScaled.z, 7.0);
// Test scaling by zero
Vec3<float> zeroScaled = floatVec1;
zeroScaled.scale(0.0f);
EXPECT_FLOAT_EQ(zeroScaled.x, 0.0f);
EXPECT_FLOAT_EQ(zeroScaled.y, 0.0f);
EXPECT_FLOAT_EQ(zeroScaled.z, 0.0f);
// Test scaling by negative number
Vec3<int> negScaled = intVec1;
negScaled.scale(-1);
EXPECT_EQ(negScaled.x, -1);
EXPECT_EQ(negScaled.y, -2);
EXPECT_EQ(negScaled.z, -3);
}
// Test dot product
TEST_F(Vec3Test, DotProduct) {
// Test integer dot product
int intDot = intVec1.dot(intVec2);
EXPECT_EQ(intDot, 32); // 1*4 + 2*5 + 3*6 = 4 + 10 + 18 = 32
// Test float dot product
float floatDot = floatVec1.dot(floatVec2);
EXPECT_FLOAT_EQ(
floatDot,
43.25f); // 1.5*4.5 + 2.5*5.5 + 3.5*6.5 = 6.75 + 13.75 + 22.75 = 43.25
// Test double dot product
double doubleDot = doubleVec1.dot(doubleVec2);
EXPECT_DOUBLE_EQ(doubleDot, 43.25); // Same calculation as float
// Test dot product with self (should equal squared length)
int selfDot = intVec1.dot(intVec1);
EXPECT_EQ(selfDot, 14); // 1*1 + 2*2 + 3*3 = 1 + 4 + 9 = 14
// Test dot product with zero vector
Vec3<int> zeroVec = {0, 0, 0};
EXPECT_EQ(intVec1.dot(zeroVec), 0);
}
// Test cross product
TEST_F(Vec3Test, CrossProduct) {
// Test integer cross product
auto intCross = intVec1.cross(intVec2);
EXPECT_EQ(intCross.x, -3); // (2*6 - 3*5) = 12 - 15 = -3
EXPECT_EQ(intCross.y, 6); // (3*4 - 1*6) = 12 - 6 = 6
EXPECT_EQ(intCross.z, -3); // (1*5 - 2*4) = 5 - 8 = -3
// Test float cross product
auto floatCross = floatVec1.cross(floatVec2);
EXPECT_FLOAT_EQ(floatCross.x,
-3.0f); // (2.5*6.5 - 3.5*5.5) = 16.25 - 19.25 = -3
EXPECT_FLOAT_EQ(floatCross.y,
6.0f); // (3.5*4.5 - 1.5*6.5) = 15.75 - 9.75 = 6
EXPECT_FLOAT_EQ(floatCross.z,
-3.0f); // (1.5*5.5 - 2.5*4.5) = 8.25 - 11.25 = -3
// Test double cross product
auto doubleCross = doubleVec1.cross(doubleVec2);
EXPECT_DOUBLE_EQ(doubleCross.x, -3.0);
EXPECT_DOUBLE_EQ(doubleCross.y, 6.0);
EXPECT_DOUBLE_EQ(doubleCross.z, -3.0);
// Test cross product with self (should be zero)
auto selfCross = intVec1.cross(intVec1);
EXPECT_EQ(selfCross.x, 0);
EXPECT_EQ(selfCross.y, 0);
EXPECT_EQ(selfCross.z, 0);
// Test cross product of standard basis vectors (i × j = k)
Vec3<int> i = {1, 0, 0};
Vec3<int> j = {0, 1, 0};
Vec3<int> k = {0, 0, 1};
auto i_cross_j = i.cross(j);
EXPECT_EQ(i_cross_j.x, 0);
EXPECT_EQ(i_cross_j.y, 0);
EXPECT_EQ(i_cross_j.z, 1);
auto j_cross_k = j.cross(k);
EXPECT_EQ(j_cross_k.x, 1);
EXPECT_EQ(j_cross_k.y, 0);
EXPECT_EQ(j_cross_k.z, 0);
auto k_cross_i = k.cross(i);
EXPECT_EQ(k_cross_i.x, 0);
EXPECT_EQ(k_cross_i.y, 1);
EXPECT_EQ(k_cross_i.z, 0);
}
// Test with edge cases
TEST_F(Vec3Test, EdgeCases) {
// Test with max values
Vec3<int> maxVec = {std::numeric_limits<int>::max(),
std::numeric_limits<int>::max(),
std::numeric_limits<int>::max()};
// Addition with max values may overflow, but we want to test the operation
// works
auto maxAddition = maxVec + intVec1;
// Test with min values
Vec3<int> minVec = {std::numeric_limits<int>::min(),
std::numeric_limits<int>::min(),
std::numeric_limits<int>::min()};
// Subtraction with min values may underflow, but we want to test the
// operation works
auto minSubtraction = minVec - intVec1;
// Test with mixed values
Vec3<double> mixedVec1 = {0.0, -1.0, std::numeric_limits<double>::infinity()};
Vec3<double> mixedVec2 = {-0.0, 1.0,
-std::numeric_limits<double>::infinity()};
auto mixedAddition = mixedVec1 + mixedVec2;
// 0.0 + (-0.0) = 0.0
EXPECT_DOUBLE_EQ(mixedAddition.x, 0.0);
// -1.0 + 1.0 = 0.0
EXPECT_DOUBLE_EQ(mixedAddition.y, 0.0);
// inf + (-inf) = NaN
EXPECT_TRUE(std::isnan(mixedAddition.z));
// Test with NaN
Vec3<double> nanVec = {std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN(),
std::numeric_limits<double>::quiet_NaN()};
// Any operation with NaN should result in NaN
auto nanResult = doubleVec1 + nanVec;
EXPECT_TRUE(std::isnan(nanResult.x));
EXPECT_TRUE(std::isnan(nanResult.y));
EXPECT_TRUE(std::isnan(nanResult.z));
}
// Main function that runs the tests
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}