mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
feat: emulator pages lead with what is needed
# Conflicts: # wiki/testing-guide.md
This commit is contained in:
commit
eb6ca6d38a
5 files changed
+404
-61
No files matched your search
@@ -3953,7 +3953,7 @@ class TheSiteCountsSlotsNotVersions(unittest.TestCase):
|
||||
]
|
||||
line = _emulator_file_summary(files, lambda f: f.get("crc32") == "2")[0]
|
||||
self.assertIn("**2 files** (3 accepted versions)", line)
|
||||
self.assertIn("1 in repo, 1 missing", line)
|
||||
self.assertIn("1 in repo and 1 missing", line)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
"""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("MD5\u00a0`abababab`", 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, lambda _f: True))
|
||||
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 | Systems | Files |", page)
|
||||
self.assertNotIn("| Engine |", page)
|
||||
self.assertNotIn(" -- ", page)
|
||||
self.assertIn("1 profile.", 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()
|
||||
Reference in new issue
Block a user