API / kiro-gateway /tests /unit /test_models_openai.py
sshinmen's picture
Clean deploy to HF Space
bf9e111
Raw
History Blame Contribute Delete
40.9 kB
# -*- coding: utf-8 -*-
"""
Unit tests for OpenAI Pydantic models.
Comprehensive tests for all OpenAI-compatible API models:
- Model listing (OpenAIModel, ModelList)
- Chat messages (ChatMessage)
- Tools (ToolFunction, Tool)
- Requests (ChatCompletionRequest)
- Responses (ChatCompletionChoice, ChatCompletionUsage, ChatCompletionResponse)
- Streaming (ChatCompletionChunk, ChatCompletionChunkChoice, ChatCompletionChunkDelta)
"""
import pytest
from pydantic import ValidationError
from kiro.models_openai import (
# Model listing
OpenAIModel,
ModelList,
# Chat messages
ChatMessage,
# Tools
ToolFunction,
Tool,
# Requests
ChatCompletionRequest,
# Responses
ChatCompletionChoice,
ChatCompletionUsage,
ChatCompletionResponse,
# Streaming
ChatCompletionChunkDelta,
ChatCompletionChunkChoice,
ChatCompletionChunk,
)
# ==================================================================================================
# Tests for OpenAIModel
# ==================================================================================================
class TestOpenAIModel:
"""Tests for OpenAIModel Pydantic model."""
def test_valid_model(self):
"""
What it does: Verifies creation of valid OpenAIModel.
Purpose: Ensure model accepts valid data.
"""
print("Setup: Creating OpenAIModel with valid data...")
model = OpenAIModel(
id="claude-sonnet-4-5",
description="Claude Sonnet 4.5 model"
)
print(f"Result: {model}")
print(f"Comparing id: Expected 'claude-sonnet-4-5', Got '{model.id}'")
assert model.id == "claude-sonnet-4-5"
print(f"Comparing object: Expected 'model', Got '{model.object}'")
assert model.object == "model"
print(f"Comparing owned_by: Expected 'anthropic', Got '{model.owned_by}'")
assert model.owned_by == "anthropic"
print(f"Comparing description: Got '{model.description}'")
assert model.description == "Claude Sonnet 4.5 model"
def test_requires_id(self):
"""
What it does: Verifies that id is required.
Purpose: Ensure validation fails without id.
"""
print("Setup: Attempting to create OpenAIModel without id...")
print("Action: Creating model (should raise ValidationError)...")
with pytest.raises(ValidationError) as exc_info:
OpenAIModel()
print(f"ValidationError raised: {exc_info.value}")
assert "id" in str(exc_info.value)
def test_object_defaults_to_model(self):
"""
What it does: Verifies that object defaults to "model".
Purpose: Ensure default value is set correctly.
"""
print("Setup: Creating OpenAIModel without explicit object...")
model = OpenAIModel(id="test-model")
print(f"Comparing object: Expected 'model', Got '{model.object}'")
assert model.object == "model"
def test_owned_by_defaults_to_anthropic(self):
"""
What it does: Verifies that owned_by defaults to "anthropic".
Purpose: Ensure default value is set correctly.
"""
print("Setup: Creating OpenAIModel without explicit owned_by...")
model = OpenAIModel(id="test-model")
print(f"Comparing owned_by: Expected 'anthropic', Got '{model.owned_by}'")
assert model.owned_by == "anthropic"
def test_created_is_auto_generated(self):
"""
What it does: Verifies that created timestamp is auto-generated.
Purpose: Ensure timestamp is set automatically.
"""
print("Setup: Creating OpenAIModel without explicit created...")
model = OpenAIModel(id="test-model")
print(f"Comparing created: Got {model.created}")
assert model.created > 0
assert isinstance(model.created, int)
def test_description_is_optional(self):
"""
What it does: Verifies that description is optional.
Purpose: Ensure models without description work.
"""
print("Setup: Creating OpenAIModel without description...")
model = OpenAIModel(id="test-model")
print(f"Comparing description: Expected None, Got {model.description}")
assert model.description is None
# ==================================================================================================
# Tests for ModelList
# ==================================================================================================
class TestModelList:
"""Tests for ModelList Pydantic model."""
def test_valid_model_list(self):
"""
What it does: Verifies creation of valid ModelList.
Purpose: Ensure model list accepts valid data.
"""
print("Setup: Creating ModelList with valid data...")
model_list = ModelList(
data=[
OpenAIModel(id="claude-sonnet-4-5"),
OpenAIModel(id="claude-opus-4")
]
)
print(f"Result: {model_list}")
print(f"Comparing object: Expected 'list', Got '{model_list.object}'")
assert model_list.object == "list"
print(f"Comparing data length: Expected 2, Got {len(model_list.data)}")
assert len(model_list.data) == 2
def test_object_defaults_to_list(self):
"""
What it does: Verifies that object defaults to "list".
Purpose: Ensure default value is set correctly.
"""
print("Setup: Creating ModelList without explicit object...")
model_list = ModelList(data=[])
print(f"Comparing object: Expected 'list', Got '{model_list.object}'")
assert model_list.object == "list"
def test_requires_data(self):
"""
What it does: Verifies that data is required.
Purpose: Ensure validation fails without data.
"""
print("Setup: Attempting to create ModelList without data...")
print("Action: Creating model (should raise ValidationError)...")
with pytest.raises(ValidationError) as exc_info:
ModelList()
print(f"ValidationError raised: {exc_info.value}")
assert "data" in str(exc_info.value)
def test_accepts_empty_list(self):
"""
What it does: Verifies that empty list is accepted.
Purpose: Ensure empty model list works.
"""
print("Setup: Creating ModelList with empty data...")
model_list = ModelList(data=[])
print(f"Comparing data: Expected [], Got {model_list.data}")
assert model_list.data == []
# ==================================================================================================
# Tests for ChatMessage
# ==================================================================================================
class TestChatMessage:
"""Tests for ChatMessage Pydantic model."""
def test_valid_user_message(self):
"""
What it does: Verifies creation of valid user message.
Purpose: Ensure model accepts valid user message.
"""
print("Setup: Creating ChatMessage with user role...")
message = ChatMessage(role="user", content="Hello!")
print(f"Result: {message}")
print(f"Comparing role: Expected 'user', Got '{message.role}'")
assert message.role == "user"
print(f"Comparing content: Expected 'Hello!', Got '{message.content}'")
assert message.content == "Hello!"
def test_valid_assistant_message(self):
"""
What it does: Verifies creation of valid assistant message.
Purpose: Ensure model accepts valid assistant message.
"""
print("Setup: Creating ChatMessage with assistant role...")
message = ChatMessage(role="assistant", content="Hi there!")
print(f"Result: {message}")
print(f"Comparing role: Expected 'assistant', Got '{message.role}'")
assert message.role == "assistant"
def test_valid_system_message(self):
"""
What it does: Verifies creation of valid system message.
Purpose: Ensure model accepts valid system message.
"""
print("Setup: Creating ChatMessage with system role...")
message = ChatMessage(role="system", content="You are helpful.")
print(f"Result: {message}")
print(f"Comparing role: Expected 'system', Got '{message.role}'")
assert message.role == "system"
def test_valid_tool_message(self):
"""
What it does: Verifies creation of valid tool message.
Purpose: Ensure model accepts valid tool message.
"""
print("Setup: Creating ChatMessage with tool role...")
message = ChatMessage(
role="tool",
content="Tool result",
tool_call_id="call_123"
)
print(f"Result: {message}")
print(f"Comparing role: Expected 'tool', Got '{message.role}'")
assert message.role == "tool"
print(f"Comparing tool_call_id: Expected 'call_123', Got '{message.tool_call_id}'")
assert message.tool_call_id == "call_123"
def test_requires_role(self):
"""
What it does: Verifies that role is required.
Purpose: Ensure validation fails without role.
"""
print("Setup: Attempting to create ChatMessage without role...")
print("Action: Creating model (should raise ValidationError)...")
with pytest.raises(ValidationError) as exc_info:
ChatMessage(content="Hello")
print(f"ValidationError raised: {exc_info.value}")
assert "role" in str(exc_info.value)
def test_content_is_optional(self):
"""
What it does: Verifies that content is optional.
Purpose: Ensure messages without content work (e.g., tool calls).
"""
print("Setup: Creating ChatMessage without content...")
message = ChatMessage(role="assistant")
print(f"Comparing content: Expected None, Got {message.content}")
assert message.content is None
def test_accepts_list_content(self):
"""
What it does: Verifies that list content is accepted.
Purpose: Ensure multimodal content works.
"""
print("Setup: Creating ChatMessage with list content...")
message = ChatMessage(
role="user",
content=[
{"type": "text", "text": "What's in this image?"},
{"type": "image_url", "image_url": {"url": "https://example.com/img.jpg"}}
]
)
print(f"Result: {message}")
print(f"Comparing content type: Expected list, Got {type(message.content)}")
assert isinstance(message.content, list)
assert len(message.content) == 2
def test_accepts_tool_calls(self):
"""
What it does: Verifies that tool_calls is accepted.
Purpose: Ensure assistant messages with tool calls work.
"""
print("Setup: Creating ChatMessage with tool_calls...")
message = ChatMessage(
role="assistant",
content="I'll call a tool",
tool_calls=[{
"id": "call_123",
"type": "function",
"function": {"name": "get_weather", "arguments": '{"location": "Moscow"}'}
}]
)
print(f"Result: {message}")
print(f"Comparing tool_calls: Got {message.tool_calls}")
assert message.tool_calls is not None
assert len(message.tool_calls) == 1
def test_name_is_optional(self):
"""
What it does: Verifies that name is optional.
Purpose: Ensure messages without name work.
"""
print("Setup: Creating ChatMessage without name...")
message = ChatMessage(role="user", content="Hello")
print(f"Comparing name: Expected None, Got {message.name}")
assert message.name is None
def test_accepts_name(self):
"""
What it does: Verifies that name is accepted.
Purpose: Ensure named messages work.
"""
print("Setup: Creating ChatMessage with name...")
message = ChatMessage(role="user", content="Hello", name="John")
print(f"Comparing name: Expected 'John', Got '{message.name}'")
assert message.name == "John"
def test_extra_fields_allowed(self):
"""
What it does: Verifies that extra fields are allowed.
Purpose: Ensure model_config extra="allow" works.
"""
print("Setup: Creating ChatMessage with extra field...")
message = ChatMessage(role="user", content="Hello", custom_field="value")
print(f"Comparing custom_field: Got '{message.custom_field}'")
assert message.custom_field == "value"
# ==================================================================================================
# Tests for ToolFunction
# ==================================================================================================
class TestToolFunction:
"""Tests for ToolFunction Pydantic model."""
def test_valid_tool_function(self):
"""
What it does: Verifies creation of valid ToolFunction.
Purpose: Ensure model accepts valid tool function.
"""
print("Setup: Creating ToolFunction with valid data...")
func = ToolFunction(
name="get_weather",
description="Get weather for a location",
parameters={
"type": "object",
"properties": {"location": {"type": "string"}}
}
)
print(f"Result: {func}")
print(f"Comparing name: Expected 'get_weather', Got '{func.name}'")
assert func.name == "get_weather"
print(f"Comparing description: Got '{func.description}'")
assert func.description == "Get weather for a location"
print(f"Comparing parameters: Got {func.parameters}")
assert "properties" in func.parameters
def test_requires_name(self):
"""
What it does: Verifies that name is required.
Purpose: Ensure validation fails without name.
"""
print("Setup: Attempting to create ToolFunction without name...")
print("Action: Creating model (should raise ValidationError)...")
with pytest.raises(ValidationError) as exc_info:
ToolFunction(description="Test")
print(f"ValidationError raised: {exc_info.value}")
assert "name" in str(exc_info.value)
def test_description_is_optional(self):
"""
What it does: Verifies that description is optional.
Purpose: Ensure functions without description work.
"""
print("Setup: Creating ToolFunction without description...")
func = ToolFunction(name="test_func")
print(f"Comparing description: Expected None, Got {func.description}")
assert func.description is None
def test_parameters_is_optional(self):
"""
What it does: Verifies that parameters is optional.
Purpose: Ensure functions without parameters work.
"""
print("Setup: Creating ToolFunction without parameters...")
func = ToolFunction(name="no_params_func")
print(f"Comparing parameters: Expected None, Got {func.parameters}")
assert func.parameters is None
# ==================================================================================================
# Tests for Tool
# ==================================================================================================
class TestTool:
"""Tests for Tool Pydantic model."""
def test_valid_tool(self):
"""
What it does: Verifies creation of valid Tool.
Purpose: Ensure model accepts valid tool.
"""
print("Setup: Creating Tool with valid data...")
tool = Tool(
type="function",
function=ToolFunction(
name="get_weather",
description="Get weather",
parameters={}
)
)
print(f"Result: {tool}")
print(f"Comparing type: Expected 'function', Got '{tool.type}'")
assert tool.type == "function"
print(f"Comparing function.name: Expected 'get_weather', Got '{tool.function.name}'")
assert tool.function.name == "get_weather"
def test_type_defaults_to_function(self):
"""
What it does: Verifies that type defaults to "function".
Purpose: Ensure default value is set correctly.
"""
print("Setup: Creating Tool without explicit type...")
tool = Tool(function=ToolFunction(name="test"))
print(f"Comparing type: Expected 'function', Got '{tool.type}'")
assert tool.type == "function"
def test_function_is_optional_for_flat_format(self):
"""
What it does: Verifies that function is optional (for flat format compatibility).
Purpose: Ensure flat format (Cursor-style) is supported without function field.
"""
print("Setup: Creating Tool with flat format (name, description, input_schema)...")
tool = Tool(
type="function",
name="test_tool",
description="A test tool",
input_schema={"type": "object", "properties": {}}
)
print(f"Result: {tool}")
print(f"Comparing name: Expected 'test_tool', Got '{tool.name}'")
assert tool.name == "test_tool"
print(f"Comparing function: Expected None, Got {tool.function}")
assert tool.function is None
print(f"Comparing description: Expected 'A test tool', Got '{tool.description}'")
assert tool.description == "A test tool"
def test_standard_format_still_works(self):
"""
What it does: Verifies that standard OpenAI format still works.
Purpose: Ensure backward compatibility with standard format.
"""
print("Setup: Creating Tool with standard OpenAI format (function field)...")
tool = Tool(
type="function",
function=ToolFunction(name="standard_tool", description="Standard")
)
print(f"Result: {tool}")
print(f"Comparing function.name: Expected 'standard_tool', Got '{tool.function.name}'")
assert tool.function.name == "standard_tool"
print(f"Comparing name: Expected None, Got {tool.name}")
assert tool.name is None
# ==================================================================================================
# Tests for ChatCompletionRequest
# ==================================================================================================
class TestChatCompletionRequest:
"""Tests for ChatCompletionRequest Pydantic model."""
def test_valid_request(self):
"""
What it does: Verifies creation of valid ChatCompletionRequest.
Purpose: Ensure model accepts valid request.
"""
print("Setup: Creating ChatCompletionRequest with valid data...")
request = ChatCompletionRequest(
model="claude-sonnet-4-5",
messages=[ChatMessage(role="user", content="Hello")]
)
print(f"Result: {request}")
print(f"Comparing model: Expected 'claude-sonnet-4-5', Got '{request.model}'")
assert request.model == "claude-sonnet-4-5"
print(f"Comparing messages length: Expected 1, Got {len(request.messages)}")
assert len(request.messages) == 1
print(f"Comparing stream: Expected False, Got {request.stream}")
assert request.stream is False
def test_requires_model(self):
"""
What it does: Verifies that model is required.
Purpose: Ensure validation fails without model.
"""
print("Setup: Attempting to create ChatCompletionRequest without model...")
print("Action: Creating model (should raise ValidationError)...")
with pytest.raises(ValidationError) as exc_info:
ChatCompletionRequest(messages=[ChatMessage(role="user", content="Hi")])
print(f"ValidationError raised: {exc_info.value}")
assert "model" in str(exc_info.value)
def test_requires_messages(self):
"""
What it does: Verifies that messages is required.
Purpose: Ensure validation fails without messages.
"""
print("Setup: Attempting to create ChatCompletionRequest without messages...")
print("Action: Creating model (should raise ValidationError)...")
with pytest.raises(ValidationError) as exc_info:
ChatCompletionRequest(model="claude-sonnet-4-5")
print(f"ValidationError raised: {exc_info.value}")
assert "messages" in str(exc_info.value)
def test_requires_at_least_one_message(self):
"""
What it does: Verifies that at least one message is required.
Purpose: Ensure validation fails with empty messages.
"""
print("Setup: Attempting to create ChatCompletionRequest with empty messages...")
print("Action: Creating model (should raise ValidationError)...")
with pytest.raises(ValidationError) as exc_info:
ChatCompletionRequest(model="claude-sonnet-4-5", messages=[])
print(f"ValidationError raised: {exc_info.value}")
def test_stream_defaults_to_false(self):
"""
What it does: Verifies that stream defaults to False.
Purpose: Ensure default value is set correctly.
"""
print("Setup: Creating ChatCompletionRequest without explicit stream...")
request = ChatCompletionRequest(
model="test",
messages=[ChatMessage(role="user", content="Hi")]
)
print(f"Comparing stream: Expected False, Got {request.stream}")
assert request.stream is False
def test_accepts_stream_true(self):
"""
What it does: Verifies that stream=True is accepted.
Purpose: Ensure streaming requests work.
"""
print("Setup: Creating ChatCompletionRequest with stream=True...")
request = ChatCompletionRequest(
model="test",
messages=[ChatMessage(role="user", content="Hi")],
stream=True
)
print(f"Comparing stream: Expected True, Got {request.stream}")
assert request.stream is True
def test_accepts_tools(self):
"""
What it does: Verifies that tools are accepted.
Purpose: Ensure function calling works.
"""
print("Setup: Creating ChatCompletionRequest with tools...")
request = ChatCompletionRequest(
model="test",
messages=[ChatMessage(role="user", content="Hi")],
tools=[Tool(function=ToolFunction(name="test_tool"))]
)
print(f"Comparing tools: Got {request.tools}")
assert request.tools is not None
assert len(request.tools) == 1
def test_accepts_generation_parameters(self):
"""
What it does: Verifies that generation parameters are accepted.
Purpose: Ensure temperature, top_p, max_tokens work.
"""
print("Setup: Creating ChatCompletionRequest with generation params...")
request = ChatCompletionRequest(
model="test",
messages=[ChatMessage(role="user", content="Hi")],
temperature=0.7,
top_p=0.9,
max_tokens=1000
)
print(f"Comparing temperature: Expected 0.7, Got {request.temperature}")
assert request.temperature == 0.7
print(f"Comparing top_p: Expected 0.9, Got {request.top_p}")
assert request.top_p == 0.9
print(f"Comparing max_tokens: Expected 1000, Got {request.max_tokens}")
assert request.max_tokens == 1000
# ==================================================================================================
# Tests for ChatCompletionUsage
# ==================================================================================================
class TestChatCompletionUsage:
"""Tests for ChatCompletionUsage Pydantic model."""
def test_valid_usage(self):
"""
What it does: Verifies creation of valid ChatCompletionUsage.
Purpose: Ensure model accepts valid usage data.
"""
print("Setup: Creating ChatCompletionUsage with valid data...")
usage = ChatCompletionUsage(
prompt_tokens=100,
completion_tokens=50,
total_tokens=150
)
print(f"Result: {usage}")
print(f"Comparing prompt_tokens: Expected 100, Got {usage.prompt_tokens}")
assert usage.prompt_tokens == 100
print(f"Comparing completion_tokens: Expected 50, Got {usage.completion_tokens}")
assert usage.completion_tokens == 50
print(f"Comparing total_tokens: Expected 150, Got {usage.total_tokens}")
assert usage.total_tokens == 150
def test_defaults_to_zero(self):
"""
What it does: Verifies that all fields default to 0.
Purpose: Ensure default values are set correctly.
"""
print("Setup: Creating ChatCompletionUsage without explicit values...")
usage = ChatCompletionUsage()
print(f"Comparing prompt_tokens: Expected 0, Got {usage.prompt_tokens}")
assert usage.prompt_tokens == 0
print(f"Comparing completion_tokens: Expected 0, Got {usage.completion_tokens}")
assert usage.completion_tokens == 0
print(f"Comparing total_tokens: Expected 0, Got {usage.total_tokens}")
assert usage.total_tokens == 0
def test_credits_used_is_optional(self):
"""
What it does: Verifies that credits_used is optional.
Purpose: Ensure Kiro-specific field is optional.
"""
print("Setup: Creating ChatCompletionUsage without credits_used...")
usage = ChatCompletionUsage()
print(f"Comparing credits_used: Expected None, Got {usage.credits_used}")
assert usage.credits_used is None
# ==================================================================================================
# Tests for ChatCompletionChoice
# ==================================================================================================
class TestChatCompletionChoice:
"""Tests for ChatCompletionChoice Pydantic model."""
def test_valid_choice(self):
"""
What it does: Verifies creation of valid ChatCompletionChoice.
Purpose: Ensure model accepts valid choice data.
"""
print("Setup: Creating ChatCompletionChoice with valid data...")
choice = ChatCompletionChoice(
index=0,
message={"role": "assistant", "content": "Hello!"},
finish_reason="stop"
)
print(f"Result: {choice}")
print(f"Comparing index: Expected 0, Got {choice.index}")
assert choice.index == 0
print(f"Comparing message: Got {choice.message}")
assert choice.message["role"] == "assistant"
print(f"Comparing finish_reason: Expected 'stop', Got '{choice.finish_reason}'")
assert choice.finish_reason == "stop"
def test_index_defaults_to_zero(self):
"""
What it does: Verifies that index defaults to 0.
Purpose: Ensure default value is set correctly.
"""
print("Setup: Creating ChatCompletionChoice without explicit index...")
choice = ChatCompletionChoice(message={"role": "assistant", "content": "Hi"})
print(f"Comparing index: Expected 0, Got {choice.index}")
assert choice.index == 0
def test_requires_message(self):
"""
What it does: Verifies that message is required.
Purpose: Ensure validation fails without message.
"""
print("Setup: Attempting to create ChatCompletionChoice without message...")
print("Action: Creating model (should raise ValidationError)...")
with pytest.raises(ValidationError) as exc_info:
ChatCompletionChoice(index=0, finish_reason="stop")
print(f"ValidationError raised: {exc_info.value}")
assert "message" in str(exc_info.value)
def test_finish_reason_is_optional(self):
"""
What it does: Verifies that finish_reason is optional.
Purpose: Ensure choices without finish_reason work.
"""
print("Setup: Creating ChatCompletionChoice without finish_reason...")
choice = ChatCompletionChoice(message={"role": "assistant", "content": "Hi"})
print(f"Comparing finish_reason: Expected None, Got {choice.finish_reason}")
assert choice.finish_reason is None
# ==================================================================================================
# Tests for ChatCompletionResponse
# ==================================================================================================
class TestChatCompletionResponse:
"""Tests for ChatCompletionResponse Pydantic model."""
def test_valid_response(self):
"""
What it does: Verifies creation of valid ChatCompletionResponse.
Purpose: Ensure model accepts valid response data.
"""
print("Setup: Creating ChatCompletionResponse with valid data...")
response = ChatCompletionResponse(
id="chatcmpl-123",
model="claude-sonnet-4-5",
choices=[ChatCompletionChoice(
message={"role": "assistant", "content": "Hello!"},
finish_reason="stop"
)],
usage=ChatCompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=15)
)
print(f"Result: {response}")
print(f"Comparing id: Expected 'chatcmpl-123', Got '{response.id}'")
assert response.id == "chatcmpl-123"
print(f"Comparing object: Expected 'chat.completion', Got '{response.object}'")
assert response.object == "chat.completion"
print(f"Comparing model: Expected 'claude-sonnet-4-5', Got '{response.model}'")
assert response.model == "claude-sonnet-4-5"
print(f"Comparing choices length: Expected 1, Got {len(response.choices)}")
assert len(response.choices) == 1
def test_object_defaults_to_chat_completion(self):
"""
What it does: Verifies that object defaults to "chat.completion".
Purpose: Ensure default value is set correctly.
"""
print("Setup: Creating ChatCompletionResponse without explicit object...")
response = ChatCompletionResponse(
id="test",
model="test",
choices=[ChatCompletionChoice(message={"role": "assistant", "content": "Hi"})],
usage=ChatCompletionUsage()
)
print(f"Comparing object: Expected 'chat.completion', Got '{response.object}'")
assert response.object == "chat.completion"
def test_created_is_auto_generated(self):
"""
What it does: Verifies that created timestamp is auto-generated.
Purpose: Ensure timestamp is set automatically.
"""
print("Setup: Creating ChatCompletionResponse without explicit created...")
response = ChatCompletionResponse(
id="test",
model="test",
choices=[ChatCompletionChoice(message={"role": "assistant", "content": "Hi"})],
usage=ChatCompletionUsage()
)
print(f"Comparing created: Got {response.created}")
assert response.created > 0
assert isinstance(response.created, int)
def test_requires_id(self):
"""
What it does: Verifies that id is required.
Purpose: Ensure validation fails without id.
"""
print("Setup: Attempting to create ChatCompletionResponse without id...")
print("Action: Creating model (should raise ValidationError)...")
with pytest.raises(ValidationError) as exc_info:
ChatCompletionResponse(
model="test",
choices=[ChatCompletionChoice(message={"role": "assistant", "content": "Hi"})],
usage=ChatCompletionUsage()
)
print(f"ValidationError raised: {exc_info.value}")
assert "id" in str(exc_info.value)
# ==================================================================================================
# Tests for Streaming Models
# ==================================================================================================
class TestChatCompletionChunkDelta:
"""Tests for ChatCompletionChunkDelta Pydantic model."""
def test_valid_delta_with_content(self):
"""
What it does: Verifies creation of valid delta with content.
Purpose: Ensure model accepts content delta.
"""
print("Setup: Creating ChatCompletionChunkDelta with content...")
delta = ChatCompletionChunkDelta(content="Hello")
print(f"Result: {delta}")
print(f"Comparing content: Expected 'Hello', Got '{delta.content}'")
assert delta.content == "Hello"
def test_valid_delta_with_role(self):
"""
What it does: Verifies creation of valid delta with role.
Purpose: Ensure model accepts role delta (first chunk).
"""
print("Setup: Creating ChatCompletionChunkDelta with role...")
delta = ChatCompletionChunkDelta(role="assistant")
print(f"Result: {delta}")
print(f"Comparing role: Expected 'assistant', Got '{delta.role}'")
assert delta.role == "assistant"
def test_all_fields_optional(self):
"""
What it does: Verifies that all fields are optional.
Purpose: Ensure empty delta works.
"""
print("Setup: Creating empty ChatCompletionChunkDelta...")
delta = ChatCompletionChunkDelta()
print(f"Comparing role: Expected None, Got {delta.role}")
assert delta.role is None
print(f"Comparing content: Expected None, Got {delta.content}")
assert delta.content is None
print(f"Comparing tool_calls: Expected None, Got {delta.tool_calls}")
assert delta.tool_calls is None
def test_accepts_tool_calls(self):
"""
What it does: Verifies that tool_calls is accepted.
Purpose: Ensure streaming tool calls work.
"""
print("Setup: Creating ChatCompletionChunkDelta with tool_calls...")
delta = ChatCompletionChunkDelta(
tool_calls=[{"index": 0, "id": "call_1", "function": {"name": "test"}}]
)
print(f"Comparing tool_calls: Got {delta.tool_calls}")
assert delta.tool_calls is not None
assert len(delta.tool_calls) == 1
class TestChatCompletionChunkChoice:
"""Tests for ChatCompletionChunkChoice Pydantic model."""
def test_valid_chunk_choice(self):
"""
What it does: Verifies creation of valid chunk choice.
Purpose: Ensure model accepts valid chunk choice.
"""
print("Setup: Creating ChatCompletionChunkChoice with valid data...")
choice = ChatCompletionChunkChoice(
index=0,
delta=ChatCompletionChunkDelta(content="Hello")
)
print(f"Result: {choice}")
print(f"Comparing index: Expected 0, Got {choice.index}")
assert choice.index == 0
print(f"Comparing delta.content: Expected 'Hello', Got '{choice.delta.content}'")
assert choice.delta.content == "Hello"
def test_index_defaults_to_zero(self):
"""
What it does: Verifies that index defaults to 0.
Purpose: Ensure default value is set correctly.
"""
print("Setup: Creating ChatCompletionChunkChoice without explicit index...")
choice = ChatCompletionChunkChoice(delta=ChatCompletionChunkDelta())
print(f"Comparing index: Expected 0, Got {choice.index}")
assert choice.index == 0
def test_finish_reason_is_optional(self):
"""
What it does: Verifies that finish_reason is optional.
Purpose: Ensure intermediate chunks work.
"""
print("Setup: Creating ChatCompletionChunkChoice without finish_reason...")
choice = ChatCompletionChunkChoice(delta=ChatCompletionChunkDelta(content="Hi"))
print(f"Comparing finish_reason: Expected None, Got {choice.finish_reason}")
assert choice.finish_reason is None
def test_accepts_finish_reason(self):
"""
What it does: Verifies that finish_reason is accepted.
Purpose: Ensure final chunk works.
"""
print("Setup: Creating ChatCompletionChunkChoice with finish_reason...")
choice = ChatCompletionChunkChoice(
delta=ChatCompletionChunkDelta(),
finish_reason="stop"
)
print(f"Comparing finish_reason: Expected 'stop', Got '{choice.finish_reason}'")
assert choice.finish_reason == "stop"
class TestChatCompletionChunk:
"""Tests for ChatCompletionChunk Pydantic model."""
def test_valid_chunk(self):
"""
What it does: Verifies creation of valid chunk.
Purpose: Ensure model accepts valid chunk data.
"""
print("Setup: Creating ChatCompletionChunk with valid data...")
chunk = ChatCompletionChunk(
id="chatcmpl-123",
model="claude-sonnet-4-5",
choices=[ChatCompletionChunkChoice(
delta=ChatCompletionChunkDelta(content="Hello")
)]
)
print(f"Result: {chunk}")
print(f"Comparing id: Expected 'chatcmpl-123', Got '{chunk.id}'")
assert chunk.id == "chatcmpl-123"
print(f"Comparing object: Expected 'chat.completion.chunk', Got '{chunk.object}'")
assert chunk.object == "chat.completion.chunk"
print(f"Comparing model: Expected 'claude-sonnet-4-5', Got '{chunk.model}'")
assert chunk.model == "claude-sonnet-4-5"
def test_object_defaults_to_chunk(self):
"""
What it does: Verifies that object defaults to "chat.completion.chunk".
Purpose: Ensure default value is set correctly.
"""
print("Setup: Creating ChatCompletionChunk without explicit object...")
chunk = ChatCompletionChunk(
id="test",
model="test",
choices=[ChatCompletionChunkChoice(delta=ChatCompletionChunkDelta())]
)
print(f"Comparing object: Expected 'chat.completion.chunk', Got '{chunk.object}'")
assert chunk.object == "chat.completion.chunk"
def test_usage_is_optional(self):
"""
What it does: Verifies that usage is optional.
Purpose: Ensure intermediate chunks work without usage.
"""
print("Setup: Creating ChatCompletionChunk without usage...")
chunk = ChatCompletionChunk(
id="test",
model="test",
choices=[ChatCompletionChunkChoice(delta=ChatCompletionChunkDelta())]
)
print(f"Comparing usage: Expected None, Got {chunk.usage}")
assert chunk.usage is None
def test_accepts_usage(self):
"""
What it does: Verifies that usage is accepted.
Purpose: Ensure final chunk with usage works.
"""
print("Setup: Creating ChatCompletionChunk with usage...")
chunk = ChatCompletionChunk(
id="test",
model="test",
choices=[ChatCompletionChunkChoice(
delta=ChatCompletionChunkDelta(),
finish_reason="stop"
)],
usage=ChatCompletionUsage(prompt_tokens=10, completion_tokens=5, total_tokens=15)
)
print(f"Comparing usage: Got {chunk.usage}")
assert chunk.usage is not None
assert chunk.usage.total_tokens == 15