test: cover tests.leaderboardRecordKeepsTheBoardSortedBestScoreFirst

This commit is contained in:
dualfroz committed 2026-09-11 20:34:09 +02:00
1 parent b0648df4e0
commit f68d0299e3
1 file changed
+173
+173
View File
@@ -9817,6 +9817,179 @@ function tests.leaderboardRecordOnAnEmptyBoardLandsAtRankOne()
eq(#board, 1, "the board now holds exactly one entry")
end
function tests.leaderboardRecordKeepsTheBoardSortedBestScoreFirst()
local board = Leaderboard.new()
Leaderboard.record(board, { score = 50, tag = "a" })
Leaderboard.record(board, { score = 90, tag = "b" })
Leaderboard.record(board, { score = 70, tag = "c" })
eq(board[1].tag, "b", "the highest score sorts to the very top")
eq(board[2].tag, "c", "the middling score lands second")
eq(board[3].tag, "a", "the lowest score lands last")
local rank = Leaderboard.record(board, { score = 80, tag = "d" })
eq(rank, 2, "a fresh entry ranks by where it actually lands, not where it was inserted")
eq(board[2].tag, "d", "the new entry displaces the weaker one down a slot")
eq(board[3].tag, "c", "everything below the insertion point shifts down by one")
end
function tests.leaderboardRecordDropsAnEntryThatDoesNotCrackTheCap()
local board = Leaderboard.new()
for i = 1, Leaderboard.CAPACITY do
Leaderboard.record(board, { score = 1000 - i })
end
eq(#board, Leaderboard.CAPACITY, "the board fills to exactly its capacity")
local rank = Leaderboard.record(board, { score = 1 })
eq(rank, nil, "a score worse than everything already on the board does not crack it")
eq(#board, Leaderboard.CAPACITY, "the board stays at capacity rather than growing")
eq(board[Leaderboard.CAPACITY].score, 1000 - Leaderboard.CAPACITY, "the weakest surviving entry is unchanged")
end
function tests.leaderboardRecordBumpsTheWeakestEntryOffOnceFull()
local board = Leaderboard.new()
for i = 1, Leaderboard.CAPACITY do
Leaderboard.record(board, { score = 1000 - i })
end
local worst = board[Leaderboard.CAPACITY].score
local rank = Leaderboard.record(board, { score = 1500 })
ok(rank ~= nil, "a score that beats the current worst entry cracks the board")
eq(#board, Leaderboard.CAPACITY, "the board stays at capacity after bumping someone off")
for _, entry in ipairs(board) do
ok(entry.score ~= worst, "the previous weakest entry no longer appears on the board")
end
end
function tests.leaderboardTopReturnsAtMostCountEntriesInOrder()
local board = Leaderboard.new()
Leaderboard.record(board, { score = 30 })
Leaderboard.record(board, { score = 10 })
Leaderboard.record(board, { score = 20 })
local top2 = Leaderboard.top(board, 2)
eq(#top2, 2, "top(2) returns exactly two entries")
eq(top2[1].score, 30, "the first slot is the best score")
eq(top2[2].score, 20, "the second slot is the next best score")
end
function tests.leaderboardTopDefaultsToTheFullCapacityWhenNoCountIsGiven()
local board = Leaderboard.new()
for i = 1, Leaderboard.CAPACITY + 3 do
Leaderboard.record(board, { score = i })
end
local top = Leaderboard.top(board)
eq(#top, Leaderboard.CAPACITY, "top() with no count returns the board's full capacity, not everything ever recorded")
end
function tests.leaderboardBestScoreReadsTheTopEntryOrZeroWhenEmpty()
eq(Leaderboard.bestScore(Leaderboard.new()), 0, "an empty board's best score is zero")
local board = Leaderboard.new()
Leaderboard.record(board, { score = 42 })
eq(Leaderboard.bestScore(board), 42, "the best score matches the single recorded entry")
end
function tests.metaLeaderboardFieldDefaultsToEmptyAndSurvivesASaveLoadRoundTrip()
local fresh = Meta.load("/tmp/warren_meta_does_not_exist_55511.sav")
eq(#fresh.leaderboard, 0, "a freshly defaulted meta state has an empty leaderboard")
local meta = Meta.new()
Leaderboard.record(meta.leaderboard, { score = 250, className = "mage", depth = 4, turn = 88, won = false, seed = 7 })
local path = os.tmpname()
Meta.save(meta, path)
local restored = Meta.load(path)
os.remove(path)
eq(#restored.leaderboard, 1, "a recorded leaderboard entry survives a save/load round trip")
eq(restored.leaderboard[1].score, 250, "a restored entry keeps its own score")
eq(restored.leaderboard[1].className, "mage", "a restored entry keeps its own class")
end
function tests.replayRunIsDeterministicAndMatchesAFreshGamesOwnReport()
local seed, steps = 55, 60
local game = Game.new(seed)
for _ = 1, steps do
if not game.player:isAlive() then break end
game:autoStep()
end
local expected = Morgue.build(game)
local replayed = Replay.run(seed, nil, steps)
local matches, mismatchField = Replay.matches(expected, replayed)
ok(matches, "replaying the same seed and step count reproduces every compared field (first mismatch: "
.. tostring(mismatchField) .. ")")
eq(replayed.turn, expected.turn, "the replay reaches the exact same turn")
eq(replayed.deepestDepth, expected.deepestDepth, "the replay reaches the exact same depth")
end
function tests.replayVerifyConfirmsAGenuineReportAndReturnsItsScore()
local seed, steps = 55, 60
local game = Game.new(seed)
for _ = 1, steps do
if not game.player:isAlive() then break end
game:autoStep()
end
local report = Morgue.build(game)
local matches, mismatchField, score = Replay.verify(seed, nil, steps, report)
ok(matches, "verify confirms a report that genuinely came from this seed and step count")
eq(mismatchField, nil, "a matching verify names no mismatched field")
eq(score, Morgue.score(report), "verify's returned score matches the report's own score")
end
function tests.replayVerifyFlagsATamperedReportAndStillReturnsTheRealScore()
local seed, steps = 55, 60
local game = Game.new(seed)
for _ = 1, steps do
if not game.player:isAlive() then break end
game:autoStep()
end
local report = Morgue.build(game)
local tampered = {}
for k, v in pairs(report) do tampered[k] = v end
tampered.gold = report.gold + 9999
local matches, mismatchField, score = Replay.verify(seed, nil, steps, tampered)
eq(matches, false, "a tampered gold total fails verification")
eq(mismatchField, "gold", "verify names gold as the field that diverged")
eq(score, Morgue.score(report), "the replay still reports the real, untampered score")
end
function tests.replayComparedFieldsCoversEveryFieldMorgueScoreActuallyReads()
local weighed = {
"deepestDepth", "kills", "bossKills", "questsCompleted", "artifactsFound",
"vaultsOpened", "setPiecesFound", "chestsOpened", "playerLevel", "gold", "won",
}
for _, field in ipairs(weighed) do
local found = false
for _, compared in ipairs(Replay.COMPARED_FIELDS) do
if compared == field then found = true end
end
ok(found, "Replay.COMPARED_FIELDS includes '" .. field .. "', every field Morgue.score weighs")
end
end
function tests.replayMatchesReportsTheFirstDivergingFieldInComparedFieldsOrder()
local base = {
won = false, alive = true, deepestDepth = 3, turn = 100, gold = 10, essence = 2,
kills = 1, bossKills = 0, questsCompleted = 0, artifactsFound = 0,
vaultsOpened = 0, setPiecesFound = 0, chestsOpened = 0, playerLevel = 1,
}
local altered = {}
for k, v in pairs(base) do altered[k] = v end
altered.turn = 999
local matches, field = Replay.matches(base, altered)
eq(matches, false, "a divergent turn count fails the match")
eq(field, "turn", "the mismatch is reported against the turn field specifically")
eq(Replay.matches(base, base), true, "an identical report matches itself")
end
function tests.challengesForDaySameDayAlwaysReturnsTheSamePresetAndSeed()
local presetA, seedA = Challenges.forDay(7)
local presetB, seedB = Challenges.forDay(7)
eq(presetA, presetB, "the same day index always names the identical preset table")
eq(seedA, seedB, "the same day index always yields the identical seed")
end
function tests.challengesForDayCyclesThroughTheCatalogInOrder()
for i = 0, #Challenges.CATALOG - 1 do
local preset = Challenges.forDay(i)
eq(preset, Challenges.CATALOG[i + 1], "day " .. i .. " maps to catalog slot " .. (i + 1))
end
local wrapped = Challenges.forDay(#Challenges.CATALOG)
eq(wrapped, Challenges.CATALOG[1], "the cycle wraps back to the first preset after one full lap")
end
end
local order = {