24 class SpecSuiteRunInstance {
29 int _timeoutMs = 3000;
32 bool _currentlySkippingTests =
false;
33 int _setupGroupsRun = 0;
34 std::unique_ptr<std::promise<ISpecRunResult*>> _currentRunResultPromise =
nullptr;
36 ISpec* _currentSpec =
nullptr;
37 bool _currentSpecFailed =
false;
38 std::unique_ptr<ISpecRunResult> _currentResult =
nullptr;
39 std::string _currentSpecFailureMessage;
41 inline bool list_only()
const {
return false; }
56 inline bool should_run_group(
ISpecGroup* group) {
59 if (group->
skip())
return false;
73 inline bool should_run_spec(
ISpec* spec) {
74 if (spec->skip())
return false;
91 _currentSpecFailed =
true;
92 _currentSpecFailureMessage = result->
message();
94 _currentResult = std::unique_ptr<ISpecRunResult>(result->
copy());
95 _currentRunResultPromise->set_value(_currentResult.get());
99 this, &SpecSuiteRunInstance::code_block_callback_fn
102 void foreach_setup_in_group(
ISpecSetup* setup) {
103 if (_currentSpecFailed || setup->skip()) {
109 _currentRunResultPromise = std::make_unique<std::promise<ISpecRunResult*>>();
111 auto* codeBlock = setup->code_block();
112 if (codeBlock->get_timeout_ms() == 0) codeBlock->set_timeout_ms(_timeoutMs);
114 codeBlock->run(setup, _currentGroup, _currentSpec, &_codeBlockCallbackFn);
116 auto future = _currentRunResultPromise->get_future();
117 if (codeBlock->get_timeout_ms() > 0) {
118 if (future.wait_for(std::chrono::milliseconds(codeBlock->get_timeout_ms())) ==
119 std::future_status::timeout) {
122 _currentSpecFailed =
true;
127 if (
auto* result = future.get()) _reporters->
report_setup(result);
128 else _Log_(
"Setup callback future.get() returned nullptr");
131 FunctionPointer<void(
ISpecSetup*)> _forEachSetupInGroupFn{
132 this, &SpecSuiteRunInstance::foreach_setup_in_group
136 if (teardown->skip())
return;
138 _currentRunResultPromise = std::make_unique<std::promise<ISpecRunResult*>>();
140 auto* codeBlock = teardown->code_block();
141 if (codeBlock->get_timeout_ms() == 0) codeBlock->set_timeout_ms(_timeoutMs);
143 codeBlock->run(teardown, _currentGroup, _currentSpec, &_codeBlockCallbackFn);
145 auto future = _currentRunResultPromise->get_future();
146 if (codeBlock->get_timeout_ms() > 0) {
147 if (future.wait_for(std::chrono::milliseconds(codeBlock->get_timeout_ms())) ==
148 std::future_status::timeout) {
151 _currentSpecFailed =
true;
157 else _Log_(
"Teardown callback future.get() returned nullptr");
160 FunctionPointer<void(
ISpecTeardown*)> _forEachTeardownInGroupFn{
161 this, &SpecSuiteRunInstance::foreach_teardown_in_group
164 void foreach_test_in_group(
ISpec* spec) {
165 if (_currentlySkippingTests || list_only() || !should_run_spec(spec)) {
173 _currentSpecFailed =
false;
174 _currentResult =
nullptr;
178 std::vector<ISpecGroup*> groupStack;
179 auto* currentGroup = _currentGroup;
180 while (currentGroup) {
181 groupStack.push_back(currentGroup);
182 currentGroup = currentGroup->
group();
186 for (
auto it = groupStack.rbegin(); it != groupStack.rend(); ++it) {
189 if (!_currentSpecFailed) _setupGroupsRun++;
192 if (_currentSpecFailed) {
201 spec, _currentGroup, spec, _currentSpecFailureMessage
210 int teardownsToRun = _setupGroupsRun;
211 auto groupCount = groupStack.size();
212 auto groupsToSkip = groupCount - teardownsToRun;
216 for (
int i = 0; i < groupCount; i++) {
217 if (i < groupsToSkip - 1)
continue;
218 auto* group = groupStack[i];
222 spec->variables()->clear();
226 _currentRunResultPromise = std::make_unique<std::promise<ISpecRunResult*>>();
228 auto* codeBlock = spec->code_block();
229 if (codeBlock->get_timeout_ms() == 0) codeBlock->set_timeout_ms(_timeoutMs);
231 codeBlock->run(spec, _currentGroup, spec, &_codeBlockCallbackFn);
233 auto future = _currentRunResultPromise->get_future();
235 if (codeBlock->get_timeout_ms() > 0) {
236 if (future.wait_for(std::chrono::milliseconds(codeBlock->get_timeout_ms())) ==
237 std::future_status::timeout) {
243 spec->variables()->clear();
248 if (
auto* result = future.get()) _reporters->
report_test(result);
249 else _Log_(
"Spec callback future.get() returned nullptr");
252 for (
auto* group : groupStack) group->
foreach_teardown(&_forEachTeardownInGroupFn);
254 if (_currentSpecFailed) {
257 spec, _currentGroup, spec, _currentSpecFailureMessage
265 spec->variables()->clear();
268 FunctionPointer<void(
ISpec*)> _forEachSpecInGroupFn{
269 this, &SpecSuiteRunInstance::foreach_test_in_group
272 void foreach_group_in_group(
ISpecGroup* group) {
274 _currentSpec =
nullptr;
275 _currentSpecFailed =
false;
276 _currentSpecFailureMessage.clear();
277 _currentResult =
nullptr;
279 if (_currentlySkippingTests) {
280 _currentGroup = group;
286 bool shouldRun = should_run_group(group);
287 _currentlySkippingTests = !shouldRun;
290 if (!_currentlySkippingTests)
293 _currentGroup = group;
298 if (!_currentlySkippingTests)
303 _currentlySkippingTests =
false;
306 FunctionPointer<void(
ISpecGroup*)> _forEachGroupInGroupFn{
307 this, &SpecSuiteRunInstance::foreach_group_in_group
311 bool shouldRun = should_run_group(group);
312 _currentlySkippingTests = !shouldRun;
315 _currentSpec =
nullptr;
316 _currentSpecFailed =
false;
317 _currentSpecFailureMessage.clear();
318 _currentResult =
nullptr;
321 if (!_currentlySkippingTests)
325 _currentGroup = group;
332 if (!_currentlySkippingTests)
335 _currentlySkippingTests =
false;
339 SpecSuiteRunInstance(
342 : _reporters(reporters), _options(options) {}
353 if (callback) callback->invoke(&_resultTotalCounts);
362 SpecSuiteRunInstance(reporters, options).run(group, callback);
static std::unique_ptr< SpecRunResult > timeout(ISpecComponent *component, ISpecGroup *group, ISpec *spec)
static std::unique_ptr< SpecRunResult > passed(ISpecComponent *component, ISpecGroup *group, ISpec *spec)
static std::unique_ptr< SpecRunResult > not_run(ISpecComponent *component, ISpecGroup *group, ISpec *spec)
static std::unique_ptr< SpecRunResult > failed(ISpecComponent *component, ISpecGroup *group, ISpec *spec, std::string_view message="")
void run(ISpecGroup *group, ISpecReporterCollection *reporters, ISpecRunOptions *options, ISpecSuiteRunResultCallbackFn *callback) override
IFunctionPointer< void(ISpecSuiteRunResult *)> ISpecSuiteRunResultCallbackFn
virtual ISpecGroup * group() const =0
virtual bool skip() const =0
virtual const char * description() const =0
virtual void foreach_one_time_teardown(ForEachTeardownFn *) const =0
virtual void foreach_group(ForEachGroupFn *) const =0
virtual void foreach_one_time_setup(ForEachSetupFn *) const =0
virtual void foreach_teardown(ForEachTeardownFn *) const =0
virtual void foreach_setup(ForEachSetupFn *) const =0
virtual void foreach_test(ForEachSpecFn *) const =0
virtual ISpecVariableCollection * variables() const =0
virtual void report_test(ISpecRunResult *)=0
virtual void report_test_begin(ISpecGroup *, ISpec *)=0
virtual void report_test_result(ISpecRunResult *)=0
virtual void report_start()=0
virtual void report_setup(ISpecRunResult *)=0
virtual void report_teardown(ISpecRunResult *)=0
virtual void report_suite_result(ISpecSuiteRunResult *)=0
virtual std::uint32_t default_timeout_ms() const =0
virtual RunResultStatus status() const =0
virtual ISpecRunResult * copy() const =0
virtual const char * message() const =0