Simbody  3.5
Testing.h
Go to the documentation of this file.
00001 #ifndef SimTK_SimTKCOMMON_TESTING_H_
00002 #define SimTK_SimTKCOMMON_TESTING_H_
00003 
00004 /* -------------------------------------------------------------------------- *
00005  *                       Simbody(tm): SimTKcommon                             *
00006  * -------------------------------------------------------------------------- *
00007  * This is part of the SimTK 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/home/simbody.  *
00011  *                                                                            *
00012  * Portions copyright (c) 2009-14 Stanford University and the Authors.        *
00013  * Authors: Michael Sherman                                                   *
00014  * Contributors:                                                              *
00015  *                                                                            *
00016  * Licensed under the Apache License, Version 2.0 (the "License"); you may    *
00017  * not use this file except in compliance with the License. You may obtain a  *
00018  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0.         *
00019  *                                                                            *
00020  * Unless required by applicable law or agreed to in writing, software        *
00021  * distributed under the License is distributed on an "AS IS" BASIS,          *
00022  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   *
00023  * See the License for the specific language governing permissions and        *
00024  * limitations under the License.                                             *
00025  * -------------------------------------------------------------------------- */
00026 
00027 #include "SimTKcommon/basics.h"
00028 #include "SimTKcommon/Simmatrix.h"
00029 #include "SimTKcommon/internal/Random.h"
00030 #include "SimTKcommon/internal/Timing.h"
00031 
00032 #include <cmath>     
00033 #include <algorithm> 
00034 #include <iostream>
00035 
00041 namespace SimTK {
00042 
00155 
00156 
00157 
00158 
00159 class Test {
00160 public:
00161     class Subtest;
00162     Test(const std::string& name)
00163     :   startCpuTime(SimTK::cpuTime()),
00164         startRealTime(SimTK::realTime()),
00165         testName(name)
00166     {
00167         std::clog << "Starting test " << testName << " ...\n";
00168     }
00169     ~Test() {
00170         const double finalRealTime=SimTK::realTime();
00171         const double finalCpuTime=SimTK::cpuTime();
00172         std::ostringstream fmt;
00173         fmt << std::fixed << std::setprecision(1);
00174         fmt << "\n" << testName << " done." 
00175             << " real/CPU ms: " << (finalRealTime-startRealTime)*1000
00176             << " / "  << (finalCpuTime-startCpuTime)*1000 <<std::endl;
00177         std::clog << fmt.str();
00178     }
00179 
00180     template <class T>
00181     static double defTol() {return (double)NTraits<typename CNT<T>::Precision>::getSignificant();}
00182 
00183     // For dissimilar types, the default tolerance is the narrowest of the two.
00184     template <class T1, class T2>
00185     static double defTol2() {return std::max(defTol<T1>(), defTol<T2>());}
00186 
00187     // Scale by the magnitude of the quantities being compared, so that we don't
00188     // ask for unreasonable precision. For magnitudes near zero, we'll be satisfied
00189     // if both are very small without demanding that they must also be relatively
00190     // close. That is, we use a relative tolerance for big numbers and an absolute
00191     // tolerance for small ones.
00192     static bool numericallyEqual(float v1, float v2, int n, double tol=defTol<float>()) {
00193         const float scale = n*std::max(std::max(std::abs(v1), std::abs(v2)), 1.0f);
00194         return std::abs(v1-v2) < scale*(float)tol;
00195     }
00196     static bool numericallyEqual(double v1, double v2, int n, double tol=defTol<double>()) {
00197         const double scale = n*std::max(std::max(std::abs(v1), std::abs(v2)), 1.0);
00198         return std::abs(v1-v2) < scale*(double)tol;
00199     }
00200     static bool numericallyEqual(long double v1, long double v2, int n, double tol=defTol<long double>()) {
00201         const long double scale = n*std::max(std::max(std::abs(v1), std::abs(v2)), 1.0l);
00202         return std::abs(v1-v2) < scale*(long double)tol;
00203     }
00204 
00205     // For integers we ignore tolerance.
00206     static bool numericallyEqual(int i1, int i2, int n, double tol=0) {return i1==i2;}
00207     static bool numericallyEqual(unsigned u1, unsigned u2, int n, double tol=0) {return u1==u2;}
00208 
00209     // Mixed floating types use default tolerance for the narrower type.
00210     static bool numericallyEqual(float v1, double v2, int n, double tol=defTol<float>())
00211     {   return numericallyEqual((double)v1, v2, n, tol); }
00212     static bool numericallyEqual(double v1, float v2, int n, double tol=defTol<float>())
00213     {   return numericallyEqual(v1, (double)v2, n, tol); }
00214     static bool numericallyEqual(float v1, long double v2, int n, double tol=defTol<float>())
00215     {   return numericallyEqual((long double)v1, v2, n, tol); }
00216     static bool numericallyEqual(long double v1, float v2, int n, double tol=defTol<float>())
00217     {   return numericallyEqual(v1, (long double)v2, n, tol); }
00218     static bool numericallyEqual(double v1, long double v2, int n, double tol=defTol<double>())
00219     {   return numericallyEqual((long double)v1, v2, n, tol); }
00220     static bool numericallyEqual(long double v1, double v2, int n, double tol=defTol<double>())
00221     {   return numericallyEqual(v1, (long double)v2, n, tol); }
00222 
00223     // Mixed int/floating just upgrades int to floating type.
00224     static bool numericallyEqual(int i1, float f2, int n, double tol=defTol<float>())
00225     {   return numericallyEqual((float)i1,f2,n,tol); }
00226     static bool numericallyEqual(float f1, int i2, int n, double tol=defTol<float>())
00227     {   return numericallyEqual(f1,(float)i2,n,tol); }
00228     static bool numericallyEqual(unsigned i1, float f2, int n, double tol=defTol<float>())
00229     {   return numericallyEqual((float)i1,f2,n,tol); }
00230     static bool numericallyEqual(float f1, unsigned i2, int n, double tol=defTol<float>())
00231     {   return numericallyEqual(f1,(float)i2,n,tol); }
00232     static bool numericallyEqual(int i1, double f2, int n, double tol=defTol<double>())
00233     {   return numericallyEqual((double)i1,f2,n,tol); }
00234     static bool numericallyEqual(double f1, int i2, int n, double tol=defTol<double>())
00235     {   return numericallyEqual(f1,(double)i2,n,tol); }
00236     static bool numericallyEqual(unsigned i1, double f2, int n, double tol=defTol<double>())
00237     {   return numericallyEqual((double)i1,f2,n,tol); }
00238     static bool numericallyEqual(double f1, unsigned i2, int n, double tol=defTol<double>())
00239     {   return numericallyEqual(f1,(double)i2,n,tol); }
00240     static bool numericallyEqual(int i1, long double f2, int n, double tol=defTol<long double>())
00241     {   return numericallyEqual((long double)i1,f2,n,tol); }
00242     static bool numericallyEqual(long double f1, int i2, int n, double tol=defTol<long double>())
00243     {   return numericallyEqual(f1,(long double)i2,n,tol); }
00244     static bool numericallyEqual(unsigned i1, long double f2, int n, double tol=defTol<long double>())
00245     {   return numericallyEqual((long double)i1,f2,n,tol); }
00246     static bool numericallyEqual(long double f1, unsigned i2, int n, double tol=defTol<long double>())
00247     {   return numericallyEqual(f1,(long double)i2,n,tol); }
00248 
00249     template <class P>
00250     static bool numericallyEqual(const std::complex<P>& v1, const std::complex<P>& v2, int n, double tol=defTol<P>()) {
00251         return numericallyEqual(v1.real(), v2.real(), n, tol)
00252             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00253     }
00254     template <class P>
00255     static bool numericallyEqual(const conjugate<P>& v1, const conjugate<P>& v2, int n, double tol=defTol<P>()) {
00256         return numericallyEqual(v1.real(), v2.real(), n, tol)
00257             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00258     }
00259     template <class P>
00260     static bool numericallyEqual(const std::complex<P>& v1, const conjugate<P>& v2, int n, double tol=defTol<P>()) {
00261         return numericallyEqual(v1.real(), v2.real(), n, tol)
00262             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00263     }
00264     template <class P>
00265     static bool numericallyEqual(const conjugate<P>& v1, const std::complex<P>& v2, int n, double tol=defTol<P>()) {
00266         return numericallyEqual(v1.real(), v2.real(), n, tol)
00267             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00268     }
00269     template <class P>
00270     static bool numericallyEqual(const negator<P>& v1, const negator<P>& v2, int n, double tol=defTol<P>()) {
00271         return numericallyEqual(-v1, -v2, n, tol);  // P, P
00272     }
00273     template <class P>
00274     static bool numericallyEqual(const P& v1, const negator<P>& v2, int n, double tol=defTol<P>()) {
00275         return numericallyEqual(-v1, -v2, n, tol);  // P, P
00276     }
00277     template <class P>
00278     static bool numericallyEqual(const negator<P>& v1, const P& v2, int n, double tol=defTol<P>()) {
00279         return numericallyEqual(-v1, -v2, n, tol);  // P, P
00280     }
00281     template <class P>
00282     static bool numericallyEqual(const negator<std::complex<P> >& v1, const conjugate<P>& v2, int n, double tol=defTol<P>()) {
00283         return numericallyEqual(-v1, -v2, n, tol);  // complex, conjugate
00284     }
00285     template <class P>
00286     static bool numericallyEqual(const negator<conjugate<P> >& v1, const std::complex<P>& v2, int n, double tol=defTol<P>()) {
00287         return numericallyEqual(-v1, -v2, n, tol);  // conjugate, complex
00288     }
00289     template <class P>
00290     static bool numericallyEqual(const std::complex<P>& v1, const negator<conjugate<P> >& v2, int n, double tol=defTol<P>()) {
00291         return numericallyEqual(-v1, -v2, n, tol); // complex, conjugate
00292     }
00293     template <class P>
00294     static bool numericallyEqual(const conjugate<P>& v1, const negator<std::complex<P> >& v2, int n, double tol=defTol<P>()) {
00295         return numericallyEqual(-v1, -v2, n, tol); // conjugate, complex
00296     }
00297     template <int M, class E1, int S1, class E2, int S2>
00298     static bool numericallyEqual(const Vec<M,E1,S1>& v1, const Vec<M,E2,S2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00299         for (int i=0; i<M; ++i) if (!numericallyEqual(v1[i],v2[i], n, tol)) return false;
00300         return true;
00301     }
00302     template <int N, class E1, int S1, class E2, int S2>
00303     static bool numericallyEqual(const Row<N,E1,S1>& v1, const Row<N,E2,S2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00304         for (int j=0; j<N; ++j) if (!numericallyEqual(v1[j],v2[j], n, tol)) return false;
00305         return true;
00306     }
00307     template <int M, int N, class E1, int CS1, int RS1, class E2, int CS2, int RS2>
00308     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>())) {
00309         for (int j=0; j<N; ++j) if (!numericallyEqual(v1(j),v2(j), n, tol)) return false;
00310         return true;
00311     }
00312     template <int N, class E1, int S1, class E2, int S2>
00313     static bool numericallyEqual(const SymMat<N,E1,S1>& v1, const SymMat<N,E2,S2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00314         return numericallyEqual(v1.getAsVec(), v2.getAsVec(), n, tol);
00315     }
00316     template <class E1, class E2>
00317     static bool numericallyEqual(const VectorView_<E1>& v1, const VectorView_<E2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00318         if (v1.size() != v2.size()) return false;
00319         for (int i=0; i < v1.size(); ++i)
00320             if (!numericallyEqual(v1[i], v2[i], n, tol)) return false;
00321         return true;
00322     }
00323     template <class E1, class E2>
00324     static bool numericallyEqual(const Vector_<E1>& v1, const Vector_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00325     {   return numericallyEqual((const VectorView_<E1>&)v1, (const VectorView_<E2>&)v2, n, tol); }
00326     template <class E1, class E2>
00327     static bool numericallyEqual(const Vector_<E1>& v1, const VectorView_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00328     {   return numericallyEqual((const VectorView_<E1>&)v1, (const VectorView_<E2>&)v2, n, tol); }
00329     template <class E1, class E2>
00330     static bool numericallyEqual(const VectorView_<E1>& v1, const Vector_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00331     {   return numericallyEqual((const VectorView_<E1>&)v1, (const VectorView_<E2>&)v2, n, tol); }
00332 
00333     template <class E1, class E2>
00334     static bool numericallyEqual(const RowVectorView_<E1>& v1, const RowVectorView_<E2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00335         if (v1.size() != v2.size()) return false;
00336         for (int i=0; i < v1.size(); ++i)
00337             if (!numericallyEqual(v1[i], v2[i], n, tol)) return false;
00338         return true;
00339     }
00340     template <class E1, class E2>
00341     static bool numericallyEqual(const RowVector_<E1>& v1, const RowVector_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00342     {   return numericallyEqual((const RowVectorView_<E1>&)v1, (const RowVectorView_<E2>&)v2, n, tol); }
00343     template <class E1, class E2>
00344     static bool numericallyEqual(const RowVector_<E1>& v1, const RowVectorView_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00345     {   return numericallyEqual((const RowVectorView_<E1>&)v1, (const RowVectorView_<E2>&)v2, n, tol); }
00346     template <class E1, class E2>
00347     static bool numericallyEqual(const RowVectorView_<E1>& v1, const RowVector_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00348     {   return numericallyEqual((const RowVectorView_<E1>&)v1, (const RowVectorView_<E2>&)v2, n, tol); }
00349 
00350     template <class E1, class E2>
00351     static bool numericallyEqual(const MatrixView_<E1>& v1, const MatrixView_<E2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00352         if (v1.nrow() != v2.nrow() || v1.ncol() != v2.ncol()) return false;
00353         for (int j=0; j < v1.ncol(); ++j)
00354             if (!numericallyEqual(v1(j), v2(j), n, tol)) return false;
00355         return true;
00356     }
00357     template <class E1, class E2>
00358     static bool numericallyEqual(const Matrix_<E1>& m1, const Matrix_<E2>& m2, int n, double tol=(defTol2<E1,E2>()))
00359     {   return numericallyEqual((const MatrixView_<E1>&)m1, (const MatrixView_<E2>&)m2, n, tol); }
00360     template <class E1, class E2>
00361     static bool numericallyEqual(const Matrix_<E1>& m1, const MatrixView_<E2>& m2, int n, double tol=(defTol2<E1,E2>()))
00362     {   return numericallyEqual((const MatrixView_<E1>&)m1, (const MatrixView_<E2>&)m2, n, tol); }
00363     template <class E1, class E2>
00364     static bool numericallyEqual(const MatrixView_<E1>& m1, const Matrix_<E2>& m2, int n, double tol=(defTol2<E1,E2>()))
00365     {   return numericallyEqual((const MatrixView_<E1>&)m1, (const MatrixView_<E2>&)m2, n, tol); }
00366 
00367     template <class P>
00368     static bool numericallyEqual(const Rotation_<P>& R1, const Rotation_<P>& R2, int n, double tol=defTol<P>()) {
00369         return R1.isSameRotationToWithinAngle(R2, (Real)(n*tol));
00370     }
00371 
00372     template <class P>
00373     static bool numericallyEqual(const Transform_<P>& T1, const Transform_<P>& T2, int n, double tol=defTol<P>()) {
00374         return numericallyEqual(T1.R(), T2.R(), n, tol)
00375             && numericallyEqual(T1.p(), T2.p(), n, tol);
00376     }
00377 
00378     template <class P>
00379     static bool numericallyEqual(const UnitInertia_<P>& G1, const UnitInertia_<P>& G2, int n, double tol=defTol<P>()) {
00380         return numericallyEqual(G1.asSymMat33(),G2.asSymMat33(), n, tol);
00381     }
00382 
00383     template <class P>
00384     static bool numericallyEqual(const Inertia_<P>& I1, const Inertia_<P>& I2, int n, double tol=defTol<P>()) {
00385         return numericallyEqual(I1.asSymMat33(),I2.asSymMat33(), n, tol);
00386     }
00387 
00388     // Random numbers
00389     static Real randReal() {
00390         static Random::Uniform rand(-1,1);
00391         return rand.getValue();
00392     }
00393     static Complex randComplex() {return Complex(randReal(),randReal());}
00394     static Conjugate randConjugate() {return Conjugate(randReal(),randReal());}
00395     static float randFloat() {return (float)randReal();}
00396     static double randDouble() {return (double)randReal();}
00397 
00398     template <int M> static Vec<M> randVec() 
00399     {   Vec<M> v; for (int i=0; i<M; ++i) v[i]=randReal(); return v;}
00400     template <int N> static Row<N> randRow() {return ~randVec<N>();}
00401     template <int M, int N> static Mat<M,N> randMat()
00402     {   Mat<M,N> m; for (int j=0; j<N; ++j) m(j)=randVec<M>(); return m;}
00403     template <int N> static SymMat<N> randSymMat() 
00404     {   SymMat<N> s; s.updAsVec() = randVec<N*(N+1)/2>(); return s; }
00405 
00406     static Vector randVector(int m)
00407     {   Vector v(m); for (int i=0; i<m; ++i) v[i]=randReal(); return v;}
00408     static Matrix randMatrix(int m, int n)
00409     {   Matrix M(m,n); for (int j=0; j<n; ++j) M(j)=randVector(m); return M;}
00410 
00411     static Vec3 randVec3() {return randVec<3>();}
00412     static Mat33 randMat33() {return randMat<3,3>();}
00413     static SymMat33 randSymMat33() {return randSymMat<3>();}
00414     static SpatialVec randSpatialVec() {
00415         return SpatialVec(randVec3(), randVec3());
00416     }
00417     static SpatialMat randSpatialMat() {
00418         return SpatialMat(randMat33(), randMat33(),
00419                           randMat33(), randMat33());
00420     }
00421     static Rotation randRotation() {
00422         // Generate random angle and random axis to rotate around.
00423         return Rotation((Pi/2)*randReal(), randVec3());
00424     }
00425     static Transform randTransform() {
00426         return Transform(randRotation(), randVec3());
00427     }
00428 private:
00429     const double startCpuTime;
00430     const double startRealTime;
00431     std::string  testName;
00432 };
00433 
00435 class Test::Subtest {
00436 public:
00437     Subtest(const std::string& name) 
00438     :   startCpuTime(SimTK::cpuTime()),
00439         startRealTime(SimTK::realTime()),
00440         subtestName(name)
00441     {
00442         std::clog << "  " << subtestName << " ...\n" << std::flush;
00443     }
00444     ~Subtest() {
00445         const double finalRealTime=SimTK::realTime();
00446         const double finalCpuTime=SimTK::cpuTime();
00447         std::ostringstream fmt;
00448         fmt << std::fixed << std::setprecision(1);
00449         fmt << "  " << subtestName << " done."
00450             << " real/CPU ms: " << (finalRealTime-startRealTime)*1000
00451             << " / "  << (finalCpuTime-startCpuTime)*1000 <<std::endl;
00452         std::clog << fmt.str();
00453     }
00454 private:
00455     const double startCpuTime;
00456     const double startRealTime;
00457     std::string  subtestName;
00458 };
00459 
00460 } // namespace SimTK
00461 
00463 #define SimTK_START_TEST(testName)      \
00464     SimTK::Test simtk_test_(testName);  \
00465     try {
00466 
00468 #define SimTK_END_TEST() \
00469     } catch(const std::exception& e) {                  \
00470         std::cerr << "Test failed due to exception: "   \
00471                   << e.what() << std::endl;             \
00472         return 1;                                       \
00473     } catch(...) {                                      \
00474         std::cerr << "Test failed due to unrecognized exception.\n";    \
00475         return 1;                                       \
00476     }                                                   \
00477     return 0;
00478 
00481 #define SimTK_SUBTEST(testFunction) \
00482     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)();} while(false)
00483 
00484 
00485 #define SimTK_SUBTEST1(testFunction,arg1) \
00486     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1);} while(false)
00487 
00488 
00489 #define SimTK_SUBTEST2(testFunction,arg1,arg2) \
00490     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2);} while(false)
00491 
00492 
00493 #define SimTK_SUBTEST3(testFunction,arg1,arg2,arg3) \
00494     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2,arg3);} while(false)
00495 
00496 
00497 #define SimTK_SUBTEST4(testFunction,arg1,arg2,arg3,arg4) \
00498     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2,arg3,arg4);} while(false)
00499 
00501 #define SimTK_TEST(cond) {SimTK_ASSERT_ALWAYS((cond), "Test condition failed.");}
00502 
00505 #define SimTK_TEST_FAILED(msg) {SimTK_ASSERT_ALWAYS(!"Test case failed.", msg);}
00506 
00510 #define SimTK_TEST_FAILED1(fmt,a1) {SimTK_ASSERT1_ALWAYS(!"Test case failed.",fmt,a1);}
00511 
00515 #define SimTK_TEST_FAILED2(fmt,a1,a2) {SimTK_ASSERT2_ALWAYS(!"Test case failed.",fmt,a1,a2);}
00516 
00520 #define SimTK_TEST_EQ(v1,v2)    \
00521     {SimTK_ASSERT_ALWAYS(SimTK::Test::numericallyEqual((v1),(v2),1),   \
00522      "Test values should have been numerically equivalent at default tolerance.");}
00523 
00526 #define SimTK_TEST_EQ_SIZE(v1,v2,n)    \
00527     {SimTK_ASSERT1_ALWAYS(SimTK::Test::numericallyEqual((v1),(v2),(n)),   \
00528      "Test values should have been numerically equivalent at size=%d times default tolerance.",(n));}
00529 
00533 #define SimTK_TEST_EQ_TOL(v1,v2,tol)    \
00534     {SimTK_ASSERT1_ALWAYS(SimTK::Test::numericallyEqual((v1),(v2),1,(tol)),   \
00535      "Test values should have been numerically equivalent at tolerance=%g.",(tol));}
00536 
00540 #define SimTK_TEST_NOTEQ(v1,v2)    \
00541     {SimTK_ASSERT_ALWAYS(!SimTK::Test::numericallyEqual((v1),(v2),1),   \
00542      "Test values should NOT have been numerically equivalent (at default tolerance).");}
00543 
00547 #define SimTK_TEST_NOTEQ_SIZE(v1,v2,n)    \
00548     {SimTK_ASSERT1_ALWAYS(!SimTK::Test::numericallyEqual((v1),(v2),(n)),   \
00549      "Test values should NOT have been numerically equivalent at size=%d times default tolerance.",(n));}
00550 
00554 #define SimTK_TEST_NOTEQ_TOL(v1,v2,tol)    \
00555     {SimTK_ASSERT1_ALWAYS(!SimTK::Test::numericallyEqual((v1),(v2),1,(tol)),   \
00556      "Test values should NOT have been numerically equivalent at tolerance=%g.",(tol));}
00557 
00559 #define SimTK_TEST_MUST_THROW(stmt)             \
00560     do {int threw=0; try {stmt;}                \
00561         catch(const std::exception&){threw=1;}  \
00562         catch(...){threw=2;}                    \
00563         if (threw==0) SimTK_TEST_FAILED1("Expected statement\n----\n%s\n----\n  to throw an exception but it did not.",#stmt); \
00564         if (threw==2) SimTK_TEST_FAILED1("Expected statement\n%s\n  to throw an std::exception but it threw something else.",#stmt); \
00565     }while(false)
00566 
00568 #define SimTK_TEST_MUST_THROW_EXC(stmt,exc)     \
00569     do {int threw=0; try {stmt;}                \
00570         catch(const exc&){threw=1;}             \
00571         catch(...){threw=2;}                    \
00572         if (threw==0) SimTK_TEST_FAILED1("Expected statement\n----\n%s\n----\n  to throw an exception but it did not.",#stmt); \
00573         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); \
00574     }while(false)
00575 
00577 #define SimTK_TEST_MAY_THROW(stmt)             \
00578     do {int threw=0; try {stmt;}                \
00579         catch(const std::exception&){threw=1;}  \
00580         catch(...){threw=2;}                    \
00581         if (threw==2) SimTK_TEST_FAILED1("Expected statement\n%s\n  to throw an std::exception but it threw something else.",#stmt); \
00582     }while(false)
00583 
00585 #define SimTK_TEST_MAY_THROW_EXC(stmt,exc)     \
00586     do {int threw=0; try {stmt;}                \
00587         catch(const exc&){threw=1;}             \
00588         catch(...){threw=2;}                    \
00589         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); \
00590     }while(false)
00591 
00592 // When we're only required to throw in Debug, we have to suppress the
00593 // test case altogether in Release because it may cause damage. 
00594 #if defined(NDEBUG)
00595 
00596 
00597     #define SimTK_TEST_MUST_THROW_DEBUG(stmt)
00598 
00599 
00600     #define SimTK_TEST_MUST_THROW_EXC_DEBUG(stmt,exc)
00601 #else
00602 
00603 
00604     #define SimTK_TEST_MUST_THROW_DEBUG(stmt) SimTK_TEST_MUST_THROW(stmt)
00605 
00606 
00607     #define SimTK_TEST_MUST_THROW_EXC_DEBUG(stmt,exc) \
00608                 SimTK_TEST_MUST_THROW_EXC(stmt,exc)
00609 #endif
00610 
00611 
00612 
00613 
00614 //  End of Regression testing group.
00616 
00617 #endif // SimTK_SimTKCOMMON_TESTING_H_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines