Coverage Report

Created: 2026-05-25 08:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/runner/work/MathCAT/MathCAT/src/lib.rs
Line
Count
Source
1
#![cfg_attr(coverage, feature(coverage_attribute))]
2
#![allow(clippy::needless_return)]
3
4
//! A library for generating speech and braille from MathML
5
//! 
6
//! Typical usage is:
7
//! 1. Set the rules directory [`set_rules_dir`]
8
//! 2. Set whatever preferences are need with repeated calls to [`set_preference`].
9
//! 3. Set MathML via [`set_mathml`]
10
//!    A string representing the cleaned up MathML along with `id`s on each node is returned for highlighting if desired
11
//! 4. Get the speech [`get_spoken_text`] or (Unicode) braille [`get_braille`].
12
//!
13
//! The expression can be navigated also.
14
//! This is done in one of two ways:
15
//! 1. Pass key strokes to allow a user to navigate the MathML by calling [`do_navigate_keypress`]; the speech is returned.
16
//! 2. Pass the MathCAT navigation command directory by called [`do_navigate_command`]; the speech is return returned.
17
//! 
18
//! To get the MathML associated with the current navigation node, call [`get_navigation_mathml`].
19
//! To just get the `id` and offset from the id of the current navigation node, call [`get_navigation_mathml_id`].
20
///
21
/// This module re-exports anyhow types. Use `bail!` for early returns and
22
/// `context()`/`with_context()` on Result to add context (replacing old `chain_err()`).
23
pub mod errors {
24
    pub use anyhow::{anyhow, bail, Error, Result, Context};
25
}
26
27
pub mod interface;
28
#[cfg(feature = "include-zip")]
29
pub use shim_filesystem::ZIPPED_RULE_FILES;
30
31
mod canonicalize;
32
mod infer_intent;
33
pub mod speech;
34
mod braille;
35
mod navigate;
36
mod prefs;
37
mod tts;
38
mod xpath_functions;
39
mod definitions;
40
pub mod pretty_print;
41
mod chemistry;
42
43
pub mod shim_filesystem; // really just for override_file_for_debugging_rules, but the config seems to throw it off
44
pub use interface::*;
45
use crate::errors::{bail, Result};
46
47
#[cfg(test)]
48
0
pub fn init_logger() {
49
0
    env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug"))
50
0
        .is_test(true)
51
0
        .format_timestamp(None)
52
0
        .format_module_path(false)
53
0
        .format_indent(None)
54
0
        .format_level(false)
55
0
        .init();
56
0
}
57
58
/// Build Absolute path to rules dir for testing
59
251
pub fn abs_rules_dir_path() -> String {
60
    cfg_if::cfg_if! {
61
    if #[cfg(feature = "include-zip")] {
62
          return "Rules".to_string();
63
    } else {
64
        // Package root (see tests/common/mod.rs `abs_rules_dir_path` for rationale).
65
251
        return std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
66
251
            .join("Rules")
67
251
            .to_str()
68
251
            .expect("CARGO_MANIFEST_DIR and Rules path must be UTF-8")
69
251
            .to_string();
70
        }
71
    }
72
251
}
73
74
141
pub fn are_strs_canonically_equal_with_locale(test: &str, target: &str, ignore_attrs: &[&str], block_separators: &str, decimal_separators: &str) -> Result<()> {
75
    use crate::{interface::*, pretty_print::mml_to_string};
76
    use sxd_document::parser;
77
    use crate::canonicalize::canonicalize;
78
    use std::panic::{catch_unwind, AssertUnwindSafe};
79
80
141
    crate::interface::init_panic_handler();
81
141
    let result = catch_unwind(AssertUnwindSafe(|| {
82
        // this forces initialization
83
141
        crate::interface::set_rules_dir(abs_rules_dir_path()).unwrap();
84
141
        set_preference("Language", "en").unwrap();
85
141
        set_preference("BlockSeparators", block_separators).unwrap();
86
141
        set_preference("DecimalSeparators", decimal_separators).unwrap();
87
141
        crate::speech::SPEECH_RULES.with(|rules|  rules.borrow_mut().read_files().unwrap());
88
89
141
        let package1 = &parser::parse(test).expect("Failed to parse test input");
90
141
        let mathml = get_element(package1);
91
141
        trim_element(mathml, false);
92
141
        let mathml_test = canonicalize(mathml).unwrap();
93
94
141
        let package2 = &parser::parse(target).expect("Failed to parse target input");
95
141
        let mathml_target = get_element(package2);
96
141
        trim_element(mathml_target, false);
97
98
141
        match is_same_element(mathml_test, mathml_target, ignore_attrs) {
99
141
            Ok(_) => Ok( () ),
100
0
            Err(e) => {
101
0
                bail!("{}\nResult:\n{}\nTarget:\n{}", e, mml_to_string(mathml_test), mml_to_string(mathml_target));
102
            },
103
        }
104
141
    }));
105
141
    match crate::interface::report_any_panic(result) {
106
140
        Ok(()) => Ok(()),
107
1
        Err(e) => {
108
1
            eprintln!("{}", e);
109
1
            Err(e)
110
        }
111
    }
112
141
}
113
114
/// sets locale to be US standard
115
30
pub fn are_strs_canonically_equal(test: &str, target: &str, ignore_attrs: &[&str]) -> bool {
116
30
    are_strs_canonically_equal_with_locale(test, target, ignore_attrs, ", \u{00A0}\u{202F}", ".").is_ok()
117
30
}
118
119
/// Like `are_strs_canonically_equal` but returns `Result` for use in `#[test]` functions that return `Result<()>`.
120
102
pub fn are_strs_canonically_equal_result(test: &str, target: &str, ignore_attrs: &[&str]) -> Result<()> {
121
102
    are_strs_canonically_equal_with_locale(test, target, ignore_attrs, ", \u{00A0}\u{202F}", ".")
122
102
}