/* * Nsock regression test suite * Same license as nmap -- see https://nmap.org/book/man-legal.html */ #include "test-common.h" #include "../src/gh_heap.h" #include #include #define HEAP_COUNT 3 struct testitem { int val; gh_hnode_t node; }; static int hnode_int_cmp(gh_hnode_t *n1, gh_hnode_t *n2) { struct testitem *a; struct testitem *b; a = container_of(n1, struct testitem, node); b = container_of(n2, struct testitem, node); return (a->val < b->val); } static gh_hnode_t *mknode(int val) { struct testitem *item; item = calloc(1, sizeof(struct testitem)); assert(item != NULL); item->val = val; gh_hnode_invalidate(&item->node); return &item->node; } static int node2int(gh_hnode_t *hnode) { struct testitem *item; item = container_of(hnode, struct testitem, node); return item->val; } void gh_heap_verify(gh_heap_t *heap) { gh_hnode_t *a, *b, *c; unsigned int bi, ci; unsigned int count = gh_heap_count(heap); for (unsigned int i=0; i < heap->count; i++) { a = gh_heap_find(heap, i); bi = (i << 1) + 1; assert(a->index == i); if (bi < count) { b = gh_heap_find(heap, bi); assert(b->index == bi); assert(node2int(a) <= node2int(b)); ci = bi + 1; if (ci < count) { c = gh_heap_find(heap, ci); assert(c->index == ci); assert(node2int(a) <= node2int(c)); } } } } static int ghheap_ordering(void *tdata) { gh_heap_t heap; int i, n, k; gh_heap_init(&heap, hnode_int_cmp); for (i = 25000; i < 50000; i++) gh_heap_push(&heap, mknode(i)); gh_heap_verify(&heap); for (i = 24999; i >= 0; i--) gh_heap_push(&heap, mknode(i)); gh_heap_verify(&heap); for (i = 0; i < 5000; i++) { gh_hnode_t *current = gh_heap_find(&heap, rand() % gh_heap_count(&heap)); gh_heap_remove(&heap, current); free(container_of(current, struct testitem, node)); } gh_heap_verify(&heap); for (i = 25000; i < 50000; i++) gh_heap_push(&heap, mknode(i)); gh_heap_verify(&heap); n = -1; do { gh_hnode_t *current; current = gh_heap_pop(&heap); assert(!gh_hnode_is_valid(current)); k = node2int(current); if (k < n) return -EINVAL; n = k; free(container_of(current, struct testitem, node)); } while (gh_heap_count(&heap) > 0); gh_heap_free(&heap); return 0; } static int ghheap_stress(void *tdata) { gh_heap_t heaps[HEAP_COUNT]; int i, num; for (i = 0; i < HEAP_COUNT; i++) gh_heap_init(&heaps[i], hnode_int_cmp); for (num = 25000; num < 50000; num++) { for (i = 0; i < HEAP_COUNT; i++) { gh_heap_push(&heaps[i], mknode(num)); } } for (i = 0; i < HEAP_COUNT; i++) gh_heap_verify(&heaps[i]); for (num = 24999; num >= 0; num--) { for (i = 0; i < HEAP_COUNT; i++) { gh_heap_push(&heaps[i], mknode(num)); } } for (i = 0; i < HEAP_COUNT; i++) gh_heap_verify(&heaps[i]); for (num = 0; num < 50000; num++) { for (i = 0; i < HEAP_COUNT; i++) { gh_heap_t *heap = &heaps[i]; gh_hnode_t *hnode; if (num % 0x7f == 0) { size_t count = gh_heap_count(heap); hnode = gh_heap_find(heap, count-1); if (hnode == NULL) { fprintf(stderr, "Failed to find node at index %lu (count-1)\n", count-1); return -EINVAL; } gh_heap_remove(heap, hnode); free(container_of(hnode, struct testitem, node)); gh_heap_verify(heap); } else if (num % 0x1fff == 0 && num < gh_heap_count(heap)) { hnode = gh_heap_find(heap, num); if (hnode == NULL) { fprintf(stderr, "Failed to find node at index %d (count = %lu)\n", num, gh_heap_count(heap)); return -EINVAL; } gh_heap_remove(heap, hnode); free(container_of(hnode, struct testitem, node)); gh_heap_verify(heap); } else { int r_min, r_pop; r_min = node2int(gh_heap_min(heap)); hnode = gh_heap_pop(heap); r_pop = node2int(hnode); if (r_min != r_pop) { fprintf(stderr, "Bogus min/pop return values (%d != %d)\n", r_min, r_pop); return -EINVAL; } if (r_min > num) { fprintf(stderr, "Bogus return value %d when expected <=%d\n", r_min, num); return -EINVAL; } free(container_of(hnode, struct testitem, node)); } } } for (i = 0; i < HEAP_COUNT; i++) { void *ret; ret = gh_heap_pop(&heaps[i]); if (ret != NULL) { fprintf(stderr, "Ret is bogus for heap %d\n", i); return -EINVAL; } } for (i = 0; i < HEAP_COUNT; i++) gh_heap_free(&heaps[i]); return 0; } const struct test_case TestGHHeaps = { .t_name = "test nsock internal ghheaps", .t_setup = NULL, .t_run = ghheap_stress, .t_teardown = NULL }; const struct test_case TestHeapOrdering = { .t_name = "test heaps conditions", .t_setup = NULL, .t_run = ghheap_ordering, .t_teardown = NULL };