This commit is contained in:
190
shellhist/tests/test_core.py
Normal file
190
shellhist/tests/test_core.py
Normal file
@@ -0,0 +1,190 @@
|
||||
"""Tests for core history loading and parsing."""
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
from datetime import datetime
|
||||
|
||||
import pytest
|
||||
|
||||
from shellhist.core import HistoryEntry, HistoryStore, HistoryLoader
|
||||
|
||||
|
||||
class TestHistoryEntry:
|
||||
"""Test HistoryEntry dataclass."""
|
||||
|
||||
def test_create_entry(self):
|
||||
"""Test creating a basic history entry."""
|
||||
entry = HistoryEntry(command="git status")
|
||||
assert entry.command == "git status"
|
||||
assert entry.timestamp is None
|
||||
assert entry.line_number == 0
|
||||
assert entry.shell_type == "unknown"
|
||||
|
||||
def test_entry_with_timestamp(self):
|
||||
"""Test creating an entry with timestamp."""
|
||||
ts = datetime.now()
|
||||
entry = HistoryEntry(command="ls -la", timestamp=ts)
|
||||
assert entry.timestamp == ts
|
||||
|
||||
def test_entry_equality(self):
|
||||
"""Test entry equality based on command."""
|
||||
entry1 = HistoryEntry(command="git status")
|
||||
entry2 = HistoryEntry(command="git status")
|
||||
entry3 = HistoryEntry(command="git log")
|
||||
|
||||
assert entry1 == entry2
|
||||
assert entry1 != entry3
|
||||
|
||||
def test_entry_hash(self):
|
||||
"""Test entry hash for use in sets/dicts."""
|
||||
entry1 = HistoryEntry(command="git status")
|
||||
entry2 = HistoryEntry(command="git status")
|
||||
|
||||
entry_set = {entry1, entry2}
|
||||
assert len(entry_set) == 1
|
||||
|
||||
|
||||
class TestHistoryStore:
|
||||
"""Test HistoryStore class."""
|
||||
|
||||
def test_empty_store(self):
|
||||
"""Test creating an empty store."""
|
||||
store = HistoryStore()
|
||||
assert len(store.entries) == 0
|
||||
assert len(store.command_frequency) == 0
|
||||
|
||||
def test_add_entry(self):
|
||||
"""Test adding entries to the store."""
|
||||
store = HistoryStore()
|
||||
entry = HistoryEntry(command="git status")
|
||||
|
||||
store.add_entry(entry)
|
||||
|
||||
assert len(store.entries) == 1
|
||||
assert store.get_frequency("git status") == 1
|
||||
|
||||
def test_frequency_tracking(self):
|
||||
"""Test command frequency tracking."""
|
||||
store = HistoryStore()
|
||||
|
||||
for _ in range(3):
|
||||
store.add_entry(HistoryEntry(command="git status"))
|
||||
|
||||
store.add_entry(HistoryEntry(command="git log"))
|
||||
|
||||
assert store.get_frequency("git status") == 3
|
||||
assert store.get_frequency("git log") == 1
|
||||
assert store.get_frequency("unknown") == 0
|
||||
|
||||
def test_most_frequent(self):
|
||||
"""Test getting most frequent commands."""
|
||||
store = HistoryStore()
|
||||
|
||||
store.add_entry(HistoryEntry(command="git status"))
|
||||
store.add_entry(HistoryEntry(command="git status"))
|
||||
store.add_entry(HistoryEntry(command="git status"))
|
||||
store.add_entry(HistoryEntry(command="git log"))
|
||||
store.add_entry(HistoryEntry(command="ls"))
|
||||
|
||||
most_frequent = store.get_most_frequent(limit=2)
|
||||
|
||||
assert most_frequent[0] == ("git status", 3)
|
||||
assert most_frequent[1] == ("git log", 1)
|
||||
|
||||
def test_get_unique_commands(self):
|
||||
"""Test getting unique commands."""
|
||||
store = HistoryStore()
|
||||
|
||||
store.add_entry(HistoryEntry(command="git status"))
|
||||
store.add_entry(HistoryEntry(command="git status"))
|
||||
store.add_entry(HistoryEntry(command="git log"))
|
||||
|
||||
unique = store.get_unique_commands()
|
||||
|
||||
assert len(unique) == 2
|
||||
assert "git status" in unique
|
||||
assert "git log" in unique
|
||||
|
||||
|
||||
class TestHistoryLoader:
|
||||
"""Test HistoryLoader class."""
|
||||
|
||||
def test_load_bash_history(self):
|
||||
"""Test parsing bash history format."""
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='_bash_history', delete=False) as f:
|
||||
f.write("git status\n")
|
||||
f.write("git log --oneline\n")
|
||||
f.write("ls -la\n")
|
||||
f.write("npm install\n")
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
loader = HistoryLoader(history_path=temp_path)
|
||||
store = loader.load()
|
||||
|
||||
assert len(store.entries) == 4
|
||||
assert store.get_unique_commands() == [
|
||||
"git status",
|
||||
"git log --oneline",
|
||||
"ls -la",
|
||||
"npm install",
|
||||
]
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
def test_load_bash_history_with_timestamps(self):
|
||||
"""Test parsing bash history with timestamps."""
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='_bash_history', delete=False) as f:
|
||||
f.write("#1700000000\n")
|
||||
f.write("git status\n")
|
||||
f.write("#1700000001\n")
|
||||
f.write("git log\n")
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
loader = HistoryLoader(history_path=temp_path)
|
||||
store = loader.load()
|
||||
|
||||
assert len(store.entries) == 2
|
||||
assert store.entries[0].timestamp is not None
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
def test_load_zsh_history(self):
|
||||
"""Test parsing zsh history format."""
|
||||
import os
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='_zsh_history', delete=False) as f:
|
||||
f.write(": 1700000000:0;git status\n")
|
||||
f.write(": 1700000001:0;git log --oneline\n")
|
||||
f.write("ls -la\n")
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
os.environ["SHELL"] = "/bin/zsh"
|
||||
loader = HistoryLoader(history_path=temp_path)
|
||||
store = loader.load()
|
||||
|
||||
assert len(store.entries) == 3
|
||||
assert store.entries[0].timestamp is not None
|
||||
del os.environ["SHELL"]
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
|
||||
def test_file_not_found(self):
|
||||
"""Test error handling for missing file."""
|
||||
loader = HistoryLoader(history_path="/nonexistent/path")
|
||||
|
||||
with pytest.raises(FileNotFoundError):
|
||||
loader.load()
|
||||
|
||||
def test_from_file_convenience_method(self):
|
||||
"""Test the from_file class method."""
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='_history', delete=False) as f:
|
||||
f.write("echo test\n")
|
||||
temp_path = f.name
|
||||
|
||||
try:
|
||||
store = HistoryLoader.from_file(temp_path)
|
||||
assert len(store.entries) == 1
|
||||
finally:
|
||||
os.unlink(temp_path)
|
||||
Reference in New Issue
Block a user