mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
Romset row and line on MAME and FinalBurn pages, files an app ships under their own badge and section, collection counts under the table, empty or constant summary columns dropped, short hashes with the full value in the title, the profile card and cards past Required folded, data directory pages kept out of the search.
187 lines
8.3 KiB
Python
187 lines
8.3 KiB
Python
"""Emulator pages say what is needed first, in names (round 2, package 7).
|
|
|
|
DuckStation's page opened on "It reads 105 files, 3 of them required" and
|
|
read as "get all three", its three BIOS were cards 12 to 14 under one
|
|
heading, its header said "Official ports" and "duckstation, Duckstation",
|
|
and every system was an id ("sony-playstation").
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
import sys
|
|
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 siterender # noqa: E402
|
|
|
|
EMPTY_DB = {"files": {}, "indexes": {"by_name": {}}}
|
|
|
|
|
|
def _profile(name: str) -> dict:
|
|
with open(REPO_ROOT / "emulators" / f"{name}.yml", encoding="utf-8") as handle:
|
|
return yaml.safe_load(handle)
|
|
|
|
|
|
def _page(name: str, profile: dict) -> str:
|
|
return gs.generate_emulator_page(name, profile, 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 TheIntroSaysWhatIsNeeded(unittest.TestCase):
|
|
def test_one_bios_per_region(self):
|
|
profile = _profile("duckstation")
|
|
intro = gs._emulator_intro("DuckStation", profile)
|
|
self.assertIn(
|
|
"It picks the BIOS for your game's region: scph5500.bin (Japan), "
|
|
"scph5501.bin (North America and Latin America) or scph5502.bin "
|
|
"(Europe and Oceania).", intro)
|
|
others = len(profile["files"]) - 3
|
|
self.assertIn(f"The {others} other files are optional.", intro)
|
|
self.assertNotIn("3 of them required", intro)
|
|
self.assertIn("DuckStation emulates Sony PlayStation.", intro)
|
|
|
|
def test_required_files_without_regions_keep_the_count(self):
|
|
intro = gs._emulator_intro("X", {"files": [
|
|
{"name": "a.bin", "required": True}, {"name": "b.bin"}]})
|
|
self.assertIn("It reads 2 files, 1 of them required", intro)
|
|
|
|
def test_several_machines_say_who_needs_a_required_file(self):
|
|
intro = gs._emulator_intro("X", {
|
|
"systems": ["sony-playstation", "sega-saturn"],
|
|
"files": [{"name": "a.bin", "required": True}]})
|
|
self.assertIn("A required file is needed only by the machines that use it.", intro)
|
|
one = gs._emulator_intro("X", {
|
|
"systems": ["sony-playstation"], "files": [{"name": "a.bin", "required": True}]})
|
|
self.assertNotIn("machines that use it", one)
|
|
|
|
|
|
class TheHeaderReadsAsWords(unittest.TestCase):
|
|
def setUp(self) -> None:
|
|
self.page = _page("duckstation", _profile("duckstation"))
|
|
|
|
def test_singular_classification(self):
|
|
self.assertIn("| Classification | Official port |", self.page)
|
|
|
|
def test_cores_once_per_spelling(self):
|
|
self.assertIn("| Cores | duckstation |", self.page)
|
|
|
|
def test_systems_by_name(self):
|
|
row = next(line for line in self.page.splitlines() if line.startswith("| Systems |"))
|
|
self.assertIn("Sony PlayStation", row)
|
|
self.assertNotIn("[sony-playstation]", row)
|
|
|
|
def test_region_badge_is_labelled(self):
|
|
self.assertIn(">Region: Japan</span>", self.page)
|
|
self.assertNotIn('rb-badge-muted">japan</span>', self.page)
|
|
|
|
def test_profile_version_names_the_pinned_build(self):
|
|
# DuckStation numbers builds v0.1-<commits since tag 0.1>: the pin,
|
|
# 4122fed9, is 12,070 commits past it.
|
|
self.assertRegex(str(_profile("duckstation")["core_version"]), r"^v0\.1-\d+$")
|
|
|
|
def test_the_second_spelling_is_a_platform_name(self):
|
|
# The lookup is case-sensitive and EmuELEC launches "Duckstation":
|
|
# the page hides the duplicate, the profile keeps it.
|
|
with open(REPO_ROOT / "platforms" / "emuelec.yml", encoding="utf-8") as handle:
|
|
emuelec = yaml.safe_load(handle)
|
|
self.assertIn("Duckstation", emuelec["cores"])
|
|
self.assertIn("Duckstation", _profile("duckstation")["cores"])
|
|
|
|
|
|
class RequiredFilesComeFirst(unittest.TestCase):
|
|
def test_sections_in_need_order(self):
|
|
files = [
|
|
{"name": "data.pak", "category": "game_data", "required": True},
|
|
{"name": "opt.bin"},
|
|
{"name": "req.bin", "required": True, "region": ["japan"], "md5": "ab" * 16},
|
|
]
|
|
page = _page("x", {"type": "standalone", "files": files})
|
|
heads = [line for line in page.splitlines() if line.startswith("## ")]
|
|
self.assertEqual(heads[:4], ["## Files", "## Required", "## Optional", "## Game data"])
|
|
self.assertLess(page.index("## Required"), page.index("req.bin"))
|
|
self.assertLess(page.index("req.bin"), page.index("## Optional"))
|
|
self.assertLess(page.index("## Game data"), page.index("data.pak"))
|
|
|
|
def test_the_table_of_contents_turns_on(self):
|
|
page = _page("duckstation", _profile("duckstation"))
|
|
self.assertGreater(len(re.findall(r"^## ", page, re.M)), 2)
|
|
|
|
def test_a_summary_table_above_the_cards(self):
|
|
files = _files(gs.EMULATOR_SUMMARY_MIN - 1) + [
|
|
{"name": "req.bin", "required": True, "region": ["japan"], "md5": "ab" * 16}]
|
|
page = _page("x", {"type": "standalone", "files": files})
|
|
self.assertIn("| File | Region | Required | Hash |", page)
|
|
row = next(line for line in page.splitlines() if "req.bin" in line and "| yes |" in line)
|
|
self.assertIn("(#file-req-bin", row)
|
|
self.assertIn("| Japan |", row)
|
|
self.assertIn(f'MD5\u00a0<code title="{"ab" * 16}">{"ab" * 6}</code>', row)
|
|
# The required row is the first one.
|
|
table = page.index("| File | Region | Required | Hash |")
|
|
self.assertLess(page.index("req.bin", table), page.index("f000.bin", table))
|
|
|
|
def test_no_table_for_a_few_cards(self):
|
|
page = _page("x", {"type": "standalone", "files": _files(2)})
|
|
self.assertNotIn("| File | Region | Required | Hash |", page)
|
|
|
|
def test_a_split_page_puts_required_on_the_first_part(self):
|
|
count = gs.EMULATOR_CARDS_PER_PAGE * 2
|
|
files = _files(count) + [{"name": "last.bin", "required": True}]
|
|
parts = gs.emulator_parts("big", files)
|
|
self.assertIn(count, parts[0][1])
|
|
pages = gs.emulator_pages("big", {"emulator": "Big", "type": "standalone",
|
|
"files": files}, {"files": {}})
|
|
main = pages["big"]
|
|
self.assertLess(main.index("## Required"), main.index("## Optional"))
|
|
self.assertLess(main.index("last.bin"), main.index("f000.bin"))
|
|
self.assertIn("## Required", pages["big-files-1"])
|
|
|
|
|
|
class TheSummaryLineIsProse(unittest.TestCase):
|
|
def test_no_pipes_and_one_number_format(self):
|
|
files = _files(1563, category="bios_zip") + [
|
|
{"name": "a.pak", "category": "game_data"}, {"name": "b.pak", "category": "game_data"}]
|
|
for f in files[:164]:
|
|
f["required"] = True
|
|
text = "\n".join(gs._emulator_file_summary(files))
|
|
self.assertNotIn(" | ", text)
|
|
self.assertNotIn("1399", text)
|
|
self.assertIn("1,401 optional", text)
|
|
self.assertIn("By kind: 1,563 BIOS ZIPs and 2 game data.", text)
|
|
|
|
def test_category_badge_in_words(self):
|
|
badges = " ".join(gs._file_badges({"name": "a", "category": "game_data"}, True))
|
|
self.assertIn(">game data</span>", badges)
|
|
|
|
|
|
class TheIndexNamesEmulatorsAndSystems(unittest.TestCase):
|
|
def test_columns_and_counts(self):
|
|
saved = dict(siterender._system_page_map)
|
|
self.addCleanup(siterender.set_system_page_map, saved)
|
|
siterender.set_system_page_map({"sony-playstation": ("sony", "PlayStation")})
|
|
page = gs.generate_emulators_index({
|
|
"duckstation": {"emulator": "DuckStation", "core_classification": "official_port",
|
|
"systems": ["sony-playstation"], "files": _files(3)},
|
|
})
|
|
self.assertIn("| Emulator | Kind | Systems | Files |", page)
|
|
self.assertIn("\n## D\n", page)
|
|
self.assertNotIn("| Engine |", page)
|
|
self.assertNotIn(" -- ", page)
|
|
row = next(line for line in page.splitlines() if line.startswith("| [DuckStation]"))
|
|
self.assertIn(f"[{siterender.system_name('sony-playstation')}]", row)
|
|
self.assertIn("(../systems/sony.md#playstation)", row)
|
|
self.assertNotIn("sony-playstation |", row)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|