oden/fine/build.rs

96 lines
3.2 KiB
Rust

use quote::{format_ident, quote};
use std::env;
use std::fs;
use std::path::{Path, PathBuf};
fn generate_test_for_file(path: PathBuf) -> String {
let contents = fs::read_to_string(&path).expect("Unable to read input");
let mut concrete_stuff: Option<String> = None;
// Start iterating over lines and processing directives....
let mut lines = contents.lines();
while let Some(line) = lines.next() {
let line = match line.strip_prefix("//") {
Some(line) => line,
None => break,
};
let line = line.trim();
if line == "concrete:" {
let mut concrete = String::new();
while let Some(line) = lines.next() {
let line = match line.strip_prefix("// | ") {
Some(line) => line,
None => break,
};
concrete.push_str(line);
concrete.push_str("\n");
}
concrete_stuff = Some(concrete);
}
}
let concrete_comparison = if let Some(concrete) = concrete_stuff {
quote! {
crate::assert_concrete(&_tree, #concrete)
}
} else {
quote! {}
};
let name = format_ident!("{}", path.file_stem().unwrap().to_string_lossy());
let test_method = quote! {
fn #name() {
let (_tree, _lines) = fine::parser::concrete::parse_concrete(#contents);
#concrete_comparison;
}
};
let syntax_tree = syn::parse2(test_method).unwrap();
prettyplease::unparse(&syntax_tree)
}
fn process_directory<T>(output: &mut String, path: T)
where
T: AsRef<Path>,
{
let fine_ext: std::ffi::OsString = "fine".into();
let path = path.as_ref();
for entry in std::fs::read_dir(path).expect("Unable to read directory") {
match entry {
Ok(dirent) => {
let file_type = dirent.file_type().unwrap();
if file_type.is_dir() {
let file_name = dirent.file_name();
let file_name = file_name.to_string_lossy().to_owned();
output.push_str(&format!("mod {file_name} {{\n"));
process_directory(output, dirent.path());
output.push_str("}\n\n");
} else if file_type.is_file() {
if dirent.path().extension() == Some(&fine_ext) {
output.push_str(&format!("// {}\n", dirent.path().display()));
output.push_str("#[test]\n");
output.push_str(&generate_test_for_file(dirent.path()));
output.push_str("\n\n");
}
} else {
eprintln!("Skipping symlink: {}", path.display());
}
}
Err(e) => eprintln!("Unable to read directory entry: {:?}", e),
}
}
}
fn main() {
println!("cargo:rerun-if-changed=./tests");
let mut test_source = String::new();
process_directory(&mut test_source, "./tests");
let out_dir = env::var_os("OUT_DIR").unwrap();
let dest_path = Path::new(&out_dir).join("generated_tests.rs");
fs::write(dest_path, test_source).unwrap();
}