mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-11-05 09:33:52 -06:00
feat: name each system once, from its own section
siterender.system_name reads the heading of the console section the id spells, then SYSTEM_NAMES, and raises for an id in neither. The emulator intro and the picker titles read it instead of the folder a system's files were voted onto.
This commit is contained in:
1 parent
2a50bc21f7
commit
72e7507ff9
4 files changed
+695
-10
No files matched your search
@@ -4656,12 +4656,9 @@ def _emulator_intro(emu_name: str, profile: dict) -> str:
|
|||||||
The page opened on a twelve-row table: "Type", "Version", "Checked by".
|
The page opened on a twelve-row table: "Type", "Version", "Checked by".
|
||||||
DuckStation needs one PlayStation BIOS of any name, and the reader had
|
DuckStation needs one PlayStation BIOS of any name, and the reader had
|
||||||
to infer it from the "Files found by" row."""
|
to infer it from the "Files found by" row."""
|
||||||
import siterender # noqa: PLC0415
|
|
||||||
|
|
||||||
names: list[str] = []
|
names: list[str] = []
|
||||||
for sys_id in profile.get("systems") or []:
|
for sys_id in profile.get("systems") or []:
|
||||||
page = siterender._system_page_map.get(sys_id) or siterender._page_by_norm(sys_id)
|
label = system_name(sys_id)
|
||||||
label = page[1] if page else str(sys_id)
|
|
||||||
if label not in names:
|
if label not in names:
|
||||||
names.append(label)
|
names.append(label)
|
||||||
files = [f for f in profile.get("files") or [] if isinstance(f, dict)]
|
files = [f for f in profile.get("files") or [] if isinstance(f, dict)]
|
||||||
@@ -6675,6 +6672,7 @@ def _generate(args: argparse.Namespace) -> None:
|
|||||||
_system_pages_from_data(manufacturers, coverages, db, profiles)
|
_system_pages_from_data(manufacturers, coverages, db, profiles)
|
||||||
)
|
)
|
||||||
print(f" {len(_system_page_map)} system IDs mapped to pages")
|
print(f" {len(_system_page_map)} system IDs mapped to pages")
|
||||||
|
set_console_sections(manufacturers, program_names(profiles))
|
||||||
|
|
||||||
print("Generating system pages...")
|
print("Generating system pages...")
|
||||||
|
|
||||||
@@ -6864,11 +6862,10 @@ def _generate(args: argparse.Namespace) -> None:
|
|||||||
json.dumps(sitestarlight.sidebar(nav, present), indent=1) + "\n")
|
json.dumps(sitestarlight.sidebar(nav, present), indent=1) + "\n")
|
||||||
write_if_changed(str(generated / "lastmod.json"),
|
write_if_changed(str(generated / "lastmod.json"),
|
||||||
json.dumps(dict(sorted(lastmod.items())), indent=1) + "\n")
|
json.dumps(dict(sorted(lastmod.items())), indent=1) + "\n")
|
||||||
mfr_names = {mfr.lower().replace(" ", "-"): mfr for mfr in manufacturers}
|
system_ids = set(_system_page_map) | {
|
||||||
titles = {}
|
sys_id for cov in coverages.values() for sys_id in cov["config"].get("systems", {})
|
||||||
for sys_id, (slug, console) in _system_page_map.items():
|
}
|
||||||
mfr = mfr_names.get(slug, "")
|
titles = {sys_id: system_name(sys_id) for sys_id in sorted(system_ids)}
|
||||||
titles[sys_id] = console if console.startswith(mfr) else f"{mfr} {console}"
|
|
||||||
sitestarlight.picker_data(_REPO_ROOT / "install", public / "data" / "picker", titles)
|
sitestarlight.picker_data(_REPO_ROOT / "install", public / "data" / "picker", titles)
|
||||||
total_pages = len(present)
|
total_pages = len(present)
|
||||||
print(f"\nGenerated {total_pages} pages in {args.docs_dir}/")
|
print(f"\nGenerated {total_pages} pages in {args.docs_dir}/")
|
||||||
@@ -6903,6 +6900,9 @@ from siterender import ( # noqa: E402,F401
|
|||||||
_system_page_map,
|
_system_page_map,
|
||||||
_system_link,
|
_system_link,
|
||||||
set_system_page_map,
|
set_system_page_map,
|
||||||
|
set_console_sections,
|
||||||
|
program_names,
|
||||||
|
system_name,
|
||||||
card_page,
|
card_page,
|
||||||
console_href,
|
console_href,
|
||||||
record_console_pages,
|
record_console_pages,
|
||||||
|
|||||||
@@ -306,3 +306,568 @@ def _by_mode(value: str | dict, mode: str) -> str:
|
|||||||
if isinstance(value, dict):
|
if isinstance(value, dict):
|
||||||
return str(value.get(mode) or "") if mode else ""
|
return str(value.get(mode) or "") if mode else ""
|
||||||
return str(value or "")
|
return str(value or "")
|
||||||
|
|
||||||
|
|
||||||
|
# System display names. A system is named by the heading of the console
|
||||||
|
# section that is its own: the folder its id spells, under the maker the id
|
||||||
|
# names when two makers file a console of that name. The page a system's
|
||||||
|
# files were voted onto is not its section and never names it. That vote
|
||||||
|
# called nintendo-gba "Nintendo Game Boy" and camplynx "Arcade". A system
|
||||||
|
# with no section of its own is named in SYSTEM_NAMES, and a system in
|
||||||
|
# neither stops the build.
|
||||||
|
|
||||||
|
# Folders that file copies by the emulator or board that loads them. Their
|
||||||
|
# headings name a program, not a system.
|
||||||
|
_PROGRAM_TOPS = frozenset({"Other", "Arcade"})
|
||||||
|
|
||||||
|
# Normalized id -> the console sections spelled that way.
|
||||||
|
_console_sections: dict[str, set[tuple[str, str]]] = {}
|
||||||
|
# Emulator and engine names. A heading spelled like one (Game Engines >
|
||||||
|
# Solarus, ZC > ZC210) files that program's copies and names no system.
|
||||||
|
_program_names: set[str] = set()
|
||||||
|
|
||||||
|
|
||||||
|
def program_names(profiles: dict[str, dict]) -> set[str]:
|
||||||
|
"""Every name an emulator profile goes by: its key, its emulator and
|
||||||
|
display names."""
|
||||||
|
names = {str(key) for key in profiles}
|
||||||
|
for profile in profiles.values():
|
||||||
|
names.update(
|
||||||
|
str(profile[field]) for field in ("emulator", "display_name")
|
||||||
|
if profile.get(field)
|
||||||
|
)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def set_console_sections(
|
||||||
|
sections: dict[str, dict] | set[tuple[str, str]],
|
||||||
|
programs: set[str] | frozenset[str] = frozenset(),
|
||||||
|
) -> None:
|
||||||
|
"""Install the console sections the system pages carry.
|
||||||
|
|
||||||
|
``sections`` maps each manufacturer to its consoles, as the system pages
|
||||||
|
group them, or is a set of (manufacturer, console) pairs. ``programs``
|
||||||
|
are the emulator names, which never name a system.
|
||||||
|
"""
|
||||||
|
from common import _norm_system_id
|
||||||
|
|
||||||
|
pairs = (
|
||||||
|
{(mfr, console) for mfr, consoles in sections.items() for console in consoles}
|
||||||
|
if isinstance(sections, dict) else set(sections)
|
||||||
|
)
|
||||||
|
_console_sections.clear()
|
||||||
|
for mfr, console in pairs:
|
||||||
|
spelled = console.lower().replace(" ", "-")
|
||||||
|
slug = mfr.lower().replace(" ", "-")
|
||||||
|
for key in {_norm_system_id(f"{slug}-{spelled}"), _norm_system_id(spelled)}:
|
||||||
|
_console_sections.setdefault(key, set()).add((mfr, console))
|
||||||
|
_program_names.clear()
|
||||||
|
_program_names.update(name.casefold() for name in programs)
|
||||||
|
_sections_installed[0] = True
|
||||||
|
|
||||||
|
|
||||||
|
_sections_installed = [False]
|
||||||
|
_REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
|
def _ensure_console_sections() -> None:
|
||||||
|
"""Read the sections from the repository when no generator installed
|
||||||
|
them, so a page rendered on its own names systems as the site does."""
|
||||||
|
if _sections_installed[0]:
|
||||||
|
return
|
||||||
|
import json
|
||||||
|
|
||||||
|
from common import load_emulator_profiles
|
||||||
|
from generate_site import _group_by_manufacturer
|
||||||
|
|
||||||
|
with open(_REPO_ROOT / "database.json", encoding="utf-8") as handle:
|
||||||
|
db = json.load(handle)
|
||||||
|
profiles = load_emulator_profiles(str(_REPO_ROOT / "emulators"), skip_aliases=False)
|
||||||
|
set_console_sections(_group_by_manufacturer(db), program_names(profiles))
|
||||||
|
|
||||||
|
|
||||||
|
def _own_section(sys_id: str) -> tuple[str, str] | None:
|
||||||
|
"""The console section that is this id's own, or None.
|
||||||
|
|
||||||
|
Of two sections spelled alike (Atari and Camputers both file a Lynx),
|
||||||
|
the one under the maker the id names is kept. Two left is no answer,
|
||||||
|
and neither is a section that files a program's copies.
|
||||||
|
"""
|
||||||
|
from common import _norm_system_id
|
||||||
|
|
||||||
|
_ensure_console_sections()
|
||||||
|
places = _console_sections.get(_norm_system_id(sys_id), set())
|
||||||
|
if len(places) > 1:
|
||||||
|
places = {
|
||||||
|
(mfr, console) for mfr, console in places
|
||||||
|
if sys_id.lower().startswith(mfr.lower().replace(" ", "-") + "-")
|
||||||
|
}
|
||||||
|
if len(places) != 1:
|
||||||
|
return None
|
||||||
|
mfr, console = next(iter(places))
|
||||||
|
# A folder under a program's top, named like its own page (Dinothawr) or
|
||||||
|
# like an emulator holds a program's files, not a system's.
|
||||||
|
if (
|
||||||
|
mfr in _PROGRAM_TOPS
|
||||||
|
or console.casefold() == mfr.casefold()
|
||||||
|
or _heading_name(mfr, console).casefold() in _program_names
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
return mfr, console
|
||||||
|
|
||||||
|
|
||||||
|
def _heading_name(mfr: str, console: str) -> str:
|
||||||
|
"""A console heading read out of its page: the maker in front, unless
|
||||||
|
the heading already starts with it or the page is a game publisher's."""
|
||||||
|
from common import GAME_DATA_TOPS
|
||||||
|
|
||||||
|
if mfr in GAME_DATA_TOPS:
|
||||||
|
return console
|
||||||
|
if console.casefold().startswith(mfr.split()[0].casefold()):
|
||||||
|
return console
|
||||||
|
return f"{mfr} {console}"
|
||||||
|
|
||||||
|
|
||||||
|
def system_name(sys_id: str) -> str:
|
||||||
|
"""The display name of a system id, the only one a page prints."""
|
||||||
|
sys_id = str(sys_id)
|
||||||
|
section = _own_section(sys_id)
|
||||||
|
if section is not None:
|
||||||
|
return _heading_name(*section)
|
||||||
|
name = SYSTEM_NAMES.get(sys_id)
|
||||||
|
if name is None:
|
||||||
|
raise KeyError(
|
||||||
|
f"system {sys_id!r} has no console section of its own and no "
|
||||||
|
"entry in siterender.SYSTEM_NAMES"
|
||||||
|
)
|
||||||
|
return name
|
||||||
|
|
||||||
|
|
||||||
|
# Systems without a console section of their own.
|
||||||
|
SYSTEM_NAMES: dict[str, str] = {
|
||||||
|
"2ship": "The Legend of Zelda: Majora's Mask",
|
||||||
|
"64dd": "Nintendo 64DD",
|
||||||
|
"aarch64": "ARM 64-bit (AArch64)",
|
||||||
|
"acclaim-zn1": "Acclaim ZN-1",
|
||||||
|
"adrift": "ADRIFT",
|
||||||
|
"advsys": "AdvSys",
|
||||||
|
"ags": "Adventure Game Studio games",
|
||||||
|
"agt": "Adventure Game Toolkit",
|
||||||
|
"alan": "Alan",
|
||||||
|
"alg-laserdisc": "American Laser Games laserdisc",
|
||||||
|
"allied-leisure-pinball": "Allied Leisure pinball",
|
||||||
|
"alpha": "DEC Alpha",
|
||||||
|
"andamiro-pumpitup": "Andamiro Pump It Up",
|
||||||
|
"apf-m1000": "APF M-1000",
|
||||||
|
"apfm1000": "APF M-1000",
|
||||||
|
"apple-iie": "Apple IIe",
|
||||||
|
"apple-ios": "Apple iOS",
|
||||||
|
"apple2": "Apple II",
|
||||||
|
"apple2gs": "Apple IIGS",
|
||||||
|
"arcade": "Arcade games",
|
||||||
|
"arcade-laserdisc": "Laserdisc arcade games",
|
||||||
|
"arcadia-systems": "Arcadia Systems Multi Select",
|
||||||
|
"arduboy": "Arduboy",
|
||||||
|
"aristocrat-mk5": "Aristocrat MK5",
|
||||||
|
"aristocrat-mk6": "Aristocrat MK6",
|
||||||
|
"aristocrat-mk7": "Aristocrat MK7",
|
||||||
|
"arm": "ARM",
|
||||||
|
"astrocde": "Bally Astrocade",
|
||||||
|
"atari-falcon": "Atari Falcon",
|
||||||
|
"atari-jaguarcd": "Atari Jaguar CD",
|
||||||
|
"atari-ste": "Atari STE",
|
||||||
|
"atari-system1": "Atari System 1",
|
||||||
|
"atari-tt": "Atari TT",
|
||||||
|
"atari-zn1": "Atari ZN-1",
|
||||||
|
"atlus-zn1": "Atlus ZN-1",
|
||||||
|
"atom": "Acorn Atom",
|
||||||
|
"bandai-playdia": "Bandai Playdia",
|
||||||
|
"bandai-wswan": "Bandai WonderSwan",
|
||||||
|
"bandai-wswanc": "Bandai WonderSwan Color",
|
||||||
|
"barcrest-mpu4": "Barcrest MPU4",
|
||||||
|
"bbc-master-128": "Acorn BBC Master 128",
|
||||||
|
"bbc-master-compact": "Acorn BBC Master Compact",
|
||||||
|
"bbc-master-et": "Acorn BBC Master ET",
|
||||||
|
"bbc-micro-b": "Acorn BBC Micro Model B",
|
||||||
|
"bbc-micro-bplus": "Acorn BBC Micro Model B+",
|
||||||
|
"bbk-longman-4980": "BBK Longman A4980",
|
||||||
|
"bbk-longman-4988": "BBK Longman A4988",
|
||||||
|
"bennugd": "BennuGD games",
|
||||||
|
"bermuda-syndrome": "Bermuda Syndrome game",
|
||||||
|
"brezzasoft-crystal": "BrezzaSoft Crystal System",
|
||||||
|
"bshift": "Half-Life: Blue Shift",
|
||||||
|
"bsyndrome": "Bermuda Syndrome game",
|
||||||
|
"caesar3": "Caesar III",
|
||||||
|
"cambridge-z88": "Cambridge Computer Z88",
|
||||||
|
"camplynx": "Camputers Lynx",
|
||||||
|
"capcom-cps1": "Capcom CPS-1",
|
||||||
|
"capcom-cps2": "Capcom CPS-2",
|
||||||
|
"capcom-cps3": "Capcom CPS-3",
|
||||||
|
"capcom-zn1": "Capcom ZN-1",
|
||||||
|
"capcom-zn2": "Capcom ZN-2",
|
||||||
|
"casio-pv1000": "Casio PV-1000",
|
||||||
|
"catacomb-3d": "Catacomb 3-D",
|
||||||
|
"catacomb-adventure": "Catacomb Adventure Series",
|
||||||
|
"cave-cv1000": "Cave CV1000",
|
||||||
|
"cave-story": "Cave Story",
|
||||||
|
"cavestory": "Cave Story",
|
||||||
|
"celeste-classic": "Celeste Classic",
|
||||||
|
"century-cvs": "Century CVS",
|
||||||
|
"ces-galaxy-games": "CES Galaxy Games",
|
||||||
|
"cgenie": "EACA Colour Genie",
|
||||||
|
"chex": "Chex Quest",
|
||||||
|
"chihiro": "Sega Chihiro",
|
||||||
|
"chip8": "CHIP-8",
|
||||||
|
"coco3": "Tandy Color Computer 3",
|
||||||
|
"commanderx16": "Commander X16",
|
||||||
|
"commodore-c64-supercpu": "Commodore 64 with SuperCPU",
|
||||||
|
"commodore-cbm-ii": "Commodore CBM-II",
|
||||||
|
"commodore-cd32": "Commodore Amiga CD32",
|
||||||
|
"commodore-cdtv": "Commodore CDTV",
|
||||||
|
"commodore-cubo": "CD Express Cubo CD32",
|
||||||
|
"commodore-pet": "Commodore PET",
|
||||||
|
"coolbar": "Coolbar feature phones",
|
||||||
|
"cps1": "Capcom CPS-1",
|
||||||
|
"cps2": "Capcom CPS-2",
|
||||||
|
"cps3": "Capcom CPS-3",
|
||||||
|
"crvision": "VTech CreatiVision",
|
||||||
|
"cstrike": "Counter-Strike",
|
||||||
|
"ctf": "Quake II: Capture the Flag",
|
||||||
|
"czero": "Counter-Strike: Condition Zero",
|
||||||
|
"czeror": "Counter-Strike: Condition Zero Deleted Scenes",
|
||||||
|
"dark-forces": "Star Wars: Dark Forces",
|
||||||
|
"dark-forces-ii": "Star Wars Jedi Knight: Dark Forces II",
|
||||||
|
"deco-cassette": "Data East DECO Cassette System",
|
||||||
|
"descent2": "Descent II",
|
||||||
|
"dingoo-a320": "Dingoo A320",
|
||||||
|
"dinothawr": "Dinothawr game",
|
||||||
|
"discrete-arcade": "Discrete logic arcade games",
|
||||||
|
"dmc": "Deathmatch Classic",
|
||||||
|
"doom": "Doom",
|
||||||
|
"doom3-bfg": "Doom 3: BFG Edition",
|
||||||
|
"dos": "MS-DOS",
|
||||||
|
"dragon32": "Dragon 32",
|
||||||
|
"dragon64": "Dragon 64",
|
||||||
|
"droidworks": "Star Wars: DroidWorks",
|
||||||
|
"duke-nukem-2": "Duke Nukem II",
|
||||||
|
"duke3d": "Duke Nukem 3D",
|
||||||
|
"dusklight": "The Legend of Zelda: Twilight Princess",
|
||||||
|
"efo-cedar-magnet": "EFO Cedar Magnet System",
|
||||||
|
"eighting-zn1": "Eighting ZN-1",
|
||||||
|
"elektor-tv-games-computer": "Elektor TV Games Computer",
|
||||||
|
"emerson-arcadia-2001": "Emerson Arcadia 2001",
|
||||||
|
"enemy-territory-quake-wars": "Enemy Territory: Quake Wars",
|
||||||
|
"enemyterritory": "Wolfenstein: Enemy Territory",
|
||||||
|
"enterprise-128": "Enterprise 128",
|
||||||
|
"enterprise-64": "Enterprise 64",
|
||||||
|
"entex-advision": "Entex Adventure Vision",
|
||||||
|
"epoch-scv": "Epoch Super Cassette Vision",
|
||||||
|
"epochcv": "Epoch Cassette Vision",
|
||||||
|
"eternal-computer": "Eternal Software Initiative computer",
|
||||||
|
"exelvision-exl100": "Exelvision EXL 100",
|
||||||
|
"exhumed": "PowerSlave",
|
||||||
|
"exidy-maxaflex": "Exidy Max-A-Flex",
|
||||||
|
"fallout": "Fallout",
|
||||||
|
"famicom": "Nintendo Famicom",
|
||||||
|
"flash": "Adobe Flash",
|
||||||
|
"flashback": "Flashback",
|
||||||
|
"fm77av": "Fujitsu FM77AV",
|
||||||
|
"fpinball": "Future Pinball tables",
|
||||||
|
"fruitmachine": "Fruit machines",
|
||||||
|
"fury": "Ion Fury game",
|
||||||
|
"gaelco-powervr": "Gaelco PowerVR boards",
|
||||||
|
"galaksija": "Galaksija computer",
|
||||||
|
"game": "Picross puzzle (libretro sample)",
|
||||||
|
"gamecom": "Tiger Game.com",
|
||||||
|
"gameplan-mpu1": "Game Plan MPU-1",
|
||||||
|
"gamepock": "Epoch Game Pocket Computer",
|
||||||
|
"gametank": "GameTank console",
|
||||||
|
"gba": "Nintendo Game Boy Advance",
|
||||||
|
"gearbox": "Half-Life: Opposing Force",
|
||||||
|
"ghostship": "Super Mario 64",
|
||||||
|
"glulx": "Glulx",
|
||||||
|
"gottlieb-system1": "Gottlieb System 1",
|
||||||
|
"half-life-2": "Half-Life 2",
|
||||||
|
"handheld-electronic": "Nintendo Game & Watch",
|
||||||
|
"heart-of-darkness": "Heart of Darkness",
|
||||||
|
"heretic": "Heretic",
|
||||||
|
"heroes-of-might-and-magic-2": "Heroes of Might and Magic II",
|
||||||
|
"hexen": "Hexen",
|
||||||
|
"hexen2": "Hexen II",
|
||||||
|
"hppa": "HP PA-RISC",
|
||||||
|
"hugo": "Hugo",
|
||||||
|
"hyper-neogeo64": "SNK Hyper Neo Geo 64",
|
||||||
|
"ibm-at": "IBM PC/AT",
|
||||||
|
"ibm-pcjr": "IBM PCjr",
|
||||||
|
"ibm-ps1": "IBM PS/1",
|
||||||
|
"ibm-xt": "IBM PC XT",
|
||||||
|
"icarus-starship-command-simulator": "Icarus Starship Command Simulator",
|
||||||
|
"igs-pgm": "IGS PolyGame Master",
|
||||||
|
"imax-macs": "I'Max MACS",
|
||||||
|
"interact": "Interact Home Computer",
|
||||||
|
"interton-vc4000": "Interton VC 4000",
|
||||||
|
"itech-eagle": "Incredible Technologies Eagle",
|
||||||
|
"jacl": "JACL",
|
||||||
|
"jedi-academy": "Star Wars Jedi Knight: Jedi Academy",
|
||||||
|
"jedi-outcast": "Star Wars Jedi Knight II: Jedi Outcast",
|
||||||
|
"jediacademy": "Star Wars Jedi Knight: Jedi Academy",
|
||||||
|
"jediknight2": "Star Wars Jedi Knight II: Jedi Outcast",
|
||||||
|
"jupiter-ace": "Jupiter Cantab Jupiter Ace",
|
||||||
|
"konami-bubble-system": "Konami Bubble System",
|
||||||
|
"konami-bubblesystem": "Konami Bubble System",
|
||||||
|
"konami-bubsys": "Konami Bubble System",
|
||||||
|
"konami-endeavour": "Konami Endeavour",
|
||||||
|
"konami-gq": "Konami GQ",
|
||||||
|
"konami-gv": "Konami GV",
|
||||||
|
"konami-gx": "Konami GX",
|
||||||
|
"konami-python": "Konami Python",
|
||||||
|
"konami-python2": "Konami Python 2",
|
||||||
|
"konami-twinkle": "Konami Twinkle",
|
||||||
|
"konami-viper": "Konami Viper",
|
||||||
|
"lambda-8300": "Lambda 8300",
|
||||||
|
"laserdisc-arcade": "Laserdisc arcade games",
|
||||||
|
"level9": "Level 9",
|
||||||
|
"lowresnx": "LowRes NX programs",
|
||||||
|
"lynx": "Atari Lynx",
|
||||||
|
"m68k": "Motorola 68000",
|
||||||
|
"magnetic-scrolls": "Magnetic Scrolls",
|
||||||
|
"marty": "Fujitsu FM Towns Marty",
|
||||||
|
"mega-cd": "Sega Mega-CD",
|
||||||
|
"mega-cd-32x": "Sega Mega-CD 32X",
|
||||||
|
"mega-duck": "Welback Mega Duck",
|
||||||
|
"mega-ld": "Sega Mega LD",
|
||||||
|
"megacd": "Sega Mega-CD",
|
||||||
|
"microdigital-tk85": "Microdigital TK85",
|
||||||
|
"microsoft-msx2": "MSX2",
|
||||||
|
"microsoft-xbox-360": "Microsoft Xbox 360",
|
||||||
|
"midway-mcr": "Midway MCR",
|
||||||
|
"mips": "MIPS",
|
||||||
|
"mips64": "MIPS64",
|
||||||
|
"miuchiz": "Miuchiz",
|
||||||
|
"mohaa": "Medal of Honor: Allied Assault",
|
||||||
|
"mohaa-breakthrough": "Medal of Honor: Allied Assault Breakthrough",
|
||||||
|
"mohaa-spearhead": "Medal of Honor: Allied Assault Spearhead",
|
||||||
|
"msx1": "MSX",
|
||||||
|
"msx2": "MSX2",
|
||||||
|
"msx2+": "MSX2+",
|
||||||
|
"msx2plus": "MSX2+",
|
||||||
|
"msxturboR": "MSX turbo R",
|
||||||
|
"msxturbor": "MSX turbo R",
|
||||||
|
"mysteries-of-the-sith": "Star Wars Jedi Knight: Mysteries of the Sith",
|
||||||
|
"myvision": "Nichibutsu My Vision",
|
||||||
|
"mz2000": "Sharp MZ-2000",
|
||||||
|
"mz2500": "Sharp MZ-2500",
|
||||||
|
"mz700": "Sharp MZ-700",
|
||||||
|
"mz800": "Sharp MZ-800",
|
||||||
|
"mz80k": "Sharp MZ-80K",
|
||||||
|
"nam": "NAM",
|
||||||
|
"namco-na1": "Namco NA-1",
|
||||||
|
"namco-nb1": "Namco NB-1",
|
||||||
|
"namco-system11": "Namco System 11",
|
||||||
|
"namco-system246": "Namco System 246",
|
||||||
|
"namco-system256": "Namco System 256",
|
||||||
|
"namco-system357": "Namco System 357",
|
||||||
|
"namco-system573": "Konami System 573",
|
||||||
|
"naomi2": "Sega NAOMI 2",
|
||||||
|
"napalm": "NAPALM",
|
||||||
|
"nec-pc-80": "NEC PC-8001",
|
||||||
|
"nec-supergrafx": "NEC SuperGrafx",
|
||||||
|
"neo-geo-pocket-color": "SNK Neo Geo Pocket Color",
|
||||||
|
"neogeo64": "SNK Hyper Neo Geo 64",
|
||||||
|
"ngp": "SNK Neo Geo Pocket",
|
||||||
|
"ngpc": "SNK Neo Geo Pocket Color",
|
||||||
|
"nichibutsu-hrdvd": "Nichibutsu High Rate DVD",
|
||||||
|
"nintendo-64dd": "Nintendo 64DD",
|
||||||
|
"nintendo-aleck64": "Nintendo Aleck64",
|
||||||
|
"nintendo-ds": "Nintendo DS",
|
||||||
|
"nintendo-dsi": "Nintendo DSi",
|
||||||
|
"nintendo-fds": "Nintendo Famicom Disk System",
|
||||||
|
"nintendo-gb": "Nintendo Game Boy",
|
||||||
|
"nintendo-gba": "Nintendo Game Boy Advance",
|
||||||
|
"nintendo-gbc": "Nintendo Game Boy Color",
|
||||||
|
"nintendo-nss": "Nintendo Super System",
|
||||||
|
"nintendo-playch10": "Nintendo PlayChoice-10",
|
||||||
|
"nintendo-sfcbox": "Nintendo Super Famicom Box",
|
||||||
|
"nintendo-sgb": "Nintendo Super Game Boy",
|
||||||
|
"nintendo-virtualboy": "Nintendo Virtual Boy",
|
||||||
|
"nintendo-wii-arcade": "Nintendo Wii arcade boards",
|
||||||
|
"nmk16": "NMK16",
|
||||||
|
"oberon": "Project Oberon",
|
||||||
|
"olivetti-pc128": "Olivetti Prodest PC 128",
|
||||||
|
"omicron": "Omicron cartridges",
|
||||||
|
"onscripter": "ONScripter visual novels",
|
||||||
|
"openbor": "OpenBOR games",
|
||||||
|
"opengoal": "Jak and Daxter",
|
||||||
|
"oric": "Tangerine Oric",
|
||||||
|
"oricatmos": "Oric Atmos",
|
||||||
|
"outlaws": "Outlaws",
|
||||||
|
"palm-os": "Palm OS",
|
||||||
|
"pc-engine-ld": "NEC PC Engine LD-ROM2",
|
||||||
|
"pc60": "NEC PC-6001",
|
||||||
|
"pc80": "NEC PC-8001",
|
||||||
|
"pce-tourvision": "TourVision",
|
||||||
|
"pdark": "Perfect Dark",
|
||||||
|
"pegasus": "Aamber Pegasus",
|
||||||
|
"pgm": "IGS PolyGame Master",
|
||||||
|
"philips-p2000t": "Philips P2000T",
|
||||||
|
"philips-vg5k": "Philips VG 5000",
|
||||||
|
"picocomputer-6502": "Picocomputer 6502 programs",
|
||||||
|
"pocket-challenge-v2": "Benesse Pocket Challenge V2",
|
||||||
|
"powerslave": "PowerSlave",
|
||||||
|
"ppc": "PowerPC",
|
||||||
|
"ppc64": "PowerPC 64-bit",
|
||||||
|
"prey": "Prey",
|
||||||
|
"prince-of-persia": "Prince of Persia",
|
||||||
|
"ps4": "Sony PlayStation 4",
|
||||||
|
"pv1000": "Casio PV-1000",
|
||||||
|
"quadrilateral-cowboy": "Quadrilateral Cowboy",
|
||||||
|
"quake2": "Quake II",
|
||||||
|
"quake3": "Quake III Arena",
|
||||||
|
"quake4": "Quake 4",
|
||||||
|
"realrtcw": "Return to Castle Wolfenstein (RealRTCW)",
|
||||||
|
"recel-system3": "Recel System III",
|
||||||
|
"redneck": "Redneck Rampage",
|
||||||
|
"ricochet": "Ricochet",
|
||||||
|
"ringo-r470": "Ringo R470",
|
||||||
|
"riscv": "RISC-V",
|
||||||
|
"riscv32": "RISC-V 32-bit",
|
||||||
|
"riscv64": "RISC-V 64-bit",
|
||||||
|
"rogue": "Quake II: Ground Zero",
|
||||||
|
"rott": "Rise of the Triad",
|
||||||
|
"rpgmaker": "RPG Maker games",
|
||||||
|
"s390x": "IBM z/Architecture (s390x)",
|
||||||
|
"sam-coupe": "MGT SAM Coupe",
|
||||||
|
"sammy-atomiswave": "Sammy Atomiswave",
|
||||||
|
"sammy-medal": "Sammy medal games",
|
||||||
|
"science-of-cambridge-mk14": "Science of Cambridge MK14",
|
||||||
|
"scott-adams": "Scott Adams adventures",
|
||||||
|
"scott-adams-plus": "Scott Adams Plus adventures",
|
||||||
|
"scummvm": "ScummVM games",
|
||||||
|
"scv": "Epoch Super Cassette Vision",
|
||||||
|
"sdlpal": "The Legend of Sword and Fairy",
|
||||||
|
"sega-atomiswave": "Sammy Atomiswave",
|
||||||
|
"sega-dreamcast-arcade": "Sega Dreamcast-based arcade boards",
|
||||||
|
"sega-genesis": "Sega Genesis",
|
||||||
|
"sega-isgsm": "Sega ISG Selection Master",
|
||||||
|
"sega-mega-cd": "Sega Mega-CD",
|
||||||
|
"sega-megacd": "Sega Mega-CD",
|
||||||
|
"sega-megaplay": "Sega Mega Play",
|
||||||
|
"sega-megatech": "Sega Mega-Tech",
|
||||||
|
"sega-model2": "Sega Model 2",
|
||||||
|
"sega-naomi": "Sega NAOMI",
|
||||||
|
"sega-naomi2": "Sega NAOMI 2",
|
||||||
|
"sega-naomigd": "Sega NAOMI GD-ROM",
|
||||||
|
"sega-outrun": "OutRun",
|
||||||
|
"sega-pico": "Sega Pico",
|
||||||
|
"sega-sg1000": "Sega SG-1000",
|
||||||
|
"sega-shootingzone": "Sega Shooting Zone",
|
||||||
|
"sega-system-sp": "Sega System SP",
|
||||||
|
"sega-system16b": "Sega System 16B",
|
||||||
|
"sega-systemsp": "Sega System SP",
|
||||||
|
"sega-vmu": "Sega Dreamcast VMU",
|
||||||
|
"serious-sam": "Serious Sam",
|
||||||
|
"sg-1000": "Sega SG-1000",
|
||||||
|
"sielectronics-y2": "SiElectronics System Y2",
|
||||||
|
"sinclair-ql": "Sinclair QL",
|
||||||
|
"sinclair-spectrum": "Sinclair ZX Spectrum",
|
||||||
|
"sinclair-zx-spectrum": "Sinclair ZX Spectrum",
|
||||||
|
"sinclair-zx-spectrum-next": "ZX Spectrum Next",
|
||||||
|
"sinclair-zx80-81": "Sinclair ZX80 and ZX81",
|
||||||
|
"sinclair-zxspectrum": "Sinclair ZX Spectrum",
|
||||||
|
"skin-deep": "Skin Deep",
|
||||||
|
"smbx": "Super Mario Bros. X",
|
||||||
|
"sms": "Sega Master System",
|
||||||
|
"snk-neogeo-aes": "SNK Neo Geo AES",
|
||||||
|
"snk-neogeo-mvs": "SNK Neo Geo MVS",
|
||||||
|
"snk-ngp": "SNK Neo Geo Pocket",
|
||||||
|
"snk-ngpc": "SNK Neo Geo Pocket Color",
|
||||||
|
"soh": "The Legend of Zelda: Ocarina of Time",
|
||||||
|
"sonic-1-2013": "Sonic the Hedgehog (2013)",
|
||||||
|
"sonic-2-2013": "Sonic the Hedgehog 2 (2013)",
|
||||||
|
"sonic-mania": "Sonic Mania",
|
||||||
|
"soniccd": "Sonic CD",
|
||||||
|
"sony-psp": "Sony PlayStation Portable",
|
||||||
|
"sparc": "SPARC",
|
||||||
|
"sparc64": "SPARC64",
|
||||||
|
"spectravideo": "Spectravideo",
|
||||||
|
"star-control-2": "Star Control II",
|
||||||
|
"starship": "Star Fox 64",
|
||||||
|
"strife": "Strife",
|
||||||
|
"sunplus-native32": "Sunplus Native32",
|
||||||
|
"sunplus-spmp8000": "Sunplus SPMP8000",
|
||||||
|
"super-famicom": "Nintendo Super Famicom",
|
||||||
|
"super-kaneko-nova": "Kaneko Super Nova System",
|
||||||
|
"super-mario-war": "Super Mario War game",
|
||||||
|
"superacan": "Funtech Super A'Can",
|
||||||
|
"supergrafx": "NEC SuperGrafx",
|
||||||
|
"supergrafx-cd": "NEC SuperGrafx CD",
|
||||||
|
"solarus": "Solarus games",
|
||||||
|
"supertux": "SuperTux game",
|
||||||
|
"supertuxkart": "SuperTuxKart game",
|
||||||
|
"supracan": "Funtech Super A'Can",
|
||||||
|
"symbian": "Symbian OS",
|
||||||
|
"tab-silverball": "TAB Austria Silverball",
|
||||||
|
"tads": "TADS",
|
||||||
|
"taito-cchip": "Taito C-Chip",
|
||||||
|
"taito-fx1": "Taito FX-1",
|
||||||
|
"taito-gnet": "Taito G-NET",
|
||||||
|
"taito-type-x": "Taito Type X",
|
||||||
|
"taito-typezero": "Taito Type Zero",
|
||||||
|
"tamagotchi-p1": "Bandai Tamagotchi P1",
|
||||||
|
"tandy-1000": "Tandy 1000",
|
||||||
|
"taylormade": "TaylorMade",
|
||||||
|
"teamarena": "Quake III: Team Arena",
|
||||||
|
"tecmo-tps": "Tecmo TPS",
|
||||||
|
"tfc": "Team Fortress Classic",
|
||||||
|
"the-dark-mod": "The Dark Mod",
|
||||||
|
"thomson-mo6": "Thomson MO6",
|
||||||
|
"thomson-to7": "Thomson TO7",
|
||||||
|
"thomson-to770": "Thomson TO7/70",
|
||||||
|
"thomson-to8": "Thomson TO8",
|
||||||
|
"thomson-to8d": "Thomson TO8D",
|
||||||
|
"thomson-to9": "Thomson TO9",
|
||||||
|
"thomson-to9plus": "Thomson TO9+",
|
||||||
|
"tic80": "TIC-80 cartridges",
|
||||||
|
"tiger-game-com": "Tiger Game.com",
|
||||||
|
"timex-tc2048": "Timex Computer 2048",
|
||||||
|
"timex-ts1500": "Timex Sinclair 1500",
|
||||||
|
"timex-ts2068": "Timex Sinclair 2068",
|
||||||
|
"tomb-raider": "Tomb Raider",
|
||||||
|
"tomb-raider-1": "Tomb Raider",
|
||||||
|
"tomb-raider-2": "Tomb Raider II",
|
||||||
|
"transport-tycoon-deluxe": "Transport Tycoon Deluxe",
|
||||||
|
"tyrian": "Tyrian",
|
||||||
|
"ur-quan-masters": "Star Control II",
|
||||||
|
"urban-terror": "Urban Terror",
|
||||||
|
"uzebox": "Uzebox",
|
||||||
|
"vaporspec": "VaporSpec cartridges",
|
||||||
|
"vc4000": "Interton VC 4000",
|
||||||
|
"vg5k": "Philips VG 5000",
|
||||||
|
"vgmplay": "Video game music files",
|
||||||
|
"videobrain": "Umtech VideoBrain",
|
||||||
|
"videosystem-zn1": "Video System ZN-1",
|
||||||
|
"vircon32": "Vircon32 cartridges",
|
||||||
|
"virtuality-su2000": "Virtuality SU2000",
|
||||||
|
"vm-labs-nuon": "VM Labs Nuon",
|
||||||
|
"vpinball": "Visual Pinball tables",
|
||||||
|
"vvvvvv": "VVVVVV game",
|
||||||
|
"watara-supervision": "Watara Supervision",
|
||||||
|
"wonderswan-color": "Bandai WonderSwan Color",
|
||||||
|
"ww2gi": "World War II GI",
|
||||||
|
"x86": "x86 PC",
|
||||||
|
"x86-64": "x86-64 PC",
|
||||||
|
"xatrix": "Quake II: The Reckoning",
|
||||||
|
"xrick": "Rick Dangerous",
|
||||||
|
"ym2608": "Yamaha YM2608",
|
||||||
|
"zc210": "Zelda Classic",
|
||||||
|
"zeldaclassic": "Zelda Classic",
|
||||||
|
"zn1-acclaim": "Acclaim ZN-1",
|
||||||
|
"zn1-atlus": "Atlus ZN-1",
|
||||||
|
"zn1-capcom": "Capcom ZN-1",
|
||||||
|
"zn1-taito": "Taito ZN-1",
|
||||||
|
"zn1-tecmo": "Tecmo ZN-1",
|
||||||
|
"zn1-video-system": "Video System ZN-1",
|
||||||
|
"zn2-capcom": "Capcom ZN-2",
|
||||||
|
"zx-spectrum": "Sinclair ZX Spectrum",
|
||||||
|
"zx-spectrum-128": "Sinclair ZX Spectrum 128",
|
||||||
|
}
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
"""One display name per system id (round 2, package P0).
|
||||||
|
|
||||||
|
An emulator page listed the folders a system's files were voted onto:
|
||||||
|
nintendo-gba read "Nintendo Game Boy", camplynx "Arcade", and MAME
|
||||||
|
"emulated FBNeo". siterender.system_name names a system from the console
|
||||||
|
section that is its own, then from SYSTEM_NAMES, and raises otherwise.
|
||||||
|
database.json carries no system id: its files reach a page through their
|
||||||
|
console folders, so the ids to name are the platforms' and the profiles'.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import sys
|
||||||
|
import unittest
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
sys.path.insert(0, str(REPO_ROOT / "scripts"))
|
||||||
|
|
||||||
|
import siterender # noqa: E402
|
||||||
|
from common import ( # noqa: E402
|
||||||
|
list_registered_platforms,
|
||||||
|
load_emulator_profiles,
|
||||||
|
load_platform_config,
|
||||||
|
)
|
||||||
|
from generate_site import _group_by_manufacturer # noqa: E402
|
||||||
|
|
||||||
|
|
||||||
|
def _profile_system_ids(profiles: dict[str, dict]) -> set[str]:
|
||||||
|
ids: set[str] = set()
|
||||||
|
for profile in profiles.values():
|
||||||
|
ids.update(str(sys_id) for sys_id in profile.get("systems") or [])
|
||||||
|
for entry in profile.get("files") or []:
|
||||||
|
if not isinstance(entry, dict):
|
||||||
|
continue
|
||||||
|
if entry.get("system"):
|
||||||
|
ids.add(str(entry["system"]))
|
||||||
|
ids.update(str(sys_id) for sys_id in entry.get("systems") or [])
|
||||||
|
return ids
|
||||||
|
|
||||||
|
|
||||||
|
class SystemNames(unittest.TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpClass(cls) -> None:
|
||||||
|
with open(REPO_ROOT / "database.json", encoding="utf-8") as handle:
|
||||||
|
db = json.load(handle)
|
||||||
|
cls.manufacturers = _group_by_manufacturer(db)
|
||||||
|
cls.profiles = load_emulator_profiles(
|
||||||
|
str(REPO_ROOT / "emulators"), skip_aliases=False)
|
||||||
|
siterender.set_console_sections(
|
||||||
|
cls.manufacturers, siterender.program_names(cls.profiles))
|
||||||
|
platforms_dir = str(REPO_ROOT / "platforms")
|
||||||
|
cls.platform_ids = {
|
||||||
|
sys_id
|
||||||
|
for name in list_registered_platforms(platforms_dir, include_archived=True)
|
||||||
|
for sys_id in load_platform_config(name, platforms_dir).get("systems", {})
|
||||||
|
}
|
||||||
|
cls.profile_ids = _profile_system_ids(cls.profiles)
|
||||||
|
|
||||||
|
def _all_ids(self) -> set[str]:
|
||||||
|
return self.platform_ids | self.profile_ids
|
||||||
|
|
||||||
|
def test_every_system_id_has_a_name(self) -> None:
|
||||||
|
unnamed = []
|
||||||
|
for sys_id in sorted(self._all_ids()):
|
||||||
|
try:
|
||||||
|
name = siterender.system_name(sys_id)
|
||||||
|
except KeyError:
|
||||||
|
unnamed.append(sys_id)
|
||||||
|
continue
|
||||||
|
self.assertTrue(name.strip(), sys_id)
|
||||||
|
self.assertEqual(unnamed, [], "add these to siterender.SYSTEM_NAMES")
|
||||||
|
|
||||||
|
def test_no_name_is_a_manufacturer_page_or_an_emulator(self) -> None:
|
||||||
|
taken = {name.casefold() for name in self.manufacturers}
|
||||||
|
taken |= {name.casefold() for name in siterender.program_names(self.profiles)}
|
||||||
|
clashes = sorted(
|
||||||
|
(sys_id, siterender.system_name(sys_id))
|
||||||
|
for sys_id in self._all_ids()
|
||||||
|
if siterender.system_name(sys_id).casefold() in taken
|
||||||
|
)
|
||||||
|
self.assertEqual(clashes, [])
|
||||||
|
|
||||||
|
def test_table_entries_are_reached(self) -> None:
|
||||||
|
"""A table entry an own section shadows is never read, and an entry
|
||||||
|
no platform or profile names is a leftover."""
|
||||||
|
shadowed = sorted(
|
||||||
|
sys_id for sys_id in siterender.SYSTEM_NAMES
|
||||||
|
if siterender._own_section(sys_id) is not None
|
||||||
|
)
|
||||||
|
self.assertEqual(shadowed, [])
|
||||||
|
unused = sorted(set(siterender.SYSTEM_NAMES) - self._all_ids())
|
||||||
|
self.assertEqual(unused, [])
|
||||||
|
|
||||||
|
def test_names_that_read_a_folder_vote(self) -> None:
|
||||||
|
self.assertEqual(siterender.system_name("nintendo-gba"), "Nintendo Game Boy Advance")
|
||||||
|
self.assertEqual(siterender.system_name("camplynx"), "Camputers Lynx")
|
||||||
|
self.assertEqual(siterender.system_name("atari-lynx"), "Atari Lynx")
|
||||||
|
self.assertEqual(siterender.system_name("arcade"), "Arcade games")
|
||||||
|
self.assertEqual(siterender.system_name("sega-naomi"), "Sega NAOMI")
|
||||||
|
|
||||||
|
def test_own_section_names_from_its_heading(self) -> None:
|
||||||
|
self.assertEqual(siterender.system_name("nintendo-snes"), "Nintendo SNES")
|
||||||
|
self.assertEqual(siterender.system_name("sony-playstation"), "Sony PlayStation")
|
||||||
|
|
||||||
|
def test_an_unknown_id_raises(self) -> None:
|
||||||
|
with self.assertRaises(KeyError):
|
||||||
|
siterender.system_name("no-such-system-anywhere")
|
||||||
|
|
||||||
|
def test_mame_names_systems_not_emulators(self) -> None:
|
||||||
|
names = {siterender.system_name(s) for s in self.profiles["mame"].get("systems") or []}
|
||||||
|
self.assertNotIn("FBNeo", names)
|
||||||
|
self.assertNotIn("Arcade", names)
|
||||||
|
self.assertFalse(names & siterender.program_names(self.profiles))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
||||||
@@ -56,7 +56,7 @@ Every module in `tests/`, by the area it guards.
|
|||||||
| Handheld port | stubbed PortMaster dialogs, fake installer | `test_port` |
|
| Handheld port | stubbed PortMaster dialogs, fake installer | `test_port` |
|
||||||
| Truth and native export | synthetic + cached originals | `test_export_counts`, `test_export_native_layer`, `test_export_report`, `test_exporters`, `test_truth_data_dir_readers`, `test_truth_diff`, `test_truth_layout` |
|
| Truth and native export | synthetic + cached originals | `test_export_counts`, `test_export_native_layer`, `test_export_report`, `test_exporters`, `test_truth_data_dir_readers`, `test_truth_diff`, `test_truth_layout` |
|
||||||
| Scrapers, upstream and provenance | inline sources, synthetic | `test_check_freshness`, `test_dedup`, `test_elec_scrapers`, `test_fbneo_parser`, `test_find_pinned_revision`, `test_hash_merge`, `test_launchers`, `test_launchers_emudeck`, `test_launchers_recalbox`, `test_launchers_retrobat`, `test_launchers_retrodeck`, `test_launchers_retropie`, `test_launchers_rocknix`, `test_mame_devices`, `test_mame_parser`, `test_mame_ref_audit`, `test_profile_sync`, `test_provenance`, `test_refresh_data_dirs`, `test_refresh_failures`, `test_refresh_stale`, `test_retrodeck_scraper_errors`, `test_romset_recipes`, `test_scraper_contract`, `test_upstream`, `test_upstream_index` |
|
| Scrapers, upstream and provenance | inline sources, synthetic | `test_check_freshness`, `test_dedup`, `test_elec_scrapers`, `test_fbneo_parser`, `test_find_pinned_revision`, `test_hash_merge`, `test_launchers`, `test_launchers_emudeck`, `test_launchers_recalbox`, `test_launchers_retrobat`, `test_launchers_retrodeck`, `test_launchers_retropie`, `test_launchers_rocknix`, `test_mame_devices`, `test_mame_parser`, `test_mame_ref_audit`, `test_profile_sync`, `test_provenance`, `test_refresh_data_dirs`, `test_refresh_failures`, `test_refresh_stale`, `test_retrodeck_scraper_errors`, `test_romset_recipes`, `test_scraper_contract`, `test_upstream`, `test_upstream_index` |
|
||||||
| Site, docs and repository contracts | rendered pages, sources | `test_contributing_text`, `test_coverage_cache`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_doc_pages`, `test_doc_surfaces`, `test_optional_dependencies`, `test_prose_style`, `test_schema_semantic_gate`, `test_site_availability`, `test_site_content_data`, `test_site_copy`, `test_site_cores`, `test_site_emulator_page`, `test_site_exports`, `test_site_funnel`, `test_site_images`, `test_site_picker`, `test_site_platform_hashes`, `test_site_render`, `test_site_system_links`, `test_site_validation`, `test_site_weight`, `test_site_write`, `test_validate_pr`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_workflow_paths` |
|
| Site, docs and repository contracts | rendered pages, sources | `test_contributing_text`, `test_coverage_cache`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_doc_pages`, `test_doc_surfaces`, `test_optional_dependencies`, `test_prose_style`, `test_schema_semantic_gate`, `test_site_availability`, `test_site_content_data`, `test_site_copy`, `test_site_cores`, `test_site_emulator_page`, `test_site_exports`, `test_site_funnel`, `test_site_images`, `test_site_picker`, `test_site_platform_hashes`, `test_site_r2_p0`, `test_site_render`, `test_site_system_links`, `test_site_validation`, `test_site_weight`, `test_site_write`, `test_validate_pr`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_workflow_paths` |
|
||||||
|
|
||||||
## Test architecture
|
## Test architecture
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user