Developer Documentation

TestingFramework.hh
Go to the documentation of this file.
1 /* ========================================================================= *
2 * *
3 * OpenMesh *
4 * Copyright (c) 2001-2015, RWTH-Aachen University *
5 * Department of Computer Graphics and Multimedia *
6 * All rights reserved. *
7 * www.openmesh.org *
8 * *
9 *---------------------------------------------------------------------------*
10 * This file is part of OpenMesh. *
11 *---------------------------------------------------------------------------*
12 * *
13 * Redistribution and use in source and binary forms, with or without *
14 * modification, are permitted provided that the following conditions *
15 * are met: *
16 * *
17 * 1. Redistributions of source code must retain the above copyright notice, *
18 * this list of conditions and the following disclaimer. *
19 * *
20 * 2. Redistributions in binary form must reproduce the above copyright *
21 * notice, this list of conditions and the following disclaimer in the *
22 * documentation and/or other materials provided with the distribution. *
23 * *
24 * 3. Neither the name of the copyright holder nor the names of its *
25 * contributors may be used to endorse or promote products derived from *
26 * this software without specific prior written permission. *
27 * *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 * ========================================================================= */
41
42
43
44 #ifndef TESTINGFRAMEWORK_HH
45 #define TESTINGFRAMEWORK_HH
46 // ----------------------------------------------------------------------------
47
53 // ----------------------------------------------------------------------------
54
55 #include "Config.hh"
56 #include <iosfwd>
57 #include <sstream>
58 #include <vector>
59 #include <algorithm>
60 #include <stdexcept>
61 #include <OpenMesh/Core/Utils/Noncopyable.hh>
62
63 // ------------------------------------------------------------- namespace ----
64
65 namespace OpenMesh { // BEGIN_NS_OPENMESH
66 namespace Utils { // BEGIN_NS_UTILS
67
68
69 // ----------------------------------------------------------------- class ----
70 //
71 // Usage Example
72 //
73 // #include <iostream>
74 // #include <.../TestingFramework.hh>
75 //
76 // struct test_func : public TestingFramework::TestFunc
77 // {
78 // typedef test_func Self;
79 //
80 // // define ctor and copy-ctor
81 // test_func( TestingFramework& _th, std::string _n ) : TestingFramework::TestFunc( _th, _n ) { }
82 // test_func( Self& _cpy ) : TestingFramework::TestFunc(_cpy) { }
83 //
84 // // overload body()
85 // void body()
86 // {
87 //
88 // // Do the tests
89 // // direct call to verify
90 // verify( testResult, expectedResult, "additional information" );
91 //
92 // // or use the define TH_VERIFY. The test-expression will be used as the message string
93 // TH_VERIFY( testResult, expectedResult );
94 //
95 // ...
96 // }
97 // };
98 //
99 // int main(...)
100 // {
101 // TestingFramework testSuite(std::cout); // send output to stdout
102 //
103 // new test_func(testSuite); // create new test instance. It registers with testSuite.
104 // return testSuite.run();
105 // }
106 //
107
108 //
109 #define TH_VERIFY( expr, expt ) \
110 verify( expr, expt, #expr )
111
112 //
113 #define TH_VERIFY_X( expr, expt ) \
114 verify_x( expr, expt, #expr )
115
119 class TestingFramework : Noncopyable
120 {
121 public:
122
123 typedef TestingFramework Self;
124 typedef std::logic_error verify_error;
125
126 #ifndef DOXY_IGNORE_THIS
127 class TestFunc
128 {
129 public:
130 TestFunc( TestingFramework& _th, const std::string& _n )
131 : th_(_th), name_(_n)
132 {
133 th_.reg(this);
134 }
135
136 virtual ~TestFunc()
137 { }
138
139 void operator() ( void )
140 {
141 prolog();
142 try
143 {
144 body();
145 }
146 catch( std::exception& x )
147 {
148 std::cerr << "<<Error>>: Cannot proceed test due to failure of last"
149 << " test: " << x.what() << std::endl;
150 }
151 catch(...)
152 {
153 std::cerr << "Fatal: cannot proceed test due to unknown error!"
154 << std::endl;
155 }
156 epilog();
157 }
158
159 const TestingFramework& testHelper() const { return th_; }
160
161 protected:
162
163 virtual void prolog(void)
164 {
165 begin(name_);
166 }
167
168 virtual void body(void) = 0;
169
170 virtual void epilog(void)
171 {
172 end();
173 }
174
175 protected:
176
177 TestingFramework& testHelper() { return th_; }
178
179 TestFunc( const TestFunc& _cpy ) : th_(_cpy.th_), name_(_cpy.name_) { }
180
181
182 // Use the following method in prolog()
183 TestFunc& begin(std::string _title, const std::string& _info = "")
184 { th_.begin(_title,_info); return *this; }
185
186
187 // Use the following method in epilog()
188 TestFunc& end(void)
189 { th_.end(); return *this; }
190
191
192 // Use the followin methods in body()
193
194 template <typename ValueType>
195 bool
196 verify( const ValueType& _rc, const ValueType& _expected,
197 std::string _info )
198 { return th_.verify( _rc, _expected, _info ); }
199
200 template <typename ValueType>
201 void
202 verify_x( const ValueType& _rc, const ValueType& _expected,
203 std::string _info )
204 {
205 if ( !verify(_rc, _expected, _info) )
206 throw verify_error(_info);
207 }
208
209 TestFunc& info(const std::string& _info)
210 { th_.info(_info); return *this; }
211
212 TestFunc& info(const std::ostringstream& _ostr)
213 { th_.info(_ostr); return *this; }
214
215 private:
216 TestFunc();
217
218 protected:
219 TestingFramework& th_;
220 std::string name_;
221 };
222 #endif
223
224 typedef TestFunc* TestFuncPtr;
225 typedef std::vector<TestFuncPtr> TestSet;
226
227 public:
228
229 TestingFramework(std::ostream& _os)
230 : errTotal_(0), errCount_(0),
231 verifyTotal_(0), verifyCount_(0),
232 testTotal_(0), testCount_(0),
233 os_(_os)
234 { }
235
236 protected:
237
238 #ifndef DOXY_IGNORE_THIS
239 struct TestDeleter
240 {
241 void operator() (TestFuncPtr _tfptr) { delete _tfptr; }
242 };
243 #endif
244
245 public:
246
247 virtual ~TestingFramework()
248 {
249 std::for_each(tests_.begin(), tests_.end(), TestDeleter() );
250 }
251
252 public:
253
254 template <typename ValueType>
255 bool verify(const ValueType& _rc,
256 const ValueType& _expected,
257 const std::string& _info)
258 {
259 ++verifyTotal_;
260 if ( _rc == _expected )
261 {
262 os_ << " " << _info << ", result: " << _rc << ", OK!" << std::endl;
263 return true;
264 }
265 ++errTotal_;
266 os_ << " " << _info << ", result: " << _rc << " != " << _expected
267 << " <<ERROR>>" << std::endl;
268 return false;
269 }
270
271 Self& begin(std::string _title, const std::string& _info = "")
272 {
273 std::ostringstream ostr;
274
275 testTitle_ = _title;
276 errCount_ = errTotal_;
277 ++testTotal_;
278
279 ostr << _title;
280 if ( !_info.empty() )
281 ostr << " ["<< _info << "]";
282 testTitle_ = ostr.str();
283 os_ << "Begin " << testTitle_ << std::endl;
284 return *this;
285 }
286
287 Self& end()
288 {
289 if (errorCount()==0)
290 ++testCount_;
291
292 os_ << "End " << testTitle_ << ": " << errorCount() << " Error(s)." << std::endl;
293 return *this;
294 }
295
296 Self& info(const std::string& _info)
297 {
298 os_ << " + " << _info << std::endl;
299 return *this;
300 }
301
302 Self& info(const std::ostringstream& _ostr)
303 {
304 os_ << " + " << _ostr.str() << std::endl;
305 return *this;
306 }
307
308 size_t errorTotal() const { return errTotal_; }
309 size_t errorCount() const { return errTotal_ - errCount_; }
310 size_t verifyTotal() const { return verifyTotal_; }
311 size_t verifyCount() const { return verifyTotal_ - verifyCount_; }
312 size_t goodTotal() const { return verifyTotal() - errorTotal(); }
313 size_t goodCount() const { return verifyCount() - errorCount(); }
314
315 size_t testTotal() const { return testTotal_; }
316 size_t testCount() const { return testCount_; }
317
318 public:
319
320 int run(void)
321 {
322 os_ << "Test started\n";
323 TestRunner executer;
324 std::for_each(tests_.begin(), tests_.end(), executer );
325 os_ << std::endl;
326 os_ << "All tests completed" << std::endl
327 << " #Tests: " << testCount() << "/" << testTotal() << std::endl
328 << " #Errors: " << errorTotal() << "/" << verifyTotal() << std::endl;
329 return errorTotal();
330 }
331
332 protected:
333
334 #ifndef DOXY_IGNORE_THIS
335 struct TestRunner
336 {
337 void operator() (TestFuncPtr _tfptr) { (*_tfptr)(); }
338 };
339 #endif
340
341 int reg(TestFuncPtr _tfptr)
342 {
343 tests_.push_back(_tfptr);
344 return true;
345 }
346
347 friend class TestFunc;
348
349 private:
350
351 size_t errTotal_;
352 size_t errCount_;
353 size_t verifyTotal_;
354 size_t verifyCount_;
355 size_t testTotal_; // #Tests
356 size_t testCount_; // #Tests ohne Fehler
357
358 std::string testTitle_;
359 std::ostream& os_;
360
361 TestSet tests_;
362
363 };
364
365 // ============================================================================
366 } // END_NS_UTILS
367 } // END_NS_OPENMESH
368 // ============================================================================
369 #endif // TESTINGFRMEWORK_HH
370 // ============================================================================
OpenMesh::Utils::Noncopyable
Definition: Noncopyable.hh:71
Config.hh
OpenMesh
Definition: MeshItems.hh:59
OpenMesh::Utils::TestingFramework
Definition: TestingFramework.hh:119
Utils
Definition: NumberParsing.cc:46