subcommanderblog.wordpress.com

Subcommander Development Blog

CPPUNIT_ASSERT_EQUAL and custom data types

with 2 comments

To write more bookmark specific settings information to the configuration file I rewrote and simplified the code that reads subcommanders project settings.  I added a few tests for the new refactored code and  used a ccpunit feature  I had discovered a while ago: assertion traits.

If you have never heard of it read on and read what an assertion trait is and how it can help in handling custom data types in cppunit tests.

I’m using a custom build string class in the subversion related code to handle utf-8 encoded strings (sc::String) in Subcommander.

This works well, but there was an issue when trying to use Strings in test code:

CPPUNIT_ASSERT_EQUAL( expected, actual );

The assertion above “crashed” when printing its error message when one of the two strings was an empty string. It crashed in stl output stream code that was called by the following code inside cppunit (from TestAssert.h):

template <class T> struct assertion_traits
{
    static bool equal( const T& x, const T& y )
    {
        return x == y;
    }

    static std::string toString( const T& x )
    {
        OStringStream ost;
        ost << x;
        return ost.str();
    }
};

Very interesting code!  CPPUNIT_ASSERT_EQUAL(a,b) calls the equal method in this template to compare its two parameters a and b and calls the toString method to print the failure message if the assertion fails.

By using a template feature that’s called template specialization we can re-implement the template for a specific data type. If the compiler finds a specialization for a specific type, in my case my custom String class, it  uses the specialization for this type instead of  instantiating the generic T template for the type.

Here is the “new” code for my String class. It is nearly the same as the generic code but handles the empty string case in toString (there is also an example in cppunit’s  TestAssert.h file):

template<> struct CPPUNIT_NS::assertion_traits<sc::String>
{
  static bool equal( const sc::String& x, const sc::String& y )
  {
    return x == y;
  }

  static std::string toString( const sc::String& x )
  {
    std::string text = '"' + (!x.isEmpty() ? std::string(x) : "<null>") + '"';
    OStringStream ost;
    ost << text;
    return ost.str();
  }
};

The interesting thing about specializing the generic assertion traits is that you can add support for any custom data type to CPPUNIT_ASSERT_EQUAL with just a few lines of code.

This is even a documented feature. Surprisingly a google search on assertion_traits delivers only about 220 hits.

Either nobody knows about this feature or it just so obvious that nobody cares to write about it :-)

Advertisements

Written by hauner

Saturday, 10 January, 2009 at 18:14

Posted in subcommander

Tagged with ,

2 Responses

Subscribe to comments with RSS.

  1. I’m trying to specialize this for bool to print ‘true’ and ‘false’ in the error message, instead of ‘1’ and ‘0’. It compiles with no errors, but CppUnit is still using its generic implementation!

    #include

    #include
    #include

    namespace CppUnit {
    template
    struct assertion_traits
    {
    static bool equal(const bool& x, const bool& y )
    {
    std::cout << "moo" << std::endl;
    return x == y;
    }

    static std::string toString(const bool& x)
    {
    std::cout << "moo" << std::endl;
    std::ostringstream oss;
    oss << std::boolalpha << x;
    return oss.str();
    }
    };
    } // namespace CppUnit

    The tests never moo.

    Nicolas

    Thursday, 2 July, 2009 at 06:49

    • That is surprising, I can’t get this working with bool either. I always end up in the basic template implementation that prints 1/0 for true/false.

      I don’t understand it. It should be possible to specialize with bool… :(

      hauner

      Monday, 13 July, 2009 at 21:52


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: