mirror of
				https://gitlab.labs.nic.cz/labs/bird.git
				synced 2024-05-11 16:54:54 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			385 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			385 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  *	BIRD Library -- Safe Linked Lists Tests
 | |
|  *
 | |
|  *	(c) 2015 CZ.NIC z.s.p.o.
 | |
|  *
 | |
|  *	Can be freely distributed and used under the terms of the GNU GPL.
 | |
|  */
 | |
| 
 | |
| #include "test/birdtest.h"
 | |
| 
 | |
| #include "lib/slists.h"
 | |
| 
 | |
| #define MAX_NUM 1000
 | |
| 
 | |
| static snode nodes[MAX_NUM];
 | |
| static slist lst;
 | |
| 
 | |
| static void
 | |
| show_list(void)
 | |
| {
 | |
|   bt_debug("\n");
 | |
|   bt_debug("list.null is at %p and point to %p \n", &lst.null, lst.null);
 | |
|   bt_debug("list.head is at %p and point to %p \n", &lst.head, lst.head);
 | |
|   bt_debug("list.tail is at %p and point to %p \n", &lst.tail, lst.tail);
 | |
|   bt_debug("list.tail_readers is at %p and point to %p \n", &lst.tail_readers, lst.tail_readers);
 | |
| 
 | |
|   int i;
 | |
|   for (i = 0; i < MAX_NUM; i++)
 | |
|     bt_debug("n[%3i] is at %p, .prev (%p) points to %p, .next (%p) points to %p, .readers (%p) points to %p \n",
 | |
| 	     i, &nodes[i], &(nodes[i].prev), nodes[i].prev, &(nodes[i].next), nodes[i].next, &(nodes[i].readers), nodes[i].readers);
 | |
| }
 | |
| 
 | |
| static int
 | |
| is_filled_list_well_linked(void)
 | |
| {
 | |
|   int i;
 | |
|   bt_assert(lst.head == &nodes[0]);
 | |
|   bt_assert(lst.tail == &nodes[MAX_NUM-1]);
 | |
|   bt_assert((void *) nodes[0].prev == (void *) &lst.head);
 | |
|   bt_assert((void *) nodes[MAX_NUM-1].next == (void *) &lst.null);
 | |
| 
 | |
|   for (i = 0; i < MAX_NUM; i++)
 | |
|   {
 | |
|     if (i < (MAX_NUM-1))
 | |
|       bt_assert(nodes[i].next == &nodes[i+1]);
 | |
| 
 | |
|     if (i > 0)
 | |
|       bt_assert(nodes[i].prev == &nodes[i-1]);
 | |
|   }
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int
 | |
| is_empty_list_well_unlinked(void)
 | |
| {
 | |
|   bt_assert(lst.head == SNODE &lst.null);
 | |
|   bt_assert(lst.tail == SNODE &lst.head);
 | |
| 
 | |
|   bt_assert(EMPTY_SLIST(lst));
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static void
 | |
| init_list__(slist *l, struct snode nodes[])
 | |
| {
 | |
|   s_init_list(l);
 | |
| 
 | |
|   int i;
 | |
|   for (i = 0; i < MAX_NUM; i++)
 | |
|   {
 | |
|     nodes[i].next = NULL;
 | |
|     nodes[i].prev = NULL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| init_list_(void)
 | |
| {
 | |
|   init_list__(&lst, nodes);
 | |
| }
 | |
| 
 | |
| static int
 | |
| t_add_tail(void)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   init_list_();
 | |
|   for (i = 0; i < MAX_NUM; i++)
 | |
|   {
 | |
|     s_add_tail(&lst, &nodes[i]);
 | |
|     bt_debug(".");
 | |
|     bt_assert(lst.tail == &nodes[i]);
 | |
|     bt_assert(lst.head == &nodes[0]);
 | |
|     bt_assert((void *) nodes[i].next == (void *) &lst.null);
 | |
|     if (i > 0)
 | |
|     {
 | |
|       bt_assert(nodes[i-1].next == &nodes[i]);
 | |
|       bt_assert(nodes[i].prev == &nodes[i-1]);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   bt_assert(is_filled_list_well_linked());
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int
 | |
| t_add_head(void)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   init_list_();
 | |
|   for (i = MAX_NUM-1; i >= 0; i--)
 | |
|   {
 | |
|     s_add_head(&lst, &nodes[i]);
 | |
|     bt_debug(".");
 | |
|     bt_assert(lst.head == &nodes[i]);
 | |
|     bt_assert(lst.tail == &nodes[MAX_NUM-1]);
 | |
|     if (i < MAX_NUM-1)
 | |
|     {
 | |
|       bt_assert(nodes[i+1].prev == &nodes[i]);
 | |
|       bt_assert(nodes[i].next == &nodes[i+1]);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   bt_assert(is_filled_list_well_linked());
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static void
 | |
| insert_node_(snode *n, snode *after)
 | |
| {
 | |
|   s_insert_node(n, after);
 | |
|   bt_debug(".");
 | |
| }
 | |
| 
 | |
| static int
 | |
| t_insert_node(void)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   init_list_();
 | |
| 
 | |
|   // add first node
 | |
|   insert_node_(&nodes[0], SNODE &lst.head);
 | |
| 
 | |
|   // add odd nodes
 | |
|   for (i = 2; i < MAX_NUM; i+=2)
 | |
|     insert_node_(&nodes[i], &nodes[i-2]);
 | |
| 
 | |
|   // add even nodes
 | |
|   for (i = 1; i < MAX_NUM; i+=2)
 | |
|     insert_node_(&nodes[i], &nodes[i-1]);
 | |
| 
 | |
|   bt_debug("\n");
 | |
|   bt_assert(is_filled_list_well_linked());
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static void
 | |
| fill_list2(slist *l, snode nodes[])
 | |
| {
 | |
|   int i;
 | |
|   for (i = 0; i < MAX_NUM; i++)
 | |
|     s_add_tail(l, &nodes[i]);
 | |
| }
 | |
| 
 | |
| static void
 | |
| fill_list(void)
 | |
| {
 | |
|   fill_list2(&lst, SNODE nodes);
 | |
| }
 | |
| 
 | |
| 
 | |
| static int
 | |
| t_remove_node(void)
 | |
| {
 | |
|   int i;
 | |
| 
 | |
|   init_list_();
 | |
| 
 | |
|   /* Fill & Remove & Check */
 | |
|   fill_list();
 | |
|   for (i = 0; i < MAX_NUM; i++)
 | |
|     s_rem_node(&nodes[i]);
 | |
|   bt_assert(is_empty_list_well_unlinked());
 | |
| 
 | |
|   /* Fill & Remove the half of nodes & Check & Remove the rest nodes & Check */
 | |
|   fill_list();
 | |
|   for (i = 0; i < MAX_NUM; i+=2)
 | |
|     s_rem_node(&nodes[i]);
 | |
| 
 | |
|   int tail_node_index = (MAX_NUM % 2) ? MAX_NUM - 2 : MAX_NUM - 1;
 | |
|   bt_assert(lst.head == &nodes[1]);
 | |
|   bt_assert(lst.tail == &nodes[tail_node_index]);
 | |
|   bt_assert(nodes[tail_node_index].next == SNODE &lst.null);
 | |
| 
 | |
|   for (i = 1; i < MAX_NUM; i+=2)
 | |
|   {
 | |
|     if (i > 1)
 | |
|       bt_assert(nodes[i].prev == &nodes[i-2]);
 | |
|     if (i < tail_node_index)
 | |
|       bt_assert(nodes[i].next == &nodes[i+2]);
 | |
|   }
 | |
| 
 | |
|   for (i = 1; i < MAX_NUM; i+=2)
 | |
|     s_rem_node(&nodes[i]);
 | |
|   bt_assert(is_empty_list_well_unlinked());
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int
 | |
| t_add_tail_list(void)
 | |
| {
 | |
|   snode nodes2[MAX_NUM];
 | |
|   slist l2;
 | |
| 
 | |
|   init_list__(&lst, SNODE &nodes);
 | |
|   fill_list2(&lst, SNODE &nodes);
 | |
| 
 | |
|   init_list__(&l2, SNODE &nodes2);
 | |
|   fill_list2(&l2, SNODE &nodes2);
 | |
| 
 | |
|   s_add_tail_list(&lst, &l2);
 | |
| 
 | |
|   bt_assert(nodes[MAX_NUM-1].next == &nodes2[0]);
 | |
|   bt_assert(nodes2[0].prev == &nodes[MAX_NUM-1]);
 | |
|   bt_assert(lst.tail == &nodes2[MAX_NUM-1]);
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| void
 | |
| dump(const char *str, slist *a)
 | |
| {
 | |
|   snode *x;
 | |
| 
 | |
|   bt_debug("%s \n", str);
 | |
|   for (x = SHEAD(*a); x; x = x->next)
 | |
|   {
 | |
|     siterator *i, *j;
 | |
|     bt_debug("%p", x);
 | |
|     j = (siterator *) x;
 | |
|     for (i = x->readers; i; i = i->next)
 | |
|     {
 | |
|       if (i->prev != j)
 | |
| 	bt_debug(" ???");
 | |
|       j = i;
 | |
|       bt_debug(" [%p:%p]", i, i->node);
 | |
|     }
 | |
|     bt_debug("\n");
 | |
|   }
 | |
|   bt_debug("---\n");
 | |
| }
 | |
| 
 | |
| static int
 | |
| t_iterator_walk(void)
 | |
| {
 | |
|   snode *node;
 | |
|   siterator iter;
 | |
| 
 | |
|   init_list_();
 | |
|   fill_list();
 | |
| 
 | |
|   int k;
 | |
|   int i = 0;
 | |
| 
 | |
|   show_list();
 | |
| 
 | |
|   s_init(&iter, &lst);
 | |
|   WALK_SLIST(node, lst)
 | |
|   {
 | |
|     s_get(&iter);
 | |
|     s_put(&iter, node);
 | |
|     bt_debug("node->readers: %p, iter: %p, nodes[%d].readers: %p, node: %p, nodes[i]: %p, node->next: %p \n",
 | |
| 	     node->readers, &iter, i, nodes[i].readers, node, &(nodes[i]), node->next);
 | |
|     bt_assert(node->readers == &iter);
 | |
|     bt_assert(node->readers == nodes[i].readers);
 | |
|     bt_assert(node == &(nodes[i]));
 | |
|     for (k = 0; k < MAX_NUM; k++)
 | |
|       if (k != i)
 | |
| 	bt_assert(nodes[k].readers == NULL);
 | |
| 
 | |
|     dump("",&lst);
 | |
|     i++;
 | |
|   }
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int
 | |
| t_original(void)
 | |
| {
 | |
|   slist a, b;
 | |
|   snode *x, *y;
 | |
|   siterator i, j;
 | |
| 
 | |
|   s_init_list(&a);
 | |
|   s_init_list(&b);
 | |
|   x = xmalloc(sizeof(*x));
 | |
|   s_add_tail(&a, x);
 | |
|   x = xmalloc(sizeof(*x));
 | |
|   s_add_tail(&a, x);
 | |
|   x = xmalloc(sizeof(*x));
 | |
|   s_add_tail(&a, x);
 | |
|   dump("1", &a);
 | |
| 
 | |
|   s_init(&i, &a);
 | |
|   s_init(&j, &a);
 | |
|   dump("2", &a);
 | |
| 
 | |
|   x = s_get(&i);
 | |
|   bt_debug("Got %p\n", x);
 | |
|   dump("3", &a);
 | |
| 
 | |
|   s_put(&i, x->next);
 | |
|   dump("4", &a);
 | |
| 
 | |
|   y = s_get(&j);
 | |
|   while (y)
 | |
|   {
 | |
|     s_put(&j, y);
 | |
|     dump("5*", &a);
 | |
|     y = s_get(&j)->next;
 | |
|   }
 | |
| 
 | |
|   dump("5 done", &a);
 | |
| 
 | |
|   s_rem_node(a.head->next);
 | |
|   dump("6 (deletion)", &a);
 | |
| 
 | |
|   s_put(&i, s_get(&i)->next);
 | |
|   dump("6 (relink)", &a);
 | |
| 
 | |
|   x = xmalloc(sizeof(*x));
 | |
|   s_add_tail(&b, x);
 | |
|   dump("7 (second list)", &b);
 | |
| 
 | |
|   s_add_tail_list(&b, &a);
 | |
|   dump("8 (after merge)", &b);
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static int
 | |
| t_safe_del_walk(void)
 | |
| {
 | |
|   init_list_();
 | |
|   fill_list();
 | |
| 
 | |
|   show_list();
 | |
| 
 | |
|   snode *node, *node_next;
 | |
|   WALK_SLIST_DELSAFE(node,node_next, lst)
 | |
|   {
 | |
|     bt_debug("Will remove node %p \n", node);
 | |
|     s_rem_node(SNODE node);
 | |
|   }
 | |
|   bt_assert(is_empty_list_well_unlinked());
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| int
 | |
| main(int argc, char *argv[])
 | |
| {
 | |
|   bt_init(argc, argv);
 | |
| 
 | |
|   bt_test_suite(t_add_tail,		"Adding nodes to tail of list");
 | |
|   bt_test_suite(t_add_head, 		"Adding nodes to head of list");
 | |
|   bt_test_suite(t_insert_node, 	 	"Inserting nodes to list");
 | |
|   bt_test_suite(t_remove_node,		"Removing nodes from list");
 | |
|   bt_test_suite(t_add_tail_list,	"At the tail of a list adding the another list");
 | |
|   bt_test_suite(t_iterator_walk,	"Iterator walk");
 | |
|   bt_test_suite(t_safe_del_walk,	"WALK_SLIST_DELSAFE and s_rem_node all nodes");
 | |
|   bt_test_suite(t_original, 		"The original BIRD test suit for SLIST");
 | |
| 
 | |
|   return bt_exit_value();
 | |
| }
 |