| /* | |
| * Copyright (C) 2024 Michael Brown <mbrown@fensystems.co.uk>. | |
| * | |
| * 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 <stdlib.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| #include <ipxe/keys.h> | |
| #include <ipxe/editstring.h> | |
| #include <ipxe/test.h> | |
| /** 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, | |
| }; |