Jack1808/Claude_Code
0
1"""Tests for api/models/responses.py Pydantic response models."""2 3from api.models.anthropic import (4 ContentBlockText,5 ContentBlockThinking,6 ContentBlockToolUse,7)8from api.models.responses import MessagesResponse, TokenCountResponse, Usage9 10 11class TestUsage:12 """Tests for Usage model."""13 14 def test_required_fields(self):15 usage = Usage(input_tokens=10, output_tokens=20)16 assert usage.input_tokens == 1017 assert usage.output_tokens == 2018 19 def test_cache_defaults_zero(self):20 usage = Usage(input_tokens=1, output_tokens=2)21 assert usage.cache_creation_input_tokens == 022 assert usage.cache_read_input_tokens == 023 24 def test_cache_fields_set(self):25 usage = Usage(26 input_tokens=10,27 output_tokens=20,28 cache_creation_input_tokens=5,29 cache_read_input_tokens=3,30 )31 assert usage.cache_creation_input_tokens == 532 assert usage.cache_read_input_tokens == 333 34 def test_serialization(self):35 usage = Usage(input_tokens=10, output_tokens=20)36 data = usage.model_dump()37 assert data == {38 "input_tokens": 10,39 "output_tokens": 20,40 "cache_creation_input_tokens": 0,41 "cache_read_input_tokens": 0,42 }43 44 45class TestTokenCountResponse:46 """Tests for TokenCountResponse model."""47 48 def test_basic(self):49 resp = TokenCountResponse(input_tokens=42)50 assert resp.input_tokens == 4251 52 def test_serialization(self):53 resp = TokenCountResponse(input_tokens=100)54 data = resp.model_dump()55 assert data == {"input_tokens": 100}56 57 58class TestMessagesResponse:59 """Tests for MessagesResponse model."""60 61 def test_minimum_fields(self):62 resp = MessagesResponse(63 id="msg_001",64 model="test-model",65 content=[ContentBlockText(type="text", text="Hello")],66 usage=Usage(input_tokens=10, output_tokens=5),67 )68 assert resp.id == "msg_001"69 assert resp.model == "test-model"70 assert resp.role == "assistant"71 assert resp.type == "message"72 assert resp.stop_reason is None73 assert resp.stop_sequence is None74 75 def test_with_text_content(self):76 resp = MessagesResponse(77 id="msg_002",78 model="model",79 content=[ContentBlockText(type="text", text="response")],80 usage=Usage(input_tokens=1, output_tokens=1),81 )82 assert len(resp.content) == 183 block = resp.content[0]84 assert isinstance(block, ContentBlockText)85 assert block.type == "text"86 assert block.text == "response"87 88 def test_with_tool_use_content(self):89 resp = MessagesResponse(90 id="msg_003",91 model="model",92 content=[93 ContentBlockToolUse(94 type="tool_use",95 id="tool_1",96 name="Read",97 input={"path": "test.py"},98 )99 ],100 usage=Usage(input_tokens=1, output_tokens=1),101 stop_reason="tool_use",102 )103 block = resp.content[0]104 assert isinstance(block, ContentBlockToolUse)105 assert block.type == "tool_use"106 assert block.name == "Read"107 assert resp.stop_reason == "tool_use"108 109 def test_with_thinking_content(self):110 resp = MessagesResponse(111 id="msg_004",112 model="model",113 content=[114 ContentBlockThinking(type="thinking", thinking="Let me reason..."),115 ContentBlockText(type="text", text="Answer"),116 ],117 usage=Usage(input_tokens=5, output_tokens=10),118 )119 assert len(resp.content) == 2120 block0 = resp.content[0]121 assert isinstance(block0, ContentBlockThinking)122 assert block0.type == "thinking"123 assert block0.thinking == "Let me reason..."124 block1 = resp.content[1]125 assert isinstance(block1, ContentBlockText)126 assert block1.type == "text"127 128 def test_with_all_content_types(self):129 resp = MessagesResponse(130 id="msg_005",131 model="model",132 content=[133 ContentBlockThinking(type="thinking", thinking="hmm"),134 ContentBlockText(type="text", text="result"),135 ContentBlockToolUse(136 type="tool_use", id="t1", name="Bash", input={"command": "ls"}137 ),138 ],139 usage=Usage(input_tokens=10, output_tokens=20),140 stop_reason="tool_use",141 )142 assert len(resp.content) == 3143 144 def test_with_dict_content(self):145 """Dict content (unknown block type) should be accepted."""146 resp = MessagesResponse(147 id="msg_006",148 model="model",149 content=[{"type": "custom", "data": "value"}],150 usage=Usage(input_tokens=1, output_tokens=1),151 )152 block = resp.content[0]153 assert isinstance(block, dict)154 assert block["type"] == "custom"155 156 def test_stop_reason_values(self):157 """All valid stop_reason values should be accepted."""158 from typing import Literal159 160 reasons: list[161 Literal["end_turn", "max_tokens", "stop_sequence", "tool_use"]162 ] = [163 "end_turn",164 "max_tokens",165 "stop_sequence",166 "tool_use",167 ]168 for reason in reasons:169 resp = MessagesResponse(170 id="msg",171 model="model",172 content=[ContentBlockText(type="text", text="x")],173 usage=Usage(input_tokens=1, output_tokens=1),174 stop_reason=reason,175 )176 assert resp.stop_reason == reason177 178 def test_serialization_round_trip(self):179 resp = MessagesResponse(180 id="msg_rt",181 model="model-v1",182 content=[ContentBlockText(type="text", text="hello")],183 usage=Usage(input_tokens=10, output_tokens=5),184 stop_reason="end_turn",185 )186 data = resp.model_dump()187 restored = MessagesResponse(**data)188 assert restored.id == resp.id189 assert restored.model == resp.model190 assert restored.stop_reason == resp.stop_reason191 192 def test_empty_content_list(self):193 resp = MessagesResponse(194 id="msg_empty",195 model="model",196 content=[],197 usage=Usage(input_tokens=0, output_tokens=0),198 )199 assert resp.content == []200 