"""System tests for Coding Memory feature.
Tests the integration of Coding Memory Rail with the agent system.
"""
import os
import tempfile
from pathlib import Path
from typing import Any, Dict, Generator, Optional
import pytest
import yaml
pytestmark = [pytest.mark.integration, pytest.mark.system]
@pytest.fixture
def temp_workspace() -> Generator[Path, None, None]:
"""Create a temporary workspace with coding_memory directory."""
with tempfile.TemporaryDirectory() as tmpdir:
workspace = Path(tmpdir)
(workspace / "coding_memory").mkdir(parents=True, exist_ok=True)
yield workspace
class TestCodingMemoryDirectoryStructure:
"""Tests for coding memory directory structure."""
@staticmethod
def test_coding_memory_directory_created(temp_workspace: Path) -> None:
"""Test that coding_memory directory is created."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
assert coding_memory_dir.exists()
assert coding_memory_dir.is_dir()
@staticmethod
def test_memory_files_in_directory(temp_workspace: Path) -> None:
"""Test creating memory files in coding_memory directory."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
memory_files = [
("user_role.md", "User role memory"),
("feedback_code_style.md", "Code style feedback"),
("project_auth_rewrite.md", "Project auth rewrite"),
]
for filename, content in memory_files:
file_path = coding_memory_dir / filename
file_path.write_text(content, encoding="utf-8")
for filename, _ in memory_files:
file_path = coding_memory_dir / filename
assert file_path.exists()
assert file_path.read_text(encoding="utf-8") == dict(memory_files)[filename]
@staticmethod
def test_memory_md_index_created(temp_workspace: Path) -> None:
"""Test that MEMORY.md index is created."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
memory_md = coding_memory_dir / "MEMORY.md"
index_content = """- [User Role](user_role.md) — Senior Python dev, new to frontend
- [Code Style](feedback_code_style.md) — prefer integration tests over mocks
"""
memory_md.write_text(index_content, encoding="utf-8")
assert memory_md.exists()
assert "User Role" in memory_md.read_text(encoding="utf-8")
class TestFrontmatterInMemoryFiles:
"""Tests for frontmatter in memory files."""
@staticmethod
def test_valid_frontmatter_in_memory_file(temp_workspace: Path) -> None:
"""Test that valid frontmatter is parsed from memory file."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
memory_content = """---
name: Developer Role
description: Senior Python dev, new to frontend
type: user
---
User is a senior Python developer, first time working with React."""
memory_file = coding_memory_dir / "user_role.md"
memory_file.write_text(memory_content, encoding="utf-8")
content = memory_file.read_text(encoding="utf-8")
assert "---" in content
assert "name: Developer Role" in content
assert "type: user" in content
@staticmethod
def test_all_memory_types(temp_workspace: Path) -> None:
"""Test all valid memory types."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
memory_types = [
("user", "User preferences and role"),
("feedback", "Code style feedback"),
("project", "Project deadline information"),
("reference", "External system reference"),
]
for mem_type, description in memory_types:
memory_content = f"""---
name: Test {mem_type.capitalize()}
description: {description}
type: {mem_type}
---
Test content for {mem_type} type."""
memory_file = coding_memory_dir / f"test_{mem_type}.md"
memory_file.write_text(memory_content, encoding="utf-8")
content = memory_file.read_text(encoding="utf-8")
assert f"type: {mem_type}" in content
class TestCodingMemoryToolsIntegration:
"""Integration tests for coding memory tools."""
@pytest.mark.asyncio
async def test_memory_write_and_read_workflow(self, temp_workspace: Path) -> None:
"""Test full workflow: write memory, update index, read memory."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
memory_content = """---
name: Developer Role
description: Senior Python dev, new to frontend
type: user
---
User is a senior Python developer."""
memory_file = coding_memory_dir / "user_role.md"
memory_file.write_text(memory_content, encoding="utf-8")
memory_md = coding_memory_dir / "MEMORY.md"
index_entry = "- [Developer Role](user_role.md) — Senior Python dev, new to frontend"
memory_md.write_text(index_entry, encoding="utf-8")
assert memory_file.exists()
read_content = memory_file.read_text(encoding="utf-8")
assert "Developer Role" in read_content
assert memory_md.exists()
index_content = memory_md.read_text(encoding="utf-8")
assert "Developer Role" in index_content
assert "user_role.md" in index_content
@pytest.mark.asyncio
async def test_memory_edit_workflow(self, temp_workspace: Path) -> None:
"""Test editing a memory file."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
initial_content = """---
name: Developer Role
description: Senior Python dev
type: user
---
User is a senior Python developer."""
memory_file = coding_memory_dir / "user_role.md"
memory_file.write_text(initial_content, encoding="utf-8")
old_text = "description: Senior Python dev"
new_text = "description: Senior Python dev, new to frontend"
content = memory_file.read_text(encoding="utf-8")
new_content = content.replace(old_text, new_text, 1)
memory_file.write_text(new_content, encoding="utf-8")
updated_content = memory_file.read_text(encoding="utf-8")
assert "new to frontend" in updated_content
assert "Senior Python dev, new to frontend" in updated_content
class TestCodingMemoryRailLifecycle:
"""Tests for CodingMemoryRail lifecycle."""
@staticmethod
def test_rail_initialization(temp_workspace: Path) -> None:
"""Test CodingMemoryRail initialization."""
coding_memory_dir = str(temp_workspace / "coding_memory")
os.makedirs(coding_memory_dir, exist_ok=True)
assert os.path.exists(coding_memory_dir)
class TestMemoryIndexManagement:
"""Tests for memory index management."""
@staticmethod
def test_index_entry_format(temp_workspace: Path) -> None:
"""Test that index entries follow correct format."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
entry = "- [Developer Role](user_role.md) — Senior Python dev, new to frontend"
memory_md = coding_memory_dir / "MEMORY.md"
memory_md.write_text(entry, encoding="utf-8")
content = memory_md.read_text(encoding="utf-8")
assert content.startswith("- [")
assert "](" in content
assert ") — " in content
@staticmethod
def test_multiple_index_entries(temp_workspace: Path) -> None:
"""Test multiple entries in index."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
entries = [
"- [Developer Role](user_role.md) — Senior Python dev",
"- [Code Style](feedback_code_style.md) — prefer integration tests",
"- [Project Deadline](project_deadline.md) — Release freeze info",
]
memory_md = coding_memory_dir / "MEMORY.md"
memory_md.write_text("\n".join(entries), encoding="utf-8")
content = memory_md.read_text(encoding="utf-8")
for entry in entries:
assert entry in content
@staticmethod
def test_index_update_existing_entry(temp_workspace: Path) -> None:
"""Test updating an existing index entry."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
initial_entry = "- [Developer Role](user_role.md) — Senior Python dev"
memory_md = coding_memory_dir / "MEMORY.md"
memory_md.write_text(initial_entry, encoding="utf-8")
updated_entry = "- [Developer Role](user_role.md) — Senior Python dev, new to frontend"
content = memory_md.read_text(encoding="utf-8")
content = content.replace(initial_entry, updated_entry)
memory_md.write_text(content, encoding="utf-8")
updated_content = memory_md.read_text(encoding="utf-8")
assert "new to frontend" in updated_content
assert updated_content == updated_entry
class TestCodingMemoryPermissions:
"""Tests for coding memory tool permissions."""
@staticmethod
def test_coding_memory_tools_in_config(temp_workspace: Path) -> None:
"""Test that coding memory tools are defined in config."""
config_content = {
"permissions": {
"tools": {
"coding_memory_write": "allow",
"coding_memory_edit": "allow",
"coding_memory_read": "allow",
},
},
}
config_file = temp_workspace / "config.yaml"
with open(config_file, "w", encoding="utf-8") as f:
yaml.dump(config_content, f)
with open(config_file, "r", encoding="utf-8") as f:
loaded_config = yaml.safe_load(f)
tools = loaded_config["permissions"]["tools"]
assert "coding_memory_write" in tools
assert "coding_memory_edit" in tools
assert "coding_memory_read" in tools
assert tools["coding_memory_write"] == "allow"
class TestCodingMemoryEndToEnd:
"""End-to-end tests for coding memory feature."""
@pytest.mark.asyncio
async def test_user_message_to_memory_recall(self, temp_workspace: Path) -> None:
"""Test end-to-end: user message → auto recall → response."""
coding_memory_dir = temp_workspace / "coding_memory"
coding_memory_dir.mkdir(exist_ok=True)
memory_files = [
("python_tips.md", """---
name: Python Tips
description: Useful Python programming tips
type: reference
---
Always use virtual environments for Python projects."""),
("code_style.md", """---
name: Code Style
description: Project code style guidelines
type: feedback
---
Use 4 spaces for indentation in Python."""),
]
for filename, content in memory_files:
(coding_memory_dir / filename).write_text(content, encoding="utf-8")
index_content = """- [Python Tips](python_tips.md) — Useful Python programming tips
- [Code Style](code_style.md) — Project code style guidelines
"""
(coding_memory_dir / "MEMORY.md").write_text(index_content, encoding="utf-8")
assert (coding_memory_dir / "python_tips.md").exists()
assert (coding_memory_dir / "code_style.md").exists()
assert (coding_memory_dir / "MEMORY.md").exists()
@staticmethod
def test_memory_directory_isolation(temp_workspace: Path) -> None:
"""Test that personal and coding memory directories are isolated."""
personal_memory_dir = temp_workspace / "memory"
coding_memory_dir = temp_workspace / "coding_memory"
personal_memory_dir.mkdir(exist_ok=True)
coding_memory_dir.mkdir(exist_ok=True)
(personal_memory_dir / "personal_note.md").write_text("Personal note", encoding="utf-8")
(coding_memory_dir / "coding_note.md").write_text("Coding note", encoding="utf-8")
assert (personal_memory_dir / "personal_note.md").exists()
assert not (personal_memory_dir / "coding_note.md").exists()
assert (coding_memory_dir / "coding_note.md").exists()
assert not (coding_memory_dir / "personal_note.md").exists()