summaryrefslogtreecommitdiffstats
path: root/tests/test-list_util.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test-list_util.c')
-rw-r--r--tests/test-list_util.c2112
1 files changed, 2112 insertions, 0 deletions
diff --git a/tests/test-list_util.c b/tests/test-list_util.c
new file mode 100644
index 00000000..fc81a562
--- /dev/null
+++ b/tests/test-list_util.c
@@ -0,0 +1,2112 @@
+#include <zebra.h>
+#include <list_util.h>
+#include <string.h>
+
+/* List util torture tests
+ *
+ */
+
+struct thread_master *master; /* allow lib/zebra.c to link ! */
+
+/* prototypes */
+int main(int argc, char **argv);
+
+static void test_ssl(void);
+static void test_sdl(void);
+static void test_ddl(void);
+
+#define test_assert(true, message) \
+ do { if (!(true)) test_assert_fail(#true, message, __func__, __LINE__) ; \
+ } while (0)
+
+static void
+test_assert_fail(const char* true, const char* message, const char* func,
+ int line)
+{
+ printf("*** %s %d: (%s) not true: %s\n", func, line, true, message) ;
+
+} ;
+
+/*==============================================================================
+ * The tests.
+ */
+int
+main(int argc, char **argv)
+{
+ printf("Starting list_util tests -- %s\n",
+#ifdef __GNUC__LIST_UTIL
+ "GNUC version"
+#else
+ "not GNUC version"
+#endif
+ " -- v0.01 26-Feb-2010") ;
+
+ srand(22) ; /* Consistent testing required */
+
+ test_ssl() ;
+ test_sdl() ;
+ test_ddl() ;
+
+ return 0;
+}
+
+/*------------------------------------------------------------------------------
+ * Construct a majic mark from two addresses
+ */
+static unsigned majic(void* a, void* b)
+{
+ uintptr_t z = (uintptr_t)a ^ (uintptr_t)b ^ (uintptr_t)&majic ;
+ return z ;
+} ;
+
+/*==============================================================================
+ * Single Base, Single Link
+ *
+ * ssl_push(base, item, next) -- add at head of list
+ * ssl_del(base, item, next) -- delete from list
+ * ssl_del_head(base, next) -- delete head of list
+ * ssl_pop(dst, base, next) -- pop head of list, if any
+ * ssl_head(base) -- return head of list
+ * ssl_next(item, next) -- step to next item, if any
+ *
+ * Cases to cover:
+ *
+ * a) adding when list is empty
+ * b) adding when list is not empty
+ * c) deletion of first item and more than one item on list
+ * d) deletion of first item when only one item on the list
+ * e) deletion of arbitrary item (list implicitly not empty)
+ * f) deletion when item not on list and list not empty
+ * g) deletion when item not on list and list is empty
+ * h) deletion of NULL item and list not empty
+ * i) deletion of NULL item and list empty
+ * j) pop of head when list not empty
+ * k) pop of head when list contains one item
+ * l) pop of head when list empty
+ * m) deletion of head when list not empty
+ * n) deletion of head when contains one item
+ * o) deletion of head when list empty
+ * p) head when list not empty
+ * q) head when list is empty
+ * r) next when not last
+ * s) next when last
+ */
+
+typedef struct ssl_test* ssl_test ;
+struct ssl_test
+{
+ ssl_test next ; /* pointer at start of structure */
+
+ unsigned majic ;
+ char dummy ;
+
+ ssl_test other_next ; /* pointer elsewhere in structure */
+} ;
+
+struct ssl_test_parent
+{
+ unsigned rubbish ;
+ char fred ;
+
+ ssl_test base ;
+
+ int z[5] ;
+} ;
+
+static struct ssl_test_parent ssl_parent ;
+
+static void
+test_ssl(void)
+{
+ ssl_test base = NULL ;
+
+ ssl_test del = NULL ;
+ ssl_test other_del = NULL ;
+ ssl_test last = NULL ;
+ ssl_test first = NULL ;
+
+ struct ssl_test dummy ;
+
+ int n = 47 ;
+
+ int i_del = 7 ; /* NB: neither of these may be 0 or 1 */
+ int i_other_del = 37 ;
+
+ ssl_test prev ;
+ ssl_test this ;
+ ssl_test other_this ;
+ ssl_test take ;
+ ssl_test temp ;
+
+ int i ;
+ int ret ;
+
+ static struct ssl_test_parent* other = &ssl_parent ;
+
+ memset(other, 77, sizeof(struct ssl_test_parent)) ;
+ other->base = NULL ;
+
+ /* Repeated insertion, starting from empty list
+ *
+ * a) adding when list is empty
+ * b) adding when list is not empty
+ *
+ * Creates lists for following tests.
+ */
+ printf("=== Testing ssl -- Single Base, Single Link -- stuff\n") ;
+
+ printf(" Creating list of items") ;
+ for (i = 1 ; i <= n ; ++i)
+ {
+ ssl_test this = calloc(1, sizeof(struct ssl_test)) ;
+
+ if (last == NULL)
+ last = this ;
+
+ this->majic = majic(this, &base) ;
+
+ this->dummy = i ;
+
+ ssl_push(base, this, next) ;
+ if (i & 1)
+ ssl_push(other->base, this, other_next) ;
+ else
+ ssl_push(ssl_parent.base, this, other_next) ;
+
+ if (i == i_del)
+ del = this ;
+ if (i == i_other_del)
+ other_del = this ;
+
+ first = this ;
+
+ printf("+") ;
+ } ;
+
+ test_assert((base == first) && (other->base == first),
+ "Failed to create consistent lists") ;
+ printf("\n") ;
+
+ passert((del != base) && (del != last)) ;
+ passert((other_del != base) && (other_del != last)) ;
+
+ /* Walk to check that have the expected items
+ *
+ * l) head when list not empty
+ * r) next when not last
+ * s) next when last
+ */
+ printf(" Walking list of items") ;
+
+ this = ssl_head(base) ;
+ test_assert(this == first, "ssl_head failed") ;
+
+ this = ssl_head(other->base) ;
+ test_assert(this == first, "ssl_head failed") ;
+
+ this = ssl_head(ssl_parent.base) ;
+ test_assert(this == first, "ssl_head failed") ;
+
+ this = ssl_next(del, next) ;
+ test_assert((this == del->next) && (this != NULL), "ssl_next failed") ;
+ this = ssl_next(last, next) ;
+ test_assert((this == last->next) && (this == NULL),
+ "ssl_next failed at end") ;
+
+ this = ssl_next(other_del, other_next) ;
+ test_assert((this == other_del->other_next) && (this != NULL),
+ "ssl_next failed") ;
+ this = ssl_next(last, other_next) ;
+ test_assert((this == last->other_next) && (this == NULL),
+ "ssl_next failed at end") ;
+
+ this = base ;
+ other_this = other->base ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ test_assert(this == other_this, "this and other_this not in step") ;
+ if (this == NULL)
+ break ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+
+ printf(".") ;
+ this = ssl_next(this, next) ;
+ other_this = ssl_next(other_this, other_next) ;
+ } ;
+ printf("\n") ;
+
+ /* Deletion specifically at the start of the list
+ *
+ * c) deletion of first item and more than one item on list
+ */
+ printf(" Deleting the first item") ;
+
+ this = base ;
+ first = base->next ;
+ ret = ssl_del(base, this, next) ;
+ test_assert(ret == 0, "ssl_del did not return 0") ;
+ test_assert(first == base, "ssl_del of first item failed") ;
+
+ this = other->base ;
+ ret = ssl_del(other->base, this, other_next) ;
+ test_assert(ret == 0, "ssl_del did not return 0") ;
+ test_assert(first == other->base, "ssl_del of first item failed") ;
+
+ printf("\n") ;
+
+ --n ; /* one less on the lists ! */
+
+ /* Deletion of items from arbitrary place in list
+ *
+ * e) deletion of arbitrary item (list implicitly not empty)
+ */
+ printf(" Deleting arbitrary items") ;
+ ret = ssl_del(base, del, next) ;
+ test_assert(ret == 0, "ssl_del did not return 0") ;
+ ret = ssl_del(ssl_parent.base, other_del, other_next) ;
+ test_assert(ret == 0, "ssl_del did not return 0") ;
+ printf("\n") ;
+
+ /* Deletion of items from arbitrary place in list
+ *
+ * f) deletion when item not on list and list not empty
+ */
+ printf(" Deleting non-existant items") ;
+ ret = ssl_del(base, &dummy, next) ;
+ test_assert(ret == -1, "ssl_del did not return -1") ;
+ ret = ssl_del(other->base, &dummy, other_next) ;
+ test_assert(ret == -1, "ssl_del did not return -1") ;
+ printf("\n") ;
+
+ /* Deletion of NULL items
+ *
+ * h) deletion of NULL item and list not empty
+ */
+ printf(" Deleting NULL items") ;
+
+ this = NULL ;
+
+ ret = ssl_del(base, this, next) ;
+ test_assert(ret == 0, "ssl_del did not return 0") ;
+
+ ret = ssl_del(ssl_parent.base, this, other_next) ;
+ test_assert(ret == 0, "ssl_del did not return 0") ;
+
+ printf("\n") ;
+
+ /* Scan lists to check after deletion */
+ printf(" Base list scan") ;
+
+ this = base ;
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ if (this == NULL)
+ break ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ if (i == i_del)
+ --i ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+
+ printf("*") ;
+ this = ssl_next(this, next) ;
+ } ;
+ printf("\n") ;
+
+ printf(" Other list scan") ;
+
+ other_this = other->base ;
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ if (other_this == NULL)
+ break ;
+
+ test_assert(other_this != prev, "this is same as prev") ;
+ prev = other_this ;
+
+ if (i == i_other_del)
+ --i ;
+
+ test_assert(other_this->dummy == i--, "don't have the right dummy") ;
+ test_assert(other_this->majic == majic(other_this, &base),
+ "don't have the right majic") ;
+
+ printf("*") ;
+ other_this = ssl_next(other_this, other_next) ;
+ } ;
+ printf("\n") ;
+
+ /* Dismantle lists
+ *
+ * j) pop of head when list not empty
+ * k) pop of head when list contains one item
+ * l) pop of head when list empty
+ * p) head when list not empty
+ * q) head when list is empty
+ */
+ printf(" Popping the head until list is empty\n") ;
+ printf(" Base list") ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ this = base ;
+ test_assert(this == ssl_head(base), "this is not head !") ;
+
+ temp = ssl_pop(&take, base, next) ;
+ test_assert(this == take, "this is not same as deleted head !") ;
+ test_assert(temp == take, "temp is not same as deleted head !") ;
+
+ if (this == NULL)
+ break ;
+
+ test_assert(base == this->next, "ssl_pop broken") ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ if (i == i_del)
+ --i ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+ printf("-") ;
+ } ;
+ test_assert(i == 0, "not the expected final value of 'i'") ;
+ test_assert(base == NULL, "Base list should be empty") ;
+
+ this = ssl_head(base) ;
+ test_assert(this == NULL, "ssl_head of empty list failed") ;
+
+ printf("\n") ;
+
+ printf(" Other list") ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ this = other->base ;
+ test_assert(this == ssl_head(other->base), "this is not head !") ;
+
+ if (i & 1)
+ temp = ssl_pop(&take, other->base, other_next) ;
+ else
+ temp = ssl_pop(&take, ssl_parent.base, other_next) ;
+
+ test_assert(this == take, "this is not same as deleted head !") ;
+ test_assert(temp == take, "temp is not same as deleted head !") ;
+
+ if (this == NULL)
+ break ;
+
+ test_assert(other->base == this->other_next, "ssl_pop broken") ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ if (i == i_other_del)
+ --i ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+ printf("-") ;
+ } ;
+ test_assert(i == 0, "not the expected final value of 'i'") ;
+ test_assert(other->base == NULL, "Other list should be empty") ;
+
+ this = ssl_head(other->base) ;
+ test_assert(this == NULL, "ssl_head of empty list failed") ;
+
+ printf("\n") ;
+
+ /* Rebuild lists to do:
+ *
+ * m) deletion of head when list not empty
+ * n) deletion of head when contains one item
+ * o) deletion of head when list empty
+ */
+ passert((base == NULL) && (other->base == NULL)) ;
+
+ last = NULL ;
+ first = NULL ;
+ prev = NULL ;
+ printf(" Building list of items again") ;
+ for (i = 1 ; i <= n ; ++i)
+ {
+ ssl_test this = calloc(1, sizeof(struct ssl_test)) ;
+
+ if (last == NULL)
+ last = this ;
+
+ this->majic = majic(this, &base) ;
+ this->dummy = i ;
+
+ ssl_push(base, this, next) ;
+ if (i & 1)
+ ssl_push(ssl_parent.base, this, other_next) ;
+ else
+ ssl_push(other->base, this, other_next) ;
+
+ test_assert(this->next == prev, "broken ssl_push") ;
+ test_assert(this->other_next == prev, "broken ssl_push") ;
+
+ test_assert(base == this, "broken ssl_push") ;
+ test_assert(other->base == this, "broken ssl_push") ;
+
+ first = this ;
+ prev = this ;
+
+ printf("+") ;
+ } ;
+
+ printf("\n") ;
+
+ printf(" Deleting the head until list is empty\n") ;
+ printf(" Base list") ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ this = base ;
+
+ ssl_del_head(base, next) ;
+
+ if (this == NULL)
+ break ;
+
+ test_assert(base == this->next, "ssl_del_head broken") ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+ printf("-") ;
+ } ;
+ test_assert(i == 0, "not the expected final value of 'i'") ;
+ test_assert(base == NULL, "Base list should be empty") ;
+
+ printf("\n") ;
+
+ printf(" Other list") ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ this = other->base ;
+
+ if (i & 1)
+ ssl_del_head(ssl_parent.base, other_next) ;
+ else
+ ssl_del_head(other->base, other_next) ;
+
+ if (this == NULL)
+ break ;
+
+ test_assert(other->base == this->other_next, "ssl_del_head broken") ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+ printf("-") ;
+ } ;
+ test_assert(i == 0, "not the expected final value of 'i'") ;
+ test_assert(other->base == NULL, "Other list should be empty") ;
+
+ printf("\n") ;
+
+ /* Final few tests
+ *
+ * d) deletion of first item when only one item on the list
+ * g) deletion when item not on list and list is empty
+ * i) deletion of NULL item and list empty
+ */
+
+ /* Deletion of items from arbitrary place in list */
+ printf(" Miscellaneous") ;
+
+ del->next = &dummy ;
+ ssl_push(base, del, next) ;
+ test_assert((base == del) && (del->next == NULL), "ssl_push failed ??") ;
+ ssl_del(base, del, next) ;
+ test_assert(base == NULL, "ssl_del of first and only item failed") ;
+
+ other_del->other_next = &dummy ;
+ ssl_push(other->base, other_del, other_next) ;
+ test_assert((other->base == other_del) && (other_del->other_next == NULL),
+ "ssl_push failed ??") ;
+ ssl_del(other->base, other_del, other_next) ;
+ test_assert(other->base == NULL, "ssl_del of first and only item failed") ;
+
+ ret = ssl_del(base, del, next) ;
+ test_assert(ret == -1, "ssl_del did not return -1") ;
+ test_assert(base == NULL, "ssl_del on empty list") ;
+
+ ret = ssl_del(other->base, other_del, other_next) ;
+ test_assert(ret == -1, "ssl_del did not return -1") ;
+ test_assert(other->base == NULL, "ssl_del on empty list") ;
+
+ this = NULL ;
+
+ ret = ssl_del(base, this, next) ;
+ test_assert(ret == 0, "ssl_del did not return 0") ;
+ test_assert(base == NULL, "ssl_del on empty list") ;
+
+ ret = ssl_del(other->base, this, other_next) ;
+ test_assert(ret == 0, "ssl_del did not return 0") ;
+ test_assert(other->base == NULL, "ssl_del on empty list") ;
+
+ printf("\n") ;
+
+} ;
+
+/*==============================================================================
+ * Single Base, Double Link
+ *
+ * sdl_push(base, item, list) -- add at head of list
+ * sdl_del(base, item, list) -- delete from list
+ * sdl_pop(&dst, base, next) -- pop head of list, if any
+ * sdl_head(base) -- return head of list
+ * sdl_next(item, next) -- step to next item, if any
+ * sdl_prev(item, next) -- step to prev item, if any
+ *
+ * Cases to cover:
+ *
+ * a) adding when list is empty
+ * b) adding when list is not empty
+ * c) deletion of first item and more than one item on list
+ * d) deletion of first item when only one item on the list
+ * e) deletion of arbitrary item (list implicitly not empty)
+ * f) deletion of NULL item and list not empty
+ * g) deletion of NULL item and list empty
+ * h) pop of head when list not empty
+ * i) pop of head when list contains one item
+ * j) pop of head when list empty
+ * k) deletion of head when list not empty
+ * l) deletion of head when list contains one item
+ * m) deletion of head when list empty
+ * n) head when list not empty
+ * o) head when list is empty
+ * p) next when not last
+ * q) next when last
+ * r) prev when not first
+ * s) prev when first
+ *
+ * NB: unlike single link stuff, cannot attempt to remove item which is
+ * not on the list !
+ */
+
+typedef struct sdl_test* sdl_test ;
+struct sdl_test
+{
+ struct dl_list_pair(sdl_test) list ;
+
+ unsigned majic ;
+ char dummy ;
+
+ struct dl_list_pair(sdl_test) other_list ;
+};
+
+struct sdl_test_parent
+{
+ long rubbish ;
+ char fred ;
+
+ sdl_test base ;
+
+ int z[7] ;
+} ;
+
+static struct sdl_test_parent sdl_parent ;
+
+static void
+test_sdl(void)
+{
+ sdl_test base = NULL ;
+
+ sdl_test del = NULL ;
+ sdl_test other_del = NULL ;
+ sdl_test last = NULL ;
+ sdl_test first = NULL ;
+
+ struct sdl_test dummy ;
+
+ int n = 57 ;
+
+ int i_del = 9 ; /* NB: neither of these may be 0 or 1 */
+ int i_other_del = 49 ;
+
+ sdl_test prev ;
+ sdl_test this ;
+ sdl_test other_this ;
+ sdl_test take ;
+ sdl_test temp ;
+
+ int i ;
+
+ static struct sdl_test_parent* other = &sdl_parent ;
+
+ memset(other, 99, sizeof(struct sdl_test_parent)) ;
+ other->base = NULL ;
+
+ /* Repeated insertion, starting from empty list
+ *
+ * a) adding when list is empty
+ * b) adding when list is not empty
+ *
+ * Creates lists for following tests.
+ */
+ printf("=== Testing sdl -- Single Base, Double Link -- stuff\n") ;
+
+ printf(" Creating list of items") ;
+ for (i = 1 ; i <= n ; ++i)
+ {
+ sdl_test this = calloc(1, sizeof(struct sdl_test)) ;
+
+ if (last == NULL)
+ last = this ;
+
+ this->majic = majic(this, &base) ;
+
+ this->dummy = i ;
+
+ sdl_push(base, this, list) ;
+ if (i & 1)
+ sdl_push(other->base, this, other_list) ;
+ else
+ sdl_push(sdl_parent.base, this, other_list) ;
+
+ if (i == i_del)
+ del = this ;
+ if (i == i_other_del)
+ other_del = this ;
+
+ first = this ;
+
+ printf("+") ;
+ } ;
+
+ test_assert((base == first) && (other->base == first),
+ "Failed to create consistent lists") ;
+
+ printf("\n") ;
+
+ passert((del != base) && (del != last)) ;
+ passert((other_del != base) && (other_del != last)) ;
+
+ /* Walk to check that have the expected items
+ *
+ * n) head when list not empty
+ * p) next when not last
+ * q) next when last
+ * r) prev when not first
+ * s) prev when first
+ */
+ printf(" Walking list of items") ;
+
+ this = sdl_head(base) ;
+ test_assert(this == first, "sdl_head failed") ;
+
+ this = sdl_head(other->base) ;
+ test_assert(this == first, "sdl_head failed") ;
+
+ this = sdl_head(sdl_parent.base) ;
+ test_assert(this == first, "sdl_head failed") ;
+
+ /* next on both lists */
+ this = sdl_next(first, list) ;
+ test_assert((this == first->list.next) && (this != NULL),
+ "sdl_next failed at start") ;
+ this = sdl_next(del, list) ;
+ test_assert((this == del->list.next) && (this != NULL), "sdl_next failed") ;
+ this = sdl_next(last, list) ;
+ test_assert((this == last->list.next) && (this == NULL),
+ "sdl_next failed at end") ;
+
+ this = sdl_next(first, other_list) ;
+ test_assert((this == first->other_list.next) && (this != NULL),
+ "sdl_next failed at start") ;
+ this = sdl_next(other_del, other_list) ;
+ test_assert((this == other_del->other_list.next) && (this != NULL),
+ "sdl_next failed") ;
+ this = sdl_next(last, other_list) ;
+ test_assert((this == last->other_list.next) && (this == NULL),
+ "sdl_next failed at end") ;
+
+ /* prev on both lists */
+ this = sdl_prev(first, list) ;
+ test_assert((this == first->list.prev) && (this == NULL),
+ "sdl_prev failed at start") ;
+ this = sdl_prev(del, list) ;
+ test_assert((this == del->list.prev) && (this != NULL), "sdl_prev failed") ;
+ this = sdl_prev(last, list) ;
+ test_assert((this == last->list.prev) && (this != NULL),
+ "sdl_prev failed at end") ;
+
+ this = sdl_prev(first, other_list) ;
+ test_assert((this == first->other_list.prev) && (this == NULL),
+ "sdl_prev failed at start") ;
+ this = sdl_prev(other_del, other_list) ;
+ test_assert((this == other_del->other_list.prev) && (this != NULL),
+ "sdl_prev failed") ;
+ this = sdl_prev(last, other_list) ;
+ test_assert((this == last->other_list.prev) && (this != NULL),
+ "sdl_prev failed at end") ;
+
+ this = base ;
+ other_this = other->base ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ test_assert(this == other_this, "this and other_this not in step") ;
+ if (this == NULL)
+ break ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+
+ printf(".") ;
+ this = sdl_next(this, list) ;
+ other_this = sdl_next(other_this, other_list) ;
+ } ;
+ printf("\n") ;
+
+ /* Deletion specifically at the start of the list
+ *
+ * c) deletion of first item and more than one item on list
+ */
+ printf(" Deleting the first item") ;
+
+ this = base ;
+ first = base->list.next ;
+ sdl_del(base, this, list) ;
+ test_assert(first == base, "sdl_del of first item failed") ;
+ test_assert((base == NULL) || (base->list.prev == NULL), "sdl_del failed") ;
+
+ this = other->base ;
+ sdl_del(sdl_parent.base, this, other_list) ;
+ test_assert(first == other->base, "sdl_del of first item failed") ;
+ test_assert((base == NULL) || (base->other_list.prev == NULL),
+ "sdl_del failed") ;
+
+ printf("\n") ;
+
+ --n ; /* one less on the lists ! */
+
+ /* Deletion of items from arbitrary place in list
+ *
+ * e) deletion of arbitrary item (list implicitly not empty)
+ */
+ printf(" Deleting arbitrary items") ;
+ sdl_del(base, del, list) ;
+ test_assert((base == NULL) || (base->list.prev == NULL), "sdl_del failed") ;
+ sdl_del(sdl_parent.base, other_del, other_list) ;
+ test_assert((base == NULL) || (base->other_list.prev == NULL),
+ "sdl_del failed") ;
+ printf("\n") ;
+
+ /* Deletion of NULL items
+ *
+ * f) deletion of NULL item and list not empty
+ */
+ printf(" Deleting NULL items") ;
+ this = NULL ;
+ sdl_del(base, this, list) ;
+ test_assert((base == NULL) || (base->list.prev == NULL), "sdl_del failed") ;
+ sdl_del(other->base, this, other_list) ;
+ test_assert((base == NULL) || (base->other_list.prev == NULL),
+ "sdl_del failed") ;
+ printf("\n") ;
+
+ /* Scan lists to check after deletion */
+ printf(" Base list scan") ;
+
+ this = base ;
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ if (this == NULL)
+ break ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ test_assert(this->list.prev == prev, "broken prev pointer") ;
+
+ if (i == i_del)
+ --i ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+ printf("*") ;
+
+ prev = this ;
+ this = sdl_next(this, list) ;
+
+ test_assert(this == prev->list.next, "broken sdl_next") ;
+ if (this != NULL)
+ test_assert(prev == sdl_prev(this, list), "broken sdl_prev") ;
+ } ;
+ printf("\n") ;
+
+ printf(" Other list scan") ;
+
+ this = other->base ;
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ if (this == NULL)
+ break ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ test_assert(this->other_list.prev == prev, "broken prev pointer") ;
+
+ if (i == i_other_del)
+ --i ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+
+ printf("*") ;
+
+ prev = this ;
+ this = sdl_next(this, other_list) ;
+
+ test_assert(this == prev->other_list.next, "broken sdl_next") ;
+ if (this != NULL)
+ test_assert(prev == sdl_prev(this, other_list), "broken sdl_prev") ;
+ } ;
+ printf("\n") ;
+
+ /* Dismantle lists
+ *
+ * h) pop of head when list not empty
+ * i) pop of head when list contains one item
+ * j) pop of head when list empty
+ * o) head when list is empty
+ */
+ printf(" Popping the head until list is empty\n") ;
+ printf(" Base list") ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ this = sdl_head(base) ;
+ test_assert(this == base, "broken sdl_head !") ;
+
+ temp = sdl_pop(&take, base, list) ;
+ test_assert(this == take, "take is not same as deleted head !") ;
+ test_assert(this == temp, "temp is not same as deleted head !") ;
+ if (base != NULL)
+ test_assert(base->list.prev == NULL, "sdl_pop failed") ;
+
+ if (this == NULL)
+ break ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ if (i == i_del)
+ --i ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+ printf("-") ;
+ } ;
+ test_assert(i == 0, "not the expected final value of 'i'") ;
+ test_assert(base == NULL, "Base list should be empty") ;
+
+ this = sdl_head(base) ;
+ test_assert(this == NULL, "sdl_head of empty list failed") ;
+
+ printf("\n") ;
+
+ printf(" Other list") ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ this = sdl_head(other->base) ;
+ test_assert(this == other->base, "broken sdl_head !") ;
+
+ if (i & 1)
+ temp = sdl_pop(&take, sdl_parent.base, other_list) ;
+ else
+ temp = sdl_pop(&take, other->base, other_list) ;
+
+ test_assert(this == take, "take is not same as deleted head !") ;
+ test_assert(this == temp, "temp is not same as deleted head !") ;
+ if (other->base != NULL)
+ test_assert(other->base->other_list.prev == NULL,
+ "sdl_pop failed") ;
+ if (this == NULL)
+ break ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ if (i == i_other_del)
+ --i ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+
+ printf("-") ;
+ } ;
+ test_assert(i == 0, "not the expected final value of 'i'") ;
+ test_assert(other->base == NULL, "Other list should be empty") ;
+
+ this = sdl_head(other->base) ;
+ test_assert(this == NULL, "sdl_head of empty list failed") ;
+
+ printf("\n") ;
+
+ /* Rebuild lists to do:
+ *
+ * k) deletion of head when list not empty
+ * l) deletion of head when list contains one item
+ * m) deletion of head when list empty
+ */
+ passert((base == NULL) && (other->base == NULL)) ;
+
+ last = NULL ;
+ first = NULL ;
+ prev = NULL ;
+ printf(" Building list of items again") ;
+ for (i = 1 ; i <= n ; ++i)
+ {
+ sdl_test this = calloc(1, sizeof(struct sdl_test)) ;
+
+ if (last == NULL)
+ last = this ;
+
+ this->majic = majic(this, &base) ;
+ this->dummy = i ;
+
+ sdl_push(base, this, list) ;
+ if (i & 1)
+ sdl_push(sdl_parent.base, this, other_list) ;
+ else
+ sdl_push(other->base, this, other_list) ;
+
+ test_assert(this->list.next == prev, "broken sdl_push") ;
+ test_assert(this->other_list.next == prev, "broken sdl_push") ;
+
+ test_assert(base == this, "broken sdl_push") ;
+ test_assert(other->base == this, "broken sdl_push") ;
+
+ first = this ;
+ prev = this ;
+
+ printf("+") ;
+ } ;
+
+ printf("\n") ;
+
+ printf(" Deleting the head until list is empty\n") ;
+ printf(" Base list") ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ this = base ;
+
+ sdl_del_head(base, list) ;
+
+ if (this == NULL)
+ break ;
+
+ test_assert(base == this->list.next, "sdl_del_head broken") ;
+ if (base != NULL)
+ test_assert(base->list.prev == NULL, "sdl_del_head broken") ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+ printf("-") ;
+ } ;
+ test_assert(i == 0, "not the expected final value of 'i'") ;
+ test_assert(base == NULL, "Base list should be empty") ;
+
+ printf("\n") ;
+
+ printf(" Other list") ;
+
+ prev = NULL ;
+ i = n ;
+ while (1)
+ {
+ this = other->base ;
+
+ if (i & 1)
+ sdl_del_head(other->base, other_list) ;
+ else
+ sdl_del_head(sdl_parent.base, other_list) ;
+
+ if (this == NULL)
+ break ;
+
+ test_assert(other->base == this->other_list.next, "sdl_del_head broken") ;
+ if (other->base != NULL)
+ test_assert(other->base->other_list.prev == NULL,
+ "sdl_del_head broken") ;
+
+ test_assert(this != prev, "this is same as prev") ;
+ prev = this ;
+
+ test_assert(this->dummy == i--, "don't have the right dummy") ;
+ test_assert(this->majic == majic(this, &base),
+ "don't have the right majic") ;
+ printf("-") ;
+ } ;
+ test_assert(i == 0, "not the expected final value of 'i'") ;
+ test_assert(other->base == NULL, "Other list should be empty") ;
+
+ printf("\n") ;
+
+ /* Final few tests
+ *
+ * d) deletion of first item when only one item on the list
+ * g) deletion of NULL item and list empty
+ */
+
+ /* Deletion of items from arbitrary place in list */
+ printf(" Miscellaneous") ;
+
+ del->list.next = &dummy ;
+ sdl_push(base, del, list) ;
+ test_assert((base == del) && (del->list.next == NULL), "sdl_push failed ??") ;
+ sdl_del(base, del, list) ;
+ test_assert(base == NULL, "sdl_del of first and only item failed") ;
+
+ other_del->other_list.next = &dummy ;
+ sdl_push(other->base, other_del, other_list) ;
+ test_assert((other->base == other_del) && (other_del->other_list.next == NULL),
+ "sdl_push failed ??") ;
+ sdl_del(other->base, other_del, other_list) ;
+ test_assert(other->base == NULL, "sdl_del of first and only item failed") ;
+
+ this = NULL ;
+ sdl_del(base, this, list) ;
+ test_assert(base == NULL, "sdl_del of NULL item with empty list") ;
+
+ sdl_del(other->base, this, other_list) ;
+ test_assert(other->base == NULL, "sdl_del of NULL item with empty list") ;
+
+ printf("\n") ;
+} ;
+
+/*==============================================================================
+ * Double Base, Double Link
+ *
+ * ddl_init(base) -- initialise base
+ * ddl_push(base, item, list) -- insert at head of list
+ * ddl_append(base, item, list) -- insert at tail of list
+ * ddl_in_after(after, base, item, list) -- insert after
+ * ddl_in_before(before, base, item, list) -- insert before
+ * ddl_pop(&dst, base, next) -- pop head of list, if any
+ * ddl_crop(&dst, base, next) -- crop tail of list, if any
+ * ddl_del(base, item, list) -- delete from list
+ * ddl_del_head(base, next) -- delete head of list
+ * ddl_del_tail(base, next) -- delete tail of list
+ * ddl_head(base) -- return head of list
+ * 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
+ *
+ * Cases to cover:
+ */
+
+/* Testing runs two lists through struct ddt_item objects. */
+
+enum list { a_list, b_list, list_count } ;
+
+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 ;
+ /* Example typedef constructor */
+
+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 ;
+};
+
+struct ddt_item /* the test items */
+{
+ struct ddt_rank a ;
+
+ char a_rubbish[21] ;
+
+ struct ddt_rank b ;
+
+ char b_rubbish[19] ;
+} ;
+
+/* The test list base pairs, and 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.
+ */
+
+enum where { first, middle, last, where_count } ;
+
+struct ddt_test_list_items
+{
+ struct
+ {
+ ddt_item where[where_count] ;
+ } list[list_count] ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * The test list items -- keep track here also for use in verification.
+ */
+enum { ddt_max_items = 1000 } ;
+
+static unsigned ddt_item_count = 0 ;
+static unsigned ddt_item_alloc = 0 ;
+static ddt_item ddt_items[ddt_max_items] ;
+
+static inline ddt_item
+ddt_new_item(void)
+{
+ ddt_item item ;
+
+ assert(ddt_item_count <= ddt_item_alloc) ;
+
+ if (ddt_item_count == ddt_item_alloc)
+ {
+ assert(ddt_item_alloc < ddt_max_items) ;
+ ddt_items[ddt_item_alloc++] = malloc(sizeof(struct ddt_item)) ;
+ } ;
+
+ item = ddt_items[ddt_item_count++] ;
+
+ memset(item, ddt_item_count & 0xFF, sizeof(struct ddt_item)) ;
+
+ item->a.lister = 0 ;
+ item->b.lister = 0 ;
+
+ item->a.ordinal = 0 ;
+ item->b.ordinal = 0 ;
+
+ return item ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Given an item and a list ordinal, return pointer to "rank" for item.
+ */
+static inline ddt_rank
+ddt_get_rank(ddt_item item, enum list l)
+{
+ if (item == NULL)
+ return NULL ;
+
+ if (l == a_list)
+ return &item->a ;
+ if (l == b_list)
+ return &item->b ;
+
+ assert(0) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Keep track of what should be found on the lists, and majic marker to check
+ * that don't get lost and point into space.
+ */
+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") ;
+
+ rank->lister = 1 ;
+ rank->majic = ddt_get_majic(item, l) ;
+ rank->ordinal = 0 ; /* unknown ordinal */
+} ;
+
+static void
+ddt_test_list_del(ddt_item item, enum list l)
+{
+ ddt_rank rank ;
+
+ if (item == NULL)
+ return ;
+
+ rank = ddt_get_rank(item, l) ;
+
+ test_assert(rank->lister == 1, "not on list") ;
+
+ rank->lister = 0 ;
+ rank->majic = 0 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Verification code.
+ *
+ * Blunt instrument to check that all known lists are valid. Checks:
+ *
+ * * bases are both NULL together, or both not NULL.
+ *
+ * * first and last items on the list have suitable prev/next pointers.
+ *
+ * * walk list to confirm, for each item:
+ *
+ * -- prev pointer valid for each item
+ * -- item majic is correct (so not pointing somewhere invalid)
+ * -- item is supposed to be on the list
+ * -- item has not already been seen on list (list bent)
+ * -- ordinal, if not zero, is bigger than any previous non-zero ordinal
+ *
+ * * last item visited on walk is what the tail points to
+ *
+ * * for any items which are supposed to be on list, but were not found
+ */
+static void
+ddt_verify_lists(void)
+{
+ ddt_base_pair base ;
+ ddt_rank r ;
+ ddt_item this ;
+ ddt_item prev ;
+ int l ;
+ int i ;
+
+ /* 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 ;
+
+ /* Walk the lists */
+ for (l = 0 ; l < list_count ; ++l)
+ {
+ int ordinal = 0 ;
+
+ base = ddt_bases[l] ;
+ if (base == NULL)
+ continue ;
+
+ if ((base->head == NULL) || (base->tail == NULL))
+ 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") ;
+
+ this = base->head ;
+ prev = NULL ;
+
+ while (this != NULL)
+ {
+ r = ddt_get_rank(this, l) ;
+
+ test_assert(r->list.prev == prev, "broken item->prev") ;
+
+ test_assert(r->lister, "should not be on this list") ;
+
+ test_assert(!r->list_found, "circular list") ;
+ r->list_found = 1 ;
+
+ 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 ;
+ } ;
+
+ 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
+ *
+ */
+static void
+ddt_reset_lists(void)
+{
+ int l ;
+
+ for (l = 0 ; l < list_count ; ++l)
+ ddl_init(*(ddt_bases[l])) ;
+
+ ddt_item_count = 0 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Make lists with 'n' items each.
+ *
+ * If 'n' 0..3, makes lists with exactly that many items.
+ *
+ * Otherwise, list length has +/- 25% jitter.
+ */
+static void
+ddt_test_make_lists(struct ddt_test_list_items* test, int n)
+{
+ ddt_base_pair base ;
+ ddt_item item ;
+ ddt_rank rank ;
+ enum list l ;
+ int t ;
+ int m ;
+
+ int req[list_count] ;
+ int mid[list_count] ;
+
+ /* Capture the requirements */
+ t = 0 ;
+ m = 1 ;
+ for (l = 0 ; l < list_count ; ++l)
+ {
+ m += m ;
+ int j = (n + 1) / 4 ;
+
+ if (n <= 3)
+ req[l] = n ;
+ else
+ req[l] = n - j + (rand() % (j + j + 1)) ;
+
+ mid[l] = req[l] / 2 ;
+
+ t += req[l] ;
+
+ test->list[l].where[first] = NULL ;
+ test->list[l].where[middle] = NULL ;
+ test->list[l].where[last] = NULL ;
+ } ;
+
+ ddt_reset_lists() ;
+
+ /* Have t = total number of items still required
+ * m = 2^n -- where there are 'n' lists
+ */
+ while (t != 0)
+ {
+ int b ;
+ int r ;
+ r = (rand() % (m - 1)) + 1 ; /* bit pattern, at least one set */
+
+ item = ddt_new_item() ;
+
+ b = 1 ;
+ for (l = 0 ; l < list_count ; ++l)
+ {
+ if ((req[l] != 0) && ((r & b) != 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 ;
+
+ 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 ;
+ }
+ } ;
+ b <<= 1 ;
+ }
+ } ;
+
+ /* Number the items */
+ for (l = 0 ; l < list_count ; ++l)
+ {
+ int o = 0 ;
+
+ base = ddt_bases[l] ;
+
+ item = base->head ;
+ while (item != NULL)
+ {
+ rank = ddt_get_rank(item, l) ;
+ rank->ordinal = ++o ; /* first is 1 */
+ item = rank->list.next ;
+ } ;
+ } ;
+
+ ddt_verify_lists() ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * ddl_init(base) -- initialise base
+ * ddl_push(base, item, list) -- insert at head of list
+ * ddl_append(base, item, list) -- insert at tail of list
+ * ddl_in_after(after, base, item, list) -- insert after
+ * ddl_in_before(before, base, item, list) -- insert before
+ * ddl_pop(&dst, base, next) -- pop head of list, if any
+ * ddl_crop(&dst, base, next) -- crop tail of list, if any
+ * ddl_del(base, item, list) -- delete from list
+ * ddl_del_head(base, next) -- delete head of list
+ * ddl_del_tail(base, next) -- delete tail of list
+ * ddl_head(base) -- return head of list
+ * 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
+ */
+
+static struct ddt_parent
+{
+ char zlxq[37] ;
+
+ struct ddt_base_pair base ;
+
+ char qxlz[45] ;
+} ddt_parent ;
+
+static void
+test_ddl(void)
+{
+ struct ddt_base_pair a_base ;
+ struct ddt_parent* b ;
+
+ 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 ;
+
+ ddt_item_count = 0 ;
+ ddt_item_alloc = 0 ;
+
+ /* Initialise the list bases */
+ b = &ddt_parent ;
+ memset(b, 42, sizeof(struct ddt_parent)) ;
+
+ ddl_init(a_base) ;
+ ddl_init(b->base) ;
+
+ ddt_verify_lists() ; /* start as mean to go on */
+
+
+ /* ddl_push(base, item, list) -- insert at head of list
+ *
+ * Cases: (a) empty list
+ * (b) list with one item
+ * (c) list with multiple items
+ */
+ printf(" ddl_push test") ;
+ ddt_reset_lists() ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n)
+ {
+ ddt_item item ;
+ int r ;
+
+ printf(".") ;
+
+ item = ddt_new_item() ;
+ r = (rand() % 3) + 1 ;
+
+ if (r & 1)
+ {
+ ddl_push(a_base, item, a.list) ;
+ test_assert(a_base.head == item, "ddl_push broken") ;
+ ddt_test_list_add(item, a_list) ;
+ item->a.ordinal = n ;
+ } ;
+ ddt_verify_lists() ;
+
+ if (r & 2)
+ {
+ ddl_push(b->base, item, b.list) ;
+ test_assert(b->base.head == item, "ddl_push broken") ;
+ ddt_test_list_add(item, b_list) ;
+ item->b.ordinal = n ;
+ } ;
+ ddt_verify_lists() ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+ /* ddl_append(base, item, list) -- insert at tail of list
+ *
+ * Cases: (a) empty list
+ * (b) list with one item
+ * (c) list with multiple items
+ */
+ printf(" ddl_append test") ;
+ ddt_reset_lists() ;
+
+ n = base_n + (rand() % rand_n) ;
+ o = 0 ;
+ while (n)
+ {
+ 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) ;
+ test_assert(a_base.tail == item, "ddl_append broken") ;
+ ddt_test_list_add(item, a_list) ;
+ item->a.ordinal = o ;
+ } ;
+ ddt_verify_lists() ;
+
+ if (r & 2)
+ {
+ ddl_append(b->base, item, b.list) ;
+ test_assert(b->base.tail == item, "ddl_append broken") ;
+ ddt_test_list_add(item, b_list) ;
+ item->b.ordinal = o ;
+ } ;
+ ddt_verify_lists() ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+ /* 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
+ */
+ printf(" ddl_in_after test") ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n)
+ {
+ ddt_item item ;
+ ddt_item after ;
+
+ 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() ;
+
+ 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() ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+ /* 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
+ */
+ printf(" ddl_in_before test") ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n)
+ {
+ ddt_item item ;
+ ddt_item before ;
+
+ printf(".") ;
+
+ ddt_test_make_lists(&test, n) ;
+
+ 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() ;
+
+ 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() ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+ /* ddl_pop(&dst, base, next) -- pop head of list, if any
+ *
+ * Cases: (a) list with more than one item
+ * (b) list with one item
+ * (c) empty list
+ */
+ printf(" ddl_pop test") ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n >= 0)
+ {
+ ddt_item item ;
+ ddt_item temp ;
+ ddt_item peek ;
+ int ordinal ;
+
+ printf(".") ;
+
+ ddt_test_make_lists(&test, n) ;
+
+ ordinal = 0 ;
+ while (1)
+ {
+ peek = a_base.head ;
+ temp = ddl_pop(&item, a_base, a.list) ;
+ test_assert(temp == item, "ddl_pop broken") ;
+ test_assert(peek == item, "ddl_pop broken") ;
+
+ ddt_test_list_del(item, 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) ;
+ test_assert(temp == item, "ddl_pop broken") ;
+ test_assert(peek == item, "ddl_pop broken") ;
+
+ ddt_test_list_del(item, b_list) ;
+ ddt_verify_lists() ;
+
+ if (item == NULL)
+ break ;
+
+ ++ordinal ;
+ test_assert(item->b.ordinal == ordinal, "ddl_pop not in order") ;
+ } ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+ /* ddl_crop(&dst, base, next) -- crop tail of list, if any
+ *
+ * Cases: (a) list with more than one item
+ * (b) list with one item
+ * (c) empty list
+ */
+
+ printf(" ddl_crop test") ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n >= 0)
+ {
+ ddt_item item ;
+ ddt_item temp ;
+ ddt_item peek ;
+ int ordinal ;
+
+ printf(".") ;
+
+ ddt_test_make_lists(&test, n) ;
+
+ ordinal = 0 ;
+ while (1)
+ {
+ peek = a_base.tail ;
+ temp = ddl_crop(&item, a_base, a.list) ;
+ test_assert(temp == item, "ddl_crop broken") ;
+ test_assert(peek == item, "ddl_crop broken") ;
+
+ ddt_test_list_del(item, 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) ;
+ test_assert(temp == item, "ddl_crop broken") ;
+ test_assert(peek == item, "ddl_crop broken") ;
+
+ ddt_test_list_del(item, 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 ;
+ } ;
+ printf("\n") ;
+
+ /* ddl_del(base, item, list) -- delete from list
+ *
+ * Cases: (a) first and only (so is also last)
+ * (b) first when more than one
+ * (c) last when more than one
+ * (d) something between
+ */
+ printf(" ddl_del test") ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n)
+ {
+ ddt_item item ;
+
+ printf(".") ;
+
+ ddt_test_make_lists(&test, n) ;
+
+ 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() ;
+
+ 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() ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+ /* ddl_del_head(base, next) -- delete head of list
+ *
+ * Cases: (a) list with more than one item
+ * (b) list with one item
+ * (c) empty list
+ */
+ printf(" ddl_del_head test") ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n >= 0)
+ {
+ ddt_item item ;
+ ddt_item peek ;
+
+ printf(".") ;
+
+ ddt_test_make_lists(&test, n) ;
+
+ while (1)
+ {
+ item = a_base.head ;
+ peek = (item != NULL) ? item->a.list.next : NULL ;
+
+ ddl_del_head(a_base, a.list) ;
+
+ test_assert(a_base.head == peek, "ddl_del_head broken") ;
+
+ ddt_test_list_del(item, a_list) ;
+ ddt_verify_lists() ;
+
+ if (item == NULL)
+ break ;
+ } ;
+
+ while (1)
+ {
+ item = b->base.head ;
+ peek = (item != NULL) ? item->b.list.next : NULL ;
+
+ ddl_del_head(b->base, b.list) ;
+
+ test_assert(b->base.head == peek, "ddl_del_head broken") ;
+
+ ddt_test_list_del(item, b_list) ;
+ ddt_verify_lists() ;
+
+ if (item == NULL)
+ break ;
+ } ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+ /* ddl_del_tail(base, next) -- delete tail of list
+ *
+ * Cases: (a) list with more than one item
+ * (b) list with one item
+ * (c) empty list
+ */
+ printf(" ddl_del_tail test") ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n >= 0)
+ {
+ ddt_item item ;
+ ddt_item peek ;
+
+ printf(".") ;
+
+ ddt_test_make_lists(&test, n) ;
+
+ while (1)
+ {
+ item = a_base.tail ;
+ peek = (item != NULL) ? item->a.list.prev : NULL ;
+
+ ddl_del_tail(a_base, a.list) ;
+
+ test_assert(a_base.tail == peek, "ddl_del_tail broken") ;
+
+ ddt_test_list_del(item, a_list) ;
+ ddt_verify_lists() ;
+
+ if (item == NULL)
+ break ;
+ } ;
+
+ while (1)
+ {
+ item = b->base.tail ;
+ peek = (item != NULL) ? item->b.list.prev : NULL ;
+
+ ddl_del_tail(b->base, b.list) ;
+
+ test_assert(b->base.tail == peek, "ddl_del_tail broken") ;
+
+ ddt_test_list_del(item, b_list) ;
+ ddt_verify_lists() ;
+
+ if (item == NULL)
+ break ;
+ } ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+ /* ddl_head(base) -- return head of list
+ * ddl_tail(base) -- return tail of list
+ *
+ * Cases: (a) list with more than one item
+ * (b) list with one item
+ * (c) empty list
+ */
+ printf(" ddl_head & ddl_tail test") ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n >= 0)
+ {
+ printf(".") ;
+
+ ddt_test_make_lists(&test, 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") ;
+ test_assert(ddl_head(b->base) == b->base.head, "ddl_head broken") ;
+ test_assert(ddl_tail(b->base) == b->base.tail, "ddl_head broken") ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+
+ /* ddl_next(item, next) -- step to next item, if any
+ * ddl_prev(item, next) -- step to prev item, if any
+ *
+ * Cases: (a) at first and only (so is also last)
+ * (b) at first when more than one
+ * (c) at last when more than one
+ * (d) at something between
+ */
+ printf(" ddl_next and ddl_prev test") ;
+
+ n = base_n + (rand() % rand_n) ;
+ while (n)
+ {
+ ddt_item item ;
+ ddt_item where ;
+
+ printf(".") ;
+
+ ddt_test_make_lists(&test, n) ;
+
+ 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") ;
+
+ 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") ;
+
+ 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") ;
+
+ 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") ;
+
+ --n ;
+ } ;
+ printf("\n") ;
+
+
+}
+
+/*
+ * TODO
+ *
+ */