From 33b4b8fefe365f87b4ddac8247a16036c97cda20 Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Sat, 31 Jan 2026 21:39:52 +0000 Subject: [PATCH] Initial upload: man-card CLI tool with PDF/PNG generation, templates, and tests --- tests/test_man_parser.py | 168 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 tests/test_man_parser.py diff --git a/tests/test_man_parser.py b/tests/test_man_parser.py new file mode 100644 index 0000000..fd14585 --- /dev/null +++ b/tests/test_man_parser.py @@ -0,0 +1,168 @@ +"""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)