Finish adding generated parser test generation.

This commit is contained in:
Jesse Brault 2025-09-14 08:11:33 -05:00
parent 024baf2064
commit 9c43e28f32
3 changed files with 25 additions and 66 deletions

View File

@ -9,10 +9,8 @@ fn main() -> std::io::Result<()> {
let out_dir_path = Path::new(&out_dir);
let parser_tests_dir = out_dir_path.join("src").join("parser").join("tests");
fs::create_dir_all(&parser_tests_dir)?;
let files = generate_test_files(Path::new("src/parser/tests"))?;
for parser_test_file in &files {
let file_path = parser_tests_dir.join(&parser_test_file.file_name);
fs::write(file_path, &parser_test_file.contents)?;
}
let test_suites_file = generate_test_files(Path::new("src/parser/tests"))?;
let file_path = parser_tests_dir.join(&test_suites_file.file_name);
fs::write(file_path, &test_suites_file.contents)?;
Ok(())
}

View File

@ -5,14 +5,13 @@ use std::path::Path;
use std::{fs, io};
use syn::File;
pub struct ParserTestFile {
pub struct ParserTestSuitesFile {
pub file_name: String,
pub contents: String,
}
pub fn generate_test_files(tests_dir: &Path) -> io::Result<Vec<ParserTestFile>> {
let mut files: Vec<ParserTestFile> = vec![];
let mut test_module_names: Vec<String> = vec![];
pub fn generate_test_files(tests_dir: &Path) -> io::Result<ParserTestSuitesFile> {
let mut test_suites: Vec<TokenStream> = vec![];
// generate test file for each sub dir
for sub_dir in fs::read_dir(tests_dir)? {
@ -21,7 +20,6 @@ pub fn generate_test_files(tests_dir: &Path) -> io::Result<Vec<ParserTestFile>>
if sub_dir_path.is_dir() {
let sub_dir_file_name = sub_dir.file_name();
let sub_dir_string = sub_dir_file_name.to_string_lossy();
test_module_names.push(sub_dir_string.to_string());
let sub_dir_pascal = sub_dir_string.to_case(Case::Pascal);
let rule_ident = format_ident!("{}", sub_dir_pascal);
@ -45,71 +43,30 @@ pub fn generate_test_files(tests_dir: &Path) -> io::Result<Vec<ParserTestFile>>
}
let tests_mod_ident = format_ident!("{}_tests", sub_dir.file_name().to_string_lossy());
let test_file_contents = quote! {
#[cfg(test)]
let test_suite = quote! {
mod #tests_mod_ident {
use crate::parser::Rule;
use crate::parser::tests::parses_to;
use super::*;
#(#tests)*
}
};
let parsed: File = syn::parse2(test_file_contents).unwrap();
let contents = prettyplease::unparse(&parsed);
let file_name = sub_dir.file_name().to_string_lossy().to_string() + ".rs";
files.push(ParserTestFile {
file_name,
contents,
})
test_suites.push(test_suite);
} else {
println!("Warning: not a directory: {:?}", sub_dir_path);
}
}
let test_mod_statements = test_module_names
.iter()
.map(|name| format_ident!("{}", name))
.map(|module_ident| quote! { mod #module_ident; })
.collect::<Vec<_>>();
// generate main test_suites file
let test_suites = quote! {
use super::*;
// generate main mod.rs file
let main_mod = quote! {
use crate::parser::DeimosParser;
use crate::parser::Rule;
use pest_derive::Parser;
#(#test_mod_statements)*
pub(crate) fn parses_to(rule: Rule, input: &str) {
let parse_result = DeimosParser::parse(rule, input);
if let Err(e) = parse_result {
panic!("Parsing failed.\n{}", e);
} else {
let mut pairs = parse_result.unwrap();
if input.trim() != pairs.as_str().trim() {
panic!(
"Parsing did not consume entire input. Consumed only:\n{}",
pairs.as_str().trim()
);
}
let first = pairs.next().unwrap();
if rule != pair.as_rule() {
panic!(
"Expected {} but found {:?}.",
stringify!(rule),
pair.as_rule()
);
}
}
}
#(#test_suites)*
};
let mod_file_parsed: File = syn::parse2(main_mod).unwrap();
let mod_file_contents = prettyplease::unparse(&mod_file_parsed);
files.push(ParserTestFile {
file_name: String::from("mod.rs"),
contents: mod_file_contents,
});
let test_suites_file: File = syn::parse2(test_suites).unwrap();
let test_suites_file_contents = prettyplease::unparse(&test_suites_file);
Ok(files)
Ok(ParserTestSuitesFile {
file_name: String::from("test_suites.rs"),
contents: test_suites_file_contents,
})
}

View File

@ -45,6 +45,10 @@ mod deimos_parser_tests {
}
}
mod generated_tests {
include!(concat!(env!("OUT_DIR"), "/src/parser/tests/test_suites.rs"));
}
#[test]
fn hex_int() {
parses_to(Rule::IntLiteral, "0x1234abcd");