00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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 ¤t; \
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 }
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