117 lines
2.8 KiB
Rust
117 lines
2.8 KiB
Rust
|
#![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::<String>() {
|
||
|
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<P>(tests: &mut Vec<Test<TestData>>, path: P) -> anyhow::Result<()>
|
||
|
where
|
||
|
P: AsRef<Path>
|
||
|
{
|
||
|
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();
|
||
|
}
|