"""Comprehensive Test Suite for Clipboard Tools - Following Proven MCP Tool Test Pattern.
import logging
logging.basicConfig(level=logging.DEBUG)
This test suite validates the Clipboard Tools functionality using the systematic
testing approach that achieved 100% success rate across 11 tool suites.
Test Coverage:
- Clipboard get/set operations with security validation
- History management and retrieval with privacy protection
- Named clipboard creation, management, and organization
- Search functionality across content and metadata
- Statistics and analytics for clipboard usage
- Security validation for sensitive content detection
- Property-based testing for robust input validation
- Integration testing with mocked clipboard managers
- Error handling for all failure scenarios
- Performance testing for large content operations
Testing Strategy:
- Property-based testing with Hypothesis for comprehensive input coverage
- Mock-based testing for ClipboardManager and NamedClipboardManager
- Security validation for sensitive content filtering
- Integration testing scenarios with realistic clipboard operations
- Performance and memory testing with content limits
"""
from __future__ import annotations
from datetime import UTC, datetime
from typing import TYPE_CHECKING, Any
from unittest.mock import AsyncMock, Mock, patch
import pytest
from fastmcp import Context
from hypothesis import HealthCheck, assume, given, settings
from hypothesis import strategies as st
from hypothesis.strategies import composite
# Import clipboard types and errors
from src.clipboard import (
ClipboardContent,
ClipboardFormat,
ClipboardManager,
NamedClipboard,
NamedClipboardManager,
)
# Import the tools we're testing
from src.server.tools.clipboard_tools import (
get_clipboard_manager,
get_named_clipboard_manager,
km_clipboard_manager,
)
if TYPE_CHECKING:
from collections.abc import Callable
# Test fixtures following proven pattern
@pytest.fixture
def mock_context() -> Mock:
"""Create mock FastMCP context following successful pattern."""
context = Mock(spec=Context)
context.info = AsyncMock()
context.warn = AsyncMock()
context.error = AsyncMock()
context.report_progress = AsyncMock()
context.read_resource = AsyncMock()
context.sample = AsyncMock()
return context
@pytest.fixture
def mock_clipboard_manager() -> Mock:
"""Create mock ClipboardManager with standard interface."""
manager = Mock(spec=ClipboardManager)
manager.get_clipboard = AsyncMock()
manager.set_clipboard = AsyncMock()
manager.get_history_item = AsyncMock()
manager.get_history_list = AsyncMock()
# Setup standard success response using Either.success() pattern
mock_result = Mock()
mock_result.is_right.return_value = True
mock_result.is_left.return_value = False
# Create proper mock for clipboard content
mock_clipboard_content = Mock(spec=ClipboardContent)
mock_clipboard_content.content = "Test clipboard content"
mock_clipboard_content.format = ClipboardFormat.TEXT
mock_clipboard_content.size_bytes = 21
mock_clipboard_content.timestamp = datetime.now(UTC)
mock_clipboard_content.is_sensitive = False
mock_clipboard_content.preview.return_value = "Test clipboard content"
mock_clipboard_content.is_empty.return_value = False
mock_result.get_right.return_value = mock_clipboard_content
# Apply to all methods
manager.get_clipboard.return_value = mock_result
manager.set_clipboard.return_value = mock_result
manager.get_history_item.return_value = mock_result
manager.get_history_list.return_value = mock_result
return manager
@pytest.fixture
def mock_named_clipboard_manager() -> Mock:
"""Create mock NamedClipboardManager with standard interface."""
manager = Mock(spec=NamedClipboardManager)
manager.create_clipboard = AsyncMock()
manager.get_clipboard = AsyncMock()
manager.list_clipboards = AsyncMock()
manager.delete_clipboard = AsyncMock()
manager.search_named_clipboards = AsyncMock()
manager.list_named_clipboards = AsyncMock()
manager.get_clipboard_stats = AsyncMock()
# Setup standard success response using Either.success() pattern
mock_result = Mock()
mock_result.is_right.return_value = True
mock_result.is_left.return_value = False
# Create proper mock for named clipboard
mock_named_clipboard = Mock(spec=NamedClipboard)
mock_named_clipboard.name = "test_clipboard"
mock_named_clipboard.content = Mock(spec=ClipboardContent)
mock_named_clipboard.content.content = "Named clipboard content"
mock_named_clipboard.content.format = ClipboardFormat.TEXT
mock_named_clipboard.content.size_bytes = 23
mock_named_clipboard.content.timestamp = datetime.now(UTC)
mock_named_clipboard.content.is_sensitive = False
mock_named_clipboard.content.preview.return_value = "Named clipboard content"
mock_named_clipboard.created_at = datetime.now(UTC)
mock_named_clipboard.accessed_at = datetime.now(UTC)
mock_named_clipboard.access_count = 1
mock_named_clipboard.tags = {"test", "example"}
mock_named_clipboard.description = "Test named clipboard"
mock_result.get_right.return_value = mock_named_clipboard
# Apply to all methods
manager.create_clipboard.return_value = mock_result
manager.get_clipboard.return_value = mock_result
manager.list_clipboards.return_value = mock_result
manager.delete_clipboard.return_value = mock_result
manager.search_named_clipboards.return_value = mock_result
manager.list_named_clipboards.return_value = mock_result
# Stats response
mock_stats_result = Mock()
mock_stats_result.is_right.return_value = True
mock_stats_result.is_left.return_value = False
mock_stats_result.get_right.return_value = {
"total_clipboards": 5,
"total_size_bytes": 12345,
"most_accessed": "test_clipboard",
"recent_activity": 10,
}
manager.get_clipboard_stats.return_value = mock_stats_result
return manager
@pytest.fixture
def sample_clipboard_data() -> Mock:
"""Sample clipboard data for testing."""
return {
"short_text": "Hello World",
"long_text": "Lorem ipsum " * 100,
"sensitive_text": "password123",
"empty_text": "",
"unicode_text": "Hello δΈη π",
"names": ["test_clipboard", "backup_clipboard", "temp_clipboard"],
"tags": ["work", "personal", "temp", "backup"],
}
class TestKMClipboardManager:
"""Test clipboard management functionality following proven pattern."""
@pytest.mark.asyncio
async def test_get_operation_success(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test successful clipboard get operation."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Execute
result = await km_clipboard_manager(
operation="get",
include_sensitive=False,
ctx=mock_context,
)
# Verify success response structure
assert result["success"] is True
assert result["data"]["content"] == "Test clipboard content"
assert result["data"]["format"] == "text"
assert result["data"]["size_bytes"] == 21
assert "timestamp" in result["data"]
assert result["data"]["is_sensitive"] is False
assert result["data"]["preview"] == "Test clipboard content"
assert result["data"]["is_empty"] is False
assert result["metadata"]["operation"] == "get"
assert result["metadata"]["security_filtered"] is False
@pytest.mark.asyncio
async def test_get_operation_sensitive_content_filtering(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test sensitive content filtering in get operation."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Setup sensitive content
mock_sensitive_content = Mock(spec=ClipboardContent)
mock_sensitive_content.content = "password123"
mock_sensitive_content.format = ClipboardFormat.TEXT
mock_sensitive_content.size_bytes = 11
mock_sensitive_content.timestamp = datetime.now(UTC)
mock_sensitive_content.is_sensitive = True
mock_sensitive_content.preview.return_value = "password123"
mock_sensitive_content.is_empty.return_value = False
mock_result = Mock()
mock_result.is_right.return_value = True
mock_result.is_left.return_value = False
mock_result.get_right.return_value = mock_sensitive_content
mock_clipboard_manager.get_clipboard.return_value = mock_result
# Execute without including sensitive
result = await km_clipboard_manager(
operation="get",
include_sensitive=False,
ctx=mock_context,
)
# Verify sensitive content is filtered
assert result["success"] is True
assert result["data"]["content"] == "[SENSITIVE CONTENT HIDDEN]"
assert result["data"]["is_sensitive"] is True
assert result["metadata"]["security_filtered"] is True
@pytest.mark.asyncio
async def test_set_operation_success(
self,
mock_context: Any,
mock_clipboard_manager: Any,
sample_clipboard_data: Any,
) -> None:
"""Test successful clipboard set operation."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Execute
result = await km_clipboard_manager(
operation="set",
content=sample_clipboard_data["short_text"],
ctx=mock_context,
)
# Verify
assert result["success"] is True
assert result["data"]["content_size"] == len(
sample_clipboard_data["short_text"].encode("utf-8"),
)
assert (
result["data"]["content_preview"] == sample_clipboard_data["short_text"]
)
assert result["metadata"]["operation"] == "set"
@pytest.mark.asyncio
async def test_set_operation_missing_content(self, mock_context: Any) -> None:
"""Test set operation without content."""
# Execute
result = await km_clipboard_manager(
operation="set",
content=None,
ctx=mock_context,
)
# Verify error response
assert result["success"] is False
assert result["error"]["code"] == "VALIDATION_ERROR"
assert "Content is required" in result["error"]["message"]
@pytest.mark.asyncio
async def test_get_history_operation_success(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test successful history get operation."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Execute
result = await km_clipboard_manager(
operation="get_history",
history_index=0,
include_sensitive=False,
ctx=mock_context,
)
# Verify
assert result["success"] is True
assert result["data"]["index"] == 0
assert result["data"]["content"] == "Test clipboard content"
assert result["data"]["format"] == "text"
assert result["metadata"]["operation"] == "get_history"
@pytest.mark.asyncio
async def test_get_history_operation_missing_index(self, mock_context: Any) -> None:
"""Test get_history operation without index."""
# Execute
result = await km_clipboard_manager(
operation="get_history",
history_index=None,
ctx=mock_context,
)
# Verify error response
assert result["success"] is False
assert result["error"]["code"] == "VALIDATION_ERROR"
assert "history_index is required" in result["error"]["message"]
@pytest.mark.asyncio
async def test_list_history_operation_success(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test successful history listing operation."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Setup multiple history items
history_items = []
for i in range(3):
mock_item = Mock(spec=ClipboardContent)
mock_item.content = f"History item {i}"
mock_item.format = ClipboardFormat.TEXT
mock_item.size_bytes = len(f"History item {i}")
mock_item.timestamp = datetime.now(UTC)
mock_item.is_sensitive = False
mock_item.preview.return_value = f"History item {i}"
history_items.append(mock_item)
mock_result = Mock()
mock_result.is_right.return_value = True
mock_result.is_left.return_value = False
mock_result.get_right.return_value = history_items
mock_clipboard_manager.get_history_list.return_value = mock_result
# Execute
result = await km_clipboard_manager(
operation="list_history",
history_count=3,
include_sensitive=False,
ctx=mock_context,
)
# Verify
assert result["success"] is True
assert result["data"]["total_items"] == 3
assert len(result["data"]["history"]) == 3
assert result["data"]["history"][0]["content"] == "History item 0"
assert result["data"]["history"][1]["content"] == "History item 1"
assert result["data"]["history"][2]["content"] == "History item 2"
assert result["metadata"]["operation"] == "list_history"
assert result["metadata"]["requested_count"] == 3
@pytest.mark.asyncio
async def test_manage_named_operation_create_success(
self,
mock_context: Any,
mock_clipboard_manager: Any,
mock_named_clipboard_manager: Any,
sample_clipboard_data: Any,
) -> None:
"""Test successful named clipboard creation."""
with (
patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
),
patch(
"src.server.tools.clipboard_tools.get_named_clipboard_manager",
return_value=mock_named_clipboard_manager,
),
):
# Setup the named clipboard manager create method to return proper result
mock_create_result = Mock()
mock_create_result.is_right.return_value = True
mock_create_result.is_left.return_value = False
mock_create_result.get_right.return_value = (
mock_named_clipboard_manager.create_clipboard.return_value
)
mock_named_clipboard_manager.create_named_clipboard = AsyncMock(
return_value=mock_create_result,
)
# Execute
result = await km_clipboard_manager(
operation="manage_named",
clipboard_name=sample_clipboard_data["names"][0],
content=sample_clipboard_data["short_text"],
description="Test named clipboard",
tags=sample_clipboard_data["tags"][:2],
overwrite=False,
ctx=mock_context,
)
# Verify
assert result["success"] is True
assert result["data"]["name"] == sample_clipboard_data["names"][0]
assert result["data"]["created"] is True
assert result["data"]["overwritten"] is False
assert result["metadata"]["operation"] == "create_named"
@pytest.mark.asyncio
async def test_manage_named_operation_missing_name(self, mock_context: Any) -> None:
"""Test manage_named operation without clipboard name."""
# Execute
result = await km_clipboard_manager(
operation="manage_named",
clipboard_name=None,
content="test content",
ctx=mock_context,
)
# Verify error response
assert result["success"] is False
assert result["error"]["code"] == "VALIDATION_ERROR"
assert "clipboard_name is required" in result["error"]["message"]
@pytest.mark.asyncio
async def test_search_named_operation_success(
self,
mock_context: Any,
mock_named_clipboard_manager: Any,
sample_clipboard_data: Any,
) -> None:
"""Test successful named clipboard search."""
with patch(
"src.server.tools.clipboard_tools.get_named_clipboard_manager",
return_value=mock_named_clipboard_manager,
):
# Setup search results
search_results = []
for i, name in enumerate(sample_clipboard_data["names"]):
mock_clipboard = Mock(spec=NamedClipboard)
mock_clipboard.name = name
mock_clipboard.content = Mock(spec=ClipboardContent)
mock_clipboard.content.content = f"Content for {name}"
mock_clipboard.content.format = ClipboardFormat.TEXT
mock_clipboard.content.size_bytes = len(f"Content for {name}")
mock_clipboard.content.timestamp = datetime.now(UTC)
mock_clipboard.content.is_sensitive = False
mock_clipboard.content.preview.return_value = f"Content for {name}"
mock_clipboard.created_at = datetime.now(UTC)
mock_clipboard.accessed_at = datetime.now(UTC)
mock_clipboard.access_count = i + 1
mock_clipboard.tags = set(sample_clipboard_data["tags"][:2])
mock_clipboard.description = f"Description for {name}"
search_results.append(mock_clipboard)
mock_result = Mock()
mock_result.is_right.return_value = True
mock_result.is_left.return_value = False
mock_result.get_right.return_value = search_results
mock_named_clipboard_manager.search_named_clipboards.return_value = (
mock_result
)
# Execute
result = await km_clipboard_manager(
operation="search_named",
search_query="test",
search_content=True,
tag_filter="work",
sort_by="access_count",
ctx=mock_context,
)
# Verify
assert result["success"] is True
assert result["data"]["total_found"] == 3
assert len(result["data"]["clipboards"]) == 3
assert (
result["data"]["clipboards"][0]["name"]
== sample_clipboard_data["names"][0]
)
assert result["metadata"]["operation"] == "search_named"
assert result["metadata"]["query"] == "test"
assert result["metadata"]["searched_content"] is True
@pytest.mark.asyncio
async def test_stats_operation_success(
self,
mock_context: Any,
mock_named_clipboard_manager: Any,
) -> None:
"""Test successful statistics operation."""
with patch(
"src.server.tools.clipboard_tools.get_named_clipboard_manager",
return_value=mock_named_clipboard_manager,
):
# Execute
result = await km_clipboard_manager(operation="stats", ctx=mock_context)
# Verify
assert result["success"] is True
assert result["data"]["total_clipboards"] == 5
assert result["data"]["total_size_bytes"] == 12345
assert result["data"]["most_accessed"] == "test_clipboard"
assert result["data"]["recent_activity"] == 10
assert result["metadata"]["operation"] == "stats"
@pytest.mark.asyncio
async def test_clipboard_manager_error_handling(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test clipboard manager error handling."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Setup error response
mock_error_result = Mock()
mock_error_result.is_right.return_value = False
mock_error_result.is_left.return_value = True
mock_error = Mock()
mock_error.code = "CLIPBOARD_ACCESS_ERROR"
mock_error.message = "Cannot access clipboard"
mock_error.details = {"system": "permission_denied"}
mock_error_result.get_left.return_value = mock_error
mock_clipboard_manager.get_clipboard.return_value = mock_error_result
# Execute
result = await km_clipboard_manager(operation="get", ctx=mock_context)
# Verify error response
assert result["success"] is False
assert result["error"]["code"] == "CLIPBOARD_ACCESS_ERROR"
assert result["error"]["message"] == "Cannot access clipboard"
assert result["error"]["details"]["system"] == "permission_denied"
@pytest.mark.asyncio
async def test_unsupported_operation(self, mock_context: Any) -> None:
"""Test handling of unsupported operation."""
# Execute with invalid operation (would be caught by pydantic in real scenario)
result = await km_clipboard_manager(
operation="invalid_operation",
ctx=mock_context,
)
# Should be handled by pydantic validation, but if it gets through:
# This would actually be caught at the pydantic level, but testing the pattern
assert result["success"] is False
assert (
"UNSUPPORTED_OPERATION" in result["error"]["code"]
or "VALIDATION_ERROR" in result["error"]["code"]
)
class TestClipboardHelperFunctions:
"""Test helper functions and manager initialization."""
def test_get_clipboard_manager_singleton(self) -> None:
"""Test clipboard manager singleton pattern."""
manager1 = get_clipboard_manager()
manager2 = get_clipboard_manager()
# Should return the same instance
assert manager1 is manager2
assert isinstance(manager1, ClipboardManager)
def test_get_named_clipboard_manager_singleton(self) -> None:
"""Test named clipboard manager singleton pattern."""
manager1 = get_named_clipboard_manager()
manager2 = get_named_clipboard_manager()
# Should return the same instance
assert manager1 is manager2
assert isinstance(manager1, NamedClipboardManager)
class TestClipboardIntegration:
"""Test integration scenarios across clipboard operations."""
@pytest.mark.asyncio
async def test_clipboard_workflow_integration(
self,
mock_context: Any,
mock_clipboard_manager: Any,
mock_named_clipboard_manager: Any,
sample_clipboard_data: Any,
) -> None:
"""Test complete clipboard workflow integration."""
with (
patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
),
patch(
"src.server.tools.clipboard_tools.get_named_clipboard_manager",
return_value=mock_named_clipboard_manager,
),
):
# Setup the named clipboard manager create method to return proper result
mock_create_result = Mock()
mock_create_result.is_right.return_value = True
mock_create_result.is_left.return_value = False
mock_create_result.get_right.return_value = (
mock_named_clipboard_manager.create_clipboard.return_value
)
mock_named_clipboard_manager.create_named_clipboard = AsyncMock(
return_value=mock_create_result,
)
# 1. Set clipboard content
set_result = await km_clipboard_manager(
operation="set",
content=sample_clipboard_data["short_text"],
ctx=mock_context,
)
assert set_result["success"] is True
# 2. Get clipboard content
get_result = await km_clipboard_manager(
operation="get",
include_sensitive=False,
ctx=mock_context,
)
assert get_result["success"] is True
# 3. Create named clipboard
named_result = await km_clipboard_manager(
operation="manage_named",
clipboard_name="workflow_test",
content=sample_clipboard_data["short_text"],
description="Workflow test clipboard",
ctx=mock_context,
)
assert named_result["success"] is True
# 4. Get statistics
stats_result = await km_clipboard_manager(
operation="stats",
ctx=mock_context,
)
assert stats_result["success"] is True
@pytest.mark.asyncio
async def test_clipboard_content_size_limits(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test clipboard content size handling."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Test with large content
large_content = "x" * 100000 # 100KB
result = await km_clipboard_manager(
operation="set",
content=large_content,
ctx=mock_context,
)
# Should succeed within limits
assert result["success"] is True
assert result["data"]["content_size"] == 100000
class TestClipboardSecurity:
"""Test security validation and prevention measures."""
@pytest.mark.asyncio
async def test_sensitive_content_detection(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test sensitive content detection and filtering."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
sensitive_contents = [
"password123",
"secret_key_abc123",
"credit_card_4532123456789012",
"api_key_sk_test_abc123",
"ssh_key_rsa_private",
]
for sensitive_content in sensitive_contents:
# Setup sensitive content response
mock_sensitive_content = Mock(spec=ClipboardContent)
mock_sensitive_content.content = sensitive_content
mock_sensitive_content.format = ClipboardFormat.TEXT
mock_sensitive_content.size_bytes = len(sensitive_content)
mock_sensitive_content.timestamp = datetime.now(UTC)
mock_sensitive_content.is_sensitive = True
mock_sensitive_content.preview.return_value = sensitive_content
mock_sensitive_content.is_empty.return_value = False
mock_result = Mock()
mock_result.is_right.return_value = True
mock_result.is_left.return_value = False
mock_result.get_right.return_value = mock_sensitive_content
mock_clipboard_manager.get_clipboard.return_value = mock_result
# Test without including sensitive
result = await km_clipboard_manager(
operation="get",
include_sensitive=False,
ctx=mock_context,
)
# Should filter sensitive content
assert result["success"] is True
assert result["data"]["content"] == "[SENSITIVE CONTENT HIDDEN]"
assert result["data"]["is_sensitive"] is True
assert result["metadata"]["security_filtered"] is True
@pytest.mark.asyncio
async def test_clipboard_name_validation(self, mock_context: Any) -> None:
"""Test clipboard name security validation."""
invalid_names = [
"../malicious",
"../../etc/passwd",
"name with <script>",
"name_with_\x00_null",
"x" * 150, # Too long
]
for invalid_name in invalid_names:
# These would be caught by pydantic validation pattern
# Testing that the pattern exists for security
assert (
not all(c.isalnum() or c in "_- " for c in invalid_name)
or len(invalid_name) > 100
)
class TestClipboardPropertyBased:
"""Property-based testing for clipboard operations."""
@composite
def clipboard_content_strategy(draw: Callable[..., Any]) -> Mock:
"""Generate valid clipboard content for testing."""
content_type = draw(st.sampled_from(["text", "short", "long", "unicode"]))
if content_type == "text":
content = draw(st.text(min_size=1, max_size=1000))
elif content_type == "short":
content = draw(st.text(min_size=1, max_size=50))
elif content_type == "long":
content = draw(st.text(min_size=100, max_size=10000))
else: # unicode
content = draw(
st.text(
alphabet=st.characters(
whitelist_categories=("Lu", "Ll", "Nd", "So"),
),
min_size=1,
max_size=100,
),
)
assume(len(content.strip()) > 0)
return content
@given(clipboard_content_strategy())
@settings(
max_examples=20,
suppress_health_check=[HealthCheck.function_scoped_fixture],
)
def test_clipboard_content_properties(self, content: str) -> None:
"""Property: Valid clipboard content should meet basic requirements."""
# Test basic content properties
assert len(content) > 0
assert len(content) <= 10000
assert isinstance(content, str)
@given(st.integers(min_value=0, max_value=199))
@settings(max_examples=10)
def test_history_index_properties(self, history_index: Any) -> None:
"""Property: History indices should be within valid range."""
assert 0 <= history_index <= 199
assert isinstance(history_index, int)
@given(
st.lists(
st.text(
alphabet=st.characters(whitelist_categories=("Lu", "Ll", "Nd")),
min_size=1,
max_size=20,
),
min_size=0,
max_size=10,
),
)
@settings(max_examples=15)
def test_tags_properties(self, tags: list[Any] | str) -> None:
"""Property: Tags should be valid and manageable."""
# All tags should be valid strings
for tag in tags:
assert isinstance(tag, str)
assert len(tag) > 0
assert len(tag) <= 20
# Tag list should be reasonable size
assert len(tags) <= 10
class TestClipboardPerformance:
"""Test performance and limits for clipboard operations."""
@pytest.mark.asyncio
async def test_large_content_handling(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test handling of large clipboard content."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Test maximum allowed content size
max_content = "x" * 1000000 # 1MB
result = await km_clipboard_manager(
operation="set",
content=max_content,
ctx=mock_context,
)
# Should succeed with max content size
assert result["success"] is True
assert result["data"]["content_size"] == 1000000
@pytest.mark.asyncio
async def test_history_count_limits(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test history count parameter limits."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Setup history items list for proper iteration
history_items = []
for i in range(10): # Create some test history items
mock_item = Mock(spec=ClipboardContent)
mock_item.content = f"History item {i}"
mock_item.format = ClipboardFormat.TEXT
mock_item.size_bytes = len(f"History item {i}")
mock_item.timestamp = datetime.now(UTC)
mock_item.is_sensitive = False
mock_item.preview.return_value = f"History item {i}"
history_items.append(mock_item)
# Override the mock to return proper list
mock_result = Mock()
mock_result.is_right.return_value = True
mock_result.is_left.return_value = False
mock_result.get_right.return_value = history_items
mock_clipboard_manager.get_history_list.return_value = mock_result
# Test maximum history count
result = await km_clipboard_manager(
operation="list_history",
history_count=50, # Maximum allowed
ctx=mock_context,
)
# Should succeed with max history count
assert result["success"] is True
class TestClipboardEdgeCases:
"""Test edge cases and boundary conditions."""
@pytest.mark.asyncio
async def test_empty_content_handling(
self,
mock_context: Any,
mock_clipboard_manager: Any,
) -> None:
"""Test handling of empty clipboard content."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Setup empty content
mock_empty_content = Mock(spec=ClipboardContent)
mock_empty_content.content = ""
mock_empty_content.format = ClipboardFormat.TEXT
mock_empty_content.size_bytes = 0
mock_empty_content.timestamp = datetime.now(UTC)
mock_empty_content.is_sensitive = False
mock_empty_content.preview.return_value = ""
mock_empty_content.is_empty.return_value = True
mock_result = Mock()
mock_result.is_right.return_value = True
mock_result.is_left.return_value = False
mock_result.get_right.return_value = mock_empty_content
mock_clipboard_manager.get_clipboard.return_value = mock_result
result = await km_clipboard_manager(operation="get", ctx=mock_context)
# Should handle empty content properly
assert result["success"] is True
assert result["data"]["content"] == ""
assert result["data"]["size_bytes"] == 0
assert result["data"]["is_empty"] is True
@pytest.mark.asyncio
async def test_unicode_content_handling(
self,
mock_context: Any,
mock_clipboard_manager: Any,
sample_clipboard_data: Any,
) -> None:
"""Test handling of Unicode content."""
with patch(
"src.server.tools.clipboard_tools.get_clipboard_manager",
return_value=mock_clipboard_manager,
):
# Setup Unicode content
unicode_content = sample_clipboard_data["unicode_text"]
result = await km_clipboard_manager(
operation="set",
content=unicode_content,
ctx=mock_context,
)
# Should handle Unicode properly
assert result["success"] is True
assert result["data"]["content_size"] == len(
unicode_content.encode("utf-8"),
)
@pytest.mark.asyncio
async def test_none_values_handling(self, mock_context: Any) -> None:
"""Test handling of None values in optional parameters."""
# Test with minimal parameters
result = await km_clipboard_manager(operation="get", ctx=mock_context)
# Should handle None values gracefully
# (This would be processed through the actual function logic)
assert isinstance(result, dict)
assert "success" in result
if __name__ == "__main__":
pytest.main([__file__, "-v"])