blob: e4f3ffc01fb82482a4d824f355978f604c954d89 [file] [log] [blame]
Simon Glass65924992023-01-06 08:52:39 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2022 Google LLC
4 * Written by Simon Glass <sjg@chromium.org>
5 */
6
Simon Glassb8c26552023-06-01 10:23:03 -06007#include <command.h>
Simon Glass65924992023-01-06 08:52:39 -06008#include <dm.h>
9#include <expo.h>
10#include <menu.h>
11#include <video.h>
12#include <linux/input.h>
Simon Glass65924992023-01-06 08:52:39 -060013#include <test/ut.h>
Simon Glass0dc275f2025-05-02 08:46:41 -060014#include <test/video.h>
Simon Glass65924992023-01-06 08:52:39 -060015#include "bootstd_common.h"
Simon Glass61300722023-06-01 10:23:01 -060016#include <test/cedit-test.h>
Simon Glass65924992023-01-06 08:52:39 -060017#include "../../boot/scene_internal.h"
18
19enum {
20 /* scenes */
21 SCENE1 = 7,
22 SCENE2,
23
24 /* objects */
25 OBJ_LOGO,
26 OBJ_TEXT,
27 OBJ_TEXT2,
Simon Glasscfb4f2c2025-05-02 08:46:42 -060028 OBJ_TEXT3,
Simon Glass65924992023-01-06 08:52:39 -060029 OBJ_MENU,
30 OBJ_MENU_TITLE,
Simon Glass138a3972025-05-02 08:46:44 -060031 OBJ_BOX,
32 OBJ_BOX2,
Simon Glass65924992023-01-06 08:52:39 -060033
34 /* strings */
Simon Glassea274b62023-06-01 10:22:27 -060035 STR_SCENE_TITLE,
36
Simon Glass65924992023-01-06 08:52:39 -060037 STR_TEXT,
38 STR_TEXT2,
Simon Glasscfb4f2c2025-05-02 08:46:42 -060039 STR_TEXT3,
Simon Glass65924992023-01-06 08:52:39 -060040 STR_MENU_TITLE,
41 STR_POINTER_TEXT,
42
43 STR_ITEM1_LABEL,
44 STR_ITEM1_DESC,
45 STR_ITEM1_KEY,
46 STR_ITEM1_PREVIEW,
47
48 STR_ITEM2_LABEL,
49 STR_ITEM2_DESC,
50 STR_ITEM2_KEY,
51 STR_ITEM2_PREVIEW,
52
53 /* menu items */
54 ITEM1,
55 ITEM1_LABEL,
56 ITEM1_DESC,
57 ITEM1_KEY,
58 ITEM1_PREVIEW,
59
60 ITEM2,
61 ITEM2_LABEL,
62 ITEM2_DESC,
63 ITEM2_KEY,
64 ITEM2_PREVIEW,
65
66 /* pointer to current item */
67 POINTER_TEXT,
68};
69
70#define BAD_POINTER ((void *)1)
71
72/* names for various things */
73#define EXPO_NAME "my menus"
74#define SCENE_NAME1 "main"
75#define SCENE_NAME2 "second"
76#define SCENE_TITLE "Main Menu"
77#define LOGO_NAME "logo"
78
79/* Check base expo support */
80static int expo_base(struct unit_test_state *uts)
81{
82 struct udevice *dev;
83 struct expo *exp;
84 ulong start_mem;
85 char name[100];
86 int i;
87
88 ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
89
90 start_mem = ut_check_free();
91
92 exp = NULL;
93 strcpy(name, EXPO_NAME);
94 ut_assertok(expo_new(name, NULL, &exp));
95 *name = '\0';
96 ut_assertnonnull(exp);
97 ut_asserteq(0, exp->scene_id);
Simon Glass53a0a2f2024-10-14 16:31:57 -060098 ut_asserteq(EXPOID_BASE_ID, exp->next_id);
Simon Glass65924992023-01-06 08:52:39 -060099
100 /* Make sure the name was allocated */
101 ut_assertnonnull(exp->name);
102 ut_asserteq_str(EXPO_NAME, exp->name);
103
104 ut_assertok(expo_set_display(exp, dev));
105 expo_destroy(exp);
106 ut_assertok(ut_check_delta(start_mem));
107
108 /* test handling out-of-memory conditions */
109 for (i = 0; i < 2; i++) {
110 struct expo *exp2;
111
112 malloc_enable_testing(i);
113 exp2 = BAD_POINTER;
114 ut_asserteq(-ENOMEM, expo_new(EXPO_NAME, NULL, &exp2));
115 ut_asserteq_ptr(BAD_POINTER, exp2);
116 malloc_disable_testing();
117 }
118
119 return 0;
120}
Simon Glass1a92f832024-08-22 07:57:48 -0600121BOOTSTD_TEST(expo_base, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600122
123/* Check creating a scene */
124static int expo_scene(struct unit_test_state *uts)
125{
126 struct scene *scn;
127 struct expo *exp;
128 ulong start_mem;
129 char name[100];
Simon Glassea274b62023-06-01 10:22:27 -0600130 int id, title_id;
Simon Glass65924992023-01-06 08:52:39 -0600131
132 start_mem = ut_check_free();
133
134 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
135
136 scn = NULL;
Simon Glass53a0a2f2024-10-14 16:31:57 -0600137 ut_asserteq(EXPOID_BASE_ID, exp->next_id);
Simon Glass65924992023-01-06 08:52:39 -0600138 strcpy(name, SCENE_NAME1);
139 id = scene_new(exp, name, SCENE1, &scn);
140 *name = '\0';
141 ut_assertnonnull(scn);
142 ut_asserteq(SCENE1, id);
143 ut_asserteq(SCENE1 + 1, exp->next_id);
144 ut_asserteq_ptr(exp, scn->expo);
145
146 /* Make sure the name was allocated */
147 ut_assertnonnull(scn->name);
148 ut_asserteq_str(SCENE_NAME1, scn->name);
149
150 /* Set the title */
Simon Glassea274b62023-06-01 10:22:27 -0600151 title_id = expo_str(exp, "title", STR_SCENE_TITLE, SCENE_TITLE);
152 ut_assert(title_id >= 0);
Simon Glass65924992023-01-06 08:52:39 -0600153
Simon Glassea274b62023-06-01 10:22:27 -0600154 /* Use an allocated ID - this will be allocated after the title str */
Simon Glass65924992023-01-06 08:52:39 -0600155 scn = NULL;
156 id = scene_new(exp, SCENE_NAME2, 0, &scn);
157 ut_assertnonnull(scn);
Simon Glassf9577852024-10-14 16:32:02 -0600158 scn->title_id = title_id;
Simon Glassea274b62023-06-01 10:22:27 -0600159 ut_asserteq(STR_SCENE_TITLE + 1, id);
160 ut_asserteq(STR_SCENE_TITLE + 2, exp->next_id);
Simon Glass65924992023-01-06 08:52:39 -0600161 ut_asserteq_ptr(exp, scn->expo);
162
163 ut_asserteq_str(SCENE_NAME2, scn->name);
Simon Glassea274b62023-06-01 10:22:27 -0600164 ut_asserteq(title_id, scn->title_id);
Simon Glass65924992023-01-06 08:52:39 -0600165
166 expo_destroy(exp);
167
168 ut_assertok(ut_check_delta(start_mem));
169
170 return 0;
171}
Simon Glass1a92f832024-08-22 07:57:48 -0600172BOOTSTD_TEST(expo_scene, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600173
Simon Glass5c6926c2024-10-14 16:31:56 -0600174/* Check creating a scene with no ID */
175static int expo_scene_no_id(struct unit_test_state *uts)
176{
177 struct scene *scn;
178 struct expo *exp;
179 char name[100];
180 int id;
181
182 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
Simon Glass53a0a2f2024-10-14 16:31:57 -0600183 ut_asserteq(EXPOID_BASE_ID, exp->next_id);
Simon Glass5c6926c2024-10-14 16:31:56 -0600184
185 strcpy(name, SCENE_NAME1);
186 id = scene_new(exp, SCENE_NAME1, 0, &scn);
Simon Glass53a0a2f2024-10-14 16:31:57 -0600187 ut_asserteq(EXPOID_BASE_ID, scn->id);
Simon Glass5c6926c2024-10-14 16:31:56 -0600188
189 return 0;
190}
191BOOTSTD_TEST(expo_scene_no_id, UTF_DM | UTF_SCAN_FDT);
192
Simon Glass65924992023-01-06 08:52:39 -0600193/* Check creating a scene with objects */
194static int expo_object(struct unit_test_state *uts)
195{
196 struct scene_obj_img *img;
197 struct scene_obj_txt *txt;
198 struct scene *scn;
199 struct expo *exp;
200 ulong start_mem;
201 char name[100];
202 char *data;
203 int id;
204
205 start_mem = ut_check_free();
206
207 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
208 id = scene_new(exp, SCENE_NAME1, SCENE1, &scn);
209 ut_assert(id > 0);
210
211 ut_asserteq(0, scene_obj_count(scn));
212
213 data = NULL;
214 strcpy(name, LOGO_NAME);
215 id = scene_img(scn, name, OBJ_LOGO, data, &img);
216 ut_assert(id > 0);
217 *name = '\0';
218 ut_assertnonnull(img);
219 ut_asserteq(OBJ_LOGO, id);
220 ut_asserteq(OBJ_LOGO + 1, exp->next_id);
221 ut_asserteq_ptr(scn, img->obj.scene);
222 ut_asserteq(SCENEOBJT_IMAGE, img->obj.type);
223
224 ut_asserteq_ptr(data, img->data);
225
226 /* Make sure the name was allocated */
227 ut_assertnonnull(scn->name);
228 ut_asserteq_str(SCENE_NAME1, scn->name);
229
230 ut_asserteq(1, scene_obj_count(scn));
231
232 id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", &txt);
233 ut_assert(id > 0);
234 ut_assertnonnull(txt);
235 ut_asserteq(OBJ_TEXT, id);
236 ut_asserteq(SCENEOBJT_TEXT, txt->obj.type);
237 ut_asserteq(2, scene_obj_count(scn));
238
239 /* Check passing NULL as the final parameter */
240 id = scene_txt_str(scn, "text2", OBJ_TEXT2, STR_TEXT2, "another string",
241 NULL);
242 ut_assert(id > 0);
243 ut_asserteq(3, scene_obj_count(scn));
244
245 expo_destroy(exp);
246
247 ut_assertok(ut_check_delta(start_mem));
248
249 return 0;
250}
Simon Glass1a92f832024-08-22 07:57:48 -0600251BOOTSTD_TEST(expo_object, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600252
Simon Glassc999e172023-06-01 10:22:53 -0600253/* Check setting object attributes and using themes */
Simon Glass65924992023-01-06 08:52:39 -0600254static int expo_object_attr(struct unit_test_state *uts)
255{
256 struct scene_obj_menu *menu;
257 struct scene_obj_img *img;
258 struct scene_obj_txt *txt;
259 struct scene *scn;
260 struct expo *exp;
261 ulong start_mem;
262 char name[100];
Simon Glassc999e172023-06-01 10:22:53 -0600263 ofnode node;
Simon Glass65924992023-01-06 08:52:39 -0600264 char *data;
265 int id;
266
267 start_mem = ut_check_free();
268
269 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
270 id = scene_new(exp, SCENE_NAME1, SCENE1, &scn);
271 ut_assert(id > 0);
272
273 data = NULL;
274 id = scene_img(scn, LOGO_NAME, OBJ_LOGO, data, &img);
275 ut_assert(id > 0);
276
277 ut_assertok(scene_obj_set_pos(scn, OBJ_LOGO, 123, 456));
Simon Glassbc3a15f2025-05-02 08:46:31 -0600278 ut_asserteq(123, img->obj.bbox.x0);
279 ut_asserteq(456, img->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600280
281 ut_asserteq(-ENOENT, scene_obj_set_pos(scn, OBJ_TEXT2, 0, 0));
282
283 id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", &txt);
284 ut_assert(id > 0);
285
286 strcpy(name, "font2");
287 ut_assertok(scene_txt_set_font(scn, OBJ_TEXT, name, 42));
Simon Glass9ef02aa2025-05-02 08:46:37 -0600288 ut_asserteq_ptr(name, txt->gen.font_name);
289 ut_asserteq(42, txt->gen.font_size);
Simon Glass65924992023-01-06 08:52:39 -0600290
291 ut_asserteq(-ENOENT, scene_txt_set_font(scn, OBJ_TEXT2, name, 42));
292
293 id = scene_menu(scn, "main", OBJ_MENU, &menu);
294 ut_assert(id > 0);
295
296 ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_TEXT));
297
298 ut_asserteq(-ENOENT, scene_menu_set_title(scn, OBJ_TEXT2, OBJ_TEXT));
299 ut_asserteq(-EINVAL, scene_menu_set_title(scn, OBJ_MENU, OBJ_TEXT2));
300
Simon Glassc999e172023-06-01 10:22:53 -0600301 node = ofnode_path("/bootstd/theme");
302 ut_assert(ofnode_valid(node));
303 ut_assertok(expo_apply_theme(exp, node));
Simon Glass9ef02aa2025-05-02 08:46:37 -0600304 ut_asserteq(30, txt->gen.font_size);
Simon Glassc999e172023-06-01 10:22:53 -0600305
Simon Glass65924992023-01-06 08:52:39 -0600306 expo_destroy(exp);
307
308 ut_assertok(ut_check_delta(start_mem));
309
310 return 0;
311}
Simon Glass1a92f832024-08-22 07:57:48 -0600312BOOTSTD_TEST(expo_object_attr, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600313
Simon Glasse90acd82023-08-14 16:40:23 -0600314/**
315 * struct test_iter_priv - private data for expo-iterator test
316 *
317 * @count: number of scene objects
318 * @menu_count: number of menus
319 * @fail_at: item ID at which to return an error
320 */
321struct test_iter_priv {
322 int count;
323 int menu_count;
324 int fail_at;
325};
326
327int h_test_iter(struct scene_obj *obj, void *vpriv)
328{
329 struct test_iter_priv *priv = vpriv;
330
331 if (priv->fail_at == obj->id)
332 return -EINVAL;
333
334 priv->count++;
335 if (obj->type == SCENEOBJT_MENU)
336 priv->menu_count++;
337
338 return 0;
339}
340
Simon Glass65924992023-01-06 08:52:39 -0600341/* Check creating a scene with a menu */
342static int expo_object_menu(struct unit_test_state *uts)
343{
344 struct scene_obj_menu *menu;
345 struct scene_menitem *item;
346 int id, label_id, desc_id, key_id, pointer_id, preview_id;
347 struct scene_obj_txt *ptr, *name1, *desc1, *key1, *tit, *prev1;
Simon Glasse90acd82023-08-14 16:40:23 -0600348 struct test_iter_priv priv;
Simon Glass65924992023-01-06 08:52:39 -0600349 struct scene *scn;
350 struct expo *exp;
351 ulong start_mem;
352
353 start_mem = ut_check_free();
354
355 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
356 id = scene_new(exp, SCENE_NAME1, SCENE1, &scn);
357 ut_assert(id > 0);
358
359 id = scene_menu(scn, "main", OBJ_MENU, &menu);
360 ut_assert(id > 0);
361 ut_assertnonnull(menu);
362 ut_asserteq(OBJ_MENU, id);
363 ut_asserteq(SCENEOBJT_MENU, menu->obj.type);
364 ut_asserteq(0, menu->title_id);
365 ut_asserteq(0, menu->pointer_id);
366
367 ut_assertok(scene_obj_set_pos(scn, OBJ_MENU, 50, 400));
Simon Glassbc3a15f2025-05-02 08:46:31 -0600368 ut_asserteq(50, menu->obj.bbox.x0);
369 ut_asserteq(400, menu->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600370
371 id = scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE,
372 "Main Menu", &tit);
373 ut_assert(id > 0);
374 ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_MENU_TITLE));
375 ut_asserteq(OBJ_MENU_TITLE, menu->title_id);
376
377 pointer_id = scene_txt_str(scn, "cur_item", POINTER_TEXT,
378 STR_POINTER_TEXT, ">", &ptr);
379 ut_assert(pointer_id > 0);
380
381 ut_assertok(scene_menu_set_pointer(scn, OBJ_MENU, POINTER_TEXT));
382 ut_asserteq(POINTER_TEXT, menu->pointer_id);
383
384 label_id = scene_txt_str(scn, "label1", ITEM1_LABEL, STR_ITEM1_LABEL,
385 "Play", &name1);
386 ut_assert(label_id > 0);
387
388 desc_id = scene_txt_str(scn, "desc1", ITEM1_DESC, STR_ITEM1_DESC,
389 "Lord Melchett", &desc1);
390 ut_assert(desc_id > 0);
391
392 key_id = scene_txt_str(scn, "item1-key", ITEM1_KEY, STR_ITEM1_KEY, "1",
393 &key1);
394 ut_assert(key_id > 0);
395
396 preview_id = scene_txt_str(scn, "item1-preview", ITEM1_PREVIEW,
397 STR_ITEM1_PREVIEW, "(preview1)", &prev1);
398 ut_assert(preview_id > 0);
399
400 id = scene_menuitem(scn, OBJ_MENU, "linux", ITEM1, ITEM1_KEY,
401 ITEM1_LABEL, ITEM1_DESC, ITEM1_PREVIEW, 0, &item);
402 ut_asserteq(ITEM1, id);
403 ut_asserteq(id, item->id);
404 ut_asserteq(key_id, item->key_id);
405 ut_asserteq(label_id, item->label_id);
406 ut_asserteq(desc_id, item->desc_id);
407 ut_asserteq(preview_id, item->preview_id);
408
Simon Glassd7e32a82023-06-01 10:22:35 -0600409 ut_assertok(scene_arrange(scn));
410
411 /* arranging the scene should cause the first item to become current */
Simon Glass65924992023-01-06 08:52:39 -0600412 ut_asserteq(id, menu->cur_item_id);
413
414 /* the title should be at the top */
Simon Glassbc3a15f2025-05-02 08:46:31 -0600415 ut_asserteq(menu->obj.bbox.x0, tit->obj.bbox.x0);
416 ut_asserteq(menu->obj.bbox.y0, tit->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600417
418 /* the first item should be next */
Simon Glassbc3a15f2025-05-02 08:46:31 -0600419 ut_asserteq(menu->obj.bbox.x0, name1->obj.bbox.x0);
420 ut_asserteq(menu->obj.bbox.y0 + 32, name1->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600421
Simon Glassbc3a15f2025-05-02 08:46:31 -0600422 ut_asserteq(menu->obj.bbox.x0 + 230, key1->obj.bbox.x0);
423 ut_asserteq(menu->obj.bbox.y0 + 32, key1->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600424
Simon Glassbc3a15f2025-05-02 08:46:31 -0600425 ut_asserteq(menu->obj.bbox.x0 + 200, ptr->obj.bbox.x0);
426 ut_asserteq(menu->obj.bbox.y0 + 32, ptr->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600427
Simon Glassbc3a15f2025-05-02 08:46:31 -0600428 ut_asserteq(menu->obj.bbox.x0 + 280, desc1->obj.bbox.x0);
429 ut_asserteq(menu->obj.bbox.y0 + 32, desc1->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600430
Simon Glassbc3a15f2025-05-02 08:46:31 -0600431 ut_asserteq(-4, prev1->obj.bbox.x0);
432 ut_asserteq(menu->obj.bbox.y0 + 32, prev1->obj.bbox.y0);
Simon Glassc55eeba2023-06-01 10:22:54 -0600433 ut_asserteq(true, prev1->obj.flags & SCENEOF_HIDE);
Simon Glass65924992023-01-06 08:52:39 -0600434
Simon Glasse90acd82023-08-14 16:40:23 -0600435 /* check iterating through scene items */
436 memset(&priv, '\0', sizeof(priv));
437 ut_assertok(expo_iter_scene_objs(exp, h_test_iter, &priv));
438 ut_asserteq(7, priv.count);
439 ut_asserteq(1, priv.menu_count);
440
441 /* check the iterator failing part way through iteration */
442 memset(&priv, '\0', sizeof(priv));
443 priv.fail_at = key_id;
444 ut_asserteq(-EINVAL, expo_iter_scene_objs(exp, h_test_iter, &priv));
445
446 /* 2 items (preview_id and the menuitem) are after key_id, 7 - 2 = 5 */
447 ut_asserteq(5, priv.count);
448
449 /* menu is first, so is still processed */
450 ut_asserteq(1, priv.menu_count);
451
Simon Glass65924992023-01-06 08:52:39 -0600452 expo_destroy(exp);
453
454 ut_assertok(ut_check_delta(start_mem));
455
456 return 0;
457}
Simon Glass1a92f832024-08-22 07:57:48 -0600458BOOTSTD_TEST(expo_object_menu, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600459
460/* Check rendering a scene */
461static int expo_render_image(struct unit_test_state *uts)
462{
463 struct scene_obj_menu *menu;
464 struct scene *scn, *scn2;
465 struct expo_action act;
466 struct scene_obj *obj;
467 struct udevice *dev;
468 struct expo *exp;
469 int id;
470
Simon Glass65924992023-01-06 08:52:39 -0600471 ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
472
473 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
474 id = scene_new(exp, SCENE_NAME1, SCENE1, &scn);
475 ut_assert(id > 0);
476 ut_assertok(expo_set_display(exp, dev));
477
478 id = scene_img(scn, "logo", OBJ_LOGO, video_get_u_boot_logo(), NULL);
479 ut_assert(id > 0);
480 ut_assertok(scene_obj_set_pos(scn, OBJ_LOGO, 50, 20));
481
482 id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", NULL);
483 ut_assert(id > 0);
484 ut_assertok(scene_txt_set_font(scn, OBJ_TEXT, "cantoraone_regular",
485 40));
486 ut_assertok(scene_obj_set_pos(scn, OBJ_TEXT, 400, 100));
487
488 id = scene_txt_str(scn, "text", OBJ_TEXT2, STR_TEXT2, "another string",
489 NULL);
490 ut_assert(id > 0);
491 ut_assertok(scene_txt_set_font(scn, OBJ_TEXT2, "nimbus_sans_l_regular",
492 60));
493 ut_assertok(scene_obj_set_pos(scn, OBJ_TEXT2, 200, 600));
494
Simon Glasscfb4f2c2025-05-02 08:46:42 -0600495 id = scene_txt_str(scn, "text", OBJ_TEXT3, STR_TEXT3,
496 "this is yet\nanother string, with word-wrap",
497 NULL);
498 ut_assert(id > 0);
499 ut_assertok(scene_txt_set_font(scn, OBJ_TEXT3, "nimbus_sans_l_regular",
500 60));
501 ut_assertok(scene_obj_set_bbox(scn, OBJ_TEXT3, 500, 200, 1000, 700));
502
Simon Glass65924992023-01-06 08:52:39 -0600503 id = scene_menu(scn, "main", OBJ_MENU, &menu);
504 ut_assert(id > 0);
505
506 id = scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE,
507 "Main Menu", NULL);
508 ut_assert(id > 0);
509 ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_MENU_TITLE));
510
511 id = scene_txt_str(scn, "cur_item", POINTER_TEXT, STR_POINTER_TEXT, ">",
512 NULL);
513 ut_assert(id > 0);
514 ut_assertok(scene_menu_set_pointer(scn, OBJ_MENU, POINTER_TEXT));
515
516 id = scene_txt_str(scn, "label1", ITEM1_LABEL, STR_ITEM1_LABEL, "Play",
517 NULL);
518 ut_assert(id > 0);
519 id = scene_txt_str(scn, "item1 txt", ITEM1_DESC, STR_ITEM1_DESC,
520 "Lord Melchett", NULL);
521 ut_assert(id > 0);
522 id = scene_txt_str(scn, "item1-key", ITEM1_KEY, STR_ITEM1_KEY, "1",
523 NULL);
524 ut_assert(id > 0);
525 id = scene_img(scn, "item1-preview", ITEM1_PREVIEW,
526 video_get_u_boot_logo(), NULL);
527 id = scene_menuitem(scn, OBJ_MENU, "item1", ITEM1, ITEM1_KEY,
528 ITEM1_LABEL, ITEM1_DESC, ITEM1_PREVIEW, 0, NULL);
529 ut_assert(id > 0);
530
531 id = scene_txt_str(scn, "label2", ITEM2_LABEL, STR_ITEM2_LABEL, "Now",
532 NULL);
533 ut_assert(id > 0);
534 id = scene_txt_str(scn, "item2 txt", ITEM2_DESC, STR_ITEM2_DESC,
535 "Lord Percy", NULL);
536 ut_assert(id > 0);
537 id = scene_txt_str(scn, "item2-key", ITEM2_KEY, STR_ITEM2_KEY, "2",
538 NULL);
539 ut_assert(id > 0);
540 id = scene_img(scn, "item2-preview", ITEM2_PREVIEW,
541 video_get_u_boot_logo(), NULL);
542 ut_assert(id > 0);
543
544 id = scene_menuitem(scn, OBJ_MENU, "item2", ITEM2, ITEM2_KEY,
545 ITEM2_LABEL, ITEM2_DESC, ITEM2_PREVIEW, 0, NULL);
546 ut_assert(id > 0);
547
548 ut_assertok(scene_obj_set_pos(scn, OBJ_MENU, 50, 400));
549
Simon Glass138a3972025-05-02 08:46:44 -0600550 id = scene_box(scn, "box", OBJ_BOX, 3, NULL);
551 ut_assert(id > 0);
552 ut_assertok(scene_obj_set_bbox(scn, OBJ_BOX, 40, 390, 1000, 510));
553
554 id = scene_box(scn, "box2", OBJ_BOX2, 1, NULL);
555 ut_assert(id > 0);
556 ut_assertok(scene_obj_set_bbox(scn, OBJ_BOX, 500, 200, 1000, 350));
557
Simon Glass65924992023-01-06 08:52:39 -0600558 scn2 = expo_lookup_scene_id(exp, SCENE1);
559 ut_asserteq_ptr(scn, scn2);
560 scn2 = expo_lookup_scene_id(exp, SCENE2);
561 ut_assertnull(scn2);
562
563 /* render without a scene */
564 ut_asserteq(-ECHILD, expo_render(exp));
565
Simon Glass7a960052023-06-01 10:22:52 -0600566 ut_assertok(expo_calc_dims(exp));
567 ut_assertok(scene_arrange(scn));
568
569 /* check dimensions of text */
570 obj = scene_obj_find(scn, OBJ_TEXT, SCENEOBJT_NONE);
571 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600572 ut_asserteq(400, obj->bbox.x0);
573 ut_asserteq(100, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600574 ut_asserteq(400 + 126, obj->bbox.x1);
575 ut_asserteq(100 + 40, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600576
577 /* check dimensions of image */
578 obj = scene_obj_find(scn, OBJ_LOGO, SCENEOBJT_NONE);
579 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600580 ut_asserteq(50, obj->bbox.x0);
581 ut_asserteq(20, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600582 ut_asserteq(50 + 160, obj->bbox.x1);
583 ut_asserteq(20 + 160, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600584
585 /* check dimensions of menu labels - both should be the same width */
586 obj = scene_obj_find(scn, ITEM1_LABEL, SCENEOBJT_NONE);
587 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600588 ut_asserteq(50, obj->bbox.x0);
589 ut_asserteq(436, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600590 ut_asserteq(50 + 29, obj->bbox.x1);
591 ut_asserteq(436 + 18, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600592
593 obj = scene_obj_find(scn, ITEM2_LABEL, SCENEOBJT_NONE);
594 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600595 ut_asserteq(50, obj->bbox.x0);
596 ut_asserteq(454, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600597 ut_asserteq(50 + 29, obj->bbox.x1);
598 ut_asserteq(454 + 18, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600599
Simon Glass43bfbb22025-05-02 08:46:36 -0600600 /* same for the key */
601 obj = scene_obj_find(scn, ITEM1_KEY, SCENEOBJT_NONE);
602 ut_assertnonnull(obj);
603 ut_asserteq(280, obj->bbox.x0);
604 ut_asserteq(436, obj->bbox.y0);
605 ut_asserteq(280 + 9, obj->bbox.x1);
606 ut_asserteq(436 + 18, obj->bbox.y1);
607
608 obj = scene_obj_find(scn, ITEM2_KEY, SCENEOBJT_NONE);
609 ut_assertnonnull(obj);
610 ut_asserteq(280, obj->bbox.x0);
611 ut_asserteq(454, obj->bbox.y0);
612 ut_asserteq(280 + 9, obj->bbox.x1);
613 ut_asserteq(454 + 18, obj->bbox.y1);
614
615 /* and the description */
616 obj = scene_obj_find(scn, ITEM1_DESC, SCENEOBJT_NONE);
617 ut_assertnonnull(obj);
618 ut_asserteq(330, obj->bbox.x0);
619 ut_asserteq(436, obj->bbox.y0);
620 ut_asserteq(330 + 89, obj->bbox.x1);
621 ut_asserteq(436 + 18, obj->bbox.y1);
622
623 obj = scene_obj_find(scn, ITEM2_DESC, SCENEOBJT_NONE);
624 ut_assertnonnull(obj);
625 ut_asserteq(330, obj->bbox.x0);
626 ut_asserteq(454, obj->bbox.y0);
627 ut_asserteq(330 + 89, obj->bbox.x1);
628 ut_asserteq(454 + 18, obj->bbox.y1);
629
Simon Glass7a960052023-06-01 10:22:52 -0600630 /* check dimensions of menu */
631 obj = scene_obj_find(scn, OBJ_MENU, SCENEOBJT_NONE);
632 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600633 ut_asserteq(50, obj->bbox.x0);
634 ut_asserteq(400, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600635 ut_asserteq(50 + 160, obj->bbox.x1);
636 ut_asserteq(400 + 160, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600637
Simon Glassc6143dc2025-05-02 08:46:35 -0600638 scene_obj_set_width(scn, OBJ_MENU, 170);
639 ut_asserteq(50 + 170, obj->bbox.x1);
640 scene_obj_set_bbox(scn, OBJ_MENU, 60, 410, 50 + 160, 400 + 160);
641 ut_asserteq(60, obj->bbox.x0);
642 ut_asserteq(410, obj->bbox.y0);
643 ut_asserteq(50 + 160, obj->bbox.x1);
644 ut_asserteq(400 + 160, obj->bbox.y1);
645
646 /* reset back to normal */
647 scene_obj_set_bbox(scn, OBJ_MENU, 50, 400, 50 + 160, 400 + 160);
648
Simon Glass65924992023-01-06 08:52:39 -0600649 /* render it */
650 expo_set_scene_id(exp, SCENE1);
651 ut_assertok(expo_render(exp));
652
Simon Glassbe04b962025-05-02 08:46:24 -0600653 ut_asserteq(0, scn->highlight_id);
Simon Glass1b3388c2025-05-02 08:46:25 -0600654 ut_assertok(scene_arrange(scn));
655 ut_asserteq(0, scn->highlight_id);
Simon Glassbe04b962025-05-02 08:46:24 -0600656
Simon Glass65924992023-01-06 08:52:39 -0600657 /* move down */
658 ut_assertok(expo_send_key(exp, BKEY_DOWN));
659
660 ut_assertok(expo_action_get(exp, &act));
661
Simon Glass719a3c62023-06-01 10:22:56 -0600662 ut_asserteq(EXPOACT_POINT_ITEM, act.type);
Simon Glass65924992023-01-06 08:52:39 -0600663 ut_asserteq(ITEM2, act.select.id);
Simon Glassbe04b962025-05-02 08:46:24 -0600664 ut_assertok(scene_menu_select_item(scn, OBJ_MENU, act.select.id));
665 ut_asserteq(ITEM2, scene_menu_get_cur_item(scn, OBJ_MENU));
Simon Glass1b3388c2025-05-02 08:46:25 -0600666 ut_assertok(scene_arrange(scn));
Simon Glass65924992023-01-06 08:52:39 -0600667 ut_assertok(expo_render(exp));
Simon Glass138a3972025-05-02 08:46:44 -0600668 ut_asserteq(14883, video_compress_fb(uts, dev, false));
Simon Glass0dc275f2025-05-02 08:46:41 -0600669 ut_assertok(video_check_copy_fb(uts, dev));
670
Simon Glass65924992023-01-06 08:52:39 -0600671 /* make sure only the preview for the second item is shown */
672 obj = scene_obj_find(scn, ITEM1_PREVIEW, SCENEOBJT_NONE);
Simon Glass6081b0f2023-06-01 10:22:50 -0600673 ut_asserteq(true, obj->flags & SCENEOF_HIDE);
Simon Glass65924992023-01-06 08:52:39 -0600674
675 obj = scene_obj_find(scn, ITEM2_PREVIEW, SCENEOBJT_NONE);
Simon Glass6081b0f2023-06-01 10:22:50 -0600676 ut_asserteq(false, obj->flags & SCENEOF_HIDE);
Simon Glass65924992023-01-06 08:52:39 -0600677
678 /* select it */
679 ut_assertok(expo_send_key(exp, BKEY_SELECT));
680
681 ut_assertok(expo_action_get(exp, &act));
682 ut_asserteq(EXPOACT_SELECT, act.type);
683 ut_asserteq(ITEM2, act.select.id);
684
685 /* make sure the action doesn't come again */
686 ut_asserteq(-EAGAIN, expo_action_get(exp, &act));
687
688 /* make sure there was no console output */
689 ut_assert_console_end();
690
691 /* now try in text mode */
Simon Glassb2c40342023-06-01 10:22:37 -0600692 expo_set_text_mode(exp, true);
Simon Glass65924992023-01-06 08:52:39 -0600693 ut_assertok(expo_render(exp));
694
695 ut_assert_nextline("U-Boot : Boot Menu");
696 ut_assert_nextline("%s", "");
697 ut_assert_nextline("Main Menu");
698 ut_assert_nextline("%s", "");
699 ut_assert_nextline(" 1 Play Lord Melchett");
700 ut_assert_nextline(" > 2 Now Lord Percy");
701
702 /* Move back up to the first item */
703 ut_assertok(expo_send_key(exp, BKEY_UP));
704
705 ut_assertok(expo_action_get(exp, &act));
706
Simon Glass719a3c62023-06-01 10:22:56 -0600707 ut_asserteq(EXPOACT_POINT_ITEM, act.type);
Simon Glass65924992023-01-06 08:52:39 -0600708 ut_asserteq(ITEM1, act.select.id);
Simon Glass1b3388c2025-05-02 08:46:25 -0600709 ut_assertok(scene_menu_select_item(scn, OBJ_MENU, act.select.id));
Simon Glass65924992023-01-06 08:52:39 -0600710
711 ut_assertok(expo_render(exp));
712 ut_assert_nextline("U-Boot : Boot Menu");
713 ut_assert_nextline("%s", "");
714 ut_assert_nextline("Main Menu");
715 ut_assert_nextline("%s", "");
716 ut_assert_nextline(" > 1 Play Lord Melchett");
717 ut_assert_nextline(" 2 Now Lord Percy");
718
719 ut_assert_console_end();
720
721 expo_destroy(exp);
722
723 return 0;
724}
Simon Glassf0425022024-08-22 07:57:54 -0600725BOOTSTD_TEST(expo_render_image, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
Simon Glass61300722023-06-01 10:23:01 -0600726
727/* Check building an expo from a devicetree description */
728static int expo_test_build(struct unit_test_state *uts)
729{
730 struct scene_obj_menu *menu;
731 struct scene_menitem *item;
732 struct scene_obj_txt *txt;
Simon Glassc5ae5b12025-05-02 08:46:40 -0600733 struct abuf orig, *copy;
Simon Glass61300722023-06-01 10:23:01 -0600734 struct scene_obj *obj;
735 struct scene *scn;
736 struct expo *exp;
737 int count;
738 ofnode node;
739
740 node = ofnode_path("/cedit");
741 ut_assert(ofnode_valid(node));
742 ut_assertok(expo_build(node, &exp));
743
744 ut_asserteq_str("name", exp->name);
745 ut_asserteq(0, exp->scene_id);
Simon Glass70c579b2023-10-01 19:13:39 -0600746 ut_asserteq(ID_DYNAMIC_START + 24, exp->next_id);
Simon Glass61300722023-06-01 10:23:01 -0600747 ut_asserteq(false, exp->popup);
748
749 /* check the scene */
750 scn = expo_lookup_scene_id(exp, ID_SCENE1);
751 ut_assertnonnull(scn);
752 ut_asserteq_str("main", scn->name);
753 ut_asserteq(ID_SCENE1, scn->id);
Simon Glass9ef02aa2025-05-02 08:46:37 -0600754 ut_asserteq(ID_DYNAMIC_START, scn->title_id);
Simon Glass61300722023-06-01 10:23:01 -0600755 ut_asserteq(0, scn->highlight_id);
756
757 /* check the title */
758 txt = scene_obj_find(scn, scn->title_id, SCENEOBJT_NONE);
759 ut_assertnonnull(txt);
760 obj = &txt->obj;
761 ut_asserteq_ptr(scn, obj->scene);
762 ut_asserteq_str("title", obj->name);
763 ut_asserteq(scn->title_id, obj->id);
764 ut_asserteq(SCENEOBJT_TEXT, obj->type);
765 ut_asserteq(0, obj->flags);
Simon Glass9ef02aa2025-05-02 08:46:37 -0600766 ut_asserteq_str("Test Configuration",
767 expo_get_str(exp, txt->gen.str_id));
Simon Glass61300722023-06-01 10:23:01 -0600768
769 /* check the menu */
770 menu = scene_obj_find(scn, ID_CPU_SPEED, SCENEOBJT_NONE);
771 obj = &menu->obj;
772 ut_asserteq_ptr(scn, obj->scene);
773 ut_asserteq_str("cpu-speed", obj->name);
774 ut_asserteq(ID_CPU_SPEED, obj->id);
775 ut_asserteq(SCENEOBJT_MENU, obj->type);
776 ut_asserteq(0, obj->flags);
777
778 txt = scene_obj_find(scn, menu->title_id, SCENEOBJT_NONE);
Simon Glass9ef02aa2025-05-02 08:46:37 -0600779 ut_asserteq_str("CPU speed", expo_get_str(exp, txt->gen.str_id));
Simon Glass61300722023-06-01 10:23:01 -0600780
781 ut_asserteq(0, menu->cur_item_id);
782 ut_asserteq(0, menu->pointer_id);
783
784 /* check the items */
785 item = list_first_entry(&menu->item_head, struct scene_menitem,
786 sibling);
787 ut_asserteq_str("00", item->name);
788 ut_asserteq(ID_CPU_SPEED_1, item->id);
789 ut_asserteq(0, item->key_id);
790 ut_asserteq(0, item->desc_id);
791 ut_asserteq(0, item->preview_id);
792 ut_asserteq(0, item->flags);
Simon Glass100389f2024-10-14 16:31:58 -0600793 ut_asserteq(0, item->value);
Simon Glass61300722023-06-01 10:23:01 -0600794
795 txt = scene_obj_find(scn, item->label_id, SCENEOBJT_NONE);
Simon Glass9ef02aa2025-05-02 08:46:37 -0600796 ut_asserteq_str("2 GHz", expo_get_str(exp, txt->gen.str_id));
Simon Glass61300722023-06-01 10:23:01 -0600797
Sughosh Ganuebb1c202024-08-28 22:24:22 +0530798 count = list_count_nodes(&menu->item_head);
Simon Glass61300722023-06-01 10:23:01 -0600799 ut_asserteq(3, count);
800
Simon Glassc5ae5b12025-05-02 08:46:40 -0600801 /* try editing some text */
802 ut_assertok(expo_edit_str(exp, txt->gen.str_id, &orig, &copy));
803 ut_asserteq_str("2 GHz", orig.data);
804 ut_asserteq_str("2 GHz", copy->data);
805
806 /* change it and check that things look right */
807 abuf_printf(copy, "atlantic %d", 123);
808 ut_asserteq_str("2 GHz", orig.data);
809 ut_asserteq_str("atlantic 123", copy->data);
810
Simon Glass61300722023-06-01 10:23:01 -0600811 expo_destroy(exp);
812
813 return 0;
814}
Simon Glass1a92f832024-08-22 07:57:48 -0600815BOOTSTD_TEST(expo_test_build, UTF_DM);