| |
| """ |
| Unit Tests for Stack 2.9 Context Module |
| """ |
|
|
| import pytest |
| import sys |
| from pathlib import Path |
| from unittest.mock import MagicMock, patch, mock_open |
| from datetime import datetime, timedelta |
|
|
| |
| sys.path.insert(0, str(Path(__file__).parent.parent / "stack_cli")) |
|
|
| from stack_cli.context import ( |
| ContextManager, |
| SessionMemory, |
| ProjectContext, |
| ) |
|
|
|
|
| class TestContextManagerBasics: |
| """Test basic context manager functionality.""" |
|
|
| @patch('stack_cli.context.Path') |
| def test_init_with_workspace(self, mock_path): |
| """Test initialization with workspace path.""" |
| with patch.object(Path, 'exists', return_value=True): |
| cm = ContextManager("/custom/workspace") |
| |
| assert cm.workspace == Path("/custom/workspace") |
|
|
| @patch('stack_cli.context.Path') |
| def test_init_loads_context(self, mock_path): |
| """Test that init loads context files.""" |
| with patch.object(Path, 'exists', return_value=False): |
| cm = ContextManager("/tmp") |
| |
| assert hasattr(cm, 'context') |
| assert isinstance(cm.context, dict) |
|
|
| @patch('stack_cli.context.Path') |
| def test_session_attribute(self, mock_path): |
| """Test that session is created.""" |
| with patch.object(Path, 'exists', return_value=False): |
| cm = ContextManager("/tmp") |
| |
| assert hasattr(cm, 'session') |
| assert isinstance(cm.session, SessionMemory) |
|
|
|
|
| class TestContextManagerProjects: |
| """Test project-related functionality.""" |
|
|
| @patch('stack_cli.context.Path') |
| def test_projects_dict_exists(self, mock_path): |
| """Test that projects dict is initialized.""" |
| with patch.object(Path, 'exists', return_value=False): |
| cm = ContextManager("/tmp") |
| |
| assert hasattr(cm, 'projects') |
| assert isinstance(cm.projects, dict) |
|
|
| @patch('stack_cli.context.Path') |
| def test_current_project_initially_none(self, mock_path): |
| """Test that current_project starts as None.""" |
| with patch.object(Path, 'exists', return_value=False): |
| cm = ContextManager("/tmp") |
| |
| assert cm.current_project is None |
|
|
|
|
| class TestContextManagerMethods: |
| """Test context manager methods.""" |
|
|
| @patch('stack_cli.context.Path') |
| def test_get_context_summary_returns_dict(self, mock_path): |
| """Test get_context_summary returns a dict.""" |
| with patch.object(Path, 'exists', return_value=False): |
| cm = ContextManager("/tmp") |
| |
| summary = cm.get_context_summary() |
| |
| assert isinstance(summary, dict) |
| assert "workspace" in summary |
|
|
| @patch('stack_cli.context.Path') |
| def test_get_workspace_context_returns_string(self, mock_path): |
| """Test get_workspace_context returns a string.""" |
| with patch.object(Path, 'exists', return_value=False): |
| cm = ContextManager("/tmp") |
| |
| context = cm.get_workspace_context() |
| |
| assert isinstance(context, str) |
| assert "Context" in context |
|
|
| @patch('stack_cli.context.Path') |
| @patch('pathlib.Path.rglob') |
| def test_search_memory_returns_list(self, mock_rglob, mock_path): |
| """Test search_memory returns a list.""" |
| mock_rglob.return_value = [] |
| |
| with patch.object(Path, 'exists', return_value=False): |
| cm = ContextManager("/tmp") |
| |
| results = cm.search_memory("query") |
| |
| assert isinstance(results, list) |
|
|
| @patch('stack_cli.context.Path') |
| @patch('pathlib.Path.open', mock_open(read_data="")) |
| def test_save_to_memory(self, mock_open_func, mock_path): |
| """Test save_to_memory writes to file.""" |
| with patch.object(Path, 'exists', return_value=True): |
| with patch('pathlib.Path.open', mock_open(read_data="")): |
| cm = ContextManager("/tmp") |
| try: |
| cm.save_to_memory("key", "value") |
| except: |
| pass |
|
|
|
|
| class TestContextManagerProjectLoading: |
| """Test project loading functionality.""" |
|
|
| @patch('stack_cli.context.Path') |
| def test_load_project_not_exists(self, mock_path): |
| """Test loading non-existent project.""" |
| with patch.object(Path, 'exists', return_value=False): |
| cm = ContextManager("/tmp") |
| |
| result = cm.load_project("nonexistent") |
| |
| assert result is None |
|
|
| @patch('stack_cli.context.Path') |
| @patch('pathlib.Path.exists') |
| def test_load_project_exists(self, mock_exists, mock_path): |
| """Test loading existing project.""" |
| |
| def mock_path_exists(self): |
| if isinstance(self, Path): |
| return str(self) != "/tmp/nonexistent" |
| return True |
| |
| mock_exists.side_effect = mock_path_exists |
| |
| with patch.object(Path, 'exists', return_value=True): |
| with patch.object(Path, 'read_text', return_value=""): |
| with patch('builtins.open', mock_open(read_data="")): |
| cm = ContextManager("/tmp") |
| |
| result = cm.load_project("test") |
| |
| assert result is None or isinstance(result, ProjectContext) |
|
|
|
|
| class TestContextManagerRecentContext: |
| """Test recent context retrieval.""" |
|
|
| @patch('stack_cli.context.Path') |
| @patch('pathlib.Path.glob') |
| def test_get_recent_context(self, mock_glob, mock_path): |
| """Test getting recent context.""" |
| mock_glob.return_value = [] |
| |
| with patch.object(Path, 'exists', return_value=False): |
| cm = ContextManager("/tmp") |
| |
| results = cm.get_recent_context(days=7) |
| |
| assert isinstance(results, list) |
|
|
|
|
| if __name__ == "__main__": |
| pytest.main([__file__, "-v"]) |
|
|