Files
nanobot/tests/test_memory_tool.py
T

240 lines
7.7 KiB
Python

"""Tests for MemoryTool20250818."""
import pytest
from pathlib import Path
from nanobot.agent.tools.anthropic import MemoryTool20250818
from nanobot.agent.tools.anthropic.base import CLIResult
@pytest.fixture
def temp_workspace(tmp_path):
"""Create temporary workspace."""
return tmp_path
@pytest.fixture
def memory_tool(temp_workspace):
"""Create MemoryTool instance."""
return MemoryTool20250818(workspace=temp_workspace)
def test_memory_tool_initialization(memory_tool, temp_workspace):
"""Test that MemoryTool initializes correctly."""
assert memory_tool.api_type == "memory_20250818"
assert memory_tool.name == "memory"
assert memory_tool.beta_flag == "context-management-2025-06-27"
assert (temp_workspace / "memories").exists()
def test_memory_tool_to_params(memory_tool):
"""Test that to_params returns correct format."""
params = memory_tool.to_params()
assert params == {
"type": "memory_20250818",
"name": "memory"
}
@pytest.mark.asyncio
async def test_view_file(memory_tool, temp_workspace):
"""Test viewing a file with line numbers."""
# Create test file
test_file = temp_workspace / "memories" / "notes.txt"
test_file.write_text("Line 1\nLine 2\nLine 3\n")
result = await memory_tool(command="view", path="/memories/notes.txt")
assert result.exit_code == 0
assert result.error == ""
assert "Here's the content of /memories/notes.txt with line numbers:" in result.output
assert " 1\tLine 1" in result.output
assert " 2\tLine 2" in result.output
assert " 3\tLine 3" in result.output
@pytest.mark.asyncio
async def test_view_file_with_range(memory_tool, temp_workspace):
"""Test viewing a file with line range."""
# Create test file with 10 lines
test_file = temp_workspace / "memories" / "test.txt"
test_file.write_text("\n".join([f"Line {i}" for i in range(1, 11)]))
result = await memory_tool(command="view", path="/memories/test.txt", view_range=[3, 5])
assert result.exit_code == 0
assert " 3\tLine 3" in result.output
assert " 4\tLine 4" in result.output
assert " 5\tLine 5" in result.output
assert "Line 1" not in result.output
assert "Line 10" not in result.output
@pytest.mark.asyncio
async def test_view_file_not_exists(memory_tool):
"""Test viewing a nonexistent file."""
result = await memory_tool(command="view", path="/memories/nonexistent.txt")
assert result.exit_code == 1
assert result.output == ""
assert "The path /memories/nonexistent.txt does not exist" in result.error
@pytest.mark.asyncio
async def test_view_directory(memory_tool, temp_workspace):
"""Test viewing a directory listing."""
# Create test directory structure
memories = temp_workspace / "memories"
(memories / "notes.txt").write_text("content")
(memories / "project").mkdir()
(memories / "project" / "status.xml").write_text("<status>ok</status>")
(memories / ".hidden").write_text("hidden") # Should be excluded
result = await memory_tool(command="view", path="/memories")
assert result.exit_code == 0
assert result.error == ""
assert "Here're the files and directories up to 2 levels deep in /memories" in result.output
assert "/memories" in result.output
assert "/memories/notes.txt" in result.output
assert "/memories/project" in result.output
assert "/memories/project/status.xml" in result.output
assert ".hidden" not in result.output # Hidden files excluded
@pytest.mark.asyncio
async def test_view_empty_directory(memory_tool):
"""Test viewing an empty directory."""
result = await memory_tool(command="view", path="/memories")
assert result.exit_code == 0
assert "/memories" in result.output
@pytest.mark.asyncio
async def test_create_file(memory_tool, temp_workspace):
"""Test creating a new file."""
result = await memory_tool(
command="create",
path="/memories/notes.txt",
file_text="My notes\nLine 2\n"
)
assert result.exit_code == 0
assert result.error == ""
assert "File created successfully at: /memories/notes.txt" in result.output
# Verify file was created
created_file = temp_workspace / "memories" / "notes.txt"
assert created_file.exists()
assert created_file.read_text() == "My notes\nLine 2\n"
@pytest.mark.asyncio
async def test_create_file_nested_directory(memory_tool, temp_workspace):
"""Test creating a file in a nested directory (auto-creates parent dirs)."""
result = await memory_tool(
command="create",
path="/memories/project/status.xml",
file_text="<status>ok</status>"
)
assert result.exit_code == 0
assert "File created successfully at: /memories/project/status.xml" in result.output
# Verify file and parent directory were created
created_file = temp_workspace / "memories" / "project" / "status.xml"
assert created_file.exists()
assert created_file.read_text() == "<status>ok</status>"
@pytest.mark.asyncio
async def test_create_file_already_exists(memory_tool, temp_workspace):
"""Test creating a file that already exists."""
# Create file first
existing = temp_workspace / "memories" / "existing.txt"
existing.write_text("existing content")
result = await memory_tool(
command="create",
path="/memories/existing.txt",
file_text="new content"
)
assert result.exit_code == 1
assert result.output == ""
assert "Error: File /memories/existing.txt already exists" in result.error
# Verify original content unchanged
assert existing.read_text() == "existing content"
@pytest.mark.asyncio
async def test_create_file_missing_text(memory_tool):
"""Test creating a file without file_text parameter."""
result = await memory_tool(
command="create",
path="/memories/notes.txt"
)
assert result.exit_code == 1
assert result.output == ""
assert "Error: file_text is required for create command" in result.error
@pytest.mark.asyncio
async def test_str_replace_success(memory_tool, temp_workspace):
"""Test replacing unique string in a file."""
test_file = temp_workspace / "memories" / "config.txt"
test_file.write_text("color: blue\nsize: large\n")
result = await memory_tool(
command="str_replace",
path="/memories/config.txt",
old_str="blue",
new_str="green"
)
assert result.exit_code == 0
assert result.error == ""
assert "The memory file has been edited." in result.output
# Verify file was modified
assert test_file.read_text() == "color: green\nsize: large\n"
@pytest.mark.asyncio
async def test_str_replace_not_found(memory_tool, temp_workspace):
"""Test replacing string that doesn't exist."""
test_file = temp_workspace / "memories" / "config.txt"
test_file.write_text("color: blue\n")
result = await memory_tool(
command="str_replace",
path="/memories/config.txt",
old_str="red",
new_str="green"
)
assert result.exit_code == 1
assert result.output == ""
assert "No replacement was performed, old_str `red` did not appear verbatim" in result.error
@pytest.mark.asyncio
async def test_str_replace_duplicate(memory_tool, temp_workspace):
"""Test replacing string that appears multiple times."""
test_file = temp_workspace / "memories" / "config.txt"
test_file.write_text("color: blue\nbackground: blue\n")
result = await memory_tool(
command="str_replace",
path="/memories/config.txt",
old_str="blue",
new_str="green"
)
assert result.exit_code == 1
assert result.output == ""
assert "Multiple occurrences of old_str `blue`" in result.error
assert "Please ensure it is unique" in result.error