use crate::{
Parser,
ast::{DiceExpression, Expression, Function},
s_expr::{
SExprError, SExprLocation, SExpressible, SExpressibleOptions,
read_s_expr
},
support::on_small_stack,
tests::ast::{DEPTH, Nesting, nest_parsable}
};
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_group() { read_deep(Nesting::Group) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_binding() { read_deep(Nesting::Binding) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_range_start() { read_deep(Nesting::RangeStart) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_range_end() { read_deep(Nesting::RangeEnd) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_negation() { read_deep(Nesting::Negation) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_exponent() { read_deep(Nesting::Exponent) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_addition() { read_deep(Nesting::Addition) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_subtraction() { read_deep(Nesting::Subtraction) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_multiplication() { read_deep(Nesting::Multiplication) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_division() { read_deep(Nesting::Division) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_modulo() { read_deep(Nesting::Modulo) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_dice_count() { read_deep(Nesting::DiceCount) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_dice_faces() { read_deep(Nesting::DiceFaces) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_custom_count() { read_deep(Nesting::CustomCount) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_drop_expression() { read_deep(Nesting::DropExpression) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_drop_clauses() { read_deep(Nesting::DropClauses) }
#[test]
#[ignore = "stress: run with just stress"]
fn test_read_deep_mixed() { read_deep(Nesting::Mixed) }
const LEAF: i32 = 1_234_567_890;
const OVERFLOW: &str = "99999999999";
fn read_deep(nesting: Nesting)
{
on_small_stack(|| {
let source = nest_parsable(nesting, DEPTH, LEAF).to_string();
let function = Parser::parse(&source).expect("deep source failed");
let s_expr = round_trip(&function);
drop(function);
let leaf = LEAF.to_string();
assert_eq!(s_expr.matches(&leaf).count(), 1, "{:?}", nesting);
let offset = s_expr.find(&leaf).unwrap();
let failing = s_expr.replacen(&leaf, OVERFLOW, 1);
let error = read_s_expr(&failing).expect_err("failing input read");
assert_eq!(
error,
SExprError::InvalidInteger {
text: OVERFLOW.to_string(),
reason: OVERFLOW.parse::<i32>().unwrap_err().to_string(),
location: SExprLocation {
offset,
line: 1,
column: offset + 1
}
},
"{:?}",
nesting
);
});
}
const WRAPPED_DEPTH: usize = 2_000;
#[test]
fn test_read_deep_wrapped()
{
for nesting in Nesting::ROTATION.into_iter().chain([Nesting::Mixed])
{
let source = nest_parsable(nesting, WRAPPED_DEPTH, 1).to_string();
let function = Parser::parse(&source).expect("deep source failed");
let options = SExpressibleOptions::default()
.with_spans(true)
.with_groups(true);
let s_expr = function.to_s_expr(options);
assert!(s_expr.lines().count() > WRAPPED_DEPTH, "{:?}", nesting);
let read = read_s_expr(&s_expr).expect("S-expression failed to read");
assert!(read == function, "{:?}: read back differently", nesting);
}
}
const WIDTH: usize = 1_000_000;
#[test]
fn test_read_wide_parameters()
{
on_small_stack(|| {
let parameters = (0..WIDTH)
.map(|i| format!("{{p{}}}", i))
.collect::<Vec<_>>()
.join(", ");
let source = format!("{}: 1", parameters);
let function = Parser::parse(&source).expect("wide source failed");
assert_eq!(function.parameters.as_ref().map_or(0, Vec::len), WIDTH);
round_trip(&function);
});
}
#[test]
fn test_read_wide_faces()
{
on_small_stack(|| {
let faces = (1..=WIDTH)
.map(|i| i.to_string())
.collect::<Vec<_>>()
.join(", ");
let source = format!("1D[{}]", faces);
let function = Parser::parse(&source).expect("wide source failed");
match &function.body
{
Expression::Dice(DiceExpression::Custom(dice)) =>
{
assert_eq!(dice.faces.len(), WIDTH)
},
_ => panic!("wide source did not parse as custom dice")
}
round_trip(&function);
});
}
fn round_trip(function: &Function<'_>) -> String
{
let options = SExpressibleOptions::new(0, 4, usize::MAX)
.with_spans(true)
.with_groups(true);
let s_expr = function.to_s_expr(options);
let read = read_s_expr(&s_expr).expect("S-expression failed to read");
assert!(read == *function, "S-expression read back differently");
drop(read);
s_expr
}