mirror of
https://github.com/Alishahryar1/free-claude-code.git
synced 2026-04-28 19:40:54 +00:00
199 lines
6.5 KiB
Python
199 lines
6.5 KiB
Python
"""Tests for api/models/responses.py Pydantic response models."""
|
|
|
|
from api.models.anthropic import (
|
|
ContentBlockText,
|
|
ContentBlockThinking,
|
|
ContentBlockToolUse,
|
|
)
|
|
from api.models.responses import MessagesResponse, TokenCountResponse, Usage
|
|
|
|
|
|
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 == []
|