static void init_testfiles(void)
{
    struct dirent *dirent;
    unsigned i = 0;
    int expect = expected_testfiles;

    DIR *d = opendir(OBJDIR"/../test");
    fail_unless(!!d, "opendir");
    if (!d)
	return;
    testfiles = NULL;
    testfiles_n = 0;
    while ((dirent = readdir(d))) {
	if (strncmp(dirent->d_name, "clam", 4))
	    continue;
        i++;
	testfiles = cli_realloc(testfiles, i*sizeof(*testfiles));
	fail_unless(!!testfiles, "cli_realloc");
	testfiles[i-1] = strdup(dirent->d_name);
    }
    testfiles_n = i;
    if (get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
        expect--;
    expect -= skip_files();
    fail_unless_fmt(testfiles_n == expect, "testfiles: %d != %d", testfiles_n, expect);

    closedir(d);
}
END_TEST
#endif

static Suite *test_cl_suite(void)
{
    Suite *s = suite_create("cl_api");
    TCase *tc_cl = tcase_create("cl_dup");
    TCase *tc_cl_scan = tcase_create("cl_scan");
    char *user_timeout = NULL;
    int expect = expected_testfiles;
    suite_add_tcase (s, tc_cl);
    tcase_add_test(tc_cl, test_cl_free);
    tcase_add_test(tc_cl, test_cl_dup);
    tcase_add_test(tc_cl, test_cl_build);
    tcase_add_test(tc_cl, test_cl_debug);
    tcase_add_test(tc_cl, test_cl_retdbdir);
    tcase_add_test(tc_cl, test_cl_retver);
    tcase_add_test(tc_cl, test_cl_cvdfree);
    tcase_add_test(tc_cl, test_cl_statfree);
    tcase_add_test(tc_cl, test_cl_retflevel);
    tcase_add_test(tc_cl, test_cl_cvdhead);
    tcase_add_test(tc_cl, test_cl_cvdparse);
    tcase_add_test(tc_cl, test_cl_load);
    tcase_add_test(tc_cl, test_cl_cvdverify);
    tcase_add_test(tc_cl, test_cl_statinidir);
    tcase_add_test(tc_cl, test_cl_statchkdir);
    tcase_add_test(tc_cl, test_cl_settempdir);
    tcase_add_test(tc_cl, test_cl_strerror);

    suite_add_tcase(s, tc_cl_scan);
    tcase_add_checked_fixture (tc_cl_scan, engine_setup, engine_teardown);
#ifdef CHECK_HAVE_LOOPS
    if (get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
        expect--;
    expect -= skip_files();
    tcase_add_loop_test(tc_cl_scan, test_cl_scandesc, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanfile, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_callback, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_callback_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_callback, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_callback_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_handle, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_handle_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem_allscan, 0, expect);

    user_timeout = getenv("T");
    if (user_timeout) {
        int timeout = atoi(user_timeout);
        tcase_set_timeout(tc_cl_scan, timeout);
	printf("Using test case timeout of %d seconds set by user\n", timeout);
    } else {
	printf("Using default test timeout; alter by setting 'T' env var (in seconds)\n");
    }
#endif
    return s;
}
END_TEST
#endif

static Suite *test_cl_suite(void)
{
    Suite *s = suite_create("cl_api");
    TCase *tc_cl = tcase_create("cl_dup");
    TCase *tc_cl_scan = tcase_create("cl_scan");
    int expect = expected_testfiles;
    suite_add_tcase (s, tc_cl);
    tcase_add_test(tc_cl, test_cl_free);
    tcase_add_test(tc_cl, test_cl_dup);
    tcase_add_test(tc_cl, test_cl_build);
    tcase_add_test(tc_cl, test_cl_debug);
    tcase_add_test(tc_cl, test_cl_retdbdir);
    tcase_add_test(tc_cl, test_cl_retver);
    tcase_add_test(tc_cl, test_cl_cvdfree);
    tcase_add_test(tc_cl, test_cl_statfree);
    tcase_add_test(tc_cl, test_cl_retflevel);
    tcase_add_test(tc_cl, test_cl_cvdhead);
    tcase_add_test(tc_cl, test_cl_cvdparse);
    tcase_add_test(tc_cl, test_cl_load);
    tcase_add_test(tc_cl, test_cl_cvdverify);
    tcase_add_test(tc_cl, test_cl_statinidir);
    tcase_add_test(tc_cl, test_cl_statchkdir);
    tcase_add_test(tc_cl, test_cl_settempdir);
    tcase_add_test(tc_cl, test_cl_strerror);

    suite_add_tcase(s, tc_cl_scan);
    tcase_add_checked_fixture (tc_cl_scan, engine_setup, engine_teardown);
#ifdef CHECK_HAVE_LOOPS
    if (get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
        expect--;
    expect -= skip_files();
    tcase_add_loop_test(tc_cl_scan, test_cl_scandesc, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanfile, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_callback, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scandesc_callback_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_callback, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanfile_callback_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_handle, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_handle_allscan, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem, 0, expect);
    tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem_allscan, 0, expect);
#endif
    return s;
}
int main(void)
{
    int nf;
    Suite *s;
    SRunner *sr;

    cl_initialize_crypto();

    fpu_words  = get_fpu_endian();
  
    check_version_compatible();
    s = test_cl_suite();
    sr = srunner_create(s);
#ifdef CHECK_HAVE_LOOPS
    srunner_add_suite(sr, test_cli_suite());
#else
    printf("*** Warning ***: your check version is too old,\nseveral important tests will not execute\n");
#endif
    srunner_add_suite(sr, test_jsnorm_suite());
    srunner_add_suite(sr, test_str_suite());
    srunner_add_suite(sr, test_regex_suite());
    srunner_add_suite(sr, test_disasm_suite());
    srunner_add_suite(sr, test_uniq_suite());
    srunner_add_suite(sr, test_matchers_suite());
    srunner_add_suite(sr, test_htmlnorm_suite());
    srunner_add_suite(sr, test_bytecode_suite());


    srunner_set_log(sr, "test.log");
    if(freopen("test-stderr.log","w+",stderr) == NULL) {
	    fputs("Unable to redirect stderr!\n",stderr);
    }
    cl_debug();

    srunner_run_all(sr, CK_NORMAL);
    nf = srunner_ntests_failed(sr);
    if (nf)
	printf("NOTICE: Use the 'T' environment variable to adjust testcase timeout\n");
    srunner_free(sr);

#if HAVE_LIBXML2
    xmlCleanupParser();
#endif
    cl_cleanup_crypto();

    return (nf == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}