From d5f5432c44969150a730366ecbdfe70114c91276 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sat, 31 Jan 2026 13:13:12 +0000 Subject: [PATCH] Initial upload with CI/CD workflow --- shellhist/tests/test_core.py | 190 +++++++++++++++++++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 shellhist/tests/test_core.py diff --git a/shellhist/tests/test_core.py b/shellhist/tests/test_core.py new file mode 100644 index 0000000..c8dd7ec --- /dev/null +++ b/shellhist/tests/test_core.py @@ -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)