test_mgr.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2018, Andrew W. Steiner
5 
6  This file is part of O2scl.
7 
8  O2scl is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12 
13  O2scl is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with O2scl. If not, see <http://www.gnu.org/licenses/>.
20 
21  -------------------------------------------------------------------
22 */
23 #ifndef O2SCL_TEST_MGR_H
24 #define O2SCL_TEST_MGR_H
25 
26 /** \file test_mgr.h
27  \brief File defining \ref o2scl::test_mgr
28 */
29 
30 #include <string>
31 
32 #include <o2scl/string_conv.h>
33 #include <o2scl/misc.h>
34 #include <o2scl/table_units.h>
35 
36 #include <gsl/gsl_vector.h>
37 #include <gsl/gsl_sys.h>
38 #include <gsl/gsl_matrix.h>
39 
40 #ifndef DOXYGEN_NO_O2NS
41 namespace o2scl {
42 #endif
43 
44  /** \brief A class to manage testing and record success and failure
45  */
46  class test_mgr {
47 
48  protected:
49 
50 #ifndef DOXYGEN_INTERNAL
51 
52  /// The number of tests performed
53  int ntests;
54 
55  /// The output level
57 
58  /// A helper function for processing tests
59  void process_test(bool ret, std::string d2, std::string description);
60 
61  /// True if all tests have passed
62  bool success;
63 
64  /// The description of the last failed test
65  std::string last_fail;
66 
67 #endif
68 
69  public:
70 
71  /// Create a \ref test_mgr object
72  test_mgr(bool success_l=true, std::string last_fail_l="",
73  int ntests_l=0, int output_level_l=1) {
74  success=success_l;
75  last_fail=last_fail_l;
76  ntests=ntests_l;
77  output_level=output_level_l;
78  }
79 
80  /** \brief Provide a report of all tests so far.
81 
82  This function reports on whether or not all tests have passed
83  according to the current output level. It returns true if all
84  tests have passed and false if at least one test failed.
85  */
86  bool report() const;
87 
88  /// \name Individual get and set methods
89  //@{
90  /// Return true if all tests have succeeded
91  bool get_success() const {
92  return success;
93  }
94 
95  /// Return the last failure description
96  std::string get_last_fail() const {
97  return last_fail;
98  }
99 
100  /// Return the output level
101  int get_output_level() const {
102  return output_level;
103  }
104 
105  /// Returns the description of the last test that failed.
106  std::string get_last_fail() { return last_fail; };
107 
108  /** \brief Set the output level
109 
110  Possible values:
111  - 0 = No output
112  - 1 = Output only tests that fail
113  - 2 = Output all tests
114  */
115  void set_output_level(int l) { output_level=l; };
116 
117  /// Return the number of tests performed so far
118  int get_ntests() const { return ntests; };
119  //@}
120 
121  /// \name Main testing methods
122  //@{
123  /** \brief Test for \f$|\mathrm{result}-\mathrm{expected}|/
124  \mathrm{expected}<\mathrm{rel\_error}\f$
125  */
126  template<class data_t>
127  bool test_rel(data_t result, data_t expected, data_t rel_error,
128  std::string description) {
129  bool ret;
130  if (std::isnan(expected)) {
131  ret=(std::isnan(expected)==std::isnan(result));
132  description=dtos(result)+" vs. "+ dtos(expected)+
133  "\n "+description;
134  } else if (std::isinf(expected)) {
135  ret=(std::isinf(expected)==std::isinf(result));
136  description=dtos(result)+" vs. "+ dtos(expected)+
137  "\n "+description;
138  } else if (expected==0.0) {
139  ret=test_abs(result,expected,rel_error,description);
140  return ret;
141  } else {
142  double obs_err=std::abs(expected-result)/std::abs(expected);
143  ret=(obs_err<rel_error);
144  if (ret) {
145  description=dtos(result)+" vs. "+dtos(expected)+
146  " : "+dtos(obs_err)+
147  " < "+dtos(rel_error)+"\n "+description;
148  } else {
149  description=dtos(result)+" vs. "+dtos(expected)+
150  " : "+dtos(obs_err)+
151  " > "+dtos(rel_error)+"\n "+description;
152  }
153  }
154 
155  process_test(ret,"relative",description);
156  return ret;
157  }
158 
159  /** \brief Test for \f$|\mathrm{result}-\mathrm{expected}|/
160  <\mathrm{abs\_error}\f$
161  */
162  template<class data_t>
163  bool test_abs(data_t result, data_t expected, data_t abs_error,
164  std::string description) {
165  bool ret;
166  if (std::isnan(expected)) {
167  ret=(std::isnan(expected)==std::isnan(result));
168  description=dtos(result)+" vs. "+ dtos(expected)+
169  "\n "+description;
170  } else if (std::isinf(expected)) {
171  ret=(std::isinf(expected)==std::isinf(result));
172  description=dtos(result)+" vs. "+ dtos(expected)+
173  "\n "+description;
174  } else {
175  ret=(std::abs(expected-result)<abs_error);
176  if (ret) {
177  description=dtos(result)+" vs. "+ dtos(expected)+" : "
178  +dtos(std::abs(expected-result))+" < "+dtos(abs_error)+
179  "\n "+description;
180  } else {
181  description=dtos(result)+" vs. "+ dtos(expected)+" : "
182  +dtos(std::abs(expected-result))+" > "+dtos(abs_error)+
183  "\n "+description;
184  }
185  }
186 
187  process_test(ret,"absolute",description);
188 
189  return ret;
190  }
191 
192  /** \brief Test for \f$1/\mathrm{factor} < \mathrm{result/expected}
193  < \mathrm{factor}\f$
194  */
195  template<class data_t>
196  bool test_fact(data_t result, data_t expected, data_t factor,
197  std::string description) {
198  bool ret;
199  double ratio;
200  if (std::isnan(expected)) {
201  ret=(std::isnan(expected)==std::isnan(result));
202  } else if (std::isinf(expected)) {
203  ret=(std::isinf(expected)==std::isinf(result));
204  } else {
205  ratio=expected/result;
206  ret=(ratio<factor && ratio>1.0/factor);
207  }
208 
209  description= dtos(result)+" vs. "+ dtos(expected)+"\n "+
210  description;
211  process_test(ret,"factor",description);
212 
213  return ret;
214  }
215 
216  /// Test for \f$\mathrm{result}=\mathrm{expected}\f$
217  bool test_str(std::string result, std::string expected,
218  std::string description);
219 
220  /// Test for \f$\mathrm{result}=\mathrm{expected}\f$
221  bool test_gen(bool value, std::string description);
222  //@}
223 
224  /// \name Vector testing methods
225  //@{
226  /** \brief Test for \f$|\mathrm{result}-\mathrm{expected}|/
227  \mathrm{expected}<\mathrm{rel\_error}\f$ over each element
228  of an array
229  */
230  template<class vec_t, class vec2_t, class data_t>
231  bool test_rel_vec(int nv, const vec_t &result, const vec2_t &expected,
232  data_t rel_error, std::string description) {
233  bool ret=true;
234  double max=0.0;
235  int i;
236 
237  for(i=0;i<nv;i++) {
238  if (std::isnan(expected[i])) {
239  ret=(ret && (std::isnan(expected[i])==std::isnan(result[i])));
240  } else if (std::isinf(expected[i])) {
241  ret=(ret && (std::isinf(expected[i])==std::isinf(result[i])));
242  } else if (expected[i]==0.0) {
243  ret=(ret && test_abs(result[i],expected[i],rel_error,description));
244  if (std::abs(result[i]-expected[i])>max) {
245  max=std::abs(result[i]-expected[i]);
246  }
247  } else {
248  ret=(ret && ((std::abs(expected[i]-result[i]))/
249  std::abs(expected[i])<rel_error));
250  if (std::abs(expected[i]-result[i])/std::abs(expected[i])>max) {
251  max=std::abs(expected[i]-result[i])/std::abs(expected[i]);
252  }
253  }
254  }
255 
256  description=((std::string)"max=")+o2scl::dtos(max)+
257  "\n "+description;
258  process_test(ret,"relative array",description);
259 
260  return ret;
261  }
262 
263  /** \brief Test for \f$|\mathrm{result}-\mathrm{expected}|/
264  <\mathrm{abs\_error}\f$ over each element
265  of an array
266  */
267  template<class vec_t, class vec2_t, class data_t>
268  bool test_abs_vec(int nv, const vec_t &result, const vec2_t &expected,
269  data_t abs_error, std::string description) {
270  bool ret=true;
271  int i;
272 
273  for(i=0;i<nv;i++) {
274  if (std::isnan(expected[i])) {
275  ret=(ret && (std::isnan(expected[i])==std::isnan(result[i])));
276  } else if (std::isinf(expected[i])) {
277  ret=(ret && (std::isinf(expected[i])==std::isinf(result[i])));
278  } else {
279  ret=(ret && (std::abs(expected[i]-result[i])<abs_error));
280  }
281  }
282 
283  description="\n "+description;
284  process_test(ret,"absolute array",description);
285 
286  return ret;
287  }
288 
289  /** \brief Test for \f$ 1/factor < result/expected < factor \f$
290  over each element of an array
291  */
292  template<class vec_t, class vec2_t, class data_t>
293  bool test_fact_vec(int nv, const vec_t &result, const vec2_t &expected,
294  data_t factor, std::string description) {
295  bool ret=true;
296  int i;
297  double ratio;
298 
299  for(i=0;i<nv;i++) {
300  if (std::isnan(expected[i])) {
301  ret=(ret && (std::isnan(expected[i])==std::isnan(result[i])));
302  } else if (std::isinf(expected[i])) {
303  ret=(ret && (std::isinf(expected[i])==std::isinf(result[i])));
304  } else {
305  ratio=expected[i]/result[i];
306  ret=(ret && (ratio<factor && ratio>1.0/factor));
307  }
308  }
309 
310  description="\n "+description;
311  process_test(ret,"factor array",description);
312 
313  return ret;
314  }
315 
316  /// Test for equality of a generic array
317  template<class vec_t>
318  bool test_gen_vec(int nv, const vec_t &result, const vec_t &expected,
319  std::string description) {
320  bool ret=true;
321  int i;
322 
323  for(i=0;i<nv;i++) {
324  ret=(ret && (result[i]==expected[i]));
325  }
326 
327  description="\n "+description;
328  process_test(ret,"generic array",description);
329 
330  return ret;
331  }
332  //@}
333 
334  /// \name Matrix testing methods
335  //@{
336  /** \brief Test for \f$|\mathrm{result}-\mathrm{expected}|/
337  \mathrm{expected}<\mathrm{rel\_error}\f$ over each element
338  in a matrix
339  */
340  template<class mat_t, class mat2_t, class data_t>
341  bool test_rel_mat(int nr, int nc, const mat_t &result,
342  const mat2_t &expected,
343  data_t rel_error, std::string description) {
344  bool ret=true;
345  double max=0.0;
346  int i, j;
347 
348  for(i=0;i<nr;i++) {
349  for(j=0;j<nc;j++) {
350  if (std::isnan(expected(i,j))) {
351  ret=(ret && (std::isnan(expected(i,j))==
352  std::isnan(result(i,j))));
353  } else if (std::isinf(expected(i,j))) {
354  ret=(ret && (std::isinf(expected(i,j))==
355  std::isinf(result(i,j))));
356  } else if (expected(i,j)==0.0) {
357  ret=(ret && test_abs(result(i,j),expected(i,j),rel_error,
358  description));
359  if (std::abs(result(i,j)-expected(i,j))>max) {
360  max=std::abs(result(i,j)-expected(i,j));
361  }
362  } else {
363  ret=(ret && ((std::abs(expected(i,j)-result(i,j)))/
364  std::abs(expected(i,j))<rel_error));
365  if (std::abs(expected(i,j)-result(i,j))/std::abs(expected(i,j))>max) {
366  max=std::abs(expected(i,j)-result(i,j))/std::abs(expected(i,j));
367  }
368  }
369  }
370  }
371 
372  description=((std::string)"max=")+o2scl::dtos(max)+
373  "\n "+description;
374  process_test(ret,"relative matrix",description);
375 
376  return ret;
377 
378  }
379 
380  /** \brief Test for \f$|\mathrm{result}-\mathrm{expected}|/
381  \mathrm{expected}<\mathrm{rel\_error}\f$ over each element
382  in a matrix larger than a specified tolerance
383  */
384  template<class mat_t, class mat2_t, class data_t>
385  bool test_rel_nonzero_mat(int nr, int nc, const mat_t &result,
386  const mat2_t &expected,
387  data_t error, data_t zero_tol,
388  std::string description) {
389  bool ret=true;
390  double max=0.0;
391  int i, j;
392 
393  for(i=0;i<nr;i++) {
394  for(j=0;j<nc;j++) {
395  if (std::isnan(expected(i,j))) {
396  ret=(ret && (std::isnan(expected(i,j))==
397  std::isnan(result(i,j))));
398  } else if (std::isinf(expected(i,j))) {
399  ret=(ret && (std::isinf(expected(i,j))==
400  std::isinf(result(i,j))));
401  } else if (expected(i,j)<zero_tol) {
402  ret=(ret && test_abs(result(i,j),expected(i,j),error,
403  description));
404  if (std::abs(result(i,j)-expected(i,j))>max) {
405  max=std::abs(result(i,j)-expected(i,j));
406  }
407  } else {
408  ret=(ret && ((std::abs(expected(i,j)-result(i,j)))/
409  std::abs(expected(i,j))<error));
410  if (std::abs(expected(i,j)-result(i,j))/
411  std::abs(expected(i,j))>max) {
412  max=std::abs(expected(i,j)-result(i,j))/
413  std::abs(expected(i,j));
414  }
415  }
416  }
417  }
418 
419  description=((std::string)"max=")+o2scl::dtos(max)+
420  "\n "+description;
421  process_test(ret,"rel_nonzero matrix",description);
422 
423  return ret;
424 
425  }
426 
427  /** \brief Test for \f$|\mathrm{result}-\mathrm{expected}| <
428  \mathrm{abs\_error} \f$ over each element in a matrix
429  */
430  template<class mat_t, class mat2_t, class data_t>
431  bool test_abs_mat(int nr, int nc, const mat_t &result,
432  const mat2_t &expected, data_t abs_error,
433  std::string description) {
434 
435  bool ret=true;
436  double max=0.0;
437  int i, j;
438 
439  for(i=0;i<nr;i++) {
440  for(j=0;j<nc;j++) {
441  if (std::isnan(expected(i,j))) {
442  ret=(ret && (std::isnan(expected(i,j))==
443  std::isnan(result(i,j))));
444  } else if (std::isinf(expected(i,j))) {
445  ret=(ret && (std::isinf(expected(i,j))==
446  std::isinf(result(i,j))));
447  } else if (expected(i,j)==0.0) {
448  ret=(ret && test_abs(result(i,j),expected(i,j),abs_error,
449  description));
450  if (std::abs(result(i,j)-expected(i,j))>max) {
451  max=std::abs(result(i,j)-expected(i,j));
452  }
453  } else {
454  ret=(ret && ((std::abs(expected(i,j)-result(i,j)))<abs_error));
455  if (std::abs(expected(i,j)-result(i,j))>max) {
456  max=std::abs(expected(i,j)-result(i,j));
457  }
458  }
459  }
460  }
461 
462  description=((std::string)"max=")+o2scl::dtos(max)+
463  "\n "+description;
464  process_test(ret,"absolute matrix",description);
465 
466  return ret;
467 
468  }
469  //@}
470 
471  /** \brief Compare entries in \c expected to see if they match
472  those in table \c result.
473 
474  If the numbers in the \c expected table have an absolute value
475  less than \c zero_tol, then the absolute value of the
476  difference is used for the comparison. Otherwise, the absolute
477  value of the relative difference is used to make the
478  comparison.
479  */
480  template<class vec_t, class data_t>
482  const table_units<vec_t> &expected,
483  data_t error, data_t zero_tol,
484  std::string description) {
485  bool ret=true;
486  int i, j;
487  int nr=result.get_nlines();
488  int nc=result.get_ncolumns();
489  std::vector<double> max(nc);
490 
491  for(i=0;i<nc;i++) {
492  std::string col_name=expected.get_column_name(i);
493  for(j=0;j<nr;j++) {
494  std::string desc1=description+" col: "+col_name+" row: "+
495  o2scl::itos(j);
496  if (std::isnan(expected.get(i,j))) {
497  bool ret1=test_gen(std::isnan(expected.get(i,j))==
498  std::isnan(result.get(i,j)),desc1);
499  ret=(ret && ret1);
500  } else if (std::isinf(expected.get(i,j))) {
501  bool ret1=test_gen(std::isinf(expected.get(i,j))==
502  std::isinf(result.get(i,j)),desc1);
503  ret=(ret && ret1);
504  } else if (expected.get(i,j)<zero_tol) {
505  bool ret1=test_abs(result.get(i,j),expected.get(i,j),error,
506  desc1);
507  if (std::abs(result.get(i,j)-expected.get(i,j))>max[i]) {
508  max[i]=std::abs(result.get(i,j)-expected.get(i,j));
509  }
510  } else {
511  bool ret1=test_rel(result.get(i,j),expected.get(i,j),error,
512  desc1);
513  ret=(ret && ret1);
514  if (std::abs(expected.get(i,j)-result.get(i,j))/
515  std::abs(expected.get(i,j))>max[i]) {
516  max[i]=std::abs(expected.get(i,j)-result.get(i,j))/
517  std::abs(expected.get(i,j));
518  }
519  }
520  }
521  }
522 
523  if ((output_level>=1 && ret==false) || output_level>=2) {
524  for(i=0;i<nc;i++) {
525  std::cout << "Max for " << expected.get_column_name(i) << " is "
526  << max[i] << std::endl;
527  }
528  }
529  process_test(ret,"rel_nonzero table",description);
530 
531  return ret;
532 
533  }
534 
535  /** \brief Add two test_mgr objects (if either failed, the sum fails)
536 
537  The output level is set to the maximum value of left and
538  right operand and the number of tests is set equal to
539  the sum. The last failure descriptions of both operands
540  are appended with a <tt>operator+()</tt> prefix, or blank
541  if there were no failures from either.
542  */
543  friend const test_mgr operator+(const test_mgr& left,
544  const test_mgr& right);
545 
546  };
547 
548 #ifndef DOXYGEN_NO_O2NS
549 }
550 #endif
551 
552 #endif
double get(std::string scol, size_t row) const
Get value from row row of column named col. .
Definition: table.h:399
bool success
True if all tests have passed.
Definition: test_mgr.h:62
bool test_fact_vec(int nv, const vec_t &result, const vec2_t &expected, data_t factor, std::string description)
Test for over each element of an array.
Definition: test_mgr.h:293
The main O<span style=&#39;position: relative; top: 0.3em; font-size: 0.8em&#39;>2</span>scl O$_2$scl names...
Definition: anneal.h:42
size_t get_nlines() const
Return the number of lines.
Definition: table.h:451
A class to manage testing and record success and failure.
Definition: test_mgr.h:46
test_mgr(bool success_l=true, std::string last_fail_l="", int ntests_l=0, int output_level_l=1)
Create a test_mgr object.
Definition: test_mgr.h:72
bool test_rel_nonzero_mat(int nr, int nc, const mat_t &result, const mat2_t &expected, data_t error, data_t zero_tol, std::string description)
Test for over each element in a matrix larger than a specified tolerance.
Definition: test_mgr.h:385
bool test_rel(data_t result, data_t expected, data_t rel_error, std::string description)
Test for .
Definition: test_mgr.h:127
bool get_success() const
Return true if all tests have succeeded.
Definition: test_mgr.h:91
bool test_abs_vec(int nv, const vec_t &result, const vec2_t &expected, data_t abs_error, std::string description)
Test for over each element of an array.
Definition: test_mgr.h:268
int get_output_level() const
Return the output level.
Definition: test_mgr.h:101
bool report() const
Provide a report of all tests so far.
bool test_rel_nonzero_table(const table_units< vec_t > &result, const table_units< vec_t > &expected, data_t error, data_t zero_tol, std::string description)
Compare entries in expected to see if they match those in table result.
Definition: test_mgr.h:481
bool test_gen_vec(int nv, const vec_t &result, const vec_t &expected, std::string description)
Test for equality of a generic array.
Definition: test_mgr.h:318
int ntests
The number of tests performed.
Definition: test_mgr.h:53
void process_test(bool ret, std::string d2, std::string description)
A helper function for processing tests.
std::string get_last_fail() const
Return the last failure description.
Definition: test_mgr.h:96
std::string last_fail
The description of the last failed test.
Definition: test_mgr.h:65
std::string dtos(double x, int prec=6, bool auto_prec=false)
Convert a double to a string.
bool test_str(std::string result, std::string expected, std::string description)
Test for .
bool test_abs(data_t result, data_t expected, data_t abs_error, std::string description)
Test for .
Definition: test_mgr.h:163
size_t get_ncolumns() const
Return the number of columns.
Definition: table.h:443
Data table table class with units.
Definition: table_units.h:42
bool test_rel_mat(int nr, int nc, const mat_t &result, const mat2_t &expected, data_t rel_error, std::string description)
Test for over each element in a matrix.
Definition: test_mgr.h:341
bool test_abs_mat(int nr, int nc, const mat_t &result, const mat2_t &expected, data_t abs_error, std::string description)
Test for over each element in a matrix.
Definition: test_mgr.h:431
std::string get_last_fail()
Returns the description of the last test that failed.
Definition: test_mgr.h:106
void set_output_level(int l)
Set the output level.
Definition: test_mgr.h:115
bool test_fact(data_t result, data_t expected, data_t factor, std::string description)
Test for .
Definition: test_mgr.h:196
friend const test_mgr operator+(const test_mgr &left, const test_mgr &right)
Add two test_mgr objects (if either failed, the sum fails)
std::string itos(int x)
Convert an integer to a string.
int get_ntests() const
Return the number of tests performed so far.
Definition: test_mgr.h:118
std::string get_column_name(size_t icol) const
Returns the name of column col .
Definition: table.h:796
bool test_gen(bool value, std::string description)
Test for .
int output_level
The output level.
Definition: test_mgr.h:56
bool test_rel_vec(int nv, const vec_t &result, const vec2_t &expected, data_t rel_error, std::string description)
Test for over each element of an array.
Definition: test_mgr.h:231

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).