aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_docs.py
diff options
context:
space:
mode:
authoruser <user@clank>2026-08-27 15:27:51 +0200
committeruser <user@clank>2026-08-27 15:27:51 +0200
commitb5df6a7b1d73fc9740a077e8eca2d7fc8f6afe60 (patch)
tree246a0c777d44b9ee610b5988740eb29115b5cab8 /tests/test_docs.py
parenta manpage: slosh(1), installed, shipped, and held to the source (diff)
downloadslosh-b5df6a7b1d73fc9740a077e8eca2d7fc8f6afe60.tar.gz
slosh-b5df6a7b1d73fc9740a077e8eca2d7fc8f6afe60.tar.xz
slosh-b5df6a7b1d73fc9740a077e8eca2d7fc8f6afe60.zip
slosh(5): the file formats get their manpage; slosh(1) learns shaders
Section 5 is where unix keeps its file formats, and slosh has two documents sharing one syntax -- the configuration and the layouts -- so they share a page the way they share a parser. docs/slosh.5 covers the KDL subset, where the file lives and how reload refuses a broken one, include and its precedence, every top-level setting grouped the way config.md groups them, the theme block, the shader vocabulary with the expression language summarised, the states and their ranking, the keys block including direct bindings, and the layout schema (tab, pane, and their properties). Held to the source like slosh.1 before it: every name in config.c's KNOWN_TOP -- the list the loader refuses unknown settings against, itself held to the loader by test_config.py -- must appear in the page, so a knob cannot be added without this page hearing about it. The pair must cross-reference each other, and both must be pure ASCII and lint clean under groff -ww. slosh(1) grows a SHADERS section -- the one feature a synopsis reader would never guess a multiplexer had -- and its SEE ALSO now names slosh(5) and nothing else: the other multiplexers can advertise themselves. Install puts the page under share/man/man5, the release tarballs carry both pages, and the Homebrew formula installs what the commit it is building has, guarded as before.
Diffstat (limited to 'tests/test_docs.py')
-rwxr-xr-xtests/test_docs.py74
1 files changed, 49 insertions, 25 deletions
diff --git a/tests/test_docs.py b/tests/test_docs.py
index def76ff..17eddc1 100755
--- a/tests/test_docs.py
+++ b/tests/test_docs.py
@@ -237,15 +237,18 @@ def test_html_in_the_source_is_escaped():
check("and not a tag", "<script>" not in got, got[:400])
-# ---- the manpage ----------------------------------------------------------
+# ---- the manpages ---------------------------------------------------------
#
-# docs/slosh.1 is hand-written roff, and prose about a program drifts from the
-# program unless something holds them together. The same idea as the nav
-# checks above: the source of truth for what the CLI accepts is main.c's
-# parser and for what the environment means is the code that reads it, so the
-# manpage is checked against those rather than against a copy of itself.
+# docs/slosh.1 and docs/slosh.5 are hand-written roff, and prose about a
+# program drifts from the program unless something holds them together. The
+# same idea as the nav checks above: the source of truth for what the CLI
+# accepts is main.c's parser, for the environment the code that reads it, and
+# for the settings config.c's KNOWN_TOP (itself held to the loader by
+# test_config.py) -- so the pages are checked against those rather than
+# against copies of themselves.
MAN = os.path.join(DOCS, "slosh.1")
+MAN5 = os.path.join(DOCS, "slosh.5")
def test_the_manpage_covers_the_cli():
@@ -278,27 +281,47 @@ def test_the_manpage_covers_the_environment():
check(f"the manpage documents ${n}", n in man, n)
-def test_the_manpage_is_clean_roff():
- """Pure ASCII (a manpage travels through implementations that never heard
- of preconv) and, where groff is present, no warnings at its strictest."""
- raw = open(MAN, "rb").read()
- bad = [i for i, b in enumerate(raw) if b > 0x7F]
- check("the roff is pure ASCII", not bad, f"non-ASCII at byte {bad[:3]}")
+def test_the_config_manpage_covers_the_settings():
+ """Every top-level setting the loader knows appears in slosh(5). KNOWN_TOP
+ is the list the loader refuses unknown names against, so a knob cannot be
+ added without this page hearing about it."""
+ man5 = open(MAN5).read()
+ config_c = open(os.path.join(ROOT, "src", "config.c")).read()
+ block = re.search(r"KNOWN_TOP\[\] = \{(.*?)\};", config_c, re.S)
+ check("KNOWN_TOP was found in config.c", block is not None, "")
+ names = re.findall(r'"(\w+)"', block.group(1)) if block else []
+ check("and it is the whole vocabulary", len(names) > 40, str(len(names)))
+ for n in names:
+ check(f"slosh(5) documents {n}", n in man5, n)
+
+def test_the_manpages_are_clean_roff():
+ """Pure ASCII (a manpage travels through implementations that never heard
+ of preconv), cross-referencing each other, and, where groff is present,
+ no warnings at its strictest."""
import shutil
- if not shutil.which("groff"):
- return # the ASCII check above still ran; lint where lint exists
- r = subprocess.run(
- ["groff", "-man", "-rCHECKSTYLE=3", "-ww", "-z", MAN],
- capture_output=True,
- text=True,
- )
- check(
- "groff -ww has nothing to say",
- r.returncode == 0 and not r.stderr.strip(),
- r.stderr.strip()[:300],
- )
+ for man in (MAN, MAN5):
+ name = os.path.basename(man)
+ raw = open(man, "rb").read()
+ bad = [i for i, b in enumerate(raw) if b > 0x7F]
+ check(f"{name} is pure ASCII", not bad, f"non-ASCII at byte {bad[:3]}")
+
+ if shutil.which("groff"):
+ r = subprocess.run(
+ ["groff", "-man", "-rCHECKSTYLE=3", "-ww", "-z", man],
+ capture_output=True,
+ text=True,
+ )
+ check(
+ f"groff -ww has nothing to say about {name}",
+ r.returncode == 0 and not r.stderr.strip(),
+ r.stderr.strip()[:300],
+ )
+
+ # The pair reference each other, so a reader who found one finds both.
+ check("slosh(1) points at slosh(5)", "slosh (5)" in open(MAN).read(), "")
+ check("slosh(5) points at slosh(1)", "slosh (1)" in open(MAN5).read(), "")
if __name__ == "__main__":
@@ -312,5 +335,6 @@ if __name__ == "__main__":
test_html_in_the_source_is_escaped()
test_the_manpage_covers_the_cli()
test_the_manpage_covers_the_environment()
- test_the_manpage_is_clean_roff()
+ test_the_config_manpage_covers_the_settings()
+ test_the_manpages_are_clean_roff()
sys.exit(report())