Mercurial > hg > th-libs
view tests.c @ 638:c4bca120bfb0
Cleanups.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 21 Jan 2020 12:23:59 +0200 |
parents | d191ded8a790 |
children | 9e1f9e1d1487 |
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" #include "th_config.h" #include "th_regex.h" #define SET_BUF_SIZE 128 #define SET_BUF_SIZE_2 ((SET_BUF_SIZE) + 32) #define SET_MAX_TESTS 64 #define SET_SENTINEL_BYTE 0x0e5 #define NCOUNT(xxx) (sizeof(xxx) / sizeof(xxx[0])) enum { TST_SUPERFLUOUS = 0x0001, TST_CORNERCASE = 0x0002, TST_OVERFLOW = 0x0004, TST_BROKEN = 0x1000, TST_ALL = 0xffff, }; typedef struct { char *header; BOOL shown, // Has test result value been shown? failed; // Did the test fail? (used by some tests to show extra info) } test_ctx; // Global variables int tests_failed, // Total number of tests failed tests_passed, // Total number of tests passed tests_total, // Total number of tests RUN sets_total, // Number of test sets sets_nenabled; // Number of test sets enabled int sets_enabled[SET_MAX_TESTS]; char buf1[SET_BUF_SIZE_2], buf2[SET_BUF_SIZE_2]; int optFlags = TST_ALL; // Define option arguments static const th_optarg arg_opts[] = { { 0, '?', "help" , NULL, "Show this help", OPT_NONE }, { 1, 'v', "verbose" , NULL, "Be more verbose", OPT_NONE }, { 2, 's', "sets" , "sets", "Perform test sets -s <set>[,<set2>..]", OPT_ARGREQ }, { 3, 't', "tests" , "tests", "Perform only tests (see below)", OPT_ARGREQ }, }; static const int arg_nopts = sizeof(arg_opts) / sizeof(arg_opts[0]); BOOL tprintv(const int level, const char *fmt, va_list ap) { if (level <= th_verbosity) { vfprintf(stdout, fmt, ap); return TRUE; } else return FALSE; } BOOL tprint(const int level, const char *fmt, ...) { BOOL retv; va_list ap; va_start(ap, fmt); retv = tprintv(level, fmt, ap); va_end(ap); return retv; } void arg_show_help(void) { th_print_banner(stdout, th_prog_name, "[options]"); th_args_help(stdout, arg_opts, arg_nopts, 0, 80 - 2); } BOOL arg_handle_opt(const int optN, char *optArg, char *currArg) { switch (optN) { case 0: arg_show_help(); exit(0); break; case 1: th_verbosity++; break; case 2: { BOOL ret = TRUE; char *pos, *pstr, *next; pos = pstr = th_strdup(optArg); memset(sets_enabled, 0, sizeof(sets_enabled)); do { if ((next = strchr(pos, ',')) != 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) sets_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; case 3: optFlags = atoi(optArg); break; default: THERR("Unknown option '%s'.\n", currArg); return FALSE; } return TRUE; } void test_end(test_ctx *ctx) { th_free_r(&ctx->header); } void test_start_v(test_ctx *ctx, const char *fmt, va_list ap) { tests_total++; memset(ctx, 0, sizeof(test_ctx)); ctx->header = th_strdup_vprintf(fmt, ap); } void test_start(test_ctx *ctx, const char *fmt, ...) { va_list ap; va_start(ap, fmt); test_start_v(ctx, fmt, ap); va_end(ap); } void test_result_msg_v(test_ctx *ctx, BOOL check, const char *fmt, va_list ap) { if (check) { if (!ctx->shown && tprint(2, "%s: OK\n", ctx->header)) ctx->shown = TRUE; tests_passed++; } else { if (!ctx->shown && tprint(0, "%s: FAIL\n", ctx->header)) ctx->shown = TRUE; if (fmt != NULL) { tprint(0, " - "); tprintv(0, fmt, ap); tprint(0, "\n"); } tests_failed++; ctx->failed = TRUE; } } BOOL test_result_msg(test_ctx *ctx, BOOL check, const char *fmt, ...) { va_list ap; va_start(ap, fmt); test_result_msg_v(ctx, check, fmt, ap); va_end(ap); return check; } BOOL test_result(test_ctx *ctx, BOOL check) { test_result_msg_v(ctx, check, NULL, NULL); return check; } void test_snprintf_do(size_t len, const char *msg, const char *fmt, va_list ap) { int ret1, ret2; va_list tmp; test_ctx ctx; // Setup printf debug value th_printf_debug = th_verbosity >= 3; th_printf_debug_prefix = " - "; // Test basic *printf() functionality test_start(&ctx, "th_vsnprintf(buflen=%" PRIu_SIZE_T ", \"%s\", %s)", len, fmt, msg); memset(buf1, SET_SENTINEL_BYTE, SET_BUF_SIZE_2); buf1[SET_BUF_SIZE_2-1] = 0; memset(buf2, SET_SENTINEL_BYTE, SET_BUF_SIZE_2); buf2[SET_BUF_SIZE_2-1] = 0; va_copy(tmp, ap); ret1 = th_vsnprintf(buf1, len, fmt, tmp); va_copy(tmp, ap); ret2 = vsnprintf(buf2, len, fmt, tmp); test_result_msg(&ctx, ret1 == ret2, "retval mismatch %d [th] != %d [libc]", ret1, ret2); test_result_msg(&ctx, strcmp(buf1, buf2) == 0, "result mismatch '%s' [th] != '%s' [libc]", buf1, buf2); if (optFlags & TST_OVERFLOW) { test_result_msg(&ctx, (unsigned char) buf1[len] == SET_SENTINEL_BYTE, "buffer #1 overflow, sentinel 0x%02x", buf1[len]); test_result_msg(&ctx, (unsigned char) buf2[len] == SET_SENTINEL_BYTE, "buffer #2 overflow, sentinel 0x%02x", buf2[len]); } if (ctx.failed && !th_printf_debug && th_verbosity >= 1) { th_printf_debug = TRUE; va_copy(tmp, ap); ret1 = th_vsnprintf(buf1, len, fmt, tmp); va_copy(tmp, ap); ret2 = vsnprintf(buf2, len, fmt, tmp); } test_end(&ctx); } void test_snprintf(const char *msg, const char *fmt, ...) { test_ctx ctx; va_list ap, tmp; va_start(ap, fmt); if (optFlags & TST_CORNERCASE) { va_copy(tmp, ap); test_snprintf_do(0, msg, fmt, tmp); va_copy(tmp, ap); test_snprintf_do(1, msg, fmt, tmp); va_copy(tmp, ap); test_snprintf_do(2, msg, fmt, tmp); va_copy(tmp, ap); test_snprintf_do(16, msg, fmt, tmp); } va_copy(tmp, ap); test_snprintf_do(SET_BUF_SIZE, msg, fmt, tmp); // Test th_strdup_vprintf() if (optFlags & TST_SUPERFLUOUS) { test_start(&ctx, "th_strdup_vprintf('%s')", fmt); va_copy(tmp, ap); char *str = th_strdup_vprintf(fmt, tmp); test_result_msg(&ctx, str != NULL, "result NULL"); th_free(str); test_end(&ctx); } va_end(ap); tprint(2, "-----------------------------------------------------\n"); } BOOL test_set_start(const char *str) { if (sets_enabled[sets_total++]) { sets_nenabled++; tprint(1, "======================================================\n" " Set #%d : %s tests\n" "======================================================\n", sets_total, str); return TRUE; } else return FALSE; } #define TEST_ASSERT(xcond) do { \ if (!(xcond)) \ { \ THERR("Assertion '" # xcond "' failed.\n"); \ return -1; \ } \ } while (0) #define TEST1(fun) do { \ test_ctx ctx; \ test_start(&ctx, # fun ); \ test_result(&ctx, fun); \ test_end(&ctx); \ } while (0) #define TEST1A(fmt, fun, fcmp, fres) do { \ test_ctx ctx; \ test_start(&ctx, #fun " " #fcmp " " fmt " (" fmt ")", fres, fun); \ test_result(&ctx, fun fcmp fres ); \ test_end(&ctx); \ } while (0) #define TEST2(fun, str1, str2, ret) do { \ test_ctx ctx; \ test_start(&ctx, # fun "('%s', '%s')", str1, str2); \ test_result(&ctx, ( fun (str1, str2) == 0) == ret); \ test_end(&ctx); \ } while (0) #define TEST2B(fun, str1, str2, ret) do { \ test_ctx ctx; \ test_start(&ctx, # fun "('%s', '%s')", str1, str2); \ test_result(&ctx, fun (str1, str2) == ret); \ test_end(&ctx); \ } while (0) #define TEST2C(fun, str1, str2, ret) do { \ test_ctx ctx; \ test_start(&ctx, # fun "('%s', '%s')", str1, str2); \ test_result(&ctx, (fun (str1, str2) != NULL) == ret); \ test_end(&ctx); \ } while (0) #define TEST3(fun, str1, str2, len, ret) do { \ test_ctx ctx; \ test_start(&ctx, # fun "('%s', '%s', %d)", str1, str2, len); \ test_result(&ctx, ( fun (str1, str2, len) == 0) == ret); \ test_end(&ctx); \ } while (0) void test_config_values(th_cfgitem_t *cfg) { th_cfgitem_t *item; int nsubtest = 0; test_ctx ctx; test_start(&ctx, "Test configuration value search #%d", ++nsubtest); test_result(&ctx, (item = th_cfg_find(cfg, "inside_sect", "intval", -1)) != NULL && *item->v.val_int == 112); test_end(&ctx); test_start(&ctx, "Test configuration value search #%d", ++nsubtest); test_result(&ctx, (item = th_cfg_find(cfg, "another_sect", "boolval", -1)) != NULL && *item->v.val_bool); test_end(&ctx); test_start(&ctx, "Test configuration value search #%d", ++nsubtest); test_result(&ctx, th_cfg_find(cfg, "no_match", NULL, -1) == NULL); test_end(&ctx); test_start(&ctx, "Test configuration value search #%d", ++nsubtest); test_result(&ctx, th_cfg_find(cfg, NULL, "no_match", -1) == NULL); test_end(&ctx); test_start(&ctx, "Test configuration value search #%d", ++nsubtest); test_result(&ctx, (item = th_cfg_find(cfg, NULL, "hexval", -1)) != NULL && *item->v.val_uint == 0x11223344); test_end(&ctx); test_start(&ctx, "Test configuration value search #%d", ++nsubtest); test_result(&ctx, (item = th_cfg_find(cfg, NULL, "a_string_setting", -1)) != NULL && strcmp(*item->v.val_str, "v_str1") == 0); test_end(&ctx); } void test_config_free(th_llist_t *node) { th_free_r(&node->data); } void test_ioctx_error(th_ioctx *fh, const int val, const char *msg) { (void) fh; (void) val; tprint(0, "IOCTX ERROR: %s", msg); } void test_ioctx_msg(th_ioctx *fh, const int val, const char *msg) { (void) fh; (void) val; tprint(1, "IOCTX MSG: %s", msg); } int test_config_strcmp(const void *v1, const void *v2) { return strcmp((const char *) v1, (const char *) v2); } static const char *test_config_strings[] = { "zoo", "foo", "b\"ar", }; void test_config_read(th_cfgitem_t *cfg, const char *filename) { int nsubtest; th_ioctx *fh = NULL; test_ctx ctx; th_cfgitem_t *item; tprint(1, "Reading configuration from '%s'.\n", filename); // Attempt to read the previously written file if (th_io_fopen(&fh, &th_stdio_io_ops, filename, "r") != THERR_OK) { int err = th_get_error(); THERR("Could not open configuration file '%s', %d: %s\n", filename, err, th_error_str(err)); goto out; } th_io_set_handlers(fh, test_ioctx_error, test_ioctx_msg); th_cfg_read(fh, cfg); // Test read values against expected values test_config_values(cfg); // Additional tests item = th_cfg_find(cfg, NULL, "string_list", -1); test_result(&ctx, item != NULL); if (item != NULL) { static const char *nostr = "not to be found"; th_llist_t **plist = (th_llist_t **) item->v.list; for (nsubtest = 0; nsubtest < (int) NCOUNT(test_config_strings); nsubtest++) { test_start(&ctx, "Test configuration string list values #%d: '%s'", nsubtest + 1, test_config_strings[nsubtest]); test_result(&ctx, th_llist_find_func(*plist, test_config_strings[nsubtest], test_config_strcmp) != NULL); test_end(&ctx); } test_start(&ctx, "Test configuration string list values #%d: '%s'", ++nsubtest, nostr); test_result(&ctx, th_llist_find_func(*plist, nostr, test_config_strcmp) == NULL); test_end(&ctx); th_llist_free_func_node(*plist, test_config_free); *plist = NULL; } out: th_io_free(fh); } void test_config(void) { static const char *filename = "cfg.temp"; test_ctx ctx; th_ioctx *fh = NULL; th_cfgitem_t *sect1, *sect2, *cfg = NULL, *item; char *v_str1 = NULL; unsigned int v_uint1; int v_int1; BOOL v_bool1, v_bool2; th_llist_t *v_str_list = NULL; // Create v_str_list for (size_t n = 0; n < NCOUNT(test_config_strings); n++) th_llist_append(&v_str_list, th_strdup(test_config_strings[n])); // Create the configuration structure tprint(2, "Creating configuration structure\n"); sect1 = NULL; th_cfg_add_comment(§1, "A comment that\nspans multiple\nlines automatically"); th_cfg_add_string(§1, "a_string_setting", &v_str1, "v_str1"); th_cfg_add_comment(§1, "Hex triplet value setting"); th_cfg_add_hexvalue(§1, "hexval", &v_uint1, 0x11223344); th_cfg_add_comment(§1, "A boolean value"); th_cfg_add_bool(§1, "boolval", &v_bool1, FALSE); th_cfg_add_comment(§1, "A string list"); th_cfg_add_string_list(§1, "string_list", &v_str_list); th_cfg_add_section(&cfg, "general", sect1); sect1 = NULL; th_cfg_add_comment(§1, "Another section"); th_cfg_add_bool(§1, "boolval", &v_bool2, TRUE); sect2 = NULL; th_cfg_add_comment(§2, "Section inside a section"); th_cfg_add_int(§2, "intval", &v_int1, 112); th_cfg_add_section(§1, "inside_sect", sect2); th_cfg_add_section(&cfg, "another_sect", sect1); // Test ptr test_start(&ctx, "Test configuration string list ptr"); test_result(&ctx, (item = th_cfg_find(cfg, NULL, "string_list", -1)) != NULL && item->v.list == &v_str_list); test_end(&ctx); // Test value finding test_config_values(cfg); // Attempt to write the file if (th_io_fopen(&fh, &th_stdio_io_ops, filename, "w") != THERR_OK) { int err = th_get_error(); THERR("Could not create configuration to file '%s', %d: %s\n", filename, err, th_error_str(err)); goto out; } th_io_set_handlers(fh, test_ioctx_error, test_ioctx_msg); th_cfg_write(fh, cfg); th_io_free(fh); fh = NULL; // Test against written configuration file test_config_read(cfg, filename); // Test against manually edited configuration file test_config_read(cfg, "cfg.test01"); out: // Free the data for v_str_list th_io_free(fh); th_llist_free_func_node(v_str_list, test_config_free); v_str_list = NULL; } #ifdef TH_EXPERIMENTAL_REGEX typedef struct { th_regex_char *str; size_t nmatches; int flags; } test_regex_def; void test_regex_list(const test_regex_def *list, const th_regex_char *pattern) { th_regex_ctx *reg = NULL; int res; printf("========================================\n"); printf("pattern '%s'\n", pattern); if ((res = th_regex_compile(®, pattern)) != THERR_OK) { THERR("Regex compilation failed: %s\n", th_error_str(res)); goto out; } for (const test_regex_def *def = list; def->str != NULL; def++) { th_regex_match_node *matches = NULL; size_t nmatches; if ((res = th_regex_match(reg, def->str, &nmatches, &matches, -1, def->flags)) != THERR_OK) { THERR("Regex match returned error: %s\n", th_error_str(res)); goto out; } printf(" '%s': matched %" PRIu_SIZE_T " time(s), testresult=%s\n", def->str, nmatches, def->nmatches == nmatches ? "YES" : "NO"); for (th_regex_match_node *m = matches; m != NULL; m = (th_regex_match_node *) m->node.next) { char *tmp = th_strndup(def->str + m->start, m->len); printf(" match [%" PRIu_SIZE_T " ++ %" PRIu_SIZE_T "]: '%s'\n", m->start, m->len, tmp); th_free(tmp); } th_regex_free_matches(matches); } out: th_regex_free(reg); } #endif int main(int argc, char *argv[]) { size_t i1, i2, i3, i4; char buf[64], buf2[64]; // // Initialization // th_init("th-test", "th-libs unit tests", "0.2", NULL, NULL); th_verbosity = 0; TEST_ASSERT(sizeof(char) == sizeof(unsigned char)); TEST_ASSERT(sizeof(char) == 1); TEST_ASSERT(sizeof(uint16_t) == 2); TEST_ASSERT(sizeof(uint32_t) == 4); TEST_ASSERT(sizeof(uint64_t) == 8); tests_failed = tests_passed = tests_total = sets_total = sets_nenabled = 0; for (i1 = 0; i1 < SET_MAX_TESTS; i1++) sets_enabled[i1] = 1; // // Parse command line arguments // if (!th_args_process(argc, argv, arg_opts, arg_nopts, arg_handle_opt, NULL, 0)) return 0; tprint(1, "Enabled test types are 0x%04x.\n", optFlags); // // Test series for printf() // char *i_fmts[] = { "", "05", "6", ".4", "1.1", "1.0", "8.5", "08.5", "3", "2.1", "3", "1", "18", "018", ".0", "0" }; char *i_mods[] = { "", "-", "+", "#", " ", }; char *i_types[] = { "d", "u", "i", "x", "X", "o", }; if (test_set_start("printf() integer")) { int i_vals[] = { 0, -0, 1, -1, 10, -10, 512, -512, -1024, 612342, -612342, 0x1fff, 0x8000000, -123456789, 2147483647, -2147483648 }; for (i1 = 0; i1 < NCOUNT(i_vals); i1++) { snprintf(buf, sizeof(buf), "%d", i_vals[i1]); for (i4 = 0; i4 < NCOUNT(i_mods); i4++) for (i3 = 0; i3 < NCOUNT(i_types); i3++) for (i2 = 0; i2 < NCOUNT(i_fmts); i2++) { snprintf(buf2, sizeof(buf2), "%%%s%s%s", i_mods[i4], i_fmts[i2], i_types[i3]); test_snprintf(buf, buf2, i_vals[i1]); } } } if (test_set_start("printf() integer 64bit")) { int64_t i_vals64[] = { 0, -0, 1, -1, 10, -10, 512, -512, -1024, 612342, -612342, 0x1fff, 0x8000000, -123456789, 4294967295, -2147483648, 0x3342344341fff, 0x1f8000000, }; for (i1 = 0; i1 < NCOUNT(i_vals64); i1++) { snprintf(buf, sizeof(buf), "%" PRId64, i_vals64[i1]); for (i4 = 0; i4 < NCOUNT(i_mods); i4++) for (i3 = 0; i3 < NCOUNT(i_types); i3++) for (i2 = 0; i2 < NCOUNT(i_fmts); i2++) { snprintf(buf2, sizeof(buf2), "%%%s%sll%s", i_mods[i4], i_fmts[i2], i_types[i3]); test_snprintf(buf, buf2, i_vals64[i1]); } } } #ifdef TH_WIP_FLOAT_SUPPORT if (test_set_start("printf() float")) { double f_vals[] = { 0, 1, 2, 3, 2.02, 612342.234, -2.07, -612342.12, 437692.9876543219, 0x1fff, 0x8000000, 0.15625 }; char *f_fmts[] = { "%f", "%1.1f", "%8.5f", "%5f", "%-5f", "", "%-5.2f", "%08.5f" }; for (i1 = 0; i1 < NCOUNT(f_vals); i1++) { snprintf(buf, sizeof(buf), "%f", f_vals[i1]); for (i2 = 0; i2 < NCOUNT(f_fmts); i2++) test_snprintf(buf, f_fmts[i2], f_vals[i1]); } } #endif if (test_set_start("printf() string")) { char *s_vals[] = { "", "XYZXYZ", "xxx yyy zzz ppp fff", NULL, "X", "abcde", "dx", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", }; // char *s_fmts[] = { "%s", "%2s", "%-2s", "%5s", "%-5s", "%16s", "%-16s", "%1s", "%-1s", "% 2s", "%03s", "% -12s", "% 03s", "%-.15s", "%.8s" }; char *s_fmts[] = { "", "-" " ", "0", " 0", ".", "-.", }; int s_widths[] = { 0, 1, 2, 5, 16, }; for (i1 = 0; i1 < NCOUNT(s_vals); i1++) for (i2 = 0; i2 < NCOUNT(s_fmts); i2++) for (i3 = 0; i3 < NCOUNT(s_widths); i3++) { snprintf(buf, sizeof(buf), "%%%s%ds", s_fmts[i2], s_widths[i3]); test_snprintf(s_vals[i1], buf, s_vals[i1]); } } if (test_set_start("printf() char")) { const char c_val = 'x'; const char *c_msg = "x"; char *c_fmts[] = { "a%cBC", "%c", "", "%0c", "%1c", "% c", "%-3c", "%3c", "%.3c", "%-.3c", "%-3.3c", "%.c", "%05c", "%-05c", }; for (i1 = 0; i1 < NCOUNT(c_fmts); i1++) test_snprintf(c_msg, c_fmts[i1], c_val); } if (test_set_start("printf() pointers")) { char *p_fmts[] = { "%p", "%2p", "%.2p", "%03p", "%04p", "%-3p", "%0.3p", "%8p", "%32p", "%032p", "%-32p", "%-032p", "%16.8p", "%016.8p" }; void *p_vals[] = { NULL, (void *) 1, &p_fmts, }; for (i1 = 0; i1 < NCOUNT(p_vals); i1++) { snprintf(buf, sizeof(buf), "%p", p_vals[i1]); for (i2 = 0; i2 < NCOUNT(p_fmts); i2++) test_snprintf(buf, p_fmts[i2], p_vals[i1]); } } // // String matching functions // if (test_set_start("String compare #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 compare #2")) { TEST3(th_strncasecmp, "aSdFq", "asFfqB", 4, FALSE); TEST3(th_strncasecmp, "aSdFq", "asFfqQ", 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 compare #3")) { TEST2C(th_strrcasecmp, "foo aSdFq", " asdfq", TRUE); TEST2C(th_strrcasecmp, "aSdFq", " asdfq", FALSE); TEST2C(th_strrcasecmp, "foo aSdFq baz", "asdfq", FALSE); } if (test_set_start("String matching #1")) { 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", "*bba*", TRUE); 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 #2")) { TEST2B(th_strcasematch, "abba ABBAkukka lol", "abbak*", FALSE); TEST2B(th_strcasematch, "abba ABBAkukka lol", "*abbak*", TRUE); TEST2B(th_strcasematch, "abba ABBAkukka lol", "*ab?ak*", 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 ((optFlags & TST_BROKEN) && test_set_start("Invalid UTF-8 handling")) { 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 } // // printf() PRI* format specifiers, also a compile time test // if (test_set_start("PRI* specifiers")) { char tmp[32]; uint32_t u32 = 0xaabbccdd; uint64_t u64 = 0xaabbccdd11223344; size_t usiz = #if TH_ARCH == 32 0x11223344; #elif TH_ARCH == 64 0xaabbccdd11223344; #else # error Unsupported TH_ARCH value. #endif snprintf(tmp, sizeof(tmp), "%16" PRIx_SIZE_T "h", usiz); #if TH_ARCH == 32 TEST2(strcmp, tmp, "0000000011223344h", TRUE); #else TEST2(strcmp, tmp, "aabbccdd11223344h", TRUE); #endif snprintf(tmp, sizeof(tmp), "%08" PRIx32 "h", u32); TEST2(strcmp, tmp, "aabbccddh", TRUE); snprintf(tmp, sizeof(tmp), "%16" PRIx64 "h", u64); TEST2(strcmp, tmp, "aabbccdd11223344h", TRUE); } // // Configuration file handling // if (test_set_start("Configuration file handling")) { test_config(); } // // String functions // if (test_set_start("String functions")) { unsigned int tmpUint; TEST1(th_get_hex_triplet("0fac11", &tmpUint) == TRUE); TEST1A("0x%06x", tmpUint, ==, 0x0fac11); TEST1(th_get_hex_triplet("120fac11", &tmpUint) == TRUE); TEST1A("0x%06x", tmpUint, ==, 0x120fac11); TEST1(th_get_hex_triplet("x120fac11", &tmpUint) == FALSE); } // // Regular expressions // #ifdef TH_EXPERIMENTAL_REGEX if (test_set_start("Regular expressions")) { th_regex_ctx *reg = NULL; int res; #ifdef TH_EXPERIMENTAL_REGEX_DEBUG th_dbg_re_flags = TH_DBG_RE_MATCH; #endif #if 0 res = th_regex_compile(®, "z*k+abba fabboa? k{4} [gz]{1,2} foo(bar|zoo)?"); if (res != THERR_OK) printf("result: %s\n", th_error_str(res)); th_regex_free(reg); // { static const test_regex_def tlist[] = { { "abcfoabccg" , 1, 0 }, { "abcbcfoabccg" , 1, 0 }, { "abcbcfoabccgabcbcfoabccg" , 2, 0 }, { "ffdsafS abcbcfoabccg zasdf" , 1, 0 }, { NULL , 0, 0 } }; test_regex_list(tlist, "a(bc){1,2}fo[oab]*cc?g"); } { static const test_regex_def tlist[] = { { "abcfoabccg" , 1, 0 }, { "abcbcfoabccg" , 1, 0 }, { "abcbcfoabccgabcbcfoabccg" , 2, 0 }, { "ffdsafS abcbcfoabccg zasdf" , 0, 0 }, { NULL , 0, 0 } }; test_regex_list(tlist, "^a(bc){1,2}fo[oab]*cc?g"); } { static const test_regex_def tlist[] = { { "cg" , 1, 0 }, { "g" , 1, 0 }, { "" , 0, 0 }, { "c" , 0, 0 }, { NULL , 0, 0 } }; test_regex_list(tlist, "g$"); } #endif { static const test_regex_def tlist[] = { // { "zoobar" , 1, 0 }, { "zoo lol bar" , 1, 0 }, { "hoho zoo lol lol bar bar" , 1, 0 }, { NULL , 0, 0 } }; test_regex_list(tlist, "zoo.*?bar"); } } #endif // // Print summary and exit // tprint(1, "======================================================\n"); tprint(0, "%d tests failed, %d passed (%d main tests), %d test sets of %d sets total.\n\n", tests_failed, tests_passed, tests_total, sets_nenabled, sets_total); return 0; }