Skip to content
Noodle
InstallLearnPlayground
GitHub

Output, debugging, and tests

Console, Debug, and Testing serve different purposes. Keeping those purposes separate makes application output, diagnostics, and tests easier to maintain.

Console.println(value : String) prints one string followed by a host-defined line terminator:

func main() -> Unit do
Console.println("Build complete");
end

Convert domain values to appropriate user-facing text before printing. Debug representation is not a stable serialization or product-copy format.

Debug.trace(value) resolves IDebug for T, renders a bounded structural representation, prints it, and returns Unit:

datatype Event
Event{name: String, code: Int}
end
func main() -> Unit do
Debug.trace(Event::Event{name: "ready", code: 200});
end

Debug.to_debug_string(value) returns the rendered string instead of printing it. Debug.render(repr) renders an already-created Debug.Repr.

The renderer quotes strings and characters, preserves structural field and constructor information, limits expansion depth, and may omit collection elements after a finite bound. It is designed for diagnostics rather than round-tripping.

The IDebug provider, lazy Debug.Repr model, and its relationship to structural equality, ordering, and hashing are explained in Structural capabilities.

A test is a named, parameterless module declaration checked as a Unit body:

func add(left : Int, right : Int) -> Int do
left + right
end
test "adds two integers" do
Testing.assert_equal(add(20, 22), 42)!;
end

Run all tests declared by one package with:

Terminal window
noodle test .

Tests may access private declarations in their own module. They are excluded from production signatures and ordinary production module artifacts.

The public assertion helpers are:

  • Testing.assert(condition)!;
  • Testing.assert_equal(actual, expected)!;
  • Testing.fail(message)!.

assert_equal resolves both equality and debug providers for the concrete type. On failure it records rendered actual and expected values plus compiler- autofilled source locations for both argument expressions.

A test infers the error types propagated directly from its body, so assertions and application Result values can both use postfix ! without an explicit test-level throws clause. Nested functions inside a test still need their own ordinary error contract.

The runner orders modules by derived module name and preserves source order within each module. Tests run serially. One failure does not prevent later tests from running.

Each test is guarded by a timeout in an isolated, terminable execution unit. Ordinary tests default to 200 milliseconds; @expensive tests default to 15,000 milliseconds. The CLI accepts --timeout, --expensive-timeout, and --compile-timeout overrides, all as positive millisecond values. noodle test --quick still checks and compiles all tests, skips execution of tests marked @expensive, and reports the skipped count in its summary.

An async test uses async test and may await tasks. The same pass/fail and timeout model applies; see Asynchronous code.

This completes the main documentation path. Return to Language basics or revisit Advanced topics as your program grows.