/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 | } |