forked from minetest-mods/mesecons
Add automated tests for some mods (#605)
Depends on mineunit from https://github.com/S-S-X/mineunit mesecons, mesecons_mvps, mesecons_fpga, and mesecons_luacontroller are now tested.
This commit is contained in:
parent
2ede29df9c
commit
c10ce2dbc5
26
.github/workflows/check-release.yml
vendored
26
.github/workflows/check-release.yml
vendored
|
@ -13,3 +13,29 @@ jobs:
|
|||
run: luarocks install --local luacheck
|
||||
- name: luacheck run
|
||||
run: $HOME/.luarocks/bin/luacheck ./
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@main
|
||||
- name: apt
|
||||
run: sudo apt-get install -y luarocks
|
||||
- name: busted install
|
||||
run: luarocks install --local busted
|
||||
- name: luacov install
|
||||
run: luarocks install --local luacov
|
||||
- name: mineunit install
|
||||
run: luarocks install --server=https://luarocks.org/dev --local mineunit
|
||||
- name: run mesecons tests
|
||||
working-directory: ./mesecons/
|
||||
run: $HOME/.luarocks/bin/mineunit -q
|
||||
- name: run mesecons_mvps tests
|
||||
working-directory: ./mesecons_mvps/
|
||||
run: $HOME/.luarocks/bin/mineunit -q
|
||||
- name: run mesecons_fpga tests
|
||||
working-directory: ./mesecons_fpga/
|
||||
run: $HOME/.luarocks/bin/mineunit -q
|
||||
- name: run mesecons_luacontroller tests
|
||||
working-directory: ./mesecons_luacontroller/
|
||||
run: $HOME/.luarocks/bin/mineunit -q
|
||||
|
|
23
.luacheckrc
23
.luacheckrc
|
@ -34,3 +34,26 @@ globals = {"mesecon"}
|
|||
files["mesecons/actionqueue.lua"] = {
|
||||
globals = {"minetest.registered_globalsteps"},
|
||||
}
|
||||
|
||||
-- Test-specific stuff follows.
|
||||
|
||||
local test_conf = {
|
||||
read_globals = {
|
||||
"assert",
|
||||
"fixture",
|
||||
"mineunit",
|
||||
"Player",
|
||||
"sourcefile",
|
||||
"world",
|
||||
},
|
||||
}
|
||||
files["*/spec/*.lua"] = test_conf
|
||||
files[".test_fixtures/*.lua"] = test_conf
|
||||
|
||||
files[".test_fixtures/screwdriver.lua"] = {
|
||||
globals = {"screwdriver"},
|
||||
}
|
||||
|
||||
files[".test_fixtures/mesecons_fpga.lua"] = {
|
||||
globals = {"minetest.register_on_player_receive_fields"},
|
||||
}
|
||||
|
|
156
.test_fixtures/mesecons.lua
Normal file
156
.test_fixtures/mesecons.lua
Normal file
|
@ -0,0 +1,156 @@
|
|||
mineunit("core")
|
||||
mineunit("server")
|
||||
mineunit("voxelmanip")
|
||||
|
||||
mineunit:set_current_modname("mesecons")
|
||||
mineunit:set_modpath("mesecons", "../mesecons")
|
||||
sourcefile("../mesecons/init")
|
||||
|
||||
-- Utility node: this conductor is used to test the connectivity and state of adjacent wires.
|
||||
do
|
||||
local off_spec = {conductor = {
|
||||
state = mesecon.state.off,
|
||||
rules = mesecon.rules.alldirs,
|
||||
onstate = "mesecons:test_conductor_on",
|
||||
}}
|
||||
local on_spec = {conductor = {
|
||||
state = mesecon.state.on,
|
||||
rules = mesecon.rules.alldirs,
|
||||
offstate = "mesecons:test_conductor_off",
|
||||
}}
|
||||
mesecon.register_node("mesecons:test_conductor", {
|
||||
description = "Test Conductor",
|
||||
}, {mesecons = off_spec}, {mesecons = on_spec})
|
||||
end
|
||||
|
||||
-- Utility node: this receptor is used to test power sources.
|
||||
do
|
||||
local off_spec = {receptor = {
|
||||
state = mesecon.state.off,
|
||||
rules = mesecon.rules.alldirs,
|
||||
}}
|
||||
local on_spec = {receptor = {
|
||||
state = mesecon.state.on,
|
||||
rules = mesecon.rules.alldirs,
|
||||
}}
|
||||
mesecon.register_node("mesecons:test_receptor", {
|
||||
description = "Test Receptor",
|
||||
}, {mesecons = off_spec}, {mesecons = on_spec})
|
||||
end
|
||||
|
||||
-- Utility node: this effector is used to test circuit outputs.
|
||||
do
|
||||
-- This is a list of actions in the form {<kind>, <pos>},
|
||||
-- where <kind> is "on", "off", or "overheat".
|
||||
mesecon._test_effector_events = {}
|
||||
local function action_on(pos, node)
|
||||
table.insert(mesecon._test_effector_events, {"on", pos})
|
||||
node.param2 = node.param2 % 64 + 128 -- Turn on bit 7
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
local function action_off(pos, node)
|
||||
table.insert(mesecon._test_effector_events, {"off", pos})
|
||||
node.param2 = node.param2 % 64 -- Turn off bit 7
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
local function action_change(pos, node, rule_name, new_state)
|
||||
if mesecon.do_overheat(pos) then
|
||||
table.insert(mesecon._test_effector_events, {"overheat", pos})
|
||||
minetest.remove_node(pos)
|
||||
return
|
||||
end
|
||||
-- Set the value of a bit in param2 according to the rule name and new state.
|
||||
local bit = tonumber(rule_name.name, 2)
|
||||
local bits_above = node.param2 - node.param2 % (bit * 2)
|
||||
local bits_below = node.param2 % bit
|
||||
local bits_flipped = new_state == mesecon.state.on and bit or 0
|
||||
node.param2 = bits_above + bits_flipped + bits_below
|
||||
minetest.swap_node(pos, node)
|
||||
end
|
||||
minetest.register_node("mesecons:test_effector", {
|
||||
description = "Test Effector",
|
||||
mesecons = {effector = {
|
||||
action_on = action_on,
|
||||
action_off = action_off,
|
||||
action_change = action_change,
|
||||
rules = {
|
||||
{x = 1, y = 0, z = 0, name = "000001"},
|
||||
{x = -1, y = 0, z = 0, name = "000010"},
|
||||
{x = 0, y = 1, z = 0, name = "000100"},
|
||||
{x = 0, y = -1, z = 0, name = "001000"},
|
||||
{x = 0, y = 0, z = 1, name = "010000"},
|
||||
{x = 0, y = 0, z = -1, name = "100000"},
|
||||
}
|
||||
}},
|
||||
})
|
||||
end
|
||||
|
||||
-- Utility node: this conductor is used to test rotation.
|
||||
do
|
||||
local get_rules = mesecon.horiz_rules_getter({{x = 1, y = 0, z = 0}, {x = -1, y = 0, z = 0}})
|
||||
local off_spec = {conductor = {
|
||||
state = mesecon.state.off,
|
||||
rules = get_rules,
|
||||
onstate = "mesecons:test_conductor_rot_on",
|
||||
}}
|
||||
local on_spec = {conductor = {
|
||||
state = mesecon.state.on,
|
||||
rules = get_rules,
|
||||
offstate = "mesecons:test_conductor_rot_off",
|
||||
}}
|
||||
mesecon.register_node("mesecons:test_conductor_rot", {
|
||||
description = "Rotatable Test Conductor",
|
||||
on_rotate = mesecon.on_rotate_horiz,
|
||||
}, {mesecons = off_spec}, {mesecons = on_spec})
|
||||
end
|
||||
|
||||
-- Utility node: this is used to test multiple conductors within a single node.
|
||||
do
|
||||
local mesecons_spec = {conductor = {
|
||||
rules = {
|
||||
{{x = 1, y = 0, z = 0}, {x = 0, y = -1, z = 0}},
|
||||
{{x = 0, y = 1, z = 0}, {x = 0, y = 0, z = -1}},
|
||||
{{x = 0, y = 0, z = 1}, {x = -1, y = 0, z = 0}},
|
||||
},
|
||||
states = {
|
||||
"mesecons:test_multiconductor_off", "mesecons:test_multiconductor_001",
|
||||
"mesecons:test_multiconductor_010", "mesecons:test_multiconductor_011",
|
||||
"mesecons:test_multiconductor_100", "mesecons:test_multiconductor_101",
|
||||
"mesecons:test_multiconductor_110", "mesecons:test_multiconductor_on",
|
||||
},
|
||||
}}
|
||||
for _, state in ipairs(mesecons_spec.conductor.states) do
|
||||
minetest.register_node(state, {
|
||||
description = "Test Multiconductor",
|
||||
mesecons = mesecons_spec,
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
mesecon._test_autoconnects = {}
|
||||
mesecon.register_autoconnect_hook("test", function(pos, node)
|
||||
table.insert(mesecon._test_autoconnects, {pos, node})
|
||||
end)
|
||||
|
||||
function mesecon._test_dig(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
minetest.remove_node(pos)
|
||||
mesecon.on_dignode(pos, node)
|
||||
end
|
||||
|
||||
function mesecon._test_place(pos, node)
|
||||
world.set_node(pos, node)
|
||||
mesecon.on_placenode(pos, minetest.get_node(pos))
|
||||
end
|
||||
|
||||
function mesecon._test_reset()
|
||||
-- First let circuits settle by simulating many globalsteps.
|
||||
for i = 1, 10 do
|
||||
mineunit:execute_globalstep(60)
|
||||
end
|
||||
mesecon.queue.actions = {}
|
||||
mesecon._test_effector_events = {}
|
||||
mesecon._test_autoconnects = {}
|
||||
end
|
||||
|
||||
mineunit:execute_globalstep(mesecon.setting("resumetime", 4) + 1)
|
59
.test_fixtures/mesecons_fpga.lua
Normal file
59
.test_fixtures/mesecons_fpga.lua
Normal file
|
@ -0,0 +1,59 @@
|
|||
mineunit("player")
|
||||
|
||||
fixture("mesecons")
|
||||
fixture("mesecons_gamecompat")
|
||||
|
||||
local registered_on_player_receive_fields = {}
|
||||
local old_register_on_player_receive_fields = minetest.register_on_player_receive_fields
|
||||
function minetest.register_on_player_receive_fields(func)
|
||||
old_register_on_player_receive_fields(func)
|
||||
table.insert(registered_on_player_receive_fields, func)
|
||||
end
|
||||
|
||||
mineunit:set_current_modname("mesecons_fpga")
|
||||
mineunit:set_modpath("mesecons_fpga", "../mesecons_fpga")
|
||||
sourcefile("../mesecons_fpga/init")
|
||||
|
||||
local fpga_user = Player("mesecons_fpga_user")
|
||||
|
||||
function mesecon._test_program_fpga(pos, program)
|
||||
local node = minetest.get_node(pos)
|
||||
assert.equal("mesecons_fpga:fpga", node.name:sub(1, 18))
|
||||
|
||||
local fields = {program = true}
|
||||
for i, instr in ipairs(program) do
|
||||
-- Translate the instruction into formspec fields.
|
||||
local op1, act, op2, dst
|
||||
if #instr == 3 then
|
||||
act, op2, dst = unpack(instr)
|
||||
else
|
||||
assert.equal(4, #instr)
|
||||
op1, act, op2, dst = unpack(instr)
|
||||
end
|
||||
fields[i .. "op1"] = op1
|
||||
fields[i .. "act"] = (" "):rep(4 - #act) .. act
|
||||
fields[i .. "op2"] = op2
|
||||
fields[i .. "dst"] = dst
|
||||
end
|
||||
|
||||
minetest.registered_nodes[node.name].on_rightclick(pos, node, fpga_user)
|
||||
|
||||
for _, func in ipairs(registered_on_player_receive_fields) do
|
||||
if func(fpga_user, "mesecons:fpga", fields) then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mesecon._test_copy_fpga_program(pos)
|
||||
fpga_user:get_inventory():set_stack("main", 1, "mesecons_fpga:programmer")
|
||||
local pt = {type = "node", under = vector.new(pos), above = vector.offset(pos, 0, 1, 0)}
|
||||
fpga_user:do_place(pt)
|
||||
return fpga_user:get_wielded_item()
|
||||
end
|
||||
|
||||
function mesecon._test_paste_fpga_program(pos, tool)
|
||||
fpga_user:get_inventory():set_stack("main", 1, tool)
|
||||
local pt = {type = "node", under = vector.new(pos), above = vector.offset(pos, 0, 1, 0)}
|
||||
fpga_user:do_use(pt)
|
||||
end
|
5
.test_fixtures/mesecons_gamecompat.lua
Normal file
5
.test_fixtures/mesecons_gamecompat.lua
Normal file
|
@ -0,0 +1,5 @@
|
|||
fixture("mesecons")
|
||||
|
||||
mineunit:set_current_modname("mesecons_gamecompat")
|
||||
mineunit:set_modpath("mesecons_gamecompat", "../mesecons_gamecompat")
|
||||
sourcefile("../mesecons_gamecompat/init")
|
12
.test_fixtures/mesecons_luacontroller.lua
Normal file
12
.test_fixtures/mesecons_luacontroller.lua
Normal file
|
@ -0,0 +1,12 @@
|
|||
fixture("mesecons")
|
||||
fixture("mesecons_gamecompat")
|
||||
|
||||
mineunit:set_current_modname("mesecons_luacontroller")
|
||||
mineunit:set_modpath("mesecons_luacontroller", "../mesecons_luacontroller")
|
||||
sourcefile("../mesecons_luacontroller/init")
|
||||
|
||||
function mesecon._test_program_luac(pos, code)
|
||||
local node = minetest.get_node(pos)
|
||||
assert.equal("mesecons_luacontroller:luacontroller", node.name:sub(1, 36))
|
||||
return minetest.registered_nodes[node.name].mesecons.luacontroller.set_program(pos, code)
|
||||
end
|
45
.test_fixtures/mesecons_mvps.lua
Normal file
45
.test_fixtures/mesecons_mvps.lua
Normal file
|
@ -0,0 +1,45 @@
|
|||
mineunit("protection")
|
||||
|
||||
fixture("mesecons")
|
||||
|
||||
mineunit:set_current_modname("mesecons_mvps")
|
||||
mineunit:set_modpath("mesecons_mvps", "../mesecons_mvps")
|
||||
sourcefile("../mesecons_mvps/init")
|
||||
|
||||
minetest.register_node("mesecons_mvps:test_stopper", {
|
||||
description = "Test Stopper",
|
||||
})
|
||||
mesecon.register_mvps_stopper("mesecons_mvps:test_stopper")
|
||||
|
||||
minetest.register_node("mesecons_mvps:test_stopper_cond", {
|
||||
description = "Test Stopper (Conditional)",
|
||||
})
|
||||
mesecon.register_mvps_stopper("mesecons_mvps:test_stopper_cond", function(node)
|
||||
return node.param2 == 0
|
||||
end)
|
||||
|
||||
minetest.register_node("mesecons_mvps:test_sticky", {
|
||||
description = "Test Sticky",
|
||||
mvps_sticky = function(pos)
|
||||
local connected = {}
|
||||
for i, rule in ipairs(mesecon.rules.alldirs) do
|
||||
connected[i] = vector.add(pos, rule)
|
||||
end
|
||||
return connected
|
||||
end,
|
||||
})
|
||||
|
||||
mesecon._test_moves = {}
|
||||
minetest.register_node("mesecons_mvps:test_on_move", {
|
||||
description = "Test Moveable",
|
||||
mesecon = {
|
||||
on_mvps_move = function(pos, node, oldpos, meta)
|
||||
table.insert(mesecon._test_moves, {pos, node, oldpos, meta})
|
||||
end
|
||||
},
|
||||
})
|
||||
local old_reset = mesecon._test_reset
|
||||
function mesecon._test_reset()
|
||||
mesecon._test_moves = {}
|
||||
old_reset()
|
||||
end
|
6
.test_fixtures/screwdriver.lua
Normal file
6
.test_fixtures/screwdriver.lua
Normal file
|
@ -0,0 +1,6 @@
|
|||
mineunit:set_current_modname("screwdriver")
|
||||
|
||||
screwdriver = {}
|
||||
|
||||
screwdriver.ROTATE_FACE = 1
|
||||
screwdriver.ROTATE_AXIS = 2
|
62
mesecons/spec/action_spec.lua
Normal file
62
mesecons/spec/action_spec.lua
Normal file
|
@ -0,0 +1,62 @@
|
|||
require("mineunit")
|
||||
|
||||
fixture("mesecons")
|
||||
|
||||
describe("action queue", function()
|
||||
local layout = {
|
||||
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_off"},
|
||||
{{x = 0, y = 0, z = 0}, "mesecons:test_conductor_off"},
|
||||
{{x = -1, y = 0, z = 0}, "mesecons:test_conductor_off"},
|
||||
{{x = 0, y = 1, z = 0}, "mesecons:test_effector"},
|
||||
{{x = -1, y = 1, z = 0}, "mesecons:test_effector"},
|
||||
}
|
||||
|
||||
before_each(function()
|
||||
world.layout(layout)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("executes in order", function()
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal(2, #mesecon._test_effector_events)
|
||||
assert.same({"on", layout[4][1]}, mesecon._test_effector_events[1])
|
||||
assert.same({"on", layout[5][1]}, mesecon._test_effector_events[2])
|
||||
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_off")
|
||||
mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
assert.equal(4, #mesecon._test_effector_events)
|
||||
assert.same({"off", layout[4][1]}, mesecon._test_effector_events[3])
|
||||
assert.same({"off", layout[5][1]}, mesecon._test_effector_events[4])
|
||||
end)
|
||||
|
||||
it("discards outdated/overwritten node events", function()
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_off")
|
||||
mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
assert.equal(0, #mesecon._test_effector_events)
|
||||
end)
|
||||
|
||||
it("delays actions", function()
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_on")
|
||||
mesecon.queue:add_action(layout[1][1], "receptor_on", {mesecon.rules.alldirs}, 1, nil)
|
||||
mineunit:execute_globalstep(0.1)
|
||||
mineunit:execute_globalstep(1)
|
||||
assert.equal(0, #mesecon._test_effector_events)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
assert.equal(0, #mesecon._test_effector_events)
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal(2, #mesecon._test_effector_events)
|
||||
end)
|
||||
end)
|
1
mesecons/spec/mineunit.conf
Normal file
1
mesecons/spec/mineunit.conf
Normal file
|
@ -0,0 +1 @@
|
|||
fixture_paths = {"../.test_fixtures"}
|
192
mesecons/spec/service_spec.lua
Normal file
192
mesecons/spec/service_spec.lua
Normal file
|
@ -0,0 +1,192 @@
|
|||
require("mineunit")
|
||||
|
||||
fixture("mesecons")
|
||||
fixture("screwdriver")
|
||||
|
||||
describe("placement/digging service", function()
|
||||
local layout = {
|
||||
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_on"},
|
||||
{{x = 0, y = 0, z = 0}, "mesecons:test_conductor_on"},
|
||||
{{x = -1, y = 0, z = 0}, "mesecons:test_conductor_on"},
|
||||
{{x = 0, y = 1, z = 0}, "mesecons:test_effector"},
|
||||
{{x = -2, y = 0, z = 0}, "mesecons:test_effector"},
|
||||
{{x = 2, y = 0, z = 0}, "mesecons:test_effector"},
|
||||
}
|
||||
|
||||
before_each(function()
|
||||
world.layout(layout)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("updates components when a receptor changes", function()
|
||||
-- Dig then replace a receptor and check that the connected effectors changed.
|
||||
|
||||
mesecon._test_dig(layout[1][1])
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(layout[2][1]).name)
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
assert.equal(3, #mesecon._test_effector_events)
|
||||
|
||||
mesecon._test_place(layout[1][1], "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[2][1]).name)
|
||||
mineunit:execute_globalstep() -- Execute activate/change action
|
||||
assert.equal(6, #mesecon._test_effector_events)
|
||||
end)
|
||||
|
||||
it("updates components when a conductor changes", function()
|
||||
-- Dig then replace a powered conductor and check that the connected effectors changed.
|
||||
|
||||
mesecon._test_dig(layout[2][1])
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name)
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
assert.equal(2, #mesecon._test_effector_events)
|
||||
|
||||
mesecon._test_place(layout[2][1], "mesecons:test_conductor_off")
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[2][1]).name)
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal(4, #mesecon._test_effector_events)
|
||||
end)
|
||||
|
||||
it("updates effectors on placement", function()
|
||||
local pos = {x = 0, y = 0, z = 1}
|
||||
mesecon._test_place(pos, "mesecons:test_effector")
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal(tonumber("10100000", 2), world.get_node(pos).param2)
|
||||
end)
|
||||
|
||||
it("updates multiconductors on placement", function()
|
||||
local pos = {x = 0, y = 0, z = 1}
|
||||
mesecon._test_place(pos, "mesecons:test_multiconductor_off")
|
||||
assert.equal("mesecons:test_multiconductor_010", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("turns off conductors on placement", function()
|
||||
local pos = {x = 3, y = 0, z = 0}
|
||||
mesecon._test_place(pos, "mesecons:test_conductor_on")
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("turns off multiconductors on placement", function()
|
||||
local pos = {x = 3, y = 0, z = 0}
|
||||
mesecon._test_place(pos, "mesecons:test_multiconductor_on")
|
||||
assert.equal("mesecons:test_multiconductor_off", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("triggers autoconnect hooks", function()
|
||||
mesecon._test_dig(layout[2][1])
|
||||
mineunit:execute_globalstep() -- Execute delayed hook
|
||||
assert.equal(1, #mesecon._test_autoconnects)
|
||||
|
||||
mesecon._test_place(layout[2][1], layout[2][2])
|
||||
assert.equal(2, #mesecon._test_autoconnects)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("overheating service", function()
|
||||
local layout = {
|
||||
{{x = 0, y = 0, z = 0}, "mesecons:test_receptor_off"},
|
||||
{{x = 1, y = 0, z = 0}, "mesecons:test_effector"},
|
||||
{{x = 2, y = 0, z = 0}, "mesecons:test_receptor_on"},
|
||||
}
|
||||
|
||||
before_each(function()
|
||||
world.layout(layout)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("tracks heat", function()
|
||||
mesecon.do_overheat(layout[2][1])
|
||||
assert.equal(1, mesecon.get_heat(layout[2][1]))
|
||||
mesecon.do_cooldown(layout[2][1])
|
||||
assert.equal(0, mesecon.get_heat(layout[2][1]))
|
||||
end)
|
||||
|
||||
it("cools over time", function()
|
||||
mesecon.do_overheat(layout[2][1])
|
||||
assert.equal(1, mesecon.get_heat(layout[2][1]))
|
||||
mineunit:execute_globalstep(60)
|
||||
mineunit:execute_globalstep(60)
|
||||
mineunit:execute_globalstep(60)
|
||||
assert.equal(0, mesecon.get_heat(layout[2][1]))
|
||||
end)
|
||||
|
||||
it("tracks movement", function()
|
||||
local oldpos = layout[2][1]
|
||||
local pos = vector.offset(oldpos, 0, 1, 0)
|
||||
mesecon.do_overheat(oldpos)
|
||||
mesecon.move_hot_nodes({{pos = pos, oldpos = oldpos}})
|
||||
assert.equal(0, mesecon.get_heat(oldpos))
|
||||
assert.equal(1, mesecon.get_heat(pos))
|
||||
end)
|
||||
|
||||
it("causes overheating", function()
|
||||
-- Switch the first receptor on and off until it overheats/breaks a receptor.
|
||||
repeat
|
||||
if mesecon.flipstate(layout[1][1], minetest.get_node(layout[1][1])) == "on" then
|
||||
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
|
||||
else
|
||||
mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs)
|
||||
end
|
||||
mineunit:execute_globalstep(0) -- Execute receptor_on/receptor_off/activate/deactivate/change actions
|
||||
until minetest.get_node(layout[2][1]).name ~= "mesecons:test_effector"
|
||||
assert.same({"overheat", layout[2][1]}, mesecon._test_effector_events[#mesecon._test_effector_events])
|
||||
assert.equal(0, mesecon.get_heat(layout[2][1]))
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("screwdriver service", function()
|
||||
local layout = {
|
||||
{{x = 0, y = 0, z = 0}, "mesecons:test_conductor_rot_on"},
|
||||
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_on"},
|
||||
{{x = -1, y = 0, z = 0}, "mesecons:test_conductor_on"},
|
||||
{{x = 0, y = 0, z = 1}, "mesecons:test_receptor_on"},
|
||||
{{x = 0, y = 0, z = -1}, "mesecons:test_conductor_off"},
|
||||
}
|
||||
|
||||
local function rotate(new_param2)
|
||||
local pos = layout[1][1]
|
||||
local node = world.get_node(pos)
|
||||
local on_rotate = minetest.registered_nodes[node.name].on_rotate
|
||||
on_rotate(pos, node, nil, screwdriver.ROTATE_FACE, new_param2)
|
||||
end
|
||||
|
||||
before_each(function()
|
||||
world.layout(layout)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("updates conductors", function()
|
||||
-- Rotate a conductor and see that the circuit state changes.
|
||||
rotate(1)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name)
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[5][1]).name)
|
||||
rotate(2)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(layout[5][1]).name)
|
||||
rotate(3)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name)
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[5][1]).name)
|
||||
rotate(0)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(layout[5][1]).name)
|
||||
end)
|
||||
end)
|
147
mesecons/spec/state_spec.lua
Normal file
147
mesecons/spec/state_spec.lua
Normal file
|
@ -0,0 +1,147 @@
|
|||
require("mineunit")
|
||||
|
||||
fixture("mesecons")
|
||||
|
||||
describe("state", function()
|
||||
local layout = {
|
||||
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_off"},
|
||||
{{x = 0, y = 1, z = 0}, "mesecons:test_receptor_off"},
|
||||
{{x = 0, y = 0, z = 0}, "mesecons:test_conductor_off"},
|
||||
{{x = -1, y = 0, z = 0}, "mesecons:test_effector"},
|
||||
{{x = 2, y = 0, z = 0}, "mesecons:test_effector"},
|
||||
{{x = 0, y = -1, z = 0}, "mesecons:test_effector"},
|
||||
}
|
||||
|
||||
before_each(function()
|
||||
world.layout(layout)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("turns on", function()
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
|
||||
assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2)
|
||||
assert.equal(tonumber("10000010", 2), world.get_node(layout[5][1]).param2)
|
||||
assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2)
|
||||
|
||||
world.set_node(layout[2][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
|
||||
assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2)
|
||||
assert.equal(tonumber("10000010", 2), world.get_node(layout[5][1]).param2)
|
||||
assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2)
|
||||
end)
|
||||
|
||||
it("turns off", function()
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_on")
|
||||
world.set_node(layout[2][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
|
||||
mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on actions
|
||||
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_off")
|
||||
mesecon.receptor_off(layout[1][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off and activate/change actions
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(layout[3][1]).name)
|
||||
assert.equal(tonumber("10000001", 2), world.get_node(layout[4][1]).param2)
|
||||
assert.equal(tonumber("00000000", 2), world.get_node(layout[5][1]).param2)
|
||||
assert.equal(tonumber("10000100", 2), world.get_node(layout[6][1]).param2)
|
||||
|
||||
world.set_node(layout[2][1], "mesecons:test_receptor_off")
|
||||
mesecon.receptor_off(layout[2][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(layout[3][1]).name)
|
||||
assert.equal(tonumber("00000000", 2), world.get_node(layout[4][1]).param2)
|
||||
assert.equal(tonumber("00000000", 2), world.get_node(layout[5][1]).param2)
|
||||
assert.equal(tonumber("00000000", 2), world.get_node(layout[6][1]).param2)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("rotation", function()
|
||||
local layout = {
|
||||
{{x = 0, y = 0, z = 0}, "mesecons:test_receptor_off"},
|
||||
{{x = 1, y = 0, z = 0}, {name = "mesecons:test_conductor_rot_off", param2 = 0}},
|
||||
{{x = 0, y = 0, z = 1}, {name = "mesecons:test_conductor_rot_off", param2 = 1}},
|
||||
{{x = -1, y = 0, z = 0}, {name = "mesecons:test_conductor_rot_off", param2 = 2}},
|
||||
{{x = 0, y = 0, z = -1}, {name = "mesecons:test_conductor_rot_off", param2 = 3}},
|
||||
}
|
||||
|
||||
before_each(function()
|
||||
for _, entry in ipairs(layout) do
|
||||
world.set_node(entry[1], entry[2])
|
||||
end
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("works", function()
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[2][1]).name)
|
||||
assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[3][1]).name)
|
||||
assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[4][1]).name)
|
||||
assert.equal("mesecons:test_conductor_rot_on", world.get_node(layout[5][1]).name)
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("multiconductor", function()
|
||||
local layout = {
|
||||
{{x = 1, y = 0, z = 0}, "mesecons:test_receptor_off"},
|
||||
{{x = 0, y = 1, z = 0}, "mesecons:test_receptor_off"},
|
||||
{{x = 0, y = 0, z = 1}, "mesecons:test_receptor_off"},
|
||||
{{x = 0, y = 0, z = 0}, "mesecons:test_multiconductor_off"},
|
||||
}
|
||||
|
||||
before_each(function()
|
||||
world.layout(layout)
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
world.clear()
|
||||
mesecon._test_reset()
|
||||
end)
|
||||
|
||||
it("separates its subparts", function()
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
assert.equal("mesecons:test_multiconductor_001", world.get_node(layout[4][1]).name)
|
||||
|
||||
world.set_node(layout[2][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[2][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
assert.equal("mesecons:test_multiconductor_011", world.get_node(layout[4][1]).name)
|
||||
|
||||
world.set_node(layout[3][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[3][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
assert.equal("mesecons:test_multiconductor_on", world.get_node(layout[4][1]).name)
|
||||
end)
|
||||
|
||||
it("loops through itself", function()
|
||||
-- Make a loop.
|
||||
world.set_node({x = 0, y = -1, z = 0}, "mesecons:test_conductor_off")
|
||||
world.set_node({x = -1, y = -1, z = 0}, "mesecons:test_conductor_off")
|
||||
world.set_node({x = -1, y = 0, z = 0}, "mesecons:test_conductor_off")
|
||||
|
||||
world.set_node(layout[1][1], "mesecons:test_receptor_on")
|
||||
mesecon.receptor_on(layout[1][1], mesecon.rules.alldirs)
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
assert.equal("mesecons:test_multiconductor_101", world.get_node(layout[4][1]).name)
|
||||
end)
|
||||
end)
|
107
mesecons_fpga/spec/helper_spec.lua
Normal file
107
mesecons_fpga/spec/helper_spec.lua
Normal file
|
@ -0,0 +1,107 @@
|
|||
require("mineunit")
|
||||
|
||||
fixture("mesecons_fpga")
|
||||
fixture("screwdriver")
|
||||
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local pos_a = {x = -1, y = 0, z = 0}
|
||||
local pos_b = {x = 0, y = 0, z = 1}
|
||||
local pos_c = {x = 1, y = 0, z = 0}
|
||||
local pos_d = {x = 0, y = 0, z = -1}
|
||||
|
||||
describe("FPGA rotation", function()
|
||||
before_each(function()
|
||||
world.set_node(pos, "mesecons_fpga:fpga0000")
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("rotates I/O operands clockwise", function()
|
||||
mesecon._test_program_fpga(pos, {{"A", "OR", "B", "C"}})
|
||||
|
||||
local node = world.get_node(pos)
|
||||
minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_FACE)
|
||||
|
||||
mesecon._test_place(pos_b, "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
|
||||
|
||||
mesecon._test_dig(pos_b)
|
||||
mesecon._test_place(pos_c, "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
|
||||
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
|
||||
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("rotates I/O operands counterclockwise", function()
|
||||
mesecon._test_program_fpga(pos, {{"A", "OR", "B", "C"}})
|
||||
|
||||
local node = world.get_node(pos)
|
||||
minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_AXIS)
|
||||
|
||||
mesecon._test_place(pos_d, "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
|
||||
|
||||
mesecon._test_dig(pos_d)
|
||||
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
|
||||
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
|
||||
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("updates ports", function()
|
||||
mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}})
|
||||
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
|
||||
|
||||
local node = world.get_node(pos)
|
||||
minetest.registered_nodes[node.name].on_rotate(pos, node, nil, screwdriver.ROTATE_AXIS)
|
||||
assert.equal("mesecons_fpga:fpga0001", world.get_node(pos).name)
|
||||
end)
|
||||
end)
|
||||
|
||||
-- mineunit does not support deprecated ItemStack:get_metadata()
|
||||
pending("FPGA programmer", function()
|
||||
local pos2 = {x = 10, y = 0, z = 0}
|
||||
|
||||
before_each(function()
|
||||
world.set_node(pos, "mesecons_fpga:fpga0000")
|
||||
world.set_node(pos2, "mesecons_fpga:fpga0000")
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("transfers instructions", function()
|
||||
mesecon._test_program_fpga(pos2, {{"NOT", "A", "B"}})
|
||||
mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2))
|
||||
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("does not copy from new FPGAs", function()
|
||||
mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}})
|
||||
mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2))
|
||||
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("does not copy from cleared FPGAs", function()
|
||||
mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}})
|
||||
mesecon._test_program_fpga(pos2, {{"=", "A", "B"}})
|
||||
mesecon._test_program_fpga(pos2, {})
|
||||
mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(pos2))
|
||||
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("does not copy from non-FPGA nodes", function()
|
||||
mesecon._test_program_fpga(pos, {{"NOT", "A", "B"}})
|
||||
mesecon._test_paste_fpga_program(pos, mesecon._test_copy_fpga_program(vector.add(pos2, 1)))
|
||||
assert.equal("mesecons_fpga:fpga0010", world.get_node(pos).name)
|
||||
end)
|
||||
end)
|
235
mesecons_fpga/spec/logic_spec.lua
Normal file
235
mesecons_fpga/spec/logic_spec.lua
Normal file
|
@ -0,0 +1,235 @@
|
|||
require("mineunit")
|
||||
|
||||
fixture("mesecons_fpga")
|
||||
|
||||
describe("FPGA logic", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local pos_a = {x = -1, y = 0, z = 0}
|
||||
local pos_b = {x = 0, y = 0, z = 1}
|
||||
local pos_c = {x = 1, y = 0, z = 0}
|
||||
local pos_d = {x = 0, y = 0, z = -1}
|
||||
|
||||
local fpga_set = false
|
||||
|
||||
local function set_fpga()
|
||||
if not fpga_set then
|
||||
world.set_node(pos, "mesecons_fpga:fpga0000")
|
||||
fpga_set = true
|
||||
end
|
||||
end
|
||||
before_each(set_fpga)
|
||||
|
||||
local function reset_world()
|
||||
if fpga_set then
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
fpga_set = false
|
||||
end
|
||||
end
|
||||
after_each(reset_world)
|
||||
|
||||
local function test_program(inputs, outputs, program)
|
||||
set_fpga()
|
||||
|
||||
mesecon._test_program_fpga(pos, program)
|
||||
|
||||
if inputs.a then mesecon._test_place(pos_a, "mesecons:test_receptor_on") end
|
||||
if inputs.b then mesecon._test_place(pos_b, "mesecons:test_receptor_on") end
|
||||
if inputs.c then mesecon._test_place(pos_c, "mesecons:test_receptor_on") end
|
||||
if inputs.d then mesecon._test_place(pos_d, "mesecons:test_receptor_on") end
|
||||
mineunit:execute_globalstep() -- Execute receptor_on actions
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
|
||||
local expected_name = "mesecons_fpga:fpga"
|
||||
.. (outputs.d and 1 or 0) .. (outputs.c and 1 or 0)
|
||||
.. (outputs.b and 1 or 0) .. (outputs.a and 1 or 0)
|
||||
assert.equal(expected_name, world.get_node(pos).name)
|
||||
|
||||
reset_world()
|
||||
end
|
||||
|
||||
it("operator and", function()
|
||||
local prog = {{"A", "AND", "B", "C"}}
|
||||
test_program({}, {}, prog)
|
||||
test_program({a = true}, {}, prog)
|
||||
test_program({b = true}, {}, prog)
|
||||
test_program({a = true, b = true}, {c = true}, prog)
|
||||
end)
|
||||
|
||||
it("operator or", function()
|
||||
local prog = {{"A", "OR", "B", "C"}}
|
||||
test_program({}, {}, prog)
|
||||
test_program({a = true}, {c = true}, prog)
|
||||
test_program({b = true}, {c = true}, prog)
|
||||
test_program({a = true, b = true}, {c = true}, prog)
|
||||
end)
|
||||
|
||||
it("operator not", function()
|
||||
local prog = {{"NOT", "A", "B"}}
|
||||
test_program({}, {b = true}, prog)
|
||||
test_program({a = true}, {}, prog)
|
||||
end)
|
||||
|
||||
it("operator xor", function()
|
||||
local prog = {{"A", "XOR", "B", "C"}}
|
||||
test_program({}, {}, prog)
|
||||
test_program({a = true}, {c = true}, prog)
|
||||
test_program({b = true}, {c = true}, prog)
|
||||
test_program({a = true, b = true}, {}, prog)
|
||||
end)
|
||||
|
||||
it("operator nand", function()
|
||||
local prog = {{"A", "NAND", "B", "C"}}
|
||||
test_program({}, {c = true}, prog)
|
||||
test_program({a = true}, {c = true}, prog)
|
||||
test_program({b = true}, {c = true}, prog)
|
||||
test_program({a = true, b = true}, {}, prog)
|
||||
end)
|
||||
|
||||
it("operator buf", function()
|
||||
local prog = {{"=", "A", "B"}}
|
||||
test_program({}, {}, prog)
|
||||
test_program({a = true}, {b = true}, prog)
|
||||
end)
|
||||
|
||||
it("operator xnor", function()
|
||||
local prog = {{"A", "XNOR", "B", "C"}}
|
||||
test_program({}, {c = true}, prog)
|
||||
test_program({a = true}, {}, prog)
|
||||
test_program({b = true}, {}, prog)
|
||||
test_program({a = true, b = true}, {c = true}, prog)
|
||||
end)
|
||||
|
||||
it("operator nor", function()
|
||||
local prog = {{"A", "NOR", "B", "C"}}
|
||||
test_program({}, {c = true}, prog)
|
||||
test_program({a = true}, {}, prog)
|
||||
test_program({b = true}, {}, prog)
|
||||
test_program({a = true, b = true}, {}, prog)
|
||||
end)
|
||||
|
||||
it("rejects duplicate operands", function()
|
||||
test_program({a = true}, {}, {{"A", "OR", "A", "B"}})
|
||||
test_program({a = true}, {}, {{"=", "A", "0"}, {"0", "OR", "0", "B"}})
|
||||
end)
|
||||
|
||||
it("rejects unassigned memory operands", function()
|
||||
test_program({a = true}, {}, {{"A", "OR", "0", "B"}})
|
||||
test_program({a = true}, {}, {{"0", "OR", "A", "B"}})
|
||||
end)
|
||||
|
||||
it("rejects double memory assignment", function()
|
||||
test_program({a = true}, {}, {{"=", "A", "0"}, {"=", "A", "0"}, {"=", "0", "B"}})
|
||||
end)
|
||||
|
||||
it("rejects assignment to memory operand", function()
|
||||
test_program({a = true}, {}, {{"=", "A", "0"}, {"A", "OR", "0", "0"}, {"=", "0", "B"}})
|
||||
end)
|
||||
|
||||
it("allows double port assignment", function()
|
||||
test_program({a = true}, {b = true}, {{"NOT", "A", "B"}, {"=", "A", "B"}})
|
||||
end)
|
||||
|
||||
it("allows assignment to port operand", function()
|
||||
test_program({a = true}, {b = true}, {{"A", "OR", "B", "B"}})
|
||||
end)
|
||||
|
||||
it("preserves initial pin states", function()
|
||||
test_program({a = true}, {b = true}, {{"=", "A", "B"}, {"=", "B", "C"}})
|
||||
end)
|
||||
|
||||
it("rejects binary operations with single operands", function()
|
||||
test_program({a = true}, {}, {{"=", "A", "B"}, {" ", "OR", "A", "C"}})
|
||||
test_program({a = true}, {}, {{"=", "A", "B"}, {"A", "OR", " ", "C"}})
|
||||
end)
|
||||
|
||||
it("rejects unary operations with first operands", function()
|
||||
test_program({a = true}, {}, {{"=", "A", "B"}, {"A", "=", " ", "C"}})
|
||||
end)
|
||||
|
||||
it("rejects operations without destinations", function()
|
||||
test_program({a = true}, {}, {{"=", "A", "B"}, {"=", "A", " "}})
|
||||
end)
|
||||
|
||||
it("allows blank statements", function()
|
||||
test_program({a = true}, {b = true, c = true}, {
|
||||
{" ", " ", " ", " "},
|
||||
{"=", "A", "B"},
|
||||
{" ", " ", " ", " "},
|
||||
{" ", " ", " ", " "},
|
||||
{"=", "A", "C"},
|
||||
})
|
||||
end)
|
||||
|
||||
it("transmits output signals to adjacent nodes", function()
|
||||
mesecon._test_program_fpga(pos, {
|
||||
{"=", "A", "B"},
|
||||
{"=", "A", "C"},
|
||||
{"NOT", "A", "D"},
|
||||
})
|
||||
mesecon._test_place(pos_b, "mesecons:test_effector")
|
||||
mesecon._test_place(pos_c, "mesecons:test_effector")
|
||||
mesecon._test_place(pos_d, "mesecons:test_effector")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on actions
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
|
||||
-- Makes an object from the last three effector events in the list for use with assert.same.
|
||||
-- This is necessary to ignore the ordering of events.
|
||||
local function event_tester(list)
|
||||
local o = {list[#list - 2], list[#list - 1], list[#list - 0]}
|
||||
table.sort(o, function(a, b)
|
||||
local fmt = "%s %d %d %d"
|
||||
return fmt:format(a[1], a[2].x, a[2].y, a[2].z) < fmt:format(b[1], b[2].x, b[2].y, b[2].z)
|
||||
end)
|
||||
return o
|
||||
end
|
||||
|
||||
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
|
||||
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
|
||||
assert.equal("mesecons_fpga:fpga0110", world.get_node(pos).name)
|
||||
assert.same(event_tester({{"on", pos_b}, {"on", pos_c}, {"off", pos_d}}), event_tester(mesecon._test_effector_events))
|
||||
|
||||
mesecon._test_dig(pos_a)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
|
||||
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
|
||||
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
|
||||
assert.same(event_tester({{"off", pos_b}, {"off", pos_c}, {"on", pos_d}}), event_tester(mesecon._test_effector_events))
|
||||
end)
|
||||
|
||||
it("considers past outputs in determining inputs", function()
|
||||
-- Memory cell: Turning on A turns on C; turning on B turns off C.
|
||||
mesecon._test_program_fpga(pos, {
|
||||
{"A", "OR", "C", "0"},
|
||||
{"B", "OR", "D", "1"},
|
||||
{"NOT", "A", "2"},
|
||||
{"NOT", "B", "3"},
|
||||
{"0", "AND", "3", "C"},
|
||||
{"1", "AND", "2", "D"},
|
||||
})
|
||||
|
||||
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on actions
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal("mesecons_fpga:fpga0100", world.get_node(pos).name)
|
||||
|
||||
mesecon._test_dig(pos_a)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off actions
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
assert.equal("mesecons_fpga:fpga0100", world.get_node(pos).name)
|
||||
|
||||
mesecon._test_place(pos_b, "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on actions
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
|
||||
|
||||
mesecon._test_dig(pos_b)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off actions
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
assert.equal("mesecons_fpga:fpga1000", world.get_node(pos).name)
|
||||
end)
|
||||
end)
|
1
mesecons_fpga/spec/mineunit.conf
Normal file
1
mesecons_fpga/spec/mineunit.conf
Normal file
|
@ -0,0 +1 @@
|
|||
fixture_paths = {"../.test_fixtures"}
|
38
mesecons_luacontroller/spec/lightweight_interrupt_spec.lua
Normal file
38
mesecons_luacontroller/spec/lightweight_interrupt_spec.lua
Normal file
|
@ -0,0 +1,38 @@
|
|||
require("mineunit")
|
||||
|
||||
-- This test is done in a separate file since it requires different configuration at startup.
|
||||
mineunit("core")
|
||||
minetest.settings:set("mesecon.luacontroller_lightweight_interrupts", "true")
|
||||
|
||||
fixture("mesecons_luacontroller")
|
||||
|
||||
describe("LuaController lightweight interrupt", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
|
||||
before_each(function()
|
||||
mesecon._test_place(pos, "mesecons_luacontroller:luacontroller0000")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("works", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
if event.type == "program" then
|
||||
interrupt(5)
|
||||
interrupt(10)
|
||||
elseif event.type == "interrupt" then
|
||||
port.a = not pin.a
|
||||
end
|
||||
]])
|
||||
mineunit:execute_globalstep(0.1)
|
||||
mineunit:execute_globalstep(9)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
mineunit:execute_globalstep(1)
|
||||
mineunit:execute_globalstep(0.1)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
|
||||
end)
|
||||
end)
|
176
mesecons_luacontroller/spec/luac_spec.lua
Normal file
176
mesecons_luacontroller/spec/luac_spec.lua
Normal file
|
@ -0,0 +1,176 @@
|
|||
require("mineunit")
|
||||
|
||||
fixture("mesecons_luacontroller")
|
||||
|
||||
-- Digiline is not tested, since that would require the digiline mod.
|
||||
|
||||
describe("LuaController", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local pos_a = {x = -1, y = 0, z = 0}
|
||||
|
||||
before_each(function()
|
||||
mesecon._test_place(pos, "mesecons_luacontroller:luacontroller0000")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("rejects binary code", function()
|
||||
local ok = mesecon._test_program_luac(pos, string.dump(function() end))
|
||||
assert.is_false(ok)
|
||||
end)
|
||||
|
||||
it("I/O", function()
|
||||
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
mesecon._test_program_luac(pos, [[
|
||||
port.a = not pin.a
|
||||
port.b = not pin.b
|
||||
port.c = not pin.c
|
||||
port.d = not pin.d
|
||||
]])
|
||||
assert.equal("mesecons_luacontroller:luacontroller1110", world.get_node(pos).name)
|
||||
mesecon._test_dig(pos_a)
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
mineunit:execute_globalstep() -- Execute deactivate/change actions
|
||||
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("memory", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
if not mem.x then
|
||||
mem.x = {}
|
||||
mem.x[mem.x] = {true, "", 1.2}
|
||||
else
|
||||
local b, s, n = unpack(mem.x[mem.x])
|
||||
if b == true and s == "" and n == 1.2 then
|
||||
port.d = true
|
||||
end
|
||||
end
|
||||
]])
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
mesecon._test_place(pos_a, "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
assert.equal("mesecons_luacontroller:luacontroller1000", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("interrupts without IDs", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
if event.type == "program" then
|
||||
interrupt(4)
|
||||
interrupt(8)
|
||||
elseif event.type == "interrupt" then
|
||||
port.a = not pin.a
|
||||
end
|
||||
]])
|
||||
mineunit:execute_globalstep(0.1)
|
||||
mineunit:execute_globalstep(3)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
mineunit:execute_globalstep(1)
|
||||
mineunit:execute_globalstep(0.1)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
|
||||
mineunit:execute_globalstep(3)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
|
||||
mineunit:execute_globalstep(1)
|
||||
mineunit:execute_globalstep(0.1)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("interrupts with IDs", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
if event.type == "program" then
|
||||
interrupt(2, "a")
|
||||
interrupt(4, "a")
|
||||
interrupt(16, "b")
|
||||
elseif event.type == "interrupt" then
|
||||
if event.iid == "a" then
|
||||
interrupt(5, "b")
|
||||
interrupt(4, "b")
|
||||
end
|
||||
port.a = not pin.a
|
||||
end
|
||||
]])
|
||||
mineunit:execute_globalstep(0.1)
|
||||
mineunit:execute_globalstep(3)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
mineunit:execute_globalstep(1)
|
||||
mineunit:execute_globalstep(0.1)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
|
||||
mineunit:execute_globalstep(3)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
|
||||
mineunit:execute_globalstep(1)
|
||||
mineunit:execute_globalstep(0.1)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("limits interrupt ID size", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
if event.type == "program" then
|
||||
interrupt(0, (" "):rep(257))
|
||||
elseif event.type == "interrupt" then
|
||||
port.a = not pin.a
|
||||
end
|
||||
]])
|
||||
mineunit:execute_globalstep(3)
|
||||
mineunit:execute_globalstep(3)
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("string.rep", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
(" "):rep(64000)
|
||||
port.a = true
|
||||
]])
|
||||
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
|
||||
mesecon._test_program_luac(pos, [[
|
||||
(" "):rep(64001)
|
||||
port.b = true
|
||||
]])
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("string.find", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
port.a = (" a"):find("a", nil, true) == 2
|
||||
]])
|
||||
assert.equal("mesecons_luacontroller:luacontroller0001", world.get_node(pos).name)
|
||||
mesecon._test_program_luac(pos, [[
|
||||
(" a"):find("a", nil)
|
||||
port.b = true
|
||||
]])
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("overheats", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
interrupt(0)
|
||||
interrupt(0)
|
||||
]])
|
||||
mineunit:execute_globalstep() -- Execute 2 interrupts
|
||||
mineunit:execute_globalstep() -- Execute 4 interrupts
|
||||
mineunit:execute_globalstep() -- Execute 8 interrupts
|
||||
mineunit:execute_globalstep() -- Execute 16 interrupts
|
||||
assert.equal("mesecons_luacontroller:luacontroller_burnt", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("limits memory", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
port.a = true
|
||||
mem.x = (" "):rep(50000) .. (" "):rep(50000)
|
||||
]])
|
||||
assert.equal("mesecons_luacontroller:luacontroller_burnt", world.get_node(pos).name)
|
||||
end)
|
||||
|
||||
it("limits run time", function()
|
||||
mesecon._test_program_luac(pos, [[
|
||||
port.a = true
|
||||
for i = 1, 1000000 do end
|
||||
]])
|
||||
assert.equal("mesecons_luacontroller:luacontroller0000", world.get_node(pos).name)
|
||||
end)
|
||||
end)
|
1
mesecons_luacontroller/spec/mineunit.conf
Normal file
1
mesecons_luacontroller/spec/mineunit.conf
Normal file
|
@ -0,0 +1 @@
|
|||
fixture_paths = {"../.test_fixtures"}
|
1
mesecons_mvps/spec/mineunit.conf
Normal file
1
mesecons_mvps/spec/mineunit.conf
Normal file
|
@ -0,0 +1 @@
|
|||
fixture_paths = {"../.test_fixtures"}
|
297
mesecons_mvps/spec/node_spec.lua
Normal file
297
mesecons_mvps/spec/node_spec.lua
Normal file
|
@ -0,0 +1,297 @@
|
|||
require("mineunit")
|
||||
|
||||
fixture("mesecons_mvps")
|
||||
|
||||
world.set_default_node("air")
|
||||
|
||||
describe("node movement", function()
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
it("works with no moved nodes", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
|
||||
assert.same({true, {}, {}}, {mesecon.mvps_push(pos, dir, 1, "")})
|
||||
assert.same({true, {}, {}}, {mesecon.mvps_pull_all(pos, dir, 1, "")})
|
||||
assert.same({true, {}, {}}, {mesecon.mvps_pull_single(pos, dir, 1, "")})
|
||||
end)
|
||||
|
||||
it("works with simple stack", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
world.set_node(vector.add(pos, dir), "mesecons:test_conductor_off")
|
||||
|
||||
assert.is_true((mesecon.mvps_push(pos, dir, 2, "")))
|
||||
assert.equal("air", world.get_node(pos).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, vector.multiply(dir, 2))).name)
|
||||
|
||||
assert.is_true((mesecon.mvps_pull_all(vector.add(pos, dir), vector.multiply(dir, -1), 2, "")))
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(pos).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name)
|
||||
assert.equal("air", world.get_node(vector.add(pos, vector.multiply(dir, 2))).name)
|
||||
|
||||
assert.is_true((mesecon.mvps_pull_single(pos, vector.multiply(dir, -1), 1, "")))
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.subtract(pos, dir)).name)
|
||||
assert.equal("air", world.get_node(pos).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos, dir)).name)
|
||||
end)
|
||||
|
||||
it("works with sticky nodes", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 0, y = 1, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
world.set_node(vector.offset(pos, 0, 1, 0), "mesecons_mvps:test_sticky")
|
||||
world.set_node(vector.offset(pos, 1, 1, 0), "mesecons:test_conductor_off")
|
||||
world.set_node(vector.offset(pos, 1, 2, 0), "mesecons:test_conductor_off")
|
||||
|
||||
assert.is_true((mesecon.mvps_push(pos, dir, 4, "")))
|
||||
assert.equal("air", world.get_node(vector.offset(pos, 1, 1, 0)).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 2, 0)).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 3, 0)).name)
|
||||
|
||||
assert.is_true((mesecon.mvps_pull_all(vector.add(pos, dir), vector.multiply(dir, -1), 4, "")))
|
||||
assert.equal("air", world.get_node(vector.offset(pos, 1, 0, 0)).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 1, 0)).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 2, 0)).name)
|
||||
|
||||
assert.is_true((mesecon.mvps_pull_single(pos, vector.multiply(dir, -1), 3, "")))
|
||||
assert.equal("air", world.get_node(vector.offset(pos, 1, -1, 0)).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.offset(pos, 1, 0, 0)).name)
|
||||
assert.equal("air", world.get_node(vector.offset(pos, 1, 1, 0)).name)
|
||||
end)
|
||||
|
||||
it("respects maximum", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
world.set_node(vector.add(pos, dir), "mesecons:test_conductor_off")
|
||||
|
||||
assert.is_true(not mesecon.mvps_push(pos, dir, 1, ""))
|
||||
end)
|
||||
|
||||
it("is blocked by basic stopper", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons_mvps:test_stopper")
|
||||
|
||||
assert.is_true(not mesecon.mvps_push(pos, dir, 1, ""))
|
||||
end)
|
||||
|
||||
it("is blocked by conditional stopper", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
|
||||
world.set_node(pos, {name = "mesecons_mvps:test_stopper_cond", param2 = 0})
|
||||
assert.is_true(not mesecon.mvps_push(pos, dir, 1, ""))
|
||||
|
||||
world.set_node(pos, {name = "mesecons_mvps:test_stopper_cond", param2 = 1})
|
||||
assert.is_true((mesecon.mvps_push(pos, dir, 1, "")))
|
||||
end)
|
||||
|
||||
-- TODO: I think this is supposed to work?
|
||||
pending("is blocked by ignore", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
world.set_node(vector.add(pos, dir), "ignore")
|
||||
|
||||
assert.is_true(not mesecon.mvps_push(pos, dir, 1, ""))
|
||||
end)
|
||||
|
||||
it("moves metadata", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
minetest.get_meta(pos):set_string("foo", "bar")
|
||||
minetest.get_node_timer(pos):set(12, 34)
|
||||
|
||||
mesecon.mvps_push(pos, dir, 1, "")
|
||||
assert.equal("bar", minetest.get_meta(vector.add(pos, dir)):get("foo"))
|
||||
local moved_timer = minetest.get_node_timer(vector.add(pos, dir))
|
||||
assert.equal(12, moved_timer:get_timeout())
|
||||
assert.equal(34, moved_timer:get_elapsed())
|
||||
moved_timer:stop()
|
||||
assert.same({}, minetest.get_meta(pos):to_table().fields)
|
||||
assert.is_false(minetest.get_node_timer(pos):is_started())
|
||||
end)
|
||||
|
||||
it("calls move callbacks", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
world.set_node(pos, {name = "mesecons_mvps:test_on_move", param2 = 123})
|
||||
minetest.get_meta(pos):set_string("foo", "bar")
|
||||
local move_info = {vector.add(pos, dir), world.get_node(pos), pos, minetest.get_meta(pos):to_table()}
|
||||
|
||||
mesecon.mvps_push(pos, dir, 1, "")
|
||||
assert.equal(1, #mesecon._test_moves)
|
||||
assert.same(move_info, mesecon._test_moves[1])
|
||||
end)
|
||||
|
||||
it("executes autoconnect hooks", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
|
||||
mesecon.mvps_push(pos, dir, 1, "")
|
||||
mineunit:execute_globalstep() -- Execute delayed autoconnect hook
|
||||
assert.equal(2, #mesecon._test_autoconnects)
|
||||
end)
|
||||
|
||||
it("updates moved receptors", function()
|
||||
local pos1 = {x = 0, y = 0, z = 0}
|
||||
local pos2 = vector.offset(pos1, 0, 1, 0)
|
||||
local pos3 = vector.offset(pos1, 2, 0, 0)
|
||||
local pos4 = vector.offset(pos1, 0, 0, 1)
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
mesecon._test_place(pos1, "mesecons:test_receptor_on")
|
||||
mesecon._test_place(pos2, "mesecons:test_conductor_off")
|
||||
mesecon._test_place(pos3, "mesecons:test_conductor_off")
|
||||
mesecon._test_place(pos4, "mesecons:test_conductor_off")
|
||||
mesecon._test_place(vector.add(pos4, dir), "mesecons:test_conductor_off")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
|
||||
mesecon.mvps_push(pos1, dir, 1, "")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(pos2).name)
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(pos3).name)
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(pos4).name)
|
||||
end)
|
||||
|
||||
it("updates moved conductors", function()
|
||||
local pos1 = {x = 0, y = 0, z = 0}
|
||||
local pos2 = vector.offset(pos1, 0, 1, 0)
|
||||
local pos3 = vector.offset(pos1, 0, -1, 0)
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
mesecon._test_place(pos1, "mesecons:test_conductor_off")
|
||||
mesecon._test_place(pos2, "mesecons:test_receptor_on")
|
||||
mesecon._test_place(pos3, "mesecons:test_conductor_off")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
|
||||
mesecon.mvps_push(pos1, dir, 1, "")
|
||||
mineunit:execute_globalstep() -- Execute receptor_off action
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(vector.add(pos1, dir)).name)
|
||||
assert.equal("mesecons:test_conductor_off", world.get_node(pos3).name)
|
||||
|
||||
mesecon.mvps_pull_all(vector.add(pos1, dir), vector.multiply(dir, -1), 1, "")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(pos1).name)
|
||||
assert.equal("mesecons:test_conductor_on", world.get_node(pos3).name)
|
||||
end)
|
||||
|
||||
it("updates moved effectors", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
mesecon._test_place(pos, "mesecons:test_effector")
|
||||
mesecon._test_place(vector.offset(pos, 0, 1, 0), "mesecons:test_receptor_on")
|
||||
mesecon._test_place(vector.add(pos, dir), "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
|
||||
mesecon.mvps_push(pos, dir, 2, "")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
|
||||
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
|
||||
assert.equal(tonumber("10000001", 2), world.get_node(vector.add(pos, dir)).param2)
|
||||
|
||||
mineunit:execute_globalstep() -- Let the component cool down
|
||||
|
||||
mesecon.mvps_pull_single(vector.add(pos, dir), vector.multiply(dir, -1), 1, "")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
|
||||
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
|
||||
assert.equal(tonumber("10000100", 2), world.get_node(pos).param2)
|
||||
end)
|
||||
|
||||
-- Since turnon is called before turnoff when pushing, effectors may be incorrectly turned off.
|
||||
pending("does not overwrite turnon with receptor_off", function()
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
local dir = {x = 1, y = 0, z = 0}
|
||||
mesecon._test_place(pos, "mesecons:test_effector")
|
||||
mesecon._test_place(vector.add(pos, dir), "mesecons:test_conductor_off")
|
||||
mesecon._test_place(vector.add(pos, vector.multiply(dir, 2)), "mesecons:test_receptor_on")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on action
|
||||
mineunit:execute_globalstep() -- Execute activate/change actions
|
||||
|
||||
mesecon.mvps_push(pos, dir, 3, "")
|
||||
mineunit:execute_globalstep() -- Execute receptor_on/receptor_off actions
|
||||
mineunit:execute_globalstep() -- Execute activate/deactivate/change actions
|
||||
assert.equal(tonumber("10000001", 2), world.get_node(vector.add(pos, dir)).param2)
|
||||
end)
|
||||
|
||||
-- mineunit doesn't yet implement minetest.check_for_falling.
|
||||
pending("causes nodes to fall", function()
|
||||
end)
|
||||
end)
|
||||
|
||||
describe("protection", function()
|
||||
teardown(function()
|
||||
minetest.settings:remove("mesecon.mvps_protection_mode")
|
||||
end)
|
||||
|
||||
after_each(function()
|
||||
mesecon._test_reset()
|
||||
world.clear()
|
||||
end)
|
||||
|
||||
local protected_pos = {x = 1, y = 0, z = 0}
|
||||
mineunit:protect(protected_pos, "Joe")
|
||||
|
||||
it("blocks movement", function()
|
||||
minetest.settings:set("mesecon.mvps_protection_mode", "restrict")
|
||||
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
|
||||
assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Bob")})
|
||||
end)
|
||||
|
||||
it("allows owner's movement", function()
|
||||
minetest.settings:set("mesecon.mvps_protection_mode", "restrict")
|
||||
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
|
||||
assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Joe")))
|
||||
end)
|
||||
|
||||
it("'ignore'", function()
|
||||
minetest.settings:set("mesecon.mvps_protection_mode", "ignore")
|
||||
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
|
||||
assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "Bob")))
|
||||
end)
|
||||
|
||||
it("'normal'", function()
|
||||
minetest.settings:set("mesecon.mvps_protection_mode", "normal")
|
||||
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
|
||||
assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "")})
|
||||
|
||||
assert.is_true((mesecon.mvps_push(pos, {x = 0, y = 1, z = 0}, 1, "")))
|
||||
end)
|
||||
|
||||
it("'compat'", function()
|
||||
minetest.settings:set("mesecon.mvps_protection_mode", "compat")
|
||||
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
|
||||
assert.is_true((mesecon.mvps_push(pos, {x = 1, y = 0, z = 0}, 1, "")))
|
||||
end)
|
||||
|
||||
it("'restrict'", function()
|
||||
minetest.settings:set("mesecon.mvps_protection_mode", "restrict")
|
||||
|
||||
local pos = {x = 0, y = 0, z = 0}
|
||||
world.set_node(pos, "mesecons:test_conductor_off")
|
||||
|
||||
assert.same({false, "protected"}, {mesecon.mvps_push(pos, {x = 0, y = 1, z = 0}, 1, "")})
|
||||
end)
|
||||
end)
|
3
mesecons_mvps/spec/object_spec.lua
Normal file
3
mesecons_mvps/spec/object_spec.lua
Normal file
|
@ -0,0 +1,3 @@
|
|||
-- mineunit doesn't yet implement minetest.get_objects_inside_radius
|
||||
pending("object movement", function()
|
||||
end)
|
Loading…
Reference in New Issue
Block a user