test.H 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. // (c) Daniel Llorens - 2012, 2014-2015
  2. // This library is free software; you can redistribute it and/or modify it under
  3. // the terms of the GNU Lesser General Public License as published by the Free
  4. // Software Foundation; either version 3 of the License, or (at your option) any
  5. // later version.
  6. #ifndef RA_TEST_H
  7. #define RA_TEST_H
  8. /// @file test.H
  9. /// @brief Minimal test library.
  10. #include <string>
  11. #include <iostream>
  12. #include <iomanip>
  13. #include <limits>
  14. #include "ra/format.H"
  15. #include "ra/real.H"
  16. // @TODO Only for where(); unfortunately I can't declare the scalar version in an earlier header.
  17. #include "ra/ra-operators.H"
  18. char const * esc_bold = "\x1b[01m";
  19. char const * esc_unbold = "\x1b[0m";
  20. char const * esc_red = "\x1b[31m";
  21. char const * esc_green = "\x1b[32m";
  22. char const * esc_cyan = "\x1b[36m";
  23. char const * esc_yellow = "\x1b[33m";
  24. char const * esc_blue = "\x1b[34m";
  25. char const * esc_plain = "\x1b[39m";
  26. template <class ... A> void section(A const & ... a)
  27. {
  28. std::cout << "\n\n" << esc_bold << format(a ...) << esc_unbold << std::endl;
  29. }
  30. struct TestRecorder
  31. {
  32. std::ostream & o;
  33. int total = 0;
  34. std::vector<int> failed;
  35. std::string info_string;
  36. bool isquiet_default, isquiet;
  37. TestRecorder(std::ostream & o_=std::cout, bool isquiet_default_=false)
  38. : o(o_), isquiet_default(isquiet_default_), isquiet(isquiet_default_) {}
  39. static std::string format_error(double e)
  40. {
  41. return format(esc_yellow, std::setprecision(2), e, esc_plain);
  42. }
  43. template <class ... A> TestRecorder & info(A && ... a)
  44. {
  45. info_string += (info_string=="" ? "" : "; ") + format(a ...);
  46. return *this;
  47. }
  48. TestRecorder & quiet(bool q=true)
  49. {
  50. isquiet = q;
  51. return *this;
  52. }
  53. void test(bool c)
  54. {
  55. if (!c) {
  56. failed.push_back(total);
  57. }
  58. if (isquiet) {
  59. if (!c) {
  60. o << esc_cyan << "[" << total << "] " << esc_plain << esc_bold << esc_red << "FAILED" << esc_plain << esc_unbold
  61. << "... " << info_string << std::endl;
  62. }
  63. } else {
  64. o << esc_cyan << "[" << total << "] " << esc_plain
  65. << (c ? std::string(esc_green)+"ok"+esc_plain
  66. : std::string(esc_bold)+esc_red+"FAILED"+esc_plain+esc_unbold)
  67. << "... " << info_string << std::endl;
  68. }
  69. info_string = "";
  70. isquiet = isquiet_default;
  71. ++total;
  72. }
  73. void operator+=(bool c)
  74. {
  75. test(c);
  76. }
  77. template <class W, class A>
  78. bool test_eq(W && wanted, A && got)
  79. {
  80. bool c = every(wanted==got);
  81. // where() to match shapes if either doesn't have one
  82. info("equal(wanted: ", where(true, wanted, got), ", got: ", got, ")").test(c);
  83. return c;
  84. }
  85. template <class W, class A, class Comp>
  86. bool test_comp(W && wanted, A && got, Comp && comp)
  87. {
  88. bool c = every(map(comp, wanted, got));
  89. // where() to match shapes if either doesn't have one
  90. info("comp(wanted: ", where(true, wanted, got), ", got: ", got, ")").test(c);
  91. return c;
  92. }
  93. template <class W, class A>
  94. double test_rel_error(W && wanted, A && got, double req_err=0)
  95. {
  96. double e = amax(where(isnan(wanted),
  97. where(isnan(got), 0., std::numeric_limits<double>::infinity()),
  98. rel_error(wanted, got)));
  99. info("rel_error(wanted: ", wanted, ", got: ", got, ") = ", format_error(e), ", req. ", req_err)
  100. .test(e<=req_err);
  101. return e;
  102. }
  103. template <class W, class A>
  104. double test_abs_error(W && wanted, A && got, double req_err=0)
  105. {
  106. double e = amax(where(isnan(wanted),
  107. where(isnan(got), 0., std::numeric_limits<double>::infinity()),
  108. abs(wanted-got)));
  109. info("abs_error(wanted: ", wanted, ", got: ", got, ") = ", format_error(e), ", req. ", req_err)
  110. .test(e<=req_err);
  111. return e;
  112. }
  113. int summary() const
  114. {
  115. if (failed.empty()) {
  116. o << esc_bold << esc_green << total << " tests passed";
  117. } else {
  118. o << esc_bold << esc_red << failed.size() << " tests of " << total << " failed (" << rawp(failed) << ")";
  119. }
  120. o << esc_plain << esc_unbold << std::flush;
  121. return failed.size();
  122. }
  123. };
  124. #endif // RA_TEST_H