use std::fmt::Write as _;
use ridl_syntax::{Parse, Profile, parse};
fn dump(parse: &Parse) -> String {
let mut out = format!("{:#?}", parse.syntax());
out.push_str("errors:");
if parse.errors().is_empty() {
out.push_str(" none\n");
} else {
out.push('\n');
for error in parse.errors() {
writeln!(out, " {} {:?} {}", error.code, error.range, error.message)
.expect("writing to a String");
}
}
out
}
#[test]
fn err_corpus_is_lossless_reports_errors_and_matches_snapshots() {
insta::glob!("../test_data/parser/err", "*.typl", |path| {
let input = std::fs::read_to_string(path).expect("a readable corpus file");
let parsed = parse(&input, Profile::Typl);
assert_eq!(
parsed.syntax().text().to_string(),
input,
"recovery is not lossless for {}",
path.display(),
);
assert!(
!parsed.errors().is_empty(),
"err-corpus file {} must report at least one diagnostic",
path.display(),
);
insta::assert_snapshot!(dump(&parsed));
});
}
#[test]
fn ridl_err_corpus_is_lossless_reports_errors_and_matches_snapshots() {
insta::glob!("../test_data/parser/err", "*.ridl", |path| {
let input = std::fs::read_to_string(path).expect("a readable corpus file");
let parsed = parse(&input, Profile::Ridl);
assert_eq!(
parsed.syntax().text().to_string(),
input,
"recovery is not lossless for {}",
path.display(),
);
assert!(
!parsed.errors().is_empty(),
"err-corpus file {} must report at least one diagnostic",
path.display(),
);
insta::assert_snapshot!(dump(&parsed));
});
}
#[test]
fn rsdl_err_corpus_is_lossless_reports_errors_and_matches_snapshots() {
insta::glob!("../test_data/parser/err", "*.rsdl", |path| {
let input = std::fs::read_to_string(path).expect("a readable corpus file");
let parsed = parse(&input, Profile::Rsdl);
assert_eq!(
parsed.syntax().text().to_string(),
input,
"recovery is not lossless for {}",
path.display(),
);
assert!(
!parsed.errors().is_empty(),
"err-corpus file {} must report at least one diagnostic",
path.display(),
);
insta::assert_snapshot!(dump(&parsed));
});
}
#[test]
fn ridl_init_value_parses_only_before_the_annotations() {
let wrap = |member: &str| format!("package p\n\ninterface I {{\n {member}\n}}\n");
for kw in ["signal", "event", "fixed"] {
for tail in [
"= 1 @10ms",
"= 1 [require true]",
"= 1 @10ms [require true]",
] {
let member = format!("{kw} s : Speed {tail}");
let parsed = parse(&wrap(&member), Profile::Ridl);
assert!(
parsed.errors().is_empty(),
"`{member}` must parse cleanly: {:?}",
parsed.errors(),
);
}
for tail in [
"@10ms = 1",
"[require true] = 1",
"@10ms [require true] = 1",
] {
let member = format!("{kw} s : Speed {tail}");
let source = wrap(&member);
let parsed = parse(&source, Profile::Ridl);
let equals = source.find(" = 1").expect("the init in the source") + 1;
assert!(
parsed
.errors()
.iter()
.any(|error| usize::from(error.range.start()) == equals),
"`{member}` must draw an error on its `=`: {:?}",
parsed.errors(),
);
}
}
}
#[test]
fn ridl_during_on_an_interface_member_is_rejected() {
let source = "package p\n\ninterface I {\n signal s : Speed during READY\n}\n";
let parsed = parse(source, Profile::Ridl);
assert!(
!parsed.errors().is_empty(),
"`during` must not parse cleanly"
);
}