HashQL testing strategies including compiletest (UI tests), unit tests, and snapshot tests. Use when writing tests for HashQL code, using //~ annotations, running --bless, debugging test failures, or choosing the right testing approach.
75
94%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
HashQL uses three testing approaches. compiletest is the default for testing compiler behavior.
| Scenario | Test Type | Location |
|---|---|---|
| Diagnostics/error messages | compiletest | tests/ui/ |
| Compiler pipeline phases | compiletest | tests/ui/ |
| MIR/HIR/AST pass integration | compiletest | tests/ui/ |
| MIR/HIR/AST pass edge cases | insta | tests/ui/<category>/ |
| MIR pass unit tests | MIR builder | src/**/tests.rs |
| Core crate (where needed) | insta | src/**/snapshots/ |
| Parser fragments (syntax-jexpr) | insta | src/*/snapshots/ |
| Internal functions/logic | Unit tests | src/*.rs |
Test parsing, type checking, and error reporting using J-Expr files with diagnostic annotations.
Structure:
package/tests/ui/
category/
.spec.toml # Suite specification (required)
test.jsonc # Test input
test.stdout # Expected output (run: pass)
test.stderr # Expected errors (run: fail)
test.aux.svg # Auxiliary output (some suites)Commands:
cargo run -p hashql-compiletest run # Run all
cargo run -p hashql-compiletest run --filter "test(name)" # Filter
cargo run -p hashql-compiletest run --bless # Update expectedTest file example:
//@ run: fail
//@ description: Tests duplicate field detection
["type", "Bad", { "#struct": { "x": "Int", "x": "String" } }, "_"]
//~^ ERROR Field `x` first defined hereDirectives (//@ at file start):
run: pass / run: fail (default) / run: skipdescription: ... (encouraged)name: custom_nameAnnotations (//~ for expected diagnostics):
//~ ERROR msg - current line//~^ ERROR msg - previous line//~v ERROR msg - next line//~| ERROR msg - same as previous annotation📖 Full Guide: references/compiletest-guide.md
Standard Rust #[test] functions for testing internal logic.
Location: #[cfg(test)] modules in source files
Example from hashql-syntax-jexpr/src/parser/state.rs:
#[test]
fn peek_returns_token_without_consuming() {
bind_context!(let context = "42");
bind_state!(let mut state from context);
let token = state.peek().expect("should not fail").expect("should have token");
assert_eq!(token.kind, number("42"));
}Commands:
cargo nextest run --package hashql-<package>
cargo test --package hashql-<package> --doc # Doc testsUse insta crate for snapshot-based output when compiletest (the preferred method) is infeasible. Three categories exist:
| Category | Crates | Snapshot Location | Rationale |
|---|---|---|---|
| Pipeline Crates | mir, hir, ast | tests/ui/<category>/*.snap | Colocate with compiletest tests |
| Core | hashql-core | Default insta (src/**/snapshots/) | Separate from pipeline; prefer unit tests |
| Syntax | syntax-jexpr | src/*/snapshots/ | Macro-based for parser fragments |
Snapshots colocate with compiletest UI tests. Test code lives in src/**/tests.rs, snapshots go in the appropriate tests/ui/<category>/ directory.
// Example: hashql-mir/src/pass/transform/ssa_repair/tests.rs
let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let mut settings = Settings::clone_current();
settings.set_snapshot_path(dir.join("tests/ui/pass/ssa_repair")); // matches test category
settings.set_prepend_module_to_snapshot(false);
let _drop = settings.bind_to_scope();
assert_snapshot!(name, value);Categories vary: reify/, lower/, pass/ssa_repair/, etc.
hashql-core is separate from the compilation pipeline, so it uses default insta directories. Prefer unit tests; only use snapshots where necessary.
Syntax crates predate compiletest and use macro-based test harnesses for testing parser fragments directly.
// hashql-syntax-jexpr/src/parser/string/test.rs
pub(crate) macro test_cases($parser:ident; $($name:ident($source:expr) => $description:expr,)*) {
$(
#[test]
fn $name() {
assert_parse!($parser, $source, $description);
}
)*
}Snapshots: hashql-syntax-jexpr/src/parser/*/snapshots/*.snap
cargo insta test --package hashql-<package>
cargo insta review # Interactive review
cargo insta accept # Accept all pendingFor testing MIR transformation and analysis passes directly with programmatically constructed MIR bodies.
Location: hashql-mir/src/pass/**/tests.rs
When to use:
Key features:
Changed enum (Yes, No, Unknown) to indicate modificationsChanged value in snapshots for verificationChanged: Yes/No/Unknown separator → after MIRThe body! macro does not support all MIR constructs. If you need a feature that is not supported, do not work around it manually - instead, stop and request that the feature be added to the macro.
body! macro)use hashql_core::{heap::Heap, r#type::environment::Environment};
use hashql_mir::{builder::body, intern::Interner};
let heap = Heap::new();
let interner = Interner::new(&heap);
let env = Environment::new(&heap);
let body = body!(interner, env; fn@0/1 -> Int {
decl x: Int, cond: Bool;
bb0() {
cond = load true;
if cond then bb1() else bb2();
},
bb1() {
goto bb3(1);
},
bb2() {
goto bb3(2);
},
bb3(x) {
return x;
}
});📖 Full Guide: references/mir-builder-guide.md
body! macro for MIR construction in tests4f2d2ce
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.