blob: c9ff5b8dd240e0265790098ee8a63ec524d600d1 [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,
31
32 /* strings */
Simon Glassea274b62023-06-01 10:22:27 -060033 STR_SCENE_TITLE,
34
Simon Glass65924992023-01-06 08:52:39 -060035 STR_TEXT,
36 STR_TEXT2,
Simon Glasscfb4f2c2025-05-02 08:46:42 -060037 STR_TEXT3,
Simon Glass65924992023-01-06 08:52:39 -060038 STR_MENU_TITLE,
39 STR_POINTER_TEXT,
40
41 STR_ITEM1_LABEL,
42 STR_ITEM1_DESC,
43 STR_ITEM1_KEY,
44 STR_ITEM1_PREVIEW,
45
46 STR_ITEM2_LABEL,
47 STR_ITEM2_DESC,
48 STR_ITEM2_KEY,
49 STR_ITEM2_PREVIEW,
50
51 /* menu items */
52 ITEM1,
53 ITEM1_LABEL,
54 ITEM1_DESC,
55 ITEM1_KEY,
56 ITEM1_PREVIEW,
57
58 ITEM2,
59 ITEM2_LABEL,
60 ITEM2_DESC,
61 ITEM2_KEY,
62 ITEM2_PREVIEW,
63
64 /* pointer to current item */
65 POINTER_TEXT,
66};
67
68#define BAD_POINTER ((void *)1)
69
70/* names for various things */
71#define EXPO_NAME "my menus"
72#define SCENE_NAME1 "main"
73#define SCENE_NAME2 "second"
74#define SCENE_TITLE "Main Menu"
75#define LOGO_NAME "logo"
76
77/* Check base expo support */
78static int expo_base(struct unit_test_state *uts)
79{
80 struct udevice *dev;
81 struct expo *exp;
82 ulong start_mem;
83 char name[100];
84 int i;
85
86 ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
87
88 start_mem = ut_check_free();
89
90 exp = NULL;
91 strcpy(name, EXPO_NAME);
92 ut_assertok(expo_new(name, NULL, &exp));
93 *name = '\0';
94 ut_assertnonnull(exp);
95 ut_asserteq(0, exp->scene_id);
Simon Glass53a0a2f2024-10-14 16:31:57 -060096 ut_asserteq(EXPOID_BASE_ID, exp->next_id);
Simon Glass65924992023-01-06 08:52:39 -060097
98 /* Make sure the name was allocated */
99 ut_assertnonnull(exp->name);
100 ut_asserteq_str(EXPO_NAME, exp->name);
101
102 ut_assertok(expo_set_display(exp, dev));
103 expo_destroy(exp);
104 ut_assertok(ut_check_delta(start_mem));
105
106 /* test handling out-of-memory conditions */
107 for (i = 0; i < 2; i++) {
108 struct expo *exp2;
109
110 malloc_enable_testing(i);
111 exp2 = BAD_POINTER;
112 ut_asserteq(-ENOMEM, expo_new(EXPO_NAME, NULL, &exp2));
113 ut_asserteq_ptr(BAD_POINTER, exp2);
114 malloc_disable_testing();
115 }
116
117 return 0;
118}
Simon Glass1a92f832024-08-22 07:57:48 -0600119BOOTSTD_TEST(expo_base, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600120
121/* Check creating a scene */
122static int expo_scene(struct unit_test_state *uts)
123{
124 struct scene *scn;
125 struct expo *exp;
126 ulong start_mem;
127 char name[100];
Simon Glassea274b62023-06-01 10:22:27 -0600128 int id, title_id;
Simon Glass65924992023-01-06 08:52:39 -0600129
130 start_mem = ut_check_free();
131
132 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
133
134 scn = NULL;
Simon Glass53a0a2f2024-10-14 16:31:57 -0600135 ut_asserteq(EXPOID_BASE_ID, exp->next_id);
Simon Glass65924992023-01-06 08:52:39 -0600136 strcpy(name, SCENE_NAME1);
137 id = scene_new(exp, name, SCENE1, &scn);
138 *name = '\0';
139 ut_assertnonnull(scn);
140 ut_asserteq(SCENE1, id);
141 ut_asserteq(SCENE1 + 1, exp->next_id);
142 ut_asserteq_ptr(exp, scn->expo);
143
144 /* Make sure the name was allocated */
145 ut_assertnonnull(scn->name);
146 ut_asserteq_str(SCENE_NAME1, scn->name);
147
148 /* Set the title */
Simon Glassea274b62023-06-01 10:22:27 -0600149 title_id = expo_str(exp, "title", STR_SCENE_TITLE, SCENE_TITLE);
150 ut_assert(title_id >= 0);
Simon Glass65924992023-01-06 08:52:39 -0600151
Simon Glassea274b62023-06-01 10:22:27 -0600152 /* Use an allocated ID - this will be allocated after the title str */
Simon Glass65924992023-01-06 08:52:39 -0600153 scn = NULL;
154 id = scene_new(exp, SCENE_NAME2, 0, &scn);
155 ut_assertnonnull(scn);
Simon Glassf9577852024-10-14 16:32:02 -0600156 scn->title_id = title_id;
Simon Glassea274b62023-06-01 10:22:27 -0600157 ut_asserteq(STR_SCENE_TITLE + 1, id);
158 ut_asserteq(STR_SCENE_TITLE + 2, exp->next_id);
Simon Glass65924992023-01-06 08:52:39 -0600159 ut_asserteq_ptr(exp, scn->expo);
160
161 ut_asserteq_str(SCENE_NAME2, scn->name);
Simon Glassea274b62023-06-01 10:22:27 -0600162 ut_asserteq(title_id, scn->title_id);
Simon Glass65924992023-01-06 08:52:39 -0600163
164 expo_destroy(exp);
165
166 ut_assertok(ut_check_delta(start_mem));
167
168 return 0;
169}
Simon Glass1a92f832024-08-22 07:57:48 -0600170BOOTSTD_TEST(expo_scene, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600171
Simon Glass5c6926c2024-10-14 16:31:56 -0600172/* Check creating a scene with no ID */
173static int expo_scene_no_id(struct unit_test_state *uts)
174{
175 struct scene *scn;
176 struct expo *exp;
177 char name[100];
178 int id;
179
180 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
Simon Glass53a0a2f2024-10-14 16:31:57 -0600181 ut_asserteq(EXPOID_BASE_ID, exp->next_id);
Simon Glass5c6926c2024-10-14 16:31:56 -0600182
183 strcpy(name, SCENE_NAME1);
184 id = scene_new(exp, SCENE_NAME1, 0, &scn);
Simon Glass53a0a2f2024-10-14 16:31:57 -0600185 ut_asserteq(EXPOID_BASE_ID, scn->id);
Simon Glass5c6926c2024-10-14 16:31:56 -0600186
187 return 0;
188}
189BOOTSTD_TEST(expo_scene_no_id, UTF_DM | UTF_SCAN_FDT);
190
Simon Glass65924992023-01-06 08:52:39 -0600191/* Check creating a scene with objects */
192static int expo_object(struct unit_test_state *uts)
193{
194 struct scene_obj_img *img;
195 struct scene_obj_txt *txt;
196 struct scene *scn;
197 struct expo *exp;
198 ulong start_mem;
199 char name[100];
200 char *data;
201 int id;
202
203 start_mem = ut_check_free();
204
205 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
206 id = scene_new(exp, SCENE_NAME1, SCENE1, &scn);
207 ut_assert(id > 0);
208
209 ut_asserteq(0, scene_obj_count(scn));
210
211 data = NULL;
212 strcpy(name, LOGO_NAME);
213 id = scene_img(scn, name, OBJ_LOGO, data, &img);
214 ut_assert(id > 0);
215 *name = '\0';
216 ut_assertnonnull(img);
217 ut_asserteq(OBJ_LOGO, id);
218 ut_asserteq(OBJ_LOGO + 1, exp->next_id);
219 ut_asserteq_ptr(scn, img->obj.scene);
220 ut_asserteq(SCENEOBJT_IMAGE, img->obj.type);
221
222 ut_asserteq_ptr(data, img->data);
223
224 /* Make sure the name was allocated */
225 ut_assertnonnull(scn->name);
226 ut_asserteq_str(SCENE_NAME1, scn->name);
227
228 ut_asserteq(1, scene_obj_count(scn));
229
230 id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", &txt);
231 ut_assert(id > 0);
232 ut_assertnonnull(txt);
233 ut_asserteq(OBJ_TEXT, id);
234 ut_asserteq(SCENEOBJT_TEXT, txt->obj.type);
235 ut_asserteq(2, scene_obj_count(scn));
236
237 /* Check passing NULL as the final parameter */
238 id = scene_txt_str(scn, "text2", OBJ_TEXT2, STR_TEXT2, "another string",
239 NULL);
240 ut_assert(id > 0);
241 ut_asserteq(3, scene_obj_count(scn));
242
243 expo_destroy(exp);
244
245 ut_assertok(ut_check_delta(start_mem));
246
247 return 0;
248}
Simon Glass1a92f832024-08-22 07:57:48 -0600249BOOTSTD_TEST(expo_object, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600250
Simon Glassc999e172023-06-01 10:22:53 -0600251/* Check setting object attributes and using themes */
Simon Glass65924992023-01-06 08:52:39 -0600252static int expo_object_attr(struct unit_test_state *uts)
253{
254 struct scene_obj_menu *menu;
255 struct scene_obj_img *img;
256 struct scene_obj_txt *txt;
257 struct scene *scn;
258 struct expo *exp;
259 ulong start_mem;
260 char name[100];
Simon Glassc999e172023-06-01 10:22:53 -0600261 ofnode node;
Simon Glass65924992023-01-06 08:52:39 -0600262 char *data;
263 int id;
264
265 start_mem = ut_check_free();
266
267 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
268 id = scene_new(exp, SCENE_NAME1, SCENE1, &scn);
269 ut_assert(id > 0);
270
271 data = NULL;
272 id = scene_img(scn, LOGO_NAME, OBJ_LOGO, data, &img);
273 ut_assert(id > 0);
274
275 ut_assertok(scene_obj_set_pos(scn, OBJ_LOGO, 123, 456));
Simon Glassbc3a15f2025-05-02 08:46:31 -0600276 ut_asserteq(123, img->obj.bbox.x0);
277 ut_asserteq(456, img->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600278
279 ut_asserteq(-ENOENT, scene_obj_set_pos(scn, OBJ_TEXT2, 0, 0));
280
281 id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", &txt);
282 ut_assert(id > 0);
283
284 strcpy(name, "font2");
285 ut_assertok(scene_txt_set_font(scn, OBJ_TEXT, name, 42));
Simon Glass9ef02aa2025-05-02 08:46:37 -0600286 ut_asserteq_ptr(name, txt->gen.font_name);
287 ut_asserteq(42, txt->gen.font_size);
Simon Glass65924992023-01-06 08:52:39 -0600288
289 ut_asserteq(-ENOENT, scene_txt_set_font(scn, OBJ_TEXT2, name, 42));
290
291 id = scene_menu(scn, "main", OBJ_MENU, &menu);
292 ut_assert(id > 0);
293
294 ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_TEXT));
295
296 ut_asserteq(-ENOENT, scene_menu_set_title(scn, OBJ_TEXT2, OBJ_TEXT));
297 ut_asserteq(-EINVAL, scene_menu_set_title(scn, OBJ_MENU, OBJ_TEXT2));
298
Simon Glassc999e172023-06-01 10:22:53 -0600299 node = ofnode_path("/bootstd/theme");
300 ut_assert(ofnode_valid(node));
301 ut_assertok(expo_apply_theme(exp, node));
Simon Glass9ef02aa2025-05-02 08:46:37 -0600302 ut_asserteq(30, txt->gen.font_size);
Simon Glassc999e172023-06-01 10:22:53 -0600303
Simon Glass65924992023-01-06 08:52:39 -0600304 expo_destroy(exp);
305
306 ut_assertok(ut_check_delta(start_mem));
307
308 return 0;
309}
Simon Glass1a92f832024-08-22 07:57:48 -0600310BOOTSTD_TEST(expo_object_attr, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600311
Simon Glasse90acd82023-08-14 16:40:23 -0600312/**
313 * struct test_iter_priv - private data for expo-iterator test
314 *
315 * @count: number of scene objects
316 * @menu_count: number of menus
317 * @fail_at: item ID at which to return an error
318 */
319struct test_iter_priv {
320 int count;
321 int menu_count;
322 int fail_at;
323};
324
325int h_test_iter(struct scene_obj *obj, void *vpriv)
326{
327 struct test_iter_priv *priv = vpriv;
328
329 if (priv->fail_at == obj->id)
330 return -EINVAL;
331
332 priv->count++;
333 if (obj->type == SCENEOBJT_MENU)
334 priv->menu_count++;
335
336 return 0;
337}
338
Simon Glass65924992023-01-06 08:52:39 -0600339/* Check creating a scene with a menu */
340static int expo_object_menu(struct unit_test_state *uts)
341{
342 struct scene_obj_menu *menu;
343 struct scene_menitem *item;
344 int id, label_id, desc_id, key_id, pointer_id, preview_id;
345 struct scene_obj_txt *ptr, *name1, *desc1, *key1, *tit, *prev1;
Simon Glasse90acd82023-08-14 16:40:23 -0600346 struct test_iter_priv priv;
Simon Glass65924992023-01-06 08:52:39 -0600347 struct scene *scn;
348 struct expo *exp;
349 ulong start_mem;
350
351 start_mem = ut_check_free();
352
353 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
354 id = scene_new(exp, SCENE_NAME1, SCENE1, &scn);
355 ut_assert(id > 0);
356
357 id = scene_menu(scn, "main", OBJ_MENU, &menu);
358 ut_assert(id > 0);
359 ut_assertnonnull(menu);
360 ut_asserteq(OBJ_MENU, id);
361 ut_asserteq(SCENEOBJT_MENU, menu->obj.type);
362 ut_asserteq(0, menu->title_id);
363 ut_asserteq(0, menu->pointer_id);
364
365 ut_assertok(scene_obj_set_pos(scn, OBJ_MENU, 50, 400));
Simon Glassbc3a15f2025-05-02 08:46:31 -0600366 ut_asserteq(50, menu->obj.bbox.x0);
367 ut_asserteq(400, menu->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600368
369 id = scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE,
370 "Main Menu", &tit);
371 ut_assert(id > 0);
372 ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_MENU_TITLE));
373 ut_asserteq(OBJ_MENU_TITLE, menu->title_id);
374
375 pointer_id = scene_txt_str(scn, "cur_item", POINTER_TEXT,
376 STR_POINTER_TEXT, ">", &ptr);
377 ut_assert(pointer_id > 0);
378
379 ut_assertok(scene_menu_set_pointer(scn, OBJ_MENU, POINTER_TEXT));
380 ut_asserteq(POINTER_TEXT, menu->pointer_id);
381
382 label_id = scene_txt_str(scn, "label1", ITEM1_LABEL, STR_ITEM1_LABEL,
383 "Play", &name1);
384 ut_assert(label_id > 0);
385
386 desc_id = scene_txt_str(scn, "desc1", ITEM1_DESC, STR_ITEM1_DESC,
387 "Lord Melchett", &desc1);
388 ut_assert(desc_id > 0);
389
390 key_id = scene_txt_str(scn, "item1-key", ITEM1_KEY, STR_ITEM1_KEY, "1",
391 &key1);
392 ut_assert(key_id > 0);
393
394 preview_id = scene_txt_str(scn, "item1-preview", ITEM1_PREVIEW,
395 STR_ITEM1_PREVIEW, "(preview1)", &prev1);
396 ut_assert(preview_id > 0);
397
398 id = scene_menuitem(scn, OBJ_MENU, "linux", ITEM1, ITEM1_KEY,
399 ITEM1_LABEL, ITEM1_DESC, ITEM1_PREVIEW, 0, &item);
400 ut_asserteq(ITEM1, id);
401 ut_asserteq(id, item->id);
402 ut_asserteq(key_id, item->key_id);
403 ut_asserteq(label_id, item->label_id);
404 ut_asserteq(desc_id, item->desc_id);
405 ut_asserteq(preview_id, item->preview_id);
406
Simon Glassd7e32a82023-06-01 10:22:35 -0600407 ut_assertok(scene_arrange(scn));
408
409 /* arranging the scene should cause the first item to become current */
Simon Glass65924992023-01-06 08:52:39 -0600410 ut_asserteq(id, menu->cur_item_id);
411
412 /* the title should be at the top */
Simon Glassbc3a15f2025-05-02 08:46:31 -0600413 ut_asserteq(menu->obj.bbox.x0, tit->obj.bbox.x0);
414 ut_asserteq(menu->obj.bbox.y0, tit->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600415
416 /* the first item should be next */
Simon Glassbc3a15f2025-05-02 08:46:31 -0600417 ut_asserteq(menu->obj.bbox.x0, name1->obj.bbox.x0);
418 ut_asserteq(menu->obj.bbox.y0 + 32, name1->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600419
Simon Glassbc3a15f2025-05-02 08:46:31 -0600420 ut_asserteq(menu->obj.bbox.x0 + 230, key1->obj.bbox.x0);
421 ut_asserteq(menu->obj.bbox.y0 + 32, key1->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600422
Simon Glassbc3a15f2025-05-02 08:46:31 -0600423 ut_asserteq(menu->obj.bbox.x0 + 200, ptr->obj.bbox.x0);
424 ut_asserteq(menu->obj.bbox.y0 + 32, ptr->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600425
Simon Glassbc3a15f2025-05-02 08:46:31 -0600426 ut_asserteq(menu->obj.bbox.x0 + 280, desc1->obj.bbox.x0);
427 ut_asserteq(menu->obj.bbox.y0 + 32, desc1->obj.bbox.y0);
Simon Glass65924992023-01-06 08:52:39 -0600428
Simon Glassbc3a15f2025-05-02 08:46:31 -0600429 ut_asserteq(-4, prev1->obj.bbox.x0);
430 ut_asserteq(menu->obj.bbox.y0 + 32, prev1->obj.bbox.y0);
Simon Glassc55eeba2023-06-01 10:22:54 -0600431 ut_asserteq(true, prev1->obj.flags & SCENEOF_HIDE);
Simon Glass65924992023-01-06 08:52:39 -0600432
Simon Glasse90acd82023-08-14 16:40:23 -0600433 /* check iterating through scene items */
434 memset(&priv, '\0', sizeof(priv));
435 ut_assertok(expo_iter_scene_objs(exp, h_test_iter, &priv));
436 ut_asserteq(7, priv.count);
437 ut_asserteq(1, priv.menu_count);
438
439 /* check the iterator failing part way through iteration */
440 memset(&priv, '\0', sizeof(priv));
441 priv.fail_at = key_id;
442 ut_asserteq(-EINVAL, expo_iter_scene_objs(exp, h_test_iter, &priv));
443
444 /* 2 items (preview_id and the menuitem) are after key_id, 7 - 2 = 5 */
445 ut_asserteq(5, priv.count);
446
447 /* menu is first, so is still processed */
448 ut_asserteq(1, priv.menu_count);
449
Simon Glass65924992023-01-06 08:52:39 -0600450 expo_destroy(exp);
451
452 ut_assertok(ut_check_delta(start_mem));
453
454 return 0;
455}
Simon Glass1a92f832024-08-22 07:57:48 -0600456BOOTSTD_TEST(expo_object_menu, UTF_DM | UTF_SCAN_FDT);
Simon Glass65924992023-01-06 08:52:39 -0600457
458/* Check rendering a scene */
459static int expo_render_image(struct unit_test_state *uts)
460{
461 struct scene_obj_menu *menu;
462 struct scene *scn, *scn2;
463 struct expo_action act;
464 struct scene_obj *obj;
465 struct udevice *dev;
466 struct expo *exp;
467 int id;
468
Simon Glass65924992023-01-06 08:52:39 -0600469 ut_assertok(uclass_first_device_err(UCLASS_VIDEO, &dev));
470
471 ut_assertok(expo_new(EXPO_NAME, NULL, &exp));
472 id = scene_new(exp, SCENE_NAME1, SCENE1, &scn);
473 ut_assert(id > 0);
474 ut_assertok(expo_set_display(exp, dev));
475
476 id = scene_img(scn, "logo", OBJ_LOGO, video_get_u_boot_logo(), NULL);
477 ut_assert(id > 0);
478 ut_assertok(scene_obj_set_pos(scn, OBJ_LOGO, 50, 20));
479
480 id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", NULL);
481 ut_assert(id > 0);
482 ut_assertok(scene_txt_set_font(scn, OBJ_TEXT, "cantoraone_regular",
483 40));
484 ut_assertok(scene_obj_set_pos(scn, OBJ_TEXT, 400, 100));
485
486 id = scene_txt_str(scn, "text", OBJ_TEXT2, STR_TEXT2, "another string",
487 NULL);
488 ut_assert(id > 0);
489 ut_assertok(scene_txt_set_font(scn, OBJ_TEXT2, "nimbus_sans_l_regular",
490 60));
491 ut_assertok(scene_obj_set_pos(scn, OBJ_TEXT2, 200, 600));
492
Simon Glasscfb4f2c2025-05-02 08:46:42 -0600493 id = scene_txt_str(scn, "text", OBJ_TEXT3, STR_TEXT3,
494 "this is yet\nanother string, with word-wrap",
495 NULL);
496 ut_assert(id > 0);
497 ut_assertok(scene_txt_set_font(scn, OBJ_TEXT3, "nimbus_sans_l_regular",
498 60));
499 ut_assertok(scene_obj_set_bbox(scn, OBJ_TEXT3, 500, 200, 1000, 700));
500
Simon Glass65924992023-01-06 08:52:39 -0600501 id = scene_menu(scn, "main", OBJ_MENU, &menu);
502 ut_assert(id > 0);
503
504 id = scene_txt_str(scn, "title", OBJ_MENU_TITLE, STR_MENU_TITLE,
505 "Main Menu", NULL);
506 ut_assert(id > 0);
507 ut_assertok(scene_menu_set_title(scn, OBJ_MENU, OBJ_MENU_TITLE));
508
509 id = scene_txt_str(scn, "cur_item", POINTER_TEXT, STR_POINTER_TEXT, ">",
510 NULL);
511 ut_assert(id > 0);
512 ut_assertok(scene_menu_set_pointer(scn, OBJ_MENU, POINTER_TEXT));
513
514 id = scene_txt_str(scn, "label1", ITEM1_LABEL, STR_ITEM1_LABEL, "Play",
515 NULL);
516 ut_assert(id > 0);
517 id = scene_txt_str(scn, "item1 txt", ITEM1_DESC, STR_ITEM1_DESC,
518 "Lord Melchett", NULL);
519 ut_assert(id > 0);
520 id = scene_txt_str(scn, "item1-key", ITEM1_KEY, STR_ITEM1_KEY, "1",
521 NULL);
522 ut_assert(id > 0);
523 id = scene_img(scn, "item1-preview", ITEM1_PREVIEW,
524 video_get_u_boot_logo(), NULL);
525 id = scene_menuitem(scn, OBJ_MENU, "item1", ITEM1, ITEM1_KEY,
526 ITEM1_LABEL, ITEM1_DESC, ITEM1_PREVIEW, 0, NULL);
527 ut_assert(id > 0);
528
529 id = scene_txt_str(scn, "label2", ITEM2_LABEL, STR_ITEM2_LABEL, "Now",
530 NULL);
531 ut_assert(id > 0);
532 id = scene_txt_str(scn, "item2 txt", ITEM2_DESC, STR_ITEM2_DESC,
533 "Lord Percy", NULL);
534 ut_assert(id > 0);
535 id = scene_txt_str(scn, "item2-key", ITEM2_KEY, STR_ITEM2_KEY, "2",
536 NULL);
537 ut_assert(id > 0);
538 id = scene_img(scn, "item2-preview", ITEM2_PREVIEW,
539 video_get_u_boot_logo(), NULL);
540 ut_assert(id > 0);
541
542 id = scene_menuitem(scn, OBJ_MENU, "item2", ITEM2, ITEM2_KEY,
543 ITEM2_LABEL, ITEM2_DESC, ITEM2_PREVIEW, 0, NULL);
544 ut_assert(id > 0);
545
546 ut_assertok(scene_obj_set_pos(scn, OBJ_MENU, 50, 400));
547
548 scn2 = expo_lookup_scene_id(exp, SCENE1);
549 ut_asserteq_ptr(scn, scn2);
550 scn2 = expo_lookup_scene_id(exp, SCENE2);
551 ut_assertnull(scn2);
552
553 /* render without a scene */
554 ut_asserteq(-ECHILD, expo_render(exp));
555
Simon Glass7a960052023-06-01 10:22:52 -0600556 ut_assertok(expo_calc_dims(exp));
557 ut_assertok(scene_arrange(scn));
558
559 /* check dimensions of text */
560 obj = scene_obj_find(scn, OBJ_TEXT, SCENEOBJT_NONE);
561 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600562 ut_asserteq(400, obj->bbox.x0);
563 ut_asserteq(100, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600564 ut_asserteq(400 + 126, obj->bbox.x1);
565 ut_asserteq(100 + 40, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600566
567 /* check dimensions of image */
568 obj = scene_obj_find(scn, OBJ_LOGO, SCENEOBJT_NONE);
569 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600570 ut_asserteq(50, obj->bbox.x0);
571 ut_asserteq(20, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600572 ut_asserteq(50 + 160, obj->bbox.x1);
573 ut_asserteq(20 + 160, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600574
575 /* check dimensions of menu labels - both should be the same width */
576 obj = scene_obj_find(scn, ITEM1_LABEL, SCENEOBJT_NONE);
577 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600578 ut_asserteq(50, obj->bbox.x0);
579 ut_asserteq(436, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600580 ut_asserteq(50 + 29, obj->bbox.x1);
581 ut_asserteq(436 + 18, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600582
583 obj = scene_obj_find(scn, ITEM2_LABEL, SCENEOBJT_NONE);
584 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600585 ut_asserteq(50, obj->bbox.x0);
586 ut_asserteq(454, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600587 ut_asserteq(50 + 29, obj->bbox.x1);
588 ut_asserteq(454 + 18, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600589
Simon Glass43bfbb22025-05-02 08:46:36 -0600590 /* same for the key */
591 obj = scene_obj_find(scn, ITEM1_KEY, SCENEOBJT_NONE);
592 ut_assertnonnull(obj);
593 ut_asserteq(280, obj->bbox.x0);
594 ut_asserteq(436, obj->bbox.y0);
595 ut_asserteq(280 + 9, obj->bbox.x1);
596 ut_asserteq(436 + 18, obj->bbox.y1);
597
598 obj = scene_obj_find(scn, ITEM2_KEY, SCENEOBJT_NONE);
599 ut_assertnonnull(obj);
600 ut_asserteq(280, obj->bbox.x0);
601 ut_asserteq(454, obj->bbox.y0);
602 ut_asserteq(280 + 9, obj->bbox.x1);
603 ut_asserteq(454 + 18, obj->bbox.y1);
604
605 /* and the description */
606 obj = scene_obj_find(scn, ITEM1_DESC, SCENEOBJT_NONE);
607 ut_assertnonnull(obj);
608 ut_asserteq(330, obj->bbox.x0);
609 ut_asserteq(436, obj->bbox.y0);
610 ut_asserteq(330 + 89, obj->bbox.x1);
611 ut_asserteq(436 + 18, obj->bbox.y1);
612
613 obj = scene_obj_find(scn, ITEM2_DESC, SCENEOBJT_NONE);
614 ut_assertnonnull(obj);
615 ut_asserteq(330, obj->bbox.x0);
616 ut_asserteq(454, obj->bbox.y0);
617 ut_asserteq(330 + 89, obj->bbox.x1);
618 ut_asserteq(454 + 18, obj->bbox.y1);
619
Simon Glass7a960052023-06-01 10:22:52 -0600620 /* check dimensions of menu */
621 obj = scene_obj_find(scn, OBJ_MENU, SCENEOBJT_NONE);
622 ut_assertnonnull(obj);
Simon Glassbc3a15f2025-05-02 08:46:31 -0600623 ut_asserteq(50, obj->bbox.x0);
624 ut_asserteq(400, obj->bbox.y0);
Simon Glassebec4972025-05-02 08:46:33 -0600625 ut_asserteq(50 + 160, obj->bbox.x1);
626 ut_asserteq(400 + 160, obj->bbox.y1);
Simon Glass7a960052023-06-01 10:22:52 -0600627
Simon Glassc6143dc2025-05-02 08:46:35 -0600628 scene_obj_set_width(scn, OBJ_MENU, 170);
629 ut_asserteq(50 + 170, obj->bbox.x1);
630 scene_obj_set_bbox(scn, OBJ_MENU, 60, 410, 50 + 160, 400 + 160);
631 ut_asserteq(60, obj->bbox.x0);
632 ut_asserteq(410, obj->bbox.y0);
633 ut_asserteq(50 + 160, obj->bbox.x1);
634 ut_asserteq(400 + 160, obj->bbox.y1);
635
636 /* reset back to normal */
637 scene_obj_set_bbox(scn, OBJ_MENU, 50, 400, 50 + 160, 400 + 160);
638
Simon Glass65924992023-01-06 08:52:39 -0600639 /* render it */
640 expo_set_scene_id(exp, SCENE1);
641 ut_assertok(expo_render(exp));
642
Simon Glassbe04b962025-05-02 08:46:24 -0600643 ut_asserteq(0, scn->highlight_id);
Simon Glass1b3388c2025-05-02 08:46:25 -0600644 ut_assertok(scene_arrange(scn));
645 ut_asserteq(0, scn->highlight_id);
Simon Glassbe04b962025-05-02 08:46:24 -0600646
Simon Glass65924992023-01-06 08:52:39 -0600647 /* move down */
648 ut_assertok(expo_send_key(exp, BKEY_DOWN));
649
650 ut_assertok(expo_action_get(exp, &act));
651
Simon Glass719a3c62023-06-01 10:22:56 -0600652 ut_asserteq(EXPOACT_POINT_ITEM, act.type);
Simon Glass65924992023-01-06 08:52:39 -0600653 ut_asserteq(ITEM2, act.select.id);
Simon Glassbe04b962025-05-02 08:46:24 -0600654 ut_assertok(scene_menu_select_item(scn, OBJ_MENU, act.select.id));
655 ut_asserteq(ITEM2, scene_menu_get_cur_item(scn, OBJ_MENU));
Simon Glass1b3388c2025-05-02 08:46:25 -0600656 ut_assertok(scene_arrange(scn));
Simon Glass65924992023-01-06 08:52:39 -0600657 ut_assertok(expo_render(exp));
658
Simon Glasscfb4f2c2025-05-02 08:46:42 -0600659 ut_asserteq(14848, video_compress_fb(uts, dev, false));
Simon Glass0dc275f2025-05-02 08:46:41 -0600660 ut_assertok(video_check_copy_fb(uts, dev));
661
Simon Glass65924992023-01-06 08:52:39 -0600662 /* make sure only the preview for the second item is shown */
663 obj = scene_obj_find(scn, ITEM1_PREVIEW, SCENEOBJT_NONE);
Simon Glass6081b0f2023-06-01 10:22:50 -0600664 ut_asserteq(true, obj->flags & SCENEOF_HIDE);
Simon Glass65924992023-01-06 08:52:39 -0600665
666 obj = scene_obj_find(scn, ITEM2_PREVIEW, SCENEOBJT_NONE);
Simon Glass6081b0f2023-06-01 10:22:50 -0600667 ut_asserteq(false, obj->flags & SCENEOF_HIDE);
Simon Glass65924992023-01-06 08:52:39 -0600668
669 /* select it */
670 ut_assertok(expo_send_key(exp, BKEY_SELECT));
671
672 ut_assertok(expo_action_get(exp, &act));
673 ut_asserteq(EXPOACT_SELECT, act.type);
674 ut_asserteq(ITEM2, act.select.id);
675
676 /* make sure the action doesn't come again */
677 ut_asserteq(-EAGAIN, expo_action_get(exp, &act));
678
679 /* make sure there was no console output */
680 ut_assert_console_end();
681
682 /* now try in text mode */
Simon Glassb2c40342023-06-01 10:22:37 -0600683 expo_set_text_mode(exp, true);
Simon Glass65924992023-01-06 08:52:39 -0600684 ut_assertok(expo_render(exp));
685
686 ut_assert_nextline("U-Boot : Boot Menu");
687 ut_assert_nextline("%s", "");
688 ut_assert_nextline("Main Menu");
689 ut_assert_nextline("%s", "");
690 ut_assert_nextline(" 1 Play Lord Melchett");
691 ut_assert_nextline(" > 2 Now Lord Percy");
692
693 /* Move back up to the first item */
694 ut_assertok(expo_send_key(exp, BKEY_UP));
695
696 ut_assertok(expo_action_get(exp, &act));
697
Simon Glass719a3c62023-06-01 10:22:56 -0600698 ut_asserteq(EXPOACT_POINT_ITEM, act.type);
Simon Glass65924992023-01-06 08:52:39 -0600699 ut_asserteq(ITEM1, act.select.id);
Simon Glass1b3388c2025-05-02 08:46:25 -0600700 ut_assertok(scene_menu_select_item(scn, OBJ_MENU, act.select.id));
Simon Glass65924992023-01-06 08:52:39 -0600701
702 ut_assertok(expo_render(exp));
703 ut_assert_nextline("U-Boot : Boot Menu");
704 ut_assert_nextline("%s", "");
705 ut_assert_nextline("Main Menu");
706 ut_assert_nextline("%s", "");
707 ut_assert_nextline(" > 1 Play Lord Melchett");
708 ut_assert_nextline(" 2 Now Lord Percy");
709
710 ut_assert_console_end();
711
712 expo_destroy(exp);
713
714 return 0;
715}
Simon Glassf0425022024-08-22 07:57:54 -0600716BOOTSTD_TEST(expo_render_image, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
Simon Glass61300722023-06-01 10:23:01 -0600717
718/* Check building an expo from a devicetree description */
719static int expo_test_build(struct unit_test_state *uts)
720{
721 struct scene_obj_menu *menu;
722 struct scene_menitem *item;
723 struct scene_obj_txt *txt;
Simon Glassc5ae5b12025-05-02 08:46:40 -0600724 struct abuf orig, *copy;
Simon Glass61300722023-06-01 10:23:01 -0600725 struct scene_obj *obj;
726 struct scene *scn;
727 struct expo *exp;
728 int count;
729 ofnode node;
730
731 node = ofnode_path("/cedit");
732 ut_assert(ofnode_valid(node));
733 ut_assertok(expo_build(node, &exp));
734
735 ut_asserteq_str("name", exp->name);
736 ut_asserteq(0, exp->scene_id);
Simon Glass70c579b2023-10-01 19:13:39 -0600737 ut_asserteq(ID_DYNAMIC_START + 24, exp->next_id);
Simon Glass61300722023-06-01 10:23:01 -0600738 ut_asserteq(false, exp->popup);
739
740 /* check the scene */
741 scn = expo_lookup_scene_id(exp, ID_SCENE1);
742 ut_assertnonnull(scn);
743 ut_asserteq_str("main", scn->name);
744 ut_asserteq(ID_SCENE1, scn->id);
Simon Glass9ef02aa2025-05-02 08:46:37 -0600745 ut_asserteq(ID_DYNAMIC_START, scn->title_id);
Simon Glass61300722023-06-01 10:23:01 -0600746 ut_asserteq(0, scn->highlight_id);
747
748 /* check the title */
749 txt = scene_obj_find(scn, scn->title_id, SCENEOBJT_NONE);
750 ut_assertnonnull(txt);
751 obj = &txt->obj;
752 ut_asserteq_ptr(scn, obj->scene);
753 ut_asserteq_str("title", obj->name);
754 ut_asserteq(scn->title_id, obj->id);
755 ut_asserteq(SCENEOBJT_TEXT, obj->type);
756 ut_asserteq(0, obj->flags);
Simon Glass9ef02aa2025-05-02 08:46:37 -0600757 ut_asserteq_str("Test Configuration",
758 expo_get_str(exp, txt->gen.str_id));
Simon Glass61300722023-06-01 10:23:01 -0600759
760 /* check the menu */
761 menu = scene_obj_find(scn, ID_CPU_SPEED, SCENEOBJT_NONE);
762 obj = &menu->obj;
763 ut_asserteq_ptr(scn, obj->scene);
764 ut_asserteq_str("cpu-speed", obj->name);
765 ut_asserteq(ID_CPU_SPEED, obj->id);
766 ut_asserteq(SCENEOBJT_MENU, obj->type);
767 ut_asserteq(0, obj->flags);
768
769 txt = scene_obj_find(scn, menu->title_id, SCENEOBJT_NONE);
Simon Glass9ef02aa2025-05-02 08:46:37 -0600770 ut_asserteq_str("CPU speed", expo_get_str(exp, txt->gen.str_id));
Simon Glass61300722023-06-01 10:23:01 -0600771
772 ut_asserteq(0, menu->cur_item_id);
773 ut_asserteq(0, menu->pointer_id);
774
775 /* check the items */
776 item = list_first_entry(&menu->item_head, struct scene_menitem,
777 sibling);
778 ut_asserteq_str("00", item->name);
779 ut_asserteq(ID_CPU_SPEED_1, item->id);
780 ut_asserteq(0, item->key_id);
781 ut_asserteq(0, item->desc_id);
782 ut_asserteq(0, item->preview_id);
783 ut_asserteq(0, item->flags);
Simon Glass100389f2024-10-14 16:31:58 -0600784 ut_asserteq(0, item->value);
Simon Glass61300722023-06-01 10:23:01 -0600785
786 txt = scene_obj_find(scn, item->label_id, SCENEOBJT_NONE);
Simon Glass9ef02aa2025-05-02 08:46:37 -0600787 ut_asserteq_str("2 GHz", expo_get_str(exp, txt->gen.str_id));
Simon Glass61300722023-06-01 10:23:01 -0600788
Sughosh Ganuebb1c202024-08-28 22:24:22 +0530789 count = list_count_nodes(&menu->item_head);
Simon Glass61300722023-06-01 10:23:01 -0600790 ut_asserteq(3, count);
791
Simon Glassc5ae5b12025-05-02 08:46:40 -0600792 /* try editing some text */
793 ut_assertok(expo_edit_str(exp, txt->gen.str_id, &orig, &copy));
794 ut_asserteq_str("2 GHz", orig.data);
795 ut_asserteq_str("2 GHz", copy->data);
796
797 /* change it and check that things look right */
798 abuf_printf(copy, "atlantic %d", 123);
799 ut_asserteq_str("2 GHz", orig.data);
800 ut_asserteq_str("atlantic 123", copy->data);
801
Simon Glass61300722023-06-01 10:23:01 -0600802 expo_destroy(exp);
803
804 return 0;
805}
Simon Glass1a92f832024-08-22 07:57:48 -0600806BOOTSTD_TEST(expo_test_build, UTF_DM);