feat(tests): implement a way to express that tests can fail

This commit is contained in:
rvcas 2023-05-25 16:54:53 -04:00
parent 65bf4a85e4
commit a124a16a61
No known key found for this signature in database
GPG Key ID: C09B64E263F7D68C
12 changed files with 131 additions and 11 deletions

View File

@ -118,6 +118,7 @@ fn str_to_keyword(word: &str) -> Option<Token> {
"test" => Some(Token::Test), "test" => Some(Token::Test),
"error" => Some(Token::ErrorTerm), "error" => Some(Token::ErrorTerm),
"validator" => Some(Token::Validator), "validator" => Some(Token::Validator),
"fail" => Some(Token::Fail),
_ => None, _ => None,
} }
} }
@ -136,6 +137,7 @@ pub struct Function<T, Expr> {
pub return_annotation: Option<Annotation>, pub return_annotation: Option<Annotation>,
pub return_type: T, pub return_type: T,
pub end_position: usize, pub end_position: usize,
pub can_error: bool,
} }
pub type TypedTypeAlias = TypeAlias<Arc<Type>>; pub type TypedTypeAlias = TypeAlias<Arc<Type>>;

View File

@ -681,6 +681,7 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
annotation: None, annotation: None,
tipo: bool(), tipo: bool(),
}], }],
can_error: false,
doc: None, doc: None,
location: Span::empty(), location: Span::empty(),
name: "not".to_string(), name: "not".to_string(),
@ -731,6 +732,7 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
annotation: None, annotation: None,
tipo: a_var.clone(), tipo: a_var.clone(),
}], }],
can_error: false,
body: TypedExpr::Var { body: TypedExpr::Var {
location: Span::empty(), location: Span::empty(),
constructor: ValueConstructor { constructor: ValueConstructor {
@ -766,6 +768,7 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
variant_name: "".to_string(), variant_name: "".to_string(),
}, },
Function { Function {
can_error: false,
arguments: vec![ arguments: vec![
Arg { Arg {
arg_name: ArgName::Named { arg_name: ArgName::Named {
@ -828,6 +831,7 @@ pub fn prelude_functions(id_gen: &IdGenerator) -> IndexMap<FunctionAccessKey, Ty
variant_name: "".to_string(), variant_name: "".to_string(),
}, },
Function { Function {
can_error: false,
arguments: vec![Arg { arguments: vec![Arg {
arg_name: ArgName::Named { arg_name: ArgName::Named {
name: "f".to_string(), name: "f".to_string(),

View File

@ -10,7 +10,7 @@ use crate::{
}, },
expr, expr,
}; };
use chumsky::prelude::*; use chumsky::{chain::Chain, prelude::*};
use error::ParseError; use error::ParseError;
use extra::ModuleExtra; use extra::ModuleExtra;
use token::Token; use token::Token;
@ -73,7 +73,8 @@ pub fn module(
result result
}); });
let definitions = module_parser().parse(chumsky::Stream::from_iter(span(len), tokens))?; let definitions =
module_parser().parse(chumsky::Stream::from_iter(span(tokens.len()), tokens))?;
let module = ast::UntypedModule { let module = ast::UntypedModule {
kind, kind,
@ -329,6 +330,7 @@ pub fn fn_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseEr
public: opt_pub.is_some(), public: opt_pub.is_some(),
return_annotation, return_annotation,
return_type: (), return_type: (),
can_error: true,
}) })
}, },
) )
@ -336,7 +338,8 @@ pub fn fn_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseEr
pub fn test_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> { pub fn test_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
just(Token::Test) just(Token::Test)
.ignore_then(select! {Token::Name {name} => name}) .ignore_then(just(Token::Fail).ignored().or_not())
.then(select! {Token::Name {name} => name})
.then_ignore(just(Token::LeftParen)) .then_ignore(just(Token::LeftParen))
.then_ignore(just(Token::RightParen)) .then_ignore(just(Token::RightParen))
.map_with_span(|name, span| (name, span)) .map_with_span(|name, span| (name, span))
@ -345,7 +348,7 @@ pub fn test_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = Parse
.or_not() .or_not()
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)), .delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
) )
.map_with_span(|((name, span_end), body), span| { .map_with_span(|(((fail, name), span_end), body), span| {
ast::UntypedDefinition::Test(ast::Function { ast::UntypedDefinition::Test(ast::Function {
arguments: vec![], arguments: vec![],
body: body.unwrap_or_else(|| expr::UntypedExpr::todo(span, None)), body: body.unwrap_or_else(|| expr::UntypedExpr::todo(span, None)),
@ -356,6 +359,7 @@ pub fn test_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = Parse
public: false, public: false,
return_annotation: None, return_annotation: None,
return_type: (), return_type: (),
can_error: fail.is_some(),
}) })
}) })
} }

View File

@ -115,6 +115,7 @@ pub fn lexer() -> impl Parser<char, Vec<(Token, Span)>, Error = ParseError> {
"todo" => Token::Todo, "todo" => Token::Todo,
"type" => Token::Type, "type" => Token::Type,
"when" => Token::When, "when" => Token::When,
"fail" => Token::Fail,
"validator" => Token::Validator, "validator" => Token::Validator,
_ => { _ => {
if s.chars().next().map_or(false, |c| c.is_uppercase()) { if s.chars().next().map_or(false, |c| c.is_uppercase()) {

View File

@ -80,6 +80,7 @@ pub enum Token {
When, When,
Trace, Trace,
Validator, Validator,
Fail,
} }
impl fmt::Display for Token { impl fmt::Display for Token {
@ -164,6 +165,7 @@ impl fmt::Display for Token {
Token::Test => "test", Token::Test => "test",
Token::ErrorTerm => "error", Token::ErrorTerm => "error",
Token::Validator => "validator", Token::Validator => "validator",
Token::Fail => "fail",
}; };
write!(f, "\"{s}\"") write!(f, "\"{s}\"")
} }

View File

@ -38,6 +38,60 @@ fn windows_newline() {
) )
} }
#[test]
fn test_fail() {
let code = indoc! {r#"
test fail invalid_inputs() {
expect True = False
False
}
"#};
assert_definitions(
code,
vec![ast::UntypedDefinition::Test(ast::Function {
arguments: vec![],
body: expr::UntypedExpr::Sequence {
location: Span::new((), 31..59),
expressions: vec![
expr::UntypedExpr::Assignment {
location: Span::new((), 31..50),
value: Box::new(expr::UntypedExpr::Var {
location: Span::new((), 45..50),
name: "False".to_string(),
}),
pattern: ast::UntypedPattern::Constructor {
is_record: false,
location: Span::new((), 38..42),
name: "True".to_string(),
arguments: vec![],
module: None,
constructor: (),
with_spread: false,
tipo: (),
},
kind: ast::AssignmentKind::Expect,
annotation: None,
},
expr::UntypedExpr::Var {
location: Span::new((), 54..59),
name: "False".to_string(),
},
],
},
doc: None,
location: Span::new((), 0..26),
name: "invalid_inputs".to_string(),
public: false,
return_annotation: None,
return_type: (),
end_position: 60,
can_error: true,
})],
);
}
#[test] #[test]
fn validator() { fn validator() {
let code = indoc! {r#" let code = indoc! {r#"
@ -54,6 +108,7 @@ fn validator() {
doc: None, doc: None,
end_position: 54, end_position: 54,
fun: Function { fun: Function {
can_error: true,
arguments: vec![ arguments: vec![
ast::Arg { ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
@ -128,6 +183,7 @@ fn double_validator() {
doc: None, doc: None,
end_position: 90, end_position: 90,
fun: Function { fun: Function {
can_error: true,
arguments: vec![ arguments: vec![
ast::Arg { ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
@ -176,6 +232,7 @@ fn double_validator() {
end_position: 52, end_position: 52,
}, },
other_fun: Some(Function { other_fun: Some(Function {
can_error: true,
arguments: vec![ arguments: vec![
ast::Arg { ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
@ -487,6 +544,7 @@ fn empty_function() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Trace { body: expr::UntypedExpr::Trace {
kind: ast::TraceKind::Todo, kind: ast::TraceKind::Todo,
@ -522,6 +580,7 @@ fn expect() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 19..69), location: Span::new((), 19..69),
@ -592,6 +651,7 @@ fn plus_binop() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
label: "a".to_string(), label: "a".to_string(),
@ -644,6 +704,7 @@ fn pipeline() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
name: "a".to_string(), name: "a".to_string(),
@ -715,6 +776,7 @@ fn if_expression() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::If { body: expr::UntypedExpr::If {
location: Span::new((), 13..106), location: Span::new((), 13..106),
@ -813,6 +875,7 @@ fn let_bindings() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
label: "a".to_string(), label: "a".to_string(),
@ -940,6 +1003,7 @@ fn block() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
label: "a".to_string(), label: "a".to_string(),
@ -1034,6 +1098,7 @@ fn when() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
label: "a".to_string(), label: "a".to_string(),
@ -1159,6 +1224,7 @@ fn anonymous_function() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 25..83), location: Span::new((), 25..83),
@ -1252,6 +1318,7 @@ fn field_access() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![ast::Arg { arguments: vec![ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
label: "user".to_string(), label: "user".to_string(),
@ -1302,6 +1369,7 @@ fn call() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 15..108), location: Span::new((), 15..108),
@ -1461,6 +1529,7 @@ fn record_update() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![ arguments: vec![
ast::Arg { ast::Arg {
arg_name: ast::ArgName::Named { arg_name: ast::ArgName::Named {
@ -1555,6 +1624,7 @@ fn record_create_labeled() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(ast::Function { vec![ast::UntypedDefinition::Fn(ast::Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Call { body: expr::UntypedExpr::Call {
arguments: vec![ arguments: vec![
@ -1612,6 +1682,7 @@ fn record_create_labeled_with_field_access() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(ast::Function { vec![ast::UntypedDefinition::Fn(ast::Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Call { body: expr::UntypedExpr::Call {
arguments: vec![ arguments: vec![
@ -1673,6 +1744,7 @@ fn record_create_unlabeled() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(ast::Function { vec![ast::UntypedDefinition::Fn(ast::Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Call { body: expr::UntypedExpr::Call {
arguments: vec![ arguments: vec![
@ -1726,6 +1798,7 @@ fn parse_tuple() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 13..85), location: Span::new((), 13..85),
@ -1829,6 +1902,7 @@ fn parse_tuple2() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 13..38), location: Span::new((), 13..38),
@ -1957,6 +2031,7 @@ fn base16_bytearray_literals() {
tipo: (), tipo: (),
}), }),
ast::UntypedDefinition::Fn(Function { ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::BinOp { body: expr::UntypedExpr::BinOp {
location: Span::new((), 55..80), location: Span::new((), 55..80),
@ -1992,6 +2067,7 @@ fn function_def() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
doc: None, doc: None,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Trace { body: expr::UntypedExpr::Trace {
@ -2026,6 +2102,7 @@ fn function_invoke() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
doc: None, doc: None,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Assignment { body: expr::UntypedExpr::Assignment {
@ -2089,6 +2166,7 @@ fn function_ambiguous_sequence() {
code, code,
vec![ vec![
ast::UntypedDefinition::Fn(Function { ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 15..32), location: Span::new((), 15..32),
@ -2121,6 +2199,7 @@ fn function_ambiguous_sequence() {
end_position: 34, end_position: 34,
}), }),
ast::UntypedDefinition::Fn(Function { ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 52..69), location: Span::new((), 52..69),
@ -2153,6 +2232,7 @@ fn function_ambiguous_sequence() {
end_position: 71, end_position: 71,
}), }),
ast::UntypedDefinition::Fn(Function { ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Assignment { body: expr::UntypedExpr::Assignment {
location: Span::new((), 89..103), location: Span::new((), 89..103),
@ -2184,6 +2264,7 @@ fn function_ambiguous_sequence() {
end_position: 104, end_position: 104,
}), }),
ast::UntypedDefinition::Fn(Function { ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 122..153), location: Span::new((), 122..153),
@ -2296,6 +2377,7 @@ fn tuple_pattern() {
assert_definitions( assert_definitions(
code, code,
vec![ast::UntypedDefinition::Fn(Function { vec![ast::UntypedDefinition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 13..49), location: Span::new((), 13..49),
@ -2349,6 +2431,7 @@ fn subtraction_vs_negate() {
assert_definitions( assert_definitions(
code, code,
vec![ast::Definition::Fn(Function { vec![ast::Definition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 14..61), location: Span::new((), 14..61),
@ -2465,6 +2548,7 @@ fn clause_guards() {
assert_definitions( assert_definitions(
code, code,
vec![ast::Definition::Fn(Function { vec![ast::Definition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 13..250), location: Span::new((), 13..250),
@ -2719,6 +2803,7 @@ fn scope_logical_expression() {
assert_definitions( assert_definitions(
code, code,
vec![ast::Definition::Fn(Function { vec![ast::Definition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 13..61), location: Span::new((), 13..61),
@ -2817,6 +2902,7 @@ fn trace_expressions() {
assert_definitions( assert_definitions(
code, code,
vec![ast::Definition::Fn(Function { vec![ast::Definition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Sequence { body: expr::UntypedExpr::Sequence {
location: Span::new((), 13..131), location: Span::new((), 13..131),
@ -2942,6 +3028,7 @@ fn parse_keyword_error() {
code, code,
vec![ vec![
ast::Definition::Fn(Function { ast::Definition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Trace { body: expr::UntypedExpr::Trace {
kind: ast::TraceKind::Error, kind: ast::TraceKind::Error,
@ -2963,6 +3050,7 @@ fn parse_keyword_error() {
end_position: 38, end_position: 38,
}), }),
ast::Definition::Fn(Function { ast::Definition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 54..110), location: Span::new((), 54..110),
@ -3041,6 +3129,7 @@ fn parse_keyword_todo() {
code, code,
vec![ vec![
ast::Definition::Fn(Function { ast::Definition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::Trace { body: expr::UntypedExpr::Trace {
kind: ast::TraceKind::Todo, kind: ast::TraceKind::Todo,
@ -3062,6 +3151,7 @@ fn parse_keyword_todo() {
end_position: 37, end_position: 37,
}), }),
ast::Definition::Fn(Function { ast::Definition::Fn(Function {
can_error: true,
arguments: vec![], arguments: vec![],
body: expr::UntypedExpr::When { body: expr::UntypedExpr::When {
location: Span::new((), 53..121), location: Span::new((), 53..121),

View File

@ -197,6 +197,7 @@ impl<'a> Environment<'a> {
return_annotation, return_annotation,
return_type, return_type,
end_position, end_position,
can_error,
}) => { }) => {
// Lookup the inferred function information // Lookup the inferred function information
let function = self let function = self
@ -241,6 +242,7 @@ impl<'a> Environment<'a> {
return_type, return_type,
body, body,
end_position, end_position,
can_error,
}) })
} }

View File

@ -160,6 +160,7 @@ fn infer_definition(
body, body,
return_annotation, return_annotation,
end_position, end_position,
can_error,
.. ..
}) => { }) => {
if public && kind.is_validator() { if public && kind.is_validator() {
@ -246,6 +247,7 @@ fn infer_definition(
.return_type() .return_type()
.expect("Could not find return type for fn"), .expect("Could not find return type for fn"),
body, body,
can_error,
end_position, end_position,
})) }))
} }

View File

@ -670,7 +670,12 @@ where
let mut programs = Vec::new(); let mut programs = Vec::new();
for (input_path, module_name, func_def) in scripts { for (input_path, module_name, func_def) in scripts {
let Function { name, body, .. } = func_def; let Function {
name,
body,
can_error,
..
} = func_def;
if verbose { if verbose {
self.event_listener.handle_event(Event::GeneratingUPLCFor { self.event_listener.handle_event(Event::GeneratingUPLCFor {
@ -711,6 +716,7 @@ where
input_path, input_path,
module_name, module_name,
name.to_string(), name.to_string(),
*can_error,
program.try_into().unwrap(), program.try_into().unwrap(),
evaluation_hint, evaluation_hint,
); );
@ -737,7 +743,7 @@ where
let mut eval_result = script.program.clone().eval(initial_budget); let mut eval_result = script.program.clone().eval(initial_budget);
EvalInfo { EvalInfo {
success: !eval_result.failed(), success: !eval_result.failed(script.can_error),
script, script,
spent_budget: eval_result.cost(), spent_budget: eval_result.cost(),
logs: eval_result.logs(), logs: eval_result.logs(),

View File

@ -8,6 +8,7 @@ pub struct Script {
pub input_path: PathBuf, pub input_path: PathBuf,
pub module: String, pub module: String,
pub name: String, pub name: String,
pub can_error: bool,
pub program: Program<NamedDeBruijn>, pub program: Program<NamedDeBruijn>,
pub evaluation_hint: Option<EvalHint>, pub evaluation_hint: Option<EvalHint>,
} }
@ -19,6 +20,7 @@ impl Script {
input_path: PathBuf, input_path: PathBuf,
module: String, module: String,
name: String, name: String,
can_error: bool,
program: Program<NamedDeBruijn>, program: Program<NamedDeBruijn>,
evaluation_hint: Option<EvalHint>, evaluation_hint: Option<EvalHint>,
) -> Script { ) -> Script {
@ -27,6 +29,7 @@ impl Script {
module, module,
name, name,
program, program,
can_error,
evaluation_hint, evaluation_hint,
} }
} }

View File

@ -80,7 +80,7 @@ fn assert_uplc(source_code: &str, expected: Term<Name>, should_fail: bool) {
let mut eval = debruijn_program.eval(ExBudget::default()); let mut eval = debruijn_program.eval(ExBudget::default());
assert_eq!( assert_eq!(
eval.failed(), eval.failed(false),
should_fail, should_fail,
"logs - {}\n", "logs - {}\n",
format!("{:#?}", eval.logs()) format!("{:#?}", eval.logs())

View File

@ -32,11 +32,15 @@ impl EvalResult {
std::mem::take(&mut self.logs) std::mem::take(&mut self.logs)
} }
pub fn failed(&self) -> bool { pub fn failed(&self, can_error: bool) -> bool {
if can_error {
!matches!(self.result, Err(_))
} else {
matches!(self.result, Err(_)) matches!(self.result, Err(_))
|| matches!(self.result, Ok(Term::Error)) || matches!(self.result, Ok(Term::Error))
|| matches!(self.result, Ok(Term::Constant(ref con)) if matches!(con.as_ref(), Constant::Bool(false))) || matches!(self.result, Ok(Term::Constant(ref con)) if matches!(con.as_ref(), Constant::Bool(false)))
} }
}
pub fn result(self) -> Result<Term<NamedDeBruijn>, Error> { pub fn result(self) -> Result<Term<NamedDeBruijn>, Error> {
self.result self.result