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
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
00181 template <class T1, class T2>
00182 static double defTol2() {return std::max(defTol<T1>(), defTol<T2>());}
00183
00184
00185
00186
00187
00188
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
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
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
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);
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);
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);
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);
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);
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);
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);
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
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
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;
00418 };
00419
00420 }
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
00530
00531 #endif // SimTK_SimTKCOMMON_TESTING_H_