19 std::uint32_t _timeout_ms = 0;
23 std::unique_ptr<std::promise<void>> _asyncDonePromise =
nullptr;
26 _managedBody =
nullptr;
28 bool _exceptionHandled =
false;
29 std::unique_ptr<std::exception_ptr> _currentExceptionPtr;
30 std::string _currentExceptionMessage;
32 void mark_async_promise_done() {
33 if (_asyncDonePromise) _asyncDonePromise->set_value();
36 FunctionPointer<void()> _markAsyncPromiseDoneFn =
37 function_pointer(
this, &SpecCodeBlock::mark_async_promise_done);
39 void store_current_exception_message(
42 if (_exceptionHandled)
return;
44 if (
auto* message = exceptionMessage->
message())
45 _currentExceptionMessage = exceptionMessage->
message();
49 _storeCurrentExceptionMessageFn =
50 function_pointer(
this, &SpecCodeBlock::store_current_exception_message);
53 if (_exceptionHandled)
return;
55 _currentExceptionPtr.get(), &_storeCurrentExceptionMessageFn
57 _exceptionHandled =
true;
61 function_pointer(
this, &SpecCodeBlock::foreach_exception_handler);
67 : _managedBody(std::move(managedBody)) {}
97 ) {
body.invoke(spec); }
102 : _managedBody(std::make_unique<FunctionPointer<
107 if (
auto* group =
dynamic_cast<ISpecGroup*
>(self))
body.invoke(group);
108 else if (
auto* group = self->group()) _Log_(
"AFTER");
143 ) {
body.invoke(self, spec); }
153 ) {
body.invoke(self->group(), spec); }
163 ) {
body.invoke(self->group(), self, spec); }
173 ) {
body.invoke(self->group(), spec,
SpecDone{asyncDone}); }
197 ) {
body.invoke(self->group(), self, spec,
SpecDone{asyncDone}); }
204 void mark_async(
bool async =
true)
override { _async = async; }
207 void set_timeout_ms(std::uint32_t timeout_ms)
override { _timeout_ms = timeout_ms; }
210 return _unmanagedBody ? _unmanagedBody : _managedBody.get();
221 _asyncDonePromise = std::make_unique<std::promise<void>>();
222 body()->invoke(self, spec, &_markAsyncPromiseDoneFn);
224 auto asyncDoneFuture = _asyncDonePromise->get_future();
226 if (asyncDoneFuture.wait_for(std::chrono::milliseconds(
get_timeout_ms())) ==
227 std::future_status::timeout) {
228 if (resultCallback) {
230 resultCallback->invoke(result.get());
233 _Log_(
"Code block timed out");
238 asyncDoneFuture.get();
241 body()->invoke(self, spec,
nullptr);
244 if (!resultCallback)
return;
246 resultCallback->invoke(result.get());
248 _exceptionHandled =
false;
251 if (_asyncDonePromise) _asyncDonePromise->set_exception(std::current_exception());
254 if (
auto* exceptionHandlers =
255 currentlyRunningSpecEnvironment->local_exception_handlers()) {
256 _currentExceptionMessage.clear();
257 _currentExceptionPtr =
258 std::make_unique<std::exception_ptr>(std::current_exception());
259 exceptionHandlers->foreach_exception_handler(&_forEachExceptionHandlerFn);
260 if (_exceptionHandled) {
261 if (resultCallback) {
263 self, group, spec, _currentExceptionMessage.c_str()
265 resultCallback->invoke(result.get());
267 _Log_(
"Code block error: {}", _currentExceptionMessage);
270 if (resultCallback) {
273 resultCallback->invoke(result.get());
276 _Log_(
"Code block error: Unhandled exception");
280 _Log_(
"No exception handlers registered");
283 _Log_(
"No currently running spec environment");
void set_body(SpecCodeBlockBodyFn *body) override
SpecCodeBlock(std::unique_ptr< IFunctionPointer< void(ISpecComponent *, ISpec *, SpecCodeBlockAsyncDoneFn *)> > managedBody)
SpecCodeBlock(FunctionPointer< void()> body)
SpecCodeBlock(FunctionPointer< void(ISpecGroup *, ISpecComponent *, ISpec *)> body)
SpecCodeBlock(FunctionPointer< void(ISpecGroup *, SpecDone)> body)
void run(ISpecComponent *self, ISpecGroup *group, ISpec *spec, ISpecRunResultCallbackFn *resultCallback) override
SpecCodeBlock(FunctionPointer< void(SpecDone)> body)
SpecCodeBlock(FunctionPointer< void(ISpec *, SpecDone)> body)
SpecCodeBlock(FunctionPointer< void(ISpecComponent *, ISpec *, SpecDone)> body)
SpecCodeBlock(FunctionPointer< void(ISpecGroup *, ISpec *)> body)
SpecCodeBlock(FunctionPointer< void(ISpecComponent *, ISpec *)> body)
void mark_async(bool async=true) override
void set_timeout_ms(std::uint32_t timeout_ms) override
SpecCodeBlock(FunctionPointer< void(ISpecGroup *, ISpec *, SpecDone)> body)
std::uint32_t get_timeout_ms() const override
bool is_async() const override
SpecCodeBlock(FunctionPointer< void(ISpecGroup *, ISpecComponent *, ISpec *, SpecDone)> body)
SpecCodeBlockBodyFn * body() const override
SpecCodeBlock(FunctionPointer< void(ISpec *)> body)
SpecCodeBlock(FunctionPointer< void(ISpecGroup *)> body)
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 > failed(ISpecComponent *component, ISpecGroup *group, ISpec *spec, std::string_view message="")
GlobalSpecEnvironment & global_spec_environment()
IFunctionPointer< void(ISpecRunResult *)> ISpecRunResultCallbackFn
virtual const char * message() const =0
virtual bool handle_exception(std::exception_ptr *exception, LocalSpecExceptionFailureMessageCallbackFn *failureMessageCallback)=0
IFunctionPointer< void(ISpecComponent *, ISpec *, SpecCodeBlockAsyncDoneFn *)> SpecCodeBlockBodyFn
IFunctionPointer< void()> SpecCodeBlockAsyncDoneFn