From 0b8edb80193e6a43bc887cd0305fa473c90ce7be Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Fri, 30 May 2025 18:40:34 +0200 Subject: [PATCH] fix & bustitute --- games/devtest/mods/unittests/bustitute.lua | 64 ++++++++++++++++++++++ games/devtest/mods/unittests/init.lua | 25 +++++---- games/devtest/mods/unittests/matrix4.lua | 32 ++++------- src/script/lua_api/l_matrix4.cpp | 4 +- src/script/lua_api/l_rotation.cpp | 6 +- src/unittest/test_irr_rotation.cpp | 12 ++-- 6 files changed, 99 insertions(+), 44 deletions(-) create mode 100644 games/devtest/mods/unittests/bustitute.lua diff --git a/games/devtest/mods/unittests/bustitute.lua b/games/devtest/mods/unittests/bustitute.lua new file mode 100644 index 000000000..fb44308cc --- /dev/null +++ b/games/devtest/mods/unittests/bustitute.lua @@ -0,0 +1,64 @@ +-- A simple substitute for a busted-like unit test interface + +local bustitute = {} + +local test_env = setmetatable({}, {__index = _G}) + +test_env.assert = setmetatable({}, {__call = function(_, ...) + return assert(...) +end}) + +function test_env.assert.equals(expected, got) + if expected ~= got then + error("expected " .. dump(expected) .. ", got " .. dump(got)) + end +end + +local function same(a, b) + if a == b then + return true + end + if type(a) ~= "table" or type(b) ~= "table" then + return false + end + for k, v in pairs(a) do + if not same(b[k], v) then + return false + end + end + for k, v in pairs(b) do + if a[k] == nil then -- if a[k] is present, we already compared them above + return false + end + end + return true +end + +function test_env.assert.same(expected, got) + if not same(expected, got) then + error("expected " .. dump(expected) .. ", got " .. dump(got)) + end +end + +local full_test_name = {} + +function test_env.describe(name, func) + table.insert(full_test_name, name) + func() + table.remove(full_test_name) +end + +function test_env.it(name, func) + table.insert(full_test_name, name) + unittests.register(table.concat(full_test_name, " "), func, {}) + table.remove(full_test_name) +end + +function bustitute.register(name) + local modpath = core.get_modpath(core.get_current_modname()) + local chunk = assert(loadfile(modpath .. "/" .. name .. ".lua")) + setfenv(chunk, test_env) + test_env.describe(name, chunk) +end + +return bustitute diff --git a/games/devtest/mods/unittests/init.lua b/games/devtest/mods/unittests/init.lua index 40200e972..625457c1f 100644 --- a/games/devtest/mods/unittests/init.lua +++ b/games/devtest/mods/unittests/init.lua @@ -74,34 +74,35 @@ function unittests.run_one(idx, counters, out_callback, player, pos) end local tbegin = core.get_us_time() - local function done(status, err) + local function done(err) local tend = core.get_us_time() local ms_taken = (tend - tbegin) / 1000 - if not status then + if err then core.log("error", err) end - printf("[%s] %s - %dms", status and "PASS" or "FAIL", def.name, ms_taken) - if seed and not status then + printf("[%s] %s - %dms", err and "FAIL" or "PASS", def.name, ms_taken) + if seed and err then printf("Random was seeded to %d", seed) end counters.time = counters.time + ms_taken counters.total = counters.total + 1 - if status then - counters.passed = counters.passed + 1 - end + counters.passed = counters.passed + (err and 0 or 1) end if def.async then core.log("info", "[unittest] running " .. def.name .. " (async)") def.func(function(err) - done(err == nil, err) + done(err) out_callback(true) end, player, pos) else core.log("info", "[unittest] running " .. def.name) - local status, err = pcall(def.func, player, pos) - done(status, err) + local err + xpcall(function() return def.func(player, pos) end, function(e) + err = e .. "\n" .. debug.traceback() + end) + done(err) out_callback(true) end @@ -201,7 +202,9 @@ dofile(modpath .. "/inventory.lua") dofile(modpath .. "/load_time.lua") dofile(modpath .. "/on_shutdown.lua") dofile(modpath .. "/color.lua") -dofile(modpath .. "/matrix4.lua") + +local bustitute = dofile(modpath .. "/bustitute.lua") +bustitute.register("matrix4") -------------- diff --git a/games/devtest/mods/unittests/matrix4.lua b/games/devtest/mods/unittests/matrix4.lua index 88fc548dc..3b9cef270 100644 --- a/games/devtest/mods/unittests/matrix4.lua +++ b/games/devtest/mods/unittests/matrix4.lua @@ -1,16 +1,8 @@ -local function describe(_, func) - func() -end - -local function it(section_name, func) - print("Running test: " .. section_name) - func() -end - -local assert = require("luassert") - -local function assert_close(a, b) - assert(a:equals(b, 1e-4)) +local function assert_close(expected, got) + local tolerance = 1e-4 + if not expected:equals(got, tolerance) then + error("expected " .. tostring(expected) .. " +- " .. tolerance .. " got " .. tostring(got)) + end end local mat1 = Matrix4.new( @@ -54,6 +46,7 @@ describe("getters & setters", function() assert.same({3, 7, 11, 15}, {mat:get_column(3)}) mat:set_column(3, 1, 2, 3, 4) assert.same({1, 2, 3, 4}, {mat:get_column(3)}) + assert.same({3, 7, 11, 15}, {mat1:get_column(3)}) end) end) @@ -149,7 +142,7 @@ local function random_matrix4() end it("determinant", function() - assert.equal(42, Matrix4.scale(vector.new(2, 3, 7)):determinant()) + assert.equals(42, Matrix4.scale(vector.new(2, 3, 7)):determinant()) end) describe("inversion", function() @@ -205,8 +198,8 @@ describe("affine transform constructors", function() end) it("rotation", function() assert_close(Matrix4.new( - 0, -1, 0, 0, - 1, 0, 0, 0, + 0, 1, 0, 0, + -1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ), Matrix4.rotation(Rotation.z(math.pi / 2))) @@ -238,12 +231,9 @@ describe("affine transform methods", function() assert.equals(t, trs:get_translation()) end) it("get rotation & scale", function() - print(trs) local rotation, scale = trs:get_rs() - print(rotation, scale) - print(r) - assert(r:angle_to(rotation) < 1e-4) - assert(s:distance(scale) < 1e-4) + assert(r:angle_to(rotation) < 1e-3) + assert(s:distance(scale) < 1e-3) end) it("set translation", function() local mat = trs:copy() diff --git a/src/script/lua_api/l_matrix4.cpp b/src/script/lua_api/l_matrix4.cpp index 23bc39957..60415df7f 100644 --- a/src/script/lua_api/l_matrix4.cpp +++ b/src/script/lua_api/l_matrix4.cpp @@ -78,7 +78,7 @@ int LuaMatrix4::l_rotation(lua_State *L) { const core::quaternion &rotation = LuaRotation::check(L, 1); core::matrix4 &matrix = create(L); - rotation.getMatrix_transposed(matrix); + rotation.getMatrix(matrix); return 1; } @@ -297,7 +297,7 @@ int LuaMatrix4::l_get_translation(lua_State *L) int LuaMatrix4::l_get_rs(lua_State *L) { - // TODO ? should check that it is, in fact, a rotation matrix; + // TODO maybe check that it is, in fact, a rotation matrix; // not a fake rotation (axis flip) or a shear matrix auto matrix = check(L, 1); v3f scale = matrix.getScale(); diff --git a/src/script/lua_api/l_rotation.cpp b/src/script/lua_api/l_rotation.cpp index 5c01a2f0f..35b9f3c65 100644 --- a/src/script/lua_api/l_rotation.cpp +++ b/src/script/lua_api/l_rotation.cpp @@ -62,9 +62,9 @@ template int LuaRotation::l_fixed_axis_angle(lua_State *L) { f32 angle = readFiniteParam(L, 1); - v3f axis; - axis.*C = 1.0f; - create(L, core::quaternion().fromAngleAxis(angle, axis)); + v3f euler_angles; + euler_angles.*C = angle; + create(L, core::quaternion(euler_angles)); return 1; } diff --git a/src/unittest/test_irr_rotation.cpp b/src/unittest/test_irr_rotation.cpp index 0686938bd..8b90fdce4 100644 --- a/src/unittest/test_irr_rotation.cpp +++ b/src/unittest/test_irr_rotation.cpp @@ -97,19 +97,17 @@ SECTION("matrix-quaternion roundtrip") { } SECTION("matrix-quaternion roundtrip") { - v3f rad(0, 0, irr::core::PI / 2); - // test_euler_angles_rad([](v3f rad) { - quaternion q; - q.set(rad); + test_euler_angles_rad([](v3f rad) { + quaternion q(rad); matrix4 mat; q.getMatrix(mat); quaternion q2(mat); - // q2.makeInverse(); matrix4 mat2; q2.getMatrix(mat2); CHECK(matrix_equals(mat, mat2)); - // CHECK(q.angleTo(q2) < 1e-4); - // }); + // FIXME why does this fail? + // CHECK(q.angleTo(q2) < 1e-2); + }); } SECTION("matrix-euler roundtrip") {