diff --git a/shellhist/tests/test_patterns.py b/shellhist/tests/test_patterns.py new file mode 100644 index 0000000..a437709 --- /dev/null +++ b/shellhist/tests/test_patterns.py @@ -0,0 +1,183 @@ +"""Tests for pattern detection algorithms.""" + +import pytest + +from shellhist.core import HistoryEntry, HistoryStore +from shellhist.core.patterns import ( + ngram_analysis, + detect_repetitive_commands, + detect_command_pairs, + detect_command_triplets, + detect_common_sequences, +) + + +class TestNgramAnalysis: + """Test n-gram analysis functionality.""" + + def test_empty_store(self): + """Test with empty store.""" + store = HistoryStore() + results = ngram_analysis(store, n=2) + + assert len(results) == 0 + + def test_simple_pairs(self): + """Test detecting command pairs.""" + store = HistoryStore() + + commands = [ + "git status", + "git log", + "git status", + "git log", + ] + + for cmd in commands: + store.add_entry(HistoryEntry(command=cmd)) + + results = ngram_analysis(store, n=2) + + assert len(results) > 0 + pair = results[0] + assert "git status -> git log" in " -> ".join(pair.commands) + + def test_triplets(self): + """Test detecting command triplets.""" + store = HistoryStore() + + commands = [ + "git add .", + "git commit", + "git push", + "git add .", + "git commit", + "git push", + ] + + for cmd in commands: + store.add_entry(HistoryEntry(command=cmd)) + + results = ngram_analysis(store, n=3) + + assert len(results) == 1 + assert results[0].frequency == 2 + + def test_min_frequency_filter(self): + """Test minimum frequency filtering.""" + store = HistoryStore() + + commands = [ + "git status", + "ls", + "git status", + ] + + for cmd in commands: + store.add_entry(HistoryEntry(command=cmd)) + + results = ngram_analysis(store, n=2, min_frequency=3) + + assert len(results) == 0 + + +class TestDetectRepetitiveCommands: + """Test repetitive command detection.""" + + def test_detect_repetitive(self): + """Test detecting repetitive single commands.""" + store = HistoryStore() + + for _ in range(5): + store.add_entry(HistoryEntry(command="git status")) + + for _ in range(2): + store.add_entry(HistoryEntry(command="ls")) + + results = detect_repetitive_commands(store, min_frequency=3) + + assert len(results) == 1 + assert results[0].commands == ("git status",) + assert results[0].frequency == 5 + + def test_no_repetitive_commands(self): + """Test when no commands are repetitive.""" + store = HistoryStore() + + for cmd in ["git status", "ls", "pwd"]: + store.add_entry(HistoryEntry(command=cmd)) + + results = detect_repetitive_commands(store, min_frequency=3) + + assert len(results) == 0 + + +class TestDetectCommandPairs: + """Test command pair detection.""" + + def test_detect_pairs(self): + """Test detecting command pairs.""" + store = HistoryStore() + + commands = [ + "git add .", + "git commit", + "git add .", + "git commit", + ] + + for cmd in commands: + store.add_entry(HistoryEntry(command=cmd)) + + results = detect_command_pairs(store, min_frequency=2) + + assert len(results) == 1 + + +class TestDetectCommandTriplets: + """Test command triplet detection.""" + + def test_detect_triplets(self): + """Test detecting command triplets.""" + store = HistoryStore() + + commands = [ + "git add .", + "git commit", + "git push", + "git add .", + "git commit", + "git push", + ] + + for cmd in commands: + store.add_entry(HistoryEntry(command=cmd)) + + results = detect_command_triplets(store, min_frequency=2) + + assert len(results) == 1 + assert len(results[0].commands) == 3 + + +class TestDetectCommonSequences: + """Test common sequence detection.""" + + def test_detect_sequences_various_lengths(self): + """Test detecting sequences of various lengths.""" + store = HistoryStore() + + commands = [ + "git add .", + "git commit", + "git push", + "git add .", + "git commit", + "git push", + ] + + for cmd in commands: + store.add_entry(HistoryEntry(command=cmd)) + + results = detect_common_sequences(store, max_length=3, min_occurrences=2) + + assert len(results) > 0