The feature was built and never tested. Three things were missing. The two packages holding a ring of macros and a macro that never settles were not dependencies of the test stanza, so both non-termination refusals failed on "no package at ..." rather than on their own reason. They fire, and now the suite sees them fire. The positive half of the rule had no acceptance case at all -- only the refusal that pins the bare name. pkg-macro.flan is asserted at three opt levels and on the dev path, which is where six package macros and the program's own coexist in one file. And the dev loop was broken in exactly the way that matters most here. Session held the imported macro set but *replaced* it on every evaluation, and the one form C-c C-c sends carries no import -- so (mac/twice 4) compiled on the build and came back "unknown function" on the first reload. It unions now. test_session drives two evaluations, because one proves nothing: the first could have re-supplied the set. BUILT.md said the expander collects from the prelude and the file being compiled. It collects from imported packages too, and the refusal's old reasoning -- that this needed a second import resolver -- was wrong for a reason worth keeping written down. Cold build cost roughly doubles for a program importing a package that declares macros: a macro module is built per round and the package's rounds are its own. Warm is unchanged at ~70ms.
172 lines
8.0 KiB
Plaintext
172 lines
8.0 KiB
Plaintext
(tests
|
|
(names test_flan test_acceptance test_reload test_agent test_session test_dev test_emacs test_repl test_cider)
|
|
; Explicit because test_sanitize lives in this directory and is not one of
|
|
; these: two stanzas in one directory have to say which modules are whose.
|
|
; watchdog is every binary's clock: a hanging test reports nothing, so each
|
|
; of these arms an alarm that turns "for ever" into a failing run.
|
|
(modules test_flan test_acceptance test_reload test_agent test_session
|
|
test_dev test_emacs test_repl test_cider watchdog)
|
|
(libraries flan unix)
|
|
; The acceptance programs are part of the test corpus: if the reader, the
|
|
; parser or the checker regresses on them we want to know here, not at the CLI.
|
|
(deps
|
|
(file %{workspace_root}/calc-me.flan)
|
|
(file %{workspace_root}/sand.flan)
|
|
; The brush sheet. sand.flan no longer embeds it — the front-end was cut back
|
|
; to what lisp/sand.lisp and sand.jank have — so nothing in the corpus reads
|
|
; it today. Kept as a dependency because it is still in the workspace and an
|
|
; embed is read by the *checker*, relative to the file the form is written
|
|
; in, which is the rule any program picking it up again would meet.
|
|
(file %{workspace_root}/brush.png)
|
|
; The raylib bindings, because sand.flan and the FFI case import them and an
|
|
; import reads the directory at build time. sand.flan itself is above: the
|
|
; headless case imports it as a single-file package.
|
|
(glob_files %{workspace_root}/vendor/raylib/*)
|
|
; The dev agent package: its Flan declarations and the C that implements them.
|
|
(glob_files %{workspace_root}/vendor/agent/*)
|
|
; The EDN tokenizer, which programs/edn.flan imports.
|
|
(glob_files %{workspace_root}/vendor/edn/*)
|
|
; The ported raylib examples. Only one of them has a headless acceptance
|
|
; case, but it imports its example as a package and that example imports
|
|
; examples/digits.flan, so the directory has to be here whole.
|
|
(glob_files %{workspace_root}/examples/*)
|
|
(glob_files programs/*.flan)
|
|
; The package tree the multi-level cases import: pkg-diamond reaches shape
|
|
; through area and draw, and pkg-cycle reaches a ring. Each directory is a
|
|
; package, so each comes whole — a glob per directory rather than one over
|
|
; programs/pkgs/*, because dune's glob does not descend.
|
|
(glob_files programs/pkgs/shape/*)
|
|
(glob_files programs/pkgs/area/*)
|
|
(glob_files programs/pkgs/draw/*)
|
|
(glob_files programs/pkgs/ring-a/*)
|
|
(glob_files programs/pkgs/ring-b/*)
|
|
(glob_files programs/pkgs/ring-c/*)
|
|
; The packages that declare macros: one whose macros a program calls
|
|
; qualified, and the two whose macros do not terminate — a ring, and one
|
|
; that never settles. Each is its own directory, so each needs its own glob.
|
|
(glob_files programs/pkgs/mac/*)
|
|
(glob_files programs/pkgs/macring/*)
|
|
(glob_files programs/pkgs/macspin/*)
|
|
; The synthetic C header the importer's table reads. Committed rather than
|
|
; reached for on the machine: the raylib case needs raylib installed, at the
|
|
; right version, with a variable set, so it skips everywhere and covers
|
|
; nothing. This one does not move.
|
|
(glob_files headers/*.h)
|
|
; The files programs/embed.flan bakes in. An embed reads them at *compile*
|
|
; time, so they are a dependency of the checker run and not of the program.
|
|
(glob_files programs/assets/*)
|
|
; The reload primitive's host: a C main that dlopens what Build.shared made.
|
|
(file reload_host.c)
|
|
; A shared object that is not a redefinition module, for the agent's refusal
|
|
; path. Its destructor is what proves the handle was closed rather than lost.
|
|
(file noinstall.c)
|
|
; The other C main: flan_dev.c's two fixed limits, which no Flan program
|
|
; reaches, driven directly.
|
|
(file dev_limits.c)
|
|
; test_dev runs the compiler itself: flan dev launches and owns a program.
|
|
(file %{workspace_root}/bin/main.exe)
|
|
; The Emacs client, which test_emacs drives against a real daemon.
|
|
(glob_files %{workspace_root}/emacs/*.el)
|
|
; The WASI host the wasm32 case runs its module under, when no wasmtime or
|
|
; wasmer is installed.
|
|
(file wasm-run.mjs)))
|
|
|
|
; The web target, in its own stanza rather than in the table above because it
|
|
; is the one case whose toolchain is a separate install: emscripten, and a
|
|
; raylib archive built by vendor/raylib/build-web.sh. It probes for both and
|
|
; skips with the reason, so it is green on a machine that has neither.
|
|
(test
|
|
(name test_web)
|
|
(modules test_web)
|
|
(libraries flan unix)
|
|
(deps
|
|
(glob_files programs/*.flan)
|
|
(glob_files programs/assets/*)
|
|
; The raylib bindings and the ported example the raylib case builds. The
|
|
; example imports examples/digits.flan, so the directory comes whole.
|
|
(glob_files %{workspace_root}/vendor/raylib/*)
|
|
(glob_files %{workspace_root}/examples/*)
|
|
; sand.flan for the browser, with the sheet it embeds and the dev agent it
|
|
; imports — the agent's directory has to be whole, because the file that
|
|
; makes a web build possible is the one Build selects out of it.
|
|
(file %{workspace_root}/sand.flan)
|
|
(file %{workspace_root}/brush.png)
|
|
(glob_files %{workspace_root}/vendor/agent/*)
|
|
; flan run --target=web is refused by the CLI, so the CLI has to be here.
|
|
(file %{workspace_root}/bin/main.exe)))
|
|
|
|
; The corpus a second time under ASan and UBSan. Its own alias and not part of
|
|
; `dune test`: a sanitized build is a statically linked 1.8MB binary that takes
|
|
; tens of seconds to produce, so the sweep is minutes against the existing
|
|
; suite's seconds, and a test nobody will wait for is a test nobody runs.
|
|
;
|
|
; dune build --root . @sanitize
|
|
; An executable plus a rule rather than a (test ...): a test stanza attaches
|
|
; to the @runtest alias and offers no way to be attached to another one, which
|
|
; is the whole point here.
|
|
(executable
|
|
(name test_sanitize)
|
|
(modules test_sanitize watchdog)
|
|
(libraries flan unix))
|
|
|
|
(rule
|
|
(alias sanitize)
|
|
(deps
|
|
test_sanitize.exe
|
|
(file %{workspace_root}/calc-me.flan)
|
|
(file %{workspace_root}/sand.flan)
|
|
(file %{workspace_root}/brush.png)
|
|
(glob_files %{workspace_root}/vendor/raylib/*)
|
|
(glob_files %{workspace_root}/vendor/agent/*)
|
|
(glob_files %{workspace_root}/vendor/edn/*)
|
|
(glob_files %{workspace_root}/examples/*)
|
|
(glob_files programs/*.flan)
|
|
(glob_files programs/assets/*))
|
|
(action (run ./test_sanitize.exe)))
|
|
|
|
; The corpus a third time, under Valgrind's memcheck. Its own alias for the
|
|
; same reason @sanitize has one, only more so: memcheck runs the program on a
|
|
; synthetic CPU, so the corpus is tens of minutes rather than seconds.
|
|
;
|
|
; dune build --root . @valgrind
|
|
;
|
|
; Why a third sweep when @sanitize exists: ASan answers "is this address
|
|
; mine", and cannot answer "were these bytes ever written". That second
|
|
; question is MSan's, MSan needs every dependency instrumented and raylib
|
|
; settles it, and memcheck answers both while needing no instrumentation at
|
|
; all. NEXT.md asked for exactly this.
|
|
(executable
|
|
(name test_valgrind)
|
|
(modules test_valgrind watchdog)
|
|
(libraries flan unix str))
|
|
|
|
(rule
|
|
(alias valgrind)
|
|
(deps
|
|
test_valgrind.exe
|
|
; The suppression file, which is all reasons and no suppressions; its own
|
|
; header says why that is the finding rather than an oversight.
|
|
(file valgrind.supp)
|
|
(file %{workspace_root}/calc-me.flan)
|
|
(file %{workspace_root}/sand.flan)
|
|
(file %{workspace_root}/brush.png)
|
|
(glob_files %{workspace_root}/vendor/raylib/*)
|
|
(glob_files %{workspace_root}/vendor/agent/*)
|
|
(glob_files %{workspace_root}/vendor/edn/*)
|
|
(glob_files %{workspace_root}/examples/*)
|
|
(glob_files programs/*.flan)
|
|
(glob_files programs/assets/*)
|
|
; The package tree the multi-level cases import, as in the test stanza
|
|
; above: a glob per directory, because dune's glob does not descend.
|
|
(glob_files programs/pkgs/shape/*)
|
|
(glob_files programs/pkgs/area/*)
|
|
(glob_files programs/pkgs/draw/*)
|
|
(glob_files programs/pkgs/ring-a/*)
|
|
(glob_files programs/pkgs/ring-b/*)
|
|
(glob_files programs/pkgs/ring-c/*)
|
|
; And the macro-declaring packages, for the same reason.
|
|
(glob_files programs/pkgs/mac/*)
|
|
(glob_files programs/pkgs/macring/*)
|
|
(glob_files programs/pkgs/macspin/*))
|
|
(action (run ./test_valgrind.exe)))
|