1 // Copyright 2006 Rutger E.W. van Beusekom.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
26 #define YAFFUT_STRINGIZE(x) YAFFUT_STRINGIZE_(x)
27 #define YAFFUT_STRINGIZE_(x) #x
29 #define __YAFFUT_AT__ __FILE__ ":" YAFFUT_STRINGIZE(__LINE__)": "
31 #define __AT__ __YAFFUT_AT__
34 #define YAFFUT_EQUAL(e,a) \
35 yaffut::equal (e ,a , __YAFFUT_AT__, "EQUAL(" #e " == " #a ") failed ")
37 #define EQUAL YAFFUT_EQUAL
40 #define YAFFUT_UNEQUAL(e,a) \
41 yaffut::unequal (e, a, __YAFFUT_AT__, "UNEQUAL(" #e " != " #a ") failed ")
43 #define UNEQUAL YAFFUT_UNEQUAL
46 #define YAFFUT_CHECK(e) \
47 yaffut::check (e, __YAFFUT_AT__, "CHECK(" #e ") failed ")
49 #define CHECK YAFFUT_CHECK
52 #define YAFFUT_FAIL(s) yaffut::fail (s, __YAFFUT_AT__);
54 #define FAIL YAFFUT_FAIL
57 #define YAFFUT_ASSERT_THROW(s, e) \
61 throw yaffut::failure (__YAFFUT_AT__, #s " failed to throw"); \
65 #define ASSERT_THROW YAFFUT_ASSERT_THROW
72 std::string demangle ()
77 char *ptr = abi::__cxa_demangle (typeid (T).name (), 0, &sz, &status);
78 std::string name (ptr ? ptr : "", ptr ? strlen (ptr) : 0);
79 if (ptr) { free (ptr); }
80 std::string::size_type pos = name.rfind ("::");
81 if (pos != std::string::npos)
83 name = name.substr (pos + 2);
87 return typeid (T).name ();
99 typedef ITest *(*Create_t) ();
101 typedef std::map<std::string, Create_t> Tests_t;
108 static bool EqualsSuiteName (std::string const &name, std::string const &s)
110 return name.find (':') >= name.length () - 2
111 && s.substr (0, name.length ()) == name;
114 static Factory &Instance ()
116 static Factory instance;
119 void Register (const std::string &name, Create_t create)
121 m_Tests[name] = create;
123 size_t Fail () { return m_fail; }
124 void List (const std::string &name)
126 for (Tests_t::const_iterator it = m_Tests.begin (); it != m_Tests.end (); ++it)
128 if (name.empty () || it->first == name
129 || EqualsSuiteName (name, it->first))
130 std::cout << it->first << std::endl;
133 void Run (const std::string &name)
135 for (Tests_t::const_iterator it = m_Tests.begin (); it != m_Tests.end (); ++it)
137 if ("All" == name || it->first == name
138 || EqualsSuiteName (name, it->first))
142 std::cout << std::endl << it->first << ' ' << std::flush;
144 std::auto_ptr<ITest> test (it->second ());
146 std::cout << "[OK]" << std::flush;
149 catch (const std::exception &e)
151 std::cout << "[FAIL]\n " << e.what () << std::flush;
156 std::cout << "[FAIL]\n unknown exception" << std::flush;
164 const size_t size = m_Tests.size ();
165 std::cout << std::endl;
166 std::cout << "[TOTAL](" << m_pass + m_fail << '/' << size << ")" << std::endl;
167 std::cout << "[OK](" << m_pass << '/' << size << ")" << std::endl;
169 std::cout << "[FAIL](" << m_fail << '/' << size << ")" << std::endl;
171 int Main (int argc, const char *argv[])
174 && (std::string (argv[1]) == "-h" || std::string (argv[1]) == "--help"))
176 std::cout << "Yaffut - Yet Another Framework For Unit Testing.\n\n"
177 "Usage: yaffut [OPTION] [Suite:|Suite::Test]...\n\n"
179 " -h, --help show this help\n"
180 " -l, --list list test cases" << std::endl;
184 && (std::string (argv[1]) == "-l" || std::string (argv[1]) == "--list"))
186 Factory::Instance ().List (argc > 2 ? argv[2] : "");
190 const char *all[] = {"All"};
191 const char **test = all;
199 for (int i = 0; i < num; ++i)
203 Factory::Instance ().Run (test[i]);
205 catch (const std::exception &e)
207 std::clog << e.what () << std::endl;
211 Factory::Instance ().Report ();
212 return Factory::Instance ().Fail ();
216 class failure: public std::exception
218 std::string failure_;
220 template <typename Expected, typename Actual>
221 failure (const Expected &e, Actual &a, const char *at = "", const char *expr = "")
223 std::ostringstream os;
224 os << at << expr << "\nexpected: "
225 << "(" << demangle<Expected>() << ") " << e
226 << " != actual: " << "(" << demangle<Actual>() << ") " << a;
227 failure_ = os.str ();
229 failure (const char *at = "", const char *expr = "")
231 std::ostringstream os;
233 failure_ = os.str ();
235 virtual ~failure () throw () {}
236 virtual const char *what () const throw () { return failure_.c_str (); }
239 template <typename Suite, typename Case>
244 Factory::Instance ().Register (TestName (), Create);
246 const std::string &TestName ()
248 static const std::string name (demangle<Suite>() + "::" + demangle<Case>());
251 static ITest *Create ()
257 template <typename Case>
258 struct Registrator<Case, void>
262 Factory::Instance ().Register (TestName (), Create);
264 const std::string &TestName ()
266 static const std::string name ("::" + demangle<Case>());
269 static ITest *Create ()
275 template <typename Suite, typename Case = void>
276 struct Test: public ITest, public virtual Suite
278 static Registrator<Suite, Case> s_Registrator;
281 Registrator<Suite, Case> *r = &s_Registrator;
284 template <typename E, typename T>
285 void assert_throw (void (T::*mf) (), const char *at)
289 (dynamic_cast<T *> (this)->*mf) ();
290 throw yaffut::failure (at, "statement failed to throw");
296 template <typename Suite, typename Case>
297 Registrator<Suite, Case> Test<Suite, Case>::s_Registrator;
299 template <typename Case>
300 struct Test<Case, void>: public ITest
302 static Registrator<Case, void> s_Registrator;
305 Registrator<Case, void> *r = &s_Registrator;
308 template <typename E, typename T>
309 void assert_throw (void (T::*mf) (), const char *at)
313 (dynamic_cast<T *> (this)->*mf) ();
314 throw yaffut::failure (at, "statement failed to throw");
320 template <typename Case>
321 Registrator<Case, void> Test<Case, void>::s_Registrator;
323 template <typename Expected, typename Actual>
324 void equal (const Expected &e, const Actual &a, const char *at = "", const char *expr = "")
328 throw failure (e, a, at, expr);
331 inline void equal (double e, double a, const char *at = "", const char *expr = "")
333 double max = std::abs (std::max (e, a));
334 max = max < 1.0 ? 1.0 : max;
335 if (std::abs (e - a) > std::numeric_limits<double>::epsilon () * max)
337 throw failure (e, a, at, expr);
340 inline void check (bool b, const char *at = "", const char *expr = "")
344 throw failure (at, expr);
348 template <typename Expected, typename Actual>
349 void unequal (const Expected &e, const Actual &a, const char *at = "", const char *expr = "")
353 throw failure (e, a, at, expr);
356 inline void unequal (double e, double a, const char *at = "", const char *expr = "")
358 double max = std::abs (std::max (e, a));
359 max = max < 1.0 ? 1.0 : max;
360 if (std::abs (e - a) <= std::numeric_limits<double>::epsilon () * max)
362 throw failure (e, a, at, expr);
366 template <typename T>
367 void fail (const T &expr, const char *at = "")
369 std::ostringstream os;
371 throw failure (at, os.str ().c_str ());
374 template <typename E>
375 void assert_throw (void (*pf) (), const char *at = "")
380 throw failure (at, " statement failed to throw");
387 //and for those who prefer macro obscurity over typing
388 #define TEST(Suite, Case)\
389 namespace { struct Case: public yaffut::Test<Suite, Case>{ Case(); }; } \
390 template struct yaffut::Test<Suite, Case>; Case::Case()
393 namespace { struct Case: public yaffut::Test<Case>{ Case(); }; } \
394 template struct yaffut::Test<Case>; Case::Case()
398 #include <sys/types.h>
400 int main (int argc, const char *argv[])
402 std::cout << "pid(" << getpid () << ")" << std::endl;
403 return yaffut::Factory::Instance ().Main (argc, argv);
406 #endif /* YAFFUT_MAIN */
408 #define yaffut_main(argc, argv) yaffut::Factory::Instance().Main (argc, argv)