Files
totk-pc-recomp/tests/settings_doc_check.py
Valiantsin DzerakhandClaude Opus 5.5 9712658328 List the settings totk.ini.example leaves out in docs/settings.md
146 of the 254 names in known[] (runtime/cfg.c) were described nowhere for a reader: diagnostics, test hooks, paths and
experiments. docs/settings.md gives each one what it does, the effect of changing it and a safety level. The rows come
from reading the code, and most effects have not been checked in a run.

tests/settings_doc_check.py fails when a known name is in neither file, when the page lists an unknown name, or when a
default on the page differs from metas[] or an rt_knob call.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 10:18:50 +03:00

63 lines
2.8 KiB
Python

"""Every setting the runtime knows is described: in totk.ini.example for players or in docs/settings.md for the rest.
python tests/settings_doc_check.py
Fails when a name of known[] (runtime/cfg.c) is in neither file, when docs/settings.md lists a name the runtime does
not know, or when a default written in docs/settings.md differs from the one the code holds: the metas[] table of
runtime/cfg.c or an rt_knob(name, default) call. No game files, no build.
"""
import re
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent.parent
def known_names(cfg):
start = cfg.index('static const char *const known[]')
return set(re.findall(r'"([A-Z0-9_]+)"', cfg[start:cfg.index('};', start)]))
def code_defaults(cfg):
"""{name: default} of metas[] and of the rt_knob calls; metas[] wins, as it is where a default lives."""
found = {}
for path in (ROOT / 'runtime').rglob('*'):
if path.suffix in ('.c', '.cpp', '.h'):
text = path.read_text(encoding='utf-8', errors='replace')
found.update(re.findall(r'rt_knob\("(?:TOTK_)?([A-Z0-9_]+)", *"([^"]*)"\)', text))
found.update(re.findall(r'\{"([A-Z0-9_]+)", "([^"]*)", (?:"[^"]*"|NULL)', cfg))
return found
def main():
cfg = (ROOT / 'runtime' / 'cfg.c').read_text(encoding='utf-8')
example = (ROOT / 'totk.ini.example').read_text(encoding='utf-8')
doc = (ROOT / 'docs' / 'settings.md').read_text(encoding='utf-8')
known = known_names(cfg)
in_example = {name.upper() for name in re.findall(r'^#? ?([a-z][a-z0-9_]*) = ', example, re.M)}
rows = re.findall(r'^\| `([a-z0-9_<>]+)`(?: \(default ([^)]*)\))? \|(.*)$', doc, re.M)
in_doc = {name.upper() for name, _, _ in rows if '<' not in name}
# The row of the button bindings names each key in its text.
for name, _, text in rows:
if '<' in name:
in_doc |= {key.upper() for key in re.findall(r'`(bind_[a-z_]+)`', text)}
problems = [f'{name}: in runtime/cfg.c known[], described in neither totk.ini.example nor docs/settings.md'
for name in sorted(known - in_example - in_doc)]
problems += [f'{name}: in docs/settings.md, not in runtime/cfg.c known[]' for name in sorted(in_doc - known)]
defaults = code_defaults(cfg)
for name, written, _ in rows:
code = defaults.get(name.upper())
if code and written != f'`{code}`':
problems.append(f'{name}: docs/settings.md says default {written or "none"}, the code says {code}')
for problem in problems:
print(problem)
print(f'settings_doc_check: {len(known)} names, {len(known & in_example)} in totk.ini.example, '
f'{len(known & in_doc)} in docs/settings.md, {len(problems)} problems')
return 1 if problems else 0
if __name__ == '__main__':
sys.exit(main())