import asyncio from types import SimpleNamespace from unittest.mock import AsyncMock import pytest from fastapi import HTTPException from app import gallery from app.routers import versions from app.schemas import ForkIn, GallerySettingsIn @pytest.mark.parametrize(("game", "expected"), [ ({"build": {"name": "MIST"}, "screens": {"rewatchgirlselectscreen": {}}}, True), ({"init": [{"k": "call", "f": {"k": "name", "id": "Gallery"}}]}, True), ({"screens": {"replay": {"k": "call", "f": {"k": "name", "id": "Replay"}}}}, True), ({"init": [], "screens": {}}, False), ({"engine": "naninovel", "init": [{"k": "call", "f": {"k": "name", "id": "Gallery"}}]}, False), ]) def test_supported_gallery_detection(monkeypatch, game, expected): monkeypatch.setattr(gallery, "file_json", lambda *_: game) assert gallery.available({"files": {"game.json": {}}}) is expected assert not gallery.available(None) def test_only_owner_can_toggle_gallery_and_scripts_are_not_modified(monkeypatch): manifest = {"files": {"game.json": {"hash": "unchanged"}}} v = SimpleNamespace(owner_id=7, status="ready", manifest=manifest, gallery_unlocked=False) monkeypatch.setattr(versions, "get_version", AsyncMock(return_value=v)) monkeypatch.setattr(versions, "gallery_available", lambda _: True) db = SimpleNamespace(commit=AsyncMock()) async def scenario(): body = GallerySettingsIn(gallery_unlocked=True) with pytest.raises(HTTPException) as error: await versions.update_gallery(1, body, SimpleNamespace(id=8), db) assert error.value.status_code == 403 assert not v.gallery_unlocked result = await versions.update_gallery(1, body, SimpleNamespace(id=7), db) assert result.gallery_unlocked assert result.manifest is manifest await versions.update_gallery(1, GallerySettingsIn(gallery_unlocked=False), SimpleNamespace(id=7), db) assert not v.gallery_unlocked assert db.commit.await_count == 2 asyncio.run(scenario()) @pytest.mark.parametrize(("state", "supported", "code"), [("converting", True, 409), ("ready", False, 422)]) def test_gallery_requires_ready_supported_game(monkeypatch, state, supported, code): v = SimpleNamespace(owner_id=7, status=state, manifest={}, gallery_unlocked=False) monkeypatch.setattr(versions, "get_version", AsyncMock(return_value=v)) monkeypatch.setattr(versions, "gallery_available", lambda _: supported) db = SimpleNamespace(commit=AsyncMock()) with pytest.raises(HTTPException) as error: asyncio.run(versions.update_gallery(1, GallerySettingsIn(gallery_unlocked=True), SimpleNamespace(id=7), db)) assert error.value.status_code == code db.commit.assert_not_awaited() def test_player_manifest_uses_version_flag_instead_of_shared_manifest(monkeypatch): shared = {"files": {"game.json": {"hash": "unchanged"}}} v = SimpleNamespace(id=1, status="ready", manifest=shared, revision_id="revision", gallery_unlocked=True) monkeypatch.setattr(versions, "get_version", AsyncMock(return_value=v)) result = asyncio.run(versions.version_manifest(1, SimpleNamespace(id=7), None)) assert result["galleryUnlocked"] is True assert "galleryUnlocked" not in shared v.gallery_unlocked = False assert asyncio.run(versions.version_manifest(1, SimpleNamespace(id=7), None))["galleryUnlocked"] is False def test_fork_inherits_gallery_setting_but_can_change_it_independently(monkeypatch): parent = SimpleNamespace(id=1, game_id=2, status="ready", gallery_unlocked=True, manifest={"files": {}}, revision_id="base", report={}, size_bytes=1) monkeypatch.setattr(versions, "get_version", AsyncMock(return_value=parent)) monkeypatch.setattr(versions, "has_perm", lambda *_: True) added = [] db = SimpleNamespace(add=added.append, commit=AsyncMock()) fork = asyncio.run(versions.fork_version(1, ForkIn(name="My fork"), SimpleNamespace(id=7), db)) assert fork.gallery_unlocked is True fork.gallery_unlocked = False assert parent.gallery_unlocked is True assert fork.manifest is parent.manifest