From f56125ced37bd7a132b9c16ce01c725981ac28bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Mon, 15 Jun 2026 00:15:11 +0200 Subject: [PATCH] docs: test-tree search (GUI) Document the Ctrl+F find bar: field checkboxes, the blockSignals pass that avoids the on_testChecked controller storm, and the flag-driven _refresh_highlight (run > search > default) that keeps the run and search highlight layers from clobbering each other. Co-Authored-By: Claude Opus 4.8 --- DESIGN.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/DESIGN.md b/DESIGN.md index ccf0d42..1739a66 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -194,6 +194,13 @@ pyside6-rcc testium_core_win.qrc -o testium_core_win_rc.py Icons are assigned once when the test file is loaded (not updated live on theme change — a file reload is required). +## Test-tree search (GUI) + +A find bar (Ctrl+F) over the `QTestTree` (`src/testium/main_win/test_tree.py`) highlights matching items and navigates them (Enter / ◂ ▸), with **Name / Type / Doc** checkboxes choosing which fields are searched. Ctrl+F toggles the bar (clearing the highlight); Esc / ✕ close it. The bar (`MainWindow._build_search_bar`, `testium_win.py`) is persistent and reset on each file load (`_reset_search`, called from `test_file_manager`). + +- `QTestTree.search(text, fields)` / `clear_search()` run a **single pass wrapped in `blockSignals(True)`**: `setBackground` emits `itemChanged`, wired to `on_testChecked` (a per-item controller round-trip) — without blocking, searching storms the controller (100 % CPU / freeze) and corrupts the check-state. It expands the ancestors of each match and returns matches in **visual (pre-order)** order for navigation. +- `QTestTreeItem._refresh_highlight()` is the single source of truth for the name-column colours: the **search** highlight (pastel amber bg + forced black text, readable in light *and* dark themes) and the green **run** highlight (`setHighlighted`) are recomputed from state flags with precedence **run > search > default**. No brush is saved/restored, so the two layers never leave a stale/permanent colour when they overlap (e.g. searching while a test runs). + ### `run` item `src/testium/interpreter/test_items/test_item_run.py` — launches a `.tum` file in a new testium instance (`-b` in batch mode, `-r` in GUI mode). Result: - **PASS** if the sub-instance launched and ran to completion (exit code is ignored) @@ -316,6 +323,7 @@ The `testium_assist` editor extension is a thin LSP client that spawns `testium Both Flatpak and AppImage export `TESTIUM_VERSION` from a launcher (Flatpak: launcher script in `org.testium.Testium.yaml`; AppImage: `runtime.env` in `AppImageBuilder.yml`). `get_testium_version()` checks `/.flatpak-info` / `APPIMAGE` and reads `TESTIUM_VERSION` rather than relying on package metadata or repo introspection. ## Recent fixes / notable changes +- Test-tree search (GUI): a Ctrl+F find bar highlights + navigates matching items, with Name/Type/Doc field checkboxes. Search modifications run under `blockSignals` (else `setBackground`→`itemChanged`→`on_testChecked` storms the controller), and the search/run highlights share one flag-driven `_refresh_highlight()` (run > search > default) so overlapping layers never leave a stale colour. See "## Test-tree search (GUI)". - `pytest` item: pytest analogue of `unittest`, but runs on the **host interpreter in a subprocess** (`bins.python_bin()`, like `py_func`) so it works across every packaging channel. A stdlib-only pytest plugin streams collected node-ids + per-test results back over stdout via sentinels; each test becomes a child item with its own PASS/FAIL/SKIP, duration and failure message. Params: `test_file`, `test_method`. Validation item: `test/validation/items/pytest/` (the validation venv now pip-installs `pytest`). See "### `pytest` item". - Graceful item load: a self-loading item that fails to load its module/file (e.g. a `unittest` test file importing a missing module, or `pytest` not installed on the host) no longer aborts the **whole** test load. `TestSet._load_item()` wraps the item's `load()`, emits a `tm.print_warn(...)` at load time and records the reason in `item._load_error`; the `@test_run` wrapper turns a non-None `_load_error` into a clean run-time `FAILURE` (message printed once via `write_footer`). The rest of the campaign loads and runs normally. Applies to module-loading items (`unittest`, `pytest`); structural action loading stays fail-fast. - `console` item — serial robustness + richer `read_until`: (1) a failed serial `open()` now raises a clear `ETUMRuntimeError` ("Serial device '…' does not exist." / permission hint) instead of dumping a pyserial traceback, and a console whose open failed is safely "not open" (init `_thd=None` + `isOpened` guards in `readchar`/`read_nowait`/`close`) so later reads no longer crash with `AttributeError: '_thd'`; the action handlers show a one-liner for expected (`ETUMRuntimeError`) errors and keep the full traceback for unexpected ones. (2) `read_until`'s `expected` now accepts a **list of values** (match any) and a new `regex: true` flag treats each pattern as a Python regex (`re.search` over a bounded tail — `Console.REGEX_WINDOW`; limitation: cost/memory bounded, so a match only after a very long stream or beyond the window won't fire). Flatpak manifest now grants `--device=all` so serial adapters (`/dev/ttyUSB*`, `/dev/ttyACM*`) are visible in the sandbox. Validation: new `read_until` list/regex cases in `test/validation/items/console/test.tum`.