view tests.c @ 291:886a42023415

Cosmetics.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 22 Feb 2016 16:00:55 +0200
parents 56b0de9f9d44
children 146cfd1dc744
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_SENTINEL_BYTE 0x0e5


// Globals
char *test_str_header = NULL,
     *test_str_res = NULL;

int tests_failed, tests_passed, tests_total, tests_set;

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 },
};

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;

    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");
}


void tests_header(const char *str)
{
    THPRINT(1,
        "======================================================\n"
        " Set #%d : %s tests\n"
        "======================================================\n",
        ++tests_set,
        str);
}


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); \
    } 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)

    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);

    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);

    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);

    // 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


    //
    // 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);

    return 0;
}