Files
gen1recomp/tests/engine/launcher_mod_downloads.lua
T
bryanthaboi bd1046f398 CLOSES #1393
2026-08-18 11:29:50 -04:00

126 lines
5.2 KiB
Lua

-- FIND MODS download counts: the index feed publishes them per listing, so
-- the panel reads the one fetch it already made instead of asking GitHub per
-- mod (that fan-out is what blew the hourly API limit in _findStatsCached's
-- own comment). This pins the resolver's precedence, the unknown-is-not-zero
-- rule the card and the sorts both depend on, and the Trending wiring.
-- luajit tests/engine/launcher_mod_downloads.lua
package.path = "./?.lua;./?/init.lua;" .. package.path
if not _G.love then _G.love = require("tests.love_stub") end
local T = require("tests.harness")
local check, eq = T.check, T.eq
-- No launcher test may reach the network: beginFetchReleases is the only door
-- out of _requestFindStats, and counting the calls is the assertion.
local ModUpdate = require("src.mods.ModUpdate")
local fetched = {}
ModUpdate.beginFetchReleases = function(repo, id)
fetched[#fetched + 1] = id
return { stage = "done" }
end
local RomImporter = require("src.import.RomImporter")
local function launcher()
return setmetatable({ tab = "find" }, RomImporter)
end
local function entry(id, downloads, github)
return { id = id, title = id, downloads = downloads, github = github }
end
-- ------- the feed's counts win, and cost nothing
do
local ri = launcher()
local e = entry("counted", { total = 1578, recent = 388, window_days = 30,
as_of = "2026-08-18T05:17:00.000Z" },
"someone/counted")
local stats = ri:_findStats(e)
eq(stats.total, 1578, "the feed's total is what the card shows")
eq(stats.recent, 388, "the trailing-window count rides along")
eq(stats.windowDays, 30, "so does the window it covers")
eq(stats.asOf, "2026-08-18T05:17:00.000Z", "and when the index read it")
eq(#fetched, 0, "a listing with a published total asks GitHub for nothing")
end
-- A bare number is what a cache written before the object shipped holds; it
-- is read back through the same resolver rather than migrated.
do
local ri = launcher()
eq(ri:_findStats(entry("legacy", 4321, "someone/legacy")).total, 4321,
"a cached scalar count still resolves")
eq(#fetched, 0, "and still costs no request")
end
-- Whole-list, not page-by-page: sorting calls the cached read for every entry
-- in the index, so all of them have to resolve from the feed alone. A
-- listing the feed dates but does not count still resolves, off `latest`.
do
local ri = launcher()
local dated = { id = "dated", title = "Dated", github = "someone/dated",
latest = { version = "1.0.0",
published_at = "2026-08-11T17:19:00Z" } }
local stats = ri:_findStats(dated)
eq(stats.latest, "2026-08-11", "the feed's own release blob dates the row")
eq(#fetched, 0, "with no repo fetch to wait on")
eq(ModUpdate.datesLine(stats.first, stats.latest), "Updated 2026-08-11",
"and the card states what it knows instead of a Released ?")
end
-- ------- unknown is unknown: null falls through to the repo, as any other
-- missing feed stat does, and a listing with no repo resolves to no counts
-- rather than to zero.
do
local ri = launcher()
check(ri:_findStats(entry("nulled", nil, "someone/nulled")) == nil,
"a null count is not an answer; the repo is still consulted")
eq(#fetched, 1, "which is the fetch the panel already made for dates")
local bare = launcher()
local stats = bare:_findStats(entry("no-repo", nil, nil))
check(stats ~= nil and stats.total == nil,
"a listing with neither counts nor a repo is resolved-but-unknown")
check(stats.recent == nil, "and has nothing to trend on")
eq(#fetched, 1, "and queues nothing of its own")
end
-- A real zero is not unknown: the index has seen the releases and counted
-- none. The card prints it and the sort ranks it above the unknowns.
do
local ri = launcher()
local stats = ri:_findStats(entry("zero", { total = 0 }, "someone/zero"))
eq(stats.total, 0, "a counted zero survives as a number")
eq(ModUpdate.downloadsShort(stats.total), "0 downloads",
"and prints as zero rather than as a dash")
end
-- ------- the panel wiring around those numbers
local view = (function()
local f = assert(io.open("src/import/LauncherView.lua", "r"))
local src = f:read("*a")
f:close()
return src
end)()
check(view:find('key = "trending"', 1, true) ~= nil,
"a Trending sort exists")
check(view:find('sortKey == "trending" then return stats and stats.recent or %-1'),
"Trending orders by the trailing-window count, unknown last")
check(view:find('sortKey == "popularity" then return stats and stats.total or %-1'),
"Most downloaded orders by the total, unknown last")
-- Trending has no meaning on the installed-mods tab, and the persisted key is
-- shared, so that panel has to degrade rather than sort on nothing.
check(view:find('if scope == "find" then', 1, true) ~= nil,
"Trending is offered only where the feed's counts exist")
check(view:find('sortKey == "trending" and scope ~= "find"', 1, true) ~= nil,
"the MODS tab falls back when the shared sort key is FIND-only")
check(view:find('sortKey or "popularity"', 1, true) ~= nil,
"the default sort is unchanged")
check(view:find("downloadsShort", 1, true) ~= nil,
"the browse card prints the abbreviated count")
T.finish("launcher_mod_downloads")