mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-24 12:49:03 -05:00
A manufacturer page over 500 KB of Markdown becomes a summary: its largest consoles move to pages of their own, cut into parts when one console is still too large, and every console keeps its heading there. MAME's 1,564 cards move to four pages, its page keeping a row per entry with the card's old anchor. RetroDECK's arcade list gets its own page. site.js follows a moved card by content or by its row. The largest page drops from 10.5 MB to 0.88 MB. Emulator groups of the navigation open by initial (65 KB to 41 KB before the content). File cards are level 3 under a level 2, and the hook keeps the table of contents of card pages to level 2: platform pages no longer list every system id. Key/value cards name their columns. The sweep runs before the decoration, which kept every page no generator wrote any more.
169 lines
7.7 KiB
Python
169 lines
7.7 KiB
Python
"""Pages a phone can open: split pages, light navigation, short tables of contents.
|
|
|
|
systems/game-engines/ was one 10.5 MB page, emulators/mame/ 3 MB, and each
|
|
of 600 emulator pages carried 65 KB of navigation. A large page is now a
|
|
summary with pages of its own, and every address cited before the split
|
|
still lands: a console's heading stays on the summary, a card's sha1 anchor
|
|
is looked up by content, an emulator card's anchor sits on its row.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
from types import SimpleNamespace
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
|
|
import generate_site # noqa: E402
|
|
import mkdocs_hooks # noqa: E402
|
|
import siterender # noqa: E402
|
|
from cross_reference import FileConsumers # noqa: E402
|
|
|
|
|
|
def _file(name: str, index: int, console: str, maker: str = "Maker") -> dict:
|
|
sha1 = f"{index:012x}" + "0" * 28
|
|
return {"name": name, "sha1": sha1, "md5": f"{index:032x}", "size": 10,
|
|
"path": f"bios/{maker}/{console}/{name}"}
|
|
|
|
|
|
class ASystemPageOverItsBudgetIsSplit(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
siterender.reset_console_pages()
|
|
self.addCleanup(siterender.reset_console_pages)
|
|
self.consoles = {
|
|
"Big": [_file(f"big{i:03d}.bin", i, "Big") for i in range(60)],
|
|
"Small": [_file("small.bin", 900, "Small")],
|
|
}
|
|
|
|
def _pages(self, budget: int) -> dict:
|
|
return generate_site.system_pages(
|
|
"Maker", self.consoles, FileConsumers({"files": {}}), budget=budget)
|
|
|
|
def test_a_page_within_its_budget_stays_whole(self):
|
|
pages = self._pages(10_000_000)
|
|
self.assertEqual(list(pages), ["maker"])
|
|
self.assertIn("## Big", pages["maker"][0])
|
|
|
|
def test_the_largest_section_moves_and_is_cut_in_parts(self):
|
|
pages = self._pages(20_000)
|
|
summary = pages["maker"][0]
|
|
# Both headings stay on the summary: systems/maker/#big still lands.
|
|
self.assertIn("## Big", summary)
|
|
self.assertIn("## Small", summary)
|
|
# The small section keeps its cards in place.
|
|
self.assertIn("{ #sha1-" + f"{900:012x}", summary)
|
|
parts = [stem for stem in pages if stem.startswith("maker-big")]
|
|
self.assertGreater(len(parts), 1)
|
|
self.assertEqual(parts[0], "maker-big")
|
|
for stem in parts:
|
|
self.assertIn(f"]({stem}.md)", summary)
|
|
self.assertLessEqual(len(pages[stem][0]), 20_000 + 5_000)
|
|
self.assertIn("## Files", pages[stem][0])
|
|
# Each card is on exactly one part, and the links follow it.
|
|
held = [f["sha1"] for stem in parts for f in pages[stem][1]["Big"]]
|
|
self.assertEqual(sorted(held), sorted(f["sha1"] for f in self.consoles["Big"]))
|
|
last = self.consoles["Big"][-1]
|
|
self.assertEqual(siterender.card_page(last["path"], last["sha1"]), parts[-1])
|
|
small = self.consoles["Small"][0]
|
|
self.assertEqual(siterender.card_page(small["path"], small["sha1"]), "maker")
|
|
self.assertEqual(siterender.console_href("maker", "Big"), "systems/maker.md#big")
|
|
|
|
def test_a_console_on_one_page_is_linked_directly(self):
|
|
self.consoles["Big"] = self.consoles["Big"][:12]
|
|
whole = self._pages(10**9)["maker"][0]
|
|
pages = self._pages(len(whole) - 1)
|
|
self.assertIn("maker-big", pages)
|
|
self.assertNotIn("maker-big-2", pages)
|
|
self.assertEqual(siterender.console_href("maker", "Big", "../"),
|
|
"../systems/maker-big.md")
|
|
|
|
|
|
class AnEmulatorWithTooManyCardsIsSplit(unittest.TestCase):
|
|
def test_parts_are_balanced_and_rows_keep_the_anchors(self):
|
|
files = [{"name": f"set{i:04d}.zip", "required": i % 2 == 0, "category": "bios_zip"}
|
|
for i in range(generate_site.EMULATOR_CARDS_PER_PAGE * 2 + 1)]
|
|
parts = generate_site.emulator_parts("big", files)
|
|
self.assertEqual([stem for stem, _ in parts], ["big-files-1", "big-files-2", "big-files-3"])
|
|
sizes = [len(entries) for _, entries in parts]
|
|
self.assertLessEqual(max(sizes) - min(sizes), 1)
|
|
self.assertEqual(generate_site.emulator_parts("small", files[:3]), [])
|
|
|
|
pages = generate_site.emulator_pages(
|
|
"big", {"emulator": "Big", "type": "standalone", "files": files}, {"files": {}})
|
|
self.assertEqual(sorted(pages), ["big", "big-files-1", "big-files-2", "big-files-3"])
|
|
main = pages["big"]
|
|
anchors = generate_site.emulator_file_anchors(files)
|
|
for anchor in anchors:
|
|
self.assertIn(f'<span id="{anchor}"></span>', main)
|
|
self.assertIn('class="rb-card-index"', main)
|
|
self.assertNotIn(".rb-file-title", main)
|
|
self.assertIn(f"{{ #{anchors[0]} .rb-file-title }}", pages["big-files-1"])
|
|
|
|
def test_cards_are_linked_on_the_page_that_holds_them(self):
|
|
files = [{"name": f"set{i:04d}.zip"} for i in range(generate_site.EMULATOR_CARDS_PER_PAGE + 1)]
|
|
generate_site.plan_emulator_pages({"big": {"files": files}})
|
|
anchors = generate_site.emulator_file_anchors(files)
|
|
self.assertEqual(siterender.emulator_card_page("big", anchors[-1]), "big-files-2")
|
|
self.assertEqual(siterender.emulator_card_page("other", "file-x"), "other")
|
|
|
|
|
|
class APlatformSystemOverItsBudgetMoves(unittest.TestCase):
|
|
def test_the_heading_stays_and_the_list_moves(self):
|
|
files = [{"name": f"f{i:04d}.zip", "status": "ok"} for i in range(40)]
|
|
config = {("arcade", f["name"]): [{"name": f["name"], "md5": "a" * 32}] for f in files}
|
|
moved: dict[str, str] = {}
|
|
budget = generate_site.PLATFORM_SECTION_BUDGET
|
|
generate_site.PLATFORM_SECTION_BUDGET = 500
|
|
try:
|
|
lines = generate_site._render_platform_systems(
|
|
{"arcade": files}, config, {}, ("deck", "Deck"), moved)
|
|
finally:
|
|
generate_site.PLATFORM_SECTION_BUDGET = budget
|
|
text = "\n".join(lines)
|
|
self.assertIn("{ #arcade }", text)
|
|
self.assertIn("](deck-arcade.md)", text)
|
|
self.assertNotIn("f0001.zip", text)
|
|
self.assertIn("f0001.zip", moved["deck-arcade"])
|
|
self.assertIn("[Deck page](deck.md#arcade)", moved["deck-arcade"])
|
|
|
|
|
|
class TheNavigationOpensOneInitial(unittest.TestCase):
|
|
def test_a_group_of_several_initials_is_nested(self):
|
|
profiles = {
|
|
key: {"emulator": name, "systems": ["s"]}
|
|
for key, name in (("a1", "Alpha"), ("b1", "Beta"), ("b2", "bravo"), ("z", "Zed"))
|
|
}
|
|
nav = generate_site._emulator_nav(profiles)
|
|
groups = {next(iter(g)): next(iter(g.values())) for g in nav[1:]}
|
|
self.assertEqual(groups["A to C"], [
|
|
{"A": [{"Alpha": "emulators/a1.md"}]},
|
|
{"B": [{"Beta": "emulators/b1.md"}, {"bravo": "emulators/b2.md"}]},
|
|
])
|
|
self.assertEqual(groups["V to Z"], [{"Zed": "emulators/z.md"}])
|
|
|
|
|
|
class TheTableOfContentsOfACardPageStopsAtLevelTwo(unittest.TestCase):
|
|
@staticmethod
|
|
def _item(level: int, children: list | None = None) -> SimpleNamespace:
|
|
return SimpleNamespace(level=level, children=children or [])
|
|
|
|
def test_cards_leave_the_toc_and_wiki_pages_keep_level_three(self):
|
|
def page(uri: str) -> SimpleNamespace:
|
|
h2 = self._item(2, [self._item(3)])
|
|
return SimpleNamespace(file=SimpleNamespace(src_uri=uri),
|
|
toc=SimpleNamespace(items=[self._item(1, [h2])]))
|
|
|
|
for uri, kept in (("systems/sony.md", 0), ("platforms/retroarch.md", 0),
|
|
("emulators/mame.md", 0), ("wiki/faq.md", 1)):
|
|
current = page(uri)
|
|
mkdocs_hooks.on_page_content("", current, None, None)
|
|
with self.subTest(uri=uri):
|
|
self.assertEqual(len(current.toc.items[0].children[0].children), kept)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|