//! Tests for the formula renderer.
//!
//! They live here rather than inside the module so that `src/` holds no test
//! code, as it does in `apsis-rs`. An integration test is a separate crate and
//! reaches only what the library makes public, so the few internal items the
//! tests need are opened through `apsis_book::testkit`.
use apsis_book::docs::mathml::*;
use apsis_book::testkit::mathml;
#[test]
fn a_variable_is_an_identifier() {
assert_eq!(mathml("x"), "x");
}
#[test]
fn a_power_becomes_a_superscript() {
assert_eq!(
mathml("x^2"),
"x2"
);
}
#[test]
fn a_group_holds_several_tokens() {
assert_eq!(
mathml("x^{12}"),
"x12"
);
}
#[test]
fn a_fraction_has_a_numerator_and_a_denominator() {
assert_eq!(
mathml("\\frac{a}{b}"),
"ab"
);
}
#[test]
fn a_greek_letter_is_translated() {
assert_eq!(mathml("\\theta"), "θ");
}
#[test]
fn an_unknown_command_is_kept_as_written() {
// Losing part of a formula would be worse than showing it plainly.
assert_eq!(mathml("\\notacommand"), "\\notacommand");
}
#[test]
fn a_comma_is_kept() {
// The command is the spacing one, so dropping it would run a list of
// symbols together. It is written as an operator so that it keeps its
// space, which is what a comma is for.
assert_eq!(
mathml("\\alpha, \\beta"),
"α, β"
);
}
#[test]
fn a_root_can_have_an_index() {
let html = mathml("\\sqrt[3]{x}");
assert!(html.contains(""), "the index was lost: {html}");
}
#[test]
fn text_is_escaped() {
assert!(mathml("a"), "no root here");
}
#[test]
fn a_subscript_within_a_subscript_is_read() {
// `delta_v_1` is delta with a subscript v, itself carrying 1.
let html = render_plain("delta_v_1 = 3").expect("a formula");
assert!(html.contains("delta"), "{html}");
assert!(html.contains(""), "the subscript was lost: {html}");
}
#[test]
fn a_power_is_read() {
let html = render_plain("e^2 = 2 f - f^2").expect("a formula");
assert!(html.contains(""), "the power was lost: {html}");
}
#[test]
fn a_root_is_read() {
let html = render_plain("x = sqrt( mu / r )").expect("a formula");
assert!(html.contains(""), "the root was lost: {html}");
}
#[test]
fn a_quotient_is_taken_as_its_own() {
// `2/r_1 - 1/a_t` is two quotients, not one quotient of a difference.
let html = render_plain("d = 2/r_1 - 1/a_t").expect("a formula");
assert_eq!(html.matches("").count(), 3, "{html}");
}
#[test]
fn a_matrix_stays_as_written() {
// A matrix is not a formula this renderer lays out.
assert!(render_plain("R = [ 1 0\n 0 1 ]").is_none());
}
#[test]
fn prose_stays_as_written() {
assert!(render_plain("e_max such that the elevation is arctan").is_none());
assert!(render_plain("just some text").is_none());
}
#[test]
fn a_trailing_note_is_not_part_of_the_equation() {
// The parenthesis is a phrase, not a bracket in the expression.
let html = render_plain("N = a / sqrt(1 - e^2 sin^2 phi) (prime vertical radius)")
.expect("a formula");
// The note is set beside the formula rather than inside it, and it is
// kept rather than dropped.
assert!(
html.contains("prime vertical radius"),
"the note was lost: {html}"
);
assert!(
html.contains(""), "{html}");
}
#[test]
fn a_brace_holds_a_subscript_of_several_symbols() {
// The Newton iteration, written the way the documents write it.
let html = render_plain("E_{n+1} = E_n - f(E_n)").expect("a formula");
assert!(html.contains(""), "the subscript was lost: {html}");
}
#[test]
fn a_continuation_line_is_kept_though_it_is_not_an_equation() {
// A block of equations often carries a line with no equals sign on it.
// Losing that line would lose the equation above it.
let html = render_plain("JDN = day + 365 y\n + 153 m").expect("a formula");
assert!(html.contains("JDN"), "{html}");
assert!(html.contains("153 m"), "the continuation was lost: {html}");
}
#[test]
fn a_block_with_no_readable_equation_is_left_alone() {
assert!(render_plain("leap(y) = (y mod 4 == 0) and (y mod 100 != 0").is_none());
}
#[test]
fn an_absolute_value_may_hold_a_product() {
// `| f'(x) | * | x| / | f(x) |` is one expression: a bar inside it
// opens the next factor rather than closing the one before.
let html = render_plain("kappa = | f'(x) | * | x| / | f(x) |").expect("a formula");
assert!(!html.contains("\u{2212}"),
"the minus was lost: {html}"
);
assert!(html.contains("="), "the equals was lost: {html}");
}
#[test]
fn an_equals_between_two_equations_is_kept() {
let html = render_plain("r = p / (1 + e cos nu), p = a (1 - e^2)").expect("a formula");
assert!(html.contains("="), "{html}");
assert!(html.contains("\u{2212}"), "{html}");
}