technic-cd2025/technic/spec/tools_spec.lua
SX 88b8a2bb17
Update power tool compatibility shims (#276)
* Update tool compatibility shims

* Tool compatibility tests

* No forced override if technic_get_charge or technic_set_charge is defined
2022-06-16 17:58:18 +03:00

470 lines
16 KiB
Lua

require("mineunit")
--[[
Technic tool regression tests.
Execute mineunit at technic source directory.
--]]
-- Load complete technic mod
fixture("technic")
sourcefile("init")
local RUN_TECHNIC_ADDONS_CHAINSAWMK3_TESTS = false
describe("Technic power tool", function()
if RUN_TECHNIC_ADDONS_CHAINSAWMK3_TESTS then
-- Load technic_addons mod
mineunit:set_modpath("technic_addons", "../../technic_addons")
mineunit:set_current_modname("technic_addons")
sourcefile("../../technic_addons/init")
mineunit:restore_current_modname()
end
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())
set_discharge_stack(ItemStack())
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()
technic.register_power_tool("mymod:powertool", {
description = "My Mod Power Tool",
inventory_image = "mymod_powertool.png",
max_charge = 1234,
on_use = function(itemstack, player, pointed_thing)
use_RE_charge_result = technic.use_RE_charge(itemstack, 123)
return itemstack
end,
})
local itemdef = minetest.registered_items["mymod:powertool"]
assert.is_hashed(itemdef)
assert.is_function(itemdef.on_use)
assert.is_function(itemdef.on_refill)
assert.equals("technic_RE_charge", itemdef.wear_represents)
assert.is_number(itemdef.technic_max_charge)
assert.gt(itemdef.technic_max_charge, 0)
end)
it("technic.use_RE_charge works (zero charge)", function()
set_player_stack("mymod:powertool")
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_false(use_RE_charge_result)
end)
it("technic.get_RE_charge works (zero charge)", function()
assert.equals(0, technic.get_RE_charge(ItemStack("mymod:powertool")))
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("charging and discharging extreme ratios", function()
local function register_test_tool(name, charge_per_use, max_charge)
technic.register_power_tool("mymod:"..name, {
description = name,
inventory_image = "mymod_powertool.png",
max_charge = max_charge,
on_use = function(itemstack, player, pointed_thing)
technic.use_RE_charge(itemstack, charge_per_use)
return itemstack
end,
})
end
setup(function()
set_charge_stack(ItemStack())
set_discharge_stack(ItemStack())
mineunit:set_current_modname("mymod")
register_test_tool("t1_1", 1, 1)
register_test_tool("t1_2", 1, 2)
register_test_tool("t1_10001", 1, 10001)
register_test_tool("t1_65535", 1, 65535)
register_test_tool("t1_65536", 1, 65536)
register_test_tool("t100_6553500", 1, 6553500)
register_test_tool("t100_6553600", 1, 6553600)
register_test_tool("t2_3", 2, 3)
mineunit:restore_current_modname()
mineunit:execute_on_joinplayer(player)
end)
teardown(function()
mineunit:execute_on_leaveplayer(player)
end)
-- Very basic tests for few simple and straightforward max_charge values
-- Add tool to battery box and test charging, 10kEU / cycle
it("t1_1 can be charged", function()
set_charge_stack(ItemStack("mymod:t1_1"))
assert.equals(0, technic.get_RE_charge(get_charge_stack()))
mineunit:execute_globalstep(1)
assert.equals(1, technic.get_RE_charge(get_charge_stack()))
end)
it("t1_2 can be charged", function()
-- Add tool to battery box
set_charge_stack(ItemStack("mymod:t1_2"))
-- Test charging, 10kEU / cycle
assert.equals(0, technic.get_RE_charge(get_charge_stack()))
mineunit:execute_globalstep(1)
assert.equals(2, technic.get_RE_charge(get_charge_stack()))
end)
it("t1_10001 can be charged", function()
-- Add tool to battery box
set_charge_stack(ItemStack("mymod:t1_10001"))
-- Test charging, 10kEU / cycle
assert.equals(0, technic.get_RE_charge(get_charge_stack()))
mineunit:execute_globalstep(1)
assert.equals(10000, technic.get_RE_charge(get_charge_stack()))
mineunit:execute_globalstep(1)
assert.equals(10001, technic.get_RE_charge(get_charge_stack()))
end)
it("t1_65535 can be charged", function()
-- Add tool to battery box
set_charge_stack(ItemStack("mymod:t1_65535"))
-- Test charging, 10kEU / cycle
assert.equals(0, technic.get_RE_charge(get_charge_stack()))
for i=1,6 do mineunit:execute_globalstep(1) end
assert.equals(60000, technic.get_RE_charge(get_charge_stack()))
mineunit:execute_globalstep(1)
assert.equals(65535, technic.get_RE_charge(get_charge_stack()))
end)
it("t1_65536 can be charged", function()
-- Add tool to battery box
set_charge_stack(ItemStack("mymod:t1_65536"))
-- Test charging, 10kEU / cycle
assert.equals(0, technic.get_RE_charge(get_charge_stack()))
for i=1,6 do mineunit:execute_globalstep(1) end
assert.equals(60000, technic.get_RE_charge(get_charge_stack()))
mineunit:execute_globalstep(1)
assert.equals(65536, technic.get_RE_charge(get_charge_stack()))
end)
it("t100_6553500 can be charged", function()
-- Add tool to battery box
set_charge_stack(ItemStack("mymod:t100_6553500"))
-- Test charging, 10kEU / cycle
assert.equals(0, technic.get_RE_charge(get_charge_stack()))
for i=1,6 do mineunit:execute_globalstep(1) end
assert.equals(60000, technic.get_RE_charge(get_charge_stack()))
mineunit:execute_globalstep(1)
assert.equals(70000, technic.get_RE_charge(get_charge_stack()))
end)
it("t100_6553600 can be charged", function()
-- Add tool to battery box
set_charge_stack(ItemStack("mymod:t100_6553600"))
-- Test charging, 10kEU / cycle
assert.equals(0, technic.get_RE_charge(get_charge_stack()))
for i=1,7 do mineunit:execute_globalstep(1) end
-- This tool already has small charge error and it is acceptable as long as error stays small
-- Charge value must be 69999-70001 after 7 charge cycles
assert.lt(69998, technic.get_RE_charge(get_charge_stack()))
assert.gt(70002, technic.get_RE_charge(get_charge_stack()))
end)
it("t100_6553600 can be used", function()
-- Add tool to battery box
local stack = ItemStack("mymod:t100_6553600")
technic.set_RE_charge(stack, 700)
set_player_stack(stack)
-- Test using, 100 / cycle
for i=1,6 do player:do_use({x=0, y=0, z=0}) end
assert.equals(100, technic.get_RE_charge(get_player_stack()))
player:do_use({x=0, y=0, z=0})
assert.equals(0, 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())
set_discharge_stack(ItemStack())
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(itemdef.technic_max_charge)
assert.gt(itemdef.technic_max_charge, 0)
end)
it("charge is used", function()
-- Get fully charged item
local stack = ItemStack(itemname)
technic.set_RE_charge(stack, itemdef.technic_max_charge)
set_player_stack(stack)
-- Use item, flashlight charge is used every globalstep and there's no on_use definition
spy.on(technic, "use_RE_charge")
for i=1, 100 do
mineunit:execute_globalstep(1)
end
assert.spy(technic.use_RE_charge).called(100)
-- Check that item charge was actually used and error is acceptable
local charge_used = itemdef.technic_max_charge - 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)
describe("Multimeter", function()
local itemname = "technic:multimeter"
local itemdef = minetest.registered_items[itemname]
setup(function()
set_charge_stack(ItemStack())
set_discharge_stack(ItemStack())
mineunit:execute_on_joinplayer(player)
player:get_inventory():set_stack("main", 1, itemname)
end)
teardown(function()
mineunit:execute_on_leaveplayer(player)
end)
it("is registered", function()
assert.is_hashed(itemdef)
assert.is_function(itemdef.on_use)
assert.is_function(itemdef.on_refill)
assert.equals("technic_RE_charge", itemdef.wear_represents)
assert.is_number(itemdef.technic_max_charge)
assert.gt(itemdef.technic_max_charge, 0)
end)
it("new item can be used", function()
spy.on(itemdef, "on_use")
player:do_use({x=0, y=0, z=0})
assert.spy(itemdef.on_use).called(1)
end)
it("has zero charge", function()
local stack = player:get_wielded_item()
assert.is_ItemStack(stack)
assert.is_false(stack:is_empty())
assert.equals(0, technic.get_RE_charge(stack))
end)
it("can be charged", function()
-- Put item from player inventory to battery box src inventory
player:do_metadata_inventory_put(BB_Charge_POS, "src", 1)
-- Verify that item charge is empty and charge in battery box for 30 seconds
assert.equals(0, technic.get_RE_charge(get_charge_stack()))
for i=1, 30 do
mineunit:execute_globalstep(1)
end
-- Take item from battery box and check charge / wear values
player:do_metadata_inventory_take(BB_Charge_POS, "src", 1)
assert.gt(itemdef.technic_max_charge, 0)
assert.equals(itemdef.technic_max_charge, technic.get_RE_charge(get_player_stack()))
end)
it("charge is used", function()
spy.on(itemdef, "on_use")
player:set_pos(vector.add(BB_Charge_POS, {x=0,y=1,z=0}))
player:do_use(BB_Charge_POS)
assert.spy(itemdef.on_use).called(1)
-- Check that item charge was actually used and is not zero
local charge = technic.get_RE_charge(get_player_stack())
assert.is_number(charge)
assert.gt(charge, 0)
assert.lt(charge, itemdef.technic_max_charge)
end)
it("can be discharged", function()
-- Put item from player inventory to battery box src inventory
player:do_metadata_inventory_put(BB_Discharge_POS, "dst", 1)
-- Verify that item is charged and discharge in battery box for 3 seconds
assert.lt(itemdef.technic_max_charge / 2, technic.get_RE_charge(get_discharge_stack()))
for i=1, 3 do
mineunit:execute_globalstep(1)
end
-- Take item from battery box and check charge / wear values
player:do_metadata_inventory_take(BB_Discharge_POS, "dst", 1)
assert.gt(itemdef.technic_max_charge, 0)
assert.equals(0, technic.get_RE_charge(get_player_stack()))
end)
end)
describe("technic_addons:chainsawmk3", function()
-- Not running technic_addons:chainsawmk3 tests, this tools is just example of
-- actually available mod where max_charge vs use ratio goes over safe limits.
if not RUN_TECHNIC_ADDONS_CHAINSAWMK3_TESTS then return end
local itemname = "technic_addons:chainsawmk3"
local itemdef = minetest.registered_items[itemname]
setup(function()
world.add_layout({
-- Some wood for chainsaw
{{{x=-10,y=0,z=-10},{x=10,y=10,z=10}}, "default:wood"},
})
set_charge_stack(ItemStack())
set_discharge_stack(ItemStack())
mineunit:execute_on_joinplayer(player)
set_player_stack(itemname)
end)
teardown(function()
mineunit:execute_on_leaveplayer(player)
end)
it("is registered", function()
assert.is_hashed(itemdef)
assert.is_function(itemdef.on_use)
assert.is_function(itemdef.on_refill)
assert.equals("technic_RE_charge", itemdef.wear_represents)
assert.is_number(itemdef.technic_max_charge)
assert.gt(itemdef.technic_max_charge, 0)
end)
it("new item can be used", function()
spy.on(itemdef, "on_use")
player:do_use({x=0, y=0, z=0})
assert.spy(itemdef.on_use).called(1)
end)
it("has zero charge", function()
local stack = player:get_wielded_item()
assert.is_ItemStack(stack)
assert.is_false(stack:is_empty())
assert.equals(0, technic.get_RE_charge(stack))
end)
it("can be charged", function()
-- Put item from player inventory to battery box src inventory
player:do_metadata_inventory_put(BB_Charge_POS, "src", 1)
-- Verify that item charge is empty and charge in battery box for 30 seconds
assert.equals(0, technic.get_RE_charge(get_charge_stack()))
for i=0, math.ceil(itemdef.technic_max_charge / 10000) do
mineunit:execute_globalstep(1)
end
-- Take item from battery box and check charge / wear values
player:do_metadata_inventory_take(BB_Charge_POS, "src", 1)
assert.gt(itemdef.technic_max_charge, 0)
assert.equals(itemdef.technic_max_charge, technic.get_RE_charge(get_player_stack()))
end)
it("charge is used", function()
spy.on(itemdef, "on_use")
player:set_pos({x=0,y=1,z=0})
player:do_use(player:get_pos())
assert.spy(itemdef.on_use).called(1)
-- Check that item charge was actually used and is not zero
local charge_used = itemdef.technic_max_charge - technic.get_RE_charge(get_player_stack())
local accurate_use = 21 * 21 * 11 * 10 -- Area times use per node
local acceptable_error = accurate_use * 0.0001
assert.gt(accurate_use + acceptable_error, charge_used)
assert.lt(accurate_use - acceptable_error, charge_used)
assert.equals(accurate_use, charge_used)
end)
end)
end)