blob: 405d1c89fd1a80e25817d59ec2a4d4687cb84d14 [file] [log] [blame] [raw]
"""
测试增强CLI界面的命令补全功能
"""
import pytest
import asyncio
from unittest.mock import Mock, patch, AsyncMock
from prompt_toolkit.completion import WordCompleter
from prompt_toolkit.shortcuts import CompleteStyle
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../../../src'))
from claude_agent.cli.enhanced_interface import EnhancedCLIInterface
class TestEnhancedCLICommandCompletion:
"""测试增强CLI界面的命令补全功能"""
def setup_method(self):
"""设置测试"""
self.cli = EnhancedCLIInterface()
def test_command_completer_initialization(self):
"""测试命令补全器初始化"""
# 验证补全器存在
assert self.cli.command_completer is not None
assert isinstance(self.cli.command_completer, WordCompleter)
# 验证sentence模式已启用
assert hasattr(self.cli.command_completer, 'sentence')
assert self.cli.command_completer.sentence is True
def test_command_completer_words(self):
"""测试命令补全器包含正确的命令"""
expected_commands = [
'/help', '/mode', '/history', '/clear', '/tools', '/status', '/quit', '/exit',
'/sshout', '/sshout connect', '/sshout disconnect', '/sshout status', '/sshout send'
]
# 获取补全器的词列表
completer_words = self.cli.command_completer.words
# 验证所有期望的命令都存在
for command in expected_commands:
assert command in completer_words
def test_session_has_completer(self):
"""测试prompt session包含补全器"""
# 验证session存在且配置了补全器
assert self.cli.session is not None
assert self.cli.session.completer is self.cli.command_completer
def test_session_complete_style(self):
"""测试session的补全样式配置"""
assert self.cli.session.complete_style == CompleteStyle.MULTI_COLUMN
def test_session_history_configured(self):
"""测试session的历史功能配置"""
assert self.cli.session.history is self.cli.history
assert self.cli.history is not None
def test_command_completion_integration(self):
"""测试命令补全的集成"""
# 测试补全器是否可以正确处理部分命令
from prompt_toolkit.document import Document
# 测试基本命令补全
document = Document('/he')
completions = list(self.cli.command_completer.get_completions(document, None))
# 应该包含 /help
completion_texts = [comp.text for comp in completions]
assert '/help' in completion_texts
def test_sshout_command_completion(self):
"""测试SSHOUT命令补全"""
from prompt_toolkit.document import Document
# 测试SSHOUT子命令补全
document = Document('/sshout con')
completions = list(self.cli.command_completer.get_completions(document, None))
# 应该包含 /sshout connect
completion_texts = [comp.text for comp in completions]
assert '/sshout connect' in completion_texts
def test_empty_input_completion(self):
"""测试空输入的补全"""
from prompt_toolkit.document import Document
# 测试空文档
document = Document('')
completions = list(self.cli.command_completer.get_completions(document, None))
# 空输入应该显示所有可能的命令
assert len(completions) > 0
def test_slash_prefix_completion(self):
"""测试斜杠前缀补全"""
from prompt_toolkit.document import Document
# 测试只输入斜杠
document = Document('/')
completions = list(self.cli.command_completer.get_completions(document, None))
# 应该显示所有以/开头的命令
completion_texts = [comp.text for comp in completions]
assert '/help' in completion_texts
assert '/mode' in completion_texts
assert '/quit' in completion_texts
def test_non_command_input_completion(self):
"""测试非命令输入的补全"""
from prompt_toolkit.document import Document
# 测试非命令输入(不以/开头)
document = Document('hello')
completions = list(self.cli.command_completer.get_completions(document, None))
# 非命令输入不应该有补全
assert len(completions) == 0
def test_partial_command_completion(self):
"""测试部分命令补全"""
from prompt_toolkit.document import Document
test_cases = [
('/he', '/help'), # /help
('/mo', '/mode'), # /mode
('/st', '/status'), # /status
('/hi', '/history'), # /history
('/cl', '/clear'), # /clear
('/to', '/tools'), # /tools
('/qu', '/quit'), # /quit
]
for partial_input, expected_completion in test_cases:
document = Document(partial_input)
completions = list(self.cli.command_completer.get_completions(document, None))
completion_texts = [comp.text for comp in completions]
assert expected_completion in completion_texts, f"Expected '{expected_completion}' for input '{partial_input}'"
@pytest.mark.asyncio
async def test_get_user_input_with_completion(self):
"""测试get_user_input方法包含补全功能"""
# Mock session的prompt_async方法
with patch.object(self.cli.session, 'prompt_async', new_callable=AsyncMock) as mock_prompt:
mock_prompt.return_value = '/help'
result = await self.cli.get_user_input("测试")
# 验证prompt_async被调用且没有额外的completer参数
mock_prompt.assert_called_once()
call_args = mock_prompt.call_args
# 确保没有传递额外的completer参数(因为已在session初始化时设置)
assert 'completer' not in call_args.kwargs
assert result == '/help'
def test_command_completion_case_sensitivity(self):
"""测试命令补全的大小写敏感性"""
from prompt_toolkit.document import Document
# 测试大写输入
document = Document('/HE')
completions = list(self.cli.command_completer.get_completions(document, None))
# 应该没有补全,因为命令是小写的
assert len(completions) == 0
def test_command_completion_with_spaces(self):
"""测试带空格的命令补全"""
from prompt_toolkit.document import Document
# 测试多词命令补全
document = Document('/sshout dis')
completions = list(self.cli.command_completer.get_completions(document, None))
completion_texts = [comp.text for comp in completions]
# 应该包含 /sshout disconnect
assert '/sshout disconnect' in completion_texts
def test_command_completion_exact_match(self):
"""测试完全匹配的命令补全"""
from prompt_toolkit.document import Document
# 测试完全输入的命令
document = Document('/help')
completions = list(self.cli.command_completer.get_completions(document, None))
# 完全匹配的命令应该还是会返回该命令(这是WordCompleter的行为)
completion_texts = [comp.text for comp in completions]
assert '/help' in completion_texts
def test_command_list_completeness(self):
"""测试命令列表的完整性"""
# 验证所有必需的基本命令都存在
basic_commands = ['/help', '/mode', '/history', '/clear', '/tools', '/status']
exit_commands = ['/quit', '/exit']
sshout_commands = ['/sshout', '/sshout connect', '/sshout disconnect', '/sshout status', '/sshout send']
all_expected = basic_commands + exit_commands + sshout_commands
completer_words = self.cli.command_completer.words
for command in all_expected:
assert command in completer_words, f"Missing command: {command}"
def test_completer_ignore_case_setting(self):
"""测试补全器的忽略大小写设置"""
# WordCompleter默认是区分大小写的,这符合我们的设计
assert not hasattr(self.cli.command_completer, 'ignore_case') or \
not getattr(self.cli.command_completer, 'ignore_case', True)
class TestEnhancedCLICommandCompletionEdgeCases:
"""测试命令补全的边界情况"""
def setup_method(self):
"""设置测试"""
self.cli = EnhancedCLIInterface()
def test_completion_with_cursor_in_middle(self):
"""测试光标在中间时的补全"""
from prompt_toolkit.document import Document
# 测试光标在单词中间
document = Document('/help', cursor_position=3) # 光标在'e'后面
completions = list(self.cli.command_completer.get_completions(document, None))
# 应该基于光标前的内容进行补全
completion_texts = [comp.text for comp in completions]
assert '/help' in completion_texts
def test_completion_with_trailing_space(self):
"""测试带尾随空格的补全"""
from prompt_toolkit.document import Document
# 测试命令后有空格
document = Document('/help ')
completions = list(self.cli.command_completer.get_completions(document, None))
# 完整命令后的空格不应该有补全
assert len(completions) == 0
def test_completion_performance(self):
"""测试补全性能"""
from prompt_toolkit.document import Document
import time
# 测试大量补全请求的性能
document = Document('/')
start_time = time.time()
for _ in range(100):
list(self.cli.command_completer.get_completions(document, None))
end_time = time.time()
# 100次补全应该在1秒内完成
assert end_time - start_time < 1.0
def test_completion_memory_usage(self):
"""测试补全的内存使用"""
from prompt_toolkit.document import Document
import gc
# 测试补全不会导致内存泄漏
document = Document('/')
# 执行多次补全并强制垃圾回收
for _ in range(50):
list(self.cli.command_completer.get_completions(document, None))
gc.collect()
# 如果没有内存泄漏,这应该正常完成
assert True
if __name__ == '__main__':
pytest.main([__file__])