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 
00038 #include <cmath>     
00039 #include <ctime>
00040 #include <algorithm> 
00041 #include <iostream>
00042 
00048 namespace SimTK {
00049 
00160 
00161 
00162 
00163 
00164 class Test {
00165 public:
00166     class Subtest;
00167     Test(const std::string& name) : testName(name)
00168     {
00169         std::clog << "Starting test " << testName << " ...\n";
00170         startTime = std::clock(); 
00171     }
00172     ~Test() {
00173         std::clog << "Done. " << testName << " time: " 
00174                   << 1000*(std::clock()-startTime)/CLOCKS_PER_SEC << "ms.\n";
00175     }
00176 
00177     template <class T>
00178     static double defTol() {return (double)NTraits<typename CNT<T>::Precision>::getSignificant();}
00179 
00180     // For dissimilar types, the default tolerance is the narrowest of the two.
00181     template <class T1, class T2>
00182     static double defTol2() {return std::max(defTol<T1>(), defTol<T2>());}
00183 
00184     // Scale by the magnitude of the quantities being compared, so that we don't
00185     // ask for unreasonable precision. For magnitudes near zero, we'll be satisfied
00186     // if both are very small without demanding that they must also be relatively
00187     // close. That is, we use a relative tolerance for big numbers and an absolute
00188     // tolerance for small ones.
00189     static bool numericallyEqual(float v1, float v2, int n, double tol=defTol<float>()) {
00190         const float scale = n*std::max(std::max(std::abs(v1), std::abs(v2)), 1.0f);
00191         return std::abs(v1-v2) < scale*(float)tol;
00192     }
00193     static bool numericallyEqual(double v1, double v2, int n, double tol=defTol<double>()) {
00194         const double scale = n*std::max(std::max(std::abs(v1), std::abs(v2)), 1.0);
00195         return std::abs(v1-v2) < scale*(double)tol;
00196     }
00197     static bool numericallyEqual(long double v1, long double v2, int n, double tol=defTol<long double>()) {
00198         const long double scale = n*std::max(std::max(std::abs(v1), std::abs(v2)), 1.0l);
00199         return std::abs(v1-v2) < scale*(long double)tol;
00200     }
00201 
00202     // For integers we ignore tolerance.
00203     static bool numericallyEqual(int i1, int i2, int n, double tol=0) {return i1==i2;}
00204     static bool numericallyEqual(unsigned u1, unsigned u2, int n, double tol=0) {return u1==u2;}
00205 
00206     // Mixed floating types use default tolerance for the narrower type.
00207     static bool numericallyEqual(float v1, double v2, int n, double tol=defTol<float>())
00208     {   return numericallyEqual((double)v1, v2, n, tol); }
00209     static bool numericallyEqual(double v1, float v2, int n, double tol=defTol<float>())
00210     {   return numericallyEqual(v1, (double)v2, n, tol); }
00211     static bool numericallyEqual(float v1, long double v2, int n, double tol=defTol<float>())
00212     {   return numericallyEqual((long double)v1, v2, n, tol); }
00213     static bool numericallyEqual(long double v1, float v2, int n, double tol=defTol<float>())
00214     {   return numericallyEqual(v1, (long double)v2, n, tol); }
00215     static bool numericallyEqual(double v1, long double v2, int n, double tol=defTol<double>())
00216     {   return numericallyEqual((long double)v1, v2, n, tol); }
00217     static bool numericallyEqual(long double v1, double v2, int n, double tol=defTol<double>())
00218     {   return numericallyEqual(v1, (long double)v2, n, tol); }
00219 
00220     // Mixed int/floating just upgrades int to floating type.
00221     static bool numericallyEqual(int i1, float f2, int n, double tol=defTol<float>())
00222     {   return numericallyEqual((float)i1,f2,n,tol); }
00223     static bool numericallyEqual(float f1, int i2, int n, double tol=defTol<float>())
00224     {   return numericallyEqual(f1,(float)i2,n,tol); }
00225     static bool numericallyEqual(unsigned i1, float f2, int n, double tol=defTol<float>())
00226     {   return numericallyEqual((float)i1,f2,n,tol); }
00227     static bool numericallyEqual(float f1, unsigned i2, int n, double tol=defTol<float>())
00228     {   return numericallyEqual(f1,(float)i2,n,tol); }
00229     static bool numericallyEqual(int i1, double f2, int n, double tol=defTol<double>())
00230     {   return numericallyEqual((double)i1,f2,n,tol); }
00231     static bool numericallyEqual(double f1, int i2, int n, double tol=defTol<double>())
00232     {   return numericallyEqual(f1,(double)i2,n,tol); }
00233     static bool numericallyEqual(unsigned i1, double f2, int n, double tol=defTol<double>())
00234     {   return numericallyEqual((double)i1,f2,n,tol); }
00235     static bool numericallyEqual(double f1, unsigned i2, int n, double tol=defTol<double>())
00236     {   return numericallyEqual(f1,(double)i2,n,tol); }
00237     static bool numericallyEqual(int i1, long double f2, int n, double tol=defTol<long double>())
00238     {   return numericallyEqual((long double)i1,f2,n,tol); }
00239     static bool numericallyEqual(long double f1, int i2, int n, double tol=defTol<long double>())
00240     {   return numericallyEqual(f1,(long double)i2,n,tol); }
00241     static bool numericallyEqual(unsigned i1, long double f2, int n, double tol=defTol<long double>())
00242     {   return numericallyEqual((long double)i1,f2,n,tol); }
00243     static bool numericallyEqual(long double f1, unsigned i2, int n, double tol=defTol<long double>())
00244     {   return numericallyEqual(f1,(long double)i2,n,tol); }
00245 
00246     template <class P>
00247     static bool numericallyEqual(const std::complex<P>& v1, const std::complex<P>& v2, int n, double tol=defTol<P>()) {
00248         return numericallyEqual(v1.real(), v2.real(), n, tol)
00249             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00250     }
00251     template <class P>
00252     static bool numericallyEqual(const conjugate<P>& v1, const conjugate<P>& v2, int n, double tol=defTol<P>()) {
00253         return numericallyEqual(v1.real(), v2.real(), n, tol)
00254             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00255     }
00256     template <class P>
00257     static bool numericallyEqual(const std::complex<P>& v1, const conjugate<P>& v2, int n, double tol=defTol<P>()) {
00258         return numericallyEqual(v1.real(), v2.real(), n, tol)
00259             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00260     }
00261     template <class P>
00262     static bool numericallyEqual(const conjugate<P>& v1, const std::complex<P>& v2, int n, double tol=defTol<P>()) {
00263         return numericallyEqual(v1.real(), v2.real(), n, tol)
00264             && numericallyEqual(v1.imag(), v2.imag(), n, tol);
00265     }
00266     template <class P>
00267     static bool numericallyEqual(const negator<P>& v1, const negator<P>& v2, int n, double tol=defTol<P>()) {
00268         return numericallyEqual(-v1, -v2, n, tol);  // P, P
00269     }
00270     template <class P>
00271     static bool numericallyEqual(const P& v1, const negator<P>& v2, int n, double tol=defTol<P>()) {
00272         return numericallyEqual(-v1, -v2, n, tol);  // P, P
00273     }
00274     template <class P>
00275     static bool numericallyEqual(const negator<P>& v1, const P& v2, int n, double tol=defTol<P>()) {
00276         return numericallyEqual(-v1, -v2, n, tol);  // P, P
00277     }
00278     template <class P>
00279     static bool numericallyEqual(const negator<std::complex<P> >& v1, const conjugate<P>& v2, int n, double tol=defTol<P>()) {
00280         return numericallyEqual(-v1, -v2, n, tol);  // complex, conjugate
00281     }
00282     template <class P>
00283     static bool numericallyEqual(const negator<conjugate<P> >& v1, const std::complex<P>& v2, int n, double tol=defTol<P>()) {
00284         return numericallyEqual(-v1, -v2, n, tol);  // conjugate, complex
00285     }
00286     template <class P>
00287     static bool numericallyEqual(const std::complex<P>& v1, const negator<conjugate<P> >& v2, int n, double tol=defTol<P>()) {
00288         return numericallyEqual(-v1, -v2, n, tol); // complex, conjugate
00289     }
00290     template <class P>
00291     static bool numericallyEqual(const conjugate<P>& v1, const negator<std::complex<P> >& v2, int n, double tol=defTol<P>()) {
00292         return numericallyEqual(-v1, -v2, n, tol); // conjugate, complex
00293     }
00294     template <int M, class E1, int S1, class E2, int S2>
00295     static bool numericallyEqual(const Vec<M,E1,S1>& v1, const Vec<M,E2,S2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00296         for (int i=0; i<M; ++i) if (!numericallyEqual(v1[i],v2[i], n, tol)) return false;
00297         return true;
00298     }
00299     template <int N, class E1, int S1, class E2, int S2>
00300     static bool numericallyEqual(const Row<N,E1,S1>& v1, const Row<N,E2,S2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00301         for (int j=0; j<N; ++j) if (!numericallyEqual(v1[j],v2[j], n, tol)) return false;
00302         return true;
00303     }
00304     template <int M, int N, class E1, int CS1, int RS1, class E2, int CS2, int RS2>
00305     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>())) {
00306         for (int j=0; j<N; ++j) if (!numericallyEqual(v1(j),v2(j), n, tol)) return false;
00307         return true;
00308     }
00309     template <int N, class E1, int S1, class E2, int S2>
00310     static bool numericallyEqual(const SymMat<N,E1,S1>& v1, const SymMat<N,E2,S2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00311         return numericallyEqual(v1.getAsVec(), v2.getAsVec(), n, tol);
00312     }
00313     template <class E1, class E2>
00314     static bool numericallyEqual(const VectorView_<E1>& v1, const VectorView_<E2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00315         if (v1.size() != v2.size()) return false;
00316         for (int i=0; i < v1.size(); ++i)
00317             if (!numericallyEqual(v1[i], v2[i], n, tol)) return false;
00318         return true;
00319     }
00320     template <class E1, class E2>
00321     static bool numericallyEqual(const Vector_<E1>& v1, const Vector_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00322     {   return numericallyEqual((const VectorView_<E1>&)v1, (const VectorView_<E2>&)v2, n, tol); }
00323 
00324     template <class E1, class E2>
00325     static bool numericallyEqual(const RowVectorView_<E1>& v1, const RowVectorView_<E2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00326         if (v1.size() != v2.size()) return false;
00327         for (int i=0; i < v1.size(); ++i)
00328             if (!numericallyEqual(v1[i], v2[i], n, tol)) return false;
00329         return true;
00330     }
00331     template <class E1, class E2>
00332     static bool numericallyEqual(const RowVector_<E1>& v1, const RowVector_<E2>& v2, int n, double tol=(defTol2<E1,E2>()))
00333     {   return numericallyEqual((const RowVectorView_<E1>&)v1, (const RowVectorView_<E2>&)v2, n, tol); }
00334 
00335     template <class E1, class E2>
00336     static bool numericallyEqual(const MatrixView_<E1>& v1, const MatrixView_<E2>& v2, int n, double tol=(defTol2<E1,E2>())) {
00337         if (v1.nrow() != v2.nrow() || v1.ncol() != v2.ncol()) return false;
00338         for (int j=0; j < v1.ncol(); ++j)
00339             if (!numericallyEqual(v1(j), v2(j), n, tol)) return false;
00340         return true;
00341     }
00342     template <class E1, class E2>
00343     static bool numericallyEqual(const Matrix_<E1>& m1, const Matrix_<E2>& m2, int n, double tol=(defTol2<E1,E2>()))
00344     {   return numericallyEqual((const MatrixView_<E1>&)m1, (const MatrixView_<E2>&)m2, n, tol); }
00345 
00346 
00347     static bool numericallyEqual(const Rotation& R1, const Rotation& R2, int n, double tol=defTol<Real>()) {
00348         return R1.isSameRotationToWithinAngle(R2, (Real)(n*tol));
00349     }
00350 
00351     static bool numericallyEqual(const Transform& T1, const Transform& T2, int n, double tol=defTol<Real>()) {
00352         return numericallyEqual(T1.R(), T2.R(), n, tol)
00353             && numericallyEqual(T1.p(), T2.p(), n, tol);
00354     }
00355 
00356     // Random numbers
00357     static Real randReal() {
00358         static Random::Uniform rand(-1,1);
00359         return rand.getValue();
00360     }
00361     static Complex randComplex() {return Complex(randReal(),randReal());}
00362     static Conjugate randConjugate() {return Conjugate(randReal(),randReal());}
00363     static float randFloat() {return (float)randReal();}
00364     static double randDouble() {return (double)randReal();}
00365 
00366     template <int M> static Vec<M> randVec() 
00367     {   Vec<M> v; for (int i=0; i<M; ++i) v[i]=randReal(); return v;}
00368     template <int N> static Row<N> randRow() {return ~randVec<N>();}
00369     template <int M, int N> static Mat<M,N> randMat()
00370     {   Mat<M,N> m; for (int j=0; j<N; ++j) m(j)=randVec<M>(); return m;}
00371     template <int N> static SymMat<N> randSymMat() {SymMat<N> s; s.updAsVec() = randVec<N*(N+1)/2>(); return s;}
00372 
00373     static Vector randVector(int m)
00374     {   Vector v(m); for (int i=0; i<m; ++i) v[i]=randReal(); return v;}
00375     static Matrix randMatrix(int m, int n)
00376     {   Matrix M(m,n); for (int j=0; j<n; ++j) M(j)=randVector(m); return M;}
00377 
00378     static Vec3 randVec3() {return randVec<3>();}
00379     static Mat33 randMat33() {return randMat<3,3>();}
00380     static SpatialVec randSpatialVec() {
00381         return SpatialVec(randVec3(), randVec3());
00382     }
00383     static SpatialMat randSpatialMat() {
00384         return SpatialMat(randMat33(), randMat33(),
00385                           randMat33(), randMat33());
00386     }
00387     static Rotation randRotation() {
00388         // Generate random angle and random axis to rotate around.
00389         return Rotation((Pi/2)*randReal(), randVec3());
00390     }
00391     static Transform randTransform() {
00392         return Transform(randRotation(), randVec3());
00393     }
00394 private:
00395     std::clock_t startTime;
00396     std::string  testName;
00397 };
00398 
00400 class Test::Subtest {
00401 public:
00402     Subtest(const std::string& name) : subtestName(name)
00403     {
00404         char padded[128];
00405         sprintf(padded, "%-20s", name.c_str());
00406         paddedName = std::string(padded);
00407         std::clog << "  " << paddedName << " ... " << std::flush;
00408         startTime = std::clock(); 
00409     }
00410     ~Subtest() {
00411         std::clog << "done. " << paddedName << " time: " 
00412                   << 1000*(std::clock()-startTime)/CLOCKS_PER_SEC << "ms.\n";
00413     }
00414 private:
00415     std::clock_t startTime;
00416     std::string  subtestName;
00417     std::string  paddedName; // name plus some blanks
00418 };
00419 
00420 } // namespace SimTK
00421 
00423 #define SimTK_START_TEST(testName)      \
00424     SimTK::Test simtk_test_(testName);  \
00425     try {
00426 
00428 #define SimTK_END_TEST() \
00429     } catch(const std::exception& e) {                  \
00430         std::cerr << "Test failed due to exception: "   \
00431                   << e.what() << std::endl;             \
00432         return 1;                                       \
00433     } catch(...) {                                      \
00434         std::cerr << "Test failed due to unrecognized exception.\n";    \
00435         return 1;                                       \
00436     }                                                   \
00437     return 0;
00438 
00441 #define SimTK_SUBTEST(testFunction) \
00442     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)();} while(false)
00445 #define SimTK_SUBTEST1(testFunction,arg1) \
00446     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1);} while(false)
00449 #define SimTK_SUBTEST2(testFunction,arg1,arg2) \
00450     do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2);} while(false)
00451 
00453 #define SimTK_TEST(cond) {SimTK_ASSERT_ALWAYS((cond), "Test condition failed.");}
00454 
00457 #define SimTK_TEST_FAILED(msg) {SimTK_ASSERT_ALWAYS(!"Test case failed.", msg);}
00458 
00462 #define SimTK_TEST_FAILED1(fmt,a1) {SimTK_ASSERT1_ALWAYS(!"Test case failed.",fmt,a1);}
00463 
00467 #define SimTK_TEST_FAILED2(fmt,a1,a2) {SimTK_ASSERT2_ALWAYS(!"Test case failed.",fmt,a1,a2);}
00468 
00472 #define SimTK_TEST_EQ(v1,v2)    \
00473     {SimTK_ASSERT_ALWAYS(SimTK::Test::numericallyEqual((v1),(v2),1),   \
00474      "Test values should have been numerically equivalent at default tolerance.");}
00475 
00478 #define SimTK_TEST_EQ_SIZE(v1,v2,n)    \
00479     {SimTK_ASSERT1_ALWAYS(SimTK::Test::numericallyEqual((v1),(v2),(n)),   \
00480      "Test values should have been numerically equivalent at size=%d times default tolerance.",(n));}
00481 
00485 #define SimTK_TEST_EQ_TOL(v1,v2,tol)    \
00486     {SimTK_ASSERT1_ALWAYS(SimTK::Test::numericallyEqual((v1),(v2),1,(tol)),   \
00487      "Test values should have been numerically equivalent at tolerance=%g.",(tol));}
00488 
00492 #define SimTK_TEST_NOTEQ(v1,v2)    \
00493     {SimTK_ASSERT_ALWAYS(!SimTK::Test::numericallyEqual((v1),(v2),1),   \
00494      "Test values should NOT have been numerically equivalent (at default tolerance).");}
00495 
00499 #define SimTK_TEST_NOTEQ_SIZE(v1,v2,n)    \
00500     {SimTK_ASSERT1_ALWAYS(!SimTK::Test::numericallyEqual((v1),(v2),(n)),   \
00501      "Test values should NOT have been numerically equivalent at size=%d times default tolerance.",(n));}
00502 
00506 #define SimTK_TEST_NOTEQ_TOL(v1,v2,tol)    \
00507     {SimTK_ASSERT1_ALWAYS(!SimTK::Test::numericallyEqual((v1),(v2),1,(tol)),   \
00508      "Test values should NOT have been numerically equivalent at tolerance=%g.",(tol));}
00509 
00510 #define SimTK_TEST_MUST_THROW(stmt)             \
00511     do {int threw=0; try {stmt;}                \
00512         catch(const std::exception&){threw=1;}  \
00513         catch(...){threw=2;}                    \
00514         if (threw==0) SimTK_TEST_FAILED1("Expected statement\n----\n%s\n----\n  to throw an exception but it did not.",#stmt); \
00515         if (threw==2) SimTK_TEST_FAILED1("Expected statement\n%s\n  to throw an std::exception but it threw something else.",#stmt); \
00516     }while(false)
00517 
00518 #define SimTK_TEST_MUST_THROW_EXC(stmt,exc)     \
00519     do {int threw=0; try {stmt;}                \
00520         catch(const exc&){threw=1;}             \
00521         catch(...){threw=2;}                    \
00522         if (threw==0) SimTK_TEST_FAILED1("Expected statement\n----\n%s\n----\n  to throw an exception but it did not.",#stmt); \
00523         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); \
00524     }while(false)
00525 
00526 
00527 
00528 //  End of Regression testing group.
00530 
00531 #endif // SimTK_SimTKCOMMON_TESTING_H_

Generated by  doxygen 1.6.2