- expectThrows
- expectFailsAssertion - fix asserts
This commit is contained in:
parent
c5ba6c3214
commit
a76e7f26cf
@ -43,7 +43,7 @@ set(SOURCES
|
||||
data/DataFixture.cpp
|
||||
data/DataUtils.cpp
|
||||
data/Data.cpp
|
||||
assert/assert.h
|
||||
assert/assert.cpp
|
||||
assert/backtrace_nonwindows.cpp
|
||||
assert/backtrace_windows.cpp
|
||||
assert/AssertFailed.cpp
|
||||
|
@ -10,7 +10,7 @@ namespace cpputils {
|
||||
|
||||
class AssertFailed final: public std::exception {
|
||||
public:
|
||||
AssertFailed(std::string message) : _message(std::move(message)) { }
|
||||
explicit AssertFailed(std::string message) : _message(std::move(message)) { }
|
||||
|
||||
const char *what() const throw() override {
|
||||
return _message.c_str();
|
||||
|
@ -1 +1,3 @@
|
||||
#include "assert.h"
|
||||
|
||||
thread_local int cpputils::_assert::DisableAbortOnFailedAssertionRAII::num_instances_ = 0;
|
||||
|
@ -10,36 +10,66 @@
|
||||
|
||||
#include "AssertFailed.h"
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include "backtrace.h"
|
||||
#include "../logging/logging.h"
|
||||
|
||||
namespace cpputils {
|
||||
namespace _assert {
|
||||
struct DisableAbortOnFailedAssertionRAII final {
|
||||
explicit DisableAbortOnFailedAssertionRAII()
|
||||
: thread_id_(std::this_thread::get_id()) {
|
||||
++num_instances_;
|
||||
}
|
||||
|
||||
~DisableAbortOnFailedAssertionRAII() {
|
||||
if (thread_id_ != std::this_thread::get_id()) {
|
||||
using namespace logging;
|
||||
LOG(ERR, "DisableAbortOnFailedAssertionRAII instance must be destructed in the same thread that created it");
|
||||
}
|
||||
--num_instances_;
|
||||
}
|
||||
|
||||
static int num_instances() {
|
||||
return num_instances_;
|
||||
}
|
||||
|
||||
private:
|
||||
static thread_local int num_instances_; // initialized to zero in assert.cpp
|
||||
|
||||
std::thread::id thread_id_;
|
||||
};
|
||||
|
||||
inline std::string format(const char *expr, const std::string &message, const char *file, int line) {
|
||||
std::string result = std::string()+"Assertion ["+expr+"] failed in "+file+":"+std::to_string(line)+": "+message+"\n\n" + backtrace();
|
||||
return result;
|
||||
}
|
||||
|
||||
inline void assert_fail_release [[noreturn]] (const char *expr, const std::string &message, const char *file, int line) {
|
||||
auto msg = format(expr, message, file, line);
|
||||
using namespace logging;
|
||||
auto msg = format(expr, message, file, line);
|
||||
LOG(ERR, msg);
|
||||
throw AssertFailed(msg);
|
||||
}
|
||||
|
||||
inline void assert_fail_debug [[noreturn]] (const char *expr, const std::string &message, const char *file, int line) {
|
||||
using namespace logging;
|
||||
LOG(ERR, format(expr, message, file, line));
|
||||
abort();
|
||||
auto msg = format(expr, message, file, line);
|
||||
LOG(ERR, msg);
|
||||
if (DisableAbortOnFailedAssertionRAII::num_instances() > 0) {
|
||||
throw AssertFailed(msg);
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NDEBUG
|
||||
//TODO Check whether disabling assertions in prod affects speed.
|
||||
# define ASSERT(expr, msg) (void)((expr) || (cpputils::_assert::assert_fail_release(#expr, msg, __FILE__, __LINE__),0))
|
||||
//TODO Check whether disabling assertions in prod affects speed.
|
||||
#define ASSERT(expr, msg) (void)((expr) || (cpputils::_assert::assert_fail_release(#expr, msg, __FILE__, __LINE__),0))
|
||||
#else
|
||||
# define ASSERT(expr, msg) (void)((expr) || (cpputils::_assert::assert_fail_debug(#expr, msg, __FILE__, __LINE__),0))
|
||||
#define ASSERT(expr, msg) (void)((expr) || (cpputils::_assert::assert_fail_debug(#expr, msg, __FILE__, __LINE__),0))
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
31
src/cpp-utils/testutils/ExpectThrows.h
Normal file
31
src/cpp-utils/testutils/ExpectThrows.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef MESSMER_CPPUTILS_EXPECTTHROWS_H
|
||||
#define MESSMER_CPPUTILS_EXPECTTHROWS_H
|
||||
|
||||
#include <gmock/gmock.h>
|
||||
#include <cpp-utils/assert/assert.h>
|
||||
|
||||
namespace cpputils {
|
||||
|
||||
template<class Exception, class Functor>
|
||||
inline void expectThrows(Functor&& functor, const char* expectMessageContains) {
|
||||
try {
|
||||
std::forward<Functor>(functor)();
|
||||
} catch (const Exception& e) {
|
||||
EXPECT_THAT(e.what(), testing::HasSubstr(expectMessageContains));
|
||||
return;
|
||||
}
|
||||
ADD_FAILURE() << "Expected to throw exception containing \""
|
||||
<< expectMessageContains << "\" but didn't throw";
|
||||
}
|
||||
|
||||
template<class Functor>
|
||||
inline void expectFailsAssertion(Functor&& functor, const char* expectMessageContains) {
|
||||
cpputils::_assert::DisableAbortOnFailedAssertionRAII _disableAbortOnFailedAssertionRAII;
|
||||
expectThrows<cpputils::AssertFailed>(std::forward<Functor>(functor), expectMessageContains);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -21,11 +21,19 @@ TEST(AssertTest_DebugBuild, DiesIfFalse) {
|
||||
);
|
||||
}
|
||||
|
||||
TEST(AssertTest_DebugBuild, whenDisablingAbort_thenThrowsIfFalse) {
|
||||
cpputils::_assert::DisableAbortOnFailedAssertionRAII _disableAbort;
|
||||
EXPECT_THROW(
|
||||
ASSERT(false, "bla"),
|
||||
cpputils::AssertFailed
|
||||
);
|
||||
}
|
||||
|
||||
TEST(AssertTest_DebugBuild, AssertMessage) {
|
||||
#if defined(_MSC_VER)
|
||||
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:\d+: my message)";
|
||||
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:\d+: my message)";
|
||||
#else
|
||||
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:[0-9]+: my message)";
|
||||
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:[0-9]+: my message)";
|
||||
#endif
|
||||
EXPECT_DEATH(
|
||||
ASSERT(2==5, "my message"),
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
//Include the ASSERT macro for a release build
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#define NDEBUG 1
|
||||
#endif
|
||||
#include "cpp-utils/assert/assert.h"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user