- expectThrows
- expectFailsAssertion - fix asserts
This commit is contained in:
parent
c5ba6c3214
commit
a76e7f26cf
@ -43,7 +43,7 @@ set(SOURCES
|
|||||||
data/DataFixture.cpp
|
data/DataFixture.cpp
|
||||||
data/DataUtils.cpp
|
data/DataUtils.cpp
|
||||||
data/Data.cpp
|
data/Data.cpp
|
||||||
assert/assert.h
|
assert/assert.cpp
|
||||||
assert/backtrace_nonwindows.cpp
|
assert/backtrace_nonwindows.cpp
|
||||||
assert/backtrace_windows.cpp
|
assert/backtrace_windows.cpp
|
||||||
assert/AssertFailed.cpp
|
assert/AssertFailed.cpp
|
||||||
|
@ -10,7 +10,7 @@ namespace cpputils {
|
|||||||
|
|
||||||
class AssertFailed final: public std::exception {
|
class AssertFailed final: public std::exception {
|
||||||
public:
|
public:
|
||||||
AssertFailed(std::string message) : _message(std::move(message)) { }
|
explicit AssertFailed(std::string message) : _message(std::move(message)) { }
|
||||||
|
|
||||||
const char *what() const throw() override {
|
const char *what() const throw() override {
|
||||||
return _message.c_str();
|
return _message.c_str();
|
||||||
|
@ -1 +1,3 @@
|
|||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
|
|
||||||
|
thread_local int cpputils::_assert::DisableAbortOnFailedAssertionRAII::num_instances_ = 0;
|
||||||
|
@ -10,30 +10,60 @@
|
|||||||
|
|
||||||
#include "AssertFailed.h"
|
#include "AssertFailed.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <thread>
|
||||||
#include "backtrace.h"
|
#include "backtrace.h"
|
||||||
#include "../logging/logging.h"
|
#include "../logging/logging.h"
|
||||||
|
|
||||||
namespace cpputils {
|
namespace cpputils {
|
||||||
namespace _assert {
|
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) {
|
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();
|
std::string result = std::string()+"Assertion ["+expr+"] failed in "+file+":"+std::to_string(line)+": "+message+"\n\n" + backtrace();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void assert_fail_release [[noreturn]] (const char *expr, const std::string &message, const char *file, int line) {
|
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;
|
using namespace logging;
|
||||||
|
auto msg = format(expr, message, file, line);
|
||||||
LOG(ERR, msg);
|
LOG(ERR, msg);
|
||||||
throw AssertFailed(msg);
|
throw AssertFailed(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void assert_fail_debug [[noreturn]] (const char *expr, const std::string &message, const char *file, int line) {
|
inline void assert_fail_debug [[noreturn]] (const char *expr, const std::string &message, const char *file, int line) {
|
||||||
using namespace logging;
|
using namespace logging;
|
||||||
LOG(ERR, format(expr, message, file, line));
|
auto msg = format(expr, message, file, line);
|
||||||
|
LOG(ERR, msg);
|
||||||
|
if (DisableAbortOnFailedAssertionRAII::num_instances() > 0) {
|
||||||
|
throw AssertFailed(msg);
|
||||||
|
} else {
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
//TODO Check whether disabling assertions in prod affects speed.
|
//TODO Check whether disabling assertions in prod affects speed.
|
||||||
|
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,6 +21,14 @@ TEST(AssertTest_DebugBuild, DiesIfFalse) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(AssertTest_DebugBuild, whenDisablingAbort_thenThrowsIfFalse) {
|
||||||
|
cpputils::_assert::DisableAbortOnFailedAssertionRAII _disableAbort;
|
||||||
|
EXPECT_THROW(
|
||||||
|
ASSERT(false, "bla"),
|
||||||
|
cpputils::AssertFailed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(AssertTest_DebugBuild, AssertMessage) {
|
TEST(AssertTest_DebugBuild, AssertMessage) {
|
||||||
#if defined(_MSC_VER)
|
#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)";
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
//Include the ASSERT macro for a release build
|
//Include the ASSERT macro for a release build
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
#define NDEBUG
|
#define NDEBUG 1
|
||||||
#endif
|
#endif
|
||||||
#include "cpp-utils/assert/assert.h"
|
#include "cpp-utils/assert/assert.h"
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user