deimos-lang/cst-test-generator/src/lib.rs
2025-09-14 08:11:33 -05:00

73 lines
2.3 KiB
Rust

use convert_case::{Case, Casing};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use std::path::Path;
use std::{fs, io};
use syn::File;
pub struct ParserTestSuitesFile {
pub file_name: String,
pub contents: String,
}
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)? {
let sub_dir = sub_dir?;
let sub_dir_path = sub_dir.path();
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();
let sub_dir_pascal = sub_dir_string.to_case(Case::Pascal);
let rule_ident = format_ident!("{}", sub_dir_pascal);
let mut tests: Vec<TokenStream> = vec![];
for test_file in fs::read_dir(sub_dir_path)? {
let test_file = test_file?;
let test_file_name = test_file.file_name();
let test_ident = format_ident!("{}", test_file_name.to_string_lossy());
let src_input = fs::read_to_string(test_file.path())?;
let test = quote! {
#[test]
fn #test_ident() {
parses_to(Rule::#rule_ident, #src_input)
}
};
tests.push(test);
}
let tests_mod_ident = format_ident!("{}_tests", sub_dir.file_name().to_string_lossy());
let test_suite = quote! {
mod #tests_mod_ident {
use super::*;
#(#tests)*
}
};
test_suites.push(test_suite);
} else {
println!("Warning: not a directory: {:?}", sub_dir_path);
}
}
// generate main test_suites file
let test_suites = quote! {
use super::*;
#(#test_suites)*
};
let test_suites_file: File = syn::parse2(test_suites).unwrap();
let test_suites_file_contents = prettyplease::unparse(&test_suites_file);
Ok(ParserTestSuitesFile {
file_name: String::from("test_suites.rs"),
contents: test_suites_file_contents,
})
}