fix: report a contradicted hash on an archive too

This commit is contained in:
Abdessamad Derraz committed 2026-09-06 23:08:04 +02:00
1 parent 8128b47aeb
commit a61c800462
2 files changed
+95 -2

No files matched your search

+14 -2
View File
@@ -1402,7 +1402,7 @@ def verify_emulator(
),
{"name": archive},
)
local_path, _ = resolve_local_file(
local_path, resolve_status = resolve_local_file(
archive_entry,
db,
zip_contents,
@@ -1412,7 +1412,19 @@ def verify_emulator(
f.get("archive") == archive and f.get("required", True)
for f in files
)
if local_path:
if local_path and resolve_status == "hash_mismatch":
# Same policy as the loose-file branch below: the name
# matched while the bytes contradict the hash the profile
# declares on the container. Reporting it covered says the
# collection holds an archive it does not.
result = {
"name": archive,
"status": Status.UNTESTED,
"required": required,
"path": local_path,
"reason": "declared hash contradicted by the local file",
}
elif local_path:
result = {
"name": archive,
"status": Status.OK,
+81
View File
@@ -154,6 +154,87 @@ class HashMismatchIsNotCoverage(unittest.TestCase):
self.assertEqual(detail["status"], verify.Status.MISSING)
class ArchiveHashMismatchIsNotCoverage(unittest.TestCase):
"""The archive branch of the same report applied a different policy.
It discarded the status resolve_local_file returns and called any
non-empty path OK, while the loose-file branch beside it reported the
divergence. Eighteen archive entries declare a container hash, so an
archive whose bytes contradict it would have read as covered.
"""
def setUp(self):
import zipfile
self._tmp = tempfile.TemporaryDirectory()
self.root = Path(self._tmp.name)
self.emulators = self.root / "emulators"
self.emulators.mkdir()
self.archive = self.root / "romset.zip"
with zipfile.ZipFile(self.archive, "w") as zf:
zf.writestr("inner.rom", b"THE MEMBER THE EMULATOR LOADS")
self.db = _db(self.archive, "romset.zip")
from common import _emulator_profiles_cache
_emulator_profiles_cache.clear()
def tearDown(self):
from common import _emulator_profiles_cache
_emulator_profiles_cache.clear()
self._tmp.cleanup()
def _profile(self, declared_md5: str) -> None:
(self.emulators / "demo.yml").write_text(
"emulator: demo\n"
"type: standalone\n"
"display_name: Demo\n"
"systems: [demo-system]\n"
"files:\n"
" - name: romset.zip\n"
" system: demo-system\n"
" category: bios_zip\n"
" required: true\n"
f" md5: \"{declared_md5}\"\n"
" - name: inner.rom\n"
" system: demo-system\n"
" archive: romset.zip\n"
" required: true\n"
)
def _run(self):
cwd = os.getcwd()
os.chdir(self.root)
try:
return verify.verify_emulator(["demo"], str(self.emulators), self.db)
finally:
os.chdir(cwd)
def _statuses(self, result):
"""Every verdict on the archive.
The container is reported twice, once by the branch that walks the
profile's files and once by the branch that walks its archives. Keying
by name keeps only the last, which is how a passing test can hide the
branch under examination.
"""
return [d["status"] for d in result["details"] if d["name"] == "romset.zip"]
def test_a_contradicted_container_hash_is_not_reported_ok(self):
self._profile("f" * 32)
statuses = self._statuses(self._run())
self.assertEqual(len(statuses), 2, statuses)
self.assertNotIn(
verify.Status.OK,
statuses,
"an archive whose bytes contradict its declared hash counted as covered",
)
def test_a_matching_container_hash_is_still_ok(self):
self._profile(hashlib.md5(self.archive.read_bytes()).hexdigest())
self.assertEqual(set(self._statuses(self._run())), {verify.Status.OK})
class UnsourceableIsNotAGap(unittest.TestCase):
"""An entry nobody can supply is absent by design, not by omission.