Catch2: When and what types should be reported as hex as well as decimal types?

Created on 7 Jan 2017  路  2Comments  路  Source: catchorg/Catch2

In a way, this is continuation of #168, but updated with current state of reporting.

Currently, testing an unsigned int or unsigned long, that is larger than 255, prints out both decimal value of the variable and its hex representation. The same happens for ints, because integral literals have default type of int and won't be coerced to unsigned int because of expression decomposition.

Example

TEST_CASE("reporting") {
    unsigned long bits = 256;
    REQUIRE(bits == 0x101);
}

outputs failed: bits == 0x101 for: 256 (0x100) == 257 (0x101)

However, this does not happen for signed longs: (notice the "l" behind the literal)

    unsigned long bits = 256;
    REQUIRE(bits == 0x101l);

outputs failed: bits == 0x101l for: 256 (0x100) == 257

And for long longs (both signed and unsigned) nothing happens:

    unsigned long long bits = 256;
    REQUIRE(bits == 0x101ll);

outputs failed: bits == 0x101ll for: 256 == 257

The question is, is this desired behaviour? I would expect at least unsigned long longs to be also printed in hex, and different behaviour between printing an int and a long int seems surprising unless you already know about limitations caused by the expression decomposition.

One thing we could do is to add Hex wrapper class, that does nothing except modifies how Catch prints it out, so user could specify that he always wants the results to be printed hexadecimally.

    REQUIRE(bits == Hex(0x101l)); // -> bits == 0x101ll for: ... == 0x101
Discussion

Most helpful comment

I'd like to add that any form of a char (char, signed char, and unsigned char) is always printed as a character literal rather than as a decimal or hexadecimal value. This can be truly inconvenient in many cases where a char or any of it's type aliases like uint8_t are not used for character storage but for a numeric value. For example 8 bit pixel component values, 8 bit fields in a protocol or a file format, byte addressed memory/streams/whatever, etc. It would be very useful to be able to influence this behavior in some sane manner and tell it to use a specific format for these types, e.g. `0x%02x'.

What is particularly confusing is that overloading operator<< like it tells you to do in the documentation has no effect whatsoever for e.g. uint8_t as this is a type alias for unsigned char and there already is an overloaded version of toString for unsigned char so the overloaded operator<< is completely ignored.

Worse, it's not possible to fix it by proving a custom toString as that one already exists within Catch. What I ended up doing for the short term is to simply remove the toString implementation for unsigned char from catch.hpp, but that is far from an ideal solution. As a more permanent solution I've been thinking of changing my project to using a BOOST_STRONG_TYPEDEF of uint8_t instead of uint8_t directly. That way operator<< will probably work and at worst I can provide my own toString. But it seems rather insane to have to change my project code to accommodate the test framework.

All 2 comments

I'd like to add that any form of a char (char, signed char, and unsigned char) is always printed as a character literal rather than as a decimal or hexadecimal value. This can be truly inconvenient in many cases where a char or any of it's type aliases like uint8_t are not used for character storage but for a numeric value. For example 8 bit pixel component values, 8 bit fields in a protocol or a file format, byte addressed memory/streams/whatever, etc. It would be very useful to be able to influence this behavior in some sane manner and tell it to use a specific format for these types, e.g. `0x%02x'.

What is particularly confusing is that overloading operator<< like it tells you to do in the documentation has no effect whatsoever for e.g. uint8_t as this is a type alias for unsigned char and there already is an overloaded version of toString for unsigned char so the overloaded operator<< is completely ignored.

Worse, it's not possible to fix it by proving a custom toString as that one already exists within Catch. What I ended up doing for the short term is to simply remove the toString implementation for unsigned char from catch.hpp, but that is far from an ideal solution. As a more permanent solution I've been thinking of changing my project to using a BOOST_STRONG_TYPEDEF of uint8_t instead of uint8_t directly. That way operator<< will probably work and at worst I can provide my own toString. But it seems rather insane to have to change my project code to accommodate the test framework.

I suggest to print unsigned char as unsigned int as I think it is seldom (if at all) used for strings.

Was this page helpful?
0 / 5 - 0 ratings