"""§4.2: apply_official_exercise_media_rules — Lifecycle, Sichtbarkeit, Copyright.""" from __future__ import annotations import os from unittest.mock import MagicMock import pytest from fastapi import HTTPException os.environ.setdefault("SKIP_DB_MIGRATE", "1") from routers.exercises import apply_official_exercise_media_rules def _row( aid: int, *, vis: str = "private", lifecycle: str = "active", copyright_notice: str | None = "", name: str = "f.bin", ) -> dict: return { "id": aid, "visibility": vis, "club_id": 1, "lifecycle_state": lifecycle, "copyright_notice": copyright_notice, "original_filename": name, } def test_non_official_visibility_noop() -> None: cur = MagicMock() apply_official_exercise_media_rules( cur, 1, "private", promote_attached_media=False, default_official_media_copyright=None, ) cur.execute.assert_not_called() def test_lifecycle_not_active_422() -> None: cur = MagicMock() cur.fetchall.return_value = [_row(1, lifecycle="trash_soft", copyright_notice="abc")] with pytest.raises(HTTPException) as ei: apply_official_exercise_media_rules( cur, 1, "official", promote_attached_media=False, default_official_media_copyright=None, ) assert ei.value.status_code == 422 assert ei.value.detail["code"] == "OFFICIAL_MEDIA_LIFECYCLE" def test_visibility_promotion_confirm_422() -> None: cur = MagicMock() cur.fetchall.return_value = [_row(1, vis="club", copyright_notice="halten")] with pytest.raises(HTTPException) as ei: apply_official_exercise_media_rules( cur, 1, "official", promote_attached_media=False, default_official_media_copyright=None, ) assert ei.value.status_code == 422 assert ei.value.detail["code"] == "OFFICIAL_MEDIA_CONFIRM_REQUIRED" assert ei.value.detail["assets_need_visibility_promotion"] def test_copyright_required_422() -> None: cur = MagicMock() cur.fetchall.return_value = [_row(1, vis="official", copyright_notice="")] with pytest.raises(HTTPException) as ei: apply_official_exercise_media_rules( cur, 1, "official", promote_attached_media=True, default_official_media_copyright=None, ) assert ei.value.status_code == 422 assert ei.value.detail["code"] == "OFFICIAL_MEDIA_CONFIRM_REQUIRED" assert ei.value.detail["assets_missing_copyright"] def test_promote_and_fill_copyright_updates() -> None: cur = MagicMock() cur.fetchall.return_value = [_row(1, vis="private", copyright_notice=" ")] apply_official_exercise_media_rules( cur, 42, "official", promote_attached_media=True, default_official_media_copyright="© Test Holding", ) assert cur.execute.call_count == 3 sql1 = cur.execute.call_args_list[1][0][0] sql2 = cur.execute.call_args_list[2][0][0] assert "visibility = 'official'" in sql1 assert "copyright_notice" in sql2