From 7d850f85aad74ae907290ba6f911d362a0478e61 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:19 -0600 Subject: sandbox: Enable mmc command and legacy images The mmc command is useful for testing mmc disk images in sandbox, so enable it. We also need to enable legacy images so that we can run tests which use them. Disable it for a few avb tests since MMC is not implemented there yet. Signed-off-by: Simon Glass --- test/py/tests/test_android/test_avb.py | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/py/tests/test_android/test_avb.py b/test/py/tests/test_android/test_avb.py index a3f883136b0..bc5c5b55821 100644 --- a/test/py/tests/test_android/test_avb.py +++ b/test/py/tests/test_android/test_avb.py @@ -39,6 +39,7 @@ def test_avb_verify(u_boot_console): @pytest.mark.buildconfigspec('cmd_avb') @pytest.mark.buildconfigspec('cmd_mmc') +@pytest.mark.notbuildconfigspec('sandbox') def test_avb_mmc_uuid(u_boot_console): """Check if 'avb get_uuid' works, compare results with 'part list mmc 1' output @@ -97,6 +98,7 @@ def test_avb_is_unlocked(u_boot_console): @pytest.mark.buildconfigspec('cmd_avb') @pytest.mark.buildconfigspec('cmd_mmc') +@pytest.mark.notbuildconfigspec('sandbox') def test_avb_mmc_read(u_boot_console): """Test mmc read operation """ -- cgit v1.2.3 From 0e38bd848d41bcfc7a113603ee37805016a09a42 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:32 -0600 Subject: video: Add font functions to the vidconsole API Support for fonts currently depends on the type of vidconsole in use. Add two new methods to enumerate fonts and to set the font. Fix a few other method comments while we are here. Signed-off-by: Simon Glass --- test/cmd/font.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/cmd/font.c b/test/cmd/font.c index 7a4156ade62..adb353965a7 100644 --- a/test/cmd/font.c +++ b/test/cmd/font.c @@ -33,7 +33,7 @@ static int font_test_base(struct unit_test_state *uts) ut_assertok(ut_check_console_end(uts)); ut_asserteq_str("nimbus_sans_l_regular", - vidconsole_get_font(dev, &size)); + vidconsole_get_font_size(dev, &size)); ut_asserteq(18, size); max_metrics = 1; @@ -53,14 +53,14 @@ static int font_test_base(struct unit_test_state *uts) ut_assertok(ut_check_console_end(uts)); ut_asserteq_str("cantoraone_regular", - vidconsole_get_font(dev, &size)); + vidconsole_get_font_size(dev, &size)); ut_asserteq(40, size); ut_assertok(run_command("font size 30", 0)); ut_assertok(ut_check_console_end(uts)); ut_asserteq_str("cantoraone_regular", - vidconsole_get_font(dev, &size)); + vidconsole_get_font_size(dev, &size)); ut_asserteq(30, size); return 0; -- cgit v1.2.3 From 2175e76a51e53798ee4e19903b368a7e6c98356a Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:33 -0600 Subject: bootstd: Read the Operating System name for distro/scripts Add the concept of an OS name to the bootflow. This typically includes the OS name, version and kernel version. Implement this for the distro and script bootmeths so that it works with Armbian and older version of Fedora. Signed-off-by: Simon Glass --- test/boot/bootflow.c | 1 + 1 file changed, 1 insertion(+) (limited to 'test') diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index e1e07082105..3296316cf0d 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -188,6 +188,7 @@ static int bootflow_cmd_info(struct unit_test_state *uts) ut_assert_nextline("Filename: /extlinux/extlinux.conf"); ut_assert_nextlinen("Buffer: "); ut_assert_nextline("Size: 253 (595 bytes)"); + ut_assert_nextline("OS: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)"); ut_assert_nextline("Error: 0"); ut_assert_console_end(); -- cgit v1.2.3 From 24d8e1b37b90760a6c9867f37210aa4b1f2e8f63 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:34 -0600 Subject: bootstd: Allow reading a logo for the OS Some operating systems provide a logo in bmp format. Read this in if present so it can be displayed in the menu. Signed-off-by: Simon Glass --- test/boot/bootflow.c | 1 + 1 file changed, 1 insertion(+) (limited to 'test') diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 3296316cf0d..00dfd990687 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -189,6 +189,7 @@ static int bootflow_cmd_info(struct unit_test_state *uts) ut_assert_nextlinen("Buffer: "); ut_assert_nextline("Size: 253 (595 bytes)"); ut_assert_nextline("OS: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)"); + ut_assert_nextline("Logo: (none)"); ut_assert_nextline("Error: 0"); ut_assert_console_end(); -- cgit v1.2.3 From fe93c14b4c62c47120bf95a79269fe94779c21f4 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:39 -0600 Subject: expo: Add basic tests Add some tests for the expo, including setting up and rendering an expo. Signed-off-by: Simon Glass --- test/boot/Makefile | 2 + test/boot/expo.c | 539 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 541 insertions(+) create mode 100644 test/boot/expo.c (limited to 'test') diff --git a/test/boot/Makefile b/test/boot/Makefile index d724629d3b0..22ed61c8fa0 100644 --- a/test/boot/Makefile +++ b/test/boot/Makefile @@ -5,6 +5,8 @@ obj-$(CONFIG_BOOTSTD) += bootdev.o bootstd_common.o bootflow.o bootmeth.o obj-$(CONFIG_FIT) += image.o +obj-$(CONFIG_EXPO) += expo.o + ifdef CONFIG_OF_LIVE obj-$(CONFIG_BOOTMETH_VBE_SIMPLE) += vbe_simple.o endif diff --git a/test/boot/expo.c b/test/boot/expo.c new file mode 100644 index 00000000000..7104dff05e8 --- /dev/null +++ b/test/boot/expo.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2022 Google LLC + * Written by Simon Glass + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "bootstd_common.h" +#include "../../boot/scene_internal.h" + +enum { + /* scenes */ + SCENE1 = 7, + SCENE2, + + /* objects */ + OBJ_LOGO, + OBJ_TEXT, + OBJ_TEXT2, + OBJ_MENU, + OBJ_MENU_TITLE, + + /* strings */ + STR_TEXT, + STR_TEXT2, + STR_MENU_TITLE, + STR_POINTER_TEXT, + + STR_ITEM1_LABEL, + STR_ITEM1_DESC, + STR_ITEM1_KEY, + STR_ITEM1_PREVIEW, + + STR_ITEM2_LABEL, + STR_ITEM2_DESC, + STR_ITEM2_KEY, + STR_ITEM2_PREVIEW, + + /* menu items */ + ITEM1, + ITEM1_LABEL, + ITEM1_DESC, + ITEM1_KEY, + ITEM1_PREVIEW, + + ITEM2, + ITEM2_LABEL, + ITEM2_DESC, + ITEM2_KEY, + ITEM2_PREVIEW, + + /* pointer to current item */ + POINTER_TEXT, +}; + +#define BAD_POINTER ((void *)1) + +/* names for various things */ +#define EXPO_NAME "my menus" +#define SCENE_NAME1 "main" +#define SCENE_NAME2 "second" +#define SCENE_TITLE "Main Menu" +#define LOGO_NAME "logo" + +/* Check base expo support */ +static int expo_base(struct unit_test_state *uts) +{ + struct udevice *dev; + struct expo *exp; + ulong start_mem; + char name[100]; + int i; + + ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev)); + + start_mem = ut_check_free(); + + exp = NULL; + strcpy(name, EXPO_NAME); + ut_assertok(expo_new(name, NULL, &exp)); + *name = '\0'; + ut_assertnonnull(exp); + ut_asserteq(0, exp->scene_id); + ut_asserteq(0, exp->next_id); + + /* Make sure the name was allocated */ + ut_assertnonnull(exp->name); + ut_asserteq_str(EXPO_NAME, exp->name); + + ut_assertok(expo_set_display(exp, dev)); + expo_destroy(exp); + ut_assertok(ut_check_delta(start_mem)); + + /* test handling out-of-memory conditions */ + for (i = 0; i < 2; i++) { + struct expo *exp2; + + malloc_enable_testing(i); + exp2 = BAD_POINTER; + ut_asserteq(-ENOMEM, expo_new(EXPO_NAME, NULL, &exp2)); + ut_asserteq_ptr(BAD_POINTER, exp2); + malloc_disable_testing(); + } + + return 0; +} +BOOTSTD_TEST(expo_base, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check creating a scene */ +static int expo_scene(struct unit_test_state *uts) +{ + struct scene *scn; + struct expo *exp; + ulong start_mem; + char name[100]; + int id; + + start_mem = ut_check_free(); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + + scn = NULL; + ut_asserteq(0, exp->next_id); + strcpy(name, SCENE_NAME1); + id = scene_new(exp, name, SCENE1, &scn); + *name = '\0'; + ut_assertnonnull(scn); + ut_asserteq(SCENE1, id); + ut_asserteq(SCENE1 + 1, exp->next_id); + ut_asserteq_ptr(exp, scn->expo); + + /* Make sure the name was allocated */ + ut_assertnonnull(scn->name); + ut_asserteq_str(SCENE_NAME1, scn->name); + + /* Set the title */ + strcpy(name, SCENE_TITLE); + ut_assertok(scene_title_set(scn, name)); + *name = '\0'; + ut_assertnonnull(scn->title); + ut_asserteq_str(SCENE_TITLE, scn->title); + + /* Use an allocated ID */ + scn = NULL; + id = scene_new(exp, SCENE_NAME2, 0, &scn); + ut_assertnonnull(scn); + ut_asserteq(SCENE2, id); + ut_asserteq(SCENE2 + 1, exp->next_id); + ut_asserteq_ptr(exp, scn->expo); + + ut_asserteq_str(SCENE_NAME2, scn->name); + + expo_destroy(exp); + + ut_assertok(ut_check_delta(start_mem)); + + return 0; +} +BOOTSTD_TEST(expo_scene, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check creating a scene with objects */ +static int expo_object(struct unit_test_state *uts) +{ + struct scene_obj_img *img; + struct scene_obj_txt *txt; + struct scene *scn; + struct expo *exp; + ulong start_mem; + char name[100]; + char *data; + int id; + + start_mem = ut_check_free(); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + id = scene_new(exp, SCENE_NAME1, SCENE1, &scn); + ut_assert(id > 0); + + ut_asserteq(0, scene_obj_count(scn)); + + data = NULL; + strcpy(name, LOGO_NAME); + id = scene_img(scn, name, OBJ_LOGO, data, &img); + ut_assert(id > 0); + *name = '\0'; + ut_assertnonnull(img); + ut_asserteq(OBJ_LOGO, id); + ut_asserteq(OBJ_LOGO + 1, exp->next_id); + ut_asserteq_ptr(scn, img->obj.scene); + ut_asserteq(SCENEOBJT_IMAGE, img->obj.type); + + ut_asserteq_ptr(data, img->data); + + /* Make sure the name was allocated */ + ut_assertnonnull(scn->name); + ut_asserteq_str(SCENE_NAME1, scn->name); + + ut_asserteq(1, scene_obj_count(scn)); + + id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", &txt); + ut_assert(id > 0); + ut_assertnonnull(txt); + ut_asserteq(OBJ_TEXT, id); + ut_asserteq(SCENEOBJT_TEXT, txt->obj.type); + ut_asserteq(2, scene_obj_count(scn)); + + /* Check passing NULL as the final parameter */ + id = scene_txt_str(scn, "text2", OBJ_TEXT2, STR_TEXT2, "another string", + NULL); + ut_assert(id > 0); + ut_asserteq(3, scene_obj_count(scn)); + + expo_destroy(exp); + + ut_assertok(ut_check_delta(start_mem)); + + return 0; +} +BOOTSTD_TEST(expo_object, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check setting object attributes */ +static int expo_object_attr(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu; + struct scene_obj_img *img; + struct scene_obj_txt *txt; + struct scene *scn; + struct expo *exp; + ulong start_mem; + char name[100]; + char *data; + int id; + + start_mem = ut_check_free(); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + id = scene_new(exp, SCENE_NAME1, SCENE1, &scn); + ut_assert(id > 0); + + data = NULL; + id = scene_img(scn, LOGO_NAME, OBJ_LOGO, data, &img); + ut_assert(id > 0); + + ut_assertok(scene_obj_set_pos(scn, OBJ_LOGO, 123, 456)); + ut_asserteq(123, img->obj.x); + ut_asserteq(456, img->obj.y); + + ut_asserteq(-ENOENT, scene_obj_set_pos(scn, OBJ_TEXT2, 0, 0)); + + id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", &txt); + ut_assert(id > 0); + + strcpy(name, "font2"); + ut_assertok(scene_txt_set_font(scn, OBJ_TEXT, name, 42)); + ut_asserteq_ptr(name, txt->font_name); + ut_asserteq(42, txt->font_size); + + ut_asserteq(-ENOENT, scene_txt_set_font(scn, OBJ_TEXT2, name, 42)); + + id = scene_menu(scn, "main", OBJ_MENU, &menu); + ut_assert(id > 0); + + ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_TEXT)); + + ut_asserteq(-ENOENT, scene_menu_set_title(scn, OBJ_TEXT2, OBJ_TEXT)); + ut_asserteq(-EINVAL, scene_menu_set_title(scn, OBJ_MENU, OBJ_TEXT2)); + + expo_destroy(exp); + + ut_assertok(ut_check_delta(start_mem)); + + return 0; +} +BOOTSTD_TEST(expo_object_attr, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check creating a scene with a menu */ +static int expo_object_menu(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu; + struct scene_menitem *item; + int id, label_id, desc_id, key_id, pointer_id, preview_id; + struct scene_obj_txt *ptr, *name1, *desc1, *key1, *tit, *prev1; + struct scene *scn; + struct expo *exp; + ulong start_mem; + + start_mem = ut_check_free(); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + id = scene_new(exp, SCENE_NAME1, SCENE1, &scn); + ut_assert(id > 0); + + id = scene_menu(scn, "main", OBJ_MENU, &menu); + ut_assert(id > 0); + ut_assertnonnull(menu); + ut_asserteq(OBJ_MENU, id); + ut_asserteq(SCENEOBJT_MENU, menu->obj.type); + ut_asserteq(0, menu->title_id); + ut_asserteq(0, menu->pointer_id); + + ut_assertok(scene_obj_set_pos(scn, OBJ_MENU, 50, 400)); + ut_asserteq(50, menu->obj.x); + ut_asserteq(400, menu->obj.y); + + id = scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE, + "Main Menu", &tit); + ut_assert(id > 0); + ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_MENU_TITLE)); + ut_asserteq(OBJ_MENU_TITLE, menu->title_id); + + pointer_id = scene_txt_str(scn, "cur_item", POINTER_TEXT, + STR_POINTER_TEXT, ">", &ptr); + ut_assert(pointer_id > 0); + + ut_assertok(scene_menu_set_pointer(scn, OBJ_MENU, POINTER_TEXT)); + ut_asserteq(POINTER_TEXT, menu->pointer_id); + + label_id = scene_txt_str(scn, "label1", ITEM1_LABEL, STR_ITEM1_LABEL, + "Play", &name1); + ut_assert(label_id > 0); + + desc_id = scene_txt_str(scn, "desc1", ITEM1_DESC, STR_ITEM1_DESC, + "Lord Melchett", &desc1); + ut_assert(desc_id > 0); + + key_id = scene_txt_str(scn, "item1-key", ITEM1_KEY, STR_ITEM1_KEY, "1", + &key1); + ut_assert(key_id > 0); + + preview_id = scene_txt_str(scn, "item1-preview", ITEM1_PREVIEW, + STR_ITEM1_PREVIEW, "(preview1)", &prev1); + ut_assert(preview_id > 0); + + id = scene_menuitem(scn, OBJ_MENU, "linux", ITEM1, ITEM1_KEY, + ITEM1_LABEL, ITEM1_DESC, ITEM1_PREVIEW, 0, &item); + ut_asserteq(ITEM1, id); + ut_asserteq(id, item->id); + ut_asserteq(key_id, item->key_id); + ut_asserteq(label_id, item->label_id); + ut_asserteq(desc_id, item->desc_id); + ut_asserteq(preview_id, item->preview_id); + + /* adding an item should cause the first item to become current */ + ut_asserteq(id, menu->cur_item_id); + + /* the title should be at the top */ + ut_asserteq(menu->obj.x, tit->obj.x); + ut_asserteq(menu->obj.y, tit->obj.y); + + /* the first item should be next */ + ut_asserteq(menu->obj.x, name1->obj.x); + ut_asserteq(menu->obj.y + 32, name1->obj.y); + + ut_asserteq(menu->obj.x + 230, key1->obj.x); + ut_asserteq(menu->obj.y + 32, key1->obj.y); + + ut_asserteq(menu->obj.x + 200, ptr->obj.x); + ut_asserteq(menu->obj.y + 32, ptr->obj.y); + + ut_asserteq(menu->obj.x + 280, desc1->obj.x); + ut_asserteq(menu->obj.y + 32, desc1->obj.y); + + ut_asserteq(-4, prev1->obj.x); + ut_asserteq(menu->obj.y + 32, prev1->obj.y); + ut_asserteq(false, prev1->obj.hide); + + expo_destroy(exp); + + ut_assertok(ut_check_delta(start_mem)); + + return 0; +} +BOOTSTD_TEST(expo_object_menu, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check rendering a scene */ +static int expo_render_image(struct unit_test_state *uts) +{ + struct scene_obj_menu *menu; + struct scene *scn, *scn2; + struct expo_action act; + struct scene_obj *obj; + struct udevice *dev; + struct expo *exp; + int id; + + console_record_reset_enable(); + ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev)); + + ut_assertok(expo_new(EXPO_NAME, NULL, &exp)); + id = scene_new(exp, SCENE_NAME1, SCENE1, &scn); + ut_assert(id > 0); + ut_assertok(expo_set_display(exp, dev)); + + id = scene_img(scn, "logo", OBJ_LOGO, video_get_u_boot_logo(), NULL); + ut_assert(id > 0); + ut_assertok(scene_obj_set_pos(scn, OBJ_LOGO, 50, 20)); + + id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", NULL); + ut_assert(id > 0); + ut_assertok(scene_txt_set_font(scn, OBJ_TEXT, "cantoraone_regular", + 40)); + ut_assertok(scene_obj_set_pos(scn, OBJ_TEXT, 400, 100)); + + id = scene_txt_str(scn, "text", OBJ_TEXT2, STR_TEXT2, "another string", + NULL); + ut_assert(id > 0); + ut_assertok(scene_txt_set_font(scn, OBJ_TEXT2, "nimbus_sans_l_regular", + 60)); + ut_assertok(scene_obj_set_pos(scn, OBJ_TEXT2, 200, 600)); + + id = scene_menu(scn, "main", OBJ_MENU, &menu); + ut_assert(id > 0); + + id = scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE, + "Main Menu", NULL); + ut_assert(id > 0); + ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_MENU_TITLE)); + + id = scene_txt_str(scn, "cur_item", POINTER_TEXT, STR_POINTER_TEXT, ">", + NULL); + ut_assert(id > 0); + ut_assertok(scene_menu_set_pointer(scn, OBJ_MENU, POINTER_TEXT)); + + id = scene_txt_str(scn, "label1", ITEM1_LABEL, STR_ITEM1_LABEL, "Play", + NULL); + ut_assert(id > 0); + id = scene_txt_str(scn, "item1 txt", ITEM1_DESC, STR_ITEM1_DESC, + "Lord Melchett", NULL); + ut_assert(id > 0); + id = scene_txt_str(scn, "item1-key", ITEM1_KEY, STR_ITEM1_KEY, "1", + NULL); + ut_assert(id > 0); + id = scene_img(scn, "item1-preview", ITEM1_PREVIEW, + video_get_u_boot_logo(), NULL); + id = scene_menuitem(scn, OBJ_MENU, "item1", ITEM1, ITEM1_KEY, + ITEM1_LABEL, ITEM1_DESC, ITEM1_PREVIEW, 0, NULL); + ut_assert(id > 0); + + id = scene_txt_str(scn, "label2", ITEM2_LABEL, STR_ITEM2_LABEL, "Now", + NULL); + ut_assert(id > 0); + id = scene_txt_str(scn, "item2 txt", ITEM2_DESC, STR_ITEM2_DESC, + "Lord Percy", NULL); + ut_assert(id > 0); + id = scene_txt_str(scn, "item2-key", ITEM2_KEY, STR_ITEM2_KEY, "2", + NULL); + ut_assert(id > 0); + id = scene_img(scn, "item2-preview", ITEM2_PREVIEW, + video_get_u_boot_logo(), NULL); + ut_assert(id > 0); + + id = scene_menuitem(scn, OBJ_MENU, "item2", ITEM2, ITEM2_KEY, + ITEM2_LABEL, ITEM2_DESC, ITEM2_PREVIEW, 0, NULL); + ut_assert(id > 0); + + ut_assertok(scene_obj_set_pos(scn, OBJ_MENU, 50, 400)); + + scn2 = expo_lookup_scene_id(exp, SCENE1); + ut_asserteq_ptr(scn, scn2); + scn2 = expo_lookup_scene_id(exp, SCENE2); + ut_assertnull(scn2); + + /* render without a scene */ + ut_asserteq(-ECHILD, expo_render(exp)); + + /* render it */ + expo_set_scene_id(exp, SCENE1); + ut_assertok(expo_render(exp)); + + /* move down */ + ut_assertok(expo_send_key(exp, BKEY_DOWN)); + + ut_assertok(expo_action_get(exp, &act)); + + ut_asserteq(EXPOACT_POINT, act.type); + ut_asserteq(ITEM2, act.select.id); + ut_assertok(expo_render(exp)); + + /* make sure only the preview for the second item is shown */ + obj = scene_obj_find(scn, ITEM1_PREVIEW, SCENEOBJT_NONE); + ut_asserteq(true, obj->hide); + + obj = scene_obj_find(scn, ITEM2_PREVIEW, SCENEOBJT_NONE); + ut_asserteq(false, obj->hide); + + /* select it */ + ut_assertok(expo_send_key(exp, BKEY_SELECT)); + + ut_assertok(expo_action_get(exp, &act)); + ut_asserteq(EXPOACT_SELECT, act.type); + ut_asserteq(ITEM2, act.select.id); + + /* make sure the action doesn't come again */ + ut_asserteq(-EAGAIN, expo_action_get(exp, &act)); + + /* make sure there was no console output */ + ut_assert_console_end(); + + /* now try in text mode */ + exp_set_text_mode(exp, true); + ut_assertok(expo_render(exp)); + + ut_assert_nextline("U-Boot : Boot Menu"); + ut_assert_nextline("%s", ""); + ut_assert_nextline("Main Menu"); + ut_assert_nextline("%s", ""); + ut_assert_nextline(" 1 Play Lord Melchett"); + ut_assert_nextline(" > 2 Now Lord Percy"); + + /* Move back up to the first item */ + ut_assertok(expo_send_key(exp, BKEY_UP)); + + ut_assertok(expo_action_get(exp, &act)); + + ut_asserteq(EXPOACT_POINT, act.type); + ut_asserteq(ITEM1, act.select.id); + + ut_assertok(expo_render(exp)); + ut_assert_nextline("U-Boot : Boot Menu"); + ut_assert_nextline("%s", ""); + ut_assert_nextline("Main Menu"); + ut_assert_nextline("%s", ""); + ut_assert_nextline(" > 1 Play Lord Melchett"); + ut_assert_nextline(" 2 Now Lord Percy"); + + ut_assert_console_end(); + + expo_destroy(exp); + + return 0; +} +BOOTSTD_TEST(expo_render_image, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -- cgit v1.2.3 From d985f1dbddb241c21a9150abf59dd386ba1ffe05 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:41 -0600 Subject: bootstd: Add a test for the bootstd menu Add a test which checks that two operating systems can be displayed in a menu, allowing one to be selected. Enable a few things on snow so that the unit tests build. Signed-off-by: Simon Glass --- test/boot/bootflow.c | 51 ++++++++ test/py/tests/bootstd/armbian.bmp.xz | Bin 0 -> 1384 bytes test/py/tests/bootstd/mmc4.img.xz | Bin 0 -> 7072 bytes test/py/tests/test_ut.py | 218 ++++++++++++++++++++++++++++++++--- 4 files changed, 250 insertions(+), 19 deletions(-) create mode 100644 test/py/tests/bootstd/armbian.bmp.xz create mode 100644 test/py/tests/bootstd/mmc4.img.xz (limited to 'test') diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index 00dfd990687..abafa44b2ed 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -11,15 +11,21 @@ #include #include #include +#include #include #ifdef CONFIG_SANDBOX #include #endif +#include #include #include #include #include "bootstd_common.h" +DECLARE_GLOBAL_DATA_PTR; + +extern U_BOOT_DRIVER(bootmeth_script); + static int inject_response(struct unit_test_state *uts) { /* @@ -462,3 +468,48 @@ static int bootflow_cmd_boot(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootflow_cmd_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/* Check 'bootflow menu' to select a bootflow */ +static int bootflow_cmd_menu(struct unit_test_state *uts) +{ + static const char *order[] = {"mmc2", "mmc1", "mmc4", NULL}; + struct udevice *dev, *bootstd; + struct bootstd_priv *std; + const char **old_order; + char prev[3]; + ofnode node; + + /* Enable the mmc4 node since we need a second bootflow */ + node = ofnode_path("/mmc4"); + ut_assertok(lists_bind_fdt(gd->dm_root, node, &dev, NULL, false)); + + /* Enable the script bootmeth too */ + ut_assertok(uclass_first_device_err(UCLASS_BOOTSTD, &bootstd)); + ut_assertok(device_bind(bootstd, DM_DRIVER_REF(bootmeth_script), + "bootmeth_script", 0, ofnode_null(), &dev)); + + /* Change the order to include mmc4 */ + std = dev_get_priv(bootstd); + old_order = std->bootdev_order; + std->bootdev_order = order; + + console_record_reset_enable(); + ut_assertok(run_command("bootflow scan", 0)); + ut_assert_console_end(); + + /* Restore the order used by the device tree */ + std->bootdev_order = old_order; + + /* Add keypresses to move to and select the second one in the list */ + prev[0] = CTL_CH('n'); + prev[1] = '\r'; + prev[2] = '\0'; + ut_asserteq(2, console_in_puts(prev)); + + ut_assertok(run_command("bootflow menu", 0)); + ut_assert_nextline("Selected: Armbian"); + ut_assert_console_end(); + + return 0; +} +BOOTSTD_TEST(bootflow_cmd_menu, UT_TESTF_DM | UT_TESTF_SCAN_FDT); diff --git a/test/py/tests/bootstd/armbian.bmp.xz b/test/py/tests/bootstd/armbian.bmp.xz new file mode 100644 index 00000000000..ad137ea6e6d Binary files /dev/null and b/test/py/tests/bootstd/armbian.bmp.xz differ diff --git a/test/py/tests/bootstd/mmc4.img.xz b/test/py/tests/bootstd/mmc4.img.xz new file mode 100644 index 00000000000..f4db011969f Binary files /dev/null and b/test/py/tests/bootstd/mmc4.img.xz differ diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py index bab8b97672b..6958fabfa34 100644 --- a/test/py/tests/test_ut.py +++ b/test/py/tests/test_ut.py @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 # Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved. +import getpass import gzip import os import os.path @@ -13,34 +14,217 @@ def mkdir_cond(dirname): """Create a directory if it doesn't already exist Args: - dirname: Name of directory to create + dirname (str): Name of directory to create """ if not os.path.exists(dirname): os.mkdir(dirname) -def setup_bootflow_image(u_boot_console): - """Create a 20MB disk image with a single FAT partition""" - cons = u_boot_console - fname = os.path.join(cons.config.source_dir, 'mmc1.img') +def setup_image(cons, mmc_dev, part_type): + """Create a 20MB disk image with a single partition + + Args: + cons (ConsoleBase): Console to use + mmc_dev (int): MMC device number to use, e.g. 1 + part_type (int): Partition type, e.g. 0xc for FAT32 + + Returns: + tuple: + str: Filename of MMC image + str: Directory name of 'mnt' directory + """ + fname = os.path.join(cons.config.source_dir, f'mmc{mmc_dev}.img') mnt = os.path.join(cons.config.persistent_data_dir, 'mnt') mkdir_cond(mnt) u_boot_utils.run_and_log(cons, 'qemu-img create %s 20M' % fname) u_boot_utils.run_and_log(cons, 'sudo sfdisk %s' % fname, - stdin=b'type=c') + stdin=f'type={part_type:x}'.encode('utf-8')) + return fname, mnt + +def mount_image(cons, fname, mnt, fstype): + """Create a filesystem and mount it on partition 1 + + Args: + cons (ConsoleBase): Console to use + fname (str): Filename of MMC image + mnt (str): Directory name of 'mnt' directory + fstype (str): Filesystem type ('vfat' or 'ext4') + + Returns: + str: Name of loop device used + """ + out = u_boot_utils.run_and_log(cons, 'sudo losetup --show -f -P %s' % fname) + loop = out.strip() + part = f'{loop}p1' + u_boot_utils.run_and_log(cons, f'sudo mkfs.{fstype} {part}') + opts = '' + if fstype == 'vfat': + opts += ' -o uid={os.getuid()},gid={os.getgid()}' + u_boot_utils.run_and_log(cons, f'sudo mount -o loop {part} {mnt}{opts}') + u_boot_utils.run_and_log(cons, f'sudo chown {getpass.getuser()} {mnt}') + return loop + +def copy_prepared_image(cons, mmc_dev, fname): + """Use a prepared image since we cannot create one + + Args: + cons (ConsoleBase): Console touse + mmc_dev (int): MMC device number + fname (str): Filename of MMC image + """ + infname = os.path.join(cons.config.source_dir, + f'test/py/tests/bootstd/mmc{mmc_dev}.img.xz') + u_boot_utils.run_and_log( + cons, + ['sh', '-c', 'xz -dc %s >%s' % (infname, fname)]) + +def setup_bootmenu_image(cons): + """Create a 20MB disk image with a single ext4 partition + + This is modelled on Armbian 22.08 Jammy + """ + mmc_dev = 4 + fname, mnt = setup_image(cons, mmc_dev, 0x83) loop = None mounted = False complete = False try: - out = u_boot_utils.run_and_log(cons, - 'sudo losetup --show -f -P %s' % fname) - loop = out.strip() - fatpart = '%sp1' % loop - u_boot_utils.run_and_log(cons, 'sudo mkfs.vfat %s' % fatpart) + loop = mount_image(cons, fname, mnt, 'ext4') + mounted = True + + vmlinux = 'Image' + initrd = 'uInitrd' + dtbdir = 'dtb' + script = '''# DO NOT EDIT THIS FILE +# +# Please edit /boot/armbianEnv.txt to set supported parameters +# + +setenv load_addr "0x9000000" +setenv overlay_error "false" +# default values +setenv rootdev "/dev/mmcblk%dp1" +setenv verbosity "1" +setenv console "both" +setenv bootlogo "false" +setenv rootfstype "ext4" +setenv docker_optimizations "on" +setenv earlycon "off" + +echo "Boot script loaded from ${devtype} ${devnum}" + +if test -e ${devtype} ${devnum} ${prefix}armbianEnv.txt; then + load ${devtype} ${devnum} ${load_addr} ${prefix}armbianEnv.txt + env import -t ${load_addr} ${filesize} +fi + +if test "${logo}" = "disabled"; then setenv logo "logo.nologo"; fi + +if test "${console}" = "display" || test "${console}" = "both"; then setenv consoleargs "console=tty1"; fi +if test "${console}" = "serial" || test "${console}" = "both"; then setenv consoleargs "console=ttyS2,1500000 ${consoleargs}"; fi +if test "${earlycon}" = "on"; then setenv consoleargs "earlycon ${consoleargs}"; fi +if test "${bootlogo}" = "true"; then setenv consoleargs "bootsplash.bootfile=bootsplash.armbian ${consoleargs}"; fi + +# get PARTUUID of first partition on SD/eMMC the boot script was loaded from +if test "${devtype}" = "mmc"; then part uuid mmc ${devnum}:1 partuuid; fi + +setenv bootargs "root=${rootdev} rootwait rootfstype=${rootfstype} ${consoleargs} consoleblank=0 loglevel=${verbosity} ubootpart=${partuuid} usb-storage.quirks=${usbstoragequirks} ${extraargs} ${extraboardargs}" + +if test "${docker_optimizations}" = "on"; then setenv bootargs "${bootargs} cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory swapaccount=1"; fi + +load ${devtype} ${devnum} ${ramdisk_addr_r} ${prefix}uInitrd +load ${devtype} ${devnum} ${kernel_addr_r} ${prefix}Image + +load ${devtype} ${devnum} ${fdt_addr_r} ${prefix}dtb/${fdtfile} +fdt addr ${fdt_addr_r} +fdt resize 65536 +for overlay_file in ${overlays}; do + if load ${devtype} ${devnum} ${load_addr} ${prefix}dtb/rockchip/overlay/${overlay_prefix}-${overlay_file}.dtbo; then + echo "Applying kernel provided DT overlay ${overlay_prefix}-${overlay_file}.dtbo" + fdt apply ${load_addr} || setenv overlay_error "true" + fi +done +for overlay_file in ${user_overlays}; do + if load ${devtype} ${devnum} ${load_addr} ${prefix}overlay-user/${overlay_file}.dtbo; then + echo "Applying user provided DT overlay ${overlay_file}.dtbo" + fdt apply ${load_addr} || setenv overlay_error "true" + fi +done +if test "${overlay_error}" = "true"; then + echo "Error applying DT overlays, restoring original DT" + load ${devtype} ${devnum} ${fdt_addr_r} ${prefix}dtb/${fdtfile} +else + if load ${devtype} ${devnum} ${load_addr} ${prefix}dtb/rockchip/overlay/${overlay_prefix}-fixup.scr; then + echo "Applying kernel provided DT fixup script (${overlay_prefix}-fixup.scr)" + source ${load_addr} + fi + if test -e ${devtype} ${devnum} ${prefix}fixup.scr; then + load ${devtype} ${devnum} ${load_addr} ${prefix}fixup.scr + echo "Applying user provided fixup script (fixup.scr)" + source ${load_addr} + fi +fi +booti ${kernel_addr_r} ${ramdisk_addr_r} ${fdt_addr_r} + +# Recompile with: +# mkimage -C none -A arm -T script -d /boot/boot.cmd /boot/boot.scr +''' % (mmc_dev) + bootdir = os.path.join(mnt, 'boot') + mkdir_cond(bootdir) + cmd_fname = os.path.join(bootdir, 'boot.cmd') + scr_fname = os.path.join(bootdir, 'boot.scr') + with open(cmd_fname, 'w') as outf: + print(script, file=outf) + + infname = os.path.join(cons.config.source_dir, + 'test/py/tests/bootstd/armbian.bmp.xz') + bmp_file = os.path.join(bootdir, 'boot.bmp') + u_boot_utils.run_and_log( + cons, + ['sh', '-c', f'xz -dc {infname} >{bmp_file}']) + + u_boot_utils.run_and_log( + cons, f'mkimage -C none -A arm -T script -d {cmd_fname} {scr_fname}') + + kernel = 'vmlinuz-5.15.63-rockchip64' + target = os.path.join(bootdir, kernel) + with open(target, 'wb') as outf: + print('kernel', outf) + + symlink = os.path.join(bootdir, 'Image') + if os.path.exists(symlink): + os.remove(symlink) + u_boot_utils.run_and_log( + cons, f'echo here {kernel} {symlink}') + os.symlink(kernel, symlink) + u_boot_utils.run_and_log( - cons, 'sudo mount -o loop %s %s -o uid=%d,gid=%d' % - (fatpart, mnt, os.getuid(), os.getgid())) + cons, f'mkimage -C none -A arm -T script -d {cmd_fname} {scr_fname}') + complete = True + + except ValueError as exc: + print('Falled to create image, failing back to prepared copy: %s', + str(exc)) + finally: + if mounted: + u_boot_utils.run_and_log(cons, 'sudo umount %s' % mnt) + if loop: + u_boot_utils.run_and_log(cons, 'sudo losetup -d %s' % loop) + + if not complete: + copy_prepared_image(cons, mmc_dev, fname) + +def setup_bootflow_image(cons): + """Create a 20MB disk image with a single FAT partition""" + mmc_dev = 1 + fname, mnt = setup_image(cons, mmc_dev, 0xc) + + loop = None + mounted = False + complete = False + try: + loop = mount_image(cons, fname, mnt, 'vfat') mounted = True vmlinux = 'vmlinuz-5.3.7-301.fc31.armv7hl' @@ -90,12 +274,7 @@ label Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl) u_boot_utils.run_and_log(cons, 'sudo losetup -d %s' % loop) if not complete: - # Use a prepared image since we cannot create one - infname = os.path.join(cons.config.source_dir, - 'test/py/tests/bootstd/mmc1.img.xz') - u_boot_utils.run_and_log( - cons, - ['sh', '-c', 'xz -dc %s >%s' % (infname, fname)]) + copy_prepared_image(cons, mmc_dev, fname) @pytest.mark.buildconfigspec('ut_dm') @@ -134,6 +313,7 @@ def test_ut_dm_init_bootstd(u_boot_console): """Initialise data for bootflow tests""" setup_bootflow_image(u_boot_console) + setup_bootmenu_image(u_boot_console) # Restart so that the new mmc1.img is picked up u_boot_console.restart_uboot() -- cgit v1.2.3 From e64c29521c0e6111b446fd67e85c6dd3d491103c Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Fri, 6 Jan 2023 08:52:42 -0600 Subject: bootstd: Support setting a theme for the menu Allow a theme to be set. For now this is very simple, just a default font size to use for all elements. Signed-off-by: Simon Glass --- test/boot/bootflow.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 80 insertions(+), 3 deletions(-) (limited to 'test') diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c index abafa44b2ed..5b76cd3ab14 100644 --- a/test/boot/bootflow.c +++ b/test/boot/bootflow.c @@ -13,6 +13,7 @@ #include #include #include +#include #ifdef CONFIG_SANDBOX #include #endif @@ -21,6 +22,8 @@ #include #include #include "bootstd_common.h" +#include "../../boot/bootflow_internal.h" +#include "../../boot/scene_internal.h" DECLARE_GLOBAL_DATA_PTR; @@ -469,14 +472,18 @@ static int bootflow_cmd_boot(struct unit_test_state *uts) } BOOTSTD_TEST(bootflow_cmd_boot, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -/* Check 'bootflow menu' to select a bootflow */ -static int bootflow_cmd_menu(struct unit_test_state *uts) +/** + * prep_mmc4_bootdev() - Set up the mmc4 bootdev so we can access a fake Armbian + * + * @uts: Unit test state + * Returns 0 on success, -ve on failure + */ +static int prep_mmc4_bootdev(struct unit_test_state *uts) { static const char *order[] = {"mmc2", "mmc1", "mmc4", NULL}; struct udevice *dev, *bootstd; struct bootstd_priv *std; const char **old_order; - char prev[3]; ofnode node; /* Enable the mmc4 node since we need a second bootflow */ @@ -500,6 +507,16 @@ static int bootflow_cmd_menu(struct unit_test_state *uts) /* Restore the order used by the device tree */ std->bootdev_order = old_order; + return 0; +} + +/* Check 'bootflow menu' to select a bootflow */ +static int bootflow_cmd_menu(struct unit_test_state *uts) +{ + char prev[3]; + + ut_assertok(prep_mmc4_bootdev(uts)); + /* Add keypresses to move to and select the second one in the list */ prev[0] = CTL_CH('n'); prev[1] = '\r'; @@ -513,3 +530,63 @@ static int bootflow_cmd_menu(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(bootflow_cmd_menu, UT_TESTF_DM | UT_TESTF_SCAN_FDT); + +/** + * check_font() - Check that the font size for an item matches expectations + * + * @uts: Unit test state + * @scn: Scene containing the text object + * @id: ID of the text object + * Returns 0 on success, -ve on failure + */ +static int check_font(struct unit_test_state *uts, struct scene *scn, uint id, + int font_size) +{ + struct scene_obj_txt *txt; + + txt = scene_obj_find(scn, id, SCENEOBJT_TEXT); + ut_assertnonnull(txt); + + ut_asserteq(font_size, txt->font_size); + + return 0; +} + +/* Check themes work with a bootflow menu */ +static int bootflow_menu_theme(struct unit_test_state *uts) +{ + const int font_size = 30; + struct scene *scn; + struct expo *exp; + ofnode node; + int i; + + ut_assertok(prep_mmc4_bootdev(uts)); + + ut_assertok(bootflow_menu_new(&exp)); + node = ofnode_path("/bootstd/theme"); + ut_assert(ofnode_valid(node)); + ut_assertok(bootflow_menu_apply_theme(exp, node)); + + scn = expo_lookup_scene_id(exp, MAIN); + ut_assertnonnull(scn); + + /* + * Check that the txt objects have the correct font size from the + * device tree node: bootstd/theme + * + * Check both menu items, since there are two bootflows + */ + ut_assertok(check_font(uts, scn, OBJ_PROMPT, font_size)); + ut_assertok(check_font(uts, scn, OBJ_POINTER, font_size)); + for (i = 0; i < 2; i++) { + ut_assertok(check_font(uts, scn, ITEM_DESC + i, font_size)); + ut_assertok(check_font(uts, scn, ITEM_KEY + i, font_size)); + ut_assertok(check_font(uts, scn, ITEM_LABEL + i, font_size)); + } + + expo_destroy(exp); + + return 0; +} +BOOTSTD_TEST(bootflow_menu_theme, UT_TESTF_DM | UT_TESTF_SCAN_FDT); -- cgit v1.2.3