00001 #ifndef __UNIT_TEST_H__
00002 #define __UNIT_TEST_H__
00003
00004 #include <string>
00005 #include <vector>
00006 #include <stdio.h>
00007
00008 #include "../debug/FatalSignals.h"
00009 #include "../debug/Log.h"
00010 #include "../io/PrettyPrintBuffer.h"
00011
00012 namespace oasys {
00013
00050 struct UnitTest {
00051 UnitTest(std::string name) : name_(name), failed_(false) {}
00052 virtual ~UnitTest() {}
00053
00054 virtual int run() = 0;
00055
00056 std::string name_;
00057 bool failed_;
00058 };
00059
00060 enum {
00061 UNIT_TEST_PASSED = 0,
00062 UNIT_TEST_FAILED,
00063 UNIT_TEST_INPUT,
00064 };
00065
00082 class UnitTester {
00083 typedef std::vector<UnitTest*> UnitTestList;
00084
00085 public:
00086 UnitTester(std::string name) :
00087 name_(name), passed_(0), failed_(0), input_(0)
00088 {
00089 }
00090
00091 virtual ~UnitTester() {}
00092
00093 int run_tests(int argc, const char* argv[]) {
00094 log_level_t level = LOG_NOTICE;
00095
00096
00097 argc -= 1;
00098 argv += 1;
00099
00100
00101 if (argc >= 2 && (strcmp(argv[0], "-l") == 0))
00102 {
00103 level = str2level(argv[1]);
00104 argc -= 2;
00105 argv += 2;
00106 }
00107
00108 Log::init(level);
00109 FatalSignals::init(name_.c_str());
00110
00111 add_tests();
00112
00113 bool in_tcl = false;
00114
00115 if (argc >= 1 &&
00116 ((strcmp(argv[0], "-h") == 0) ||
00117 (strcmp(argv[0], "-help") == 0) ||
00118 (strcmp(argv[0], "--help") == 0)))
00119 {
00120 printf("%s [-h] {[test name]}*\n", argv[0]);
00121 printf("test names:\n");
00122 for (UnitTestList::const_iterator i = tests_.begin();
00123 i != tests_.end(); ++i)
00124 {
00125 printf(" %s\n", (*i)->name_.c_str());
00126 }
00127
00128 exit(0);
00129 }
00130
00131 if (argc >= 1 && (strcmp(argv[1], "-test") == 0)) {
00132 argc -= 1;
00133 argv += 1;
00134 in_tcl = true;
00135 }
00136
00137 UnitTestList new_tests;
00138 while (argc != 0) {
00139 for (UnitTestList::iterator i = tests_.begin();
00140 i != tests_.end(); ++i)
00141 {
00142 const char* testname = argv[0];
00143 if (strcmp((*i)->name_.c_str(), testname) == 0) {
00144 new_tests.push_back(*i);
00145 }
00146 }
00147 argc--;
00148 argv++;
00149 }
00150 if (new_tests.size() > 0) {
00151 std::swap(tests_, new_tests);
00152 }
00153
00154 if (in_tcl) {
00155 print_tcl_header();
00156 } else {
00157 print_header();
00158 }
00159
00160 int test_num = 1;
00161 for (UnitTestList::iterator i=tests_.begin();
00162 i != tests_.end(); ++i, ++test_num)
00163 {
00164 printf("%s...\n", (*i)->name_.c_str());
00165 fflush(stdout);
00166
00167 int err = (*i)->run();
00168 switch(err) {
00169 case UNIT_TEST_PASSED:
00170 if (in_tcl) {
00171 fprintf(stderr, "{ %d %s P } ",
00172 test_num, (*i)->name_.c_str());
00173 } else {
00174 printf("%s... Passed\n\n", (*i)->name_.c_str());
00175 }
00176 passed_++;
00177 break;
00178 case UNIT_TEST_FAILED:
00179 if (in_tcl) {
00180 fprintf(stderr, "{ %d %s F } ",
00181 test_num, (*i)->name_.c_str());
00182 } else {
00183 printf("%s... Failed\n\n", (*i)->name_.c_str());
00184 }
00185 failed_++;
00186 break;
00187 case UNIT_TEST_INPUT:
00188 if (in_tcl) {
00189 fprintf(stderr, "{ %d %s I } ",
00190 test_num, (*i)->name_.c_str());
00191 } else {
00192 printf("%s... Unknown (UNIT_TEST_INPUT)\n\n",
00193 (*i)->name_.c_str());
00194 }
00195 input_++;
00196 break;
00197 }
00198 }
00199
00200 if (in_tcl) {
00201 print_tcl_tail();
00202 } else {
00203 print_results();
00204 }
00205
00206 return 0;
00207 }
00208
00209 void print_tcl_header() {
00210 fprintf(stderr, "set result { \"%s\" { ", name_.c_str());
00211 }
00212 void print_tcl_tail() {
00213 fprintf(stderr, "} { %zu %d %d %d } }\n",
00214 tests_.size(), passed_, failed_, input_);
00215 }
00216 void print_header() {
00217 printf("\n\nRunning Test: %s\n\n", name_.c_str());
00218 }
00219
00220 void print_results() {
00221 printf("\n%s Complete:\n", name_.c_str());
00222 if (passed_ != 0) {
00223 printf("\t\t%u Passed\n", passed_);
00224 }
00225 if (failed_ != 0) {
00226 printf("\t\t%u Failed\n", failed_);
00227 }
00228 }
00229
00230 protected:
00234 virtual void add_tests() = 0;
00235
00239 void add(UnitTest* unit) {
00240 tests_.push_back(unit);
00241 }
00242
00243 private:
00244 std::string name_;
00245 UnitTestList tests_;
00246
00247 int passed_;
00248 int failed_;
00249 int input_;
00250 };
00251
00253 #define ADD_TEST(_name) \
00254 add(new _name ## UnitTest())
00255
00256 #define DECLARE_TEST(_name) \
00257 struct _name ## UnitTest : public oasys::UnitTest { \
00258 _name ## UnitTest() : UnitTest(#_name) {} \
00259 int run(); \
00260 }; \
00261 int _name ## UnitTest::run()
00262
00263 #define RUN_TESTER(_UnitTesterClass, testname, argc, argv) \
00264 _UnitTesterClass test(testname); \
00265 return test.run_tests(argc, argv);
00266
00267 #define DECLARE_TEST_FILE(_UnitTesterClass, testname) \
00268 int main(int argc, const char* argv[]) { \
00269 RUN_TESTER(_UnitTesterClass, testname, argc, argv); \
00270 }
00271
00272 #define DECLARE_TESTER(_name) \
00273 class _name : public oasys::UnitTester { \
00274 public: \
00275 _name::_name(std::string name) : UnitTester(name) {} \
00276 protected: \
00277 void add_tests(); \
00278 }; \
00279 void _name::add_tests() \
00280
00281 #define DO(x) \
00282 do { \
00283 ::oasys::__logf(oasys::LOG_NOTICE, "/test", \
00284 "DO (%s) at %s:%d", #x, __FILE__, __LINE__); \
00285 x; \
00286 } while (0)
00287
00288 #define CHECK(x) \
00289 do { if (! (x)) { \
00290 ::oasys::Breaker::break_here(); \
00291 ::oasys::__logf(oasys::LOG_ERR, "/test", \
00292 "CHECK FAILED (%s) at %s:%d", \
00293 #x, __FILE__, __LINE__); \
00294 return oasys::UNIT_TEST_FAILED; \
00295 } else { \
00296 ::oasys::__logf(oasys::LOG_NOTICE, "/test", \
00297 "CHECK (%s) ok at %s:%d", #x, __FILE__, __LINE__); \
00298 } } while(0)
00299
00300 #define CHECK_EQUAL(_a, _b) \
00301 do { int a = _a; int b = _b; if ((a) != (b)) { \
00302 ::oasys::Breaker::break_here(); \
00303 oasys::logf("/test", oasys::LOG_ERR, \
00304 "CHECK FAILED: '" #_a "' (%d) != '" #_b "' (%d) at %s:%d", \
00305 (a), (b), __FILE__, __LINE__); \
00306 return oasys::UNIT_TEST_FAILED; \
00307 } else { \
00308 oasys::logf("/test", oasys::LOG_NOTICE, \
00309 "CHECK '" #_a "' (%d) == '" #_b "' (%d) " \
00310 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00311 } } while(0)
00312
00313 #define CHECK_LT(_a, _b) \
00314 do { int a = _a; int b = _b; if (! (((a) < (b))) { \
00315 ::oasys::Breaker::break_here(); \
00316 oasys::logf("/test", oasys::LOG_ERR, \
00317 "CHECK FAILED: '" #_a "' (%d) < '" #_b "' (%d) at %s:%d", \
00318 (a), (b), __FILE__, __LINE__); \
00319 return oasys::UNIT_TEST_FAILED; \
00320 } else { \
00321 oasys::logf("/test", oasys::LOG_NOTICE, \
00322 "CHECK '" #_a "' (%d) < '" #_b "' (%d) " \
00323 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00324 } } while(0)
00325
00326 #define CHECK_GT(_a, _b) \
00327 do { int a = _a; int b = _b; if (! ((a) > (b))) { \
00328 ::oasys::Breaker::break_here(); \
00329 oasys::logf("/test", oasys::LOG_ERR, \
00330 "CHECK FAILED: '" #_a "' (%d) > '" #_b "' (%d) at %s:%d", \
00331 (a), (b), __FILE__, __LINE__); \
00332 return oasys::UNIT_TEST_FAILED; \
00333 } else { \
00334 oasys::logf("/test", oasys::LOG_NOTICE, \
00335 "CHECK '" #_a "' (%d) > '" #_b "' (%d) " \
00336 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00337 } } while(0)
00338
00339 #define CHECK_LTU(_a, _b) \
00340 do { u_int a = _a; u_int b = _b; if (! ((a) <= (b))) { \
00341 ::oasys::Breaker::break_here(); \
00342 oasys::logf("/test", oasys::LOG_ERR, \
00343 "CHECK FAILED: '" #_a "' (%u) <= '" #_b "' (%u) at %s:%u", \
00344 (a), (b), __FILE__, __LINE__); \
00345 return oasys::UNIT_TEST_FAILED; \
00346 } else { \
00347 oasys::logf("/test", oasys::LOG_NOTICE, \
00348 "CHECK '" #_a "' (%u) <= '" #_b "' (%u) " \
00349 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00350 } } while(0)
00351
00352 #define CHECK_GTU(_a, _b) \
00353 do { u_int a = _a; u_int b = _b; if (! ((a) >= (b))) { \
00354 ::oasys::Breaker::break_here(); \
00355 oasys::logf("/test", oasys::LOG_ERR, \
00356 "CHECK FAILED: '" #_a "' (%u) >= '" #_b "' (%u) at %s:%u", \
00357 (a), (b), __FILE__, __LINE__); \
00358 return oasys::UNIT_TEST_FAILED; \
00359 } else { \
00360 oasys::logf("/test", oasys::LOG_NOTICE, \
00361 "CHECK '" #_a "' (%u) >= '" #_b "' (%u) " \
00362 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00363 } } while(0)
00364
00365 #define CHECK_EQUAL_U64(a, b) \
00366 do { if ((a) != (b)) { \
00367 ::oasys::Breaker::break_here(); \
00368 oasys::logf("/test", oasys::LOG_ERR, \
00369 "CHECK FAILED: '" #a "' (%llu) != '" #b "' (%llu) at %s:%d", \
00370 (u_int64_t)(a), (u_int64_t)(b), __FILE__, __LINE__); \
00371 return oasys::UNIT_TEST_FAILED; \
00372 } else { \
00373 oasys::logf("/test", oasys::LOG_NOTICE, \
00374 "CHECK '" #a "' (%llu) == '" #b "' (%llu) " \
00375 "at %s:%d", \
00376 (u_int64_t)(a), (u_int64_t)(b), __FILE__, __LINE__); \
00377 } } while(0)
00378
00379 #define CHECK_EQUALSTR(a, b) \
00380 do { if (strcmp((a), (b)) != 0) { \
00381 ::oasys::Breaker::break_here(); \
00382 oasys::logf("/test", oasys::LOG_ERR, \
00383 "CHECK FAILED: '" #a "' != '" #b "' at %s:%d.", \
00384 __FILE__, __LINE__); \
00385 oasys::logf("/test", oasys::LOG_ERR, "Contents of " #a \
00386 " (length %zu): ", strlen(a)); \
00387 oasys::PrettyPrintBuf buf_a(a, strlen(a)); \
00388 std::string s; \
00389 bool done; \
00390 do { \
00391 done = buf_a.next_str(&s); \
00392 oasys::logf("/test", oasys::LOG_ERR, s.c_str()); \
00393 } while (!done); \
00394 \
00395 oasys::logf("/test", oasys::LOG_ERR, "Contents of " #b \
00396 " (length %zu): ", strlen(b)); \
00397 oasys::PrettyPrintBuf buf_b(b, strlen(b)); \
00398 \
00399 do { \
00400 done = buf_b.next_str(&s); \
00401 oasys::logf("/test", oasys::LOG_ERR, s.c_str()); \
00402 } while (!done); \
00403 \
00404 return oasys::UNIT_TEST_FAILED; \
00405 } else { \
00406 oasys::logf("/test", oasys::LOG_NOTICE, \
00407 "CHECK '" #a "' (%s) == '" #b "' (%s) " \
00408 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00409 } } while(0);
00410
00411 #define CHECK_EQUALSTRN(a, b, len) \
00412 do { u_int print_len = (len > 32) ? 32 : len; \
00413 if (strncmp((const char*)(a), (const char*)(b), (len)) != 0) { \
00414 ::oasys::Breaker::break_here(); \
00415 oasys::logf("/test", oasys::LOG_ERR, "CHECK FAILED: " \
00416 "'" #a "' (%.*s...) != '" #b "' (%.*s...) at %s:%d", \
00417 print_len, (a), print_len, (b), \
00418 __FILE__, __LINE__); \
00419 return oasys::UNIT_TEST_FAILED; \
00420 } else { \
00421 oasys::logf("/test", oasys::LOG_NOTICE, \
00422 "CHECK '" #a "' (%.*s...) == '" #b "' (%.*s...) " \
00423 "at %s:%d", \
00424 print_len, (a), print_len, (b), __FILE__, __LINE__); \
00425 } \
00426 } while(0)
00427
00429
00430 };
00431
00432 #endif //__UNIT_TEST_H__