diff --git a/src/tests/list_test.c b/src/tests/list_test.c new file mode 100644 index 00000000..93195bce --- /dev/null +++ b/src/tests/list_test.c @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2011 Michael Brown . + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +/** @file + * + * List function tests + * + */ + +/* Forcibly enable assertions for list_check() */ +#undef NDEBUG + +#include +#include +#include +#include +#include + +/** A list test structure */ +struct list_test { + /** List element */ + struct list_head list; + /** Label */ + char label; +}; + +/** List test elements */ +static struct list_test list_tests[] = { + { .label = '0' }, + { .label = '1' }, + { .label = '2' }, + { .label = '3' }, + { .label = '4' }, + { .label = '5' }, + { .label = '6' }, + { .label = '7' }, + { .label = '8' }, + { .label = '9' }, +}; + +/** Test list */ +static LIST_HEAD ( test_list ); + +/** + * Check list contents are as expected + * + * @v list Test list + * @v expected Expected contents + * @v ok List contents are as expected + */ +static int list_check_contents ( struct list_head *list, + const char *expected ) { + struct list_test *entry; + size_t num_entries = 0; + + /* Determine size of list */ + list_for_each_entry ( entry, list, list ) + num_entries++; + + { + char found[ num_entries + 1 ]; + char found_rev[ num_entries + 1 ]; + char *tmp; + + /* Build up list content string */ + tmp = found; + list_for_each_entry ( entry, list, list ) + *(tmp++) = entry->label; + *tmp = '\0'; + + /* Sanity check reversed list */ + tmp = &found_rev[ sizeof ( found_rev ) - 1 ]; + *tmp = '\0'; + list_for_each_entry_reverse ( entry, list, list ) + *(--tmp) = entry->label; + if ( strcmp ( found, found_rev ) != 0 ) { + printf ( "FAILURE: list reversal mismatch (forward " + "\"%s\", reverse \"%s\")\n", + found, found_rev ); + return 0; + } + + /* Compare against expected content */ + if ( strcmp ( found, expected ) == 0 ) { + return 1; + } else { + printf ( "FAILURE: expected \"%s\", got \"%s\"\n", + expected, found ); + return 0; + } + } +} + +/** + * Report list test result + * + * @v list Test list + * @v expected Expected contents + */ +#define list_contents_ok( list, expected ) do { \ + ok ( list_check_contents ( (list), (expected) ) ); \ + } while ( 0 ) + +/** + * Perform list self-test + * + */ +static void list_test_exec ( void ) { + struct list_head *list = &test_list; + + /* Test initialiser and list_empty() */ + ok ( list_empty ( list ) ); + list_contents_ok ( list, "" ); + + /* Test list_add(), list_add_tail() and list_del() */ + INIT_LIST_HEAD ( list ); + list_contents_ok ( list, "" ); + list_add ( &list_tests[4].list, list ); /* prepend */ + list_contents_ok ( list, "4" ); + list_add ( &list_tests[2].list, list ); /* prepend */ + list_contents_ok ( list, "24" ); + list_add_tail ( &list_tests[7].list, list ); /* append */ + list_contents_ok ( list, "247" ); + list_add ( &list_tests[1].list, &list_tests[4].list ); /* after */ + list_contents_ok ( list, "2417" ); + list_add_tail ( &list_tests[8].list, &list_tests[7].list ); /* before */ + list_contents_ok ( list, "24187" ); + list_del ( &list_tests[4].list ); /* delete middle */ + list_contents_ok ( list, "2187" ); + list_del ( &list_tests[2].list ); /* delete first */ + list_contents_ok ( list, "187" ); + list_del ( &list_tests[7].list ); /* delete last */ + list_contents_ok ( list, "18" ); + list_del ( &list_tests[1].list ); /* delete all */ + list_del ( &list_tests[8].list ); /* delete all */ + list_contents_ok ( list, "" ); + ok ( list_empty ( list ) ); + + /* Test list_entry() */ + INIT_LIST_HEAD ( &list_tests[3].list ); // for list_check() + ok ( list_entry ( &list_tests[3].list, struct list_test, list ) + == &list_tests[3] ); + + /* Test list_first_entry() */ + INIT_LIST_HEAD ( list ); + list_add_tail ( &list_tests[9].list, list ); + list_add_tail ( &list_tests[5].list, list ); + list_add_tail ( &list_tests[6].list, list ); + ok ( list_first_entry ( list, struct list_test, list ) + == &list_tests[9] ); + list_del ( &list_tests[9].list ); + ok ( list_first_entry ( list, struct list_test, list ) + == &list_tests[5] ); + + /* Test list_for_each() */ + INIT_LIST_HEAD ( list ); + list_add_tail ( &list_tests[6].list, list ); + list_add_tail ( &list_tests[7].list, list ); + list_add_tail ( &list_tests[3].list, list ); + { + char *expected = "673"; + struct list_head *pos; + struct list_test *entry; + list_for_each ( pos, list ) { + entry = list_entry ( pos, struct list_test, list ); + ok ( entry->label == *(expected++) ); + } + } + + /* list_for_each_entry() and list_for_each_entry_reverse() are + * already tested as part of list_contents_ok() + */ + + /* Test list_for_each_entry_safe() */ + INIT_LIST_HEAD ( list ); + list_add_tail ( &list_tests[2].list, list ); + list_add_tail ( &list_tests[4].list, list ); + list_add_tail ( &list_tests[1].list, list ); + { + char *expected = "241"; + struct list_test *pos; + struct list_test *tmp; + list_for_each_entry_safe ( pos, tmp, list, list ) { + list_contents_ok ( list, expected ); + list_del ( &pos->list ); + expected++; + list_contents_ok ( list, expected ); + } + } + ok ( list_empty ( list ) ); + + /* Test list_contains() and list_contains_entry() */ + INIT_LIST_HEAD ( list ); + INIT_LIST_HEAD ( &list_tests[3].list ); + list_add ( &list_tests[8].list, list ); + list_add ( &list_tests[5].list, list ); + ok ( list_contains ( &list_tests[8].list, list ) ); + ok ( list_contains_entry ( &list_tests[8], list, list ) ); + ok ( list_contains ( &list_tests[5].list, list ) ); + ok ( list_contains_entry ( &list_tests[5], list, list ) ); + ok ( ! list_contains ( &list_tests[3].list, list ) ); + ok ( ! list_contains_entry ( &list_tests[3], list, list ) ); + + /* Test list_check_contains_entry() */ + INIT_LIST_HEAD ( list ); + list_add ( &list_tests[4].list, list ); + list_add ( &list_tests[0].list, list ); + list_add ( &list_tests[3].list, list ); + list_check_contains_entry ( &list_tests[4], list, list ); + list_check_contains_entry ( &list_tests[0], list, list ); + list_check_contains_entry ( &list_tests[3], list, list ); +} + +/** List self-test */ +struct self_test list_test __self_test = { + .name = "list", + .exec = list_test_exec, +}; diff --git a/src/tests/test.c b/src/tests/test.c index fa9f5797..8a1e27c7 100644 --- a/src/tests/test.c +++ b/src/tests/test.c @@ -137,3 +137,6 @@ static void test_init ( void ) { struct init_fn test_init_fn __init_fn ( INIT_NORMAL ) = { .initialise = test_init, }; + +/* Drag in all applicable self-tests */ +REQUIRE_OBJECT ( list_test );