123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222 |
- #ifndef TEST_SUPPORT_VERBOSE_ASSERT
- #define TEST_SUPPORT_VERBOSE_ASSERT
- #include <iostream>
- #include <cstdio>
- #include <sstream>
- #include <string>
- #include "test_macros.h"
- namespace verbose_assert {
- typedef std::basic_ostream<char>&(EndLType)(std::basic_ostream<char>&);
- template <class Stream, class Tp,
- class = decltype(std::declval<Stream&>() << std::declval<Tp const&>())>
- std::true_type IsStreamableImp(int);
- template <class Stream, class Tp> std::false_type IsStreamableImp(long);
- template <class Stream, class Tp>
- struct IsStreamable : decltype(IsStreamableImp<Stream, Tp>(0)) {};
- template <class Tp, int ST = (IsStreamable<decltype(std::cerr), Tp>::value ? 1
- : (IsStreamable<decltype(std::wcerr), Tp>::value ? 2 : -1))>
- struct SelectStream {
- static_assert(ST == -1, "specialization required for ST != -1");
- static void Print(Tp const&) { std::clog << "Value Not Streamable!\n"; }
- };
- template <class Tp>
- struct SelectStream<Tp, 1> {
- static void Print(Tp const& val) { std::cerr << val; }
- };
- template <class Tp>
- struct SelectStream<Tp, 2> {
- static void Print(Tp const& val) { std::wcerr << val; }
- };
- struct AssertData {
- AssertData(const char* xcheck, const char* xfile, const char* xfunc,
- unsigned long xline, bool xpassed = true)
- : passed(xpassed), check(xcheck), file(xfile), func(xfunc), line(xline),
- msg() {}
- AssertData& SetFailed(std::string xmsg = std::string()) {
- msg = xmsg;
- passed = false;
- return *this;
- }
- void PrintFailed() const {
- std::fprintf(stderr, "%s:%lu %s: Assertion '%s' failed.\n", file, line,
- func, check);
- if (!msg.empty())
- std::fprintf(stderr, "%s\n", msg.data());
- }
- bool passed;
- const char* check;
- const char* file;
- const char* func;
- unsigned long line;
- std::string msg;
- };
- // AssertHandler is the class constructed by failing CHECK macros. AssertHandler
- // will log information about the failures and abort when it is destructed.
- class AssertHandler {
- public:
- AssertHandler(AssertData const& Data)
- : passed(Data.passed) {
- if (!passed)
- Data.PrintFailed();
- }
- ~AssertHandler() TEST_NOEXCEPT_FALSE {
- if (!passed) {
- error_log << std::endl;
- std::abort();
- }
- }
- class LogType {
- friend class AssertHandler;
- template <class Tp>
- friend LogType& operator<<(LogType& log, Tp const& value) {
- if (!log.is_disabled) {
- SelectStream<Tp>::Print(value);
- }
- return log;
- }
- friend LogType& operator<<(LogType& log, EndLType* m) {
- if (!log.is_disabled) {
- SelectStream<EndLType*>::Print(m);
- }
- return log;
- }
- private:
- LogType(bool disable) : is_disabled(disable) {}
- bool is_disabled;
- LogType(LogType const&);
- LogType& operator=(LogType const&);
- };
- LogType& GetLog() {
- if (passed)
- return null_log;
- return error_log;
- }
- private:
- static LogType null_log;
- static LogType error_log;
- AssertHandler& operator=(const AssertHandler&) = delete;
- AssertHandler(const AssertHandler&) = delete;
- AssertHandler() = delete;
- private:
- bool passed;
- };
- AssertHandler::LogType AssertHandler::null_log(true);
- AssertHandler::LogType AssertHandler::error_log(false);
- template <class It1>
- std::string PrintRange(const char* Name, It1 F, It1 E) {
- std::stringstream ss;
- ss << " " << Name << " = [";
- while (F != E) {
- ss << *F;
- ++F;
- if (F != E)
- ss << ", ";
- }
- ss << "]\n";
- return ss.str();
- }
- template <class Tp, class Up>
- std::string PrintMismatch(Tp const& LHS, Up const& RHS, int Elem) {
- std::stringstream ss;
- ss << " Element " << Elem << " mismatched: `" << LHS << "` != `" << RHS
- << "`!\n";
- return ss.str();
- };
- struct EqualToComp {
- template <class Tp, class Up>
- bool operator()(Tp const& LHS, Up const& RHS) const {
- return LHS == RHS;
- }
- };
- template <class It1, class It2, class Comp>
- AssertData CheckCollectionsEqual(It1 F1, It1 E1, It2 F2, It2 E2,
- AssertData Data, Comp C = EqualToComp()) {
- const It1 F1Orig = F1;
- const It2 F2Orig = F2;
- bool Failed = false;
- std::string ErrorMsg;
- int Idx = 0;
- while (F1 != E1 && F2 != E2) {
- if (!(C(*F1, *F2))) {
- ErrorMsg += PrintMismatch(*F1, *F2, Idx);
- Failed = true;
- break;
- }
- ++Idx;
- ++F1;
- ++F2;
- }
- if (!Failed && (F1 != E1 || F2 != E2)) {
- ErrorMsg += " Ranges have different sizes!\n";
- Failed = true;
- }
- if (Failed) {
- ErrorMsg += PrintRange("LHS", F1Orig, E1);
- ErrorMsg += PrintRange("RHS", F2Orig, E2);
- Data.SetFailed(ErrorMsg);
- }
- return Data;
- }
- } // namespace verbose_assert
- #ifdef __GNUC__
- #define ASSERT_FN_NAME() __PRETTY_FUNCTION__
- #else
- #define ASSERT_FN_NAME() __func__
- #endif
- #define DISPLAY(...) " " #__VA_ARGS__ " = " << (__VA_ARGS__) << "\n"
- #define ASSERT(...) \
- ::verbose_assert::AssertHandler(::verbose_assert::AssertData( \
- #__VA_ARGS__, __FILE__, ASSERT_FN_NAME(), __LINE__,(__VA_ARGS__))).GetLog()
- #define ASSERT_EQ(LHS, RHS) \
- ASSERT(LHS == RHS) << DISPLAY(LHS) << DISPLAY(RHS)
- #define ASSERT_NEQ(LHS, RHS) \
- ASSERT(LHS != RHS) << DISPLAY(LHS) << DISPLAY(RHS)
- #define ASSERT_PRED(PRED, LHS, RHS) \
- ASSERT(PRED(LHS, RHS)) << DISPLAY(LHS) << DISPLAY(RHS)
- #define ASSERT_COLLECTION_EQ_COMP(F1, E1, F2, E2, Comp) \
- (::verbose_assert::AssertHandler( \
- ::verbose_assert::CheckCollectionsEqual( \
- F1, E1, F2, E2, \
- ::verbose_assert::AssertData("CheckCollectionsEqual(" #F1 ", " #E1 \
- ", " #F2 ", " #E2 ")", \
- __FILE__, ASSERT_FN_NAME(), __LINE__), \
- Comp)) \
- .GetLog())
- #define ASSERT_COLLECTION_EQ(F1, E1, F2, E2) \
- ASSERT_COLLECTION_EQ_COMP(F1, E1, F2, E2, ::verbose_assert::EqualToComp())
- #endif
|