Source code for simvx.core.testing.selftest

"""Exit codes for the headless self-checks examples run behind ``--test``.

Three outcomes, three codes::

    0   the mechanic works
    1   the mechanic is broken
    2   this environment cannot answer the question

Without the third, an example that needs an optional package (or a device this
machine has not got) either fails as though the mechanic were broken or passes
as though the fallback it measured were the thing under test. Raise
:class:`Unsupported` from inside the check to say so, and let
:func:`run_selftest` turn it into the exit code::

    def _selftest() -> bool:
        ...
        if backend != "JoltPhysics":
            raise Unsupported("install simvx-physics-jolt to check the Jolt half")
        print("SELFTEST:", "PASS" if ok else "FAIL")
        return ok

    if "--test" in sys.argv:
        sys.exit(run_selftest(_selftest))

Report the checks that DID run before raising: a check that ran on a fallback
still says something, and a failure among them is a genuine failure, so raise
only once nothing else has gone wrong.
"""

from collections.abc import Callable

__all__ = ["SELFTEST_FAIL", "SELFTEST_PASS", "SELFTEST_UNSUPPORTED", "Unsupported", "run_selftest"]

#: The self-check ran and every claim held.
SELFTEST_PASS = 0
#: The self-check ran and something it asserts is broken.
SELFTEST_FAIL = 1
#: The self-check could not run here: a capability it needs is absent.
SELFTEST_UNSUPPORTED = 2


[docs] class Unsupported(Exception): """Raised by a self-check whose environment lacks a capability it needs. The message says which capability, and how to get it where that is actionable ("install simvx-physics-jolt"). It is not a failure: the question was never put to the code under test. """
[docs] def run_selftest(check: Callable[[], bool]) -> int: """Run *check* and return the process exit code for its outcome. ``SELFTEST_PASS`` when it returns true, ``SELFTEST_FAIL`` when it returns false, ``SELFTEST_UNSUPPORTED`` when it raises :class:`Unsupported`. Any other exception propagates: an unexpected traceback is a failure worth seeing in full, not an exit code. """ try: passed = check() except Unsupported as exc: print(f"SELFTEST: UNSUPPORTED ({exc})") return SELFTEST_UNSUPPORTED return SELFTEST_PASS if passed else SELFTEST_FAIL