mirror of
https://github.com/Alishahryar1/free-claude-code.git
synced 2026-04-30 04:20:04 +00:00
Phase 7: Directory restructuring (messaging/ and tests/)
- Create messaging/platforms/ (base, discord, telegram, factory) - Create messaging/rendering/ (discord_markdown, telegram_markdown) - Create messaging/trees/ (data, repository, processor, queue_manager) - Organize tests/ into api/, providers/, messaging/, cli/, config/ - Add backward-compatible re-exports at old locations - Update handler.py and test_messaging_factory.py imports - Fix Telegram type hints for TELEGRAM_AVAILABLE=False case - Fix Python 3 except syntax in discord_markdown Co-authored-by: Ali Khokhar <alishahryar2@gmail.com>
This commit is contained in:
parent
38a7980546
commit
4b4f87515d
76 changed files with 3294 additions and 3124 deletions
199
tests/api/test_response_models.py
Normal file
199
tests/api/test_response_models.py
Normal file
|
|
@ -0,0 +1,199 @@
|
|||
"""Tests for api/models/responses.py Pydantic response models."""
|
||||
|
||||
from api.models.responses import MessagesResponse, Usage, TokenCountResponse
|
||||
from api.models.anthropic import (
|
||||
ContentBlockText,
|
||||
ContentBlockToolUse,
|
||||
ContentBlockThinking,
|
||||
)
|
||||
|
||||
|
||||
class TestUsage:
|
||||
"""Tests for Usage model."""
|
||||
|
||||
def test_required_fields(self):
|
||||
usage = Usage(input_tokens=10, output_tokens=20)
|
||||
assert usage.input_tokens == 10
|
||||
assert usage.output_tokens == 20
|
||||
|
||||
def test_cache_defaults_zero(self):
|
||||
usage = Usage(input_tokens=1, output_tokens=2)
|
||||
assert usage.cache_creation_input_tokens == 0
|
||||
assert usage.cache_read_input_tokens == 0
|
||||
|
||||
def test_cache_fields_set(self):
|
||||
usage = Usage(
|
||||
input_tokens=10,
|
||||
output_tokens=20,
|
||||
cache_creation_input_tokens=5,
|
||||
cache_read_input_tokens=3,
|
||||
)
|
||||
assert usage.cache_creation_input_tokens == 5
|
||||
assert usage.cache_read_input_tokens == 3
|
||||
|
||||
def test_serialization(self):
|
||||
usage = Usage(input_tokens=10, output_tokens=20)
|
||||
data = usage.model_dump()
|
||||
assert data == {
|
||||
"input_tokens": 10,
|
||||
"output_tokens": 20,
|
||||
"cache_creation_input_tokens": 0,
|
||||
"cache_read_input_tokens": 0,
|
||||
}
|
||||
|
||||
|
||||
class TestTokenCountResponse:
|
||||
"""Tests for TokenCountResponse model."""
|
||||
|
||||
def test_basic(self):
|
||||
resp = TokenCountResponse(input_tokens=42)
|
||||
assert resp.input_tokens == 42
|
||||
|
||||
def test_serialization(self):
|
||||
resp = TokenCountResponse(input_tokens=100)
|
||||
data = resp.model_dump()
|
||||
assert data == {"input_tokens": 100}
|
||||
|
||||
|
||||
class TestMessagesResponse:
|
||||
"""Tests for MessagesResponse model."""
|
||||
|
||||
def test_minimum_fields(self):
|
||||
resp = MessagesResponse(
|
||||
id="msg_001",
|
||||
model="test-model",
|
||||
content=[ContentBlockText(type="text", text="Hello")],
|
||||
usage=Usage(input_tokens=10, output_tokens=5),
|
||||
)
|
||||
assert resp.id == "msg_001"
|
||||
assert resp.model == "test-model"
|
||||
assert resp.role == "assistant"
|
||||
assert resp.type == "message"
|
||||
assert resp.stop_reason is None
|
||||
assert resp.stop_sequence is None
|
||||
|
||||
def test_with_text_content(self):
|
||||
resp = MessagesResponse(
|
||||
id="msg_002",
|
||||
model="model",
|
||||
content=[ContentBlockText(type="text", text="response")],
|
||||
usage=Usage(input_tokens=1, output_tokens=1),
|
||||
)
|
||||
assert len(resp.content) == 1
|
||||
block = resp.content[0]
|
||||
assert isinstance(block, ContentBlockText)
|
||||
assert block.type == "text"
|
||||
assert block.text == "response"
|
||||
|
||||
def test_with_tool_use_content(self):
|
||||
resp = MessagesResponse(
|
||||
id="msg_003",
|
||||
model="model",
|
||||
content=[
|
||||
ContentBlockToolUse(
|
||||
type="tool_use",
|
||||
id="tool_1",
|
||||
name="Read",
|
||||
input={"path": "test.py"},
|
||||
)
|
||||
],
|
||||
usage=Usage(input_tokens=1, output_tokens=1),
|
||||
stop_reason="tool_use",
|
||||
)
|
||||
block = resp.content[0]
|
||||
assert isinstance(block, ContentBlockToolUse)
|
||||
assert block.type == "tool_use"
|
||||
assert block.name == "Read"
|
||||
assert resp.stop_reason == "tool_use"
|
||||
|
||||
def test_with_thinking_content(self):
|
||||
resp = MessagesResponse(
|
||||
id="msg_004",
|
||||
model="model",
|
||||
content=[
|
||||
ContentBlockThinking(type="thinking", thinking="Let me reason..."),
|
||||
ContentBlockText(type="text", text="Answer"),
|
||||
],
|
||||
usage=Usage(input_tokens=5, output_tokens=10),
|
||||
)
|
||||
assert len(resp.content) == 2
|
||||
block0 = resp.content[0]
|
||||
assert isinstance(block0, ContentBlockThinking)
|
||||
assert block0.type == "thinking"
|
||||
assert block0.thinking == "Let me reason..."
|
||||
block1 = resp.content[1]
|
||||
assert isinstance(block1, ContentBlockText)
|
||||
assert block1.type == "text"
|
||||
|
||||
def test_with_all_content_types(self):
|
||||
resp = MessagesResponse(
|
||||
id="msg_005",
|
||||
model="model",
|
||||
content=[
|
||||
ContentBlockThinking(type="thinking", thinking="hmm"),
|
||||
ContentBlockText(type="text", text="result"),
|
||||
ContentBlockToolUse(
|
||||
type="tool_use", id="t1", name="Bash", input={"command": "ls"}
|
||||
),
|
||||
],
|
||||
usage=Usage(input_tokens=10, output_tokens=20),
|
||||
stop_reason="tool_use",
|
||||
)
|
||||
assert len(resp.content) == 3
|
||||
|
||||
def test_with_dict_content(self):
|
||||
"""Dict content (unknown block type) should be accepted."""
|
||||
resp = MessagesResponse(
|
||||
id="msg_006",
|
||||
model="model",
|
||||
content=[{"type": "custom", "data": "value"}],
|
||||
usage=Usage(input_tokens=1, output_tokens=1),
|
||||
)
|
||||
block = resp.content[0]
|
||||
assert isinstance(block, dict)
|
||||
assert block["type"] == "custom"
|
||||
|
||||
def test_stop_reason_values(self):
|
||||
"""All valid stop_reason values should be accepted."""
|
||||
from typing import Literal
|
||||
|
||||
reasons: list[
|
||||
Literal["end_turn", "max_tokens", "stop_sequence", "tool_use"]
|
||||
] = [
|
||||
"end_turn",
|
||||
"max_tokens",
|
||||
"stop_sequence",
|
||||
"tool_use",
|
||||
]
|
||||
for reason in reasons:
|
||||
resp = MessagesResponse(
|
||||
id="msg",
|
||||
model="model",
|
||||
content=[ContentBlockText(type="text", text="x")],
|
||||
usage=Usage(input_tokens=1, output_tokens=1),
|
||||
stop_reason=reason,
|
||||
)
|
||||
assert resp.stop_reason == reason
|
||||
|
||||
def test_serialization_round_trip(self):
|
||||
resp = MessagesResponse(
|
||||
id="msg_rt",
|
||||
model="model-v1",
|
||||
content=[ContentBlockText(type="text", text="hello")],
|
||||
usage=Usage(input_tokens=10, output_tokens=5),
|
||||
stop_reason="end_turn",
|
||||
)
|
||||
data = resp.model_dump()
|
||||
restored = MessagesResponse(**data)
|
||||
assert restored.id == resp.id
|
||||
assert restored.model == resp.model
|
||||
assert restored.stop_reason == resp.stop_reason
|
||||
|
||||
def test_empty_content_list(self):
|
||||
resp = MessagesResponse(
|
||||
id="msg_empty",
|
||||
model="model",
|
||||
content=[],
|
||||
usage=Usage(input_tokens=0, output_tokens=0),
|
||||
)
|
||||
assert resp.content == []
|
||||
Loading…
Add table
Add a link
Reference in a new issue