1use crate::messages::MessageType;
4use crate::runners::act::Act;
5use crate::{Assert, Message, PanicWhen};
6use std::panic;
7use std::panic::AssertUnwindSafe;
8
9const NO_PANIC_ERROR: &str = "Code has not panicked";
10const PANIC_ERROR: &str = "Code has panicked";
11
12pub struct Runner<'a, T, E> {
71 arrange_function: Box<Fn(&mut Message) -> T + 'a>,
72 actions: Vec<Act<'a, T, E>>,
73}
74
75impl<'a, T, E> Runner<'a, T, E> {
76 pub fn arrange(function: impl Fn(&mut Message) -> T + 'a) -> Self {
81 Self {
82 arrange_function: Box::new(function),
83 actions: Vec::new(),
84 }
85 }
86
87 pub fn act(
92 &mut self,
93 action: impl Fn(&mut Message, &mut T) + 'a,
94 expectation: impl Fn() -> E + 'a,
95 ) -> &mut Self {
96 self.actions.push(Act::new(action, expectation));
97 self
98 }
99
100 pub fn act_panic(
106 &self,
107 when: PanicWhen,
108 function: impl Fn(&mut Message, &mut T) + 'a,
109 ) -> &Self {
110 let mut message = Message::new();
111 let mut value = (self.arrange_function)(&mut message);
112 message.set_current_type(MessageType::Act);
113 let result = panic::catch_unwind(AssertUnwindSafe(|| {
114 function(&mut message, &mut value);
115 }));
116 if result.is_ok() == Self::should_panic(when) {
117 message.set_current_type(MessageType::Assert);
118 message.set("** Skipped **");
119 if result.is_ok() {
120 panic!(Self::format_error_message(&message, NO_PANIC_ERROR));
121 } else {
122 panic!(Self::format_error_message(&message, PANIC_ERROR));
123 }
124 }
125 self
126 }
127
128 pub fn assert<A: Assert>(
133 &self,
134 function: impl Fn(&mut Message, T, E) -> A + 'a,
135 ) -> &Self {
136 for act in &self.actions {
137 let mut message = Message::new();
138 let mut value = (self.arrange_function)(&mut message);
139 message.set_current_type(MessageType::Act);
140 act.execute(&mut message, &mut value);
141 let expected = act.expect();
142 message.set_current_type(MessageType::Assert);
143 let result = function(&mut message, value, expected);
144 if !result.success() {
145 panic!(Self::format_error_message(
146 &message,
147 &result.error_message()
148 ));
149 }
150 }
151 self
152 }
153
154 pub fn assert_panic<A: Assert>(
159 &self,
160 when: PanicWhen,
161 function: impl Fn(&mut Message, T, E) -> A + 'a,
162 ) -> &Self {
163 for act in &self.actions {
164 let mut message = Message::new();
165 let mut value = (self.arrange_function)(&mut message);
166 message.set_current_type(MessageType::Act);
167 act.execute(&mut message, &mut value);
168 let expected = act.expect();
169 message.set_current_type(MessageType::Assert);
170 let result = panic::catch_unwind(AssertUnwindSafe(|| {
171 function(&mut message, value, expected)
172 }));
173 if result.is_ok() == Self::should_panic(when) {
174 if result.is_ok() {
175 panic!(Self::format_error_message(
176 &message,
177 NO_PANIC_ERROR
178 ));
179 } else {
180 panic!(Self::format_error_message(&message, PANIC_ERROR));
181 }
182 }
183 }
184 self
185 }
186
187 fn format_error_message(message: &Message, error: &str) -> String {
189 "\n--------------------------------------------\n".to_string()
190 + &format!("Arrange:\n {}\n", message.arrange_message())
191 + &format!("Act:\n {}\n", message.act_message())
192 + &format!("Assert:\n {}\n", message.assert_message())
193 + &format!("Error:\n {}\n", error.replace("\n", "\n "))
194 + "--------------------------------------------\n"
195 }
196
197 fn should_panic(panic_when: PanicWhen) -> bool {
203 #[cfg(debug_assertions)]
204 match panic_when {
205 PanicWhen::Debug | PanicWhen::DebugAndRelease => true,
206 PanicWhen::Release => false,
207 }
208 #[cfg(not(debug_assertions))]
209 match panic_when {
210 PanicWhen::Release | PanicWhen::DebugAndRelease => true,
211 PanicWhen::Debug => false,
212 }
213 }
214}
215
216#[cfg(test)]
217mod tests {
218 use crate::{Equal, PanicWhen, Runner};
219
220 const VALUE_EXAMPLE: usize = 10;
221
222 struct Expected {
223 value: usize,
224 }
225
226 #[test]
227 fn test_ok() {
228 Runner::arrange(|message| {
229 message.set("Initialization");
230 0
231 })
232 .act(
233 |message, value| {
234 message.set("Action");
235 *value = VALUE_EXAMPLE
236 },
237 || Expected {
238 value: VALUE_EXAMPLE,
239 },
240 )
241 .act_panic(PanicWhen::Debug, |message, value| {
242 message.set("Other action");
243 *value -= 1;
244 })
245 .assert_panic(PanicWhen::Debug, |message, mut _value, _expected| {
246 message.set("Evaluation");
247 _value -= VALUE_EXAMPLE + 1;
248 Equal::new(0, 0)
249 })
250 .assert(|message, value, expected| {
251 message.set("Other evaluation");
252 Equal::new(value, expected.value)
253 });
254 }
255
256 #[test]
257 #[should_panic]
258 #[cfg(debug_assertions)]
259 fn test_act_panic_fail() {
260 Runner::arrange(|message| {
261 message.set("Initialization");
262 0
263 })
264 .act(
265 |message, value| {
266 message.set("Action");
267 *value = VALUE_EXAMPLE
268 },
269 || Expected {
270 value: VALUE_EXAMPLE,
271 },
272 )
273 .act_panic(PanicWhen::Debug, |message, value| {
274 message.set("Other action");
275 *value -= 0;
276 })
277 .assert_panic(PanicWhen::Debug, |message, mut _value, _expected| {
278 message.set("Evaluation");
279 _value -= VALUE_EXAMPLE + 1;
280 Equal::new(0, 0)
281 })
282 .assert(|message, value, expected| {
283 message.set("Other evaluation");
284 Equal::new(value, expected.value)
285 });
286 }
287
288 #[test]
289 #[should_panic]
290 #[cfg(debug_assertions)]
291 fn test_assert_panic_fail() {
292 Runner::arrange(|message| {
293 message.set("Initialization");
294 0
295 })
296 .act(
297 |message, value| {
298 message.set("Action");
299 *value = VALUE_EXAMPLE
300 },
301 || Expected {
302 value: VALUE_EXAMPLE,
303 },
304 )
305 .act_panic(PanicWhen::Debug, |message, value| {
306 message.set("Other action");
307 *value -= 1;
308 })
309 .assert_panic(PanicWhen::Debug, |message, mut _value, _expected| {
310 message.set("Evaluation");
311 _value -= 0;
312 Equal::new(0, 0)
313 })
314 .assert(|message, value, expected| {
315 message.set("Other evaluation");
316 Equal::new(value, expected.value)
317 });
318 }
319
320 #[test]
321 #[should_panic]
322 fn test_assert_fail() {
323 Runner::arrange(|message| {
324 message.set("Initialization");
325 0
326 })
327 .act(
328 |message, value| {
329 message.set("Action");
330 *value = VALUE_EXAMPLE
331 },
332 || Expected {
333 value: VALUE_EXAMPLE,
334 },
335 )
336 .act_panic(PanicWhen::Debug, |message, value| {
337 message.set("Other action");
338 *value -= 1;
339 })
340 .assert_panic(PanicWhen::Debug, |message, mut _value, _expected| {
341 message.set("Evaluation");
342 _value -= VALUE_EXAMPLE + 1;
343 Equal::new(0, 0)
344 })
345 .assert(|message, value, expected| {
346 message.set("Other evaluation");
347 Equal::new(value, expected.value + 1)
348 });
349 }
350}