"""P1-B 回归测试: 非法 cursor → 400 + code=INVALID_CURSOR。 运行: pytest tests/test_p1_b_invalid_cursor.py -v (_parse_cursor 为纯函数,无 DB/网络依赖;HTTP 层仅测非法格式。) """ from __future__ import annotations from datetime import datetime, timezone import pytest from fastapi import HTTPException from fastapi.testclient import TestClient from src.api.app import app from src.api.deps import require_admin from src.api.routes.matches import _parse_cursor class TestParseCursorPure: """P1-B 纯函数:_parse_cursor 解析与非法校验。""" def test_valid_cursor(self): d, mid = _parse_cursor("2026-01-01T15:00:00+00:00|42") assert d == datetime(2026, 1, 1, 15, 0, tzinfo=timezone.utc) assert mid == 42 def test_missing_pipe_raises_400(self): with pytest.raises(HTTPException) as ei: _parse_cursor("no-pipe-here") assert ei.value.status_code == 400 assert ei.value.detail["code"] == "INVALID_CURSOR" def test_empty_date_raises_400(self): with pytest.raises(HTTPException) as ei: _parse_cursor("|5") assert ei.value.status_code == 400 assert ei.value.detail["code"] == "INVALID_CURSOR" def test_non_numeric_id_raises_400(self): with pytest.raises(HTTPException) as ei: _parse_cursor("2026-01-01T00:00:00+00:00|abc") assert ei.value.status_code == 400 assert ei.value.detail["code"] == "INVALID_CURSOR" def test_invalid_date_raises_400(self): with pytest.raises(HTTPException) as ei: _parse_cursor("not-a-date|1") assert ei.value.status_code == 400 assert ei.value.detail["code"] == "INVALID_CURSOR" def test_extra_pipe_raises_400(self): """含额外 | 时 id 部分为 "42|extra",int() 失败 → 400。""" with pytest.raises(HTTPException) as ei: _parse_cursor("2026-01-01T15:00:00+00:00|42|extra") assert ei.value.status_code == 400 assert ei.value.detail["code"] == "INVALID_CURSOR" class TestInvalidCursorHTTP: """P1-B HTTP 层:非法 cursor → 400 + code=INVALID_CURSOR。""" @pytest.fixture def client(self): app.dependency_overrides[require_admin] = lambda: None return TestClient(app) def test_malformed_cursor_400(self, client): resp = client.get("/api/v1/matches?cursor=garbage") assert resp.status_code == 400 assert resp.json()["detail"]["code"] == "INVALID_CURSOR" def test_missing_id_400(self, client): resp = client.get("/api/v1/matches?cursor=2026-01-01T00:00:00|") assert resp.status_code == 400 assert resp.json()["detail"]["code"] == "INVALID_CURSOR"