Skip to content

Commit a76e7f2

Browse files
committed
- expectThrows
- expectFailsAssertion - fix asserts
1 parent c5ba6c3 commit a76e7f2

7 files changed

Lines changed: 82 additions & 11 deletions

File tree

src/cpp-utils/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ set(SOURCES
4343
data/DataFixture.cpp
4444
data/DataUtils.cpp
4545
data/Data.cpp
46-
assert/assert.h
46+
assert/assert.cpp
4747
assert/backtrace_nonwindows.cpp
4848
assert/backtrace_windows.cpp
4949
assert/AssertFailed.cpp

src/cpp-utils/assert/AssertFailed.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace cpputils {
1010

1111
class AssertFailed final: public std::exception {
1212
public:
13-
AssertFailed(std::string message) : _message(std::move(message)) { }
13+
explicit AssertFailed(std::string message) : _message(std::move(message)) { }
1414

1515
const char *what() const throw() override {
1616
return _message.c_str();

src/cpp-utils/assert/assert.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
11
#include "assert.h"
2+
3+
thread_local int cpputils::_assert::DisableAbortOnFailedAssertionRAII::num_instances_ = 0;

src/cpp-utils/assert/assert.h

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,66 @@
1010

1111
#include "AssertFailed.h"
1212
#include <iostream>
13+
#include <thread>
1314
#include "backtrace.h"
1415
#include "../logging/logging.h"
1516

1617
namespace cpputils {
1718
namespace _assert {
19+
struct DisableAbortOnFailedAssertionRAII final {
20+
explicit DisableAbortOnFailedAssertionRAII()
21+
: thread_id_(std::this_thread::get_id()) {
22+
++num_instances_;
23+
}
24+
25+
~DisableAbortOnFailedAssertionRAII() {
26+
if (thread_id_ != std::this_thread::get_id()) {
27+
using namespace logging;
28+
LOG(ERR, "DisableAbortOnFailedAssertionRAII instance must be destructed in the same thread that created it");
29+
}
30+
--num_instances_;
31+
}
32+
33+
static int num_instances() {
34+
return num_instances_;
35+
}
36+
37+
private:
38+
static thread_local int num_instances_; // initialized to zero in assert.cpp
39+
40+
std::thread::id thread_id_;
41+
};
42+
1843
inline std::string format(const char *expr, const std::string &message, const char *file, int line) {
1944
std::string result = std::string()+"Assertion ["+expr+"] failed in "+file+":"+std::to_string(line)+": "+message+"\n\n" + backtrace();
2045
return result;
2146
}
2247

2348
inline void assert_fail_release [[noreturn]] (const char *expr, const std::string &message, const char *file, int line) {
24-
auto msg = format(expr, message, file, line);
2549
using namespace logging;
50+
auto msg = format(expr, message, file, line);
2651
LOG(ERR, msg);
2752
throw AssertFailed(msg);
2853
}
2954

3055
inline void assert_fail_debug [[noreturn]] (const char *expr, const std::string &message, const char *file, int line) {
3156
using namespace logging;
32-
LOG(ERR, format(expr, message, file, line));
33-
abort();
57+
auto msg = format(expr, message, file, line);
58+
LOG(ERR, msg);
59+
if (DisableAbortOnFailedAssertionRAII::num_instances() > 0) {
60+
throw AssertFailed(msg);
61+
} else {
62+
abort();
63+
}
3464
}
3565
}
3666
}
3767

3868
#ifdef NDEBUG
39-
//TODO Check whether disabling assertions in prod affects speed.
40-
# define ASSERT(expr, msg) (void)((expr) || (cpputils::_assert::assert_fail_release(#expr, msg, __FILE__, __LINE__),0))
69+
//TODO Check whether disabling assertions in prod affects speed.
70+
#define ASSERT(expr, msg) (void)((expr) || (cpputils::_assert::assert_fail_release(#expr, msg, __FILE__, __LINE__),0))
4171
#else
42-
# define ASSERT(expr, msg) (void)((expr) || (cpputils::_assert::assert_fail_debug(#expr, msg, __FILE__, __LINE__),0))
72+
#define ASSERT(expr, msg) (void)((expr) || (cpputils::_assert::assert_fail_debug(#expr, msg, __FILE__, __LINE__),0))
4373
#endif
4474

4575
#endif
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
#ifndef MESSMER_CPPUTILS_EXPECTTHROWS_H
4+
#define MESSMER_CPPUTILS_EXPECTTHROWS_H
5+
6+
#include <gmock/gmock.h>
7+
#include <cpp-utils/assert/assert.h>
8+
9+
namespace cpputils {
10+
11+
template<class Exception, class Functor>
12+
inline void expectThrows(Functor&& functor, const char* expectMessageContains) {
13+
try {
14+
std::forward<Functor>(functor)();
15+
} catch (const Exception& e) {
16+
EXPECT_THAT(e.what(), testing::HasSubstr(expectMessageContains));
17+
return;
18+
}
19+
ADD_FAILURE() << "Expected to throw exception containing \""
20+
<< expectMessageContains << "\" but didn't throw";
21+
}
22+
23+
template<class Functor>
24+
inline void expectFailsAssertion(Functor&& functor, const char* expectMessageContains) {
25+
cpputils::_assert::DisableAbortOnFailedAssertionRAII _disableAbortOnFailedAssertionRAII;
26+
expectThrows<cpputils::AssertFailed>(std::forward<Functor>(functor), expectMessageContains);
27+
}
28+
29+
}
30+
31+
#endif

test/cpp-utils/assert/assert_debug_test.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,19 @@ TEST(AssertTest_DebugBuild, DiesIfFalse) {
2121
);
2222
}
2323

24+
TEST(AssertTest_DebugBuild, whenDisablingAbort_thenThrowsIfFalse) {
25+
cpputils::_assert::DisableAbortOnFailedAssertionRAII _disableAbort;
26+
EXPECT_THROW(
27+
ASSERT(false, "bla"),
28+
cpputils::AssertFailed
29+
);
30+
}
31+
2432
TEST(AssertTest_DebugBuild, AssertMessage) {
2533
#if defined(_MSC_VER)
26-
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:\d+: my message)";
34+
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:\d+: my message)";
2735
#else
28-
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:[0-9]+: my message)";
36+
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:[0-9]+: my message)";
2937
#endif
3038
EXPECT_DEATH(
3139
ASSERT(2==5, "my message"),

test/cpp-utils/assert/assert_release_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
//Include the ASSERT macro for a release build
1010
#ifndef NDEBUG
11-
#define NDEBUG
11+
#define NDEBUG 1
1212
#endif
1313
#include "cpp-utils/assert/assert.h"
1414

0 commit comments

Comments
 (0)