Error integration: error::Flag as subclass of State. Wrapped throw
This commit is contained in:
parent
acd0671390
commit
90d311dc1d
5 changed files with 134 additions and 69 deletions
|
|
@ -192,7 +192,6 @@ namespace backend {
|
|||
lumiera_thread_join (thread_);
|
||||
thread_ = 0;
|
||||
|
||||
TODO("check this, is error::State approbiate or do we want Runtime as thrown by throwOnError()");
|
||||
if (errorInOtherThread)
|
||||
throw lumiera::error::State ("Thread terminated with error:", errorInOtherThread);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
ERROR.hpp - Lumiera Exception Interface
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
2008-2010 Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License as
|
||||
|
|
@ -49,9 +49,9 @@ namespace lumiera {
|
|||
class Error : public std::exception
|
||||
{
|
||||
public:
|
||||
Error (string description="", const char* id=LUMIERA_ERROR_EXCEPTION) throw();
|
||||
Error (string description="", const char* const id=LUMIERA_ERROR_EXCEPTION) throw();
|
||||
Error (std::exception const& cause,
|
||||
string description="", const char* id=LUMIERA_ERROR_EXCEPTION) throw();
|
||||
string description="", const char* const id=LUMIERA_ERROR_EXCEPTION) throw();
|
||||
|
||||
Error (const Error&) throw();
|
||||
virtual ~Error () throw() {};
|
||||
|
|
@ -97,8 +97,7 @@ namespace lumiera {
|
|||
|
||||
/* === Exception Sub-categories === */
|
||||
|
||||
namespace error
|
||||
{
|
||||
namespace error {
|
||||
|
||||
/** global function for handling unknown exceptions
|
||||
* encountered at functions declaring not to throw
|
||||
|
|
@ -117,6 +116,7 @@ namespace lumiera {
|
|||
LUMIERA_ERROR_DECLARE (FATAL ); ///< unable to cope with, internal logic floundered
|
||||
LUMIERA_ERROR_DECLARE (CONFIG ); ///< execution aborted due to misconfiguration
|
||||
LUMIERA_ERROR_DECLARE (STATE ); ///< unforeseen internal state
|
||||
LUMIERA_ERROR_DECLARE (FLAG ); ///< non-cleared lumiera errorstate from C code
|
||||
LUMIERA_ERROR_DECLARE (INVALID ); ///< invalid input or parameters encountered
|
||||
LUMIERA_ERROR_DECLARE (EXTERNAL ); ///< failure in external service the application relies on
|
||||
LUMIERA_ERROR_DECLARE (ASSERTION); ///< assertion failure
|
||||
|
|
@ -125,7 +125,6 @@ namespace lumiera {
|
|||
LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch
|
||||
LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached
|
||||
LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value
|
||||
LUMIERA_ERROR_DECLARE (RUNTIME); ///< generic runtime error, will be overridden by id
|
||||
|
||||
|
||||
/** Macro for creating derived exception classes properly
|
||||
|
|
@ -143,7 +142,7 @@ namespace lumiera {
|
|||
const char* id=_ID_) throw() \
|
||||
: PARENT (description, id) {} \
|
||||
\
|
||||
CLASS (std::exception& cause, \
|
||||
CLASS (std::exception const& cause, \
|
||||
std::string description="", \
|
||||
const char* id=_ID_) throw() \
|
||||
: PARENT (cause, description, id) {} \
|
||||
|
|
@ -154,30 +153,59 @@ namespace lumiera {
|
|||
LUMIERA_EXCEPTION_DECLARE (Fatal, Logic, LUMIERA_ERROR_FATAL);
|
||||
LUMIERA_EXCEPTION_DECLARE (Config, Error, LUMIERA_ERROR_CONFIG);
|
||||
LUMIERA_EXCEPTION_DECLARE (State, Error, LUMIERA_ERROR_STATE);
|
||||
LUMIERA_EXCEPTION_DECLARE (Flag, State, LUMIERA_ERROR_FLAG);
|
||||
LUMIERA_EXCEPTION_DECLARE (Invalid, Error, LUMIERA_ERROR_INVALID);
|
||||
LUMIERA_EXCEPTION_DECLARE (External, Error, LUMIERA_ERROR_EXTERNAL);
|
||||
LUMIERA_EXCEPTION_DECLARE (Runtime, Error, LUMIERA_ERROR_RUNTIME);
|
||||
|
||||
|
||||
/** install our own handler for undeclared exceptions. Will be
|
||||
* called automatically ON_BASIC_INIT when linking exception.cpp */
|
||||
void install_unexpectedException_handler ();
|
||||
|
||||
/** @return error detail-info if currently set, a default message else */
|
||||
const char* detailInfo ();
|
||||
|
||||
} // namespace error
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Throw a 'Runtime' error which wraps an existing lumiera error
|
||||
* no-op when no error is pending. Does not clear the error state.
|
||||
* Check the lumiera error state, which maybe was set by C-code.
|
||||
* @throw Errorflag exception to signal an detected lumiera error
|
||||
* @note specific error code and information is enclosed in
|
||||
* the raised exception; the error state is \em not cleared.
|
||||
*/
|
||||
static inline void throwOnError()
|
||||
inline void
|
||||
throwOnError()
|
||||
{
|
||||
lumiera_err err = lumiera_error_peek();
|
||||
if (err)
|
||||
if (lumiera_err errorFlag =lumiera_error())
|
||||
{
|
||||
const char* extra = lumiera_error_extra();
|
||||
throw error::Runtime(extra?extra:"", err);
|
||||
}
|
||||
throw error::Flag( error::detailInfo()
|
||||
, errorFlag);
|
||||
} } //causes the error state to be set
|
||||
|
||||
/** Check the lumiera error state and throw a specific exception
|
||||
* in case a non-cleared errorflag is detected. No-op else.
|
||||
* @throw instance of the lumiera::Error subclass provided as
|
||||
* template parameter, containing an lumiera::error::Flag
|
||||
* as root cause to denote the detected error-flag state.
|
||||
*/
|
||||
template<class EX>
|
||||
inline void
|
||||
maybeThrow(string description)
|
||||
{
|
||||
if (lumiera_err errorFlag =lumiera_error())
|
||||
{
|
||||
throw EX (error::Flag( error::detailInfo()
|
||||
, errorFlag)
|
||||
,description);
|
||||
} }
|
||||
|
||||
template<class EX>
|
||||
inline void
|
||||
maybeThrow()
|
||||
{
|
||||
maybeThrow<EX>("");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ using std::exception;
|
|||
|
||||
|
||||
namespace lumiera {
|
||||
|
||||
typedef const char* CStr;
|
||||
typedef const char* const CCStr;
|
||||
|
||||
|
||||
namespace error {
|
||||
|
||||
/** the message shown to the user per default
|
||||
|
|
@ -48,18 +53,27 @@ namespace lumiera {
|
|||
+ typeid(*exception_obj).name() + ")";
|
||||
}
|
||||
|
||||
inline const char*
|
||||
default_or_given (const char* id)
|
||||
inline CStr
|
||||
default_or_given (CCStr id)
|
||||
{
|
||||
return id? id : LUMIERA_ERROR_STATE;
|
||||
}
|
||||
|
||||
CStr
|
||||
detailInfo ()
|
||||
{
|
||||
CCStr detailinfo = lumiera_error_extra();
|
||||
return isnil (detailinfo)? "Lumiera errorstate detected"
|
||||
: detailinfo;
|
||||
}
|
||||
|
||||
|
||||
/* constants to be used as error IDs */
|
||||
LUMIERA_ERROR_DEFINE (LOGIC , "internal logic broken");
|
||||
LUMIERA_ERROR_DEFINE (FATAL , "floundered");
|
||||
LUMIERA_ERROR_DEFINE (CONFIG , "misconfiguration");
|
||||
LUMIERA_ERROR_DEFINE (STATE , "unforeseen state");
|
||||
LUMIERA_ERROR_DEFINE (FLAG , "non-cleared lumiera errorstate");
|
||||
LUMIERA_ERROR_DEFINE (INVALID , "invalid input or parameters");
|
||||
LUMIERA_ERROR_DEFINE (EXTERNAL , "failure in external service");
|
||||
LUMIERA_ERROR_DEFINE (ASSERTION, "assertion failure");
|
||||
|
|
@ -78,7 +92,7 @@ namespace lumiera {
|
|||
|
||||
|
||||
/** @note we set the C-style errorstate as a side effect */
|
||||
Error::Error (string description, const char* id) throw()
|
||||
Error::Error (string description, CCStr id) throw()
|
||||
: std::exception (),
|
||||
id_ (error::default_or_given (id)),
|
||||
msg_ (error::default_usermsg (this)),
|
||||
|
|
@ -90,7 +104,7 @@ namespace lumiera {
|
|||
|
||||
|
||||
Error::Error (std::exception const& cause,
|
||||
string description, const char* id) throw()
|
||||
string description, CCStr id) throw()
|
||||
: std::exception (),
|
||||
id_ (error::default_or_given (id)),
|
||||
msg_ (error::default_usermsg (this)),
|
||||
|
|
@ -117,7 +131,7 @@ namespace lumiera {
|
|||
* If a root cause can be obtained, this will be included in the
|
||||
* generated output as well.
|
||||
*/
|
||||
const char*
|
||||
CStr
|
||||
Error::what() const throw()
|
||||
{
|
||||
if (isnil (this->what_))
|
||||
|
|
@ -160,13 +174,13 @@ namespace lumiera {
|
|||
|
||||
void lumiera_unexpectedException () throw()
|
||||
{
|
||||
const char* is_halted
|
||||
CCStr is_halted
|
||||
= "### Lumiera halted due to an unexpected Error ###";
|
||||
|
||||
std::cerr << "\n" << is_halted << "\n\n";
|
||||
ERROR (NOBUG_ON, "%s", is_halted);
|
||||
|
||||
if (const char * errorstate = lumiera_error ())
|
||||
if (CCStr errorstate = lumiera_error ())
|
||||
ERROR (NOBUG_ON, "last registered error was....\n%s", errorstate);
|
||||
|
||||
std::terminate();
|
||||
|
|
|
|||
|
|
@ -205,7 +205,9 @@ out: intermediate handler caught: LUMIERA_ERROR_EXTERNAL:failure in external ser
|
|||
out: caught lumiera::Error: LUMIERA_ERROR_STATE:unforeseen state -- caused by: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-7\).
|
||||
out: intermediate handler caught: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-8\).....will rethrow as error::State
|
||||
out: 2nd intermediate handler caught: LUMIERA_ERROR_STATE:unforeseen state -- caused by: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-8\).....will rethrow as error::Config
|
||||
out: caught lumiera::Error: LUMIERA_ERROR_CONFIG:misconfiguration -- caused by: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-8\).
|
||||
out: caught lumiera::Error: LUMIERA_ERROR_CONFIG:misconfiguration -- caused by: LUMIERA_ERROR_EXTERNAL:failure in external service \(test-8\)\.
|
||||
out: caught lumiera::Error: LUMIERA_ERROR_LIFE_AND_UNIVERSE:and everything\? \(what is the answer\?\)\.
|
||||
out: caught error::Logic: LUMIERA_ERROR_LOGIC:internal logic broken \(the big bang\). -- caused by: LUMIERA_ERROR_LIFE_AND_UNIVERSE:and everything\? \(what is the answer\?\)\.
|
||||
END
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -83,6 +83,7 @@ namespace lumiera {
|
|||
catcher (&test::doubleNestedTh,"test-8");
|
||||
|
||||
checkErrorIntegration();
|
||||
checkErrorFlagPropagation();
|
||||
checkRootCauseChaining();
|
||||
}
|
||||
|
||||
|
|
@ -153,6 +154,27 @@ namespace lumiera {
|
|||
ASSERT (!lumiera_error ());
|
||||
}
|
||||
|
||||
|
||||
void detectErrorflag (string) { throwOnError(); }
|
||||
void detectErrorflagChained (string msg) { maybeThrow<error::Logic>(msg); }
|
||||
|
||||
|
||||
/** @test verify throwing of Exceptions
|
||||
* based on a non-cleared C error flag
|
||||
*/
|
||||
void checkErrorFlagPropagation()
|
||||
{
|
||||
lumiera_error_set(LUMIERA_ERROR_LIFE_AND_UNIVERSE, "what is the answer?");
|
||||
ASSERT (lumiera_error_peek());
|
||||
|
||||
catcher (&test::detectErrorflag, "");
|
||||
ASSERT (LUMIERA_ERROR_LIFE_AND_UNIVERSE == lumiera_error_peek());
|
||||
|
||||
catcher (&test::detectErrorflagChained, "the big bang");
|
||||
ASSERT (LUMIERA_ERROR_LIFE_AND_UNIVERSE == lumiera_error());
|
||||
}
|
||||
|
||||
|
||||
/** @test the chaining of lumiera::Exception objects
|
||||
* and the retrieval of the original root cause.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue