2007-08-26 19:14:39 +02:00
|
|
|
/*
|
2009-01-03 01:11:21 +01:00
|
|
|
ExceptionError(Test) - throwing and catching our exception type
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2008-03-10 04:25:03 +01:00
|
|
|
Copyright (C) Lumiera.org
|
|
|
|
|
2008, Hermann Vosseler <Ichthyostega@web.de>
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
This program is free software; you can redistribute it and/or
|
|
|
|
|
modify it under the terms of the GNU General Public License as
|
2010-12-17 23:28:49 +01:00
|
|
|
published by the Free Software Foundation; either version 2 of
|
|
|
|
|
the License, or (at your option) any later version.
|
|
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
2010-12-17 23:28:49 +01:00
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
* *****************************************************/
|
|
|
|
|
|
2017-04-02 04:22:51 +02:00
|
|
|
/** @file exception-error-test.cpp
|
2017-02-22 03:17:18 +01:00
|
|
|
** unit test \ref ExceptionError_test
|
2016-11-03 18:20:10 +01:00
|
|
|
*/
|
|
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "lib/error.h"
|
2008-12-27 00:53:35 +01:00
|
|
|
#include "lib/error.hpp"
|
2008-12-18 04:47:41 +01:00
|
|
|
#include "lib/test/run.hpp"
|
2018-04-01 23:45:00 +02:00
|
|
|
#include "lib/format-cout.hpp"
|
2008-12-18 04:47:41 +01:00
|
|
|
#include "lib/util.hpp"
|
2007-08-26 19:14:39 +02:00
|
|
|
|
|
|
|
|
#include <exception>
|
|
|
|
|
#include <stdexcept>
|
2018-04-01 23:45:00 +02:00
|
|
|
#include <string>
|
2007-08-26 19:14:39 +02:00
|
|
|
|
|
|
|
|
using std::runtime_error;
|
|
|
|
|
using std::exception;
|
|
|
|
|
using std::string;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2009-01-03 01:11:21 +01:00
|
|
|
namespace lumiera {
|
|
|
|
|
namespace test {
|
|
|
|
|
|
2018-04-01 23:45:00 +02:00
|
|
|
LUMIERA_ERROR_DEFINE (LIFE_AND_UNIVERSE, "and everything?");
|
|
|
|
|
/** local specific error-constant for use in the
|
2009-01-03 01:11:21 +01:00
|
|
|
* constructor of the nested SpecificError class.
|
2007-08-26 19:14:39 +02:00
|
|
|
*/
|
2018-04-01 23:45:00 +02:00
|
|
|
LUMIERA_ERROR_DECLARE(DERIVED);
|
|
|
|
|
LUMIERA_ERROR_DEFINE (DERIVED, "convoluted exception");
|
2007-08-26 19:14:39 +02:00
|
|
|
|
2018-04-01 23:45:00 +02:00
|
|
|
/** define a specific Error subclass derived from error::external */
|
|
|
|
|
using DerivedError = error::LumieraError<LERR_(DERIVED), error::External>;
|
2007-08-26 19:14:39 +02:00
|
|
|
|
|
|
|
|
|
2013-10-24 23:06:36 +02:00
|
|
|
/******************************************************//**
|
2007-08-26 19:14:39 +02:00
|
|
|
* Some aspects of C++ exception handling.
|
2018-04-01 23:45:00 +02:00
|
|
|
* Not to be confused with the basic C-style error value
|
2018-11-15 21:13:52 +01:00
|
|
|
* mechanism used by the low-level parts of the vault.
|
2018-04-01 23:45:00 +02:00
|
|
|
* Both approaches are largely orthogonal, but the
|
2007-08-26 19:14:39 +02:00
|
|
|
* C++ exception handling uses the C-style error constants.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
class ExceptionError_test : public Test
|
|
|
|
|
{
|
|
|
|
|
typedef ExceptionError_test test;
|
2023-10-01 20:11:45 +02:00
|
|
|
|
|
|
|
|
virtual void
|
|
|
|
|
run (Arg)
|
2007-08-26 19:14:39 +02:00
|
|
|
{
|
|
|
|
|
catcher (&test::throwSpecial, "");
|
|
|
|
|
catcher (&test::throwDerived, "test-1");
|
|
|
|
|
catcher (&test::throwFatal, "test-2");
|
|
|
|
|
catcher (&test::throwInvalid, "test-3");
|
|
|
|
|
catcher (&test::throwExternal, "test-4");
|
|
|
|
|
catcher (&test::throwRuntime, "test-5");
|
|
|
|
|
catcher (&test::throwExceptn, "test-6");
|
|
|
|
|
|
|
|
|
|
catcher (&test::nestedThrower, "test-7");
|
|
|
|
|
catcher (&test::doubleNestedTh,"test-8");
|
|
|
|
|
|
2010-02-13 20:56:41 +01:00
|
|
|
checkErrorFlagPropagation();
|
2007-08-26 19:14:39 +02:00
|
|
|
checkRootCauseChaining();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test simply throw some exception and pass context info */
|
2008-12-28 05:36:37 +01:00
|
|
|
void throwSpecial (string ) { throw SpecificError(); }
|
|
|
|
|
void throwDerived (string ) { throw DerivedError(); }
|
2007-08-26 19:14:39 +02:00
|
|
|
void throwFatal (string _) { throw error::Fatal(_); }
|
|
|
|
|
void throwInvalid (string _) { throw error::Invalid(_); }
|
|
|
|
|
void throwExternal(string _) { throw error::External(_); }
|
|
|
|
|
void throwRuntime (string _) { throw std::runtime_error(_); }
|
2008-12-28 05:36:37 +01:00
|
|
|
void throwExceptn (string ) { throw std::exception(); }
|
2009-01-03 01:11:21 +01:00
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
|
|
|
|
|
/** @test catching, repackaging and rethrowing of errors.
|
2008-12-28 05:36:37 +01:00
|
|
|
* This feature is important for passing exceptions transparently
|
2007-08-26 19:14:39 +02:00
|
|
|
* over several layers. The nested operation will throw an error::External,
|
|
|
|
|
* which we are able to catch because it is derived from std::exception.
|
|
|
|
|
* We don't need to know the exact type, but we can classify the error situation
|
|
|
|
|
* as a "state error" and throw an error::State, passing on the root cause.
|
2018-04-01 23:45:00 +02:00
|
|
|
* Some levels up, this error get caught and the root cause can be
|
2007-08-26 19:14:39 +02:00
|
|
|
* extracted successfully.
|
|
|
|
|
*/
|
2018-04-01 23:45:00 +02:00
|
|
|
void nestedThrower (string msg)
|
2007-08-26 19:14:39 +02:00
|
|
|
{
|
|
|
|
|
try { throwExternal(msg); }
|
|
|
|
|
catch (std::exception& e)
|
|
|
|
|
{
|
2018-04-01 23:45:00 +02:00
|
|
|
cout << "intermediate handler caught: " << e.what()
|
2007-08-26 19:14:39 +02:00
|
|
|
<< "....will rethrow as error::State\n";
|
|
|
|
|
throw error::State (e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** @test repeated repackaging and rethrowing */
|
2018-04-01 23:45:00 +02:00
|
|
|
void doubleNestedTh (string msg)
|
2007-08-26 19:14:39 +02:00
|
|
|
{
|
|
|
|
|
try { nestedThrower (msg); }
|
|
|
|
|
catch (Error& e)
|
|
|
|
|
{
|
2009-01-03 01:11:21 +01:00
|
|
|
cout << "2nd intermediate handler caught: " << e.what()
|
2007-08-26 19:14:39 +02:00
|
|
|
<< "....will rethrow as error::Config\n";
|
|
|
|
|
throw error::Config (e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2023-10-01 20:11:45 +02:00
|
|
|
void detectErrorflag (string) { throwOnError(); }
|
2010-02-13 20:56:41 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @test verify throwing of Exceptions
|
|
|
|
|
* based on a non-cleared C error flag
|
|
|
|
|
*/
|
|
|
|
|
void checkErrorFlagPropagation()
|
|
|
|
|
{
|
2018-04-01 23:45:00 +02:00
|
|
|
lumiera_error_set(LERR_(LIFE_AND_UNIVERSE), "what is the answer?");
|
2010-12-10 02:55:40 +01:00
|
|
|
CHECK (lumiera_error_peek());
|
2010-02-13 20:56:41 +01:00
|
|
|
|
2023-10-01 20:11:45 +02:00
|
|
|
catcher (&test::detectErrorflag);
|
|
|
|
|
CHECK (not lumiera_error_peek());
|
|
|
|
|
}// yet translating that into an exception also clears the error flag
|
2010-02-13 20:56:41 +01:00
|
|
|
|
|
|
|
|
|
2008-03-10 06:09:44 +01:00
|
|
|
/** @test the chaining of lumiera::Exception objects
|
2007-08-26 19:14:39 +02:00
|
|
|
* and the retrieval of the original root cause.
|
|
|
|
|
*/
|
|
|
|
|
void checkRootCauseChaining()
|
|
|
|
|
{
|
|
|
|
|
error::Logic err1;
|
|
|
|
|
error::Config err2(err1);
|
2018-04-01 23:45:00 +02:00
|
|
|
error::Config err3(err2);
|
|
|
|
|
Error err4(err1); // note: copy ctor
|
2007-08-26 19:14:39 +02:00
|
|
|
|
|
|
|
|
std::runtime_error rerr("what a shame");
|
|
|
|
|
error::External err5(rerr);
|
|
|
|
|
Error err6(err5);
|
|
|
|
|
|
2010-12-10 02:55:40 +01:00
|
|
|
CHECK (err2.rootCause() == err1.what());
|
|
|
|
|
CHECK (err3.rootCause() == err1.what());
|
2018-04-01 23:45:00 +02:00
|
|
|
CHECK (err4.rootCause() == err1.rootCause()); // mere copy is not a root cause
|
2009-01-03 01:11:21 +01:00
|
|
|
|
2010-12-10 02:55:40 +01:00
|
|
|
CHECK (err5.rootCause() == rerr.what());
|
|
|
|
|
CHECK (err6.rootCause() == rerr.what());
|
2007-08-26 19:14:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** a very specific Exception class
|
2018-04-01 23:45:00 +02:00
|
|
|
* local to this scope and with
|
2007-08-26 19:14:39 +02:00
|
|
|
* additional behaviour.
|
2018-04-01 23:45:00 +02:00
|
|
|
*/
|
|
|
|
|
class SpecificError
|
|
|
|
|
: public error::Invalid
|
2007-08-26 19:14:39 +02:00
|
|
|
{
|
2018-04-01 23:45:00 +02:00
|
|
|
int value_;
|
2007-08-26 19:14:39 +02:00
|
|
|
public:
|
2018-04-01 23:45:00 +02:00
|
|
|
SpecificError()
|
|
|
|
|
: error::Invalid{"don't panic", LUMIERA_ERROR_LIFE_AND_UNIVERSE}
|
|
|
|
|
, value_(42)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
revealIt()
|
|
|
|
|
{
|
|
|
|
|
return value_;
|
|
|
|
|
}
|
2007-08-26 19:14:39 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-04-01 23:45:00 +02:00
|
|
|
/** helper: provides a bunch of catch-clauses and
|
2007-08-26 19:14:39 +02:00
|
|
|
* runs the given member functions within
|
|
|
|
|
*/
|
2023-10-01 20:11:45 +02:00
|
|
|
void catcher (void (ExceptionError_test::*funky)(string), string context ="")
|
2007-08-26 19:14:39 +02:00
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
(this->*funky) (context);
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-03 01:11:21 +01:00
|
|
|
catch (SpecificError& e) { cout << "caught: " << e.what() << "..the answer is: " << e.revealIt() << "\n"; }
|
|
|
|
|
catch (error::Logic& e) { cout << "caught error::Logic: " << e.what() << "\n"; }
|
|
|
|
|
catch (error::Invalid&e) { cout << "caught error::Invalid: " << e.what() << "\n"; }
|
|
|
|
|
catch (Error& e) { cout << "caught lumiera::Error: " << e.what() << "\n"; }
|
|
|
|
|
catch (runtime_error& e) { cout << "caught std::runtime_error: " << e.what() << "\n"; }
|
2008-05-20 13:04:22 +02:00
|
|
|
catch (exception& e) { cout << "caught std::exception. (unspecific)" << "\n"; }
|
2007-08-26 19:14:39 +02:00
|
|
|
catch (...) { cout << "caught an unknown exception\n"; }
|
|
|
|
|
}
|
|
|
|
|
};
|
2009-01-03 01:11:21 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** register this test class... */
|
|
|
|
|
LAUNCHER (ExceptionError_test, "function common");
|
|
|
|
|
|
|
|
|
|
|
2007-08-26 19:14:39 +02:00
|
|
|
} // namespace test
|
|
|
|
|
|
|
|
|
|
} // namespace util
|
|
|
|
|
|