From b63e9448309b8abfcb7a39ca88fede06eab3d618 Mon Sep 17 00:00:00 2001 From: "opencode[bot]" Date: Sun, 3 May 2026 13:22:44 +0000 Subject: [PATCH 1/2] test: add voxel and mat4 tests for engine/math --- modules/engine-math/src/root.zig | 1 + modules/engine-math/src/voxel_tests.zig | 95 +++++++++++++++++++++++++ src/tests.zig | 1 + 3 files changed, 97 insertions(+) create mode 100644 modules/engine-math/src/voxel_tests.zig diff --git a/modules/engine-math/src/root.zig b/modules/engine-math/src/root.zig index 265319ce..ad642c65 100644 --- a/modules/engine-math/src/root.zig +++ b/modules/engine-math/src/root.zig @@ -15,3 +15,4 @@ pub const utils = @import("utils.zig"); pub const frustum_tests = @import("frustum_tests.zig"); pub const mat4_tests = @import("mat4_tests.zig"); pub const utils_tests = @import("utils_tests.zig"); +pub const voxel_tests = @import("voxel_tests.zig"); diff --git a/modules/engine-math/src/voxel_tests.zig b/modules/engine-math/src/voxel_tests.zig new file mode 100644 index 00000000..36fbf331 --- /dev/null +++ b/modules/engine-math/src/voxel_tests.zig @@ -0,0 +1,95 @@ +const std = @import("std"); +const testing = std.testing; +const voxel = @import("voxel.zig"); +const Face = voxel.Face; + +test "Face.getShade returns correct values per face" { + try testing.expectApproxEqAbs(@as(f32, 1.0), Face.top.getShade(), 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0.5), Face.bottom.getShade(), 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0.8), Face.north.getShade(), 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0.8), Face.south.getShade(), 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0.7), Face.east.getShade(), 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0.7), Face.west.getShade(), 0.0001); +} + +test "Face.getNormal returns correct normals" { + try testing.expectEqual([3]i8{ 0, 1, 0 }, Face.top.getNormal()); + try testing.expectEqual([3]i8{ 0, -1, 0 }, Face.bottom.getNormal()); + try testing.expectEqual([3]i8{ 0, 0, -1 }, Face.north.getNormal()); + try testing.expectEqual([3]i8{ 0, 0, 1 }, Face.south.getNormal()); + try testing.expectEqual([3]i8{ 1, 0, 0 }, Face.east.getNormal()); + try testing.expectEqual([3]i8{ -1, 0, 0 }, Face.west.getNormal()); +} + +test "Face.getOffset returns integer offsets matching normals" { + try testing.expectEqual(Face.top.getOffset(), .{ .x = 0, .y = 1, .z = 0 }); + try testing.expectEqual(Face.bottom.getOffset(), .{ .x = 0, .y = -1, .z = 0 }); + try testing.expectEqual(Face.north.getOffset(), .{ .x = 0, .y = 0, .z = -1 }); + try testing.expectEqual(Face.south.getOffset(), .{ .x = 0, .y = 0, .z = 1 }); + try testing.expectEqual(Face.east.getOffset(), .{ .x = 1, .y = 0, .z = 0 }); + try testing.expectEqual(Face.west.getOffset(), .{ .x = -1, .y = 0, .z = 0 }); +} + +test "ALL_FACES contains exactly six distinct faces" { + try testing.expectEqual(@as(usize, 6), voxel.ALL_FACES.len); + var seen = std.EnumArray(Face, bool).initEmpty(); + for (voxel.ALL_FACES) |f| { + seen.set(f, true); + } + for (comptime std.enums.values(Face)) |f| { + try testing.expect(seen.get(f)); + } +} + +test "Mat4.multiply identity preserves matrix" { + const Mat4 = @import("mat4.zig").Mat4; + const m = Mat4.identity; + const result = Mat4.multiply(m, m); + try testing.expectApproxEqAbs(@as(f32, 1), result.data[0][0], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 1), result.data[1][1], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 1), result.data[2][2], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 1), result.data[3][3], 0.0001); +} + +test "Mat4.multiply translate then rotate produces correct transform" { + const Mat4 = @import("mat4.zig").Mat4; + const Vec3 = @import("vec3.zig").Vec3; + const translate = Mat4.translate(Vec3.init(5, 0, 0)); + const rotate = Mat4.rotateY(std.math.pi / 2.0); + const combined = Mat4.multiply(rotate, translate); + const point = combined.transformPoint(Vec3.zero); + try testing.expectApproxEqAbs(@as(f32, 0), point.x, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), point.y, 0.0001); + try testing.expectApproxEqAbs(@as(f32, -5), point.z, 0.0001); +} + +test "Mat4.transformPoint with w=1 does not divide" { + const Mat4 = @import("mat4.zig").Mat4; + const Vec3 = @import("vec3.zig").Vec3; + const m = Mat4.identity; + const result = m.transformPoint(Vec3.init(1, 2, 3)); + try testing.expectApproxEqAbs(@as(f32, 1), result.x, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 2), result.y, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 3), result.z, 0.0001); +} + +test "Mat4.inverse of singular matrix returns identity" { + const Mat4 = @import("mat4.zig").Mat4; + const singular = Mat4.zero; + const inv = singular.inverse(); + try testing.expectApproxEqAbs(@as(f32, 1), inv.data[0][0], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 1), inv.data[1][1], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 1), inv.data[2][2], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 1), inv.data[3][3], 0.0001); +} + +test "Mat4.rotateY 90 degrees maps +X to -Z" { + const Mat4 = @import("mat4.zig").Mat4; + const Vec3 = @import("vec3.zig").Vec3; + const rot = Mat4.rotateY(std.math.pi / 2.0); + const v = Vec3.init(1, 0, 0); + const transformed = rot.transformDirection(v); + try testing.expectApproxEqAbs(@as(f32, 0), transformed.x, 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), transformed.y, 0.0001); + try testing.expectApproxEqAbs(@as(f32, -1), transformed.z, 0.0001); +} diff --git a/src/tests.zig b/src/tests.zig index f9c06fe8..c4bb6aaa 100644 --- a/src/tests.zig +++ b/src/tests.zig @@ -50,6 +50,7 @@ test { _ = @import("engine-graphics").shadow_tests; _ = @import("engine-shadows").shadow_system_tests; _ = @import("engine-math").utils_tests; + _ = @import("engine-math").voxel_tests; _ = @import("engine-math").frustum_tests; _ = @import("engine-math").mat4_tests; _ = @import("world-meshing").world_tests; From 12167f78afee5fe5f135a241fea9ce1b74bb0d80 Mon Sep 17 00:00:00 2001 From: MichaelFisher1997 <91565606+MichaelFisher1997@users.noreply.github.com> Date: Sun, 3 May 2026 18:34:40 +0000 Subject: [PATCH 2/2] Code review fixes applied, all tests pass Co-authored-by: MichaelFisher1997 --- modules/engine-math/src/voxel_tests.zig | 37 ++++++++++++++++++------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/modules/engine-math/src/voxel_tests.zig b/modules/engine-math/src/voxel_tests.zig index 36fbf331..bd19bb52 100644 --- a/modules/engine-math/src/voxel_tests.zig +++ b/modules/engine-math/src/voxel_tests.zig @@ -1,6 +1,8 @@ const std = @import("std"); const testing = std.testing; const voxel = @import("voxel.zig"); +const Mat4 = @import("mat4.zig").Mat4; +const Vec3 = @import("vec3.zig").Vec3; const Face = voxel.Face; test "Face.getShade returns correct values per face" { @@ -42,18 +44,26 @@ test "ALL_FACES contains exactly six distinct faces" { } test "Mat4.multiply identity preserves matrix" { - const Mat4 = @import("mat4.zig").Mat4; - const m = Mat4.identity; - const result = Mat4.multiply(m, m); + const result = Mat4.multiply(Mat4.identity, Mat4.identity); try testing.expectApproxEqAbs(@as(f32, 1), result.data[0][0], 0.0001); try testing.expectApproxEqAbs(@as(f32, 1), result.data[1][1], 0.0001); try testing.expectApproxEqAbs(@as(f32, 1), result.data[2][2], 0.0001); try testing.expectApproxEqAbs(@as(f32, 1), result.data[3][3], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[0][1], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[0][2], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[0][3], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[1][0], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[1][2], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[1][3], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[2][0], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[2][1], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[2][3], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[3][0], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[3][1], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), result.data[3][2], 0.0001); } test "Mat4.multiply translate then rotate produces correct transform" { - const Mat4 = @import("mat4.zig").Mat4; - const Vec3 = @import("vec3.zig").Vec3; const translate = Mat4.translate(Vec3.init(5, 0, 0)); const rotate = Mat4.rotateY(std.math.pi / 2.0); const combined = Mat4.multiply(rotate, translate); @@ -64,8 +74,6 @@ test "Mat4.multiply translate then rotate produces correct transform" { } test "Mat4.transformPoint with w=1 does not divide" { - const Mat4 = @import("mat4.zig").Mat4; - const Vec3 = @import("vec3.zig").Vec3; const m = Mat4.identity; const result = m.transformPoint(Vec3.init(1, 2, 3)); try testing.expectApproxEqAbs(@as(f32, 1), result.x, 0.0001); @@ -74,18 +82,27 @@ test "Mat4.transformPoint with w=1 does not divide" { } test "Mat4.inverse of singular matrix returns identity" { - const Mat4 = @import("mat4.zig").Mat4; const singular = Mat4.zero; const inv = singular.inverse(); try testing.expectApproxEqAbs(@as(f32, 1), inv.data[0][0], 0.0001); try testing.expectApproxEqAbs(@as(f32, 1), inv.data[1][1], 0.0001); try testing.expectApproxEqAbs(@as(f32, 1), inv.data[2][2], 0.0001); try testing.expectApproxEqAbs(@as(f32, 1), inv.data[3][3], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[0][1], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[0][2], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[0][3], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[1][0], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[1][2], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[1][3], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[2][0], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[2][1], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[2][3], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[3][0], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[3][1], 0.0001); + try testing.expectApproxEqAbs(@as(f32, 0), inv.data[3][2], 0.0001); } test "Mat4.rotateY 90 degrees maps +X to -Z" { - const Mat4 = @import("mat4.zig").Mat4; - const Vec3 = @import("vec3.zig").Vec3; const rot = Mat4.rotateY(std.math.pi / 2.0); const v = Vec3.init(1, 0, 0); const transformed = rot.transformDirection(v);