diff --git a/shellhist/tests/test_search.py b/shellhist/tests/test_search.py new file mode 100644 index 0000000..fef592a --- /dev/null +++ b/shellhist/tests/test_search.py @@ -0,0 +1,128 @@ +"""Tests for search functionality.""" + +import pytest + +from shellhist.core import HistoryEntry, HistoryStore +from shellhist.core.search import fuzzy_search, rank_by_frequency + + +class TestFuzzySearch: + """Test fuzzy search functionality.""" + + def setup_method(self): + """Set up test fixtures.""" + self.store = HistoryStore() + + commands = [ + "git status", + "git commit -m 'update'", + "git push origin main", + "git pull", + "git checkout feature", + "npm install", + "npm run build", + "npm test", + "docker ps", + "docker images", + ] + + for i, cmd in enumerate(commands): + entry = HistoryEntry(command=cmd, line_number=i) + self.store.add_entry(entry) + + def test_basic_search(self): + """Test basic fuzzy search.""" + results = fuzzy_search(self.store, "git status", threshold=50) + + assert len(results) > 0 + assert any(r[0].command == "git status" for r in results) + + def test_search_with_threshold(self): + """Test search with custom threshold.""" + results = fuzzy_search(self.store, "git commit message", threshold=80) + + assert all(r[1] >= 80 for r in results) + + def test_search_no_match(self): + """Test search with no matches.""" + results = fuzzy_search(self.store, "xyz123nonexistent", threshold=70) + + assert len(results) == 0 + + def test_search_limit(self): + """Test search result limit.""" + results = fuzzy_search(self.store, "git", threshold=50, limit=3) + + assert len(results) <= 3 + + def test_search_reverse_sort(self): + """Test search with reverse sorting.""" + results_normal = fuzzy_search(self.store, "git", threshold=50, reverse=False) + results_reverse = fuzzy_search(self.store, "git", threshold=50, reverse=True) + + if len(results_normal) > 1: + assert results_normal != results_reverse + + def test_search_recent_boost(self): + """Test that recent commands get boosted.""" + from datetime import datetime, timedelta + + self.store = HistoryStore() + + recent_entry = HistoryEntry( + command="git status", + timestamp=datetime.now() - timedelta(hours=12), + line_number=0 + ) + old_entry = HistoryEntry( + command="git status", + timestamp=datetime.now() - timedelta(days=5), + line_number=1 + ) + + self.store.add_entry(recent_entry) + self.store.add_entry(old_entry) + + results_with_boost = fuzzy_search(self.store, "git status", recent=True) + results_no_boost = fuzzy_search(self.store, "git status", recent=False) + + assert len(results_with_boost) == 1 + assert len(results_no_boost) == 1 + + +class TestRankByFrequency: + """Test frequency ranking functionality.""" + + def setup_method(self): + """Set up test fixtures.""" + self.store = HistoryStore() + + for _ in range(5): + self.store.add_entry(HistoryEntry(command="git status")) + + for _ in range(2): + self.store.add_entry(HistoryEntry(command="git log")) + + self.store.add_entry(HistoryEntry(command="ls")) + + def test_rank_by_frequency(self): + """Test ranking results by frequency.""" + entry = HistoryEntry(command="git status") + results = [(entry, 100)] + + ranked = rank_by_frequency(self.store, results) + + assert len(ranked) == 1 + assert ranked[0][2] == 5 + + def test_rank_multiple(self): + """Test ranking multiple results.""" + entry1 = HistoryEntry(command="git status") + entry2 = HistoryEntry(command="git log") + results = [(entry1, 100), (entry2, 80)] + + ranked = rank_by_frequency(self.store, results) + + assert len(ranked) == 2 + assert ranked[0][2] == 5 + assert ranked[1][2] == 2