00001 #ifndef SimTK_SimTKCOMMON_TESTING_H_
00002 #define SimTK_SimTKCOMMON_TESTING_H_
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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
00182 template <class T1, class T2>
00183 static double defTol2() {return std::max(defTol<T1>(), defTol<T2>());}
00184
00185
00186
00187
00188
00189
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
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
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
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);
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);
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);
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);
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);
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);
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);
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 Gyration_<P>& G1, const Gyration_<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
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
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;
00432 };
00433
00434 }
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)
00459 #define SimTK_SUBTEST1(testFunction,arg1) \
00460 do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1);} while(false)
00463 #define SimTK_SUBTEST2(testFunction,arg1,arg2) \
00464 do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2);} while(false)
00467 #define SimTK_SUBTEST3(testFunction,arg1,arg2,arg3) \
00468 do {SimTK::Test::Subtest sub(#testFunction); (testFunction)(arg1,arg2,arg3);} while(false)
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
00567
00568 #if defined(NDEBUG)
00571 #define SimTK_TEST_MUST_THROW_DEBUG(stmt)
00574 #define SimTK_TEST_MUST_THROW_EXC_DEBUG(stmt,exc)
00575 #else
00578 #define SimTK_TEST_MUST_THROW_DEBUG(stmt) SimTK_TEST_MUST_THROW(stmt)
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
00590
00591 #endif // SimTK_SimTKCOMMON_TESTING_H_