""" The man page is generated from the parser; these keep the generator honest. An option added to an action must reach the page, every exit code must be explained, and troff must read the result without a warning. """ import argparse import os import shutil import subprocess import pytest from meshbay_cli import __main__ as cli from meshbay_cli import errors, manpage def _section(page: str, start: str) -> str: return page.split(start + "\n", 1)[1].split("\n.S", 1)[0] def _entry(option: str) -> str: """How an option opens its entry: `.TP`, then the option in bold.""" return f"\\fB{manpage._roff(option)}\\fR" def test_every_action_and_option_is_in_its_section(): page = manpage.render() parser = cli.build_parser() glob = _section(page, ".SH GLOBAL OPTIONS") for a in parser._actions: for option in a.option_strings: assert _entry(option) in glob, f"global {option} missing" sub = next(a for a in parser._actions if isinstance(a, argparse._SubParsersAction)) assert list(sub.choices) == list(cli.ACTIONS) for name, sp in sub.choices.items(): own = _section(page, f".SS {manpage._roff(name)}") for a in sp._actions: if isinstance(a, argparse._HelpAction): continue if a.option_strings and _entry(a.option_strings[0]) in glob: continue # a global one, listed once if a.option_strings: for option in a.option_strings: assert _entry(option) in own, f"{name} {option} missing" elif a.choices: for choice in a.choices: assert _entry(choice) in own, f"{name} {choice} missing" else: meta = a.metavar or a.dest.upper() assert f"\\fI{manpage._roff(meta)}\\fR" in own, f"{name} {meta} missing" def test_every_exit_code_is_explained(): codes = {v for k, v in vars(errors).items() if k.isupper() and isinstance(v, int)} assert codes | {0} == set(manpage.EXIT_CODES) def test_names_and_text_cannot_break_the_page(): assert manpage._roff(".hidden") == "\\&.hidden" assert manpage._roff("a\\b — c-d") == "a\\eb \\[u2014] c\\-d" @pytest.mark.skipif(not shutil.which("groff"), reason="groff not installed") def test_troff_reads_it_without_a_warning(tmp_path): page = tmp_path / "meshbay-cli.1" page.write_text(manpage.render(), encoding="ascii") # nothing past ASCII left r = subprocess.run(["groff", "-man", "-Tutf8", "-ww", "-z", str(page)], capture_output=True, text=True, env={**os.environ, "LC_ALL": "C"}) assert r.returncode == 0 and not r.stderr, r.stderr