Implemented ASSERT macro

This commit is contained in:
Sebastian Messmer 2015-07-22 13:38:36 +02:00
parent 9572cf9ea7
commit cce24dd64b
6 changed files with 122 additions and 2 deletions

1
assert/AssertFailed.cpp Normal file
View File

@ -0,0 +1 @@
#include "AssertFailed.h"

23
assert/AssertFailed.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
#ifndef MESSMER_CPP_UTILS_ASSERT_ASSERTFAILED_H
#define MESSMER_CPP_UTILS_ASSERT_ASSERTFAILED_H
#include <stdexcept>
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

39
assert/assert.h Normal file
View File

@ -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 <iostream>
#include <string>
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

View File

@ -6,6 +6,7 @@
#include <cryptopp/cryptopp/osrng.h>
#include <string>
#include <cstring>
#include "../assert/assert.h"
namespace cpputils {
@ -67,7 +68,7 @@ FixedSizeData<SIZE> FixedSizeData<SIZE>::CreateOSRandom() {
template<unsigned int SIZE>
FixedSizeData<SIZE> FixedSizeData<SIZE>::FromString(const std::string &data) {
assert(data.size() == STRING_LENGTH);
ASSERT(data.size() == STRING_LENGTH, "Wrong string size for parsing FixedSizeData");
FixedSizeData<SIZE> result;
CryptoPP::StringSource(data, true,
new CryptoPP::HexDecoder(
@ -85,7 +86,7 @@ std::string FixedSizeData<SIZE>::ToString() const {
new CryptoPP::StringSink(result)
)
);
assert(result.size() == STRING_LENGTH);
ASSERT(result.size() == STRING_LENGTH, "Created wrongly sized string");
return result;
}

View File

@ -0,0 +1,26 @@
#include <google/gtest/gtest.h>
#include <google/gmock/gmock.h>
//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"
);
}

View File

@ -0,0 +1,30 @@
#include <google/gtest/gtest.h>
#include <google/gmock/gmock.h>
//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"
));
}
}