test: cover tests.gameOpenChestRefusesWhenNothingIsHereOrItIsAlreadyE...

This commit is contained in:
dualfroz committed 2026-09-11 20:32:13 +02:00
1 parent 2498a1129b
commit b0648df4e0
1 file changed
+173
+173
View File
@@ -9644,6 +9644,179 @@ function tests.gameOpenChestFallsBackToALockpickWhenNoKeyIsCarried()
for _, item in ipairs(game.player.inventory) do for _, item in ipairs(game.player.inventory) do
if item.kind == Items.LOCKPICK then stillHasPick = true end if item.kind == Items.LOCKPICK then stillHasPick = true end
end end
ok(not stillHasPick, "the lockpick is spent gambling against the lock with no key on hand")
end
function tests.gameOpenChestRefusesWhenNothingIsHereOrItIsAlreadyEmpty()
local game = stagedGame(1, arena(21, 11), 3, 6)
game.level.chests = {}
eq(game:openChest(), false, "opening with no chest underfoot fails")
local chest = { x = 3, y = 6, locked = false, trapped = false, opened = true, loot = {} }
game.level.chests = { chest }
eq(game:openChest(), false, "opening an already-emptied chest fails")
end
function tests.chestsFieldsSurviveSerialization()
local level = arena(21, 11)
local chest = Chests.new(Rng.new(4), 3)
chest.x, chest.y = 5, 5
chest.locked = true
chest.trapped = true
level.chests = { chest }
local restored = Level.fromData(level:toData())
eq(#restored.chests, 1, "the chest list survives a round trip")
eq(restored.chests[1].locked, true, "a chest's locked flag survives a round trip")
eq(restored.chests[1].trapped, true, "a chest's trapped flag survives a round trip")
eq(restored.chests[1].opened, false, "a chest's opened flag survives a round trip")
eq(#restored.chests[1].loot, #chest.loot, "a chest's loot list survives a round trip intact")
eq(restored.chests[1].loot[1].kind, chest.loot[1].kind, "a chest's loot items keep their own kind")
end
function tests.renderShowsAClosedChestGlyphAndAnOpenedOneOnceEmptied()
local game = stagedGame(1, arena(21, 11), 3, 6)
local chest = { x = 4, y = 6, locked = true, trapped = false, opened = false, loot = { Items.gold(5) } }
game.level.chests = { chest }
game:computeVisible()
local frame = game:render()
ok(contains(frame, "B"), "a closed chest renders as its own glyph")
chest.opened = true
chest.loot = {}
frame = game:render()
ok(contains(frame, "b"), "an emptied chest renders as its own distinct glyph")
end
function tests.autopilotOpensAnUnlockedChestOnSightButSkipsALockedOneWithNoKeyOrPick()
local game = stagedGame(1, arena(21, 11), 3, 6)
local chest = { x = 3, y = 6, locked = false, trapped = false, opened = false, loot = { Items.gold(5) } }
game.level.chests = { chest }
game:choosePlayerAction()
eq(chest.opened, true, "the autopilot opens a free chest the instant it stands on one")
local lockedGame = stagedGame(1, arena(21, 11), 3, 6)
local locked = { x = 3, y = 6, locked = true, trapped = false, opened = false, loot = { Items.gold(5) } }
lockedGame.level.chests = { locked }
local beforeX, beforeY = lockedGame.player.x, lockedGame.player.y
lockedGame:choosePlayerAction()
eq(locked.opened, false, "the autopilot never gambles a lock it has neither a key nor a lockpick for")
ok(lockedGame.player.x ~= beforeX or lockedGame.player.y ~= beforeY,
"the autopilot still makes progress toward the stairs instead of parking on an unopenable chest")
end
function tests.morgueScoreWeighsEveryStatByItsOwnFixedWeight()
local w = Morgue.SCORE_WEIGHTS
local report = {
deepestDepth = 4, kills = 12, bossKills = 1, questsCompleted = 2, artifactsFound = 1,
vaultsOpened = 1, setPiecesFound = 3, chestsOpened = 5, playerLevel = 6, gold = 40, won = false,
}
local expected = 4 * w.depth + 12 * w.kill + 1 * w.bossKill + 2 * w.quest + 1 * w.artifact
+ 1 * w.vault + 3 * w.setPiece + 5 * w.chest + 6 * w.playerLevel + 40
eq(Morgue.score(report), expected, "score sums every weighted stat plus flat gold")
end
function tests.morgueScoreAddsTheWinBonusOnlyWhenWon()
local base = {
deepestDepth = 1, kills = 0, bossKills = 0, questsCompleted = 0, artifactsFound = 0,
vaultsOpened = 0, setPiecesFound = 0, chestsOpened = 0, playerLevel = 1, gold = 0, won = false,
}
local lost = Morgue.score(base)
base.won = true
local won = Morgue.score(base)
eq(won - lost, Morgue.SCORE_WEIGHTS.win, "winning adds exactly the win bonus and nothing else")
end
function tests.morgueEquipmentListsOnlyOccupiedSlotsInFixedOrder()
local game = Game.new(9)
eq(#Morgue.equipment(game.player), 0, "a fresh player with nothing worn has no equipment lines")
game.player.armor = Items.armor("plate", 4)
game.player.weapon = Items.weapon("sword", 3)
local lines = Morgue.equipment(game.player)
eq(#lines, 2, "only the two worn slots produce a line")
eq(lines[1], "weapon: sword", "weapon is listed before armor regardless of assignment order")
eq(lines[2], "armor: plate", "armor keeps its own slot label")
end
function tests.morgueEquipmentPrefixesARevealedCurseButNotAHiddenOne()
local game = Game.new(9)
local ring = Items.ring("ring of woe", 0, 0)
Curses.afflict(ring, Curses.pool.ring[1])
game.player.ring = ring
eq(Morgue.equipment(game.player)[1], "ring: ring of woe", "an unrevealed curse reads like an ordinary item")
Curses.reveal(ring)
eq(Morgue.equipment(game.player)[1], "ring: cursed ring of woe", "a revealed curse is prefixed")
end
function tests.morgueKillTallySortsByCountThenByCatalogOrderOnTies()
local compendium = Compendium.new()
Compendium.noteKill(compendium, "goblin")
Compendium.noteKill(compendium, "rat")
Compendium.noteKill(compendium, "rat")
Compendium.noteKill(compendium, "bat")
local rows = Morgue.killTally(compendium)
eq(#rows, 3, "only species with at least one kill appear")
eq(rows[1].key, "rat", "the heaviest kill count sorts first")
eq(rows[1].kills, 2, "rat's tally is exactly two")
eq(rows[2].key, "bat", "a tie between bat and goblin breaks toward bat's earlier catalog slot")
eq(rows[3].key, "goblin", "goblin follows bat on the same tied count")
end
function tests.morgueBuildMirrorsGameStatsPlayerAndCompendium()
local game = Game.new(21)
game.stats.kills = 3
game.stats.bossKills = 1
game.deepestDepth = 5
game.turn = 120
game.player.gold = 77
Compendium.noteKill(game.compendium, "orc")
local report = Morgue.build(game)
eq(report.kills, 3, "build copies the live kill tally")
eq(report.bossKills, 1, "build copies the live boss kill tally")
eq(report.deepestDepth, 5, "build copies the deepest depth reached")
eq(report.turn, 120, "build copies the current turn")
eq(report.gold, 77, "build copies the player's gold")
eq(report.alive, true, "a living player's report says so")
eq(#report.killTally, 1, "the compendium's own kill feeds straight into the tally")
eq(report.killTally[1].key, "orc", "the tallied species matches what was actually killed")
end
function tests.morgueFormatRendersOutcomeGearKillsAndScoreInOrder()
local game = Game.new(3)
game.player.weapon = Items.weapon("axe", 2)
Compendium.noteKill(game.compendium, "kobold")
game.player.hp = 0
local text = Morgue.format(Morgue.build(game))
ok(contains(text, "died in the dark"), "a dead player's obituary names the outcome")
ok(contains(text, "weapon: axe"), "the report lists the worn weapon")
ok(contains(text, "kobold"), "the report lists a slain species")
local scoreLine = "score: " .. Morgue.score(Morgue.build(game))
ok(contains(text, scoreLine), "the report ends with the matching numeric score")
local scorePos = text:find("score:", 1, true)
local killsPos = text:find("kills:", 1, true)
ok(killsPos < scorePos, "the kill tally is printed before the score line")
end
function tests.morgueFormatNamesTheWinOutcomeWhenWon()
local game = Game.new(3)
game.won = true
local text = Morgue.format(Morgue.build(game))
ok(contains(text, "Victorious the wanderer"), "a won run's heading calls the player victorious")
ok(contains(text, "escaped the warren with the Amulet"), "a won run's outcome line names the escape")
end
function tests.morgueFormatOmitsEquipmentAndKillsSectionsWhenEmpty()
local game = Game.new(3)
local text = Morgue.format(Morgue.build(game))
ok(not contains(text, "equipment:"), "an unarmed player's report has no equipment section")
ok(not contains(text, "kills:"), "a report with no recorded kills has no kill section")
ok(contains(text, "still drawing breath"), "a living player's report says so")
end
function tests.leaderboardRecordOnAnEmptyBoardLandsAtRankOne()
local board = Leaderboard.new()
local rank = Leaderboard.record(board, { score = 100 })
eq(rank, 1, "the first entry ever recorded ranks first")
eq(#board, 1, "the board now holds exactly one entry")
end
end end
local order = { local order = {