mirror of
https://github.com/bryanthaboi/gen1recomp.git
synced 2026-08-18 19:54:21 +02:00
126 lines
5.2 KiB
Lua
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")
|