Module

std::test

Test Assertions

Native testing helpers for @test functions.

The std::test module provides the standard assertion and snapshot surface used by ignis test.

It is intentionally small and stable:

  • Test::assert(condition)
  • Test::assertEq<T>(left, right)
  • Test::assertNe<T>(left, right)
  • Test::fail()
  • Test::assertSnapshot(name, actual)
  • Test::assertFileSnapshot(name, filePath)

Design Goals

  • keep language-level tests deterministic
  • make failures explicit and easy to spot in runner output
  • route generic equality through the canonical std::hash::Eq contract
  • store snapshots next to the source module under test
  • avoid compiler-only test APIs leaking into user code

Assertions

assert, assertEq, and assertNe all fail the current test by calling @panic(...) with a fixed message.

assertEq<T> and assertNe<T> rely on builtin @eq<T>. Supported T includes:

  • integer primitives
  • boolean
  • char
  • str
  • records and enums implementing canonical std::hash::Eq

Unsupported equality must be rejected during analysis before code generation or harness build.

Snapshots

Snapshot helpers compare UTF-8 text against deterministic files under a sibling __snapshots__/ directory.

File naming is derived from:

  • the fully-qualified test name
  • the user-supplied snapshot label

Both parts are escaped so snapshots from different modules can safely reuse the same logical label.

Update behavior is driven by the native runner through environment variables:

  • IGNIS_TEST_NAME
  • IGNIS_TEST_SNAPSHOT_DIR
  • IGNIS_TEST_UPDATE_SNAPSHOTS

With update mode enabled, missing or mismatched snapshots are written back to disk. Without update mode, the helpers fail the current test.

Failure Output

Snapshot mismatches print small, bounded diagnostics to stderr before panicking:

  • failure reason
  • snapshot path
  • expected byte count
  • actual byte count

The native runner is responsible for truncating long stderr/stdout blocks in the final report.

Example

import Test from "std::test";

@test
function smoke(): void {
  Test::assert(true);
  Test::assertEq<i32>(2 + 2, 4);
}

Generic Equality Example

import Eq from "std::hash";
import Test from "std::test";

@implements(Eq)
record UserId {
  public value: i32;

  equals(&self, other: &UserId): boolean {
    return self.value == other.value;
  }
}

@test
function compareUserIds(): void {
  let left: UserId = UserId { value: 7 };
  let right: UserId = UserId { value: 7 };
  let other: UserId = UserId { value: 8 };

  Test::assertEq<UserId>(left, right);
  Test::assertNe<UserId>(left, other);
}

Snapshot Example

import Test from "std::test";

@test
function snapshotRenderedOutput(): void {
  Test::assertSnapshot("rendered", "hello snapshot\n");
}

File Snapshot Example

import Test from "std::test";

@test
function snapshotGeneratedFile(): void {
  Test::assertFileSnapshot("artifact", "./actual-output.txt");
}
namespace Test

Assertion and snapshot helpers for @test bodies.

Test is a pure namespace surface used by the native ignis test runner. It does not hold state; instead, snapshot helpers read runner-provided environment variables to discover the active test name, snapshot directory, and update mode.

Equality assertions route through canonical builtin @eq<T> dispatch. Snapshot assertions compare or update UTF-8 text files in a sibling __snapshots__/ directory.

Functions

function assert(condition: boolean): void

Fails the current test when condition is false.

Arguments

  • condition - Boolean condition that must evaluate to true.

Panics

Panics with "assertion failed" when condition is false.

Example

import Test from "std::test";

@test
function smoke(): void {
  Test::assert(2 + 2 == 4);
}
function assertEq<T>(left: T, right: T): void

Fails the current test when two values are not equal under canonical Eq.

T must be supported by builtin @eq<T>. For user-defined records and enums this means implementing canonical std::hash::Eq with a valid equals(&self, other: &T): boolean method.

Type Parameters

  • T - The type being compared.

Arguments

  • left - Left-hand value.
  • right - Right-hand value.

Panics

Panics with "assertion failed: values are not equal" when the values do not compare equal.

Example

import Test from "std::test";

@test
function compareNumbers(): void {
  Test::assertEq<i32>(40 + 2, 42);
  Test::assertEq<str>("abc", "abc");
}
function assertFileSnapshot(name: str, filePath: str): void

Reads filePath as UTF-8 text before applying snapshot comparison.

This is useful when the code under test writes an artifact to disk and the test wants the snapshot baseline to track the file contents.

Arguments

  • name - Logical snapshot label within the current test.
  • filePath - Path to a UTF-8 text file to snapshot.

Panics

Panics with "snapshot assertion failed" if the input file cannot be read, if the snapshot mismatches without update mode, or if snapshot I/O fails.

Example

import Test from "std::test";

@test
function snapshotFile(): void {
  Test::assertFileSnapshot("artifact", "./actual-output.txt");
}
function assertNe<T>(left: T, right: T): void

Fails the current test when two values are equal under canonical Eq.

This is the inverse of assertEq<T>.

Type Parameters

  • T - The type being compared.

Arguments

  • left - Left-hand value.
  • right - Right-hand value.

Panics

Panics with "assertion failed: values are equal" when the values compare equal.

Example

import Test from "std::test";

@test
function compareDifferentValues(): void {
  Test::assertNe<i32>(1, 2);
}
function assertSnapshot(name: str, actual: str): void

Fails the current test when the named text snapshot does not match.

The snapshot file is resolved from the current test name and the snapshot label, then stored in a sibling __snapshots__/ directory next to the module under test.

Arguments

  • name - Logical snapshot label within the current test.
  • actual - UTF-8 text to compare or write.

Update Mode

When ignis test --update-snapshots is active, missing or mismatched snapshots are written to disk instead of failing the test.

Example

import Test from "std::test";

@test
function snapshotText(): void {
  Test::assertSnapshot("rendered", "hello snapshot\n");
}
function fail(): void

Fails the current test unconditionally.

Use this when a branch should be treated as an immediate test failure.

Panics

Always panics with "test failed".

Example

import Test from "std::test";

@test
function forcedFailure(): void {
  Test::fail();
}

Functions

function assertSnapshotText(name: str, actual: &String): void

Internal text snapshot engine shared by Test::assertSnapshot and Test::assertFileSnapshot.

This resolves runner context, computes the snapshot file path, performs compare-or-update behavior, and emits bounded mismatch diagnostics before panicking on failure.

function escapeSnapshotComponent(value: &String): String

Escapes a file-name component into a deterministic ASCII-safe string.

Safe bytes are kept as-is. All other bytes are rewritten as _<hex><hex>.

Arguments

  • value - Raw component to normalize for use in a file name.
function failSnapshotIo(reason: str, snapshotPath: str, detail: str): void

Emits a standard snapshot I/O diagnostic and panics.

Arguments

  • reason - High-level failure category.
  • snapshotPath - Path associated with the failed I/O operation.
  • detail - Small detail string included in stderr output.
function failSnapshotMismatch(snapshotPath: &String, expectedBytes: u64, actualBytes: u64): void

Emits a standard mismatch diagnostic and panics.

The byte counts are reported to keep diagnostics stable and compact even for large snapshot bodies.

Arguments

  • snapshotPath - Snapshot file path.
  • expectedBytes - Byte length of the baseline snapshot.
  • actualBytes - Byte length of the actual snapshot text.
function failSnapshotMissing(snapshotPath: &String): void

Emits a standard snapshot missing failure and panics.

Arguments

  • snapshotPath - Missing snapshot file path.
function hexDigit(value: u8): char

Converts a nibble (0..=15) to its lowercase hexadecimal digit.

function isSafeSnapshotByte(byte: u8): boolean

Returns whether a byte may appear unchanged in a snapshot file name.

Safe bytes are limited to ASCII letters, digits, -, ., and _.

function printSnapshotPath(snapshotPath: &String): void

Prints the normalized snapshot: ... line shared by all snapshot failure diagnostics.

Arguments

  • snapshotPath - Snapshot path to print in user-facing diagnostics.
function requiredSnapshotEnv(name: str): String

Reads a required test-runner environment variable as an owned String.

Arguments

  • name - Name of the environment variable to read.

Panics

Panics with "snapshot assertion failed" if the runner did not provide the required snapshot context variable.

function snapshotFileName(testName: &String, snapshotName: str): String

Produces the deterministic on-disk file name for a snapshot.

The file name layout is:

<escaped-test-name>__<escaped-snapshot-name>.snap.txt

Escaping prevents collisions with path separators, ::, spaces, and other punctuation while keeping ASCII-safe names for the filesystem.

Arguments

  • testName - Fully-qualified test name.
  • snapshotName - Logical snapshot label.
function snapshotPath(snapshotDir: &String, testName: &String, snapshotName: str): PathBuf

Builds the final snapshot path for the current test and snapshot label.

The resulting file lives in the test’s snapshot directory and uses the escaped file name returned by snapshotFileName(...).

Arguments

  • snapshotDir - Snapshot directory provided by the runner.
  • testName - Fully-qualified test name.
  • snapshotName - Logical snapshot label within the test.
function snapshotUpdateModeEnabled(): boolean

Returns whether snapshot update mode is enabled for the current test run.

The native runner encodes this as IGNIS_TEST_UPDATE_SNAPSHOTS=1.

function writeSnapshot(snapshotDir: &String, snapshotPath: &PathBuf, actual: &String): void

Writes snapshot text to disk, creating the snapshot directory first.

Arguments

  • snapshotDir - Parent snapshot directory.
  • snapshotPath - Full path to the snapshot file.
  • actual - Snapshot contents to write.

Panics

Panics with "snapshot assertion failed" if directory creation or file writing fails, or if the write reports a short write.