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 { let mut test_suites: Vec = 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 = 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, }) }