aboutsummaryrefslogtreecommitdiff
path: root/dependencies/uthash/tests/test92.c
diff options
context:
space:
mode:
Diffstat (limited to 'dependencies/uthash/tests/test92.c')
-rw-r--r--dependencies/uthash/tests/test92.c245
1 files changed, 245 insertions, 0 deletions
diff --git a/dependencies/uthash/tests/test92.c b/dependencies/uthash/tests/test92.c
new file mode 100644
index 000000000..106819451
--- /dev/null
+++ b/dependencies/uthash/tests/test92.c
@@ -0,0 +1,245 @@
+#include <stdio.h>
+
+#define HASH_NONFATAL_OOM 1
+
+#include "uthash.h"
+
+#undef uthash_malloc
+#undef uthash_free
+#undef uthash_nonfatal_oom
+#define uthash_malloc(sz) alt_malloc(sz)
+#define uthash_free(ptr,sz) alt_free(ptr)
+#define uthash_nonfatal_oom(e) do{(e)->mem_failed=1;}while(0)
+#define all_select(a) 1
+
+typedef struct example_user_t {
+ int id;
+ int cookie;
+ UT_hash_handle hh;
+ UT_hash_handle hh2;
+ int mem_failed;
+} example_user_t;
+
+static int malloc_cnt = 0;
+static int malloc_failed = 0;
+static int free_cnt = 0;
+
+static void *alt_malloc(size_t sz)
+{
+ if (--malloc_cnt <= 0) {
+ malloc_failed = 1;
+ return 0;
+ }
+ malloc_failed = 0;
+ return malloc(sz);
+}
+
+static void alt_free(void *ptr) {
+ free_cnt++;
+ free(ptr);
+}
+
+static void complain(int index, example_user_t *users, example_user_t *user)
+{
+ int expected_frees = (3 - index);
+ if (users) {
+ printf("%d: users hash must be empty\n", index);
+ }
+ if (user->hh.tbl) {
+ printf("%d hash table must be empty\n", index);
+ }
+ if (free_cnt != expected_frees) {
+ printf("%d Expected %d frees, only had %d\n", index, expected_frees, free_cnt);
+ }
+ if (user->mem_failed != 1) {
+ printf("%d Expected user->mem_failed(%d) to be 1\n", index, user->mem_failed);
+ }
+}
+
+int main()
+{
+ example_user_t *users = NULL;
+ example_user_t *user = (example_user_t*)malloc(sizeof(example_user_t));
+ example_user_t *test;
+ example_user_t *users2 = NULL;
+ int id = 0;
+ int i;
+ int saved_cnt;
+
+ user->id = id;
+
+#ifdef HASH_BLOOM
+ malloc_cnt = 3; // bloom filter must fail
+ user->mem_failed = 0;
+ user->hh.tbl = (UT_hash_table*)1;
+ free_cnt = 0;
+ HASH_ADD_INT(users, id, user);
+ complain(1, users, user);
+#endif /* HASH_BLOOM */
+
+ malloc_cnt = 2; // bucket creation must fail
+ user->mem_failed = 0;
+ free_cnt = 0;
+ user->hh.tbl = (UT_hash_table*)1;
+ HASH_ADD_INT(users, id, user);
+ complain(2, users, user);
+
+ malloc_cnt = 1; // table creation must fail
+ user->mem_failed = 0;
+ free_cnt = 0;
+ user->hh.tbl = (UT_hash_table*)1;
+ HASH_ADD_INT(users, id, user);
+ complain(3, users, user);
+
+ malloc_cnt = 4; // hash must create OK
+ user->mem_failed = 0;
+ HASH_ADD_INT(users, id, user);
+ if (user->mem_failed) {
+ printf("mem_failed must be 0, not %d\n", user->mem_failed);
+ }
+ HASH_FIND_INT(users,&id,test);
+ if (!test) {
+ printf("test user ID %d not found\n", id);
+ }
+
+ if (HASH_COUNT(users) != 1) {
+ printf("Got HASH_COUNT(users)=%d, should be 1\n", HASH_COUNT(users));
+ }
+
+ // let's add users until expansion fails.
+ malloc_failed = 0;
+ free_cnt = 0;
+ malloc_cnt = 1;
+ for (id = 1; 1; ++id) {
+ user = (example_user_t*)malloc(sizeof(example_user_t));
+ user->id = id;
+ if (id >= 1000) {
+ // prevent infinite, or too long of a loop here
+ puts("too many allocs before memory request");
+ break;
+ }
+ user->hh.tbl = (UT_hash_table*)1;
+ HASH_ADD_INT(users, id, user);
+ if (malloc_failed) {
+ if (id < 10) {
+ puts("there is no way your bucket size is <= 10");
+ }
+
+ if (user->hh.tbl) {
+ puts("user->hh.tbl should be NULL after failure");
+ } else if (user->mem_failed != 1) {
+ printf("mem_failed should be 1 after failure, not %d\n", user->mem_failed);
+ }
+
+ if (free_cnt != 0) {
+ printf("Expected 0 frees, had %d\n", free_cnt);
+ }
+
+ // let's make sure all previous IDs are there.
+ for (i=0; i<id; ++i) {
+ HASH_FIND_INT(users,&i,test);
+ if (test == NULL) {
+ printf("test user ID %d not found\n", i);
+ }
+ }
+
+ // let's try to add again, but with mem_failed set to 0
+ user->hh.tbl = NULL;
+ user->mem_failed = 0;
+ malloc_failed = 0;
+ HASH_ADD_INT(users, id, user);
+ if (!malloc_failed) {
+ puts("malloc should have been attempted");
+ }
+ if (user->hh.tbl) {
+ puts("user->hh.tbl should be NULL after second failure");
+ } else if (user->mem_failed != 1) {
+ printf("mem_failed should be 1 after second failure, not %d\n", user->mem_failed);
+ }
+
+ break;
+ }
+ }
+
+ // let's test HASH_SELECT.
+ // let's double the size of the table we've already built.
+ saved_cnt = id;
+
+ if (HASH_COUNT(users) != (unsigned)saved_cnt) {
+ printf("Got HASH_COUNT(users)=%d, should be %d\n", HASH_COUNT(users), saved_cnt);
+ }
+
+ for (i=0; i < saved_cnt; i++) {
+ user = (example_user_t*)malloc(sizeof(example_user_t));
+ user->id = ++id;
+ malloc_cnt = 20; // don't fail
+ HASH_ADD_INT(users, id, user);
+ }
+
+ HASH_ITER(hh, users, user, test) {
+ user->mem_failed = 0;
+ }
+
+// HASH_SELECT calls uthash_nonfatal_oom() with an argument of type (void*).
+#undef uthash_nonfatal_oom
+#define uthash_nonfatal_oom(e) do{((example_user_t*)e)->mem_failed=1;}while(0)
+
+ malloc_cnt = 0;
+ free_cnt = 0;
+ HASH_SELECT(hh2, users2, hh, users, all_select);
+ if (users2) {
+ puts("Nothing should have been copied into users2");
+ }
+ HASH_ITER(hh, users, user, test) {
+ if (user->hh2.tbl) {
+ printf("User ID %d has tbl at %p\n", user->id, (void*)user->hh2.tbl);
+ }
+ if (user->mem_failed != 1) {
+ printf("User ID %d has mem_failed(%d), should be 1\n", user->id, user->mem_failed);
+ }
+ user->mem_failed = 0;
+ }
+
+ malloc_cnt = 4;
+ HASH_SELECT(hh2, users2, hh, users, all_select);
+
+ // note about the above.
+ // we tried to stick up to 1,000 entries into users,
+ // and the malloc failed after saved_cnt. The bucket threshold must have
+ // been triggered. We then doubled the amount of entries in user,
+ // and just ran HASH_SELECT, trying to copy them into users2.
+ // because the order is different, and because we continue after
+ // failures, the bucket threshold may get triggered on arbitrary
+ // elements, depending on the hash function.
+
+ saved_cnt = 0;
+ HASH_ITER(hh, users, user, test) {
+ example_user_t * user2;
+ HASH_FIND(hh2, users2, &user->id, sizeof(int), user2);
+ if (user2) {
+ if (!user->hh2.tbl) {
+ printf("User ID %d has tbl==NULL\n", user->id);
+ }
+ if (user->mem_failed != 0) {
+ printf("User ID %d has mem_failed(%d), expected 0\n", user->id, user->mem_failed);
+ }
+ } else {
+ saved_cnt++;
+ if (user->hh2.tbl) {
+ printf("User ID %d has tbl at %p, expected 0\n", user->id, (void*)user->hh2.tbl);
+ }
+ if (user->mem_failed != 1) {
+ printf("User ID %d has mem_failed(%d), expected is 1\n", user->id, user->mem_failed);
+ }
+ }
+ }
+
+ if (saved_cnt + HASH_CNT(hh2, users2) != HASH_COUNT(users)) {
+ printf("Selected elements : %d + %d != %d\n",
+ saved_cnt, HASH_CNT(hh2, users2), HASH_COUNT(users));
+ }
+
+ puts("End");
+
+ return 0;
+}