[PATCH 39/40] expo: Add tests for the configuration editor
Simon Glass
sjg at chromium.org
Thu Jun 1 18:23:03 CEST 2023
Add some simple tests and a helpful script to make the configuration
editor easier to set up.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
arch/sandbox/dts/sandbox.dtsi | 6 ++
arch/sandbox/dts/test.dts | 6 ++
test/boot/expo.c | 44 +++++++++++
test/boot/files/expo_layout.dts | 84 +++++++++++++++++++++
test/py/tests/test_ut.py | 10 +++
tools/expo.py | 130 ++++++++++++++++++++++++++++++++
6 files changed, 280 insertions(+)
create mode 100644 test/boot/files/expo_layout.dts
create mode 100755 tools/expo.py
diff --git a/arch/sandbox/dts/sandbox.dtsi b/arch/sandbox/dts/sandbox.dtsi
index 30a305c4d208..f0ee0b3481ac 100644
--- a/arch/sandbox/dts/sandbox.dtsi
+++ b/arch/sandbox/dts/sandbox.dtsi
@@ -16,6 +16,12 @@
stdout-path = "/serial";
};
+ cedit-theme {
+ font-size = <30>;
+ menu-inset = <3>;
+ menuitem-gap-y = <1>;
+ };
+
alarm_wdt: alarm-wdt {
compatible = "sandbox,alarm-wdt";
timeout-sec = <5>;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 442222e4b995..b5509eee8cfe 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -144,6 +144,12 @@
cedit: cedit {
};
+ cedit-theme {
+ font-size = <30>;
+ menu-inset = <3>;
+ menuitem-gap-y = <1>;
+ };
+
fuzzing-engine {
compatible = "sandbox,fuzzing-engine";
};
diff --git a/test/boot/expo.c b/test/boot/expo.c
index e7148024fe30..3898f853a751 100644
--- a/test/boot/expo.c
+++ b/test/boot/expo.c
@@ -5,6 +5,7 @@
*/
#include <common.h>
+#include <command.h>
#include <dm.h>
#include <expo.h>
#include <menu.h>
@@ -668,3 +669,46 @@ static int expo_test_build(struct unit_test_state *uts)
return 0;
}
BOOTSTD_TEST(expo_test_build, UT_TESTF_DM);
+
+/* Check the cedit command */
+static int expo_cedit(struct unit_test_state *uts)
+{
+ extern struct expo *cur_exp;
+ struct scene_obj_menu *menu;
+ struct scene_obj_txt *txt;
+ struct expo *exp;
+ struct scene *scn;
+
+ if (!IS_ENABLED(CONFIG_CMD_CEDIT))
+ return -EAGAIN;
+
+ ut_assertok(run_command("cedit load hostfs - cedit.dtb", 0));
+
+ console_record_reset_enable();
+
+ /*
+ * ^N Move down to second menu
+ * ^M Open menu
+ * ^N Move down to second item
+ * ^M Select item
+ * \e Quit
+ */
+ console_in_puts("\x0e\x0d\x0e\x0d\e");
+ ut_assertok(run_command("cedit run", 0));
+
+ exp = cur_exp;
+ scn = expo_lookup_scene_id(exp, exp->scene_id);
+ ut_assertnonnull(scn);
+
+ menu = scene_obj_find(scn, scn->highlight_id, SCENEOBJT_NONE);
+ ut_assertnonnull(menu);
+
+ txt = scene_obj_find(scn, menu->title_id, SCENEOBJT_NONE);
+ ut_assertnonnull(txt);
+ ut_asserteq_str("AC Power", expo_get_str(exp, txt->str_id));
+
+ ut_asserteq(ID_AC_ON, menu->cur_item_id);
+
+ return 0;
+}
+BOOTSTD_TEST(expo_cedit, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
diff --git a/test/boot/files/expo_layout.dts b/test/boot/files/expo_layout.dts
new file mode 100644
index 000000000000..55d5c910dd5e
--- /dev/null
+++ b/test/boot/files/expo_layout.dts
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Sample expo screen layout
+ */
+
+/dts-v1/;
+
+/*
+enum {
+ ZERO,
+ ID_PROMPT,
+
+ ID_SCENE1,
+ ID_SCENE1_TITLE,
+
+ ID_CPU_SPEED,
+ ID_CPU_SPEED_TITLE,
+ ID_CPU_SPEED_1,
+ ID_CPU_SPEED_2,
+ ID_CPU_SPEED_3,
+
+ ID_POWER_LOSS,
+ ID_AC_OFF,
+ ID_AC_ON,
+ ID_AC_MEMORY,
+
+ ID_DYNAMIC_START,
+};
+*/
+
+/ {
+ dynamic-start = <ID_DYNAMIC_START>;
+
+ scenes {
+ main {
+ id = <ID_SCENE1>;
+
+ /* value refers to the matching id in /strings */
+ title-id = <ID_SCENE1_TITLE>;
+
+ /* simple string is used as it is */
+ prompt = "UP and DOWN to choose, ENTER to select";
+
+ /* defines a menu within the scene */
+ cpu-speed {
+ type = "menu";
+ id = <ID_CPU_SPEED>;
+
+ /*
+ * has both string and ID. The string is ignored
+ * if the ID is present and points to a string
+ */
+ title = "CPU speed";
+ title-id = <ID_CPU_SPEED_TITLE>;
+
+ /* menu items as simple strings */
+ item-label = "2 GHz", "2.5 GHz", "3 GHz";
+
+ /* IDs for the menu items */
+ item-id = <ID_CPU_SPEED_1 ID_CPU_SPEED_2
+ ID_CPU_SPEED_3>;
+ };
+
+ power-loss {
+ type = "menu";
+ id = <ID_POWER_LOSS>;
+
+ title = "AC Power";
+ item-label = "Always Off", "Always On",
+ "Memory";
+
+ item-id = <ID_AC_OFF ID_AC_ON ID_AC_MEMORY>;
+ };
+ };
+ };
+
+ strings {
+ title {
+ id = <ID_SCENE1_TITLE>;
+ value = "Test Configuration";
+ value-es = "configuración de prueba";
+ };
+ };
+};
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index 0b45863b4385..aa1d477cd565 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -282,6 +282,15 @@ label Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
copy_prepared_image(cons, mmc_dev, fname)
+def setup_cedit_file(cons):
+ infname = os.path.join(cons.config.source_dir,
+ 'test/boot/files/expo_layout.dts')
+ expo_tool = os.path.join(cons.config.source_dir, 'tools/expo.py')
+ outfname = 'cedit.dtb'
+ u_boot_utils.run_and_log(
+ cons, f'{expo_tool} -e {infname} -l {infname} -o {outfname}')
+
+
@pytest.mark.buildconfigspec('ut_dm')
def test_ut_dm_init(u_boot_console):
"""Initialize data for ut dm tests."""
@@ -319,6 +328,7 @@ def test_ut_dm_init_bootstd(u_boot_console):
setup_bootflow_image(u_boot_console)
setup_bootmenu_image(u_boot_console)
+ setup_cedit_file(u_boot_console)
# Restart so that the new mmc1.img is picked up
u_boot_console.restart_uboot()
diff --git a/tools/expo.py b/tools/expo.py
new file mode 100755
index 000000000000..c6eb87aec739
--- /dev/null
+++ b/tools/expo.py
@@ -0,0 +1,130 @@
+#!/usr/bin/env python3
+# SPDX-License-Identifier: GPL-2.0+
+
+"""
+Expo utility - used for testing of expo features
+
+Copyright 2023 Google LLC
+Written by Simon Glass <sjg at chromium.org>
+"""
+
+import argparse
+import collections
+import io
+import re
+import subprocess
+import sys
+
+#from u_boot_pylib import cros_subprocess
+from u_boot_pylib import tools
+
+# Parse:
+# SCENE1 = 7,
+# or SCENE2,
+RE_ENUM = re.compile(r'(\S*)(\s*= (\d))?,')
+
+# Parse #define <name> "string"
+RE_DEF = re.compile(r'#define (\S*)\s*"(.*)"')
+
+def calc_ids(fname):
+ """Figure out the value of the enums in a C file
+
+ Args:
+ fname (str): Filename to parse
+
+ Returns:
+ OrderedDict():
+ key (str): enum name
+ value (int or str):
+ Value of enum, if int
+ Value of #define, if string
+ """
+ vals = collections.OrderedDict()
+ with open(fname, 'r', encoding='utf-8') as inf:
+ in_enum = False
+ cur_id = 0
+ for line in inf.readlines():
+ line = line.strip()
+ if line == 'enum {':
+ in_enum = True
+ continue
+ if in_enum and line == '};':
+ in_enum = False
+
+ if in_enum:
+ if not line or line.startswith('/*'):
+ continue
+ m_enum = RE_ENUM.match(line)
+ if m_enum.group(3):
+ cur_id = int(m_enum.group(3))
+ vals[m_enum.group(1)] = cur_id
+ cur_id += 1
+ else:
+ m_def = RE_DEF.match(line)
+ if m_def:
+ vals[m_def.group(1)] = tools.to_bytes(m_def.group(2))
+
+ return vals
+
+
+def run_expo(args):
+ """Run the expo program"""
+ ids = calc_ids(args.enum_fname)
+
+ indata = tools.read_file(args.layout)
+
+ outf = io.BytesIO()
+
+ for name, val in ids.items():
+ if isinstance(val, int):
+ outval = b'%d' % val
+ else:
+ outval = b'"%s"' % val
+ find_str = r'\b%s\b' % name
+ indata = re.sub(tools.to_bytes(find_str), outval, indata)
+
+ outf.write(indata)
+ data = outf.getvalue()
+
+ with open('/tmp/asc', 'wb') as outf:
+ outf.write(data)
+ proc = subprocess.run('dtc', input=data, capture_output=True, check=True)
+ edtb = proc.stdout
+ if proc.stderr:
+ print(proc.stderr)
+ return 1
+ tools.write_file(args.outfile, edtb)
+ return 0
+
+
+def parse_args(argv):
+ """Parse the command-line arguments
+
+ Args:
+ argv (list of str): List of string arguments
+
+ Returns:
+ tuple: (options, args) with the command-line options and arugments.
+ options provides access to the options (e.g. option.debug)
+ args is a list of string arguments
+ """
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-e', '--enum-fname', type=str,
+ help='C file containing enum declaration for expo items')
+ parser.add_argument('-l', '--layout', type=str,
+ help='Devicetree file source .dts for expo layout')
+ parser.add_argument('-o', '--outfile', type=str,
+ help='Filename to write expo layout dtb')
+
+ return parser.parse_args(argv)
+
+def start_expo():
+ """Start the expo program"""
+ args = parse_args(sys.argv[1:])
+
+ ret_code = run_expo(args)
+ sys.exit(ret_code)
+
+
+if __name__ == "__main__":
+ start_expo()
--
2.41.0.rc0.172.g3f132b7071-goog
More information about the U-Boot
mailing list