Skip to content

jamesgober/test-lang

Repository files navigation

Rust logo
test-lang
SNAPSHOT HARNESS

Crates.io Downloads docs.rs CI MSRV

test-lang is a snapshot test harness for language front-ends. Give it source, run that source through a stage — a lexer, a parser, a diagnostics renderer — and assert the rendered result against a known-good block of text. When the output changes, you get a line-level diff pointing at exactly what moved, and accepting the new behavior is a copy-paste.

It owns no grammar and takes no runtime dependencies. The harness works over anything that renders itself to text — a Display value, a Debug tree, or an iterator of displayable items — so the same two types serve a hand-written lexer, a generated parser, or a diagnostics layer without coupling to any of them. It is no_std + alloc capable and normalizes line endings and trailing whitespace so a snapshot captured on Windows matches one written on Linux.



MSRV is 1.85+ (Rust 2024 edition). Part of the -lang language-construction family.

Stable — API frozen at 1.0.0. The public surface will not change in a breaking way before a 2.0; 1.x releases are additive. See docs/API.md for the frozen surface and CHANGELOG.md for history.


Performance First

Latest local Criterion means (cargo bench, Windows x86_64, Rust stable). The workload that matters in a test suite is the check on the matching path — the case a green suite runs on every pass:

  • Capture (per_line, 16 lines): ~0.5 µs
  • Check, matching (16 lines): ~1.2 µs
  • Check, matching (256 lines): ~19 µs

The check is a line-level diff with a common prefix/suffix fast path: identical leading and trailing lines are matched in linear time before the quadratic LCS engine runs, so a near-miss snapshot only pays for the region that actually changed.




Installation

[dependencies]
test-lang = "1"

no_std + alloc (drops the std::error::Error anchor, keeps everything else):

[dependencies]
test-lang = { version = "1", default-features = false }

Quick Start

Snapshot a token stream, one token per line, and assert it:

use test_lang::Snapshot;

// Whatever your lexer produces — here a stand-in that yields display strings.
fn lex(source: &str) -> Vec<String> {
    source.split_whitespace().map(str::to_string).collect()
}

let snapshot = Snapshot::per_line(lex("let x = 1"));
snapshot.check("let\nx\n=\n1").expect("token stream matches");

When the output drifts, the returned Mismatch shows precisely what changed:

use test_lang::Snapshot;

let snapshot = Snapshot::per_line(["let", "y", "=", "1"]);
let err = snapshot.check("let\nx\n=\n1").unwrap_err();

// `-x` was expected; `+y` was produced in its place.
assert!(err.to_string().contains("-x"));
assert!(err.to_string().contains("+y"));


Features

  • Three capture modesSnapshot::display for a Display value, Snapshot::debug for a pretty-printed Debug tree, and Snapshot::per_line for a token stream (one item per line, so the diff points at the exact token).
  • Cross-platform normalization — CRLF/CR collapse to LF, trailing whitespace is stripped, and trailing blank lines are trimmed. A snapshot written by hand in a test matches output captured on any platform.
  • Line-level diffs — a failed check returns a Mismatch whose Display is a unified -expected/+actual diff; Mismatch::diff exposes the Diff for programmatic inspection.
  • No runtime dependencies — built on core::fmt and alloc only. no_std capable.
  • No panicscheck returns Result; the test author decides whether to unwrap, expect, or propagate.

API Overview

For a complete reference with examples, see docs/API.md.

  • Snapshot — a normalized, comparable rendering of compiler output; new / display / debug / per_line / check.
  • Diff & Change — the line-level edit script, rendered as a unified diff.
  • Mismatch — the error returned by Snapshot::check, carrying the Diff.

Runnable examples: examples/tokens.rs, examples/ast.rs, examples/diagnostics.rs.

cargo run --example tokens
cargo run --example ast
cargo run --example diagnostics


Contributing

See REPS.md for engineering standards and the definition of done. Before a PR: cargo fmt --all, cargo clippy --all-targets --all-features -- -D warnings, and cargo test --all-features must be clean.


License

Licensed under either of

at your option.

COPYRIGHT © 2026 James Gober .

About

Compiler snapshot test harness for tokens, ASTs, and errors.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors

Languages