00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef __UNIT_TEST_H__
00018 #define __UNIT_TEST_H__
00019
00020 #include <cstring>
00021 #include <string>
00022 #include <vector>
00023 #include <stdio.h>
00024 #include <errno.h>
00025
00026 #include "../debug/FatalSignals.h"
00027 #include "../debug/Log.h"
00028 #include "../io/PrettyPrintBuffer.h"
00029 #include "../util/Random.h"
00030
00031 namespace oasys {
00032
00069 struct UnitTest {
00070 UnitTest(std::string name) : name_(name), failed_(false) {}
00071 virtual ~UnitTest() {}
00072
00073 virtual int run() = 0;
00074
00075 std::string name_;
00076 bool failed_;
00077
00078 int errno_;
00079 const char* strerror_;
00080 };
00081
00082 enum {
00083 UNIT_TEST_PASSED = 0,
00084 UNIT_TEST_FAILED,
00085 UNIT_TEST_INPUT,
00086 };
00087
00104 class UnitTester {
00105 typedef std::vector<UnitTest*> UnitTestList;
00106
00107 public:
00108 UnitTester(std::string name) :
00109 name_(name), passed_(0), failed_(0), input_(0),
00110 progname_(0), in_tcl_(false)
00111 {}
00112
00113 virtual ~UnitTester() {}
00114
00115 void init(int argc, const char* argv[], bool init_log)
00116 {
00117 progname_ = argv[0];
00118 argc -= 1;
00119 argv += 1;
00120
00121 log_level_t level = LOG_NOTICE;
00122 struct timeval tv;
00123 ::gettimeofday(&tv, 0);
00124 u_int random_seed = tv.tv_sec;
00125
00126 while (argc != 0) {
00127 if ((strcmp(argv[0], "-l") == 0) && (argc >= 2))
00128 {
00129 level = str2level(argv[1]);
00130 argc -= 2;
00131 argv += 2;
00132 }
00133 else if (((strcmp(argv[0], "-h") == 0) ||
00134 (strcmp(argv[0], "-help") == 0) ||
00135 (strcmp(argv[0], "--help") == 0)))
00136 {
00137 printf("%s [-h] {[test name]}*\n", progname_);
00138 printf("test names:\n");
00139 for (UnitTestList::const_iterator i = tests_.begin();
00140 i != tests_.end(); ++i)
00141 {
00142 printf(" %s\n", (*i)->name_.c_str());
00143 }
00144
00145 exit(0);
00146 }
00147 else if (strcmp(argv[0], "--in_tcl") == 0)
00148 {
00149 in_tcl_ = true;
00150 }
00151 else if ((strcmp(argv[0], "--seed") == 0) && (argc >= 2))
00152 {
00153 char* end;
00154 random_seed = strtoul(argv[1], &end, 10);
00155 argc -= 2;
00156 argv += 2;
00157 }
00158 else
00159 {
00160 fprintf(stderr, "unknown unit test argument '%s',",
00161 argv[0]);
00162 exit(1);
00163 }
00164 }
00165
00166 if (init_log) {
00167 Log::init(level);
00168 }
00169 FatalSignals::init(name_.c_str());
00170
00171 oasys::Random::seed(random_seed);
00172 printf("Test random seed: %u\n", random_seed);
00173 }
00174
00175 int run_tests() {
00176 add_tests();
00177
00178 if (in_tcl_) {
00179 print_tcl_header();
00180 } else {
00181 print_header();
00182 }
00183
00184 int test_num = 1;
00185 for (UnitTestList::iterator i=tests_.begin();
00186 i != tests_.end(); ++i, ++test_num)
00187 {
00188 printf("%s...\n", (*i)->name_.c_str());
00189 fflush(stdout);
00190
00191 int err = (*i)->run();
00192 switch(err) {
00193 case UNIT_TEST_PASSED:
00194 if (in_tcl_) {
00195 fprintf(stderr, "{ %d %s P } ",
00196 test_num, (*i)->name_.c_str());
00197 } else {
00198 printf("%s... Passed\n\n", (*i)->name_.c_str());
00199 }
00200 passed_++;
00201 break;
00202 case UNIT_TEST_FAILED:
00203 if (in_tcl_) {
00204 fprintf(stderr, "{ %d %s F } ",
00205 test_num, (*i)->name_.c_str());
00206 } else {
00207 printf("%s... Failed\n\n", (*i)->name_.c_str());
00208 }
00209 failed_++;
00210 break;
00211 case UNIT_TEST_INPUT:
00212 if (in_tcl_) {
00213 fprintf(stderr, "{ %d %s I } ",
00214 test_num, (*i)->name_.c_str());
00215 } else {
00216 printf("%s... Unknown (UNIT_TEST_INPUT)\n\n",
00217 (*i)->name_.c_str());
00218 }
00219 input_++;
00220 break;
00221 }
00222 }
00223
00224 if (in_tcl_) {
00225 print_tcl_tail();
00226 } else {
00227 print_results();
00228 }
00229
00230 return 0;
00231 }
00232
00233 void print_tcl_header() {
00234 fprintf(stderr, "set result { \"%s\" { ", name_.c_str());
00235 }
00236 void print_tcl_tail() {
00237 fprintf(stderr, "} { %zu %d %d %d } }\n",
00238 tests_.size(), passed_, failed_, input_);
00239 }
00240 void print_header() {
00241 printf("\n\nRunning Test: %s\n\n", name_.c_str());
00242 }
00243
00244 void print_results() {
00245 printf("\n%s Complete:\n", name_.c_str());
00246 if (passed_ != 0) {
00247 printf("\t\t%u Passed\n", passed_);
00248 }
00249 if (failed_ != 0) {
00250 printf("\t\t%u Failed\n", failed_);
00251 }
00252 }
00253
00254 protected:
00258 virtual void add_tests() = 0;
00259
00263 void add(UnitTest* unit) {
00264 tests_.push_back(unit);
00265 }
00266
00267 private:
00268 std::string name_;
00269 UnitTestList tests_;
00270
00271 int passed_;
00272 int failed_;
00273 int input_;
00274 const char* progname_;
00275 bool in_tcl_;
00276 };
00277
00279 #define ADD_TEST(_name) \
00280 add(new _name ## UnitTest())
00281
00282 #define DECLARE_TEST(_name) \
00283 struct _name ## UnitTest : public oasys::UnitTest { \
00284 _name ## UnitTest() : UnitTest(#_name) {} \
00285 int run(); \
00286 }; \
00287 int _name ## UnitTest::run()
00288
00289 #define RUN_TESTER(_UnitTesterClass, testname, argc, argv) \
00290 _UnitTesterClass test(testname); \
00291 test.init(argc, argv, true); \
00292 int _ret = test.run_tests(); \
00293 return _ret;
00294
00295 #define RUN_TESTER_NO_LOG(_UnitTesterClass, testname, argc, argv) \
00296 _UnitTesterClass test(testname); \
00297 test.init(argc, argv, false); \
00298 int _ret = test.run_tests(); \
00299 return _ret;
00300
00301 #define DECLARE_TEST_FILE(_UnitTesterClass, testname) \
00302 int main(int argc, const char* argv[]) { \
00303 RUN_TESTER(_UnitTesterClass, testname, argc, argv); \
00304 }
00305
00306 #define DECLARE_TESTER(_name) \
00307 class _name : public oasys::UnitTester { \
00308 public: \
00309 _name(std::string name) : UnitTester(name) {} \
00310 protected: \
00311 void add_tests(); \
00312 }; \
00313 void _name::add_tests() \
00314
00315 #define DO(x) \
00316 do { \
00317 log_notice_p("/test", \
00318 "DO (%s) at %s:%d", #x, __FILE__, __LINE__); \
00319 x; \
00320 } while (0)
00321
00322 #define CHECK(x) \
00323 do { if (! (x)) { \
00324 errno_ = errno; \
00325 strerror_ = strerror(errno_); \
00326 ::oasys::Breaker::break_here(); \
00327 log_err_p("/test", \
00328 "CHECK FAILED (%s) at %s:%d", \
00329 #x, __FILE__, __LINE__); \
00330 return oasys::UNIT_TEST_FAILED; \
00331 } else { \
00332 log_notice_p("/test", \
00333 "CHECK (%s) ok at %s:%d", #x, __FILE__, __LINE__); \
00334 } } while(0)
00335
00336 #define CHECK_SYS(x) \
00337 do { if (! (x)) { \
00338 errno_ = errno; \
00339 strerror_ = strerror(errno_); \
00340 ::oasys::Breaker::break_here(); \
00341 log_err_p("/test", \
00342 "CHECK FAILED (%s) at %s:%d, errno=%s", \
00343 #x, __FILE__, __LINE__, strerror_); \
00344 return oasys::UNIT_TEST_FAILED; \
00345 } else { \
00346 log_notice_p("/test", \
00347 "CHECK (%s) ok at %s:%d", #x, __FILE__, __LINE__); \
00348 } } while(0)
00349
00350 #define CHECK_EQUAL(_a, _b) \
00351 do { int a = _a; int b = _b; if ((a) != (b)) { \
00352 errno_ = errno; \
00353 strerror_ = strerror(errno_); \
00354 ::oasys::Breaker::break_here(); \
00355 log_err_p("/test", \
00356 "CHECK FAILED: '" #_a "' (%d) != '" #_b "' (%d) at %s:%d", \
00357 (a), (b), __FILE__, __LINE__); \
00358 return oasys::UNIT_TEST_FAILED; \
00359 } else { \
00360 log_notice_p("/test", \
00361 "CHECK '" #_a "' (%d) == '" #_b "' (%d) " \
00362 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00363 } } while(0)
00364
00365 #define CHECK_LT(_a, _b) \
00366 do { int a = _a; int b = _b; if (! (((a) < (b))) { \
00367 errno_ = errno; \
00368 strerror_ = strerror(errno_); \
00369 ::oasys::Breaker::break_here(); \
00370 log_err_p("/test", \
00371 "CHECK FAILED: '" #_a "' (%d) < '" #_b "' (%d) at %s:%d", \
00372 (a), (b), __FILE__, __LINE__); \
00373 return oasys::UNIT_TEST_FAILED; \
00374 } else { \
00375 log_notice_p("/test", \
00376 "CHECK '" #_a "' (%d) < '" #_b "' (%d) " \
00377 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00378 } } while(0)
00379
00380 #define CHECK_GT(_a, _b) \
00381 do { int a = _a; int b = _b; if (! ((a) > (b))) { \
00382 errno_ = errno; \
00383 strerror_ = strerror(errno_); \
00384 ::oasys::Breaker::break_here(); \
00385 log_err_p("/test", \
00386 "CHECK FAILED: '" #_a "' (%d) > '" #_b "' (%d) at %s:%d", \
00387 (a), (b), __FILE__, __LINE__); \
00388 return oasys::UNIT_TEST_FAILED; \
00389 } else { \
00390 log_notice_p("/test", \
00391 "CHECK '" #_a "' (%d) > '" #_b "' (%d) " \
00392 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00393 } } while(0)
00394
00395 #define CHECK_LTU(_a, _b) \
00396 do { u_int a = _a; u_int b = _b; if (! ((a) <= (b))) { \
00397 errno_ = errno; \
00398 strerror_ = strerror(errno_); \
00399 ::oasys::Breaker::break_here(); \
00400 log_err_p("/test", \
00401 "CHECK FAILED: '" #_a "' (%u) <= '" #_b "' (%u) at %s:%u", \
00402 (a), (b), __FILE__, __LINE__); \
00403 return oasys::UNIT_TEST_FAILED; \
00404 } else { \
00405 log_notice_p("/test", \
00406 "CHECK '" #_a "' (%u) <= '" #_b "' (%u) " \
00407 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00408 } } while(0)
00409
00410 #define CHECK_GTU(_a, _b) \
00411 do { u_int a = _a; u_int b = _b; if (! ((a) >= (b))) { \
00412 errno_ = errno; \
00413 strerror_ = strerror(errno_); \
00414 ::oasys::Breaker::break_here(); \
00415 log_err_p("/test", \
00416 "CHECK FAILED: '" #_a "' (%u) >= '" #_b "' (%u) at %s:%u", \
00417 (a), (b), __FILE__, __LINE__); \
00418 return oasys::UNIT_TEST_FAILED; \
00419 } else { \
00420 log_notice_p("/test", \
00421 "CHECK '" #_a "' (%u) >= '" #_b "' (%u) " \
00422 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00423 } } while(0)
00424
00425 #define CHECK_EQUAL_U64(a, b) \
00426 do { if ((a) != (b)) { \
00427 errno_ = errno; \
00428 strerror_ = strerror(errno_); \
00429 ::oasys::Breaker::break_here(); \
00430 log_err_p("/test", \
00431 "CHECK FAILED: '" #a "' (%llu) != '" #b "' (%llu) at %s:%d", \
00432 (long long unsigned int)(a), \
00433 (long long unsigned int)(b), \
00434 __FILE__, __LINE__); \
00435 return oasys::UNIT_TEST_FAILED; \
00436 } else { \
00437 log_notice_p("/test", \
00438 "CHECK '" #a "' (%llu) == '" #b "' (%llu) " \
00439 "at %s:%d", \
00440 (long long unsigned int)(a), \
00441 (long long unsigned int)(b), \
00442 __FILE__, __LINE__); \
00443 } } while(0)
00444
00445 #define CHECK_EQUALSTR(a, b) \
00446 do { if (strcmp((a), (b)) != 0) { \
00447 errno_ = errno; \
00448 strerror_ = strerror(errno_); \
00449 ::oasys::Breaker::break_here(); \
00450 log_err_p("/test", \
00451 "CHECK FAILED: '" #a "' != '" #b "' at %s:%d.", \
00452 __FILE__, __LINE__); \
00453 log_err_p("/test", "Contents of " #a \
00454 " (length %zu): ", strlen(a)); \
00455 oasys::PrettyPrintBuf buf_a(a, strlen(a)); \
00456 std::string s; \
00457 bool done; \
00458 do { \
00459 done = buf_a.next_str(&s); \
00460 log_err_p("/test", s.c_str()); \
00461 } while (!done); \
00462 \
00463 log_err_p("/test", "Contents of " #b \
00464 " (length %zu): ", strlen(b)); \
00465 oasys::PrettyPrintBuf buf_b(b, strlen(b)); \
00466 \
00467 do { \
00468 done = buf_b.next_str(&s); \
00469 log_err_p("/test", s.c_str()); \
00470 } while (!done); \
00471 \
00472 return oasys::UNIT_TEST_FAILED; \
00473 } else { \
00474 log_notice_p("/test", \
00475 "CHECK '" #a "' (%s) == '" #b "' (%s) " \
00476 "at %s:%d", (a), (b), __FILE__, __LINE__); \
00477 } } while(0);
00478
00479 #define CHECK_EQUALSTRN(a, b, len) \
00480 do { u_int print_len = (len > 32) ? 32 : len; \
00481 if (strncmp((const char*)(a), (const char*)(b), (len)) != 0) { \
00482 errno_ = errno; \
00483 strerror_ = strerror(errno_); \
00484 ::oasys::Breaker::break_here(); \
00485 log_err_p("/test", "CHECK FAILED: " \
00486 "'" #a "' (%.*s...) != '" #b "' (%.*s...) at %s:%d", \
00487 print_len, (a), print_len, (b), \
00488 __FILE__, __LINE__); \
00489 return oasys::UNIT_TEST_FAILED; \
00490 } else { \
00491 log_notice_p("/test", \
00492 "CHECK '" #a "' (%.*s...) == '" #b "' (%.*s...) " \
00493 "at %s:%d", \
00494 print_len, (a), print_len, (b), __FILE__, __LINE__); \
00495 } \
00496 } while(0)
00497
00499
00500 };
00501
00502 #endif //__UNIT_TEST_H__