Merge origin/develop into feature/a-card-operations

This commit is contained in:
郑龙捷
2026-09-02 10:33:00 +08:00
73 changed files with 7177 additions and 3280 deletions
@@ -0,0 +1,39 @@
"""Unit tests for auth profile / password request schemas."""
from __future__ import annotations
import pytest
from pydantic import ValidationError
from backend.api.auth import PasswordChange, ProfileUpdate
from backend.api.platform.employees import PlatformEmployeePasswordReset
def test_profile_update_allows_partial_fields() -> None:
only_name = ProfileUpdate(display_name="张三")
assert only_name.display_name == "张三"
assert only_name.email is None
only_email = ProfileUpdate(email="a@example.com")
assert only_email.email == "a@example.com"
def test_profile_update_forbids_unknown_fields() -> None:
with pytest.raises(ValidationError):
ProfileUpdate(display_name="张三", username="hacked") # type: ignore[call-arg]
def test_password_change_enforces_new_password_length() -> None:
with pytest.raises(ValidationError):
PasswordChange(current_password="old-pass", new_password="short")
ok = PasswordChange(current_password="old-pass-1", new_password="new-pass-12")
assert ok.new_password == "new-pass-12"
def test_admin_password_reset_schema() -> None:
with pytest.raises(ValidationError):
PlatformEmployeePasswordReset(new_password="1234567")
payload = PlatformEmployeePasswordReset(new_password="reset-pass-9")
assert payload.new_password == "reset-pass-9"
+57
View File
@@ -0,0 +1,57 @@
"""Unit tests for platform cursor pagination helpers."""
from __future__ import annotations
import datetime
import pytest
from fastapi import HTTPException
from backend.api.platform._pagination import (
decode_cursor,
encode_cursor,
page_meta,
)
def test_encode_decode_roundtrip() -> None:
created_at = datetime.datetime(2026, 3, 15, 12, 30, 45, 123000)
row_id = "01HXY9C5B8N3K4P7Q6RT2V0J8D"
cursor = encode_cursor(created_at, row_id)
decoded_ts, decoded_id = decode_cursor(cursor)
assert decoded_ts == created_at
assert decoded_id == row_id
def test_decode_strips_timezone() -> None:
created_at = datetime.datetime(2026, 1, 1, 0, 0, 0, tzinfo=datetime.timezone.utc)
cursor = encode_cursor(created_at, "abc")
decoded_ts, decoded_id = decode_cursor(cursor)
assert decoded_ts.tzinfo is None
assert decoded_id == "abc"
def test_decode_invalid_cursor_raises_400() -> None:
with pytest.raises(HTTPException) as exc_info:
decode_cursor("not-a-valid-cursor!!!")
assert exc_info.value.status_code == 400
def test_page_meta_has_more() -> None:
meta = page_meta(
limit=10,
page_count=10,
total_count=25,
next_cursor="abc",
)
assert meta["has_more"] is True
assert meta["next_cursor"] == "abc"
assert meta["total_count"] == 25
meta_end = page_meta(
limit=10,
page_count=5,
total_count=25,
next_cursor=None,
)
assert meta_end["has_more"] is False