1#ifndef BANDIT_GRAMMAR_H
2#define BANDIT_GRAMMAR_H
3
4#include <bandit/adapters/adapters.h>
5#include <bandit/reporters/reporters.h>
6#include <bandit/run_policies/run_policy.h>
7
8namespace bandit {
9 inline void describe(const std::string& desc, detail::voidfunc_t func,
10 detail::listener& listener, detail::contextstack_t& context_stack,
11 bool hard_skip = false) {
12 listener.context_starting(desc);
13
14 context_stack.back()->execution_is_starting();
15
16 detail::bandit_context ctxt(desc, hard_skip);
17
18 context_stack.push_back(&ctxt);
19
20 try {
21 func();
22 } catch (const bandit::detail::test_run_error& error) {
23 listener.test_run_error(desc, error);
24 }
25
26 context_stack.pop_back();
27
28 listener.context_ended(desc);
29 }
30
31 inline void describe(const std::string& desc, detail::voidfunc_t func, bool hard_skip = false) {
32 describe(desc, func, detail::registered_listener(), detail::context_stack(), hard_skip);
33 }
34
35 inline void describe_skip(const std::string& desc, detail::voidfunc_t func,
36 detail::listener& listener, detail::contextstack_t& context_stack) {
37 describe(desc, func, listener, context_stack, true);
38 }
39
40 inline void describe_skip(const std::string& desc, detail::voidfunc_t func) {
41 describe_skip(desc, func, detail::registered_listener(),
42 detail::context_stack());
43 }
44
45 inline void xdescribe(const std::string& desc, detail::voidfunc_t func,
46 detail::listener& listener = detail::registered_listener(),
47 detail::contextstack_t& context_stack = detail::context_stack()) {
48 describe_skip(desc, func, listener, context_stack);
49 }
50
51 inline void before_each(detail::voidfunc_t func,
52 detail::contextstack_t& context_stack) {
53 context_stack.back()->register_before_each(func);
54 }
55
56 inline void before_each(detail::voidfunc_t func) {
57 before_each(func, detail::context_stack());
58 }
59
60 inline void after_each(detail::voidfunc_t func,
61 detail::contextstack_t& context_stack) {
62 context_stack.back()->register_after_each(func);
63 }
64
65 inline void after_each(detail::voidfunc_t func) {
66 after_each(func, detail::context_stack());
67 }
68
69 inline void it_skip(const std::string& desc, detail::voidfunc_t, detail::listener& listener) {
70 listener.it_skip(desc);
71 }
72
73 inline void it_skip(const std::string& desc, detail::voidfunc_t func) {
74 it_skip(desc, func, detail::registered_listener());
75 }
76
77 inline void xit(const std::string& desc, detail::voidfunc_t func,
78 detail::listener& listener = detail::registered_listener()) {
79 it_skip(desc, func, listener);
80 }
81
82 inline void it(const std::string& desc, detail::voidfunc_t func, detail::listener& listener,
83 detail::contextstack_t& context_stack,
84 bandit::adapters::assertion_adapter& assertion_adapter,
85 detail::run_policy& run_policy,
86 bool hard_skip = false) {
87 if (hard_skip || !run_policy.should_run(desc, context_stack)) {
88 it_skip(desc, func, listener);
89 return;
90 }
91
92 listener.it_starting(desc);
93
94 context_stack.back()->execution_is_starting();
95
96 auto try_with_adapter = [&](detail::voidfunc_t do_it) {
97 try {
98 assertion_adapter.adapt_exceptions([&] { do_it(); });
99 } catch (const bandit::detail::assertion_exception& ex) {
100 listener.it_failed(desc, ex);
101 run_policy.encountered_failure();
102 } catch (const std::exception& ex) {
103 std::string err = std::string("exception: ") + ex.what();
104 listener.it_failed(desc, bandit::detail::assertion_exception(err));
105 run_policy.encountered_failure();
106 } catch (...) {
107 listener.it_unknown_error(desc);
108 run_policy.encountered_failure();
109 }
110 };
111
112 bool success = false;
113 try_with_adapter([&] {
114 for (auto context : context_stack) {
115 context->run_before_eaches();
116 }
117
118 func();
119 success = true;
120 });
121
122 try_with_adapter([&] {
123 for (auto context : context_stack) {
124 context->run_after_eaches();
125 }
126
127 if (success) {
128 listener.it_succeeded(desc);
129 }
130 });
131 }
132
133 inline void it(const std::string& desc, detail::voidfunc_t func, bool hard_skip = false) {
134 it(desc, func, detail::registered_listener(), detail::context_stack(),
135 detail::registered_adapter(), detail::registered_run_policy(), hard_skip);
136 }
137}
138#endif
139