Testing, projects, and the CLI
Z tests are declarations, not a separate source language. They may live beside
private implementation code or in dedicated *.test.zs modules.
import { expect } from "std/test";
function add(left: i32, right: i32): i32 { return left + right;}
test "add combines two values" { const answer = add(20, 22); expect(answer).toEqual(42);}The file suffix is an organizational convention. Production build, run,
and emit paths omit test bodies, names, and runner code wherever the test is
written.
Expectations use ordinary Z semantics
Section titled “Expectations use ordinary Z semantics”import { expect, fail } from "std/test";
test "an owned value can be inspected without moving it" { const status = "ready"; expect(in status).toEqual("ready");
if (status.byteLength == 0) { fail("status must not be empty"); }}expect(actual).toEqual(expected) uses the same == semantics as ordinary Z;
it does not introduce implicit deep structural equality. Expectation operands
are borrowed for the statement. The explicit in above is valid but optional,
just as it is at an ordinary immutable-borrow call site.
Numeric literals take their type from the other operand, in either order:
expect(handle).toEqual(1) works for a u32 handle, as does
expect(1).toEqual(handle). Out-of-range literals and mismatched numeric binding
types remain compile-time errors; expectations do not introduce implicit casts.
Failures preserve deterministic cleanup and do not prevent later tests from running. The current public runner supports synchronous tests; async tests and reusable assertion helpers need later test-context support.
Run reachable tests
Section titled “Run reachable tests”z test path/to/module.zsz test path/to/projectThe runner discovers tests in the selected entry module’s project-owned import
graph. A test target does not require function main().
During repository bootstrap, use bun run z test .... The fixed-point native
compiler exposes the same command as z test ....
Describe a project with z.json
Section titled “Describe a project with z.json”An executable target needs a name and entry module:
{ "target": { "name": "notes", "entry": "main.zs" }}Omitting kind selects an executable. Library projects choose
"static-library" or "shared-library" and expose checked C entry points with
export c function.
Reusable Z packages expose one library root plus optional exact subpaths. A consumer declares the package once:
{ "dependencies": { "zapp": { "path": "../zapp" } }, "target": { "name": "notes", "entry": "main.zs" }}Both the compiler and editor resolve the package’s checked root and declared subpaths. Paths are relative to the manifest that declares them, transitive local dependencies are supported, and undeclared package files remain private. Registry installation and version selection remain future tooling.
Native dependencies remain build configuration rather than source-level linker directives:
{ "target": { "name": "notes", "entry": "main.zs", "platform": "macos", "minimumVersion": "14.0", "includeDirectories": ["vendor/include"], "link": { "directories": ["vendor/lib"], "libraries": ["sqlite3"], "frameworks": ["AppKit"] } }}Relative paths resolve from the manifest directory. The editor schema completes and validates manifest fields; the compiler remains authoritative for path, platform, availability, and ABI checks.
For a reusable package, put the same includeDirectories and link object
under library.native. Every consumer receives those requirements transitively
and deduplicates them with its target; only application-specific native
artifacts remain in the consumer manifest.
One command surface
Section titled “One command surface”| Command | Purpose |
|---|---|
z check <input> |
Parse, type-check, and validate ownership |
z emit <input> |
Print generated C-family source for inspection |
z metadata <input> |
Produce checked versioned metadata for tools |
z build <project> |
Build the configured executable or library |
z run <input> |
Build and execute an executable |
z test <input> |
Discover, compile, and run reachable tests |
<input> may be a .zs entry, project directory, or z.json where the
command allows it. Add --release to build or run for an optimized native
build.
z check .z run . --releasez build . --releaseThe repository currently uses bun run z as the trusted Stage-0 seed. Running
bun run bootstrap produces the local fixed-point native z binary with the
same user-facing command surface. A versioned compiler distribution remains
future release engineering.
Project z build also records a content-addressed whole-project input set. An
unchanged build can reuse its published executable or library before loading
the module graph. The record covers the compiler, reachable Z source,
manifests, generated overlays, explicit native-library bytes, and transitive
foreign headers and .zd contracts. Changing a recorded dependency performs a
complete build; persistent per-module incremental compilation remains future
work.
For compiler-development test tiers, timeouts, sanitizers, and CI organization, see the maintained testing reference.
Next: Native interop.