1mod configuration;
4mod observer;
5
6pub use runner::configuration::*;
7pub use runner::observer::*;
8
9use std::borrow::Borrow;
10use std::cell::Cell;
11use std::ops::{Deref, DerefMut};
12use std::panic;
13#[cfg(not(test))]
14use std::process;
15use std::sync::{Arc, Mutex};
16
17use time::Instant;
18
19use rayon::prelude::*;
20
21use block::Block;
22use block::Context;
23use block::Example;
24use block::Suite;
25use report::ContextReport;
26use report::ExampleReport;
27use report::SuiteReport;
28use report::{BlockReport, Report};
29use visitor::TestSuiteVisitor;
30
31pub struct Runner {
33 pub configuration: configuration::Configuration,
34 observers: Vec<Arc<dyn RunnerObserver>>,
35 should_exit: Mutex<Cell<bool>>,
36}
37
38impl Runner {
39 pub fn new(configuration: Configuration, observers: Vec<Arc<dyn RunnerObserver>>) -> Runner {
40 Runner {
41 configuration,
42 observers,
43 should_exit: Mutex::new(Cell::new(false)),
44 }
45 }
46}
47
48impl Runner {
49 pub fn run<T>(&self, suite: &Suite<T>) -> SuiteReport
50 where
51 T: Clone + Send + Sync + ::std::fmt::Debug,
52 {
53 let mut environment = suite.environment.clone();
54 self.prepare_before_run();
55 let report = self.visit(suite, &mut environment);
56 self.clean_after_run();
57 if let Ok(mut mutex_guard) = self.should_exit.lock() {
58 *mutex_guard.deref_mut().get_mut() |= report.is_failure();
59 }
60 report
61 }
62
63 fn broadcast<F>(&self, mut handler: F)
64 where
65 F: FnMut(&dyn RunnerObserver),
66 {
67 for observer in &self.observers {
68 handler(observer.borrow());
69 }
70 }
71
72 fn wrap_all<T, U, F>(&self, context: &Context<T>, environment: &mut T, wrapped_block: F) -> U
73 where
74 F: Fn(&mut T) -> U,
75 {
76 for before_function in context.before_all.iter() {
77 before_function(environment);
78 }
79 let result = wrapped_block(environment);
80 for after_function in context.after_all.iter() {
81 after_function(environment);
82 }
83 result
84 }
85
86 fn wrap_each<T, U, F>(&self, context: &Context<T>, environment: &mut T, wrapped_block: F) -> U
87 where
88 F: Fn(&mut T) -> U,
89 {
90 for before_function in context.before_each.iter() {
91 before_function(environment);
92 }
93 let result = wrapped_block(environment);
94 for after_function in context.after_each.iter() {
95 after_function(environment);
96 }
97 result
98 }
99
100 fn evaluate_blocks_parallel<T>(&self, context: &Context<T>, environment: &T) -> Vec<BlockReport>
101 where
102 T: Clone + Send + Sync + ::std::fmt::Debug,
103 {
104 context
105 .blocks
106 .par_iter()
107 .map(|block| self.evaluate_block(block, context, environment))
108 .collect()
109 }
110
111 fn evaluate_blocks_serial<T>(&self, context: &Context<T>, environment: &T) -> Vec<BlockReport>
112 where
113 T: Clone + Send + Sync + ::std::fmt::Debug,
114 {
115 context
116 .blocks
117 .iter()
118 .map(|block| self.evaluate_block(block, context, environment))
119 .collect()
120 }
121
122 fn evaluate_block<T>(
123 &self,
124 block: &Block<T>,
125 context: &Context<T>,
126 environment: &T,
127 ) -> BlockReport
128 where
129 T: Clone + Send + Sync + ::std::fmt::Debug,
130 {
131 let mut environment = environment.clone();
132 self.wrap_each(context, &mut environment, |environment| {
133 self.visit(block, environment)
134 })
135 }
136
137 fn prepare_before_run(&self) {
138 panic::set_hook(Box::new(|_panic_info| {
139 }));
141 }
142
143 fn clean_after_run(&self) {
144 let _ = panic::take_hook();
146 }
147}
148
149#[cfg(test)]
150impl Default for Runner {
151 fn default() -> Self {
153 Runner::new(Configuration::default(), vec![])
154 }
155}
156
157impl Drop for Runner {
158 fn drop(&mut self) {
159 let should_exit = if let Ok(mutex_guard) = self.should_exit.lock() {
160 mutex_guard.deref().get()
161 } else {
162 false
163 };
164
165 if self.configuration.exit_on_failure && should_exit {
166 #[cfg(not(test))]
174 process::exit(101);
175 #[cfg(test)]
176 panic!("test suite failed !")
177 }
178 }
179}
180
181impl<T> TestSuiteVisitor<Suite<T>> for Runner
182where
183 T: Clone + Send + Sync + ::std::fmt::Debug,
184{
185 type Environment = T;
186 type Output = SuiteReport;
187
188 fn visit(&self, suite: &Suite<T>, environment: &mut Self::Environment) -> Self::Output {
189 self.broadcast(|handler| handler.enter_suite(self, &suite.header));
190 let report = SuiteReport::new(
191 suite.header.clone(),
192 self.visit(&suite.context, environment),
193 );
194 self.broadcast(|handler| handler.exit_suite(self, &suite.header, &report));
195 report
196 }
197}
198
199impl<T> TestSuiteVisitor<Block<T>> for Runner
200where
201 T: Clone + Send + Sync + ::std::fmt::Debug,
202{
203 type Environment = T;
204 type Output = BlockReport;
205
206 fn visit(&self, member: &Block<T>, environment: &mut Self::Environment) -> Self::Output {
207 match member {
208 Block::Example(ref example) => {
209 let header = example.header.clone();
210 let report = self.visit(example, environment);
211 BlockReport::Example(header, report)
212 }
213 Block::Context(ref context) => {
214 let header = context.header.clone();
215 let report = self.visit(context, &mut environment.clone());
216 BlockReport::Context(header, report)
217 }
218 }
219 }
220}
221
222impl<T> TestSuiteVisitor<Context<T>> for Runner
223where
224 T: Clone + Send + Sync + ::std::fmt::Debug,
225{
226 type Environment = T;
227 type Output = ContextReport;
228
229 fn visit(&self, context: &Context<T>, environment: &mut Self::Environment) -> Self::Output {
230 if let Some(ref header) = context.header {
231 self.broadcast(|handler| handler.enter_context(self, &header));
232 }
233 let start_time = Instant::now();
234 let reports: Vec<_> = self.wrap_all(context, environment, |environment| {
235 if self.configuration.parallel {
236 self.evaluate_blocks_parallel(context, environment)
237 } else {
238 self.evaluate_blocks_serial(context, environment)
239 }
240 });
241 let end_time = Instant::now();
242 let elapsed_time = end_time - start_time;
243 let report = ContextReport::new(reports, elapsed_time);
244 if let Some(ref header) = context.header {
245 self.broadcast(|handler| handler.exit_context(self, &header, &report));
246 }
247 report
248 }
249}
250
251impl<T> TestSuiteVisitor<Example<T>> for Runner
252where
253 T: Clone + Send + Sync + ::std::fmt::Debug,
254{
255 type Environment = T;
256 type Output = ExampleReport;
257
258 fn visit(&self, example: &Example<T>, environment: &mut Self::Environment) -> Self::Output {
259 self.broadcast(|handler| handler.enter_example(self, &example.header));
260 let start_time = Instant::now();
261 let result = (example.function)(environment);
262 let end_time = Instant::now();
263 let elapsed_time = end_time - start_time;
264 let report = ExampleReport::new(result, elapsed_time);
265 self.broadcast(|handler| handler.exit_example(self, &example.header, &report));
266 report
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 mod runner {
275 use super::*;
276
277 #[test]
278 fn it_can_be_instanciated() {
279 let _ = Runner::new(Configuration::default(), vec![]);
281 }
284
285 mod broadcast {
286 use super::*;
287
288 use header::*;
289 use std::sync::atomic::*;
290
291 impl RunnerObserver for () {}
293
294 #[test]
295 fn it_calls_the_closure() {
296 let spy = Arc::new(());
298 let runner = Runner::new(Configuration::default(), vec![spy]);
299 let has_been_called = AtomicBool::new(false);
300 runner.broadcast(|_| has_been_called.store(true, Ordering::SeqCst));
302 assert_eq!(true, has_been_called.load(Ordering::SeqCst));
304 }
305
306 #[test]
307 fn it_calls_it_once_per_observer() {
308 let spy1 = Arc::new(());
310 let spy2 = Arc::new(());
311 let runner = Runner::new(Configuration::default(), vec![spy1, spy2]);
312 let call_times = AtomicUsize::new(0);
313 runner.broadcast(|_| {
315 call_times.fetch_add(1, Ordering::SeqCst);
316 });
317 assert_eq!(2, call_times.load(Ordering::SeqCst))
319 }
320
321 struct ObserverStub {
322 events: Mutex<Vec<(&'static str, SuiteHeader)>>,
323 }
324 impl ObserverStub {
325 fn new() -> Self {
326 ObserverStub {
327 events: Mutex::new(vec![]),
328 }
329 }
330 }
331
332 impl RunnerObserver for ObserverStub {
334 fn enter_suite(&self, _runner: &Runner, header: &SuiteHeader) {
335 let mut vec = self.events.lock().unwrap();
336 (*vec).push(("enter_suite", header.clone()));
337 }
338 }
339
340 #[test]
341 fn it_gives_the_observer_as_callback_argument() {
342 let spy1 = Arc::new(ObserverStub::new());
344 let expected = SuiteHeader::new(SuiteLabel::Describe, "hello");
345 let runner = Runner::new(Configuration::default(), vec![spy1.clone()]);
346 runner.broadcast(|observer| observer.enter_suite(&runner, &expected.clone()));
348 let lock = spy1.events.lock().expect("no dangling threads");
350 let res = (*lock).get(0).expect("to have been called once");
351 assert_eq!(&("enter_suite", expected), res);
352 }
353 }
354
355 mod wrap_each {
356 use super::*;
357
358 use std::sync::atomic::*;
359
360 #[test]
361 fn it_can_be_called() {
362 let runner = Runner::default();
364 runner.wrap_each(&Context::default(), &mut (), |_| {})
366 }
368
369 #[test]
370 fn it_calls_the_closure() {
371 let runner = Runner::default();
373 let has_been_called = AtomicBool::new(false);
374 runner.wrap_each(&Context::default(), &mut (), |_| {
376 has_been_called.store(true, Ordering::SeqCst)
377 });
378 assert_eq!(true, has_been_called.load(Ordering::SeqCst));
380 }
381
382 #[test]
383 fn it_calls_the_before_each_callbacks() {
384 let runner = Runner::default();
386 let has_been_called = Arc::new(AtomicBool::new(false));
387 let closure_bool_handler = has_been_called.clone();
388 let mut context = Context::default();
389 context.before_each(move |_| closure_bool_handler.store(true, Ordering::SeqCst));
391 runner.wrap_each(&context, &mut (), |_| ());
392 assert_eq!(true, has_been_called.load(Ordering::SeqCst));
394 }
395
396 #[test]
397 fn it_calls_the_after_each_callbacks() {
398 let runner = Runner::default();
400 let has_been_called = Arc::new(AtomicBool::new(false));
401 let closure_bool_handler = has_been_called.clone();
402 let mut context = Context::default();
403 context.after_each(move |_| closure_bool_handler.store(true, Ordering::SeqCst));
405 runner.wrap_each(&context, &mut (), |_| ());
406 assert_eq!(true, has_been_called.load(Ordering::SeqCst));
408 }
409
410 #[test]
411 fn it_calls_all_before_each_callbacks() {
412 let runner = Runner::default();
414 let call_counter = Arc::new(AtomicUsize::new(0));
415 let closure_counter_handler1 = call_counter.clone();
416 let closure_counter_handler2 = call_counter.clone();
417 let mut context = Context::default();
418 context.before_each(move |_| {
420 closure_counter_handler1.fetch_add(1, Ordering::SeqCst);
421 });
422 context.before_each(move |_| {
423 closure_counter_handler2.fetch_add(1, Ordering::SeqCst);
424 });
425 runner.wrap_each(&context, &mut (), |_| ());
426 assert_eq!(2, call_counter.load(Ordering::SeqCst));
428 }
429
430 #[test]
431 fn it_calls_all_after_each_callbacks() {
432 let runner = Runner::default();
434 let call_counter = Arc::new(AtomicUsize::new(0));
435 let closure_counter_handler1 = call_counter.clone();
436 let closure_counter_handler2 = call_counter.clone();
437 let mut context = Context::default();
438 context.after_each(move |_| {
440 closure_counter_handler1.fetch_add(1, Ordering::SeqCst);
441 });
442 context.after_each(move |_| {
443 closure_counter_handler2.fetch_add(1, Ordering::SeqCst);
444 });
445 runner.wrap_each(&context, &mut (), |_| ());
446 assert_eq!(2, call_counter.load(Ordering::SeqCst));
448 }
449
450 #[test]
451 fn it_calls_before_each_hook_before_the_main_closure() {
452 let runner = Runner::default();
454 let last_caller_id = Arc::new(AtomicUsize::new(0));
455 let last_caller_handler1 = last_caller_id.clone();
456 let last_caller_handler2 = last_caller_id.clone();
457 let mut context = Context::default();
458 context.before_each(move |_| {
460 last_caller_handler1.store(1, Ordering::SeqCst);
461 });
462 runner.wrap_each(&context, &mut (), |_| {
463 last_caller_handler2.store(2, Ordering::SeqCst);
464 });
465 assert_eq!(2, last_caller_id.load(Ordering::SeqCst));
467 }
468
469 #[test]
470 fn it_calls_after_each_hook_after_the_main_closure() {
471 let runner = Runner::default();
473 let last_caller_id = Arc::new(AtomicUsize::new(0));
474 let last_caller_handler1 = last_caller_id.clone();
475 let last_caller_handler2 = last_caller_id.clone();
476 let mut context = Context::default();
477 context.after_each(move |_| {
479 last_caller_handler1.store(1, Ordering::SeqCst);
480 });
481 runner.wrap_each(&context, &mut (), |_| {
482 last_caller_handler2.store(2, Ordering::SeqCst);
483 });
484 assert_eq!(1, last_caller_id.load(Ordering::SeqCst));
486 }
487 }
488
489 mod wrap_all {
490 use super::*;
491
492 use std::sync::atomic::*;
493
494 #[test]
495 fn it_can_be_called() {
496 let runner = Runner::default();
498 runner.wrap_all(&Context::default(), &mut (), |_| {})
500 }
502
503 #[test]
504 fn it_calls_the_closure() {
505 let runner = Runner::default();
507 let has_been_called = AtomicBool::new(false);
508 runner.wrap_all(&Context::default(), &mut (), |_| {
510 has_been_called.store(true, Ordering::SeqCst)
511 });
512 assert_eq!(true, has_been_called.load(Ordering::SeqCst));
514 }
515
516 #[test]
517 fn it_calls_the_before_all_callbacks() {
518 let runner = Runner::default();
520 let has_been_called = Arc::new(AtomicBool::new(false));
521 let closure_bool_handler = has_been_called.clone();
522 let mut context = Context::default();
523 context.before_all(move |_| closure_bool_handler.store(true, Ordering::SeqCst));
525 runner.wrap_all(&context, &mut (), |_| ());
526 assert_eq!(true, has_been_called.load(Ordering::SeqCst));
528 }
529
530 #[test]
531 fn it_calls_the_after_all_callbacks() {
532 let runner = Runner::default();
534 let has_been_called = Arc::new(AtomicBool::new(false));
535 let closure_bool_handler = has_been_called.clone();
536 let mut context = Context::default();
537 context.after_all(move |_| closure_bool_handler.store(true, Ordering::SeqCst));
539 runner.wrap_all(&context, &mut (), |_| ());
540 assert_eq!(true, has_been_called.load(Ordering::SeqCst));
542 }
543
544 #[test]
545 fn it_calls_all_before_all_callbacks() {
546 let runner = Runner::default();
548 let call_counter = Arc::new(AtomicUsize::new(0));
549 let closure_counter_handler1 = call_counter.clone();
550 let closure_counter_handler2 = call_counter.clone();
551 let mut context = Context::default();
552 context.before_all(move |_| {
554 closure_counter_handler1.fetch_add(1, Ordering::SeqCst);
555 });
556 context.before_all(move |_| {
557 closure_counter_handler2.fetch_add(1, Ordering::SeqCst);
558 });
559 runner.wrap_all(&context, &mut (), |_| ());
560 assert_eq!(2, call_counter.load(Ordering::SeqCst));
562 }
563
564 #[test]
565 fn it_calls_all_after_all_callbacks() {
566 let runner = Runner::default();
568 let call_counter = Arc::new(AtomicUsize::new(0));
569 let closure_counter_handler1 = call_counter.clone();
570 let closure_counter_handler2 = call_counter.clone();
571 let mut context = Context::default();
572 context.after_all(move |_| {
574 closure_counter_handler1.fetch_add(1, Ordering::SeqCst);
575 });
576 context.after_all(move |_| {
577 closure_counter_handler2.fetch_add(1, Ordering::SeqCst);
578 });
579 runner.wrap_all(&context, &mut (), |_| ());
580 assert_eq!(2, call_counter.load(Ordering::SeqCst));
582 }
583
584 #[test]
585 fn it_calls_before_all_hook_before_the_main_closure() {
586 let runner = Runner::default();
588 let last_caller_id = Arc::new(AtomicUsize::new(0));
589 let last_caller_handler1 = last_caller_id.clone();
590 let last_caller_handler2 = last_caller_id.clone();
591 let mut context = Context::default();
592 context.before_all(move |_| {
594 last_caller_handler1.store(1, Ordering::SeqCst);
595 });
596 runner.wrap_all(&context, &mut (), |_| {
597 last_caller_handler2.store(2, Ordering::SeqCst);
598 });
599 assert_eq!(2, last_caller_id.load(Ordering::SeqCst));
601 }
602
603 #[test]
604 fn it_calls_after_all_hook_after_the_main_closure() {
605 let runner = Runner::default();
607 let last_caller_id = Arc::new(AtomicUsize::new(0));
608 let last_caller_handler1 = last_caller_id.clone();
609 let last_caller_handler2 = last_caller_id.clone();
610 let mut context = Context::default();
611 context.after_all(move |_| {
613 last_caller_handler1.store(1, Ordering::SeqCst);
614 });
615 runner.wrap_all(&context, &mut (), |_| {
616 last_caller_handler2.store(2, Ordering::SeqCst);
617 });
618 assert_eq!(1, last_caller_id.load(Ordering::SeqCst));
620 }
621 }
622 }
623
624 mod impl_drop_for_runner {
625 use super::*;
626
627 #[test]
628 #[should_panic]
629 fn it_should_abort() {
630 let config = ConfigurationBuilder::default()
632 .exit_on_failure(true)
633 .build()
634 .unwrap();
635 {
637 let runner = Runner::new(config, vec![]);
638 (*runner.should_exit.lock().unwrap()).set(true);
639 }
640 }
643 }
644
645 mod impl_visitor_example_for_runner {
646 use super::*;
647
648 use header::*;
649 use report::*;
650 use std::sync::atomic::*;
651
652 #[derive(Default, Debug, Clone)]
653 struct SpyObserver {
654 enter_example: Arc<AtomicBool>,
655 exit_example: Arc<AtomicBool>,
656 }
657 impl RunnerObserver for SpyObserver {
658 fn enter_example(&self, _runner: &Runner, _header: &ExampleHeader) {
659 self.enter_example.store(true, Ordering::SeqCst)
660 }
661
662 fn exit_example(
663 &self,
664 _runner: &Runner,
665 _header: &ExampleHeader,
666 _report: &ExampleReport,
667 ) {
668 self.exit_example.store(true, Ordering::SeqCst)
669 }
670 }
671
672 #[test]
673 fn it_can_be_called() {
674 let runner = Runner::default();
676 let example = Example::fixture_success();
677 runner.visit(&example, &mut ());
680 }
681
682 #[test]
683 fn it_calls_observer_hooks() {
684 let spy = Arc::new(SpyObserver::default());
686 let runner = Runner::new(Configuration::default(), vec![spy.clone()]);
687 let example = Example::fixture_success();
688 runner.visit(&example, &mut ());
690 assert_eq!(true, spy.enter_example.load(Ordering::SeqCst));
692 assert_eq!(true, spy.exit_example.load(Ordering::SeqCst))
693 }
694
695 #[test]
696 fn it_gives_an_env_to_the_example() {
697 let runner = Runner::default();
699 let mut environment = Arc::new(AtomicBool::new(false));
700 let example = Example::new(ExampleHeader::default(), |env: &Arc<AtomicBool>| {
702 env.store(true, Ordering::SeqCst);
703 ExampleResult::Success
704 });
705 runner.visit(&example, &mut environment);
706 assert_eq!(true, environment.load(Ordering::SeqCst));
708 }
709 }
710
711 mod impl_visitor_block_for_runner {
712 use super::*;
713
714 #[test]
715 fn it_can_be_called() {
716 let runner = Runner::default();
718 let block = Block::Example(Example::fixture_success());
719 runner.visit(&block, &mut ());
722 }
723 }
724}