From ba98fa53780bf19266d7e5049fd7ec31eaad18bf Mon Sep 17 00:00:00 2001 From: "Y. Wang" Date: Fri, 4 Nov 2022 11:15:04 +0100 Subject: Harden type 2 signal group API; add test for type 2 main signals --- advtrains_interlocking/signal_aspects.lua | 17 +++-- advtrains_interlocking/spec/type2_spec.lua | 103 +++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+), 5 deletions(-) create mode 100644 advtrains_interlocking/spec/type2_spec.lua diff --git a/advtrains_interlocking/signal_aspects.lua b/advtrains_interlocking/signal_aspects.lua index 37af7aa..65e970f 100644 --- a/advtrains_interlocking/signal_aspects.lua +++ b/advtrains_interlocking/signal_aspects.lua @@ -9,13 +9,15 @@ local type2defs = {} local function register_type2(def) local t = {type = 2} local name = def.name - if type2defs[name] then - return error("Name " .. name .. " already used") - elseif type(name) ~= "string" then + if type(name) ~= "string" then return error("Name is not a string") + elseif type2defs[name] then + return error(string.format("Attempt to redefine type 2 signal aspect group %q, previously defined in %s", name, type2defs[name].defined)) end t.name = name + t.defined = debug.getinfo(2, "S").short_src or "[?]" + local label = def.label or name if type(label) ~= "string" then return error("Label is not a string") @@ -54,7 +56,12 @@ end -- @return[1] The definition for the signal group (if present). -- @return[2] The nil constant (otherwise). local function get_type2_definition(name) - return type2defs[name] + local t = type2defs[name] + if t then + return table.copy(t) + else + return nil + end end --- Get the name of the distant aspect before the current aspect. @@ -151,7 +158,7 @@ local function type1_to_type2main(asp, group, shift) return t_main[math.max(1, idx-(shift or 0))].name end ---- Compare two signal aspect tables. +--- Compare two type 1 signal aspect tables. -- @function equalp -- @param asp1 The first signal aspect table. -- @param asp2 The second signal aspect table. diff --git a/advtrains_interlocking/spec/type2_spec.lua b/advtrains_interlocking/spec/type2_spec.lua new file mode 100644 index 0000000..514f6aa --- /dev/null +++ b/advtrains_interlocking/spec/type2_spec.lua @@ -0,0 +1,103 @@ +require "mineunit" +mineunit("core") + +_G.advtrains = { + interlocking = { + aspects = sourcefile("signal_aspects"), + }, + ndb = { + get_node = minetest.get_node, + swap_node = minetest.swap_node, + } +} + +fixture("advtrains_helpers") +sourcefile("database") +sourcefile("signal_api") +sourcefile("distant") +sourcefile("signal_aspect_accessors") + +local A = advtrains.interlocking.aspects +local D = advtrains.distant +local I = advtrains.interlocking +local N = advtrains.ndb + +local type2def = { + name = "foo", + main = { + {name = "proceed", main = -1}, + {name = "caution"}, + {name = "danger", main = 0}, + }, +} + +local asps = {} +for _, v in pairs(type2def.main) do + minetest.register_node("advtrains_interlocking:" .. v.name, { + advtrains = { + supported_aspects = { + type = 2, + group = "foo", + }, + get_aspect = function() return v.name end, + set_aspect = function(pos, _, name) + N.swap_node(pos, {name = "advtrains_interlocking:" .. name}) + end, + } + }) + asps[v.name] = { + main = v.main, + type2group = "foo", + type2name = v.name, + } +end + +local origin = vector.new(0, 0, 0) +local dstpos = vector.new(0, 0, 1) + +world.layout { + {origin, "advtrains_interlocking:danger"}, + {dstpos, "advtrains_interlocking:proceed"}, +} + +describe("type 2 signal group registration", function() + it("should work", function() + A.register_type2(type2def) + assert(A.get_type2_definition("foo")) + end) + it("should only be allowed once for the same group", function() + assert.has.errors(function() A.register_type2(type2def) end) + end) + it("should handle nonexistant groups", function() + assert.is_nil(A.get_type2_definition("something_else")) + end) +end) + +describe("signal aspect conversion", function() + it("should work for converting from type 1 to type 2", function() + assert.equal("danger", A.type1_to_type2main({main = 0}, "foo")) + assert.equal("caution", A.type1_to_type2main({main = 6}, "foo")) + assert.equal("proceed", A.type1_to_type2main({}, "foo")) + end) + -- Type 2 -> type 1 conversion is tested with signal aspect accessors +end) + +describe("type 2 signals", function() + it("should support distant signaling", function() + assert.equal("caution", A.get_type2_dst("foo", 3)) + assert.equal("proceed", A.get_type2_dst("foo", "caution")) + assert.equal("proceed", A.get_type2_dst("foo", "proceed")) + end) + it("should work with accessors", function() + assert.same(asps.danger, I.signal_get_aspect(origin)) + local newasp = {type2group = "foo", type2name = "proceed", main = 6} + I.signal_set_aspect(origin, newasp) + assert.same(newasp, I.signal_get_aspect(origin)) + end) + it("should work with distant signaling", function() + assert.same(asps.proceed, I.signal_get_aspect(dstpos)) + local dstasp = {type2group = "foo", type2name = "proceed", dst = 6, main = -1} + D.assign(origin, dstpos) + assert.same(dstasp, I.signal_get_aspect(dstpos)) + end) +end) -- cgit v1.2.3