128 lines
6.8 KiB
Python
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()
|