#![warn(rust_2018_idioms)] #![deny(elided_lifetimes_in_paths)] #![forbid(unsafe_code)] use compiler::{ compile::{compile, CompileResult}, diagnostic::{Diagnostic, Source} }; use lazy_regex::regex_replace_all; use libtest::{run_tests, Arguments, Outcome, Test}; use std::{ fs::{self, File}, io::{Read as _, Write as _}, panic::catch_unwind, path::{Path, PathBuf} }; struct TestData { path: PathBuf } fn run_test(data: &TestData) -> anyhow::Result<()> { let mut file = File::open(&data.path)?; let mut input = String::new(); file.read_to_string(&mut input)?; drop(file); let compile_result = match catch_unwind(|| compile(&input)) { Ok(result) => result, Err(e) => match e.downcast_ref::() { Some(str) => anyhow::bail!("The compiler paniced: {str}"), None => match e.downcast_ref::<&str>() { Some(str) => anyhow::bail!("The compiler paniced: {str}"), None => anyhow::bail!("The compiler paniced") } } }; let msg = match compile_result { Ok(CompileResult::Ok { .. }) => anyhow::bail!("Code compiled successfully"), Ok(CompileResult::InternalErr(code, err)) => { let mut buf = Vec::new(); Diagnostic::ice(err).write(Source::new(&code), &mut buf)?; String::from_utf8(buf).unwrap() }, Err(err) => { let filename = data.path.file_name().unwrap().to_str().unwrap(); let mut buf = Vec::new(); err.write(Source::new(&input).with_filename(filename), &mut buf)?; String::from_utf8(buf).unwrap() } }; // remove colors from the msg let msg = regex_replace_all!("\x1B\\[[^m]+m", &msg, |_| ""); let mut path = data.path.clone(); path.set_extension("out"); if !path.exists() { let mut file = File::create(&path)?; write!(file, "{msg}")?; Ok(()) } else { let mut file = File::open(&path)?; let mut buf = String::new(); file.read_to_string(&mut buf)?; drop(file); if msg == buf { Ok(()) } else { Err(anyhow::anyhow!( "Error: Expected output\n\n{buf}\n\nActual output\n\n{msg}" )) } } } fn add_tests_from_dir

(tests: &mut Vec>, path: P) -> anyhow::Result<()> where P: AsRef { for file in fs::read_dir(path)? { let file = file?; let path = file.path(); let ty = file.file_type()?; if ty.is_dir() { add_tests_from_dir(tests, &path)?; } else if ty.is_file() && path.extension().map(|ext| ext == "txt").unwrap_or(false) { tests.push(Test { name: path.display().to_string(), kind: "".into(), is_ignored: false, is_bench: false, data: TestData { path } }); } } Ok(()) } fn main() -> anyhow::Result<()> { let args = Arguments::from_args(); let mut tests = Vec::new(); add_tests_from_dir(&mut tests, "integration/fail")?; run_tests(&args, tests, |test| match run_test(&test.data) { Ok(()) => Outcome::Passed, Err(err) => Outcome::Failed { msg: Some(format!("{err:?}")) } }) .exit(); }