Python: Track and enforce 85%+ unit test coverage for anthropic package (#3926)

* Initial plan

* Add initial coverage tests for anthropic package

Co-authored-by: TaoChenOSU <12570346+TaoChenOSU@users.noreply.github.com>

* Achieve 89% test coverage for anthropic package and enforce in CI

Co-authored-by: TaoChenOSU <12570346+TaoChenOSU@users.noreply.github.com>

* Address code review feedback - fix async tests and add constants

Co-authored-by: TaoChenOSU <12570346+TaoChenOSU@users.noreply.github.com>

* Format code with ruff to pass pre-commit checks

Co-authored-by: TaoChenOSU <12570346+TaoChenOSU@users.noreply.github.com>

* Split coverage tests into multiple focused test files

Co-authored-by: TaoChenOSU <12570346+TaoChenOSU@users.noreply.github.com>

* Fix test imports - move helpers to conftest.py for proper pytest discovery

Co-authored-by: TaoChenOSU <12570346+TaoChenOSU@users.noreply.github.com>

* Fix test imports and mock attributes - move helpers to each file, fix mock data

Co-authored-by: TaoChenOSU <12570346+TaoChenOSU@users.noreply.github.com>

* Fix text editor error mock to use error_code attribute

Co-authored-by: TaoChenOSU <12570346+TaoChenOSU@users.noreply.github.com>

* Consolidate all tests into test_anthropic_client.py - remove separate test files

Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>

* Remove accidentally committed .orig file

Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>

* Remove temporary .gitignore file

Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: TaoChenOSU <12570346+TaoChenOSU@users.noreply.github.com>
Co-authored-by: eavanvalkenburg <13749212+eavanvalkenburg@users.noreply.github.com>
This commit is contained in:
Copilot
2026-02-17 19:22:58 +00:00
committed by GitHub
Unverified
parent 09b219c009
commit a37f27b475
2 changed files with 967 additions and 9 deletions
@@ -21,11 +21,14 @@ from anthropic.types.beta import (
BetaToolUseBlock,
BetaUsage,
)
from pydantic import Field
from pydantic import BaseModel, Field
from agent_framework_anthropic import AnthropicClient
from agent_framework_anthropic._chat_client import AnthropicSettings
# Test constants
VALID_PNG_BASE64 = b"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=="
skip_if_anthropic_integration_tests_disabled = pytest.mark.skipif(
os.getenv("RUN_INTEGRATION_TESTS", "false").lower() != "true"
or os.getenv("ANTHROPIC_API_KEY", "") in ("", "test-api-key-12345"),
@@ -895,3 +898,944 @@ async def test_anthropic_client_integration_images() -> None:
assert response is not None
assert response.messages[0].text is not None
assert "house" in response.messages[0].text.lower()
# Response Format Tests
def test_prepare_response_format_openai_style(mock_anthropic_client: MagicMock) -> None:
"""Test response_format with OpenAI-style json_schema."""
client = create_test_anthropic_client(mock_anthropic_client)
response_format = {
"json_schema": {
"schema": {
"type": "object",
"properties": {"name": {"type": "string"}},
}
}
}
result = client._prepare_response_format(response_format)
assert result["type"] == "json_schema"
assert result["schema"]["additionalProperties"] is False
assert result["schema"]["properties"]["name"]["type"] == "string"
def test_prepare_response_format_direct_schema(mock_anthropic_client: MagicMock) -> None:
"""Test response_format with direct schema key."""
client = create_test_anthropic_client(mock_anthropic_client)
response_format = {
"schema": {
"type": "object",
"properties": {"value": {"type": "number"}},
}
}
result = client._prepare_response_format(response_format)
assert result["type"] == "json_schema"
assert result["schema"]["additionalProperties"] is False
assert result["schema"]["properties"]["value"]["type"] == "number"
def test_prepare_response_format_raw_schema(mock_anthropic_client: MagicMock) -> None:
"""Test response_format with raw schema dict."""
client = create_test_anthropic_client(mock_anthropic_client)
response_format = {
"type": "object",
"properties": {"count": {"type": "integer"}},
}
result = client._prepare_response_format(response_format)
assert result["type"] == "json_schema"
assert result["schema"]["additionalProperties"] is False
assert result["schema"]["properties"]["count"]["type"] == "integer"
def test_prepare_response_format_pydantic_model(mock_anthropic_client: MagicMock) -> None:
"""Test response_format with Pydantic BaseModel."""
client = create_test_anthropic_client(mock_anthropic_client)
class TestModel(BaseModel):
name: str
age: int
result = client._prepare_response_format(TestModel)
assert result["type"] == "json_schema"
assert result["schema"]["additionalProperties"] is False
assert "properties" in result["schema"]
# Message Preparation Tests
def test_prepare_message_with_image_data(mock_anthropic_client: MagicMock) -> None:
"""Test preparing messages with base64-encoded image data."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create message with image data content
message = Message(
role="user",
contents=[Content.from_data(media_type="image/png", data=VALID_PNG_BASE64)],
)
result = client._prepare_message_for_anthropic(message)
assert result["role"] == "user"
assert len(result["content"]) == 1
assert result["content"][0]["type"] == "image"
assert result["content"][0]["source"]["type"] == "base64"
assert result["content"][0]["source"]["media_type"] == "image/png"
def test_prepare_message_with_image_uri(mock_anthropic_client: MagicMock) -> None:
"""Test preparing messages with image URI."""
client = create_test_anthropic_client(mock_anthropic_client)
message = Message(
role="user",
contents=[Content.from_uri(uri="https://example.com/image.jpg", media_type="image/jpeg")],
)
result = client._prepare_message_for_anthropic(message)
assert result["role"] == "user"
assert len(result["content"]) == 1
assert result["content"][0]["type"] == "image"
assert result["content"][0]["source"]["type"] == "url"
assert result["content"][0]["source"]["url"] == "https://example.com/image.jpg"
def test_prepare_message_with_unsupported_data_type(
mock_anthropic_client: MagicMock,
) -> None:
"""Test preparing messages with unsupported data content type."""
client = create_test_anthropic_client(mock_anthropic_client)
message = Message(
role="user",
contents=[Content.from_data(media_type="application/pdf", data=b"PDF data")],
)
result = client._prepare_message_for_anthropic(message)
# PDF should be ignored
assert result["role"] == "user"
assert len(result["content"]) == 0
def test_prepare_message_with_unsupported_uri_type(mock_anthropic_client: MagicMock) -> None:
"""Test preparing messages with unsupported URI content type."""
client = create_test_anthropic_client(mock_anthropic_client)
message = Message(
role="user",
contents=[Content.from_uri(uri="https://example.com/video.mp4", media_type="video/mp4")],
)
result = client._prepare_message_for_anthropic(message)
# Video should be ignored
assert result["role"] == "user"
assert len(result["content"]) == 0
# Content Parsing Tests
def test_parse_contents_mcp_tool_use(mock_anthropic_client: MagicMock) -> None:
"""Test parsing MCP tool use content."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock MCP tool use block
mock_block = MagicMock()
mock_block.type = "mcp_tool_use"
mock_block.id = "call_123"
mock_block.name = "test_tool"
mock_block.input = {"arg": "value"}
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "mcp_server_tool_call"
def test_parse_contents_code_execution_tool(mock_anthropic_client: MagicMock) -> None:
"""Test parsing code execution tool use."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock code execution tool use block
mock_block = MagicMock()
mock_block.type = "tool_use"
mock_block.id = "call_456"
mock_block.name = "code_execution_tool"
mock_block.input = "print('hello')"
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "code_interpreter_tool_call"
def test_parse_contents_mcp_tool_result_list_content(
mock_anthropic_client: MagicMock,
) -> None:
"""Test parsing MCP tool result with list content."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_123", "test_tool")
# Create mock MCP tool result with list content
mock_text_block = MagicMock()
mock_text_block.type = "text"
mock_text_block.text = "Result text"
mock_block = MagicMock()
mock_block.type = "mcp_tool_result"
mock_block.tool_use_id = "call_123"
mock_block.content = [mock_text_block]
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "mcp_server_tool_result"
def test_parse_contents_mcp_tool_result_string_content(
mock_anthropic_client: MagicMock,
) -> None:
"""Test parsing MCP tool result with string content."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_123", "test_tool")
# Create mock MCP tool result with string content
mock_block = MagicMock()
mock_block.type = "mcp_tool_result"
mock_block.tool_use_id = "call_123"
mock_block.content = "Simple string result"
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "mcp_server_tool_result"
def test_parse_contents_mcp_tool_result_bytes_content(
mock_anthropic_client: MagicMock,
) -> None:
"""Test parsing MCP tool result with bytes content."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_123", "test_tool")
# Create mock MCP tool result with bytes content
mock_block = MagicMock()
mock_block.type = "mcp_tool_result"
mock_block.tool_use_id = "call_123"
mock_block.content = b"Binary data"
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "mcp_server_tool_result"
def test_parse_contents_mcp_tool_result_object_content(
mock_anthropic_client: MagicMock,
) -> None:
"""Test parsing MCP tool result with object content."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_123", "test_tool")
# Create mock MCP tool result with object content
mock_content_obj = MagicMock()
mock_content_obj.type = "text"
mock_content_obj.text = "Object content"
mock_block = MagicMock()
mock_block.type = "mcp_tool_result"
mock_block.tool_use_id = "call_123"
mock_block.content = mock_content_obj
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "mcp_server_tool_result"
def test_parse_contents_web_search_tool_result(mock_anthropic_client: MagicMock) -> None:
"""Test parsing web search tool result."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_789", "web_search")
# Create mock web search tool result
mock_block = MagicMock()
mock_block.type = "web_search_tool_result"
mock_block.tool_use_id = "call_789"
mock_block.content = "Search results"
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "function_result"
def test_parse_contents_web_fetch_tool_result(mock_anthropic_client: MagicMock) -> None:
"""Test parsing web fetch tool result."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_101", "web_fetch")
# Create mock web fetch tool result
mock_block = MagicMock()
mock_block.type = "web_fetch_tool_result"
mock_block.tool_use_id = "call_101"
mock_block.content = "Fetched content"
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "function_result"
# MCP Tool Configuration Tests
def test_get_mcp_tool_with_allowed_tools() -> None:
"""Test get_mcp_tool with allowed_tools parameter."""
result = AnthropicClient.get_mcp_tool(
name="Test Server",
url="https://example.com/mcp",
allowed_tools=["tool1", "tool2"],
)
assert result["type"] == "mcp"
assert result["server_label"] == "Test_Server"
assert result["server_url"] == "https://example.com/mcp"
assert result["allowed_tools"] == ["tool1", "tool2"]
def test_get_mcp_tool_without_allowed_tools() -> None:
"""Test get_mcp_tool without allowed_tools parameter."""
result = AnthropicClient.get_mcp_tool(name="Test Server", url="https://example.com/mcp")
assert result["type"] == "mcp"
assert result["server_label"] == "Test_Server"
assert result["server_url"] == "https://example.com/mcp"
assert "allowed_tools" not in result
def test_prepare_tools_mcp_with_allowed_tools(mock_anthropic_client: MagicMock) -> None:
"""Test MCP tool with allowed_tools configuration."""
client = create_test_anthropic_client(mock_anthropic_client)
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
mcp_tool = {
"type": "mcp",
"server_label": "test_server",
"server_url": "https://example.com/mcp",
"allowed_tools": ["tool1", "tool2"],
}
options = {"tools": [mcp_tool]}
result = client._prepare_options(messages, options)
assert "mcp_servers" in result
assert len(result["mcp_servers"]) == 1
assert result["mcp_servers"][0]["tool_configuration"]["allowed_tools"] == [
"tool1",
"tool2",
]
# Tool Choice Mode Tests
def test_tool_choice_auto_with_allow_multiple(mock_anthropic_client: MagicMock) -> None:
"""Test tool_choice auto mode with allow_multiple=False."""
client = create_test_anthropic_client(mock_anthropic_client)
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
@tool(approval_mode="never_require")
def test_func() -> str:
"""Test function."""
return "test"
options = {
"tools": [test_func],
"tool_choice": "auto",
"allow_multiple_tool_calls": False,
}
result = client._prepare_options(messages, options)
assert result["tool_choice"]["type"] == "auto"
assert result["tool_choice"]["disable_parallel_tool_use"] is True
def test_tool_choice_required_any(mock_anthropic_client: MagicMock) -> None:
"""Test tool_choice required mode without specific function."""
client = create_test_anthropic_client(mock_anthropic_client)
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
@tool(approval_mode="never_require")
def test_func() -> str:
"""Test function."""
return "test"
options = {"tools": [test_func], "tool_choice": "required"}
result = client._prepare_options(messages, options)
assert result["tool_choice"]["type"] == "any"
def test_tool_choice_required_specific_function(mock_anthropic_client: MagicMock) -> None:
"""Test tool_choice required mode with specific function."""
client = create_test_anthropic_client(mock_anthropic_client)
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
@tool(approval_mode="never_require")
def test_func() -> str:
"""Test function."""
return "test"
options = {
"tools": [test_func],
"tool_choice": {"mode": "required", "required_function_name": "test_func"},
}
result = client._prepare_options(messages, options)
assert result["tool_choice"]["type"] == "tool"
assert result["tool_choice"]["name"] == "test_func"
def test_tool_choice_none(mock_anthropic_client: MagicMock) -> None:
"""Test tool_choice none mode."""
client = create_test_anthropic_client(mock_anthropic_client)
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
@tool(approval_mode="never_require")
def test_func() -> str:
"""Test function."""
return "test"
options = {"tools": [test_func], "tool_choice": "none"}
result = client._prepare_options(messages, options)
assert result["tool_choice"]["type"] == "none"
def test_tool_choice_required_allows_parallel_use(mock_anthropic_client: MagicMock) -> None:
"""Test tool choice required mode with allow_multiple=True."""
client = create_test_anthropic_client(mock_anthropic_client)
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
@tool(approval_mode="never_require")
def test_func() -> str:
"""Test function."""
return "test"
options = {
"tools": [test_func],
"tool_choice": "required",
"allow_multiple_tool_calls": True,
}
# This tests line 739: setting disable_parallel_tool_use in required mode
result = client._prepare_options(messages, options)
assert result["tool_choice"]["type"] == "any"
assert result["tool_choice"]["disable_parallel_tool_use"] is False
# Options Preparation Tests
def test_prepare_options_with_instructions(mock_anthropic_client: MagicMock) -> None:
"""Test prepare_options with instructions parameter."""
client = create_test_anthropic_client(mock_anthropic_client)
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
options = {"instructions": "You are a helpful assistant"}
result = client._prepare_options(messages, options)
# Instructions should be prepended as system message
assert result["model"] == "claude-3-5-sonnet-20241022"
assert result["max_tokens"] == 1024
def test_prepare_options_missing_model_id(mock_anthropic_client: MagicMock) -> None:
"""Test prepare_options raises error when model_id is missing."""
client = create_test_anthropic_client(mock_anthropic_client)
client.model_id = "" # Set empty model_id
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
options = {}
try:
client._prepare_options(messages, options)
raise AssertionError("Expected ValueError")
except ValueError as e:
assert "model_id must be a non-empty string" in str(e)
def test_prepare_options_with_user_metadata(mock_anthropic_client: MagicMock) -> None:
"""Test prepare_options maps user to metadata.user_id."""
client = create_test_anthropic_client(mock_anthropic_client)
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
options = {"user": "user123"}
result = client._prepare_options(messages, options)
assert "user" not in result
assert result["metadata"]["user_id"] == "user123"
def test_prepare_options_user_metadata_no_override(
mock_anthropic_client: MagicMock,
) -> None:
"""Test user option doesn't override existing user_id in metadata."""
client = create_test_anthropic_client(mock_anthropic_client)
messages = [Message(role="user", contents=[Content.from_text("Hello")])]
options = {"user": "user123", "metadata": {"user_id": "existing_user"}}
result = client._prepare_options(messages, options)
# Existing user_id should be preserved
assert result["metadata"]["user_id"] == "existing_user"
def test_process_stream_event_message_stop(mock_anthropic_client: MagicMock) -> None:
"""Test processing message_stop event."""
client = create_test_anthropic_client(mock_anthropic_client)
# message_stop events don't produce output
mock_event = MagicMock()
mock_event.type = "message_stop"
result = client._process_stream_event(mock_event)
assert result is None
def test_parse_usage_with_cache_tokens(mock_anthropic_client: MagicMock) -> None:
"""Test parsing usage with cache creation and read tokens."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock usage with cache tokens
mock_usage = MagicMock()
mock_usage.input_tokens = 100
mock_usage.output_tokens = 50
mock_usage.cache_creation_input_tokens = 20
mock_usage.cache_read_input_tokens = 30
result = client._parse_usage_from_anthropic(mock_usage)
assert result is not None
assert result["output_token_count"] == 50
assert result["input_token_count"] == 100
assert result["anthropic.cache_creation_input_tokens"] == 20
assert result["anthropic.cache_read_input_tokens"] == 30
# Code Execution Result Tests
def test_parse_code_execution_result_with_error(mock_anthropic_client: MagicMock) -> None:
"""Test parsing code execution result with error."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_code1", "code_execution_tool")
# Create mock code execution result with error
from anthropic.types.beta.beta_code_execution_tool_result_error import (
BetaCodeExecutionToolResultError,
)
mock_block = MagicMock()
mock_block.type = "code_execution_tool_result"
mock_block.tool_use_id = "call_code1"
mock_block.content = BetaCodeExecutionToolResultError(
type="code_execution_tool_result_error", error_code="execution_time_exceeded"
)
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "code_interpreter_tool_result"
def test_parse_code_execution_result_with_stdout(mock_anthropic_client: MagicMock) -> None:
"""Test parsing code execution result with stdout."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_code2", "code_execution_tool")
# Create mock code execution result with stdout
mock_content = MagicMock()
mock_content.stdout = "Hello, world!"
mock_content.stderr = None
mock_content.content = []
mock_block = MagicMock()
mock_block.type = "code_execution_tool_result"
mock_block.tool_use_id = "call_code2"
mock_block.content = mock_content
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "code_interpreter_tool_result"
def test_parse_code_execution_result_with_stderr(mock_anthropic_client: MagicMock) -> None:
"""Test parsing code execution result with stderr."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_code3", "code_execution_tool")
# Create mock code execution result with stderr
mock_content = MagicMock()
mock_content.stdout = None
mock_content.stderr = "Warning message"
mock_content.content = []
mock_block = MagicMock()
mock_block.type = "code_execution_tool_result"
mock_block.tool_use_id = "call_code3"
mock_block.content = mock_content
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "code_interpreter_tool_result"
def test_parse_code_execution_result_with_files(mock_anthropic_client: MagicMock) -> None:
"""Test parsing code execution result with file outputs."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_code4", "code_execution_tool")
# Create mock file output
mock_file = MagicMock()
mock_file.file_id = "file_123"
# Create mock code execution result with files
mock_content = MagicMock()
mock_content.stdout = None
mock_content.stderr = None
mock_content.content = [mock_file]
mock_block = MagicMock()
mock_block.type = "code_execution_tool_result"
mock_block.tool_use_id = "call_code4"
mock_block.content = mock_content
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "code_interpreter_tool_result"
# Bash Execution Result Tests
def test_parse_bash_execution_result_with_stdout(mock_anthropic_client: MagicMock) -> None:
"""Test parsing bash execution result with stdout."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_bash2", "bash_code_execution")
# Create mock bash execution result with stdout
mock_content = MagicMock()
mock_content.stdout = "Output text"
mock_content.stderr = None
mock_content.content = []
mock_block = MagicMock()
mock_block.type = "bash_code_execution_tool_result"
mock_block.tool_use_id = "call_bash2"
mock_block.content = mock_content
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "function_result"
def test_parse_bash_execution_result_with_stderr(mock_anthropic_client: MagicMock) -> None:
"""Test parsing bash execution result with stderr."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_bash3", "bash_code_execution")
# Create mock bash execution result with stderr
mock_content = MagicMock()
mock_content.stdout = None
mock_content.stderr = "Error output"
mock_content.content = []
mock_block = MagicMock()
mock_block.type = "bash_code_execution_tool_result"
mock_block.tool_use_id = "call_bash3"
mock_block.content = mock_content
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "function_result"
# Text Editor Result Tests
def test_parse_text_editor_result_error(mock_anthropic_client: MagicMock) -> None:
"""Test parsing text editor result with error."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_editor1", "text_editor_code_execution")
# Create mock text editor result with error
mock_content = MagicMock()
mock_content.type = "text_editor_code_execution_tool_result_error"
mock_content.error = "File not found"
mock_block = MagicMock()
mock_block.type = "text_editor_code_execution_tool_result"
mock_block.tool_use_id = "call_editor1"
mock_block.content = mock_content
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "function_result"
def test_parse_text_editor_result_view(mock_anthropic_client: MagicMock) -> None:
"""Test parsing text editor view result."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_editor2", "text_editor_code_execution")
# Create mock text editor view result
mock_content = MagicMock()
mock_content.type = "text_editor_code_execution_view_result"
mock_content.content = "File content"
mock_content.start_line = 10
mock_content.num_lines = 5
mock_block = MagicMock()
mock_block.type = "text_editor_code_execution_tool_result"
mock_block.tool_use_id = "call_editor2"
mock_block.content = mock_content
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "function_result"
def test_parse_text_editor_result_str_replace(mock_anthropic_client: MagicMock) -> None:
"""Test parsing text editor string replace result."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_editor3", "text_editor_code_execution")
# Create mock text editor str_replace result
mock_content = MagicMock()
mock_content.type = "text_editor_code_execution_str_replace_result"
mock_content.old_start = 5
mock_content.old_lines = 3
mock_content.new_start = 5
mock_content.new_lines = 4
mock_content.lines = ["line1", "line2", "line3", "line4"]
mock_block = MagicMock()
mock_block.type = "text_editor_code_execution_tool_result"
mock_block.tool_use_id = "call_editor3"
mock_block.content = mock_content
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "function_result"
def test_parse_text_editor_result_file_create(mock_anthropic_client: MagicMock) -> None:
"""Test parsing text editor file create result."""
client = create_test_anthropic_client(mock_anthropic_client)
client._last_call_id_name = ("call_editor4", "text_editor_code_execution")
# Create mock text editor create result
mock_content = MagicMock()
mock_content.type = "text_editor_code_execution_create_result"
mock_content.is_file_update = False
mock_block = MagicMock()
mock_block.type = "text_editor_code_execution_tool_result"
mock_block.tool_use_id = "call_editor4"
mock_block.content = mock_content
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "function_result"
# Thinking Block Tests
def test_parse_thinking_block(mock_anthropic_client: MagicMock) -> None:
"""Test parsing thinking content block."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock thinking block
mock_block = MagicMock()
mock_block.type = "thinking"
mock_block.thinking = "Let me think about this..."
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "text_reasoning"
def test_parse_thinking_delta_block(mock_anthropic_client: MagicMock) -> None:
"""Test parsing thinking delta content block."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock thinking delta block
mock_block = MagicMock()
mock_block.type = "thinking_delta"
mock_block.thinking = "more thinking..."
result = client._parse_contents_from_anthropic([mock_block])
assert len(result) == 1
assert result[0].type == "text_reasoning"
# Citation Tests
def test_parse_citations_char_location(mock_anthropic_client: MagicMock) -> None:
"""Test parsing citations with char_location."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock text block with citations
mock_citation = MagicMock()
mock_citation.type = "char_location"
mock_citation.title = "Source Title"
mock_citation.cited_text = "Citation snippet"
mock_citation.start_char_index = 0
mock_citation.end_char_index = 10
mock_citation.file_id = None
mock_block = MagicMock()
mock_block.type = "text"
mock_block.text = "Text with citation"
mock_block.citations = [mock_citation]
result = client._parse_citations_from_anthropic(mock_block)
assert len(result) > 0
def test_parse_citations_page_location(mock_anthropic_client: MagicMock) -> None:
"""Test parsing citations with page_location."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock citation with page location
mock_citation = MagicMock()
mock_citation.type = "page_location"
mock_citation.document_title = "Document Title"
mock_citation.cited_text = "Cited text from page"
mock_citation.start_page_number = 1
mock_citation.end_page_number = 3
mock_citation.file_id = None
mock_block = MagicMock()
mock_block.type = "text"
mock_block.text = "Text with page citation"
mock_block.citations = [mock_citation]
result = client._parse_citations_from_anthropic(mock_block)
assert len(result) > 0
def test_parse_citations_content_block_location(mock_anthropic_client: MagicMock) -> None:
"""Test parsing citations with content_block_location."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock citation with content block location
mock_citation = MagicMock()
mock_citation.type = "content_block_location"
mock_citation.document_title = "Document Title"
mock_citation.cited_text = "Cited text from content blocks"
mock_citation.start_block_index = 0
mock_citation.end_block_index = 2
mock_citation.file_id = None
mock_block = MagicMock()
mock_block.type = "text"
mock_block.text = "Text with block citation"
mock_block.citations = [mock_citation]
result = client._parse_citations_from_anthropic(mock_block)
assert len(result) > 0
def test_parse_citations_web_search_location(mock_anthropic_client: MagicMock) -> None:
"""Test parsing citations with web_search_result_location."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock citation with web search location
mock_citation = MagicMock()
mock_citation.type = "web_search_result_location"
mock_citation.title = "Search Result"
mock_citation.cited_text = "Cited text from search"
mock_citation.url = "https://example.com"
mock_citation.file_id = None
mock_block = MagicMock()
mock_block.type = "text"
mock_block.text = "Text with web citation"
mock_block.citations = [mock_citation]
result = client._parse_citations_from_anthropic(mock_block)
assert len(result) > 0
def test_parse_citations_search_result_location(mock_anthropic_client: MagicMock) -> None:
"""Test parsing citations with search_result_location."""
client = create_test_anthropic_client(mock_anthropic_client)
# Create mock citation with search result location
mock_citation = MagicMock()
mock_citation.type = "search_result_location"
mock_citation.title = "Search Result"
mock_citation.cited_text = "Cited text"
mock_citation.source = "https://source.com"
mock_citation.start_block_index = 0
mock_citation.end_block_index = 1
mock_citation.file_id = None
mock_block = MagicMock()
mock_block.type = "text"
mock_block.text = "Text with search citation"
mock_block.citations = [mock_citation]
result = client._parse_citations_from_anthropic(mock_block)
assert len(result) > 0