use pulldown_latex::{push_mathml, Parser, Storage};
macro_rules! should_error {
($name:ident, $($input:literal),+ $(,)?) => {
#[test]
pub fn $name() {
let inputs = &[$($input),*];
let mut storage = pulldown_latex::Storage::new();
for input in inputs {
let parser = pulldown_latex::parser::Parser::new(input, &storage);
let result = parser.collect::<Result<Vec<_>, _>>();
assert!(result.is_err(), "expected error for input: {}", input);
storage.reset();
}
}
};
}
#[test]
fn error_rendering() {
let storage = pulldown_latex::Storage::new();
let mut out = String::new();
let parser = pulldown_latex::parser::Parser::new(r"\errors \should \render", &storage);
push_mathml(&mut out, parser, Default::default()).unwrap();
}
#[test]
fn error_rendering_unclosed_environment() {
let storage = pulldown_latex::Storage::new();
let mut out = String::new();
let parser = pulldown_latex::parser::Parser::new("\\symit\\\0D", &storage);
push_mathml(&mut out, parser, Default::default()).unwrap();
}
should_error! {
double_scripts,
r"a^b^c",
r"a_b_c",
r"a^b_c^d",
r"a_b^c_d",
r"a^b_c_d",
r"a_b^c_d^e",
}
should_error! {
invalid_escape_sequence,
"5\\\u{6eb}%"
}
#[test]
fn comments() {
let s = r#"{%"#;
let storage = Storage::new();
let parser = Parser::new(s, &storage);
let mut mathml = String::new();
let config = Default::default();
push_mathml(&mut mathml, parser, config).unwrap();
}
should_error! {
space_missing_groups,
r"\Space 1em{2ex}{0pt}",
r"\Space{1em} 2ex{0pt}",
r"\Space{1em}{2ex} 0pt",
}
should_error! {
braced_dimension_trailing_garbage,
r"\kern{1em foo}",
r"\hskip{1em garbage}",
}
should_error! {
mkern_mskip_non_mu_units,
r"\mkern{1em}",
r"\mskip{1em plus 1em}",
}
#[test]
fn macro_param_overflow() {
let storage = Storage::new();
let parser = Parser::new("\\def\\]#\x1d{}", &storage);
for _ in parser {}
}
#[test]
fn newline_in_unexpected_env() {
let storage = Storage::new();
let parser = Parser::new(
"\\begin{matrix} \\\x1d\\\\\\frac}1\\\\]\\\\\\\\\\]\\end{matrix}",
&storage,
);
let mut out = String::new();
push_mathml(&mut out, parser, Default::default()).unwrap();
}
#[test]
fn error_context_char_boundary() {
let storage = Storage::new();
let parser = Parser::new(
"\\newcommand{\\foo}[1]{#1}\\foo{x}\\foo}[1]{#1}\\foo{x}^]_\u{8df7}:",
&storage,
);
for _ in parser {}
}
#[test]
fn macro_recursion_limit() {
let storage = Storage::new();
let parser = Parser::new(
"~zU\\newcommand{\\foo}[2]{#1]\\foo{x}\0#1}\\foo{}}",
&storage,
);
let mut out = String::new();
push_mathml(&mut out, parser, Default::default()).unwrap();
}
#[test]
fn suffix_bounds_check() {
let storage = Storage::new();
let parser = Parser::new("\0\\def\\]a#1 {}f\\]ar3c%\\", &storage);
for _ in parser {}
}
#[test]
fn escapes_html_special_chars() {
for (input, expected) in [
(r"\text{a < b > c & d}", "a < b > c & d"),
(r"\text{<>&}", "<>&"),
(r"\text{<<&&>>}", "<<&&>>"),
(r"\text{plain}", "plain"),
] {
let storage = Storage::new();
let parser = Parser::new(input, &storage);
let mut out = String::new();
push_mathml(&mut out, parser, Default::default()).unwrap();
assert!(
out.contains(expected),
"expected {expected:?} in output for {input:?}, got {out}"
);
}
}