Mercurial > hg > th-libs
view tests.c @ 300:385d0b40a6c8
Fix -t option handling, had a off-by one in value handling.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 22 Feb 2016 18:31:37 +0200 |
parents | ec8357d02a52 |
children | 5a758be2769e |
line wrap: on
line source
#include "th_types.h" #include "th_args.h" #include "th_util.h" #include "th_string.h" #include "th_crypto.h" #define SET_BUF_SIZE 128 #define SET_MAX_TESTS 64 #define SET_SENTINEL_BYTE 0x0e5 // Globals char *test_str_header = NULL, *test_str_res = NULL; int tests_failed, tests_passed, tests_total, tests_sets, tests_nenabled; int tests_enabled[SET_MAX_TESTS]; char buf1[SET_BUF_SIZE+2], buf2[SET_BUF_SIZE+2]; // Define option arguments static const th_optarg_t arg_opts[] = { { 0, '?', "help", "Show this help", OPT_NONE }, { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, { 2, 't', "tests", "Perform tests -t <set>[,<set2>..]", OPT_ARGREQ }, }; static const int arg_nopts = sizeof(arg_opts) / sizeof(arg_opts[0]); void arg_show_help(void) { th_print_banner(stdout, th_prog_name, "[options]"); th_args_help(stdout, arg_opts, arg_nopts, 0); } BOOL arg_handle_opt(const int optN, char *optArg, char *currArg) { switch (optN) { case 0: arg_show_help(); exit(0); break; case 1: th_verbosityLevel++; break; case 2: { BOOL ret = TRUE; char *pos, *pstr, *next; pos = pstr = th_strdup(optArg); memset(tests_enabled, 0, sizeof(tests_enabled)); do { next = strchr(pos, ','); if (next != NULL) *next = 0; char *tmp = th_strdup_trim(pos, TH_TRIM_BOTH); if (tmp != NULL) { int val = atoi(tmp); if (val > 0 && val <= SET_MAX_TESTS) tests_enabled[val - 1] = 1; else { THERR("Invalid test number #%d, out of range [%d .. %d]\n", val, 1, SET_MAX_TESTS); ret = FALSE; } th_free(tmp); } if (next != NULL) pos = next + 1; } while (next != NULL); th_free(pstr); return ret; } break; default: THERR("Unknown option '%s'.\n", currArg); return FALSE; } return TRUE; } void test_start_v(const char *fmt, va_list ap) { tests_total++; th_free_r(&test_str_header); th_free_r(&test_str_res); test_str_header = th_strdup_vprintf(fmt, ap); } void test_start(const char *fmt, ...) { va_list ap; va_start(ap, fmt); test_start_v(fmt, ap); va_end(ap); } void test_result_msg_v(BOOL check, const char *fmt, va_list ap) { if (check) { THPRINT(2, "%s: OK\n", test_str_header); tests_passed++; } else { THPRINT(0, "%s: FAIL\n", test_str_header); if (fmt != NULL) { THPRINT(0, " - "); THPRINT_V(0, fmt, ap); THPRINT(0, "\n"); } if (test_str_res != NULL) THPRINT(0, "%s\n", test_str_res); tests_failed++; } } void test_result_msg(BOOL check, const char *fmt, ...) { va_list ap; va_start(ap, fmt); test_result_msg_v(check, fmt, ap); va_end(ap); } void test_result(BOOL check) { test_result_msg_v(check, NULL, NULL); } void test_snprintf_do(size_t len, const char *fmt, va_list ap, const char *msg) { int ret1, ret2; va_list tmp; // Test basic *printf() functionality test_start("th_vsnprintf('%s', %s)", fmt, msg); memset(buf1, SET_SENTINEL_BYTE, SET_BUF_SIZE+2); buf1[SET_BUF_SIZE+1] = 0; memset(buf2, SET_SENTINEL_BYTE, SET_BUF_SIZE+2); buf2[SET_BUF_SIZE+1] = 0; va_copy(tmp, ap); ret1 = th_vsnprintf(buf1, len, fmt, ap); ret2 = vsnprintf(buf2, len, fmt, tmp); test_result_msg(ret1 == ret2, "retval mismatch %d != %d", ret1, ret2); test_result_msg(strcmp(buf1, buf2) == 0, "result mismatch '%s' != '%s'", buf1, buf2); test_result_msg((unsigned char) buf1[len] == SET_SENTINEL_BYTE, "buffer #1 overflow, sentinel 0x%02x", buf1[len]); test_result_msg((unsigned char) buf2[len] == SET_SENTINEL_BYTE, "buffer #2 overflow, sentinel 0x%02x", buf2[len]); // Test th_strdup_vprintf() test_start("th_strdup_vprintf('%s')", fmt); char *str = th_strdup_vprintf(fmt, ap); test_result_msg(str != NULL, "result NULL"); th_free(str); } void test_snprintf(const char *fmt, ...) { va_list ap, tmp; va_start(ap, fmt); va_copy(tmp, ap); test_snprintf_do(0, fmt, tmp, "0"); va_copy(tmp, ap); test_snprintf_do(1, fmt, tmp, "1"); va_copy(tmp, ap); test_snprintf_do(2, fmt, tmp, "2"); va_copy(tmp, ap); test_snprintf_do(16, fmt, tmp, "16"); va_copy(tmp, ap); test_snprintf_do(SET_BUF_SIZE, fmt, tmp, "SET_BUF_SIZE"); va_end(ap); THPRINT(2, "-----------------------------------------------------\n"); } BOOL test_set_start(const char *str) { if (tests_enabled[tests_sets++]) { tests_nenabled++; THPRINT(1, "======================================================\n" " Set #%d : %s tests\n" "======================================================\n", tests_sets, str); return TRUE; } else return FALSE; } #define TEST2(fun, str1, str2, ret) do { \ test_start(# fun "('%s', '%s')", str1, str2); \ test_result(( fun (str1, str2) == 0) == ret); \ } while (0) #define TEST2B(fun, str1, str2, ret) do { \ test_start(# fun "('%s', '%s')", str1, str2); \ test_result( fun (str1, str2) == ret); \ } while (0) #define TEST3(fun, str1, str2, len, ret) do { \ test_start(# fun "('%s', '%s', %d)", str1, str2, len); \ test_result(( fun (str1, str2, len) == 0) == ret); \ } while (0) int main(int argc, char *argv[]) { size_t i1, i2; // // Initialization // th_init("th-test", "th-libs unit tests", "0.0.1", NULL, NULL); th_verbosityLevel = 0; if (sizeof(char) != sizeof(unsigned char)) { THERR("sizeof(char) != sizeof(unsigned char)???\n"); return -1; } tests_failed = tests_passed = tests_total = tests_sets = tests_nenabled = 0; for (i1 = 0; i1 < SET_MAX_TESTS; i1++) tests_enabled[i1] = 1; // // Parse command line arguments // if (!th_args_process(argc, argv, arg_opts, arg_nopts, arg_handle_opt, NULL, 0)) return 0; // // Test series #1 // if (test_set_start("printf() integer")) { int i_vals[] = { 2, 612342, -2, -612342, 0x1fff, 0x8000000, }; char *i_fmts[] = { "%d", "%x", "%05d", "%5d", "%-5d", "%05x", "%5x", "", "% 3d", "% 3o", "%+3o", "%+3d", }; for (i1 = 0; i1 < sizeof(i_vals) / sizeof(i_vals[0]); i1++) for (i2 = 0; i2 < sizeof(i_fmts) / sizeof(i_fmts[0]); i2++) test_snprintf(i_fmts[i2], i_vals); } if (test_set_start("printf() float")) { int f_vals[] = { 2.02, 612342.234, -2.07, -612342.12, 0x1fff, 0x8000000, }; char *f_fmts[] = { "%f", "%1.1f", "%5.5f", "%5f", "%-5f", "", }; for (i1 = 0; i1 < sizeof(f_vals) / sizeof(f_vals[0]); i1++) for (i2 = 0; i2 < sizeof(f_fmts) / sizeof(f_fmts[0]); i2++) test_snprintf(f_fmts[i2], f_vals); } if (test_set_start("printf() string")) { char *s_vals[] = { "", "XYZXYZ", "xxx yyy zzz ppp fff", NULL, "X", "abcde", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", }; char *s_fmts[] = { "%s", "%2s", "%-2s", "%5s", "%-5s", "%16s", "%-16s", "%1s", "%-1s", "% 2s", "%03s", "% -12s", "% 03s", }; for (i1 = 0; i1 < sizeof(s_vals) / sizeof(s_vals[0]); i1++) for (i2 = 0; i2 < sizeof(s_fmts) / sizeof(s_fmts[0]); i2++) test_snprintf(s_fmts[i2], s_vals); } if (test_set_start("printf() char")) { test_snprintf("a%cBC", 'x'); test_snprintf("%c", 'x'); test_snprintf("", 'x'); test_snprintf("%0c", 'x'); test_snprintf("%1c", 'x'); test_snprintf("% c", 'x'); test_snprintf("%-3c", 'x'); test_snprintf("%3c", 'x'); } // // String matching functions // if (test_set_start("String matching #1")) { TEST2(th_strcasecmp, "aSdFq", "asdfq", TRUE); TEST2(th_strcasecmp, "aSdFq", "asFfq", FALSE); TEST2(th_strcasecmp, "abcde", "abcde", TRUE); TEST2(th_strcasecmp, "öäå", "öäå", TRUE); TEST2(th_strcasecmp, "aöäå", "aöäå", TRUE); } if (test_set_start("String matching #2")) { TEST3(th_strncasecmp, "aSdFq", "asFfq", 4, FALSE); TEST3(th_strncasecmp, "aSdFq", "asFfq", 2, TRUE); TEST3(th_strncasecmp, "aSdFq", "asDfq", 3, TRUE); TEST3(th_strncasecmp, "aSdFq", "asDfq", 2, TRUE); TEST3(th_strncasecmp, "aSdFq", "asDfq", 0, TRUE); TEST3(th_strncasecmp, "aSdFq", "QsDfq", 0, TRUE); TEST3(th_strncasecmp, "aSdFq", "QsDfq", 1, FALSE); } if (test_set_start("String matching #3")) { TEST2B(th_strmatch, "abba ABBAkukka lol", "*lol", TRUE); TEST2B(th_strmatch, "abba ABBAkukka lol", "*lo*", TRUE); TEST2B(th_strmatch, "abba ABBAkukka lol", "*lo", FALSE); TEST2B(th_strmatch, "abba ABBAkukka lol", "abba", FALSE); TEST2B(th_strmatch, "abba ABBAkukka lol", "abba*", TRUE); TEST2B(th_strmatch, "abba ABBAkukka lol", "abbak*", FALSE); TEST2B(th_strmatch, "abba ABBAöökukka lol", "*abbaö?", FALSE); } if (test_set_start("String matching #4")) { TEST2B(th_strcasematch, "abba ABBAkukka lol", "abbak*", FALSE); TEST2B(th_strcasematch, "abba ABBAkukka lol", "*abbak*", TRUE); TEST2B(th_strcasematch, "abba ABBAkukka lol", "*abbak?", FALSE); TEST2B(th_strcasematch, "abba ABBAkukka lol", "?bba?abba*", TRUE); } // Tests that test for things that do not work correctly yet // Unicode / multibyte UTF-8 causes problems here if (test_set_start("Invalid")) { TEST2(th_strcasecmp, "ÖÄÅ", "öäå", FALSE); // SHOULD match TEST3(th_strncasecmp, "Aäöå", "aöå", 2, TRUE); // should NOT match TEST2B(th_strmatch, "öriÖRI! lol", "?ri?RI!*", FALSE); // should match } // // Print summary and exit // THPRINT(1, "======================================================\n"); THPRINT(0, "%d tests failed, %d passed (%d main tests), %d test sets of %d sets total.\n", tests_failed, tests_passed, tests_total, tests_nenabled, tests_sets); return 0; }