aprender_test_showcase/core/
evaluator.rs1use crate::core::parser::AstNode;
6use crate::core::{AnomalyValidator, CalcResult, Calculator, Operation};
7
8#[derive(Debug)]
10pub struct Evaluator {
11 calculator: Calculator,
12}
13
14impl Default for Evaluator {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20impl Evaluator {
21 #[must_use]
23 pub fn new() -> Self {
24 Self {
25 calculator: Calculator::new(),
26 }
27 }
28
29 #[must_use]
31 pub fn with_validator(validator: AnomalyValidator) -> Self {
32 Self {
33 calculator: Calculator::with_validator(validator),
34 }
35 }
36
37 pub fn evaluate(&mut self, node: &AstNode) -> CalcResult<f64> {
39 match node {
40 AstNode::Number(n) => Ok(*n),
41 AstNode::Negate(inner) => {
42 let value = self.evaluate(inner)?;
43 self.calculator.calculate(value, -1.0, Operation::Multiply)
45 }
46 AstNode::BinaryOp { left, op, right } => {
47 let left_val = self.evaluate(left)?;
48 let right_val = self.evaluate(right)?;
49 self.calculator.calculate(left_val, right_val, *op)
50 }
51 }
52 }
53
54 pub fn evaluate_str(&mut self, input: &str) -> CalcResult<f64> {
56 use crate::core::parser::Parser;
57 let ast = Parser::parse_str(input)?;
58 self.evaluate(&ast)
59 }
60
61 #[must_use]
63 pub fn history(&self) -> &std::collections::VecDeque<f64> {
64 self.calculator.validator.history()
65 }
66
67 pub fn clear_history(&mut self) {
69 self.calculator.validator.clear_history();
70 }
71
72 #[must_use]
74 pub fn validator(&self) -> Option<&AnomalyValidator> {
75 Some(&self.calculator.validator)
76 }
77}
78
79#[cfg(test)]
80#[allow(clippy::unwrap_used)]
81mod tests {
82 use super::*;
83 use crate::core::CalcError;
84
85 #[test]
88 fn test_evaluate_number() {
89 let mut eval = Evaluator::new();
90 let ast = AstNode::number(42.0);
91 assert_eq!(eval.evaluate(&ast), Ok(42.0));
92 }
93
94 #[test]
95 fn test_evaluate_negative_number() {
96 let mut eval = Evaluator::new();
97 let ast = AstNode::negate(AstNode::number(5.0));
98 assert_eq!(eval.evaluate(&ast), Ok(-5.0));
99 }
100
101 #[test]
102 fn test_evaluate_double_negative() {
103 let mut eval = Evaluator::new();
104 let ast = AstNode::negate(AstNode::negate(AstNode::number(5.0)));
105 assert_eq!(eval.evaluate(&ast), Ok(5.0));
106 }
107
108 #[test]
109 fn test_evaluate_addition() {
110 let mut eval = Evaluator::new();
111 let ast = AstNode::binary(AstNode::number(2.0), Operation::Add, AstNode::number(3.0));
112 assert_eq!(eval.evaluate(&ast), Ok(5.0));
113 }
114
115 #[test]
116 fn test_evaluate_subtraction() {
117 let mut eval = Evaluator::new();
118 let ast = AstNode::binary(
119 AstNode::number(5.0),
120 Operation::Subtract,
121 AstNode::number(3.0),
122 );
123 assert_eq!(eval.evaluate(&ast), Ok(2.0));
124 }
125
126 #[test]
127 fn test_evaluate_multiplication() {
128 let mut eval = Evaluator::new();
129 let ast = AstNode::binary(
130 AstNode::number(4.0),
131 Operation::Multiply,
132 AstNode::number(3.0),
133 );
134 assert_eq!(eval.evaluate(&ast), Ok(12.0));
135 }
136
137 #[test]
138 fn test_evaluate_division() {
139 let mut eval = Evaluator::new();
140 let ast = AstNode::binary(
141 AstNode::number(12.0),
142 Operation::Divide,
143 AstNode::number(4.0),
144 );
145 assert_eq!(eval.evaluate(&ast), Ok(3.0));
146 }
147
148 #[test]
149 fn test_evaluate_modulo() {
150 let mut eval = Evaluator::new();
151 let ast = AstNode::binary(
152 AstNode::number(7.0),
153 Operation::Modulo,
154 AstNode::number(3.0),
155 );
156 assert_eq!(eval.evaluate(&ast), Ok(1.0));
157 }
158
159 #[test]
160 fn test_evaluate_power() {
161 let mut eval = Evaluator::new();
162 let ast = AstNode::binary(AstNode::number(2.0), Operation::Power, AstNode::number(3.0));
163 assert_eq!(eval.evaluate(&ast), Ok(8.0));
164 }
165
166 #[test]
169 fn test_evaluate_nested_expression() {
170 let mut eval = Evaluator::new();
171 let ast = AstNode::binary(
173 AstNode::binary(AstNode::number(2.0), Operation::Add, AstNode::number(3.0)),
174 Operation::Multiply,
175 AstNode::number(4.0),
176 );
177 assert_eq!(eval.evaluate(&ast), Ok(20.0));
178 }
179
180 #[test]
181 fn test_evaluate_deeply_nested() {
182 let mut eval = Evaluator::new();
183 let ast = AstNode::binary(
185 AstNode::binary(AstNode::number(1.0), Operation::Add, AstNode::number(2.0)),
186 Operation::Multiply,
187 AstNode::binary(AstNode::number(3.0), Operation::Add, AstNode::number(4.0)),
188 );
189 assert_eq!(eval.evaluate(&ast), Ok(21.0));
190 }
191
192 #[test]
193 fn test_evaluate_with_negative_in_expression() {
194 let mut eval = Evaluator::new();
195 let ast = AstNode::binary(
197 AstNode::number(5.0),
198 Operation::Add,
199 AstNode::negate(AstNode::number(3.0)),
200 );
201 assert_eq!(eval.evaluate(&ast), Ok(2.0));
202 }
203
204 #[test]
207 fn test_evaluate_division_by_zero() {
208 let mut eval = Evaluator::new();
209 let ast = AstNode::binary(
210 AstNode::number(10.0),
211 Operation::Divide,
212 AstNode::number(0.0),
213 );
214 assert_eq!(eval.evaluate(&ast), Err(CalcError::DivisionByZero));
215 }
216
217 #[test]
218 fn test_evaluate_modulo_by_zero() {
219 let mut eval = Evaluator::new();
220 let ast = AstNode::binary(
221 AstNode::number(10.0),
222 Operation::Modulo,
223 AstNode::number(0.0),
224 );
225 assert_eq!(eval.evaluate(&ast), Err(CalcError::DivisionByZero));
226 }
227
228 #[test]
229 fn test_evaluate_error_propagates_from_left() {
230 let mut eval = Evaluator::new();
231 let ast = AstNode::binary(
233 AstNode::binary(
234 AstNode::number(10.0),
235 Operation::Divide,
236 AstNode::number(0.0),
237 ),
238 Operation::Add,
239 AstNode::number(5.0),
240 );
241 assert!(matches!(
242 eval.evaluate(&ast),
243 Err(CalcError::DivisionByZero)
244 ));
245 }
246
247 #[test]
248 fn test_evaluate_error_propagates_from_right() {
249 let mut eval = Evaluator::new();
250 let ast = AstNode::binary(
252 AstNode::number(5.0),
253 Operation::Add,
254 AstNode::binary(
255 AstNode::number(10.0),
256 Operation::Divide,
257 AstNode::number(0.0),
258 ),
259 );
260 assert!(matches!(
261 eval.evaluate(&ast),
262 Err(CalcError::DivisionByZero)
263 ));
264 }
265
266 #[test]
269 fn test_evaluate_str_simple() {
270 let mut eval = Evaluator::new();
271 assert_eq!(eval.evaluate_str("2 + 3"), Ok(5.0));
272 }
273
274 #[test]
275 fn test_evaluate_str_complex() {
276 let mut eval = Evaluator::new();
277 assert_eq!(eval.evaluate_str("42 * (3 + 7)"), Ok(420.0));
278 }
279
280 #[test]
281 fn test_evaluate_str_power() {
282 let mut eval = Evaluator::new();
283 assert_eq!(eval.evaluate_str("2 ^ 3 ^ 2"), Ok(512.0)); }
285
286 #[test]
287 fn test_evaluate_str_precedence() {
288 let mut eval = Evaluator::new();
289 assert_eq!(eval.evaluate_str("2 + 3 * 4"), Ok(14.0)); }
291
292 #[test]
293 fn test_evaluate_str_unary_minus() {
294 let mut eval = Evaluator::new();
295 assert_eq!(eval.evaluate_str("-5"), Ok(-5.0));
296 }
297
298 #[test]
299 fn test_evaluate_str_empty() {
300 let mut eval = Evaluator::new();
301 assert!(matches!(
302 eval.evaluate_str(""),
303 Err(CalcError::EmptyExpression)
304 ));
305 }
306
307 #[test]
308 fn test_evaluate_str_invalid() {
309 let mut eval = Evaluator::new();
310 assert!(matches!(
311 eval.evaluate_str("2 +"),
312 Err(CalcError::ParseError(_))
313 ));
314 }
315
316 #[test]
319 fn test_evaluate_with_jidoka_overflow() {
320 let validator = AnomalyValidator::with_max_magnitude(100.0);
321 let mut eval = Evaluator::with_validator(validator);
322 let result = eval.evaluate_str("50 * 3"); assert!(matches!(result, Err(CalcError::AnomalyViolation(_))));
324 }
325
326 #[test]
327 fn test_evaluator_history() {
328 let mut eval = Evaluator::new();
329 eval.evaluate_str("1 + 1").unwrap();
331 eval.evaluate_str("2 + 2").unwrap();
332 eval.evaluate_str("3 + 3").unwrap();
333 assert_eq!(eval.history().len(), 3);
334 }
335
336 #[test]
337 fn test_evaluator_clear_history() {
338 let mut eval = Evaluator::new();
339 eval.evaluate_str("1").unwrap();
340 eval.evaluate_str("2").unwrap();
341 eval.clear_history();
342 assert!(eval.history().is_empty());
343 }
344
345 #[test]
348 fn test_evaluator_new() {
349 let eval = Evaluator::new();
350 assert!(eval.history().is_empty());
351 }
352
353 #[test]
354 fn test_evaluator_default() {
355 let eval = Evaluator::default();
356 assert!(eval.history().is_empty());
357 }
358
359 #[test]
360 fn test_evaluator_with_validator() {
361 let validator = AnomalyValidator::with_max_magnitude(50.0);
362 let mut eval = Evaluator::with_validator(validator);
363 let result = eval.evaluate_str("10 * 10");
365 assert!(matches!(result, Err(CalcError::AnomalyViolation(_))));
366 }
367
368 #[test]
371 fn test_evaluate_all_operations() {
372 let mut eval = Evaluator::new();
373
374 assert_eq!(eval.evaluate_str("10 + 5"), Ok(15.0));
376
377 assert_eq!(eval.evaluate_str("10 - 3"), Ok(7.0));
379
380 assert_eq!(eval.evaluate_str("6 * 7"), Ok(42.0));
382
383 assert_eq!(eval.evaluate_str("20 / 4"), Ok(5.0));
385
386 assert_eq!(eval.evaluate_str("17 % 5"), Ok(2.0));
388
389 assert_eq!(eval.evaluate_str("3 ^ 4"), Ok(81.0));
391 }
392
393 #[test]
394 fn test_evaluate_complex_real_world() {
395 let mut eval = Evaluator::new();
396
397 assert_eq!(eval.evaluate_str("5 ^ 2 - 4 * 1 * 6"), Ok(1.0));
400 }
401}