Files
2026-11-03 12:41:09 -05:00

69 lines
3.3 KiB
Lua
Executable File

local M = dofile(assert(arg[1], "model.lua path required"))
local total = 0
local function test(name, fn)
local ok, err = pcall(fn)
assert(ok, name .. ": " .. tostring(err)); total = total + 1
end
-- Explicit UTC fixtures; os.time(table) would depend on the machine timezone.
local june_noon, december_noon = 1782043200, 1797854400
test("reject malformed locations", function()
assert(not M.location("bad", 0)); assert(not M.location(91, 0))
assert(not M.location(0, 181)); assert(not M.location(0 / 0, 0))
assert(not M.location(math.huge, 0)); assert(M.location(0, 0))
end)
test("latitude changes solstice elevation", function()
local summer = M.solar(june_noon, 45, 0)
local winter = M.solar(december_noon, 45, 0)
assert(summer.elevation > winter.elevation + 40)
assert(summer.temperature > winter.temperature)
end)
test("opposite hemispheres reverse seasons", function()
assert(M.solar(june_noon, 45, 0).season == "Summer")
assert(M.solar(june_noon, -45, 0).season == "Winter")
end)
test("longitude changes solar time", function()
local a, b = M.solar(june_noon, 0, 0), M.solar(june_noon, 0, 90)
assert(math.abs((b.hour - a.hour) % 24 - 6) < 0.01)
end)
test("polar night and polar day stay finite", function()
assert(M.solar(june_noon, 90, 0).daylight)
assert(not M.solar(december_noon, 90, 0).daylight)
assert(M.solar(june_noon, -90, 0).timeofday >= 0)
end)
test("deterministic weather across restarts", function()
assert(M.weather(june_noon, 30, -70) == M.weather(june_noon, 30, -70))
end)
local initial = {food = 80, water = 80, warmth = 80, wet = 20, stamina = 70}
test("shelter dries while exposed rain wets", function()
local dry = M.needs(initial, {temperature = 5, shelter = 1, rain = true}, 1)
local wet = M.needs(initial, {temperature = 5, shelter = 0, rain = true}, 1)
assert(dry.wet < initial.wet and wet.wet > initial.wet)
assert(initial.wet == 20) -- no hidden mutation
end)
test("rain cloak slows wetting, adds warmth, and a rack accelerates sheltered drying", function()
local cold = {food = 80, water = 80, warmth = 68, wet = 20, stamina = 70}
local bare = M.needs(cold, {temperature = 5, shelter = 0, rain = true}, 1)
local coated = M.needs(cold, {temperature = 5, shelter = 0, rain = true, clothing = true}, 1)
assert(coated.wet < bare.wet and coated.warmth > bare.warmth)
local rack = M.needs(initial, {temperature = 5, shelter = 1, rain = true, drying = true}, 1)
assert(rack.wet < M.needs(initial, {temperature = 5, shelter = 1, rain = true}, 1).wet)
end)
test("rest recovers sprint reserve", function()
local rest = M.needs(initial, {temperature = 20}, 1)
local run = M.needs(initial, {temperature = 20, sprinting = true}, 1)
assert(rest.stamina > initial.stamina and run.stamina < initial.stamina)
end)
test("large pauses never replay offline starvation", function()
local state = M.needs(initial, {temperature = -20}, 100000)
assert(state.food > 79 and state.water > 79)
end)
test("negative elapsed does not reverse needs", function()
local state = M.needs(initial, {temperature = -20}, -1)
assert(state.food == initial.food)
end)
test("fuel expires and is bounded", function()
assert(M.fuel_remaining(100, 101) == 0)
assert(M.fuel_remaining(10000000, 0) == 600)
end)
print("PASS " .. total .. " model tests")