Stack-2-9-finetuned / samples /unit /test_memory.py
walidsobhie-code
refactor: Squeeze folders further - cleaner structure
65888d5
#!/usr/bin/env python3
"""
Unit Tests for Stack 2.9 Memory & Context Module
"""
import pytest
import sys
import json
from pathlib import Path
from unittest.mock import MagicMock, patch
from datetime import datetime
# Add stack_cli to path
sys.path.insert(0, str(Path(__file__).parent.parent / "stack_cli"))
from stack_cli.context import (
ProjectContext,
SessionMemory,
ContextManager,
ProjectAware,
create_context_manager
)
class TestProjectContext:
"""Test ProjectContext dataclass."""
def test_project_context_creation(self):
"""Test creating a project context."""
ctx = ProjectContext(
name="test_project",
path="/path/to/project",
language="python",
framework="fastapi"
)
assert ctx.name == "test_project"
assert ctx.path == "/path/to/project"
assert ctx.language == "python"
assert ctx.framework == "fastapi"
assert ctx.files == []
assert ctx.dirs == []
def test_project_context_defaults(self):
"""Test default values."""
ctx = ProjectContext(name="test", path="/test")
assert ctx.language is None
assert ctx.framework is None
assert ctx.has_git is False
class TestSessionMemory:
"""Test SessionMemory class."""
def test_session_memory_creation(self):
"""Test creating session memory."""
session = SessionMemory()
assert session.messages == []
assert session.tools_used == []
assert session.files_touched == []
assert session.commands_run == []
def test_add_message(self):
"""Test adding a message."""
session = SessionMemory()
session.add_message("user", "Hello")
assert len(session.messages) == 1
assert session.messages[0]["role"] == "user"
assert session.messages[0]["content"] == "Hello"
def test_add_tool_usage(self):
"""Test recording tool usage."""
session = SessionMemory()
session.add_tool_usage("read", {"success": True})
assert len(session.tools_used) == 1
assert session.tools_used[0]["tool"] == "read"
def test_add_file_touched(self):
"""Test recording file access."""
session = SessionMemory()
session.add_file_touched("test.py", "read")
assert len(session.files_touched) == 1
assert session.files_touched[0]["path"] == "test.py"
def test_add_command(self):
"""Test recording command execution."""
session = SessionMemory()
session.add_command("ls -la", {"success": True})
assert len(session.commands_run) == 1
assert session.commands_run[0]["command"] == "ls -la"
def test_get_summary(self):
"""Test getting session summary."""
session = SessionMemory()
session.add_message("user", "Hello")
session.add_tool_usage("read", {"success": True})
summary = session.get_summary()
assert summary["messages_count"] == 1
assert summary["tools_used_count"] == 1
assert "duration_minutes" in summary
class TestContextManager:
"""Test ContextManager class."""
@patch('stack_cli.context.Path')
def test_context_manager_creation(self, mock_path):
"""Test creating context manager."""
with patch.object(Path, 'exists', return_value=False):
cm = ContextManager("/tmp/test")
assert cm is not None
assert cm.workspace == Path("/tmp/test")
@patch('stack_cli.context.Path')
def test_load_context(self, mock_path):
"""Test loading context files."""
with patch.object(Path, 'exists', return_value=False):
cm = ContextManager("/tmp/test")
assert hasattr(cm, 'context')
assert hasattr(cm, 'projects')
@patch('stack_cli.context.Path')
def test_get_context_summary(self, mock_path):
"""Test getting context summary."""
with patch.object(Path, 'exists', return_value=False):
cm = ContextManager("/tmp/test")
summary = cm.get_context_summary()
assert "workspace" in summary
assert "projects" in summary
assert "session" in summary
@patch('stack_cli.context.Path')
def test_get_workspace_context(self, mock_path):
"""Test getting formatted workspace context."""
with patch.object(Path, 'exists', return_value=False):
cm = ContextManager("/tmp/test")
context = cm.get_workspace_context()
assert isinstance(context, str)
assert "Workspace Context" in context
@patch('pathlib.Path.exists')
@patch('pathlib.Path.read_text')
def test_search_memory(self, mock_read, mock_exists):
"""Test searching memory."""
# Setup mock
mock_exists.return_value = True
def mock_file_exists(self):
if str(self).endswith('MEMORY.md'):
return True
return False
with patch.object(Path, 'exists', mock_file_exists):
mock_read.return_value = "### key\nvalue"
cm = ContextManager("/tmp/test")
results = cm.search_memory("key")
assert isinstance(results, list)
@patch('pathlib.Path.write_text')
def test_save_to_memory(self, mock_write):
"""Test saving to memory."""
with patch.object(Path, 'exists', return_value=True):
with patch('pathlib.Path.open', mock_open(read_data="")):
cm = ContextManager("/tmp/test")
cm.save_to_memory("test_key", "test_value")
mock_write.assert_called()
class TestProjectAware:
"""Test ProjectAware mixin."""
def test_project_aware_creation(self):
"""Test creating project aware."""
pa = ProjectAware()
assert pa is not None
assert hasattr(pa, 'context_manager')
def test_detect_project(self):
"""Test project detection."""
pa = ProjectAware()
# Should return None for non-existent path
result = pa.detect_project("/nonexistent/path")
assert result is None or isinstance(result, str)
def test_get_project_context(self):
"""Test getting project context."""
pa = ProjectAware()
# Should return None for non-existent project
result = pa.get_project_context("nonexistent_project")
assert result is None or isinstance(result, ProjectContext)
def test_format_context_for_prompt(self):
"""Test formatting context for prompt."""
pa = ProjectAware()
context = pa.format_context_for_prompt()
assert isinstance(context, str)
class TestCreateContextManager:
"""Test create_context_manager factory."""
@patch('stack_cli.context.ContextManager')
def test_create_context_manager_default(self, mock_cm):
"""Test creating with defaults."""
mock_cm.return_value = MagicMock()
cm = create_context_manager()
assert cm is not None
@patch('stack_cli.context.ContextManager')
def test_create_context_manager_custom(self, mock_cm):
"""Test creating with custom workspace."""
mock_cm.return_value = MagicMock()
cm = create_context_manager("/custom/path")
assert cm is not None
if __name__ == "__main__":
pytest.main([__file__, "-v"])