Skip to content
Snippets Groups Projects
Commit 59676019 authored by Stéphane Del Pino's avatar Stéphane Del Pino
Browse files

Improve handling of AssertionError

- Assert can now take one or two arguments: first argument is the assertion
  itself. The optional second argument is used to provide a custom error
  message.

- remove try/catch from main: AssertionError may now be catched in
  SignalManager. This allows to write the AssertionError message as well as to
  print the back trace and eventually pause the execution.
parent d39f4164
No related branches found
No related tags found
1 merge request!11Feature/mpi
...@@ -28,10 +28,8 @@ ...@@ -28,10 +28,8 @@
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
std::string filename = initialize(argc, argv); std::string filename = initialize(argc, argv);
std::map<std::string, double> method_cost_map; std::map<std::string, double> method_cost_map;
try {
if (filename != "") { if (filename != "") {
pout() << "Reading (gmsh) " << rang::style::underline << filename << rang::style::reset << " ...\n"; pout() << "Reading (gmsh) " << rang::style::underline << filename << rang::style::reset << " ...\n";
Timer gmsh_timer; Timer gmsh_timer;
...@@ -374,11 +372,6 @@ int main(int argc, char *argv[]) ...@@ -374,11 +372,6 @@ int main(int argc, char *argv[])
perr() << "Connectivity1D defined by number of nodes no more implemented\n"; perr() << "Connectivity1D defined by number of nodes no more implemented\n";
std::exit(0); std::exit(0);
} }
}
catch (const AssertError& error) {
perr() << error << '\n';
std::exit(1);
}
finalize(); finalize();
......
...@@ -7,12 +7,19 @@ ...@@ -7,12 +7,19 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
template <typename ErrorType>
void printAndThrow(const ErrorType& error)
{
throw error;
}
class AssertError class AssertError
{ {
private: private:
const std::string m_file; const std::string m_file;
const int m_line; const int m_line;
const std::string m_function; const std::string m_function;
const std::string m_test;
const std::string m_message; const std::string m_message;
public: public:
...@@ -22,11 +29,16 @@ class AssertError ...@@ -22,11 +29,16 @@ class AssertError
{ {
os << '\n' os << '\n'
<< rang::style::bold << rang::style::bold
<< "*** Assertion error ***\n" << "---------- Assertion error -----------\n"
<< " at " << assert_error.m_file << ':' << assert_error.m_line << '\n' << " at " << assert_error.m_file << ':' << assert_error.m_line << '\n'
<< " in " << assert_error.m_function << '\n' << " in " << assert_error.m_function << '\n'
<< "*** " << rang::fgB::red << assert_error.m_message << rang::fg::reset << " assertion (" << rang::fgB::red << assert_error.m_test << rang::fg::reset
<< rang::style::reset << '\n'; << ") failed!\n";
if (not assert_error.m_message.empty()) {
os << ' ' << rang::fgB::yellow << assert_error.m_message
<< rang::fg::reset << '\n';
}
os << "--------------------------------------" << rang::style::reset << '\n';
return os; return os;
} }
...@@ -35,10 +47,12 @@ class AssertError ...@@ -35,10 +47,12 @@ class AssertError
AssertError(std::string file, AssertError(std::string file,
int line, int line,
std::string function, std::string function,
std::string message) std::string test,
std::string message="")
: m_file(file), : m_file(file),
m_line(line), m_line(line),
m_function(function), m_function(function),
m_test(test),
m_message(message) m_message(message)
{ {
; ;
...@@ -59,17 +73,32 @@ PRAGMA_DIAGNOSTIC_POP ...@@ -59,17 +73,32 @@ PRAGMA_DIAGNOSTIC_POP
#ifdef NDEBUG #ifdef NDEBUG
// Useless test is there to check syntax even in optimized mode. Costs nothing. // Useless test is there to check syntax even in optimized mode. Costs nothing.
#define Assert(assertion) \ #define Assert(assertion,...) \
if (not _pastis_assert(assertion)) {} if (not _pastis_assert(assertion)) { \
using vargs_t = decltype(std::make_tuple(__VA_ARGS__)); \
static_assert(std::tuple_size_v<vargs_t> <= 1, \
"too many arguments"); \
}
#else // NDEBUG #else // NDEBUG
#define Assert(assertion) \ #define Assert(assertion,...) \
if (not _pastis_assert(assertion)) { \ if (not _pastis_assert(assertion)) { \
throw AssertError(__FILE__, \ using vargs_t = decltype(std::make_tuple(__VA_ARGS__)); \
static_assert(std::tuple_size_v<vargs_t> <= 1, \
"too many arguments"); \
if constexpr(std::tuple_size_v<vargs_t> == 0) { \
printAndThrow(AssertError(__FILE__, \
__LINE__, \
__PRETTY_FUNCTION__, \
#assertion)); \
} else { \
printAndThrow(AssertError(__FILE__, \
__LINE__, \ __LINE__, \
__PRETTY_FUNCTION__, \ __PRETTY_FUNCTION__, \
(#assertion)); \ #assertion, \
#__VA_ARGS__)); \
} \
} }
#endif // NDEBUG #endif // NDEBUG
......
#include <SignalManager.hpp> #include <SignalManager.hpp>
#include <PastisAssert.hpp>
#include <PastisOStream.hpp> #include <PastisOStream.hpp>
#include <BacktraceManager.hpp> #include <BacktraceManager.hpp>
...@@ -60,6 +61,19 @@ void SignalManager::handler(int signal) ...@@ -60,6 +61,19 @@ void SignalManager::handler(int signal)
std::signal(SIGINT, SIG_DFL); std::signal(SIGINT, SIG_DFL);
std::signal(SIGABRT, SIG_DFL); std::signal(SIGABRT, SIG_DFL);
std::exception_ptr eptr = std::current_exception();
try {
if (eptr) {
std::rethrow_exception(eptr);
}
}
catch(const AssertError& assert_error) {
perr() << assert_error << '\n';
}
catch(...) {
perr() << "Unknown exception!\n";
}
perr() << "\n *** " perr() << "\n *** "
<< rang::style::reset << rang::style::reset
<< rang::fg::reset << rang::fg::reset
......
...@@ -8,10 +8,22 @@ TEST_CASE("PastisAssert", "[utils]") { ...@@ -8,10 +8,22 @@ TEST_CASE("PastisAssert", "[utils]") {
const std::string filename = "filename"; const std::string filename = "filename";
const int line = 10; const int line = 10;
const std::string function = "function"; const std::string function = "function";
const std::string test = "test";
AssertError assert_error(filename, line, function, test);
REQUIRE(Catch::Detail::stringify(assert_error) == "\n---------- Assertion error -----------\n at filename:10\n in function\n assertion (test) failed!\n--------------------------------------\n");
}
SECTION("checking for assert error with message") {
const std::string filename = "filename";
const int line = 10;
const std::string function = "function";
const std::string test = "test";
const std::string message = "message"; const std::string message = "message";
AssertError assert_error(filename, line, function, message); AssertError assert_error(filename, line, function, test, message);
REQUIRE(Catch::Detail::stringify(assert_error) == "\n*** Assertion error ***\n at filename:10\n in function\n*** message\n"); REQUIRE(Catch::Detail::stringify(assert_error) == "\n---------- Assertion error -----------\n at filename:10\n in function\n assertion (test) failed!\n message\n--------------------------------------\n");
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment