testsoon.hpp

Go to the documentation of this file.
00001 // vim:ts=2:sw=2:expandtab:autoindent:filetype=cpp:
00002 /*
00003   testsoon.hpp: "Test soon" testing framework.
00004 
00005   Copyright (C) 2006 Aristid Breitkreuz, Ronny Pfannschmidt and 
00006                      Benjamin Bykowski
00007 
00008   This software is provided 'as-is', without any express or implied
00009   warranty.  In no event will the authors be held liable for any damages
00010   arising from the use of this software.
00011 
00012   Permission is granted to anyone to use this software for any purpose,
00013   including commercial applications, and to alter it and redistribute it
00014   freely, subject to the following restrictions:
00015 
00016   1. The origin of this software must not be misrepresented; you must not
00017      claim that you wrote the original software. If you use this software
00018      in a product, an acknowledgment in the product documentation would be
00019      appreciated but is not required.
00020   2. Altered source versions must be plainly marked as such, and must not be
00021      misrepresented as being the original software.
00022   3. This notice may not be removed or altered from any source distribution.
00023 
00024   Aristid Breitkreuz aribrei@arcor.de
00025   Ronny Pfannschmidt Ronny.Pfannschmidt@gmx.de
00026   Benjamin Bykowski bennybyko@gmx.de
00027 */
00028 
00029 #ifndef TESTSOON_HPP
00030 #define TESTSOON_HPP
00031 
00032 #include <boost/preprocessor.hpp>
00033 #include <boost/assign/list_of.hpp>
00034 #include <boost/tuple/tuple.hpp>
00035 
00036 #ifndef NO_STDLIB
00037 #include <string>
00038 #include <sstream>
00039 #include <vector>
00040 #include <typeinfo>
00041 #endif
00042 
00043 namespace testsoon {
00044 
00045 #ifndef NO_STDLIB
00046 
00047 using std::string;
00048 
00049 typedef std::vector<string> string_vector;
00050 typedef std::ostream stream_class;
00051 
00052 template<class T>
00053 inline string object_to_string(T const &object) {
00054   std::ostringstream stream;
00055   stream << object;
00056   return stream.str();
00057 }
00058 
00059 inline string object_to_string(std::type_info const &object) {
00060   return string(object.name());
00061 }
00062 
00063 inline string object_to_string(char const * const object) {
00064   return string(object);
00065 }
00066 
00067 inline string object_to_string(string const &object) {
00068   return string(object);
00069 }
00070 
00071 #endif
00072 
00073 #ifndef IN_DOXYGEN
00074 class test_holder;
00075 #endif
00076 
00077 extern test_holder &tests();
00078 
00079 #ifndef IN_DOXYGEN
00080 #if defined(__EXCEPTIONS) || defined(_CPPUNWIND)
00081 #define TESTSOON_EXCEPTIONS 1
00082 #define TESTSOON_NO_EXCEPTIONS 0
00083 #else
00084 #define TESTSOON_EXCEPTIONS 0
00085 #define TESTSOON_NO_EXCEPTIONS 1
00086 #endif
00087 #endif
00088 
00089 #ifndef TESTSOON_CATCHALL
00090 #ifdef DEBUG
00091 #define TESTSOON_CATCHALL 0
00092 #else
00093 #define TESTSOON_CATCHALL 1
00094 #endif
00095 #endif
00096 
00097 class test_reporter;
00098 class test_info;
00099 class test_group;
00100 class test_failure;
00101 
00102 class statistics {
00103 public:
00104   statistics() : good(0), bad(0) {}
00105   unsigned good;
00106   unsigned bad;
00107 private:
00108   typedef bool (statistics::*bool_type)() const;
00109   bool do_not_compare_implicit_bool() const { return false; }
00110 public:
00111   operator bool_type() const {
00112     return bad == 0 ? &statistics::do_not_compare_implicit_bool : 0;
00113   }
00114 };
00115 
00116 template<class T> bool operator==(statistics const &x, T const &) {
00117   return x.do_not_compare_implicit_bool();
00118 }
00119 template<class T> bool operator!=(statistics const &x, T const &) {
00120   return x.do_not_compare_implicit_bool();
00121 }
00122 template<class T> bool operator==(T const &, statistics const &x) {
00123   return x.do_not_compare_implicit_bool();
00124 }
00125 template<class T> bool operator!=(T const &, statistics const &x) {
00126   return x.do_not_compare_implicit_bool();
00127 }
00128 
00132 class test_reporter {
00133 public:
00135   virtual void start() {}
00137   virtual void stop() {}
00139   virtual void begin_group(test_group const &group) { (void)group; }
00141   virtual void end_group(test_group const &group) { (void)group; }
00143   virtual void before_tests(test_group const &group) { (void)group; }
00145   virtual void after_tests(test_group const &group) { (void)group; }
00147   virtual void success(test_info const &info, string const &sequence_key) {
00148     (void)info;
00149     (void)sequence_key;
00150   }
00152   virtual void failure(test_info const &info, test_failure const &failure, 
00153                        string const &value) = 0;
00155   virtual void unexpected_exception(test_info const &info, string const &value);
00157   virtual void stats(statistics const &stat) { (void)stat; }
00159   virtual ~test_reporter() {}
00160 };
00161 
00162 #ifndef IN_DOXYGEN
00163 
00164 class node {
00165 public:
00166   node(test_group *, char const * const, bool = false);
00167   virtual void run(test_reporter &, statistics &) const = 0;
00168   virtual ~node() {}
00169 
00170   test_group const * const parent;
00171   char const * const name;
00172 
00173   void print(stream_class &out) const;
00174 
00175 private:
00176   friend class test_group;
00177   node *next;
00178 };
00179 
00180 inline stream_class &operator<<(stream_class &out, node const &n) {
00181   n.print(out);
00182   return out;
00183 }
00184 
00185 class test_group : public node {
00186 public:
00187   test_group(test_group *parent, char const *name)
00188     : node(parent, name), child(0) {}
00189   
00190   void add(node *, bool);
00191 
00192   void run(test_reporter &, statistics &) const;
00193 
00194 private:
00195   node *child;
00196   test_info *test;
00197 };
00198 
00199 inline node::node(test_group *parent, char const *name, bool is_test)
00200 : parent(parent), name(name), next(0) {
00201   if (parent)
00202     parent->add(this, is_test);
00203 }
00204 
00205 inline void node::print(stream_class &out) const {
00206   if (parent) {
00207     parent->print(out);
00208     if (parent->parent)
00209       out << '/' << name;
00210     else
00211       out << '"' << name << '"';
00212   }
00213 }
00214 
00215 class test_holder : public test_group {
00216 public:
00217   test_holder() : test_group(0, "") {}
00218   statistics run(test_reporter &rep) {
00219     statistics stats;
00220     run(rep, stats);
00221     return stats;
00222   }
00223   void run(test_reporter &rep, statistics &stats) {
00224     rep.start();
00225     test_group::run(rep, stats);
00226     rep.stop();
00227     rep.stats(stats);
00228   }
00229 };
00230 
00231 class test_file : public test_group {
00232 public:
00233   test_file(test_group *parent, char const *file)
00234     : test_group(parent, file) {}
00235 };
00236 
00237 class test_info : public node {
00238 public:
00239   test_info(test_group *group,
00240             char const *name, char const *file, unsigned line)
00241   : node(group, name, true), file(file), line(line) {}
00242 
00243   char const *file;
00244   unsigned const line;
00245 };
00246 
00247 #endif
00248 
00249 class test_failure {
00250 public:
00251   test_failure() : line(0) {}
00252   test_failure(char const *message,
00253                unsigned line,
00254                string_vector const &data = string_vector())
00255     : message(message), line(line), data(data) {}
00256   ~test_failure() {}
00257   char const *message;
00258   unsigned line;
00259   string_vector data;
00260 
00261   bool is_failure() { return line; }
00262 };
00263 
00264 inline void
00265 test_reporter::unexpected_exception(test_info const &info, string const &val) {
00266   failure(info, test_failure("unexpected exception", info.line), val);
00267 }
00268 
00269 
00270 struct failure_info {
00271   failure_info(test_info const &test, test_failure const &failure, 
00272                string const &value)
00273     : ptest(&test), failure(failure), value(value) {}
00274 
00275   test_info const *ptest;
00276   test_failure failure;
00277   string value;
00278 };
00279 
00280 class simple_reporter : public test_reporter {
00281 public:
00282   typedef stream_class stream;
00283   simple_reporter(stream &out) : out(out) {}
00284   void before_tests(test_group const &group) {
00285     out << group << " : ";
00286     out.flush();
00287   }
00288 
00289   void after_tests(test_group const &) {
00290     out << '\n';
00291     out.flush();
00292   }
00293 
00294   void success(test_info const &, string const &){
00295     out << '.';
00296     out.flush();
00297   }
00298 
00299   void failure(test_info const &i, test_failure const &x, string const &k) {
00300     out << "[F=" << i.line << '.' << x.line;
00301     if (k != string())
00302       out << '<' << k << '>';
00303     out << ']';
00304     out.flush();
00305   }
00306 
00307 protected:
00308   stream &out;
00309 };
00310 
00311 class concise_reporter : public simple_reporter {
00312 public:  
00313   concise_reporter(stream &out) 
00314   : simple_reporter(out) {}
00315 
00316 private:
00317   typedef std::vector<failure_info> failure_vector;
00318   failure_vector reports;
00319   
00320   void stats(statistics const &x) {
00321     out << (x.good + x.bad) << " tests, "
00322         << x.good << " succeeded, "
00323         << x.bad << " failed.\n";
00324     out.flush();
00325   }
00326   
00327   void write_report() {
00328     for (failure_vector::const_iterator it = reports.begin();
00329         it != reports.end();
00330         ++it)
00331       write_report_entry(*it);
00332     out << '\n';
00333     out.flush();
00334   }
00335 
00336   void write_report_entry(failure_info const &info) {
00337     out << "\nError occured in test ";
00338     if (*info.ptest->name)
00339       out << '"' << info.ptest->name << "\" ";
00340     out << "in " << *info.ptest->parent
00341         << " on line " << info.ptest->line
00342         << " in check on line " << info.failure.line;
00343     if (info.value != string())
00344       out << " with value: \n\t" << info.value;
00345     else
00346       out << '.';
00347     out << "\nProblem: " << info.failure.message << '\n';
00348 
00349     if (!info.failure.data.empty()) {
00350       out << "Data:\n";
00351       for (string_vector::const_iterator it = info.failure.data.begin();
00352            it != info.failure.data.end();
00353            ++it) {
00354         out << "\t" << *it << '\n';
00355       }
00356     }
00357     out.flush();
00358   } 
00359 
00360   void success(test_info const &i, string const &k) {
00361     simple_reporter::success(i, k);
00362   }
00363     
00364   void failure(test_info const &i, test_failure const &x, string const &k) {
00365     simple_reporter::failure(i, x, k);
00366     reports.push_back(failure_info(i, x, k));
00367   }
00368 
00369   void stop() {
00370     write_report();
00371   }
00372 };
00373 
00374 typedef concise_reporter default_reporter;
00375 
00376 #ifndef IN_DOXYGEN
00377 
00378 inline void test_group::add(node *nchild, bool is_test) {
00379   node *tail = is_test ? test : child;
00380   if (!tail) {
00381     if (is_test) test = static_cast<test_info *>(nchild);
00382     else         child = nchild;
00383   } else {
00384     while (tail->next)
00385       tail = tail->next;    
00386     tail->next = nchild;
00387   }
00388 }
00389 
00390 inline void test_group::run(test_reporter &rep, statistics &stats) const {
00391   rep.begin_group(*this);
00392   if (test) {
00393     rep.before_tests(*this);
00394     for (node *it = test; it; it = it->next)
00395       it->run(rep, stats);
00396     rep.after_tests(*this);
00397   }
00398   for (node *it = child; it; it = it->next)
00399     it->run(rep, stats);
00400   rep.end_group(*this);
00401 }
00402 
00403 template<class T, class U>
00404 inline void check_equals(T const &a, U const &b,
00405                          char const *msg, unsigned line,
00406                          test_failure &fail) {
00407   if (!(a == b)) {
00408     string_vector data;
00409     data.push_back(object_to_string(a));
00410     data.push_back(object_to_string(b));
00411     fail = test_failure(msg, line, data);
00412   }
00413 }
00414 
00415 template<class T, class U>
00416 inline void check_not_equals(T const &a, U const &b,
00417                          char const *msg, unsigned line,
00418                          test_failure &fail) {
00419   if (a == b) {
00420     string_vector data;
00421     data.push_back(object_to_string(a));
00422     data.push_back(object_to_string(b));
00423     fail = test_failure(msg, line, data);
00424   }
00425 }
00426 
00427 template<class F, class T>
00428 inline void do_check1(F fun, T const &val,
00429                       char const *msg, unsigned line,
00430                       test_failure &fail) {
00431   if (!fun(val)) {
00432     string_vector data;
00433     data.push_back(object_to_string(val));
00434     fail = test_failure(msg, line, data);
00435   }
00436 }
00437 
00438 template<class F, class T, class U>
00439 inline void do_check2(F fun, T const &a, U const &b,
00440                       char const *msg, unsigned line,
00441                       test_failure &fail) {
00442   if (!fun(a, b)) {
00443     string_vector data;
00444     data.push_back(object_to_string(a));
00445     data.push_back(object_to_string(b));
00446     fail = test_failure(msg, line, data);
00447   }
00448 }
00449 
00450 #endif
00451 
00452 template<typename Type>
00453 class range_generator {
00454 public:
00455   typedef Type value_type;
00456   typedef Type const &const_reference;
00457 
00458   range_generator(const_reference a, const_reference b) : a(a), b(b) {}
00459 
00460   class iterator {
00461   public:
00462     iterator(const_reference v = value_type()) : v(v) {}
00463     iterator(iterator const &x) : v(x.v) {}
00464     
00465     bool operator!=(iterator const &rhs) {
00466       return v != rhs.v;
00467     }
00468 
00469     value_type &operator*() { return v;}
00470 
00471     iterator &operator++() { 
00472       ++v;
00473       return *this; 
00474     }
00475 
00476     iterator operator++(int) { 
00477       iterator tmp(*this); 
00478       ++*this;
00479       return tmp;
00480     }
00481 
00482   private:
00483     value_type v;
00484   };
00485 
00486   iterator begin() { return iterator(a); }
00487   iterator end() { return iterator(b); }
00488 
00489 private:
00490   value_type a;
00491   value_type b;
00492 };
00493 
00494 template<typename Type>
00495 class array_generator {
00496 public:
00497   typedef Type value_type;
00498   typedef Type const &const_reference;
00499   typedef Type const *const_pointer;
00500   typedef const_pointer iterator;
00501 
00502   template<int N>
00503   array_generator(Type (&array)[N]) : a(array), b(array + N) {}
00504 
00505   template<int N>
00506   array_generator(Type const (&array)[N]) : a(array), b(array + N) {}
00507 
00508   iterator begin() { return a; }
00509   iterator end() { return b; }
00510 
00511 private:
00512   const_pointer a, b;
00513 };
00514 
00518 #define TEST_REGISTRY \
00519   namespace testsoon { \
00520     test_holder &tests() { \
00521       static test_holder t; \
00522       return t; \
00523     } \
00524   }
00525 
00530 #define TEST_GROUP(name) \
00531     namespace BOOST_PP_CAT(name, _helper) { \
00532       static ::testsoon::test_group *get_upper_test_group() { \
00533         return get_test_group(__FILE__); \
00534       } \
00535     } \
00536     namespace BOOST_PP_CAT(name, _testgroup) { \
00537       static ::testsoon::test_group * \
00538       get_test_group(char const *) { \
00539         static ::testsoon::test_group current( \
00540           BOOST_PP_CAT(name, _helper)::get_upper_test_group(), #name); \
00541         return &current; \
00542       } \
00543     } \
00544     namespace BOOST_PP_CAT(name, _testgroup)
00545 
00546 #ifndef TESTSOON_DUMMY
00547 
00553 #define PTEST(name, fixture, group_fixture, generator) \
00554   TESTSOON_PTEST1( \
00555     name, \
00556     BOOST_PP_CAT(test_, __LINE__), \
00557     BOOST_PP_TUPLE_ELEM(2, 0, fixture), \
00558     BOOST_PP_TUPLE_ELEM(2, 1, fixture), \
00559     group_fixture, \
00560     BOOST_PP_TUPLE_ELEM(2, 0, generator), \
00561     BOOST_PP_TUPLE_ELEM(2, 1, generator))
00562 #else
00563 #define PTEST(name, fixture, group_fixture, generator) \
00564   static void BOOST_PP_CAT(dummy_, __LINE__) ()
00565 #endif
00566 
00571 #define TEST(name) \
00572   PTEST(#name, (0, ~), 0, (0, ()))
00573 
00579 #define FTEST(name, fixture_class) \
00580   PTEST(#name, (1, fixture_class), 0, (0, ()))
00581 
00586 #define GFTEST(name) \
00587   PTEST(#name, (0, ~), 1, (0, ()))
00588 
00589 #ifndef IN_DOXYGEN
00590 
00591 #if TESTSOON_NO_EXCEPTIONS
00592 #define TESTSOON_FAILURE_P ::testsoon::test_failure &testsoon_failure
00593 #else
00594 #define TESTSOON_FAILURE_P int
00595 #endif
00596 
00597 #define TESTSOON_TEST_PARAM( \
00598     has_fixture, \
00599     fixture_class, \
00600     has_group_fixture, \
00601     has_generator, \
00602     generator_class) \
00603   BOOST_PP_IIF(has_fixture, fixture_class &fixture, int), \
00604   BOOST_PP_IIF(has_group_fixture, group_fixture_t &group_fixture, int), \
00605   BOOST_PP_IIF(has_generator, generator_class::const_reference value, int), \
00606   TESTSOON_FAILURE_P
00607 
00608 #define TESTSOON_PTEST1( \
00609     name, \
00610     test_class, \
00611     has_fixture, \
00612     fixture_class, \
00613     group_fixture, \
00614     has_generator, \
00615     generator_seq) \
00616   TESTSOON_PTEST2( \
00617     name, test_class, has_fixture, fixture_class, \
00618     TESTSOON_TEST_PARAM( \
00619       has_fixture, fixture_class, group_fixture, \
00620       has_generator, BOOST_PP_SEQ_HEAD(generator_seq)), \
00621     group_fixture, \
00622     has_generator, \
00623     BOOST_PP_SEQ_HEAD(generator_seq), \
00624     BOOST_PP_ARRAY_POP_FRONT(BOOST_PP_SEQ_TO_ARRAY(generator_seq)) \
00625   )
00626 
00627 #if TESTSOON_EXCEPTIONS
00628 
00629 #define TESTSOON_TESTRUN(x) \
00630   try { \
00631     x; \
00632     reporter.success(*this, key); \
00633     ++stats.good; \
00634   } catch (::testsoon::test_failure const &state) { \
00635     reporter.failure(*this, state, key); \
00636     ++stats.bad; \
00637   } \
00638   BOOST_PP_EXPR_IIF(TESTSOON_CATCHALL, \
00639   catch (...) { \
00640     reporter.unexpected_exception(*this, key); \
00641     ++stats.bad; \
00642   } \
00643   )
00644 
00645 #else
00646 
00647 #define TESTSOON_TESTRUN(x) \
00648   ::testsoon::test_failure state; \
00649   x; \
00650   if (!state.is_failure()) { \
00651     reporter.success(*this, key); \
00652     ++stats.good; \
00653   } else { \
00654     reporter.failure(*this, state, key); \
00655     ++stats.bad; \
00656   }
00657 
00658 #endif
00659 
00660 #define TESTSOON_PTEST2(\
00661     name, \
00662     test_class, \
00663     has_fixture, \
00664     fixture_class, \
00665     test_param, \
00666     has_group_fixture, \
00667     has_generator, \
00668     generator_class, \
00669     generator_param) \
00670   namespace { \
00671     struct test_class \
00672     : public ::testsoon::test_info { \
00673       test_class () : ::testsoon::test_info( \
00674             get_test_group(__FILE__), name, __FILE__, __LINE__) {} \
00675       void run( \
00676           ::testsoon::test_reporter &reporter, \
00677           ::testsoon::statistics &stats \
00678       ) const { \
00679         BOOST_PP_EXPR_IIF(has_fixture, fixture_class fixture;) \
00680         BOOST_PP_EXPR_IIF(has_group_fixture, group_fixture_t group_fixture;) \
00681         BOOST_PP_EXPR_IIF(has_generator, \
00682         generator_class gen \
00683           BOOST_PP_IIF( \
00684             BOOST_PP_EQUAL(BOOST_PP_ARRAY_SIZE(generator_param), 0), \
00685             BOOST_PP_EMPTY(), \
00686             BOOST_PP_ARRAY_DATA(generator_param)); \
00687         for (generator_class::iterator i = gen.begin(); i != gen.end(); ++i)) {\
00688           ::testsoon::string key \
00689             BOOST_PP_EXPR_IIF( \
00690               has_generator, \
00691               (::testsoon::object_to_string(*i))); \
00692           TESTSOON_TESTRUN( \
00693             do_test( \
00694                 BOOST_PP_IIF(has_fixture, fixture, 0), \
00695                 BOOST_PP_IIF(has_group_fixture, group_fixture, 0), \
00696                 BOOST_PP_IIF(has_generator, *i, 0), \
00697                 BOOST_PP_IIF(TESTSOON_NO_EXCEPTIONS, state, 0) \
00698             ) \
00699           ) \
00700         } \
00701       } \
00702       void do_test(test_param) const; \
00703     } BOOST_PP_CAT(test_obj_, __LINE__); \
00704   } \
00705   void test_class::do_test(test_param) const
00706 
00707 #define TESTSOON_GEN_TUPLE2SEQ_PROCESS2(x, y) \
00708   ((x, y)) \
00709   TESTSOON_GEN_TUPLE2SEQ_PROCESS
00710 
00711 #define TESTSOON_GEN_TUPLE2SEQ_PROCESS(x, y) \
00712   ((x, y)) \
00713   TESTSOON_GEN_TUPLE2SEQ_PROCESS2
00714 
00715 #define TESTSOON_GEN_TUPLE2SEQ_PROCESS_ELIM
00716 #define TESTSOON_GEN_TUPLE2SEQ_PROCESS2_ELIM
00717 
00718 #define TESTSOON_GEN_TUPLE2SEQ(x) \
00719   BOOST_PP_CAT(TESTSOON_GEN_TUPLE2SEQ_PROCESS x, _ELIM)
00720 
00721 #define TESTSOON_PARAM_CHANGES(x) \
00722   ((0, BOOST_PP_SEQ_ELEM(0, TESTSOON_PARAM_INITIAL))) \
00723   BOOST_PP_SEQ_FOR_EACH( \
00724     TESTSOON_PARAM_EXPAND, \
00725     ~, \
00726     TESTSOON_GEN_TUPLE2SEQ(x))
00727 
00728 #define TESTSOON_PARAM_EXPAND(r, d, e) \
00729   TESTSOON_PARAM_EXPAND2 e
00730 
00731 #define TESTSOON_PARAM_EXPAND2(x, y) \
00732   ((BOOST_PP_CAT(TESTSOON_PARAM__, x)(y)))
00733 
00734 #define TESTSOON_PARAM_COMBINE(s, state, x) \
00735   BOOST_PP_SEQ_REPLACE( \
00736     state, \
00737     BOOST_PP_TUPLE_ELEM(2, 0, x), \
00738     BOOST_PP_TUPLE_ELEM(2, 1, x))
00739 
00740 #define TESTSOON_PARAM_INVOKE2(x) \
00741   BOOST_PP_SEQ_TO_TUPLE( \
00742     BOOST_PP_SEQ_FOLD_LEFT( \
00743       TESTSOON_PARAM_COMBINE, \
00744       TESTSOON_PARAM_INITIAL, \
00745       TESTSOON_PARAM_CHANGES(x)))
00746 
00747 #define TESTSOON_PARAM_INVOKE(x) \
00748   TESTSOON_PARAM_INVOKEx(TESTSOON_PARAM_INVOKE2(x))
00749 
00750 
00751 #define TESTSOON_PARAM__name(x)           0, x
00752 #define TESTSOON_PARAM__n(x)              TESTSOON_PARAM__name(x)
00753 #define TESTSOON_PARAM__fixture(x)        1, (1, x)
00754 #define TESTSOON_PARAM__f(x)              TESTSOON_PARAM__fixture(x)
00755 #define TESTSOON_PARAM__group_fixture(x)  2, x
00756 #define TESTSOON_PARAM__gf(x)             TESTSOON_PARAM__group_fixture(x)
00757 #define TESTSOON_PARAM__generator(x)      3, (1, x)
00758 #define TESTSOON_PARAM__gen(x)            TESTSOON_PARAM__generator(x)
00759 
00760 #define TESTSOON_PARAM_SHORT_GENERATOR(n, x) \
00761   TESTSOON_PARAM__generator( \
00762     (n < \
00763       BOOST_PP_TUPLE_ELEM(3, 0, x) \
00764     >) \
00765     (BOOST_PP_TUPLE_ELEM(3, 1, x)) \
00766     (BOOST_PP_TUPLE_ELEM(3, 2, x)) \
00767   )
00768 
00769 
00770 template<typename>
00771 struct quote_type;
00772 
00773 template<typename X>
00774 struct quote_type<void (X)> {
00775   typedef X type;
00776 };
00777 
00778 #define TESTSOON_PARAM__range(x) \
00779   TESTSOON_PARAM_SHORT_GENERATOR(::testsoon::range_generator, x)
00780 #define TESTSOON_PARAM__array(x) \
00781   TESTSOON_PARAM__generator( \
00782     (::testsoon::array_generator< \
00783       ::testsoon::quote_type<void (BOOST_PP_TUPLE_ELEM(2, 0, x))>::type \
00784     >) \
00785     (BOOST_PP_TUPLE_ELEM(2, 1, x)) \
00786   )
00787 #define TESTSOON_PARAM__values(x) \
00788   TESTSOON_PARAM__generator( \
00789     ( \
00790       std::vector< ::testsoon::quote_type<void ( \
00791         BOOST_PP_SEQ_HEAD(x) \
00792       )>::type> \
00793     ) \
00794     ( \
00795       (::boost::assign::list_of BOOST_PP_SEQ_TAIL(x)). \
00796       operator ::std::vector< \
00797         ::testsoon::quote_type<void (BOOST_PP_SEQ_HEAD(x))>::type \
00798       >() \
00799     ) \
00800   )
00801 
00802 #define TESTSOON_PARAM__2tuples(x) \
00803   TESTSOON_PARAM_2tuples1(TESTSOON_GEN_TUPLE2SEQ(x))
00804 
00805 #define TESTSOON_PARAM_2tuples1(x) \
00806   TESTSOON_PARAM_2tuples2( \
00807     BOOST_PP_SEQ_HEAD(x), \
00808     BOOST_PP_SEQ_TO_ARRAY(x) \
00809   )
00810 #define TESTSOON_PARAM_2tuples2(types, arr) \
00811   TESTSOON_PARAM__generator( \
00812     ( \
00813       ::std::vector< \
00814         ::testsoon::quote_type<void ( \
00815           ::boost::tuple<BOOST_PP_TUPLE_REM(2) types>) \
00816         >::type \
00817       > \
00818     ) \
00819     (::boost::assign::list_of \
00820       BOOST_PP_REPEAT( \
00821         BOOST_PP_DEC(BOOST_PP_ARRAY_SIZE(arr)), \
00822         TESTSOON_PARAM_2tuples3, \
00823         arr \
00824       ).operator ::std::vector< \
00825         ::testsoon::quote_type<void ( \
00826           ::boost::tuple<BOOST_PP_TUPLE_REM(2) types>) \
00827         >::type \
00828       >() \
00829     ) \
00830   )
00831 
00832 #define TESTSOON_PARAM_2tuples3(z, i, arr) \
00833   ( \
00834     ::testsoon::quote_type<void ( \
00835       boost::tuple< \
00836         BOOST_PP_TUPLE_REM(2) BOOST_PP_ARRAY_ELEM(0, arr) \
00837       > \
00838     )>::type \
00839     BOOST_PP_ARRAY_ELEM(BOOST_PP_INC(i), arr) \
00840   )
00841 
00842 #define TESTSOON_PARAM_INITIAL \
00843   ("") ((0, ~)) (0) ((0, ()))
00844 
00845 #define TESTSOON_PARAM_INVOKEx(x) \
00846   PTEST x
00847 
00848 #if TESTSOON_EXCEPTIONS
00849 
00850 #define TESTSOON_FAIL(msg, data) \
00851     throw ::testsoon::test_failure(msg, __LINE__, data);
00852 
00853 #define TESTSOON_ENCLOSURE(x) \
00854   do { \
00855     ::testsoon::test_failure testsoon_failure; \
00856     x; \
00857     if (testsoon_failure.is_failure()) \
00858       throw testsoon_failure; \
00859   } while (false)
00860 
00861 #else //TESTSOON_NO_EXCEPTIONS
00862 
00863 #define TESTSOON_FAIL(msg, data) \
00864   testsoon_failure = ::testsoon::test_failure(msg, __LINE__, data); \
00865   return;
00866 
00867 #define TESTSOON_ENCLOSURE(x) \
00868   do { \
00869     x; \
00870     if (testsoon_failure.is_failure()) \
00871       return; \
00872   } while (false)
00873 
00874 #endif
00875 
00876 #endif //IN_DOXY
00877 
00882 #define XTEST(named_parameter_sequence) \
00883   TESTSOON_PARAM_INVOKE(named_parameter_sequence)
00884 
00891 #define TESTSOON_Equals(a, b) \
00892   TESTSOON_ENCLOSURE( \
00893     ::testsoon::check_equals(a, b, \
00894     "not equal: " #a " and " #b, __LINE__, testsoon_failure); \
00895   )
00896 
00903 #define Equals(a, b) TESTSOON_Equals(a, b)
00904 
00911 #define TESTSOON_Not_equals(a, b) \
00912   TESTSOON_ENCLOSURE( \
00913     ::testsoon::check_not_equals(a, b, \
00914     "equal: " #a " and " #b, __LINE__, testsoon_failure); \
00915   )
00916 
00923 #define Not_equals(a, b) TESTSOON_Not_equals(a, b)
00924 
00932 #if TESTSOON_EXCEPTIONS
00933 #define TESTSOON_Throws(x, t, w) \
00934   do { \
00935     try { \
00936       (x); \
00937       TESTSOON_FAIL("not throwed " #t, ::testsoon::string_vector()); \
00938     } catch (t &e) { \
00939       if ( \
00940         ::testsoon::string(w) != ::testsoon::string() && \
00941         ::testsoon::string(e.what()) != ::testsoon::string((w))) \
00942         TESTSOON_FAIL("throwed " #t " with wrong message", \
00943           ::testsoon::string_vector(1, e.what())); \
00944     } \
00945   } while (0)
00946 #else
00947 #define TESTSOON_Throws(x, t, w) \
00948   TESTSOON_Check(!"Throws check without exception support")
00949 #endif
00950 
00958 #define Throws(x, t, w) TESTSOON_Throws(x, t, w)
00959 
00960 #if TESTSOON_EXCEPTIONS
00961 
00967 #define TESTSOON_Nothrows(x, t) \
00968         do { \
00969                 try { \
00970                         (x); \
00971                 } catch (t) { \
00972                         TESTSOON_FAIL("throwed " #t, ::testsoon::string_vector()); \
00973                 } \
00974         } while (0)
00975 #else
00976 #define TESTSOON_Nothrows(x, t) \
00977   TESTSOON_Check(!"Nothrows check without exception support")
00978 #endif
00979 
00986 #define Nothrows(x, t) TESTSOON_Nothrows(x, t)
00987 
00993 #define TESTSOON_Check(x) \
00994   do { \
00995     if (!(x)) \
00996       TESTSOON_FAIL("check " #x, ::testsoon::string_vector()); \
00997   } while (0)
00998 
01004 #define Check(x) TESTSOON_Check(x)
01005 
01006 #define TESTSOON_Check1(x, a) \
01007   TESTSOON_ENCLOSURE( \
01008     ::testsoon::do_check1(x, a, "check1 " #x, __LINE__, testsoon_failure); \
01009   )
01010 
01011 #define Check1(x, a) TESTSOON_Check1(x, a)
01012 
01013 #define TESTSOON_Check2(x, a, b) \
01014   TESTSOON_ENCLOSURE( \
01015     ::testsoon::do_check2(x, a, b, "check2 " #x, __LINE__, testsoon_failure); \
01016   )
01017 
01018 #define Check2(x, a, b) TESTSOON_Check2(x, a, b)
01019 
01020 } //namespace testsoon
01021 
01022 #ifndef IN_DOXYGEN
01023 
01024 inline static ::testsoon::test_group *
01025 get_test_group(char const *filename) {
01026   static ::testsoon::test_file file(&::testsoon::tests(), filename);
01027   return &file;
01028 }
01029 
01030 #endif
01031 
01032 #endif

Generated on Sat Dec 22 15:34:59 2007 for Test soon by  doxygen 1.5.3