1use crate::result::{ProbarError, ProbarResult};
16use std::collections::HashMap;
17use std::fmt;
18
19#[derive(Debug, Clone)]
21pub struct Variable {
22 pub name: String,
24 pub value: f64,
26 pub unit: Option<String>,
28}
29
30impl Variable {
31 #[must_use]
33 pub fn new(name: &str, value: f64) -> Self {
34 Self {
35 name: name.to_string(),
36 value,
37 unit: None,
38 }
39 }
40
41 #[must_use]
43 pub fn with_unit(name: &str, value: f64, unit: &str) -> Self {
44 Self {
45 name: name.to_string(),
46 value,
47 unit: Some(unit.to_string()),
48 }
49 }
50}
51
52impl fmt::Display for Variable {
53 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54 match &self.unit {
55 Some(unit) => write!(f, "{} = {} {}", self.name, self.value, unit),
56 None => write!(f, "{} = {}", self.name, self.value),
57 }
58 }
59}
60
61#[derive(Debug, Clone, Default)]
63pub struct EquationContext {
64 variables: HashMap<String, f64>,
65}
66
67impl EquationContext {
68 #[must_use]
70 pub fn new() -> Self {
71 Self::default()
72 }
73
74 pub fn set(&mut self, name: &str, value: f64) -> &mut Self {
76 self.variables.insert(name.to_string(), value);
77 self
78 }
79
80 #[must_use]
82 pub fn get(&self, name: &str) -> Option<f64> {
83 self.variables.get(name).copied()
84 }
85
86 #[must_use]
88 pub fn has(&self, name: &str) -> bool {
89 self.variables.contains_key(name)
90 }
91
92 #[must_use]
94 pub fn variables(&self) -> Vec<&str> {
95 self.variables.keys().map(String::as_str).collect()
96 }
97
98 #[must_use]
100 pub fn from_variables(vars: &[Variable]) -> Self {
101 let mut ctx = Self::new();
102 for var in vars {
103 ctx.set(&var.name, var.value);
104 }
105 ctx
106 }
107}
108
109#[derive(Debug, Clone)]
111pub struct EquationResult {
112 pub name: String,
114 pub passed: bool,
116 pub expected: f64,
118 pub actual: f64,
120 pub tolerance: f64,
122 pub difference: f64,
124 pub relative_difference: f64,
126 pub message: String,
128}
129
130impl EquationResult {
131 #[must_use]
133 fn new(name: &str, expected: f64, actual: f64, tolerance: f64) -> Self {
134 let difference = (expected - actual).abs();
135 let relative_difference = if expected.abs() > f64::EPSILON {
136 (difference / expected.abs()) * 100.0
137 } else {
138 0.0
139 };
140 let passed = difference <= tolerance;
141
142 let message = if passed {
143 format!(
144 "{}: expected {} ≈ {} (diff: {:.6}, tolerance: {})",
145 name, expected, actual, difference, tolerance
146 )
147 } else {
148 format!(
149 "{}: FAILED - expected {} but got {} (diff: {:.6} > tolerance: {})",
150 name, expected, actual, difference, tolerance
151 )
152 };
153
154 Self {
155 name: name.to_string(),
156 passed,
157 expected,
158 actual,
159 tolerance,
160 difference,
161 relative_difference,
162 message,
163 }
164 }
165}
166
167impl fmt::Display for EquationResult {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 write!(f, "{}", self.message)
170 }
171}
172
173#[derive(Debug)]
175pub struct EquationVerifier {
176 name: String,
178 tolerance: f64,
180 results: Vec<EquationResult>,
182}
183
184impl EquationVerifier {
185 #[must_use]
187 pub fn new(name: &str) -> Self {
188 Self {
189 name: name.to_string(),
190 tolerance: 1e-6,
191 results: Vec::new(),
192 }
193 }
194
195 #[must_use]
197 pub fn with_tolerance(mut self, tolerance: f64) -> Self {
198 self.tolerance = tolerance;
199 self
200 }
201
202 #[must_use]
204 pub fn name(&self) -> &str {
205 &self.name
206 }
207
208 #[must_use]
210 pub fn tolerance(&self) -> f64 {
211 self.tolerance
212 }
213
214 pub fn verify_eq(&mut self, name: &str, expected: f64, actual: f64) -> &mut Self {
216 let result = EquationResult::new(name, expected, actual, self.tolerance);
217 self.results.push(result);
218 self
219 }
220
221 pub fn verify_eq_with_tolerance(
223 &mut self,
224 name: &str,
225 expected: f64,
226 actual: f64,
227 tolerance: f64,
228 ) -> &mut Self {
229 let result = EquationResult::new(name, expected, actual, tolerance);
230 self.results.push(result);
231 self
232 }
233
234 pub fn verify_in_range(&mut self, name: &str, value: f64, min: f64, max: f64) -> &mut Self {
236 let passed = value >= min && value <= max;
237 let midpoint = (min + max) / 2.0;
238 let difference = if passed {
239 0.0
240 } else if value < min {
241 min - value
242 } else {
243 value - max
244 };
245
246 let message = if passed {
247 format!("{}: {} is within [{}, {}]", name, value, min, max)
248 } else {
249 format!(
250 "{}: FAILED - {} is outside range [{}, {}]",
251 name, value, min, max
252 )
253 };
254
255 self.results.push(EquationResult {
256 name: name.to_string(),
257 passed,
258 expected: midpoint,
259 actual: value,
260 tolerance: (max - min) / 2.0,
261 difference,
262 relative_difference: 0.0,
263 message,
264 });
265 self
266 }
267
268 pub fn verify_non_negative(&mut self, name: &str, value: f64) -> &mut Self {
270 let passed = value >= 0.0;
271 let message = if passed {
272 format!("{}: {} >= 0", name, value)
273 } else {
274 format!("{}: FAILED - {} < 0", name, value)
275 };
276
277 self.results.push(EquationResult {
278 name: name.to_string(),
279 passed,
280 expected: 0.0,
281 actual: value,
282 tolerance: 0.0,
283 difference: if passed { 0.0 } else { -value },
284 relative_difference: 0.0,
285 message,
286 });
287 self
288 }
289
290 pub fn verify_positive(&mut self, name: &str, value: f64) -> &mut Self {
292 let passed = value > 0.0;
293 let message = if passed {
294 format!("{}: {} > 0", name, value)
295 } else {
296 format!("{}: FAILED - {} <= 0", name, value)
297 };
298
299 self.results.push(EquationResult {
300 name: name.to_string(),
301 passed,
302 expected: f64::EPSILON,
303 actual: value,
304 tolerance: 0.0,
305 difference: if passed { 0.0 } else { -value },
306 relative_difference: 0.0,
307 message,
308 });
309 self
310 }
311
312 #[must_use]
314 pub fn results(&self) -> &[EquationResult] {
315 &self.results
316 }
317
318 #[must_use]
320 pub fn all_passed(&self) -> bool {
321 self.results.iter().all(|r| r.passed)
322 }
323
324 #[must_use]
326 pub fn failures(&self) -> Vec<&EquationResult> {
327 self.results.iter().filter(|r| !r.passed).collect()
328 }
329
330 #[must_use]
332 pub fn passed_count(&self) -> usize {
333 self.results.iter().filter(|r| r.passed).count()
334 }
335
336 #[must_use]
338 pub fn failed_count(&self) -> usize {
339 self.results.iter().filter(|r| !r.passed).count()
340 }
341
342 pub fn assert_all(&self) -> ProbarResult<()> {
344 if self.all_passed() {
345 Ok(())
346 } else {
347 let failures: Vec<String> = self.failures().iter().map(|r| r.message.clone()).collect();
348 Err(ProbarError::AssertionFailed {
349 message: format!(
350 "Equation verification '{}' failed:\n{}",
351 self.name,
352 failures.join("\n")
353 ),
354 })
355 }
356 }
357
358 pub fn clear(&mut self) {
360 self.results.clear();
361 }
362}
363
364#[derive(Debug)]
370pub struct KinematicVerifier {
371 verifier: EquationVerifier,
372}
373
374impl KinematicVerifier {
375 #[must_use]
377 pub fn new() -> Self {
378 Self {
379 verifier: EquationVerifier::new("kinematics").with_tolerance(1e-4),
380 }
381 }
382
383 #[must_use]
385 pub fn with_tolerance(mut self, tolerance: f64) -> Self {
386 self.verifier = self.verifier.with_tolerance(tolerance);
387 self
388 }
389
390 pub fn verify_velocity(
392 &mut self,
393 v: f64, v0: f64, a: f64, t: f64, ) -> &mut Self {
398 let expected = v0 + a * t;
399 self.verifier.verify_eq("v = v0 + at", expected, v);
400 self
401 }
402
403 pub fn verify_position(
405 &mut self,
406 x: f64, x0: f64, v0: f64, a: f64, t: f64, ) -> &mut Self {
412 let expected = x0 + v0 * t + 0.5 * a * t * t;
413 self.verifier
414 .verify_eq("x = x0 + v0*t + 0.5*a*t²", expected, x);
415 self
416 }
417
418 pub fn verify_velocity_squared(
420 &mut self,
421 v: f64, v0: f64, a: f64, x: f64, x0: f64, ) -> &mut Self {
427 let expected = v0 * v0 + 2.0 * a * (x - x0);
428 self.verifier
429 .verify_eq("v² = v0² + 2a(x-x0)", expected, v * v);
430 self
431 }
432
433 #[must_use]
435 pub fn verifier(&self) -> &EquationVerifier {
436 &self.verifier
437 }
438
439 pub fn assert_all(&self) -> ProbarResult<()> {
441 self.verifier.assert_all()
442 }
443}
444
445impl Default for KinematicVerifier {
446 fn default() -> Self {
447 Self::new()
448 }
449}
450
451#[derive(Debug)]
453pub struct EnergyVerifier {
454 verifier: EquationVerifier,
455}
456
457impl EnergyVerifier {
458 #[must_use]
460 pub fn new() -> Self {
461 Self {
462 verifier: EquationVerifier::new("energy").with_tolerance(1e-4),
463 }
464 }
465
466 #[must_use]
468 pub fn with_tolerance(mut self, tolerance: f64) -> Self {
469 self.verifier = self.verifier.with_tolerance(tolerance);
470 self
471 }
472
473 pub fn verify_kinetic_energy(
475 &mut self,
476 ke: f64, m: f64, v: f64, ) -> &mut Self {
480 let expected = 0.5 * m * v * v;
481 self.verifier.verify_eq("KE = 0.5*m*v²", expected, ke);
482 self
483 }
484
485 pub fn verify_potential_energy(
487 &mut self,
488 pe: f64, m: f64, g: f64, h: f64, ) -> &mut Self {
493 let expected = m * g * h;
494 self.verifier.verify_eq("PE = m*g*h", expected, pe);
495 self
496 }
497
498 pub fn verify_conservation(
500 &mut self,
501 ke_initial: f64,
502 pe_initial: f64,
503 ke_final: f64,
504 pe_final: f64,
505 ) -> &mut Self {
506 let total_initial = ke_initial + pe_initial;
507 let total_final = ke_final + pe_final;
508 self.verifier
509 .verify_eq("E_total conserved", total_initial, total_final);
510 self
511 }
512
513 pub fn verify_work_energy(&mut self, work: f64, ke_initial: f64, ke_final: f64) -> &mut Self {
515 let delta_ke = ke_final - ke_initial;
516 self.verifier.verify_eq("W = ΔKE", work, delta_ke);
517 self
518 }
519
520 #[must_use]
522 pub fn verifier(&self) -> &EquationVerifier {
523 &self.verifier
524 }
525
526 pub fn assert_all(&self) -> ProbarResult<()> {
528 self.verifier.assert_all()
529 }
530}
531
532impl Default for EnergyVerifier {
533 fn default() -> Self {
534 Self::new()
535 }
536}
537
538#[derive(Debug)]
540pub struct MomentumVerifier {
541 verifier: EquationVerifier,
542}
543
544impl MomentumVerifier {
545 #[must_use]
547 pub fn new() -> Self {
548 Self {
549 verifier: EquationVerifier::new("momentum").with_tolerance(1e-4),
550 }
551 }
552
553 #[must_use]
555 pub fn with_tolerance(mut self, tolerance: f64) -> Self {
556 self.verifier = self.verifier.with_tolerance(tolerance);
557 self
558 }
559
560 pub fn verify_momentum(
562 &mut self,
563 p: f64, m: f64, v: f64, ) -> &mut Self {
567 let expected = m * v;
568 self.verifier.verify_eq("p = m*v", expected, p);
569 self
570 }
571
572 pub fn verify_conservation(
574 &mut self,
575 m1: f64,
576 v1_initial: f64,
577 m2: f64,
578 v2_initial: f64,
579 v1_final: f64,
580 v2_final: f64,
581 ) -> &mut Self {
582 let p_initial = m1 * v1_initial + m2 * v2_initial;
583 let p_final = m1 * v1_final + m2 * v2_final;
584 self.verifier
585 .verify_eq("p_total conserved", p_initial, p_final);
586 self
587 }
588
589 pub fn verify_elastic_collision(
591 &mut self,
592 m1: f64,
593 v1_initial: f64,
594 m2: f64,
595 v2_initial: f64,
596 v1_final: f64,
597 v2_final: f64,
598 ) -> &mut Self {
599 self.verify_conservation(m1, v1_initial, m2, v2_initial, v1_final, v2_final);
601
602 let ke_initial = 0.5 * m1 * v1_initial * v1_initial + 0.5 * m2 * v2_initial * v2_initial;
604 let ke_final = 0.5 * m1 * v1_final * v1_final + 0.5 * m2 * v2_final * v2_final;
605 self.verifier
606 .verify_eq("KE conserved (elastic)", ke_initial, ke_final);
607 self
608 }
609
610 #[must_use]
612 pub fn verifier(&self) -> &EquationVerifier {
613 &self.verifier
614 }
615
616 pub fn assert_all(&self) -> ProbarResult<()> {
618 self.verifier.assert_all()
619 }
620}
621
622impl Default for MomentumVerifier {
623 fn default() -> Self {
624 Self::new()
625 }
626}
627
628#[derive(Debug)]
630pub struct InvariantVerifier {
631 verifier: EquationVerifier,
632}
633
634impl InvariantVerifier {
635 #[must_use]
637 pub fn new(name: &str) -> Self {
638 Self {
639 verifier: EquationVerifier::new(name).with_tolerance(1e-6),
640 }
641 }
642
643 #[must_use]
645 pub fn with_tolerance(mut self, tolerance: f64) -> Self {
646 self.verifier = self.verifier.with_tolerance(tolerance);
647 self
648 }
649
650 pub fn verify_score_non_negative(&mut self, score: f64) -> &mut Self {
652 self.verifier.verify_non_negative("score >= 0", score);
653 self
654 }
655
656 pub fn verify_health(&mut self, health: f64, max_health: f64) -> &mut Self {
658 self.verifier
659 .verify_in_range("health", health, 0.0, max_health);
660 self
661 }
662
663 pub fn verify_position_bounds(
665 &mut self,
666 x: f64,
667 y: f64,
668 min_x: f64,
669 max_x: f64,
670 min_y: f64,
671 max_y: f64,
672 ) -> &mut Self {
673 self.verifier.verify_in_range("x position", x, min_x, max_x);
674 self.verifier.verify_in_range("y position", y, min_y, max_y);
675 self
676 }
677
678 pub fn verify_speed_limit(&mut self, vx: f64, vy: f64, max_speed: f64) -> &mut Self {
680 let speed = (vx * vx + vy * vy).sqrt();
681 self.verifier
682 .verify_in_range("speed", speed, 0.0, max_speed);
683 self
684 }
685
686 pub fn verify_entity_count(&mut self, count: usize, expected: usize) -> &mut Self {
688 self.verifier
689 .verify_eq("entity count", expected as f64, count as f64);
690 self
691 }
692
693 pub fn verify_custom(&mut self, name: &str, expected: f64, actual: f64) -> &mut Self {
695 self.verifier.verify_eq(name, expected, actual);
696 self
697 }
698
699 #[must_use]
701 pub fn verifier(&self) -> &EquationVerifier {
702 &self.verifier
703 }
704
705 pub fn assert_all(&self) -> ProbarResult<()> {
707 self.verifier.assert_all()
708 }
709}
710
711#[cfg(test)]
712#[allow(clippy::unwrap_used, clippy::expect_used)]
713mod tests {
714 use super::*;
715
716 mod variable_tests {
717 use super::*;
718
719 #[test]
720 fn test_new() {
721 let var = Variable::new("x", 10.0);
722 assert_eq!(var.name, "x");
723 assert!((var.value - 10.0).abs() < f64::EPSILON);
724 assert!(var.unit.is_none());
725 }
726
727 #[test]
728 fn test_with_unit() {
729 let var = Variable::with_unit("velocity", 5.0, "m/s");
730 assert_eq!(var.unit, Some("m/s".to_string()));
731 }
732
733 #[test]
734 fn test_display() {
735 let var1 = Variable::new("x", 10.0);
736 assert_eq!(format!("{}", var1), "x = 10");
737
738 let var2 = Variable::with_unit("v", 5.0, "m/s");
739 assert_eq!(format!("{}", var2), "v = 5 m/s");
740 }
741 }
742
743 mod equation_context_tests {
744 use super::*;
745
746 #[test]
747 fn test_new() {
748 let ctx = EquationContext::new();
749 assert!(ctx.variables().is_empty());
750 }
751
752 #[test]
753 fn test_set_and_get() {
754 let mut ctx = EquationContext::new();
755 ctx.set("x", 10.0);
756
757 assert!(ctx.has("x"));
758 assert_eq!(ctx.get("x"), Some(10.0));
759 assert_eq!(ctx.get("y"), None);
760 }
761
762 #[test]
763 fn test_from_variables() {
764 let vars = vec![Variable::new("x", 1.0), Variable::new("y", 2.0)];
765 let ctx = EquationContext::from_variables(&vars);
766
767 assert_eq!(ctx.get("x"), Some(1.0));
768 assert_eq!(ctx.get("y"), Some(2.0));
769 }
770 }
771
772 mod equation_verifier_tests {
773 use super::*;
774
775 #[test]
776 fn test_new() {
777 let verifier = EquationVerifier::new("test");
778 assert_eq!(verifier.name(), "test");
779 assert!(verifier.results().is_empty());
780 }
781
782 #[test]
783 fn test_verify_eq_pass() {
784 let mut verifier = EquationVerifier::new("test");
785 verifier.verify_eq("1 + 1 = 2", 2.0, 2.0);
786
787 assert!(verifier.all_passed());
788 assert_eq!(verifier.passed_count(), 1);
789 }
790
791 #[test]
792 fn test_verify_eq_fail() {
793 let mut verifier = EquationVerifier::new("test");
794 verifier.verify_eq("1 + 1 = 3", 3.0, 2.0);
795
796 assert!(!verifier.all_passed());
797 assert_eq!(verifier.failed_count(), 1);
798 }
799
800 #[test]
801 fn test_verify_eq_with_tolerance() {
802 let mut verifier = EquationVerifier::new("test");
803 verifier.verify_eq_with_tolerance("approx", 1.0, 1.001, 0.01);
804
805 assert!(verifier.all_passed());
806 }
807
808 #[test]
809 fn test_verify_in_range_pass() {
810 let mut verifier = EquationVerifier::new("test");
811 verifier.verify_in_range("value", 5.0, 0.0, 10.0);
812
813 assert!(verifier.all_passed());
814 }
815
816 #[test]
817 fn test_verify_in_range_fail() {
818 let mut verifier = EquationVerifier::new("test");
819 verifier.verify_in_range("value", 15.0, 0.0, 10.0);
820
821 assert!(!verifier.all_passed());
822 }
823
824 #[test]
825 fn test_verify_non_negative_pass() {
826 let mut verifier = EquationVerifier::new("test");
827 verifier.verify_non_negative("positive", 5.0);
828 verifier.verify_non_negative("zero", 0.0);
829
830 assert!(verifier.all_passed());
831 }
832
833 #[test]
834 fn test_verify_non_negative_fail() {
835 let mut verifier = EquationVerifier::new("test");
836 verifier.verify_non_negative("negative", -5.0);
837
838 assert!(!verifier.all_passed());
839 }
840
841 #[test]
842 fn test_verify_positive_pass() {
843 let mut verifier = EquationVerifier::new("test");
844 verifier.verify_positive("positive", 5.0);
845
846 assert!(verifier.all_passed());
847 }
848
849 #[test]
850 fn test_verify_positive_fail() {
851 let mut verifier = EquationVerifier::new("test");
852 verifier.verify_positive("zero", 0.0);
853
854 assert!(!verifier.all_passed());
855 }
856
857 #[test]
858 fn test_assert_all_pass() {
859 let mut verifier = EquationVerifier::new("test");
860 verifier.verify_eq("test", 1.0, 1.0);
861
862 assert!(verifier.assert_all().is_ok());
863 }
864
865 #[test]
866 fn test_assert_all_fail() {
867 let mut verifier = EquationVerifier::new("test");
868 verifier.verify_eq("test", 1.0, 2.0);
869
870 assert!(verifier.assert_all().is_err());
871 }
872
873 #[test]
874 fn test_clear() {
875 let mut verifier = EquationVerifier::new("test");
876 verifier.verify_eq("test", 1.0, 1.0);
877 verifier.clear();
878
879 assert!(verifier.results().is_empty());
880 }
881 }
882
883 mod kinematic_verifier_tests {
884 use super::*;
885
886 #[test]
887 fn test_verify_velocity() {
888 let mut verifier = KinematicVerifier::new();
889 verifier.verify_velocity(20.0, 10.0, 2.0, 5.0);
891
892 assert!(verifier.assert_all().is_ok());
893 }
894
895 #[test]
896 fn test_verify_position() {
897 let mut verifier = KinematicVerifier::new();
898 verifier.verify_position(75.0, 0.0, 10.0, 2.0, 5.0);
900
901 assert!(verifier.assert_all().is_ok());
902 }
903
904 #[test]
905 fn test_verify_velocity_squared() {
906 let mut verifier = KinematicVerifier::new();
907 let v = (300.0_f64).sqrt();
910 verifier.verify_velocity_squared(v, 10.0, 2.0, 50.0, 0.0);
911
912 assert!(verifier.assert_all().is_ok());
913 }
914
915 #[test]
916 fn test_free_fall() {
917 let mut verifier = KinematicVerifier::new();
918 let g = 9.81;
919 let t = 2.0;
920
921 let v = g * t; let y = 0.5 * g * t * t; verifier.verify_velocity(v, 0.0, g, t);
926 verifier.verify_position(y, 0.0, 0.0, g, t);
927
928 assert!(verifier.assert_all().is_ok());
929 }
930 }
931
932 mod energy_verifier_tests {
933 use super::*;
934
935 #[test]
936 fn test_verify_kinetic_energy() {
937 let mut verifier = EnergyVerifier::new();
938 verifier.verify_kinetic_energy(9.0, 2.0, 3.0);
940
941 assert!(verifier.assert_all().is_ok());
942 }
943
944 #[test]
945 fn test_verify_potential_energy() {
946 let mut verifier = EnergyVerifier::new();
947 verifier.verify_potential_energy(50.0, 1.0, 10.0, 5.0);
949
950 assert!(verifier.assert_all().is_ok());
951 }
952
953 #[test]
954 fn test_verify_conservation() {
955 let mut verifier = EnergyVerifier::new();
956 verifier.verify_conservation(50.0, 100.0, 100.0, 50.0);
960
961 assert!(verifier.assert_all().is_ok());
962 }
963
964 #[test]
965 fn test_pendulum_energy() {
966 let mut verifier = EnergyVerifier::new().with_tolerance(0.01);
967 let m = 1.0;
968 let g = 9.81;
969
970 let pe_top = m * g * 1.0;
972 let ke_top = 0.0;
973
974 let v_bottom = (2.0_f64 * g * 1.0).sqrt();
976 let ke_bottom = 0.5 * m * v_bottom * v_bottom;
977 let pe_bottom = 0.0;
978
979 verifier.verify_conservation(ke_top, pe_top, ke_bottom, pe_bottom);
980
981 assert!(verifier.assert_all().is_ok());
982 }
983 }
984
985 mod momentum_verifier_tests {
986 use super::*;
987
988 #[test]
989 fn test_verify_momentum() {
990 let mut verifier = MomentumVerifier::new();
991 verifier.verify_momentum(10.0, 2.0, 5.0);
993
994 assert!(verifier.assert_all().is_ok());
995 }
996
997 #[test]
998 fn test_verify_conservation() {
999 let mut verifier = MomentumVerifier::new();
1000 verifier.verify_conservation(1.0, 10.0, 1.0, 0.0, 0.0, 10.0);
1003
1004 assert!(verifier.assert_all().is_ok());
1005 }
1006
1007 #[test]
1008 fn test_verify_elastic_collision() {
1009 let mut verifier = MomentumVerifier::new();
1010 verifier.verify_elastic_collision(1.0, 10.0, 1.0, 0.0, 0.0, 10.0);
1012
1013 assert!(verifier.assert_all().is_ok());
1014 }
1015
1016 #[test]
1017 fn test_pong_collision() {
1018 let mut verifier = MomentumVerifier::new().with_tolerance(0.1);
1019
1020 let ball_mass = 1.0;
1023 let ball_v_initial = 10.0;
1024 let ball_v_final = -10.0; let ke_initial = 0.5 * ball_mass * ball_v_initial * ball_v_initial;
1029 let ke_final = 0.5 * ball_mass * ball_v_final * ball_v_final;
1030
1031 verifier
1032 .verifier
1033 .verify_eq("KE conserved", ke_initial, ke_final);
1034 assert!(verifier.assert_all().is_ok());
1035 }
1036 }
1037
1038 mod invariant_verifier_tests {
1039 use super::*;
1040
1041 #[test]
1042 fn test_verify_score_non_negative() {
1043 let mut verifier = InvariantVerifier::new("game");
1044 verifier.verify_score_non_negative(100.0);
1045
1046 assert!(verifier.assert_all().is_ok());
1047 }
1048
1049 #[test]
1050 fn test_verify_health() {
1051 let mut verifier = InvariantVerifier::new("game");
1052 verifier.verify_health(50.0, 100.0);
1053
1054 assert!(verifier.assert_all().is_ok());
1055 }
1056
1057 #[test]
1058 fn test_verify_position_bounds() {
1059 let mut verifier = InvariantVerifier::new("game");
1060 verifier.verify_position_bounds(400.0, 300.0, 0.0, 800.0, 0.0, 600.0);
1061
1062 assert!(verifier.assert_all().is_ok());
1063 }
1064
1065 #[test]
1066 fn test_verify_speed_limit() {
1067 let mut verifier = InvariantVerifier::new("game");
1068 verifier.verify_speed_limit(3.0, 4.0, 10.0); assert!(verifier.assert_all().is_ok());
1071 }
1072
1073 #[test]
1074 fn test_verify_entity_count() {
1075 let mut verifier = InvariantVerifier::new("game");
1076 verifier.verify_entity_count(10, 10);
1077
1078 assert!(verifier.assert_all().is_ok());
1079 }
1080
1081 #[test]
1082 fn test_game_frame_invariants() {
1083 let mut verifier = InvariantVerifier::new("pong").with_tolerance(0.001);
1084
1085 let score = 5.0;
1087 let ball_x = 400.0;
1088 let ball_y = 300.0;
1089 let ball_vx = 5.0;
1090 let ball_vy = -3.0;
1091 let max_speed = 10.0;
1092
1093 verifier
1094 .verify_score_non_negative(score)
1095 .verify_position_bounds(ball_x, ball_y, 0.0, 800.0, 0.0, 600.0)
1096 .verify_speed_limit(ball_vx, ball_vy, max_speed);
1097
1098 assert!(verifier.assert_all().is_ok());
1099 }
1100
1101 #[test]
1102 fn test_verify_custom() {
1103 let mut verifier = InvariantVerifier::new("custom");
1104 verifier.verify_custom("custom_check", 42.0, 42.0);
1105 assert!(verifier.assert_all().is_ok());
1106 }
1107
1108 #[test]
1109 fn test_invariant_verifier_accessor() {
1110 let verifier = InvariantVerifier::new("test");
1111 assert_eq!(verifier.verifier().name(), "test");
1112 }
1113 }
1114
1115 mod additional_coverage_tests {
1117 use super::*;
1118
1119 #[test]
1120 fn test_equation_result_display() {
1121 let result = EquationResult::new("test_eq", 1.0, 1.0, 0.001);
1123 let display = format!("{}", result);
1124 assert!(display.contains("test_eq"));
1125 assert!(display.contains("expected"));
1126 }
1127
1128 #[test]
1129 fn test_equation_result_relative_difference_zero_expected() {
1130 let result = EquationResult::new("zero_expected", 0.0, 0.0001, 0.001);
1132 assert!((result.relative_difference - 0.0).abs() < f64::EPSILON);
1133 }
1134
1135 #[test]
1136 fn test_equation_result_failed_message() {
1137 let result = EquationResult::new("fail_test", 10.0, 5.0, 0.001);
1139 assert!(!result.passed);
1140 assert!(result.message.contains("FAILED"));
1141 assert!(result.message.contains('>'));
1142 }
1143
1144 #[test]
1145 fn test_equation_verifier_tolerance_accessor() {
1146 let verifier = EquationVerifier::new("test").with_tolerance(0.01);
1148 assert!((verifier.tolerance() - 0.01).abs() < f64::EPSILON);
1149 }
1150
1151 #[test]
1152 fn test_equation_verifier_failures() {
1153 let mut verifier = EquationVerifier::new("test");
1155 verifier.verify_eq("pass", 1.0, 1.0);
1156 verifier.verify_eq("fail1", 10.0, 5.0);
1157 verifier.verify_eq("fail2", 20.0, 15.0);
1158
1159 let failures = verifier.failures();
1160 assert_eq!(failures.len(), 2);
1161 assert!(failures.iter().any(|f| f.name == "fail1"));
1162 assert!(failures.iter().any(|f| f.name == "fail2"));
1163 }
1164
1165 #[test]
1166 fn test_verify_in_range_below_min() {
1167 let mut verifier = EquationVerifier::new("test");
1169 verifier.verify_in_range("below_min", -5.0, 0.0, 10.0);
1170
1171 assert!(!verifier.all_passed());
1172 let result = &verifier.results()[0];
1173 assert!(!result.passed);
1174 assert!((result.difference - 5.0).abs() < f64::EPSILON);
1175 assert!(result.message.contains("outside range"));
1176 }
1177
1178 #[test]
1179 fn test_verify_positive_negative_value() {
1180 let mut verifier = EquationVerifier::new("test");
1182 verifier.verify_positive("negative", -5.0);
1183
1184 assert!(!verifier.all_passed());
1185 let result = &verifier.results()[0];
1186 assert!(!result.passed);
1187 assert!((result.difference - 5.0).abs() < f64::EPSILON);
1188 }
1189
1190 #[test]
1191 fn test_kinematic_verifier_default() {
1192 let verifier = KinematicVerifier::default();
1194 assert_eq!(verifier.verifier().name(), "kinematics");
1195 }
1196
1197 #[test]
1198 fn test_kinematic_verifier_accessor() {
1199 let verifier = KinematicVerifier::new();
1201 let inner = verifier.verifier();
1202 assert_eq!(inner.name(), "kinematics");
1203 }
1204
1205 #[test]
1206 fn test_energy_verifier_default() {
1207 let verifier = EnergyVerifier::default();
1209 assert_eq!(verifier.verifier().name(), "energy");
1210 }
1211
1212 #[test]
1213 fn test_energy_verifier_work_energy() {
1214 let mut verifier = EnergyVerifier::new();
1216 verifier.verify_work_energy(50.0, 50.0, 100.0);
1218 assert!(verifier.assert_all().is_ok());
1219 }
1220
1221 #[test]
1222 fn test_energy_verifier_accessor() {
1223 let verifier = EnergyVerifier::new();
1225 let inner = verifier.verifier();
1226 assert_eq!(inner.name(), "energy");
1227 }
1228
1229 #[test]
1230 fn test_momentum_verifier_default() {
1231 let verifier = MomentumVerifier::default();
1233 assert_eq!(verifier.verifier().name(), "momentum");
1234 }
1235
1236 #[test]
1237 fn test_momentum_verifier_accessor() {
1238 let verifier = MomentumVerifier::new();
1240 let inner = verifier.verifier();
1241 assert_eq!(inner.name(), "momentum");
1242 }
1243
1244 #[test]
1245 fn test_equation_context_chaining() {
1246 let mut ctx = EquationContext::new();
1248 ctx.set("a", 1.0).set("b", 2.0).set("c", 3.0);
1249
1250 assert_eq!(ctx.get("a"), Some(1.0));
1251 assert_eq!(ctx.get("b"), Some(2.0));
1252 assert_eq!(ctx.get("c"), Some(3.0));
1253 }
1254
1255 #[test]
1256 fn test_equation_context_has_missing() {
1257 let ctx = EquationContext::new();
1259 assert!(!ctx.has("missing"));
1260 }
1261
1262 #[test]
1263 fn test_equation_result_relative_difference_calculation() {
1264 let result = EquationResult::new("rel_diff", 100.0, 90.0, 1.0);
1266 assert!((result.relative_difference - 10.0).abs() < f64::EPSILON);
1268 }
1269
1270 #[test]
1271 fn test_verifier_chaining() {
1272 let mut verifier = EquationVerifier::new("chain");
1274 verifier
1275 .verify_eq("eq1", 1.0, 1.0)
1276 .verify_eq("eq2", 2.0, 2.0)
1277 .verify_non_negative("nn", 5.0)
1278 .verify_positive("pos", 1.0)
1279 .verify_in_range("range", 5.0, 0.0, 10.0);
1280
1281 assert!(verifier.all_passed());
1282 assert_eq!(verifier.results().len(), 5);
1283 }
1284
1285 #[test]
1286 fn test_invariant_verifier_health_out_of_range() {
1287 let mut verifier = InvariantVerifier::new("game");
1289 verifier.verify_health(150.0, 100.0);
1290 assert!(verifier.assert_all().is_err());
1291 }
1292
1293 #[test]
1294 fn test_invariant_verifier_speed_exceeds_limit() {
1295 let mut verifier = InvariantVerifier::new("game");
1297 verifier.verify_speed_limit(8.0, 6.0, 5.0); assert!(verifier.assert_all().is_err());
1299 }
1300
1301 #[test]
1302 fn test_kinematic_verifier_with_tolerance() {
1303 let mut verifier = KinematicVerifier::new().with_tolerance(0.1);
1305 verifier.verify_velocity(20.05, 10.0, 2.0, 5.0);
1306 assert!(verifier.assert_all().is_ok());
1307 }
1308
1309 #[test]
1310 fn test_momentum_verifier_with_tolerance() {
1311 let mut verifier = MomentumVerifier::new().with_tolerance(0.1);
1313 verifier.verify_momentum(10.05, 2.0, 5.0);
1314 assert!(verifier.assert_all().is_ok());
1315 }
1316
1317 #[test]
1318 fn test_invariant_verifier_with_tolerance() {
1319 let mut verifier = InvariantVerifier::new("test").with_tolerance(0.1);
1321 verifier.verify_custom("approx", 10.0, 10.05);
1322 assert!(verifier.assert_all().is_ok());
1323 }
1324
1325 #[test]
1326 fn test_kinematic_verifier_failed_assertion() {
1327 let mut verifier = KinematicVerifier::new();
1329 verifier.verify_velocity(100.0, 10.0, 2.0, 5.0); assert!(verifier.assert_all().is_err());
1331 }
1332
1333 #[test]
1334 fn test_energy_verifier_failed_assertion() {
1335 let mut verifier = EnergyVerifier::new();
1337 verifier.verify_kinetic_energy(100.0, 2.0, 3.0); assert!(verifier.assert_all().is_err());
1339 }
1340
1341 #[test]
1342 fn test_momentum_verifier_failed_assertion() {
1343 let mut verifier = MomentumVerifier::new();
1345 verifier.verify_momentum(100.0, 2.0, 5.0); assert!(verifier.assert_all().is_err());
1347 }
1348
1349 #[test]
1350 fn test_invariant_verifier_failed_assertion() {
1351 let mut verifier = InvariantVerifier::new("test");
1353 verifier.verify_score_non_negative(-10.0);
1354 assert!(verifier.assert_all().is_err());
1355 }
1356
1357 #[test]
1358 fn test_verify_in_range_at_boundaries() {
1359 let mut verifier = EquationVerifier::new("boundaries");
1361 verifier.verify_in_range("at_min", 0.0, 0.0, 10.0);
1362 verifier.verify_in_range("at_max", 10.0, 0.0, 10.0);
1363 assert!(verifier.all_passed());
1364 }
1365
1366 #[test]
1367 fn test_equation_context_variables_list() {
1368 let mut ctx = EquationContext::new();
1370 ctx.set("x", 1.0).set("y", 2.0);
1371
1372 let vars = ctx.variables();
1373 assert_eq!(vars.len(), 2);
1374 assert!(vars.contains(&"x"));
1375 assert!(vars.contains(&"y"));
1376 }
1377
1378 #[test]
1379 fn test_equation_verifier_empty_results() {
1380 let verifier = EquationVerifier::new("empty");
1382 assert!(verifier.all_passed()); assert!(verifier.failures().is_empty());
1384 assert_eq!(verifier.passed_count(), 0);
1385 assert_eq!(verifier.failed_count(), 0);
1386 }
1387
1388 #[test]
1389 fn test_equation_context_from_empty_variables() {
1390 let vars: Vec<Variable> = vec![];
1392 let ctx = EquationContext::from_variables(&vars);
1393 assert!(ctx.variables().is_empty());
1394 }
1395
1396 #[test]
1397 fn test_variable_clone() {
1398 let var1 = Variable::with_unit("velocity", 10.0, "m/s");
1400 let var2 = var1;
1401 assert_eq!(var2.name, "velocity");
1402 assert!((var2.value - 10.0).abs() < f64::EPSILON);
1403 assert_eq!(var2.unit, Some("m/s".to_string()));
1404 }
1405
1406 #[test]
1407 fn test_equation_context_clone() {
1408 let mut ctx1 = EquationContext::new();
1410 ctx1.set("x", 5.0);
1411 let ctx2 = ctx1.clone();
1412 assert_eq!(ctx2.get("x"), Some(5.0));
1413 }
1414
1415 #[test]
1416 fn test_equation_result_clone() {
1417 let result1 = EquationResult::new("clone_test", 10.0, 10.0, 0.001);
1419 let result2 = result1;
1420 assert_eq!(result2.name, "clone_test");
1421 assert!(result2.passed);
1422 }
1423
1424 #[test]
1425 fn test_equation_verifier_multiple_failures() {
1426 let mut verifier = EquationVerifier::new("multi_fail");
1428 verifier.verify_eq("fail1", 1.0, 100.0);
1429 verifier.verify_eq("fail2", 2.0, 200.0);
1430 verifier.verify_eq("fail3", 3.0, 300.0);
1431
1432 let result = verifier.assert_all();
1433 assert!(result.is_err());
1434 if let Err(ProbarError::AssertionFailed { message }) = result {
1435 assert!(message.contains("fail1"));
1436 assert!(message.contains("fail2"));
1437 assert!(message.contains("fail3"));
1438 }
1439 }
1440
1441 #[test]
1442 fn test_verify_in_range_message_passed() {
1443 let mut verifier = EquationVerifier::new("test");
1445 verifier.verify_in_range("in_bounds", 5.0, 0.0, 10.0);
1446
1447 let result = &verifier.results()[0];
1448 assert!(result.message.contains("is within"));
1449 }
1450
1451 #[test]
1452 fn test_verify_non_negative_message() {
1453 let mut verifier = EquationVerifier::new("test");
1455 verifier.verify_non_negative("positive_val", 5.0);
1456
1457 let result = &verifier.results()[0];
1458 assert!(result.message.contains(">= 0"));
1459 }
1460
1461 #[test]
1462 fn test_verify_positive_message() {
1463 let mut verifier = EquationVerifier::new("test");
1465 verifier.verify_positive("pos_val", 5.0);
1466
1467 let result = &verifier.results()[0];
1468 assert!(result.message.contains("> 0"));
1469 }
1470
1471 #[test]
1472 fn test_equation_result_all_fields() {
1473 let result = EquationResult::new("field_test", 100.0, 95.0, 1.0);
1475 assert_eq!(result.name, "field_test");
1476 assert!(!result.passed); assert!((result.expected - 100.0).abs() < f64::EPSILON);
1478 assert!((result.actual - 95.0).abs() < f64::EPSILON);
1479 assert!((result.tolerance - 1.0).abs() < f64::EPSILON);
1480 assert!((result.difference - 5.0).abs() < f64::EPSILON);
1481 assert!((result.relative_difference - 5.0).abs() < f64::EPSILON); }
1483
1484 #[test]
1485 fn test_energy_verifier_conservation_fails() {
1486 let mut verifier = EnergyVerifier::new();
1488 verifier.verify_conservation(50.0, 100.0, 80.0, 80.0); assert!(verifier.assert_all().is_err());
1490 }
1491
1492 #[test]
1493 fn test_kinematic_verifier_position_fails() {
1494 let mut verifier = KinematicVerifier::new();
1496 verifier.verify_position(100.0, 0.0, 10.0, 2.0, 5.0); assert!(verifier.assert_all().is_err());
1498 }
1499
1500 #[test]
1501 fn test_kinematic_verifier_velocity_squared_fails() {
1502 let mut verifier = KinematicVerifier::new();
1504 verifier.verify_velocity_squared(100.0, 10.0, 2.0, 50.0, 0.0); assert!(verifier.assert_all().is_err());
1506 }
1507
1508 #[test]
1509 fn test_momentum_conservation_fails() {
1510 let mut verifier = MomentumVerifier::new();
1512 verifier.verify_conservation(1.0, 10.0, 1.0, 0.0, 5.0, 3.0); assert!(verifier.assert_all().is_err());
1514 }
1515
1516 #[test]
1517 fn test_elastic_collision_ke_fails() {
1518 let mut verifier = MomentumVerifier::new();
1520 verifier.verify_elastic_collision(1.0, 10.0, 1.0, 0.0, 5.0, 5.0);
1522 assert!(verifier.assert_all().is_err());
1523 }
1524
1525 #[test]
1526 fn test_invariant_entity_count_fails() {
1527 let mut verifier = InvariantVerifier::new("game");
1529 verifier.verify_entity_count(5, 10);
1530 assert!(verifier.assert_all().is_err());
1531 }
1532
1533 #[test]
1534 fn test_invariant_position_out_of_bounds() {
1535 let mut verifier = InvariantVerifier::new("game");
1537 verifier.verify_position_bounds(900.0, 700.0, 0.0, 800.0, 0.0, 600.0);
1538 assert!(verifier.assert_all().is_err());
1539 }
1540
1541 #[test]
1542 fn test_verify_negative_value_non_negative() {
1543 let mut verifier = EquationVerifier::new("test");
1545 verifier.verify_non_negative("neg", -10.0);
1546
1547 let result = &verifier.results()[0];
1548 assert!((result.difference - 10.0).abs() < f64::EPSILON);
1549 assert!(result.message.contains("< 0"));
1550 }
1551
1552 #[test]
1553 fn test_verifier_debug_impl() {
1554 let verifier = EquationVerifier::new("debug_test");
1556 let debug_str = format!("{:?}", verifier);
1557 assert!(debug_str.contains("debug_test"));
1558 }
1559
1560 #[test]
1561 fn test_kinematic_verifier_debug_impl() {
1562 let verifier = KinematicVerifier::new();
1564 let debug_str = format!("{:?}", verifier);
1565 assert!(debug_str.contains("KinematicVerifier"));
1566 }
1567
1568 #[test]
1569 fn test_energy_verifier_debug_impl() {
1570 let verifier = EnergyVerifier::new();
1572 let debug_str = format!("{:?}", verifier);
1573 assert!(debug_str.contains("EnergyVerifier"));
1574 }
1575
1576 #[test]
1577 fn test_momentum_verifier_debug_impl() {
1578 let verifier = MomentumVerifier::new();
1580 let debug_str = format!("{:?}", verifier);
1581 assert!(debug_str.contains("MomentumVerifier"));
1582 }
1583
1584 #[test]
1585 fn test_invariant_verifier_debug_impl() {
1586 let verifier = InvariantVerifier::new("test");
1588 let debug_str = format!("{:?}", verifier);
1589 assert!(debug_str.contains("InvariantVerifier"));
1590 }
1591
1592 #[test]
1593 fn test_variable_debug_impl() {
1594 let var = Variable::new("x", 5.0);
1596 let debug_str = format!("{:?}", var);
1597 assert!(debug_str.contains("Variable"));
1598 }
1599
1600 #[test]
1601 fn test_equation_context_debug_impl() {
1602 let ctx = EquationContext::new();
1604 let debug_str = format!("{:?}", ctx);
1605 assert!(debug_str.contains("EquationContext"));
1606 }
1607
1608 #[test]
1609 fn test_equation_result_debug_impl() {
1610 let result = EquationResult::new("test", 1.0, 1.0, 0.001);
1612 let debug_str = format!("{:?}", result);
1613 assert!(debug_str.contains("EquationResult"));
1614 }
1615
1616 #[test]
1617 fn test_equation_context_default() {
1618 let ctx = EquationContext::default();
1620 assert!(ctx.variables().is_empty());
1621 }
1622
1623 #[test]
1624 fn test_energy_work_energy_fails() {
1625 let mut verifier = EnergyVerifier::new();
1627 verifier.verify_work_energy(100.0, 50.0, 100.0); assert!(verifier.assert_all().is_err());
1629 }
1630 }
1631}