99#include < string>
1010#include < deque>
1111#include < queue>
12+ #include < forward_list>
1213#include " it.hpp"
1314#include " class_description.hpp"
1415
@@ -18,18 +19,28 @@ template <typename T>
1819class ClassDescription ; // forward-declaration for ClassDescription
1920
2021class Description : public Runnable {
22+ using VoidBlock = std::function<void ()>;
23+
2124 public:
2225 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;
2432
2533 private:
2634 Block block;
2735
2836 protected:
2937 std::string description = " " ;
3038
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 ;
3344 explicit Description (std::string description) noexcept
3445 : description(description) {}
3546
@@ -42,22 +53,21 @@ class Description : public Runnable {
4253 void exec_after_eaches ();
4354
4455 public:
45- // Constructor
56+ // Copy constructor
57+ Description (const Description ©) = default;
58+
59+ // Primary constructor. Entry of all specs.
4660 Description (std::string description, Block block) noexcept
4761 : block(block),
4862 description(description) {}
4963
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 *********/
5565
56- // Specify/It functions
5766 Result it (std::string description, ItD::Block body);
5867 Result it (ItD::Block body);
5968
60- // Context functions
69+ /* ******** Context ***********/
70+
6171 Result context (std::string name, Block body);
6272
6373 template <class T >
@@ -71,34 +81,34 @@ class Description : public Runnable {
7181 Result context (std::initializer_list<U> init_list,
7282 std::function<void (ClassDescription<T> &)> block);
7383
84+ /* ******** Each/All *********/
85+
7486 void before_each (VoidBlock block);
7587 void before_all (VoidBlock block);
7688 void after_each (VoidBlock block);
7789 void after_all (VoidBlock block);
7890
91+ /* ******** Let *********/
92+
7993 template <typename T>
8094 auto let (T body) -> Let<decltype(body())>;
8195 void reset_lets () noexcept ;
8296
83- Result run (Formatters::BaseFormatter &printer) override ;
97+ /* ******** Standard getters ******** */
8498
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 ******** */
89103
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 ;
92105};
93106
94107using Context = Description;
95108
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 =========*/
102112
103113inline Result Description::it (std::string description, ItD::Block block) {
104114 ItD it (*this , description, block);
@@ -116,6 +126,17 @@ inline Result Description::it(ItD::Block block) {
116126 return result;
117127}
118128
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+
119140inline void Description::before_each (VoidBlock b) {
120141 before_eaches.push_back (b);
121142
@@ -134,14 +155,18 @@ inline void Description::after_each(VoidBlock b) { after_eaches.push_back(b); }
134155
135156inline void Description::after_all (VoidBlock b) { after_alls.push_back (b); }
136157
158+ /* ----------- private -------------*/
159+
137160inline void Description::exec_before_eaches () {
138- for (VoidBlock b : before_eaches) b ();
161+ for (VoidBlock & b : before_eaches) b ();
139162}
140163
141164inline void Description::exec_after_eaches () {
142- for (VoidBlock b : after_eaches) b ();
165+ for (VoidBlock & b : after_eaches) b ();
143166}
144167
168+ /* ========= Description::let =========*/
169+
145170/* *
146171 * @brief Object generator for Let.
147172 *
@@ -150,26 +175,48 @@ inline void Description::exec_after_eaches() {
150175 * @return a new Let object
151176 */
152177template <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
166188}
167189
190+ // TODO: Should this be protected?
168191inline void Description::reset_lets () noexcept {
192+ // For every let in our list, reset it.
169193 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+ }
171199}
172200
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+
173220inline Result ItD::run (Formatters::BaseFormatter &printer) {
174221 block (*this );
175222 printer.format (*this );
0 commit comments