github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/image/jxr/jxrlib/test/test.cc (about)

     1  // Copyright 2013 <chaishushan{AT}gmail.com>. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include "test.h"
     6  
     7  #include <stdarg.h>
     8  #include <stdio.h>
     9  #include <stdlib.h>
    10  #include <string.h>
    11  #include <math.h>
    12  #include <time.h>
    13  
    14  #include <string>
    15  #include <algorithm>
    16  
    17  static std::vector<std::string> args;
    18  static std::string flag_list_regexp = "";
    19  static std::string flag_test_regexp = ".*";
    20  static std::string flag_test_bench_regexp = "";
    21  static std::string flag_test_bench_benchtime_second = "1";
    22  
    23  static struct { int N; double benchtime, timer_start, timer_duration; bool timer_on; } bench;
    24  static struct { void (*fn)(void); const char *name, *type; } tests[10000];
    25  static int ntests = 0;
    26  
    27  static bool strHasPrefix(const std::string& str, const std::string& prefix) {
    28  	return str.size() >= prefix.size()
    29  		&& str.compare(0, prefix.size(), prefix) == 0;
    30  }
    31  static bool strHasSuffix(const std::string& str, const std::string& suffix) {
    32  	return str.size() >= suffix.size()
    33  		&& str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0;
    34  }
    35  
    36  static const char* getBaseName(const char* fname) {
    37  	int len = strlen(fname);
    38  	const char* s = fname + len;
    39  	while(s > fname) {
    40  		if(s[-1] == '/' || s[-1] == '\\') return s;
    41  		s--;
    42  	}
    43  	return s;
    44  }
    45  
    46  static int matchhere(const char* regexp, const char* text);
    47  static int match(const char *regexp, const char *text) {
    48  	if (regexp[0] == '^') {
    49  		return matchhere(regexp+1, text);
    50  	}
    51  	do {
    52  		if (matchhere(regexp, text)) return 1;
    53  	} while (*text++ != '\0');
    54  	return 0;
    55  }
    56  static int matchstar(int c, const char *regexp, const char *text) {
    57  	do {
    58  		if (matchhere(regexp, text)) return 1;
    59  	} while (*text != '\0' && (*text++ == c || c == '.'));
    60  	return 0;
    61  }
    62  static int matchhere(const char *regexp, const char *text) {
    63  	if (regexp[0] == '\0') return 1;
    64  	if (regexp[1] == '*') return matchstar(regexp[0], regexp+2, text);
    65  	if (regexp[0] == '$' && regexp[1] == '\0') return *text == '\0';
    66  	if (*text!='\0' && (regexp[0]=='.' || regexp[0]==*text)) return matchhere(regexp+1, text+1);
    67  	return 0;
    68  }
    69  
    70  const std::vector<std::string>& TestArgs() {
    71  	return args;
    72  }
    73  
    74  void RegisterTest(void (*fn)(void), const char* name, const char* type) {
    75  	if(ntests >= sizeof(tests)/sizeof(tests[0])) {
    76  		printf("%s %s, line %d: RegisterTest failed\n", name, getBaseName(__FILE__), __LINE__);
    77  		exit(-1);
    78  	}
    79  	tests[ntests].fn = fn;
    80  	tests[ntests].name = name;
    81  	tests[ntests].type = type;
    82  	ntests++;
    83  }
    84  
    85  void TestAssertTrue(bool condition, const char* fname, int lineno, const char* fmt, ...) {
    86  	if(!condition) {
    87  		fname = getBaseName(fname);
    88  		if(fmt != NULL && fmt[0] != '\0') {
    89  			va_list ap;
    90  			va_start(ap, fmt);
    91  			printf("fail, %s, line %d: ASSERT_TRUE(false), ", fname, lineno);
    92  			vprintf(fmt, ap);
    93  			printf("\n");
    94  			va_end(ap);
    95  		} else {
    96  			printf("fail, %s, line %d: ASSERT_TRUE(false)\n", fname, lineno);
    97  		}
    98  		exit(-1);
    99  	}
   100  }
   101  
   102  void TestAssertEQ(int a, int b, const char* fname, int lineno, const char* fmt, ...) {
   103  	if(a != b) {
   104  		fname = getBaseName(fname);
   105  		if(fmt != NULL && fmt[0] != '\0') {
   106  			va_list ap;
   107  			va_start(ap, fmt);
   108  			printf("fail, %s, line %d: ASSERT_EQ(%d, %d), ", fname, lineno, a, b);
   109  			vprintf(fmt, ap);
   110  			printf("\n");
   111  			va_end(ap);
   112  		} else {
   113  			printf("fail, %s, line %d: ASSERT_EQ(%d, %d)\n", fname, lineno, a, b);
   114  		}
   115  		exit(-1);
   116  	}
   117  }
   118  void TestAssertStrEQ(const char* a, const char* b, const char* fname, int lineno, const char* fmt, ...) {
   119  	if(strcmp(a, b) != 0) {
   120  		fname = getBaseName(fname);
   121  		if(fmt != NULL && fmt[0] != '\0') {
   122  			va_list ap;
   123  			va_start(ap, fmt);
   124  			printf("fail, %s, line %d: ASSERT_STREQ(\"%s\", \"%s\"), ", fname, lineno, a, b);
   125  			vprintf(fmt, ap);
   126  			printf("\n");
   127  			va_end(ap);
   128  		} else {
   129  			printf("fail, %s, line %d: ASSERT_STREQ(\"%s\", \"%s\")\n", fname, lineno, a, b);
   130  		}
   131  		exit(-1);
   132  	}
   133  }
   134  void TestAssertNear(float a, float b, float abs_error, const char* fname, int lineno, const char* fmt, ...) {
   135  	if(abs(a-b) > abs(abs_error)) {
   136  		fname = getBaseName(fname);
   137  		if(fmt != NULL && fmt[0] != '\0') {
   138  			va_list ap;
   139  			va_start(ap, fmt);
   140  			printf("fail, %s, line %d: ASSERT_NEAR(%f, %f, %f), ", fname, lineno, a, b, abs_error);
   141  			vprintf(fmt, ap);
   142  			printf("\n");
   143  			va_end(ap);
   144  		} else {
   145  			printf("fail, %s, line %d: ASSERT_NEAR(%f, %f, %f)\n", fname, lineno, a, b, abs_error);
   146  		}
   147  		exit(-1);
   148  	}
   149  }
   150  
   151  // roundDown10 rounds a number down to the nearest power of 10.
   152  static int roundDown10(int n) {
   153  	int tens = 0;
   154  	// tens = floor(log_10(n))
   155  	while(n >= 10) {
   156  		n = n / 10;
   157  		tens++;
   158  	}
   159  	// result = 10^tens
   160  	int result = 1;
   161  	for(int i = 0; i < tens; ++i) {
   162  		result *= 10;
   163  	}
   164  	return result;
   165  }
   166  
   167  // roundUp rounds x up to a number of the form [1eX, 2eX, 5eX].
   168  static int roundUp(int n) {
   169  	int base = roundDown10(n);
   170  	if(n <= base) return base;
   171  	if(n <= base*2) return base*2;
   172  	if(n <= base*5) return base*5;
   173  	return base*10;
   174  }
   175  
   176  static double timeNowSec() {
   177  	return 1.0 * clock() / CLOCKS_PER_SEC;
   178  }
   179  
   180  static void benchRunN(int id, int n) {
   181  	bench.N = n;
   182  	BenchResetTimer();
   183  	BenchStartTimer();
   184  	tests[id].fn();
   185  	BenchStopTimer();
   186  }
   187  
   188  static void benchRun(int id) {
   189  	int n = 1;
   190  	benchRunN(id, n);
   191  	while(bench.timer_duration < bench.benchtime && n < 1e9) {
   192  		int last = n;
   193  		// Run more iterations than we think we'll need for a second (1.5x).
   194  		// Don't grow too fast in case we had timing errors previously.
   195  		// Be sure to run at least one more than last time.
   196  		n = std::max(std::min(n+n/2, 100*last), last+1);
   197  		// Round up to something easy to read.
   198  		n = roundUp(n);
   199  		benchRunN(id, n);
   200  	}
   201  
   202  	double nsop = 1e9*bench.timer_duration/bench.N;
   203  	if(nsop < 10) {
   204  		printf("[bench] %s %d %.2f ns/op\n", tests[id].name, bench.N, float(nsop));
   205  	} else if(nsop < 100) {
   206  		printf("[bench] %s %d %.1f ns/op\n", tests[id].name, bench.N, float(nsop));
   207  	} else {
   208  		printf("[bench] %s %d %d ns/op\n", tests[id].name, bench.N, int(nsop));
   209  	}
   210  }
   211  
   212  int BenchN() {
   213  	return bench.N;
   214  }
   215  void BenchResetTimer() {
   216  	bench.timer_start = timeNowSec();
   217  	bench.timer_duration = 0.0;
   218  }
   219  void BenchStartTimer() {
   220  	if(!bench.timer_on) {
   221  		bench.timer_start = timeNowSec();
   222  		bench.timer_on = true;
   223  	}
   224  }
   225  void BenchStopTimer() {
   226  	if(bench.timer_on) {
   227  		bench.timer_duration += timeNowSec() - bench.timer_start;
   228  		bench.timer_on = false;
   229  	}
   230  }
   231  
   232  static void usage(int argc, char* argv[]) {
   233  	printf("C++ Mini UnitTest and Benchmark Library.\n");
   234  	printf("https://github.com/chai2010/cc-mini-test\n");
   235  	printf("\n");
   236  
   237  	printf("Usage: %s\n", getBaseName(argv[0]));
   238  	printf("  [-list=.*]\n");
   239  	printf("  [-test=.*]\n");
   240  	printf("  [-test.bench=]\n");
   241  	printf("  [-test.benchtime=1second]\n");
   242  	printf("  [-help]\n");
   243  	printf("  [-h]\n");
   244  	printf("\n");
   245  
   246  	printf("Report bugs to <chaishushan{AT}gmail.com>.\n");
   247  }
   248  
   249  int main(int argc, char* argv[]) {
   250  	args.assign(argv, argv + argc);
   251  	for(int i = 1; i < argc; ++i) {
   252  		if(argv[i] == std::string("-help") || argv[i] == std::string("-h")) {
   253  			usage(argc, argv);
   254  			return 0;
   255  		}
   256  
   257  		if(argv[i] == std::string("-list")) {
   258  			flag_list_regexp = ".*";
   259  			break;
   260  		}
   261  		if(argv[i] == std::string("-test")) {
   262  			flag_test_regexp = ".*";
   263  			continue;
   264  		}
   265  		if(argv[i] == std::string("-test.bench")) {
   266  			flag_test_bench_regexp = ".*";
   267  			continue;
   268  		}
   269  
   270  		if(strHasPrefix(argv[i], "-list=")) {
   271  			flag_list_regexp = argv[i]+sizeof("-list=")-1;
   272  			continue;
   273  		}
   274  		if(strHasPrefix(argv[i], "-test=")) {
   275  			flag_test_regexp = argv[i]+sizeof("-test=")-1;
   276  			continue;
   277  		}
   278  		if(strHasPrefix(argv[i], "-test.bench=")) {
   279  			flag_test_bench_regexp = argv[i]+sizeof("-test.bench=")-1;
   280  			continue;
   281  		}
   282  
   283  		if(strHasPrefix(argv[i], "-test.benchtime=")) {
   284  			flag_test_bench_benchtime_second = argv[i]+sizeof("-test.benchtime=")-1;
   285  			bench.benchtime = atof(flag_test_bench_benchtime_second.c_str());
   286  			if(bench.benchtime <= 0.1) bench.benchtime = 1.0;
   287  			continue;
   288  		}
   289  
   290  		// ingore user defined flag
   291  	}
   292  
   293  	if(!flag_list_regexp.empty()) {
   294  		int total = 0;
   295  		for(int id = 0; id < ntests; ++id) {
   296  			if(std::string(tests[id].type) == "init") {
   297  				if(match(flag_list_regexp.c_str(), tests[id].name) != 0) {
   298  					printf("[init] %s\n", tests[id].name);
   299  					total++;
   300  				}
   301  			}
   302  		}
   303  		for(int id = 0; id < ntests; ++id) {
   304  			if(std::string(tests[id].type) == "exit") {
   305  				if(match(flag_list_regexp.c_str(), tests[id].name) != 0) {
   306  					printf("[exit] %s\n", tests[id].name);
   307  					total++;
   308  				}
   309  			}
   310  		}
   311  		for(int id = 0; id < ntests; ++id) {
   312  			if(std::string(tests[id].type) == "test") {
   313  				if(match(flag_list_regexp.c_str(), tests[id].name) != 0) {
   314  					printf("[test] %s\n", tests[id].name);
   315  					total++;
   316  				}
   317  			}
   318  		}
   319  		for(int id = 0; id < ntests; ++id) {
   320  			if(std::string(tests[id].type) == "bench") {
   321  				if(match(flag_list_regexp.c_str(), tests[id].name) != 0) {
   322  					printf("[bench] %s\n", tests[id].name);
   323  					total++;
   324  				}
   325  			}
   326  		}
   327  		printf("total %d\n", total);
   328  		return 0;
   329  	}
   330  
   331  	// run init func
   332  	for(int id = 0; id < ntests; ++id) {
   333  		if(std::string(tests[id].type) == "init") {
   334  			printf("[init] %s ", tests[id].name);
   335  			tests[id].fn();
   336  			printf("\n");
   337  		}
   338  	}
   339  
   340  	// run test func
   341  	if(!flag_test_regexp.empty()) {
   342  		for(int id = 0; id < ntests; ++id) {
   343  			if(std::string(tests[id].type) == "test") {
   344  				if(match(flag_test_regexp.c_str(), tests[id].name) != 0) {
   345  					printf("[test] %s ", tests[id].name);
   346  					tests[id].fn();
   347  					printf("ok\n");
   348  				}
   349  			}
   350  		}
   351  	}
   352  
   353  	// run bench func
   354  	if(!flag_test_bench_regexp.empty()) {
   355  		if(bench.benchtime <= 0.1) bench.benchtime = 1.0;
   356  		for(int id = 0; id < ntests; ++id) {
   357  			if(std::string(tests[id].type) == "bench") {
   358  				if(match(flag_test_bench_regexp.c_str(), tests[id].name) != 0) {
   359  					benchRun(id);
   360  				}
   361  			}
   362  		}
   363  	}
   364  
   365  	// run exit func
   366  	for(int id = 0; id < ntests; ++id) {
   367  		if(std::string(tests[id].type) == "exit") {
   368  			printf("[exit] %s ", tests[id].name);
   369  			tests[id].fn();
   370  			printf("\n");
   371  		}
   372  	}
   373  
   374  	printf("PASS\n");
   375  	return 0;
   376  }