Simbody 3.9
Loading...
Searching...
No Matches
SimTK Regression Testing

SimTK defines some utilities to facilitate the creation of regression tests for SimTK facilities. More...

Classes

class  SimTK::Test
 This is the main class to support testing. More...
 
class  SimTK::Test::Subtest
 Internal utility class for generating test messages for subtests. More...
 

Macros

#define SimTK_START_TEST(testName)
 Invoke this macro before anything else in your test's main().
 
#define SimTK_END_TEST()
 Invoke this macro as the last thing in your test's main().
 
#define SimTK_SUBTEST(testFunction)    do {SimTK::Test::Subtest sub(#testFunction); (testFunction)();} while(false)
 Invoke a subtest in the form of a no-argument function, arranging for some friendly output and timing information.
 
#define SimTK_SUBTEST1(testFunction, arg1)    do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1);} while(false)
 Invoke a subtest in the form of a 1-argument function, arranging for some friendly output and timing information.
 
#define SimTK_SUBTEST2(testFunction, arg1, arg2)    do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2);} while(false)
 Invoke a subtest in the form of a 2-argument function, arranging for some friendly output and timing information.
 
#define SimTK_SUBTEST3(testFunction, arg1, arg2, arg3)    do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2,arg3);} while(false)
 Invoke a subtest in the form of a 3-argument function, arranging for some friendly output and timing information.
 
#define SimTK_SUBTEST4(testFunction, arg1, arg2, arg3, arg4)    do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2,arg3,arg4);} while(false)
 Invoke a subtest in the form of a 4-argument function, arranging for some friendly output and timing information.
 
#define SimTK_TEST(cond)   {SimTK_ASSERT_ALWAYS((cond), "Test condition failed.");}
 Test that some condition holds and complain if it doesn't.
 
#define SimTK_TEST_FAILED(msg)   {SimTK_ASSERT_ALWAYS(!"Test case failed.", msg);}
 Call this if you have determined that a test case has failed and just need to report it and die.
 
#define SimTK_TEST_FAILED1(fmt, a1)   {SimTK_ASSERT1_ALWAYS(!"Test case failed.",fmt,a1);}
 Call this if you have determined that a test case has failed and just need to report it and die.
 
#define SimTK_TEST_FAILED2(fmt, a1, a2)   {SimTK_ASSERT2_ALWAYS(!"Test case failed.",fmt,a1,a2);}
 Call this if you have determined that a test case has failed and just need to report it and die.
 
#define SimTK_TEST_EQ(v1, v2)
 Test that two numerical values are equal to within a reasonable numerical error tolerance, using a relative and absolute error tolerance.
 
#define SimTK_TEST_EQ_SIZE(v1, v2, n)
 Test that two numerical values are equal to within a specified multiple of the default error tolerance.
 
#define SimTK_TEST_EQ_TOL(v1, v2, tol)
 Test that two numerical values are equal to within a specified numerical error tolerance, using a relative and absolute error tolerance.
 
#define SimTK_TEST_NOTEQ(v1, v2)
 Test that two numerical values are NOT equal to within a reasonable numerical error tolerance, using a relative and absolute error tolerance.
 
#define SimTK_TEST_NOTEQ_SIZE(v1, v2, n)
 Test that two numerical values are NOT equal to within a specified multiple of the default error tolerance, using a relative and absolute error tolerance.
 
#define SimTK_TEST_NOTEQ_TOL(v1, v2, tol)
 Test that two numerical values are NOT equal to within a specified numerical error tolerance, using a relative and absolute error tolerance.
 
#define SimTK_TEST_MUST_THROW(stmt)
 Test that the supplied statement throws an std::exception of some kind.
 
#define SimTK_TEST_MUST_THROW_SHOW(stmt)
 Test that the supplied statement throws an std::exception of some kind, and show what message got thrown.
 
#define SimTK_TEST_MUST_THROW_EXC(stmt, exc)
 Test that the supplied statement throws a particular exception.
 
#define SimTK_TEST_MAY_THROW(stmt)
 Allow the supplied statement to throw any std::exception without failing.
 
#define SimTK_TEST_MAY_THROW_EXC(stmt, exc)
 Allow the supplied statement to throw a particular exception without failing.
 
#define SimTK_TEST_MUST_THROW_DEBUG(stmt)   SimTK_TEST_MUST_THROW(stmt)
 Include a bad statement when in Debug and insist that it get caught, but don't include the statement at all in Release.
 
#define SimTK_TEST_MUST_THROW_EXC_DEBUG(stmt, exc)    SimTK_TEST_MUST_THROW_EXC(stmt,exc)
 Include a bad statement when in Debug and insist that it get caught, but don't include the statement at all in Release.
 

Detailed Description

SimTK defines some utilities to facilitate the creation of regression tests for SimTK facilities.

These utilities consist of a SimTK::Test class and related support macros.

Features include:

Here's how you use this facility:

#include "SimTKcommon.h"
void myFirstSubtest() {...}
void myNextSubtest() {...}
int main() {
     SimTK_START_TEST("OverallTestName");
         SimTK_SUBTEST(myFirstSubtest);
         SimTK_SUBTEST(myNextSubtest);
     SimTK_END_TEST();
}

The arguments to SimTK_SUBTEST are function names and will be called with "()" appended. If your subtest functions have arguments, use SimTK_SUBTEST1(name,arg) or SimTK_SUBTEST2(name,arg1,arg2) which will call name(arg) or name(arg1,arg2) as appropriate.

This will result in nice output including execution times for the overall test and the individual subtests, and arrange for any exceptions raised in the tests to be caught, properly reported, and cause a non-zero return from main(). If everything runs successfully, main() will return 0. Here is an example of the output produced:

Starting test TestScalar ...
  testIsNaN            ... done. testIsNaN            time: 0ms.
  testIsInf            ... done. testIsInf            time: 0ms.
  testIsFinite         ... done. testIsFinite         time: 0ms.
  testSignBit          ... done. testSignBit          time: 0ms.
  testSign             ... done. testSign             time: 0ms.
  testSquareAndCube    ... done. testSquareAndCube    time: 0ms.
Done. TestScalar time: 15ms.

(Admittedly the timings aren't much use in that example!)

Within your subtests, several useful macros and static functions are available. By using these macros, the resulting message will include the actual line number at which the test failure occurred.

     SimTK_TEST(cond)             -- this is like assert(cond)
     SimTK_TEST_FAILED("message") -- like assert(!"message")

     SimTK_TEST_EQ(a,b)           -- equal to within a default tolerance
     SimTK_TEST_NOTEQ(a,b)        -- not equal to within a default tolerance

     SimTK_TEST_EQ_SIZE(a,b,n)    -- equal to within n * default tolerance
     SimTK_TEST_NOTEQ_SIZE(a,b,n) -- not equal to within n * default tolerance

     SimTK_TEST_EQ_TOL(a,b,tol)   -- same as above with specified tolerance
     SimTK_TEST_NOTEQ_TOL(a,b,tol)

     SimTK_TEST_MUST_THROW(statement)        -- we expect the statement to throw some exception
     SimTK_TEST_MUST_THROW_EXC(statement, exception) -- we expect a particular exception type
     SimTK_TEST_MUST_THROW_DEBUG(statement)  -- same as above but only checked in Debug builds
     SimTK_TEST_MUST_THROW_EXC_DEBUG(statement, exception) -- ditto

     #define SimTK_TEST_SUPPRESS_MUST_THROW 
         -- Define this temporarily at top of test programs to make it 
            easier to locate an *unexpected* exception while debugging. It
            simply disables the "MUST_THROW" macros so you don't have to wade
            through them in the debugger to get to the actual problem.

The SimTK_TEST_EQ macros test scalar and composite numerical values for equality to within a numerical tolerance, using both relative and absolute tolerances. The default is the value of SignificantReal for the underlying numerical type. For composite types the equality test is done elementwise; that is, we apply it strictly to each pair of elements not to an overall norm.

The SimTK_TEST_EQ_SIZE macros allows you to specify a multiple of default tolerance to be used. This is necessary for most Matrix operations since attainable accuracy falls off with the size of the matrix. Typically, if the smallest dimension of the Matrix is n, then the tolerance you should allow is n*scalarTol where scalarTol is the default tolerance for a scalar operation. Note that you still need to specify size when comparing Vector or scalar values if those values were produced using a matrix computation.

The SimTK_TEST_EQ_TOL macros take a user-specified tolerance value for the elementwise tests, overriding the default.

The SimTK::Test class has a number of static methods that are useful in tests. Currently these are all for generating numerical objects filled with random numbers (all uniform between -1 and 1). These are:

     randReal()      randFloat()     randDouble()
     randComplex()   randConjugate()
     randVec<M>()    randRow<N>()    randMat<M,N>()  randSymMat<N>()
     randVector(m)   randMatrix(m,n)
     randVec3()      randMat33()
     randSpatialVec() randSpatialMat()
     randRotation()  randTransform()

These are invoked Test::randReal() etc.

Macro Definition Documentation

◆ SimTK_START_TEST

#define SimTK_START_TEST (   testName)
Value:
SimTK::Test simtk_test_(testName); \
try {
This is the main class to support testing.
Definition Testing.h:163

Invoke this macro before anything else in your test's main().

◆ SimTK_END_TEST

#define SimTK_END_TEST ( )
Value:
} catch(const std::exception& e) { \
std::cerr << "Test failed due to exception: " \
<< e.what() << std::endl; \
return 1; \
} catch(...) { \
std::cerr << "Test failed due to unrecognized exception.\n"; \
return 1; \
} \
return 0;

Invoke this macro as the last thing in your test's main().

◆ SimTK_SUBTEST

#define SimTK_SUBTEST (   testFunction)     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)();} while(false)

Invoke a subtest in the form of a no-argument function, arranging for some friendly output and timing information.

◆ SimTK_SUBTEST1

#define SimTK_SUBTEST1 (   testFunction,
  arg1 
)     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1);} while(false)

Invoke a subtest in the form of a 1-argument function, arranging for some friendly output and timing information.

◆ SimTK_SUBTEST2

#define SimTK_SUBTEST2 (   testFunction,
  arg1,
  arg2 
)     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2);} while(false)

Invoke a subtest in the form of a 2-argument function, arranging for some friendly output and timing information.

◆ SimTK_SUBTEST3

#define SimTK_SUBTEST3 (   testFunction,
  arg1,
  arg2,
  arg3 
)     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2,arg3);} while(false)

Invoke a subtest in the form of a 3-argument function, arranging for some friendly output and timing information.

◆ SimTK_SUBTEST4

#define SimTK_SUBTEST4 (   testFunction,
  arg1,
  arg2,
  arg3,
  arg4 
)     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2,arg3,arg4);} while(false)

Invoke a subtest in the form of a 4-argument function, arranging for some friendly output and timing information.

◆ SimTK_TEST

#define SimTK_TEST (   cond)    {SimTK_ASSERT_ALWAYS((cond), "Test condition failed.");}

Test that some condition holds and complain if it doesn't.

◆ SimTK_TEST_FAILED

#define SimTK_TEST_FAILED (   msg)    {SimTK_ASSERT_ALWAYS(!"Test case failed.", msg);}

Call this if you have determined that a test case has failed and just need to report it and die.

Pass the message as a string in quotes.

◆ SimTK_TEST_FAILED1

#define SimTK_TEST_FAILED1 (   fmt,
  a1 
)    {SimTK_ASSERT1_ALWAYS(!"Test case failed.",fmt,a1);}

Call this if you have determined that a test case has failed and just need to report it and die.

The message is a printf format string in quotes; here with one argument expected.

◆ SimTK_TEST_FAILED2

#define SimTK_TEST_FAILED2 (   fmt,
  a1,
  a2 
)    {SimTK_ASSERT2_ALWAYS(!"Test case failed.",fmt,a1,a2);}

Call this if you have determined that a test case has failed and just need to report it and die.

The message is a printf format string in quotes; here with two arguments expected.

◆ SimTK_TEST_EQ

#define SimTK_TEST_EQ (   v1,
  v2 
)
Value:
"Test values should have been numerically equivalent at default tolerance.");}
#define SimTK_ASSERT_ALWAYS(cond, msg)
Definition ExceptionMacros.h:349
static bool numericallyEqual(float v1, float v2, int n, double tol=defTol< float >())
Definition Testing.h:196

Test that two numerical values are equal to within a reasonable numerical error tolerance, using a relative and absolute error tolerance.

In the case of composite types, the test is performed elementwise.

◆ SimTK_TEST_EQ_SIZE

#define SimTK_TEST_EQ_SIZE (   v1,
  v2,
  n 
)
Value:
"Test values should have been numerically equivalent at size=%d times default tolerance.",(n));}
#define SimTK_ASSERT1_ALWAYS(cond, msg, a1)
Definition ExceptionMacros.h:351

Test that two numerical values are equal to within a specified multiple of the default error tolerance.

◆ SimTK_TEST_EQ_TOL

#define SimTK_TEST_EQ_TOL (   v1,
  v2,
  tol 
)
Value:
"Test values should have been numerically equivalent at tolerance=%g.",(tol));}

Test that two numerical values are equal to within a specified numerical error tolerance, using a relative and absolute error tolerance.

In the case of composite types, the test is performed elementwise.

◆ SimTK_TEST_NOTEQ

#define SimTK_TEST_NOTEQ (   v1,
  v2 
)
Value:
"Test values should NOT have been numerically equivalent (at default tolerance).");}

Test that two numerical values are NOT equal to within a reasonable numerical error tolerance, using a relative and absolute error tolerance.

In the case of composite types, the equality test is performed elementwise.

◆ SimTK_TEST_NOTEQ_SIZE

#define SimTK_TEST_NOTEQ_SIZE (   v1,
  v2,
  n 
)
Value:
"Test values should NOT have been numerically equivalent at size=%d times default tolerance.",(n));}

Test that two numerical values are NOT equal to within a specified multiple of the default error tolerance, using a relative and absolute error tolerance.

In the case of composite types, the equality test is performed elementwise.

◆ SimTK_TEST_NOTEQ_TOL

#define SimTK_TEST_NOTEQ_TOL (   v1,
  v2,
  tol 
)
Value:
"Test values should NOT have been numerically equivalent at tolerance=%g.",(tol));}

Test that two numerical values are NOT equal to within a specified numerical error tolerance, using a relative and absolute error tolerance.

In the case of composite types, the equality test is performed elementwise.

◆ SimTK_TEST_MUST_THROW

#define SimTK_TEST_MUST_THROW (   stmt)
Value:
do {int threw=0; try {stmt;} \
catch(const std::exception&){threw=1;} \
catch(...){threw=2;} \
if (threw==0) SimTK_TEST_FAILED1("Expected statement\n----\n%s\n----\n to throw an exception but it did not.",#stmt); \
if (threw==2) SimTK_TEST_FAILED1("Expected statement\n%s\n to throw an std::exception but it threw something else.",#stmt); \
}while(false)
#define SimTK_TEST_FAILED1(fmt, a1)
Call this if you have determined that a test case has failed and just need to report it and die.
Definition Testing.h:499

Test that the supplied statement throws an std::exception of some kind.

◆ SimTK_TEST_MUST_THROW_SHOW

#define SimTK_TEST_MUST_THROW_SHOW (   stmt)
Value:
do {int threw=0; try {stmt;} \
catch(const std::exception& e) {threw=1; \
std::cout << "(OK) Threw: " << e.what() << std::endl;} \
catch(...){threw=2;} \
if (threw==0) SimTK_TEST_FAILED1("Expected statement\n----\n%s\n----\n to throw an exception but it did not.",#stmt); \
if (threw==2) SimTK_TEST_FAILED1("Expected statement\n%s\n to throw an std::exception but it threw something else.",#stmt); \
}while(false)

Test that the supplied statement throws an std::exception of some kind, and show what message got thrown.

◆ SimTK_TEST_MUST_THROW_EXC

#define SimTK_TEST_MUST_THROW_EXC (   stmt,
  exc 
)
Value:
do {int threw=0; try {stmt;} \
catch(const exc&){threw=1;} \
catch(...){threw=2;} \
if (threw==0) SimTK_TEST_FAILED1("Expected statement\n----\n%s\n----\n to throw an exception but it did not.",#stmt); \
if (threw==2) SimTK_TEST_FAILED2("Expected statement\n----\n%s\n----\n to throw exception type %s but it threw something else.",#stmt,#exc); \
}while(false)

Test that the supplied statement throws a particular exception.

◆ SimTK_TEST_MAY_THROW

#define SimTK_TEST_MAY_THROW (   stmt)
Value:
do {int threw=0; try {stmt;} \
catch(const std::exception&){threw=1;} \
catch(...){threw=2;} \
if (threw==2) SimTK_TEST_FAILED1("Expected statement\n%s\n to throw an std::exception but it threw something else.",#stmt); \
}while(false)

Allow the supplied statement to throw any std::exception without failing.

◆ SimTK_TEST_MAY_THROW_EXC

#define SimTK_TEST_MAY_THROW_EXC (   stmt,
  exc 
)
Value:
do {int threw=0; try {stmt;} \
catch(const exc&){threw=1;} \
catch(...){threw=2;} \
if (threw==2) SimTK_TEST_FAILED2("Expected statement\n----\n%s\n----\n to throw exception type %s but it threw something else.",#stmt,#exc); \
}while(false)
#define SimTK_TEST_FAILED2(fmt, a1, a2)
Call this if you have determined that a test case has failed and just need to report it and die.
Definition Testing.h:504

Allow the supplied statement to throw a particular exception without failing.

◆ SimTK_TEST_MUST_THROW_DEBUG

#define SimTK_TEST_MUST_THROW_DEBUG (   stmt)    SimTK_TEST_MUST_THROW(stmt)

Include a bad statement when in Debug and insist that it get caught, but don't include the statement at all in Release.

◆ SimTK_TEST_MUST_THROW_EXC_DEBUG

#define SimTK_TEST_MUST_THROW_EXC_DEBUG (   stmt,
  exc 
)     SimTK_TEST_MUST_THROW_EXC(stmt,exc)

Include a bad statement when in Debug and insist that it get caught, but don't include the statement at all in Release.