diff --git a/.idea/omath.iml b/.idea/omath.iml new file mode 100644 index 00000000..4c942354 --- /dev/null +++ b/.idea/omath.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/examples/example_glfw3.cpp b/examples/example_glfw3.cpp index 0a3c5e35..da55ac07 100644 --- a/examples/example_glfw3.cpp +++ b/examples/example_glfw3.cpp @@ -127,8 +127,8 @@ int main() glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif - const int SCR_WIDTH = 800; - const int SCR_HEIGHT = 600; + constexpr int SCR_WIDTH = 800; + constexpr int SCR_HEIGHT = 600; GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "omath cube + camera (GLEW)", nullptr, nullptr); if (!window) diff --git a/tests/general/unit_test_a_star.cpp b/tests/general/unit_test_a_star.cpp index 83ec7f51..fc7011ad 100644 --- a/tests/general/unit_test_a_star.cpp +++ b/tests/general/unit_test_a_star.cpp @@ -1,8 +1,8 @@ // Extra unit tests for the project's A* implementation +#include #include #include #include -#include #include using namespace omath; @@ -11,12 +11,12 @@ using namespace omath::pathfinding; TEST(AStarExtra, TrivialNeighbor) { NavigationMesh nav; - Vector3 v1{0.f,0.f,0.f}; - Vector3 v2{1.f,0.f,0.f}; + Vector3 v1{0.f, 0.f, 0.f}; + Vector3 v2{1.f, 0.f, 0.f}; nav.m_vertex_map[v1] = {v2}; nav.m_vertex_map[v2] = {v1}; - auto path = Astar::find_path(v1, v2, nav); + const auto path = Astar::find_path(v1, v2, nav); ASSERT_EQ(path.size(), 1u); EXPECT_EQ(path.front(), v2); } @@ -24,10 +24,10 @@ TEST(AStarExtra, TrivialNeighbor) TEST(AStarExtra, StartEqualsGoal) { NavigationMesh nav; - Vector3 v{1.f,1.f,0.f}; + constexpr Vector3 v{1.f, 1.f, 0.f}; nav.m_vertex_map[v] = {}; - auto path = Astar::find_path(v, v, nav); + const auto path = Astar::find_path(v, v, nav); ASSERT_EQ(path.size(), 1u); EXPECT_EQ(path.front(), v); } @@ -35,13 +35,13 @@ TEST(AStarExtra, StartEqualsGoal) TEST(AStarExtra, BlockedNoPathBetweenTwoVertices) { NavigationMesh nav; - Vector3 left{0.f,0.f,0.f}; - Vector3 right{2.f,0.f,0.f}; + constexpr Vector3 left{0.f, 0.f, 0.f}; + constexpr Vector3 right{2.f, 0.f, 0.f}; // both vertices present but no connections nav.m_vertex_map[left] = {}; nav.m_vertex_map[right] = {}; - auto path = Astar::find_path(left, right, nav); + const auto path = Astar::find_path(left, right, nav); // disconnected vertices -> empty result EXPECT_TRUE(path.empty()); } @@ -50,44 +50,47 @@ TEST(AStarExtra, LongerPathAvoidsBlock) { NavigationMesh nav; // build 3x3 grid of vertices, block center (1,1) - auto idx = [&](int x, int y){ return Vector3{static_cast(x), static_cast(y), 0.f}; }; + auto idx = [&](const int x, const int y) + { return Vector3{static_cast(x), static_cast(y), 0.f}; }; for (int y = 0; y < 3; ++y) { for (int x = 0; x < 3; ++x) { - Vector3 v = idx(x,y); - if (x==1 && y==1) continue; // center is omitted (blocked) + Vector3 v = idx(x, y); + if (x == 1 && y == 1) + continue; // center is omitted (blocked) std::vector> neigh; - const std::array,4> offs{{{1,0},{-1,0},{0,1},{0,-1}}}; - for (auto [dx,dy]: offs) + constexpr std::array, 4> offs{{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}}; + for (auto [dx, dy] : offs) { - int nx = x + dx, ny = y + dy; - if (nx < 0 || nx >= 3 || ny < 0 || ny >= 3) continue; - if (nx==1 && ny==1) continue; // neighbor is the blocked center - neigh.push_back(idx(nx,ny)); + const int nx = x + dx, ny = y + dy; + if (nx < 0 || nx >= 3 || ny < 0 || ny >= 3) + continue; + if (nx == 1 && ny == 1) + continue; // neighbor is the blocked center + neigh.push_back(idx(nx, ny)); } nav.m_vertex_map[v] = neigh; } } - Vector3 start = idx(0,1); - Vector3 goal = idx(2,1); - auto path = Astar::find_path(start, goal, nav); + constexpr Vector3 start = idx(0, 1); + constexpr Vector3 goal = idx(2, 1); + const auto path = Astar::find_path(start, goal, nav); ASSERT_FALSE(path.empty()); EXPECT_EQ(path.front(), goal); // Astar convention: single-element or endpoint present } - TEST(AstarTests, TrivialDirectNeighborPath) { NavigationMesh nav; // create two vertices directly connected - Vector3 v1{0.f,0.f,0.f}; - Vector3 v2{1.f,0.f,0.f}; + Vector3 v1{0.f, 0.f, 0.f}; + Vector3 v2{1.f, 0.f, 0.f}; nav.m_vertex_map.emplace(v1, std::vector>{v2}); nav.m_vertex_map.emplace(v2, std::vector>{v1}); - auto path = Astar::find_path(v1, v2, nav); + const auto path = Astar::find_path(v1, v2, nav); // Current A* implementation returns the end vertex as the reconstructed // path (single-element) in the simple neighbor scenario. Assert that the // endpoint is present and reachable. @@ -98,12 +101,12 @@ TEST(AstarTests, TrivialDirectNeighborPath) TEST(AstarTests, NoPathWhenDisconnected) { NavigationMesh nav; - Vector3 v1{0.f,0.f,0.f}; - Vector3 v2{10.f,0.f,0.f}; + Vector3 v1{0.f, 0.f, 0.f}; + constexpr Vector3 v2{10.f, 0.f, 0.f}; // nav has only v1 nav.m_vertex_map.emplace(v1, std::vector>{}); - auto path = Astar::find_path(v1, v2, nav); + const auto path = Astar::find_path(v1, v2, nav); // When the nav mesh contains only the start vertex, the closest // vertex for both start and end will be the same vertex. In that // case Astar returns a single-element path with the start vertex. @@ -113,11 +116,11 @@ TEST(AstarTests, NoPathWhenDisconnected) TEST(AstarTests, EmptyNavReturnsNoPath) { - NavigationMesh nav; - Vector3 v1{0.f,0.f,0.f}; - Vector3 v2{1.f,0.f,0.f}; + const NavigationMesh nav; + constexpr Vector3 v1{0.f, 0.f, 0.f}; + constexpr Vector3 v2{1.f, 0.f, 0.f}; - auto path = Astar::find_path(v1, v2, nav); + const auto path = Astar::find_path(v1, v2, nav); EXPECT_TRUE(path.empty()); } diff --git a/tests/general/unit_test_angle.cpp b/tests/general/unit_test_angle.cpp index 0e4c7ba0..d1fc410f 100644 --- a/tests/general/unit_test_angle.cpp +++ b/tests/general/unit_test_angle.cpp @@ -13,11 +13,11 @@ namespace { // Handy aliases (defaults: Type=float, [0,360], Normalized) - using Deg = Angle; - using Pitch = Angle; - using Turn = Angle; + using Deg = Angle(0), static_cast(360), AngleFlags::Normalized>; + using Pitch = Angle(-90), static_cast(90), AngleFlags::Clamped>; + using Turn = Angle(-180), static_cast(180), AngleFlags::Normalized>; - constexpr float kEps = 1e-5f; + constexpr float k_eps = 1e-5f; } // namespace @@ -25,7 +25,7 @@ namespace TEST(UnitTestAngle, DefaultConstructor_IsZeroDegrees) { - Deg a; // default ctor + constexpr Deg a; // default ctor EXPECT_FLOAT_EQ(*a, 0.0f); EXPECT_FLOAT_EQ(a.as_degrees(), 0.0f); } @@ -44,8 +44,8 @@ TEST(UnitTestAngle, FromDegrees_Normalized_WrapsBelowMin) TEST(UnitTestAngle, FromDegrees_Clamped_ClampsToRange) { - const Pitch hi = Pitch::from_degrees(100.0f); - const Pitch lo = Pitch::from_degrees(-120.0f); + constexpr Pitch hi = Pitch::from_degrees(100.0f); + constexpr Pitch lo = Pitch::from_degrees(-120.0f); EXPECT_FLOAT_EQ(hi.as_degrees(), 90.0f); EXPECT_FLOAT_EQ(lo.as_degrees(), -90.0f); @@ -80,8 +80,8 @@ TEST(UnitTestAngle, DereferenceReturnsDegrees) TEST(UnitTestAngle, SinCosTanCot_BasicCases) { const Deg a0 = Deg::from_degrees(0.0f); - EXPECT_NEAR(a0.sin(), 0.0f, kEps); - EXPECT_NEAR(a0.cos(), 1.0f, kEps); + EXPECT_NEAR(a0.sin(), 0.0f, k_eps); + EXPECT_NEAR(a0.cos(), 1.0f, k_eps); // cot(0) -> cos/sin -> div by 0: allow inf or nan const float cot0 = a0.cot(); EXPECT_TRUE(std::isinf(cot0) || std::isnan(cot0)); @@ -99,7 +99,7 @@ TEST(UnitTestAngle, Atan_IsAtanOfRadians) { // atan(as_radians). For 0° -> atan(0)=0. const Deg a0 = Deg::from_degrees(0.0f); - EXPECT_NEAR(a0.atan(), 0.0f, kEps); + EXPECT_NEAR(a0.atan(), 0.0f, k_eps); const Deg a45 = Deg::from_degrees(45.0f); // atan(pi/4) ≈ 0.665773... diff --git a/tests/general/unit_test_collision_extra.cpp b/tests/general/unit_test_collision_extra.cpp index 6d42e85e..4884c630 100644 --- a/tests/general/unit_test_collision_extra.cpp +++ b/tests/general/unit_test_collision_extra.cpp @@ -66,18 +66,18 @@ TEST(CollisionExtra, EPAConvergesOnSimpleCase) std::vector>{{ {0.f,0.f,0.f}, {}, {} }, { {1.f,0.f,0.f}, {}, {} } }, {} }; - omath::source_engine::Mesh meshB = meshA; - meshB.set_origin({0.5f, 0.f, 0.f}); // translate to overlap + omath::source_engine::Mesh mesh_b = meshA; + mesh_b.set_origin({0.5f, 0.f, 0.f}); // translate to overlap - omath::source_engine::MeshCollider A(meshA); - omath::source_engine::MeshCollider B(meshB); + omath::source_engine::MeshCollider a(meshA); + omath::source_engine::MeshCollider b(mesh_b); // Create a simplex that approximately contains the origin in Minkowski space Simplex> simplex; simplex = { omath::Vector3{0.5f,0.f,0.f}, omath::Vector3{-0.5f,0.f,0.f}, omath::Vector3{0.f,0.5f,0.f}, omath::Vector3{0.f,-0.5f,0.f} }; auto pool = std::pmr::monotonic_buffer_resource(1024); - auto res = Epa::solve(A, B, simplex, {}, pool); + auto res = Epa::solve(a, b, simplex, {}, pool); // EPA may or may not converge depending on numerics; ensure it returns optionally // but if it does, fields should be finite if (res.has_value()) diff --git a/tests/general/unit_test_color_grouped.cpp b/tests/general/unit_test_color_grouped.cpp index 0d74c330..a32eaf1a 100644 --- a/tests/general/unit_test_color_grouped.cpp +++ b/tests/general/unit_test_color_grouped.cpp @@ -113,50 +113,50 @@ TEST_F(UnitTestColorGrouped, BlendVector3) TEST(UnitTestColorGrouped_Extra, SetHueSaturationValue) { Color c = Color::red(); - auto h1 = c.to_hsv(); + const auto h1 = c.to_hsv(); EXPECT_FLOAT_EQ(h1.hue, 0.f); c.set_hue(0.5f); - auto h2 = c.to_hsv(); + const auto h2 = c.to_hsv(); EXPECT_NEAR(h2.hue, 0.5f, 1e-3f); c = Color::from_hsv(0.25f, 0.8f, 0.6f); c.set_saturation(0.3f); - auto h3 = c.to_hsv(); + const auto h3 = c.to_hsv(); EXPECT_NEAR(h3.saturation, 0.3f, 1e-3f); c.set_value(1.0f); - auto h4 = c.to_hsv(); + const auto h4 = c.to_hsv(); EXPECT_NEAR(h4.value, 1.0f, 1e-3f); } TEST(UnitTestColorGrouped_Extra, ToStringVariants) { - Color c = Color::from_rgba(10, 20, 30, 255); + constexpr Color c = Color::from_rgba(10, 20, 30, 255); auto s = c.to_string(); EXPECT_NE(s.find("r:"), std::string::npos); - auto ws = c.to_wstring(); + const auto ws = c.to_wstring(); EXPECT_FALSE(ws.empty()); - auto u8 = c.to_u8string(); + const auto u8 = c.to_u8string(); EXPECT_FALSE(u8.empty()); } TEST(UnitTestColorGrouped_Extra, BlendEdgeCases) { - Color a = Color::red(); - Color b = Color::blue(); - auto r0 = a.blend(b, 0.f); + constexpr Color a = Color::red(); + constexpr Color b = Color::blue(); + constexpr auto r0 = a.blend(b, 0.f); EXPECT_FLOAT_EQ(r0.x, a.x); - auto r1 = a.blend(b, 1.f); + constexpr auto r1 = a.blend(b, 1.f); EXPECT_FLOAT_EQ(r1.x, b.x); } // From unit_test_color_more.cpp TEST(UnitTestColorGrouped_More, DefaultCtorIsZero) { - Color c; + constexpr Color c; EXPECT_FLOAT_EQ(c.x, 0.0f); EXPECT_FLOAT_EQ(c.y, 0.0f); EXPECT_FLOAT_EQ(c.z, 0.0f); @@ -165,7 +165,7 @@ TEST(UnitTestColorGrouped_More, DefaultCtorIsZero) TEST(UnitTestColorGrouped_More, FloatCtorAndClampForRGB) { - Color c(1.2f, -0.5f, 0.5f, 2.0f); + constexpr Color c(1.2f, -0.5f, 0.5f, 2.0f); EXPECT_FLOAT_EQ(c.x, 1.0f); EXPECT_FLOAT_EQ(c.y, 0.0f); EXPECT_FLOAT_EQ(c.z, 0.5f); @@ -174,7 +174,7 @@ TEST(UnitTestColorGrouped_More, FloatCtorAndClampForRGB) TEST(UnitTestColorGrouped_More, FromRgbaProducesScaledComponents) { - Color c = Color::from_rgba(25u, 128u, 230u, 64u); + constexpr Color c = Color::from_rgba(25u, 128u, 230u, 64u); EXPECT_NEAR(c.x, 25.0f/255.0f, 1e-6f); EXPECT_NEAR(c.y, 128.0f/255.0f, 1e-6f); EXPECT_NEAR(c.z, 230.0f/255.0f, 1e-6f); @@ -183,9 +183,9 @@ TEST(UnitTestColorGrouped_More, FromRgbaProducesScaledComponents) TEST(UnitTestColorGrouped_More, BlendProducesIntermediate) { - Color c0(0.0f, 0.0f, 0.0f, 1.0f); - Color c1(1.0f, 1.0f, 1.0f, 0.0f); - Color mid = c0.blend(c1, 0.5f); + constexpr Color c0(0.0f, 0.0f, 0.0f, 1.0f); + constexpr Color c1(1.0f, 1.0f, 1.0f, 0.0f); + constexpr Color mid = c0.blend(c1, 0.5f); EXPECT_FLOAT_EQ(mid.x, 0.5f); EXPECT_FLOAT_EQ(mid.y, 0.5f); EXPECT_FLOAT_EQ(mid.z, 0.5f); @@ -194,9 +194,9 @@ TEST(UnitTestColorGrouped_More, BlendProducesIntermediate) TEST(UnitTestColorGrouped_More, HsvRoundTrip) { - Color red = Color::red(); - auto hsv = red.to_hsv(); - Color back = Color::from_hsv(hsv); + constexpr Color red = Color::red(); + const auto hsv = red.to_hsv(); + const Color back = Color::from_hsv(hsv); EXPECT_NEAR(back.x, 1.0f, 1e-6f); EXPECT_NEAR(back.y, 0.0f, 1e-6f); EXPECT_NEAR(back.z, 0.0f, 1e-6f); @@ -204,7 +204,7 @@ TEST(UnitTestColorGrouped_More, HsvRoundTrip) TEST(UnitTestColorGrouped_More, ToStringContainsComponents) { - Color c = Color::from_rgba(10, 20, 30, 40); + constexpr Color c = Color::from_rgba(10, 20, 30, 40); std::string s = c.to_string(); EXPECT_NE(s.find("r:"), std::string::npos); EXPECT_NE(s.find("g:"), std::string::npos); @@ -215,7 +215,7 @@ TEST(UnitTestColorGrouped_More, ToStringContainsComponents) // From unit_test_color_more2.cpp TEST(UnitTestColorGrouped_More2, FromRgbaAndToString) { - auto c = Color::from_rgba(255, 128, 0, 64); + constexpr auto c = Color::from_rgba(255, 128, 0, 64); const auto s = c.to_string(); EXPECT_NE(s.find("r:255"), std::string::npos); EXPECT_NE(s.find("g:128"), std::string::npos); @@ -225,7 +225,7 @@ TEST(UnitTestColorGrouped_More2, FromRgbaAndToString) TEST(UnitTestColorGrouped_More2, FromHsvCases) { - const float eps = 1e-5f; + constexpr float eps = 1e-5f; auto check_hue = [&](float h) { SCOPED_TRACE(::testing::Message() << "h=" << h); @@ -257,7 +257,7 @@ TEST(UnitTestColorGrouped_More2, FromHsvCases) TEST(UnitTestColorGrouped_More2, ToHsvAndSetters) { Color c{0.2f, 0.4f, 0.6f, 1.f}; - auto hsv = c.to_hsv(); + const auto hsv = c.to_hsv(); EXPECT_NEAR(hsv.value, 0.6f, 1e-6f); c.set_hue(0.0f); @@ -272,16 +272,16 @@ TEST(UnitTestColorGrouped_More2, ToHsvAndSetters) TEST(UnitTestColorGrouped_More2, BlendAndStaticColors) { - Color a = Color::red(); - Color b = Color::blue(); - auto mid = a.blend(b, 0.5f); + constexpr Color a = Color::red(); + constexpr Color b = Color::blue(); + constexpr auto mid = a.blend(b, 0.5f); EXPECT_GT(mid.x, 0.f); EXPECT_GT(mid.z, 0.f); - auto all_a = a.blend(b, -1.f); + constexpr auto all_a = a.blend(b, -1.f); EXPECT_NEAR(all_a.x, a.x, 1e-6f); - auto all_b = a.blend(b, 2.f); + constexpr auto all_b = a.blend(b, 2.f); EXPECT_NEAR(all_b.z, b.z, 1e-6f); } diff --git a/tests/general/unit_test_epa.cpp b/tests/general/unit_test_epa.cpp index 97838d3d..43e6b014 100644 --- a/tests/general/unit_test_epa.cpp +++ b/tests/general/unit_test_epa.cpp @@ -60,7 +60,7 @@ TEST(UnitTestEpa, TestCollisionTrue) EXPECT_NEAR(epa->normal.z, 0.0f, 1e-3f); // Try both signs with a tiny margin (avoid grazing contacts) - const float margin = 1.0f + 1e-3f; + constexpr float margin = 1.0f + 1e-3f; const auto pen = epa->penetration_vector; Mesh b_plus = b; diff --git a/tests/general/unit_test_epa_internal.cpp b/tests/general/unit_test_epa_internal.cpp index 25982810..f31416c4 100644 --- a/tests/general/unit_test_epa_internal.cpp +++ b/tests/general/unit_test_epa_internal.cpp @@ -9,7 +9,8 @@ using Vector3f = omath::Vector3; struct DummyCollider { using VectorType = Vector3f; - VectorType find_abs_furthest_vertex_position(const VectorType& dir) const noexcept + [[nodiscard]] + static VectorType find_abs_furthest_vertex_position(const VectorType& dir) noexcept { // map direction to a small point so support_point is finite return Vector3f{dir.x * 0.01f, dir.y * 0.01f, dir.z * 0.01f}; @@ -25,12 +26,13 @@ TEST(EpaInternal, SolveHandlesSmallPolytope) Simplex s; s = { Vector3f{0.01f, 0.f, 0.f}, Vector3f{0.f, 0.01f, 0.f}, Vector3f{0.f, 0.f, 0.01f}, Vector3f{-0.01f, -0.01f, -0.01f} }; - DummyCollider a, b; + constexpr DummyCollider a; + constexpr DummyCollider b; EpaDummy::Params params; params.max_iterations = 16; params.tolerance = 1e-6f; - auto result = EpaDummy::solve(a, b, s, params); + const auto result = EpaDummy::solve(a, b, s, params); // Should either return a valid result or gracefully return nullopt if (result) diff --git a/tests/general/unit_test_epa_more.cpp b/tests/general/unit_test_epa_more.cpp index 2c491b65..086987db 100644 --- a/tests/general/unit_test_epa_more.cpp +++ b/tests/general/unit_test_epa_more.cpp @@ -30,12 +30,13 @@ TEST(EpaExtra, DegenerateFaceHandled) Simplex s; s = { Vector3f{0.01f, 0.f, 0.f}, Vector3f{0.02f, 0.f, 0.f}, Vector3f{0.03f, 0.f, 0.f}, Vector3f{0.0f, 0.0f, 0.01f} }; - DegenerateCollider a, b; + constexpr DegenerateCollider a; + constexpr DegenerateCollider b; Epa::Params params; params.max_iterations = 4; params.tolerance = 1e-6f; - auto result = Epa::solve(a, b, s, params); + const auto result = Epa::solve(a, b, s, params); // The algorithm should either return a valid result or gracefully exit (not crash) if (result) diff --git a/tests/general/unit_test_line_trace.cpp b/tests/general/unit_test_line_trace.cpp index 8387c4cb..8f1ec124 100644 --- a/tests/general/unit_test_line_trace.cpp +++ b/tests/general/unit_test_line_trace.cpp @@ -19,9 +19,9 @@ namespace // ----------------------------------------------------------------------------- // Constants & helpers // ----------------------------------------------------------------------------- - constexpr float kTol = 1e-5f; + constexpr float k_tol = 1e-5f; - bool VecEqual(const Vec3& a, const Vec3& b, float tol = kTol) + bool vec_equal(const Vec3& a, const Vec3& b, const float tol = k_tol) { return std::fabs(a.x - b.x) < tol && std::fabs(a.y - b.y) < tol && @@ -58,8 +58,8 @@ namespace TEST_P(CanTraceLineParam, VariousRays) { - const auto& p = GetParam(); - EXPECT_EQ(LineTracer::can_trace_line(p.ray, triangle), p.expected_clear); + const auto& [ray, expected_clear] = GetParam(); + EXPECT_EQ(LineTracer::can_trace_line(ray, triangle), expected_clear); } INSTANTIATE_TEST_SUITE_P( @@ -85,8 +85,8 @@ namespace constexpr Vec3 expected{0.3f, 0.3f, 0.f}; const Vec3 hit = LineTracer::get_ray_hit_point(ray, triangle); - ASSERT_FALSE(VecEqual(hit, ray.end)); - EXPECT_TRUE(VecEqual(hit, expected)); + ASSERT_FALSE(vec_equal(hit, ray.end)); + EXPECT_TRUE(vec_equal(hit, expected)); } // ----------------------------------------------------------------------------- diff --git a/tests/general/unit_test_line_tracer.cpp b/tests/general/unit_test_line_tracer.cpp index 33787981..fccc1675 100644 --- a/tests/general/unit_test_line_tracer.cpp +++ b/tests/general/unit_test_line_tracer.cpp @@ -8,51 +8,51 @@ using omath::Vector3; TEST(LineTracerTests, ParallelRayReturnsEnd) { // Triangle in XY plane - omath::Triangle> tri{ {0.f,0.f,0.f}, {1.f,0.f,0.f}, {0.f,1.f,0.f} }; + constexpr omath::Triangle> tri{ {0.f,0.f,0.f}, {1.f,0.f,0.f}, {0.f,1.f,0.f} }; omath::collision::Ray ray; ray.start = Vector3{0.f,0.f,1.f}; ray.end = Vector3{1.f,1.f,2.f}; // direction parallel to plane normal (z) -> but choose parallel to plane? make direction parallel to triangle plane ray.end = Vector3{1.f,1.f,1.f}; // For a ray parallel to the triangle plane the algorithm should return ray.end - auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); + const auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); EXPECT_TRUE(hit == ray.end); EXPECT_TRUE(omath::collision::LineTracer::can_trace_line(ray, tri)); } TEST(LineTracerTests, MissesTriangleReturnsEnd) { - omath::Triangle> tri{ {0.f,0.f,0.f}, {1.f,0.f,0.f}, {0.f,1.f,0.f} }; + constexpr omath::Triangle> tri{ {0.f,0.f,0.f}, {1.f,0.f,0.f}, {0.f,1.f,0.f} }; omath::collision::Ray ray; ray.start = Vector3{2.f,2.f,-1.f}; ray.end = Vector3{2.f,2.f,1.f}; // passes above the triangle area - auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); + const auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); EXPECT_TRUE(hit == ray.end); } TEST(LineTracerTests, HitTriangleReturnsPointInsideSegment) { - omath::Triangle> tri{ {0.f,0.f,0.f}, {2.f,0.f,0.f}, {0.f,2.f,0.f} }; + constexpr omath::Triangle> tri{ {0.f,0.f,0.f}, {2.f,0.f,0.f}, {0.f,2.f,0.f} }; omath::collision::Ray ray; ray.start = Vector3{0.25f,0.25f,-1.f}; ray.end = Vector3{0.25f,0.25f,1.f}; - auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); + const auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); // Should return a point between start and end (z approximately 0) EXPECT_NE(hit, ray.end); EXPECT_NEAR(hit.z, 0.f, 1e-4f); // t_hit should be between 0 and 1 along the ray direction - auto dir = ray.direction_vector(); + const auto dir = ray.direction_vector(); // find t such that start + dir * t == hit (only check z comp for stability) - float t = (hit.z - ray.start.z) / dir.z; + const float t = (hit.z - ray.start.z) / dir.z; EXPECT_GT(t, 0.f); EXPECT_LT(t, 1.f); } TEST(LineTracerTests, InfiniteLengthEarlyOut) { - omath::Triangle> tri{ {0.f,0.f,0.f}, {1.f,0.f,0.f}, {0.f,1.f,0.f} }; + constexpr omath::Triangle> tri{ {0.f,0.f,0.f}, {1.f,0.f,0.f}, {0.f,1.f,0.f} }; omath::collision::Ray ray; ray.start = Vector3{0.25f,0.25f,0.f}; ray.end = Vector3{0.25f,0.25f,1.f}; @@ -60,6 +60,6 @@ TEST(LineTracerTests, InfiniteLengthEarlyOut) // If t_hit <= epsilon the algorithm should return ray.end when infinite_length is true. // Using start on the triangle plane should produce t_hit <= epsilon. - auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); + const auto hit = omath::collision::LineTracer::get_ray_hit_point(ray, tri); EXPECT_TRUE(hit == ray.end); } diff --git a/tests/general/unit_test_line_tracer_extra.cpp b/tests/general/unit_test_line_tracer_extra.cpp index 73766441..51214dd2 100644 --- a/tests/general/unit_test_line_tracer_extra.cpp +++ b/tests/general/unit_test_line_tracer_extra.cpp @@ -8,17 +8,17 @@ using namespace omath::collision; TEST(LineTracerExtra, MissParallel) { - Triangle> tri({0,0,0},{1,0,0},{0,1,0}); - Ray ray{ {0.3f,0.3f,1.f}, {0.3f,0.3f,2.f}, false };// parallel above triangle - auto hit = LineTracer::get_ray_hit_point(ray, tri); + constexpr Triangle> tri({0,0,0},{1,0,0},{0,1,0}); + constexpr Ray ray{ {0.3f,0.3f,1.f}, {0.3f,0.3f,2.f}, false }; // parallel above triangle + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } TEST(LineTracerExtra, HitCenter) { - Triangle> tri({0,0,0},{1,0,0},{0,1,0}); - Ray ray{ {0.3f,0.3f,-1.f}, {0.3f,0.3f,1.f}, false }; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + constexpr Triangle> tri({0,0,0},{1,0,0},{0,1,0}); + constexpr Ray ray{ {0.3f,0.3f,-1.f}, {0.3f,0.3f,1.f}, false }; + const auto hit = LineTracer::get_ray_hit_point(ray, tri); ASSERT_FALSE(hit == ray.end); EXPECT_NEAR(hit.x, 0.3f, 1e-6f); EXPECT_NEAR(hit.y, 0.3f, 1e-6f); @@ -27,9 +27,9 @@ TEST(LineTracerExtra, HitCenter) TEST(LineTracerExtra, HitOnEdge) { - Triangle> tri({0,0,0},{1,0,0},{0,1,0}); - Ray ray{ {0.0f,0.0f,1.f}, {0.0f,0.0f,0.f}, false }; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + constexpr Triangle> tri({0,0,0},{1,0,0},{0,1,0}); + constexpr Ray ray{ {0.0f,0.0f,1.f}, {0.0f,0.0f,0.f}, false }; + const auto hit = LineTracer::get_ray_hit_point(ray, tri); // hitting exact vertex/edge may be considered miss; ensure function handles without crash if (hit != ray.end) { @@ -40,9 +40,9 @@ TEST(LineTracerExtra, HitOnEdge) TEST(LineTracerExtra, InfiniteRayIgnoredIfBehind) { - Triangle> tri({0,0,0},{1,0,0},{0,1,0}); + constexpr Triangle> tri({0,0,0},{1,0,0},{0,1,0}); // Ray pointing away but infinite_length true should be ignored - Ray ray{ {0.5f,0.5f,-1.f}, {0.5f,0.5f,-2.f}, true }; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + constexpr Ray ray{ {0.5f,0.5f,-1.f}, {0.5f,0.5f,-2.f}, true }; + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } diff --git a/tests/general/unit_test_line_tracer_more.cpp b/tests/general/unit_test_line_tracer_more.cpp index 66b1c941..81c711b7 100644 --- a/tests/general/unit_test_line_tracer_more.cpp +++ b/tests/general/unit_test_line_tracer_more.cpp @@ -11,53 +11,53 @@ using Triangle3 = omath::Triangle>; TEST(LineTracerMore, ParallelRayReturnsEnd) { // Ray parallel to triangle plane: construct triangle in XY plane and ray along X axis - Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); + constexpr Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); Ray ray; ray.start = {0.f,0.f,1.f}; ray.end = {1.f,0.f,1.f}; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } TEST(LineTracerMore, UOutOfRangeReturnsEnd) { // Construct a ray that misses due to u < 0 - Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); + constexpr Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); Ray ray; ray.start = {-1.f,-1.f,-1.f}; ray.end = {-0.5f,-1.f,1.f}; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } TEST(LineTracerMore, VOutOfRangeReturnsEnd) { // Construct ray that has v < 0 - Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); + constexpr Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); Ray ray; ray.start = {2.f,2.f,-1.f}; ray.end = {2.f,2.f,1.f}; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } TEST(LineTracerMore, THitTooSmallReturnsEnd) { - Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); + constexpr Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); Ray ray; ray.start = {0.f,0.f,0.0000000001f}; ray.end = {0.f,0.f,1.f}; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } TEST(LineTracerMore, THitGreaterThanOneReturnsEnd) { - Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); + constexpr Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); // Choose a ray and compute t_hit locally to assert consistency Ray ray; ray.start = {0.f,0.f,-1.f}; ray.end = {0.f,0.f,-0.5f}; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); - const float k_epsilon = std::numeric_limits::epsilon(); - const auto side_a = tri.side_a_vector(); - const auto side_b = tri.side_b_vector(); + constexpr float k_epsilon = std::numeric_limits::epsilon(); + constexpr auto side_a = tri.side_a_vector(); + constexpr auto side_b = tri.side_b_vector(); const auto ray_dir = ray.direction_vector(); const auto p = ray_dir.cross(side_b); const auto det = side_a.dot(p); @@ -82,21 +82,21 @@ TEST(LineTracerMore, THitGreaterThanOneReturnsEnd) TEST(LineTracerMore, InfiniteLengthWithSmallTHitReturnsEnd) { Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); - Triangle3 tri2(Vector3{0.f,0.f,-1e-8f}, Vector3{1.f,0.f,-1e-8f}, Vector3{0.f,1.f,-1e-8f}); + constexpr Triangle3 tri2(Vector3{0.f,0.f,-1e-8f}, Vector3{1.f,0.f,-1e-8f}, Vector3{0.f,1.f,-1e-8f}); Ray ray; ray.start = {0.f,0.f,0.f}; ray.end = {0.f,0.f,1.f}; ray.infinite_length = true; // Create triangle slightly behind so t_hit <= eps tri = tri2; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } TEST(LineTracerMore, SuccessfulHitReturnsPoint) { - Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); + constexpr Triangle3 tri(Vector3{0.f,0.f,0.f}, Vector3{1.f,0.f,0.f}, Vector3{0.f,1.f,0.f}); Ray ray; ray.start = {0.1f,0.1f,-1.f}; ray.end = {0.1f,0.1f,1.f}; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_NE(hit, ray.end); // Hit should be on plane z=0 and near x=0.1,y=0.1 EXPECT_NEAR(hit.z, 0.f, 1e-6f); diff --git a/tests/general/unit_test_line_tracer_more2.cpp b/tests/general/unit_test_line_tracer_more2.cpp index d8ff62d1..716453f8 100644 --- a/tests/general/unit_test_line_tracer_more2.cpp +++ b/tests/general/unit_test_line_tracer_more2.cpp @@ -10,48 +10,48 @@ using Triangle3 = omath::Triangle>; TEST(LineTracerMore2, UGreaterThanOneReturnsEnd) { - Triangle3 tri({0.f,0.f,0.f},{1.f,0.f,0.f},{0.f,1.f,0.f}); + constexpr Triangle3 tri({0.f,0.f,0.f},{1.f,0.f,0.f},{0.f,1.f,0.f}); // choose ray so barycentric u > 1 Ray ray; ray.start = {2.f, -1.f, -1.f}; ray.end = {2.f, -1.f, 1.f}; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } TEST(LineTracerMore2, VGreaterThanOneReturnsEnd) { - Triangle3 tri({0.f,0.f,0.f},{1.f,0.f,0.f},{0.f,1.f,0.f}); + constexpr Triangle3 tri({0.f,0.f,0.f},{1.f,0.f,0.f},{0.f,1.f,0.f}); // choose ray so barycentric v > 1 Ray ray; ray.start = {-1.f, 2.f, -1.f}; ray.end = {-1.f, 2.f, 1.f}; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } TEST(LineTracerMore2, UPlusVGreaterThanOneReturnsEnd) { - Triangle3 tri({0.f,0.f,0.f},{1.f,0.f,0.f},{0.f,1.f,0.f}); + constexpr Triangle3 tri({0.f,0.f,0.f},{1.f,0.f,0.f},{0.f,1.f,0.f}); // Ray aimed so u+v > 1 (outside triangle region) Ray ray; ray.start = {1.f, 1.f, -1.f}; ray.end = {1.f, 1.f, 1.f}; - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } TEST(LineTracerMore2, DirectionVectorNormalizedProducesUnitLength) { Ray r; r.start = {0.f,0.f,0.f}; r.end = {0.f,3.f,4.f}; - auto dir = r.direction_vector_normalized(); - auto len = dir.length(); + const auto dir = r.direction_vector_normalized(); + const auto len = dir.length(); EXPECT_NEAR(len, 1.f, 1e-6f); } TEST(LineTracerMore2, ZeroLengthRayHandled) { - Triangle3 tri({0.f,0.f,0.f},{1.f,0.f,0.f},{0.f,1.f,0.f}); + constexpr Triangle3 tri({0.f,0.f,0.f},{1.f,0.f,0.f},{0.f,1.f,0.f}); Ray ray; ray.start = {0.f,0.f,0.f}; ray.end = {0.f,0.f,0.f}; // Zero-length ray: direction length == 0; algorithm should handle without crash - auto hit = LineTracer::get_ray_hit_point(ray, tri); + const auto hit = LineTracer::get_ray_hit_point(ray, tri); EXPECT_EQ(hit, ray.end); } diff --git a/tests/general/unit_test_linear_algebra_cover_more_ops.cpp b/tests/general/unit_test_linear_algebra_cover_more_ops.cpp index bfedb00d..b49ea48e 100644 --- a/tests/general/unit_test_linear_algebra_cover_more_ops.cpp +++ b/tests/general/unit_test_linear_algebra_cover_more_ops.cpp @@ -31,16 +31,16 @@ TEST(Vector3ScalarOps, InPlaceScalarOperators) TEST(Vector4BinaryOps, ElementWiseMulDiv) { - Vector4 a{2.f, 4.f, 6.f, 8.f}; - Vector4 b{1.f, 2.f, 3.f, 4.f}; + constexpr Vector4 a{2.f, 4.f, 6.f, 8.f}; + constexpr Vector4 b{1.f, 2.f, 3.f, 4.f}; - auto m = a * b; + constexpr auto m = a * b; EXPECT_FLOAT_EQ(m.x, 2.f); EXPECT_FLOAT_EQ(m.y, 8.f); EXPECT_FLOAT_EQ(m.z, 18.f); EXPECT_FLOAT_EQ(m.w, 32.f); - auto d = a / b; + constexpr auto d = a / b; EXPECT_FLOAT_EQ(d.x, 2.f); EXPECT_FLOAT_EQ(d.y, 2.f); EXPECT_FLOAT_EQ(d.z, 2.f); diff --git a/tests/general/unit_test_linear_algebra_cover_remaining.cpp b/tests/general/unit_test_linear_algebra_cover_remaining.cpp index 7027f330..be42f383 100644 --- a/tests/general/unit_test_linear_algebra_cover_remaining.cpp +++ b/tests/general/unit_test_linear_algebra_cover_remaining.cpp @@ -10,23 +10,21 @@ using namespace omath; static void make_bad_mat_rows() { // wrong number of rows -> should throw inside initializer-list ctor - Mat<2, 2, float> m{{1.f, 2.f}}; - (void)m; + [[maybe_unused]] const Mat<2, 2, float> m{{1.f, 2.f}}; } static void make_bad_mat_cols() { // row with wrong number of columns -> should throw - Mat<2, 2, float> m{{1.f, 2.f}, {1.f}}; - (void)m; + [[maybe_unused]] const Mat<2, 2, float> m{{1.f, 2.f}, {1.f}}; } TEST(Vector4Operator, Subtraction) { - Vector4 a{5.f, 6.f, 7.f, 8.f}; - Vector4 b{1.f, 2.f, 3.f, 4.f}; + constexpr Vector4 a{5.f, 6.f, 7.f, 8.f}; + constexpr Vector4 b{1.f, 2.f, 3.f, 4.f}; - auto r = a - b; + constexpr auto r = a - b; EXPECT_FLOAT_EQ(r.x, 4.f); EXPECT_FLOAT_EQ(r.y, 4.f); EXPECT_FLOAT_EQ(r.z, 4.f); diff --git a/tests/general/unit_test_linear_algebra_extra.cpp b/tests/general/unit_test_linear_algebra_extra.cpp index b081033a..c5926e84 100644 --- a/tests/general/unit_test_linear_algebra_extra.cpp +++ b/tests/general/unit_test_linear_algebra_extra.cpp @@ -11,12 +11,12 @@ using namespace omath; TEST(LinearAlgebraExtra, FormatterAndHashVector2) { Vector2 v{1.0f, 2.0f}; - std::string s = std::format("{}", v); + const std::string s = std::format("{}", v); EXPECT_EQ(s, "[1, 2]"); - std::size_t h1 = std::hash>{}(v); - std::size_t h2 = std::hash>{}(Vector2{1.0f, 2.0f}); - std::size_t h3 = std::hash>{}(Vector2{2.0f, 3.0f}); + const std::size_t h1 = std::hash>{}(v); + const std::size_t h2 = std::hash>{}(Vector2{1.0f, 2.0f}); + const std::size_t h3 = std::hash>{}(Vector2{2.0f, 3.0f}); EXPECT_EQ(h1, h2); EXPECT_NE(h1, h3); @@ -25,11 +25,11 @@ TEST(LinearAlgebraExtra, FormatterAndHashVector2) TEST(LinearAlgebraExtra, FormatterAndHashVector3) { Vector3 v{1.0f, 2.0f, 3.0f}; - std::string s = std::format("{}", v); + const std::string s = std::format("{}", v); EXPECT_EQ(s, "[1, 2, 3]"); - std::size_t h1 = std::hash>{}(v); - std::size_t h2 = std::hash>{}(Vector3{1.0f, 2.0f, 3.0f}); + const std::size_t h1 = std::hash>{}(v); + const std::size_t h2 = std::hash>{}(Vector3{1.0f, 2.0f, 3.0f}); EXPECT_EQ(h1, h2); // point_to_same_direction @@ -40,18 +40,18 @@ TEST(LinearAlgebraExtra, FormatterAndHashVector3) TEST(LinearAlgebraExtra, FormatterAndHashVector4) { Vector4 v{1.0f, 2.0f, 3.0f, 4.0f}; - std::string s = std::format("{}", v); + const std::string s = std::format("{}", v); EXPECT_EQ(s, "[1, 2, 3, 4]"); - std::size_t h1 = std::hash>{}(v); - std::size_t h2 = std::hash>{}(Vector4{1.0f, 2.0f, 3.0f, 4.0f}); + const std::size_t h1 = std::hash>{}(v); + const std::size_t h2 = std::hash>{}(Vector4{1.0f, 2.0f, 3.0f, 4.0f}); EXPECT_EQ(h1, h2); } TEST(LinearAlgebraExtra, MatRawArrayAndOperators) { Mat<2,2> m{{1.0f, 2.0f},{3.0f,4.0f}}; - auto raw = m.raw_array(); + const auto raw = m.raw_array(); EXPECT_EQ(raw.size(), 4); EXPECT_FLOAT_EQ(raw[0], 1.0f); EXPECT_FLOAT_EQ(raw[3], 4.0f); diff --git a/tests/general/unit_test_linear_algebra_helpers.cpp b/tests/general/unit_test_linear_algebra_helpers.cpp index 2cca9120..3483fa0d 100644 --- a/tests/general/unit_test_linear_algebra_helpers.cpp +++ b/tests/general/unit_test_linear_algebra_helpers.cpp @@ -12,14 +12,14 @@ using namespace omath; TEST(LinearAlgebraHelpers, Vector3NoInlineHelpersExecute) { - Vector3 a{1.f, 2.f, 3.f}; - Vector3 b{4.f, 5.f, 6.f}; + constexpr Vector3 a{1.f, 2.f, 3.f}; + constexpr Vector3 b{4.f, 5.f, 6.f}; // Execute helpers that were made non-inlined - auto l = a.length(); - auto ang = a.angle_between(b); - auto perp = a.is_perpendicular(b); - auto norm = a.normalized(); + const auto l = a.length(); + const auto ang = a.angle_between(b); + const auto perp = a.is_perpendicular(b); + const auto norm = a.normalized(); (void)l; (void)ang; (void)perp; (void)norm; SUCCEED(); @@ -27,17 +27,17 @@ TEST(LinearAlgebraHelpers, Vector3NoInlineHelpersExecute) TEST(LinearAlgebraHelpers, TriangleNoInlineHelpersExecute) { - Vector3 v1{0.f,0.f,0.f}; - Vector3 v2{3.f,0.f,0.f}; - Vector3 v3{3.f,4.f,0.f}; + constexpr Vector3 v1{0.f,0.f,0.f}; + constexpr Vector3 v2{3.f,0.f,0.f}; + constexpr Vector3 v3{3.f,4.f,0.f}; - Triangle> t{v1, v2, v3}; + constexpr Triangle> t{v1, v2, v3}; - auto n = t.calculate_normal(); - auto a = t.side_a_length(); - auto b = t.side_b_length(); - auto h = t.hypot(); - auto r = t.is_rectangular(); + const auto n = t.calculate_normal(); + const auto a = t.side_a_length(); + const auto b = t.side_b_length(); + const auto h = t.hypot(); + const auto r = t.is_rectangular(); (void)n; (void)a; (void)b; (void)h; (void)r; SUCCEED(); @@ -47,8 +47,8 @@ TEST(LinearAlgebraHelpers, Vector4NoInlineHelpersExecute) { Vector4 v{1.f,2.f,3.f,4.f}; - auto l = v.length(); - auto s = v.sum(); + const auto l = v.length(); + const auto s = v.sum(); v.clamp(-10.f, 10.f); (void)l; (void)s; diff --git a/tests/general/unit_test_linear_algebra_more.cpp b/tests/general/unit_test_linear_algebra_more.cpp index dc4dd023..e29a7eed 100644 --- a/tests/general/unit_test_linear_algebra_more.cpp +++ b/tests/general/unit_test_linear_algebra_more.cpp @@ -7,32 +7,32 @@ using namespace omath; TEST(LinearAlgebraMore, Vector3EdgeCases) { - Vector3 zero{0.f,0.f,0.f}; - Vector3 v{1.f,0.f,0.f}; + constexpr Vector3 zero{0.f,0.f,0.f}; + constexpr Vector3 v{1.f,0.f,0.f}; // angle_between should be unexpected when one vector has zero length - auto angle = zero.angle_between(v); + const auto angle = zero.angle_between(v); EXPECT_FALSE(static_cast(angle)); // normalized of zero should return zero - auto nz = zero.normalized(); + const auto nz = zero.normalized(); EXPECT_EQ(nz.x, 0.f); EXPECT_EQ(nz.y, 0.f); EXPECT_EQ(nz.z, 0.f); // perpendicular case: x-axis and y-axis - Vector3 x{1.f,0.f,0.f}; - Vector3 y{0.f,1.f,0.f}; + constexpr Vector3 x{1.f,0.f,0.f}; + constexpr Vector3 y{0.f,1.f,0.f}; EXPECT_TRUE(x.is_perpendicular(y)); } TEST(LinearAlgebraMore, TriangleRectangularAndDegenerate) { - Vector3 v1{0.f,0.f,0.f}; - Vector3 v2{3.f,0.f,0.f}; - Vector3 v3{3.f,4.f,0.f}; // 3-4-5 triangle, rectangular at v2 + constexpr Vector3 v1{0.f,0.f,0.f}; + constexpr Vector3 v2{3.f,0.f,0.f}; + constexpr Vector3 v3{3.f,4.f,0.f}; // 3-4-5 triangle, rectangular at v2 - Triangle> t{v1,v2,v3}; + constexpr Triangle> t{v1,v2,v3}; EXPECT_NEAR(t.side_a_length(), 3.f, 1e-6f); EXPECT_NEAR(t.side_b_length(), 4.f, 1e-6f); @@ -40,7 +40,7 @@ TEST(LinearAlgebraMore, TriangleRectangularAndDegenerate) EXPECT_TRUE(t.is_rectangular()); // Degenerate: all points same - Triangle> d{v1,v1,v1}; + constexpr Triangle> d{v1,v1,v1}; EXPECT_NEAR(d.side_a_length(), 0.f, 1e-6f); EXPECT_NEAR(d.side_b_length(), 0.f, 1e-6f); EXPECT_NEAR(d.hypot(), 0.f, 1e-6f); @@ -49,7 +49,7 @@ TEST(LinearAlgebraMore, TriangleRectangularAndDegenerate) TEST(LinearAlgebraMore, Vector4ClampAndComparisons) { Vector4 v{10.f, -20.f, 30.f, -40.f}; - auto s = v.sum(); + const auto s = v.sum(); EXPECT_NEAR(s, -20.f, 1e-6f); v.clamp(-10.f, 10.f); @@ -58,7 +58,7 @@ TEST(LinearAlgebraMore, Vector4ClampAndComparisons) EXPECT_LE(v.y, 10.f); EXPECT_GE(v.y, -10.f); - Vector4 a{1.f,2.f,3.f,4.f}; - Vector4 b{2.f,2.f,2.f,2.f}; + constexpr Vector4 a{1.f,2.f,3.f,4.f}; + constexpr Vector4 b{2.f,2.f,2.f,2.f}; EXPECT_TRUE(a < b || a > b || a == b); // just exercise comparisons } diff --git a/tests/general/unit_test_linear_algebra_more2.cpp b/tests/general/unit_test_linear_algebra_more2.cpp index 73d7dfdc..e9c4e3f9 100644 --- a/tests/general/unit_test_linear_algebra_more2.cpp +++ b/tests/general/unit_test_linear_algebra_more2.cpp @@ -47,7 +47,7 @@ TEST(LinearAlgebraMore2, Vector4NonInlinedHelpers) EXPECT_GE(v.x, 0.f); EXPECT_LE(v.z, 2.5f); - Vector4 shorter{0.1f,0.1f,0.1f,0.1f}; + constexpr Vector4 shorter{0.1f,0.1f,0.1f,0.1f}; EXPECT_TRUE(shorter < v); EXPECT_FALSE(v < shorter); } @@ -59,7 +59,7 @@ TEST(LinearAlgebraMore2, MatNonInlinedAndStringHelpers) auto maybe_inv = m.inverted(); EXPECT_TRUE(maybe_inv.has_value()); - auto inv = maybe_inv.value(); + const auto& inv = maybe_inv.value(); // m * inv should be identity (approximately) auto prod = m * inv; @@ -72,14 +72,14 @@ TEST(LinearAlgebraMore2, MatNonInlinedAndStringHelpers) EXPECT_EQ(t.at(0,1), m.at(1,0)); auto raw = m.raw_array(); - EXPECT_EQ(raw.size(), size_t(4)); + EXPECT_EQ(raw.size(), static_cast(4)); auto s = m.to_string(); EXPECT_NE(s.size(), 0u); auto ws = m.to_wstring(); EXPECT_NE(ws.size(), 0u); - auto u8s = m.to_u8string(); - EXPECT_NE(u8s.size(), 0u); + auto u8_s = m.to_u8string(); + EXPECT_NE(u8_s.size(), 0u); // to_screen_mat static helper auto screen = Mat<4,4,float>::to_screen_mat(800.f, 600.f); diff --git a/tests/general/unit_test_mat.cpp b/tests/general/unit_test_mat.cpp index 08ed4719..7cfc9c1d 100644 --- a/tests/general/unit_test_mat.cpp +++ b/tests/general/unit_test_mat.cpp @@ -154,12 +154,12 @@ TEST_F(UnitTestMat, AssignmentOperator_Move) // Test static methods TEST_F(UnitTestMat, StaticMethod_ToScreenMat) { - Mat<4, 4> screenMat = Mat<4, 4>::to_screen_mat(800.0f, 600.0f); - EXPECT_FLOAT_EQ(screenMat.at(0, 0), 400.0f); - EXPECT_FLOAT_EQ(screenMat.at(1, 1), -300.0f); - EXPECT_FLOAT_EQ(screenMat.at(3, 0), 400.0f); - EXPECT_FLOAT_EQ(screenMat.at(3, 1), 300.0f); - EXPECT_FLOAT_EQ(screenMat.at(3, 3), 1.0f); + Mat<4, 4> screen_mat = Mat<4, 4>::to_screen_mat(800.0f, 600.0f); + EXPECT_FLOAT_EQ(screen_mat.at(0, 0), 400.0f); + EXPECT_FLOAT_EQ(screen_mat.at(1, 1), -300.0f); + EXPECT_FLOAT_EQ(screen_mat.at(3, 0), 400.0f); + EXPECT_FLOAT_EQ(screen_mat.at(3, 1), 300.0f); + EXPECT_FLOAT_EQ(screen_mat.at(3, 3), 1.0f); } @@ -220,8 +220,8 @@ TEST(UnitTestMatStandalone, Equanity) constexpr omath::Vector3 left_handed = {0, 2, 10}; constexpr omath::Vector3 right_handed = {0, 2, -10}; - auto proj_left_handed = omath::mat_perspective_left_handed(90.f, 16.f / 9.f, 0.1, 1000); - auto proj_right_handed = omath::mat_perspective_right_handed(90.f, 16.f / 9.f, 0.1, 1000); + const auto proj_left_handed = omath::mat_perspective_left_handed(90.f, 16.f / 9.f, 0.1, 1000); + const auto proj_right_handed = omath::mat_perspective_right_handed(90.f, 16.f / 9.f, 0.1, 1000); auto ndc_left_handed = proj_left_handed * omath::mat_column_from_vector(left_handed); auto ndc_right_handed = proj_right_handed * omath::mat_column_from_vector(right_handed); @@ -233,7 +233,7 @@ TEST(UnitTestMatStandalone, Equanity) } TEST(UnitTestMatStandalone, MatPerspectiveLeftHanded) { - auto perspective_proj = mat_perspective_left_handed(90.f, 16.f/9.f, 0.1f, 1000.f); + const auto perspective_proj = mat_perspective_left_handed(90.f, 16.f/9.f, 0.1f, 1000.f); auto projected = perspective_proj * mat_column_from_vector({0, 0, 0.1001}); diff --git a/tests/general/unit_test_mat_coverage_extra.cpp b/tests/general/unit_test_mat_coverage_extra.cpp index 0c52aba7..bddb26ee 100644 --- a/tests/general/unit_test_mat_coverage_extra.cpp +++ b/tests/general/unit_test_mat_coverage_extra.cpp @@ -16,9 +16,9 @@ TEST(MatCoverageExtra, InitListColumnsMismatchThrows) { TEST(MatCoverageExtra, DeterminantFallbackIsCallable) { // Call determinant for 1x1 and 2x2 matrices to cover determinant paths - Mat<1,1> m1{{3.14f}}; + const Mat<1,1> m1{{3.14f}}; EXPECT_FLOAT_EQ(m1.determinant(), 3.14f); - Mat<2,2> m2{{{1.0f,2.0f},{3.0f,4.0f}}}; + const Mat<2,2> m2{{{1.0f,2.0f},{3.0f,4.0f}}}; EXPECT_FLOAT_EQ(m2.determinant(), -2.0f); } diff --git a/tests/general/unit_test_mat_more.cpp b/tests/general/unit_test_mat_more.cpp index 68467fcf..bb023fc4 100644 --- a/tests/general/unit_test_mat_more.cpp +++ b/tests/general/unit_test_mat_more.cpp @@ -15,7 +15,7 @@ TEST(MatMore, InitListAndMultiply) TEST(MatMore, Determinant) { - Mat<2,2,double> m{{{1.0,2.0},{2.0,4.0}}}; // singular - double det = m.determinant(); + const Mat<2,2,double> m{{{1.0,2.0},{2.0,4.0}}}; // singular + const double det = m.determinant(); EXPECT_DOUBLE_EQ(det, 0.0); } diff --git a/tests/general/unit_test_navigation_mesh.cpp b/tests/general/unit_test_navigation_mesh.cpp index 15fab61a..b5ba7b0f 100644 --- a/tests/general/unit_test_navigation_mesh.cpp +++ b/tests/general/unit_test_navigation_mesh.cpp @@ -26,8 +26,8 @@ TEST(NavigationMeshTests, SerializeDeserializeRoundTrip) TEST(NavigationMeshTests, GetClosestVertexWhenEmpty) { - NavigationMesh nav; - Vector3 p{5.f,5.f,5.f}; - auto res = nav.get_closest_vertex(p); + const NavigationMesh nav; + constexpr Vector3 p{5.f,5.f,5.f}; + const auto res = nav.get_closest_vertex(p); EXPECT_FALSE(res.has_value()); } diff --git a/tests/general/unit_test_pattern_scan_extra.cpp b/tests/general/unit_test_pattern_scan_extra.cpp index 6fe0f26b..cb371731 100644 --- a/tests/general/unit_test_pattern_scan_extra.cpp +++ b/tests/general/unit_test_pattern_scan_extra.cpp @@ -6,23 +6,26 @@ using namespace omath; TEST(unit_test_pattern_scan_extra, IteratorScanFound) { - std::vector buf = {std::byte(0xDE), std::byte(0xAD), std::byte(0xBE), std::byte(0xEF), std::byte(0x00)}; - auto it = PatternScanner::scan_for_pattern(buf.begin(), buf.end(), "DE AD BE EF"); + std::vector buf = {static_cast(0xDE), static_cast(0xAD), + static_cast(0xBE), static_cast(0xEF), + static_cast(0x00)}; + const auto it = PatternScanner::scan_for_pattern(buf.begin(), buf.end(), "DE AD BE EF"); EXPECT_NE(it, buf.end()); EXPECT_EQ(std::distance(buf.begin(), it), 0); } TEST(unit_test_pattern_scan_extra, IteratorScanNotFound) { - std::vector buf = {std::byte(0x00), std::byte(0x11), std::byte(0x22)}; - auto it = PatternScanner::scan_for_pattern(buf.begin(), buf.end(), "FF EE DD"); + std::vector buf = {static_cast(0x00), static_cast(0x11), + static_cast(0x22)}; + const auto it = PatternScanner::scan_for_pattern(buf.begin(), buf.end(), "FF EE DD"); EXPECT_EQ(it, buf.end()); } TEST(unit_test_pattern_scan_extra, ParseInvalidPattern) { // invalid hex token should cause the public scan to return end (no match) - std::vector buf = {std::byte(0x00), std::byte(0x11)}; - auto it = PatternScanner::scan_for_pattern(buf.begin(), buf.end(), "GG HH"); + std::vector buf = {static_cast(0x00), static_cast(0x11)}; + const auto it = PatternScanner::scan_for_pattern(buf.begin(), buf.end(), "GG HH"); EXPECT_EQ(it, buf.end()); } diff --git a/tests/general/unit_test_pe_pattern_scan_file.cpp b/tests/general/unit_test_pe_pattern_scan_file.cpp index 193ee53c..5e2abb84 100644 --- a/tests/general/unit_test_pe_pattern_scan_file.cpp +++ b/tests/general/unit_test_pe_pattern_scan_file.cpp @@ -64,7 +64,7 @@ static bool write_minimal_pe_file(const std::string& path, const std::vector placeholder(section_header_rest, 0); f.write(placeholder.data(), placeholder.size()); @@ -75,7 +75,7 @@ static bool write_minimal_pe_file(const std::string& path, const std::vector(section_bytes.size()); - const std::uint32_t virtual_address = 0x1000u; + constexpr std::uint32_t virtual_address = 0x1000u; const std::uint32_t size_raw_data = static_cast(section_bytes.size()); const std::uint32_t ptr_raw_data = static_cast(data_pos); @@ -95,9 +95,9 @@ static bool write_minimal_pe_file(const std::string& path, const std::vector bytes = {0x55, 0x8B, 0xEC, 0x90, 0x90}; // pattern at offset 0 - ASSERT_TRUE(write_minimal_pe_file(path, bytes)); + constexpr std::string_view path = "./test_minimal_pe.bin"; + const std::vector bytes = {0x55, 0x8B, 0xEC, 0x90, 0x90}; // pattern at offset 0 + ASSERT_TRUE(write_minimal_pe_file(path.data(), bytes)); const auto res = PePatternScanner::scan_for_pattern_in_file(path, "55 8B EC", ".text"); EXPECT_TRUE(res.has_value()); @@ -105,9 +105,9 @@ TEST(unit_test_pe_pattern_scan_file, ScanFindsPattern) TEST(unit_test_pe_pattern_scan_file, ScanMissingPattern) { - const std::string path = "./test_minimal_pe_2.bin"; - std::vector bytes = {0x00, 0x01, 0x02, 0x03}; - ASSERT_TRUE(write_minimal_pe_file(path, bytes)); + constexpr std::string_view path = "./test_minimal_pe_2.bin"; + const std::vector bytes = {0x00, 0x01, 0x02, 0x03}; + ASSERT_TRUE(write_minimal_pe_file(path.data(), bytes)); const auto res = PePatternScanner::scan_for_pattern_in_file(path, "FF EE DD", ".text"); EXPECT_FALSE(res.has_value()); diff --git a/tests/general/unit_test_pe_pattern_scan_loaded.cpp b/tests/general/unit_test_pe_pattern_scan_loaded.cpp index d06dfbff..963cd729 100644 --- a/tests/general/unit_test_pe_pattern_scan_loaded.cpp +++ b/tests/general/unit_test_pe_pattern_scan_loaded.cpp @@ -11,23 +11,23 @@ static std::vector make_fake_module(std::uint32_t base_of_code, std::uint32_t size_code, const std::vector& code_bytes) { - const std::uint32_t e_lfanew = 0x80; + constexpr std::uint32_t e_lfanew = 0x80; const std::uint32_t total_size = e_lfanew + 0x200 + size_code + 0x100; std::vector buf(total_size, 0); // DOS header: e_magic at 0, e_lfanew at offset 0x3C buf[0] = 0x4D; buf[1] = 0x5A; // 'M' 'Z' (little-endian 0x5A4D) - std::uint32_t le = e_lfanew; + constexpr std::uint32_t le = e_lfanew; std::memcpy(buf.data() + 0x3C, &le, sizeof(le)); // NT signature at e_lfanew - const std::uint32_t nt_sig = 0x4550; // 'PE\0\0' + constexpr std::uint32_t nt_sig = 0x4550; // 'PE\0\0' std::memcpy(buf.data() + e_lfanew, &nt_sig, sizeof(nt_sig)); // FileHeader is 20 bytes: we only need to ensure its size is present; leave zeros // OptionalHeader magic (optional header begins at e_lfanew + 4 + sizeof(FileHeader) == e_lfanew + 24) - const std::uint16_t opt_magic = 0x020B; // x64 + constexpr std::uint16_t opt_magic = 0x020B; // x64 std::memcpy(buf.data() + e_lfanew + 24, &opt_magic, sizeof(opt_magic)); // size_code is at offset 4 inside OptionalHeader -> absolute e_lfanew + 28 @@ -45,25 +45,25 @@ static std::vector make_fake_module(std::uint32_t base_of_code, TEST(PePatternScanLoaded, FindsPatternAtBase) { - std::vector code = {0x90, 0x01, 0x02, 0x03, 0x04}; + const std::vector code = {0x90, 0x01, 0x02, 0x03, 0x04}; auto buf = make_fake_module(0x200, static_cast(code.size()), code); - auto res = PePatternScanner::scan_for_pattern_in_loaded_module(buf.data(), "90 01 02"); + const auto res = PePatternScanner::scan_for_pattern_in_loaded_module(buf.data(), "90 01 02"); ASSERT_TRUE(res.has_value()); // address should point somewhere in our buffer; check offset - uintptr_t addr = res.value(); - uintptr_t base = reinterpret_cast(buf.data()); + const uintptr_t addr = res.value(); + const uintptr_t base = reinterpret_cast(buf.data()); EXPECT_EQ(addr - base, 0x200u); } TEST(PePatternScanLoaded, WildcardMatches) { - std::vector code = {0xDE, 0xAD, 0xBE, 0xEF}; + const std::vector code = {0xDE, 0xAD, 0xBE, 0xEF}; auto buf = make_fake_module(0x300, static_cast(code.size()), code); - auto res = PePatternScanner::scan_for_pattern_in_loaded_module(buf.data(), "DE ?? BE"); + const auto res = PePatternScanner::scan_for_pattern_in_loaded_module(buf.data(), "DE ?? BE"); ASSERT_TRUE(res.has_value()); - uintptr_t addr = res.value(); - uintptr_t base = reinterpret_cast(buf.data()); + const uintptr_t addr = res.value(); + const uintptr_t base = reinterpret_cast(buf.data()); EXPECT_EQ(addr - base, 0x300u); } diff --git a/tests/general/unit_test_pe_pattern_scan_more.cpp b/tests/general/unit_test_pe_pattern_scan_more.cpp index f68f9af2..36e8e629 100644 --- a/tests/general/unit_test_pe_pattern_scan_more.cpp +++ b/tests/general/unit_test_pe_pattern_scan_more.cpp @@ -1,73 +1,111 @@ // Additional tests for PePatternScanner to exercise edge cases and loaded-module scanning +#include +#include +#include #include #include -#include #include -#include -#include using namespace omath; -static bool write_bytes(const std::string &path, const std::vector& data) +static bool write_bytes(const std::string& path, const std::vector& data) { std::ofstream f(path, std::ios::binary); - if (!f.is_open()) return false; + if (!f.is_open()) + return false; f.write(reinterpret_cast(data.data()), data.size()); return true; } TEST(unit_test_pe_pattern_scan_more, InvalidDosHeader) { - const std::string path = "./test_bad_dos.bin"; + constexpr std::string_view path = "./test_bad_dos.bin"; std::vector data(128, 0); // write wrong magic - data[0] = 'N'; data[1] = 'Z'; - ASSERT_TRUE(write_bytes(path, data)); + data[0] = 'N'; + data[1] = 'Z'; + ASSERT_TRUE(write_bytes(path.data(), data)); - auto res = PePatternScanner::scan_for_pattern_in_file(path, "55 8B EC", ".text"); + const auto res = PePatternScanner::scan_for_pattern_in_file(path, "55 8B EC", ".text"); EXPECT_FALSE(res.has_value()); } TEST(unit_test_pe_pattern_scan_more, InvalidNtSignature) { - const std::string path = "./test_bad_nt.bin"; + constexpr std::string_view path = "./test_bad_nt.bin"; std::vector data(256, 0); // valid DOS header - data[0] = 'M'; data[1] = 'Z'; + data[0] = 'M'; + data[1] = 'Z'; // point e_lfanew to 0x80 - std::uint32_t e_lfanew = 0x80; - std::memcpy(data.data()+0x3C, &e_lfanew, sizeof(e_lfanew)); + constexpr std::uint32_t e_lfanew = 0x80; + std::memcpy(data.data() + 0x3C, &e_lfanew, sizeof(e_lfanew)); // write garbage at e_lfanew (not 'PE\0\0') - data[e_lfanew + 0] = 'X'; data[e_lfanew + 1] = 'Y'; data[e_lfanew + 2] = 'Z'; data[e_lfanew + 3] = 'W'; - ASSERT_TRUE(write_bytes(path, data)); + data[e_lfanew + 0] = 'X'; + data[e_lfanew + 1] = 'Y'; + data[e_lfanew + 2] = 'Z'; + data[e_lfanew + 3] = 'W'; + ASSERT_TRUE(write_bytes(path.data(), data)); - auto res = PePatternScanner::scan_for_pattern_in_file(path, "55 8B EC", ".text"); + const auto res = PePatternScanner::scan_for_pattern_in_file(path, "55 8B EC", ".text"); EXPECT_FALSE(res.has_value()); } TEST(unit_test_pe_pattern_scan_more, SectionNotFound) { // reuse minimal writer but with section named .data and search .text - const std::string path = "./test_section_not_found.bin"; - std::ofstream f(path, std::ios::binary); + constexpr std::string_view path = "./test_section_not_found.bin"; + std::ofstream f(path.data(), std::ios::binary); ASSERT_TRUE(f.is_open()); // DOS - std::vector dos(64, 0); dos[0]='M'; dos[1]='Z'; std::uint32_t e_lfanew=0x80; std::memcpy(dos.data()+0x3C,&e_lfanew,sizeof(e_lfanew)); f.write(reinterpret_cast(dos.data()), dos.size()); + std::vector dos(64, 0); + dos[0] = 'M'; + dos[1] = 'Z'; + std::uint32_t e_lfanew = 0x80; + std::memcpy(dos.data() + 0x3C, &e_lfanew, sizeof(e_lfanew)); + f.write(reinterpret_cast(dos.data()), dos.size()); // pad - std::vector pad(e_lfanew - static_cast(f.tellp()), 0); f.write(pad.data(), pad.size()); + std::vector pad(e_lfanew - static_cast(f.tellp()), 0); + f.write(pad.data(), pad.size()); // NT sig - f.put('P'); f.put('E'); f.put('\0'); f.put('\0'); + f.put('P'); + f.put('E'); + f.put('\0'); + f.put('\0'); // FileHeader minimal - std::uint16_t machine=0x8664; std::uint16_t num_sections=1; std::uint32_t z=0; std::uint32_t z2=0; std::uint32_t numsym=0; std::uint16_t size_opt=0xF0; std::uint16_t ch=0; - f.write(reinterpret_cast(&machine), sizeof(machine)); f.write(reinterpret_cast(&num_sections), sizeof(num_sections)); f.write(reinterpret_cast(&z), sizeof(z)); f.write(reinterpret_cast(&z2), sizeof(z2)); f.write(reinterpret_cast(&numsym), sizeof(numsym)); f.write(reinterpret_cast(&size_opt), sizeof(size_opt)); f.write(reinterpret_cast(&ch), sizeof(ch)); + std::uint16_t machine = 0x8664; + std::uint16_t num_sections = 1; + std::uint32_t z = 0; + std::uint32_t z2 = 0; + std::uint32_t numsym = 0; + std::uint16_t size_opt = 0xF0; + std::uint16_t ch = 0; + f.write(reinterpret_cast(&machine), sizeof(machine)); + f.write(reinterpret_cast(&num_sections), sizeof(num_sections)); + f.write(reinterpret_cast(&z), sizeof(z)); + f.write(reinterpret_cast(&z2), sizeof(z2)); + f.write(reinterpret_cast(&numsym), sizeof(numsym)); + f.write(reinterpret_cast(&size_opt), sizeof(size_opt)); + f.write(reinterpret_cast(&ch), sizeof(ch)); // Optional header magic - std::uint16_t magic = 0x20b; f.write(reinterpret_cast(&magic), sizeof(magic)); std::vector opt(size_opt - sizeof(magic),0); f.write(reinterpret_cast(opt.data()), opt.size()); + std::uint16_t magic = 0x20b; + f.write(reinterpret_cast(&magic), sizeof(magic)); + std::vector opt(size_opt - sizeof(magic), 0); + f.write(reinterpret_cast(opt.data()), opt.size()); // Section header named .data - char name[8] = {'.','d','a','t','a',0,0,0}; f.write(name,8); - std::uint32_t vs=4, va=0x1000, srd=4, prd=0x200; f.write(reinterpret_cast(&vs),4); f.write(reinterpret_cast(&va),4); f.write(reinterpret_cast(&srd),4); f.write(reinterpret_cast(&prd),4); - std::vector rest(16,0); f.write(rest.data(), rest.size()); + char name[8] = {'.', 'd', 'a', 't', 'a', 0, 0, 0}; + f.write(name, 8); + std::uint32_t vs = 4, va = 0x1000, srd = 4, prd = 0x200; + f.write(reinterpret_cast(&vs), 4); + f.write(reinterpret_cast(&va), 4); + f.write(reinterpret_cast(&srd), 4); + f.write(reinterpret_cast(&prd), 4); + std::vector rest(16, 0); + f.write(rest.data(), rest.size()); // section bytes - std::vector sec={0x00,0x01,0x02,0x03}; f.write(reinterpret_cast(sec.data()), sec.size()); f.close(); + std::vector sec = {0x00, 0x01, 0x02, 0x03}; + f.write(reinterpret_cast(sec.data()), sec.size()); + f.close(); auto res = PePatternScanner::scan_for_pattern_in_file(path, "00 01", ".text"); EXPECT_FALSE(res.has_value()); @@ -77,24 +115,76 @@ TEST(unit_test_pe_pattern_scan_more, LoadedModuleScanFinds) { // Create an in-memory buffer that mimics loaded module layout // Define local header structs matching those in source - struct DosHeader { std::uint16_t e_magic; std::uint16_t e_cblp; std::uint16_t e_cp; std::uint16_t e_crlc; std::uint16_t e_cparhdr; std::uint16_t e_minalloc; std::uint16_t e_maxalloc; std::uint16_t e_ss; std::uint16_t e_sp; std::uint16_t e_csum; std::uint16_t e_ip; std::uint16_t e_cs; std::uint16_t e_lfarlc; std::uint16_t e_ovno; std::uint16_t e_res[4]; std::uint16_t e_oemid; std::uint16_t e_oeminfo; std::uint16_t e_res2[10]; std::uint32_t e_lfanew; }; - struct FileHeader { std::uint16_t machine; std::uint16_t num_sections; std::uint32_t timedate_stamp; std::uint32_t ptr_symbols; std::uint32_t num_symbols; std::uint16_t size_optional_header; std::uint16_t characteristics; }; - struct OptionalHeaderX64 { std::uint16_t magic; std::uint16_t linker_version; std::uint32_t size_code; std::uint32_t size_init_data; std::uint32_t size_uninit_data; std::uint32_t entry_point; std::uint32_t base_of_code; std::uint64_t image_base; std::uint32_t section_alignment; std::uint32_t file_alignment; /* rest omitted */ std::uint32_t size_image; std::uint32_t size_headers; /* keep space */ std::uint8_t pad[200]; }; - struct ImageNtHeadersX64 { std::uint32_t signature; FileHeader file_header; OptionalHeaderX64 optional_header; }; + struct DosHeader + { + std::uint16_t e_magic; + std::uint16_t e_cblp; + std::uint16_t e_cp; + std::uint16_t e_crlc; + std::uint16_t e_cparhdr; + std::uint16_t e_minalloc; + std::uint16_t e_maxalloc; + std::uint16_t e_ss; + std::uint16_t e_sp; + std::uint16_t e_csum; + std::uint16_t e_ip; + std::uint16_t e_cs; + std::uint16_t e_lfarlc; + std::uint16_t e_ovno; + std::uint16_t e_res[4]; + std::uint16_t e_oemid; + std::uint16_t e_oeminfo; + std::uint16_t e_res2[10]; + std::uint32_t e_lfanew; + }; + struct FileHeader + { + std::uint16_t machine; + std::uint16_t num_sections; + std::uint32_t timedate_stamp; + std::uint32_t ptr_symbols; + std::uint32_t num_symbols; + std::uint16_t size_optional_header; + std::uint16_t characteristics; + }; + struct OptionalHeaderX64 + { + std::uint16_t magic; + std::uint16_t linker_version; + std::uint32_t size_code; + std::uint32_t size_init_data; + std::uint32_t size_uninit_data; + std::uint32_t entry_point; + std::uint32_t base_of_code; + std::uint64_t image_base; + std::uint32_t section_alignment; + std::uint32_t file_alignment; /* rest omitted */ + std::uint32_t size_image; + std::uint32_t size_headers; /* keep space */ + std::uint8_t pad[200]; + }; + struct ImageNtHeadersX64 + { + std::uint32_t signature; + FileHeader file_header; + OptionalHeaderX64 optional_header; + }; - const std::vector pattern_bytes = {0xDE,0xAD,0xBE,0xEF,0x90}; - const std::uint32_t base_of_code = 0x200; // will place bytes at offset 0x200 + const std::vector pattern_bytes = {0xDE, 0xAD, 0xBE, 0xEF, 0x90}; + constexpr std::uint32_t base_of_code = 0x200; // will place bytes at offset 0x200 const std::uint32_t size_code = static_cast(pattern_bytes.size()); const std::uint32_t bufsize = 0x400 + size_code; std::vector buf(bufsize, 0); // DOS header - auto dos = reinterpret_cast(buf.data()); - dos->e_magic = 0x5A4D; dos->e_lfanew = 0x80; + const auto dos = reinterpret_cast(buf.data()); + dos->e_magic = 0x5A4D; + dos->e_lfanew = 0x80; // NT headers - auto nt = reinterpret_cast(buf.data() + dos->e_lfanew); + const auto nt = reinterpret_cast(buf.data() + dos->e_lfanew); nt->signature = 0x4550; // 'PE\0\0' - nt->file_header.machine = 0x8664; nt->file_header.num_sections = 1; + nt->file_header.machine = 0x8664; + nt->file_header.num_sections = 1; nt->optional_header.magic = 0x020B; // x64 nt->optional_header.base_of_code = base_of_code; nt->optional_header.size_code = size_code; @@ -102,6 +192,6 @@ TEST(unit_test_pe_pattern_scan_more, LoadedModuleScanFinds) // place code at base_of_code std::memcpy(buf.data() + base_of_code, pattern_bytes.data(), pattern_bytes.size()); - auto res = PePatternScanner::scan_for_pattern_in_loaded_module(buf.data(), "DE AD BE EF"); + const auto res = PePatternScanner::scan_for_pattern_in_loaded_module(buf.data(), "DE AD BE EF"); EXPECT_TRUE(res.has_value()); } diff --git a/tests/general/unit_test_pe_pattern_scan_more2.cpp b/tests/general/unit_test_pe_pattern_scan_more2.cpp index e0763d49..7b4ddeb4 100644 --- a/tests/general/unit_test_pe_pattern_scan_more2.cpp +++ b/tests/general/unit_test_pe_pattern_scan_more2.cpp @@ -1,19 +1,29 @@ +#include +#include +#include #include #include -#include #include -#include -#include using namespace omath; // Local minimal FileHeader used by tests when constructing raw NT headers -struct TestFileHeader { std::uint16_t machine; std::uint16_t num_sections; std::uint32_t timedate_stamp; std::uint32_t ptr_symbols; std::uint32_t num_symbols; std::uint16_t size_optional_header; std::uint16_t characteristics; }; - -static bool write_bytes(const std::string &path, const std::vector& data) +struct TestFileHeader +{ + std::uint16_t machine; + std::uint16_t num_sections; + std::uint32_t timedate_stamp; + std::uint32_t ptr_symbols; + std::uint32_t num_symbols; + std::uint16_t size_optional_header; + std::uint16_t characteristics; +}; + +static bool write_bytes(const std::string& path, const std::vector& data) { std::ofstream f(path, std::ios::binary); - if (!f.is_open()) return false; + if (!f.is_open()) + return false; f.write(reinterpret_cast(data.data()), data.size()); return true; } @@ -22,11 +32,13 @@ static bool write_bytes(const std::string &path, const std::vector static bool write_minimal_pe_file(const std::string& path, const std::vector& section_bytes) { std::ofstream f(path, std::ios::binary); - if (!f.is_open()) return false; + if (!f.is_open()) + return false; // Write DOS header (e_magic = 0x5A4D, e_lfanew at offset 0x3C) std::vector dos(64, 0); - dos[0] = 'M'; dos[1] = 'Z'; + dos[0] = 'M'; + dos[1] = 'Z'; std::uint32_t e_lfanew = 0x80; std::memcpy(dos.data() + 0x3C, &e_lfanew, sizeof(e_lfanew)); f.write(reinterpret_cast(dos.data()), dos.size()); @@ -39,7 +51,10 @@ static bool write_minimal_pe_file(const std::string& path, const std::vector(opt.data()), opt.size()); // Section header (name 8 bytes, then remaining 36 bytes) - char name[8] = {'.','t','e','x','t',0,0,0}; + char name[8] = {'.', 't', 'e', 'x', 't', 0, 0, 0}; f.write(name, 8); - const std::uint32_t section_header_rest = 36u; + constexpr std::uint32_t section_header_rest = 36u; const std::streampos header_rest_pos = f.tellp(); std::vector placeholder(section_header_rest, 0); f.write(placeholder.data(), placeholder.size()); @@ -78,7 +93,7 @@ static bool write_minimal_pe_file(const std::string& path, const std::vector(section_bytes.size()); - const std::uint32_t virtual_address = 0x1000u; + constexpr std::uint32_t virtual_address = 0x1000u; const std::uint32_t size_raw_data = static_cast(section_bytes.size()); const std::uint32_t ptr_raw_data = static_cast(data_pos); @@ -95,7 +110,7 @@ static bool write_minimal_pe_file(const std::string& path, const std::vector buf(0x200, 0); - struct DosHeader { std::uint16_t e_magic; std::uint8_t pad[0x3A]; std::uint32_t e_lfanew; }; - auto dos = reinterpret_cast(buf.data()); - dos->e_magic = 0x5A4D; dos->e_lfanew = 0x80; + struct DosHeader + { + std::uint16_t e_magic; + std::uint8_t pad[0x3A]; + std::uint32_t e_lfanew; + }; + const auto dos = reinterpret_cast(buf.data()); + dos->e_magic = 0x5A4D; + dos->e_lfanew = 0x80; // Place an NT header with wrong optional magic at e_lfanew - auto nt_ptr = buf.data() + dos->e_lfanew; + const auto nt_ptr = buf.data() + dos->e_lfanew; // write signature - nt_ptr[0] = 'P'; nt_ptr[1] = 'E'; nt_ptr[2] = 0; nt_ptr[3] = 0; + nt_ptr[0] = 'P'; + nt_ptr[1] = 'E'; + nt_ptr[2] = 0; + nt_ptr[3] = 0; // craft FileHeader with size_optional_header large enough - std::uint16_t size_opt = 0xE0; + constexpr std::uint16_t size_opt = 0xE0; // file header starts at offset 4 - std::memcpy(nt_ptr + 4 + 12, &size_opt, sizeof(size_opt)); // size_optional_header located after 12 bytes into FileHeader + std::memcpy(nt_ptr + 4 + 12, &size_opt, + sizeof(size_opt)); // size_optional_header located after 12 bytes into FileHeader // write optional header magic to be invalid value - std::uint16_t bad_magic = 0x9999; - std::memcpy(nt_ptr + 4 + sizeof(std::uint32_t) + sizeof(std::uint16_t) + sizeof(std::uint16_t), &bad_magic, sizeof(bad_magic)); + constexpr std::uint16_t bad_magic = 0x9999; + std::memcpy(nt_ptr + 4 + sizeof(std::uint32_t) + sizeof(std::uint16_t) + sizeof(std::uint16_t), &bad_magic, + sizeof(bad_magic)); - auto res = PePatternScanner::scan_for_pattern_in_loaded_module(buf.data(), "DE AD"); + const auto res = PePatternScanner::scan_for_pattern_in_loaded_module(buf.data(), "DE AD"); EXPECT_FALSE(res.has_value()); } TEST(unit_test_pe_pattern_scan_more2, FileX86OptionalHeaderScanFindsPattern) { - const std::string path = "./test_pe_x86.bin"; + constexpr std::string_view path = "./test_pe_x86.bin"; const std::vector pattern = {0xDE, 0xAD, 0xBE, 0xEF}; // Use helper from this file to write a consistent minimal PE file with .text section - ASSERT_TRUE(write_minimal_pe_file(path, pattern)); + ASSERT_TRUE(write_minimal_pe_file(path.data(), pattern)); - auto res = PePatternScanner::scan_for_pattern_in_file(path, "DE AD BE EF", ".text"); + const auto res = PePatternScanner::scan_for_pattern_in_file(path, "DE AD BE EF", ".text"); ASSERT_TRUE(res.has_value()); EXPECT_GE(res->virtual_base_addr, 0u); EXPECT_GE(res->raw_base_addr, 0u); @@ -143,21 +169,36 @@ TEST(unit_test_pe_pattern_scan_more2, FilePatternNotFoundReturnsNull) const std::string path = "./test_pe_no_pattern.bin"; std::vector data(512, 0); // minimal DOS/NT headers to make extract_section fail earlier or return empty data - data[0] = 'M'; data[1] = 'Z'; std::uint32_t e_lfanew = 0x80; std::memcpy(data.data()+0x3C, &e_lfanew, sizeof(e_lfanew)); + data[0] = 'M'; + data[1] = 'Z'; + constexpr std::uint32_t e_lfanew = 0x80; + std::memcpy(data.data() + 0x3C, &e_lfanew, sizeof(e_lfanew)); // NT signature - data[e_lfanew + 0] = 'P'; data[e_lfanew + 1] = 'E'; data[e_lfanew + 2] = 0; data[e_lfanew + 3] = 0; + data[e_lfanew + 0] = 'P'; + data[e_lfanew + 1] = 'E'; + data[e_lfanew + 2] = 0; + data[e_lfanew + 3] = 0; // FileHeader: one section, size_optional_header set low - std::uint16_t num_sections = 1; std::uint16_t size_optional_header = 0xE0; std::memcpy(data.data() + e_lfanew + 6, &num_sections, sizeof(num_sections)); std::memcpy(data.data() + e_lfanew + 4 + 12, &size_optional_header, sizeof(size_optional_header)); + constexpr std::uint16_t num_sections = 1; + constexpr std::uint16_t size_optional_header = 0xE0; + std::memcpy(data.data() + e_lfanew + 6, &num_sections, sizeof(num_sections)); + std::memcpy(data.data() + e_lfanew + 4 + 12, &size_optional_header, sizeof(size_optional_header)); // Optional header magic x64 - std::uint16_t magic = 0x020B; std::memcpy(data.data() + e_lfanew + 4 + sizeof(TestFileHeader), &magic, sizeof(magic)); + constexpr std::uint16_t magic = 0x020B; + std::memcpy(data.data() + e_lfanew + 4 + sizeof(TestFileHeader), &magic, sizeof(magic)); // Section header .text with small data that does not contain the pattern - const std::size_t offset_to_segment_table = e_lfanew + 4 + sizeof(TestFileHeader) + size_optional_header; - const char name[8] = {'.','t','e','x','t',0,0,0}; std::memcpy(data.data() + offset_to_segment_table, name, 8); - std::uint32_t vs = 4, va = 0x1000, srd = 4, prd = 0x200; std::memcpy(data.data() + offset_to_segment_table + 8, &vs, 4); std::memcpy(data.data() + offset_to_segment_table + 12, &va, 4); std::memcpy(data.data() + offset_to_segment_table + 16, &srd, 4); std::memcpy(data.data() + offset_to_segment_table + 20, &prd, 4); + constexpr std::size_t offset_to_segment_table = e_lfanew + 4 + sizeof(TestFileHeader) + size_optional_header; + constexpr char name[8] = {'.', 't', 'e', 'x', 't', 0, 0, 0}; + std::memcpy(data.data() + offset_to_segment_table, name, 8); + std::uint32_t vs = 4, va = 0x1000, srd = 4, prd = 0x200; + std::memcpy(data.data() + offset_to_segment_table + 8, &vs, 4); + std::memcpy(data.data() + offset_to_segment_table + 12, &va, 4); + std::memcpy(data.data() + offset_to_segment_table + 16, &srd, 4); + std::memcpy(data.data() + offset_to_segment_table + 20, &prd, 4); // write file ASSERT_TRUE(write_bytes(path, data)); - auto res = PePatternScanner::scan_for_pattern_in_file(path, "AA BB CC", ".text"); + const auto res = PePatternScanner::scan_for_pattern_in_file(path, "AA BB CC", ".text"); EXPECT_FALSE(res.has_value()); } // Extra tests for pe_pattern_scan edge cases (on-disk API) @@ -165,7 +206,7 @@ TEST(unit_test_pe_pattern_scan_more2, FilePatternNotFoundReturnsNull) TEST(PePatternScanMore2, PatternAtStartFound) { const std::string path = "./test_pe_more_start.bin"; - std::vector bytes = {0x90, 0x01, 0x02, 0x03, 0x04}; + const std::vector bytes = {0x90, 0x01, 0x02, 0x03, 0x04}; ASSERT_TRUE(write_minimal_pe_file(path, bytes)); const auto res = PePatternScanner::scan_for_pattern_in_file(path, "90 01 02", ".text"); @@ -187,7 +228,7 @@ TEST(PePatternScanMore2, PatternAtEndFound) // search for ".text" name in.seekg(0, std::ios::beg); std::vector filebuf((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - const auto it = std::search(filebuf.begin(), filebuf.end(), std::begin(".text"), std::end(".text")-1); + const auto it = std::search(filebuf.begin(), filebuf.end(), std::begin(".text"), std::end(".text") - 1); if (it != filebuf.end()) { const size_t pos = std::distance(filebuf.begin(), it); @@ -197,12 +238,14 @@ TEST(PePatternScanMore2, PatternAtEndFound) uint32_t virtual_address{}; uint32_t size_raw_data{}; uint32_t ptr_raw_data{}; - std::memcpy(&virtual_size, filebuf.data()+meta_off, sizeof(virtual_size)); - std::memcpy(&virtual_address, filebuf.data()+meta_off+4, sizeof(virtual_address)); - std::memcpy(&size_raw_data, filebuf.data()+meta_off+8, sizeof(size_raw_data)); - std::memcpy(&ptr_raw_data, filebuf.data()+meta_off+12, sizeof(ptr_raw_data)); + std::memcpy(&virtual_size, filebuf.data() + meta_off, sizeof(virtual_size)); + std::memcpy(&virtual_address, filebuf.data() + meta_off + 4, sizeof(virtual_address)); + std::memcpy(&size_raw_data, filebuf.data() + meta_off + 8, sizeof(size_raw_data)); + std::memcpy(&ptr_raw_data, filebuf.data() + meta_off + 12, sizeof(ptr_raw_data)); - std::cerr << "Parsed section header: virtual_size=" << virtual_size << " virtual_address=0x" << std::hex << virtual_address << std::dec << " size_raw_data=" << size_raw_data << " ptr_raw_data=" << ptr_raw_data << "\n"; + std::cerr << "Parsed section header: virtual_size=" << virtual_size << " virtual_address=0x" << std::hex + << virtual_address << std::dec << " size_raw_data=" << size_raw_data + << " ptr_raw_data=" << ptr_raw_data << "\n"; if (ptr_raw_data + size_raw_data <= filebuf.size()) { @@ -223,7 +266,7 @@ TEST(PePatternScanMore2, PatternAtEndFound) TEST(PePatternScanMore2, WildcardMatches) { const std::string path = "./test_pe_more_wild.bin"; - std::vector bytes = {0xDE, 0xAD, 0xBE, 0xEF}; + const std::vector bytes = {0xDE, 0xAD, 0xBE, 0xEF}; ASSERT_TRUE(write_minimal_pe_file(path, bytes)); const auto res = PePatternScanner::scan_for_pattern_in_file(path, "DE ?? BE", ".text"); @@ -233,7 +276,7 @@ TEST(PePatternScanMore2, WildcardMatches) TEST(PePatternScanMore2, PatternLongerThanBuffer) { const std::string path = "./test_pe_more_small.bin"; - std::vector bytes = {0xAA, 0xBB}; + const std::vector bytes = {0xAA, 0xBB}; ASSERT_TRUE(write_minimal_pe_file(path, bytes)); const auto res = PePatternScanner::scan_for_pattern_in_file(path, "AA BB CC", ".text"); @@ -243,10 +286,9 @@ TEST(PePatternScanMore2, PatternLongerThanBuffer) TEST(PePatternScanMore2, InvalidPatternParse) { const std::string path = "./test_pe_more_invalid.bin"; - std::vector bytes = {0x01, 0x02, 0x03}; + const std::vector bytes = {0x01, 0x02, 0x03}; ASSERT_TRUE(write_minimal_pe_file(path, bytes)); const auto res = PePatternScanner::scan_for_pattern_in_file(path, "01 GG 03", ".text"); EXPECT_FALSE(res.has_value()); } - diff --git a/tests/general/unit_test_pred_engine_trait.cpp b/tests/general/unit_test_pred_engine_trait.cpp index 88e91ea5..8ea766b7 100644 --- a/tests/general/unit_test_pred_engine_trait.cpp +++ b/tests/general/unit_test_pred_engine_trait.cpp @@ -14,7 +14,8 @@ TEST(PredEngineTrait, PredictProjectilePositionBasic) p.m_launch_speed = 10.f; p.m_gravity_scale = 1.f; - auto pos = PredEngineTrait::predict_projectile_position(p, /*pitch*/0.f, /*yaw*/0.f, /*time*/1.f, /*gravity*/9.81f); + const auto pos = PredEngineTrait::predict_projectile_position(p, /*pitch*/ 0.f, /*yaw*/ 0.f, /*time*/ 1.f, + /*gravity*/ 9.81f); // With zero pitch and yaw forward vector is along X; expect x ~10, z reduced by gravity*0.5 EXPECT_NEAR(pos.x, 10.f, 1e-3f); EXPECT_NEAR(pos.z, -9.81f * 0.5f, 1e-3f); @@ -23,11 +24,11 @@ TEST(PredEngineTrait, PredictProjectilePositionBasic) TEST(PredEngineTrait, PredictTargetPositionAirborne) { projectile_prediction::Target t; - t.m_origin = {0.f,0.f,10.f}; - t.m_velocity = {1.f,0.f,0.f}; + t.m_origin = {0.f, 0.f, 10.f}; + t.m_velocity = {1.f, 0.f, 0.f}; t.m_is_airborne = true; - auto pred = PredEngineTrait::predict_target_position(t, 2.f, 9.81f); + const auto pred = PredEngineTrait::predict_target_position(t, 2.f, 9.81f); EXPECT_NEAR(pred.x, 2.f, 1e-6f); // z should have been reduced by gravity* t^2 EXPECT_NEAR(pred.z, 10.f - 9.81f * 4.f * 0.5f, 1e-6f); @@ -35,30 +36,31 @@ TEST(PredEngineTrait, PredictTargetPositionAirborne) TEST(PredEngineTrait, CalcVector2dDistance) { - Vector3 d{3.f,4.f,0.f}; + constexpr Vector3 d{3.f, 4.f, 0.f}; EXPECT_NEAR(PredEngineTrait::calc_vector_2d_distance(d), 5.f, 1e-6f); } TEST(PredEngineTrait, CalcViewpointFromAngles) { projectile_prediction::Projectile p; - p.m_origin = {0.f,0.f,0.f}; + p.m_origin = {0.f, 0.f, 0.f}; p.m_launch_speed = 10.f; - Vector3 predicted{10.f, 0.f, 0.f}; - std::optional pitch = 45.f; - auto vp = PredEngineTrait::calc_viewpoint_from_angles(p, predicted, pitch); + constexpr Vector3 predicted{10.f, 0.f, 0.f}; + constexpr std::optional pitch = 45.f; + const auto vp = PredEngineTrait::calc_viewpoint_from_angles(p, predicted, pitch); // For 45 degrees, height = delta2d * tan(45deg) = 10 * 1 = 10 EXPECT_NEAR(vp.z, 10.f, 1e-6f); } TEST(PredEngineTrait, DirectAngles) { - Vector3 origin{0.f,0.f,0.f}; - Vector3 target{0.f,1.f,1.f}; + constexpr Vector3 origin{0.f, 0.f, 0.f}; + constexpr Vector3 target{0.f, 1.f, 1.f}; // yaw should be 90 degrees (pointing along y) EXPECT_NEAR(PredEngineTrait::calc_direct_yaw_angle(origin, target), 90.f, 1e-3f); // pitch should be asin(z/distance) const float dist = origin.distance_to(target); - EXPECT_NEAR(PredEngineTrait::calc_direct_pitch_angle(origin, target), angles::radians_to_degrees(std::asin((target.z-origin.z)/dist)), 1e-3f); + EXPECT_NEAR(PredEngineTrait::calc_direct_pitch_angle(origin, target), + angles::radians_to_degrees(std::asin((target.z - origin.z) / dist)), 1e-3f); } diff --git a/tests/general/unit_test_proj_pred_engine_legacy_more.cpp b/tests/general/unit_test_proj_pred_engine_legacy_more.cpp index 1b909819..26080b42 100644 --- a/tests/general/unit_test_proj_pred_engine_legacy_more.cpp +++ b/tests/general/unit_test_proj_pred_engine_legacy_more.cpp @@ -32,11 +32,11 @@ struct FakeEngineZeroGravity TEST(ProjPredLegacyMore, ZeroGravityUsesDirectPitchAndReturnsViewpoint) { - Projectile proj{ .m_origin = {0.f, 0.f, 0.f}, .m_launch_speed = 10.f, .m_gravity_scale = 0.f }; - Target target{ .m_origin = {100.f, 0.f, 0.f}, .m_velocity = {0.f,0.f,0.f}, .m_is_airborne = false }; + constexpr Projectile proj{ .m_origin = {0.f, 0.f, 0.f}, .m_launch_speed = 10.f, .m_gravity_scale = 0.f }; + constexpr Target target{ .m_origin = {100.f, 0.f, 0.f}, .m_velocity = {0.f,0.f,0.f}, .m_is_airborne = false }; using Engine = omath::projectile_prediction::ProjPredEngineLegacy; - Engine engine(9.8f, 0.1f, 5.f, 1e-3f); + const Engine engine(9.8f, 0.1f, 5.f, 1e-3f); const auto res = engine.maybe_calculate_aim_point(proj, target); ASSERT_TRUE(res.has_value()); @@ -61,11 +61,11 @@ struct FakeEngineNoSolution TEST(ProjPredLegacyMore, NoSolutionRootReturnsNullopt) { // Very slow projectile and large distance -> quadratic root negative - Projectile proj{ .m_origin = {0.f,0.f,0.f}, .m_launch_speed = 1.f, .m_gravity_scale = 1.f }; - Target target{ .m_origin = {10000.f, 0.f, 0.f}, .m_velocity = {0.f,0.f,0.f}, .m_is_airborne = false }; + constexpr Projectile proj{ .m_origin = {0.f,0.f,0.f}, .m_launch_speed = 1.f, .m_gravity_scale = 1.f }; + constexpr Target target{ .m_origin = {10000.f, 0.f, 0.f}, .m_velocity = {0.f,0.f,0.f}, .m_is_airborne = false }; using Engine = omath::projectile_prediction::ProjPredEngineLegacy; - Engine engine(9.8f, 0.5f, 2.f, 1.f); + const Engine engine(9.8f, 0.5f, 2.f, 1.f); const auto res = engine.maybe_calculate_aim_point(proj, target); EXPECT_FALSE(res.has_value()); @@ -89,11 +89,11 @@ struct FakeEngineAngleButMiss TEST(ProjPredLegacyMore, AngleComputedButMissReturnsNullopt) { - Projectile proj{ .m_origin = {0.f,0.f,0.f}, .m_launch_speed = 100.f, .m_gravity_scale = 1.f }; - Target target{ .m_origin = {10.f, 0.f, 0.f}, .m_velocity = {0.f,0.f,0.f}, .m_is_airborne = false }; + constexpr Projectile proj{ .m_origin = {0.f,0.f,0.f}, .m_launch_speed = 100.f, .m_gravity_scale = 1.f }; + constexpr Target target{ .m_origin = {10.f, 0.f, 0.f}, .m_velocity = {0.f,0.f,0.f}, .m_is_airborne = false }; using Engine = omath::projectile_prediction::ProjPredEngineLegacy; - Engine engine(9.8f, 0.1f, 1.f, 0.1f); + const Engine engine(9.8f, 0.1f, 1.f, 0.1f); const auto res = engine.maybe_calculate_aim_point(proj, target); EXPECT_FALSE(res.has_value()); diff --git a/tests/general/unit_test_simplex_more.cpp b/tests/general/unit_test_simplex_more.cpp index b0f838a3..f70ac852 100644 --- a/tests/general/unit_test_simplex_more.cpp +++ b/tests/general/unit_test_simplex_more.cpp @@ -23,7 +23,7 @@ TEST(SimplexExtra, HandleLine_CollinearProducesPerp) EXPECT_TRUE(std::isfinite(dir.x)); EXPECT_TRUE(std::isfinite(dir.y)); EXPECT_TRUE(std::isfinite(dir.z)); - auto zero = Vector3{0.f, 0.f, 0.f}; + constexpr auto zero = Vector3{0.f, 0.f, 0.f}; EXPECT_FALSE(dir == zero); // Ensure direction is (approximately) perpendicular to ab @@ -89,23 +89,23 @@ TEST(SimplexExtra, HandleTetrahedron_InsideReturnsTrue) TEST(SimplexMore, PushFrontAndAccess) { omath::collision::Simplex> s; - s.push_front(omath::Vector3{1.f,0.f,0.f}); - s.push_front(omath::Vector3{2.f,0.f,0.f}); - s.push_front(omath::Vector3{3.f,0.f,0.f}); + s.push_front(omath::Vector3{1.f, 0.f, 0.f}); + s.push_front(omath::Vector3{2.f, 0.f, 0.f}); + s.push_front(omath::Vector3{3.f, 0.f, 0.f}); EXPECT_EQ(s.size(), 3u); - omath::Vector3 exp_front{3.f,0.f,0.f}; - omath::Vector3 exp_back{1.f,0.f,0.f}; + constexpr omath::Vector3 exp_front{3.f, 0.f, 0.f}; + constexpr omath::Vector3 exp_back{1.f, 0.f, 0.f}; EXPECT_TRUE(s.front() == exp_front); EXPECT_TRUE(s.back() == exp_back); - auto d = s.data(); + const auto d = s.data(); EXPECT_TRUE(d[0] == exp_front); } TEST(SimplexMore, ClearAndEmpty) { omath::collision::Simplex> s; - s.push_front(omath::Vector3{1.f,1.f,1.f}); + s.push_front(omath::Vector3{1.f, 1.f, 1.f}); EXPECT_FALSE(s.empty()); s.clear(); EXPECT_TRUE(s.empty()); @@ -114,8 +114,8 @@ TEST(SimplexMore, ClearAndEmpty) TEST(SimplexMore, HandleLineCollinearProducesPerp) { omath::collision::Simplex> s; - s = { omath::Vector3{2.f,0.f,0.f}, omath::Vector3{1.f,0.f,0.f} }; - omath::Vector3 dir{0.f,0.f,0.f}; + s = {omath::Vector3{2.f, 0.f, 0.f}, omath::Vector3{1.f, 0.f, 0.f}}; + omath::Vector3 dir{0.f, 0.f, 0.f}; const bool res = s.handle(dir); EXPECT_FALSE(res); EXPECT_GT(dir.length_sqr(), 0.0f); @@ -123,15 +123,15 @@ TEST(SimplexMore, HandleLineCollinearProducesPerp) TEST(SimplexMore, HandleTriangleFlipWinding) { - const omath::Vector3 a{1.f,0.f,0.f}; - const omath::Vector3 b{0.f,1.f,0.f}; - const omath::Vector3 c{0.f,0.f,1.f}; + constexpr omath::Vector3 a{1.f, 0.f, 0.f}; + constexpr omath::Vector3 b{0.f, 1.f, 0.f}; + constexpr omath::Vector3 c{0.f, 0.f, 1.f}; omath::collision::Simplex> s; - s = { a, b, c }; - omath::Vector3 dir{0.f,0.f,0.f}; + s = {a, b, c}; + omath::Vector3 dir{0.f, 0.f, 0.f}; - const auto ab = b - a; - const auto ac = c - a; + constexpr auto ab = b - a; + constexpr auto ac = c - a; const auto abc = ab.cross(ac); const bool res = s.handle(dir); @@ -145,8 +145,9 @@ TEST(SimplexMore, HandleTriangleFlipWinding) TEST(SimplexMore, HandleTetrahedronInsideTrue) { omath::collision::Simplex> s; - s = { omath::Vector3{1.f,0.f,0.f}, omath::Vector3{0.f,1.f,0.f}, omath::Vector3{0.f,0.f,1.f}, omath::Vector3{-1.f,-1.f,-1.f} }; - omath::Vector3 dir{0.f,0.f,0.f}; + s = {omath::Vector3{1.f, 0.f, 0.f}, omath::Vector3{0.f, 1.f, 0.f}, + omath::Vector3{0.f, 0.f, 1.f}, omath::Vector3{-1.f, -1.f, -1.f}}; + omath::Vector3 dir{0.f, 0.f, 0.f}; const bool inside = s.handle(dir); EXPECT_TRUE(inside); } @@ -154,8 +155,8 @@ TEST(SimplexMore, HandleTetrahedronInsideTrue) TEST(SimplexMore, HandlePointSetsDirection) { omath::collision::Simplex> s; - s = { omath::Vector3{1.f,2.f,3.f} }; - omath::Vector3 dir{0.f,0.f,0.f}; + s = {omath::Vector3{1.f, 2.f, 3.f}}; + omath::Vector3 dir{0.f, 0.f, 0.f}; EXPECT_FALSE(s.handle(dir)); EXPECT_NEAR(dir.x, -1.f, 1e-6f); EXPECT_NEAR(dir.y, -2.f, 1e-6f); @@ -165,8 +166,8 @@ TEST(SimplexMore, HandlePointSetsDirection) TEST(SimplexMore, HandleLineReducesToPointWhenAoOpposite) { omath::collision::Simplex> s; - s = { omath::Vector3{1.f,0.f,0.f}, omath::Vector3{2.f,0.f,0.f} }; - omath::Vector3 dir{0.f,0.f,0.f}; + s = {omath::Vector3{1.f, 0.f, 0.f}, omath::Vector3{2.f, 0.f, 0.f}}; + omath::Vector3 dir{0.f, 0.f, 0.f}; EXPECT_FALSE(s.handle(dir)); EXPECT_EQ(s.size(), 1u); EXPECT_NEAR(dir.x, -1.f, 1e-6f); diff --git a/tests/general/unit_test_triangle.cpp b/tests/general/unit_test_triangle.cpp index a4e4b912..f972a8a5 100644 --- a/tests/general/unit_test_triangle.cpp +++ b/tests/general/unit_test_triangle.cpp @@ -99,15 +99,15 @@ TEST_F(UnitTestTriangle, SideLengths) // Test side vectors TEST_F(UnitTestTriangle, SideVectors) { - const Vector3 sideA_t1 = t1.side_a_vector(); // m_vertex1 - m_vertex2 - EXPECT_FLOAT_EQ(sideA_t1.x, 0.0f - 1.0f); - EXPECT_FLOAT_EQ(sideA_t1.y, 0.0f - 0.0f); - EXPECT_FLOAT_EQ(sideA_t1.z, 0.0f - 0.0f); - - const Vector3 sideB_t1 = t1.side_b_vector(); // m_vertex3 - m_vertex2 - EXPECT_FLOAT_EQ(sideB_t1.x, 0.0f - 1.0f); - EXPECT_FLOAT_EQ(sideB_t1.y, 1.0f - 0.0f); - EXPECT_FLOAT_EQ(sideB_t1.z, 0.0f - 0.0f); + const Vector3 side_a_t1 = t1.side_a_vector(); // m_vertex1 - m_vertex2 + EXPECT_FLOAT_EQ(side_a_t1.x, 0.0f - 1.0f); + EXPECT_FLOAT_EQ(side_a_t1.y, 0.0f - 0.0f); + EXPECT_FLOAT_EQ(side_a_t1.z, 0.0f - 0.0f); + + const Vector3 side_b_t1 = t1.side_b_vector(); // m_vertex3 - m_vertex2 + EXPECT_FLOAT_EQ(side_b_t1.x, 0.0f - 1.0f); + EXPECT_FLOAT_EQ(side_b_t1.y, 1.0f - 0.0f); + EXPECT_FLOAT_EQ(side_b_t1.z, 0.0f - 0.0f); } TEST_F(UnitTestTriangle, IsRectangular) diff --git a/tests/general/unit_test_vector2.cpp b/tests/general/unit_test_vector2.cpp index a8f641d7..1aeb7cdf 100644 --- a/tests/general/unit_test_vector2.cpp +++ b/tests/general/unit_test_vector2.cpp @@ -306,7 +306,7 @@ TEST_F(UnitTestVector2, DivisionAssignmentOperator_VectorWithZero) // Test operations with infinity and NaN TEST_F(UnitTestVector2, Operator_WithInfinity) { - constexpr Vector2 v_inf(INFINITY, INFINITY); + const Vector2 v_inf(INFINITY, INFINITY); const Vector2 result = v1 + v_inf; EXPECT_TRUE(std::isinf(result.x)); EXPECT_TRUE(std::isinf(result.y)); diff --git a/tests/general/unit_test_vector3.cpp b/tests/general/unit_test_vector3.cpp index 7b5119cd..492033b8 100644 --- a/tests/general/unit_test_vector3.cpp +++ b/tests/general/unit_test_vector3.cpp @@ -12,55 +12,55 @@ using namespace omath; TEST(Vector3More, ConstructorsAndEquality) { - Vector3 a; + constexpr Vector3 a; EXPECT_EQ(a.x, 0.f); EXPECT_EQ(a.y, 0.f); EXPECT_EQ(a.z, 0.f); - Vector3 b{1.f, 2.f, 3.f}; + constexpr Vector3 b{1.f, 2.f, 3.f}; EXPECT_EQ(b.x, 1.f); EXPECT_EQ(b.y, 2.f); EXPECT_EQ(b.z, 3.f); - Vector3 c = b; + const Vector3 c = b; EXPECT_EQ(c, b); } TEST(Vector3More, ArithmeticAndDotCross) { - Vector3 a{1.f, 0.f, 0.f}; - Vector3 b{0.f, 1.f, 0.f}; - auto c = a + b; - const Vector3 expect_c{1.f,1.f,0.f}; + constexpr Vector3 a{1.f, 0.f, 0.f}; + constexpr Vector3 b{0.f, 1.f, 0.f}; + const auto c = a + b; + constexpr Vector3 expect_c{1.f,1.f,0.f}; EXPECT_EQ(c, expect_c); - auto d = a - b; - const Vector3 expect_d{1.f,-1.f,0.f}; + const auto d = a - b; + constexpr Vector3 expect_d{1.f,-1.f,0.f}; EXPECT_EQ(d, expect_d); - auto e = a * 2.f; - const Vector3 expect_e{2.f,0.f,0.f}; + const auto e = a * 2.f; + constexpr Vector3 expect_e{2.f,0.f,0.f}; EXPECT_EQ(e, expect_e); EXPECT_FLOAT_EQ(a.dot(b), 0.f); // manual cross product check - auto cr = Vector3{ a.y * b.z - a.z * b.y, + const auto cr = Vector3{ a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x }; - const Vector3 expect_cr{0.f,0.f,1.f}; + constexpr Vector3 expect_cr{0.f,0.f,1.f}; EXPECT_EQ(cr, expect_cr); } TEST(Vector3More, NormalizationEdgeCases) { - Vector3 z{0.0,0.0,0.0}; - auto zn = z.normalized(); + constexpr Vector3 z{0.0,0.0,0.0}; + const auto zn = z.normalized(); EXPECT_DOUBLE_EQ(zn.x, 0.0); EXPECT_DOUBLE_EQ(zn.y, 0.0); EXPECT_DOUBLE_EQ(zn.z, 0.0); - Vector3 v{3.0,4.0,0.0}; - auto vn = v.normalized(); + constexpr Vector3 v{3.0,4.0,0.0}; + const auto vn = v.normalized(); EXPECT_NEAR(vn.x, 0.6, 1e-12); EXPECT_NEAR(vn.y, 0.8, 1e-12); } @@ -315,7 +315,7 @@ TEST_F(UnitTestVector3, Division_ByZeroScalar) // Test operations with infinity TEST_F(UnitTestVector3, Addition_WithInfinity) { - constexpr Vector3 v_inf(INFINITY, INFINITY, INFINITY); + const Vector3 v_inf(INFINITY, INFINITY, INFINITY); const Vector3 result = v1 + v_inf; EXPECT_TRUE(std::isinf(result.x)); EXPECT_TRUE(std::isinf(result.y)); diff --git a/tests/general/unit_test_vector4.cpp b/tests/general/unit_test_vector4.cpp index 0ada7059..ad777a77 100644 --- a/tests/general/unit_test_vector4.cpp +++ b/tests/general/unit_test_vector4.cpp @@ -13,7 +13,7 @@ using namespace omath; TEST(Vector4More, ConstructorsAndClamp) { - Vector4 a; + constexpr Vector4 a; EXPECT_EQ(a.x, 0.f); EXPECT_EQ(a.y, 0.f); EXPECT_EQ(a.z, 0.f); @@ -28,8 +28,8 @@ TEST(Vector4More, ConstructorsAndClamp) TEST(Vector4More, ComparisonsAndHashFormatter) { - Vector4 a{1,2,3,4}; - Vector4 b{1,2,3,5}; + constexpr Vector4 a{1,2,3,4}; + constexpr Vector4 b{1,2,3,5}; EXPECT_NE(a, b); // exercise to_string via formatting if available by converting via std::format