mirror of
https://github.com/Abdess/retrobios.git
synced 2026-06-26 21:02:47 +00:00
59 lines
1.9 KiB
Python
59 lines
1.9 KiB
Python
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import os
|
||
|
|
import unittest
|
||
|
|
from collections import defaultdict
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
|
||
|
|
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||
|
|
BIOS_ROOT = REPO_ROOT / "bios"
|
||
|
|
|
||
|
|
|
||
|
|
class TestNoCaseCollisions(unittest.TestCase):
|
||
|
|
"""Guard against case-colliding paths in bios/.
|
||
|
|
|
||
|
|
On case-insensitive filesystems (Windows, macOS default), git can only
|
||
|
|
check out one path per casefold-equivalence class, silently corrupting
|
||
|
|
clones. Issue #33 and #49 both stemmed from this.
|
||
|
|
|
||
|
|
.variants/ subdirs are exempt: they intentionally hold genuine content
|
||
|
|
variants disambiguated by hash suffix (e.g., BIOS.ROM.910fae67).
|
||
|
|
"""
|
||
|
|
|
||
|
|
def test_bios_has_no_case_colliding_paths(self) -> None:
|
||
|
|
if not BIOS_ROOT.is_dir():
|
||
|
|
self.skipTest("bios/ directory not present")
|
||
|
|
|
||
|
|
collisions: list[str] = []
|
||
|
|
for root, dirs, files in os.walk(BIOS_ROOT):
|
||
|
|
if ".variants" in Path(root).parts:
|
||
|
|
continue
|
||
|
|
|
||
|
|
dir_groups: dict[str, list[str]] = defaultdict(list)
|
||
|
|
for d in dirs:
|
||
|
|
dir_groups[d.casefold()].append(d)
|
||
|
|
for variants in dir_groups.values():
|
||
|
|
if len(variants) > 1:
|
||
|
|
rel = Path(root).relative_to(REPO_ROOT)
|
||
|
|
collisions.append(f"DIR {rel}: {sorted(variants)}")
|
||
|
|
|
||
|
|
file_groups: dict[str, list[str]] = defaultdict(list)
|
||
|
|
for f in files:
|
||
|
|
file_groups[f.casefold()].append(f)
|
||
|
|
for variants in file_groups.values():
|
||
|
|
if len(variants) > 1:
|
||
|
|
rel = Path(root).relative_to(REPO_ROOT)
|
||
|
|
collisions.append(f"FILE {rel}: {sorted(variants)}")
|
||
|
|
|
||
|
|
self.assertEqual(
|
||
|
|
collisions,
|
||
|
|
[],
|
||
|
|
"Case-colliding paths in bios/ would break Windows/macOS clones:\n"
|
||
|
|
+ "\n".join(collisions),
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
if __name__ == "__main__":
|
||
|
|
unittest.main()
|