Simbody

Testing.h

Go to the documentation of this file.
00001 #ifndef SimTK_SimTKCOMMON_TESTING_H_
00002 #define SimTK_SimTKCOMMON_TESTING_H_
00003 
00004 /* -------------------------------------------------------------------------- *
00005  *                      SimTK Core: SimTKcommon                               *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK Core biosimulation toolkit originating from      *
00008  * Simbios, the NIH National Center for Physics-Based Simulation of           *
00009  * Biological Structures at Stanford, funded under the NIH Roadmap for        *
00010  * Medical Research, grant U54 GM072970. See https://simtk.org.               *
00011  *                                                                            *
00012  * Portions copyright (c) 2009 Stanford University and the Authors.           *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Permission is hereby granted, free of charge, to any person obtaining a    *
00017  * copy of this software and associated documentation files (the "Software"), *
00018  * to deal in the Software without restriction, including without limitation  *
00019  * the rights to use, copy, modify, merge, publish, distribute, sublicense,   *
00020  * and/or sell copies of the Software, and to permit persons to whom the      *
00021  * Software is furnished to do so, subject to the following conditions:       *
00022  *                                                                            *
00023  * The above copyright notice and this permission notice shall be included in *
00024  * all copies or substantial portions of the Software.                        *
00025  *                                                                            *
00026  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
00027  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,   *
00028  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL    *
00029  * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,    *
00030  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR      *
00031  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  *
00032  * USE OR OTHER DEALINGS IN THE SOFTWARE.                                     *
00033  * -------------------------------------------------------------------------- */
00034 
00035 #include "SimTKcommon/basics.h"
00036 #include "SimTKcommon/Simmatrix.h"
00037 #include "SimTKcommon/internal/Random.h"
00038 
00039 #include <cmath>     
00040 #include <ctime>
00041 #include <algorithm> 
00042 #include <iostream>
00043 
00049 namespace SimTK {
00050 
00161 
00162 
00163 
00164 
00165 class Test {
00166 public:
00167     class Subtest;
00168     Test(const std::string& name) : testName(name)
00169     {
00170         std::clog << "Starting test " << testName << " ...\n";
00171         startTime = std::clock(); 
00172     }
00173     ~Test() {
00174         std::clog << "Done. " << testName << " time: " 
00175                   << 1000*(std::clock()-startTime)/CLOCKS_PER_SEC << "ms.\n";
00176     }
00177 
00178     template <class T>
00179     static double defTol() {return (double)NTraits<typename CNT<T>::Precision>::getSignificant();}
00180 
00181     // For dissimilar types, the default tolerance is the narrowest of the two.
00182     template <class T1, class T2>
00183     static double defTol2() {return std::max(defTol<T1>(), defTol<T2>());}
00184 
00185     // Scale by the magnitude of the quantities being compared, so that we don't
00186     // ask for unreasonable precision. For magnitudes near zero, we'll be satisfied
00187     // if both are very small without demanding that they must also be relatively
00188     // close. That is, we use a relative tolerance for big numbers and an absolute
00189     // tolerance for small ones.
00190     static bool numericallyEqual(float v1, float v2, int n, double tol=defTol<float>()) {
00191         const float scale = n*std::max(std::max(std::abs(v1), std::abs(v2)), 1.0f);
00192         return std::abs(v1-v2) < scale*(float)tol;
00193     }
00194     static bool numericallyEqual(double v1, double v2, int n, double tol=defTol<double>()) {
00195         const double scale = n*std::max(std::max(std::abs(v1), std::abs(v2)), 1.0);
00196         return std::abs(v1-v2) < scale*(double)tol;
00197     }
00198     static bool numericallyEqual(long double v1, long double v2, int n, double tol=defTol<long double>()) {
00199         const long double scale = n*std::max(std::max(std::abs(v1), std::abs(v2)), 1.0l);
00200         return std::abs(v1-v2) < scale*(long double)tol;
00201     }
00202 
00203     // For integers we ignore tolerance.
00204     static bool numericallyEqual(int i1, int i2, int n, double tol=0) {return i1==i2;}
00205     static bool numericallyEqual(unsigned u1, unsigned u2, int n, double tol=0) {return u1==u2;}
00206 
00207     // Mixed floating types use default tolerance for the narrower type.
00208     static bool numericallyEqual(float v1, double v2, int n, double tol=defTol<float>())
00209     {   return numericallyEqual((double)v1, v2, n, tol); }
00210     static bool numericallyEqual(double v1, float v2, int n, double tol=defTol<float>())
00211     {   return numericallyEqual(v1, (double)v2, n, tol); }
00212     static bool numericallyEqual(float v1, long double v2, int n, double tol=defTol<float>())
00213     {   return numericallyEqual((long double)v1, v2, n, tol); }
00214     static bool numericallyEqual(long double v1, float v2, int n, double tol=defTol<float>())
00215     {   return numericallyEqual(v1, (long double)v2, n, tol); }
00216     static bool numericallyEqual(double v1, long double v2, int n, double tol=defTol<double>())
00217     {   return numericallyEqual((long double)v1, v2, n, tol); }
00218     static bool numericallyEqual(long double v1, double v2, int n, double tol=defTol<double>())
00219     {   return numericallyEqual(v1, (long double)v2, n, tol); }
00220 
00221     // Mixed int/floating just upgrades int to floating type.
00222     static bool numericallyEqual(int i1, float f2, int n, double tol=defTol<float>())
00223     {   return numericallyEqual((float)i1,f2,n,tol); }
00224     static bool numericallyEqual(float f1, int i2, int n, double tol=defTol<float>())
00225     {   return numericallyEqual(f1,(float)i2,n,tol); }
00226     static bool numericallyEqual(unsigned i1, float f2, int n, double tol=defTol<float>())
00227     {   return numericallyEqual((float)i1,f2,n,tol); }
00228     static bool numericallyEqual(float f1, unsigned i2, int n, double tol=defTol<float>())
00229     {   return numericallyEqual(f1,(float)i2,n,tol); }
00230     static bool numericallyEqual(int i1, double f2, int n, double tol=defTol<double>())
00231     {   return numericallyEqual((double)i1,f2,n,tol); }
00232     static bool numericallyEqual(double f1, int i2, int n, double tol=defTol<double>())
00233     {   return numericallyEqual(f1,(double)i2,n,tol); }
00234     static bool numericallyEqual(unsigned i1, double f2, int n, double tol=defTol<double>())
00235     {   return numericallyEqual((double)i1,f2,n,tol); }
00236     static bool numericallyEqual(double f1, unsigned i2, int n, double tol=defTol<double>())
00237     {   return numericallyEqual(f1,(double)i2,n,tol); }
00238     static bool numericallyEqual(int i1, long double f2, int n, double tol=defTol<long double>())
00239     {   return numericallyEqual((long double)i1,f2,n,tol); }
00240     static bool numericallyEqual(long double f1, int i2, int n, double tol=defTol<long double>())
00241     {   return numericallyEqual(f1,(long double)i2,n,tol); }
00242     static bool numericallyEqual(unsigned i1, long double f2, int n, double tol=defTol<long double>())
00243     {   return numericallyEqual((long double)i1,f2,n,tol); }
00244     static bool numericallyEqual(long double f1, unsigned i2, int n, double tol=defTol<long double>())
00245     {   return numericallyEqual(f1,(long double)i2,n,tol); }
00246 
00247     template <class P>
00248     static bool numericallyEqual(const std::complex<P>& v1, const std::complex<P>& v2, int n, double tol=defTol<P>()) {
00249         return numericallyEqual(v1.real(), v2.real(), n, tol)
00250             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00251     }
00252     template <class P>
00253     static bool numericallyEqual(const conjugate<P>& v1, const conjugate<P>& v2, int n, double tol=defTol<P>()) {
00254         return numericallyEqual(v1.real(), v2.real(), n, tol)
00255             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00256     }
00257     template <class P>
00258     static bool numericallyEqual(const std::complex<P>& v1, const conjugate<P>& v2, int n, double tol=defTol<P>()) {
00259         return numericallyEqual(v1.real(), v2.real(), n, tol)
00260             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00261     }
00262     template <class P>
00263     static bool numericallyEqual(const conjugate<P>& v1, const std::complex<P>& v2, int n, double tol=defTol<P>()) {
00264         return numericallyEqual(v1.real(), v2.real(), n, tol)
00265             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00266     }
00267     template <class P>
00268     static bool numericallyEqual(const negator<P>& v1, const negator<P>& v2, int n, double tol=defTol<P>()) {
00269         return numericallyEqual(-v1, -v2, n, tol);  // P, P
00270     }
00271     template <class P>
00272     static bool numericallyEqual(const P& v1, const negator<P>& v2, int n, double tol=defTol<P>()) {
00273         return numericallyEqual(-v1, -v2, n, tol);  // P, P
00274     }
00275     template <class P>
00276     static bool numericallyEqual(const negator<P>& v1, const P& v2, int n, double tol=defTol<P>()) {
00277         return numericallyEqual(-v1, -v2, n, tol);  // P, P
00278     }
00279     template <class P>
00280     static bool numericallyEqual(const negator<std::complex<P> >& v1, const conjugate<P>& v2, int n, double tol=defTol<P>()) {
00281         return numericallyEqual(-v1, -v2, n, tol);  // complex, conjugate
00282     }
00283     template <class P>
00284     static bool numericallyEqual(const negator<conjugate<P> >& v1, const std::complex<P>& v2, int n, double tol=defTol<P>()) {
00285         return numericallyEqual(-v1, -v2, n, tol);  // conjugate, complex
00286     }
00287     template <class P>
00288     static bool numericallyEqual(const std::complex<P>& v1, const negator<conjugate<P> >& v2, int n, double tol=defTol<P>()) {
00289         return numericallyEqual(-v1, -v2, n, tol); // complex, conjugate
00290     }
00291     template <class P>
00292     static bool numericallyEqual(const conjugate<P>& v1, const negator<std::complex<P> >& v2, int n, double tol=defTol<P>()) {
00293         return numericallyEqual(-v1, -v2, n, tol); // conjugate, complex
00294     }
00295     template <int M, class E1, int S1, class E2, int S2>
00296     static bool numericallyEqual(const Vec<M,E1,S1>& v1, const Vec<M,E2,S2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00297         for (int i=0; i<M; ++i) if (!numericallyEqual(v1[i],v2[i], n, tol)) return false;
00298         return true;
00299     }
00300     template <int N, class E1, int S1, class E2, int S2>
00301     static bool numericallyEqual(const Row<N,E1,S1>& v1, const Row<N,E2,S2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00302         for (int j=0; j<N; ++j) if (!numericallyEqual(v1[j],v2[j], n, tol)) return false;
00303         return true;
00304     }
00305     template <int M, int N, class E1, int CS1, int RS1, class E2, int CS2, int RS2>
00306     static bool numericallyEqual(const Mat<M,N,E1,CS1,RS1>& v1, const Mat<M,N,E2,CS2,RS2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00307         for (int j=0; j<N; ++j) if (!numericallyEqual(v1(j),v2(j), n, tol)) return false;
00308         return true;
00309     }
00310     template <int N, class E1, int S1, class E2, int S2>
00311     static bool numericallyEqual(const SymMat<N,E1,S1>& v1, const SymMat<N,E2,S2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00312         return numericallyEqual(v1.getAsVec(), v2.getAsVec(), n, tol);
00313     }
00314     template <class E1, class E2>
00315     static bool numericallyEqual(const VectorView_<E1>& v1, const VectorView_<E2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00316         if (v1.size() != v2.size()) return false;
00317         for (int i=0; i < v1.size(); ++i)
00318             if (!numericallyEqual(v1[i], v2[i], n, tol)) return false;
00319         return true;
00320     }
00321     template <class E1, class E2>
00322     static bool numericallyEqual(const Vector_<E1>& v1, const Vector_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00323     {   return numericallyEqual((const VectorView_<E1>&)v1, (const VectorView_<E2>&)v2, n, tol); }
00324 
00325     template <class E1, class E2>
00326     static bool numericallyEqual(const RowVectorView_<E1>& v1, const RowVectorView_<E2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00327         if (v1.size() != v2.size()) return false;
00328         for (int i=0; i < v1.size(); ++i)
00329             if (!numericallyEqual(v1[i], v2[i], n, tol)) return false;
00330         return true;
00331     }
00332     template <class E1, class E2>
00333     static bool numericallyEqual(const RowVector_<E1>& v1, const RowVector_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00334     {   return numericallyEqual((const RowVectorView_<E1>&)v1, (const RowVectorView_<E2>&)v2, n, tol); }
00335 
00336     template <class E1, class E2>
00337     static bool numericallyEqual(const MatrixView_<E1>& v1, const MatrixView_<E2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00338         if (v1.nrow() != v2.nrow() || v1.ncol() != v2.ncol()) return false;
00339         for (int j=0; j < v1.ncol(); ++j)
00340             if (!numericallyEqual(v1(j), v2(j), n, tol)) return false;
00341         return true;
00342     }
00343     template <class E1, class E2>
00344     static bool numericallyEqual(const Matrix_<E1>& m1, const Matrix_<E2>& m2, int n, double tol=(defTol2<E1,E2>()))
00345     {   return numericallyEqual((const MatrixView_<E1>&)m1, (const MatrixView_<E2>&)m2, n, tol); }
00346 
00347     template <class P>
00348     static bool numericallyEqual(const Rotation_<P>& R1, const Rotation_<P>& R2, int n, double tol=defTol<P>()) {
00349         return R1.isSameRotationToWithinAngle(R2, (Real)(n*tol));
00350     }
00351 
00352     template <class P>
00353     static bool numericallyEqual(const Transform_<P>& T1, const Transform_<P>& T2, int n, double tol=defTol<P>()) {
00354         return numericallyEqual(T1.R(), T2.R(), n, tol)
00355             && numericallyEqual(T1.p(), T2.p(), n, tol);
00356     }
00357 
00358     template <class P>
00359     static bool numericallyEqual(const UnitInertia_<P>& G1, const UnitInertia_<P>& G2, int n, double tol=defTol<P>()) {
00360         return numericallyEqual(G1.asSymMat33(),G2.asSymMat33(), n, tol);
00361     }
00362 
00363     template <class P>
00364     static bool numericallyEqual(const Inertia_<P>& I1, const Inertia_<P>& I2, int n, double tol=defTol<P>()) {
00365         return numericallyEqual(I1.asSymMat33(),I2.asSymMat33(), n, tol);
00366     }
00367 
00368     // Random numbers
00369     static Real randReal() {
00370         static Random::Uniform rand(-1,1);
00371         return rand.getValue();
00372     }
00373     static Complex randComplex() {return Complex(randReal(),randReal());}
00374     static Conjugate randConjugate() {return Conjugate(randReal(),randReal());}
00375     static float randFloat() {return (float)randReal();}
00376     static double randDouble() {return (double)randReal();}
00377 
00378     template <int M> static Vec<M> randVec() 
00379     {   Vec<M> v; for (int i=0; i<M; ++i) v[i]=randReal(); return v;}
00380     template <int N> static Row<N> randRow() {return ~randVec<N>();}
00381     template <int M, int N> static Mat<M,N> randMat()
00382     {   Mat<M,N> m; for (int j=0; j<N; ++j) m(j)=randVec<M>(); return m;}
00383     template <int N> static SymMat<N> randSymMat() 
00384     {   SymMat<N> s; s.updAsVec() = randVec<N*(N+1)/2>(); return s; }
00385 
00386     static Vector randVector(int m)
00387     {   Vector v(m); for (int i=0; i<m; ++i) v[i]=randReal(); return v;}
00388     static Matrix randMatrix(int m, int n)
00389     {   Matrix M(m,n); for (int j=0; j<n; ++j) M(j)=randVector(m); return M;}
00390 
00391     static Vec3 randVec3() {return randVec<3>();}
00392     static Mat33 randMat33() {return randMat<3,3>();}
00393     static SymMat33 randSymMat33() {return randSymMat<3>();}
00394     static SpatialVec randSpatialVec() {
00395         return SpatialVec(randVec3(), randVec3());
00396     }
00397     static SpatialMat randSpatialMat() {
00398         return SpatialMat(randMat33(), randMat33(),
00399                           randMat33(), randMat33());
00400     }
00401     static Rotation randRotation() {
00402         // Generate random angle and random axis to rotate around.
00403         return Rotation((Pi/2)*randReal(), randVec3());
00404     }
00405     static Transform randTransform() {
00406         return Transform(randRotation(), randVec3());
00407     }
00408 private:
00409     std::clock_t startTime;
00410     std::string  testName;
00411 };
00412 
00414 class Test::Subtest {
00415 public:
00416     Subtest(const std::string& name) : subtestName(name)
00417     {
00418         char padded[128];
00419         sprintf(padded, "%-20s", name.c_str());
00420         paddedName = std::string(padded);
00421         std::clog << "  " << paddedName << " ... " << std::flush;
00422         startTime = std::clock(); 
00423     }
00424     ~Subtest() {
00425         std::clog << "done. " << paddedName << " time: " 
00426                   << 1000*(std::clock()-startTime)/CLOCKS_PER_SEC << "ms.\n";
00427     }
00428 private:
00429     std::clock_t startTime;
00430     std::string  subtestName;
00431     std::string  paddedName; // name plus some blanks
00432 };
00433 
00434 } // namespace SimTK
00435 
00437 #define SimTK_START_TEST(testName)      \
00438     SimTK::Test simtk_test_(testName);  \
00439     try {
00440 
00442 #define SimTK_END_TEST() \
00443     } catch(const std::exception& e) {                  \
00444         std::cerr << "Test failed due to exception: "   \
00445                   << e.what() << std::endl;             \
00446         return 1;                                       \
00447     } catch(...) {                                      \
00448         std::cerr << "Test failed due to unrecognized exception.\n";    \
00449         return 1;                                       \
00450     }                                                   \
00451     return 0;
00452 
00455 #define SimTK_SUBTEST(testFunction) \
00456     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)();} while(false)
00457 
00458 
00459 #define SimTK_SUBTEST1(testFunction,arg1) \
00460     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1);} while(false)
00461 
00462 
00463 #define SimTK_SUBTEST2(testFunction,arg1,arg2) \
00464     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2);} while(false)
00465 
00466 
00467 #define SimTK_SUBTEST3(testFunction,arg1,arg2,arg3) \
00468     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2,arg3);} while(false)
00469 
00470 
00471 #define SimTK_SUBTEST4(testFunction,arg1,arg2,arg3,arg4) \
00472     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2,arg3,arg4);} while(false)
00473 
00475 #define SimTK_TEST(cond) {SimTK_ASSERT_ALWAYS((cond), "Test condition failed.");}
00476 
00479 #define SimTK_TEST_FAILED(msg) {SimTK_ASSERT_ALWAYS(!"Test case failed.", msg);}
00480 
00484 #define SimTK_TEST_FAILED1(fmt,a1) {SimTK_ASSERT1_ALWAYS(!"Test case failed.",fmt,a1);}
00485 
00489 #define SimTK_TEST_FAILED2(fmt,a1,a2) {SimTK_ASSERT2_ALWAYS(!"Test case failed.",fmt,a1,a2);}
00490 
00494 #define SimTK_TEST_EQ(v1,v2)    \
00495     {SimTK_ASSERT_ALWAYS(SimTK::Test::numericallyEqual((v1),(v2),1),   \
00496      "Test values should have been numerically equivalent at default tolerance.");}
00497 
00500 #define SimTK_TEST_EQ_SIZE(v1,v2,n)    \
00501     {SimTK_ASSERT1_ALWAYS(SimTK::Test::numericallyEqual((v1),(v2),(n)),   \
00502      "Test values should have been numerically equivalent at size=%d times default tolerance.",(n));}
00503 
00507 #define SimTK_TEST_EQ_TOL(v1,v2,tol)    \
00508     {SimTK_ASSERT1_ALWAYS(SimTK::Test::numericallyEqual((v1),(v2),1,(tol)),   \
00509      "Test values should have been numerically equivalent at tolerance=%g.",(tol));}
00510 
00514 #define SimTK_TEST_NOTEQ(v1,v2)    \
00515     {SimTK_ASSERT_ALWAYS(!SimTK::Test::numericallyEqual((v1),(v2),1),   \
00516      "Test values should NOT have been numerically equivalent (at default tolerance).");}
00517 
00521 #define SimTK_TEST_NOTEQ_SIZE(v1,v2,n)    \
00522     {SimTK_ASSERT1_ALWAYS(!SimTK::Test::numericallyEqual((v1),(v2),(n)),   \
00523      "Test values should NOT have been numerically equivalent at size=%d times default tolerance.",(n));}
00524 
00528 #define SimTK_TEST_NOTEQ_TOL(v1,v2,tol)    \
00529     {SimTK_ASSERT1_ALWAYS(!SimTK::Test::numericallyEqual((v1),(v2),1,(tol)),   \
00530      "Test values should NOT have been numerically equivalent at tolerance=%g.",(tol));}
00531 
00533 #define SimTK_TEST_MUST_THROW(stmt)             \
00534     do {int threw=0; try {stmt;}                \
00535         catch(const std::exception&){threw=1;}  \
00536         catch(...){threw=2;}                    \
00537         if (threw==0) SimTK_TEST_FAILED1("Expected statement\n----\n%s\n----\n  to throw an exception but it did not.",#stmt); \
00538         if (threw==2) SimTK_TEST_FAILED1("Expected statement\n%s\n  to throw an std::exception but it threw something else.",#stmt); \
00539     }while(false)
00540 
00542 #define SimTK_TEST_MUST_THROW_EXC(stmt,exc)     \
00543     do {int threw=0; try {stmt;}                \
00544         catch(const exc&){threw=1;}             \
00545         catch(...){threw=2;}                    \
00546         if (threw==0) SimTK_TEST_FAILED1("Expected statement\n----\n%s\n----\n  to throw an exception but it did not.",#stmt); \
00547         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); \
00548     }while(false)
00549 
00551 #define SimTK_TEST_MAY_THROW(stmt)             \
00552     do {int threw=0; try {stmt;}                \
00553         catch(const std::exception&){threw=1;}  \
00554         catch(...){threw=2;}                    \
00555         if (threw==2) SimTK_TEST_FAILED1("Expected statement\n%s\n  to throw an std::exception but it threw something else.",#stmt); \
00556     }while(false)
00557 
00559 #define SimTK_TEST_MAY_THROW_EXC(stmt,exc)     \
00560     do {int threw=0; try {stmt;}                \
00561         catch(const exc&){threw=1;}             \
00562         catch(...){threw=2;}                    \
00563         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); \
00564     }while(false)
00565 
00566 // When we're only required to throw in Debug, we have to suppress the
00567 // test case altogether in Release because it may cause damage. 
00568 #if defined(NDEBUG)
00569 
00570 
00571     #define SimTK_TEST_MUST_THROW_DEBUG(stmt)
00572 
00573 
00574     #define SimTK_TEST_MUST_THROW_EXC_DEBUG(stmt,exc)
00575 #else
00576 
00577 
00578     #define SimTK_TEST_MUST_THROW_DEBUG(stmt) SimTK_TEST_MUST_THROW(stmt)
00579 
00580 
00581     #define SimTK_TEST_MUST_THROW_EXC_DEBUG(stmt,exc) \
00582                 SimTK_TEST_MUST_THROW_EXC(stmt,exc)
00583 #endif
00584 
00585 
00586 
00587 
00588 //  End of Regression testing group.
00590 
00591 #endif // SimTK_SimTKCOMMON_TESTING_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines