/** * @file ui_verbs.c * @brief Tests the group K verbs against the recording mock backend. * * Same arrangement as tests/graphics_verbs.c and for the same reason: these * verbs produce nothing a golden file can compare, so the assertions are on what * reached the device. Running a real BASIC line rather than calling the handler * directly exercises the dispatch-table row and the parse handler too, which is * where an added verb is most likely to be wrong. * * The one thing a mock has to fake is a *choice*: a real activation comes from a * keystroke libakgl consumed, and there is no keyboard here. mock_menu_choose() * is that, and it is the only thing in this file that is not a BASIC program. */ #include #include #include #include #include "harness.h" #include "mockdevice.h" #include "testutil.h" /** @brief Bring up a runtime with the mock UI attached and a program loaded. */ static akerr_ErrorContext AKERR_NOIGNORE *run_program(const char *source) { PREPARE_ERROR(errctx); PASS(errctx, harness_start(NULL)); mock_devices_init(); PASS(errctx, akbasic_runtime_set_ui(&HARNESS_RUNTIME, &MOCK_UI)); PASS(errctx, akbasic_runtime_load(&HARNESS_RUNTIME, source)); PASS(errctx, akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); PASS(errctx, akbasic_runtime_run(&HARNESS_RUNTIME, 0)); SUCCEED_RETURN(errctx); } /** @brief The white of palette index 2, and the black of index 1. */ #define WHITE "#ffffff" #define BLACK "#000000" /** * @brief MENU defines, redefines, retires one and retires all. */ static void test_menu(void) { TEST_REQUIRE_OK(run_program("10 MENU 1, \"START\", \"QUIT\"\n")); TEST_REQUIRE_STR(MOCK.log, "menu 0 count 2 [START] [QUIT]\n"); TEST_REQUIRE(HARNESS_RUNTIME.ui_state.menudefined[0], "MENU 1 should have marked menu 1 defined"); harness_stop(); /* A number and nothing else retires that one. */ TEST_REQUIRE_OK(run_program("10 MENU 2, \"A\"\n20 MENU 2\n")); TEST_REQUIRE_STR(MOCK.log, "menu 1 count 1 [A]\n" "menu 1 count 0\n"); TEST_REQUIRE(!HARNESS_RUNTIME.ui_state.menudefined[1], "a bare MENU n should have retired menu n"); harness_stop(); /* No arguments retires them all, the way a bare SOLID does. */ TEST_REQUIRE_OK(run_program("10 MENU 1, \"A\"\n20 MENU 3, \"B\"\n30 MENU\n")); TEST_REQUIRE_STR(MOCK.log, "menu 0 count 1 [A]\n" "menu 2 count 1 [B]\n" "menu 0 count 0\n" "menu 1 count 0\n" "menu 2 count 0\n" "menu 3 count 0\n"); harness_stop(); /* Entries can be expressions, not only literals. */ TEST_REQUIRE_OK(run_program("10 A$ = \"LOAD\"\n20 MENU 1, A$ + \" GAME\"\n")); TEST_REQUIRE_STR(MOCK.log, "menu 0 count 1 [LOAD GAME]\n"); harness_stop(); } /** * @brief MENU refuses a slot outside 1..4, a number where a string belongs, and * more entries than libakgl's menu can hold. */ static void test_menu_refusals(void) { TEST_REQUIRE_OK(run_program("10 MENU 0, \"A\"\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "menu 0 is outside 1..4") != NULL, "MENU 0 should refuse by name, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(run_program("10 MENU 5, \"A\"\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "menu 5 is outside 1..4") != NULL, "MENU 5 should refuse by name, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(run_program("10 MENU 1, 42\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "MENU expected a string") != NULL, "a numeric MENU entry should be a type error, got \"%s\"", HARNESS_OUTPUT); harness_stop(); /* * A seventeenth entry is refused by the verb, and there is deliberately no * test for it here: AKBASIC_MAX_TOKENS is 32, so seventeen strings and their * commas exceed the line's token ceiling and the scanner refuses first. The * check in akbasic_cmd_menu() is unreachable from BASIC as the scanner * stands and is kept anyway -- it is the thing that would matter the day * that ceiling moves, and a MENU that silently wrote past * akgl_UiMenu::items would be a memory error rather than a diagnostic. */ } /** * @brief RMENU reads the highlight without consuming it, and the latch with. * * The read-and-clear on field 1 is the whole contract: without it a program * polling in a loop sees the same choice forever. Same rule BUMP() carries. */ static void test_rmenu(void) { TEST_REQUIRE_OK(harness_start(NULL)); mock_devices_init(); TEST_REQUIRE_OK(akbasic_runtime_set_ui(&HARNESS_RUNTIME, &MOCK_UI)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 MENU 1, \"A\", \"B\", \"C\"\n" "20 PRINT RMENU(1,0)\n" "30 PRINT RMENU(1,1)\n" "40 PRINT RMENU(1,1)\n" "50 PRINT RMENU(1,0)\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); /* * The MENU line first, *then* the choice. Defining a menu resets its * selection and its latch, so a choice made before line 10 runs is a choice * into a menu that does not exist yet -- and line 10 would wipe it. * * Fifteen steps, not one. A step advances the program counter by one *line * number*, not one statement, so line 10 runs on step 11 and line 20 on step * 21; fifteen lands between them. Same reason the frontend's per-frame * budget is 256. */ TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 15)); mock_menu_choose(0, 1); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); /* * 2 -- entries are numbered from one, so the second is 2 and not 1. * -1 -- BASIC true, once. * 0 -- because reading it cleared it. * 2 -- and reading the latch did not disturb the highlight. */ TEST_REQUIRE_STR(HARNESS_OUTPUT, "2\n-1\n0\n2\n"); harness_stop(); } /** @brief RMENU refuses a bad slot and a field outside 0..1. */ static void test_rmenu_refusals(void) { TEST_REQUIRE_OK(run_program("10 PRINT RMENU(9,0)\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "menu 9 is outside 1..4") != NULL, "RMENU should refuse menu 9, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(run_program("10 PRINT RMENU(1,7)\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "field 7 is outside 0..1") != NULL, "RMENU should refuse field 7, got \"%s\"", HARNESS_OUTPUT); harness_stop(); } /** * @brief GETMENU holds the step loop, then assigns the entry that was chosen. * * The property being asserted is that the step *returns* while the program does * not advance -- section 1.6's whole point. A run of a hundred steps with * nothing chosen must leave the program on the GETMENU line and must come back. */ static void test_getmenu_holds(void) { TEST_REQUIRE_OK(harness_start(NULL)); mock_devices_init(); TEST_REQUIRE_OK(akbasic_runtime_set_ui(&HARNESS_RUNTIME, &MOCK_UI)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 MENU 1, \"A\", \"B\", \"C\"\n" "20 GETMENU 1, C%\n" "30 PRINT C%\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 100)); TEST_REQUIRE(HARNESS_RUNTIME.ui_state.waiting, "GETMENU should still be holding after a hundred steps"); TEST_REQUIRE_STR(HARNESS_OUTPUT, ""); mock_menu_choose(0, 2); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(!HARNESS_RUNTIME.ui_state.waiting, "GETMENU should have released"); TEST_REQUIRE_STR(HARNESS_OUTPUT, "3\n"); harness_stop(); } /** * @brief A GETMENU that arrives after the choice does not wait at all. * * The latch survives between frames precisely so an unread activation is never * lost, so a program that gets round to its GETMENU late must find the answer * waiting rather than park for a second one. */ static void test_getmenu_takes_a_waiting_choice(void) { TEST_REQUIRE_OK(harness_start(NULL)); mock_devices_init(); TEST_REQUIRE_OK(akbasic_runtime_set_ui(&HARNESS_RUNTIME, &MOCK_UI)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 MENU 1, \"A\", \"B\", \"C\"\n" "20 GETMENU 1, C%\n" "30 PRINT C%\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); /* Through line 10 only, then choose before line 20 ever runs. */ TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 15)); mock_menu_choose(0, 2); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(!HARNESS_RUNTIME.ui_state.waiting, "GETMENU should not have held when the choice was already made"); TEST_REQUIRE_STR(HARNESS_OUTPUT, "3\n"); harness_stop(); } /** * @brief Retiring the menu underneath a holding GETMENU releases it with 0. * * Reached from BASIC only through an interrupt handler, which is the one thing * that can run a line while the program is parked; the menu is retired directly * here because building a collision interrupt to do it would be testing * something else. */ static void test_getmenu_released_by_retirement(void) { TEST_REQUIRE_OK(harness_start(NULL)); mock_devices_init(); TEST_REQUIRE_OK(akbasic_runtime_set_ui(&HARNESS_RUNTIME, &MOCK_UI)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 MENU 1, \"A\", \"B\"\n" "20 C% = 9\n" "30 GETMENU 1, C%\n" "40 PRINT C%\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 35)); TEST_REQUIRE(HARNESS_RUNTIME.ui_state.waiting, "GETMENU should be holding"); TEST_REQUIRE_OK(MOCK_UI.menu(&MOCK_UI, 0, NULL, 0)); HARNESS_RUNTIME.ui_state.menudefined[0] = false; TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(!HARNESS_RUNTIME.ui_state.waiting, "retiring the menu should have released the GETMENU"); TEST_REQUIRE_STR(HARNESS_OUTPUT, "0\n"); harness_stop(); } /** * @brief Withdrawing the device releases a holding GETMENU rather than wedging it. * * A host is allowed to change its mind about what it lends out, and a script * parked forever on a device that no longer exists is the worse outcome. Same * rule akbasic_input_service() keeps for a withdrawn keyboard. */ static void test_getmenu_released_by_withdrawal(void) { TEST_REQUIRE_OK(harness_start(NULL)); mock_devices_init(); TEST_REQUIRE_OK(akbasic_runtime_set_ui(&HARNESS_RUNTIME, &MOCK_UI)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 MENU 1, \"A\", \"B\"\n" "20 C% = 9\n" "30 GETMENU 1, C%\n" "40 PRINT C%\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); /* Through line 30, where the GETMENU is; see the note in test_rmenu(). */ TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 35)); TEST_REQUIRE(HARNESS_RUNTIME.ui_state.waiting, "GETMENU should be holding"); TEST_REQUIRE_OK(akbasic_runtime_set_ui(&HARNESS_RUNTIME, NULL)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(!HARNESS_RUNTIME.ui_state.waiting, "withdrawing the UI should have released the GETMENU"); /* Released, not chosen: 0 rather than the 9 the variable held. */ TEST_REQUIRE_STR(HARNESS_OUTPUT, "0\n"); harness_stop(); } /** @brief GETMENU refuses a menu that has no entries rather than holding forever. */ static void test_getmenu_needs_a_menu(void) { TEST_REQUIRE_OK(run_program("10 GETMENU 1, C%\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "has no entries") != NULL, "GETMENU on an undefined menu should refuse, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(run_program("10 MENU 1, \"A\"\n20 GETMENU 1, A$\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "expected a numeric variable") != NULL, "GETMENU into a string should be a type error, got \"%s\"", HARNESS_OUTPUT); harness_stop(); } /** @brief DIALOG puts the panel up with a string and takes it down with nothing. */ static void test_dialog(void) { TEST_REQUIRE_OK(run_program("10 DIALOG \"HELLO\"\n20 DIALOG\n")); TEST_REQUIRE_STR(MOCK.log, "dialog HELLO\n" "dialog (none)\n"); harness_stop(); TEST_REQUIRE_OK(run_program("10 DIALOG 42\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "DIALOG expected a string") != NULL, "a numeric DIALOG should be a type error, got \"%s\"", HARNESS_OUTPUT); harness_stop(); } /** * @brief HUD sets each of the five anchors, retires one, and retires all. * * Five and not seven. libakgl's akgl_UiAnchor has the four corners and dead * centre; there is no top-centre or bottom-centre, and this asserts that 5 is * refused rather than quietly mapped onto something. */ static void test_hud(void) { TEST_REQUIRE_OK(run_program("10 HUD 1, 0, \"TL\"\n" "20 HUD 2, 1, \"TR\"\n" "30 HUD 3, 2, \"BL\"\n" "40 HUD 4, 3, \"BR\"\n" "50 HUD 5, 4, \"MID\"\n")); TEST_REQUIRE_STR(MOCK.log, "label 0 anchor 0 TL\n" "label 1 anchor 1 TR\n" "label 2 anchor 2 BL\n" "label 3 anchor 3 BR\n" "label 4 anchor 4 MID\n"); harness_stop(); TEST_REQUIRE_OK(run_program("10 HUD 2, 0, \"X\"\n20 HUD 2\n")); TEST_REQUIRE_STR(MOCK.log, "label 1 anchor 0 X\n" "label 1 anchor 0 (none)\n"); harness_stop(); /* No arguments retires all eight, the way a bare MENU retires all four. */ TEST_REQUIRE_OK(run_program("10 HUD 1, 0, \"X\"\n20 HUD\n")); TEST_REQUIRE_STR(MOCK.log, "label 0 anchor 0 X\n" "label 0 anchor 0 (none)\n" "label 1 anchor 0 (none)\n" "label 2 anchor 0 (none)\n" "label 3 anchor 0 (none)\n" "label 4 anchor 0 (none)\n" "label 5 anchor 0 (none)\n" "label 6 anchor 0 (none)\n" "label 7 anchor 0 (none)\n"); harness_stop(); TEST_REQUIRE_OK(run_program("10 HUD 1, 5, \"NOPE\"\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "anchor 5 is outside 0..4") != NULL, "HUD should refuse anchor 5, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(run_program("10 HUD 9, 0, \"NOPE\"\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "slot 9 is outside 1..8") != NULL, "HUD should refuse slot 9, got \"%s\"", HARNESS_OUTPUT); harness_stop(); /* A slot and an anchor with nothing to say is a typo, not an empty label. */ TEST_REQUIRE_OK(run_program("10 HUD 1, 0\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "a slot, an anchor and a string") != NULL, "a two-argument HUD should be refused, got \"%s\"", HARNESS_OUTPUT); harness_stop(); } /** @brief UISTYLE converts palette indices, defaults its tail, and resets. */ static void test_uistyle(void) { TEST_REQUIRE_OK(run_program("10 UISTYLE 1, 2, 2\n")); TEST_REQUIRE_STR(MOCK.log, "style " BLACK " " WHITE " " WHITE " pad 8.0 radius 0.0\n"); harness_stop(); TEST_REQUIRE_OK(run_program("10 UISTYLE 1, 2, 2, 12, 4\n")); TEST_REQUIRE_STR(MOCK.log, "style " BLACK " " WHITE " " WHITE " pad 12.0 radius 4.0\n"); harness_stop(); TEST_REQUIRE_OK(run_program("10 UISTYLE\n")); TEST_REQUIRE_STR(MOCK.log, "style default\n"); harness_stop(); TEST_REQUIRE_OK(run_program("10 UISTYLE 17, 2, 2\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "RUNTIME ERROR") != NULL, "UISTYLE should refuse palette index 17, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(run_program("10 UISTYLE 1, 2\n")); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "a fill, an edge and an ink") != NULL, "UISTYLE with two colours should be refused, got \"%s\"", HARNESS_OUTPUT); harness_stop(); } /** @brief NEW takes every widget down; a deleted program's menu must not survive it. */ static void test_new_retires_everything(void) { TEST_REQUIRE_OK(harness_start(NULL)); mock_devices_init(); TEST_REQUIRE_OK(akbasic_runtime_set_ui(&HARNESS_RUNTIME, &MOCK_UI)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 MENU 1, \"A\"\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(HARNESS_RUNTIME.ui_state.menudefined[0], "the menu should be up"); mock_log_reset(); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 NEW\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(strstr(MOCK.log, "uiclear") != NULL, "NEW should have retired the widgets, log was \"%s\"", MOCK.log); TEST_REQUIRE(!HARNESS_RUNTIME.ui_state.menudefined[0], "NEW should have forgotten the menu"); harness_stop(); } /** * @brief Every verb in the group refuses by name when no UI device was lent. * * This is the standalone driver's situation and every no-SDL build's, so it is * the common path rather than an edge case. */ static void test_no_device(void) { TEST_REQUIRE_OK(harness_start(NULL)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 MENU 1, \"A\"\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "MENU needs a UI device") != NULL, "MENU without a device should name itself, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(harness_start(NULL)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 DIALOG \"X\"\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "DIALOG needs a UI device") != NULL, "DIALOG without a device should name itself, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(harness_start(NULL)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 HUD 1, 0, \"X\"\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "HUD needs a UI device") != NULL, "HUD without a device should name itself, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(harness_start(NULL)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 UISTYLE 1, 2, 2\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "UISTYLE needs a UI device") != NULL, "UISTYLE without a device should name itself, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(harness_start(NULL)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 GETMENU 1, C%\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "GETMENU needs a UI device") != NULL, "GETMENU without a device should name itself, got \"%s\"", HARNESS_OUTPUT); harness_stop(); TEST_REQUIRE_OK(harness_start(NULL)); TEST_REQUIRE_OK(akbasic_runtime_load(&HARNESS_RUNTIME, "10 PRINT RMENU(1,0)\n")); TEST_REQUIRE_OK(akbasic_runtime_start(&HARNESS_RUNTIME, AKBASIC_MODE_RUN)); TEST_REQUIRE_OK(akbasic_runtime_run(&HARNESS_RUNTIME, 0)); TEST_REQUIRE(strstr(HARNESS_OUTPUT, "RMENU needs a UI device") != NULL, "RMENU without a device should name itself, got \"%s\"", HARNESS_OUTPUT); harness_stop(); } /** @brief A NULL runtime is refused rather than dereferenced. */ static void test_set_ui_validation(void) { TEST_REQUIRE_STATUS(akbasic_runtime_set_ui(NULL, NULL), AKERR_NULLPOINTER); TEST_REQUIRE_STATUS(akbasic_ui_state_init(NULL), AKERR_NULLPOINTER); } int main(void) { test_menu(); test_menu_refusals(); test_rmenu(); test_rmenu_refusals(); test_getmenu_holds(); test_getmenu_takes_a_waiting_choice(); test_getmenu_released_by_retirement(); test_getmenu_released_by_withdrawal(); test_getmenu_needs_a_menu(); test_dialog(); test_hud(); test_uistyle(); test_new_retires_everything(); test_no_device(); test_set_ui_validation(); return akbasic_test_failures; }