Tighten inbox coverage

This commit is contained in:
mikecarper committed 2026-09-17 13:31:00 -07:00
1 parent 0aaa64d41b
commit 35331d235e
4 files changed
+69 -7

No files matched your search

+1 -1
View File
@@ -195,7 +195,7 @@ jobs:
working-directory: test
run: >-
python3 -B -m unittest
test_message_navigation test_companion_john test_reader_touch_coordinates
test_message_navigation test_companion_reader test_reader_touch_coordinates
test_touch_debug_overlay test_touch_debug_cli test_color_theme
test_indicator_messages_profile test_t096_message_footer_profile
test_indicator_display_profile test_indicator_render_profile
+61 -3
View File
@@ -158,6 +158,24 @@ int main() {
assert(task.getPreviewCount() == 32 && task.getMsgCount() == 0);
displayPowerPrefs().inbox = DisplayInboxMode::Pending;
assert(!messages.hasMessages());
#if COMPANION_FEATURE_JOHN
// Receiving and downloading messages must leave an open reader alone.
Screen reader;
task.john_reader = task.curr = &reader;
for (bool connected : {false, true}) {
task.connected = connected;
for (int i = 0; i < 2; ++i) {
mesh.receive("while reading");
assert(task.isJohnReaderActive());
}
for (int remaining : {1, 0}) {
mesh.download();
assert(task.getMsgCount() == remaining);
assert(task.isJohnReaderActive());
}
}
#endif
}
'''
@@ -260,13 +278,13 @@ int main() {
'''
self.compile_and_run(preamble + implementation)
def compile_and_run(self, source):
def compile_and_run(self, source, reader_enabled=0):
compiler = shutil.which("g++") or shutil.which("clang++")
self.assertIsNotNone(compiler)
with tempfile.TemporaryDirectory(prefix="mesh-inbox-test-") as directory:
executable = Path(directory) / "inbox.exe"
result = subprocess.run([
compiler, "-std=c++17", "-DCOMPANION_FEATURE_JOHN=0",
compiler, "-std=c++17", f"-DCOMPANION_FEATURE_JOHN={reader_enabled}",
"-I" + str(ROOT / "src"), "-I" + str(ROOT / "test/mocks"),
"-x", "c++", "-", str(ROOT / "src/helpers/ui/MomentaryButton.cpp"),
str(ROOT / "src/helpers/ui/DisplayDriver.cpp"), "-o", str(executable),
@@ -287,7 +305,47 @@ int main() {
implementation += QUEUE
for signature in ("bool MyMesh::addToOfflineQueue(", "int MyMesh::getFromOfflineQueue("):
implementation += extract_braced(mesh, signature) + "\n"
self.compile_and_run(preamble + implementation + SCENARIOS)
for reader_enabled in (0, 1):
with self.subTest(reader_enabled=reader_enabled):
self.compile_and_run(preamble + implementation + SCENARIOS, reader_enabled)
def test_summary_shows_newest_visible_message_per_thread(self):
ui = (ROOT / "examples/companion_radio/ui-new/UITask.cpp").read_text()
implementation = extract_braced(ui, "class MsgPreviewScreen :") + ";\n"
scenarios = r'''
struct SummaryDisplay : Display {
SummaryDisplay() { setDimensions(160, 160); }
};
int main() {
using namespace mesh::ui;
SummaryDisplay display;
UITask task(display);
MsgPreviewScreen messages(&task);
messages.addPreview(1, "Alice", "old public", 0, "Public", 0);
messages.addPreview(1, "Bob", "pending public", 0, "Public", 1);
messages.addPreview(1, "Alice", "delivered public", 0, "Public");
messages.addPreview(1, "Carol", "second channel", 2, "Second", 2);
messages.addPreview(0xFF, "Dan", "old direct", -1, nullptr, 3);
messages.addPreview(0xFF, "Dan", "new direct", -1, nullptr, 4);
for (auto mode : {DisplayInboxMode::History, DisplayInboxMode::Pending,
DisplayInboxMode::Unread}) {
displayPowerPrefs().inbox = mode;
display.clear();
messages.renderSummary(display);
assert(display.rectangles.size() == 3); // One divider per thread.
assert(display.contains("Public") && display.contains("Second"));
assert(display.contains("Direct: Dan"));
assert(display.contains("second channel") && display.contains("new direct"));
assert(!display.contains("old public") && !display.contains("old direct"));
// A delivered newer entry cannot hide the newest pending entry.
const bool pending = mode == DisplayInboxMode::Pending;
assert(display.contains("pending public") == pending);
assert(display.contains("delivered public") == !pending);
}
}
'''
self.compile_and_run(PREAMBLE + implementation + scenarios)
def test_summary_uses_newest_visible_message_per_thread(self):
ui = (ROOT / "examples/companion_radio/ui-new/UITask.cpp").read_text()
@@ -20,7 +20,7 @@ packer = importlib.util.module_from_spec(spec)
spec.loader.exec_module(packer)
class CompanionJohnTest(unittest.TestCase):
class CompanionReaderTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.document = json.loads(packer.SOURCE.read_text(encoding="utf-8"))
@@ -83,11 +83,11 @@ class CompanionJohnTest(unittest.TestCase):
cc, cxx = shutil.which("gcc"), shutil.which("g++")
if not cc or not cxx:
self.skipTest("host GCC and G++ required")
with tempfile.TemporaryDirectory(prefix="meshcore-john-") as directory:
with tempfile.TemporaryDirectory(prefix="meshcore-reader-") as directory:
directory = Path(directory)
for platform in ("ESP32_PLATFORM", "NRF52_PLATFORM"):
flags = [f"-D{platform}=1", "-DCOMPANION_RADIO_FULL=1", "-DENABLE_USB_INTERFACE=1"]
obj, binary = directory / "tinf.o", directory / "john.exe"
obj, binary = directory / "tinf.o", directory / "reader.exe"
self.run_checked([cc, "-std=c11", "-Os", *flags, "-c",
str(ROOT / "src/helpers/ota/OtaTinf.c"), "-o", str(obj)])
self.run_checked([cxx, "-std=c++17", "-Os", "-Wall", "-Wextra", "-Werror",
@@ -151,6 +151,8 @@ class CompanionJohnTest(unittest.TestCase):
self.assertIn("#if COMPANION_FEATURE_JOHN\n#include \"JohnReaderScreen.h\"", ui)
self.assertLess(ui.index("#define UI_BUTTON_READER_HINT 1"),
ui.index('#include "JohnReaderScreen.h"'))
# Queue downloads preserve the current screen unconditionally now;
# test_companion_inbox exercises this with the reader enabled.
self.assertIn("else if (isJohnReaderActive())", ui)
self.assertIn("c = handleLongPress(KEY_ENTER);", ui)
self.assertIn("handleDoubleClick(KEY_PREV)", ui)
+2
View File
@@ -99,6 +99,8 @@ int main() {{ return 0; }}
self.assertIn("esp_timer_get_time()", ui)
# Thread selection must respect the selected inbox view. The compiled
# summary regression in test_companion_inbox covers this behavior.
# Summary deduplication must consider the selected inbox mode.
# test_companion_inbox checks the rendered rows for each mode.
if __name__ == "__main__":