Search code examples
localestring-formattingstringstreamfacetboost-test

BOOST_CHECK_EQUAL_COLLECTIONS with unsigned char outputs non-printable characters on mismatch


Is there any way to change the unsigned char output formatting of BOOST_CHECK_EQUAL_COLLECTIONS?

I'm using Boost.Test 1.37.0 to validate values in an unsigned char array:

//  result.Message is a fixed-size unsigned char array
//  result.Length is the length of the data inside result.Message

const unsigned expected_message[] = { 3, 60, 43, 17 };

BOOST_CHECK_EQUAL_COLLECTIONS(
    result.Message,
    result.Message + result.Length,
    expected_message,
    expected_message + sizeof(expected_message) / sizeof(*expected_message) );

and I get unprintable characters on mismatch:

test_foo.cpp(117): error in "test_bar": check { result.Message, result.Message + result.Length } == { expected_message, expected_message + sizeof(expected_message) /  sizeof(*expected_message) } failed. 
Mismatch in a position 1:  != 60
Mismatch in a position 2: < != 43
Mismatch in a position 3:          != 17

I temporarily changed expected_message to an unsigned array so it prints numbers rather than characters - similarly, I could copy result.Message to a new vector<unsigned> and compare against that:

vector<unsigned> result_message(result.Message, result.Message + result.Length);

which isn't terrible, but I'd prefer to compare against the original if possible.

Internally, BOOST_CHECK_EQUAL_COLLECTIONS is using a temporary stringstream that I can't access, but it got me wondering about ostream formatting.

I don't have a lot of experience dealing with facets and locales, but I'm wondering if I could use them somehow to make individual unsigned chars print as numbers instead of ASCII?


Solution

  • Much to my surprise, you can accomplish this by defining operator<< for unsigned char in the std namespace inside your test file (in my case, test_foo.cpp):

    namespace std {
    
    ostream &operator<<( ostream &os, const unsigned char &uc ) {
        return os << static_cast<unsigned>(uc);
    }
    
    }
    

    This gives:

    Mismatch in a position 0: 4 != 60
    Mismatch in a position 1: 60 != 43
    Mismatch in a position 2: 9 != 17