chroma_solstice/tests/test_wire.lua
2026-08-12 00:12:26 -04:00

254 lines
9.9 KiB
Lua

package.path = "./?.lua;" .. package.path
class = require "libs/middleclass"
local Wire = require "wire"
require "world"
gridWidth, gridHeight = 2, 2
local passed = 0
local function test(name, fn)
local ok, err = pcall(fn)
if not ok then
io.stderr:write("FAIL: " .. name .. "\n" .. err .. "\n")
os.exit(1)
end
passed = passed + 1
end
local function assertTrue(value, message)
if not value then error(message or "expected true", 2) end
end
local function assertFalse(value, message)
if value then error(message or "expected false", 2) end
end
local function switch(color, x, y)
local entity = {x = x, y = y, activated = false}
entity.color = {getname = function() return color end}
function entity:getGridPos() return {x = self.x, y = self.y} end
function entity:activate() self.activated = true end
function entity:deactivate() self.activated = false end
return entity
end
local function door(circuitId, x, y)
local entity = {circuitId = circuitId, x = x, y = y, powered = false}
function entity:getGridPos() return {x = self.x, y = self.y} end
function entity:setPowered(powered) self.powered = powered end
return entity
end
local function makeWorld(secondSwitch)
local blueSwitch = switch("blue", 2, 1)
local wiredDoor = door("circuit_a", 1, 1)
local roomA = {
name = "a", player = {}, wiredSwitches = {}, wiredDoors = {wiredDoor},
wires = {[1] = {
[1] = {circuit_a = Wire.EAST},
[2] = {circuit_a = Wire.WEST + Wire.EAST},
}},
}
local roomB = {
name = "b", player = {}, wiredSwitches = {blueSwitch}, wiredDoors = {},
wires = {[1] = {
[1] = {circuit_a = Wire.WEST + Wire.EAST},
[2] = {circuit_a = Wire.WEST},
}},
}
local function wireCircuitAt(room, cell)
local tracks = room.wires[cell.y] and room.wires[cell.y][cell.x]
for circuitId in pairs(tracks or {}) do return circuitId end
end
roomA.wireCircuitAt = wireCircuitAt
roomB.wireCircuitAt = wireCircuitAt
if secondSwitch then table.insert(roomB.wiredSwitches, secondSwitch) end
local instance = setmetatable({
levels = {a = roomA, b = roomB},
roomByName = {a = {name = "a", x = 1, y = 1}, b = {name = "b", x = 2, y = 1}},
collidableMatrices = {red = {}, green = {}, blue = {}},
}, {__index = World})
function instance:roomCell(cell)
if cell.x <= gridWidth then return roomA, {x = cell.x, y = cell.y} end
return roomB, {x = cell.x - gridWidth, y = cell.y}
end
local function wireTracksAt(room, cell, create)
local row = room.wires[cell.y]
if not row and create then row = {}; room.wires[cell.y] = row end
local tracks = row and row[cell.x]
if not tracks and create then tracks = {}; row[cell.x] = tracks end
return tracks
end
roomA.wireTracksAt = wireTracksAt
roomB.wireTracksAt = wireTracksAt
return instance, roomA, roomB, wiredDoor, blueSwitch
end
test("direction masks add and remove without duplicating bits", function()
local mask = Wire.add(0, Wire.EAST)
mask = Wire.add(mask, Wire.EAST)
assertTrue(mask == Wire.EAST)
assertTrue(Wire.has(mask, Wire.EAST))
assertFalse(Wire.has(mask, Wire.WEST))
assertTrue(Wire.remove(mask, Wire.EAST) == 0)
end)
test("orphaned and overlapping wire cells remain selectable without a door", function()
local world, roomA = makeWorld()
roomA.wires[1][1].orphan_b = Wire.SOUTH
local top = world:circuitAt({x = 1, y = 1})
assertTrue(top == "orphan_b", "top orphaned circuit was not selectable")
local preferred = world:circuitAt({x = 1, y = 1}, "circuit_a")
assertTrue(preferred == "circuit_a", "selected overlapping circuit was not preferred")
end)
test("a white switch powers every layer of a white door", function()
local world, roomA, roomB = makeWorld()
roomA.wiredDoors = {
door("circuit_a", 1, 1),
door("old_green_id", 1, 1),
door("old_blue_id", 1, 1),
}
roomB.wiredSwitches = {
switch("red", 2, 1),
switch("green", 2, 1),
switch("blue", 2, 1),
}
world.collidableMatrices.red[1] = {[4] = {}}
world.collidableMatrices.green[1] = {[4] = {}}
world.collidableMatrices.blue[1] = {[4] = {}}
world:resolveCircuits()
for _, wiredDoor in ipairs(roomA.wiredDoors) do
assertTrue(wiredDoor.circuitId == "circuit_a", "door layer did not adopt terminal circuit")
assertTrue(world.circuitState.doorPowered[wiredDoor], "white door layer remained locked")
end
local color = world:wireColorAt(roomA, {x = 1, y = 1}, "circuit_a")
assertTrue(color[1] == 1 and color[2] == 1 and color[3] == 1, "white switch did not produce white wire")
local redGreenOnly = world:wireColorAt(roomA, {x = 1, y = 1}, "circuit_a", {red = true, green = true})
assertTrue(redGreenOnly[1] == 1 and redGreenOnly[2] == 1 and redGreenOnly[3] == 0,
"white wire did not obey the room's visible player channels")
end)
test("world matrices join a circuit across a room boundary", function()
local world, _, _, wiredDoor, blueSwitch = makeWorld()
world.collidableMatrices.blue[1] = {[4] = {}}
world:resolveCircuits()
assertTrue(world.wireMatrix[1][2].circuit_a ~= nil)
assertTrue(world.wireMatrix[1][3].circuit_a ~= nil)
assertTrue(world.wiredDoorMatrix[1][1][1].entity == wiredDoor)
assertTrue(world.wiredSwitchMatrix[1][4][1].entity == blueSwitch)
assertTrue(world.circuitState.switchPressed[blueSwitch])
assertTrue(world.circuitState.doorPowered[wiredDoor])
assertTrue(wiredDoor.powered)
assertTrue(world:wireColorAt(world.levels.a, {x = 1, y = 1}, "circuit_a", {red = true, green = true}) == nil,
"blue wire leaked into a room without a blue player channel")
local visibleBlue = world:wireColorAt(world.levels.a, {x = 1, y = 1}, "circuit_a", {blue = true})
assertTrue(visibleBlue[1] == 0 and visibleBlue[2] == 0 and visibleBlue[3] == 1,
"blue wire did not render in a room with a blue player channel")
end)
test("wire color is re-derived when its terminal switch changes", function()
local world, roomA, roomB = makeWorld()
world:resolveCircuits()
local colors = world:wireSwitchColorsAt(roomA, {x = 1, y = 1}, "circuit_a")
assertTrue(colors.blue and not colors.red)
roomB.wiredSwitches = {switch("red", 2, 1)}
world:resolveCircuits()
colors = world:wireSwitchColorsAt(roomA, {x = 1, y = 1}, "circuit_a")
assertTrue(colors.red and not colors.blue, "wire retained the deleted terminal switch color")
end)
test("a switchless wire component has no gameplay color", function()
local world, roomA, roomB = makeWorld()
roomB.wiredSwitches = {}
world:resolveCircuits()
assertTrue(world:wireSwitchColorsAt(roomA, {x = 1, y = 1}, "circuit_a") == nil)
assertTrue(world:wireColorAt(roomA, {x = 1, y = 1}, "circuit_a") == nil)
end)
test("a door requires every independent switch run at its terminal", function()
local greenSwitch = switch("green", 1, 2)
local world, roomA, _, wiredDoor = makeWorld()
table.insert(roomA.wiredSwitches, greenSwitch)
roomA.wires[1][1].circuit_b = Wire.SOUTH
roomA.wires[2] = {[1] = {circuit_b = Wire.NORTH}}
world.collidableMatrices.blue[1] = {[4] = {}}
world:resolveCircuits()
assertFalse(world.circuitState.doorPowered[wiredDoor])
world.collidableMatrices.green[2] = {[1] = {}}
world:resolveCircuits()
assertTrue(world.circuitState.doorPowered[wiredDoor])
end)
test("an orphaned stub at a door does not block a valid switch run", function()
local world, roomA, _, wiredDoor = makeWorld()
roomA.wires[1][1].abandoned_stroke = 0
world.collidableMatrices.blue[1] = {[4] = {}}
world:resolveCircuits()
assertTrue(world.circuitState.doorPowered[wiredDoor])
assertTrue(wiredDoor.powered)
end)
test("selecting a parked colour changes to its room", function()
local function player()
local entity = {switched = false}
function entity:playSwitchSound(success) self.switched = success end
return entity
end
local function room(name, players, active)
local entity = {name = name, player = players, activeColors = active, colorsPlayerHas = {}}
for color in pairs(players) do table.insert(entity.colorsPlayerHas, color) end
function entity:getPossibleColors() return self.colorsPlayerHas end
function entity:setActiveColor(color, value) self.activeColors[color] = value end
function entity:getActiveColors()
local colors = {}
for color, value in pairs(self.activeColors) do if value then table.insert(colors, color) end end
return colors
end
return entity
end
local roomA = room("a", {red = player()}, {red = true, green = false, blue = false})
local roomB = room("b", {blue = player()}, {red = false, green = false, blue = false})
local world = setmetatable({
levels = {a = roomA, b = roomB},
roomByName = {a = {name = "a", x = 1, y = 1}, b = {name = "b", x = 2, y = 1}},
}, {__index = World})
world.flushRuntime = function(self) self.flushed = true end
local oldCurrentRoom, oldSetEditorRoomName = currentRoom, setEditorRoomName
currentRoom = roomA
setEditorRoomName = function() end
assertTrue(world:switchPlayerColor(roomA, "blue"))
assertTrue(currentRoom == roomB)
assertFalse(roomA.activeColors.red)
assertTrue(roomB.activeColors.blue)
assertTrue(roomB.player.blue.switched)
assertTrue(world.flushed)
currentRoom, setEditorRoomName = oldCurrentRoom, oldSetEditorRoomName
end)
test("one run cannot terminate at two different switches", function()
local second = switch("red", 1, 2)
local world, _, roomB = makeWorld(second)
world:resolveCircuits()
local rooms, err = world:addWireConnection({x = 3, y = 1}, {x = 3, y = 2}, "circuit_a")
assertTrue(#rooms == 0 and err ~= nil, "second switch terminal was accepted")
assertTrue(roomB.wires[2] == nil or roomB.wires[2][1] == nil,
"rejected second terminal left a connected wire cell")
local colors = world:wireSwitchColorsAt(world.levels.a, {x = 1, y = 1}, "circuit_a")
assertTrue(colors.blue and not colors.red, "run stopped deriving color from its sole terminal switch")
end)
test("matching IDs do not bridge a gap or one-sided room edge", function()
local world, _, roomB, wiredDoor = makeWorld()
world.collidableMatrices.blue[1] = {[4] = {}}
roomB.wires[1][1].circuit_a = Wire.EAST -- no reciprocal WEST edge
world:resolveCircuits()
assertFalse(world.circuitState.doorPowered[wiredDoor])
end)
io.write("PASS: " .. passed .. " wire tests\n")