Skip to main content

aprender_test_showcase/
lib.rs

1//! Showcase Calculator - 100% Test Coverage Demo
2//!
3//! This crate demonstrates achieving 100% test coverage across both
4//! TUI and WASM platforms using Probar's unified testing framework.
5//!
6//! # Probar Testing Principles
7//!
8//! - **Error prevention**: Type-safe operations prevent invalid states at compile time
9//! - **Anomaly**: Automatic anomaly detection during calculations
10//! - **Balanced testing**: Balanced test distribution across components
11//! - **Visual feedback**: History tracking for visibility into operations
12//! - **Kaizen**: Mutation testing for continuous improvement
13//!
14//! # Example
15//!
16//! ```rust
17//! use showcase_calculator::prelude::*;
18//!
19//! // Create an evaluator
20//! let mut eval = Evaluator::new();
21//!
22//! // Evaluate expressions
23//! let result = eval.evaluate_str("42 * (3 + 7)").unwrap();
24//! assert_eq!(result, 420.0);
25//!
26//! // With Anomaly validation
27//! let validator = AnomalyValidator::with_max_magnitude(100.0);
28//! let mut safe_eval = Evaluator::with_validator(validator);
29//! assert!(safe_eval.evaluate_str("50 * 3").is_err()); // Exceeds max
30//! ```
31
32// Allow common test patterns in this showcase crate
33#![cfg_attr(
34    test,
35    allow(
36        clippy::unwrap_used,
37        clippy::expect_used,
38        clippy::panic,
39        clippy::float_cmp
40    )
41)]
42#![deny(missing_docs)]
43#![deny(missing_debug_implementations)]
44
45pub mod core;
46pub mod driver;
47
48#[cfg(feature = "tui")]
49pub mod tui;
50
51/// WASM module - always available for testing
52/// (Mock DOM allows testing without actual browser bindings)
53pub mod wasm;
54
55/// Probar Advanced Testing Module
56/// Demonstrates all Probar features: Page Objects, Accessibility,
57/// Visual Regression, Device Emulation, Fixtures, Replay, UX Coverage
58#[cfg(test)]
59mod probar_tests;
60
61/// Prelude for convenient imports
62pub mod prelude {
63    pub use crate::core::evaluator::Evaluator;
64    pub use crate::core::history::{History, HistoryEntry};
65    pub use crate::core::parser::{AstNode, Parser, Token, Tokenizer};
66    pub use crate::core::{
67        AnomalyValidator, AnomalyViolation, CalcError, CalcResult, Calculator, Operation,
68    };
69    pub use crate::driver::{CalculatorDriver, HistoryItem};
70
71    #[cfg(feature = "tui")]
72    pub use crate::driver::TuiDriver;
73
74    pub use crate::wasm::{DomElement, DomEvent, MockDom, WasmCalculator, WasmDriver};
75}
76
77#[cfg(test)]
78mod tests {
79    use super::prelude::*;
80
81    #[test]
82    fn test_prelude_imports() {
83        // Verify all prelude exports work
84        let mut eval = Evaluator::new();
85        let result = eval.evaluate_str("2 + 3").unwrap();
86        assert_eq!(result, 5.0);
87    }
88
89    #[test]
90    fn test_calculator_direct() {
91        let mut calc = Calculator::new();
92        let result = calc.calculate(6.0, 7.0, Operation::Multiply).unwrap();
93        assert_eq!(result, 42.0);
94    }
95
96    #[test]
97    fn test_parser_direct() {
98        let ast = Parser::parse_str("1 + 2 * 3").unwrap();
99        let mut eval = Evaluator::new();
100        assert_eq!(eval.evaluate(&ast).unwrap(), 7.0);
101    }
102
103    #[test]
104    fn test_history_tracking() {
105        let mut history = History::new();
106        history.record("10 / 2", 5.0);
107        assert_eq!(history.len(), 1);
108        assert_eq!(history.last().unwrap().display(), "10 / 2 = 5");
109    }
110
111    #[test]
112    fn test_jidoka_validation() {
113        let validator = AnomalyValidator::with_max_magnitude(50.0);
114        let mut eval = Evaluator::with_validator(validator);
115
116        // Within bounds
117        assert!(eval.evaluate_str("5 * 5").is_ok());
118
119        // Exceeds bounds
120        assert!(matches!(
121            eval.evaluate_str("10 * 10"),
122            Err(CalcError::AnomalyViolation(_))
123        ));
124    }
125
126    #[test]
127    fn test_error_handling() {
128        let mut eval = Evaluator::new();
129
130        // Division by zero
131        assert!(matches!(
132            eval.evaluate_str("1 / 0"),
133            Err(CalcError::DivisionByZero)
134        ));
135
136        // Empty expression
137        assert!(matches!(
138            eval.evaluate_str(""),
139            Err(CalcError::EmptyExpression)
140        ));
141
142        // Parse error
143        assert!(matches!(
144            eval.evaluate_str("1 + + 2"),
145            Err(CalcError::ParseError(_))
146        ));
147    }
148
149    #[test]
150    fn test_all_operations() {
151        let mut eval = Evaluator::new();
152
153        assert_eq!(eval.evaluate_str("10 + 5").unwrap(), 15.0);
154        assert_eq!(eval.evaluate_str("10 - 3").unwrap(), 7.0);
155        assert_eq!(eval.evaluate_str("6 * 7").unwrap(), 42.0);
156        assert_eq!(eval.evaluate_str("20 / 4").unwrap(), 5.0);
157        assert_eq!(eval.evaluate_str("17 % 5").unwrap(), 2.0);
158        assert_eq!(eval.evaluate_str("2 ^ 10").unwrap(), 1024.0);
159    }
160
161    #[test]
162    fn test_complex_expressions() {
163        let mut eval = Evaluator::new();
164
165        // PEMDAS: 2 + 3 * 4 = 2 + 12 = 14
166        assert_eq!(eval.evaluate_str("2 + 3 * 4").unwrap(), 14.0);
167
168        // Parentheses: (2 + 3) * 4 = 5 * 4 = 20
169        assert_eq!(eval.evaluate_str("(2 + 3) * 4").unwrap(), 20.0);
170
171        // Power right associative: 2^3^2 = 2^9 = 512
172        assert_eq!(eval.evaluate_str("2 ^ 3 ^ 2").unwrap(), 512.0);
173
174        // Complex: 42 * (3 + 7) = 42 * 10 = 420
175        assert_eq!(eval.evaluate_str("42 * (3 + 7)").unwrap(), 420.0);
176
177        // Unary minus: -5 + 10 = 5
178        assert_eq!(eval.evaluate_str("-5 + 10").unwrap(), 5.0);
179    }
180}