From cce24dd64ba5c1e32cd814d9ba2c58300e58829b Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Wed, 22 Jul 2015 13:38:36 +0200 Subject: [PATCH] Implemented ASSERT macro --- assert/AssertFailed.cpp | 1 + assert/AssertFailed.h | 23 +++++++++++++++++ assert/assert.h | 39 +++++++++++++++++++++++++++++ data/FixedSizeData.h | 5 ++-- test/assert/assert_debug_test.cpp | 26 +++++++++++++++++++ test/assert/assert_release_test.cpp | 30 ++++++++++++++++++++++ 6 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 assert/AssertFailed.cpp create mode 100644 assert/AssertFailed.h create mode 100644 assert/assert.h create mode 100644 test/assert/assert_debug_test.cpp create mode 100644 test/assert/assert_release_test.cpp diff --git a/assert/AssertFailed.cpp b/assert/AssertFailed.cpp new file mode 100644 index 00000000..226ef4b4 --- /dev/null +++ b/assert/AssertFailed.cpp @@ -0,0 +1 @@ +#include "AssertFailed.h" diff --git a/assert/AssertFailed.h b/assert/AssertFailed.h new file mode 100644 index 00000000..279572d3 --- /dev/null +++ b/assert/AssertFailed.h @@ -0,0 +1,23 @@ +#pragma once +#ifndef MESSMER_CPP_UTILS_ASSERT_ASSERTFAILED_H +#define MESSMER_CPP_UTILS_ASSERT_ASSERTFAILED_H + +#include + +namespace cpputils { + + class AssertFailed : public std::exception { + public: + AssertFailed(const std::string &message) : _message(message) { } + + const char *what() const throw() override { + return _message.c_str(); + } + + private: + std::string _message; + }; + +} + +#endif diff --git a/assert/assert.h b/assert/assert.h new file mode 100644 index 00000000..03482544 --- /dev/null +++ b/assert/assert.h @@ -0,0 +1,39 @@ +#pragma once +#ifndef MESSMER_CPP_UTILS_ASSERT_ASSERT_H +#define MESSMER_CPP_UTILS_ASSERT_ASSERT_H + +/** + * This implements an ASSERT(expr, msg) macro. + * In a debug build, it will crash and halt the program on an assert failure. + * In a release build, it will throw an AssertFailed exception instead, which can then be caught. + */ + +#include "AssertFailed.h" +#include +#include + +namespace cpputils { + namespace _assert { + inline std::string format(const char *expr, const char *message, const char *file, int line) { + return std::string()+"Assertion ["+expr+"] failed in "+file+":"+std::to_string(line)+": "+message; + } + + inline void assert_fail_release(const char *expr, const char *message, const char *file, int line) { + throw AssertFailed(format(expr, message, file, line)); + } + + inline void assert_fail_debug(const char *expr, const char *message, const char *file, int line) { + std::cerr << format(expr, message, file, line) << std::endl; + 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)) +#else +# define ASSERT(expr, msg) (void)((expr) || (cpputils::_assert::assert_fail_debug(#expr, msg, __FILE__, __LINE__),0)) +#endif + +#endif diff --git a/data/FixedSizeData.h b/data/FixedSizeData.h index a99a12ff..028a5e9e 100644 --- a/data/FixedSizeData.h +++ b/data/FixedSizeData.h @@ -6,6 +6,7 @@ #include #include #include +#include "../assert/assert.h" namespace cpputils { @@ -67,7 +68,7 @@ FixedSizeData FixedSizeData::CreateOSRandom() { template FixedSizeData FixedSizeData::FromString(const std::string &data) { - assert(data.size() == STRING_LENGTH); + ASSERT(data.size() == STRING_LENGTH, "Wrong string size for parsing FixedSizeData"); FixedSizeData result; CryptoPP::StringSource(data, true, new CryptoPP::HexDecoder( @@ -85,7 +86,7 @@ std::string FixedSizeData::ToString() const { new CryptoPP::StringSink(result) ) ); - assert(result.size() == STRING_LENGTH); + ASSERT(result.size() == STRING_LENGTH, "Created wrongly sized string"); return result; } diff --git a/test/assert/assert_debug_test.cpp b/test/assert/assert_debug_test.cpp new file mode 100644 index 00000000..748b995d --- /dev/null +++ b/test/assert/assert_debug_test.cpp @@ -0,0 +1,26 @@ +#include +#include + +//Include the ASSERT macro for a debug build +#undef NDEBUG +#include "../../assert/assert.h" + +using testing::MatchesRegex; + +TEST(AssertTest_DebugBuild, DoesntDieIfTrue) { + ASSERT(true, "bla"); +} + +TEST(AssertTest_DebugBuild, DiesIfFalse) { + EXPECT_DEATH( + ASSERT(false, "bla"), + "" + ); +} + +TEST(AssertTest_DebugBuild, AssertMessage) { + EXPECT_DEATH( + ASSERT(2==5, "my message"), + "Assertion \\[2==5\\] failed in .*/assert_debug_test.cpp:25: my message" + ); +} \ No newline at end of file diff --git a/test/assert/assert_release_test.cpp b/test/assert/assert_release_test.cpp new file mode 100644 index 00000000..13c1cbca --- /dev/null +++ b/test/assert/assert_release_test.cpp @@ -0,0 +1,30 @@ +#include +#include + +//Include the ASSERT macro for a release build +#define NDEBUG +#include "../../assert/assert.h" + +using testing::MatchesRegex; + +TEST(AssertTest_ReleaseBuild, DoesntThrowIfTrue) { + ASSERT(true, "bla"); +} + +TEST(AssertTest_ReleaseBuild, ThrowsIfFalse) { + EXPECT_THROW( + ASSERT(false, "bla"), + cpputils::AssertFailed + ); +} + +TEST(AssertTest_ReleaseBuild, AssertMessage) { + try { + ASSERT(2==5, "my message"); + FAIL(); + } catch (const cpputils::AssertFailed &e) { + EXPECT_THAT(e.what(), MatchesRegex( + "Assertion \\[2==5\\] failed in .*/assert_release_test.cpp:23: my message" + )); + } +} \ No newline at end of file