showcase_calculator/
lib.rs1#![cfg_attr(
34 test,
35 allow(
36 clippy::unwrap_used,
37 clippy::expect_used,
38 clippy::panic,
39 clippy::float_cmp
40 )
41)]
42#![allow(clippy::disallowed_methods)]
44#![deny(missing_docs)]
45#![deny(missing_debug_implementations)]
46
47pub mod core;
48pub mod driver;
49
50#[cfg(feature = "tui")]
51pub mod tui;
52
53pub mod wasm;
56
57pub mod prelude {
70 pub use crate::core::evaluator::Evaluator;
71 pub use crate::core::history::{History, HistoryEntry};
72 pub use crate::core::parser::{AstNode, Parser, Token, Tokenizer};
73 pub use crate::core::{
74 AnomalyValidator, AnomalyViolation, CalcError, CalcResult, Calculator, Operation,
75 };
76 pub use crate::driver::{CalculatorDriver, HistoryItem};
77
78 #[cfg(feature = "tui")]
79 pub use crate::driver::TuiDriver;
80
81 pub use crate::wasm::{DomElement, DomEvent, MockDom, WasmCalculator, WasmDriver};
82}
83
84#[cfg(test)]
85mod tests {
86 use super::prelude::*;
87
88 #[test]
89 fn test_prelude_imports() {
90 let mut eval = Evaluator::new();
92 let result = eval.evaluate_str("2 + 3").unwrap();
93 assert_eq!(result, 5.0);
94 }
95
96 #[test]
97 fn test_calculator_direct() {
98 let mut calc = Calculator::new();
99 let result = calc.calculate(6.0, 7.0, Operation::Multiply).unwrap();
100 assert_eq!(result, 42.0);
101 }
102
103 #[test]
104 fn test_parser_direct() {
105 let ast = Parser::parse_str("1 + 2 * 3").unwrap();
106 let mut eval = Evaluator::new();
107 assert_eq!(eval.evaluate(&ast).unwrap(), 7.0);
108 }
109
110 #[test]
111 fn test_history_tracking() {
112 let mut history = History::new();
113 history.record("10 / 2", 5.0);
114 assert_eq!(history.len(), 1);
115 assert_eq!(history.last().unwrap().display(), "10 / 2 = 5");
116 }
117
118 #[test]
119 fn test_jidoka_validation() {
120 let validator = AnomalyValidator::with_max_magnitude(50.0);
121 let mut eval = Evaluator::with_validator(validator);
122
123 assert!(eval.evaluate_str("5 * 5").is_ok());
125
126 assert!(matches!(
128 eval.evaluate_str("10 * 10"),
129 Err(CalcError::AnomalyViolation(_))
130 ));
131 }
132
133 #[test]
134 fn test_error_handling() {
135 let mut eval = Evaluator::new();
136
137 assert!(matches!(
139 eval.evaluate_str("1 / 0"),
140 Err(CalcError::DivisionByZero)
141 ));
142
143 assert!(matches!(
145 eval.evaluate_str(""),
146 Err(CalcError::EmptyExpression)
147 ));
148
149 assert!(matches!(
151 eval.evaluate_str("1 + + 2"),
152 Err(CalcError::ParseError(_))
153 ));
154 }
155
156 #[test]
157 fn test_all_operations() {
158 let mut eval = Evaluator::new();
159
160 assert_eq!(eval.evaluate_str("10 + 5").unwrap(), 15.0);
161 assert_eq!(eval.evaluate_str("10 - 3").unwrap(), 7.0);
162 assert_eq!(eval.evaluate_str("6 * 7").unwrap(), 42.0);
163 assert_eq!(eval.evaluate_str("20 / 4").unwrap(), 5.0);
164 assert_eq!(eval.evaluate_str("17 % 5").unwrap(), 2.0);
165 assert_eq!(eval.evaluate_str("2 ^ 10").unwrap(), 1024.0);
166 }
167
168 #[test]
169 fn test_complex_expressions() {
170 let mut eval = Evaluator::new();
171
172 assert_eq!(eval.evaluate_str("2 + 3 * 4").unwrap(), 14.0);
174
175 assert_eq!(eval.evaluate_str("(2 + 3) * 4").unwrap(), 20.0);
177
178 assert_eq!(eval.evaluate_str("2 ^ 3 ^ 2").unwrap(), 512.0);
180
181 assert_eq!(eval.evaluate_str("42 * (3 + 7)").unwrap(), 420.0);
183
184 assert_eq!(eval.evaluate_str("-5 + 10").unwrap(), 5.0);
186 }
187}