test_mgr.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2006-2017, 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=fabs(expected-result)/fabs(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=(fabs(expected-result)<abs_error);
176  if (ret) {
177  description=dtos(result)+" vs. "+ dtos(expected)+" : "
178  +dtos(fabs(expected-result))+" < "+dtos(abs_error)+
179  "\n "+description;
180  } else {
181  description=dtos(result)+" vs. "+ dtos(expected)+" : "
182  +dtos(fabs(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 (fabs(result[i]-expected[i])>max) {
245  max=fabs(result[i]-expected[i]);
246  }
247  } else {
248  ret=(ret && ((fabs(expected[i]-result[i]))/
249  fabs(expected[i])<rel_error));
250  if (fabs(expected[i]-result[i])/fabs(expected[i])>max) {
251  max=fabs(expected[i]-result[i])/fabs(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 && (fabs(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 (fabs(result(i,j)-expected(i,j))>max) {
360  max=fabs(result(i,j)-expected(i,j));
361  }
362  } else {
363  ret=(ret && ((fabs(expected(i,j)-result(i,j)))/
364  fabs(expected(i,j))<rel_error));
365  if (fabs(expected(i,j)-result(i,j))/fabs(expected(i,j))>max) {
366  max=fabs(expected(i,j)-result(i,j))/fabs(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 (fabs(result(i,j)-expected(i,j))>max) {
405  max=fabs(result(i,j)-expected(i,j));
406  }
407  } else {
408  ret=(ret && ((fabs(expected(i,j)-result(i,j)))/
409  fabs(expected(i,j))<error));
410  if (fabs(expected(i,j)-result(i,j))/fabs(expected(i,j))>max) {
411  max=fabs(expected(i,j)-result(i,j))/fabs(expected(i,j));
412  }
413  }
414  }
415  }
416 
417  description=((std::string)"max=")+o2scl::dtos(max)+
418  "\n "+description;
419  process_test(ret,"rel_nonzero matrix",description);
420 
421  return ret;
422 
423  }
424 
425  /** \brief Test for \f$|\mathrm{result}-\mathrm{expected}| <
426  \mathrm{abs\_error} \f$ over each element in a matrix
427  */
428  template<class mat_t, class mat2_t, class data_t>
429  bool test_abs_mat(int nr, int nc, const mat_t &result,
430  const mat2_t &expected, data_t abs_error,
431  std::string description) {
432 
433  bool ret=true;
434  double max=0.0;
435  int i, j;
436 
437  for(i=0;i<nr;i++) {
438  for(j=0;j<nc;j++) {
439  if (std::isnan(expected(i,j))) {
440  ret=(ret && (std::isnan(expected(i,j))==
441  std::isnan(result(i,j))));
442  } else if (std::isinf(expected(i,j))) {
443  ret=(ret && (std::isinf(expected(i,j))==
444  std::isinf(result(i,j))));
445  } else if (expected(i,j)==0.0) {
446  ret=(ret && test_abs(result(i,j),expected(i,j),abs_error,
447  description));
448  if (fabs(result(i,j)-expected(i,j))>max) {
449  max=fabs(result(i,j)-expected(i,j));
450  }
451  } else {
452  ret=(ret && ((fabs(expected(i,j)-result(i,j)))<abs_error));
453  if (fabs(expected(i,j)-result(i,j))>max) {
454  max=fabs(expected(i,j)-result(i,j));
455  }
456  }
457  }
458  }
459 
460  description=((std::string)"max=")+o2scl::dtos(max)+
461  "\n "+description;
462  process_test(ret,"absolute matrix",description);
463 
464  return ret;
465 
466  }
467  //@}
468 
469  /** \brief Compare entries in \c expected to see if they match
470  those in table \c result.
471 
472  If the numbers in the \c expected table have an absolute value
473  less than \c zero_tol, then the absolute value of the
474  difference is used for the comparison. Otherwise, the absolute
475  value of the relative difference is used to make the
476  comparison.
477  */
478  template<class vec_t, class data_t>
480  const table_units<vec_t> &expected,
481  data_t error, data_t zero_tol,
482  std::string description) {
483  bool ret=true;
484  double max=0.0;
485  int i, j;
486  int nr=result.get_nlines();
487  int nc=result.get_ncolumns();
488 
489  for(i=0;i<nc;i++) {
490  for(j=0;j<nr;j++) {
491  if (std::isnan(expected.get(i,j))) {
492  ret=(ret && (std::isnan(expected.get(i,j))==
493  std::isnan(result.get(i,j))));
494  } else if (std::isinf(expected.get(i,j))) {
495  ret=(ret && (std::isinf(expected.get(i,j))==
496  std::isinf(result.get(i,j))));
497  } else if (expected.get(i,j)<zero_tol) {
498  ret=(ret && test_abs(result.get(i,j),expected.get(i,j),error,
499  description));
500  if (fabs(result.get(i,j)-expected.get(i,j))>max) {
501  max=fabs(result.get(i,j)-expected.get(i,j));
502  }
503  } else {
504  ret=(ret && ((fabs(expected.get(i,j)-result.get(i,j)))/
505  fabs(expected.get(i,j))<error));
506  if (fabs(expected.get(i,j)-result.get(i,j))/
507  fabs(expected.get(i,j))>max) {
508  max=fabs(expected.get(i,j)-result.get(i,j))/
509  fabs(expected.get(i,j));
510  }
511  }
512  }
513  }
514 
515  description=((std::string)"max=")+o2scl::dtos(max)+
516  "\n "+description;
517  process_test(ret,"rel_nonzero table",description);
518 
519  return ret;
520 
521  }
522 
523  /** \brief Add two test_mgr objects (if either failed, the sum fails)
524 
525  The output level is set to the maximum value of left and
526  right operand and the number of tests is set equal to
527  the sum. The last failure descriptions of both operands
528  are appended with a <tt>operator+()</tt> prefix, or blank
529  if there were no failures from either.
530  */
531  friend const test_mgr operator+(const test_mgr& left,
532  const test_mgr& right);
533 
534  };
535 
536 #ifndef DOXYGEN_NO_O2NS
537 }
538 #endif
539 
540 #endif
double get(std::string scol, size_t row) const
Get value from row row of column named col. .
Definition: table.h:414
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:457
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:479
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:449
Data table table class with units.
Definition: table_units.h:37
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:429
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)
int get_ntests() const
Return the number of tests performed so far.
Definition: test_mgr.h:118
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).