1 //                                               -*- C++ -*-
2 /**
3  *  @brief The header file that declares exit codes for tests
4  *
5  *  Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6  *
7  *  This library is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 #ifndef OPENTURNS_OTTESTCODE_HXX
22 #define OPENTURNS_OTTESTCODE_HXX
23 
24 #include "openturns/OTconfig.hxx"
25 
26 #include <exception>
27 #include <string>         // for std::string
28 #include <sstream>        // for std::ostringstream
29 #include <cstdlib>        // for exit codes
30 #include <cstring>        // for strcmp
31 
32 #include "openturns/RandomGenerator.hxx"
33 #include "openturns/OStream.hxx"
34 #include "openturns/Sample.hxx"
35 #include "openturns/Matrix.hxx"
36 #include "openturns/PlatformInfo.hxx"
37 #include "openturns/SpecFunc.hxx"
38 #include "openturns/TBB.hxx"
39 
40 #define TESTPREAMBLE { OT::TBB::Enable(); }
41 
42 BEGIN_NAMESPACE_OPENTURNS
43 
44 /**
45  * @brief      The namespace for test specific definitions
46  */
47 
48 namespace Test
49 {
50 
51 /**
52  * @typedef int ExitCodeValue
53  * ExitCodeValue is the type of the exit code to the operating
54  * system. The actual type is determined at configuration time.
55  */
56 typedef int ExitCodeValue;
57 
58 
59 /**
60  * @class ExitCode
61  * Class ExitCode is a compound that declares exit codes to the
62  * operating system when doing the test suite of the project.
63  * Each code has a special meaning to the operating system, and
64  * precisely to the compilation tools (automake et al.) that use
65  * them to know if the test succeeded or failed.
66  */
67 
68 class ExitCode
69 {
70 
71 public:
72   /** You should return Success when it's OK */
73   static const ExitCodeValue Success = EXIT_SUCCESS;
74 
75   /** You should return Error when something went wrong */
76   static const ExitCodeValue Error = EXIT_FAILURE;
77 
78   /** You should return ExpectedToFail when it failed as it should */
79   static const ExitCodeValue ExpectedToFail = 77;
80 
81 }
82 
83 ; /* class ExitCode */
84 
85 
86 
87 
88 
89 /**
90  * Function parseOptions analyse what the user put
91  * on the command line of the executable.
92  */
parseOptions(int argc,char * argv[])93 inline void parseOptions(int argc, char *argv[])
94 {
95   for(int i = 1; i < argc; ++ i)
96   {
97     if (!strcmp(argv[i], "--version"))
98     {
99       std::cout << argv[0] << " version " << PACKAGE_VERSION
100                 << " (copyright 2005-2010 " << PACKAGE_NAME << ")"
101                 << std::endl;
102       exit(ExitCode::Success);
103     }
104   } /* end for */
105 
106 #if defined(_MSC_VER) && (_MSC_VER < 1900)
107   // Windows displays scientific notation with 3 digits in the exponent.
108   // We force 2 digits to avoid test failures.
109   _set_output_format(_TWO_DIGIT_EXPONENT);
110 #endif
111 }
112 
113 
114 
115 /**
116  * Random generator initialization
117  */
setRandomGenerator()118 inline void setRandomGenerator()
119 {
120   RandomGenerator::SetSeed(0);
121 }
122 
123 
124 
125 
126 
127 /**
128  * @class TestFailed
129  *
130  * Class TestFailed is an exception derived class that should be
131  * used to throw exception in unitary test code.
132  */
133 class TestFailed : public std::exception
134 {
135 public:
TestFailed(const std::string & message)136   TestFailed(const std::string & message) : message_(message) {}
~TestFailed()137   ~TestFailed() throw() {}
what() const138   const char * what() const throw()
139   {
140     return message_.c_str();
141   }
142 
143 private:
144 
145   const std::string message_;
146 };
147 
operator <<(std::ostream & os,const TestFailed & obj)148 inline std::ostream & operator <<(std::ostream & os, const TestFailed & obj)
149 {
150   return os << "*** EXCEPTION ***" << std::endl
151          << "TestFailed : " << obj.what() << std::endl
152          << "*****************";
153 }
154 
155 
156 /**
157  * @fn streamObject(const T & anObject)
158  *
159  * Try to stream an object onto an ostream object (std::cout).
160  * This method tests the operator << of the object.
161  */
162 template <class T>
streamObject(const T & anObject)163 void streamObject(const T & anObject)
164 {
165   std::cout << "streamObject(const T & anObject)"
166             << std::endl;
167   OT::OStream fullprint(std::cout);
168   fullprint << anObject << std::endl;
169 }
170 
171 
172 /**
173  * @fn show_className()
174  *
175  * Try to get the name of the class. Check the GetClassName static
176  * method.
177  */
178 template <class T>
showClassName()179 void showClassName()
180 {
181   std::cout << "Testing class "
182             << T::GetClassName()
183             << std::endl;
184 }
185 
186 
187 /**
188  * @fn checkConstructorAndDestructor()
189  *
190  * Try to instanciate an object and delete it. This method tests the
191  * default constructor and the destructor ot the class.
192  */
193 template <class T>
checkConstructorAndDestructor()194 void checkConstructorAndDestructor()
195 {
196   std::cout << "checkConstructorAndDestructor()"
197             << std::endl;
198 
199   // Call the default constructor
200   T anObject;
201 }
202 
203 
204 /**
205  * @fn checkCopyConstructor()
206  *
207  * Try to instanciate an object and copy-construct it.
208  */
209 template <class T>
checkCopyConstructor()210 void checkCopyConstructor()
211 {
212   std::cout << "checkCopyConstructor()"
213             << std::endl;
214 
215   // Call the default constructor
216   T anObject;
217 
218   // Call the copy-contructor
219   T anCopiedObject( anObject );
220 }
221 
222 
223 /**
224  * @fn areSameObjects(const T & firstObject, const T & secondObject)
225  *
226  * Try to compare two objects supposed to be identical.
227  * This method tests the operator == of the object.
228  */
229 template <class T>
areSameObjects(const T & firstObject,const T & secondObject)230 OT::Bool areSameObjects(const T & firstObject,
231                         const T & secondObject)
232 {
233   std::cout << "areSameObjects(const T & firstObject, const T & secondObject)"
234             << std::endl;
235 
236   return (firstObject == secondObject);
237 }
238 
239 
240 /**
241  * @fn areDifferentObjects(const T & firstObject, const T & secondObject)
242  *
243  * Try to compare two objects supposed to be different.
244  * This method tests the operator != of the object.
245  */
246 template <class T>
areDifferentObjects(const T & firstObject,const T & secondObject)247 OT::Bool areDifferentObjects(const T & firstObject,
248                              const T & secondObject)
249 {
250   std::cout << "areDifferentObjects(const T & firstObject, const T & secondObject)"
251             << std::endl;
252 
253   return (firstObject != secondObject);
254 }
255 
256 
257 /**
258  * @fn checkClassWithoutClassName()
259  *
260  * Try to check the standard functionnalities of the class
261  */
262 template <class T>
checkClassWithoutClassName()263 void checkClassWithoutClassName()
264 {
265   checkConstructorAndDestructor<T>();
266   checkCopyConstructor<T>();
267 
268   T object1;
269   streamObject<T>(object1);
270 
271   T object2(object1);
272   streamObject<T>(object2);
273 
274   if (! areSameObjects<T>(object1, object2))
275   {
276     throw TestFailed("areSameObjects<T>(object1, object2)");
277   }
278 
279   if (areDifferentObjects<T>(object1, object2))
280   {
281     throw TestFailed("areDifferentObjects<T>(object1, object2)");
282   }
283 }
284 
285 
286 /**
287  * @fn checkClassWithClassName()
288  *
289  * Try to check some basic functionnalities of the class
290  */
291 template <class T>
checkClassWithClassName()292 void checkClassWithClassName()
293 {
294   showClassName<T>();
295   checkClassWithoutClassName<T>();
296 }
297 
298 
assert_almost_equal(const Scalar a,const Scalar b,const Scalar rtol=1.0e-5,const Scalar atol=1.0e-8,const String errMsg="")299 inline void assert_almost_equal(const Scalar a, const Scalar b, const Scalar rtol = 1.0e-5, const Scalar atol = 1.0e-8, const String errMsg = "")
300 {
301   if (!SpecFunc::IsNormal(a) || !SpecFunc::IsNormal(b))
302     throw TestFailed(OSS() << "Value a: " << a << " or b: " << b << " are invalid " << errMsg);
303   if (std::abs(a - b) > atol + rtol * std::abs(b))
304   {
305     throw TestFailed(OSS() << "Value " << a << " is not close enough to " << b << " " << errMsg);
306   }
307 }
308 
assert_almost_equal(const Indices & a,const Indices & b,const String errMsg="")309 inline void assert_almost_equal(const Indices &a, const Indices &b, const String errMsg = "")
310 {
311   if (a.getSize() != b.getSize())
312     throw InvalidArgumentException(HERE) << "A and B must have the same size " << a.getSize() << " vs " << b.getSize();
313   const UnsignedInteger size = a.getSize();
314   for (UnsignedInteger j = 0; j < size; ++j)
315   {
316     assert_almost_equal(a[j], b[j], 0, 0, errMsg);
317   }
318 }
319 
assert_almost_equal(const Point & a,const Point & b,const Scalar rtol=1.0e-5,const Scalar atol=1.0e-8,const String errMsg="")320 inline void assert_almost_equal(const Point & a, const Point & b, const Scalar rtol = 1.0e-5, const Scalar atol = 1.0e-8, const String errMsg = "")
321 {
322   if (a.getDimension() != b.getDimension())
323     throw InvalidArgumentException(HERE) << "A and B must have the same dimension " << a.getDimension() << " vs " << b.getDimension();
324   const UnsignedInteger dimension = a.getDimension();
325   for (UnsignedInteger j = 0; j < dimension; ++ j)
326   {
327     assert_almost_equal(a[j], b[j], rtol, atol, errMsg);
328   }
329 }
330 
331 
assert_almost_equal(const Sample & a,const Sample & b,const Scalar rtol=1.0e-5,const Scalar atol=1.0e-8,const String errMsg="")332 inline void assert_almost_equal(const Sample & a, const Sample & b, const Scalar rtol = 1.0e-5, const Scalar atol = 1.0e-8, const String errMsg = "")
333 {
334   if (a.getSize() != b.getSize())
335     throw InvalidArgumentException(HERE) << "A and B must have the same size " << a.getSize() << " vs " << b.getSize();
336   if (a.getDimension() != b.getDimension())
337     throw InvalidArgumentException(HERE) << "A and B must have the same dimension " << a.getDimension() << " vs " << b.getDimension();
338   const UnsignedInteger size = a.getSize();
339   const UnsignedInteger dimension = a.getDimension();
340   for (UnsignedInteger i = 0; i < size; ++ i)
341   {
342     for (UnsignedInteger j = 0; j < dimension; ++ j)
343     {
344       assert_almost_equal(a(i, j), b(i, j), rtol, atol, errMsg);
345     }
346   }
347 }
348 
assert_almost_equal(const Matrix & a,const Matrix & b,const Scalar rtol=1.0e-5,const Scalar atol=1.0e-8,const String errMsg="")349 inline void assert_almost_equal(const Matrix &a, const Matrix &b, const Scalar rtol = 1.0e-5, const Scalar atol = 1.0e-8, const String errMsg = "")
350 {
351   if (a.getNbRows() != b.getNbRows())
352     throw InvalidArgumentException(HERE) << "A and B must have the same row number " << a.getNbRows() << " vs " << b.getNbRows();
353   if (a.getNbColumns() != b.getNbColumns())
354     throw InvalidArgumentException(HERE) << "A and B must have the same column number " << a.getNbColumns() << " vs " << b.getNbColumns();
355   const UnsignedInteger rows = a.getNbRows();
356   const UnsignedInteger columns = a.getNbColumns();
357 
358   for (UnsignedInteger j = 0; j < columns; ++ j)
359   {
360     for (UnsignedInteger i = 0; i < rows; ++ i)
361     {
362       assert_almost_equal(a(i, j), b(i, j), rtol, atol, errMsg);
363     }
364   }
365 }
366 
assert_almost_equal(const SymmetricMatrix & a,const SymmetricMatrix & b,const Scalar rtol=1.0e-5,const Scalar atol=1.0e-8,const String errMsg="")367 inline void assert_almost_equal(const SymmetricMatrix &a, const SymmetricMatrix &b, const Scalar rtol = 1.0e-5, const Scalar atol = 1.0e-8, const String errMsg = "")
368 {
369   if (a.getDimension() != b.getDimension())
370     throw InvalidArgumentException(HERE) << "A and B must have the same dimension " << a.getDimension() << " vs " << b.getDimension();
371   const UnsignedInteger dimension = a.getDimension();
372 
373   for (UnsignedInteger j = 0; j < dimension; ++j)
374   {
375     for (UnsignedInteger i = j; i < dimension; ++i)
376     {
377       assert_almost_equal(a(i, j), b(i, j), rtol, atol, errMsg);
378     }
379   }
380 }
381 
382 } /* namespace Test */
383 
384 END_NAMESPACE_OPENTURNS
385 
386 #endif /* OPENTURNS_OTTESTCODE_HXX */
387