# HG changeset patch # User Matti Hamalainen # Date 1456149745 -7200 # Node ID 146cfd1dc744010799146f11d7e976c2c3c4a68f # Parent 54032f17c7e5c2474968334e0a80c6d019fadf05# Parent 01e7edd68075cf1ef8a33dc5332563990a5fbd8d Merged. diff -r 54032f17c7e5 -r 146cfd1dc744 tests.c --- a/tests.c Mon Feb 22 16:01:04 2016 +0200 +++ b/tests.c Mon Feb 22 16:02:25 2016 +0200 @@ -5,6 +5,7 @@ #include "th_crypto.h" #define SET_BUF_SIZE 128 +#define SET_MAX_TESTS 64 #define SET_SENTINEL_BYTE 0x0e5 @@ -12,7 +13,8 @@ char *test_str_header = NULL, *test_str_res = NULL; -int tests_failed, tests_passed, tests_total, tests_set; +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]; @@ -22,6 +24,7 @@ { { 0, '?', "help", "Show this help", OPT_NONE }, { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 2, 't', "tests", "Perform tests -t [,..]", OPT_ARGREQ }, }; static const int arg_nopts = sizeof(arg_opts) / sizeof(arg_opts[0]); @@ -47,6 +50,40 @@ 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; + 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; @@ -133,7 +170,7 @@ 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]); @@ -160,69 +197,24 @@ } -void tests_header(const char *str) +BOOL test_set_start(const char *str) { - THPRINT(1, - "======================================================\n" - " Set #%d : %s tests\n" - "======================================================\n", - ++tests_set, - 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; } -int main(int argc, char *argv[]) -{ - // - // 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_set = 0; - - // - // Parse command line arguments - // - if (!th_args_process(argc, argv, arg_opts, arg_nopts, - arg_handle_opt, NULL, 0)) - return 0; - - - // - // Test series #1 - // - tests_header("printf() function family"); - int i_vals[] = { 2, 612342, -2, -612342, 0x1fff, 0x8000000, }; - char *i_fmts[] = { "%d", "%x", "%05d", "%5d", "%-5d", "%05x", "%5x", "", }; - size_t i1, i2; - - 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); - - char *s_vals[] = { "", "asdf", "xxx yyy zzz ppp fff", NULL, "X", "abcde", }; - char *s_fmts[] = { "%s", "%2s", "%-2s", "%5s", "%-5s", "%16s", "%-16s", "%1s", "%-1s", }; - - 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); - - test_snprintf("a%cBC", 'x'); - test_snprintf("%c", 'x'); - test_snprintf("", 'x'); - - // - // String matching functions - // - tests_header("String matching"); - #define TEST2(fun, str1, str2, ret) do { \ test_start(# fun "('%s', '%s')", str1, str2); \ test_result(( fun (str1, str2) == 0) == ret); \ @@ -238,50 +230,132 @@ test_result(( fun (str1, str2, len) == 0) == ret); \ } while (0) - 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); + + +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() function family #1")) + { + 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() function family #2")) + { + 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); + + } - 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("printf() function family #3")) + { + 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); + } - 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_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); - TEST2B(th_strmatch, "abba ABBAöökukka lol", "*abbaö?", FALSE); + 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 - tests_header("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 - + 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.\n", - tests_failed, tests_passed, tests_total, tests_set); + "%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; } diff -r 54032f17c7e5 -r 146cfd1dc744 th_string.c --- a/th_string.c Mon Feb 22 16:01:04 2016 +0200 +++ b/th_string.c Mon Feb 22 16:02:25 2016 +0200 @@ -124,9 +124,21 @@ // // Simple implementations of printf() type functions // -static int th_vput_int(th_printf_ctx *ctx, int (*vputch)(th_printf_ctx *ctx, const char ch), +static int th_printf_vput_pad(th_printf_ctx *ctx, th_printf_vputch vputch, int nwidth, const char padChar) +{ + while (nwidth--) + { + int ret; + if ((ret = vputch(ctx, padChar)) == EOF) + return ret; + } + return 0; +} + + +static int th_printf_vput_int(th_printf_ctx *ctx, th_printf_vputch vputch, int pval, const int radix, const char padMode, const char padChar, - const int width, const BOOL unsig, const BOOL upcase, const BOOL sign) + const int f_width, const BOOL unsig, const BOOL upcase, const BOOL f_sign) { char buf[64]; size_t pos = 0; @@ -165,23 +177,17 @@ // Do we want a sign prefix? Not for unsigned values if (!unsig) { - char ch = sign ? (neg ? '-' : '+') : (neg ? '-' : 0); + char ch = f_sign ? (neg ? '-' : '+') : (neg ? '-' : 0); if (ch && (ret = vputch(ctx, ch)) == EOF) goto out; } // Calculate necessary padding, if any - int nwidth = width - pos; + int nwidth = f_width - pos; // Prefix padding? - if (padMode != '-' && nwidth > 0) - { - while (nwidth--) - { - if ((ret = vputch(ctx, padMode)) == EOF) - goto out; - } - } + if (padMode != '-' && nwidth > 0 && (ret = th_printf_vput_pad(ctx, vputch, nwidth, padMode)) == EOF) + goto out; // Output the value while (pos--) @@ -191,23 +197,17 @@ } // Postfix padding? - if (padMode == '-' && nwidth > 0) - { - while (nwidth--) - { - if ((ret = vputch(ctx, ' ')) == EOF) - goto out; - } - } + if (padMode == '-' && nwidth > 0 && (ret = th_printf_vput_pad(ctx, vputch, nwidth, ' ')) == EOF) + goto out; out: return ret; } -static int th_vput_str(th_printf_ctx *ctx, int (*vputch)(th_printf_ctx *ctx, const char ch), +static int th_printf_vput_str(th_printf_ctx *ctx, th_printf_vputch vputch, const char *str, const char padMode, const char padChar, - const int width, const int prec) + const int f_width, const int f_prec) { int nwidth, ret = 0; @@ -215,17 +215,11 @@ if (str == NULL) str = "(null)"; - nwidth = width - strlen(str); + nwidth = f_width - strlen(str); // Prefix padding? - if (padMode != '-' && nwidth > 0) - { - while (nwidth--) - { - if ((ret = vputch(ctx, padMode)) == EOF) - goto out; - } - } + if (padMode != '-' && nwidth > 0 && (ret = th_printf_vput_pad(ctx, vputch, nwidth, padMode)) == EOF) + goto out; while (*str) { @@ -234,23 +228,15 @@ } // Postfix padding? - if (padMode == '-' && nwidth > 0) - { - while (nwidth--) - { - if ((ret = vputch(ctx, ' ')) == EOF) - goto out; - } - } + if (padMode == '-' && nwidth > 0 && (ret = th_printf_vput_pad(ctx, vputch, nwidth, ' ')) == EOF) + goto out; out: return ret; } -int th_vprintf_do(th_printf_ctx *ctx, - int (*vputch)(th_printf_ctx *ctx, const char ch), - const char *fmt, va_list ap) +int th_vprintf_do(th_printf_ctx *ctx, th_printf_vputch vputch, const char *fmt, va_list ap) { int ret = 0; @@ -264,15 +250,15 @@ else { char padMode = ' ', padChar = 0; - BOOL sign = FALSE; - int width = 0, prec = -1; + int f_width = 0, f_prec = -1; + BOOL f_sign = FALSE; fmt++; - // Check sign + // Check for field sign if (*fmt == '+') { - sign = TRUE; + f_sign = TRUE; fmt++; } @@ -292,9 +278,9 @@ return -102; } - // Get width + // Get field width while (th_isdigit(*fmt)) - width = width * 10 + (*fmt++ - '0'); + f_width = f_width * 10 + (*fmt++ - '0'); // Check for precision if (*fmt == '.') @@ -303,9 +289,20 @@ if (!th_isdigit(*fmt)) return -103; - prec = 0; + f_prec = 0; while (th_isdigit(*fmt)) - prec = prec * 10 + (*fmt++ - '0'); + f_prec = f_prec * 10 + (*fmt++ - '0'); + } + // Check for length modifiers (NOT SUPPORTED CURRENTLY) + switch (*fmt) + { + case 'l': + case 'L': + case 'h': + case 'j': + case 'z': + case 't': + return -202; } switch (*fmt) @@ -314,7 +311,7 @@ return -104; case 'c': - if (padMode != ' ' || width > 0 || prec >= 0 || sign) + if (padMode != ' ' || f_width > 0 || f_prec >= 0 || f_sign) return -105; if ((ret = vputch(ctx, va_arg(ap, int))) == EOF) @@ -323,21 +320,21 @@ case 'u': case 'd': - if ((padMode != '0' && padMode != '-' && padMode != ' ') || prec >= 0) + if ((padMode != '0' && padMode != '-' && padMode != ' ') || f_prec >= 0) return -105; - if ((ret = th_vput_int(ctx, vputch, va_arg(ap, unsigned int), - 10, padMode, padChar, width, *fmt == 'u', FALSE, sign)) == EOF) + if ((ret = th_printf_vput_int(ctx, vputch, va_arg(ap, unsigned int), + 10, padMode, padChar, f_width, *fmt == 'u', FALSE, f_sign)) == EOF) goto out; break; case 'x': case 'X': - if ((padMode != '0' && padMode != '-' && padMode != ' ') || prec >= 0) + if ((padMode != '0' && padMode != '-' && padMode != ' ') || f_prec >= 0) return -106; - if ((ret = th_vput_int(ctx, vputch, va_arg(ap, unsigned int), - 16, padMode, padChar, width, TRUE, *fmt == 'X', FALSE)) == EOF) + if ((ret = th_printf_vput_int(ctx, vputch, va_arg(ap, unsigned int), + 16, padMode, padChar, f_width, TRUE, *fmt == 'X', FALSE)) == EOF) goto out; break; @@ -346,14 +343,14 @@ break; case 's': - if ((padMode != '-' && padMode != ' ') || sign) + if ((padMode != '-' && padMode != ' ') || f_sign) return -108; - if ((ret = th_vput_str(ctx, vputch, va_arg(ap, char *), padMode, padChar, width, prec)) == EOF) + if ((ret = th_printf_vput_str(ctx, vputch, va_arg(ap, char *), padMode, padChar, f_width, f_prec)) == EOF) goto out; break; - case '%': + //case '%': default: if ((ret = vputch(ctx, *fmt)) == EOF) goto out; @@ -364,7 +361,7 @@ } out: - return ret == EOF ? ret : ctx->pos; + return ret == EOF ? ret : ctx->ipos; } @@ -373,7 +370,9 @@ { if (ctx->pos < ctx->size) ctx->buf[ctx->pos] = ch; + ctx->pos++; + ctx->ipos++; return ch; } @@ -381,6 +380,7 @@ static int th_stdio_vputch(th_printf_ctx *ctx, const char ch) { ctx->pos++; + ctx->ipos++; return fputc(ch, (FILE *) ctx->data); } #endif @@ -394,6 +394,7 @@ ctx.buf = buf; ctx.size = size; ctx.pos = 0; + ctx.ipos = 0; ret = th_vprintf_do(&ctx, th_pbuf_vputch, fmt, ap); @@ -431,6 +432,7 @@ th_printf_ctx ctx; ctx.data = (void *) fh; ctx.pos = 0; + ctx.ipos = 0; return th_vprintf_do(&ctx, th_stdio_vputch, fmt, ap); #else @@ -450,6 +452,8 @@ #ifdef TH_USE_INTERNAL_SPRINTF ctx.data = (void *) fh; ctx.pos = 0; + ctx.ipos = 0; + ret = th_vprintf_do(&ctx, th_stdio_vputch, fmt, ap); #else ret = fprintf(fh, fmt, ap); @@ -552,7 +556,7 @@ { int k = th_tolower(*s1) - th_tolower(*s2); if (k != 0) - return k; + return k; s1++; s2++; } @@ -574,7 +578,7 @@ { int k = th_tolower(*s1) - th_tolower(*s2); if (k != 0) - return k; + return k; s1++; s2++; n--; diff -r 54032f17c7e5 -r 146cfd1dc744 th_string.h --- a/th_string.h Mon Feb 22 16:01:04 2016 +0200 +++ b/th_string.h Mon Feb 22 16:02:25 2016 +0200 @@ -52,10 +52,14 @@ { char *buf; size_t size, pos; + int ipos; void *data; } th_printf_ctx; +typedef int (*th_printf_vputch)(th_printf_ctx *ctx, const char ch); + + /* Normal NUL-terminated string functions */ size_t th_strlen(const char *str);