An open API service indexing awesome lists of open source software.

https://github.com/jamesgober/test-lang

Compiler snapshot test harness for tokens, ASTs, and errors.
https://github.com/jamesgober/test-lang

compiler language rust snapshot testing

Last synced: 1 day ago
JSON representation

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

Awesome Lists containing this project

README

          


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

```toml
[dependencies]
test-lang = "1"
```

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

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


## Quick Start

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

```rust
use test_lang::Snapshot;

// Whatever your lexer produces — here a stand-in that yields display strings.
fn lex(source: &str) -> Vec {
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:

```rust
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 modes** — `Snapshot::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 panics** — `check` returns `Result`; the test author decides whether to `unwrap`, `expect`, or propagate.


## API Overview

For a complete reference with examples, see [`docs/API.md`](./docs/API.md).

- [`Snapshot`](./docs/API.md#snapshot) — a normalized, comparable rendering of compiler output; `new` / `display` / `debug` / `per_line` / `check`.
- [`Diff`](./docs/API.md#diff) & [`Change`](./docs/API.md#change) — the line-level edit script, rendered as a unified diff.
- [`Mismatch`](./docs/API.md#mismatch) — the error returned by `Snapshot::check`, carrying the `Diff`.

Runnable examples: [`examples/tokens.rs`](./examples/tokens.rs), [`examples/ast.rs`](./examples/ast.rs), [`examples/diagnostics.rs`](./examples/diagnostics.rs).

```bash
cargo run --example tokens
cargo run --example ast
cargo run --example diagnostics
```




## Contributing

See [`REPS.md`](./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 .