import pytest from src import gitea_proxy @pytest.mark.anyio async def test_unread_notifications_are_bounded_and_normalized_for_mobile_handoff(monkeypatch): requested_paths = [] async def fake_fetch(path): requested_paths.append(path) return [ { "id": 42, "unread": True, "updated_at": "2026-08-06T12:30:00Z", "repository": {"full_name": "stackchain/api"}, "subject": { "title": "Retry failed deploy", "type": "Issue", "state": "open", "html_url": "https://forge.example/stackchain/api/issues/7", "latest_comment_html_url": "https://forge.example/stackchain/api/issues/7#issuecomment-9", }, }, {"id": 43, "repository": None, "subject": None}, { "id": 44, "repository": {"full_name": "stackchain/web"}, "subject": {"title": "Unsafe", "html_url": "javascript:alert(1)"}, }, "malformed", ] monkeypatch.setattr(gitea_proxy, "fetch", fake_fetch) result = await gitea_proxy.notifications() assert requested_paths == ["notifications?status-types=unread&limit=50"] assert result == [ { "id": 42, "unread": True, "updated_at": "2026-08-06T12:30:00Z", "repository": "stackchain/api", "number": 7, "title": "Retry failed deploy", "subject_type": "Issue", "state": "open", "url": "https://forge.example/stackchain/api/issues/7#issuecomment-9", "subject_url": "https://forge.example/stackchain/api/issues/7", }, { "id": 43, "unread": False, "updated_at": "", "repository": "", "number": None, "title": "Untitled update", "subject_type": "Update", "state": "", "url": "", "subject_url": "", }, { "id": 44, "unread": False, "updated_at": "", "repository": "stackchain/web", "number": None, "title": "Unsafe", "subject_type": "Update", "state": "", "url": "", "subject_url": "", }, ] @pytest.mark.anyio async def test_notification_collection_rejects_non_list_payload(monkeypatch): async def fake_fetch(_path): return {"message": "unexpected"} monkeypatch.setattr(gitea_proxy, "fetch", fake_fetch) with pytest.raises(ValueError, match="notification response was not a list"): await gitea_proxy.notifications()