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
57#[cfg(test)]
61mod probar_tests;
62
63pub mod prelude {
65 pub use crate::core::evaluator::Evaluator;
66 pub use crate::core::history::{History, HistoryEntry};
67 pub use crate::core::parser::{AstNode, Parser, Token, Tokenizer};
68 pub use crate::core::{
69 AnomalyValidator, AnomalyViolation, CalcError, CalcResult, Calculator, Operation,
70 };
71 pub use crate::driver::{CalculatorDriver, HistoryItem};
72
73 #[cfg(feature = "tui")]
74 pub use crate::driver::TuiDriver;
75
76 pub use crate::wasm::{DomElement, DomEvent, MockDom, WasmCalculator, WasmDriver};
77}
78
79#[cfg(test)]
80mod tests {
81 use super::prelude::*;
82
83 #[test]
84 fn test_prelude_imports() {
85 let mut eval = Evaluator::new();
87 let result = eval.evaluate_str("2 + 3").unwrap();
88 assert_eq!(result, 5.0);
89 }
90
91 #[test]
92 fn test_calculator_direct() {
93 let mut calc = Calculator::new();
94 let result = calc.calculate(6.0, 7.0, Operation::Multiply).unwrap();
95 assert_eq!(result, 42.0);
96 }
97
98 #[test]
99 fn test_parser_direct() {
100 let ast = Parser::parse_str("1 + 2 * 3").unwrap();
101 let mut eval = Evaluator::new();
102 assert_eq!(eval.evaluate(&ast).unwrap(), 7.0);
103 }
104
105 #[test]
106 fn test_history_tracking() {
107 let mut history = History::new();
108 history.record("10 / 2", 5.0);
109 assert_eq!(history.len(), 1);
110 assert_eq!(history.last().unwrap().display(), "10 / 2 = 5");
111 }
112
113 #[test]
114 fn test_jidoka_validation() {
115 let validator = AnomalyValidator::with_max_magnitude(50.0);
116 let mut eval = Evaluator::with_validator(validator);
117
118 assert!(eval.evaluate_str("5 * 5").is_ok());
120
121 assert!(matches!(
123 eval.evaluate_str("10 * 10"),
124 Err(CalcError::AnomalyViolation(_))
125 ));
126 }
127
128 #[test]
129 fn test_error_handling() {
130 let mut eval = Evaluator::new();
131
132 assert!(matches!(
134 eval.evaluate_str("1 / 0"),
135 Err(CalcError::DivisionByZero)
136 ));
137
138 assert!(matches!(
140 eval.evaluate_str(""),
141 Err(CalcError::EmptyExpression)
142 ));
143
144 assert!(matches!(
146 eval.evaluate_str("1 + + 2"),
147 Err(CalcError::ParseError(_))
148 ));
149 }
150
151 #[test]
152 fn test_all_operations() {
153 let mut eval = Evaluator::new();
154
155 assert_eq!(eval.evaluate_str("10 + 5").unwrap(), 15.0);
156 assert_eq!(eval.evaluate_str("10 - 3").unwrap(), 7.0);
157 assert_eq!(eval.evaluate_str("6 * 7").unwrap(), 42.0);
158 assert_eq!(eval.evaluate_str("20 / 4").unwrap(), 5.0);
159 assert_eq!(eval.evaluate_str("17 % 5").unwrap(), 2.0);
160 assert_eq!(eval.evaluate_str("2 ^ 10").unwrap(), 1024.0);
161 }
162
163 #[test]
164 fn test_complex_expressions() {
165 let mut eval = Evaluator::new();
166
167 assert_eq!(eval.evaluate_str("2 + 3 * 4").unwrap(), 14.0);
169
170 assert_eq!(eval.evaluate_str("(2 + 3) * 4").unwrap(), 20.0);
172
173 assert_eq!(eval.evaluate_str("2 ^ 3 ^ 2").unwrap(), 512.0);
175
176 assert_eq!(eval.evaluate_str("42 * (3 + 7)").unwrap(), 420.0);
178
179 assert_eq!(eval.evaluate_str("-5 + 10").unwrap(), 5.0);
181 }
182}