"""Smoke test for the native (libadwaita-free) UI backend. Under ``TANINUX_UI=native`` every registered page must ``build()`` without tripping over a gap in the native widget shims (``ui/native.py``). The point is to catch ``AttributeError`` / ``TypeError`` — a missing method or a wrong kwarg on a shim — the kind of runtime crash that only surfaces when a page is opened. The test is deliberately tolerant of *environmental* failures: several pages call system tools (pacman, nmcli, gsettings, …) inside ``build()``. When such a call blows up we skip that page rather than fail — those are not shim gaps. Needs a display. If GTK cannot initialise (headless CI), the whole module is skipped at import time. """ from __future__ import annotations import os # Must be set before taninux.gui.ui is imported so the native backend is chosen. os.environ.setdefault("TANINUX_UI", "native") import pytest # --- GTK availability gate (module-level skip when there is no display) -------- try: import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk _res = Gtk.init_check() _gtk_ok = _res[0] if isinstance(_res, tuple) else bool(_res) except Exception as exc: # noqa: BLE001 — any import/version error means no GTK pytest.skip(f"GTK 4 unavailable: {exc}", allow_module_level=True) else: if not _gtk_ok: pytest.skip("GTK could not initialise (no display)", allow_module_level=True) from taninux.gui import ui # noqa: E402 from taninux.gui.pages import PAGES # noqa: E402 @pytest.fixture(scope="module") def window(): """An off-screen GTK root so built pages have a real window to parent into. Deliberately never presented and never destroyed: realising/tearing down a window here (while pages have spawned worker threads that post idle callbacks) can crash GTK at interpreter shutdown. Leaving it for the OS to reclaim keeps the smoke test stable. """ ui.ensure_css() win = Gtk.Window() ui.set_dark(win, False) yield win @pytest.mark.parametrize("page", PAGES, ids=lambda p: p.key) def test_page_builds(page, window): try: widget = page.build() except (AttributeError, TypeError): # A shim gap (missing method / wrong kwarg) — exactly what we hunt for. raise except Exception as exc: # noqa: BLE001 — a system tool the sandbox lacks pytest.skip(f"{page.key}: build() needs a live system resource: {exc!r}") assert widget is not None, f"{page.key}.build() returned None" # Parent it (unrealised) so the native container measure paths are exercised. holder = Gtk.Box() holder.append(widget)