Teuchos Package Browser (Single Doxygen Collection)  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 //
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:
102  {
104  }
105 };
106 
107 
112 template <class Scalar>
113 class RelErrSmallNumber<false,Scalar> {
114 public:
116  {
117  return Scalar(1e-8);
118  }
119 };
120 
121 
126 template <class Scalar>
128 public:
130  {
132  }
133 };
134 
135 
140 template <class Scalar>
142 {
143  const bool hasMachineParameters = ScalarTraits<Scalar>::hasMachineParameters;
145 }
146 
147 
154 template <class Scalar1, class Scalar2>
156 relErr( const Scalar1 &s1, const Scalar2 &s2 );
157 
158 
165 template <typename T1, typename T2, typename Enabled = void>
166 struct TestRelErr {
169  typedef typename std::common_type<magType1,magType2>::type magnitudeType;
170  static bool eval(
171  const std::string &v1_name,
172  const T1 &v1,
173  const std::string &v2_name,
174  const T2 &v2,
175  const std::string &maxRelErr_error_name,
176  const magnitudeType &maxRelErr_error,
177  const std::string &maxRelErr_warning_name,
178  const magnitudeType &maxRelErr_warning,
179  const Ptr<std::ostream> &out
180  )
181  {
182  using std::endl;
183  typedef ScalarTraits<magnitudeType> SMT;
184  const magnitudeType rel_err = relErr( v1, v2 );
185  const bool success = ( !SMT::isnaninf(rel_err) && !SMT::isnaninf(maxRelErr_error)
186  && rel_err <= maxRelErr_error );
187  if (!is_null(out)) {
188  *out
189  << endl
190  << "Check: rel_err(" << v1_name << ", " << v2_name << ")\n"
191  << " = rel_err(" << v1 << ", " << v2 << ") "
192  << "= " << rel_err << endl
193  << " <= " << maxRelErr_error_name
194  << " = " << maxRelErr_error << " : " << passfail(success) << endl;
195  if( success && rel_err >= maxRelErr_warning ) {
196  *out
197  << "Warning! rel_err(" << v1_name << ", " << v2_name << ")\n"
198  << " = rel_err(" << v1 << ", " << v2 << ") "
199  << "= " << rel_err << endl
200  << " >= " << maxRelErr_warning_name
201  << " = " << maxRelErr_warning << "!\n";
202  }
203  }
204  return success;
205  }
206 };
207 
208 template <typename T1, typename T2>
210  const std::string &v1_name,
211  const T1 &v1,
212  const std::string &v2_name,
213  const T2 &v2,
214  const std::string &maxRelErr_error_name,
215  const typename TestRelErr<T1,T2>::magnitudeType &maxRelErr_error,
216  const std::string &maxRelErr_warning_name,
217  const typename TestRelErr<T1,T2>::magnitudeType &maxRelErr_warning,
218  const Ptr<std::ostream> &out) {
219  return TestRelErr<T1,T2>::eval(v1_name, v1, v2_name,v2, maxRelErr_error_name, maxRelErr_error, maxRelErr_warning_name, maxRelErr_warning, out);
220 }
221 
235 template<class Array1, class Array2>
236 bool compareArrays(
237  const Array1 &a1, const std::string &a1_name,
238  const Array2 &a2, const std::string &a2_name,
240  );
241 
242 
258 template<class Array1, class Array2, class ScalarMag>
260  const Array1 &a1, const std::string &a1_name,
261  const Array2 &a2, const std::string &a2_name,
262  const ScalarMag &tol,
264  );
265 
282 template<class Array1, class Array2, class ScalarMag>
284  const Array1 &a1, const std::string &a1_name,
285  const Array2 &a2, const std::string &a2_name,
286  const ScalarMag &tol,
288  );
289 
290 
291 } // namespace Teuchos
292 
293 
302 #define TEUCHOS_PASS_FAIL(RESULT) \
303  Teuchos::passfail_with_location((RESULT), __FILE__, __LINE__)
304 
305 
312 #define TEUCHOS_ECHO( statement, out ) \
313  (out) << #statement ";\n"; \
314  statement;
315 
322 #define TEUCHOS_TEST_EQUALITY_CONST( v1, v2, out, success ) \
323  { \
324  (out) << #v1" = "<<Teuchos::toString(v1)<<" == "<<Teuchos::toString(v2)<<" : "; \
325  const bool l_result = (v1) == (v2); \
326  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
327  if (!l_result) (success) = false; \
328  }
329 
336 #define TEUCHOS_TEST_ASSERT( v1, out, success ) \
337  { \
338  const bool l_result = v1; \
339  (out) << #v1" = "<<l_result<<" == true : "; \
340  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
341  if (!l_result) (success) = false; \
342  }
343 
350 #define TEUCHOS_TEST_EQUALITY( v1, v2, out, success ) \
351  { \
352  (out) << #v1" = "<<Teuchos::toString(v1)<<" == "#v2" = "<<Teuchos::toString(v2)<<" : "; \
353  const bool l_result = (v1) == (v2); \
354  if (!l_result) (success) = false; \
355  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
356  }
357 
358 
365 #define TEUCHOS_TEST_INEQUALITY_CONST( v1, v2, out, success ) \
366  { \
367  (out) << #v1" = "<<Teuchos::toString(v1)<<" != "<<Teuchos::toString(v2)<<" : "; \
368  const bool l_result = (v1) != (v2); \
369  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
370  if (!l_result) (success) = false; \
371  }
372 
373 
380 #define TEUCHOS_TEST_INEQUALITY( v1, v2, out, success ) \
381  { \
382  (out) << #v1" = "<<Teuchos::toString(v1)<<" != "#v2" = "<<Teuchos::toString(v2)<<" : "; \
383  const bool l_result = (v1) != (v2); \
384  if (!l_result) (success) = false; \
385  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
386  }
387 
388 
395 #define TEUCHOS_TEST_FLOATING_EQUALITY( v1, v2, tol, out, success ) \
396  { \
397  const bool l_result = Teuchos::testRelErr( \
398  #v1, v1, #v2, v2, "tol", tol, "tol", tol, Teuchos::outArg(out) ); \
399  if (!l_result) (success) = false; \
400  }
401 
402 
412 #define TEUCHOS_TEST_ITER_EQUALITY( iter1, iter2, out, success ) \
413  { \
414  (out) << #iter1" == "#iter2" = : "; \
415  const bool l_result = (iter1) == (iter2); \
416  if (!l_result) (success) = false; \
417  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
418  }
419 
420 
430 #define TEUCHOS_TEST_ITER_INEQUALITY( iter1, iter2, out, success ) \
431  { \
432  (out) << #iter1" != "#iter2" = : "; \
433  const bool l_result = (iter1) != (iter2); \
434  if (!l_result) (success) = false; \
435  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
436  }
437 
438 
445 #define TEUCHOS_TEST_ARRAY_ELE_EQUALITY( a, i, val, printPass, out, success ) \
446  { \
447  const bool l_result = ( (a)[i] == (val) ); \
448  if (!l_result) (success) = false; \
449  if (printPass || !(l_result)) { \
450  out << #a"["<<i<<"] = " << Teuchos::toString((a)[i]) << " == "#val" = " << Teuchos::toString(val) \
451  << " : " << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
452  } \
453  }
454 
455 
462 #define TEUCHOS_TEST_ARRAY_ELE_INEQUALITY( a, i, val, printPass, out, success ) \
463  { \
464  const bool l_result = ( (a)[i] != (val) ); \
465  if (!l_result) (success) = false; \
466  if (printPass || !(l_result)) { \
467  out << #a"["<<i<<"] = " << Teuchos::toString((a)[i]) << " != "#val" = " << Teuchos::toString(val) \
468  << " : " << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
469  } \
470  }
471 
472 
480 #define TEUCHOS_TEST_MATRIX_ELE_FLOATING_EQUALITY( a, i, j, val, tol, printPass, out, success ) \
481  { \
482  std::ostringstream a_i_str; \
483  a_i_str <<#a<<"("<<i<<","<<j<<")"; \
484  const bool l_result = Teuchos::testRelErr( \
485  a_i_str.str(), (a)(i,j), #val, val, "tol", tol, "tol", tol, \
486  (printPass) ? Teuchos::outArg(out) : Teuchos::null ); \
487  if (!l_result) (success) = false; \
488  }
489 
490 
497 #define TEUCHOS_TEST_MATRIX_ELE_EQUALITY( a, i, j, val, printPass, out, success ) \
498  { \
499  const bool l_result = ( (a)(i,j) == (val) ); \
500  if (!l_result) (success) = false; \
501  if (printPass || !(l_result)) { \
502  out << #a"("<<i<<","<<j<<") = " << (a)(i,j) << " == "#val" = " << (val) \
503  << " : " << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
504  } \
505  }
506 
507 
517 #define TEUCHOS_TEST_COMPARE( v1, comp, v2, out, success ) \
518  { \
519  out << #v1" = "<<(v1)<<" "#comp" "#v2" = "<<(v2)<<" : "; \
520  const bool l_result = (v1) comp (v2); \
521  if (!l_result) (success) = false; \
522  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
523  }
524 
525 
536 #define TEUCHOS_TEST_COMPARE_CONST( v1, comp, v2, out, success ) \
537  { \
538  out << #v1" = "<<(v1)<<" "#comp" "<<(v2)<<" : "; \
539  const bool l_result = (v1) comp (v2); \
540  if (!l_result) (success) = false; \
541  (out) << TEUCHOS_PASS_FAIL(l_result) << "\n"; \
542  }
543 
544 
559 #define TEUCHOS_TEST_THROW( code, ExceptType, out, success ) \
560  { \
561  std::ostream& l_out = (out); \
562  try { \
563  l_out << "Test that code {"#code";} throws " \
564  << Teuchos::TypeNameTraits<ExceptType>::name () << ": "; \
565  code; \
566  (success) = false; \
567  l_out << "failed (code did not throw an exception at all)\n"; \
568  } \
569  catch (const ExceptType& except) { \
570  l_out << "passed\n"; \
571  l_out << "\nException message for expected exception:\n\n"; \
572  { \
573  Teuchos::OSTab l_tab(out); \
574  l_out << except.what () << "\n\n"; \
575  (void)l_tab; \
576  } \
577  } \
578  catch (std::exception& except) { \
579  l_out << "The code was supposed to throw an exception of type " \
580  << Teuchos::TypeNameTraits<ExceptType>::name () << ", but " \
581  << "instead threw an exception of type " \
582  << typeid (except).name () << ", which is a subclass of " \
583  << "std::exception. The exception's message is:\n\n"; \
584  { \
585  Teuchos::OSTab l_tab(out); \
586  l_out << except.what () << "\n\n"; \
587  (void)l_tab; \
588  } \
589  l_out << "failed\n"; \
590  } \
591  catch (...) { \
592  l_out << "The code was supposed to throw an exception of type " \
593  << Teuchos::TypeNameTraits<ExceptType>::name () << ", but " \
594  << "instead threw an exception of some unknown type, which is " \
595  << "not a subclass of std::exception. This means we cannot " \
596  << "show you the exception's message, if it even has one.\n\n"; \
597  l_out << "failed\n"; \
598  } \
599  }
600 
601 
608 #define TEUCHOS_TEST_NOTHROW( code, out, success ) \
609  { \
610  std::ostream& l_out = (out); \
611  try { \
612  l_out << "Test that code {"#code";} does not throw : "; \
613  code; \
614  l_out << "passed\n"; \
615  } \
616  catch (std::exception& except) { \
617  (success) = false; \
618  l_out << "The code was not supposed to throw an exception, but " \
619  << "instead threw an exception of type " \
620  << typeid (except).name () << ", which is a subclass of " \
621  << "std::exception. The exception's message is:\n\n"; \
622  { \
623  Teuchos::OSTab l_tab(out); \
624  l_out << except.what () << "\n\n"; \
625  (void)l_tab; \
626  } \
627  l_out << "failed\n"; \
628  } \
629  catch (...) { \
630  (success) = false; \
631  l_out << "The code was not supposed to throw an exception, but " \
632  << "instead threw an exception of some unknown type, which is " \
633  << "not a subclass of std::exception. This means we cannot " \
634  << "show you the exception's message, if it even has one.\n\n"; \
635  l_out << "failed\n"; \
636  } \
637  }
638 
639 //
640 // Implementations
641 //
642 
643 
644 inline
645 void Teuchos::updateSuccess(const bool result, bool &success)
646 {
647  if (!result) success = false;
648 }
649 
650 
651 inline
652 const std::string
653 Teuchos::passfail(const bool result)
654 {
655  if (!result)
656  return "FAILED";
657  return "passed";
658 }
659 
660 
661 template <class Scalar1, class Scalar2>
663 Teuchos::relErr( const Scalar1 &s1, const Scalar2 &s2 )
664 {
665  typedef typename std::common_type<Scalar1,Scalar2>::type Scalar;
667  return
668  ST::magnitude( s1 - s2 )
669  / (
670  ST::magnitude(
672  )
673  + std::max( ST::magnitude(s1), ST::magnitude(s2) )
674  );
675 }
676 
677 
678 template<class Array1, class Array2>
680  const Array1 &a1, const std::string &a1_name,
681  const Array2 &a2, const std::string &a2_name,
683  )
684 {
685  using Teuchos::as;
686 
687  bool success = true;
688 
689  out << "Comparing " << a1_name << " == " << a2_name << " ... ";
690 
691  const int n = a1.size();
692 
693  // Compare sizes
694  if (as<int>(a2.size()) != n) {
695  out << "\nError, "<<a1_name<<".size() = "<<a1.size()<<" == "
696  << a2_name<<".size() = "<<a2.size()<<" : failed!\n";
697  return false;
698  }
699 
700  // Compare elements
701  for( int i = 0; i < n; ++i ) {
702  const bool result = ( a1[i] == a2[i] ); // Tests C::operator[](i) const
703  if (!result) {
704  out << "\nError, "<<a1_name<<"["<<i<<"] = "<<a1[i]<<" == "
705  << a2_name<<"["<<i<<"] = "<<a2[i]<<": failed!\n";
706  success = false;
707  }
708  }
709  if (success) {
710  out << "passed\n";
711  }
712 
713  return success;
714 
715 }
716 
717 
718 template<class Array1, class Array2, class ScalarMag>
720  const Array1 &a1, const std::string &a1_name,
721  const Array2 &a2, const std::string &a2_name,
722  const ScalarMag &tol,
724  )
725 {
726  using Teuchos::as;
727 
728  // Determine the element types of Array1 and Array2
729  using Elem1 = std::decay_t<decltype(std::declval<Array1>()[0])>;
730  using Elem2 = std::decay_t<decltype(std::declval<Array2>()[0])>;
731 
732  static_assert(std::is_same_v<Elem1, Elem2>,
733  "Teuchos::compareFloatingArrays: element types of Array1 and Array2 must be the same.");
734 
735  bool success = true;
736 
737  out << "Comparing " << a1_name << " == " << a2_name << " ... ";
738 
739  const int n = a1.size();
740 
741  // Compare sizes
742  if (as<int>(a2.size()) != n) {
743  out << "\nError, "<<a1_name<<".size() = "<<a1.size()<<" == "
744  << a2_name<<".size() = "<<a2.size()<<" : failed!\n";
745  return false;
746  }
747 
748  // Compare elements
749  for( int i = 0; i < n; ++i ) {
750  const ScalarMag err = relErr( a1[i], a2[i] );
751  if ( !(err <= tol) ) {
752  out
753  <<"\nError, relErr("<<a1_name<<"["<<i<<"],"
754  <<a2_name<<"["<<i<<"]) = relErr("<<a1[i]<<","<<a2[i]<<") = "
755  <<err<<" <= tol = "<<tol<<": failed!\n";
756  success = false;
757  }
758  }
759  if (success) {
760  out << "passed\n";
761  }
762 
763  return success;
764 
765 }
766 
767 template<class Array1, class Array2, class ScalarMag>
769  const Array1 &a1, const std::string &a1_name,
770  const Array2 &a2, const std::string &a2_name,
771  const ScalarMag &tol,
773  )
774 {
775  using Teuchos::as;
776  using Teuchos::ScalarTraits;
777 
778  // Determine the element types of Array1 and Array2
779  using Elem1 = std::decay_t<decltype(std::declval<Array1>()[0])>;
780  using Elem2 = std::decay_t<decltype(std::declval<Array2>()[0])>;
781 
782  static_assert(std::is_same_v<Elem1, Elem2>,
783  "Teuchos::compareFloatingArraysAbsolute: element types of Array1 and Array2 must be the same.");
784 
785  bool success = true;
786 
787  out << "Comparing " << a1_name << " == " << a2_name << " ... ";
788 
789  const int n = a1.size();
790 
791  // Compare sizes
792  if (as<int>(a2.size()) != n) {
793  out << "\nError, "<<a1_name<<".size() = "<<a1.size()<<" == "
794  << a2_name<<".size() = "<<a2.size()<<" : failed!\n";
795  return false;
796  }
797 
798  // Compare elements
799  for( int i = 0; i < n; ++i ) {
800  const ScalarMag err = ScalarTraits<Elem1>::magnitude( a1[i] - a2[i] );
801  if ( !(err <= tol) ) {
802  out
803  <<"\nError, ||"<<a1_name<<"["<<i<<"] - " << a2_name<<"["<<i<<"]|| = "
804  <<err<<" <= tol = "<<tol<<": failed!\n";
805  success = false;
806  }
807  }
808  if (success) {
809  out << "passed\n";
810  }
811  return success;
812 }
813 
814 
815 #endif // TEUCHOS_TESTING_HELPERS_HPP
static bool eval(const std::string &v1_name, const T1 &v1, const std::string &v2_name, const T2 &v2, const std::string &maxRelErr_error_name, const magnitudeType &maxRelErr_error, const std::string &maxRelErr_warning_name, const magnitudeType &maxRelErr_warning, const Ptr< std::ostream > &out)
void showTestFailureLocation(bool)
Set if TEUCHOS_PASS_FAIL(...) should print test failure location.
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...
Scalar defaultSmallNumber()
static magnitudeType eps()
Returns relative machine precision.
bool is_null(const std::shared_ptr< T > &p)
Returns true if p.get()==NULL.
Teuchos::ScalarTraits< T2 >::magnitudeType magType2
Teuchos header file which uses auto-configuration information to include necessary C++ headers...
const std::string passfail(const bool result)
Return &quot;passed&quot; or &quot;failed&quot;.
std::common_type< magType1, magType2 >::type magnitudeType
This structure defines some basic traits for a scalar field type.
Teuchos::ScalarTraits< T1 >::magnitudeType magType1
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.
void updateSuccess(const bool result, bool &success)
Update the success bool flag.
#define TEUCHOSCORE_LIB_DLL_EXPORT
std::ostream subclass that performs the magic of indenting data sent to an std::ostream object among ...
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.
Compute, check and optionally print the relative error in two scalars.
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(...).
bool testRelErr(const std::string &v1_name, const T1 &v1, const std::string &v2_name, const T2 &v2, const std::string &maxRelErr_error_name, const typename TestRelErr< T1, T2 >::magnitudeType &maxRelErr_error, const std::string &maxRelErr_warning_name, const typename TestRelErr< T1, T2 >::magnitudeType &maxRelErr_warning, const Ptr< std::ostream > &out)
TypeTo as(const TypeFrom &t)
Convert from one value type to another.
Teuchos::ScalarTraits< typename std::common_type< Scalar1, Scalar2 >::type >::magnitudeType relErr(const Scalar1 &s1, const Scalar2 &s2)
Return relative error of two scalars.
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...