From 29ea14c0f9bceeeb65a9fec2ab685c9d4224d4a0 Mon Sep 17 00:00:00 2001 From: Andreas Waidler Date: Sun, 26 Sep 2010 13:19:39 +0200 Subject: [PATCH] Added RETHROW macro, functionality, tests, examples, etc. --- include/libsex/declare.hxx | 5 +++++ include/libsex/define.hxx | 7 +++++++ include/libsex/throw.hxx | 19 ++++++++++++++++++- include/libsex/utility.hxx | 15 +++++++++++++++ include/libsex/utility.ixx | 23 +++++++++++++++++++++-- tests/framework/MockException.cxx | 7 +++++++ tests/framework/MockException.hxx | 3 +++ tests/src/TestUtility.cxx | 23 +++++++++++++++++++++++ tests/src/TestUtility.hxx | 3 +++ tests/src/UsageExamples.cxx | 16 +++++++++++----- tests/src/UsageExamples.hxx | 2 +- 11 files changed, 114 insertions(+), 9 deletions(-) diff --git a/include/libsex/declare.hxx b/include/libsex/declare.hxx index 8f6a98c..b97152e 100644 --- a/include/libsex/declare.hxx +++ b/include/libsex/declare.hxx @@ -1,6 +1,8 @@ #ifndef LIBSEX_DECLARE_HXX #define LIBSEX_DECLARE_HXX +#include + /// Macro for declaring exception classes (.hxx). #define LIBSEX_DECLARE(parent, name) \ class name : public parent\ @@ -8,6 +10,9 @@ class name : public parent\ public:\ static const char* const TEMPLATE;\ name(const char* const errorMessage);\ + name(\ + const char* const errorMessage,\ + const libsex::Exception& previous);\ }; #endif diff --git a/include/libsex/define.hxx b/include/libsex/define.hxx index f7ff070..2d6ff85 100644 --- a/include/libsex/define.hxx +++ b/include/libsex/define.hxx @@ -9,5 +9,12 @@ name::name(const char* const errorMessage)\ : parent(errorMessage)\ {\ }\ +\ +name::name(\ + const char* const errorMessage,\ + const libsex::Exception& previous)\ +: parent(errorMessage, previous)\ +{\ +}\ #endif diff --git a/include/libsex/throw.hxx b/include/libsex/throw.hxx index 230a264..036d103 100644 --- a/include/libsex/throw.hxx +++ b/include/libsex/throw.hxx @@ -3,14 +3,31 @@ #include +/** + * Macro to throw an exception. + * + * File name and line number are inserted automatically. + * + * @param class Which exception to throw. + * @param args... Optional. Arguments for message template. + */ #define THROW(class, args...) \ { \ throw libsex::formatted(__FILE__, __LINE__, ##args); \ } +/** + * Macro to throw another exception when an exception has + * been caught. + * + * Chains the previous exception and the newly created one + * together. + * + * @see THROW + */ #define RETHROW(class, args...) \ {\ - /*throw libsex::formatted(e, __FILE__, __LINE__, ##args);*/ \ + throw libsex::formatted(e, __FILE__, __LINE__, ##args); \ } #endif diff --git a/include/libsex/utility.hxx b/include/libsex/utility.hxx index 59b8c96..8a120a6 100644 --- a/include/libsex/utility.hxx +++ b/include/libsex/utility.hxx @@ -1,6 +1,8 @@ #ifndef LIBSEX_UTILITY_HXX #define LIBSEX_UTILITY_HXX +#include + #include // variadic argument fun #include // size_t @@ -55,6 +57,19 @@ T formatted( unsigned short line, ...) throw(); +/** + * Instanciates T with properly formatted message and + * a previous exception. + * + * @see formatted() + */ +template +T formatted( + const Exception& previous, + const char* const file, + unsigned short line, + ...) throw(); + }; // End of namespace. #include "utility.ixx" diff --git a/include/libsex/utility.ixx b/include/libsex/utility.ixx index 489d8cc..d75aac1 100644 --- a/include/libsex/utility.ixx +++ b/include/libsex/utility.ixx @@ -14,9 +14,9 @@ T formatted( va_list ap; va_start(ap, line); + // Fill buf with formatted T::TEMPLATE message. - vformat( - buf, Exception::LENGTH + 1, + vformat(buf, Exception::LENGTH + 1, file, line, T::TEMPLATE, ap);\ va_end(ap); @@ -24,4 +24,23 @@ T formatted( return T(buf); } +template +T formatted( + const Exception& previous, + const char* const file, + unsigned short line, + ...) throw() +{ + char buf[Exception::LENGTH + 1] = { 0 }; + + va_list ap; + va_start(ap, line); + vformat(buf, Exception::LENGTH + 1, + file, line, + T::TEMPLATE, ap);\ + va_end(ap); + + return T(buf, previous); +} + }; // End of namespace. diff --git a/tests/framework/MockException.cxx b/tests/framework/MockException.cxx index 88af2e9..2143879 100644 --- a/tests/framework/MockException.cxx +++ b/tests/framework/MockException.cxx @@ -6,3 +6,10 @@ MockException::MockException(const char* const message) throw() : libsex::Exception(message) { } + +MockException::MockException( + const char* const message, + const libsex::Exception& previous) throw() +: libsex::Exception(message, previous) +{ +} diff --git a/tests/framework/MockException.hxx b/tests/framework/MockException.hxx index c4dd985..2d04ee1 100644 --- a/tests/framework/MockException.hxx +++ b/tests/framework/MockException.hxx @@ -9,6 +9,9 @@ public: static const char* const TEMPLATE; MockException(const char* const message) throw(); + MockException( + const char* const message, + const libsex::Exception& previous) throw(); }; #endif diff --git a/tests/src/TestUtility.cxx b/tests/src/TestUtility.cxx index 1f4d7e0..716e658 100644 --- a/tests/src/TestUtility.cxx +++ b/tests/src/TestUtility.cxx @@ -3,6 +3,8 @@ #include +#include + void TestUtility::testShortTemplateWithoutFormatting() { char buf[100] = { 0 }; @@ -159,6 +161,27 @@ void TestUtility::testTemplateFactory() std::string(e.what())); } +void TestUtility::testChainedTemplateFactory() +{ + MockException e1 + = libsex::formatted( + "foobar.cxx", 42, + "VAR", 42); + + MockException e = libsex::formatted( + e1, + "foobar.cxx", 84, + "#exceptions", 1); + + std::stringstream act; + e.backtrace(act); + + CPPUNIT_ASSERT_EQUAL( + std::string("foobar.cxx:84: #exceptions=1\n" + "foobar.cxx:42: VAR=42"), + act.str()); +} + void TestUtility::assertBoundary( const char* const buffer, size_t boundary, diff --git a/tests/src/TestUtility.hxx b/tests/src/TestUtility.hxx index f8c5ef1..d252b0a 100644 --- a/tests/src/TestUtility.hxx +++ b/tests/src/TestUtility.hxx @@ -17,6 +17,7 @@ CPPUNIT_TEST_SUITE(TestUtility); CPPUNIT_TEST(testWhetherMultipleParametersDontOverflowBeforeFormatstring); CPPUNIT_TEST(testWhetherMultipleParametersDontOverflowInFormatstring); CPPUNIT_TEST(testTemplateFactory); + CPPUNIT_TEST(testChainedTemplateFactory); CPPUNIT_TEST_SUITE_END(); public: @@ -30,7 +31,9 @@ public: void testMultipleFormatParameters(); void testWhetherMultipleParametersDontOverflowBeforeFormatstring(); void testWhetherMultipleParametersDontOverflowInFormatstring(); + void testTemplateFactory(); + void testChainedTemplateFactory(); void assertBoundary( const char* const buffer, diff --git a/tests/src/UsageExamples.cxx b/tests/src/UsageExamples.cxx index b53cb4b..bfdc8cc 100644 --- a/tests/src/UsageExamples.cxx +++ b/tests/src/UsageExamples.cxx @@ -2,7 +2,10 @@ * Shows how this framework is supposed to be used. */ +// Needed for the tests in this file, not part of the +// examples. #include +#include // This is the way to declare an exception class. @@ -83,7 +86,7 @@ void UsageExamples::testSimpleThrowing() // arbitrary string. THROW(Error); } catch (Error& e) { - std::string exp("UsageExamples.cxx:84: Error!"); + std::string exp("UsageExamples.cxx:87: Error!"); std::string act(e.what()); CPPUNIT_ASSERT_EQUAL(exp, act); @@ -106,7 +109,7 @@ void UsageExamples::testThrowing() // containing the resulting string. THROW(MyException, "foobar", 42); } catch (MyException& e) { - std::string exp("UsageExamples.cxx:107: foobar is 42"); + std::string exp("UsageExamples.cxx:110: foobar is 42"); std::string act(e.what()); CPPUNIT_ASSERT_EQUAL(exp, act); @@ -133,12 +136,15 @@ void UsageExamples::testChaining() RETHROW(MyException, "bar", 42); } } catch (MyException& e) { - const char* exp = "UsageExamples.cxx:133: bar is 42\n" - "UsageExamples.cxx:128: foo is 21"; + const char* exp = "UsageExamples.cxx:136: bar is 42\n" + "UsageExamples.cxx:131: foo is 21"; + + std::stringstream act; + e.backtrace(act); CPPUNIT_ASSERT_EQUAL( std::string(exp), - std::string(e.what())); + act.str()); success = true; } diff --git a/tests/src/UsageExamples.hxx b/tests/src/UsageExamples.hxx index dd0efe2..1b98cde 100644 --- a/tests/src/UsageExamples.hxx +++ b/tests/src/UsageExamples.hxx @@ -9,7 +9,7 @@ CPPUNIT_TEST_SUITE(UsageExamples); CPPUNIT_TEST(testSimpleConstruction); CPPUNIT_TEST(testSimpleThrowing); CPPUNIT_TEST(testThrowing); - // CPPUNIT_TEST(testChaining); + CPPUNIT_TEST(testChaining); CPPUNIT_TEST_SUITE_END(); public: -- 2.11.4.GIT