mirror of
https://github.com/Abdess/retroarch_system.git
synced 2026-10-10 13:33:24 -05:00
fix: one size predicate, size_options retired
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a090e64336
commit
5816562bf6
16 files changed
+115
-61
No files matched your search
+1
-1
@@ -124,7 +124,7 @@ files:
|
|||||||
- name: "<game>.dkey"
|
- name: "<game>.dkey"
|
||||||
aliases: ["<game>.key"]
|
aliases: ["<game>.key"]
|
||||||
required: false
|
required: false
|
||||||
size_options: [16, 32]
|
size: [16, 32]
|
||||||
validation: [size]
|
validation: [size]
|
||||||
unsourceable: "per-disc AES-128 key named after the image it decrypts, one per title, carried by disc dump catalogues rather than by the emulator"
|
unsourceable: "per-disc AES-128 key named after the image it decrypts, one per title, carried by disc dump catalogues rather than by the emulator"
|
||||||
description: "Redump disc decryption key read beside an encrypted ISO"
|
description: "Redump disc decryption key read beside an encrypted ISO"
|
||||||
|
|||||||
@@ -498,10 +498,9 @@ files:
|
|||||||
system: bbc-micro-b
|
system: bbc-micro-b
|
||||||
required: false
|
required: false
|
||||||
bundled: true
|
bundled: true
|
||||||
size: 8192
|
size: [2048, 4096, 8192]
|
||||||
md5: f786d0647f9732fa065695d569d261ab
|
md5: f786d0647f9732fa065695d569d261ab
|
||||||
sha1: e6ee738e5f2f8556002b79d18caa8ef21f14e08d
|
sha1: e6ee738e5f2f8556002b79d18caa8ef21f14e08d
|
||||||
size_options: [2048, 4096, 8192]
|
|
||||||
note: >
|
note: >
|
||||||
Loaded for TubeDevice::TorchZ80. Up to 8192 bytes are read and a short image
|
Loaded for TubeDevice::TorchZ80. Up to 8192 bytes are read and a short image
|
||||||
is mirrored to fill the 8 KB window: a 2 KB image is repeated four times, a
|
is mirrored to fill the 8 KB window: a 2 KB image is repeated four times, a
|
||||||
|
|||||||
+1
-1
@@ -117,7 +117,7 @@ files:
|
|||||||
required: true
|
required: true
|
||||||
path: "x1box/flash.bin"
|
path: "x1box/flash.bin"
|
||||||
config_key: "sys.files.flashrom_path"
|
config_key: "sys.files.flashrom_path"
|
||||||
size_options: [262144, 524288, 1048576]
|
min_size: 65536
|
||||||
size_note: "Any non-zero multiple of 65536; 256 KB is assumed when the image cannot be read."
|
size_note: "Any non-zero multiple of 65536; 256 KB is assumed when the image cannot be read."
|
||||||
validation: [size]
|
validation: [size]
|
||||||
description: "Xbox flash ROM"
|
description: "Xbox flash ROM"
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ files:
|
|||||||
description: "Nintendo DS firmware image"
|
description: "Nintendo DS firmware image"
|
||||||
required: false
|
required: false
|
||||||
hle_fallback: true
|
hle_fallback: true
|
||||||
size_options: [131072, 262144, 524288]
|
size: [131072, 262144, 524288]
|
||||||
validation: [size]
|
validation: [size]
|
||||||
note: >-
|
note: >-
|
||||||
Three lengths are accepted and everything else is rejected. Loaded only in
|
Three lengths are accepted and everything else is rejected. Loaded only in
|
||||||
|
|||||||
@@ -372,7 +372,7 @@ files:
|
|||||||
path: "Machines/Shared Roms/KANJI.rom"
|
path: "Machines/Shared Roms/KANJI.rom"
|
||||||
system: msx2plus
|
system: msx2plus
|
||||||
required: true
|
required: true
|
||||||
size_options: [131072, 262144]
|
size: [131072, 262144]
|
||||||
validation: [size]
|
validation: [size]
|
||||||
description: "Kanji character ROM, named by the MSX2+ and turbo R machine definitions"
|
description: "Kanji character ROM, named by the MSX2+ and turbo R machine definitions"
|
||||||
note: >-
|
note: >-
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ files:
|
|||||||
required: true
|
required: true
|
||||||
path: "x1box/flash.bin"
|
path: "x1box/flash.bin"
|
||||||
config_key: "sys.files.flashrom_path"
|
config_key: "sys.files.flashrom_path"
|
||||||
size_options: [262144, 524288, 1048576]
|
min_size: 65536
|
||||||
size_note: "Any non-zero multiple of 65536; 256 KB is assumed when the image cannot be read."
|
size_note: "Any non-zero multiple of 65536; 256 KB is assumed when the image cannot be read."
|
||||||
validation: [size]
|
validation: [size]
|
||||||
description: "Xbox flash ROM"
|
description: "Xbox flash ROM"
|
||||||
|
|||||||
@@ -239,7 +239,6 @@ files:
|
|||||||
system: sharp-x68000
|
system: sharp-x68000
|
||||||
required: false
|
required: false
|
||||||
min_size: 8192
|
min_size: 8192
|
||||||
size_options: [8192, 131072]
|
|
||||||
validation: [size]
|
validation: [size]
|
||||||
description: "Internal SCSI interface ROM, SUPER and later"
|
description: "Internal SCSI interface ROM, SUPER and later"
|
||||||
source_ref: "xm6g.pdf p.17, xm6g.exe:0x1404fd1ef (reads at 0x1404fd327, 0x1404fd3dd), XM6 2.06 vm/memory.cpp:305-310, 328-345"
|
source_ref: "xm6g.pdf p.17, xm6g.exe:0x1404fd1ef (reads at 0x1404fd327, 0x1404fd3dd), XM6 2.06 vm/memory.cpp:305-310, 328-345"
|
||||||
@@ -254,7 +253,6 @@ files:
|
|||||||
system: sharp-x68000
|
system: sharp-x68000
|
||||||
required: false
|
required: false
|
||||||
min_size: 8160
|
min_size: 8160
|
||||||
size_options: [8160, 8192, 131072]
|
|
||||||
validation: [size]
|
validation: [size]
|
||||||
description: "External SCSI interface ROM, CZ-6BS1 board"
|
description: "External SCSI interface ROM, CZ-6BS1 board"
|
||||||
source_ref: "xm6g.pdf p.17, xm6g.exe:0x1404fd20a (retry at 0x1404fd419), XM6 2.06 vm/memory.cpp:316-318, 341-352"
|
source_ref: "xm6g.pdf p.17, xm6g.exe:0x1404fd20a (retry at 0x1404fd419), XM6 2.06 vm/memory.cpp:316-318, 341-352"
|
||||||
@@ -270,7 +268,7 @@ files:
|
|||||||
- name: SRAM.DAT
|
- name: SRAM.DAT
|
||||||
system: sharp-x68000
|
system: sharp-x68000
|
||||||
required: false
|
required: false
|
||||||
size_options: [16384, 65536]
|
size: [16384, 65536]
|
||||||
description: "SRAM image for EXPERT and the other base models"
|
description: "SRAM image for EXPERT and the other base models"
|
||||||
source_ref: "xm6g.pdf p.18, xm6g.exe:0x140592350 index 14, XM6 2.06 vm/sram.cpp:70-81, 112"
|
source_ref: "xm6g.pdf p.18, xm6g.exe:0x140592350 index 14, XM6 2.06 vm/sram.cpp:70-81, 112"
|
||||||
note: >-
|
note: >-
|
||||||
@@ -282,7 +280,7 @@ files:
|
|||||||
- name: SRAMXVI.DAT
|
- name: SRAMXVI.DAT
|
||||||
system: sharp-x68000
|
system: sharp-x68000
|
||||||
required: false
|
required: false
|
||||||
size_options: [16384, 65536]
|
size: [16384, 65536]
|
||||||
description: "SRAM image for XVI"
|
description: "SRAM image for XVI"
|
||||||
source_ref: "xm6g.pdf p.18, xm6g.exe:0x140592350 index 15"
|
source_ref: "xm6g.pdf p.18, xm6g.exe:0x140592350 index 15"
|
||||||
note: >-
|
note: >-
|
||||||
@@ -292,7 +290,7 @@ files:
|
|||||||
- name: SRAMCMP.DAT
|
- name: SRAMCMP.DAT
|
||||||
system: sharp-x68000
|
system: sharp-x68000
|
||||||
required: false
|
required: false
|
||||||
size_options: [16384, 65536]
|
size: [16384, 65536]
|
||||||
description: "SRAM image for Compact"
|
description: "SRAM image for Compact"
|
||||||
source_ref: "xm6g.pdf p.18, xm6g.exe:0x140592350 index 16"
|
source_ref: "xm6g.pdf p.18, xm6g.exe:0x140592350 index 16"
|
||||||
note: >-
|
note: >-
|
||||||
@@ -301,7 +299,7 @@ files:
|
|||||||
- name: SRAM030.DAT
|
- name: SRAM030.DAT
|
||||||
system: sharp-x68000
|
system: sharp-x68000
|
||||||
required: false
|
required: false
|
||||||
size_options: [16384, 65536]
|
size: [16384, 65536]
|
||||||
description: "SRAM image for X68030, 040turbo and 060turbo"
|
description: "SRAM image for X68030, 040turbo and 060turbo"
|
||||||
source_ref: "xm6g.pdf p.18, xm6g.exe:0x140592350 index 17"
|
source_ref: "xm6g.pdf p.18, xm6g.exe:0x140592350 index 17"
|
||||||
note: >-
|
note: >-
|
||||||
|
|||||||
@@ -344,8 +344,7 @@ files:
|
|||||||
# ============================================================
|
# ============================================================
|
||||||
|
|
||||||
- name: "zx80.rom"
|
- name: "zx80.rom"
|
||||||
size: 4096
|
size: [4096, 8192]
|
||||||
size_options: [4096, 8192]
|
|
||||||
validation: [size]
|
validation: [size]
|
||||||
required: true
|
required: true
|
||||||
bundled: true
|
bundled: true
|
||||||
@@ -630,8 +629,7 @@ files:
|
|||||||
note: "Beta Disk / TR-DOS firmware."
|
note: "Beta Disk / TR-DOS firmware."
|
||||||
|
|
||||||
- name: "if1-v1.rom"
|
- name: "if1-v1.rom"
|
||||||
size: 8192
|
size: [8192, 16384]
|
||||||
size_options: [8192, 16384]
|
|
||||||
validation: [size]
|
validation: [size]
|
||||||
required: false
|
required: false
|
||||||
bundled: true
|
bundled: true
|
||||||
@@ -640,8 +638,7 @@ files:
|
|||||||
note: "Interface 1 firmware version 1, selected when if1_rom_version is 1. The load accepts 8192 or 16384 bytes and disables Interface 1 emulation otherwise."
|
note: "Interface 1 firmware version 1, selected when if1_rom_version is 1. The load accepts 8192 or 16384 bytes and disables Interface 1 emulation otherwise."
|
||||||
|
|
||||||
- name: "if1-v2.rom"
|
- name: "if1-v2.rom"
|
||||||
size: 8192
|
size: [8192, 16384]
|
||||||
size_options: [8192, 16384]
|
|
||||||
validation: [size]
|
validation: [size]
|
||||||
required: false
|
required: false
|
||||||
bundled: true
|
bundled: true
|
||||||
|
|||||||
@@ -415,12 +415,6 @@
|
|||||||
"size_note": {
|
"size_note": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"size_options": {
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"standalone_path": {
|
"standalone_path": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|||||||
+10
-6
@@ -64,6 +64,15 @@ def name_match_size_ok(file_entry: dict, candidate_size: int | None) -> bool:
|
|||||||
validation = validation.get("core", [])
|
validation = validation.get("core", [])
|
||||||
if "size" not in (validation or []) or candidate_size is None:
|
if "size" not in (validation or []) or candidate_size is None:
|
||||||
return True
|
return True
|
||||||
|
return size_fits(file_entry, candidate_size)
|
||||||
|
|
||||||
|
|
||||||
|
def size_fits(file_entry: dict, candidate_size: int) -> bool:
|
||||||
|
"""Whether a size is one the entry declares.
|
||||||
|
|
||||||
|
``size`` is an exact size or the list of sizes the code accepts; it
|
||||||
|
outranks a ``min_size``/``max_size`` range. Nothing declared fits all.
|
||||||
|
"""
|
||||||
declared = file_entry.get("size")
|
declared = file_entry.get("size")
|
||||||
if declared is not None:
|
if declared is not None:
|
||||||
allowed = declared if isinstance(declared, list) else [declared]
|
allowed = declared if isinstance(declared, list) else [declared]
|
||||||
@@ -450,16 +459,11 @@ def _resolve_agnostic(file_entry: dict, files_db: dict, has_strong_hash: bool):
|
|||||||
prefix = file_entry.get("agnostic_path_prefix", "")
|
prefix = file_entry.get("agnostic_path_prefix", "")
|
||||||
if not prefix:
|
if not prefix:
|
||||||
return None
|
return None
|
||||||
min_size = file_entry.get("min_size", 0)
|
|
||||||
max_size = file_entry.get("max_size", float("inf"))
|
|
||||||
exact_size = file_entry.get("size")
|
|
||||||
if exact_size and not min_size:
|
|
||||||
min_size = max_size = exact_size
|
|
||||||
for _sha1, entry in files_db.items():
|
for _sha1, entry in files_db.items():
|
||||||
path = entry.get("path", "")
|
path = entry.get("path", "")
|
||||||
if not path.startswith(prefix):
|
if not path.startswith(prefix):
|
||||||
continue
|
continue
|
||||||
if min_size <= entry.get("size", 0) <= max_size and os.path.exists(path):
|
if size_fits(file_entry, entry.get("size", 0)) and os.path.exists(path):
|
||||||
return path, "agnostic_fallback"
|
return path, "agnostic_fallback"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
+21
-15
@@ -57,6 +57,7 @@ from common import (
|
|||||||
resolve_local_file,
|
resolve_local_file,
|
||||||
sanitize_pack_path,
|
sanitize_pack_path,
|
||||||
select_emulator_profiles,
|
select_emulator_profiles,
|
||||||
|
size_fits,
|
||||||
yaml_load,
|
yaml_load,
|
||||||
)
|
)
|
||||||
import packresolve
|
import packresolve
|
||||||
@@ -65,6 +66,7 @@ import slot as slot_mod
|
|||||||
import slots
|
import slots
|
||||||
import split_pack
|
import split_pack
|
||||||
from deterministic_zip import _FIXED_DATE_TIME, rebuild_zip_deterministic
|
from deterministic_zip import _FIXED_DATE_TIME, rebuild_zip_deterministic
|
||||||
|
from largefiles import asset_name
|
||||||
from nativemode import (
|
from nativemode import (
|
||||||
digest_algorithm,
|
digest_algorithm,
|
||||||
hash_mismatch_excludes_file,
|
hash_mismatch_excludes_file,
|
||||||
@@ -847,14 +849,9 @@ def generate_pack(
|
|||||||
_path = _entry.get("path", "")
|
_path = _entry.get("path", "")
|
||||||
if _path:
|
if _path:
|
||||||
_prefix = _path.rsplit("/", 1)[0] + "/"
|
_prefix = _path.rsplit("/", 1)[0] + "/"
|
||||||
_min = _ef.get("min_size", 0)
|
|
||||||
_max = _ef.get("max_size", float("inf"))
|
|
||||||
if _ef.get("size") and not _min:
|
|
||||||
_min = _ef["size"]
|
|
||||||
_max = _ef["size"]
|
|
||||||
for _s, _e in files_db.items():
|
for _s, _e in files_db.items():
|
||||||
if _e.get("path", "").startswith(_prefix):
|
if _e.get("path", "").startswith(_prefix):
|
||||||
if _min <= _e.get("size", 0) <= _max:
|
if size_fits(_ef, _e.get("size", 0)):
|
||||||
if os.path.exists(_e["path"]):
|
if os.path.exists(_e["path"]):
|
||||||
local_path = _e["path"]
|
local_path = _e["path"]
|
||||||
agnostic_path = _prefix
|
agnostic_path = _prefix
|
||||||
@@ -2765,12 +2762,23 @@ def _is_release_asset(local_path: str, repo_root: str) -> bool:
|
|||||||
is still served by the repository, and announcing it as a release asset
|
is still served by the repository, and announcing it as a release asset
|
||||||
sends the installer to an asset nobody uploaded.
|
sends the installer to an asset nobody uploaded.
|
||||||
"""
|
"""
|
||||||
gitignore = _load_gitignore_entries(repo_root)
|
return _repo_relative(local_path, repo_root) in _load_gitignore_entries(repo_root)
|
||||||
|
|
||||||
|
|
||||||
|
def _repo_relative(local_path: str, repo_root: str) -> str:
|
||||||
try:
|
try:
|
||||||
rel = os.path.relpath(local_path, repo_root)
|
return os.path.relpath(local_path, repo_root)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
rel = ""
|
return ""
|
||||||
return rel in gitignore
|
|
||||||
|
|
||||||
|
def _release_asset_name(local_path: str, repo_root: str) -> str:
|
||||||
|
"""The large-files asset install.py downloads for a gitignored file."""
|
||||||
|
registered = [
|
||||||
|
entry for entry in _load_gitignore_entries(repo_root)
|
||||||
|
if entry.startswith("bios/")
|
||||||
|
]
|
||||||
|
return asset_name(_repo_relative(local_path, repo_root), registered)
|
||||||
|
|
||||||
|
|
||||||
def _get_repo_path(sha1: str, db: dict) -> str:
|
def _get_repo_path(sha1: str, db: dict) -> str:
|
||||||
@@ -2880,9 +2888,7 @@ def _manifest_core_entries(
|
|||||||
|
|
||||||
if _is_release_asset(local_path or "", repo_root):
|
if _is_release_asset(local_path or "", repo_root):
|
||||||
entry["storage"] = "release"
|
entry["storage"] = "release"
|
||||||
entry["release_asset"] = (
|
entry["release_asset"] = _release_asset_name(local_path, repo_root)
|
||||||
os.path.basename(local_path) if local_path else fe["name"]
|
|
||||||
)
|
|
||||||
|
|
||||||
manifest_files.append(entry)
|
manifest_files.append(entry)
|
||||||
omitted_by_destination.pop(full_dest, None)
|
omitted_by_destination.pop(full_dest, None)
|
||||||
@@ -3117,8 +3123,8 @@ def generate_manifest(
|
|||||||
|
|
||||||
if is_release_asset:
|
if is_release_asset:
|
||||||
entry["storage"] = "release"
|
entry["storage"] = "release"
|
||||||
entry["release_asset"] = (
|
entry["release_asset"] = _release_asset_name(
|
||||||
os.path.basename(local_path) if local_path else file_entry["name"]
|
local_path, repo_root
|
||||||
)
|
)
|
||||||
|
|
||||||
manifest_files.append(entry)
|
manifest_files.append(entry)
|
||||||
|
|||||||
@@ -1976,7 +1976,6 @@ def _render_emulator_file(
|
|||||||
fpattern = f.get("pattern", "")
|
fpattern = f.get("pattern", "")
|
||||||
region_check = f.get("region_check")
|
region_check = f.get("region_check")
|
||||||
size_note = f.get("size_note", "")
|
size_note = f.get("size_note", "")
|
||||||
size_options = f.get("size_options", [])
|
|
||||||
size_range = f.get("size_range", "")
|
size_range = f.get("size_range", "")
|
||||||
|
|
||||||
badges = _file_badges(f, in_repo)
|
badges = _file_badges(f, in_repo)
|
||||||
@@ -2062,10 +2061,6 @@ def _render_emulator_file(
|
|||||||
details.append(f"Region check: {'yes' if region_check else 'no'}")
|
details.append(f"Region check: {'yes' if region_check else 'no'}")
|
||||||
if size_note:
|
if size_note:
|
||||||
details.append(f"Size note: {size_note}")
|
details.append(f"Size note: {size_note}")
|
||||||
if size_options:
|
|
||||||
details.append(
|
|
||||||
f"Size options: {', '.join(_fmt_size(s) for s in size_options)}"
|
|
||||||
)
|
|
||||||
if size_range:
|
if size_range:
|
||||||
details.append(f"Size range: {size_range}")
|
details.append(f"Size range: {size_range}")
|
||||||
|
|
||||||
|
|||||||
+2
-10
@@ -12,6 +12,7 @@ from common import resolution_is_hash_exact
|
|||||||
from common import resolve_local_file
|
from common import resolve_local_file
|
||||||
from common import runs_standalone
|
from common import runs_standalone
|
||||||
from common import sanitize_pack_path
|
from common import sanitize_pack_path
|
||||||
|
from common import size_fits
|
||||||
def _emulator_systems_index(emu_profiles: dict | None) -> dict[str, list[str]]:
|
def _emulator_systems_index(emu_profiles: dict | None) -> dict[str, list[str]]:
|
||||||
"""Map both the profile key and its display name to the profile's systems.
|
"""Map both the profile key and its display name to the profile's systems.
|
||||||
|
|
||||||
@@ -213,21 +214,12 @@ def _agnostic_scan_extras(
|
|||||||
if ambiguous and agnostic_votes.get(path_prefix, 0) < 2:
|
if ambiguous and agnostic_votes.get(path_prefix, 0) < 2:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Size criteria from the file entry
|
|
||||||
min_size = f.get("min_size", 0)
|
|
||||||
max_size = f.get("max_size", float("inf"))
|
|
||||||
exact_size = f.get("size")
|
|
||||||
if exact_size and not min_size:
|
|
||||||
min_size = exact_size
|
|
||||||
max_size = exact_size
|
|
||||||
|
|
||||||
# Scan DB for all files under this prefix matching size
|
# Scan DB for all files under this prefix matching size
|
||||||
for sha1, entry in files_db.items():
|
for sha1, entry in files_db.items():
|
||||||
path = entry.get("path", "")
|
path = entry.get("path", "")
|
||||||
if not path.startswith(path_prefix):
|
if not path.startswith(path_prefix):
|
||||||
continue
|
continue
|
||||||
size = entry.get("size", 0)
|
if not size_fits(f, entry.get("size", 0)):
|
||||||
if not (min_size <= size <= max_size):
|
|
||||||
continue
|
continue
|
||||||
scan_name = entry.get("name", "")
|
scan_name = entry.get("name", "")
|
||||||
if not scan_name:
|
if not scan_name:
|
||||||
|
|||||||
@@ -106,6 +106,25 @@ class AgnosticScanStaysInItsTree(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
return [e for e in extras if e.get("agnostic_scan")]
|
return [e for e in extras if e.get("agnostic_scan")]
|
||||||
|
|
||||||
|
def test_a_list_of_accepted_sizes_selects_the_scan(self):
|
||||||
|
"""`size` may list every size the code accepts. The scan compared it
|
||||||
|
as one integer and failed on a list."""
|
||||||
|
profiles = self._write_profile(
|
||||||
|
"emulator: demo\n"
|
||||||
|
"type: libretro\n"
|
||||||
|
"display_name: Demo\n"
|
||||||
|
"bios_mode: agnostic\n"
|
||||||
|
"systems: [demo-system]\n"
|
||||||
|
"cores: [demo]\n"
|
||||||
|
"files:\n"
|
||||||
|
" - name: boot.bin\n"
|
||||||
|
" system: demo-system\n"
|
||||||
|
" size: [512, 1024]\n"
|
||||||
|
" agnostic: true\n"
|
||||||
|
)
|
||||||
|
names = sorted(e["name"] for e in self._scan(profiles))
|
||||||
|
self.assertIn("boot.bin", names)
|
||||||
|
|
||||||
def test_it_collects_the_interchangeable_dumps(self):
|
def test_it_collects_the_interchangeable_dumps(self):
|
||||||
profiles = self._write_profile(
|
profiles = self._write_profile(
|
||||||
"emulator: demo\n"
|
"emulator: demo\n"
|
||||||
|
|||||||
@@ -174,6 +174,17 @@ class TestSizeGateOnTheNameStep(unittest.TestCase):
|
|||||||
self.assertIsNotNone(path)
|
self.assertIsNotNone(path)
|
||||||
self.assertEqual(status, "hash_mismatch")
|
self.assertEqual(status, "hash_mismatch")
|
||||||
|
|
||||||
|
def test_a_list_of_accepted_sizes_gates_the_name_step(self):
|
||||||
|
# SC-55/ROM2.BIN accepts two sizes; a PlayStation 2 ROM2.BIN of a
|
||||||
|
# third size answered to the name because the list was ignored.
|
||||||
|
entry = {"name": "ROM", "size": [8, 999], "validation": ["size"]}
|
||||||
|
path, status = resolve_local_file(entry, self.db)
|
||||||
|
self.assertEqual(status, "name_exact")
|
||||||
|
self.assertIn("IIGS", path)
|
||||||
|
entry = {"name": "ROM", "size": [999, 1000], "validation": ["size"]}
|
||||||
|
path, status = resolve_local_file(entry, self.db)
|
||||||
|
self.assertEqual(status, "hash_mismatch")
|
||||||
|
|
||||||
def test_a_size_without_validation_rejects_nothing(self):
|
def test_a_size_without_validation_rejects_nothing(self):
|
||||||
# Documented behaviour: a size is informative until the emulator
|
# Documented behaviour: a size is informative until the emulator
|
||||||
# itself checks it.
|
# itself checks it.
|
||||||
|
|||||||
@@ -198,6 +198,19 @@ class AgnosticFallback(unittest.TestCase):
|
|||||||
}
|
}
|
||||||
self.assertIsNotNone(common._resolve_agnostic(entry, self.files_db, False))
|
self.assertIsNotNone(common._resolve_agnostic(entry, self.files_db, False))
|
||||||
|
|
||||||
|
def test_a_list_of_accepted_sizes_is_honoured(self):
|
||||||
|
entry = {
|
||||||
|
"agnostic": True,
|
||||||
|
"agnostic_path_prefix": str(self.root),
|
||||||
|
"size": [32, 64],
|
||||||
|
}
|
||||||
|
self.assertEqual(
|
||||||
|
common._resolve_agnostic(entry, self.files_db, False),
|
||||||
|
(str(self.match), "agnostic_fallback"),
|
||||||
|
)
|
||||||
|
entry["size"] = [32, 65]
|
||||||
|
self.assertIsNone(common._resolve_agnostic(entry, self.files_db, False))
|
||||||
|
|
||||||
def test_without_a_prefix_nothing_is_scanned(self):
|
def test_without_a_prefix_nothing_is_scanned(self):
|
||||||
entry = {"agnostic": True, "size": 64}
|
entry = {"agnostic": True, "size": 64}
|
||||||
self.assertIsNone(common._resolve_agnostic(entry, self.files_db, False))
|
self.assertIsNone(common._resolve_agnostic(entry, self.files_db, False))
|
||||||
@@ -207,5 +220,31 @@ class AgnosticFallback(unittest.TestCase):
|
|||||||
self.assertIsNone(common._resolve_agnostic(entry, self.files_db, False))
|
self.assertIsNone(common._resolve_agnostic(entry, self.files_db, False))
|
||||||
|
|
||||||
|
|
||||||
|
class OneSpellingForAcceptedSizes(unittest.TestCase):
|
||||||
|
"""A set of sizes the code accepts is ``size: [a, b]`` and nothing else.
|
||||||
|
|
||||||
|
SC-55/ROM2.BIN declared its two sizes under a field the resolver never
|
||||||
|
read and resolved by name to a PlayStation 2 ROM of a third size.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_no_profile_uses_a_second_field(self):
|
||||||
|
offenders = [
|
||||||
|
path.name
|
||||||
|
for path in sorted((REPO_ROOT / "emulators").glob("*.yml"))
|
||||||
|
if "size_options" in path.read_text(encoding="utf-8")
|
||||||
|
]
|
||||||
|
self.assertEqual(offenders, [])
|
||||||
|
|
||||||
|
def test_the_schema_refuses_the_second_field(self):
|
||||||
|
import json
|
||||||
|
|
||||||
|
schema = json.loads(
|
||||||
|
(REPO_ROOT / "schemas/emulator.schema.json").read_text(encoding="utf-8")
|
||||||
|
)
|
||||||
|
file_entry = schema["properties"]["files"]["items"]["properties"]
|
||||||
|
self.assertNotIn("size_options", file_entry)
|
||||||
|
self.assertEqual(file_entry["size"]["type"], ["integer", "array", "null"])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
unittest.main()
|
unittest.main()
|
||||||
Reference in new issue
Block a user