mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 20:28:02 +00:00
Add a Malformed trait, and assert that 'passing' tests don't produce a malformed result
This commit is contained in:
parent
c60dcd763d
commit
a1cd114198
26 changed files with 506 additions and 64 deletions
|
@ -10,9 +10,9 @@ mod test_snapshots {
|
|||
use bumpalo::collections::vec::Vec;
|
||||
use bumpalo::{self, Bump};
|
||||
use roc_parse::ast::Expr::{self, *};
|
||||
use roc_parse::ast::StrLiteral::*;
|
||||
use roc_parse::ast::StrSegment::*;
|
||||
use roc_parse::ast::{self, EscapedChar};
|
||||
use roc_parse::ast::{Malformed, StrLiteral::*};
|
||||
use roc_parse::parser::SyntaxError;
|
||||
use roc_parse::test_helpers::parse_expr_with;
|
||||
use roc_region::all::{Loc, Region};
|
||||
|
@ -35,25 +35,45 @@ mod test_snapshots {
|
|||
};
|
||||
}
|
||||
|
||||
macro_rules! should_pass {
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
enum TestExpectation {
|
||||
Pass, // The test parses successfully and there are no Malformed nodes
|
||||
Fail, // The test gives a parse error
|
||||
Malformed, // The test parses successfully but there are Malformed nodes
|
||||
}
|
||||
|
||||
impl TestExpectation {
|
||||
fn to_dir_name(self) -> &'static str {
|
||||
match self {
|
||||
TestExpectation::Pass => "pass",
|
||||
TestExpectation::Fail => "fail",
|
||||
TestExpectation::Malformed => "malformed",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! test_expectation {
|
||||
(pass) => {
|
||||
true
|
||||
TestExpectation::Pass
|
||||
};
|
||||
(fail) => {
|
||||
false
|
||||
TestExpectation::Fail
|
||||
};
|
||||
(malformed) => {
|
||||
TestExpectation::Malformed
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! snapshot_tests {
|
||||
(
|
||||
$($pass_or_fail:ident / $test_name:ident . $kind:ident),*
|
||||
$($pass_or_fail_or_malformed:ident / $test_name:ident . $kind:ident),*
|
||||
$(,)?
|
||||
) => {
|
||||
#[test]
|
||||
fn no_extra_snapshot_test_files() {
|
||||
let tests = &[
|
||||
$(concat!(
|
||||
stringify!($pass_or_fail),
|
||||
stringify!($pass_or_fail_or_malformed),
|
||||
"/",
|
||||
stringify!($test_name),
|
||||
".",
|
||||
|
@ -70,7 +90,7 @@ mod test_snapshots {
|
|||
let pass_or_fail_names = list(&base);
|
||||
let mut extra_test_files = std::collections::HashSet::new();
|
||||
for res in pass_or_fail_names {
|
||||
assert!(res == "pass" || res == "fail", "a pass or fail filename was neither \"pass\" nor \"fail\", but rather: {:?}", res);
|
||||
assert!(res == "pass" || res == "fail" || res == "malformed", "expected only pass/fail/malformed dirs, but I see: {:?}", res);
|
||||
let res_dir = base.join(&res);
|
||||
for file in list(&res_dir) {
|
||||
let test = if let Some(test) = file.strip_suffix(".formatted.roc") {
|
||||
|
@ -150,7 +170,7 @@ mod test_snapshots {
|
|||
#[test]
|
||||
fn $test_name() {
|
||||
snapshot_test(
|
||||
should_pass!($pass_or_fail),
|
||||
test_expectation!($pass_or_fail_or_malformed),
|
||||
stringify!($test_name),
|
||||
stringify!($kind),
|
||||
|input| snapshot_input!($kind => input));
|
||||
|
@ -227,6 +247,11 @@ mod test_snapshots {
|
|||
fail/when_over_indented_int.expr,
|
||||
fail/when_over_indented_underscore.expr,
|
||||
fail/wild_case_arrow.expr,
|
||||
malformed/bad_opaque_ref.expr,
|
||||
malformed/malformed_ident_due_to_underscore.expr,
|
||||
malformed/malformed_pattern_field_access.expr, // See https://github.com/roc-lang/roc/issues/399
|
||||
malformed/malformed_pattern_module_name.expr, // See https://github.com/roc-lang/roc/issues/399
|
||||
malformed/underscore_expr_in_def.expr,
|
||||
pass/ability_demand_signature_is_multiline.expr,
|
||||
pass/ability_multi_line.expr,
|
||||
pass/ability_single_line.expr,
|
||||
|
@ -244,7 +269,6 @@ mod test_snapshots {
|
|||
pass/apply_two_args.expr,
|
||||
pass/apply_unary_negation.expr,
|
||||
pass/apply_unary_not.expr,
|
||||
pass/bad_opaque_ref.expr,
|
||||
pass/basic_apply.expr,
|
||||
pass/basic_docs.expr,
|
||||
pass/basic_field.expr,
|
||||
|
@ -301,9 +325,6 @@ mod test_snapshots {
|
|||
pass/list_patterns.expr,
|
||||
pass/lowest_float.expr,
|
||||
pass/lowest_int.expr,
|
||||
pass/malformed_ident_due_to_underscore.expr,
|
||||
pass/malformed_pattern_field_access.expr, // See https://github.com/roc-lang/roc/issues/399
|
||||
pass/malformed_pattern_module_name.expr, // See https://github.com/roc-lang/roc/issues/399
|
||||
pass/minimal_app_header.header,
|
||||
pass/minus_twelve_minus_five.expr,
|
||||
pass/mixed_docs.expr,
|
||||
|
@ -324,8 +345,8 @@ mod test_snapshots {
|
|||
pass/negative_float.expr,
|
||||
pass/negative_in_apply_def.expr,
|
||||
pass/negative_int.expr,
|
||||
pass/nested_def_annotation.moduledefs,
|
||||
pass/nested_backpassing_no_newline_before.expr,
|
||||
pass/nested_def_annotation.moduledefs,
|
||||
pass/nested_def_without_newline.expr,
|
||||
pass/nested_if.expr,
|
||||
pass/nested_module.header,
|
||||
|
@ -384,7 +405,7 @@ mod test_snapshots {
|
|||
pass/positive_int.expr,
|
||||
pass/provides_type.header,
|
||||
pass/qualified_field.expr,
|
||||
pass/qualified_tag.expr,
|
||||
malformed/qualified_tag.expr,
|
||||
pass/qualified_var.expr,
|
||||
pass/record_access_after_tuple.expr,
|
||||
pass/record_destructure_def.expr,
|
||||
|
@ -423,7 +444,6 @@ mod test_snapshots {
|
|||
pass/unary_not.expr,
|
||||
pass/unary_not_with_parens.expr,
|
||||
pass/underscore_backpassing.expr,
|
||||
pass/underscore_expr_in_def.expr,
|
||||
pass/underscore_in_assignment_pattern.expr,
|
||||
pass/value_def_confusion.expr,
|
||||
pass/var_else.expr,
|
||||
|
@ -501,13 +521,13 @@ mod test_snapshots {
|
|||
}
|
||||
}
|
||||
|
||||
fn snapshot_test<F>(should_pass: bool, name: &str, ty: &str, func: F)
|
||||
fn snapshot_test<F>(expect: TestExpectation, name: &str, ty: &str, func: F)
|
||||
where
|
||||
F: for<'a> Fn(&'a str) -> Input<'a>,
|
||||
{
|
||||
let mut parent = std::path::PathBuf::from("tests");
|
||||
parent.push("snapshots");
|
||||
parent.push(if should_pass { "pass" } else { "fail" });
|
||||
parent.push(expect.to_dir_name());
|
||||
let input_path = parent.join(&format!("{}.{}.roc", name, ty));
|
||||
let result_path = parent.join(&format!("{}.{}.result-ast", name, ty));
|
||||
let formatted_path = parent.join(&format!("{}.{}.formatted.roc", name, ty));
|
||||
|
@ -523,21 +543,27 @@ mod test_snapshots {
|
|||
|
||||
let arena = Bump::new();
|
||||
let result = match input.parse_in(&arena) {
|
||||
Ok(ast) => Ok(ast.debug_format_inner()),
|
||||
Ok(ast) => {
|
||||
if expect == TestExpectation::Pass {
|
||||
assert!(!ast.is_malformed());
|
||||
}
|
||||
Ok(ast.debug_format_inner())
|
||||
}
|
||||
Err(err) => Err(format!("{:?}", err)),
|
||||
};
|
||||
|
||||
let actual_result = if should_pass {
|
||||
result.expect("The source code for this test did not successfully parse!")
|
||||
} else {
|
||||
result.expect_err(
|
||||
let actual_result =
|
||||
if expect == TestExpectation::Pass || expect == TestExpectation::Malformed {
|
||||
result.expect("The source code for this test did not successfully parse!")
|
||||
} else {
|
||||
result.expect_err(
|
||||
"The source code for this test successfully parsed, but it was not expected to!",
|
||||
)
|
||||
};
|
||||
};
|
||||
|
||||
compare_snapshots(&result_path, Some(&actual_result));
|
||||
|
||||
if should_pass {
|
||||
if expect == TestExpectation::Pass || expect == TestExpectation::Malformed {
|
||||
input.check_invariants(check_saved_formatting(input.as_str(), formatted_path), true);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue