Language-neutral test-runner CONTRACT shared across vis language packs.
ONE vocabulary for selecting and reporting tests, modeled on lazytest's CLI (NoahTheDuke/lazytest): single test, many namespaces, ignore by name or by metadata tag. A future python / js language pack returns the SAME shaped result map and accepts the SAME selector keys, so the agent learns the words once and they carry across languages.
The selector vocabulary and the result shape are DEFINED with clojure.spec
(::selectors, ::result). selector-keys / result-keys are DERIVED from
those specs (via s/form) so the spec is the single source of truth - a key
never drifts out of sync with its documentation.
SELECTOR keys (all optional; the Python dict the tool receives):
:paths vector of ENTRIES - WHERE the tests are. The ONE way a call names
what to run, in every language. An entry is a file, a directory,
or a NODE ID <path>::<test-name> naming ONE test inside it
(::<test-name> alone = wherever it lives). Splitting on the
first :: is pytest's own node-id grammar, so the same string
selects in every pack: a pack resolves the path the way its
runner discovers tests under it (clojure reads each *_test.clj
for its ns and maps a SOURCE file to its *-test ns; python/bun
hand paths to pytest / bun test) and narrows to the named test.
No namespace, module, package or second name key rides beside it.
:include vector of metadata-tag strings - run only tests carrying one of
these tags, e.g. "integration". (lazytest -i)
:exclude vector of metadata-tag strings - skip tests carrying one of
these tags, e.g. "slow". (lazytest -e)
PRECEDENCE (copied verbatim from lazytest):
RESULT keys (the uniform map every pack returns): :language "clojure" | "python" | ... :mode "repl" | "cli" - which execution path ran :framework "clojure.test" | "lazytest" | ... (repl path) :tool "clj" | "lein" | "bb" | ... (cli path) :ns the namespace(s) that RAN - what a pack reports back, never what the call selected (that is :paths) :total test count actually run :pass passing count :fail count that did NOT pass - assertion failures AND errors :errored the SUBSET of :fail that THREW instead of asserting false (:fail minus :errored is the assertion failures). Already inside :fail and :total - never add it to either again :selected count chosen by the selectors (before skips) :skipped count filtered out by :exclude / source :skip :failures [{:ns :test :type :message :file :line} ...] - EVERY fault, in ONE list; :type is "fail" (an assertion came back false) or "error" (the test threw), so nothing is restated in a second parallel collection :output captured run log (framework report + error/exception traces)
Language-neutral test-runner CONTRACT shared across vis language packs.
ONE vocabulary for selecting and reporting tests, modeled on lazytest's CLI
(NoahTheDuke/lazytest): single test, many namespaces, ignore by name or by
metadata tag. A future python / js language pack returns the SAME shaped
result map and accepts the SAME selector keys, so the agent learns the
words once and they carry across languages.
The selector vocabulary and the result shape are DEFINED with clojure.spec
(`::selectors`, `::result`). `selector-keys` / `result-keys` are DERIVED from
those specs (via `s/form`) so the spec is the single source of truth - a key
never drifts out of sync with its documentation.
SELECTOR keys (all optional; the Python dict the tool receives):
:paths vector of ENTRIES - WHERE the tests are. The ONE way a call names
what to run, in every language. An entry is a file, a directory,
or a NODE ID `<path>::<test-name>` naming ONE test inside it
(`::<test-name>` alone = wherever it lives). Splitting on the
first `::` is pytest's own node-id grammar, so the same string
selects in every pack: a pack resolves the path the way its
runner discovers tests under it (clojure reads each *_test.clj
for its ns and maps a SOURCE file to its *-test ns; python/bun
hand paths to pytest / bun test) and narrows to the named test.
No namespace, module, package or second name key rides beside it.
:include vector of metadata-tag strings - run only tests carrying one of
these tags, e.g. "integration". (lazytest -i)
:exclude vector of metadata-tag strings - skip tests carrying one of
these tags, e.g. "slow". (lazytest -e)
PRECEDENCE (copied verbatim from lazytest):
- :exclude OVERRIDES :include (a test tagged both is skipped).
- a node id's test name narrows within what :paths already selected.
- source-level :skip OVERRIDES :focus.
RESULT keys (the uniform map every pack returns):
:language "clojure" | "python" | ...
:mode "repl" | "cli" - which execution path ran
:framework "clojure.test" | "lazytest" | ... (repl path)
:tool "clj" | "lein" | "bb" | ... (cli path)
:ns the namespace(s) that RAN - what a pack reports back, never
what the call selected (that is :paths)
:total test count actually run
:pass passing count
:fail count that did NOT pass - assertion failures AND errors
:errored the SUBSET of :fail that THREW instead of asserting false
(:fail minus :errored is the assertion failures). Already
inside :fail and :total - never add it to either again
:selected count chosen by the selectors (before skips)
:skipped count filtered out by :exclude / source :skip
:failures [{:ns :test :type :message :file :line} ...] - EVERY fault, in
ONE list; :type is "fail" (an assertion came back false) or
"error" (the test threw), so nothing is restated in a second
parallel collection
:output captured run log (framework report + error/exception traces)(normalize-selectors m)Normalize a raw selector map (the Python dict the tool received) into the
canonical shape {:paths [{:path :var}] :include [str] :exclude [str]}.
ONE selection vocabulary - entries in, whatever the pack's runner discovers
under them out. Each entry is SPLIT here (see split-node-id) so every pack
reads the node id the same way; a pack that runs namespaces (clojure)
resolves the path halves to them itself and carries the result in its OWN
key, so no second selector spelling ever reaches this map.
Normalize a raw selector map (the Python dict the tool received) into the
canonical shape `{:paths [{:path :var}] :include [str] :exclude [str]}`.
ONE selection vocabulary - entries in, whatever the pack's runner discovers
under them out. Each entry is SPLIT here (see `split-node-id`) so every pack
reads the node id the same way; a pack that runs namespaces (clojure)
resolves the path halves to them itself and carries the result in its OWN
key, so no second selector spelling ever reaches this map.The uniform result-map keys every language pack's runner returns. Derived
from the ::result spec.
The uniform result-map keys every language pack's runner returns. Derived from the `::result` spec.
(selected? {:keys [vars include exclude]}
{test-ns :ns test-name :name tags :tags})Apply the lazytest precedence to ONE test, given selectors a pack has already
RESOLVED. vars is what the node ids in :paths became -
[{:ns <ns-or-nil> :name <test-name>}], nil :ns meaning 'wherever it lives' -
because only the pack knows how a path turns into a namespace. test is
{:ns :name :tags}. Returns true when the test should RUN: an :exclude tag
wins over everything, a non-empty var list narrows by name, and :include
gates by tag when present.
Apply the lazytest precedence to ONE test, given selectors a pack has already
RESOLVED. `vars` is what the node ids in :paths became -
`[{:ns <ns-or-nil> :name <test-name>}]`, nil :ns meaning 'wherever it lives' -
because only the pack knows how a path turns into a namespace. `test` is
`{:ns :name :tags}`. Returns true when the test should RUN: an :exclude tag
wins over everything, a non-empty var list narrows by name, and :include
gates by tag when present.The optional selector keys a runner tool accepts on its opts dict. Derived
from the ::selectors spec.
The optional selector keys a runner tool accepts on its opts dict. Derived from the `::selectors` spec.
(split-node-id entry)Split ONE :paths entry into {:path :var}. An entry is a path, a NODE ID
<path>::<test-name>, or ::<test-name> (no path - wherever it lives).
The split is on the FIRST ::, which is pytest's own node-id grammar, so one
string names a file, a directory AND a single test in every pack instead of a
second only / filter key repeating what a path already said. Blank halves
come back nil, so {:path nil :var nil} is a total answer for junk.
Split ONE `:paths` entry into `{:path :var}`. An entry is a path, a NODE ID
`<path>::<test-name>`, or `::<test-name>` (no path - wherever it lives).
The split is on the FIRST `::`, which is pytest's own node-id grammar, so one
string names a file, a directory AND a single test in every pack instead of a
second `only` / `filter` key repeating what a path already said. Blank halves
come back nil, so `{:path nil :var nil}` is a total answer for junk.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |