use test_lang::{Change, Snapshot};
fn lex(source: &str) -> Vec<String> {
source
.split_whitespace()
.map(|lexeme| {
let kind = if lexeme.chars().all(|c| c.is_ascii_digit()) {
"Int"
} else if lexeme == "=" {
"Eq"
} else {
"Ident"
};
format!("{kind}({lexeme})")
})
.collect()
}
#[test]
fn test_token_stream_snapshot_matches() {
let snapshot = Snapshot::per_line(lex("let x = 1"));
snapshot
.check("Ident(let)\nIdent(x)\nEq(=)\nInt(1)")
.expect("token stream should match the expected snapshot");
}
#[test]
fn test_token_stream_snapshot_reports_drift() {
let snapshot = Snapshot::per_line(lex("let y = 1"));
let err = snapshot
.check("Ident(let)\nIdent(x)\nEq(=)\nInt(1)")
.expect_err("a changed identifier should fail the check");
let rendered = err.to_string();
assert!(
rendered.contains("-Ident(x)"),
"expected line missing: {rendered}"
);
assert!(
rendered.contains("+Ident(y)"),
"actual line present: {rendered}"
);
}
#[test]
fn test_ast_debug_snapshot() {
#[derive(Debug)]
#[allow(dead_code)]
struct Binary {
op: char,
lhs: i64,
rhs: i64,
}
let tree = Binary {
op: '+',
lhs: 1,
rhs: 2,
};
let snapshot = Snapshot::debug(&tree);
assert!(snapshot.check(snapshot.as_str()).is_ok());
assert!(snapshot.as_str().contains("op: '+'"));
assert!(snapshot.as_str().contains("lhs: 1"));
}
#[test]
fn test_diagnostics_snapshot() {
let rendered =
"error: unexpected token\n --> 1:5\n |\n1 | let = 1\n | ^ expected identifier";
let snapshot = Snapshot::new(rendered);
snapshot
.check(rendered)
.expect("a diagnostic should snapshot verbatim");
}
#[test]
fn test_cross_platform_line_endings_and_trailing_space() {
let windows_output = "error: bad token \r\n --> 1:1\r\n";
let snapshot = Snapshot::new(windows_output);
snapshot
.check("error: bad token\n --> 1:1")
.expect("normalization should erase platform differences");
}
#[test]
fn test_empty_output_snapshots_clean() {
let snapshot = Snapshot::per_line(Vec::<String>::new());
snapshot
.check("")
.expect("no tokens means an empty snapshot");
}
#[test]
fn test_multiline_insertion_reports_each_line() {
let snapshot = Snapshot::per_line(["a", "b", "c", "d"]);
let err = snapshot.check("a\nd").unwrap_err();
let inserted: Vec<_> = err
.diff()
.changes()
.filter(|(change, _)| *change == Change::Insert)
.map(|(_, line)| line.to_string())
.collect();
assert_eq!(inserted, ["b", "c"]);
}
#[test]
fn test_display_value_snapshot() {
struct Version(u32, u32, u32);
impl std::fmt::Display for Version {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}.{}.{}", self.0, self.1, self.2)
}
}
Snapshot::display(&Version(0, 2, 0))
.check("0.2.0")
.expect("a Display value should snapshot to its rendering");
}