99 lines
4.1 KiB
Python
99 lines
4.1 KiB
Python
"""Tests for folder persistence and metadata repair (GOG rename handling)."""
|
|
|
|
from pathlib import Path
|
|
|
|
from src.config import MetadataStore
|
|
from src.models import DownloadedBonus, DownloadedInstaller, GameRecord, InstallerType
|
|
|
|
|
|
def _installer(version: str, filename: str) -> DownloadedInstaller:
|
|
return DownloadedInstaller(
|
|
filename=filename, size=1, version=version, language="en",
|
|
installer_type=InstallerType.GAME, downloaded_at="",
|
|
)
|
|
|
|
|
|
def _make_version(base: Path, folder: str, version: str, *filenames: str) -> None:
|
|
d = base / folder / version
|
|
d.mkdir(parents=True, exist_ok=True)
|
|
for f in filenames:
|
|
(d / f).write_text("x")
|
|
|
|
|
|
def _make_bonus(base: Path, folder: str, *filenames: str) -> None:
|
|
d = base / folder / "Bonus"
|
|
d.mkdir(parents=True, exist_ok=True)
|
|
for f in filenames:
|
|
(d / f).write_text("x")
|
|
|
|
|
|
class TestFolderField:
|
|
def test_roundtrip_persists_folder(self) -> None:
|
|
rec = GameRecord(game_id="1", name="Old Name", folder="Pinned Folder")
|
|
restored = GameRecord.from_dict("1", rec.to_dict())
|
|
assert restored.folder == "Pinned Folder"
|
|
|
|
def test_empty_folder_not_written(self) -> None:
|
|
rec = GameRecord(game_id="1", name="Game")
|
|
assert "folder" not in rec.to_dict()
|
|
|
|
|
|
class TestCandidateLookup:
|
|
def test_finds_files_across_folders(self, tmp_path: Path) -> None:
|
|
# Game renamed: v1 under old folder, v2 under new (pinned) folder.
|
|
_make_version(tmp_path, "New Title", "2.0", "setup.exe")
|
|
_make_version(tmp_path, "Old Title", "1.0", "setup.exe")
|
|
store = MetadataStore(str(tmp_path))
|
|
rec = GameRecord(
|
|
game_id="1", name="Old Title", folder="New Title", latest_version="2.0",
|
|
installers=[_installer("2.0", "setup.exe"), _installer("1.0", "setup.exe")],
|
|
)
|
|
store.games["1"] = rec
|
|
store.save = lambda: None # type: ignore[method-assign]
|
|
|
|
removed = store.verify_metadata()
|
|
assert removed == 0 # both installers found despite living in different folders
|
|
assert rec.latest_version == "2.0"
|
|
assert len(rec.installers) == 2
|
|
|
|
|
|
class TestRepairFolders:
|
|
def test_repoints_to_newest_version_folder_and_merges(self, tmp_path: Path) -> None:
|
|
# Split data: old folder has 1.0 + a bonus, new-title folder has 2.0.
|
|
_make_version(tmp_path, "Witcher Complete", "1.0", "setup_1.exe")
|
|
_make_version(tmp_path, "Witcher Remastered", "2.0", "setup_2.exe")
|
|
_make_bonus(tmp_path, "Witcher Complete", "ost.zip")
|
|
|
|
store = MetadataStore(str(tmp_path))
|
|
# Metadata still points at the old folder and (wrongly) a single version.
|
|
rec = GameRecord(
|
|
game_id="1", name="Witcher Complete", folder="", latest_version="2.0",
|
|
installers=[_installer("1.0", "setup_1.exe"), _installer("2.0", "setup_2.exe")],
|
|
bonuses=[DownloadedBonus(filename="ost.zip", name="OST", bonus_type="audio", size=1, downloaded_at="")],
|
|
)
|
|
store.games["1"] = rec
|
|
saved: dict[str, bool] = {}
|
|
store.save = lambda: saved.update(saved=True) # type: ignore[method-assign]
|
|
|
|
changed = store.repair_folders({"1": ["Witcher Remastered"]})
|
|
|
|
assert changed == 1
|
|
assert rec.folder == "Witcher Remastered" # pinned to newest-version folder
|
|
assert rec.latest_version == "2.0"
|
|
assert {i.version for i in rec.installers} == {"1.0", "2.0"} # merged from both folders
|
|
assert len(rec.bonuses) == 1 # bonus in old folder still found
|
|
assert saved.get("saved")
|
|
|
|
def test_drops_bonus_with_missing_file(self, tmp_path: Path) -> None:
|
|
_make_version(tmp_path, "Game", "1.0", "setup.exe")
|
|
store = MetadataStore(str(tmp_path))
|
|
rec = GameRecord(
|
|
game_id="1", name="Game", installers=[_installer("1.0", "setup.exe")],
|
|
bonuses=[DownloadedBonus(filename="gone.zip", name="X", bonus_type="", size=1, downloaded_at="")],
|
|
)
|
|
store.games["1"] = rec
|
|
store.save = lambda: None # type: ignore[method-assign]
|
|
|
|
store.repair_folders({"1": ["Game"]})
|
|
assert rec.bonuses == [] # file not on disk -> dropped
|