Return non-zero exit code on test failure
And integrated test results with miette report.
This commit is contained in:
parent
3a9cc668fc
commit
87546e0abd
|
@ -1,5 +1,5 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::{env, path::PathBuf};
|
||||
use std::{env, path::PathBuf, process};
|
||||
|
||||
use aiken_project::{
|
||||
config::Config,
|
||||
|
@ -36,12 +36,21 @@ where
|
|||
|
||||
if let Err(err) = build_result {
|
||||
err.report();
|
||||
|
||||
miette::bail!("Failed: {} error(s), {warning_count} warning(s)", err.len(),);
|
||||
};
|
||||
|
||||
println!("\nFinished with {warning_count} warning(s)\n");
|
||||
|
||||
println!("{}", "Summary".purple().bold());
|
||||
println!(
|
||||
" {}, {}",
|
||||
format!("{} error(s)", err.len()),
|
||||
format!("{warning_count} warning(s)").yellow(),
|
||||
);
|
||||
process::exit(1);
|
||||
} else {
|
||||
println!("{}", "Summary".purple().bold());
|
||||
println!(
|
||||
" {}, {}",
|
||||
"0 error",
|
||||
format!("{warning_count} warning(s)").yellow(),
|
||||
);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ pub enum Error {
|
|||
#[error(transparent)]
|
||||
StandardIo(#[from] io::Error),
|
||||
|
||||
#[error("Syclical module imports")]
|
||||
#[error("Cyclical module imports")]
|
||||
ImportCycle { modules: Vec<String> },
|
||||
|
||||
/// Useful for returning many [`Error::Parse`] at once
|
||||
|
@ -73,6 +73,9 @@ pub enum Error {
|
|||
src: String,
|
||||
named: NamedSource,
|
||||
},
|
||||
|
||||
#[error("{} failed", name)]
|
||||
TestFailure { name: String, path: PathBuf },
|
||||
}
|
||||
|
||||
impl Error {
|
||||
|
@ -148,6 +151,7 @@ impl Error {
|
|||
Error::Type { path, .. } => Some(path.to_path_buf()),
|
||||
Error::ValidatorMustReturnBool { path, .. } => Some(path.to_path_buf()),
|
||||
Error::WrongValidatorArity { path, .. } => Some(path.to_path_buf()),
|
||||
Error::TestFailure { path, .. } => Some(path.to_path_buf()),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -163,6 +167,7 @@ impl Error {
|
|||
Error::Type { src, .. } => Some(src.to_string()),
|
||||
Error::ValidatorMustReturnBool { src, .. } => Some(src.to_string()),
|
||||
Error::WrongValidatorArity { src, .. } => Some(src.to_string()),
|
||||
Error::TestFailure { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -203,6 +208,7 @@ impl Diagnostic for Error {
|
|||
Error::Format { .. } => None,
|
||||
Error::ValidatorMustReturnBool { .. } => Some(Box::new("aiken::scripts")),
|
||||
Error::WrongValidatorArity { .. } => Some(Box::new("aiken::validators")),
|
||||
Error::TestFailure { path, .. } => Some(Box::new(path.to_str().unwrap_or(""))),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,6 +231,7 @@ impl Diagnostic for Error {
|
|||
Error::Format { .. } => None,
|
||||
Error::ValidatorMustReturnBool { .. } => Some(Box::new("Try annotating the validator's return type with Bool")),
|
||||
Error::WrongValidatorArity { .. } => Some(Box::new("Validators require a minimum number of arguments please add the missing arguments.\nIf you don't need one of the required arguments use an underscore `_datum`.")),
|
||||
Error::TestFailure { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,6 +251,7 @@ impl Diagnostic for Error {
|
|||
Error::WrongValidatorArity { location, .. } => Some(Box::new(
|
||||
vec![LabeledSpan::new_with_span(None, *location)].into_iter(),
|
||||
)),
|
||||
Error::TestFailure { .. } => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,6 +267,7 @@ impl Diagnostic for Error {
|
|||
Error::Format { .. } => None,
|
||||
Error::ValidatorMustReturnBool { named, .. } => Some(named),
|
||||
Error::WrongValidatorArity { named, .. } => Some(named),
|
||||
Error::TestFailure { .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -144,33 +144,50 @@ where
|
|||
self.event_listener.handle_event(Event::GeneratingUPLC {
|
||||
output_path: self.output_path(),
|
||||
});
|
||||
|
||||
let programs = self.code_gen(validators, &checked_modules)?;
|
||||
|
||||
self.write_build_outputs(programs, uplc_dump)?;
|
||||
Ok(())
|
||||
}
|
||||
CodeGenMode::Test(match_tests) => {
|
||||
let tests =
|
||||
self.scripts_gen(&checked_modules, |def| matches!(def, Definition::Test(..)))?;
|
||||
let tests = self
|
||||
.collect_scripts(&checked_modules, |def| matches!(def, Definition::Test(..)))?;
|
||||
if !tests.is_empty() {
|
||||
self.event_listener.handle_event(Event::RunningTests);
|
||||
}
|
||||
let results = self.eval_scripts(tests, match_tests);
|
||||
let errors: Vec<Error> = results
|
||||
.iter()
|
||||
.filter_map(|e| {
|
||||
if e.success {
|
||||
None
|
||||
} else {
|
||||
Some(Error::TestFailure {
|
||||
name: e.script.name.clone(),
|
||||
path: e.script.input_path.clone(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
self.event_listener
|
||||
.handle_event(Event::FinishedTests { tests: results });
|
||||
if !errors.is_empty() {
|
||||
Err(Error::List(errors))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
CodeGenMode::Eval(func_name) => {
|
||||
let scripts =
|
||||
self.scripts_gen(&checked_modules, |def| matches!(def, Definition::Fn(..)))?;
|
||||
let scripts = self
|
||||
.collect_scripts(&checked_modules, |def| matches!(def, Definition::Fn(..)))?;
|
||||
let results = self.eval_scripts(scripts, Some(func_name));
|
||||
self.event_listener
|
||||
.handle_event(Event::EvaluatingFunction { results });
|
||||
}
|
||||
CodeGenMode::NoOp => (),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
CodeGenMode::NoOp => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
fn read_source_files(&mut self) -> Result<(), Error> {
|
||||
let lib = self.root.join("lib");
|
||||
|
@ -307,7 +324,7 @@ where
|
|||
fn validate_validators(
|
||||
&self,
|
||||
checked_modules: &mut CheckedModules,
|
||||
) -> Result<Vec<(String, TypedFunction)>, Error> {
|
||||
) -> Result<Vec<(PathBuf, String, TypedFunction)>, Error> {
|
||||
let mut errors = Vec::new();
|
||||
let mut validators = Vec::new();
|
||||
let mut indices_to_remove = Vec::new();
|
||||
|
@ -361,7 +378,11 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
validators.push((module.name.clone(), func_def.clone()));
|
||||
validators.push((
|
||||
module.input_path.clone(),
|
||||
module.name.clone(),
|
||||
func_def.clone(),
|
||||
));
|
||||
indices_to_remove.push(index);
|
||||
}
|
||||
}
|
||||
|
@ -381,7 +402,7 @@ where
|
|||
|
||||
fn code_gen(
|
||||
&mut self,
|
||||
validators: Vec<(String, TypedFunction)>,
|
||||
validators: Vec<(PathBuf, String, TypedFunction)>,
|
||||
checked_modules: &CheckedModules,
|
||||
) -> Result<Vec<Script>, Error> {
|
||||
let mut programs = Vec::new();
|
||||
|
@ -437,7 +458,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
for (module_name, func_def) in validators {
|
||||
for (input_path, module_name, func_def) in validators {
|
||||
let Function {
|
||||
arguments,
|
||||
name,
|
||||
|
@ -456,7 +477,7 @@ where
|
|||
|
||||
let program = generator.generate(body, arguments, true);
|
||||
|
||||
let script = Script::new(module_name, name, program.try_into().unwrap());
|
||||
let script = Script::new(input_path, module_name, name, program.try_into().unwrap());
|
||||
|
||||
programs.push(script);
|
||||
}
|
||||
|
@ -465,7 +486,7 @@ where
|
|||
}
|
||||
|
||||
// TODO: revisit ownership and lifetimes of data in this function
|
||||
fn scripts_gen(
|
||||
fn collect_scripts(
|
||||
&mut self,
|
||||
checked_modules: &CheckedModules,
|
||||
should_collect: fn(&TypedDefinition) -> bool,
|
||||
|
@ -503,12 +524,12 @@ where
|
|||
func,
|
||||
);
|
||||
if should_collect(def) {
|
||||
scripts.push((module.name.clone(), func));
|
||||
scripts.push((module.input_path.clone(), module.name.clone(), func));
|
||||
}
|
||||
}
|
||||
Definition::Test(func) => {
|
||||
if should_collect(def) {
|
||||
scripts.push((module.name.clone(), func));
|
||||
scripts.push((module.input_path.clone(), module.name.clone(), func));
|
||||
}
|
||||
// indices_to_remove.push(index);
|
||||
}
|
||||
|
@ -538,7 +559,7 @@ where
|
|||
// }
|
||||
}
|
||||
|
||||
for (module_name, func_def) in scripts {
|
||||
for (input_path, module_name, func_def) in scripts {
|
||||
let Function {
|
||||
arguments,
|
||||
name,
|
||||
|
@ -557,7 +578,12 @@ where
|
|||
|
||||
let program = generator.generate(body.clone(), arguments.clone(), false);
|
||||
|
||||
let script = Script::new(module_name, name.to_string(), program.try_into().unwrap());
|
||||
let script = Script::new(
|
||||
input_path,
|
||||
module_name,
|
||||
name.to_string(),
|
||||
program.try_into().unwrap(),
|
||||
);
|
||||
|
||||
programs.push(script);
|
||||
}
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
use std::path::PathBuf;
|
||||
use uplc::ast::{NamedDeBruijn, Program};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Script {
|
||||
pub input_path: PathBuf,
|
||||
pub module: String,
|
||||
pub name: String,
|
||||
pub program: Program<NamedDeBruijn>,
|
||||
}
|
||||
|
||||
impl Script {
|
||||
pub fn new(module: String, name: String, program: Program<NamedDeBruijn>) -> Script {
|
||||
pub fn new(
|
||||
input_path: PathBuf,
|
||||
module: String,
|
||||
name: String,
|
||||
program: Program<NamedDeBruijn>,
|
||||
) -> Script {
|
||||
Script {
|
||||
input_path,
|
||||
module,
|
||||
name,
|
||||
program,
|
||||
|
|
Loading…
Reference in New Issue