13#include <collections.h>
23 static constexpr auto META_DATA_KEY_TIMEOUT =
"timeout";
24 static constexpr auto META_DATA_KEY_SKIP =
"skip";
26 std::vector<ISpecGroup*> _currentGroupStack;
27 std::vector<ISpecGroup*> _savedGroupStack;
35 std::vector<std::unique_ptr<SpecTest>> _registeredSpecs;
36 std::vector<std::unique_ptr<SpecSetup>> _registeredsetups;
37 std::vector<std::unique_ptr<SpecTeardown>> _registeredteardowns;
38 std::vector<std::unique_ptr<SpecGroup>> _registeredGroups;
39 std::vector<std::unique_ptr<SpecSetup>> _registeredOneTimesetups;
40 std::vector<std::unique_ptr<SpecTeardown>> _registeredOneTimeteardowns;
42 collections_map<std::string, std::unique_ptr<SpecGroup>> _testTemplateGroups;
49 if (_metaDataForNextComponent.
has(META_DATA_KEY_SKIP)) {
50 auto skip = _metaDataForNextComponent.
get(META_DATA_KEY_SKIP)->
bool_value();
55 if (_metaDataForNextComponent.
has(META_DATA_KEY_TIMEOUT)) {
58 _metaDataForNextComponent.
get(META_DATA_KEY_TIMEOUT)->
int_value();
59 hasCodeBlock->code_block()->set_timeout_ms(timeout);
63 component->
data()->
merge(&_metaDataForNextComponent);
64 component->
tags()->
merge(&_tagsForNextComponent);
65 _metaDataForNextComponent.
clear();
66 _tagsForNextComponent.
clear();
72 auto rootGroup = std::make_unique<SpecGroup>(
nullptr,
"");
73 _registeredGroups.push_back(std::move(rootGroup));
74 _currentGroupStack.push_back(_registeredGroups.back().get());
87 return _currentGroupStack.empty() ? nullptr : _currentGroupStack.back();
91 void pop() { _currentGroupStack.pop_back(); }
94 _currentGroupStack.clear();
97 _currentFileGroup =
nullptr;
98 _currentTopLevelGroup =
nullptr;
103 if (
auto* rootGroup =
root())
push(rootGroup);
107 _savedFileGroup = _currentFileGroup;
108 _savedTopLevelGroup = _currentTopLevelGroup;
109 _savedGroupStack = _currentGroupStack;
113 _currentFileGroup = _savedFileGroup;
114 _currentTopLevelGroup = _savedTopLevelGroup;
115 _currentGroupStack = _savedGroupStack;
119 std::string_view templateName, std::unique_ptr<SpecCodeBlock> codeBlock
121 auto templateGroup = std::make_unique<SpecGroup>(
nullptr, templateName);
122 auto* templateGroupPtr = templateGroup.get();
123 component_defined(templateGroupPtr);
125 auto* currentGroup =
get();
126 set(templateGroupPtr);
127 codeBlock->run(templateGroupPtr, templateGroupPtr,
nullptr,
nullptr);
130 _testTemplateGroups[templateName.data()] = std::move(templateGroup);
134 std::string_view description, std::unique_ptr<SpecCodeBlock> codeBlock,
135 bool removeUnderscores =
false
137 if (
auto* group =
get()) {
138 std::string descriptionText{description};
139 if (removeUnderscores) {
140 std::replace(descriptionText.begin(), descriptionText.end(),
'_',
' ');
141 description = descriptionText;
143 auto specGroup = std::make_unique<SpecGroup>(
get(), descriptionText);
144 auto* specGroupPtr = specGroup.get();
145 component_defined(specGroupPtr);
147 _registeredGroups.push_back(std::move(specGroup));
148 group->add_group(_registeredGroups.back().get());
152 codeBlock->run(specGroupPtr, specGroupPtr,
nullptr,
nullptr);
155 _Log_(
"define_group() called but no group is active!");
160 std::string_view description, std::unique_ptr<SpecCodeBlock> codeBlock,
163 if (
auto* group =
get()) {
164 auto spec = std::make_unique<SpecTest>(
get(), description, std::move(codeBlock));
165 if (skip) spec->mark_skipped(
true);
166 auto* specPtr = spec.get();
167 component_defined(specPtr);
169 _registeredSpecs.push_back(std::move(spec));
170 group->add_test(specPtr);
172 _Log_(
"define_spec() called but no group is active!");
176 void define_setup(std::unique_ptr<SpecCodeBlock> codeBlock,
bool skip =
false) {
177 if (
auto* group =
get()) {
178 auto setup = std::make_unique<SpecSetup>(
get(), std::move(codeBlock));
179 if (skip) setup->mark_skipped(
true);
180 auto* setupPtr = setup.get();
181 component_defined(setupPtr);
183 _registeredsetups.push_back(std::move(setup));
184 group->add_setup(setupPtr);
189 if (
auto* group =
get()) {
190 auto teardown = std::make_unique<SpecTeardown>(
get(), std::move(codeBlock));
191 if (skip) teardown->mark_skipped(
true);
192 auto* teardownPtr = teardown.get();
193 component_defined(teardownPtr);
195 _registeredteardowns.push_back(std::move(teardown));
196 group->add_teardown(teardownPtr);
201 if (
auto* group =
get()) {
202 auto setup = std::make_unique<SpecSetup>(
get(), std::move(codeBlock));
203 if (skip) setup->mark_skipped(
true);
204 auto* setupPtr = setup.get();
205 component_defined(setupPtr);
207 _registeredOneTimesetups.push_back(std::move(setup));
208 group->add_one_time_setup(setupPtr);
213 if (
auto* group =
get()) {
214 auto teardown = std::make_unique<SpecTeardown>(
get(), std::move(codeBlock));
215 if (skip) teardown->mark_skipped(
true);
216 auto* teardownPtr = teardown.get();
217 component_defined(teardownPtr);
219 _registeredOneTimeteardowns.push_back(std::move(teardown));
220 group->add_one_time_teardown(teardownPtr);
225 if (
auto* group =
get()) {
227 if (_currentTopLevelGroup) {
228 while (
get() != _currentTopLevelGroup)
pop();
229 if (
get() == _currentTopLevelGroup)
pop();
231 _currentTopLevelGroup =
nullptr;
238 if (
auto* group =
get()) {
239 auto specGroup = std::make_unique<SpecGroup>(
get(), description);
240 auto* specGroupPtr = specGroup.get();
241 component_defined(specGroupPtr);
243 _currentTopLevelGroup = specGroupPtr;
244 _registeredGroups.push_back(std::move(specGroup));
251 if (
auto* group =
get()) {
253 if (_currentFileGroup) {
254 while (
get() != _currentFileGroup)
pop();
255 if (
get() == _currentFileGroup)
pop();
257 _currentFileGroup =
nullptr;
265 if (
auto* group =
get()) {
266 std::string descriptionText{description};
267 if (removeUnderscores) {
268 std::replace(descriptionText.begin(), descriptionText.end(),
'_',
' ');
269 description = descriptionText;
271 auto specGroup = std::make_unique<SpecGroup>(
get(), descriptionText);
272 auto* specGroupPtr = specGroup.get();
273 component_defined(specGroupPtr);
275 _currentFileGroup = specGroupPtr;
276 _registeredGroups.push_back(std::move(specGroup));
283 std::string_view templateName,
bool clearFileGroup =
false,
284 bool removeUnderscores =
true
289 if (
auto* group =
get()) {
290 std::string descriptionText{templateName};
291 if (removeUnderscores) {
292 std::replace(descriptionText.begin(), descriptionText.end(),
'_',
' ');
293 templateName = descriptionText;
295 auto foundExisting = _testTemplateGroups.find(descriptionText.data());
296 if (foundExisting != _testTemplateGroups.end()) {
299 auto specGroup = std::make_unique<SpecGroup>(
get(), descriptionText);
300 auto* specGroupPtr = specGroup.get();
301 component_defined(specGroupPtr);
303 _currentTopLevelGroup = specGroupPtr;
304 _testTemplateGroups[descriptionText] = std::move(specGroup);
310 void declare_group(std::string_view description,
bool removeUnderscores =
true) {
311 if (
auto* group =
get()) {
312 std::string descriptionText{description};
313 if (removeUnderscores) {
314 std::replace(descriptionText.begin(), descriptionText.end(),
'_',
' ');
315 description = descriptionText;
317 auto specGroup = std::make_unique<SpecGroup>(
get(), descriptionText);
318 auto* specGroupPtr = specGroup.get();
319 component_defined(specGroupPtr);
321 _registeredGroups.push_back(std::move(specGroup));
322 group->add_group(_registeredGroups.back().get());
328 for (
auto& description : descriptions)
declare_group(description);
332 if (
auto* group =
get()) {
333 auto found = _testTemplateGroups.find(templateName.data());
334 if (found == _testTemplateGroups.end()) {
335 _Error_(
"Test template not found: {}", templateName);
339 auto* templateGroup = found->second.get();
340 group->merge(templateGroup);
345 if (
auto* group =
get())
346 for (
auto& templateName : templateNames)
use_template(templateName);
350 _metaDataForNextComponent.
add(value);
354 _tagsForNextComponent.
add(value.data());
void add_tag_for_next_component(std::string_view value)
void push(ISpecGroup *group)
void use_templates(std::vector< std::string_view > templateNames)
void clear_top_level_group()
static GlobalSpecGroup & instance()
void define_group(std::string_view description, std::unique_ptr< SpecCodeBlock > codeBlock, bool removeUnderscores=false)
void define_teardown(std::unique_ptr< SpecCodeBlock > codeBlock, bool skip=false)
void define_spec(std::string_view description, std::unique_ptr< SpecCodeBlock > codeBlock, bool skip=false)
void define_setup(std::unique_ptr< SpecCodeBlock > codeBlock, bool skip=false)
void define_one_time_teardown(std::unique_ptr< SpecCodeBlock > codeBlock, bool skip=false)
void declare_groups(std::vector< std::string > descriptions)
void use_template(std::string_view templateName)
void define_one_time_setup(std::unique_ptr< SpecCodeBlock > codeBlock, bool skip=false)
ISpecGroup * root() const
void declare_top_level_group(std::string_view description)
void set(ISpecGroup *group)
void restore_group_stack()
void add_meta_data_for_next_component(ISpecDataValue *value)
GlobalSpecGroup(ISpecGroup *rootGroup)
void define_template(std::string_view templateName, std::unique_ptr< SpecCodeBlock > codeBlock)
void declare_file_group(std::string_view description, bool removeUnderscores=true)
void add_tags_for_next_component(std::vector< std::string_view > values)
void declare_group(std::string_view description, bool removeUnderscores=true)
void declare_top_level_template(std::string_view templateName, bool clearFileGroup=false, bool removeUnderscores=true)
ISpecDataValue * get(const char *key) const override
bool has(const char *key) const override
void add(ISpecDataValue *value) override
void add(const char *value) override
virtual ISpecDataValueCollection * data() const =0
virtual void mark_skipped(bool skip=true)=0
virtual ISpecTagCollection * tags() const =0
virtual void merge(ISpecDataValueCollection *)=0
virtual int int_value() const =0
virtual bool bool_value() const =0
virtual void add_group(ISpecGroup *)=0
virtual void merge(ISpecTagCollection *)=0