1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
"""
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
|