jugar_probar/assertion/
mod.rs1mod equation;
10mod retry;
11mod soft;
12
13use std::fmt::Debug;
14
15pub use equation::{
17 EnergyVerifier, EquationContext, EquationResult, EquationVerifier, InvariantVerifier,
18 KinematicVerifier, MomentumVerifier, Variable,
19};
20pub use retry::{
21 retry_contains, retry_eq, retry_none, retry_some, retry_true, AssertionCheckResult,
22 RetryAssertion, RetryConfig, RetryError, RetryResult,
23};
24pub use soft::{
25 AssertionFailure, AssertionMode, AssertionSummary, SoftAssertionError, SoftAssertions,
26};
27
28#[derive(Debug, Clone)]
30pub struct AssertionResult {
31 pub passed: bool,
33 pub message: String,
35}
36
37impl AssertionResult {
38 #[must_use]
40 pub const fn pass() -> Self {
41 Self {
42 passed: true,
43 message: String::new(),
44 }
45 }
46
47 #[must_use]
49 pub fn fail(message: impl Into<String>) -> Self {
50 Self {
51 passed: false,
52 message: message.into(),
53 }
54 }
55}
56
57#[derive(Debug)]
59pub struct Assertion;
60
61impl Assertion {
62 #[must_use]
64 pub fn equals<T: PartialEq + Debug>(expected: &T, actual: &T) -> AssertionResult {
65 contract_pre_assertion_evaluation!();
66 if expected == actual {
67 AssertionResult::pass()
68 } else {
69 AssertionResult::fail(format!("expected {expected:?}, got {actual:?}"))
70 }
71 }
72
73 #[must_use]
75 pub fn contains(haystack: &str, needle: &str) -> AssertionResult {
76 if haystack.contains(needle) {
77 AssertionResult::pass()
78 } else {
79 AssertionResult::fail(format!("expected '{haystack}' to contain '{needle}'"))
80 }
81 }
82
83 #[must_use]
85 pub fn in_range(value: f64, min: f64, max: f64) -> AssertionResult {
86 contract_pre_assertion_evaluation!();
87 if value >= min && value <= max {
88 AssertionResult::pass()
89 } else {
90 AssertionResult::fail(format!("expected {value} to be in range [{min}, {max}]"))
91 }
92 }
93
94 #[must_use]
96 pub fn is_true(condition: bool, message: &str) -> AssertionResult {
97 if condition {
98 AssertionResult::pass()
99 } else {
100 AssertionResult::fail(message)
101 }
102 }
103
104 #[must_use]
106 pub fn is_false(condition: bool, message: &str) -> AssertionResult {
107 if condition {
108 AssertionResult::fail(message)
109 } else {
110 AssertionResult::pass()
111 }
112 }
113
114 #[must_use]
116 pub fn is_some<T>(opt: &Option<T>) -> AssertionResult {
117 if opt.is_some() {
118 AssertionResult::pass()
119 } else {
120 AssertionResult::fail("expected Some, got None")
121 }
122 }
123
124 #[must_use]
126 pub fn is_none<T>(opt: &Option<T>) -> AssertionResult {
127 if opt.is_none() {
128 AssertionResult::pass()
129 } else {
130 AssertionResult::fail("expected None, got Some")
131 }
132 }
133
134 #[must_use]
136 pub fn is_ok<T, E>(result: &Result<T, E>) -> AssertionResult {
137 if result.is_ok() {
138 AssertionResult::pass()
139 } else {
140 AssertionResult::fail("expected Ok, got Err")
141 }
142 }
143
144 #[must_use]
146 pub fn is_err<T, E>(result: &Result<T, E>) -> AssertionResult {
147 if result.is_err() {
148 AssertionResult::pass()
149 } else {
150 AssertionResult::fail("expected Err, got Ok")
151 }
152 }
153
154 #[must_use]
156 pub fn approx_eq(a: f64, b: f64, epsilon: f64) -> AssertionResult {
157 contract_pre_assertion_evaluation!();
158 if (a - b).abs() < epsilon {
159 AssertionResult::pass()
160 } else {
161 AssertionResult::fail(format!("expected {a} ≈ {b} (epsilon: {epsilon})"))
162 }
163 }
164
165 #[must_use]
167 pub fn has_length<T>(collection: &[T], expected: usize) -> AssertionResult {
168 if collection.len() == expected {
169 AssertionResult::pass()
170 } else {
171 AssertionResult::fail(format!(
172 "expected length {expected}, got {}",
173 collection.len()
174 ))
175 }
176 }
177}