rust/crates/parser/src/tests.rs

167 lines
4.6 KiB
Rust
Raw Normal View History

mod sourcegen_inline_tests;
2022-01-02 06:18:34 -06:00
mod top_entries;
2022-01-02 09:46:01 -06:00
mod prefix_entries;
2021-12-12 12:32:58 -06:00
use std::{
fmt::Write,
fs,
path::{Path, PathBuf},
};
use expect_test::expect_file;
2022-01-02 06:01:20 -06:00
use crate::{LexedStr, TopEntryPoint};
2021-12-12 12:32:58 -06:00
#[test]
fn lex_ok() {
2021-12-12 12:32:58 -06:00
for case in TestCase::list("lexer/ok") {
let actual = lex(&case.text);
expect_file![case.rast].assert_eq(&actual)
2021-12-12 12:32:58 -06:00
}
}
#[test]
fn lex_err() {
2021-12-12 12:32:58 -06:00
for case in TestCase::list("lexer/err") {
let actual = lex(&case.text);
expect_file![case.rast].assert_eq(&actual)
2021-12-12 12:32:58 -06:00
}
}
fn lex(text: &str) -> String {
2021-12-18 06:31:50 -06:00
let lexed = LexedStr::new(text);
2021-12-12 12:32:58 -06:00
let mut res = String::new();
2021-12-18 06:31:50 -06:00
for i in 0..lexed.len() {
let kind = lexed.kind(i);
let text = lexed.text(i);
let error = lexed.error(i);
let error = error.map(|err| format!(" error: {err}")).unwrap_or_default();
writeln!(res, "{kind:?} {text:?}{error}").unwrap();
2021-12-12 12:32:58 -06:00
}
res
}
2021-12-26 08:58:33 -06:00
#[test]
fn parse_ok() {
2021-12-26 08:58:33 -06:00
for case in TestCase::list("parser/ok") {
2022-01-02 06:01:20 -06:00
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(!errors, "errors in an OK file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual);
2021-12-26 08:58:33 -06:00
}
}
#[test]
fn parse_inline_ok() {
for case in TestCase::list("parser/inline/ok") {
2022-01-02 06:01:20 -06:00
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(!errors, "errors in an OK file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual);
}
}
#[test]
fn parse_err() {
2021-12-26 08:58:33 -06:00
for case in TestCase::list("parser/err") {
2022-01-02 06:01:20 -06:00
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(errors, "no errors in an ERR file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual)
2021-12-26 08:58:33 -06:00
}
}
#[test]
fn parse_inline_err() {
for case in TestCase::list("parser/inline/err") {
2022-01-02 06:01:20 -06:00
let (actual, errors) = parse(TopEntryPoint::SourceFile, &case.text);
assert!(errors, "no errors in an ERR file {}:\n{actual}", case.rs.display());
expect_file![case.rast].assert_eq(&actual)
}
}
2022-01-02 06:01:20 -06:00
fn parse(entry: TopEntryPoint, text: &str) -> (String, bool) {
2021-12-26 08:58:33 -06:00
let lexed = LexedStr::new(text);
let input = lexed.to_input();
2022-01-02 06:01:20 -06:00
let output = entry.parse(&input);
2021-12-26 08:58:33 -06:00
let mut buf = String::new();
let mut errors = Vec::new();
let mut indent = String::new();
2022-01-02 06:15:04 -06:00
let mut depth = 0;
let mut len = 0;
2021-12-28 10:13:30 -06:00
lexed.intersperse_trivia(&output, &mut |step| match step {
2021-12-26 08:58:33 -06:00
crate::StrStep::Token { kind, text } => {
2022-01-02 06:15:04 -06:00
assert!(depth > 0);
len += text.len();
write!(buf, "{indent}").unwrap();
write!(buf, "{kind:?} {text:?}\n").unwrap();
2021-12-26 08:58:33 -06:00
}
crate::StrStep::Enter { kind } => {
2022-01-02 06:15:04 -06:00
assert!(depth > 0 || len == 0);
depth += 1;
write!(buf, "{indent}").unwrap();
write!(buf, "{kind:?}\n").unwrap();
2021-12-26 08:58:33 -06:00
indent.push_str(" ");
}
crate::StrStep::Exit => {
2022-01-02 06:15:04 -06:00
assert!(depth > 0);
depth -= 1;
2021-12-26 08:58:33 -06:00
indent.pop();
indent.pop();
}
2022-01-02 06:15:04 -06:00
crate::StrStep::Error { msg, pos } => {
assert!(depth > 0);
errors.push(format!("error {pos}: {msg}\n"))
2022-01-02 06:15:04 -06:00
}
2021-12-26 08:58:33 -06:00
});
2022-01-02 08:18:21 -06:00
assert_eq!(
len,
text.len(),
"didn't parse all text.\nParsed:\n{}\n\nAll:\n{}\n",
&text[..len],
text
);
2021-12-26 08:58:33 -06:00
for (token, msg) in lexed.errors() {
let pos = lexed.text_start(token);
errors.push(format!("error {pos}: {msg}\n"));
2021-12-26 08:58:33 -06:00
}
let has_errors = !errors.is_empty();
for e in errors {
buf.push_str(&e);
}
(buf, has_errors)
}
2021-12-12 12:32:58 -06:00
#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct TestCase {
rs: PathBuf,
rast: PathBuf,
2021-12-12 12:32:58 -06:00
text: String,
}
impl TestCase {
fn list(path: &'static str) -> Vec<TestCase> {
let crate_root_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
let test_data_dir = crate_root_dir.join("test_data");
let dir = test_data_dir.join(path);
let mut res = Vec::new();
let read_dir = fs::read_dir(&dir)
.unwrap_or_else(|err| panic!("can't `read_dir` {}: {err}", dir.display()));
2021-12-12 12:32:58 -06:00
for file in read_dir {
let file = file.unwrap();
let path = file.path();
if path.extension().unwrap_or_default() == "rs" {
let rs = path;
let rast = rs.with_extension("rast");
2021-12-12 12:32:58 -06:00
let text = fs::read_to_string(&rs).unwrap();
res.push(TestCase { rs, rast, text });
2021-12-12 12:32:58 -06:00
}
}
res.sort();
res
}
}