|
Boost : |
From: John Torjo (john_at_[hidden])
Date: 2003-04-24 03:30:47
Hi all,
Is anyone interested in a slightly better assertion technique?
(to be used only in debug mode, of course)
It struck me when BOOST_CHECK_EQUAL macro.
What if I want something like: assert( (i == j) || (k < 0) );
If this fails, I would like to see some output similar to:
(2 == 2) || (5 < 0).
So, I came with a solution:
Transform assert( (i == j) || (k < 0) ); into
OP_ASSERT( (i op_ == j) op_ || (k op_ < 0) );
( op_ is a macro, of course).
Which means: prepend each operator with 'op_'
(in order to keep the assertion kind of readable)
A simple example to ilustrate the technique follows:
(the output when the assertion fails is a little scrambled;
don't let that cool you off - it will get much better)
If I improve the technique a little,
OP_ASSERT( (i op_ == j) op_ || (k op_ < 0) ) can generate output similar to
this:
(i == j) || (k < 0)
(2 == 2) || (-5 < 0)
^ assertion failed here
-------------------------------------------------
#include <assert.h>
#include <sstream>
#include <iostream>
// helper
struct test_helper
{
test_helper( std::stringstream & out, bool & bTestOk )
: m_out( out), m_bTestOk( bTestOk) {}
std::stringstream & out() const { return ( std::stringstream &)m_out; }
bool & test_ok() const { return ( bool&)m_bTestOk; }
private:
std::stringstream & m_out;
bool & m_bTestOk;
};
template< class type>
struct value_keeper
{
value_keeper( const type & val, std::stringstream & out, bool & bTestOk)
: m_val( val), m_out( out), m_bTestOk( bTestOk)
{}
std::stringstream & out() const { return ( std::stringstream &)m_out; }
bool & test_ok() const { return ( bool&)m_bTestOk; }
const type & m_val;
private:
std::stringstream & m_out;
bool & m_bTestOk;
};
// note: operator+ (could have been any operator; anyway,
// we just need it to return a value_keeper, which will
// further be compared.
template< class type> inline value_keeper< type> operator + ( const type &
first, const test_helper & second)
{ return value_keeper< type>( first, second.out(), second.test_ok() ); }
template< class type1, class type2>
inline bool operator==( const value_keeper< type1> & first, const type2
& second)
{
first.out() << " (" << first.m_val << " == " << second << ") ";
first.test_ok() &= ( first.m_val == second);
return ( first.m_val == second);
}
template< class type1, class type2>
inline bool operator||( const value_keeper< type1> & first, const type2
& second)
{
first.out() << " (" << first.m_val << " || " << second << ") ";
first.test_ok() &= ( first.m_val || second);
return ( first.m_val || second);
}
template< class type1, class type2>
inline bool operator<( const value_keeper< type1> & first, const type2 &
second)
{
first.out() << " (" << first.m_val << " < " << second << ") ";
first.test_ok() &= ( first.m_val < second);
return ( first.m_val < second);
}
#define op_ + test_helper( out_str, bTestOk)
#define OP_ASSERT(x) do { \
std::stringstream out_str; \
bool bTestOk = true; \
(x); \
if ( !bTestOk) std::cout << "Assertion failed: \n'" << #x << "'\n" <<
out_str.str() << std::endl; \
} while(0)
int main()
{
int i, j, k;
k = 1;
i = 2;
j = 3;
OP_ASSERT( i op_ == j );
// ... note: output a little scrambled, we can fix that!
OP_ASSERT( ( j op_ < i) op_ || (k op_ < 0) );
std::cin.get();
return 0;
}
-------------------------------------------------
Best,
John
-- John Torjo -- "Practical C++" column writer for builder.com.com Freelancer, C++ consultant mailto:john_at_[hidden]
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk