diff options
Diffstat (limited to '')
-rw-r--r-- | dhall/build.rs | 483 | ||||
-rw-r--r-- | dhall/src/phase/resolve.rs | 13 | ||||
-rw-r--r-- | dhall/src/tests.rs | 323 |
3 files changed, 457 insertions, 362 deletions
diff --git a/dhall/build.rs b/dhall/build.rs index 166b036..4c654c9 100644 --- a/dhall/build.rs +++ b/dhall/build.rs @@ -2,77 +2,99 @@ use std::env; use std::ffi::OsString; use std::fs::File; use std::io::Write; -use std::path::Path; +use std::path::{Path, PathBuf}; use walkdir::WalkDir; +#[derive(Debug, Clone, Copy)] +enum FileType { + Text, + Binary, +} + +impl FileType { + fn to_ext(self) -> &'static str { + match self { + FileType::Text => "dhall", + FileType::Binary => "dhallb", + } + } +} + fn dhall_files_in_dir<'a>( dir: &'a Path, take_a_suffix: bool, + filetype: FileType, ) -> impl Iterator<Item = (String, String)> + 'a { WalkDir::new(dir) .into_iter() .filter_map(|e| e.ok()) .filter_map(move |path| { - let path = path.path(); - let path = path.strip_prefix(dir).unwrap(); - let ext = path.extension(); - if ext != Some(&OsString::from("dhall")) - && ext != Some(&OsString::from("dhallb")) - { + let path = path.path().strip_prefix(dir).unwrap(); + let ext = path.extension()?; + if ext != &OsString::from(filetype.to_ext()) { return None; } - let ext = ext.unwrap(); let path = path.to_string_lossy(); let path = &path[..path.len() - 1 - ext.len()]; - let path = if take_a_suffix { - if &path[path.len() - 1..] != "A" { - return None; - } else { - path[..path.len() - 1].to_owned() - } + let path = if take_a_suffix && &path[path.len() - 1..] != "A" { + return None; + } else if take_a_suffix { + path[..path.len() - 1].to_owned() } else { path.to_owned() }; + // Transform path into a valie Rust identifier let name = path.replace("/", "_").replace("-", "_"); Some((name, path)) }) } +#[derive(Debug, Clone)] +struct TestFeature<F> { + /// Name of the module, used in the output of `cargo test` + module_name: &'static str, + /// Directory containing the tests files + directory: PathBuf, + /// Relevant variant of `dhall::tests::Test` + variant: &'static str, + /// Given a file name, whether to exclude it + path_filter: F, + /// Type of the input file + input_type: FileType, + /// Type of the output file, if any + output_type: Option<FileType>, +} + fn make_test_module( w: &mut impl Write, // Where to output the generated code - mod_name: &str, // Name of the module, used in the output of `cargo test` - subdir: &str, // Directory containing the tests files - feature: &str, // Relevant variant of `dhall::tests::Feature` - mut exclude: impl FnMut(&str) -> bool, // Given a file name, whether to exclude it + mut feature: TestFeature<impl FnMut(&str) -> bool>, ) -> std::io::Result<()> { - let all_tests_dir = Path::new("../dhall-lang/tests/"); - let tests_dir = all_tests_dir.join(subdir); - writeln!(w, "mod {} {{", mod_name)?; - for (name, path) in dhall_files_in_dir(&tests_dir.join("success/"), true) { - if exclude(&("success/".to_owned() + &path)) { + let tests_dir = feature.directory; + writeln!(w, "mod {} {{", feature.module_name)?; + let take_a_suffix = feature.output_type.is_some(); + for (name, path) in + dhall_files_in_dir(&tests_dir, take_a_suffix, feature.input_type) + { + if (feature.path_filter)(&path) { continue; } - writeln!( - w, - r#"make_spec_test!({}, Success, success_{}, "{}/success/{}");"#, - feature, - name, - tests_dir.to_string_lossy(), - path - )?; - } - for (name, path) in dhall_files_in_dir(&tests_dir.join("failure/"), false) { - if exclude(&("failure/".to_owned() + &path)) { - continue; - } - writeln!( - w, - r#"make_spec_test!({}, Failure, failure_{}, "{}/failure/{}");"#, - feature, - name, - tests_dir.to_string_lossy(), - path - )?; + let path = tests_dir.join(path); + let path = path.to_string_lossy(); + let test = match feature.output_type { + None => { + let input_file = + format!("\"{}.{}\"", path, feature.input_type.to_ext()); + format!("{}({})", feature.variant, input_file) + } + Some(output_type) => { + let input_file = + format!("\"{}A.{}\"", path, feature.input_type.to_ext()); + let output_file = + format!("\"{}B.{}\"", path, output_type.to_ext()); + format!("{}({}, {})", feature.variant, input_file, output_file) + } + }; + writeln!(w, "make_spec_test!({}, {});", test, name)?; } writeln!(w, "}}")?; Ok(()) @@ -88,177 +110,270 @@ fn main() -> std::io::Result<()> { let out_dir = env::var("OUT_DIR").unwrap(); let parser_tests_path = Path::new(&out_dir).join("spec_tests.rs"); + let spec_tests_dir = Path::new("../dhall-lang/tests/"); let mut file = File::create(parser_tests_path)?; - make_test_module(&mut file, "parse", "parser/", "Parser", |path| { - false - // Too slow in debug mode - || path == "success/largeExpression" - // TODO: projection by expression - || path == "success/recordProjectionByExpression" - || path == "success/RecordProjectionByType" - || path == "success/unit/RecordProjectionByType" - || path == "success/unit/RecordProjectionByTypeEmpty" - || path == "success/unit/RecordProjectFields" - // TODO: RFC3986 URLs - || path == "success/unit/import/urls/emptyPath0" - || path == "success/unit/import/urls/emptyPath1" - || path == "success/unit/import/urls/emptyPathSegment" - // TODO: toMap - || path == "success/toMap" - })?; + make_test_module( + &mut file, + TestFeature { + module_name: "parser_success", + directory: spec_tests_dir.join("parser/success/"), + variant: "ParserSuccess", + path_filter: |path: &str| { + false + // Too slow in debug mode + || path == "largeExpression" + // TODO: projection by expression + || path == "recordProjectionByExpression" + || path == "RecordProjectionByType" + || path == "unit/RecordProjectionByType" + || path == "unit/RecordProjectionByTypeEmpty" + || path == "unit/RecordProjectFields" + // TODO: RFC3986 URLs + || path == "unit/import/urls/emptyPath0" + || path == "unit/import/urls/emptyPath1" + || path == "unit/import/urls/emptyPathSegment" + // TODO: toMap + || path == "toMap" + }, + input_type: FileType::Text, + output_type: Some(FileType::Binary), + }, + )?; + + make_test_module( + &mut file, + TestFeature { + module_name: "parser_failure", + directory: spec_tests_dir.join("parser/failure/"), + variant: "ParserFailure", + path_filter: |_path: &str| false, + input_type: FileType::Text, + output_type: None, + }, + )?; + + make_test_module( + &mut file, + TestFeature { + module_name: "printer", + directory: spec_tests_dir.join("parser/success/"), + variant: "Printer", + path_filter: |path: &str| { + false + // Too slow in debug mode + || path == "largeExpression" + // TODO: projection by expression + || path == "recordProjectionByExpression" + || path == "RecordProjectionByType" + || path == "unit/RecordProjectionByType" + || path == "unit/RecordProjectionByTypeEmpty" + // TODO: RFC3986 URLs + || path == "unit/import/urls/emptyPath0" + || path == "unit/import/urls/emptyPath1" + || path == "unit/import/urls/emptyPathSegment" + // TODO: toMap + || path == "toMap" + }, + input_type: FileType::Text, + output_type: Some(FileType::Binary), + }, + )?; - make_test_module(&mut file, "printer", "parser/", "Printer", |path| { - // Failure tests are only for the parser - path.starts_with("failure/") - // Too slow in debug mode - || path == "success/largeExpression" - // TODO: projection by expression - || path == "success/recordProjectionByExpression" - || path == "success/RecordProjectionByType" - || path == "success/unit/RecordProjectionByType" - || path == "success/unit/RecordProjectionByTypeEmpty" - // TODO: RFC3986 URLs - || path == "success/unit/import/urls/emptyPath0" - || path == "success/unit/import/urls/emptyPath1" - || path == "success/unit/import/urls/emptyPathSegment" - // TODO: toMap - || path == "success/toMap" - })?; + make_test_module( + &mut file, + TestFeature { + module_name: "binary_encoding", + directory: spec_tests_dir.join("parser/success/"), + variant: "BinaryEncoding", + path_filter: |path: &str| { + false + // Too slow in debug mode + || path == "largeExpression" + // See https://github.com/pyfisch/cbor/issues/109 + || path == "double" + || path == "unit/DoubleLitExponentNoDot" + || path == "unit/DoubleLitSecretelyInt" + // TODO: projection by expression + || path == "recordProjectionByExpression" + || path == "RecordProjectionByType" + || path == "unit/RecordProjectionByType" + || path == "unit/RecordProjectionByTypeEmpty" + // TODO: RFC3986 URLs + || path == "unit/import/urls/emptyPath0" + || path == "unit/import/urls/emptyPath1" + || path == "unit/import/urls/emptyPathSegment" + // TODO: toMap + || path == "toMap" + }, + input_type: FileType::Text, + output_type: Some(FileType::Binary), + }, + )?; + + make_test_module( + &mut file, + TestFeature { + module_name: "binary_decoding_success", + directory: spec_tests_dir.join("binary-decode/success/"), + variant: "BinaryDecodingSuccess", + path_filter: |path: &str| { + false + // TODO: projection by expression + || path == "unit/RecordProjectFields" + || path == "unit/recordProjectionByExpression" + // TODO: toMap + || path == "unit/ToMap" + || path == "unit/ToMapAnnotated" + }, + input_type: FileType::Binary, + output_type: Some(FileType::Text), + }, + )?; + + make_test_module( + &mut file, + TestFeature { + module_name: "binary_decoding_failure", + directory: spec_tests_dir.join("binary-decode/failure/"), + variant: "BinaryDecodingFailure", + path_filter: |_path: &str| false, + input_type: FileType::Binary, + output_type: None, + }, + )?; make_test_module( &mut file, - "binary_encoding", - "parser/", - "BinaryEncoding", - |path| { - // Failure tests are only for the parser - path.starts_with("failure/") - // Too slow in debug mode - || path == "success/largeExpression" - // See https://github.com/pyfisch/cbor/issues/109 - || path == "success/double" - || path == "success/unit/DoubleLitExponentNoDot" - || path == "success/unit/DoubleLitSecretelyInt" - // TODO: projection by expression - || path == "success/recordProjectionByExpression" - || path == "success/RecordProjectionByType" - || path == "success/unit/RecordProjectionByType" - || path == "success/unit/RecordProjectionByTypeEmpty" - // TODO: RFC3986 URLs - || path == "success/unit/import/urls/emptyPath0" - || path == "success/unit/import/urls/emptyPath1" - || path == "success/unit/import/urls/emptyPathSegment" - // TODO: toMap - || path == "success/toMap" + TestFeature { + module_name: "beta_normalize", + directory: spec_tests_dir.join("normalization/success/"), + variant: "Normalization", + path_filter: |path: &str| { + // We don't support bignums + path == "simple/integerToDouble" + // Too slow + || path == "remoteSystems" + // TODO: projection by expression + || path == "unit/RecordProjectionByTypeEmpty" + || path == "unit/RecordProjectionByTypeNonEmpty" + || path == "unit/RecordProjectionByTypeNormalizeProjection" + // TODO: fix Double/show + || path == "prelude/JSON/number/1" + // TODO: toMap + || path == "unit/EmptyToMap" + || path == "unit/ToMap" + || path == "unit/ToMapWithType" + // TODO: Normalize field selection further by inspecting the argument + || path == "simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0" + || path == "simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1" + || path == "simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselection" + || path == "unit/RecordProjectionByTypeWithinFieldSelection" + || path == "unit/RecordProjectionWithinFieldSelection" + || path == "unit/RecursiveRecordMergeWithinFieldSelection0" + || path == "unit/RecursiveRecordMergeWithinFieldSelection1" + || path == "unit/RecursiveRecordMergeWithinFieldSelection2" + || path == "unit/RecursiveRecordMergeWithinFieldSelection3" + || path == "unit/RightBiasedMergeWithinFieldSelection0" + || path == "unit/RightBiasedMergeWithinFieldSelection1" + || path == "unit/RightBiasedMergeWithinFieldSelection2" + || path == "unit/RightBiasedMergeWithinFieldSelection3" + || path == "unit/RightBiasedMergeEquivalentArguments" + }, + input_type: FileType::Text, + output_type: Some(FileType::Text), }, )?; make_test_module( &mut file, - "binary_decoding", - "binary-decode/", - "BinaryDecoding", - |path| { - false - // TODO: projection by expression - || path == "success/unit/RecordProjectFields" - || path == "success/unit/recordProjectionByExpression" - // TODO: toMap - || path == "success/unit/ToMap" - || path == "success/unit/ToMapAnnotated" + TestFeature { + module_name: "alpha_normalize", + directory: spec_tests_dir.join("alpha-normalization/success/"), + variant: "AlphaNormalization", + path_filter: |path: &str| { + // This test doesn't typecheck + path == "unit/FunctionNestedBindingXXFree" + }, + input_type: FileType::Text, + output_type: Some(FileType::Text), }, )?; make_test_module( &mut file, - "beta_normalize", - "normalization/", - "Normalization", - |path| { - // We don't support bignums - path == "success/simple/integerToDouble" - // Too slow - || path == "success/remoteSystems" - // TODO: projection by expression - || path == "success/unit/RecordProjectionByTypeEmpty" - || path == "success/unit/RecordProjectionByTypeNonEmpty" - || path == "success/unit/RecordProjectionByTypeNormalizeProjection" - // TODO: fix Double/show - || path == "success/prelude/JSON/number/1" - // TODO: toMap - || path == "success/unit/EmptyToMap" - || path == "success/unit/ToMap" - || path == "success/unit/ToMapWithType" - // TODO: Normalize field selection further by inspecting the argument - || path == "success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection0" - || path == "success/simplifications/rightBiasedMergeWithinRecordProjectionWithinFieldSelection1" - || path == "success/simplifications/rightBiasedMergeWithinRecursiveRecordMergeWithinFieldselection" - || path == "success/unit/RecordProjectionByTypeWithinFieldSelection" - || path == "success/unit/RecordProjectionWithinFieldSelection" - || path == "success/unit/RecursiveRecordMergeWithinFieldSelection0" - || path == "success/unit/RecursiveRecordMergeWithinFieldSelection1" - || path == "success/unit/RecursiveRecordMergeWithinFieldSelection2" - || path == "success/unit/RecursiveRecordMergeWithinFieldSelection3" - || path == "success/unit/RightBiasedMergeWithinFieldSelection0" - || path == "success/unit/RightBiasedMergeWithinFieldSelection1" - || path == "success/unit/RightBiasedMergeWithinFieldSelection2" - || path == "success/unit/RightBiasedMergeWithinFieldSelection3" - || path == "success/unit/RightBiasedMergeEquivalentArguments" + TestFeature { + module_name: "typecheck_success", + directory: spec_tests_dir.join("typecheck/success/"), + variant: "TypecheckSuccess", + path_filter: |path: &str| { + false + // Too slow + || path == "prelude" + }, + input_type: FileType::Text, + output_type: Some(FileType::Text), }, )?; make_test_module( &mut file, - "alpha_normalize", - "alpha-normalization/", - "AlphaNormalization", - |path| { - // This test doesn't typecheck - path == "success/unit/FunctionNestedBindingXXFree" + TestFeature { + module_name: "typecheck_failure", + directory: spec_tests_dir.join("typecheck/failure/"), + variant: "TypecheckFailure", + path_filter: |path: &str| { + false + // TODO: Enable imports in typecheck tests + || path == "importBoundary" + || path == "customHeadersUsingBoundVariable" + // TODO: projection by expression + || path == "unit/RecordProjectionByTypeFieldTypeMismatch" + || path == "unit/RecordProjectionByTypeNotPresent" + // TODO: toMap + || path == "unit/EmptyToMap" + || path == "unit/HeterogenousToMap" + || path == "unit/MistypedToMap1" + || path == "unit/MistypedToMap2" + || path == "unit/MistypedToMap3" + || path == "unit/MistypedToMap4" + || path == "unit/NonRecordToMap" + }, + input_type: FileType::Text, + output_type: None, }, )?; make_test_module( &mut file, - "typecheck", - "typecheck/", - "Typecheck", - |path| { - false - // TODO: Enable imports in typecheck tests - || path == "failure/importBoundary" - || path == "failure/customHeadersUsingBoundVariable" - // Too slow - || path == "success/prelude" - // TODO: projection by expression - || path == "failure/unit/RecordProjectionByTypeFieldTypeMismatch" - || path == "failure/unit/RecordProjectionByTypeNotPresent" - // TODO: toMap - || path == "failure/unit/EmptyToMap" - || path == "failure/unit/HeterogenousToMap" - || path == "failure/unit/MistypedToMap1" - || path == "failure/unit/MistypedToMap2" - || path == "failure/unit/MistypedToMap3" - || path == "failure/unit/MistypedToMap4" - || path == "failure/unit/NonRecordToMap" + TestFeature { + module_name: "type_inference_success", + directory: spec_tests_dir.join("type-inference/success/"), + variant: "TypeInferenceSuccess", + path_filter: |path: &str| { + false + // TODO: projection by expression + || path == "unit/RecordProjectionByType" + || path == "unit/RecordProjectionByTypeEmpty" + || path == "unit/RecordProjectionByTypeJudgmentalEquality" + // TODO: toMap + || path == "unit/ToMap" + || path == "unit/ToMapAnnotated" + }, + input_type: FileType::Text, + output_type: Some(FileType::Text), }, )?; make_test_module( &mut file, - "type_inference", - "type-inference/", - "TypeInference", - |path| { - false - // TODO: projection by expression - || path == "success/unit/RecordProjectionByType" - || path == "success/unit/RecordProjectionByTypeEmpty" - || path == "success/unit/RecordProjectionByTypeJudgmentalEquality" - // TODO: toMap - || path == "success/unit/ToMap" - || path == "success/unit/ToMapAnnotated" + TestFeature { + module_name: "type_inference_failure", + directory: spec_tests_dir.join("type-inference/failure/"), + variant: "TypeInferenceFailure", + path_filter: |_path: &str| false, + input_type: FileType::Text, + output_type: None, }, )?; diff --git a/dhall/src/phase/resolve.rs b/dhall/src/phase/resolve.rs index b715e72..a58f5e4 100644 --- a/dhall/src/phase/resolve.rs +++ b/dhall/src/phase/resolve.rs @@ -109,13 +109,22 @@ pub(crate) fn skip_resolve_expr( mod spec_tests { macro_rules! import_success { ($name:ident, $path:expr) => { - make_spec_test!(Import, Success, $name, &("../dhall-lang/tests/import/success/".to_owned() + $path)); + make_spec_test!( + ImportSuccess( + &("../dhall-lang/tests/import/success/".to_owned() + $path + "A.dhall"), + &("../dhall-lang/tests/import/success/".to_owned() + $path + "B.dhall") + ), + $name + ); }; } // macro_rules! import_failure { // ($name:ident, $path:expr) => { - // make_spec_test!(Import, Failure, $name, &("../dhall-lang/tests/import/failure/".to_owned() + $path)); + // make_spec_test!( + // ImportFailure(&("../dhall-lang/tests/import/failure/".to_owned() + $path + ".dhall")), + // $name + // ); // }; // } diff --git a/dhall/src/tests.rs b/dhall/src/tests.rs index 3055717..ae41038 100644 --- a/dhall/src/tests.rs +++ b/dhall/src/tests.rs @@ -22,13 +22,13 @@ right: `{}`"#, #[macro_export] macro_rules! make_spec_test { - ($type:ident, $status:ident, $name:ident, $path:expr) => { + ($type:expr, $name:ident) => { #[test] #[allow(non_snake_case)] fn $name() { + use crate::tests::Test::*; use crate::tests::*; - match run_test_stringy_error($path, Feature::$type, Status::$status) - { + match run_test_stringy_error($type) { Ok(_) => {} Err(s) => panic!(s), } @@ -44,24 +44,22 @@ use crate::error::{Error, Result}; use crate::phase::Parsed; #[allow(dead_code)] -#[derive(Copy, Clone)] -pub enum Feature { - Parser, - Printer, - BinaryEncoding, - BinaryDecoding, - Import, - Normalization, - AlphaNormalization, - Typecheck, - TypeInference, -} - -#[allow(dead_code)] -#[derive(Copy, Clone)] -pub enum Status { - Success, - Failure, +#[derive(Clone)] +pub enum Test<'a> { + ParserSuccess(&'a str, &'a str), + ParserFailure(&'a str), + Printer(&'a str, &'a str), + BinaryEncoding(&'a str, &'a str), + BinaryDecodingSuccess(&'a str, &'a str), + BinaryDecodingFailure(&'a str), + ImportSuccess(&'a str, &'a str), + ImportFailure(&'a str), + TypecheckSuccess(&'a str, &'a str), + TypecheckFailure(&'a str), + TypeInferenceSuccess(&'a str, &'a str), + TypeInferenceFailure(&'a str), + Normalization(&'a str, &'a str), + AlphaNormalization(&'a str, &'a str), } fn parse_file_str(file_path: &str) -> Result<Parsed> { @@ -70,180 +68,153 @@ fn parse_file_str(file_path: &str) -> Result<Parsed> { #[allow(dead_code)] pub fn run_test_stringy_error( - base_path: &str, - feature: Feature, - status: Status, + test: Test<'_>, ) -> std::result::Result<(), String> { - let base_path: String = base_path.to_string(); - run_test(&base_path, feature, status) - .map_err(|e| e.to_string()) - .map(|_| ()) + run_test(test).map_err(|e| e.to_string()).map(|_| ()) } -#[allow(clippy::single_match)] -pub fn run_test( - base_path: &str, - feature: Feature, - status: Status, -) -> Result<()> { - use self::Feature::*; - use self::Status::*; - let base_path = base_path.to_owned(); - match status { - Success => { - match feature { - BinaryDecoding => { - let expr_file_path = base_path.clone() + "A.dhallb"; - let expr_file_path = PathBuf::from(&expr_file_path); - let mut expr_data = Vec::new(); - { - File::open(&expr_file_path)? - .read_to_end(&mut expr_data)?; - } - let expr = Parsed::parse_binary(&expr_data)?; - let expected_file_path = base_path + "B.dhall"; - let expected = parse_file_str(&expected_file_path)?; - assert_eq_pretty!(expr, expected); - - return Ok(()); +pub fn run_test(test: Test<'_>) -> Result<()> { + use self::Test::*; + match test { + ParserSuccess(expr_file_path, expected_file_path) => { + let expr = parse_file_str(&expr_file_path)?; + // This exercices both parsing and binary decoding + // Compare parse/decoded + let expected = + Parsed::parse_binary_file(&PathBuf::from(expected_file_path))?; + assert_eq_pretty!(expr, expected); + } + ParserFailure(file_path) => { + let err = parse_file_str(&file_path).unwrap_err(); + match &err { + Error::Parse(_) => {} + Error::IO(e) if e.kind() == std::io::ErrorKind::InvalidData => { } - _ => {} + e => panic!("Expected parse error, got: {:?}", e), } - let expr_file_path = base_path.clone() + "A.dhall"; + } + BinaryEncoding(expr_file_path, expected_file_path) => { let expr = parse_file_str(&expr_file_path)?; - - match feature { - Parser => { - // This exercices both parsing and binary decoding - // Compare parse/decoded - let expected_file_path = base_path + "B.dhallb"; - let expected_file_path = PathBuf::from(&expected_file_path); - let mut expected_data = Vec::new(); - { - File::open(&expected_file_path)? - .read_to_end(&mut expected_data)?; - } - let expected = Parsed::parse_binary(&expected_data)?; - assert_eq_pretty!(expr, expected); - - return Ok(()); - } - Printer => { - // Round-trip pretty-printer - let expr_string = expr.to_string(); - let expected = expr; - let expr: Parsed = Parsed::parse_str(&expr_string)?; - assert_eq!(expr, expected); - - return Ok(()); - } - BinaryEncoding => { - let expected_file_path = base_path + "B.dhallb"; - let expected_file_path = PathBuf::from(&expected_file_path); - let mut expected_data = Vec::new(); - { - File::open(&expected_file_path)? - .read_to_end(&mut expected_data)?; - } - let expr_data = expr.encode()?; - - // Compare bit-by-bit - if expr_data != expected_data { - // use std::io::Write; - // File::create(&expected_file_path)?.write_all(&expr_data)?; - // Pretty-print difference - assert_eq_pretty!( - serde_cbor::de::from_slice::< - serde_cbor::value::Value, - >(&expr_data) - .unwrap(), - serde_cbor::de::from_slice::< - serde_cbor::value::Value, - >(&expected_data) - .unwrap() - ); - // If difference was not visible in the cbor::Value - assert_eq!(expr_data, expected_data); - } - - return Ok(()); - } - _ => {} + let mut expected_data = Vec::new(); + { + File::open(&PathBuf::from(&expected_file_path))? + .read_to_end(&mut expected_data)?; } + let expr_data = expr.encode()?; + + // Compare bit-by-bit + if expr_data != expected_data { + // use std::io::Write; + // File::create(&expected_file_path)?.write_all(&expr_data)?; + // Pretty-print difference + assert_eq_pretty!( + serde_cbor::de::from_slice::<serde_cbor::value::Value>( + &expr_data + ) + .unwrap(), + serde_cbor::de::from_slice::<serde_cbor::value::Value>( + &expected_data + ) + .unwrap() + ); + // If difference was not visible in the cbor::Value + assert_eq!(expr_data, expected_data); + } + } + BinaryDecodingSuccess(expr_file_path, expected_file_path) => { + let expr = + Parsed::parse_binary_file(&PathBuf::from(expr_file_path))?; + let expected = parse_file_str(&expected_file_path)?; + assert_eq_pretty!(expr, expected); + } + BinaryDecodingFailure(file_path) => { + Parsed::parse_binary_file(&PathBuf::from(file_path)).unwrap_err(); + } + Printer(expr_file_path, _) => { + let expected = parse_file_str(&expr_file_path)?; + // Round-trip pretty-printer + let expr: Parsed = Parsed::parse_str(&expected.to_string())?; + assert_eq!(expr, expected); + } + ImportSuccess(expr_file_path, expected_file_path) => { + let expr = parse_file_str(&expr_file_path)? + .resolve()? + .typecheck()? + .normalize(); + let expected = parse_file_str(&expected_file_path)? + .resolve()? + .typecheck()? + .normalize(); - let expr = expr.resolve()?; - - let expected_file_path = base_path + "B.dhall"; + assert_eq_display!(expr, expected); + } + ImportFailure(file_path) => { + parse_file_str(&file_path)?.resolve().unwrap_err(); + } + TypecheckSuccess(expr_file_path, expected_file_path) => { + let expr = parse_file_str(&expr_file_path)?.resolve()?; let expected = parse_file_str(&expected_file_path)? .resolve()? .typecheck()? .normalize(); - match feature { - Parser | Printer | BinaryEncoding | BinaryDecoding => { - unreachable!() - } - Import => { - let expr = expr.typecheck()?.normalize(); - assert_eq_display!(expr, expected); - } - Typecheck => { - expr.typecheck_with(&expected.into_typed())?.get_type()?; - } - TypeInference => { - let expr = expr.typecheck()?; - let ty = expr.get_type()?.normalize(); - assert_eq_display!(ty, expected); - } - Normalization => { - let expr = expr.typecheck()?.normalize(); - assert_eq_display!(expr, expected); - } - AlphaNormalization => { - let expr = expr.typecheck()?.normalize().to_expr_alpha(); - assert_eq_display!(expr, expected.to_expr()); + expr.typecheck_with(&expected.into_typed())?.get_type()?; + } + TypecheckFailure(file_path) => { + let res = parse_file_str(&file_path)?.skip_resolve()?.typecheck(); + match res { + Err(_) => {} + // If e did typecheck, check that it doesn't have a type + Ok(e) => { + e.get_type().unwrap_err(); } } } - Failure => { - let file_path = base_path + ".dhall"; - match feature { - Parser => { - let err = parse_file_str(&file_path).unwrap_err(); - match &err { - Error::Parse(_) => {} - Error::IO(e) - if e.kind() == std::io::ErrorKind::InvalidData => {} - e => panic!("Expected parse error, got: {:?}", e), - } - } - Printer | BinaryEncoding => unreachable!(), - BinaryDecoding => { - let expr_file_path = file_path + "b"; - let mut expr_data = Vec::new(); - { - File::open(&PathBuf::from(&expr_file_path))? - .read_to_end(&mut expr_data)?; - } - Parsed::parse_binary(&expr_data).unwrap_err(); - } - Import => { - parse_file_str(&file_path)?.resolve().unwrap_err(); - } - Normalization | AlphaNormalization => unreachable!(), - Typecheck | TypeInference => { - let res = - parse_file_str(&file_path)?.skip_resolve()?.typecheck(); - match res { - Err(_) => {} - // If e did typecheck, check that it doesn't have a type - Ok(e) => { - e.get_type().unwrap_err(); - } - } + TypeInferenceSuccess(expr_file_path, expected_file_path) => { + let expr = + parse_file_str(&expr_file_path)?.resolve()?.typecheck()?; + let ty = expr.get_type()?.normalize(); + let expected = parse_file_str(&expected_file_path)? + .resolve()? + .typecheck()? + .normalize(); + assert_eq_display!(ty, expected); + } + TypeInferenceFailure(file_path) => { + let res = parse_file_str(&file_path)?.skip_resolve()?.typecheck(); + match res { + Err(_) => {} + // If e did typecheck, check that it doesn't have a type + Ok(e) => { + e.get_type().unwrap_err(); } } } + Normalization(expr_file_path, expected_file_path) => { + let expr = parse_file_str(&expr_file_path)? + .resolve()? + .typecheck()? + .normalize(); + let expected = parse_file_str(&expected_file_path)? + .resolve()? + .typecheck()? + .normalize(); + + assert_eq_display!(expr, expected); + } + AlphaNormalization(expr_file_path, expected_file_path) => { + let expr = parse_file_str(&expr_file_path)? + .resolve()? + .typecheck()? + .normalize() + .to_expr_alpha(); + let expected = parse_file_str(&expected_file_path)? + .resolve()? + .typecheck()? + .normalize(); + + assert_eq_display!(expr, expected.to_expr()); + } } Ok(()) } |