Teuchos - Trilinos Tools Package  Version of the Day
Teuchos_TestingHelpers.hpp
Go to the documentation of this file.
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #ifndef TEUCHOS_TESTING_HELPERS_HPP
43 #define TEUCHOS_TESTING_HELPERS_HPP
44 
45 
51 #include "Teuchos_ConfigDefs.hpp"
52 #include "Teuchos_ScalarTraits.hpp"
54 #include "Teuchos_FancyOStream.hpp"
55 
56 
57 namespace Teuchos {
58 
59 
64 inline void updateSuccess(const bool result, bool &success);
65 
66 
71 inline const std::string passfail(const bool result);
72 
73 
78 TEUCHOSCORE_LIB_DLL_EXPORT const std::string passfail_with_location(const bool result, const std::string &file, const int lineNumber);
79 
84 void showTestFailureLocation(bool);
85 
86 
92 
93 
98 template <bool hasMachineParameters, class Scalar>
100 public:
101  static Scalar smallNumber()
102  {
104  }
105 };
106 
107 
112 template <class Scalar>
113 class RelErrSmallNumber<false,Scalar> {
114 public:
115  static Scalar smallNumber()
116  {
117  return Scalar(1e-8);
118  }
119 };
120 
121 
126 template <class Scalar>
127 class RelErrSmallNumber<true,Scalar> {
128 public:
129  static Scalar smallNumber()
130  {
132  }
133 };
134 
135 
140 template <class Scalar>
142 {
143  const bool hasMachineParameters = ScalarTraits<Scalar>::hasMachineParameters;
145 }
146 
147 
154 template <class Scalar>
156 relErr( const Scalar &s1, const Scalar &s2 );
157 
158 
165 template<class Scalar>
166 bool testRelErr(
167  const std::string &v1_name,
168  const Scalar &v1,
169  const std::string &v2_name,
170  const Scalar &v2,
171  const std::string &maxRelErr_error_name,
172  const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &maxRelErr_error,
173  const std::string &maxRelErr_warning_name,
174  const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &maxRelErr_warning,
175  const Ptr<std::ostream> &out
176  );
177 
178 
190 template<class Array1, class Array2>
191 bool compareArrays(
192  const Array1 &a1, const std::string &a1_name,
193  const Array2 &a2, const std::string &a2_name,
195  );
196 
197 
210 template<class Array1, class Array2, class ScalarMag>
212  const Array1 &a1, const std::string &a1_name,
213  const Array2 &a2, const std::string &a2_name,
214  const ScalarMag &tol,
216  );
217 
218 
219 } // namespace Teuchos
220 
221 
230 #define TEUCHOS_PASS_FAIL(RESULT) \
231  Teuchos::passfail_with_location((RESULT), __FILE__, __LINE__)
232 
233 
240 #define TEUCHOS_ECHO( statement, out ) \
241  (out) << #statement ";\n"; \
242  statement;
243 
250 #define TEUCHOS_TEST_EQUALITY_CONST( v1, v2, out, success ) \
251  { \
252  (out) << #v1" = "<<Teuchos::toString(v1)<<" == "<<Teuchos::toString(v2)<<" : "; \
253  const bool l_result = (v1) == (v2); \
254  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
255  if (!l_result) (success) = false; \
256  }
257 
264 #define TEUCHOS_TEST_ASSERT( v1, out, success ) \
265  { \
266  const bool l_result = v1; \
267  (out) << #v1" = "<<l_result<<" == true : "; \
268  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
269  if (!l_result) (success) = false; \
270  }
271 
278 #define TEUCHOS_TEST_EQUALITY( v1, v2, out, success ) \
279  { \
280  (out) << #v1" = "<<Teuchos::toString(v1)<<" == "#v2" = "<<Teuchos::toString(v2)<<" : "; \
281  const bool l_result = (v1) == (v2); \
282  if (!l_result) (success) = false; \
283  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
284  }
285 
286 
293 #define TEUCHOS_TEST_INEQUALITY_CONST( v1, v2, out, success ) \
294  { \
295  (out) << #v1" = "<<Teuchos::toString(v1)<<" != "<<Teuchos::toString(v2)<<" : "; \
296  const bool l_result = (v1) != (v2); \
297  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
298  if (!l_result) (success) = false; \
299  }
300 
301 
308 #define TEUCHOS_TEST_INEQUALITY( v1, v2, out, success ) \
309  { \
310  (out) << #v1" = "<<Teuchos::toString(v1)<<" != "#v2" = "<<Teuchos::toString(v2)<<" : "; \
311  const bool l_result = (v1) != (v2); \
312  if (!l_result) (success) = false; \
313  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
314  }
315 
316 
323 #define TEUCHOS_TEST_FLOATING_EQUALITY( v1, v2, tol, out, success ) \
324  { \
325  const bool l_result = Teuchos::testRelErr( \
326  #v1, v1, #v2, v2, "tol", tol, "tol", tol, Teuchos::outArg(out) ); \
327  if (!l_result) (success) = false; \
328  }
329 
330 
340 #define TEUCHOS_TEST_ITER_EQUALITY( iter1, iter2, out, success ) \
341  { \
342  (out) << #iter1" == "#iter2" = : "; \
343  const bool l_result = (iter1) == (iter2); \
344  if (!l_result) (success) = false; \
345  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
346  }
347 
348 
358 #define TEUCHOS_TEST_ITER_INEQUALITY( iter1, iter2, out, success ) \
359  { \
360  (out) << #iter1" != "#iter2" = : "; \
361  const bool l_result = (iter1) != (iter2); \
362  if (!l_result) (success) = false; \
363  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
364  }
365 
366 
373 #define TEUCHOS_TEST_ARRAY_ELE_EQUALITY( a, i, val, printPass, out, success ) \
374  { \
375  const bool l_result = ( (a)[i] == (val) ); \
376  if (!l_result) (success) = false; \
377  if (printPass || !(l_result)) { \
378  out << #a"["<<i<<"] = " << Teuchos::toString((a)[i]) << " == "#val" = " << Teuchos::toString(val) \
379  << " : " << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
380  } \
381  }
382 
383 
390 #define TEUCHOS_TEST_ARRAY_ELE_INEQUALITY( a, i, val, printPass, out, success ) \
391  { \
392  const bool l_result = ( (a)[i] != (val) ); \
393  if (!l_result) (success) = false; \
394  if (printPass || !(l_result)) { \
395  out << #a"["<<i<<"] = " << Teuchos::toString((a)[i]) << " != "#val" = " << Teuchos::toString(val) \
396  << " : " << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
397  } \
398  }
399 
400 
408 #define TEUCHOS_TEST_MATRIX_ELE_FLOATING_EQUALITY( a, i, j, val, tol, printPass, out, success ) \
409  { \
410  std::ostringstream a_i_str; \
411  a_i_str <<#a<<"("<<i<<","<<j<<")"; \
412  const bool l_result = Teuchos::testRelErr( \
413  a_i_str.str(), (a)(i,j), #val, val, "tol", tol, "tol", tol, \
414  (printPass) ? Teuchos::outArg(out) : Teuchos::null ); \
415  if (!l_result) (success) = false; \
416  }
417 
418 
425 #define TEUCHOS_TEST_MATRIX_ELE_EQUALITY( a, i, j, val, printPass, out, success ) \
426  { \
427  const bool l_result = ( (a)(i,j) == (val) ); \
428  if (!l_result) (success) = false; \
429  if (printPass || !(l_result)) { \
430  out << #a"("<<i<<","<<j<<") = " << (a)(i,j) << " == "#val" = " << (val) \
431  << " : " << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
432  } \
433  }
434 
435 
445 #define TEUCHOS_TEST_COMPARE( v1, comp, v2, out, success ) \
446  { \
447  out << #v1" = "<<(v1)<<" "#comp" "#v2" = "<<(v2)<<" : "; \
448  const bool l_result = (v1) comp (v2); \
449  if (!l_result) (success) = false; \
450  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
451  }
452 
453 
468 #define TEUCHOS_TEST_THROW( code, ExceptType, out, success ) \
469  { \
470  std::ostream& l_out = (out); \
471  try { \
472  l_out << "Test that code {"#code";} throws " \
473  << Teuchos::TypeNameTraits<ExceptType>::name () << ": "; \
474  code; \
475  (success) = false; \
476  l_out << "failed (code did not throw an exception at all)\n"; \
477  } \
478  catch (const ExceptType& except) { \
479  l_out << "passed\n"; \
480  l_out << "\nException message for expected exception:\n\n"; \
481  { \
482  Teuchos::OSTab l_tab (out); \
483  l_out << except.what () << "\n\n"; \
484  } \
485  } \
486  catch (std::exception& except) { \
487  l_out << "The code was supposed to throw an exception of type " \
488  << Teuchos::TypeNameTraits<ExceptType>::name () << ", but " \
489  << "instead threw an exception of type " \
490  << typeid (except).name () << ", which is a subclass of " \
491  << "std::exception. The exception's message is:\n\n"; \
492  { \
493  Teuchos::OSTab l_tab (out); \
494  l_out << except.what () << "\n\n"; \
495  } \
496  l_out << "failed\n"; \
497  } \
498  catch (...) { \
499  l_out << "The code was supposed to throw an exception of type " \
500  << Teuchos::TypeNameTraits<ExceptType>::name () << ", but " \
501  << "instead threw an exception of some unknown type, which is " \
502  << "not a subclass of std::exception. This means we cannot " \
503  << "show you the exception's message, if it even has one.\n\n"; \
504  l_out << "failed\n"; \
505  } \
506  }
507 
508 
515 #define TEUCHOS_TEST_NOTHROW( code, out, success ) \
516  { \
517  std::ostream& l_out = (out); \
518  try { \
519  l_out << "Test that code {"#code";} does not throw : "; \
520  code; \
521  l_out << "passed\n"; \
522  } \
523  catch (std::exception& except) { \
524  (success) = false; \
525  l_out << "The code was not supposed to throw an exception, but " \
526  << "instead threw an exception of type " \
527  << typeid (except).name () << ", which is a subclass of " \
528  << "std::exception. The exception's message is:\n\n"; \
529  { \
530  Teuchos::OSTab l_tab (out); \
531  l_out << except.what () << "\n\n"; \
532  } \
533  l_out << "failed\n"; \
534  } \
535  catch (...) { \
536  (success) = false; \
537  l_out << "The code was not supposed to throw an exception, but " \
538  << "instead threw an exception of some unknown type, which is " \
539  << "not a subclass of std::exception. This means we cannot " \
540  << "show you the exception's message, if it even has one.\n\n"; \
541  l_out << "failed\n"; \
542  } \
543  }
544 
545 //
546 // Implementations
547 //
548 
549 
550 inline
551 void Teuchos::updateSuccess(const bool result, bool &success)
552 {
553  if (!result) success = false;
554 }
555 
556 
557 inline
558 const std::string
559 Teuchos::passfail(const bool result)
560 {
561  if (!result)
562  return "FAILED";
563  return "passed";
564 }
565 
566 
567 template <class Scalar>
569 Teuchos::relErr( const Scalar &s1, const Scalar &s2 )
570 {
572  return
573  ST::magnitude( s1 - s2 )
574  / (
575  ST::magnitude(
576  RelErrSmallNumber<ST::hasMachineParameters,Scalar>::smallNumber()
577  )
578  + std::max( ST::magnitude(s1), ST::magnitude(s2) )
579  );
580 }
581 
582 
583 template<class Scalar>
585  const std::string &v1_name,
586  const Scalar &v1,
587  const std::string &v2_name,
588  const Scalar &v2,
589  const std::string &maxRelErr_error_name,
590  const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &maxRelErr_error,
591  const std::string &maxRelErr_warning_name,
592  const typename Teuchos::ScalarTraits<Scalar>::magnitudeType &maxRelErr_warning,
593  const Ptr<std::ostream> &out
594  )
595 {
596  using std::endl;
597  typedef ScalarTraits<Scalar> ST;
598  typedef typename ST::magnitudeType ScalarMag;
599  typedef ScalarTraits<ScalarMag> SMT;
600  const ScalarMag rel_err = relErr( v1, v2 );
601  const bool success = ( !SMT::isnaninf(rel_err) && !SMT::isnaninf(maxRelErr_error)
602  && rel_err <= maxRelErr_error );
603  if (!is_null(out)) {
604  *out
605  << endl
606  << "Check: rel_err(" << v1_name << ", " << v2_name << ")\n"
607  << " = rel_err(" << v1 << ", " << v2 << ") "
608  << "= " << rel_err << endl
609  << " <= " << maxRelErr_error_name
610  << " = " << maxRelErr_error << " : " << passfail(success) << endl;
611  if( success && rel_err >= maxRelErr_warning ) {
612  *out
613  << "Warning! rel_err(" << v1_name << ", " << v2_name << ")\n"
614  << " = rel_err(" << v1 << ", " << v2 << ") "
615  << "= " << rel_err << endl
616  << " >= " << maxRelErr_warning_name
617  << " = " << maxRelErr_warning << "!\n";
618  }
619  }
620  return success;
621 }
622 
623 
624 template<class Array1, class Array2>
626  const Array1 &a1, const std::string &a1_name,
627  const Array2 &a2, const std::string &a2_name,
629  )
630 {
631  using Teuchos::as;
632  bool success = true;
633 
634  out << "Comparing " << a1_name << " == " << a2_name << " ... ";
635 
636  const int n = a1.size();
637 
638  // Compare sizes
639  if (as<int>(a2.size()) != n) {
640  out << "\nError, "<<a1_name<<".size() = "<<a1.size()<<" == "
641  << a2_name<<".size() = "<<a2.size()<<" : failed!\n";
642  return false;
643  }
644 
645  // Compare elements
646  for( int i = 0; i < n; ++i ) {
647  const bool result = ( a1[i] == a2[i] ); // Tests C::operator[](i) const
648  if (!result) {
649  out << "\nError, "<<a1_name<<"["<<i<<"] = "<<a1[i]<<" == "
650  << a2_name<<"["<<i<<"] = "<<a2[i]<<": failed!\n";
651  success = false;
652  }
653  }
654  if (success) {
655  out << "passed\n";
656  }
657 
658  return success;
659 
660 }
661 
662 
663 template<class Array1, class Array2, class ScalarMag>
665  const Array1 &a1, const std::string &a1_name,
666  const Array2 &a2, const std::string &a2_name,
667  const ScalarMag &tol,
669  )
670 {
671  using Teuchos::as;
672  bool success = true;
673 
674  out << "Comparing " << a1_name << " == " << a2_name << " ... ";
675 
676  const int n = a1.size();
677 
678  // Compare sizes
679  if (as<int>(a2.size()) != n) {
680  out << "\nError, "<<a1_name<<".size() = "<<a1.size()<<" == "
681  << a2_name<<".size() = "<<a2.size()<<" : failed!\n";
682  return false;
683  }
684 
685  // Compare elements
686  for( int i = 0; i < n; ++i ) {
687  const ScalarMag err = relErr( a1[i], a2[i] );
688  if ( !(err <= tol) ) {
689  out
690  <<"\nError, relErr("<<a1_name<<"["<<i<<"],"
691  <<a2_name<<"["<<i<<"]) = relErr("<<a1[i]<<","<<a2[i]<<") = "
692  <<err<<" <= tol = "<<tol<<": failed!\n";
693  success = false;
694  }
695  }
696  if (success) {
697  out << "passed\n";
698  }
699 
700  return success;
701 
702 }
703 
704 
705 #endif // TEUCHOS_TESTING_HELPERS_HPP
bool compareFloatingArrays(const Array1 &a1, const std::string &a1_name, const Array2 &a2, const std::string &a2_name, const ScalarMag &tol, Teuchos::FancyOStream &out)
Compare if two array objects are the same or not up to a relative floating point precision.
T magnitudeType
Mandatory typedef for result of magnitude.
static magnitudeType eps()
Returns relative machine precision.
bool compareArrays(const Array1 &a1, const std::string &a1_name, const Array2 &a2, const std::string &a2_name, Teuchos::FancyOStream &out)
Compare if two array objects are the same or not.
TEUCHOSCORE_LIB_DLL_EXPORT const std::string passfail_with_location(const bool result, const std::string &file, const int lineNumber)
Helper function for TEUCHOS_PASS_FAIL(...).
const std::string passfail(const bool result)
Return "passed" or "failed".
Teuchos header file which uses auto-configuration information to include necessary C++ headers...
bool is_null(const ArrayRCP< T > &p)
Returns true if p.get()==NULL.
This structure defines some basic traits for a scalar field type.
Scalar defaultSmallNumber()
void showTestFailureLocation(bool)
Set if TEUCHOS_PASS_FAIL(...) should print test failure location.
std::ostream subclass that performs the magic of indenting data sent to an std::ostream object among ...
ScalarTraits< Scalar >::magnitudeType relErr(const Scalar &s1, const Scalar &s2)
Return relative error of two scalars.
void updateSuccess(const bool result, bool &success)
Update the success bool flag.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos, as well as a number of utility routines.
TypeTo as(const TypeFrom &t)
Convert from one value type to another.
Defines basic traits for the scalar field type.
bool testRelErr(const std::string &v1_name, const Scalar &v1, const std::string &v2_name, const Scalar &v2, const std::string &maxRelErr_error_name, const typename Teuchos::ScalarTraits< Scalar >::magnitudeType &maxRelErr_error, const std::string &maxRelErr_warning_name, const typename Teuchos::ScalarTraits< Scalar >::magnitudeType &maxRelErr_warning, const Ptr< std::ostream > &out)
Compute, check and optionally print the relative error in two scalars.
Defines basic traits returning the name of a type in a portable and readable way. ...
Simple wrapper class for raw pointers to single objects where no persisting relationship exists...