[Concept,22/22] test: expo: Add a test for textline rendering in an expo

Message ID 20251207201628.2882382-23-sjg@u-boot.org
State New
Headers
Series expo: Expand docs, dump and textlines in non-popup expos |

Commit Message

Simon Glass Dec. 7, 2025, 8:16 p.m. UTC
  From: Simon Glass <simon.glass@canonical.com>

Add a test that creates a textline in a non-popup expo, renders it,
opens it, sends keypresses to edit text (including cursor movement
with Ctrl+B and character deletion with Ctrl+D), and verifies the
text is saved when the textline is closed.

Co-developed-by: Claude <claude@anthropic.com>
Signed-off-by: Simon Glass <simon.glass@canonical.com>
---

 test/boot/expo.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 116 insertions(+)
  

Patch

diff --git a/test/boot/expo.c b/test/boot/expo.c
index f98a1e46854..03ad3e2167d 100644
--- a/test/boot/expo.c
+++ b/test/boot/expo.c
@@ -33,6 +33,7 @@  enum {
 	OBJ_MENU_TITLE,
 	OBJ_BOX,
 	OBJ_BOX2,
+	OBJ_TEXTLINE,
 	OBJ_TEXTED,
 	OBJ_OVERLAP,
 
@@ -1392,3 +1393,118 @@  static int expo_dump_test(struct unit_test_state *uts)
 	return 0;
 }
 BOOTSTD_TEST(expo_dump_test, UTF_DM | UTF_SCAN_FDT);
+
+/* Check behaviour of textlines in a non-popup expo */
+static int expo_render_textline(struct unit_test_state *uts)
+{
+	struct scene_obj_textline *tline;
+	struct scene_obj_menu *menu;
+	struct abuf buf, logo_copy;
+	struct expo_action act;
+	struct scene *scn;
+	struct udevice *dev;
+	struct expo *exp;
+	int id;
+
+	ut_assertok(create_test_expo(uts, &exp, &scn, &menu, &buf, &logo_copy));
+	dev = exp->display;
+
+	id = scene_textline(scn, "textline", OBJ_TEXTLINE, 20, &tline);
+	ut_assert(id > 0);
+	ut_assertok(scene_obj_set_pos(scn, OBJ_TEXTLINE, 500, 500));
+	strcpy(abuf_data(&tline->buf), "sample hopwind");
+
+	/* create the label text object */
+	id = scene_txt_str(scn, "tline-label", 0, 0, "Label:", NULL);
+	ut_assert(id > 0);
+	tline->label_id = id;
+
+	/* create the edit text object pointing to the textline buffer */
+	id = scene_txt_str(scn, "tline-edit", 0, 0, abuf_data(&tline->buf),
+			   NULL);
+	ut_assert(id > 0);
+	tline->edit_id = id;
+	ut_assertok(scene_txt_set_font(scn, tline->edit_id,
+				       "nimbus_sans_l_regular", 40));
+
+	expo_set_scene_id(exp, SCENE1);
+	ut_assertok(scene_arrange(scn));
+	ut_assertok(expo_render(exp));
+	ut_asserteq(21007, video_compress_fb(uts, dev, false));
+
+	/* highlight the textline and re-render */
+	scene_set_highlight_id(scn, OBJ_TEXTLINE);
+	ut_assertok(scene_arrange(scn));
+	ut_assertok(expo_render(exp));
+	ut_asserteq(22693, video_compress_fb(uts, dev, false));
+
+	/* open the textline and re-render */
+	ut_assertok(scene_set_open(scn, OBJ_TEXTLINE, true));
+	ut_assertok(scene_arrange(scn));
+	ut_assertok(expo_render(exp));
+
+	/* the cursor should be at the end */
+	ut_asserteq(22695, video_compress_fb(uts, dev, false));
+
+	/* send a keypress to add a character */
+	ut_assertok(expo_send_key(exp, 'a'));
+	ut_assertok(scene_arrange(scn));
+	ut_assertok(expo_render(exp));
+	ut_asserteq(22818, video_compress_fb(uts, dev, false));
+
+	/* move cursor left 3 times */
+	ut_assertok(expo_send_key(exp, CTL_CH('b')));
+
+	/* check cursor moved back one position, before 'a' */
+	ut_asserteq(14, scn->cls.num);
+	ut_asserteq(15, scn->cls.eol_num);
+	ut_asserteq_str("sample hopwinda", abuf_data(&tline->buf));
+	ut_assertok(scene_arrange(scn));
+	ut_assertok(expo_render(exp));
+	ut_asserteq(22884, video_compress_fb(uts, dev, false));
+
+	ut_assertok(expo_send_key(exp, CTL_CH('b')));
+	ut_assertok(expo_send_key(exp, CTL_CH('b')));
+	ut_assertok(expo_send_key(exp, CTL_CH('b')));
+
+	/* check cursor moved back three more positions, before 'i' */
+	ut_asserteq(11, scn->cls.num);
+	ut_asserteq(15, scn->cls.eol_num);
+	ut_asserteq_str("sample hopwinda", abuf_data(&tline->buf));
+	ut_assertok(scene_arrange(scn));
+	ut_assertok(expo_render(exp));
+	ut_asserteq(22915, video_compress_fb(uts, dev, false));
+
+	/* delete a character at the cursor */
+	ut_assertok(expo_send_key(exp, CTL_CH('d')));
+
+	/* check character deleted at cursor position */
+	ut_asserteq(11, scn->cls.num);
+	ut_asserteq(14, scn->cls.eol_num);
+	ut_asserteq_str("sample hopwnda", abuf_data(&tline->buf));
+	ut_assertok(scene_arrange(scn));
+	ut_assertok(expo_render(exp));
+	ut_asserteq(22856, video_compress_fb(uts, dev, false));
+
+	/* close the textline with Enter (BKEY_SELECT) */
+	ut_assertok(expo_send_key(exp, BKEY_SELECT));
+	ut_assertok(expo_action_get(exp, &act));
+	ut_asserteq(EXPOACT_CLOSE, act.type);
+	ut_asserteq(OBJ_TEXTLINE, act.select.id);
+	ut_assertok(scene_set_open(scn, act.select.id, false));
+
+	/* check the textline is closed and text was saved */
+	ut_asserteq(0, tline->obj.flags & SCENEOF_OPEN);
+	ut_asserteq_str("sample hopwnda", abuf_data(&tline->buf));
+	ut_assertok(scene_arrange(scn));
+	ut_assertok(expo_render(exp));
+	ut_asserteq(22839, video_compress_fb(uts, dev, false));
+
+	abuf_uninit(&buf);
+	abuf_uninit(&logo_copy);
+
+	expo_destroy(exp);
+
+	return 0;
+}
+BOOTSTD_TEST(expo_render_textline, UTF_DM | UTF_SCAN_FDT | UTF_NO_SILENT);