1 // what: simple unit test framework
2 // who: developed by Kevlin Henney
4 // where: tested with BCC 5.5, MSVC 6.0, and g++ 2.91
9 #include <boost/config.hpp>
12 #ifdef BOOST_NO_STRINGSTREAM
13 #include <strstream> // for out-of-the-box g++ pre-2.95.3
19 namespace any_tests // test tuple comprises name and nullary function (object)
21 template<typename string_type, typename function_type>
27 static test make(string_type name, function_type action)
29 test result; // MSVC aggreggate initializer bugs
31 result.action = action;
37 namespace any_tests // failure exception used to indicate checked test failures
39 class failure : public std::exception
41 public: // struction (default cases are OK)
43 failure(const std::string & why) throw()
52 virtual const char * what() const throw()
54 return reason.c_str();
57 private: // representation
64 namespace any_tests // not_implemented exception used to mark unimplemented tests
66 class not_implemented : public std::exception
68 public: // usage (default ctor and dtor are OK)
70 virtual const char * what() const throw()
72 return "not implemented";
78 namespace any_tests // test utilities
80 inline void check(bool condition, const std::string & description)
84 throw failure(description);
88 inline void check_true(bool value, const std::string & description)
90 check(value, "expected true: " + description);
93 inline void check_false(bool value, const std::string & description)
95 check(!value, "expected false: " + description);
98 template<typename lhs_type, typename rhs_type>
100 const lhs_type & lhs, const rhs_type & rhs,
101 const std::string & description)
103 check(lhs == rhs, "expected equal values: " + description);
106 template<typename lhs_type, typename rhs_type>
108 const lhs_type & lhs, const rhs_type & rhs,
109 const std::string & description)
111 check(lhs != rhs, "expected unequal values: " + description);
114 inline void check_null(const void * ptr, const std::string & description)
116 check(!ptr, "expected null pointer: " + description);
119 inline void check_non_null(const void * ptr, const std::string & description)
121 check(ptr != 0, "expected non-null pointer: " + description);
125 #define TEST_CHECK_THROW(expression, exception, description) \
129 throw ::any_tests::failure(description); \
135 namespace any_tests // memory tracking (enabled if test new and delete linked in)
139 public: // singleton access
141 static allocations & instance()
143 static allocations singleton;
151 alloc_count = dealloc_count = 0;
166 unsigned long allocated() const
171 unsigned long deallocated() const
173 return dealloc_count;
176 bool balanced() const
178 return alloc_count == dealloc_count;
181 private: // structors (default dtor is fine)
184 : alloc_count(0), dealloc_count(0)
188 private: // prevention
190 allocations(const allocations &);
191 allocations & operator=(const allocations &);
195 unsigned long alloc_count, dealloc_count;
200 namespace any_tests // tester is the driver class for a sequence of tests
202 template<typename test_iterator>
205 public: // structors (default destructor is OK)
207 tester(test_iterator first_test, test_iterator after_last_test)
208 : begin(first_test), end(after_last_test)
214 bool operator()(); // returns true if all tests passed
216 private: // representation
218 test_iterator begin, end;
220 private: // prevention
222 tester(const tester &);
223 tester &operator=(const tester &);
227 #if defined(__GNUC__) && defined(__SGI_STL_PORT) && (__GNUC__ < 3)
228 // function scope using declarations don't work:
232 template<typename test_iterator>
233 bool tester<test_iterator>::operator()()
238 using std::exception;
242 unsigned long passed = 0, failed = 0, unimplemented = 0;
244 for(test_iterator current = begin; current != end; ++current)
246 cerr << "[" << current->name << "] " << flush;
247 string result = "passed"; // optimistic
251 allocations::instance().clear();
254 if(!allocations::instance().balanced())
256 unsigned long allocated = allocations::instance().allocated();
257 unsigned long deallocated = allocations::instance().deallocated();
258 #ifdef BOOST_NO_STRINGSTREAM
259 std::ostrstream report;
261 std::ostringstream report;
263 report << "new/delete ("
264 << allocated << " allocated, "
265 << deallocated << " deallocated)"
267 const string text = report.str();
268 #ifdef BOOST_NO_STRINGSTREAM
269 report.freeze(false);
276 catch(const failure & caught)
278 (result = "failed: ") += caught.what();
281 catch(const not_implemented &)
283 result = "not implemented";
286 catch(const exception & caught)
288 (result = "exception: ") += caught.what();
293 result = "failed with unknown exception";
297 cerr << result << endl;
300 cerr << (passed + failed) << " tests: "
301 << passed << " passed, "
302 << failed << " failed";
306 cerr << " (" << unimplemented << " not implemented)";
317 // Copyright Kevlin Henney, 2000. All rights reserved.
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)