/* * Copyright (C) 2024 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 (at your option) 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 * * Editable string tests * */ /* Forcibly enable assertions */ #undef NDEBUG #include #include #include #include #include #include /** An editable string test */ struct editstring_test { /** Initial string, or NULL */ const char *start; /** Key sequence */ const int *keys; /** Length of key sequence */ unsigned int count; /** Expected result */ const char *expected; }; /** Define an inline key sequence */ #define KEYS(...) { __VA_ARGS__ } /** Define an editable string test */ #define EDITSTRING_TEST( name, START, EXPECTED, KEYS ) \ static const int name ## _keys[] = KEYS; \ static struct editstring_test name = { \ .start = START, \ .keys = name ## _keys, \ .count = ( sizeof ( name ## _keys ) / \ sizeof ( name ## _keys[0] ) ), \ .expected = EXPECTED, \ }; /* Simple typing */ EDITSTRING_TEST ( simple, "", "hello world!", KEYS ( 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!' ) ); /* Simple typing from a NULL starting value */ EDITSTRING_TEST ( simple_null, NULL, "hi there", KEYS ( 'h', 'i', ' ', 't', 'h', 'e', 'r', 'e' ) ); /* Insertion */ EDITSTRING_TEST ( insert, "in middle", "in the middle", KEYS ( KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, 't', 'h', 'e', ' ' ) ); /* Backspace at end */ EDITSTRING_TEST ( backspace_end, "byebye", "bye", KEYS ( KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE ) ); /* Backspace of whole string */ EDITSTRING_TEST ( backspace_all, "abc", "", KEYS ( KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE ) ); /* Backspace of empty string */ EDITSTRING_TEST ( backspace_empty, NULL, "", KEYS ( KEY_BACKSPACE ) ); /* Backspace beyond start of string */ EDITSTRING_TEST ( backspace_beyond, "too far", "", KEYS ( KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE, KEY_BACKSPACE ) ); /* Deletion of character at cursor via DEL */ EDITSTRING_TEST ( delete_dc, "go away", "goaway", KEYS ( KEY_HOME, KEY_RIGHT, KEY_RIGHT, KEY_DC ) ); /* Deletion of character at cursor via Ctrl-D */ EDITSTRING_TEST ( delete_ctrl_d, "not here", "nohere", KEYS ( KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, CTRL_D, CTRL_D ) ); /* Deletion of word at end of string */ EDITSTRING_TEST ( word_end, "remove these two words", "remove these ", KEYS ( CTRL_W, CTRL_W ) ); /* Deletion of word at start of string */ EDITSTRING_TEST ( word_start, "no word", "word", KEYS ( CTRL_A, KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, CTRL_W ) ); /* Deletion of word mid-string */ EDITSTRING_TEST ( word_mid, "delete this word", "delete word", KEYS ( KEY_LEFT, KEY_LEFT, KEY_LEFT, KEY_LEFT, CTRL_W ) ); /* Deletion to start of line */ EDITSTRING_TEST ( sol, "everything must go", "go", KEYS ( KEY_LEFT, KEY_LEFT, CTRL_U ) ); /* Delete to end of line */ EDITSTRING_TEST ( eol, "all is lost", "all", KEYS ( KEY_HOME, KEY_RIGHT, KEY_RIGHT, KEY_RIGHT, CTRL_K ) ); /** * Report an editable string test result * * @v test Editable string test * @v file Test code file * @v line Test code line */ static void editstring_okx ( struct editstring_test *test, const char *file, unsigned int line ) { struct edit_string string; unsigned int i; char *actual; int key; /* Initialise editable string */ memset ( &string, 0, sizeof ( string ) ); actual = NULL; init_editstring ( &string, &actual ); /* Set initial string content */ okx ( replace_string ( &string, test->start ) == 0, file, line ); okx ( actual != NULL, file, line ); okx ( string.cursor == ( test->start ? strlen ( test->start ) : 0 ), file, line ); DBGC ( test, "Initial string: \"%s\"\n", actual ); /* Inject keypresses */ for ( i = 0 ; i < test->count ; i++ ) { key = test->keys[i]; okx ( edit_string ( &string, key ) == 0, file, line ); okx ( actual != NULL, file, line ); okx ( string.cursor <= strlen ( actual ), file, line ); DBGC ( test, "After key %#02x (%c): \"%s\"\n", key, ( isprint ( key ) ? key : '.' ), actual ); } /* Verify result string */ okx ( strcmp ( actual, test->expected ) == 0, file, line ); /* Free result string */ free ( actual ); } #define editstring_ok( test ) editstring_okx ( test, __FILE__, __LINE__ ) /** * Perform editable string self-tests * */ static void editstring_test_exec ( void ) { editstring_ok ( &simple ); editstring_ok ( &simple_null ); editstring_ok ( &insert ); editstring_ok ( &backspace_end ); editstring_ok ( &backspace_all ); editstring_ok ( &backspace_empty ); editstring_ok ( &backspace_beyond ); editstring_ok ( &delete_dc ); editstring_ok ( &delete_ctrl_d ); editstring_ok ( &word_end ); editstring_ok ( &word_start ); editstring_ok ( &word_mid ); editstring_ok ( &sol ); editstring_ok ( &eol ); } /** Editable string self-test */ struct self_test editstring_test __self_test = { .name = "editstring", .exec = editstring_test_exec, };