diff options
Diffstat (limited to 'tests/test-list_util.c')
-rw-r--r-- | tests/test-list_util.c | 1230 |
1 files changed, 867 insertions, 363 deletions
diff --git a/tests/test-list_util.c b/tests/test-list_util.c index 7078762c..1107586e 100644 --- a/tests/test-list_util.c +++ b/tests/test-list_util.c @@ -4,6 +4,7 @@ #include "command.h" #include "list_util.h" #include <string.h> +#include "vector.h" /* List util torture tests * @@ -16,6 +17,9 @@ static void test_ssl(void); static void test_sdl(void); static void test_ddl(void); +static uint assert_limit ; + + #define test_assert(true, message) \ do { if (!(true)) test_assert_fail(#true, message, __func__, __LINE__) ; \ } while (0) @@ -26,6 +30,11 @@ test_assert_fail(const char* truth, const char* message, const char* func, { printf("*** %s %d: (%s) not true: %s\n", func, line, truth, message) ; + if (assert_limit > 0) + { + --assert_limit ; + assert(assert_limit > 0) ; + } ; } ; /*============================================================================== @@ -47,6 +56,8 @@ main(int argc, char **argv) srand(22) ; /* Consistent testing required */ + assert_limit = 25 ; + test_ssl() ; test_sdl() ; test_ddl() ; @@ -63,6 +74,22 @@ static unsigned majic(void* a, void* b) return z ; } ; +/* aux list (vector) functions + */ +static vector aux_init(void) ; +static void aux_reset(vector aux) ; +static int aux_length(vector aux) ; +static void* aux_item(vector aux, int index) ; +static void* aux_next_item(vector aux, int index) ; +static void* aux_prev_item(vector aux, int index) ; +static void aux_insert(vector aux, int index, void* item) ; +static void aux_delete(vector aux, void* item) ; +static void aux_push_head(vector aux, void* item) ; +static void* aux_pop_head(vector aux) ; +static void aux_push_tail(vector aux, void* item) ; +static void* aux_pop_tail(vector aux) ; +static int aux_find(vector aux, void* item) ; + /*============================================================================== * Single Base, Single Link * @@ -1162,157 +1189,201 @@ test_sdl(void) * ddl_next(item, next) -- step to next item, if any * ddl_prev(item, next) -- step to prev item, if any * + * ddl_slice(base, sub, list) -- remove sublist from given list + * ddl_splice_after(after, base, sub, list) + * -- insert sublist after given item + * ddl_splice_before(before, base, sub, list) + * -- insert sublist before given item + * * Cases to cover: */ /* Testing runs two lists through struct ddt_item objects. */ -enum list { a_list, b_list, list_count } ; +enum list + { + a_list, + b_list, /* a_list..b_list is all main lists */ + + a_sub_list, + b_sub_list, /* a_sub_list..b_sub_list is all sub lists */ + + list_count /* 0..list_count -1 is all lists */ + } ; +typedef enum list list_t ; + +enum list_bit + { + a_list_bit = 1 << a_list, + b_list_bit = 1 << b_list, + + a_sub_list_bit = 1 << a_sub_list, + b_sub_list_bit = 1 << b_sub_list, + + list_bits = 1 << list_count, + } ; +typedef enum list_bit list_bit_t ; typedef struct ddt_item* ddt_item ; struct ddt_list_pair dl_list_pair(ddt_item) ; /* Example struct constructor */ struct ddt_base_pair dl_base_pair(ddt_item) ; -typedef struct dl_base_pair(ddt_item) ddt_base_pair_t ; - /* Example typedef constructor */ -typedef struct dl_base_pair(ddt_item)* p_ddt_base_pair ; +typedef struct dl_base_pair(ddt_item) ddt_base_pair_xt ; /* Example typedef constructor */ +typedef struct ddt_list_pair ddt_list_pair_t ; typedef struct ddt_list_pair* ddt_list_pair ; -typedef struct ddt_base_pair* ddt_base_pair ; - -typedef struct ddt_rank* ddt_rank ; -struct ddt_rank /* information for each list */ -{ - struct ddt_list_pair list ; /* the thing we are testing */ - - int lister ; - int list_found ; - unsigned majic ; - - int ordinal ; -}; +typedef struct ddt_base_pair ddt_base_pair_t ; +typedef struct ddt_base_pair* ddt_base_pair ; struct ddt_item /* the test items */ { - struct ddt_rank a ; + ddt_list_pair_t a ; char a_rubbish[21] ; - struct ddt_rank b ; + uint seen ; + + ddt_list_pair_t b ; char b_rubbish[19] ; } ; -/* The test list base pairs, and pointers to the actual bases, for use in +/* Pointers to the actual bases, for use in * the verification code. */ -static ddt_base_pair ddt_bases[list_count] ; - -/* For some tests want to construct lists and know the first, last and - * somewhere between items. - */ +struct ddt_test_list +{ + const char* name ; -enum where { first, middle, last, where_count } ; + ddt_base_pair base ; -struct ddt_test_list_items -{ - struct - { - ddt_item where[where_count] ; - } list[list_count] ; + vector aux ; } ; -/*------------------------------------------------------------------------------ - * The test list items -- keep track here also for use in verification. - */ -enum { ddt_max_items = 1000 } ; +typedef struct ddt_test_list* ddt_test_list ; +typedef struct ddt_test_list ddt_test_list_t ; -static unsigned ddt_item_count = 0 ; -static unsigned ddt_item_alloc = 0 ; -static ddt_item ddt_items[ddt_max_items] ; +static ddt_test_list_t ddt_lists[list_count] ; -static inline ddt_item -ddt_new_item(void) + +static inline ddt_list_pair +ddt_list(ddt_item item, list_t lt) { - ddt_item item ; + switch (lt) + { + case a_list: + case a_sub_list: + return &(item->a) ; - assert(ddt_item_count <= ddt_item_alloc) ; + case b_list: + case b_sub_list: + return &(item->b) ; - if (ddt_item_count == ddt_item_alloc) - { - assert(ddt_item_alloc < ddt_max_items) ; - ddt_items[ddt_item_alloc++] = malloc(sizeof(struct ddt_item)) ; + default: + assert(false) ; } ; +} ; - item = ddt_items[ddt_item_count++] ; +static inline ddt_base_pair +ddt_base(list_t lt) +{ + switch (lt) + { + case a_list: + case a_sub_list: + case b_list: + case b_sub_list: + return ddt_lists[lt].base ; + + default: + assert(false) ; + } ; +} ; - memset(item, ddt_item_count & 0xFF, sizeof(struct ddt_item)) ; +static inline vector +ddt_aux(list_t lt) +{ + switch (lt) + { + case a_list: + case a_sub_list: + case b_list: + case b_sub_list: + return ddt_lists[lt].aux ; + + default: + assert(false) ; + } ; +} ; - item->a.lister = 0 ; - item->b.lister = 0 ; +static inline uint +ddt_list_bit(list_t lt) +{ + switch (lt) + { + case a_list: + case a_sub_list: + return 1 ; - item->a.ordinal = 0 ; - item->b.ordinal = 0 ; + case b_list: + case b_sub_list: + return 2 ; - return item ; + default: + assert(false) ; + } ; } ; /*------------------------------------------------------------------------------ - * Given an item and a list ordinal, return pointer to "rank" for item. + * Initialise a test list. */ -static inline ddt_rank -ddt_get_rank(ddt_item item, enum list l) +static void +ddt_test_list_init(ddt_test_list tl, ddt_base_pair base, const char* name) { - if (item == NULL) - return NULL ; + tl->name = name ; - if (l == a_list) - return &item->a ; - if (l == b_list) - return &item->b ; + tl->base = base ; - assert(0) ; + base->head = NULL ; + base->tail = NULL ; + + tl->aux = aux_init() ; } ; /*------------------------------------------------------------------------------ - * Keep track of what should be found on the lists, and majic marker to check - * that don't get lost and point into space. + * The test list items -- keep track here also for use in verification. */ -static inline unsigned -ddt_get_majic(ddt_item item, enum list l) -{ - return majic(item, ddt_bases[l]) ; -} ; - -static void -ddt_test_list_add(ddt_item item, enum list l) -{ - ddt_rank rank = ddt_get_rank(item, l) ; - - test_assert(rank->lister == 0, "already on list") ; +enum { ddt_max_items = 1000 } ; - rank->lister = 1 ; - rank->majic = ddt_get_majic(item, l) ; - rank->ordinal = 0 ; /* unknown ordinal */ -} ; +static unsigned ddt_item_count = 0 ; +static unsigned ddt_item_alloc = 0 ; +static unsigned ddt_item_byte = 0 ; +static ddt_item ddt_items[ddt_max_items] ; -static void -ddt_test_list_del(ddt_item item, enum list l) +static ddt_item +ddt_new_item(void) { - ddt_rank rank ; + ddt_item item ; + uint i, b ; - if (item == NULL) - return ; + assert(ddt_item_count <= ddt_item_alloc) ; - rank = ddt_get_rank(item, l) ; + if (ddt_item_count == ddt_item_alloc) + { + assert(ddt_item_alloc < ddt_max_items) ; + ddt_items[ddt_item_alloc++] = malloc(sizeof(struct ddt_item)) ; + } ; - test_assert(rank->lister == 1, "not on list") ; + item = ddt_items[ddt_item_count++] ; - rank->lister = 0 ; - rank->majic = 0 ; + b = ddt_item_byte + 0xA5 ; + for (i = 0 ; i < sizeof(struct ddt_item) ; ++i) + ((uchar*)item)[i] = (b += 0x55) ; + + return item ; } ; /*------------------------------------------------------------------------------ @@ -1339,24 +1410,20 @@ ddt_test_list_del(ddt_item item, enum list l) static void ddt_verify_lists(void) { - ddt_base_pair base ; - ddt_rank r ; - ddt_item this ; - ddt_item prev ; - int l ; - int i ; + uint i, l ; - /* Wash the found flags */ - for (l = 0 ; l < list_count ; ++l) - for (i = 0 ; i < (int)ddt_item_count ; ++i) - ddt_get_rank(ddt_items[i], l)->list_found = 0 ; + /* Wash the seen flags + */ + for (i = 0 ; i < ddt_item_count ; ++i) + ddt_items[i]->seen = 0 ; - /* Walk the lists */ + /* Walk the lists + */ for (l = 0 ; l < list_count ; ++l) { - int ordinal = 0 ; + ddt_base_pair base ; - base = ddt_bases[l] ; + base = ddt_lists[l].base ; if (base == NULL) continue ; @@ -1364,56 +1431,52 @@ ddt_verify_lists(void) test_assert(base->head == base->tail, "broken list bases") ; else { - r = ddt_get_rank(base->head, l) ; - test_assert(r->list.prev == NULL, "broken list first item->prev") ; - r = ddt_get_rank(base->tail, l) ; - test_assert(r->list.next == NULL, "broken list last item->next") ; + vector aux ; + ddt_list_pair list ; + ddt_item this ; + ddt_item prev ; + uint s ; + + list = ddt_list(base->head, l) ; + test_assert(list->prev == NULL, "broken list first item->prev") ; + list = ddt_list(base->tail, l) ; + test_assert(list->next == NULL, "broken list last item->next") ; this = base->head ; prev = NULL ; + s = ddt_list_bit(l) ; /* seen flag */ + + aux = ddt_lists[l].aux ; + i = 0 ; while (this != NULL) { - r = ddt_get_rank(this, l) ; + test_assert(i < vector_length(aux), "list longer than aux list") ; + test_assert(aux_item(aux, i) == this, + "list and aux list out of step") ; - test_assert(r->list.prev == prev, "broken item->prev") ; + test_assert((this->seen & s) == 0, "list item seen already") ; + this->seen |= s ; - test_assert(r->lister, "should not be on this list") ; + list = ddt_list(this, l) ; - test_assert(!r->list_found, "circular list") ; - r->list_found = 1 ; + test_assert(list->prev == prev, "broken item->prev") ; - if (r->ordinal != 0) - { - test_assert(r->ordinal > ordinal, "list out of order") ; - ordinal = r->ordinal ; - } - - test_assert(r->majic == ddt_get_majic(this, l), - "wrong sort of majic") ; prev = this ; - this = r->list.next ; + this = list->next ; + ++i ; } ; + test_assert(i == vector_length(aux), "list shorter than aux list") ; test_assert(base->tail == prev, "broken tail pointer") ; } ; } ; - - /* Verify that did not miss anything should have found */ - /* Wash the found flags */ - for (l = 0 ; l < list_count ; ++l) - for (i = 0 ; i < (int)ddt_item_count ; ++i) - { - r = ddt_get_rank(ddt_items[i], l) ; - - if (r->lister) - test_assert(r->list_found, "should have found this on list") ; - } ; } ; /*------------------------------------------------------------------------------ * Reset the test list handling * + * Sets all ddt_lists empty. */ static void ddt_reset_lists(void) @@ -1421,126 +1484,130 @@ ddt_reset_lists(void) int l ; for (l = 0 ; l < list_count ; ++l) - ddl_init(*(ddt_bases[l])) ; + { + ddl_init(*(ddt_lists[l].base)) ; + aux_reset(ddt_lists[l].aux) ; + } ; ddt_item_count = 0 ; } ; /*------------------------------------------------------------------------------ - * Make lists with 'n' items each. - * - * If 'n' 0..3, makes lists with exactly that many items. + * Set all lists empty, make main lists with 'n' and sub lists with 'm' items + * each. * - * Otherwise, list length has +/- 25% jitter. + * Lists will have a random number of items in common. */ static void -ddt_test_make_lists(struct ddt_test_list_items* test, int n) +ddt_test_make_lists(int n, int m) { - ddt_base_pair base ; ddt_item item ; - ddt_rank rank ; - enum list l ; - int t ; - int m ; + vector aux ; - int req[list_count] ; - int mid[list_count] ; + uint l, t ; - /* Capture the requirements */ + ddt_reset_lists() ; + + uint req[list_count] ; + + /* Capture the requirements + */ t = 0 ; - m = 1 ; for (l = 0 ; l < list_count ; ++l) { - m += m ; - int j = (n + 1) / 4 ; + uint ln ; - if (n <= 3) - req[l] = n ; - else - req[l] = n - j + (rand() % (j + j + 1)) ; + switch (l) + { + case a_list: + case b_list: + ln = n ; + break ; - mid[l] = req[l] / 2 ; + case a_sub_list: + case b_sub_list: + ln = m ; + break ; - t += req[l] ; + default: + assert(false) ; + } ; - test->list[l].where[first] = NULL ; - test->list[l].where[middle] = NULL ; - test->list[l].where[last] = NULL ; + t += ln ; + req[l] = ln ; } ; - ddt_reset_lists() ; - /* Have t = total number of items still required - * m = 2^n -- where there are 'n' lists + * + * We ensure that the a_list and the a_sub_list are distinct, and that + * the b_list and the b_sub_list are also distinct. */ while (t != 0) { - int b ; - int r ; - r = (rand() % (m - 1)) + 1 ; /* bit pattern, at least one set */ + uint r ; - item = ddt_new_item() ; + r = rand() % list_bits ; - b = 1 ; - for (l = 0 ; l < list_count ; ++l) + if ((r & a_list_bit) || (m == 0)) + r &= ~a_sub_list_bit ; + if ((r & b_list_bit) || (m == 0)) + r &= ~b_sub_list_bit ; + + item = NULL ; + + l = 0 ; + while (r != 0) { - if ((req[l] != 0) && ((r & b) != 0)) + if ((r & 1) && (req[l] != 0)) { --req[l] ; --t ; - ddt_test_list_add(item, l) ; - - if (test->list[l].where[first] == NULL) - test->list[l].where[first] = item ; - - if (mid[l]-- == 0) - test->list[l].where[middle] = item ; + if (item == NULL) + item = ddt_new_item() ; - test->list[l].where[last] = item ; - - base = ddt_bases[l] ; - rank = ddt_get_rank(item, l) ; - - if (base->head == NULL) - { - base->head = item ; - base->tail = item ; - rank->list.next = NULL ; - rank->list.prev = NULL ; - } - else if (rand() & 1) - { - rank->list.next = base->head ; - rank->list.prev = NULL ; - ddt_get_rank(base->head, l)->list.prev = item ; - base->head = item ; - } - else - { - rank->list.next = NULL ; - rank->list.prev = base->tail ; - ddt_get_rank(base->tail, l)->list.next = item ; - base->tail = item ; - } + aux = ddt_lists[l].aux ; + aux_insert(aux, rand() % (vector_length(aux) + 1), item) ; } ; - b <<= 1 ; + + r >>= 1 ; + l += 1 ; } } ; - /* Number the items */ + /* Construct the lists + */ for (l = 0 ; l < list_count ; ++l) { - int o = 0 ; + ddt_base_pair base ; + ddt_list_pair list ; + uint i ; + + base = ddt_lists[l].base ; + aux = ddt_lists[l].aux ; - base = ddt_bases[l] ; + base->head = NULL ; /* Both NULL if list empty */ + base->tail = NULL ; - item = base->head ; - while (item != NULL) + list = NULL ; + for (i = 0 ; i < vector_length(aux) ; ++i) { - rank = ddt_get_rank(item, l) ; - rank->ordinal = ++o ; /* first is 1 */ - item = rank->list.next ; + ddt_list_pair prev ; + + prev = list ; + + item = aux_item(aux, i) ; + list = ddt_list(item, l) ; + + if (prev == NULL) + base->head = item ; + else + prev->next = item ; + + list->next = NULL ; + list->prev = base->tail ; + + base->tail = item ; } ; } ; @@ -1562,6 +1629,12 @@ ddt_test_make_lists(struct ddt_test_list_items* test, int n) * ddl_tail(base) -- return tail of list * ddl_next(item, next) -- step to next item, if any * ddl_prev(item, next) -- step to prev item, if any + * + * ddl_slice(base, sub, list) -- remove sublist from given list + * ddl_splice_after(after, base, sub, list) + * -- insert sublist after given item + * ddl_splice_before(before, base, sub, list) + * -- insert sublist before given item */ static struct ddt_parent @@ -1578,19 +1651,23 @@ test_ddl(void) { struct ddt_base_pair a_base ; struct ddt_parent* b ; + ddt_base_pair_t a_sub ; + ddt_base_pair_t b_sub ; - struct ddt_test_list_items test ; int n ; - int o ; int base_n = 23 ; int rand_n = 17 ; printf("=== Testing ddl -- Double Base, Double Link -- stuff\n") ; - /* Initialise the test support */ - ddt_bases[a_list] = &a_base ; - ddt_bases[b_list] = &ddt_parent.base ; + /* Initialise the test support + */ + ddt_test_list_init(&ddt_lists[a_list], &a_base, "a-list") ; + ddt_test_list_init(&ddt_lists[b_list], &ddt_parent.base, "b-list") ; + + ddt_test_list_init(&ddt_lists[a_sub_list], &a_sub, "a-sub-list") ; + ddt_test_list_init(&ddt_lists[b_sub_list], &b_sub, "b-sub-list") ; ddt_item_count = 0 ; ddt_item_alloc = 0 ; @@ -1604,7 +1681,6 @@ test_ddl(void) ddt_verify_lists() ; /* start as mean to go on */ - /* ddl_push(base, item, list) -- insert at head of list * * Cases: (a) empty list @@ -1615,7 +1691,7 @@ test_ddl(void) ddt_reset_lists() ; n = base_n + (rand() % rand_n) ; - while (n) + while (n > 0) { ddt_item item ; int r ; @@ -1627,19 +1703,17 @@ test_ddl(void) if (r & 1) { - ddl_push(a_base, item, a.list) ; + ddl_push(a_base, item, a) ; test_assert(a_base.head == item, "ddl_push broken") ; - ddt_test_list_add(item, a_list) ; - item->a.ordinal = n ; + aux_push_head(ddt_lists[a_list].aux, item) ; } ; ddt_verify_lists() ; if (r & 2) { - ddl_push(b->base, item, b.list) ; + ddl_push(b->base, item, b) ; test_assert(b->base.head == item, "ddl_push broken") ; - ddt_test_list_add(item, b_list) ; - item->b.ordinal = n ; + aux_push_head(ddt_lists[b_list].aux, item) ; } ; ddt_verify_lists() ; @@ -1657,33 +1731,29 @@ test_ddl(void) ddt_reset_lists() ; n = base_n + (rand() % rand_n) ; - o = 0 ; - while (n) + while (n > 0) { ddt_item item ; int r ; printf(".") ; - ++o ; item = ddt_new_item() ; r = (rand() % 3) + 1 ; if (r & 1) { - ddl_append(a_base, item, a.list) ; + ddl_append(a_base, item, a) ; test_assert(a_base.tail == item, "ddl_append broken") ; - ddt_test_list_add(item, a_list) ; - item->a.ordinal = o ; + aux_push_tail(ddt_lists[a_list].aux, item) ; } ; ddt_verify_lists() ; if (r & 2) { - ddl_append(b->base, item, b.list) ; + ddl_append(b->base, item, b) ; test_assert(b->base.tail == item, "ddl_append broken") ; - ddt_test_list_add(item, b_list) ; - item->b.ordinal = o ; + aux_push_tail(ddt_lists[b_list].aux, item) ; } ; ddt_verify_lists() ; @@ -1693,37 +1763,60 @@ test_ddl(void) /* ddl_in_after(after, base, item, list) -- insert after * - * Cases: (a) after first and only (so is also last) - * (b) after first when more than one - * (c) after last when more than one - * (d) after something between + * NB: after may NOT be NULL. + * + * Cases: (a) after NULL when list is empty + * (b) after NULL when list has 1 or more entries + * (c) after first and only (so is also last) + * (d) after first when more than one + * (e) after last when more than one + * (f) after something between */ printf(" ddl_in_after test") ; n = base_n + (rand() % rand_n) ; - while (n) + while (n >= 0) { - ddt_item item ; - ddt_item after ; + int w ; printf(".") ; - ddt_test_make_lists(&test, n) ; - item = ddt_new_item() ; - after = test.list[a_list].where[n % where_count] ; - ddl_in_after(after, a_base, item, a.list) ; - test_assert(after->a.list.next == item, "ddl_in_after broken") ; - test_assert(item->a.list.prev == after, "ddl_in_after broken") ; - ddt_test_list_add(item, a_list) ; - ddt_verify_lists() ; + for (w = 0 ; w <= n ; ++w) + { + ddt_item item ; + ddt_item after ; + vector aux ; - item = ddt_new_item() ; - after = test.list[b_list].where[n % where_count] ; - ddl_in_after(after, b->base, item, b.list) ; - test_assert(after->b.list.next == item, "ddl_in_after broken") ; - test_assert(item->b.list.prev == after, "ddl_in_after broken") ; - ddt_test_list_add(item, b_list) ; - ddt_verify_lists() ; + ddt_test_make_lists(n, n) ; + + item = ddt_new_item() ; + + aux = ddt_aux(a_list) ; + after = aux_item(aux, w) ; + + ddl_in_after(after, a_base, item, a) ; + + if (after != NULL) + aux_insert(aux, w+1, item) ; + else + aux_push_tail(aux, item) ; + + ddt_verify_lists() ; + + item = ddt_new_item() ; + + aux = ddt_aux(b_list) ; + after = aux_item(aux, w) ; + + ddl_in_after(after, b->base, item, b) ; + + if (after != NULL) + aux_insert(aux, w+1, item) ; + else + aux_push_tail(aux, item) ; + + ddt_verify_lists() ; + } ; --n ; } ; @@ -1731,38 +1824,58 @@ test_ddl(void) /* ddl_in_before(before, base, item, list) -- insert before * - * Cases: (a) before first and only (so is also last) - * (b) before first when more than one - * (c) before last when more than one - * (d) before something between + * Cases: (a) before NULL when list empty + * (b) before NULL when list has 1 or more entries + * (c) before first and only (so is also last) + * (d) before first when more than one + * (e) before last when more than one + * (f) before something between */ printf(" ddl_in_before test") ; n = base_n + (rand() % rand_n) ; - while (n) + while (n >= 0) { - ddt_item item ; - ddt_item before ; + int w ; printf(".") ; - ddt_test_make_lists(&test, n) ; + for (w = 0 ; w <= n ; ++w) + { + ddt_item item ; + ddt_item before ; + vector aux ; - item = ddt_new_item() ; - before = test.list[a_list].where[n % where_count] ; - ddl_in_before(before, a_base, item, a.list) ; - test_assert(before->a.list.prev == item, "ddl_in_before broken") ; - test_assert(item->a.list.next == before, "ddl_in_before broken") ; - ddt_test_list_add(item, a_list) ; - ddt_verify_lists() ; + ddt_test_make_lists(n, n) ; - item = ddt_new_item() ; - before = test.list[b_list].where[n % where_count] ; - ddl_in_before(before, b->base, item, b.list) ; - test_assert(before->b.list.prev == item, "ddl_in_before broken") ; - test_assert(item->b.list.next == before, "ddl_in_before broken") ; - ddt_test_list_add(item, b_list) ; - ddt_verify_lists() ; + item = ddt_new_item() ; + + aux = ddt_aux(a_list) ; + before = aux_item(aux, w) ; + + ddl_in_before(before, a_base, item, a) ; + + if (before != NULL) + aux_insert(aux, w, item) ; + else + aux_push_head(aux, item) ; + + ddt_verify_lists() ; + + item = ddt_new_item() ; + + aux = ddt_aux(b_list) ; + before = aux_item(aux, w) ; + + ddl_in_before(before, b->base, item, b) ; + + if (before != NULL) + aux_insert(aux, w, item) ; + else + aux_push_head(aux, item) ; + + ddt_verify_lists() ; + } ; --n ; } ; @@ -1782,46 +1895,37 @@ test_ddl(void) ddt_item item ; ddt_item temp ; ddt_item peek ; - int ordinal ; printf(".") ; - ddt_test_make_lists(&test, n) ; + ddt_test_make_lists(n, n) ; - ordinal = 0 ; while (1) { peek = a_base.head ; - temp = ddl_pop(&item, a_base, a.list) ; + temp = ddl_pop(&item, a_base, a) ; test_assert(temp == item, "ddl_pop broken") ; test_assert(peek == item, "ddl_pop broken") ; - ddt_test_list_del(item, a_list) ; + aux_pop_head(ddt_aux(a_list)) ; ddt_verify_lists() ; if (item == NULL) break ; - - ++ordinal ; - test_assert(item->a.ordinal == ordinal, "ddl_pop not in order") ; } ; - ordinal = 0 ; while (1) { peek = b->base.head ; - temp = ddl_pop(&item, b->base, b.list) ; + temp = ddl_pop(&item, b->base, b) ; test_assert(temp == item, "ddl_pop broken") ; test_assert(peek == item, "ddl_pop broken") ; - ddt_test_list_del(item, b_list) ; + aux_pop_head(ddt_aux(b_list)) ; ddt_verify_lists() ; if (item == NULL) break ; - - ++ordinal ; - test_assert(item->b.ordinal == ordinal, "ddl_pop not in order") ; } ; --n ; @@ -1834,7 +1938,6 @@ test_ddl(void) * (b) list with one item * (c) empty list */ - printf(" ddl_crop test") ; n = base_n + (rand() % rand_n) ; @@ -1843,58 +1946,37 @@ test_ddl(void) ddt_item item ; ddt_item temp ; ddt_item peek ; - int ordinal ; printf(".") ; - ddt_test_make_lists(&test, n) ; + ddt_test_make_lists(n, n) ; - ordinal = 0 ; while (1) { peek = a_base.tail ; - temp = ddl_crop(&item, a_base, a.list) ; + temp = ddl_crop(&item, a_base, a) ; test_assert(temp == item, "ddl_crop broken") ; test_assert(peek == item, "ddl_crop broken") ; - ddt_test_list_del(item, a_list) ; + aux_pop_tail(ddt_aux(a_list)) ; ddt_verify_lists() ; if (item == NULL) break ; - - if (ordinal == 0) - ordinal = item->a.ordinal ; - else - { - test_assert(ordinal > 0, "ordinal out of whack") ; - --ordinal ; - test_assert(item->a.ordinal == ordinal, "ddl_crop not in order") ; - } ; } ; - ordinal = 0 ; while (1) { peek = b->base.tail ; - temp = ddl_crop(&item, b->base, b.list) ; + temp = ddl_crop(&item, b->base, b) ; test_assert(temp == item, "ddl_crop broken") ; test_assert(peek == item, "ddl_crop broken") ; - ddt_test_list_del(item, b_list) ; + aux_pop_tail(ddt_aux(b_list)) ; ddt_verify_lists() ; if (item == NULL) break ; - - if (ordinal == 0) - ordinal = item->b.ordinal ; - else - { - test_assert(ordinal > 0, "ordinal out of whack") ; - --ordinal ; - test_assert(item->b.ordinal == ordinal, "ddl_crop not in order") ; - } ; } ; --n ; @@ -1906,28 +1988,38 @@ test_ddl(void) * Cases: (a) first and only (so is also last) * (b) first when more than one * (c) last when more than one - * (d) something between + * (d) everything between */ printf(" ddl_del test") ; n = base_n + (rand() % rand_n) ; - while (n) + while (n > 0) { - ddt_item item ; + int w ; printf(".") ; - ddt_test_make_lists(&test, n) ; + for (w = 0 ; w < n ; ++w) + { + ddt_item item ; + vector aux ; - item = test.list[a_list].where[n % where_count] ; - ddl_del(a_base, item, a.list) ; - ddt_test_list_del(item, a_list) ; - ddt_verify_lists() ; + ddt_test_make_lists(n, n) ; - item = test.list[b_list].where[n % where_count] ; - ddl_del(b->base, item, b.list) ; - ddt_test_list_del(item, b_list) ; - ddt_verify_lists() ; + aux = ddt_aux(a_list) ; + item = aux_item(aux, w) ; + + ddl_del(a_base, item, a) ; + aux_delete(aux, item) ; + ddt_verify_lists() ; + + aux = ddt_aux(b_list) ; + item = aux_item(aux, w) ; + + ddl_del(b->base, item, b) ; + aux_delete(aux, item) ; + ddt_verify_lists() ; + } ; --n ; } ; @@ -1949,18 +2041,20 @@ test_ddl(void) printf(".") ; - ddt_test_make_lists(&test, n) ; + ddt_test_make_lists(n, n) ; while (1) { item = a_base.head ; - peek = (item != NULL) ? item->a.list.next : NULL ; + peek = (item != NULL) ? item->a.next : NULL ; - ddl_del_head(a_base, a.list) ; + ddl_del_head(a_base, a) ; test_assert(a_base.head == peek, "ddl_del_head broken") ; - ddt_test_list_del(item, a_list) ; + if (item != NULL) + aux_delete(ddt_aux(a_list), item) ; + ddt_verify_lists() ; if (item == NULL) @@ -1970,13 +2064,15 @@ test_ddl(void) while (1) { item = b->base.head ; - peek = (item != NULL) ? item->b.list.next : NULL ; + peek = (item != NULL) ? item->b.next : NULL ; - ddl_del_head(b->base, b.list) ; + ddl_del_head(b->base, b) ; test_assert(b->base.head == peek, "ddl_del_head broken") ; - ddt_test_list_del(item, b_list) ; + if (item != NULL) + aux_delete(ddt_aux(b_list), item) ; + ddt_verify_lists() ; if (item == NULL) @@ -2003,18 +2099,20 @@ test_ddl(void) printf(".") ; - ddt_test_make_lists(&test, n) ; + ddt_test_make_lists(n, n) ; while (1) { item = a_base.tail ; - peek = (item != NULL) ? item->a.list.prev : NULL ; + peek = (item != NULL) ? item->a.prev : NULL ; - ddl_del_tail(a_base, a.list) ; + ddl_del_tail(a_base, a) ; test_assert(a_base.tail == peek, "ddl_del_tail broken") ; - ddt_test_list_del(item, a_list) ; + if (item != NULL) + aux_delete(ddt_aux(a_list), item) ; + ddt_verify_lists() ; if (item == NULL) @@ -2024,13 +2122,15 @@ test_ddl(void) while (1) { item = b->base.tail ; - peek = (item != NULL) ? item->b.list.prev : NULL ; + peek = (item != NULL) ? item->b.prev : NULL ; - ddl_del_tail(b->base, b.list) ; + ddl_del_tail(b->base, b) ; test_assert(b->base.tail == peek, "ddl_del_tail broken") ; - ddt_test_list_del(item, b_list) ; + if (item != NULL) + aux_delete(ddt_aux(b_list), item) ; + ddt_verify_lists() ; if (item == NULL) @@ -2055,7 +2155,7 @@ test_ddl(void) { printf(".") ; - ddt_test_make_lists(&test, n) ; + ddt_test_make_lists(n, n) ; test_assert(ddl_head(a_base) == a_base.head, "ddl_head broken") ; test_assert(ddl_tail(a_base) == a_base.tail, "ddl_head broken") ; @@ -2066,7 +2166,6 @@ test_ddl(void) } ; printf("\n") ; - /* ddl_next(item, next) -- step to next item, if any * ddl_prev(item, next) -- step to prev item, if any * @@ -2078,39 +2177,444 @@ test_ddl(void) printf(" ddl_next and ddl_prev test") ; n = base_n + (rand() % rand_n) ; - while (n) + while (n > 0) { - ddt_item item ; - ddt_item where ; + int w ; printf(".") ; - ddt_test_make_lists(&test, n) ; + for (w = 0 ; w < n ; ++w) + { + ddt_item item ; + vector aux ; + int i ; + + ddt_test_make_lists(n, n) ; + + aux = ddt_aux(a_list) ; + item = aux_item(aux, w) ; + + i = aux_find(aux, item) ; + test_assert(i == w, "ddl_next/_prev list and aux list out of step") ; - where = test.list[a_list].where[n % where_count] ; - item = ddl_next(where, a.list) ; - test_assert(item == where->a.list.next, "ddl_next broken") ; + test_assert(ddl_next(item, a) == aux_next_item(aux, i), + "ddl_next broken") ; + test_assert(ddl_prev(item, a) == aux_prev_item(aux, i), + "ddl_prev broken") ; - where = test.list[b_list].where[n % where_count] ; - item = ddl_next(where, b.list) ; - test_assert(item == where->b.list.next, "ddl_next broken") ; + aux = ddt_aux(b_list) ; + item = aux_item(aux, w) ; - where = test.list[a_list].where[n % where_count] ; - item = ddl_prev(where, a.list) ; - test_assert(item == where->a.list.prev, "ddl_prev broken") ; + i = aux_find(aux, item) ; + test_assert(i == w, "ddl_next/_prev list and aux list out of step") ; - where = test.list[b_list].where[n % where_count] ; - item = ddl_prev(where, b.list) ; - test_assert(item == where->b.list.prev, "ddl_prev broken") ; + test_assert(ddl_next(item, b) == aux_next_item(aux, i), + "ddl_next broken") ; + test_assert(ddl_prev(item, b) == aux_prev_item(aux, i), + "ddl_prev broken") ; + } ; --n ; } ; printf("\n") ; + /* ddl_slice(base, sub, list) -- remove sublist from given list + * + * Cases: (a) sub is empty + * (b) sub is the entire list -- list with 1 or more entries. + * (c) sub includes head of list, but 1 or more entries remain + * (d) sub includes tail of list, but 1 or more entries remain + * (e) sub is part of list, and 1 or more entries remain at either + * end. + */ + printf(" ddl_slice") ; -} + n = base_n + (rand() % rand_n) ; + while (n >= 0) + { + int s, e ; + + printf(".") ; + + for (s = 0 ; s <= n ; ++s) + { + for (e = s ; e <= n ; ++e) + { + vector aux ; + + ddt_test_make_lists(n, 0) ; + + if (s < e) + { + vector aux_sub ; + + aux = ddt_aux(a_list) ; + + a_sub.head = aux_item(aux, s) ; + a_sub.tail = aux_item(aux, e - 1) ; + + aux_sub = ddt_aux(a_sub_list) ; + assert(vector_length(aux_sub) == 0) ; + + vector_move_extract(aux_sub, aux, s, e - s) ; + } ; + + ddl_slice(a_base, a_sub, a) ; + ddt_verify_lists() ; + + if (s < e) + { + vector aux_sub ; + + aux = ddt_aux(b_list) ; + + b_sub.head = aux_item(aux, s) ; + b_sub.tail = aux_item(aux, e - 1) ; + + aux_sub = ddt_aux(b_sub_list) ; + assert(vector_length(aux_sub) == 0) ; + + vector_move_extract(aux_sub, aux, s, e - s) ; + } ; + + ddl_slice(b->base, b_sub, b) ; + ddt_verify_lists() ; + } ; + } ; + + --n ; + } ; + printf("\n") ; + + /* ddl_splice_after(after, base, sub, list) + * -- insert sublist after given item + * Cases: (a) sub is empty and list is empty + * (b) sub has 1 or more entries and list is empty (after = NULL). + * (c) sub includes head of list, but 1 or more entries remain + * (d) sub includes tail of list, but 1 or more entries remain + * (e) sub is part of list, and 1 or more entries remain at either + * end. + */ + printf(" ddl_splice_after") ; + + n = base_n + (rand() % rand_n) ; + while (n >= 0) + { + printf(".") ; + + int m ; + + for (m = 0 ; m <= 5 ; ++m) + { + int w ; + + for (w = 0 ; w <= n ; ++w) + { + ddt_item after ; + vector aux, s_aux ; + + ddt_test_make_lists(n, m) ; + + aux = ddt_aux(a_list) ; + after = aux_item(aux, w) ; + + ddl_splice_after(after, a_base, a_sub, a) ; + + s_aux = ddt_aux(a_sub_list) ; + + if (after != NULL) + vector_move_replace(aux, w+1, 0, s_aux, 0, m) ; + else + vector_move_replace(aux, w, 0, s_aux, 0, m) ; + + ddl_init(a_sub) ; + + ddt_verify_lists() ; + + aux = ddt_aux(b_list) ; + after = aux_item(aux, w) ; + + ddl_splice_after(after, b->base, b_sub, b) ; + + s_aux = ddt_aux(b_sub_list) ; + + if (after != NULL) + vector_move_replace(aux, w+1, 0, s_aux, 0, m) ; + else + vector_move_replace(aux, w, 0, s_aux, 0, m) ; + + ddl_init(b_sub) ; + + ddt_verify_lists() ; + } ; + } ; + + --n ; + } ; + printf("\n") ; + + /* ddl_splice_before(before, base, sub, list) + * -- insert sublist before given item + * + * Cases: (a) sub is empty and list is empty + * (b) sub has 1 or more entries and list is empty (before = NULL). + * (c) sub includes head of list, but 1 or more entries remain + * (d) sub includes tail of list, but 1 or more entries remain + * (e) sub is part of list, and 1 or more entries remain at either + * end. + */ + printf(" ddl_splice_before") ; + + n = base_n + (rand() % rand_n) ; + while (n >= 0) + { + printf(".") ; + + int m ; + + for (m = 0 ; m <= 5 ; ++m) + { + int w ; + + for (w = 0 ; w <= n ; ++w) + { + ddt_item before ; + vector aux, s_aux ; + + ddt_test_make_lists(n, m) ; + + aux = ddt_aux(a_list) ; + before = aux_item(aux, w) ; + + ddl_splice_before(before, a_base, a_sub, a) ; + + s_aux = ddt_aux(a_sub_list) ; + + if (before != NULL) + vector_move_replace(aux, w, 0, s_aux, 0, m) ; + else + vector_move_replace(aux, 0, 0, s_aux, 0, m) ; + + ddl_init(a_sub) ; + + ddt_verify_lists() ; + + aux = ddt_aux(b_list) ; + before = aux_item(aux, w) ; + + ddl_splice_before(before, b->base, b_sub, b) ; + + s_aux = ddt_aux(b_sub_list) ; + + if (before != NULL) + vector_move_replace(aux, w, 0, s_aux, 0, m) ; + else + vector_move_replace(aux, 0, 0, s_aux, 0, m) ; + + ddl_init(b_sub) ; + + ddt_verify_lists() ; + } ; + } ; + + --n ; + } ; + printf("\n") ; + +} ; /* * TODO * */ + +/*============================================================================== + * Auxilliary list handling -- so that can test one list structure against + * another. + * + * Implements list as vector of pointers. + */ + +/*------------------------------------------------------------------------------ + * Create new, empty aux list (vector) + */ +static vector +aux_init(void) +{ + return vector_init_new(NULL, 50) ; +} ; + +/*------------------------------------------------------------------------------ + * Empty the aux vector + */ +static void +aux_reset(vector aux) +{ + vector_set_length(aux, 0) ; +} ; + +/*------------------------------------------------------------------------------ + * Get number of items in the given aux list + */ +static int +aux_length(vector aux) +{ + return vector_length(aux) ; +} ; + +/*------------------------------------------------------------------------------ + * Get item at the given index -- -ve counts from length + * + * Index must be -length..length + */ +static void* +aux_item(vector aux, int index) +{ + int length ; + + length = vector_length(aux) ; + + if (index < 0) + index += length ; + + if ((index >= 0) && (index < length)) + return vector_get_item(aux, index) ; + else + return NULL ; +} ; + +/*------------------------------------------------------------------------------ + * Get item after item at the given index -- -ve counts from length + * + * Index must be -length..length + */ +static void* +aux_next_item(vector aux, int index) +{ + int length ; + + length = vector_length(aux) ; + + if (index < 0) + index += length ; + + if ((index >= 0) && (index < length)) + return vector_get_item(aux, index + 1) ; + else + return NULL ; +} ; + +/*------------------------------------------------------------------------------ + * Get item before the item at the given index -- -ve counts from length + * + * Offset must be -length..length + */ +static void* +aux_prev_item(vector aux, int index) +{ + int length ; + + length = vector_length(aux) ; + + if (index < 0) + index += length ; + + if ((index > 0) && (index <= length)) + return vector_get_item(aux, index - 1) ; + else + return NULL ; +} ; + +/*------------------------------------------------------------------------------ + * Insert item at given offset in the aux list. + * + * Item(s) at and beyond the given offset (if any) move along the list. + * + * 0 => at start + * -1 => at end + * + * Offset must be -1..length + */ +static void +aux_insert(vector aux, int index, void* item) +{ + if (index >= 0) + assert((uint)index <= vector_length(aux)) ; + else + index = vector_length(aux) ; + + vector_insert_item(aux, index, item) ; +} ; + +/*------------------------------------------------------------------------------ + * Find given item in the aux list and remove it. + * + * Shortens the list by 1 ! + */ +static void +aux_delete(vector aux, void* item) +{ + int index ; + + index = aux_find(aux, item) ; + + if (index < 0) + test_assert(index >= 0, "aux_delete: item not found !") ; + else + vector_delete_item(aux, index) ; +} ; + +/*------------------------------------------------------------------------------ + * Push item onto front of list. + */ +static void +aux_push_head(vector aux, void* item) +{ + vector_unshift_item(aux, item) ; /* opposite sense to vector ! */ +} ; + +/*------------------------------------------------------------------------------ + * Pop item from front of list -- returns NULL if list is empty. + */ +static void* +aux_pop_head(vector aux) +{ + return vector_shift_item(aux) ; /* opposite sense to vector ! */ +} ; + +/*------------------------------------------------------------------------------ + * Append item to end of list. + */ +static void +aux_push_tail(vector aux, void* item) +{ + vector_push_item(aux, item) ; /* opposite sense to vector ! */ +} ; + +/*------------------------------------------------------------------------------ + * Remove item from end of list -- returns NULL if list is empty. + */ +static void* +aux_pop_tail(vector aux) +{ + return vector_pop_item(aux) ; /* opposite sense to vector ! */ +} ; + +/*------------------------------------------------------------------------------ + * Find index of item -- returns -1 if not found. + */ +static int +aux_find(vector aux, void* item) +{ + int i, l ; + + l = aux_length(aux) ; + + for (i = 0 ; i < l ; ++i) + if (aux_item(aux, i) == item) + return i ; + + return -1 ; +} ; + + |