STIR 6.4.0
RunTests.h
Go to the documentation of this file.
1/*
2 Copyright (C) 2000 PARAPET partners
3 Copyright (C) 2000-2005, Hammersmith Imanet Ltd
4 Copyright (C) 2013, Kris Thielemans
5 Copyright (C) 2013, 2020, 2022, 2023, 2024 University College London
6 Copyright (C) 2018, University of Hull
7 This file is part of STIR.
8
9 SPDX-License-Identifier: Apache-2.0 AND License-ref-PARAPET-license
10
11 See STIR/LICENSE.txt for details
12*/
23
26#include "stir/IndexRange.h"
27#include "stir/stream.h"
28#include "stir/Bin.h"
31#include <iostream>
32#include <typeinfo>
33#include <vector>
34#include <complex>
35#include <string>
36
37START_NAMESPACE_STIR
38
72{
73public:
75 explicit RunTests(const double tolerance = 1E-4);
76
78 virtual ~RunTests();
79
81
82 virtual void run_tests() = 0;
83
85 bool is_everything_ok() const;
86
88
89 int main_return_value() const;
90
92 void set_tolerance(const double tolerance);
93
95 double get_tolerance() const;
96
98
102 bool check(const bool, const std::string& str = "");
103
109 bool check_if_equal(const std::string& a, const std::string& b, const std::string& str = "");
110 bool check_if_equal(const double a, const double b, const std::string& str = "");
111 // Note: due to current C++ overloading rules, we need copies for every integer type
112 bool check_if_equal(const short a, const short b, const std::string& str = "");
113 bool check_if_equal(const unsigned short a, const unsigned short b, const std::string& str = "");
114 bool check_if_equal(const int a, const int b, const std::string& str = "");
115 bool check_if_equal(const unsigned int a, const unsigned int b, const std::string& str = "");
116 bool check_if_equal(const long a, const long b, const std::string& str = "");
117 bool check_if_equal(const unsigned long a, const unsigned long b, const std::string& str = "");
118#ifdef BOOST_HAS_LONG_LONG
119 // necessary to cope with std::size_t for instance (on 64 bit systems)
120 bool check_if_equal(const long long a, const long long b, const std::string& str = "");
121 bool check_if_equal(const unsigned long long a, const unsigned long long b, const std::string& str = "");
122#endif
123 bool check_if_equal(const Bin& a, const Bin& b, const std::string& str = "")
124 {
125 return this->check_if_equal_generic(a, b, str);
126 }
127 template <class T>
128 bool check_if_equal(const DetectionPosition<T>& a, const DetectionPosition<T>& b, const std::string& str = "")
129 {
130 return this->check_if_equal_generic(a, b, str);
131 }
132
133 // VC 6.0 needs definition of template members in the class def unfortunately.
135 template <class T>
136 bool check_if_equal(const std::complex<T> a, const std::complex<T> b, const std::string& str = "")
137 {
138 return check_if_equal(a.real(), b.real(), str) && check_if_equal(a.imag(), b.imag(), str);
139 }
140
141 template <class T>
142 bool check_if_equal(const VectorWithOffset<T>& t1, const VectorWithOffset<T>& t2, const std::string& str = "")
143 {
144 if (t1.get_min_index() != t2.get_min_index() || t1.get_max_index() != t2.get_max_index())
145 {
146 std::cerr << "Error: unequal ranges. " << str << std::endl;
147 return everything_ok = false;
148 }
149
150 for (int i = t1.get_min_index(); i <= t1.get_max_index(); i++)
151 {
152 if (!check_if_equal(t1[i], t2[i], str))
153 {
154 std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n";
155 return everything_ok = false;
156 }
157 }
158 return true;
159 }
160 // VC 6.0 needs definition of template members in the class def unfortunately.
162 template <class T>
163 bool check_if_equal(const std::vector<T>& t1, const std::vector<T>& t2, const std::string& str = "")
164 {
165 if (t1.size() != t2.size())
166 {
167 std::cerr << "Error: unequal ranges. " << str << std::endl;
168 return everything_ok = false;
169 }
170
171 bool all_equal = true;
172 for (unsigned int i = 0; i < t1.size(); i++)
173 {
174 if (!check_if_equal(t1[i], t2[i], str))
175 {
176 std::cerr << "(at vector<" << typeid(T).name() << "> mismatch at index " << i << ")\n";
177 all_equal = false;
178 }
179 }
180 return all_equal;
181 }
182
183 bool check_if_equal(const ProjDataInMemory& t1, const ProjDataInMemory& t2, const std::string& str = "");
184
185 // VC 6.0 needs definition of template members in the class def unfortunately.
186 template <int n>
187 bool check_if_equal(const IndexRange<n>& t1, const IndexRange<n>& t2, const std::string& str = "")
188 {
189 if (t1 != t2)
190 {
191 std::cerr << "Error: unequal ranges. " << str << std::endl;
192 return everything_ok = false;
193 }
194 else
195 return true;
196 }
198 template <int num_dimensions, class coordT>
201 const std::string& str = "")
202 {
203 if (norm(a - b) > tolerance)
204 {
205 std::cerr << "Error : Unequal Coordinate value are " << a << " and " << b << ". " << str << std::endl;
206 everything_ok = false;
207 return false;
208 }
209 else
210 return true;
211 }
212
213
219 bool check_if_zero(const double a, const std::string& str = "");
220 bool check_if_zero(const short a, const std::string& str = "");
221 bool check_if_zero(const unsigned short a, const std::string& str = "");
222 bool check_if_zero(const int a, const std::string& str = "");
223 bool check_if_zero(const unsigned int a, const std::string& str = "");
224 bool check_if_zero(const long a, const std::string& str = "");
225 bool check_if_zero(const unsigned long a, const std::string& str = "");
226#ifdef BOOST_HAS_LONG_LONG
227 bool check_if_zero(const long long a, const std::string& str = "");
228 bool check_if_zero(const unsigned long long a, const std::string& str = "");
229#endif
230
231 // VC needs definition of template members in the class def unfortunately.
233 template <class T>
234 bool check_if_zero(const VectorWithOffset<T>& t, const std::string& str = "")
235 {
236 for (int i = t.get_min_index(); i <= t.get_max_index(); i++)
237 {
238 if (!check_if_zero(t[i], str))
239 {
240 std::cerr << "(at VectorWithOffset<" << typeid(T).name() << "> first mismatch at index " << i << ")\n";
241 return false;
242 }
243 }
244 return true;
245 }
246
248 template <int num_dimensions, class coordT>
249 bool check_if_zero(const BasicCoordinate<num_dimensions, coordT>& a, const std::string& str = "")
250 {
251 if (norm(a) > tolerance)
252 {
253 std::cerr << "Error : Coordinate value is " << a << " expected 0s. " << str << std::endl;
254 everything_ok = false;
255 return false;
256 }
257 else
258 return true;
259 }
260
261
263 template <class T1, class T2>
264 inline bool check_if_less(T1 a, T2 b, const std::string& str = "");
265
266protected:
268 double tolerance;
271
273 template <class T>
274 bool check_if_equal_generic(const T& a, const T& b, const std::string& str)
275 {
276 if (a != b)
277 {
278 std::cerr << "Error : unequal values are " << a << " and " << b << ". " << str << std::endl;
279 everything_ok = false;
280 return false;
281 }
282 else
283 return true;
284 }
285
287 template <class T>
288 bool check_if_zero_generic(T a, const std::string& str)
289 {
290 if ((a != static_cast<T>(0)))
291 {
292 std::cerr << "Error : 0 value is " << a << " ." << str << std::endl;
293 everything_ok = false;
294 return false;
295 }
296 else
297 return true;
298 }
299};
300
301END_NAMESPACE_STIR
302
303START_NAMESPACE_STIR
304
307 everything_ok(true)
308{}
309
311{
312#if defined(_DEBUG) && defined(__MSL__)
313 DebugNewReportLeaks();
314#endif
315
316 if (everything_ok)
317 std::cerr << "\nAll tests ok !\n\n" << std::endl;
318 else
319 std::cerr << "\nEnd of tests. Please correct errors !\n\n" << std::endl;
320}
321
322bool
324{
325 return everything_ok;
326}
327
328int
330{
331 return everything_ok ? EXIT_SUCCESS : EXIT_FAILURE;
332}
333
334void
335RunTests::set_tolerance(const double tolerance_v)
336{
337 tolerance = tolerance_v;
338}
339
340double
342{
343 return tolerance;
344}
345
346bool
347RunTests::check(const bool result, const std::string& str)
348{
349 if (!result)
350 {
351 std::cerr << "Error. " << str << std::endl;
352 everything_ok = false;
353 }
354 return result;
355}
356
357bool
358RunTests::check_if_equal(const std::string& a, const std::string& b, const std::string& str)
359{
360 return this->check_if_equal_generic(a, b, str);
361}
362
377bool
378RunTests::check_if_equal(const double a, const double b, const std::string& str)
379{
380 const double diff = fabs(b - a);
381 if (diff <= tolerance)
382 return true;
383
384 const double largest = (std::max(fabs(b), fabs(a)));
385
386 if (diff > tolerance * largest)
387 {
388 std::cerr << "Error : unequal values are " << a << " and " << b << ". " << str << std::endl;
389 everything_ok = false;
390 return false;
391 }
392 else
393 return true;
394}
395
396bool
397RunTests::check_if_equal(const short a, const short b, const std::string& str)
398{
399 return this->check_if_equal_generic(a, b, str);
400}
401bool
402RunTests::check_if_equal(const unsigned short a, const unsigned short b, const std::string& str)
403{
404 return this->check_if_equal_generic(a, b, str);
405}
406bool
407RunTests::check_if_equal(const int a, const int b, const std::string& str)
408{
409 return this->check_if_equal_generic(a, b, str);
410}
411bool
412RunTests::check_if_equal(const unsigned int a, const unsigned int b, const std::string& str)
413{
414 return this->check_if_equal_generic(a, b, str);
415}
416bool
417RunTests::check_if_equal(const long a, const long b, const std::string& str)
418{
419 return this->check_if_equal_generic(a, b, str);
420}
421bool
422RunTests::check_if_equal(const unsigned long a, const unsigned long b, const std::string& str)
423{
424 return this->check_if_equal_generic(a, b, str);
425}
426#ifdef BOOST_HAS_LONG_LONG
427bool
428RunTests::check_if_equal(const long long a, const long long b, const std::string& str)
429{
430 return this->check_if_equal_generic(a, b, str);
431}
432bool
433RunTests::check_if_equal(const unsigned long long a, const unsigned long long b, const std::string& str)
434{
435 return this->check_if_equal_generic(a, b, str);
436}
437#endif
438
439bool
440RunTests::check_if_equal(const ProjDataInMemory& t1, const ProjDataInMemory& t2, const std::string& str)
441{
442 if (*t1.get_proj_data_info_sptr() != *t2.get_proj_data_info_sptr())
443 {
444 std::cerr << "Error: unequal proj_data_info. " << str << std::endl;
445 return everything_ok = false;
446 }
447
448 for (auto i1 = t1.begin(), i2 = t2.begin(); i1 != t1.end(); ++i1, ++i2)
449 {
450 if (!check_if_equal(*i1, *i2, str))
451 {
452 return everything_ok = false;
453 }
454 }
455 return true;
456}
457
458bool
459RunTests::check_if_zero(const short a, const std::string& str)
460{
461 return this->check_if_zero_generic(a, str);
462}
463bool
464RunTests::check_if_zero(const unsigned short a, const std::string& str)
465{
466 return this->check_if_zero_generic(a, str);
467}
468bool
469RunTests::check_if_zero(const int a, const std::string& str)
470{
471 return this->check_if_zero_generic(a, str);
472}
473bool
474RunTests::check_if_zero(const unsigned int a, const std::string& str)
475{
476 return this->check_if_zero_generic(a, str);
477}
478bool
479RunTests::check_if_zero(const long a, const std::string& str)
480{
481 return this->check_if_zero_generic(a, str);
482}
483bool
484RunTests::check_if_zero(const unsigned long a, const std::string& str)
485{
486 return this->check_if_zero_generic(a, str);
487}
488#ifdef BOOST_HAS_LONG_LONG
489bool
490RunTests::check_if_zero(const long long a, const std::string& str)
491{
492 return this->check_if_zero_generic(a, str);
493}
494bool
495RunTests::check_if_zero(const unsigned long long a, const std::string& str)
496{
497 return this->check_if_zero_generic(a, str);
498}
499#endif
500
502bool
503RunTests::check_if_zero(const double a, const std::string& str)
504{
505 if (fabs(a) > tolerance)
506 {
507 std::cerr << "Error : 0 value is " << a << " ." << str << std::endl;
508 everything_ok = false;
509 return false;
510 }
511 else
512 return true;
513}
514
515template <class T1, class T2>
516bool
517RunTests::check_if_less(T1 a, T2 b, const std::string& str)
518{
519 if (a >= b)
520 {
521 std::cerr << "Error : " << a << " is larger than " << b << ", " << str << std::endl;
522 everything_ok = false;
523 return false;
524 }
525 else
526 return true;
527}
528
529END_NAMESPACE_STIR
This file declares class stir::BasicCoordinate and some functions acting on stir::BasicCoordinate obj...
Declaration of class stir::Bin.
Declaration of class stir::DetectionPosition.
This file defines the stir::IndexRange class.
Declaration of class stir::ProjDataInMemory.
defines the stir::VectorWithOffset class
class BasicCoordinate<int num_dimensions, typename coordT> defines num_dimensions -dimensional coordi...
Definition BasicCoordinate.h:57
A class for storing coordinates and value of a single projection bin.
Definition Bin.h:49
A class for storing coordinates of a detection.
Definition DetectionPosition.h:61
This class defines ranges which can be 'irregular'.
Definition IndexRange.h:69
A class which reads/writes projection data from/to memory.
Definition ProjDataInMemory.h:39
double get_tolerance() const
Get value used in floating point comparisons (see check_* functions)
Definition RunTests.h:341
bool check_if_equal(const VectorWithOffset< T > &t1, const VectorWithOffset< T > &t2, const std::string &str="")
check equality by comparing ranges and calling check_if_equal on all elements
Definition RunTests.h:142
bool check_if_less(T1 a, T2 b, const std::string &str="")
check if a<b
Definition RunTests.h:517
bool everything_ok
variable storing current status
Definition RunTests.h:270
bool check_if_equal(const BasicCoordinate< num_dimensions, coordT > &a, const BasicCoordinate< num_dimensions, coordT > &b, const std::string &str="")
check equality by comparing norm(a-b) with tolerance
Definition RunTests.h:199
bool check(const bool, const std::string &str="")
Tests if true, str can be used to tell what you are testing.
Definition RunTests.h:347
bool is_everything_ok() const
Returns if all checks were fine upto now.
Definition RunTests.h:323
RunTests(const double tolerance=1E-4)
Default constructor.
Definition RunTests.h:305
double tolerance
tolerance for comparisons with real values
Definition RunTests.h:268
bool check_if_equal(const std::vector< T > &t1, const std::vector< T > &t2, const std::string &str="")
check equality by comparing size and calling check_if_equal on all elements
Definition RunTests.h:163
int main_return_value() const
Handy return value for a main() function.
Definition RunTests.h:329
bool check_if_equal(const std::complex< T > a, const std::complex< T > b, const std::string &str="")
check equality by calling check_if_equal on real and imaginary parts
Definition RunTests.h:136
bool check_if_equal_generic(const T &a, const T &b, const std::string &str)
function that is called by some check_if_equal implementations. It just uses operator!...
Definition RunTests.h:274
bool check_if_zero_generic(T a, const std::string &str)
function that is called by some check_if_zero implementations. It just uses operator!...
Definition RunTests.h:288
virtual ~RunTests()
Destructor, outputs a diagnostic message.
Definition RunTests.h:310
bool check_if_zero(const double a, const std::string &str="")
Definition RunTests.h:503
bool check_if_zero(const VectorWithOffset< T > &t, const std::string &str="")
use check_if_zero on all elements
Definition RunTests.h:234
void set_tolerance(const double tolerance)
Set value used in floating point comparisons (see check_* functions)
Definition RunTests.h:335
bool check_if_zero(const BasicCoordinate< num_dimensions, coordT > &a, const std::string &str="")
compare norm with tolerance
Definition RunTests.h:249
virtual void run_tests()=0
Function (to be overloaded) which does the actual tests.
A templated class for vectors, but with indices starting not from 0.
Definition VectorWithOffset.h:65
int get_max_index() const
get value of last valid index
Definition VectorWithOffset.inl:131
int get_min_index() const
get value of first valid index
Definition VectorWithOffset.inl:124
double norm(const BasicCoordinate< num_dimensions, coordT > &p1)
compute sqrt(inner_product(p1,p1))
Definition BasicCoordinate.inl:426
Input/output of basic vector-like types to/from streams.