Initial upload: Shell History Alias Generator with full test suite
Some checks failed
CI / test (push) Failing after 12s
Some checks failed
CI / test (push) Failing after 12s
This commit is contained in:
218
tests/test_parsers.py
Normal file
218
tests/test_parsers.py
Normal file
@@ -0,0 +1,218 @@
|
||||
"""Tests for history parsers."""
|
||||
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
from shell_alias_gen.parsers import (
|
||||
HistoryParserFactory,
|
||||
BashHistoryParser,
|
||||
ZshHistoryParser,
|
||||
FishHistoryParser,
|
||||
ParsedCommand,
|
||||
)
|
||||
|
||||
|
||||
class TestParsedCommand:
|
||||
"""Tests for ParsedCommand class."""
|
||||
|
||||
def test_normalized(self):
|
||||
"""Test command normalization."""
|
||||
cmd = ParsedCommand(raw_command=" git status ")
|
||||
assert cmd.normalized == "git status"
|
||||
|
||||
def test_words(self):
|
||||
"""Test word splitting."""
|
||||
cmd = ParsedCommand(raw_command="git checkout -b feature")
|
||||
assert cmd.words == ["git", "checkout", "-b", "feature"]
|
||||
|
||||
|
||||
class TestBashHistoryParser:
|
||||
"""Tests for BashHistoryParser class."""
|
||||
|
||||
def test_parse_content(self):
|
||||
"""Test parsing bash history content."""
|
||||
parser = BashHistoryParser()
|
||||
content = "ls -la\ncd /tmp\ngit status"
|
||||
|
||||
commands = parser.parse_content(content)
|
||||
assert len(commands) == 3
|
||||
assert commands[0].raw_command == "ls -la"
|
||||
assert commands[1].raw_command == "cd /tmp"
|
||||
|
||||
def test_parse_file(self):
|
||||
"""Test parsing bash history file."""
|
||||
parser = BashHistoryParser()
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.bash_history', delete=False) as f:
|
||||
f.write("echo hello\nworld\n")
|
||||
f.flush()
|
||||
filepath = f.name
|
||||
|
||||
try:
|
||||
commands = parser.parse_file(filepath)
|
||||
assert len(commands) == 2
|
||||
finally:
|
||||
os.unlink(filepath)
|
||||
|
||||
def test_parse_file_not_found(self):
|
||||
"""Test parsing non-existent file."""
|
||||
parser = BashHistoryParser()
|
||||
commands = parser.parse_file("/nonexistent/path")
|
||||
assert commands == []
|
||||
|
||||
def test_parse_content_skips_comments(self):
|
||||
"""Test that comments are skipped."""
|
||||
parser = BashHistoryParser()
|
||||
content = "# this is a comment\nls -la\n# another comment"
|
||||
|
||||
commands = parser.parse_content(content)
|
||||
assert len(commands) == 1
|
||||
assert commands[0].raw_command == "ls -la"
|
||||
|
||||
|
||||
class TestZshHistoryParser:
|
||||
"""Tests for ZshHistoryParser class."""
|
||||
|
||||
def test_parse_content(self):
|
||||
"""Test parsing zsh history content."""
|
||||
parser = ZshHistoryParser()
|
||||
content = ": 1704067200:0;ls -la\n: 1704067201:0;cd /tmp"
|
||||
|
||||
commands = parser.parse_content(content)
|
||||
assert len(commands) == 2
|
||||
assert commands[0].raw_command == "ls -la"
|
||||
assert commands[1].raw_command == "cd /tmp"
|
||||
|
||||
def test_parse_content_with_special_chars(self):
|
||||
"""Test parsing zsh content with special characters."""
|
||||
parser = ZshHistoryParser()
|
||||
content = ": 1704067200:0;git commit -m 'fix: bug fix'"
|
||||
|
||||
commands = parser.parse_content(content)
|
||||
assert len(commands) == 1
|
||||
assert commands[0].raw_command == "git commit -m 'fix: bug fix'"
|
||||
|
||||
def test_parse_file(self):
|
||||
"""Test parsing zsh history file."""
|
||||
parser = ZshHistoryParser()
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.zsh_history', delete=False) as f:
|
||||
f.write(": 1704067200:0;echo test\n")
|
||||
f.flush()
|
||||
filepath = f.name
|
||||
|
||||
try:
|
||||
commands = parser.parse_file(filepath)
|
||||
assert len(commands) == 1
|
||||
finally:
|
||||
os.unlink(filepath)
|
||||
|
||||
|
||||
class TestFishHistoryParser:
|
||||
"""Tests for FishHistoryParser class."""
|
||||
|
||||
def test_parse_content(self):
|
||||
"""Test parsing fish history content."""
|
||||
parser = FishHistoryParser()
|
||||
import json
|
||||
content = json.dumps([
|
||||
{"text": "ls -la", "timestamp": 1704067200},
|
||||
{"text": "cd /tmp", "timestamp": 1704067201},
|
||||
])
|
||||
|
||||
commands = parser.parse_content(content)
|
||||
assert len(commands) == 2
|
||||
assert commands[0].raw_command == "ls -la"
|
||||
|
||||
def test_parse_content_invalid_json(self):
|
||||
"""Test parsing invalid json returns empty."""
|
||||
parser = FishHistoryParser()
|
||||
commands = parser.parse_content("not valid json")
|
||||
assert commands == []
|
||||
|
||||
def test_parse_content_empty_list(self):
|
||||
"""Test parsing empty list."""
|
||||
parser = FishHistoryParser()
|
||||
commands = parser.parse_content("[]")
|
||||
assert commands == []
|
||||
|
||||
def test_parse_file(self):
|
||||
"""Test parsing fish history file."""
|
||||
parser = FishHistoryParser()
|
||||
with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as f:
|
||||
import json
|
||||
json.dump([{"text": "test command"}], f)
|
||||
filepath = f.name
|
||||
|
||||
try:
|
||||
commands = parser.parse_file(filepath)
|
||||
assert len(commands) == 1
|
||||
finally:
|
||||
os.unlink(filepath)
|
||||
|
||||
|
||||
class TestHistoryParserFactory:
|
||||
"""Tests for HistoryParserFactory class."""
|
||||
|
||||
def test_get_bash_parser(self):
|
||||
"""Test getting bash parser."""
|
||||
parser = HistoryParserFactory.get_parser("bash")
|
||||
assert isinstance(parser, BashHistoryParser)
|
||||
|
||||
def test_get_zsh_parser(self):
|
||||
"""Test getting zsh parser."""
|
||||
parser = HistoryParserFactory.get_parser("zsh")
|
||||
assert isinstance(parser, ZshHistoryParser)
|
||||
|
||||
def test_get_fish_parser(self):
|
||||
"""Test getting fish parser."""
|
||||
parser = HistoryParserFactory.get_parser("fish")
|
||||
assert isinstance(parser, FishHistoryParser)
|
||||
|
||||
def test_get_unknown_parser(self):
|
||||
"""Test getting unknown parser returns None."""
|
||||
parser = HistoryParserFactory.get_parser("unknown")
|
||||
assert parser is None
|
||||
|
||||
def test_get_supported_shells(self):
|
||||
"""Test getting supported shells list."""
|
||||
shells = HistoryParserFactory.get_supported_shells()
|
||||
assert "bash" in shells
|
||||
assert "zsh" in shells
|
||||
assert "fish" in shells
|
||||
|
||||
def test_detect_shell_from_file(self):
|
||||
"""Test shell detection from file path."""
|
||||
assert HistoryParserFactory.detect_shell_from_file("/path/.bash_history") == "bash"
|
||||
assert HistoryParserFactory.detect_shell_from_file("/path/.zsh_history") == "zsh"
|
||||
assert HistoryParserFactory.detect_shell_from_file("/path/commands.json") == "fish"
|
||||
|
||||
def test_case_insensitive_shell(self):
|
||||
"""Test shell type is case insensitive."""
|
||||
parser1 = HistoryParserFactory.get_parser("BASH")
|
||||
parser2 = HistoryParserFactory.get_parser("Bash")
|
||||
assert isinstance(parser1, BashHistoryParser)
|
||||
assert isinstance(parser2, BashHistoryParser)
|
||||
|
||||
|
||||
class TestBaseParserValidation:
|
||||
"""Tests for base parser validation methods."""
|
||||
|
||||
def test_valid_alias_names(self):
|
||||
"""Test valid alias name validation."""
|
||||
parser = BashHistoryParser()
|
||||
assert parser.validate_alias_name("gco") is True
|
||||
assert parser.validate_alias_name("_git") is True
|
||||
assert parser.validate_alias_name("git_checkout") is True
|
||||
|
||||
def test_invalid_alias_names(self):
|
||||
"""Test invalid alias name validation."""
|
||||
parser = BashHistoryParser()
|
||||
assert parser.validate_alias_name("") is False
|
||||
assert parser.validate_alias_name("123abc") is False
|
||||
assert parser.validate_alias_name("git-commit") is False
|
||||
|
||||
def test_sanitize_alias_name(self):
|
||||
"""Test alias name sanitization."""
|
||||
parser = BashHistoryParser()
|
||||
assert parser.sanitize_alias_name("git checkout") == "gitcheckout"
|
||||
assert parser.sanitize_alias_name("123test").startswith("alias")
|
||||
assert parser.sanitize_alias_name("docker-compose") == "dockercompose"
|
||||
Reference in New Issue
Block a user