diff --git a/.tests/test_history.py b/.tests/test_history.py new file mode 100644 index 0000000..cdd93a6 --- /dev/null +++ b/.tests/test_history.py @@ -0,0 +1,236 @@ +"""Tests for ShellGenius history module.""" + +import os +import tempfile + +from shellgenius.history import HistoryEntry, HistoryLearner, HistoryStorage + + +class TestHistoryEntry: + """Test history entry dataclass.""" + + def test_entry_creation(self): + """Test creating a history entry.""" + entry = HistoryEntry( + id="test-id", + timestamp="2024-01-01T00:00:00", + description="Test description", + commands=["cmd1", "cmd2"], + shell_type="bash", + ) + assert entry.id == "test-id" + assert len(entry.commands) == 2 + assert entry.usage_count == 1 + + +class TestHistoryStorage: + """Test history storage.""" + + def test_add_and_get_entry(self): + """Test adding and retrieving entries.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + storage = HistoryStorage(storage_path) + + entry = HistoryEntry( + id="test-id", + timestamp="2024-01-01T00:00:00", + description="Test", + commands=["echo hello"], + shell_type="bash", + ) + + storage.add_entry(entry) + entries = storage.get_entries() + + assert len(entries) == 1 + assert entries[0].description == "Test" + + def test_search_entries(self): + """Test searching entries.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + storage = HistoryStorage(storage_path) + + entry = HistoryEntry( + id="test-id", + timestamp="2024-01-01T00:00:00", + description="Find Python files", + commands=["find . -name *.py"], + shell_type="bash", + ) + + storage.add_entry(entry) + results = storage.search("python", limit=10) + + assert len(results) == 1 + + def test_get_popular(self): + """Test getting popular entries.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + storage = HistoryStorage(storage_path) + + entry = HistoryEntry( + id="test-id", + timestamp="2024-01-01T00:00:00", + description="Test", + commands=["echo hello"], + shell_type="bash", + usage_count=5, + ) + + storage.add_entry(entry) + popular = storage.get_popular(limit=10) + + assert len(popular) == 1 + assert popular[0].usage_count == 5 + + def test_update_usage(self): + """Test updating usage count.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + storage = HistoryStorage(storage_path) + + entry = HistoryEntry( + id="test-id", + timestamp="2024-01-01T00:00:00", + description="Test", + commands=["echo hello"], + shell_type="bash", + ) + + storage.add_entry(entry) + storage.update_usage("test-id") + + entries = storage.get_entries() + assert entries[0].usage_count == 2 + + def test_delete_entry(self): + """Test deleting entry.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + storage = HistoryStorage(storage_path) + + entry = HistoryEntry( + id="test-id", + timestamp="2024-01-01T00:00:00", + description="Test", + commands=["echo hello"], + shell_type="bash", + ) + + storage.add_entry(entry) + storage.delete_entry("test-id") + + entries = storage.get_entries() + assert len(entries) == 0 + + def test_clear_history(self): + """Test clearing all history.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + storage = HistoryStorage(storage_path) + + for i in range(3): + entry = HistoryEntry( + id=f"test-{i}", + timestamp="2024-01-01T00:00:00", + description=f"Test {i}", + commands=[f"echo {i}"], + shell_type="bash", + ) + storage.add_entry(entry) + + storage.clear() + entries = storage.get_entries() + + assert len(entries) == 0 + + def test_limit_and_offset(self): + """Test limit and offset for retrieval.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + storage = HistoryStorage(storage_path) + + for i in range(5): + entry = HistoryEntry( + id=f"test-{i}", + timestamp="2024-01-01T00:00:00", + description=f"Test {i}", + commands=[f"echo {i}"], + shell_type="bash", + ) + storage.add_entry(entry) + + entries = storage.get_entries(limit=2, offset=2) + assert len(entries) == 2 + + +class TestHistoryLearner: + """Test history learning functionality.""" + + def test_learn(self): + """Test learning from commands.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + learner = HistoryLearner() + learner.storage = HistoryStorage(storage_path) + + entry = learner.learn( + description="List files", + commands=["ls -la"], + shell_type="bash", + ) + + assert entry is not None + assert "List files" in entry.description + + def test_find_similar(self): + """Test finding similar commands.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + learner = HistoryLearner() + learner.storage = HistoryStorage(storage_path) + + learner.learn( + description="Find Python files", + commands=["find . -name *.py"], + shell_type="bash", + ) + + similar = learner.find_similar("python", limit=5) + assert len(similar) == 1 + + def test_suggest(self): + """Test getting suggestions.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + learner = HistoryLearner() + learner.storage = HistoryStorage(storage_path) + + learner.learn( + description="Find Python files", + commands=["find . -name *.py"], + shell_type="bash", + ) + + suggestions = learner.suggest("python files", limit=3) + assert len(suggestions) >= 1 + + def test_get_frequent_patterns(self): + """Test analyzing frequent patterns.""" + with tempfile.TemporaryDirectory() as tmpdir: + storage_path = os.path.join(tmpdir, "history.yaml") + learner = HistoryLearner() + learner.storage = HistoryStorage(storage_path) + + learner.learn( + description="Find files", + commands=["find . -type f"], + shell_type="bash", + ) + + patterns = learner.get_frequent_patterns() + assert "common_commands" in patterns + assert "shell_types" in patterns