/* * 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., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. * * You can also choose to distribute this program under the terms of * the Unmodified Binary Distribution Licence (as given in the file * COPYING.UBDL), provided that you have satisfied its requirements. */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); /** @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 ) /** * Report list iteration test result * * @v macro Iterator macro * @v expected Expected contents * @v pos Iterator * @v ... Arguments to iterator macro */ #define list_iterate_ok( macro, expected, pos, ... ) do { \ const char *check = expected; \ macro ( pos, __VA_ARGS__ ) { \ struct list_test *entry = \ list_entry ( pos, struct list_test, \ list ); \ ok ( entry->label == *(check++) ); \ } \ ok ( *check == '\0' ); \ } while ( 0 ) /** * Report list entry iteration test result * * @v macro Iterator macro * @v expected Expected contents * @v pos Iterator * @v ... Arguments to iterator macro */ #define list_iterate_entry_ok( macro, expected, pos, ... ) do { \ const char *check = expected; \ macro ( pos, __VA_ARGS__ ) { \ ok ( (pos)->label == *(check++) ); \ } \ ok ( *check == '\0' ); \ } while ( 0 ) /** * Perform list self-test * */ static void list_test_exec ( void ) { struct list_head *list = &test_list; struct list_head target_list; struct list_head *target = &target_list; struct list_head *raw_pos; struct list_test *pos; struct list_test *tmp; /* 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_is_singular() */ INIT_LIST_HEAD ( list ); ok ( ! list_is_singular ( list ) ); list_add ( &list_tests[1].list, list ); ok ( list_is_singular ( list ) ); list_add ( &list_tests[3].list, list ); ok ( ! list_is_singular ( list ) ); list_del ( &list_tests[1].list ); ok ( list_is_singular ( list ) ); /* Test list_is_last() */ INIT_LIST_HEAD ( list ); list_add_tail ( &list_tests[6].list, list ); ok ( list_is_last ( &list_tests[6].list, list ) ); list_add_tail ( &list_tests[4].list, list ); ok ( list_is_last ( &list_tests[4].list, list ) ); ok ( ! list_is_last ( &list_tests[6].list, list ) ); /* Test list_cut_position() - empty list */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_cut_position ( target, list, list ); list_contents_ok ( list, "" ); list_contents_ok ( target, "" ); /* Test list_cut_position() - singular list, move nothing */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[4].list, list ); list_cut_position ( target, list, list ); list_contents_ok ( list, "4" ); list_contents_ok ( target, "" ); /* Test list_cut_position() - singular list, move singular entry */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[9].list, list ); list_cut_position ( target, list, &list_tests[9].list ); list_contents_ok ( list, "" ); list_contents_ok ( target, "9" ); /* Test list_cut_position() - multi-entry list, move nothing */ INIT_LIST_HEAD ( list ); list_add_tail ( &list_tests[3].list, list ); list_add_tail ( &list_tests[2].list, list ); list_add_tail ( &list_tests[7].list, list ); INIT_LIST_HEAD ( target ); list_cut_position ( target, list, list ); list_contents_ok ( list, "327" ); list_contents_ok ( target, "" ); /* Test list_cut_position() - multi-entry list, move some */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[8].list, list ); list_add_tail ( &list_tests[0].list, list ); list_add_tail ( &list_tests[9].list, list ); list_add_tail ( &list_tests[3].list, list ); list_add_tail ( &list_tests[2].list, list ); list_cut_position ( target, list, &list_tests[0].list ); list_contents_ok ( list, "932" ); list_contents_ok ( target, "80" ); /* Test list_cut_position() - multi-entry list, move everything */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[3].list, list ); list_add_tail ( &list_tests[5].list, list ); list_add_tail ( &list_tests[4].list, list ); list_add_tail ( &list_tests[7].list, list ); list_add_tail ( &list_tests[1].list, list ); list_cut_position ( target, list, &list_tests[1].list ); list_contents_ok ( list, "" ); list_contents_ok ( target, "35471" ); /* Test list_splice() - empty list */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_splice ( list, target ); list_contents_ok ( list, "" ); list_contents_ok ( target, "" ); /* Test list_splice() - both lists empty */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_splice ( list, target ); list_contents_ok ( target, "" ); /* Test list_splice() - source list empty */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[1].list, target ); list_add_tail ( &list_tests[3].list, target ); list_splice ( list, &list_tests[1].list ); list_contents_ok ( target, "13" ); /* Test list_splice() - destination list empty */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[6].list, list ); list_add_tail ( &list_tests[5].list, list ); list_add_tail ( &list_tests[2].list, list ); list_splice ( list, target ); list_contents_ok ( target, "652" ); /* Test list_splice() - both lists non-empty */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[8].list, list ); list_add_tail ( &list_tests[4].list, list ); list_add_tail ( &list_tests[5].list, list ); list_add_tail ( &list_tests[1].list, target ); list_add_tail ( &list_tests[9].list, target ); list_splice ( list, &list_tests[1].list ); list_contents_ok ( target, "18459" ); /* Test list_splice_tail() - both lists empty */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_splice_tail ( list, target ); list_contents_ok ( target, "" ); /* Test list_splice_tail() - source list empty */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[5].list, target ); list_splice_tail ( list, &list_tests[5].list ); list_contents_ok ( target, "5" ); /* Test list_splice_tail() - destination list empty */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[2].list, list ); list_add_tail ( &list_tests[1].list, list ); list_add_tail ( &list_tests[0].list, list ); list_splice_tail ( list, target ); list_contents_ok ( target, "210" ); /* Test list_splice_tail() - both lists non-empty */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[9].list, list ); list_add_tail ( &list_tests[5].list, list ); list_add_tail ( &list_tests[7].list, list ); list_add_tail ( &list_tests[2].list, target ); list_add_tail ( &list_tests[4].list, target ); list_splice_tail ( list, &list_tests[2].list ); list_contents_ok ( target, "95724" ); /* Test list_splice_init() */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[4].list, list ); list_add_tail ( &list_tests[1].list, target ); list_splice_init ( list, target ); ok ( list_empty ( list ) ); list_contents_ok ( list, "" ); list_contents_ok ( target, "41" ); /* Test list_splice_tail_init() */ INIT_LIST_HEAD ( list ); INIT_LIST_HEAD ( target ); list_add_tail ( &list_tests[3].list, list ); list_add_tail ( &list_tests[2].list, list ); list_add_tail ( &list_tests[5].list, target ); list_splice_tail_init ( list, &list_tests[5].list ); ok ( list_empty ( list ) ); list_contents_ok ( list, "" ); list_contents_ok ( target, "325" ); /* 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() and list_last_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] ); ok ( list_last_entry ( list, struct list_test, list ) == &list_tests[6] ); list_del ( &list_tests[9].list ); ok ( list_first_entry ( list, struct list_test, list ) == &list_tests[5] ); ok ( list_last_entry ( list, struct list_test, list ) == &list_tests[6] ); list_del ( &list_tests[6].list ); ok ( list_first_entry ( list, struct list_test, list ) == &list_tests[5] ); ok ( list_last_entry ( list, struct list_test, list ) == &list_tests[5] ); list_del ( &list_tests[5].list ); ok ( list_first_entry ( list, struct list_test, list ) == NULL ); ok ( list_last_entry ( list, struct list_test, list ) == NULL ); /* Test list_next_entry() and list_prev_entry() */ INIT_LIST_HEAD ( list ); list_add_tail ( &list_tests[5].list, list ); list_add_tail ( &list_tests[3].list, list ); list_add_tail ( &list_tests[1].list, list ); list_add_tail ( &list_tests[7].list, list ); ok ( list_prev_entry ( &list_tests[5], list, list ) == NULL ); ok ( list_next_entry ( &list_tests[5], list, list ) == &list_tests[3] ); ok ( list_prev_entry ( &list_tests[3], list, list ) == &list_tests[5] ); ok ( list_next_entry ( &list_tests[3], list, list ) == &list_tests[1] ); ok ( list_prev_entry ( &list_tests[1], list, list ) == &list_tests[3] ); ok ( list_next_entry ( &list_tests[1], list, list ) == &list_tests[7] ); ok ( list_prev_entry ( &list_tests[7], list, list ) == &list_tests[1] ); ok ( list_next_entry ( &list_tests[7], list, list ) == NULL ); list_del ( &list_tests[7].list ); ok ( list_prev_entry ( &list_tests[1], list, list ) == &list_tests[3] ); ok ( list_next_entry ( &list_tests[1], list, list ) == NULL ); list_del ( &list_tests[3].list ); ok ( list_prev_entry ( &list_tests[5], list, list ) == NULL ); ok ( list_next_entry ( &list_tests[5], list, list ) == &list_tests[1] ); ok ( list_prev_entry ( &list_tests[1], list, list ) == &list_tests[5] ); ok ( list_next_entry ( &list_tests[1], list, list ) == NULL ); /* Test list_is_first_entry() and list_is_last_entry() */ INIT_LIST_HEAD ( list ); list_add_tail ( &list_tests[4].list, list ); list_add_tail ( &list_tests[8].list, list ); list_add_tail ( &list_tests[3].list, list ); list_add_tail ( &list_tests[6].list, list ); ok ( list_is_first_entry ( &list_tests[4], list, list ) ); ok ( ! list_is_first_entry ( &list_tests[8], list, list ) ); ok ( ! list_is_first_entry ( &list_tests[3], list, list ) ); ok ( ! list_is_first_entry ( &list_tests[6], list, list ) ); ok ( ! list_is_last_entry ( &list_tests[4], list, list ) ); ok ( ! list_is_last_entry ( &list_tests[8], list, list ) ); ok ( ! list_is_last_entry ( &list_tests[3], list, list ) ); ok ( list_is_last_entry ( &list_tests[6], list, list ) ); list_del ( &list_tests[4].list ); ok ( list_is_first_entry ( &list_tests[8], list, list ) ); list_del ( &list_tests[8].list ); list_del ( &list_tests[6].list ); ok ( list_is_first_entry ( &list_tests[3], list, list ) ); ok ( list_is_last_entry ( &list_tests[3], list, list ) ); /* 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 ); list_iterate_ok ( list_for_each, "673", raw_pos, list ); /* Test list_for_each_entry() and list_for_each_entry_reverse() */ INIT_LIST_HEAD ( list ); list_add_tail ( &list_tests[3].list, list ); list_add_tail ( &list_tests[2].list, list ); list_add_tail ( &list_tests[6].list, list ); list_add_tail ( &list_tests[9].list, list ); list_iterate_entry_ok ( list_for_each_entry, "3269", pos, list, list ); list_iterate_entry_ok ( list_for_each_entry_reverse, "9623", pos, list, list ); /* 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"; 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_for_each_entry_continue() and * list_for_each_entry_continue_reverse() */ INIT_LIST_HEAD ( list ); list_add_tail ( &list_tests[4].list, list ); list_add_tail ( &list_tests[7].list, list ); list_add_tail ( &list_tests[2].list, list ); list_add_tail ( &list_tests[9].list, list ); list_add_tail ( &list_tests[3].list, list ); pos = &list_tests[7]; list_iterate_entry_ok ( list_for_each_entry_continue, "293", pos, list, list ); ok ( pos == list_entry ( list, struct list_test, list ) ); list_iterate_entry_ok ( list_for_each_entry_continue, "47293", pos, list, list ); pos = &list_tests[3]; list_iterate_entry_ok ( list_for_each_entry_continue, "", pos, list, list ); pos = &list_tests[2]; list_iterate_entry_ok ( list_for_each_entry_continue_reverse, "74", pos, list, list ); ok ( pos == list_entry ( list, struct list_test, list ) ); list_iterate_entry_ok ( list_for_each_entry_continue_reverse, "39274", pos, list, list ); pos = &list_tests[4]; list_iterate_entry_ok ( list_for_each_entry_continue_reverse, "", pos, list, 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, };