9
9
#include < string>
10
10
#include < deque>
11
11
#include < queue>
12
+ #include < forward_list>
12
13
#include " it.hpp"
13
14
#include " class_description.hpp"
14
15
@@ -18,18 +19,28 @@ template <typename T>
18
19
class ClassDescription ; // forward-declaration for ClassDescription
19
20
20
21
class Description : public Runnable {
22
+ using VoidBlock = std::function<void ()>;
23
+
21
24
public:
22
25
using Block = std::function<void (Description &)>;
23
- using VoidBlock = std::function<void ()>;
26
+
27
+ const bool has_subject = false ;
28
+ std::forward_list<LetBase *> lets;
29
+ std::deque<VoidBlock> after_alls;
30
+ std::deque<VoidBlock> before_eaches;
31
+ std::deque<VoidBlock> after_eaches;
24
32
25
33
private:
26
34
Block block;
27
35
28
36
protected:
29
37
std::string description = " " ;
30
38
31
- Description () {}
32
-
39
+ // These two constructors are the most basic ones,
40
+ // used to create Descriptions with only their description
41
+ // field initialized. They should only be used by subclasses
42
+ // of Description.
43
+ Description () = default ;
33
44
explicit Description (std::string description) noexcept
34
45
: description(description) {}
35
46
@@ -42,22 +53,21 @@ class Description : public Runnable {
42
53
void exec_after_eaches ();
43
54
44
55
public:
45
- // Constructor
56
+ // Copy constructor
57
+ Description (const Description ©) = default;
58
+
59
+ // Primary constructor. Entry of all specs.
46
60
Description (std::string description, Block block) noexcept
47
61
: block(block),
48
62
description(description) {}
49
63
50
- const bool has_subject = false ;
51
- std::unordered_set<LetBase *> lets;
52
- std::deque<VoidBlock> after_alls;
53
- std::deque<VoidBlock> before_eaches;
54
- std::deque<VoidBlock> after_eaches;
64
+ /* ******** Specify/It *********/
55
65
56
- // Specify/It functions
57
66
Result it (std::string description, ItD::Block body);
58
67
Result it (ItD::Block body);
59
68
60
- // Context functions
69
+ /* ******** Context ***********/
70
+
61
71
Result context (std::string name, Block body);
62
72
63
73
template <class T >
@@ -71,34 +81,34 @@ class Description : public Runnable {
71
81
Result context (std::initializer_list<U> init_list,
72
82
std::function<void (ClassDescription<T> &)> block);
73
83
84
+ /* ******** Each/All *********/
85
+
74
86
void before_each (VoidBlock block);
75
87
void before_all (VoidBlock block);
76
88
void after_each (VoidBlock block);
77
89
void after_all (VoidBlock block);
78
90
91
+ /* ******** Let *********/
92
+
79
93
template <typename T>
80
94
auto let (T body) -> Let<decltype(body())>;
81
95
void reset_lets () noexcept ;
82
96
83
- Result run (Formatters::BaseFormatter &printer) override ;
97
+ /* ******** Standard getters ******** */
84
98
85
- virtual std::string get_description () noexcept { return description; }
86
- virtual const std::string get_description () const noexcept {
87
- return description;
88
- }
99
+ virtual std::string get_description () const noexcept { return description; }
100
+ virtual std::string get_subject_type () const noexcept { return " " ; }
101
+
102
+ /* ******** Run ******** */
89
103
90
- virtual std::string get_subject_type () noexcept { return " " ; }
91
- virtual const std::string get_subject_type () const noexcept { return " " ; }
104
+ Result run (Formatters::BaseFormatter &printer) override ;
92
105
};
93
106
94
107
using Context = Description;
95
108
96
- inline Result Description::context (std::string description, Block body) {
97
- Context context (*this , description, body);
98
- context.before_eaches = this ->before_eaches ;
99
- context.after_eaches = this ->after_eaches ;
100
- return context.run (this ->get_formatter ());
101
- }
109
+ /* >>>>>>>>>>>>>>>>>>>> Description <<<<<<<<<<<<<<<<<<<<<<<<<*/
110
+
111
+ /* ========= Description::it =========*/
102
112
103
113
inline Result Description::it (std::string description, ItD::Block block) {
104
114
ItD it (*this , description, block);
@@ -116,6 +126,17 @@ inline Result Description::it(ItD::Block block) {
116
126
return result;
117
127
}
118
128
129
+ /* ========= Description::context =========*/
130
+
131
+ inline Result Description::context (std::string description, Block body) {
132
+ Context context (*this , description, body);
133
+ context.before_eaches = this ->before_eaches ;
134
+ context.after_eaches = this ->after_eaches ;
135
+ return context.run (this ->get_formatter ());
136
+ }
137
+
138
+ /* ========= Description:: each/alls =========*/
139
+
119
140
inline void Description::before_each (VoidBlock b) {
120
141
before_eaches.push_back (b);
121
142
@@ -134,14 +155,18 @@ inline void Description::after_each(VoidBlock b) { after_eaches.push_back(b); }
134
155
135
156
inline void Description::after_all (VoidBlock b) { after_alls.push_back (b); }
136
157
158
+ /* ----------- private -------------*/
159
+
137
160
inline void Description::exec_before_eaches () {
138
- for (VoidBlock b : before_eaches) b ();
161
+ for (VoidBlock & b : before_eaches) b ();
139
162
}
140
163
141
164
inline void Description::exec_after_eaches () {
142
- for (VoidBlock b : after_eaches) b ();
165
+ for (VoidBlock & b : after_eaches) b ();
143
166
}
144
167
168
+ /* ========= Description::let =========*/
169
+
145
170
/* *
146
171
* @brief Object generator for Let.
147
172
*
@@ -150,26 +175,48 @@ inline void Description::exec_after_eaches() {
150
175
* @return a new Let object
151
176
*/
152
177
template <typename T>
153
- inline auto Description::let (T block) -> Let<decltype(block())> {
154
- Let<decltype (block ())> let (block);
155
- lets.insert (&let);
156
- return let;
157
- }
158
-
159
- inline Result Description::run (Formatters::BaseFormatter &printer) {
160
- if (not this ->has_formatter ()) this ->set_printer (printer);
161
- printer.format (*this );
162
- block (*this );
163
- for (auto a : after_alls) a ();
164
- if (this ->get_parent () == nullptr ) printer.flush ();
165
- return this ->get_status () ? Result::success () : Result::failure ();
178
+ auto Description::let (T block) -> Let<decltype(block())> {
179
+ // In reality, this gets inlined due to the fact that it's
180
+ // a templated function. Otherwise we wouldn't be able to
181
+ // add the address of the Let, return the Let by value,
182
+ // and still be able to do a valid deference of the Let
183
+ // pointer later on when we needed to reset the Let.
184
+
185
+ Let<decltype (block ())> let (block); // Create a Let
186
+ lets.push_front (&let); // Add it to our list
187
+ return let; // Hand it object off
166
188
}
167
189
190
+ // TODO: Should this be protected?
168
191
inline void Description::reset_lets () noexcept {
192
+ // For every let in our list, reset it.
169
193
for (auto &let : lets) let->reset ();
170
- if (this ->has_parent ()) this ->get_parent_as <Description *>()->reset_lets ();
194
+
195
+ // Recursively reset all the lets in the family tree
196
+ if (this ->has_parent ()) {
197
+ this ->get_parent_as <Description *>()->reset_lets ();
198
+ }
171
199
}
172
200
201
+ /* ========= Description::run =========*/
202
+
203
+ inline Result Description::run (Formatters::BaseFormatter &formatter) {
204
+ // If there isn't already a formatter in the family tree, set ours.
205
+ if (!this ->has_formatter ()) this ->set_formatter (formatter);
206
+
207
+ formatter.format (*this ); // Format our description in some way
208
+ block (*this ); // Run the block
209
+ for (VoidBlock &a : after_alls) a (); // Run all our after_alls
210
+ if (!this ->has_parent ()) formatter.flush (); // Inform the printer we're done
211
+
212
+ // Return success or failure
213
+ return this ->get_status () ? Result::success () : Result::failure ();
214
+ }
215
+
216
+ /* >>>>>>>>>>>>>>>>>>>> ItD <<<<<<<<<<<<<<<<<<<<<<<<<*/
217
+
218
+ /* ========= ItD::run =========*/
219
+
173
220
inline Result ItD::run (Formatters::BaseFormatter &printer) {
174
221
block (*this );
175
222
printer.format (*this );
0 commit comments