Skip to content

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.

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.

Terminal window
z test path/to/module.zs
z test path/to/project

The 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 ....

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.

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.

Terminal window
z check .
z run . --release
z build . --release

The 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.