1

In some code i found the following line:

CPPUNIT_ASSERT(1, val.getBytefield().size());

Does this really compare the two parameters for equality? Normally, i would expect this comparison with CPPUNIT_ASSERT_EQUAL:

CPPUNIT_ASSERT_EQUAL(1, val.getBytefield().size());

The test compiles and the assertion works in case 1, but not in case 2. Where is the difference?

Doenbot3000
  • 27
  • 1
  • 8
  • `CPPUNIT_ASSERT` accepts only 1 argument, how can the first version work? – Danh Nov 30 '16 at 07:55
  • To be clear: We want to compare the size with the expected value 1. In case 1, the code compiles AND the assert is okay when running the test. In case 2, the code compiles BUT the assert is not okay when running the test. – Doenbot3000 Nov 30 '16 at 08:06

2 Answers2

1

This just looks like broken code to me, probably the result of some refactoring or other editing that was done.

The CPPUNIT_ASSERT macro takes a single argument—a condition expression—and asserts that that condition is true (i.e., fails if it is false).

This code is attempting to pass two arguments, but rather than functioning as an argument delimiter here, the comma is actually working as the (somewhat obscure) comma operator. The comma operator evaluates its first operand, discards the result, and then evaluates to the result of the second operand. Therefore, the initial 1 is an irrelevant no-op. The code is equivalent to:

CPPUNIT_ASSERT(val.getBytefield().size());

which means that it's asserting that the byte field has a non-zero size.

Obviously, this is different from your second snippet of code:

CPPUNIT_ASSERT_EQUAL(1, val.getBytefield().size());

which asserts that the byte field's size is exactly equal to 1.

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 1
    I see. So I should really refactor this code, because it is broken, right? I really cant think of a way, someone wanted to implement the first case here. – Doenbot3000 Nov 30 '16 at 08:05
0

It seems like you are using a compiler has an extension, which accepts 2 parameters to a single argument macro. I guess it's MSVC, see this

Hence, the macro will check if the first argument is true or not, in your case, it's 1, which is contextual converted to the bool value true, by this expansion

#define CPPUNIT_ASSERT(C) \
( CPPUNIT_NS::Asserter::failIf( !(C),                                   \
                                 CPPUNIT_NS::Message( "assertion failed",         \
                                                      "Expression: " #C), \
                                 CPPUNIT_SOURCELINE() ) )

You can double check my statement by change:

CPPUNIT_ASSERT(1, val.getBytefield().size());

with:

CPPUNIT_ASSERT(1000, val.getBytefield().size());

CPPUNIT_ASSERT_EQUAL(1, val.getBytefield().size());

From my experiment, .size() will likely return a std::size_t. From the definition of CPPUNIT_ASSERT_EQUAL:

#define CPPUNIT_ASSERT_EQUAL(expected,actual) \
                (assertEquals((expected),          \
                          (actual),                \
                          CPPUNIT_SOURCELINE(),    \
                          "" ) )

and assertEquals:

template<class T>
void assertEquals   (   const T &   expected,
    const T &   actual,
    SourceLine  sourceLine,
    const std::string &     message
)   

Because type of 1 (int) and return type of .size() (std::size_t) is different, then no matching function can be found, the compiler can not compile your code.


I think this is the solution:

CPPUNIT_ASSERT(1 == val.getBytefield().size());
CPPUNIT_ASSERT_EQUAL(std::size_t(1), val.getBytefield().size());
Danh
  • 5,916
  • 7
  • 30
  • 45