/* * Copyright (c) 2011 Red Hat, Inc. * * All rights reserved. * * Author: Angus Salkeld * * This file is part of libqb. * * libqb is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * libqb is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libqb. If not, see . */ #include "os_base.h" #include "check_common.h" #include #include #include const char *chars[] = { "0","1","2","3","4","5","6","7","8","9", "A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z", "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z", NULL, }; const char *chars2[] = { "0","1","2","3","4","5","6","7","8","9", "a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z", NULL, }; static char *notified_key = NULL; static void *notified_value = NULL; static void *notified_new_value = NULL; static void *notified_user_data = NULL; static int32_t notified_event = 0; static int32_t notified_event_prev = 0; static int32_t notified_events = 0; static void my_map_notification_iter(uint32_t event, char* key, void* old_value, void* value, void* user_data) { const char *p; void *data; qb_map_t *m = (qb_map_t *)user_data; qb_map_iter_t *it = qb_map_iter_create(m); notified_events++; for (p = qb_map_iter_next(it, &data); p; p = qb_map_iter_next(it, &data)) { printf("%s > %s\n", p, (char*) data); } qb_map_iter_free(it); } /* * create some entries * add a notifier * delete an entry * in the notifier iterate over the map. */ static void test_map_notifications_iter(qb_map_t *m) { int i; qb_map_put(m, "k1", "one"); qb_map_put(m, "k12", "two"); qb_map_put(m, "k34", "three"); ck_assert_int_eq(qb_map_count_get(m), 3); notified_events = 0; i = qb_map_notify_add(m, NULL, my_map_notification_iter, (QB_MAP_NOTIFY_DELETED | QB_MAP_NOTIFY_RECURSIVE), m); ck_assert_int_eq(i, 0); qb_map_rm(m, "k12"); ck_assert_int_eq(notified_events, 1); ck_assert_int_eq(qb_map_count_get(m), 2); } static void test_map_simple(qb_map_t *m, const char *name) { int i; const char *p; void *data; qb_map_iter_t *it; qb_map_put(m, "k1", "one"); qb_map_put(m, "k12", "two"); qb_map_put(m, "k34", "three"); ck_assert_int_eq(qb_map_count_get(m), 3); qb_map_put(m, "k3", "four"); ck_assert_int_eq(qb_map_count_get(m), 4); it = qb_map_iter_create(m); i = 0; for (p = qb_map_iter_next(it, &data); p; p = qb_map_iter_next(it, &data)) { printf("%25s(%d) %s > %s\n", name, i, p, (char*) data); i++; } qb_map_iter_free(it); ck_assert_int_eq(i, 4); ck_assert_str_eq(qb_map_get(m, "k34"), "three"); ck_assert_str_eq(qb_map_get(m, "k1"), "one"); ck_assert_str_eq(qb_map_get(m, "k12"), "two"); ck_assert_str_eq(qb_map_get(m, "k3"), "four"); qb_map_rm(m, "k12"); ck_assert_int_eq(qb_map_count_get(m), 3); qb_map_put(m, "9k", "nine"); qb_map_put(m, "k34", "not_three"); ck_assert_str_eq(qb_map_get(m, "k34"), "not_three"); ck_assert_int_eq(qb_map_count_get(m), 4); qb_map_destroy(m); } static int32_t my_traverse(const char *key, void *value, void *data) { ck_assert((*key) > 0); return QB_FALSE; } static int32_t check_order(const char *key, void *value, void *data) { int *o = (int*)data; ck_assert_str_eq(chars[*o], key); ck_assert_str_eq(chars[*o], value); (*o)++; return QB_FALSE; } static int32_t check_order2(const char *key, void *value, void *data) { int *o = (int*)data; ck_assert_str_eq(chars2[*o], key); ck_assert_str_eq(chars2[*o], value); (*o)++; return QB_FALSE; } static void test_map_search(qb_map_t* m) { int32_t i; int32_t removed; int order; char c[2]; const char *p; for (i = 0; chars[i]; i++) { qb_map_put(m, chars[i], chars[i]); } qb_map_foreach(m, my_traverse, NULL); ck_assert_int_eq(qb_map_count_get(m), (26*2 + 10)); order = 0; qb_map_foreach(m, check_order, &order); for (i = 0; i < 26; i++) { removed = qb_map_rm(m, chars[i + 10]); ck_assert(removed); } c[0] = '\0'; c[1] = '\0'; removed = qb_map_rm(m, c); ck_assert(!removed); qb_map_foreach(m, my_traverse, NULL); ck_assert_int_eq(qb_map_count_get(m), 26+10); order = 0; qb_map_foreach(m, check_order2, &order); for (i = 25; i >= 0; i--) { qb_map_put(m, chars[i + 10], chars[i + 10]); } order = 0; qb_map_foreach(m, check_order, &order); c[0] = '0'; p = qb_map_get(m, c); ck_assert(p && *p == *c); c[0] = 'A'; p = qb_map_get(m, c); ck_assert(p && *p == *c); c[0] = 'a'; p = qb_map_get(m, c); ck_assert(p && *p == *c); c[0] = 'z'; p = qb_map_get(m, c); ck_assert(p && *p == *c); c[0] = '!'; p = qb_map_get(m, c); ck_assert(p == NULL); c[0] = '='; p = qb_map_get(m, c); ck_assert(p == NULL); c[0] = '|'; p = qb_map_get(m, c); ck_assert(p == NULL); qb_map_destroy(m); } static void my_map_notification(uint32_t event, char* key, void* old_value, void* value, void* user_data) { notified_key = key; notified_value = old_value; notified_new_value = value; notified_user_data = user_data; notified_event_prev = notified_event; notified_event = event; } static void my_map_notification_2(uint32_t event, char* key, void* old_value, void* value, void* user_data) { } static void test_map_remove(qb_map_t *m) { const char * a, *b, *c, *d; int32_t i; int32_t removed; const char *remove_ch[] = {"o","m","k","j","i","g","f","e","d","b","a", NULL}; i = qb_map_notify_add(m, NULL, my_map_notification, (QB_MAP_NOTIFY_DELETED| QB_MAP_NOTIFY_REPLACED| QB_MAP_NOTIFY_RECURSIVE), m); ck_assert_int_eq(i, 0); for (i = 0; chars[i]; i++) { qb_map_put(m, chars[i], chars[i]); } a = "0"; qb_map_put(m, a, a); ck_assert(notified_key == chars[0]); ck_assert(notified_value == chars[0]); ck_assert(notified_user_data == m); notified_key = NULL; notified_value = NULL; notified_user_data = NULL; b = "5"; removed = qb_map_rm(m, b); ck_assert(removed); ck_assert(notified_key == chars[5]); ck_assert(notified_value == chars[5]); ck_assert(notified_user_data == m); notified_key = NULL; notified_value = NULL; notified_user_data = NULL; d = "1"; qb_map_put(m, d, d); ck_assert(notified_key == chars[1]); ck_assert(notified_value == chars[1]); ck_assert(notified_user_data == m); notified_key = NULL; notified_value = NULL; c = "2"; removed = qb_map_rm(m, c); ck_assert(removed); ck_assert(notified_key == chars[2]); ck_assert(notified_value == chars[2]); notified_key = NULL; notified_value = NULL; for (i = 0; remove_ch[i]; i++) { removed = qb_map_rm(m, remove_ch[i]); ck_assert(removed); } qb_map_destroy(m); } static void test_map_notifications_basic(qb_map_t *m) { int32_t i; /* with global notifier */ i = qb_map_notify_add(m, NULL, my_map_notification, (QB_MAP_NOTIFY_INSERTED| QB_MAP_NOTIFY_DELETED| QB_MAP_NOTIFY_REPLACED| QB_MAP_NOTIFY_RECURSIVE), m); ck_assert_int_eq(i, 0); notified_key = NULL; notified_value = NULL; notified_new_value = NULL; /* insert */ qb_map_put(m, "garden", "grow"); ck_assert_str_eq(notified_key, "garden"); ck_assert_str_eq(notified_new_value, "grow"); ck_assert(notified_user_data == m); /* update */ qb_map_put(m, "garden", "green"); ck_assert_str_eq(notified_key, "garden"); ck_assert_str_eq(notified_value, "grow"); ck_assert_str_eq(notified_new_value, "green"); ck_assert(notified_user_data == m); /* delete */ qb_map_rm(m, "garden"); ck_assert_str_eq(notified_key, "garden"); ck_assert_str_eq(notified_value, "green"); ck_assert(notified_user_data == m); /* no event with notifier removed */ i = qb_map_notify_del(m, NULL, my_map_notification, (QB_MAP_NOTIFY_INSERTED| QB_MAP_NOTIFY_DELETED| QB_MAP_NOTIFY_REPLACED| QB_MAP_NOTIFY_RECURSIVE)); ck_assert_int_eq(i, 0); notified_key = NULL; notified_value = NULL; notified_new_value = NULL; qb_map_put(m, "age", "67"); ck_assert(notified_key == NULL); ck_assert(notified_value == NULL); ck_assert(notified_new_value == NULL); /* deleting a non-existing notification */ i = qb_map_notify_del(m, "a", my_map_notification, (QB_MAP_NOTIFY_INSERTED| QB_MAP_NOTIFY_DELETED| QB_MAP_NOTIFY_REPLACED| QB_MAP_NOTIFY_RECURSIVE)); ck_assert_int_eq(i, -ENOENT); /* test uniquess */ qb_map_put(m, "fred", "null"); i = qb_map_notify_add(m, "fred", my_map_notification, QB_MAP_NOTIFY_REPLACED, m); ck_assert_int_eq(i, 0); i = qb_map_notify_add(m, "fred", my_map_notification, QB_MAP_NOTIFY_REPLACED, m); ck_assert_int_eq(i, -EEXIST); } /* test free'ing notifier * * input: * only one can be added * can only be added with NULL key (global) * output: * is the last notifier called (after deleted or replaced) * recursive is implicit */ static void test_map_notifications_free(qb_map_t *m) { int32_t i; i = qb_map_notify_add(m, "not global", my_map_notification, QB_MAP_NOTIFY_FREE, m); ck_assert_int_eq(i, -EINVAL); i = qb_map_notify_add(m, NULL, my_map_notification, QB_MAP_NOTIFY_FREE, m); ck_assert_int_eq(i, 0); i = qb_map_notify_add(m, NULL, my_map_notification_2, QB_MAP_NOTIFY_FREE, m); ck_assert_int_eq(i, -EEXIST); i = qb_map_notify_del_2(m, NULL, my_map_notification, QB_MAP_NOTIFY_FREE, m); ck_assert_int_eq(i, 0); i = qb_map_notify_add(m, NULL, my_map_notification, (QB_MAP_NOTIFY_FREE | QB_MAP_NOTIFY_REPLACED | QB_MAP_NOTIFY_DELETED | QB_MAP_NOTIFY_RECURSIVE), m); ck_assert_int_eq(i, 0); qb_map_put(m, "garden", "grow"); /* update */ qb_map_put(m, "garden", "green"); ck_assert_int_eq(notified_event_prev, QB_MAP_NOTIFY_REPLACED); ck_assert_int_eq(notified_event, QB_MAP_NOTIFY_FREE); /* delete */ qb_map_rm(m, "garden"); ck_assert_int_eq(notified_event_prev, QB_MAP_NOTIFY_DELETED); ck_assert_int_eq(notified_event, QB_MAP_NOTIFY_FREE); } static void test_map_notifications_prefix(qb_map_t *m) { int32_t i; /* with prefix notifier */ i = qb_map_notify_add(m, "add", my_map_notification, (QB_MAP_NOTIFY_INSERTED| QB_MAP_NOTIFY_DELETED| QB_MAP_NOTIFY_REPLACED| QB_MAP_NOTIFY_RECURSIVE), &i); ck_assert_int_eq(i, 0); /* insert */ qb_map_put(m, "adder", "snake"); ck_assert_str_eq(notified_key, "adder"); ck_assert_str_eq(notified_new_value, "snake"); ck_assert(notified_user_data == &i); /* insert (no match) */ notified_key = NULL; notified_value = NULL; notified_new_value = NULL; qb_map_put(m, "adjust", "it"); ck_assert(notified_key == NULL); ck_assert(notified_value == NULL); ck_assert(notified_new_value == NULL); /* update */ qb_map_put(m, "adder", "+++"); ck_assert_str_eq(notified_key, "adder"); ck_assert_str_eq(notified_value, "snake"); ck_assert_str_eq(notified_new_value, "+++"); /* delete */ qb_map_rm(m, "adder"); ck_assert_str_eq(notified_key, "adder"); ck_assert_str_eq(notified_value, "+++"); } static void test_map_traverse_ordered(qb_map_t *m) { int32_t i; const char *p; char *result; void *data; qb_map_iter_t *it = qb_map_iter_create(m); for (i = 0; chars[i]; i++) { qb_map_put(m, chars[i], chars[i]); } result = calloc(sizeof(char), 26 * 2 + 10 + 1); i = 0; for (p = qb_map_iter_next(it, &data); p; p = qb_map_iter_next(it, &data)) { result[i] = *(char*) data; i++; } qb_map_iter_free(it); ck_assert_str_eq(result, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"); qb_map_destroy(m); } static int32_t traverse_and_remove_func(const char *key, void *value, void *data) { int kk = random() % 30; qb_map_t *m = (qb_map_t *)data; qb_map_rm(m, chars[kk]); qb_map_put(m, chars[kk+30], key); return QB_FALSE; } static void test_map_iter_safety(qb_map_t *m, int32_t ordered) { void *data; void *data2; const char *p; const char *p2; qb_map_iter_t *it; qb_map_iter_t *it2; int32_t found_good = QB_FALSE; qb_map_put(m, "aaaa", "aye"); qb_map_put(m, "bbbb", "bee"); qb_map_put(m, "cccc", "sea"); it = qb_map_iter_create(m); it2 = qb_map_iter_create(m); while ((p = qb_map_iter_next(it, &data)) != NULL) { printf("1: %s == %s\n", p, (char*)data); if (strcmp(p, "bbbb") == 0) { qb_map_rm(m, "bbbb"); qb_map_rm(m, "cccc"); qb_map_put(m, "fffff", "yum"); while ((p2 = qb_map_iter_next(it2, &data2)) != NULL) { printf("2: %s == %s\n", p2, (char*)data2); if (strcmp(p2, "fffff") == 0) { qb_map_put(m, "ggggg", "good"); } } qb_map_iter_free(it2); } if (strcmp(p, "ggggg") == 0) { found_good = QB_TRUE; } } qb_map_iter_free(it); if (ordered) { ck_assert_int_eq(found_good, QB_TRUE); } qb_map_destroy(m); } static void test_map_iter_prefix(qb_map_t *m) { void *data; const char *p; qb_map_iter_t *it; int count; qb_map_put(m, "aaaa", "aye"); qb_map_put(m, "facc", "nope"); qb_map_put(m, "abbb", "bee"); qb_map_put(m, "a.ac", "nope"); qb_map_put(m, "aacc", "yip"); qb_map_put(m, "cacc", "nope"); qb_map_put(m, "c", "----"); count = 0; it = qb_map_pref_iter_create(m, "aa"); while ((p = qb_map_iter_next(it, &data)) != NULL) { printf("1: %s == %s\n", p, (char*)data); count++; } qb_map_iter_free(it); ck_assert_int_eq(count, 2); count = 0; it = qb_map_pref_iter_create(m, "a"); while ((p = qb_map_iter_next(it, &data)) != NULL) { printf("2: %s == %s\n", p, (char*)data); count++; } qb_map_iter_free(it); ck_assert_int_eq(count, 4); count = 0; it = qb_map_pref_iter_create(m, "zz"); while ((p = qb_map_iter_next(it, &data)) != NULL) { printf("??: %s == %s\n", p, (char*)data); count++; } qb_map_iter_free(it); ck_assert_int_eq(count, 0); count = 0; it = qb_map_pref_iter_create(m, "c"); while ((p = qb_map_iter_next(it, &data)) != NULL) { printf("3: %s == %s\n", p, (char*)data); count++; } qb_map_iter_free(it); ck_assert_int_eq(count, 2); qb_map_destroy(m); } static void test_map_traverse_unordered(qb_map_t *m) { int32_t i; srand(time(NULL)); for (i = 0; i < 30; i++) { qb_map_put(m, chars[i], chars[i]); } qb_map_foreach(m, traverse_and_remove_func, m); qb_map_destroy(m); } static int32_t my_counter_traverse(const char *key, void *value, void *data) { int32_t *c = (int32_t*)data; (*c)++; return QB_FALSE; } static void test_map_load(qb_map_t *m, const char* test_name) { char word[1000]; char *w; FILE *fp; int32_t res = 0; int32_t count; int32_t count2; float ops; float secs; void *value; qb_util_stopwatch_t *sw; ck_assert(m != NULL); sw = qb_util_stopwatch_create(); #define MAX_WORDS 100000 /* * Load with dictionary */ fp = fopen("/usr/share/dict/words", "r"); qb_util_stopwatch_start(sw); count = 0; while (fgets(word, sizeof(word), fp) && count < MAX_WORDS) { w = strdup(word); qb_map_put(m, w, w); count++; } qb_util_stopwatch_stop(sw); ck_assert_int_eq(qb_map_count_get(m), count); fclose(fp); secs = qb_util_stopwatch_sec_elapsed_get(sw); ops = (float)count / secs; qb_log(LOG_INFO, "%25s %12.2f puts/sec (%d/%fs)\n", test_name, ops, count, secs); /* * Verify dictionary produces correct values */ fp = fopen("/usr/share/dict/words", "r"); qb_util_stopwatch_start(sw); count2 = 0; while (fgets(word, sizeof(word), fp) && count2 < MAX_WORDS) { value = qb_map_get(m, word); ck_assert_str_eq(word, value); count2++; } qb_util_stopwatch_stop(sw); fclose(fp); secs = qb_util_stopwatch_sec_elapsed_get(sw); ops = (float)count2 / secs; qb_log(LOG_INFO, "%25s %12.2f gets/sec (%d/%fs)\n", test_name, ops, count2, secs); /* * time the iteration */ count2 = 0; qb_util_stopwatch_start(sw); qb_map_foreach(m, my_counter_traverse, &count2); qb_util_stopwatch_stop(sw); ck_assert_int_eq(qb_map_count_get(m), count2); secs = qb_util_stopwatch_sec_elapsed_get(sw); ops = (float)count2 / secs; qb_log(LOG_INFO, "%25s %12.2f iters/sec (%d/%fs)\n", test_name, ops, count2, secs); /* * Delete all dictionary entries */ fp = fopen("/usr/share/dict/words", "r"); qb_util_stopwatch_start(sw); count2 = 0; while (fgets(word, sizeof(word), fp) && count2 < MAX_WORDS) { res = qb_map_rm(m, word); ck_assert_int_eq(res, QB_TRUE); count2++; } qb_util_stopwatch_stop(sw); ck_assert_int_eq(qb_map_count_get(m), 0); fclose(fp); secs = qb_util_stopwatch_sec_elapsed_get(sw); ops = (float)count2 / secs; qb_log(LOG_INFO, "%25s %12.2f dels/sec (%d/%fs)\n", test_name, ops, count2, secs); } START_TEST(test_skiplist_simple) { qb_map_t *m = qb_skiplist_create(); test_map_simple(m, __func__); } END_TEST START_TEST(test_hashtable_simple) { qb_map_t *m = qb_hashtable_create(32); test_map_simple(m, __func__); } END_TEST START_TEST(test_trie_simple) { qb_map_t *m = qb_trie_create(); test_map_simple(m, __func__); } END_TEST START_TEST(test_skiplist_search) { qb_map_t *m = qb_skiplist_create(); test_map_search(m); } END_TEST START_TEST(test_trie_search) { qb_map_t *m = qb_trie_create(); test_map_search(m); } END_TEST START_TEST(test_skiplist_remove) { qb_map_t *m = qb_skiplist_create(); test_map_remove(m); } END_TEST START_TEST(test_hashtable_remove) { qb_map_t *m = qb_hashtable_create(256); test_map_remove(m); } END_TEST START_TEST(test_trie_notifications) { qb_map_t *m; m = qb_trie_create(); test_map_remove(m); m = qb_trie_create(); test_map_notifications_basic(m); m = qb_trie_create(); test_map_notifications_prefix(m); m = qb_trie_create(); test_map_notifications_free(m); m = qb_trie_create(); test_map_notifications_iter(m); } END_TEST START_TEST(test_hash_notifications) { qb_map_t *m; m = qb_hashtable_create(256); test_map_notifications_basic(m); m = qb_hashtable_create(256); test_map_notifications_free(m); } END_TEST START_TEST(test_skiplist_notifications) { qb_map_t *m; m = qb_skiplist_create(); test_map_notifications_basic(m); m = qb_skiplist_create(); test_map_notifications_free(m); } END_TEST START_TEST(test_skiplist_traverse) { qb_map_t *m; m = qb_skiplist_create(); test_map_traverse_ordered(m); m = qb_skiplist_create(); test_map_traverse_unordered(m); m = qb_skiplist_create(); test_map_iter_safety(m, QB_TRUE); } END_TEST START_TEST(test_hashtable_traverse) { qb_map_t *m; m = qb_hashtable_create(256); test_map_traverse_unordered(m); m = qb_hashtable_create(256); test_map_iter_safety(m, QB_FALSE); } END_TEST START_TEST(test_trie_traverse) { qb_map_t *m; m = qb_trie_create(); test_map_traverse_unordered(m); m = qb_trie_create(); test_map_iter_safety(m, QB_FALSE); m = qb_trie_create(); test_map_iter_prefix(m); } END_TEST START_TEST(test_skiplist_load) { qb_map_t *m; if (access("/usr/share/dict/words", R_OK) != 0) { printf("no dict/words - not testing\n"); return; } m = qb_skiplist_create(); test_map_load(m, __func__); } END_TEST START_TEST(test_hashtable_load) { qb_map_t *m; if (access("/usr/share/dict/words", R_OK) != 0) { printf("no dict/words - not testing\n"); return; } m = qb_hashtable_create(100000); test_map_load(m, __func__); } END_TEST START_TEST(test_trie_load) { qb_map_t *m; if (access("/usr/share/dict/words", R_OK) != 0) { printf("no dict/words - not testing\n"); return; } m = qb_trie_create(); test_map_load(m, __func__); } END_TEST /* * From Honza: https://github.com/asalkeld/libqb/issues/44 */ START_TEST(test_trie_partial_iterate) { qb_map_t *map; qb_map_iter_t *iter; const char *res; char *item; int rc; ck_assert((map = qb_trie_create()) != NULL); qb_map_put(map, strdup("testobj.testkey"), strdup("one")); qb_map_put(map, strdup("testobj.testkey2"), strdup("two")); iter = qb_map_pref_iter_create(map, "testobj."); ck_assert(iter != NULL); res = qb_map_iter_next(iter, (void **)&item); fprintf(stderr, "%s = %s\n", res, item); qb_map_iter_free(iter); item = qb_map_get(map, "testobj.testkey"); ck_assert_str_eq(item, "one"); rc = qb_map_rm(map, "testobj.testkey"); ck_assert(rc == QB_TRUE); item = qb_map_get(map, "testobj.testkey"); ck_assert(item == NULL); } END_TEST static Suite * map_suite(void) { TCase *tc; Suite *s = suite_create("qb_map"); add_tcase(s, tc, test_skiplist_simple); add_tcase(s, tc, test_hashtable_simple); add_tcase(s, tc, test_trie_simple); add_tcase(s, tc, test_trie_partial_iterate); add_tcase(s, tc, test_skiplist_remove); add_tcase(s, tc, test_hashtable_remove); add_tcase(s, tc, test_trie_notifications); add_tcase(s, tc, test_hash_notifications); add_tcase(s, tc, test_skiplist_notifications); add_tcase(s, tc, test_skiplist_search); /* * No hashtable_search as it assumes an ordered * collection */ add_tcase(s, tc, test_trie_search); add_tcase(s, tc, test_skiplist_traverse); add_tcase(s, tc, test_hashtable_traverse); add_tcase(s, tc, test_trie_traverse); add_tcase(s, tc, test_skiplist_load, 30); add_tcase(s, tc, test_hashtable_load, 30); add_tcase(s, tc, test_trie_load, 30); return s; } int32_t main(void) { int32_t number_failed; Suite *s = map_suite(); SRunner *sr = srunner_create(s); qb_log_init("check", LOG_USER, LOG_EMERG); atexit(qb_log_fini); qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE); qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FILE, "*", LOG_INFO); qb_log_format_set(QB_LOG_STDERR, "%f:%l %p %b"); qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE); srunner_run_all(sr, CK_VERBOSE); number_failed = srunner_ntests_failed(sr); srunner_free(sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; }