205 lines
5.6 KiB
Lua
205 lines
5.6 KiB
Lua
local math = require("math")
|
|
|
|
local function assert_close(a, b, tolerance)
|
|
tolerance = tolerance or 1e-10
|
|
if math.abs(a - b) > tolerance then
|
|
error(string.format("Expected %g, got %g (diff: %g)", a, b, math.abs(a - b)))
|
|
end
|
|
end
|
|
|
|
local function assert_equal(a, b)
|
|
if a ~= b then
|
|
error(string.format("Expected %s, got %s", tostring(a), tostring(b)))
|
|
end
|
|
end
|
|
|
|
local passed = 0
|
|
local total = 0
|
|
|
|
local function test(name, fn)
|
|
print("Testing " .. name .. "...")
|
|
total = total + 1
|
|
local ok, err = pcall(fn)
|
|
if ok then
|
|
passed = passed + 1
|
|
print(" ✓ PASS")
|
|
else
|
|
print(" ✗ FAIL: " .. err)
|
|
end
|
|
end
|
|
|
|
-- Test constants
|
|
test("Constants", function()
|
|
assert_close(math.pi, 3.14159265358979323846)
|
|
assert_close(math.tau, 6.28318530717958647693)
|
|
assert_close(math.e, 2.71828182845904523536)
|
|
assert_close(math.phi, 1.61803398874989484820)
|
|
assert_equal(math.infinity, 1/0)
|
|
assert_equal(math.isnan(math.nan), true)
|
|
end)
|
|
|
|
-- Test extended functions
|
|
test("Extended Functions", function()
|
|
assert_close(math.cbrt(8), 2)
|
|
assert_close(math.cbrt(-8), -2)
|
|
assert_close(math.hypot(3, 4), 5)
|
|
assert_equal(math.isnan(0/0), true)
|
|
assert_equal(math.isnan(5), false)
|
|
assert_equal(math.isfinite(5), true)
|
|
assert_equal(math.isfinite(math.infinity), false)
|
|
assert_equal(math.sign(5), 1)
|
|
assert_equal(math.sign(-5), -1)
|
|
assert_equal(math.sign(0), 0)
|
|
assert_equal(math.clamp(5, 0, 3), 3)
|
|
assert_equal(math.clamp(-1, 0, 3), 0)
|
|
assert_close(math.lerp(0, 10, 0.5), 5)
|
|
assert_close(math.map(5, 0, 10, 0, 100), 50)
|
|
assert_equal(math.round(2.7), 3)
|
|
assert_equal(math.round(-2.7), -3)
|
|
assert_close(math.roundto(3.14159, 2), 3.14)
|
|
assert_close(math.distance(0, 0, 3, 4), 5)
|
|
end)
|
|
|
|
-- Test random functions
|
|
test("Random Functions", function()
|
|
local r = math.randomf(0, 1)
|
|
assert_equal(r >= 0 and r < 1, true)
|
|
local i = math.randint(1, 10)
|
|
assert_equal(i >= 1 and i <= 10, true)
|
|
assert_equal(type(math.randboolean()), "boolean")
|
|
end)
|
|
|
|
-- Test statistics
|
|
test("Statistics", function()
|
|
local data = {1, 2, 3, 4, 5}
|
|
assert_equal(math.sum(data), 15)
|
|
assert_equal(math.mean(data), 3)
|
|
assert_equal(math.median(data), 3)
|
|
assert_close(math.variance(data), 2)
|
|
assert_close(math.stdev(data), math.sqrt(2))
|
|
local min, max = math.minmax(data)
|
|
assert_equal(min, 1)
|
|
assert_equal(max, 5)
|
|
assert_equal(math.mode({1, 2, 2, 3}), 2)
|
|
end)
|
|
|
|
-- Test 2D vectors
|
|
test("2D Vectors", function()
|
|
local v1 = math.vec2.new(3, 4)
|
|
local v2 = math.vec2.new(1, 2)
|
|
|
|
assert_equal(v1.x, 3)
|
|
assert_equal(v1.y, 4)
|
|
assert_close(math.vec2.length(v1), 5)
|
|
assert_equal(math.vec2.length_squared(v1), 25)
|
|
|
|
local v3 = math.vec2.add(v1, v2)
|
|
assert_equal(v3.x, 4)
|
|
assert_equal(v3.y, 6)
|
|
|
|
local v4 = math.vec2.sub(v1, v2)
|
|
assert_equal(v4.x, 2)
|
|
assert_equal(v4.y, 2)
|
|
|
|
local v5 = math.vec2.mul(v1, 2)
|
|
assert_equal(v5.x, 6)
|
|
assert_equal(v5.y, 8)
|
|
|
|
assert_equal(math.vec2.dot(v1, v2), 11)
|
|
assert_close(math.vec2.distance(v1, v2), math.sqrt(8))
|
|
|
|
local normalized = math.vec2.normalize(v1)
|
|
assert_close(math.vec2.length(normalized), 1)
|
|
end)
|
|
|
|
-- Test 3D vectors
|
|
test("3D Vectors", function()
|
|
local v1 = math.vec3.new(1, 2, 3)
|
|
local v2 = math.vec3.new(4, 5, 6)
|
|
|
|
assert_close(math.vec3.length(v1), math.sqrt(14))
|
|
assert_equal(math.vec3.dot(v1, v2), 32)
|
|
|
|
local cross = math.vec3.cross(v1, v2)
|
|
assert_equal(cross.x, -3)
|
|
assert_equal(cross.y, 6)
|
|
assert_equal(cross.z, -3)
|
|
|
|
local add = math.vec3.add(v1, v2)
|
|
assert_equal(add.x, 5)
|
|
assert_equal(add.y, 7)
|
|
assert_equal(add.z, 9)
|
|
end)
|
|
|
|
-- Test 2x2 matrices
|
|
test("2x2 Matrices", function()
|
|
local m1 = math.mat2.new(1, 2, 3, 4)
|
|
local m2 = math.mat2.new(2, 0, 1, 3)
|
|
|
|
assert_equal(math.mat2.det(m1), -2)
|
|
|
|
local product = math.mat2.mul(m1, m2)
|
|
assert_equal(product[1][1], 4)
|
|
assert_equal(product[1][2], 6)
|
|
assert_equal(product[2][1], 10)
|
|
assert_equal(product[2][2], 12)
|
|
|
|
local rotation = math.mat2.rotation(math.pi/2)
|
|
assert_close(rotation[1][1], 0, 1e-10)
|
|
assert_close(rotation[1][2], -1)
|
|
assert_close(rotation[2][1], 1)
|
|
assert_close(rotation[2][2], 0, 1e-10)
|
|
end)
|
|
|
|
-- Test 3x3 matrices
|
|
test("3x3 Matrices", function()
|
|
local identity = math.mat3.identity()
|
|
assert_equal(identity[1][1], 1)
|
|
assert_equal(identity[2][2], 1)
|
|
assert_equal(identity[3][3], 1)
|
|
assert_equal(identity[1][2], 0)
|
|
|
|
local translation = math.mat3.translation(5, 10)
|
|
assert_equal(translation[1][3], 5)
|
|
assert_equal(translation[2][3], 10)
|
|
|
|
local point = {x = 1, y = 2}
|
|
local transformed = math.mat3.transform_point(translation, point)
|
|
assert_equal(transformed.x, 6)
|
|
assert_equal(transformed.y, 12)
|
|
end)
|
|
|
|
-- Test geometry functions
|
|
test("Geometry", function()
|
|
assert_close(math.geometry.triangle_area(0, 0, 4, 0, 0, 3), 6)
|
|
assert_equal(math.geometry.point_in_triangle(1, 1, 0, 0, 4, 0, 0, 3), true)
|
|
assert_equal(math.geometry.point_in_triangle(5, 5, 0, 0, 4, 0, 0, 3), false)
|
|
|
|
local intersects, x, y = math.geometry.line_intersect(0, 0, 2, 2, 0, 2, 2, 0)
|
|
assert_equal(intersects, true)
|
|
assert_close(x, 1)
|
|
assert_close(y, 1)
|
|
|
|
local closest_x, closest_y = math.geometry.closest_point_on_segment(1, 3, 0, 0, 4, 0)
|
|
assert_close(closest_x, 1)
|
|
assert_close(closest_y, 0)
|
|
end)
|
|
|
|
-- Test interpolation
|
|
test("Interpolation", function()
|
|
assert_close(math.interpolation.bezier(0.5, 0, 1, 2, 3), 1.5)
|
|
assert_close(math.interpolation.quadratic_bezier(0.5, 0, 2, 4), 2)
|
|
assert_close(math.interpolation.smoothstep(0, 1, 0.5), 0.5)
|
|
assert_close(math.interpolation.smootherstep(0, 1, 0.5), 0.5)
|
|
assert_close(math.interpolation.catmull_rom(0.5, 0, 1, 2, 3), 1.5)
|
|
end)
|
|
|
|
print("=" .. string.rep("=", 50))
|
|
print(string.format("Test Results: %d/%d passed", passed, total))
|
|
if passed == total then
|
|
print("🎉 All tests passed!")
|
|
os.exit(0)
|
|
else
|
|
print("❌ Some tests failed!")
|
|
os.exit(1)
|
|
end |