diff --git a/.github/workflows/luacheck.yml b/.github/workflows/luacheck.yml index 5290e245..3c99a991 100644 --- a/.github/workflows/luacheck.yml +++ b/.github/workflows/luacheck.yml @@ -1,11 +1,10 @@ -on: [push, pull_request] name: luacheck +on: [push, pull_request] jobs: - lint: + luacheck: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master - - name: lint - uses: Roang-zero1/factorio-mod-luacheck@master - with: - luacheckrc_url: "" + - name: Checkout + uses: actions/checkout@master + - name: Luacheck + uses: lunarmodules/luacheck@master diff --git a/.github/workflows/mineunit.yml b/.github/workflows/mineunit.yml index f047d379..b1a1b449 100644 --- a/.github/workflows/mineunit.yml +++ b/.github/workflows/mineunit.yml @@ -3,22 +3,21 @@ name: mineunit on: [push, pull_request] jobs: - build: + mineunit: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - with: - submodules: true + - uses: actions/checkout@v3 - id: mineunit uses: mt-mods/mineunit-actions@master with: working-directory: ./technic + mineunit-args: --engine-version 5.4.1 badge-label: Test coverage - - uses: RubbaBoy/BYOB@v1.2.0 + - uses: RubbaBoy/BYOB@v1.3.0 if: success() && github.event_name == 'push' && github.ref == 'refs/heads/master' with: NAME: "${{ steps.mineunit.outputs.badge-name }}" @@ -40,6 +39,7 @@ jobs: -------------------------------------------------------------- ${{ steps.mineunit.outputs.mineunit-report }} ``` + ### Raw test runner output for geeks: ``` ${{ steps.mineunit.outputs.mineunit-stdout }} @@ -53,7 +53,7 @@ jobs: comment: |
Mineunit failed regression tests, click for details - ### Regression test log for technic: + ### Regression test log for Technic: ``` ${{ steps.mineunit.outputs.mineunit-stdout }} ``` diff --git a/technic/spec/fixtures/default.lua b/technic/spec/fixtures/default.lua new file mode 100644 index 00000000..35532a00 --- /dev/null +++ b/technic/spec/fixtures/default.lua @@ -0,0 +1,32 @@ +mineunit:set_modpath("default", "spec/fixtures") + +local function register_node(name, groups, additional_definition) + local definition = { + description = name.." description", + tiles = { "default_"..name }, + groups = groups, + } + for k,v in pairs(additional_definition or {}) do definition[k] = v end + minetest.register_node(":default:"..name, definition) +end + +local function register_item(name) + minetest.register_craftitem(":default:"..name, { + description = name.." description", + }) +end + +-- Register some basic nodes for cutting, grinding, digging, registering recipes etc. +register_node("stone", {cracky = 3, stone = 1}, {is_ground_content = true, drop = "default:cobble"}) +register_node("cobble", {cracky=3, stone = 2}) +register_node("sand", {snappy=2, choppy=2, oddly_breakable_by_hand=2}) +register_node("wood", {tree=1, choppy=2, oddly_breakable_by_hand=2}) +register_node("dirt", {crumbly = 3, soil = 1}) +register_node("sandstone", {crumbly = 1, cracky = 3}) +register_node("steelblock", {cracky = 1, level = 2}) +register_node("furnace", {cracky=2}) +register_node("furnace_active", {cracky=2, not_in_creative_inventory=1}, {drop = "default:furnace"}) + +register_item("steel_ingot") + +screwdriver = {} \ No newline at end of file diff --git a/technic/spec/fixtures/digilines.lua b/technic/spec/fixtures/digilines.lua new file mode 100644 index 00000000..ad3a2c2b --- /dev/null +++ b/technic/spec/fixtures/digilines.lua @@ -0,0 +1,36 @@ +-- Simple digilines mod fixture that logs sent messages, works with some simple digiline mods + +mineunit:set_modpath("digilines", "spec/fixtures") + +digilines = { + _msg_log = {}, + receptor_send = function(pos, rules, channel, msg) + table.insert(digilines._msg_log, { + pos = pos, + rules = rules, + channel = channel, + msg = msg, + }) + end, + rules = { + default = { + {x=0, y=0, z=-1}, + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=0, y=0, z=1}, + {x=1, y=1, z=0}, + {x=1, y=-1, z=0}, + {x=-1, y=1, z=0}, + {x=-1, y=-1, z=0}, + {x=0, y=1, z=1}, + {x=0, y=-1, z=1}, + {x=0, y=1, z=-1}, + {x=0, y=-1, z=-1} + } + } +} + +digilines = setmetatable(digilines, { + __call = function(self,...) return self end, + __index = function(...) return function(...)end end, +}) diff --git a/technic/spec/fixtures/mesecons.lua b/technic/spec/fixtures/mesecons.lua new file mode 100644 index 00000000..1b2abf6e --- /dev/null +++ b/technic/spec/fixtures/mesecons.lua @@ -0,0 +1,27 @@ +mineunit:set_modpath("mesecons", "spec/fixtures") +mineunit:set_modpath("mesecons_mvps", "spec/fixtures") + +mesecon = { + state = {}, + rules = { + default = { + {x = 0, y = 0, z = -1}, + {x = 1, y = 0, z = 0}, + {x = -1, y = 0, z = 0}, + {x = 0, y = 0, z = 1}, + {x = 1, y = 1, z = 0}, + {x = 1, y = -1, z = 0}, + {x = -1, y = 1, z = 0}, + {x = -1, y = -1, z = 0}, + {x = 0, y = 1, z = 1}, + {x = 0, y = -1, z = 1}, + {x = 0, y = 1, z = -1}, + {x = 0, y = -1, z = -1}, + } + } +} + +mesecon = setmetatable(mesecon, { + __call = function(self,...) return self end, + __index = function(...) return function(...)end end, +}) diff --git a/technic/spec/fixtures/mineunit.conf b/technic/spec/fixtures/mineunit.conf deleted file mode 100644 index e69de29b..00000000 diff --git a/technic/spec/fixtures/technic.conf b/technic/spec/fixtures/technic.conf new file mode 100644 index 00000000..f17e5da4 --- /dev/null +++ b/technic/spec/fixtures/technic.conf @@ -0,0 +1,27 @@ +enable_cans = true +enable_chainsaw = true +enable_flashlight = true +enable_mining_drill = true +enable_mining_laser = true +enable_multimeter = true +enable_prospector = true +enable_sonic_screwdriver = true +enable_tree_tap = true +enable_vacuum = true + +multimeter_remote_start_ttl = 300 + +enable_wind_mill = true +enable_nuclear_reactor_digiline_selfdestruct = true +quarry_max_depth = 100 +quarry_time_limit = 5000 + +switch_off_delay_seconds = 1800 +network_overload_reset_time = 20 +admin_priv = basic_privs +enable_corium_griefing = true +enable_radiation_protection = true +enable_radiation_throttling = true +enable_entity_radiation_damage = true +enable_longterm_radiation_damage = true +max_lag_reduction_multiplier = 0.99 \ No newline at end of file diff --git a/technic/spec/fixtures/technic.lua b/technic/spec/fixtures/technic.lua new file mode 100644 index 00000000..ad9e86b4 --- /dev/null +++ b/technic/spec/fixtures/technic.lua @@ -0,0 +1,22 @@ +-- Use this fixture when loading full Technic mod. +-- Loads all required modules and fixtures for technic + +-- Load modules required by tests +mineunit("core") +mineunit("player") +mineunit("protection") +mineunit("common/after") +mineunit("server") +mineunit("voxelmanip") +if mineunit:config("engine_version") ~= "mineunit" then + mineunit("game/voxelarea") +end + +-- Load fixtures required by tests +fixture("default") +fixture("mesecons") +fixture("digilines") +fixture("pipeworks") + +-- Load technic_worldgen +fixture("technic_worldgen") diff --git a/technic/spec/fixtures/technic_worldgen.lua b/technic/spec/fixtures/technic_worldgen.lua new file mode 100644 index 00000000..13b3e986 --- /dev/null +++ b/technic/spec/fixtures/technic_worldgen.lua @@ -0,0 +1,7 @@ +-- Load technic_worldgen mod + +mineunit:set_modpath("technic_worldgen", "../technic_worldgen") + +mineunit:set_current_modname("technic_worldgen") +sourcefile("../technic_worldgen/init") +mineunit:restore_current_modname() diff --git a/technic/spec/mineunit.conf b/technic/spec/mineunit.conf index e69de29b..e67077f5 100644 --- a/technic/spec/mineunit.conf +++ b/technic/spec/mineunit.conf @@ -0,0 +1,11 @@ +deprecated = "ignore" +time_step = 100 +exclude = { + -- Integration tests are not part of mod code + "integration_test", + -- These are commented out, not part of mod without manually editing code + "machines/MV/lighting", + "machines/MV/power_radiator", + -- Exclude everything outside of technic directory, some are tested but we do not want stats for these + "^../" +} \ No newline at end of file diff --git a/technic/spec/tools_spec.lua b/technic/spec/tools_spec.lua new file mode 100644 index 00000000..1d0a9f86 --- /dev/null +++ b/technic/spec/tools_spec.lua @@ -0,0 +1,168 @@ +require("mineunit") +--[[ + Technic tool regression tests. + Execute mineunit at technic source directory. +--]] + +-- Load complete technic mod +fixture("technic") +sourcefile("init") + +describe("Technic power tool", function() + + world.set_default_node("air") + + -- HV battery box and some HV solar arrays for charging + local BB_Charge_POS = {x=0,y=51,z=0} + local BB_Discharge_POS = {x=0,y=51,z=2} + world.layout({ + -- Network with generators for charging tools in battery box + {BB_Charge_POS, "technic:hv_battery_box0"}, + {{x=1,y=51,z=0}, "technic:switching_station"}, + {{{x=2,y=51,z=0},{x=10,y=51,z=0}}, "technic:solar_array_hv"}, + {{{x=0,y=50,z=0},{x=10,y=50,z=0}}, "technic:hv_cable"}, + -- Network without generators for discharging tools in battery box + {BB_Discharge_POS, "technic:hv_battery_box0"}, + {{x=1,y=51,z=2}, "technic:switching_station"}, + {{{x=0,y=50,z=2},{x=1,y=50,z=2}}, "technic:hv_cable"}, + }) + + -- Some helpers to make stack access simpler + local player = Player("SX") + local charge_inv = minetest.get_meta(BB_Charge_POS):get_inventory() + local discharge_inv = minetest.get_meta(BB_Discharge_POS):get_inventory() + local function set_charge_stack(stack) charge_inv:set_stack("src", 1, stack) end + local function get_charge_stack() return charge_inv:get_stack("src", 1) end + local function set_discharge_stack(stack) discharge_inv:set_stack("dst", 1, stack) end + local function get_discharge_stack() return discharge_inv:get_stack("dst", 1) end + local function set_player_stack(stack) return player:get_inventory():set_stack("main", 1, stack) end + local function get_player_stack() return player:get_inventory():get_stack("main", 1) end + + -- Execute on mods loaded callbacks to finish loading. + mineunit:mods_loaded() + -- Tell mods that 1 minute passed already to execute all weird minetest.after hacks. + mineunit:execute_globalstep(60) + + describe("API", function() + + setup(function() + set_charge_stack(ItemStack(nil)) + set_discharge_stack(ItemStack(nil)) + mineunit:set_current_modname("mymod") + mineunit:execute_on_joinplayer(player) + end) + + teardown(function() + mineunit:execute_on_leaveplayer(player) + mineunit:restore_current_modname() + end) + + local use_RE_charge_result + + it("technic.register_power_tool works", function() + core.register_item("mymod:powertool", { + type = "tool", + description = "My Mod Power Tool", + inventory_image = "mymod_powertool.png", + wear_represents = "technic_RE_charge", + on_use = function(itemstack, player, pointed_thing) + use_RE_charge_result = technic.use_RE_charge(itemstack, 123) + return itemstack + end, + }) + technic.power_tools["mymod:powertool"] = 1234 + local itemdef = minetest.registered_items["mymod:powertool"] + assert.is_hashed(itemdef) + end) + + it("technic.use_RE_charge works (zero charge)", function() + local stack = ItemStack("mymod:powertool") + local use_RE_charge_result = technic.use_RE_charge(stack, 123) + assert.equals("boolean", type(use_RE_charge_result)) + assert.is_false(use_RE_charge_result) + end) + + it("technic.get_RE_charge works (zero charge)", function() + local stack = ItemStack("mymod:powertool") + local charge, max_charge = technic.get_RE_charge(stack) + assert.equals(0, charge) + assert.equals(1234, max_charge) + end) + + it("technic.set_RE_charge works (zero charge -> 123)", function() + local stack = ItemStack("mymod:powertool") + technic.set_RE_charge(stack, 123) + assert.equals(123, technic.get_RE_charge(stack)) + end) + + it("technic.use_RE_charge works (minimum charge)", function() + -- Add partially charged tool to player inventory + local stack = ItemStack("mymod:powertool") + technic.set_RE_charge(stack, 123) + set_player_stack(stack) + + -- Use tool and verify results + spy.on(technic, "use_RE_charge") + player:do_use(player:get_pos()) + assert.spy(technic.use_RE_charge).called(1) + assert.equals("boolean", type(use_RE_charge_result)) + assert.is_true(use_RE_charge_result) + assert.equals(0, technic.get_RE_charge(get_player_stack())) + end) + + it("technic.use_RE_charge works (minimum charge + 1)", function() + -- Add partially charged tool to player inventory + local stack = ItemStack("mymod:powertool") + technic.set_RE_charge(stack, 124) + set_player_stack(stack) + -- Use tool and verify results + player:do_use(player:get_pos()) + assert.equals(1, technic.get_RE_charge(get_player_stack())) + end) + + end) + + describe("Flashlight", function() + + local itemname = "technic:flashlight" + local itemdef = minetest.registered_items[itemname] + + setup(function() + set_charge_stack(ItemStack(nil)) + set_discharge_stack(ItemStack(nil)) + mineunit:execute_on_joinplayer(player) + end) + + teardown(function() + mineunit:execute_on_leaveplayer(player) + end) + + it("is registered", function() + assert.is_hashed(itemdef) + assert.is_function(itemdef.on_refill) + assert.equals("technic_RE_charge", itemdef.wear_represents) + assert.is_number(technic.power_tools[itemname]) + assert.gt(technic.power_tools[itemname], 0) + end) + + it("charge is used", function() + -- Get fully charged item + local stack = ItemStack(itemname) + technic.set_RE_charge(stack, technic.power_tools[itemname]) + set_player_stack(stack) + + -- Use item, flashlight charge is used every globalstep and there's no on_use definition + for i=1, 100 do + mineunit:execute_globalstep(1) + end + + -- Check that item charge was actually used and error is acceptable + local charge_used = technic.power_tools[itemname] - technic.get_RE_charge(get_player_stack()) + local exact_use = 2 * 100 -- 2 per cycle / 100 cycles + assert.lt(0.9, charge_used / exact_use) + assert.gt(1.1, charge_used / exact_use) + end) + + end) + +end)