Imported Upstream version 1.57.0
[platform/upstream/boost.git] / libs / any / test / test.hpp
1 // what:  simple unit test framework
2 // who:   developed by Kevlin Henney
3 // when:  November 2000
4 // where: tested with BCC 5.5, MSVC 6.0, and g++ 2.91
5
6 #ifndef TEST_INCLUDED
7 #define TEST_INCLUDED
8
9 #include <boost/config.hpp>
10 #include <exception>
11 #include <iostream>
12 #ifdef BOOST_NO_STRINGSTREAM
13 #include <strstream> // for out-of-the-box g++ pre-2.95.3
14 #else
15 #include <sstream>
16 #endif
17 #include <string>
18
19 namespace any_tests // test tuple comprises name and nullary function (object)
20 {
21     template<typename string_type, typename function_type>
22     struct test
23     {
24         string_type   name;
25         function_type action;
26
27         static test make(string_type name, function_type action)
28         {
29             test result; // MSVC aggreggate initializer bugs
30             result.name   = name;
31             result.action = action;
32             return result;
33         }
34     };
35 }
36
37 namespace any_tests // failure exception used to indicate checked test failures
38 {
39     class failure : public std::exception
40     {
41     public: // struction (default cases are OK)
42
43         failure(const std::string & why) throw()
44           : reason(why)
45         {
46         }
47
48               ~failure() throw() {}
49
50     public: // usage
51
52         virtual const char * what() const throw()
53         {
54             return reason.c_str();
55         }
56
57     private: // representation
58
59         std::string reason;
60
61     };
62 }
63
64 namespace any_tests // not_implemented exception used to mark unimplemented tests
65 {
66     class not_implemented : public std::exception
67     {
68     public: // usage (default ctor and dtor are OK)
69
70         virtual const char * what() const throw()
71         {
72             return "not implemented";
73         }
74
75     };
76 }
77
78 namespace any_tests // test utilities
79 {
80     inline void check(bool condition, const std::string & description)
81     {
82         if(!condition)
83         {
84             throw failure(description);
85         }
86     }
87
88     inline void check_true(bool value, const std::string & description)
89     {
90         check(value, "expected true: " + description);
91     }
92
93     inline void check_false(bool value, const std::string & description)
94     {
95         check(!value, "expected false: " + description);
96     }
97
98     template<typename lhs_type, typename rhs_type>
99     void check_equal(
100         const lhs_type & lhs, const rhs_type & rhs,
101         const std::string & description)
102     {
103         check(lhs == rhs, "expected equal values: " + description);
104     }
105
106     template<typename lhs_type, typename rhs_type>
107     void check_unequal(
108         const lhs_type & lhs, const rhs_type & rhs,
109         const std::string & description)
110     {
111         check(lhs != rhs, "expected unequal values: " + description);
112     }
113
114     inline void check_null(const void * ptr, const std::string & description)
115     {
116         check(!ptr, "expected null pointer: " + description);
117     }
118
119     inline void check_non_null(const void * ptr, const std::string & description)
120     {
121         check(ptr != 0, "expected non-null pointer: " + description);
122     }
123 }
124
125 #define TEST_CHECK_THROW(expression, exception, description) \
126     try \
127     { \
128         expression; \
129         throw ::any_tests::failure(description); \
130     } \
131     catch(exception &) \
132     { \
133     }
134
135 namespace any_tests // memory tracking (enabled if test new and delete linked in)
136 {
137     class allocations
138     {
139     public: // singleton access
140
141         static allocations & instance()
142         {
143             static allocations singleton;
144             return singleton;
145         }
146
147     public: // logging
148
149         void clear()
150         {
151             alloc_count = dealloc_count = 0;
152         }
153
154         void allocation()
155         {
156             ++alloc_count;
157         }
158
159         void deallocation()
160         {
161             ++dealloc_count;
162         }
163
164     public: // reporting
165
166         unsigned long allocated() const
167         {
168             return alloc_count;
169         }
170
171         unsigned long deallocated() const
172         {
173             return dealloc_count;
174         }
175
176         bool balanced() const
177         {
178             return alloc_count == dealloc_count;
179         }
180
181     private: // structors (default dtor is fine)
182     
183         allocations()
184           : alloc_count(0), dealloc_count(0)
185         {
186         }
187
188     private: // prevention
189
190         allocations(const allocations &);
191         allocations & operator=(const allocations &);
192
193     private: // state
194
195         unsigned long alloc_count, dealloc_count;
196
197     };
198 }
199
200 namespace any_tests // tester is the driver class for a sequence of tests
201 {
202     template<typename test_iterator>
203     class tester
204     {
205     public: // structors (default destructor is OK)
206
207         tester(test_iterator first_test, test_iterator after_last_test)
208           : begin(first_test), end(after_last_test)
209         {
210         }
211
212     public: // usage
213
214         bool operator()(); // returns true if all tests passed
215
216     private: // representation
217
218         test_iterator begin, end;
219
220     private: // prevention
221
222         tester(const tester &);
223         tester &operator=(const tester &);
224
225     };
226     
227 #if defined(__GNUC__) && defined(__SGI_STL_PORT) && (__GNUC__ < 3)
228     // function scope using declarations don't work:
229     using namespace std;
230 #endif
231
232     template<typename test_iterator>
233     bool tester<test_iterator>::operator()()
234     {
235         using std::cerr;
236         using std::endl;
237         using std::ends;
238         using std::exception;
239         using std::flush;
240         using std::string;
241
242         unsigned long passed = 0, failed = 0, unimplemented = 0;
243
244         for(test_iterator current = begin; current != end; ++current)
245         {
246             cerr << "[" << current->name << "] " << flush;
247             string result = "passed"; // optimistic
248
249             try
250             {
251                 allocations::instance().clear();
252                 current->action();
253
254                 if(!allocations::instance().balanced())
255                 {
256                     unsigned long allocated   = allocations::instance().allocated();
257                     unsigned long deallocated = allocations::instance().deallocated();
258 #ifdef BOOST_NO_STRINGSTREAM
259                     std::ostrstream report;
260 #else
261                     std::ostringstream report;
262 #endif
263                     report << "new/delete ("
264                            << allocated << " allocated, "
265                            << deallocated << " deallocated)"
266                            << ends;
267                     const string text = report.str();
268 #ifdef BOOST_NO_STRINGSTREAM
269                     report.freeze(false);
270 #endif
271                     throw failure(text);
272                 }
273
274                 ++passed;
275             }
276             catch(const failure & caught)
277             {
278                 (result = "failed: ") += caught.what();
279                 ++failed;
280             }
281             catch(const not_implemented &)
282             {
283                 result = "not implemented";
284                 ++unimplemented;
285             }
286             catch(const exception & caught)
287             {
288                 (result = "exception: ") += caught.what();
289                 ++failed;
290             }
291             catch(...)
292             {
293                 result = "failed with unknown exception";
294                 ++failed;
295             }
296
297             cerr << result << endl;
298         }
299
300         cerr << (passed + failed) << " tests: "
301              << passed << " passed, "
302              << failed << " failed";
303
304         if(unimplemented)
305         {
306             cerr << " (" << unimplemented << " not implemented)";
307         }
308
309         cerr << endl;
310
311         return failed == 0;
312     }
313 }
314
315 #endif
316
317 // Copyright Kevlin Henney, 2000. All rights reserved.
318 //
319 // Distributed under the Boost Software License, Version 1.0. (See
320 // accompanying file LICENSE_1_0.txt or copy at
321 // http://www.boost.org/LICENSE_1_0.txt)