Files
man-card/tests/test_man_parser.py
2026-01-31 21:39:52 +00:00

169 lines
4.8 KiB
Python

"""Tests for man page parser."""
import pytest
from unittest.mock import patch, MagicMock
from man_card.man_parser import ManPageParser, CommandInfo, Option
SAMPLE_MAN_PAGE = """
NAME
ls - list directory contents
SYNOPSIS
ls [OPTION]... [FILE]...
DESCRIPTION
List information about the FILEs (the current directory by default).
OPTIONS
-a, --all
do not ignore entries starting with .
-l
use a long listing format
-h, --human-readable
with -l and -s, print sizes like 1K 234M 2G etc.
EXAMPLES
ls -la
ls -lh /var
"""
class TestCommandInfo:
"""Tests for CommandInfo dataclass."""
def test_default_values(self):
"""Test CommandInfo has correct default values."""
info = CommandInfo(name="test")
assert info.name == "test"
assert info.synopsis == ""
assert info.description == ""
assert info.options == []
assert info.examples == []
assert info.section == "1"
def test_with_values(self):
"""Test CommandInfo with all values."""
info = CommandInfo(
name="ls",
synopsis="ls [OPTION]... [FILE]...",
description="List directory contents",
options=[Option(flag="-a", description="show all files")],
examples=["ls -la"],
section="1"
)
assert info.name == "ls"
assert info.synopsis == "ls [OPTION]... [FILE]..."
assert len(info.options) == 1
class TestOption:
"""Tests for Option dataclass."""
def test_option_creation(self):
"""Test Option can be created with all fields."""
opt = Option(flag="-v", description="verbose output", argument="FILE")
assert opt.flag == "-v"
assert opt.description == "verbose output"
assert opt.argument == "FILE"
def test_option_optional_argument(self):
"""Test Option with optional argument."""
opt = Option(flag="-h", description="help")
assert opt.flag == "-h"
assert opt.argument is None
class TestManPageParser:
"""Tests for ManPageParser class."""
def setup_method(self):
"""Set up test fixtures."""
self.parser = ManPageParser()
@patch('subprocess.run')
def test_parse_simple_man_page(self, mock_run):
"""Test parsing a simple man page."""
mock_run.return_value = MagicMock(
returncode=0,
stdout=SAMPLE_MAN_PAGE
)
result = self.parser.parse("ls")
assert result.name == "ls"
assert "OPTION" in result.synopsis
@patch('subprocess.run')
def test_parse_extracts_options(self, mock_run):
"""Test that options are correctly extracted."""
mock_run.return_value = MagicMock(
returncode=0,
stdout=SAMPLE_MAN_PAGE
)
result = self.parser.parse("ls")
assert len(result.options) >= 2
@patch('subprocess.run')
def test_parse_extracts_examples(self, mock_run):
"""Test that examples are correctly extracted."""
mock_run.return_value = MagicMock(
returncode=0,
stdout=SAMPLE_MAN_PAGE
)
result = self.parser.parse("ls")
assert len(result.examples) >= 1
@patch('subprocess.run')
def test_parse_command_not_found(self, mock_run):
"""Test handling of missing command."""
mock_run.return_value = MagicMock(returncode=1, stderr="No manual entry for unknowncmd")
with pytest.raises(ValueError) as exc_info:
self.parser.parse("unknowncmd")
assert "command not found" in str(exc_info.value)
def test_parse_content_empty(self):
"""Test parsing empty content."""
result = self.parser._parse_content("", "test")
assert result.name == "test"
assert result.synopsis == ""
def test_parse_content_with_font_codes(self):
"""Test parsing content with font formatting codes."""
content = """
NAME
test - a test command
SYNOPSIS
test \\fB-v\\fR [FILE]
OPTIONS
\\fB-v\\fR
enable verbose mode
"""
result = self.parser._parse_content(content, "test")
assert result.name == "test"
assert "-v" in result.synopsis or "v" in result.synopsis
def test_section_pattern_recognition(self):
"""Test section pattern recognition."""
assert self.parser.SECTION_PATTERN.match("NAME")
assert self.parser.SECTION_PATTERN.match("SYNOPSIS")
assert self.parser.SECTION_PATTERN.match("OPTIONS")
assert not self.parser.SECTION_PATTERN.match("This is not a section")
def test_option_pattern_recognition(self):
"""Test option pattern recognition."""
match = self.parser.OPTION_PATTERN.match("-a, --all")
assert match is not None
assert "-a" in match.group(1)