use leo_ast::{NetworkName, NodeBuilder};
use leo_errors::{BufferEmitter, Handler, LeoError};
use leo_span::{Symbol, create_session_if_not_set_then, source_map::FileName, with_session_globals};
use serial_test::serial;
use std::fmt::{Display, Write as _};
fn run_parse_many_test<T: Display>(
test: &str,
handler: &Handler,
test_index: usize,
parse: fn(Handler, &NodeBuilder, &str, u32) -> Result<T, LeoError>,
) -> Result<String, ()> {
let source_map =
with_session_globals(|s| s.source_map.new_source(test, FileName::Custom(format!("test_{test_index}"))));
let result = parse(handler.clone(), &Default::default(), &source_map.src, source_map.absolute_start);
let displayable = handler.extend_if_error(result)?;
Ok(format!("{displayable}\n"))
}
fn runner_parse_many_test<'a, T: Display>(
tests: impl Iterator<Item = &'a str>,
parse: fn(Handler, &NodeBuilder, &str, u32) -> Result<T, LeoError>,
) -> String {
create_session_if_not_set_then(|_| {
let mut output = String::new();
let buf = BufferEmitter::new();
let handler = Handler::new(buf.clone());
for (i, test) in tests.enumerate() {
match run_parse_many_test(test, &handler, i, parse) {
Ok(s) => writeln!(output, "{s}").unwrap(),
Err(()) => write!(output, "{}{}", buf.extract_errs(), buf.extract_warnings()).unwrap(),
}
}
output
})
}
#[test]
#[serial]
fn parse_module_tests() {
leo_test_framework::run_tests("parser-module", runner_module_test);
}
fn runner_module_test(test: &str) -> String {
let test_cases: Vec<String> = test
.lines()
.map(str::trim)
.collect::<Vec<_>>()
.split(|line| line.is_empty())
.map(|paragraph| paragraph.join("\n"))
.filter(|s| !s.trim().is_empty())
.collect();
runner_parse_many_test(test_cases.iter().map(|s| s.as_str()), |handler, node_builder, source, start_pos| {
crate::parse_module(
handler,
node_builder,
source,
start_pos,
Symbol::intern("module_test"),
Vec::new(),
NetworkName::TestnetV0,
)
})
}
fn runner_expression_test(test: &str) -> String {
let tests = test.lines().map(|line| line.trim()).filter(|line| !line.is_empty());
runner_parse_many_test(tests, |handler, node_builder, source, start_pos| {
crate::parse_expression(handler, node_builder, source, start_pos, NetworkName::TestnetV0)
})
}
#[test]
#[serial]
fn parse_expression_tests() {
leo_test_framework::run_tests("parser-expression", runner_expression_test);
}
fn runner_statement_test(test: &str) -> String {
let tests = test.split("\n\n").map(|text| text.trim()).filter(|text| !text.is_empty());
runner_parse_many_test(tests, |handler, node_builder, source, start_pos| {
crate::parse_statement(handler, node_builder, source, start_pos, NetworkName::TestnetV0)
})
}
#[test]
#[serial]
fn parse_statement_tests() {
leo_test_framework::run_tests("parser-statement", runner_statement_test);
}
fn runner_library_test(test: &str) -> String {
let test_cases: Vec<String> = test
.lines()
.map(str::trim)
.collect::<Vec<_>>()
.split(|line| line.is_empty())
.map(|paragraph| paragraph.join("\n"))
.filter(|s| !s.trim().is_empty())
.collect();
create_session_if_not_set_then(|_| {
let mut output = String::new();
let buf = BufferEmitter::new();
let handler = Handler::new(buf.clone());
for (i, test_case) in test_cases.iter().enumerate() {
let source_file =
with_session_globals(|s| s.source_map.new_source(test_case, FileName::Custom(format!("test_{i}"))));
let result = crate::parse_library(
handler.clone(),
&Default::default(),
Symbol::intern("test_lib"),
&source_file,
&[],
NetworkName::TestnetV0,
);
match handler.extend_if_error(result) {
Ok(library) => writeln!(output, "{library}\n").unwrap(),
Err(()) => write!(output, "{}{}", buf.extract_errs(), buf.extract_warnings()).unwrap(),
}
}
output
})
}
#[test]
#[serial]
fn parse_library_tests() {
leo_test_framework::run_tests("parser-library", runner_library_test);
}
fn run_parser_test(test: &str, handler: &Handler) -> Result<String, ()> {
let source_file = with_session_globals(|s| s.source_map.new_source(test, FileName::Custom("test".into())));
let result =
crate::parse_program(handler.clone(), &Default::default(), &source_file, &Vec::new(), NetworkName::TestnetV0);
let ast = handler.extend_if_error(result)?;
Ok(format!("{}\n", ast))
}
fn runner_parser_test(test: &str) -> String {
create_session_if_not_set_then(|_| {
let buf = BufferEmitter::new();
let handler = Handler::new(buf.clone());
match run_parser_test(test, &handler) {
Ok(x) => x,
Err(()) => format!("{}{}", buf.extract_errs(), buf.extract_warnings()),
}
})
}
#[test]
#[serial]
fn parser_tests() {
leo_test_framework::run_tests("parser", runner_parser_test);
}