Applied 236 return type annotations to functions with no return values across 100+ files (core modules, tests, scripts, simulations). Added Phase 4 to python_style_refactor track for remaining 597 items (untyped params, vars, and functions with return values). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
127 lines
4.4 KiB
Python
127 lines
4.4 KiB
Python
import pytest
|
|
from unittest.mock import patch, MagicMock
|
|
import ai_client
|
|
|
|
def test_deepseek_model_selection() -> None:
|
|
"""
|
|
Verifies that ai_client.set_provider('deepseek', 'deepseek-chat') correctly updates the internal state.
|
|
"""
|
|
ai_client.set_provider("deepseek", "deepseek-chat")
|
|
assert ai_client._provider == "deepseek"
|
|
assert ai_client._model == "deepseek-chat"
|
|
|
|
def test_deepseek_completion_logic() -> None:
|
|
"""
|
|
Verifies that ai_client.send() correctly calls the DeepSeek API and returns content.
|
|
"""
|
|
ai_client.set_provider("deepseek", "deepseek-chat")
|
|
with patch("requests.post") as mock_post:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {
|
|
"choices": [{
|
|
"message": {"role": "assistant", "content": "DeepSeek Response"},
|
|
"finish_reason": "stop"
|
|
}],
|
|
"usage": {"prompt_tokens": 10, "completion_tokens": 5}
|
|
}
|
|
mock_post.return_value = mock_response
|
|
result = ai_client.send(md_content="Context", user_message="Hello", base_dir=".")
|
|
assert result == "DeepSeek Response"
|
|
assert mock_post.called
|
|
|
|
def test_deepseek_reasoning_logic() -> None:
|
|
"""
|
|
Verifies that reasoning_content is captured and wrapped in <thinking> tags.
|
|
"""
|
|
ai_client.set_provider("deepseek", "deepseek-reasoner")
|
|
with patch("requests.post") as mock_post:
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
mock_response.json.return_value = {
|
|
"choices": [{
|
|
"message": {
|
|
"role": "assistant",
|
|
"content": "Final Answer",
|
|
"reasoning_content": "Chain of thought"
|
|
},
|
|
"finish_reason": "stop"
|
|
}],
|
|
"usage": {"prompt_tokens": 10, "completion_tokens": 20}
|
|
}
|
|
mock_post.return_value = mock_response
|
|
result = ai_client.send(md_content="Context", user_message="Reasoning test", base_dir=".")
|
|
assert "<thinking>\nChain of thought\n</thinking>" in result
|
|
assert "Final Answer" in result
|
|
|
|
def test_deepseek_tool_calling() -> None:
|
|
"""
|
|
Verifies that DeepSeek provider correctly identifies and executes tool calls.
|
|
"""
|
|
ai_client.set_provider("deepseek", "deepseek-chat")
|
|
with patch("requests.post") as mock_post, \
|
|
patch("mcp_client.dispatch") as mock_dispatch:
|
|
# 1. Mock first response with a tool call
|
|
mock_resp1 = MagicMock()
|
|
mock_resp1.status_code = 200
|
|
mock_resp1.json.return_value = {
|
|
"choices": [{
|
|
"message": {
|
|
"role": "assistant",
|
|
"content": "Let me read that file.",
|
|
"tool_calls": [{
|
|
"id": "call_123",
|
|
"type": "function",
|
|
"function": {
|
|
"name": "read_file",
|
|
"arguments": '{"path": "test.txt"}'
|
|
}
|
|
}]
|
|
},
|
|
"finish_reason": "tool_calls"
|
|
}],
|
|
"usage": {"prompt_tokens": 50, "completion_tokens": 10}
|
|
}
|
|
# 2. Mock second response (final answer)
|
|
mock_resp2 = MagicMock()
|
|
mock_resp2.status_code = 200
|
|
mock_resp2.json.return_value = {
|
|
"choices": [{
|
|
"message": {
|
|
"role": "assistant",
|
|
"content": "File content is: Hello World"
|
|
},
|
|
"finish_reason": "stop"
|
|
}],
|
|
"usage": {"prompt_tokens": 100, "completion_tokens": 20}
|
|
}
|
|
mock_post.side_effect = [mock_resp1, mock_resp2]
|
|
mock_dispatch.return_value = "Hello World"
|
|
result = ai_client.send(md_content="Context", user_message="Read test.txt", base_dir=".")
|
|
assert "File content is: Hello World" in result
|
|
assert mock_dispatch.called
|
|
assert mock_dispatch.call_args[0][0] == "read_file"
|
|
assert mock_dispatch.call_args[0][1] == {"path": "test.txt"}
|
|
|
|
def test_deepseek_streaming() -> None:
|
|
"""
|
|
Verifies that DeepSeek provider correctly aggregates streaming chunks.
|
|
"""
|
|
ai_client.set_provider("deepseek", "deepseek-chat")
|
|
with patch("requests.post") as mock_post:
|
|
# Mock a streaming response
|
|
mock_response = MagicMock()
|
|
mock_response.status_code = 200
|
|
# Simulate OpenAI-style server-sent events (SSE) for streaming
|
|
# Each line starts with 'data: ' and contains a JSON object
|
|
chunks = [
|
|
'data: {"choices": [{"delta": {"role": "assistant", "content": "Hello"}, "index": 0, "finish_reason": null}]}',
|
|
'data: {"choices": [{"delta": {"content": " World"}, "index": 0, "finish_reason": null}]}',
|
|
'data: {"choices": [{"delta": {}, "index": 0, "finish_reason": "stop"}]}',
|
|
'data: [DONE]'
|
|
]
|
|
mock_response.iter_lines.return_value = [c.encode('utf-8') for c in chunks]
|
|
mock_post.return_value = mock_response
|
|
result = ai_client.send(md_content="Context", user_message="Stream test", base_dir=".", stream=True)
|
|
assert result == "Hello World"
|