Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_TestingHelpers.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef TEUCHOS_TESTING_HELPERS_HPP
11 #define TEUCHOS_TESTING_HELPERS_HPP
12 
13 
19 #include "Teuchos_ConfigDefs.hpp"
20 #include "Teuchos_ScalarTraits.hpp"
22 #include "Teuchos_FancyOStream.hpp"
23 
24 
25 namespace Teuchos {
26 
27 
32 inline void updateSuccess(const bool result, bool &success);
33 
34 
39 inline const std::string passfail(const bool result);
40 
41 
46 TEUCHOSCORE_LIB_DLL_EXPORT const std::string passfail_with_location(const bool result, const std::string &file, const int lineNumber);
47 
52 void showTestFailureLocation(bool);
53 
54 
60 
61 
66 template <bool hasMachineParameters, class Scalar>
68 public:
69  static Scalar smallNumber()
70  {
72  }
73 };
74 
75 
80 template <class Scalar>
81 class RelErrSmallNumber<false,Scalar> {
82 public:
83  static Scalar smallNumber()
84  {
85  return Scalar(1e-8);
86  }
87 };
88 
89 
94 template <class Scalar>
95 class RelErrSmallNumber<true,Scalar> {
96 public:
97  static Scalar smallNumber()
98  {
100  }
101 };
102 
103 
108 template <class Scalar>
110 {
111  const bool hasMachineParameters = ScalarTraits<Scalar>::hasMachineParameters;
113 }
114 
115 
122 template <class Scalar1, class Scalar2>
124 relErr( const Scalar1 &s1, const Scalar2 &s2 );
125 
126 
133 template <typename T1, typename T2, typename Enabled = void>
134 struct TestRelErr {
135  typedef typename Teuchos::ScalarTraits<T1>::magnitudeType magType1;
136  typedef typename Teuchos::ScalarTraits<T2>::magnitudeType magType2;
137  typedef typename std::common_type<magType1,magType2>::type magnitudeType;
138  static bool eval(
139  const std::string &v1_name,
140  const T1 &v1,
141  const std::string &v2_name,
142  const T2 &v2,
143  const std::string &maxRelErr_error_name,
144  const magnitudeType &maxRelErr_error,
145  const std::string &maxRelErr_warning_name,
146  const magnitudeType &maxRelErr_warning,
147  const Ptr<std::ostream> &out
148  )
149  {
150  using std::endl;
151  typedef ScalarTraits<magnitudeType> SMT;
152  const magnitudeType rel_err = relErr( v1, v2 );
153  const bool success = ( !SMT::isnaninf(rel_err) && !SMT::isnaninf(maxRelErr_error)
154  && rel_err <= maxRelErr_error );
155  if (!is_null(out)) {
156  *out
157  << endl
158  << "Check: rel_err(" << v1_name << ", " << v2_name << ")\n"
159  << " = rel_err(" << v1 << ", " << v2 << ") "
160  << "= " << rel_err << endl
161  << " <= " << maxRelErr_error_name
162  << " = " << maxRelErr_error << " : " << passfail(success) << endl;
163  if( success && rel_err >= maxRelErr_warning ) {
164  *out
165  << "Warning! rel_err(" << v1_name << ", " << v2_name << ")\n"
166  << " = rel_err(" << v1 << ", " << v2 << ") "
167  << "= " << rel_err << endl
168  << " >= " << maxRelErr_warning_name
169  << " = " << maxRelErr_warning << "!\n";
170  }
171  }
172  return success;
173  }
174 };
175 
176 template <typename T1, typename T2>
177 bool testRelErr(
178  const std::string &v1_name,
179  const T1 &v1,
180  const std::string &v2_name,
181  const T2 &v2,
182  const std::string &maxRelErr_error_name,
183  const typename TestRelErr<T1,T2>::magnitudeType &maxRelErr_error,
184  const std::string &maxRelErr_warning_name,
185  const typename TestRelErr<T1,T2>::magnitudeType &maxRelErr_warning,
186  const Ptr<std::ostream> &out) {
187  return TestRelErr<T1,T2>::eval(v1_name, v1, v2_name,v2, maxRelErr_error_name, maxRelErr_error, maxRelErr_warning_name, maxRelErr_warning, out);
188 }
189 
203 template<class Array1, class Array2>
204 bool compareArrays(
205  const Array1 &a1, const std::string &a1_name,
206  const Array2 &a2, const std::string &a2_name,
208  );
209 
210 
226 template<class Array1, class Array2, class ScalarMag>
228  const Array1 &a1, const std::string &a1_name,
229  const Array2 &a2, const std::string &a2_name,
230  const ScalarMag &tol,
232  );
233 
250 template<class Array1, class Array2, class ScalarMag>
252  const Array1 &a1, const std::string &a1_name,
253  const Array2 &a2, const std::string &a2_name,
254  const ScalarMag &tol,
256  );
257 
258 
259 } // namespace Teuchos
260 
261 
270 #define TEUCHOS_PASS_FAIL(RESULT) \
271  Teuchos::passfail_with_location((RESULT), __FILE__, __LINE__)
272 
273 
280 #define TEUCHOS_ECHO( statement, out ) \
281  (out) << #statement ";\n"; \
282  statement;
283 
290 #define TEUCHOS_TEST_EQUALITY_CONST( v1, v2, out, success ) \
291  { \
292  (out) << #v1" = "<<Teuchos::toString(v1)<<" == "<<Teuchos::toString(v2)<<" : "; \
293  const bool l_result = (v1) == (v2); \
294  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
295  if (!l_result) (success) = false; \
296  }
297 
304 #define TEUCHOS_TEST_ASSERT( v1, out, success ) \
305  { \
306  const bool l_result = v1; \
307  (out) << #v1" = "<<l_result<<" == true : "; \
308  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
309  if (!l_result) (success) = false; \
310  }
311 
318 #define TEUCHOS_TEST_EQUALITY( v1, v2, out, success ) \
319  { \
320  (out) << #v1" = "<<Teuchos::toString(v1)<<" == "#v2" = "<<Teuchos::toString(v2)<<" : "; \
321  const bool l_result = (v1) == (v2); \
322  if (!l_result) (success) = false; \
323  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
324  }
325 
326 
333 #define TEUCHOS_TEST_INEQUALITY_CONST( v1, v2, out, success ) \
334  { \
335  (out) << #v1" = "<<Teuchos::toString(v1)<<" != "<<Teuchos::toString(v2)<<" : "; \
336  const bool l_result = (v1) != (v2); \
337  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
338  if (!l_result) (success) = false; \
339  }
340 
341 
348 #define TEUCHOS_TEST_INEQUALITY( v1, v2, out, success ) \
349  { \
350  (out) << #v1" = "<<Teuchos::toString(v1)<<" != "#v2" = "<<Teuchos::toString(v2)<<" : "; \
351  const bool l_result = (v1) != (v2); \
352  if (!l_result) (success) = false; \
353  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
354  }
355 
356 
363 #define TEUCHOS_TEST_FLOATING_EQUALITY( v1, v2, tol, out, success ) \
364  { \
365  const bool l_result = Teuchos::testRelErr( \
366  #v1, v1, #v2, v2, "tol", tol, "tol", tol, Teuchos::outArg(out) ); \
367  if (!l_result) (success) = false; \
368  }
369 
370 
380 #define TEUCHOS_TEST_ITER_EQUALITY( iter1, iter2, out, success ) \
381  { \
382  (out) << #iter1" == "#iter2" = : "; \
383  const bool l_result = (iter1) == (iter2); \
384  if (!l_result) (success) = false; \
385  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
386  }
387 
388 
398 #define TEUCHOS_TEST_ITER_INEQUALITY( iter1, iter2, out, success ) \
399  { \
400  (out) << #iter1" != "#iter2" = : "; \
401  const bool l_result = (iter1) != (iter2); \
402  if (!l_result) (success) = false; \
403  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
404  }
405 
406 
413 #define TEUCHOS_TEST_ARRAY_ELE_EQUALITY( a, i, val, printPass, out, success ) \
414  { \
415  const bool l_result = ( (a)[i] == (val) ); \
416  if (!l_result) (success) = false; \
417  if (printPass || !(l_result)) { \
418  out << #a"["<<i<<"] = " << Teuchos::toString((a)[i]) << " == "#val" = " << Teuchos::toString(val) \
419  << " : " << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
420  } \
421  }
422 
423 
430 #define TEUCHOS_TEST_ARRAY_ELE_INEQUALITY( a, i, val, printPass, out, success ) \
431  { \
432  const bool l_result = ( (a)[i] != (val) ); \
433  if (!l_result) (success) = false; \
434  if (printPass || !(l_result)) { \
435  out << #a"["<<i<<"] = " << Teuchos::toString((a)[i]) << " != "#val" = " << Teuchos::toString(val) \
436  << " : " << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
437  } \
438  }
439 
440 
448 #define TEUCHOS_TEST_MATRIX_ELE_FLOATING_EQUALITY( a, i, j, val, tol, printPass, out, success ) \
449  { \
450  std::ostringstream a_i_str; \
451  a_i_str <<#a<<"("<<i<<","<<j<<")"; \
452  const bool l_result = Teuchos::testRelErr( \
453  a_i_str.str(), (a)(i,j), #val, val, "tol", tol, "tol", tol, \
454  (printPass) ? Teuchos::outArg(out) : Teuchos::null ); \
455  if (!l_result) (success) = false; \
456  }
457 
458 
465 #define TEUCHOS_TEST_MATRIX_ELE_EQUALITY( a, i, j, val, printPass, out, success ) \
466  { \
467  const bool l_result = ( (a)(i,j) == (val) ); \
468  if (!l_result) (success) = false; \
469  if (printPass || !(l_result)) { \
470  out << #a"("<<i<<","<<j<<") = " << (a)(i,j) << " == "#val" = " << (val) \
471  << " : " << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
472  } \
473  }
474 
475 
485 #define TEUCHOS_TEST_COMPARE( v1, comp, v2, out, success ) \
486  { \
487  out << #v1" = "<<(v1)<<" "#comp" "#v2" = "<<(v2)<<" : "; \
488  const bool l_result = (v1) comp (v2); \
489  if (!l_result) (success) = false; \
490  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
491  }
492 
493 
504 #define TEUCHOS_TEST_COMPARE_CONST( v1, comp, v2, out, success ) \
505  { \
506  out << #v1" = "<<(v1)<<" "#comp" "<<(v2)<<" : "; \
507  const bool l_result = (v1) comp (v2); \
508  if (!l_result) (success) = false; \
509  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
510  }
511 
512 
527 #define TEUCHOS_TEST_THROW( code, ExceptType, out, success ) \
528  { \
529  std::ostream& l_out = (out); \
530  try { \
531  l_out << "Test that code {"#code";} throws " \
532  << Teuchos::TypeNameTraits<ExceptType>::name () << ": "; \
533  code; \
534  (success) = false; \
535  l_out << "failed (code did not throw an exception at all)\n"; \
536  } \
537  catch (const ExceptType& except) { \
538  l_out << "passed\n"; \
539  l_out << "\nException message for expected exception:\n\n"; \
540  { \
541  Teuchos::OSTab l_tab(out); \
542  l_out << except.what () << "\n\n"; \
543  (void)l_tab; \
544  } \
545  } \
546  catch (std::exception& except) { \
547  l_out << "The code was supposed to throw an exception of type " \
548  << Teuchos::TypeNameTraits<ExceptType>::name () << ", but " \
549  << "instead threw an exception of type " \
550  << typeid (except).name () << ", which is a subclass of " \
551  << "std::exception. The exception's message is:\n\n"; \
552  { \
553  Teuchos::OSTab l_tab(out); \
554  l_out << except.what () << "\n\n"; \
555  (void)l_tab; \
556  } \
557  l_out << "failed\n"; \
558  } \
559  catch (...) { \
560  l_out << "The code was supposed to throw an exception of type " \
561  << Teuchos::TypeNameTraits<ExceptType>::name () << ", but " \
562  << "instead threw an exception of some unknown type, which is " \
563  << "not a subclass of std::exception. This means we cannot " \
564  << "show you the exception's message, if it even has one.\n\n"; \
565  l_out << "failed\n"; \
566  } \
567  }
568 
569 
576 #define TEUCHOS_TEST_NOTHROW( code, out, success ) \
577  { \
578  std::ostream& l_out = (out); \
579  try { \
580  l_out << "Test that code {"#code";} does not throw : "; \
581  code; \
582  l_out << "passed\n"; \
583  } \
584  catch (std::exception& except) { \
585  (success) = false; \
586  l_out << "The code was not supposed to throw an exception, but " \
587  << "instead threw an exception of type " \
588  << typeid (except).name () << ", which is a subclass of " \
589  << "std::exception. The exception's message is:\n\n"; \
590  { \
591  Teuchos::OSTab l_tab(out); \
592  l_out << except.what () << "\n\n"; \
593  (void)l_tab; \
594  } \
595  l_out << "failed\n"; \
596  } \
597  catch (...) { \
598  (success) = false; \
599  l_out << "The code was not supposed to throw an exception, but " \
600  << "instead threw an exception of some unknown type, which is " \
601  << "not a subclass of std::exception. This means we cannot " \
602  << "show you the exception's message, if it even has one.\n\n"; \
603  l_out << "failed\n"; \
604  } \
605  }
606 
607 //
608 // Implementations
609 //
610 
611 
612 inline
613 void Teuchos::updateSuccess(const bool result, bool &success)
614 {
615  if (!result) success = false;
616 }
617 
618 
619 inline
620 const std::string
621 Teuchos::passfail(const bool result)
622 {
623  if (!result)
624  return "FAILED";
625  return "passed";
626 }
627 
628 
629 template <class Scalar1, class Scalar2>
631 Teuchos::relErr( const Scalar1 &s1, const Scalar2 &s2 )
632 {
633  typedef typename std::common_type<Scalar1,Scalar2>::type Scalar;
635  return
636  ST::magnitude( s1 - s2 )
637  / (
638  ST::magnitude(
640  )
641  + std::max( ST::magnitude(s1), ST::magnitude(s2) )
642  );
643 }
644 
645 
646 template<class Array1, class Array2>
648  const Array1 &a1, const std::string &a1_name,
649  const Array2 &a2, const std::string &a2_name,
651  )
652 {
653  using Teuchos::as;
654 
655  bool success = true;
656 
657  out << "Comparing " << a1_name << " == " << a2_name << " ... ";
658 
659  const int n = a1.size();
660 
661  // Compare sizes
662  if (as<int>(a2.size()) != n) {
663  out << "\nError, "<<a1_name<<".size() = "<<a1.size()<<" == "
664  << a2_name<<".size() = "<<a2.size()<<" : failed!\n";
665  return false;
666  }
667 
668  // Compare elements
669  for( int i = 0; i < n; ++i ) {
670  const bool result = ( a1[i] == a2[i] ); // Tests C::operator[](i) const
671  if (!result) {
672  out << "\nError, "<<a1_name<<"["<<i<<"] = "<<a1[i]<<" == "
673  << a2_name<<"["<<i<<"] = "<<a2[i]<<": failed!\n";
674  success = false;
675  }
676  }
677  if (success) {
678  out << "passed\n";
679  }
680 
681  return success;
682 
683 }
684 
685 
686 template<class Array1, class Array2, class ScalarMag>
688  const Array1 &a1, const std::string &a1_name,
689  const Array2 &a2, const std::string &a2_name,
690  const ScalarMag &tol,
692  )
693 {
694  using Teuchos::as;
695 
696  // Determine the element types of Array1 and Array2
697  using Elem1 = std::decay_t<decltype(std::declval<Array1>()[0])>;
698  using Elem2 = std::decay_t<decltype(std::declval<Array2>()[0])>;
699 
700  static_assert(std::is_same_v<Elem1, Elem2>,
701  "Teuchos::compareFloatingArrays: element types of Array1 and Array2 must be the same.");
702 
703  bool success = true;
704 
705  out << "Comparing " << a1_name << " == " << a2_name << " ... ";
706 
707  const int n = a1.size();
708 
709  // Compare sizes
710  if (as<int>(a2.size()) != n) {
711  out << "\nError, "<<a1_name<<".size() = "<<a1.size()<<" == "
712  << a2_name<<".size() = "<<a2.size()<<" : failed!\n";
713  return false;
714  }
715 
716  // Compare elements
717  for( int i = 0; i < n; ++i ) {
718  const ScalarMag err = relErr( a1[i], a2[i] );
719  if ( !(err <= tol) ) {
720  out
721  <<"\nError, relErr("<<a1_name<<"["<<i<<"],"
722  <<a2_name<<"["<<i<<"]) = relErr("<<a1[i]<<","<<a2[i]<<") = "
723  <<err<<" <= tol = "<<tol<<": failed!\n";
724  success = false;
725  }
726  }
727  if (success) {
728  out << "passed\n";
729  }
730 
731  return success;
732 
733 }
734 
735 template<class Array1, class Array2, class ScalarMag>
737  const Array1 &a1, const std::string &a1_name,
738  const Array2 &a2, const std::string &a2_name,
739  const ScalarMag &tol,
741  )
742 {
743  using Teuchos::as;
744  using Teuchos::ScalarTraits;
745 
746  // Determine the element types of Array1 and Array2
747  using Elem1 = std::decay_t<decltype(std::declval<Array1>()[0])>;
748  using Elem2 = std::decay_t<decltype(std::declval<Array2>()[0])>;
749 
750  static_assert(std::is_same_v<Elem1, Elem2>,
751  "Teuchos::compareFloatingArraysAbsolute: element types of Array1 and Array2 must be the same.");
752 
753  bool success = true;
754 
755  out << "Comparing " << a1_name << " == " << a2_name << " ... ";
756 
757  const int n = a1.size();
758 
759  // Compare sizes
760  if (as<int>(a2.size()) != n) {
761  out << "\nError, "<<a1_name<<".size() = "<<a1.size()<<" == "
762  << a2_name<<".size() = "<<a2.size()<<" : failed!\n";
763  return false;
764  }
765 
766  // Compare elements
767  for( int i = 0; i < n; ++i ) {
768  const ScalarMag err = ScalarTraits<Elem1>::magnitude( a1[i] - a2[i] );
769  if ( !(err <= tol) ) {
770  out
771  <<"\nError, ||"<<a1_name<<"["<<i<<"] - " << a2_name<<"["<<i<<"]|| = "
772  <<err<<" <= tol = "<<tol<<": failed!\n";
773  success = false;
774  }
775  }
776  if (success) {
777  out << "passed\n";
778  }
779  return success;
780 }
781 
782 
783 #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 compareFloatingArraysAbsolute(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 up to an absolute tolerance: elements a1[i] and a2[i] are c...
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.
bool is_null(const std::shared_ptr< T > &p)
Returns true if p.get()==NULL.
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 &quot;passed&quot; or &quot;failed&quot;.
Teuchos header file which uses auto-configuration information to include necessary C++ headers...
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 ...
Compute, check and optionally print the relative error in two scalars.
void updateSuccess(const bool result, bool &success)
Update the success bool flag.
Teuchos::ScalarTraits< typename std::common_type< Scalar1, Scalar2 >::type >::magnitudeType relErr(const Scalar1 &s1, const Scalar2 &s2)
Return relative error of two scalars.
TypeTo as(const TypeFrom &t)
Convert from one value type to another.
Defines basic traits for the scalar field type.
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...