Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2018 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @brief doubly-linked list tests
 *
 * @defgroup lib_dlist_tests Dlist
 */

#include <ztest.h>
#include <sys/dlist.h>

#define NODE_SIZE 5

static sys_dlist_t test_list;

struct container_node {
	sys_dnode_t node;
	int value;
};

/**
 * @brief Test whether dlist node struct is embeddedable
 * in any user structure
 *
 * @details Initialize an user defined structure contains
 * dlist node.Appending nodes into the doubly-linked list
 * and enumerate the doubly-linked list.
 *
 * Verify that the value enumerated is equal to the
 * value initialized.If the verification pass,the user
 * defined structure works.
 *
 * @ingroup lib_dlist_tests
 *
 * @see sys_dlist_append()
 */

void test_dlist_container(void)
{
	int i, count;
	struct container_node *cnode, *s_cnode;

	/* Initialize an user-defiend structure of contains dlist node */
	struct container_node data_node[NODE_SIZE] = {
		{ .value = 0 },
		{ .value = 1 },
		{ .value = 2 },
		{ .value = 3 },
		{ .value = 4 }
	};

	sys_dlist_init(&test_list);
	zassert_true(sys_dlist_is_empty(&test_list),
			"sys_dlist_init failed");

	/* Add into a doubly-linked list */
	for (i = 0; i < NODE_SIZE; i++) {
		sys_dlist_append(&test_list, &data_node[i].node);
	}

	/* Enumerate the doubly-linked list */
	count = 0;
	SYS_DLIST_FOR_EACH_CONTAINER(&test_list, cnode, node) {
		zassert_true(cnode->value == count,
				"SYS_DLIST_FOR_EACH_CONTAINER failed");
		count++;
	}
	zassert_true(count == NODE_SIZE,
			"SYS_DLIST_FOR_EACH_CONTAINER failed "
			"expected %d get %d", NODE_SIZE, count);

	/* Enumerate the doubly-linked list */
	count = 0;
	SYS_DLIST_FOR_EACH_CONTAINER_SAFE(&test_list, cnode, s_cnode, node) {
		zassert_true(cnode->value == count,
				"SYS_DLIST_FOR_EACH_CONTAINER_SAFE failed");
		count++;
	}
	zassert_true(count == NODE_SIZE,
			"SYS_DLIST_FOR_EACH_CONTAINER_SAFE failed");
}

/**
 * @brief Test dlist for each function
 *
 * @details Initialize a double-linked list.
 * Appending nodes into the doubly-linked list
 * and enumerate the doubly-linked list.
 *
 * Verify that the value enumerated is equal to the
 * value initialized.If the verification pass,the "for each"
 * style API work.
 *
 * @ingroup lib_dlist_tests
 *
 * @see SYS_DLIST_FOR_EACH_NODE(),SYS_DLIST_FOR_EACH_NODE_SAFE()
 * SYS_DLIST_ITERATE_FROM_NODE()
 */

void test_dlist_for_each(void)
{
	int i, count, val;
	sys_dnode_t *node, *s_node;

	/* Initialize a doubly-linked list */
	struct container_node data_node[NODE_SIZE] = {
		{ .value = 0 },
		{ .value = 1 },
		{ .value = 2 },
		{ .value = 3 },
		{ .value = 4 }
	};

	sys_dlist_init(&test_list);
	zassert_true(sys_dlist_is_empty(&test_list),
			"sys_dlist_init failed");

	for (i = 0; i < NODE_SIZE; i++) {
		sys_dlist_append(&test_list, &data_node[i].node);
	}

	/* Enumerate the doubly-linked list */
	count = 0;
	SYS_DLIST_FOR_EACH_NODE(&test_list, node) {
		val = CONTAINER_OF(node, struct container_node, node)->value;
		zassert_true(val == count, "SYS_DLIST_FOR_EACH_NODE failed"
				" expected %d get %d", count, val);
		count++;
	}
	zassert_true(count == NODE_SIZE,
			"SYS_DLIST_FOR_EACH_NODE failed");

	/* Enumerate the doubly-linked list */
	count = 0;
	SYS_DLIST_FOR_EACH_NODE_SAFE(&test_list, node, s_node) {
		val = CONTAINER_OF(node, struct container_node, node)->value;
		zassert_true(val == count, "SYS_DLIST_FOR_EACH_NODE_SAFE failed"
				" expected %d get %d", count, val);
		count++;
	}
	zassert_true(count == NODE_SIZE,
			"SYS_DLIST_FOR_EACH_NODE_SAFE failed");

	/* Enumerate the doubly-linked list */
	count = 0;
	SYS_DLIST_ITERATE_FROM_NODE(&test_list, node) {
		count++;
		val = ((struct container_node *)node)->value;
		if (val == 1) {
			break;
		}
	}
	zassert_true(count == 2, "SYS_DLIST_ITERATE_FROM_NODE failed");

	count = 0;
	SYS_DLIST_ITERATE_FROM_NODE(&test_list, node) {
		count++;
		val = ((struct container_node *)node)->value;
		if (val == 2) {
			break;
		}
	}
	zassert_true(count == 1, "SYS_DLIST_ITERATE_FROM_NODE failed");

	count = 0;
	SYS_DLIST_ITERATE_FROM_NODE(&test_list, node) {
		count++;
	}
	zassert_true(count == 2, "SYS_DLIST_ITERATE_FROM_NODE failed");
}

/**
 * @brief Test that access the 'head' and 'tail' in constant time
 *
 * @details Defined a double list and append several nodes.
 * defined two pointers---'head','tail'.No matter how many nodes
 * dlist have, get head and tail from the dlist directly.the time
 * complexity of accessing head and tail is O(1).
 *
 * @ingroup lib_dlist_tests
 */
void test_dlist_peak_head_tail(void)
{
	sys_dlist_t list;
	sys_dnode_t node[10];
	sys_dnode_t *head, *tail;

	sys_dlist_init(&list);

	for (int i = 0; i < ARRAY_SIZE(node); i++) {
		sys_dlist_append(&list, &node[i]);
	}

	/* Get 'head' node directly, the time complexity is O(1) */
	head = list.head;
	zassert_true(head == &node[0],
			"dlist can't access 'head' in constant time");

	/* Get 'tail' node directly, the time complexity is O(1) */
	tail = list.tail;
	zassert_true(tail == &node[ARRAY_SIZE(node) - 1],
			"dlist can't access 'tail' in constant time");
}

/**
 * @brief Test that insert or remove operates in constant time
 *
 * @details Defined a double list and append several nodes that
 * a node has two pointers 'pre' and 'next' in pointer area.
 * And define a node to be ready for inserting or removing,
 * 'insert' and 'remove' are the operations with fixed steps and
 * no matter the size of a dlist.
 * Verify that the operations are running in constant time by
 * proving the time complexity is O(1).
 *
 * @ingroup lib_dlist_tests
 */
void test_dlist_insert_and_remove(void)
{
	sys_dlist_t list;
	sys_dlist_t node[10];

	sys_dlist_init(&list);

	for (int i = 0; i < ARRAY_SIZE(node); i++) {
		sys_dlist_append(&list, &node[i]);
	}

	sys_dnode_t node_ins, *insert_at = &node[ARRAY_SIZE(node)/2];
	sys_dnode_t *insert_node = &node_ins;

	/* Insert a node and steps are fixed,the time complexity is O(1) */
	insert_node->prev = insert_at->prev;
	insert_node->next = insert_at;
	insert_at->prev->next = insert_node;
	insert_at->prev = insert_node;
	/*Check if the node is inserted successfully*/
	zassert_true(insert_node == sys_dlist_peek_prev(&list,
		&node[ARRAY_SIZE(node)/2]), "dlist can't insert a node in constant time");
	zassert_true(insert_node == sys_dlist_peek_next(&list,
		&node[ARRAY_SIZE(node)/2 - 1]), "dlist can't insert a node in constant time");

	/* Remove a node and steps are fixed,the time complexity is O(1) */
	insert_node->prev->next = insert_node->next;
	insert_node->next->prev = insert_node->prev;
	/*Check if the node is removed successfully*/
	zassert_true(insert_node != sys_dlist_peek_prev(&list,
		&node[ARRAY_SIZE(node)/2]), "dlist can't insert a node in constant time");
	zassert_true(insert_node != sys_dlist_peek_next(&list,
		&node[ARRAY_SIZE(node)/2 - 1]), "dlist can't remove a node in constant time");
}

/* ztest main entry */
void test_main(void)
{
	ztest_test_suite(test_dlist,
			ztest_unit_test(test_dlist_container),
			ztest_unit_test(test_dlist_for_each),
			ztest_unit_test(test_dlist_peak_head_tail),
			ztest_unit_test(test_dlist_insert_and_remove)
			);
	ztest_run_test_suite(test_dlist);
}