C++Spec 1.0.0
BDD testing for C++
Loading...
Searching...
No Matches
class_description.hpp
Go to the documentation of this file.
1
2#pragma once
3#include <source_location>
4#include <string>
5
6#include "description.hpp"
7
8namespace CppSpec {
9
21template <class T>
22class ClassDescription : public Description {
23 using Block = std::function<void(ClassDescription<T>&)>;
24
25 Block block;
26 std::string type;
27
28 public:
29 T subject; // subject field public for usage in `expect([self.]subject)`
30
31 // Constructor
32 // if there's no explicit subject given, then use
33 // the default constructor of the given type as the implicit subject.
34 ClassDescription(Block block, std::source_location location = std::source_location::current())
35 : Description(location, Pretty::to_word(subject)),
36 block(block),
37 type(" : " + Util::demangle(typeid(T).name())),
38 subject(T()) {}
39
40 ClassDescription(const char* description,
41 Block block,
42 std::source_location location = std::source_location::current())
43 : Description(location, description), block(block), subject(T()) {}
44
45 ClassDescription(const char* description,
46 T& subject,
47 Block block,
48 std::source_location location = std::source_location::current())
49 : Description(location, description), block(block), subject(subject) {}
50
51 template <Util::not_c_string U>
52 ClassDescription(U& subject, Block block, std::source_location location = std::source_location::current())
53 : Description(location, Pretty::to_word(subject)),
54 block(block),
55 type(" : " + Util::demangle(typeid(T).name())),
56 subject(subject) {}
57
58 ClassDescription(const char* description,
59 T&& subject,
60 Block block,
61 std::source_location location = std::source_location::current())
62 : Description(location, description), block(block), subject(std::move(subject)) {}
63
64 template <Util::not_c_string U>
65 ClassDescription(U&& subject, Block block, std::source_location location = std::source_location::current())
66 : Description(location, Pretty::to_word(subject)),
67 block(block),
68 type(" : " + Util::demangle(typeid(T).name())),
69 subject(std::forward<U>(subject)) {}
70
71 template <typename U>
72 ClassDescription(std::initializer_list<U> init_list,
73 Block block,
74 std::source_location location = std::source_location::current())
75 : Description(location, Pretty::to_word(subject)),
76 block(block),
77 type(" : " + Util::demangle(typeid(T).name())),
78 subject(T(init_list)) {}
79
80 template <typename U>
81 ClassDescription(const char* description,
82 std::initializer_list<U> init_list,
83 Block block,
84 std::source_location location = std::source_location::current())
85 : Description(location, description), block(block), subject(T(init_list)) {}
86
87 ItCD<T>& it(const char* name,
88 std::function<void(ItCD<T>&)> block,
89 std::source_location location = std::source_location::current());
90 ItCD<T>& it(std::function<void(ItCD<T>&)> block, std::source_location location = std::source_location::current());
91
92 template <class U = std::nullptr_t, class B>
93 ClassDescription<T>& context(const char* description,
94 B block,
95 std::source_location location = std::source_location::current());
96
97 template <class U, class B>
98 ClassDescription<U>& context(const char* description,
99 U& subject,
100 B block,
101 std::source_location location = std::source_location::current());
102
103 template <class U, class B>
104 ClassDescription<U>& context(U& subject, B block, std::source_location location = std::source_location::current()) {
105 return this->context("", subject, block, location);
106 }
107
108 template <class U, class B>
109 ClassDescription<U>& context(const char* description,
110 U&& subject,
111 B block,
112 std::source_location location = std::source_location::current());
113
114 template <class U, class B>
115 ClassDescription<U>& context(U&& subject, B block, std::source_location location = std::source_location::current()) {
116 return this->context("", std::forward<U>(subject), block, location);
117 }
118 void run() override;
119
120 [[nodiscard]] std::string get_subject_type() const noexcept override { return type; }
121};
122
123template <Util::not_c_string U>
124ClassDescription(U&, std::function<void(ClassDescription<U>&)>, std::source_location) -> ClassDescription<U>;
125
126template <Util::not_c_string U>
127ClassDescription(U&&, std::function<void(ClassDescription<U>&)>, std::source_location) -> ClassDescription<U>;
128
129template <class T>
130using ClassContext = ClassDescription<T>;
131
132template <class T>
133template <class U, class B>
134ClassContext<U>& ClassDescription<T>::context(const char* description,
135 U& subject,
136 B block,
137 std::source_location location) {
138 auto* context = this->make_child<ClassContext<U>>(description, subject, block, location);
139 context->ClassContext<U>::before_eaches = this->before_eaches;
140 context->ClassContext<U>::after_eaches = this->after_eaches;
141 context->timed_run();
142 return *context;
143}
144
145template <class T>
146template <class U, class B>
147ClassContext<U>& ClassDescription<T>::context(const char* description,
148 U&& subject,
149 B block,
150 std::source_location location) {
151 auto* context = this->make_child<ClassContext<U>>(description, std::forward<U>(subject), block, location);
152 context->ClassContext<U>::before_eaches = this->before_eaches;
153 context->ClassContext<U>::after_eaches = this->after_eaches;
154 context->timed_run();
155 return *context;
156}
157
158template <class T>
159template <class U, class B>
160ClassContext<T>& ClassDescription<T>::context(const char* description, B block, std::source_location location) {
161 auto* context = this->make_child<ClassContext<T>>(description, this->subject, block, location);
162 context->before_eaches = this->before_eaches;
163 context->after_eaches = this->after_eaches;
164 context->timed_run();
165 return *context;
166}
167
168template <Util::not_c_string T, class B>
169ClassContext<T>& Description::context(T& subject, B block, std::source_location location) {
170 auto* context = this->make_child<ClassContext<T>>(subject, block, location);
171 context->before_eaches = this->before_eaches;
172 context->after_eaches = this->after_eaches;
173 context->timed_run();
174 return *context;
175}
176
177template <class T, class B>
178ClassContext<T>& Description::context(const char* description, T& subject, B block, std::source_location location) {
179 auto* context = this->make_child<ClassContext<T>>(description, subject, block, location);
180 context->before_eaches = this->before_eaches;
181 context->after_eaches = this->after_eaches;
182 context->timed_run();
183 return *context;
184}
185
186template <Util::not_c_string T, class B>
187ClassContext<T>& Description::context(T&& subject, B block, std::source_location location) {
188 auto* context = this->make_child<ClassContext<T>>(std::forward<T>(subject), block, location);
189 context->before_eaches = this->before_eaches;
190 context->after_eaches = this->after_eaches;
191 context->timed_run();
192 return *context;
193}
194
195template <class T, class B>
196ClassContext<T>& Description::context(const char* description, T&& subject, B block, std::source_location location) {
197 auto* context = this->make_child<ClassContext<T>>(description, std::forward<T>(subject), block, location);
198 context->before_eaches = this->before_eaches;
199 context->after_eaches = this->after_eaches;
200 context->timed_run();
201 return *context;
202}
203
204template <class T, typename U>
205ClassContext<T>& Description::context(std::initializer_list<U> init_list,
206 std::function<void(ClassDescription<T>&)> block,
207 std::source_location location) {
208 auto* context = this->make_child<ClassContext<T>>(T(init_list), block, location);
209 context->before_eaches = this->before_eaches;
210 context->after_eaches = this->after_eaches;
211 context->timed_run();
212 return *context;
213}
214
236template <class T>
237ItCD<T>& ClassDescription<T>::it(const char* name, std::function<void(ItCD<T>&)> block, std::source_location location) {
238 auto* it = this->make_child<ItCD<T>>(location, this->subject, name, block);
239 it->timed_run();
240 exec_after_eaches();
241 exec_before_eaches();
242 return *it;
243}
244
266template <class T>
267ItCD<T>& ClassDescription<T>::it(std::function<void(ItCD<T>&)> block, std::source_location location) {
268 auto* it = this->make_child<ItCD<T>>(location, this->subject, block);
269 it->timed_run();
270 exec_after_eaches();
271 exec_before_eaches();
272 return *it;
273}
274
275template <class T>
276void ClassDescription<T>::run() {
277 this->block(*this);
278 for (const auto& a : after_alls) {
279 a();
280 }
281}
282
283template <class T>
284void ItCD<T>::run() {
285 this->block(*this);
286 auto* cd = this->get_parent_as<ClassDescription<T>>();
287 cd->reset_lets();
288}
289
290} // namespace CppSpec
A Description with a defined subject.
Definition class_description.hpp:22
ItCD< T > & it(const char *name, std::function< void(ItCD< T > &)> block, std::source_location location=std::source_location::current())
Definition class_description.hpp:237
An it embedded in a ClassDescription.
Definition it.hpp:89
Defines the Description class and associated functions.
static std::string to_word(const T &item)
Formats an object as a string when operator<< is available.
Definition pretty_matchers.hpp:122
std::string demangle(const char *name)
Definition util.hpp:38