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