diff options
Diffstat (limited to 'tests/helpers/check_exports.py')
| -rw-r--r-- | tests/helpers/check_exports.py | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/tests/helpers/check_exports.py b/tests/helpers/check_exports.py new file mode 100644 index 0000000..0d10014 --- /dev/null +++ b/tests/helpers/check_exports.py @@ -0,0 +1,42 @@ +"""Require the shared library to export exactly the public header functions.""" + +import argparse +from pathlib import Path +import re +import subprocess + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument('--allow-export', action='append', default=[]) + parser.add_argument('nm') + parser.add_argument('library') + parser.add_argument('headers', nargs='+') + args = parser.parse_args() + declarations = re.compile( + r"^[^\n;{}]*\b(yasl_\w+)\s*\([^;{}]*\);", re.MULTILINE + ) + expected = set() + for header in args.headers: + source = re.sub(r"/\*.*?\*/|//[^\n]*", "", Path(header).read_text(), flags=re.DOTALL) + expected.update(declarations.findall(source)) + if not expected: + raise SystemExit("No public function declarations found") + + output = subprocess.check_output( + [args.nm, "-D", "--defined-only", "--format=posix", args.library], text=True + ) + exported = {line.split()[0] for line in output.splitlines() if line.strip()} + missing = expected - exported + leaked = exported - expected - set(args.allow_export) + if missing or leaked: + if missing: + print("Missing public exports:", ", ".join(sorted(missing))) + if leaked: + print("Unexpected exports:", ", ".join(sorted(leaked))) + raise SystemExit(1) + print(f"Verified {len(expected)} public exports") + + +if __name__ == "__main__": + main() |
