mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-23 20:29:06 -05:00
Setup pages name the setup version the ZIP was made from, offer a partial install, answer a file in place but reported missing, and link the offline install. Get your files folds its tables into one closed block with part buttons. The setup comparison moves to the verification modes page. New Linux handhelds guide page.
274 lines
13 KiB
Python
274 lines
13 KiB
Python
"""Entry pages and guides (round 3, package 4).
|
|
|
|
A handheld owner found no tile for Android, ArkOS, muOS, Onion or spruceOS:
|
|
the systems sat in a closed note with a path seen from inside the device.
|
|
The setup version a pack fits was named only under Reference, the setup page
|
|
offered the full pack only, Get your files listed every setup twice, the Your
|
|
setup index ended on a table in project words, and the home page said a
|
|
Dreamcast needs its BIOS while Flycast boots without one.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import re
|
|
import sys
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
|
sys.path.insert(0, str(REPO_ROOT))
|
|
|
|
import generate_site # noqa: E402
|
|
import release_record # noqa: E402
|
|
import siteguides # noqa: E402
|
|
from common import load_platform_config, load_platform_registry # noqa: E402
|
|
from tests import sitepages # noqa: E402
|
|
|
|
REGISTRY = load_platform_registry(str(REPO_ROOT / "platforms"))
|
|
GUIDE = siteguides.HANDHELD_GUIDE
|
|
|
|
|
|
def _page(name: str) -> str:
|
|
sitepages.require()
|
|
return sitepages.page(name).read_text(encoding="utf-8")
|
|
|
|
|
|
def _guide_part(text: str) -> str:
|
|
"""The guide part of a setup page, glossary marks taken off."""
|
|
match = re.search(r"^## Reference\b", text, re.M)
|
|
text = text[: match.start()] if match else text
|
|
return re.sub(r"</?abbr[^>]*>", "", text)
|
|
|
|
|
|
def _display(key: str) -> str:
|
|
return load_platform_config(key, str(REPO_ROOT / "platforms")).get("platform", key)
|
|
|
|
|
|
class HandheldWayIn(unittest.TestCase):
|
|
def test_android_and_linux_tiles_on_home_and_get_your_files(self):
|
|
tiles = siteguides.GROUP_TILES.get("handheld", ())
|
|
self.assertEqual([tile.name for tile in tiles], ["Android", "Linux handhelds"])
|
|
for name in ("index.md", "which-pack.md"):
|
|
text = _page(name)
|
|
with self.subTest(page=name):
|
|
self.assertIn('href="/retrobios/platforms/retroarch/#where-the-files-go"', text)
|
|
self.assertIn('href="/retrobios/platforms/linux-handhelds/"', text)
|
|
self.assertIn(">Retroid, AYN Odin and other Android handhelds</span>", text)
|
|
|
|
def test_the_closed_note_is_gone(self):
|
|
self.assertNotIn("Other handhelds that run RetroArch", _page("which-pack.md"))
|
|
|
|
def test_one_row_per_detected_system(self):
|
|
detected = [name for name, _folder in siteguides.detected_systems(REGISTRY, GUIDE.uses)]
|
|
self.assertEqual(sorted((s.name for s in GUIDE.systems), key=str.casefold), detected)
|
|
text = _page(GUIDE.path)
|
|
for system in GUIDE.systems:
|
|
with self.subTest(system=system.name):
|
|
self.assertIn(f"| {system.name} |", text)
|
|
|
|
def test_every_folder_and_device_list_is_cited(self):
|
|
for system in GUIDE.systems:
|
|
with self.subTest(system=system.name):
|
|
if system.folder:
|
|
self.assertTrue(system.folder_source.startswith("https://"))
|
|
if system.devices:
|
|
self.assertTrue(system.devices_source.startswith("https://"))
|
|
for name in ("ArkOS", "muOS", "Onion", "spruceOS"):
|
|
system = next(s for s in GUIDE.systems if s.name == name)
|
|
with self.subTest(system=name):
|
|
self.assertTrue(system.folder and system.devices)
|
|
|
|
def test_a_value_without_its_page_is_refused(self):
|
|
with self.assertRaises(siteguides.GuideError):
|
|
siteguides._handheld_system({"name": "Onion", "folder": "`BIOS`"}, "x")
|
|
with self.assertRaises(siteguides.GuideError):
|
|
siteguides._handheld_system(
|
|
{"name": "Onion", "devices": ["Miyoo Mini"], "devices_source": "a blog"}, "x")
|
|
|
|
def test_the_guide_rejects_a_missing_or_unknown_system(self):
|
|
data = {"page": "x", "title": "X", "summary": "S", "uses": "retroarch",
|
|
"systems": [{"name": "Onion"}]}
|
|
with self.assertRaises(siteguides.GuideError):
|
|
siteguides._handheld_guide(data, REGISTRY, siteguides.GUIDES, "x")
|
|
|
|
def test_devices_are_a_search_field_with_no_text(self):
|
|
text = _page(GUIDE.path)
|
|
match = re.search(r'<span data-pagefind-meta="devices:([^"]*)"></span>', text)
|
|
self.assertIsNotNone(match)
|
|
self.assertIn("R36S", match[1])
|
|
self.assertIn("Miyoo Mini", match[1])
|
|
self.assertNotIn(",", match[1])
|
|
# The names typed most often are also on the page itself.
|
|
self.assertIn("R36S", text.split(match[0], 1)[1])
|
|
|
|
def test_the_guide_is_in_the_handheld_group_of_the_navigation(self):
|
|
coverages = {key: {"platform": _display(key)} for key in REGISTRY}
|
|
nav = generate_site.generate_nav(coverages, {}, {}, REGISTRY)
|
|
setup = next(tab["Your setup"] for tab in nav if "Your setup" in tab)
|
|
groups = {next(iter(item)): next(iter(item.values()))
|
|
for item in setup if isinstance(item, dict)}
|
|
label = siteguides.DEVICE_GROUPS["handheld"][0]
|
|
self.assertIn({GUIDE.title: GUIDE.path}, groups[label])
|
|
|
|
def test_the_guide_fills_the_card_and_never_its_root(self):
|
|
text = _page(GUIDE.path)
|
|
self.assertIn("--platform retroarch --dest E:\\BIOS", text)
|
|
self.assertNotRegex(text, r"--dest E:\\\s")
|
|
|
|
|
|
class PackNamesItsVersion(unittest.TestCase):
|
|
def test_the_line_under_the_release(self):
|
|
record = release_record.load_record()
|
|
if not release_record.pack_for("batocera", record):
|
|
self.skipTest("release.json has no Batocera pack")
|
|
block = generate_site._pack_buttons("batocera")
|
|
version = generate_site._pack_version(release_record.pack_name_for("batocera", record))
|
|
self.assertIn(f"Made from the BIOS list of Batocera {version}. "
|
|
+ generate_site.OTHER_VERSION, block)
|
|
|
|
def test_a_version_gap_is_said_once(self):
|
|
record = {"tag": "v2026.10.10", "packs": {"RetroBat_1.0_BIOS_Pack.zip": {
|
|
"assets": ["RetroBat_1.0_BIOS_Pack.zip"], "platforms": ["retrobat"]}}}
|
|
released = generate_site.release_line("retrobat", record)
|
|
line = generate_site.version_line("retrobat", record, named=len(released) > 1)
|
|
self.assertEqual(line, generate_site.OTHER_VERSION)
|
|
|
|
def test_the_v_prefix_is_dropped(self):
|
|
self.assertEqual(generate_site.setup_version("retroarch", {}),
|
|
f"RetroArch {load_platform_config('retroarch', 'platforms')['version'].lstrip('v')}")
|
|
|
|
def test_every_setup_page_names_a_version(self):
|
|
for key in REGISTRY:
|
|
with self.subTest(platform=key):
|
|
text = _guide_part(_page(f"platforms/{key}.md"))
|
|
self.assertRegex(text, r"(?:from the BIOS list of|This pack was built for) \S")
|
|
|
|
|
|
class SetupPagesOfferPartOfThePack(unittest.TestCase):
|
|
def test_pick_them_and_press_c(self):
|
|
for key in REGISTRY:
|
|
with self.subTest(platform=key):
|
|
text = _guide_part(_page(f"platforms/{key}.md"))
|
|
self.assertIn(f"/retrobios/which-pack/?platform={key}#only-some-consoles", text)
|
|
self.assertIn("or press **c** when the command asks.", text)
|
|
|
|
def test_the_anchor_exists(self):
|
|
self.assertIn("## Only some consoles?", _page("which-pack.md"))
|
|
|
|
def test_a_file_in_place_but_missing_is_answered(self):
|
|
for key in REGISTRY:
|
|
with self.subTest(platform=key):
|
|
self.assertIn("In place but reported missing?",
|
|
_guide_part(_page(f"platforms/{key}.md")))
|
|
|
|
|
|
class OfflineLine(unittest.TestCase):
|
|
def test_under_from_your_computer(self):
|
|
text = _page("platforms/batocera.md")
|
|
start = text.index("## From your computer")
|
|
line = text.index("No internet on the device?")
|
|
self.assertLess(start, line)
|
|
self.assertLess(line, text.index("## On the device"))
|
|
self.assertIn("/retrobios/wiki/installer/#without-a-network", text)
|
|
self.assertIn("{ #without-a-network }", (REPO_ROOT / "wiki" / "installer.md").read_text(
|
|
encoding="utf-8"))
|
|
|
|
|
|
class GetYourFilesListsEachSetupOnce(unittest.TestCase):
|
|
def setUp(self):
|
|
self.text = _page("which-pack.md")
|
|
|
|
def test_the_tables_are_in_one_closed_block(self):
|
|
block = re.search(r'<details class="rb-details[^"]*">\s*<summary>Every folder and ZIP '
|
|
r'in one table</summary>(.*?)</details>', self.text, re.S)
|
|
self.assertIsNotNone(block)
|
|
outside = self.text.replace(block[0], "")
|
|
self.assertNotIn("| Setup | Runs on | BIOS folder | ZIP |", outside)
|
|
for key in REGISTRY:
|
|
with self.subTest(platform=key):
|
|
self.assertEqual(block[1].count(f"| [{_display(key)}](/retrobios/platforms/{key}/) |"), 1)
|
|
|
|
def test_single_setup_groups_share_one_table(self):
|
|
self.assertIn("**Other setups**", self.text)
|
|
self.assertNotIn("**MiSTer FPGA**", self.text)
|
|
self.assertNotIn("**Self-hosted game library**", self.text)
|
|
|
|
def test_no_unzip_into_without_a_zip(self):
|
|
record = release_record.load_record()
|
|
for line in self.text.splitlines():
|
|
if "Unzip into" in line:
|
|
key = re.search(r"/retrobios/platforms/([a-z0-9]+)/", line)[1]
|
|
with self.subTest(platform=key):
|
|
self.assertTrue(release_record.pack_for(key, record))
|
|
|
|
def test_parts_are_buttons_with_the_size_after(self):
|
|
rows = [line for line in self.text.splitlines() if "Part 1 of" in line]
|
|
self.assertTrue(rows)
|
|
for row in rows:
|
|
self.assertRegex(row, r'<a class="rb-button" href="[^"]+">Part 1 of \d</a>')
|
|
self.assertRegex(row, r"</a> \(\d[\d.]* [KMG]B\) \|$")
|
|
|
|
def test_the_zip_note(self):
|
|
for line in ("A big ZIP comes in parts. Download every part.",
|
|
"Leave the ZIPs inside, like `neogeo.zip`, as they are.",
|
|
"Their setup's page says where to unzip them."):
|
|
self.assertIn(line, self.text)
|
|
self.assertNotIn("**Unzip into** means", self.text)
|
|
|
|
|
|
class YourSetupIndexInPlainWords(unittest.TestCase):
|
|
def test_the_index_links_the_table(self):
|
|
text = _page("platforms/index.md")
|
|
self.assertNotIn("| Platform |", text)
|
|
self.assertNotIn("at a glance", text.split("---", 2)[-1].lower().replace(
|
|
"every setup at a glance", ""))
|
|
self.assertIn("/retrobios/wiki/verification-modes/#every-setup-at-a-glance", text)
|
|
|
|
def test_the_table_on_verification_modes(self):
|
|
text = _page("wiki/verification-modes.md")
|
|
self.assertIn("| Setup | Files on its own list | Files in the ZIP | How it checks |", text)
|
|
table = text.split("## Every setup at a glance", 1)[1].split("\n## ", 1)[0]
|
|
self.assertNotIn("existence", table)
|
|
self.assertIn("| name only |", table)
|
|
self.assertIn("No list of its own", table)
|
|
self.assertLess(text.index("## Every setup at a glance"), text.index("## Next steps"))
|
|
|
|
def test_insertion_keeps_next_steps_last(self):
|
|
page = "# T\n\nBody.\n\n## Next steps\n\n- [A](a.md)\n"
|
|
out = generate_site.with_setup_table(page, {}, {})
|
|
self.assertTrue(out.rstrip().endswith("- [A](a.md)"))
|
|
self.assertIn("## Every setup at a glance", out)
|
|
|
|
|
|
class HomeCopy(unittest.TestCase):
|
|
def test_dreamcast_and_the_check_link(self):
|
|
home = re.sub(r"</?abbr[^>]*>", "", _page("index.md"))
|
|
self.assertIn("- **Yes** for PlayStation 1 and 2, Saturn and Neo Geo.", home)
|
|
self.assertIn("- **Better with it** for Dreamcast: some games need it.", home)
|
|
# The level label opens its line, never the middle of a sentence.
|
|
self.assertNotIn("? Reference:", home)
|
|
self.assertIn("- Reference: [Check your file]", home)
|
|
self.assertIn("BIOS missing, even with the file there?", home)
|
|
|
|
def test_flycast_boots_without_the_dreamcast_bios(self):
|
|
import yaml
|
|
|
|
profile = yaml.safe_load((REPO_ROOT / "emulators" / "flycast.yml").read_text(encoding="utf-8"))
|
|
boot = next(f for f in profile["files"] if f.get("name") == "dc_boot.bin")
|
|
self.assertFalse(boot.get("required"))
|
|
self.assertTrue(boot.get("hle_fallback"))
|
|
|
|
|
|
class DownloadLine(unittest.TestCase):
|
|
def test_checksums_and_signature_read_as_two(self):
|
|
record = release_record.load_record()
|
|
if not release_record.pack_for("batocera", record):
|
|
self.skipTest("release.json has no Batocera pack")
|
|
line = generate_site.release_line("batocera", record)[0]
|
|
self.assertRegex(line, r"\[SHA256SUMS\.txt\]\([^)]+\) and its \[signature\]\([^)]+\)\.$")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|