"""T5.5 POST /projects/:id/rules 端点(内存替身,无 DB/无网络)。 覆盖: - 201 + 回显 level/content + 端点 commit; - 非法 level → 422(Pydantic Literal 校验,FastAPI 422); - 空 content → 422。 """ from __future__ import annotations import uuid import httpx import pytest from cryptography.fernet import Fernet from fakes_projects import FakeSession from ww_core.domain.rule_repo import RuleWriteView class _FakeRuleWriteRepo: def __init__(self) -> None: self.rows: list[RuleWriteView] = [] async def create(self, project_id: uuid.UUID, *, level: str, content: str) -> RuleWriteView: view = RuleWriteView(project_id=project_id, level=level, content=content) self.rows.append(view) return view def _make_client() -> tuple[httpx.AsyncClient, _FakeRuleWriteRepo, FakeSession]: import os os.environ.setdefault("CREDENTIAL_ENC_KEY", Fernet.generate_key().decode()) from ww_api.main import create_app from ww_api.services.project_deps import get_rule_write_repo from ww_db import get_session repo = _FakeRuleWriteRepo() session = FakeSession() app = create_app() app.dependency_overrides[get_rule_write_repo] = lambda: repo app.dependency_overrides[get_session] = lambda: session transport = httpx.ASGITransport(app=app) client = httpx.AsyncClient(transport=transport, base_url="http://test") return client, repo, session @pytest.mark.asyncio async def test_create_rule_returns_201_and_commits() -> None: client, repo, session = _make_client() pid = uuid.uuid4() async with client: resp = await client.post( f"/projects/{pid}/rules", json={"level": "project", "content": "主角不许中途复活"}, ) assert resp.status_code == 201 body = resp.json() assert body["level"] == "project" assert body["content"] == "主角不许中途复活" assert session.commits == 1 assert len(repo.rows) == 1 assert repo.rows[0].project_id == pid @pytest.mark.asyncio async def test_create_rule_invalid_level_returns_422() -> None: client, _repo, _session = _make_client() pid = uuid.uuid4() async with client: resp = await client.post( f"/projects/{pid}/rules", json={"level": "nonsense", "content": "x"}, ) assert resp.status_code == 422 @pytest.mark.asyncio async def test_create_rule_empty_content_returns_422() -> None: client, _repo, _session = _make_client() pid = uuid.uuid4() async with client: resp = await client.post( f"/projects/{pid}/rules", json={"level": "global", "content": ""}, ) assert resp.status_code == 422