09 March 2009

Unit tests again

Life is funny sometimes. It's occasionally the case that one thinks some almost-trivial task is totally unnecessary, yet the "best practice" is to do it anyway&emdash;and the task turns out to catch or prevent a subtle but insidious error.

This evening I started writing unit tests for my code, and the first one on the list was the (almost) dead-simple "check direction vector" routine, which is overloaded on Blitz tinyvector length. The one-D case has to ensure that the cosine is bounded by one. Simple enough, right?
inline bool checkDirectionVector(
const blitz::TinyVector<double, 1>& omega)
{
return (abs(omega[0]) <= 1.0);
}

Well, in addition to testing that it called a value of 1.0 and -0.5 allowed, I tested whether -1.1 was disallowed. I was flabbergasted when I got the message
  /---- Unit test tBlitzStuff failed
| in <build/imclib/tests/tBlitzStuff.cpp> on line 32
| !checkDirectionVector(mu)
+-------------------------------

which corresponded to the code
    mu = -1.1;
TESTER_CHECKFORPASS(!checkDirectionVector(mu));


What the heck? Then I realized the mistake. My compiler (gcc 4.0) was silently downcasting a double to an integer, truncating -1.1 to -1, and then upcasting the result to the double -1.0, which satisfies the condition.

The solution is simple, to just use std::fabs(omega[0]) instead. But seriously? I never would have expected a failure on that unit test of all places. These things aren't as worthless as one might think.

0 comments:

Post a Comment