import uuid from fastapi.testclient import TestClient from tests.conftest import ( admin_token, approve_cloud, bearer, register_and_confirm, upload_cloud, ) def _set_favorite(client: TestClient, token: str, cloud_id: str, favorited: bool): return client.put( f"/api/v1/clouds/{cloud_id}/favorite", headers=bearer(token), json={"favorited": favorited}, ) def _get_favorite(client: TestClient, token: str, cloud_id: str, **params): return client.get( f"/api/v1/clouds/{cloud_id}/favorite", headers=bearer(token), params=params or None, ) def test_favorite_and_unfavorite_public_cloud(client: TestClient, monkeypatch) -> None: owner = register_and_confirm( client, monkeypatch, f"fav-owner-{uuid.uuid4().hex[:8]}@example.com", "favowner12", "收藏主人", ) fan = register_and_confirm( client, monkeypatch, f"fav-fan-{uuid.uuid4().hex[:8]}@example.com", "favfan1234", "点赞粉丝", ) upload = upload_cloud(client, owner["token"], cloud_type_id="1") cloud_id = upload.json()["cloud"]["id"] approve_cloud(client, admin_token(client), cloud_id) r = _get_favorite(client, fan["token"], cloud_id) assert r.status_code == 200 assert r.json()["favorited"] is False assert r.json()["favorite_count"] == 0 assert r.json()["user_id"] == fan["user_id"] r = _set_favorite(client, fan["token"], cloud_id, True) assert r.status_code == 200 body = r.json() assert body["cloud_id"] == cloud_id assert body["user_id"] == fan["user_id"] assert body["favorited"] is True assert body["favorite_count"] == 1 r = _get_favorite(client, fan["token"], cloud_id) assert r.status_code == 200 assert r.json()["favorited"] is True assert r.json()["favorite_count"] == 1 # idempotent re-favorite r = _set_favorite(client, fan["token"], cloud_id, True) assert r.status_code == 200 assert r.json()["favorited"] is True assert r.json()["favorite_count"] == 1 r = _set_favorite(client, fan["token"], cloud_id, False) assert r.status_code == 200 assert r.json()["favorited"] is False assert r.json()["favorite_count"] == 0 r = _get_favorite(client, fan["token"], cloud_id) assert r.status_code == 200 assert r.json()["favorited"] is False def test_get_favorite_for_other_user_forbidden(client: TestClient, monkeypatch) -> None: owner = register_and_confirm( client, monkeypatch, f"other-owner-{uuid.uuid4().hex[:8]}@example.com", "otherowner", "他人主人", ) fan = register_and_confirm( client, monkeypatch, f"other-fan-{uuid.uuid4().hex[:8]}@example.com", "otherfan12", "他人粉丝", ) upload = upload_cloud(client, owner["token"], cloud_type_id="1") cloud_id = upload.json()["cloud"]["id"] approve_cloud(client, admin_token(client), cloud_id) assert _set_favorite(client, fan["token"], cloud_id, True).status_code == 200 # 普通用户不能查别人的喜欢状态 r = _get_favorite(client, owner["token"], cloud_id, user_id=fan["user_id"]) assert r.status_code == 403 # 管理员可以 r = _get_favorite(client, admin_token(client), cloud_id, user_id=fan["user_id"]) assert r.status_code == 200 assert r.json()["user_id"] == fan["user_id"] assert r.json()["favorited"] is True assert r.json()["favorite_count"] == 1 def test_get_favorite_unauthenticated(client: TestClient) -> None: r = client.get(f"/api/v1/clouds/{uuid.uuid4()}/favorite") assert r.status_code == 401 def test_favorite_unauthenticated(client: TestClient) -> None: r = client.put( f"/api/v1/clouds/{uuid.uuid4()}/favorite", json={"favorited": True}, ) assert r.status_code == 401 def test_cannot_favorite_pending_cloud_of_others(client: TestClient, monkeypatch) -> None: owner = register_and_confirm( client, monkeypatch, f"pending-owner-{uuid.uuid4().hex[:8]}@example.com", "pendingown", "待审主人", ) fan = register_and_confirm( client, monkeypatch, f"pending-fan-{uuid.uuid4().hex[:8]}@example.com", "pendingfan", "待审粉丝", ) upload = upload_cloud(client, owner["token"], cloud_type_id="2") cloud_id = upload.json()["cloud"]["id"] r = _set_favorite(client, fan["token"], cloud_id, True) assert r.status_code == 404 def test_owner_can_favorite_own_pending_cloud(client: TestClient, monkeypatch) -> None: owner = register_and_confirm( client, monkeypatch, f"own-fav-{uuid.uuid4().hex[:8]}@example.com", "ownfavpass", "自赞用户", ) upload = upload_cloud(client, owner["token"], cloud_type_id="3") cloud_id = upload.json()["cloud"]["id"] r = _set_favorite(client, owner["token"], cloud_id, True) assert r.status_code == 200 assert r.json()["favorited"] is True assert r.json()["favorite_count"] == 1 def test_list_my_favorites(client: TestClient, monkeypatch) -> None: owner = register_and_confirm( client, monkeypatch, f"list-owner-{uuid.uuid4().hex[:8]}@example.com", "listowner1", "列表主人", ) fan = register_and_confirm( client, monkeypatch, f"list-fan-{uuid.uuid4().hex[:8]}@example.com", "listfan123", "列表粉丝", ) ids = [] for type_id in ("1", "2"): upload = upload_cloud(client, owner["token"], cloud_type_id=type_id) cloud_id = upload.json()["cloud"]["id"] approve_cloud(client, admin_token(client), cloud_id) ids.append(cloud_id) assert _set_favorite(client, fan["token"], cloud_id, True).status_code == 200 r = client.get("/api/v1/favorites/me", headers=bearer(fan["token"])) assert r.status_code == 200 body = r.json() assert body["total"] == 2 returned_ids = [item["id"] for item in body["items"]] assert set(returned_ids) == set(ids) assert _set_favorite(client, fan["token"], ids[0], False).status_code == 200 r = client.get("/api/v1/favorites/me", headers=bearer(fan["token"])) assert r.status_code == 200 assert r.json()["total"] == 1 assert r.json()["items"][0]["id"] == ids[1] def test_favorite_missing_cloud(client: TestClient, monkeypatch) -> None: user = register_and_confirm( client, monkeypatch, f"missing-{uuid.uuid4().hex[:8]}@example.com", "missing123", "缺图用户", ) r = _set_favorite(client, user["token"], str(uuid.uuid4()), True) assert r.status_code == 404 def test_list_favorites_unauthenticated(client: TestClient) -> None: r = client.get("/api/v1/favorites/me") assert r.status_code == 401