use mathlex::ast::{BinaryOp, ExprKind, Expression};
use mathlex::error::ParseOutput;
#[test]
fn test_parse_output_is_ok_when_success() {
let output = ParseOutput {
expression: Some(Expression::integer(42)),
errors: vec![],
};
assert!(output.is_ok());
assert!(!output.has_errors());
}
#[test]
fn test_parse_output_not_ok_when_no_expression() {
let output = ParseOutput {
expression: None,
errors: vec![],
};
assert!(!output.is_ok());
}
#[test]
fn test_parse_output_not_ok_when_has_errors() {
let output = ParseOutput {
expression: Some(Expression::integer(42)),
errors: vec![mathlex::ParseError::empty_expression(None)],
};
assert!(!output.is_ok());
assert!(output.has_errors());
}
#[test]
fn test_parse_output_from_ok_result() {
let result: Result<Expression, mathlex::ParseError> = Ok(Expression::integer(1));
let output = ParseOutput::from_result(result);
assert!(output.is_ok());
assert_eq!(output.expression, Some(Expression::integer(1)));
}
#[test]
fn test_parse_output_from_err_result() {
let result: Result<Expression, mathlex::ParseError> =
Err(mathlex::ParseError::empty_expression(None));
let output = ParseOutput::from_result(result);
assert!(!output.is_ok());
assert!(output.expression.is_none());
assert_eq!(output.errors.len(), 1);
}
#[test]
fn test_strict_parse_still_works() {
let expr = mathlex::parse("2 + 3").unwrap();
assert!(matches!(
expr.kind,
ExprKind::Binary {
op: BinaryOp::Add,
..
}
));
}
#[test]
fn test_strict_parse_still_fails_on_error() {
assert!(mathlex::parse("2 + 3)").is_err());
}
#[test]
fn test_strict_latex_still_works() {
let expr = mathlex::parse_latex(r"\frac{1}{2}").unwrap();
assert!(matches!(
expr.kind,
ExprKind::Binary {
op: BinaryOp::Div,
..
}
));
}
#[test]
fn test_strict_latex_still_fails_on_error() {
assert!(mathlex::parse_latex(r"\frac{1}{}").is_err());
}
#[test]
fn test_lenient_text_valid_expression() {
let output = mathlex::parse_lenient("2 + 3");
assert!(output.is_ok());
assert!(matches!(
output.expression,
Some(ref e) if matches!(e.kind, ExprKind::Binary { op: BinaryOp::Add, .. })
));
}
#[test]
fn test_lenient_text_single_number() {
let output = mathlex::parse_lenient("42");
assert!(output.is_ok());
assert_eq!(output.expression, Some(Expression::integer(42)));
}
#[test]
fn test_lenient_text_complex_valid() {
let output = mathlex::parse_lenient("sin(x) + cos(y)");
assert!(output.is_ok());
assert!(!output.has_errors());
}
#[test]
fn test_lenient_text_collects_errors() {
let output = mathlex::parse_lenient("2 + 3)");
assert!(output.has_errors());
}
#[test]
fn test_lenient_text_partial_ast_on_trailing_garbage() {
let output = mathlex::parse_lenient("2 + 3) extra");
assert!(output.has_errors());
assert!(output.expression.is_some());
}
#[test]
fn test_lenient_text_empty_input() {
let output = mathlex::parse_lenient("");
assert!(output.expression.is_none() || output.has_errors());
}
#[test]
fn test_lenient_text_unmatched_paren() {
let output = mathlex::parse_lenient("(2 + 3");
assert!(output.has_errors());
}
#[test]
fn test_lenient_text_multiple_expressions() {
let output = mathlex::parse_lenient("2 + 3 ) 4 + 5");
assert!(output.has_errors());
assert!(output.expression.is_some());
}
#[test]
fn test_lenient_latex_valid_expression() {
let output = mathlex::parse_latex_lenient(r"\frac{1}{2}");
assert!(output.is_ok());
assert!(matches!(
output.expression,
Some(ref e) if matches!(e.kind, ExprKind::Binary { op: BinaryOp::Div, .. })
));
}
#[test]
fn test_lenient_latex_simple_addition() {
let output = mathlex::parse_latex_lenient(r"x + y");
assert!(output.is_ok());
assert!(!output.has_errors());
}
#[test]
fn test_lenient_latex_complex_valid() {
let output = mathlex::parse_latex_lenient(r"\int_0^1 x^2 dx");
assert!(output.is_ok());
}
#[test]
fn test_lenient_latex_empty_frac_denominator() {
let output = mathlex::parse_latex_lenient(r"\frac{1}{}");
assert!(output.has_errors());
}
#[test]
fn test_lenient_latex_partial_ast_with_errors() {
let output = mathlex::parse_latex_lenient(r"x + \frac{}{} + y");
assert!(output.has_errors());
}
#[test]
fn test_lenient_latex_empty_input() {
let output = mathlex::parse_latex_lenient("");
assert!(output.expression.is_none() || output.has_errors());
}
#[test]
fn test_lenient_latex_unmatched_brace() {
let output = mathlex::parse_latex_lenient(r"\frac{1}{2");
assert!(output.has_errors());
}
#[test]
fn test_lenient_latex_multiple_errors() {
let output = mathlex::parse_latex_lenient(r"\frac{}{} + \frac{}{}");
assert!(output.has_errors());
assert!(!output.errors.is_empty());
}
#[test]
fn test_lenient_latex_recovers_after_bad_command() {
let output = mathlex::parse_latex_lenient(r"\badcommand + x");
assert!(output.has_errors());
}
#[test]
fn test_lenient_with_config_implicit_mult() {
let config = mathlex::ParserConfig {
implicit_multiplication: true,
..Default::default()
};
let output = mathlex::parse_lenient_with_config("2x + 3", &config);
assert!(output.is_ok());
}
#[test]
fn test_lenient_with_config_no_implicit_mult() {
let config = mathlex::ParserConfig {
implicit_multiplication: false,
..Default::default()
};
let output = mathlex::parse_lenient_with_config("2x", &config);
assert!(output.expression.is_some() || output.has_errors());
}
#[test]
fn test_lenient_errors_have_spans() {
let output = mathlex::parse_lenient("2 + + 3");
for err in &output.errors {
assert!(err.span.is_some(), "Error missing span: {}", err);
}
}
#[test]
fn test_lenient_latex_errors_have_spans() {
let output = mathlex::parse_latex_lenient(r"\frac{1}{}");
for err in &output.errors {
assert!(err.span.is_some(), "Error missing span: {}", err);
}
}