From a4ba46a81ab47fdec7542e7cd15ed1f0b5cd171e Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Sun, 4 Oct 2026 12:54:59 +0300 Subject: [PATCH 1/2] refactor: share message text constraints between send and edit requests --- app/schemas/api.py | 9 ++++++--- tests/test_schemas.py | 28 +++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/app/schemas/api.py b/app/schemas/api.py index 42c0c0c..b87ddef 100644 --- a/app/schemas/api.py +++ b/app/schemas/api.py @@ -1,7 +1,7 @@ import datetime import uuid from collections.abc import Iterable -from typing import Any, Self +from typing import Annotated, Any, Self import pydantic from pydantic import BaseModel, PositiveInt @@ -9,6 +9,9 @@ from app.database import tables +MessageText = Annotated[str, pydantic.Field(min_length=1, max_length=4000)] + + class Base(BaseModel): model_config = pydantic.ConfigDict(from_attributes=True) @@ -66,11 +69,11 @@ class ChatDetail(Chat): class SendMessageRequest(Base): idempotency_key: uuid.UUID - text: str = pydantic.Field(min_length=1, max_length=4000) + text: MessageText class EditMessageRequest(Base): - text: str = pydantic.Field(min_length=1, max_length=4000) + text: MessageText class Message(Base): diff --git a/tests/test_schemas.py b/tests/test_schemas.py index cfb6b81..8d251cf 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -1,4 +1,9 @@ -from app.schemas.api import Collection, User +import uuid + +import pydantic +import pytest + +from app.schemas.api import Collection, EditMessageRequest, SendMessageRequest, User from tests.factories import UserFactory @@ -6,3 +11,24 @@ def test_collection_builds_from_models() -> None: user = UserFactory.build(id=1, username="alice", display_name="Alice") collection = Collection[User].from_models([user]) assert collection.items == [User(id=1, username="alice", display_name="Alice")] + + +def _build_message_request( + model: type[SendMessageRequest | EditMessageRequest], text: str +) -> SendMessageRequest | EditMessageRequest: + return model.model_validate({"idempotency_key": uuid.uuid4(), "text": text}) + + +@pytest.mark.parametrize("model", [SendMessageRequest, EditMessageRequest]) +@pytest.mark.parametrize("text", ["", "x" * 4001], ids=["empty", "over_max"]) +def test_message_request_rejects_out_of_bounds_text( + model: type[SendMessageRequest | EditMessageRequest], text: str +) -> None: + with pytest.raises(pydantic.ValidationError): + _build_message_request(model, text) + + +@pytest.mark.parametrize("model", [SendMessageRequest, EditMessageRequest]) +def test_message_request_accepts_max_length_text(model: type[SendMessageRequest | EditMessageRequest]) -> None: + text = "x" * 4000 + assert _build_message_request(model, text).text == text From 9edbdb98f1d0c6c4b177423ccc63a621f5d58e9f Mon Sep 17 00:00:00 2001 From: Artur Shiriev Date: Sun, 4 Oct 2026 13:03:02 +0300 Subject: [PATCH 2/2] test: build each message request with only its own fields --- tests/test_schemas.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/test_schemas.py b/tests/test_schemas.py index 8d251cf..67c2a82 100644 --- a/tests/test_schemas.py +++ b/tests/test_schemas.py @@ -16,7 +16,9 @@ def test_collection_builds_from_models() -> None: def _build_message_request( model: type[SendMessageRequest | EditMessageRequest], text: str ) -> SendMessageRequest | EditMessageRequest: - return model.model_validate({"idempotency_key": uuid.uuid4(), "text": text}) + if model is SendMessageRequest: + return SendMessageRequest(idempotency_key=uuid.uuid4(), text=text) + return EditMessageRequest(text=text) @pytest.mark.parametrize("model", [SendMessageRequest, EditMessageRequest])