Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ test to verify equality operator is kept consistent with struct over time

Tags:

c++

testing

I voted up @TomalakGeretkal for a good note about by-contract; I'm haven't accepted an answer as my question is how to programatically check the equals function.


I have a POD struct & an equality operator, a (very) small part of a system with >100 engineers.

Over time I expect the struct to be modified (members added/removed/reordered) and I want to write a test to verify that the equality op is testing every member of the struct (eg is kept up to date as the struct changes).

As Tomalak pointed out - comments & "by contract" is often the best/only way to enforce this; however in my situation I expect issues and want to explore whether there are any ways to proactively catch (at least many) of the modifications.

I'm not coming up with a satisfactory answer - this is the best I've thought of:

-new up two instances struct (x, y), fill each with identical non-zero data.
-check x==y
-modify x "byte by byte"
    -take ptr to be (unsigned char*)&x
    -iterator over ptr (for sizeof(x))
        -increment the current byte
        -check !(x==y)
        -decrement the current byte
        -check x==y

The test passes if the equality operator caught every byte (NOTE: there is a caveat to this - not all bytes are used in the compilers representation of x, therefore the test would have to 'skip' these bytes - eg hard code ignore bytes)

My proposed test has significant problems: (at least) the 'don't care' bytes, and the fact that incrementing one byte of the types in x may not result in a valid value for the variable at that memory location.

Any better solutions?

(This shouldn't matter, but I'm using VS2008, rtti is off, googletest suite)

like image 543
some bits flipped Avatar asked May 02 '11 00:05

some bits flipped


2 Answers

Though tempting to make code 'fool-proof' with self-checks like this, it's my experience that keeping the self-checks themselves fool-proof is, well, a fool's errand.

Keep it simple and localise the effect of any changes. Write a comment in the struct definition making it clear that the equality operator must also be updated if the struct is; then, if this fails, it's just the programmer's fault.

I know that this will not seem optimal to you as it leaves the potential for user error in the future, but in reality you can't get around this (at least without making your code horrendously complicated), and often it's most practical just not to bother.

like image 105
Lightness Races in Orbit Avatar answered Nov 14 '22 23:11

Lightness Races in Orbit


I agree with (and upvoted) Tomalak's answer. It's unlikely that you'll find a foolproof solution. Nonetheless, one simple semi-automated approach could be to validate the expected size within the equality operator:

MyStruct::operator==(const MyStruct &rhs) 
{
  assert(sizeof(MyStruct) == 42);  // reminder to update as new members added

  // actual functionality here ...
}

This way, if any new members are added, the assert will fire until someone updates the equality operator. This isn't foolproof, of course. (Member vars might be replaced with something of same size, etc.) Nonetheless, it's a relatively simple (one line assert) that has a good shot of detecting the error case.

like image 35
Eric Pi Avatar answered Nov 14 '22 23:11

Eric Pi