add check_names.py: detect and fix mod folder name mismatches

Compares @Mod folder names in downloads/ against server canonical
names. Uses meta.cpp steam_id as primary lookup (most reliable),
falls back to normalized name. Reports OK / MISMATCH / NOT_ON_SERVER
per folder.

--fix mode renames mismatched folders and updates arma_dir junctions
in one pass so the full pipeline can run cleanly afterward.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
revernomad17
2026-04-07 16:56:10 +07:00
parent da9e7782d6
commit e706e71f29
2 changed files with 324 additions and 1 deletions

View File

@@ -1059,7 +1059,93 @@ test("all exported symbols are callable or types", _test_exports_are_callable)
# ---------------------------------------------------------------------------
# 9. Integration: parse → compare → reporter (offline)
# 9. check_names helpers
# ---------------------------------------------------------------------------
group("check_names helpers")
from check_names import _server_name_from_url, _read_local_steam_id, _lookup_server_name
def _test_server_name_from_url():
assert_eq(_server_name_from_url("https://x.com/mods/@ace/"), "@ace")
assert_eq(_server_name_from_url("https://x.com/mods/@cba_a3"), "@cba_a3")
def _test_read_local_steam_id_present():
with tempfile.TemporaryDirectory() as d:
d = Path(d)
(d / "meta.cpp").write_text('publishedid = 463939057;\nname = "ACE3";', encoding="utf-8")
assert_eq(_read_local_steam_id(d), "463939057")
def _test_read_local_steam_id_missing():
with tempfile.TemporaryDirectory() as d:
assert _read_local_steam_id(Path(d)) is None
def _test_read_local_steam_id_no_id_in_file():
with tempfile.TemporaryDirectory() as d:
d = Path(d)
(d / "meta.cpp").write_text('name = "LocalMod";\n', encoding="utf-8")
assert _read_local_steam_id(d) is None
def _test_lookup_server_name_by_steam_id():
index = {
"by_steam_id": {"463939057": "https://x.com/@ace3/"},
"by_name": {},
}
with tempfile.TemporaryDirectory() as d:
d = Path(d)
(d / "meta.cpp").write_text("publishedid = 463939057;", encoding="utf-8")
result = _lookup_server_name("@ACE3", d, index)
assert_eq(result, "@ace3")
def _test_lookup_server_name_by_name_fallback():
index = {
"by_steam_id": {},
"by_name": {"cbaa3": "https://x.com/@cba_a3/"},
}
with tempfile.TemporaryDirectory() as d:
# No meta.cpp — name fallback
result = _lookup_server_name("@CBA_A3", Path(d), index)
assert_eq(result, "@cba_a3")
def _test_lookup_server_name_steam_id_beats_name():
"""steam_id lookup must take priority over name fallback."""
index = {
"by_steam_id": {"111": "https://x.com/@correct/"},
"by_name": {"mymod": "https://x.com/@wrong/"},
}
with tempfile.TemporaryDirectory() as d:
d = Path(d)
(d / "meta.cpp").write_text("publishedid = 111;", encoding="utf-8")
result = _lookup_server_name("@MyMod", d, index)
assert_eq(result, "@correct")
def _test_lookup_server_name_not_found():
index = {"by_steam_id": {}, "by_name": {}}
with tempfile.TemporaryDirectory() as d:
result = _lookup_server_name("@Unknown", Path(d), index)
assert result is None
test("_server_name_from_url: extracts name from URL", _test_server_name_from_url)
test("_read_local_steam_id: reads meta.cpp", _test_read_local_steam_id_present)
test("_read_local_steam_id: no meta.cpp -> None", _test_read_local_steam_id_missing)
test("_read_local_steam_id: meta.cpp without id -> None", _test_read_local_steam_id_no_id_in_file)
test("_lookup_server_name: matches by steam_id", _test_lookup_server_name_by_steam_id)
test("_lookup_server_name: falls back to name", _test_lookup_server_name_by_name_fallback)
test("_lookup_server_name: steam_id beats name fallback", _test_lookup_server_name_steam_id_beats_name)
test("_lookup_server_name: not found -> None", _test_lookup_server_name_not_found)
# ---------------------------------------------------------------------------
# 10. Integration: parse → compare → reporter (offline)
# ---------------------------------------------------------------------------
group("integration: parse → compare → reporter (offline)")