[Concept,08/22] doc: expo: Add documentation for writing and debugging tests

Message ID 20251207201628.2882382-9-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 new section covering how to write expo tests, including test
structure, memory checking, creating test expos, testing rendering
and input, building from devicetree, and using IDs.

Also add a debugging section with sandbox command-line options useful
for expo development. Add a bit more detail for --video_frames

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

 doc/arch/sandbox/sandbox.rst  |   5 +-
 doc/develop/expo.rst          | 195 ++++++++++++++++++++++++++++++++++
 doc/develop/tests_writing.rst |   2 +
 3 files changed, 201 insertions(+), 1 deletion(-)
  

Patch

diff --git a/doc/arch/sandbox/sandbox.rst b/doc/arch/sandbox/sandbox.rst
index 0d94c5a49cf..b2f4d8913d2 100644
--- a/doc/arch/sandbox/sandbox.rst
+++ b/doc/arch/sandbox/sandbox.rst
@@ -253,7 +253,10 @@  available options. Some of these are described below:
   Show console output from tests. Normally this is suppressed.
 
 --video_frames <dir>
-  Write video frames to the specified directory for debugging purposes.
+  Write video frames to the specified directory for debugging purposes. Each
+  time video_compress_fb() is called, this writes a file called 'frame%d.bmp'
+  to the given directory where %d is the sequence number starting from 0. Note
+  that sandbox removes all 'frame%d.bmp' files in that directory on startup.
 
 -V, --video_test <ms>
   Enable video test mode with a delay (in milliseconds) between assertions. This
diff --git a/doc/develop/expo.rst b/doc/develop/expo.rst
index 84d01b6313b..ca83b403621 100644
--- a/doc/develop/expo.rst
+++ b/doc/develop/expo.rst
@@ -605,6 +605,201 @@  These metrics help identify performance bottlenecks and verify that expo is
 operating efficiently. The timing information is particularly useful when
 optimizing display drivers or debugging slow rendering issues.
 
+Writing expo tests
+------------------
+
+Expo has extensive tests in ``test/boot/expo.c`` and ``test/boot/cedit.c``.
+These can be run under sandbox like any other test (see :doc:`testing`).
+
+Test structure
+~~~~~~~~~~~~~~
+
+Each test function follows a standard pattern::
+
+    static int expo_my_test(struct unit_test_state *uts)
+    {
+        struct expo *exp;
+
+        /* Create expo and perform tests */
+
+        ut_assertok(expo_new("test", NULL, &exp));
+
+        /* ... test code ... */
+
+        expo_destroy(exp);
+
+        return 0;
+    }
+    BOOTSTD_TEST(expo_my_test, UTF_DM | UTF_SCAN_FDT);
+
+The ``BOOTSTD_TEST()`` macro registers the test with the test framework.
+Common flags include:
+
+UTF_DM
+    Requires driver model to be enabled (most expo tests need this)
+
+UTF_SCAN_FDT
+    Scans the device tree for devices (needed for video display)
+
+UTF_CONSOLE
+    Test needs to record console output (needed for commands)
+
+UTF_NO_SILENT
+    Don't silence console output (needed for tests that check rendering output
+    with user input)
+
+Memory checking
+~~~~~~~~~~~~~~~
+
+Tests should verify that no memory is leaked::
+
+    ulong start_mem;
+
+    start_mem = ut_check_free();
+
+    /* ... create expo, test, destroy ... */
+
+    ut_assertok(ut_check_delta(start_mem));
+
+For assertions, see :ref:`tests_writing_assertions`.
+
+Creating test expos
+~~~~~~~~~~~~~~~~~~~
+
+A common pattern is to create a helper function that sets up an expo with
+scenes and objects for testing. See ``create_test_expo()`` in
+``test/boot/expo.c`` for an example::
+
+    static int create_test_expo(struct unit_test_state *uts, struct expo **expp,
+                                struct scene **scnp, struct scene_obj_menu **menup,
+                                ...)
+    {
+        struct expo *exp;
+        struct scene *scn;
+        int id;
+
+        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));
+
+        /* Add objects to the scene */
+        id = scene_txt_str(scn, "text", OBJ_TEXT, STR_TEXT, "my string", NULL);
+        ut_assert(id > 0);
+
+        /* Return pointers */
+        *expp = exp;
+        *scnp = scn;
+
+        return 0;
+    }
+
+Testing rendering
+~~~~~~~~~~~~~~~~~
+
+For graphical rendering tests, use ``video_compress_fb()`` to get a checksum
+of the framebuffer::
+
+    ut_assertok(expo_render(exp));
+    ut_asserteq(expected_checksum, video_compress_fb(uts, dev, false));
+
+For text-mode rendering, check console output lines::
+
+    expo_set_text_mode(exp, true);
+    ut_assertok(expo_render(exp));
+    ut_assert_nextline("Expected line");
+    ut_assert_console_end();
+
+Testing input
+~~~~~~~~~~~~~
+
+To test keyboard input handling, use ``expo_send_key()``::
+
+    ut_assertok(expo_send_key(exp, BKEY_DOWN));
+    ut_assertok(expo_action_get(exp, &act));
+    ut_asserteq(EXPOACT_POINT_ITEM, act.type);
+    ut_asserteq(ITEM2, act.select.id);
+
+To test mouse clicks, use ``scene_send_click()``::
+
+    ut_assertok(scene_send_click(scn, x, y, &act));
+    ut_asserteq(EXPOACT_SELECT, act.type);
+
+Building from devicetree
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+To test building an expo from a devicetree description::
+
+    ofnode node;
+
+    node = ofnode_path("/cedit");
+    ut_assert(ofnode_valid(node));
+    ut_assertok(expo_build(node, &exp));
+
+The test devicetree is in ``test/boot/files/expo_layout.dts`` with IDs
+defined in ``test/boot/files/expo_ids.h``. See ``setup_cedit_file()`` in
+``test/py/img/cedit.py`` for how this is set up.
+
+Using IDs
+~~~~~~~~~
+
+Define an enum for all object IDs at the top of the test file::
+
+    enum {
+        /* scenes */
+        SCENE1 = 7,
+
+        /* objects */
+        OBJ_LOGO,
+        OBJ_TEXT,
+        OBJ_MENU,
+
+        /* strings */
+        STR_TEXT,
+        STR_MENU_TITLE,
+
+        /* menu items */
+        ITEM1,
+        ITEM2,
+    };
+
+Starting IDs from a value higher than ``EXPOID_BASE_ID`` avoids conflicts
+with reserved expo IDs.
+
+Debugging tests
+~~~~~~~~~~~~~~~
+
+Running tests directly (without pytest) makes debugging easier. See
+:doc:`tests_sandbox` for details on running sandbox tests with gdb.
+
+For example, to run a single expo test::
+
+    ./u-boot -T -c "ut bootstd expo_render_image"
+
+To debug with gdb::
+
+    gdb --args ./u-boot -T -c "ut bootstd expo_render_image"
+    (gdb) break expo_render_image
+    (gdb) run
+
+IDEs such as Visual Studio Code can also be used.
+
+Sandbox provides command-line options useful for debugging expo and video
+tests, including ``-l`` (show LCD), ``-K`` (double LCD size), ``-V`` (video
+test mode with delay), ``--video_frames`` (capture frames), ``-f`` (continue
+after failure), and ``-F`` (skip flat-tree tests). See
+:doc:`../arch/sandbox/sandbox` for full details.
+
+For example, to watch an expo test render with a visible display::
+
+    ./u-boot -T -l -V 500 --video_frames /tmp/good -c "ut bootstd expo_render_image"
+
+This will write each asserted expo frame to ``/tmp/good/frame0.bmp``,
+``/tmp/good/frame1.bmp``, etc.
+
 API documentation
 -----------------
 
diff --git a/doc/develop/tests_writing.rst b/doc/develop/tests_writing.rst
index 4b0616376d0..31454aa4819 100644
--- a/doc/develop/tests_writing.rst
+++ b/doc/develop/tests_writing.rst
@@ -373,6 +373,8 @@  existing suite or creating a new one.
 An example SPL test is spl_test_load().
 
 
+.. _tests_writing_assertions:
+
 Assertions
 ----------