-- Original MIT-licensed integration checks. Staged as a disposable world mod; -- never copy this into the persistent play world. No engine globals are mocked. local mode = core.settings:get("hearth_launcher_mode") local token = core.settings:get("hearth_smoke_token") assert(mode == "check" or mode == "smoke", "Invalid launcher test mode") assert(token and token:match("^[%x%-]+$"), "Missing launcher test token") local modpath = core.get_modpath(core.get_current_modname()) local finished = false local function finish(ok, message) if finished then return end finished = true if ok then core.log("action", "LAST_HEARTH_" .. mode:upper() .. "_PASS " .. token) else core.log("error", "LAST_HEARTH_TEST_FAIL: " .. tostring(message)) end core.request_shutdown("Last Hearth " .. mode .. " complete", false, 0) end local function guarded(fn) local ok, message = pcall(fn) if not ok then finish(false, message) end end local function syntax_check() local manifest = dofile(modpath .. "/syntax_manifest.lua") assert(#manifest > 0, "Empty syntax manifest") for _, entry in ipairs(manifest) do local chunk, message = loadfile(modpath .. "/syntax/" .. entry.file) assert(chunk, entry.label .. ": " .. tostring(message)) end core.log("action", "Last Hearth: compiled " .. #manifest .. " Lua files (standalone specs not executed)") end local function registry_check() assert(type(hearth) == "table", "Real hearth global was not loaded") assert(type(hearth.model) == "table", "hearth.model missing") assert(type(hearth.players) == "table", "hearth.players missing") assert(core.get_modpath("hearth"), "hearth mod missing") for _, name in ipairs({"default", "doors", "farming", "fire", "stairs", "wool", "sfinv"}) do assert(not core.get_modpath(name), "Unexpected MTG dependency: " .. name) end for name in pairs(core.registered_items) do assert(not name:match("^default:"), "MTG item leaked into standalone game: " .. name) end for _, name in ipairs({"stone", "soil", "grass", "sand", "water_source", "water_flowing", "log", "leaves", "loose_stone", "sticks", "berry_bush", "reeds", "planks", "wall", "roof", "fire", "fire_lit"}) do assert(core.registered_nodes["hearth:" .. name], "Missing node: " .. name) end for _, name in ipairs({"berries", "raw_food", "cooked_food", "vessel", "water_raw", "water_clean", "knife", "axe", "pick", "spear"}) do assert(core.registered_items["hearth:" .. name], "Missing item: " .. name) end for _, name in ipairs({"knife", "axe", "pick", "spear", "vessel", "fire", "wall", "roof", "planks", "sticks", "raw_food"}) do local output = "hearth:" .. name local recipe = core.get_craft_recipe(output) assert(recipe.items and next(recipe.items), "Missing craft: " .. output) for _, ingredient in pairs(recipe.items) do assert(ingredient == "" or core.registered_items[ingredient], "Unknown ingredient: " .. ingredient) end local inputs = {} for index = 1, (recipe.width == 0 and #recipe.items or recipe.width * 3) do inputs[index] = ItemStack(recipe.items[index] or "") end local width = recipe.width > 0 and recipe.width or #inputs local result = core.get_craft_result({method = "normal", width = width, items = inputs}) assert(result.item:get_name() == output, "Engine craft result mismatch: " .. output) assert(result.item:get_count() == ItemStack(recipe.output):get_count(), "Craft quantity mismatch: " .. output) end assert(core.registered_aliases.mapgen_stone == "hearth:stone", "Missing mapgen stone alias") assert(core.registered_aliases.mapgen_water_source == "hearth:water_source", "Missing water alias") assert(core.registered_biomes.hearth_temperate, "Missing temperate biome") assert(core.registered_biomes.hearth_riverbank, "Missing riverbank biome") assert(core.settings:get_bool("enable_pvp") == false, "PvP must be disabled") assert(core.settings:get_bool("secure.enable_security") == true, "Mod security must be enabled") assert(core.settings:get("bind_address") == "127.0.0.1", "Server must bind loopback only") end local function unit_check() -- Each standalone harness receives its own globals and os table. Mocked core, -- hearth and os.time never replace globals of the running game. local manifest = dofile(modpath .. "/syntax_manifest.lua") local lookup = {} for _, entry in ipairs(manifest) do lookup[entry.label] = modpath .. "/syntax/" .. entry.file end local count = 0 for label, filename in pairs(lookup) do if label:match("_spec%.lua$") then local module = label:match("tests/(.+)_spec%.lua$") local target = assert(lookup["mods/hearth/" .. module .. ".lua"], "Missing test module") local env = setmetatable({arg = {target}, os = {}}, {__index = _G}) for k, v in pairs(os) do env.os[k] = v end env._G = env env.dofile = function(path) assert(path == target, "Unit harness attempted unexpected file access") local chunk = assert(loadfile(path)); setfenv(chunk, env); return chunk() end local chunk = assert(loadfile(filename)); setfenv(chunk, env); chunk() count = count + 1 end end assert(count >= 2, "Expected model and content regression suites") core.log("action", "Last Hearth: " .. count .. " isolated unit suites executed") end local function emerge_check() local callbacks = 0 core.emerge_area({x = -64, y = -32, z = -64}, {x = 64, y = 96, z = 64}, function(_, action, remaining) if finished then return end guarded(function() assert(action ~= core.EMERGE_ERRORED and action ~= core.EMERGE_CANCELLED, "Map emergence failed or was cancelled") callbacks = callbacks + 1 if remaining ~= 0 then return end -- Inspect after mapgen callbacks have completed, on a server step. core.after(0, function() guarded(function() assert(callbacks > 0, "No emerge callbacks received") local material = false for z = -16, 16, 4 do for y = -32, 16, 4 do for x = -16, 16, 4 do local node = core.get_node_or_nil({x = x, y = y, z = z}) assert(node and node.name ~= "ignore", "Emerged map contains unloaded nodes") assert(core.registered_nodes[node.name], "Unregistered generated node: " .. node.name) assert(node.name == "air" or node.name:match("^hearth:"), "Foreign generated node: " .. node.name) if node.name:match("^hearth:") then material = true end end end end assert(material, "Mapgen produced no hearth terrain in the test volume") local resources = {} for _, name in ipairs({"grass", "loose_stone", "sticks", "berry_bush", "reeds", "log", "water_source"}) do local nodes = core.find_nodes_in_area({x = -64, y = -16, z = -64}, {x = 64, y = 96, z = 64}, {"hearth:" .. name}) resources[#resources + 1] = name .. "=" .. #nodes assert(#nodes > 0, "Starting region missing required resource: " .. name) end core.log("action", "Last Hearth starting resources: " .. table.concat(resources, ", ")) local p = {x = 0, y = 85, z = 0} core.set_node(vector.offset(p, 0, 3, 0), {name = "hearth:roof"}) for _, d in ipairs({{1,0},{-1,0},{0,1},{0,-1}}) do core.set_node(vector.offset(p, d[1]*2, 1, d[2]*2), {name = "hearth:wall"}) end local env = hearth.environment(p) assert(env.roof and env.shelter == 1, "A roof and four walls must enclose a shelter") core.remove_node(vector.offset(p, 0, 3, 0)) assert(hearth.environment(p).shelter == 0, "Walls without a roof are exposed") finish(true) end) end) end) end) end core.after(1, function() guarded(function() syntax_check() if mode == "check" then finish(true); return end registry_check() unit_check() emerge_check() end) end) core.after(60, function() finish(false, "Engine test deadline exceeded") end)