Simbody
3.5
|
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_