Files
MeshCore/test/test_pocket_gui.py
T

128 lines
6.8 KiB
Python

#!/usr/bin/env python3
"""Exercise MeshPocket GUI state and settings with the production headers."""
import os
from pathlib import Path
import shutil
import subprocess
import tempfile
import unittest
from test_replay_reset_integration import extract_braced
ROOT = Path(__file__).resolve().parents[1]
FIXTURE = ROOT / "test/fixtures/pocket_gui"
class PocketGuiTest(unittest.TestCase):
def test_gui_is_only_enabled_for_pocket_full(self):
compiler = shutil.which("g++")
if compiler is None:
self.skipTest("host G++ required")
source = "#include <helpers/ui/PocketGuiConfig.h>\nUI_POCKET_GUI\n"
profiles = [
([], "0"),
(["HELTEC_MESH_POCKET=1"], "0"),
(["COMPANION_RADIO_FULL=1"], "0"),
(["NRF52_PLATFORM=1", "RAK_4631=1", "COMPANION_RADIO_FULL=1"], "0"),
(["ESP32_PLATFORM=1", "LILYGO_T_DECK=1", "COMPANION_RADIO_FULL=1"], "0"),
(["HELTEC_MESH_POCKET=1", "COMPANION_RADIO_FULL=1"], "1"),
(["HELTEC_MESH_POCKET=1", "COMPANION_RADIO_FULL=1", "UI_POCKET_GUI=0"], "0"),
]
for flags, expected in profiles:
with self.subTest(flags=flags):
command = [compiler, "-E", "-P", "-x", "c++", "-",
"-I" + str(ROOT / "src"), *("-D" + flag for flag in flags)]
result = subprocess.run(command, input=source, capture_output=True, text=True)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(result.stdout.strip(), expected)
for flags in ([], ["HELTEC_MESH_POCKET=1"], ["COMPANION_RADIO_FULL=1"]):
command = [compiler, "-E", "-P", "-x", "c++", "-", "-DUI_POCKET_GUI=1",
"-I" + str(ROOT / "src"), *("-D" + flag for flag in flags)]
result = subprocess.run(command, input=source, capture_output=True, text=True)
self.assertNotEqual(result.returncode, 0, "unsupported board accepted Pocket GUI")
self.assertIn("requires MeshPocket Full Companion", result.stderr)
def compile_and_run(self, source, extra_flags=()):
compiler = shutil.which("g++")
if compiler is None:
self.skipTest("host G++ required")
with tempfile.TemporaryDirectory(prefix="mesh-pocket-gui-") as directory:
binary = Path(directory) / "gui-test"
flags = ["-std=c++17", "-Wall", "-Wextra", "-Werror", "-g"]
if os.name != "nt":
flags += ["-fsanitize=address,undefined", "-fno-omit-frame-pointer",
"-fno-pie", "-no-pie"]
command = [compiler, *flags, *extra_flags,
"-I" + str(FIXTURE), "-I" + str(ROOT / "src"), "-I" + str(ROOT),
str(source), "-o", str(binary)]
for args in (command, [str(binary)]):
result = subprocess.run(args, capture_output=True, text=True)
self.assertEqual(result.returncode, 0,
" ".join(args) + "\n" + result.stdout + result.stderr)
def test_sent_messages_preserve_history_without_becoming_unread(self):
self.compile_and_run(FIXTURE / "test_sent_history.cpp")
def test_settings_integrity_and_message_board_state(self):
self.compile_and_run(FIXTURE / "test_pocket_state.cpp")
def test_native_board_layout_and_fractional_timezones(self):
self.compile_and_run(FIXTURE / "test_pocket_render.cpp",
["-DHELTEC_MESH_POCKET=1", "-DCOMPANION_RADIO_FULL=1"])
def test_pocket_controls_keep_network_reader_access(self):
source = (ROOT / "examples/companion_radio/ui-new/UITask.cpp").read_text()
home = source[source.index("class HomeScreen :"):]
navigation = home[home.index(" bool handleInput(char c) override {"):]
navigation = navigation.split("#ifdef COMPANION_EXCLUSIVE_WIFI_BLE", 1)[0]
implementation = "\n".join(extract_braced(home, signature) for signature in (
"void resetRadioProfileDisplayPage() {", "bool isPageVisible(uint8_t page) const {",
"void movePage(int direction) {", "void showFirstPage() {",
"bool isRadioPage() const {"))
implementation += "\n" + navigation + "return false; }\n"
fixture = (FIXTURE / "test_pocket_controls.cpp").read_text()
fixture = fixture.replace("// @HOME_IMPLEMENTATION@", implementation)
with tempfile.TemporaryDirectory(prefix="mesh-pocket-controls-") as directory:
generated = Path(directory) / "controls.cpp"
generated.write_text(fixture)
for signedness in ("-fsigned-char", "-funsigned-char"):
with self.subTest(signedness=signedness):
self.compile_and_run(generated, [signedness, "-DUI_POCKET_GUI=1",
"-DCOMPANION_FEATURE_READER=1", "-DUI_NO_DISCOVER_SCREEN=1",
"-Wno-unused-parameter"])
def test_map_page_shows_world_without_locations_and_preserves_zoom(self):
source = (ROOT / "examples/companion_radio/ui-new/UITask.cpp").read_text()
implementation = "\n".join(extract_braced(source, signature) for signature in (
"static bool pocketLocation(",
"__attribute__((noinline)) void renderPocketMap() {"))
fixture = (FIXTURE / "test_pocket_map_binding.cpp").read_text()
fixture = fixture.replace("// @MAP_IMPLEMENTATION@", implementation)
gui = (ROOT / "examples/companion_radio/ui-new/PocketGui.h").read_text()
fixture = fixture.replace("// @MAP_CHROME_IMPLEMENTATION@",
extract_braced(gui, "void renderMapChrome("))
with tempfile.TemporaryDirectory(prefix="mesh-pocket-map-binding-") as directory:
generated = Path(directory) / "map.cpp"
generated.write_text(fixture)
self.compile_and_run(generated)
def test_received_and_sent_message_bindings_preserve_screen_policy(self):
source = (ROOT / "examples/companion_radio/ui-new/UITask.cpp").read_text()
methods = "\n".join(extract_braced(source, signature) for signature in (
"void UITask::newMsg(", "void UITask::channelMessageSent(",
"char UITask::handleMultiClick("))
fixture = (FIXTURE / "test_pocket_bindings.cpp").read_text()
fixture = fixture.replace("// @ADD_SENT@", extract_braced(source, "void addSent("))
fixture = fixture.replace("// @TASK_METHODS@", methods)
with tempfile.TemporaryDirectory(prefix="mesh-pocket-bindings-") as directory:
generated = Path(directory) / "bindings.cpp"
generated.write_text(fixture)
self.compile_and_run(generated, ["-DUI_POCKET_GUI=1",
"-DCOMPANION_FEATURE_READER=1", "-Wno-unused-parameter"])
if __name__ == "__main__":
unittest.main()