"""Emulator pages say what to get, and fit (round 3, package 7). NetherSX2 counted three interface fonts its app ships among "4 required" files and opened its file list on the project's counts. AetherSX2's summary held an empty Region column that pushed Required off a phone. No MAME or FinalBurn page said which romset its sets must match. DuckStation's page was 59 phone screens of optional cards, and MAME's index put 13,300 elements on one page. """ from __future__ import annotations import re import sys import tempfile import unittest from pathlib import Path import yaml REPO_ROOT = Path(__file__).resolve().parents[1] sys.path.insert(0, str(REPO_ROOT / "scripts")) import generate_site as gs # noqa: E402 import validate_site # noqa: E402 EMPTY_DB = {"files": {}, "indexes": {"by_name": {}}} DIST = REPO_ROOT / "website" / "dist" def _profile(name: str) -> dict: return yaml.safe_load((REPO_ROOT / "emulators" / f"{name}.yml").read_text(encoding="utf-8")) def _page(name: str, profile: dict | None = None) -> str: return gs.generate_emulator_page(name, profile or _profile(name), EMPTY_DB, None, set()) def _files(count: int, **fields: object) -> list[dict]: return [{"name": f"f{i:03d}.bin", **fields} for i in range(count)] class EachArcadePageNamesItsRomset(unittest.TestCase): def test_the_romset_by_profile(self): self.assertEqual(gs.emulator_romset(_profile("mame2003")), "MAME 0.78") # The app's version is 1.38.1, its MAME is 0.289. self.assertEqual(gs.emulator_romset(_profile("mame4droid-2024")), "MAME 0.289") self.assertEqual(gs.emulator_romset(_profile("mame2003_plus")), "MAME 0.78 (plus backports)") self.assertTrue(gs.emulator_romset(_profile("fbneo")).startswith("FinalBurn Neo ")) self.assertTrue(gs.emulator_romset(_profile("fbalpha2012")).startswith("FB Alpha ")) self.assertEqual(gs.emulator_romset(_profile("duckstation")), "") # HBMAME publishes no MAME release number. self.assertEqual(gs.emulator_romset(_profile("hbmame")), "") def test_a_row_and_a_line_under_the_intro(self): page = _page("mame2003") self.assertIn(f"| Romset | [MAME 0.78]({gs.ROMSET_FAQ}) |", page) self.assertNotIn("| MAME version |", _page("mame2016")) line = page.index("Its BIOS and game sets must come from the MAME 0.78 romset.") self.assertLess(line, page.index("About this profile")) self.assertIn(f"[Which version each core reads]({gs.ROMSET_FAQ})", page) def test_the_faq_answer_exists(self): faq = (REPO_ROOT / "wiki" / "technical-faq.md").read_text(encoding="utf-8") self.assertIn("## Which MAME version do the arcade BIOS sets match?", faq) def test_no_line_without_bios_zips(self): self.assertNotIn("must come from the", _page("duckstation")) class WhatTheAppShipsIsNoFileToGet(unittest.TestCase): def setUp(self) -> None: self.profile = _profile("nethersx2") self.page = _page("nethersx2", self.profile) def test_the_badge(self): font = next(f for f in self.profile["files"] if f["name"] == "Roboto-Regular.ttf") badges = " ".join(gs._file_badges(font, False)) self.assertIn(">comes with the app", badges) self.assertNotIn(">required", badges) self.assertNotIn(">missing", badges) # Installed by one build only: the other still reads it from the folder. dual = " ".join(gs._file_badges({"name": "a", "bundled": True, "mode": "standalone", "required": True}, False)) self.assertIn(">required", dual) self.assertIn("installed with the standalone emulator", dual) def test_counts_leave_them_out(self): shipped = sum(1 for f in self.profile["files"] if gs.comes_with_app(f)) self.assertGreater(shipped, 0) summary = self.page[self.page.index("## Files"):] self.assertIn(f"{shipped} more files come with the app.", summary) self.assertIn(": 1 required,", summary) # Found by content: one BIOS of any name, said as steps (round 4). self.assertIn("NetherSX2 needs one Sony PlayStation 2 BIOS file, any region.", self.page) def test_their_own_section_after_the_others(self): heads = re.findall(r"^## (.+)$", self.page, re.M) self.assertEqual(heads[heads.index("Files") + 1:heads.index("Files") + 3], ["Required", "Optional"]) self.assertIn("Comes with the app", heads) section = self.page[self.page.index("## Required"):self.page.index("## Optional")] self.assertNotIn("Roboto-Regular.ttf", section) def test_the_collection_counts_go_under_the_table(self): held = self.page.index("
In this collection:")
table = self.page.index("| File |")
self.assertLess(table, held)
self.assertLess(held, self.page.index("## Required"))
self.assertNotIn("in repo", self.page[self.page.index("## Files"):table])
def test_the_folder_is_the_apps_own(self):
self.assertIn("| BIOS directory | `bios/`, inside the app's own data folder |", self.page)
class TheSummaryTableFitsItsContent(unittest.TestCase):
def test_an_empty_region_column_goes(self):
page = _page("aethersx2")
table = next(line for line in page.splitlines() if line.startswith("| File |"))
self.assertNotIn("Region", table)
def test_a_constant_required_column_goes(self):
rows = gs._summary_table(_files(3, required=True), [0, 1, 2], lambda _i, s: s)
self.assertEqual(rows[0], "| File |")
def test_hashes_are_short_with_the_whole_value_in_the_title(self):
md5 = "0123456789abcdef" * 2
cell = gs._hash_short({"md5": md5})
self.assertEqual(cell, f'MD5 {md5[:12]}')
def test_the_split_index_holds_each_id_on_its_link(self):
files = _files(gs.EMULATOR_CARDS_PER_PAGE + 1, category="bios_zip")
main = gs.emulator_pages("big", {"emulator": "Big", "type": "standalone",
"files": files}, {"files": {}})["big"]
anchor = gs.emulator_file_anchors(files)[0]
self.assertIn(f'', main)
self.assertNotIn(f'', main)
class LongPagesFold(unittest.TestCase):
def test_optional_cards_fold_below_the_table(self):
files = _files(gs.EMULATOR_SUMMARY_MIN) + [{"name": "req.bin", "required": True}]
page = _page("x", {"type": "standalone", "files": files})
required = page[page.index("## Required"):page.index("## Optional")]
self.assertNotIn("2 files
", page)
def test_the_profile_card_folds(self):
page = _page("duckstation")
start = page.index("About this profile
")
self.assertLess(start, page.index('