#![allow(missing_docs)] use std::collections::HashMap; use std::path::Path; use nomo::Context; use nomo::functions::FunctionMap; use nomo::input::NomoInput; test_each_file::test_each_path! { for ["nomo"] in "./tests/cases/" as cases => check_for_input } test_each_file::test_each_path! { for ["nomo"] in "./tests/errors/" as error_cases => check_errors } #[derive(serde::Serialize)] struct Info { input: String, context: HashMap, } fn check_for_input([path]: [&Path; 1]) { let mut settings = insta::Settings::clone_current(); settings.set_snapshot_path("cases"); settings.set_prepend_module_to_snapshot(false); let basename = path.file_stem().unwrap().to_string_lossy(); let input = std::fs::read_to_string(path).unwrap(); let (context, input) = input.split_once("\n---\n").unwrap_or_else(|| ("", &input)); let map = if !context.is_empty() { serde_json::from_str::>(context).unwrap() } else { HashMap::new() }; settings.set_info(&Info { input: input.to_string(), context: map.clone(), }); let mut context = Context::new(); for (k, v) in map { context.try_insert(k, v).unwrap(); } let input = NomoInput::from(input); let parsed = nomo::lexer::parse(input.clone()).unwrap(); let _guard = settings.bind_to_scope(); insta::assert_debug_snapshot!(format!("{basename}.1-parsed"), parsed); let ast = match nomo::parser::parse(input, parsed.tokens()) { Ok(ast) => ast, Err(err) => { eprintln!("{}", err); panic!("Could not evaluate ast"); } }; insta::assert_debug_snapshot!(format!("{basename}.2-ast"), ast); let emit = nomo::compiler::emit_machine(ast); insta::assert_debug_snapshot!(format!("{basename}.3-instructions"), emit); let output = nomo::eval::execute(&FunctionMap::default(), &emit, &context).unwrap(); insta::assert_debug_snapshot!(format!("{basename}.4-output"), output); } fn check_errors([path]: [&Path; 1]) { let mut settings = insta::Settings::clone_current(); settings.set_snapshot_path("errors"); settings.set_prepend_module_to_snapshot(false); let basename = path.file_stem().unwrap().to_string_lossy(); let input = std::fs::read_to_string(path).unwrap(); let (context, input) = input.split_once("\n---\n").unwrap_or_else(|| ("", &input)); let map = if !context.is_empty() { serde_json::from_str::>(context).unwrap() } else { HashMap::new() }; settings.set_info(&Info { input: input.to_string(), context: map.clone(), }); let mut context = Context::new(); for (k, v) in map { context.try_insert(k, v).unwrap(); } let _guard = settings.bind_to_scope(); let input = NomoInput::from(input); let parsed = nomo::lexer::parse(input.clone()).map_err(|err| err.to_report()); match &parsed { Ok(parsed) => insta::assert_debug_snapshot!(format!("{basename}.1-parsed"), parsed), Err(parsed) => insta::assert_snapshot!(format!("{basename}.1-parsed"), parsed), } let Ok(parsed) = parsed else { return; }; let ast = nomo::parser::parse(input, parsed.tokens()).map_err(|err| err.to_string()); match &ast { Ok(ast) => insta::assert_debug_snapshot!(format!("{basename}.2-ast"), ast), Err(ast) => insta::assert_snapshot!(format!("{basename}.2-ast"), ast), } let Ok(ast) = ast else { return; }; let emit = nomo::compiler::emit_machine(ast); insta::assert_debug_snapshot!(format!("{basename}.3-instructions"), emit); let output = nomo::eval::execute(&FunctionMap::default(), &emit, &context) .map_err(|err| err.to_string()); match &output { Ok(output) => insta::assert_debug_snapshot!(format!("{basename}.4-output"), output), Err(output) => insta::assert_snapshot!(format!("{basename}.4-output"), output), } }