facett-map3d/tests/lane_flag.rs
//! **"A flag saying GPU or CPU when rendering osm 3d, so i know whats being used"** —
//! The owner, 2026-08-23. This is the guard that it is really ON SCREEN, and that its
//! third state exists.
//!
//! # Why the assertion is the a11y tree and not a pixel
//!
//! `facett_core::devid::badge` learned this the hard way and says so: *"Painted-only text
//! is invisible to every check we have — which is how a badge ships green and never
//! appears."* So the chip is emitted as a real AccessKit node and the oracle is
//! `get_by_label` / `query_by_label` over that tree — which proves the chip was laid out
//! at a real rect in a real pass, not that some code path could have painted it.
//!
//! # Three states, and the third is the point
//!
//! `Map3D::used_gpu_observed()` is `None` until a frame has been through the backend.
//! Rendering that as `CPU` is the exact lie this codebase keeps getting caught by: on
//! 2026-08-06 a pre-paint read of `used_gpu()` published `false` — the spelling of the
//! real defect — on a build with the GPU lane compiled in, the renderer installed and a
//! discrete card selected, and three people read it as the defect. So `Pending` is
//! asserted as its own answer, distinct from both.
//!
//! Run (the GPU arm needs the real device and opens NO window):
//! ```text
//! env -u WAYLAND_DISPLAY -u DISPLAY \
//! cargo test -p facett-map3d --features wgpu --test lane_flag -- --test-threads=1 --nocapture
//! ```
use egui_kittest::kittest::Queryable;
use facett_core::render::lane::{lane_flag_atom, LaneFlag};
use facett_core::Theme;
use facett_map::Way;
use facett_map3d::Map3D;
const CANVAS: egui::Vec2 = egui::vec2(640.0, 480.0);
/// Six little buildings in central Stockholm — the same shape
/// `gpu_lane_before_the_first_frame::scene` uses, so both files probe one scene.
fn scene() -> Map3D {
let theme = Theme::default();
let ring = |lon: f64, lat: f64, h: f64| {
vec![(lon - h, lat - h), (lon + h, lat - h), (lon + h, lat + h), (lon - h, lat + h), (lon - h, lat - h)]
};
let mut ways: Vec<Way> = Vec::new();
for i in 0..6 {
let d = f64::from(i) * 0.0004;
ways.extend(Way::from_lonlat(
100 + i64::from(i),
&ring(18.0686 + d, 59.3293 + d, 0.00008),
&[("building", "yes")],
&theme,
));
}
Map3D::from_geometry("lane probe", &ways)
}
/// The three atom labels, so a "present" assertion cannot accidentally match the wrong
/// one and a "absent" assertion covers every alternative.
fn atoms() -> [String; 3] {
[lane_flag_atom(LaneFlag::Gpu), lane_flag_atom(LaneFlag::Cpu), lane_flag_atom(LaneFlag::Pending)]
}
/// Assert the pane shows EXACTLY `want` and none of the other two — the part that makes
/// this non-vacuous. "the GPU label is there" is satisfied by a pane that paints all
/// three; "exactly one, and it is this one" is not.
fn assert_shows_exactly(harness: &egui_kittest::Harness<'_>, want: LaneFlag) {
let wanted = lane_flag_atom(want);
let present: Vec<String> =
atoms().into_iter().filter(|a| harness.query_by_label(a.as_str()).is_some()).collect();
assert_eq!(
present,
vec![wanted.clone()],
"the pane must carry EXACTLY the {want:?} flag ({wanted:?}); the a11y tree carries \
{present:?}"
);
}
// ─────────────────────────────────────────────────────────────────────────────
/// **PENDING is a real state, and it is not CPU.** Before the scene has been through
/// `view` there is no measurement, and `lane_flag()` must say so.
///
/// Non-vacuous both ways: the same scene must STOP being pending once it has painted, or
/// this would pass on a `lane_flag()` hardwired to `Pending`.
///
/// RED: make `Map3D::lane_flag` read `used_gpu()` (the `bool` reader that collapses "not
/// measured" into `false`) instead of `used_gpu_observed()` — the first assertion then
/// reports `Cpu` before a single frame has existed, which is the 2026-08-06 defect
/// reproduced exactly.
#[test]
fn before_any_paint_the_flag_is_pending_and_after_one_it_is_not() {
let mut map = scene();
assert_eq!(
map.lane_flag(),
LaneFlag::Pending,
"a scene that has never been painted has no lane to report — it must not claim the \
CPU painter drew it"
);
assert_eq!(map.used_gpu_observed(), None, "…and that is exactly what the raw reader says");
let mut harness = egui_kittest::Harness::builder()
.with_size(CANVAS)
.build_ui(move |ui| {
facett_core::set_theme(ui.ctx(), Theme::default());
// **The call korp makes**, not the inherent `Map3D::view`. korp paints this
// pane with `facett_core::Facet::ui(map, ui)` (korp/src/map_views.rs:2210),
// which the `impl_facet_via_elm!` bridge writes as the FC-9 loop
// `for m in view(ui) { update(m) }`. Driving the inherent method would prove
// the FUNCTION paints the chip and leave the PROGRAM unproven — the same
// function-vs-program gap that made `run_watch`'s degrade promise true of the
// function and false of the binary.
facett_core::Facet::ui(&mut map, ui);
// Read INSIDE the closure: the flag is a fact about the paint that just
// happened, and `map` is moved in here.
FLAG_AFTER.with(|c| c.set(Some(map.lane_flag())));
});
// `run_steps`, never `run()`: `Map3D::view` keeps requesting repaints (the idle
// animation at lib.rs:4884), so `run()` trips its max-steps guard — that is a
// property of the pane, not a failure of this probe.
harness.run_steps(3);
let after = FLAG_AFTER.with(std::cell::Cell::get).expect("the closure ran at least once");
assert_ne!(
after,
LaneFlag::Pending,
"after a real pass the pane must have an ANSWER — a `lane_flag` stuck on Pending \
would satisfy the first assertion and mean nothing"
);
}
thread_local! {
static FLAG_AFTER: std::cell::Cell<Option<LaneFlag>> = const { std::cell::Cell::new(None) };
}
/// **The CPU painter shows CPU.** The default backend IS the CPU painter (`wgpu` is off by
/// default and no renderer is installed here), so this is the shipped answer for every
/// host without the GPU lane — and it must be on the pane, not only in a log.
///
/// RED: change `paint_lane_flag`'s call site in `Map3D::view` to sit BEFORE
/// `self.backend.paint(..)` — the flag then reads `—` on every frame forever, which is
/// the same non-answer `log_what_it_is_drawing` printed on 41 consecutive draws.
#[test]
fn the_cpu_painter_shows_cpu_on_the_pane() {
let mut map = scene();
assert!(!map.gpu_lane_selected(), "fixture: no GPU lane is selected in this build/config");
let mut harness = egui_kittest::Harness::builder()
.with_size(CANVAS)
.build_ui(move |ui| {
facett_core::set_theme(ui.ctx(), Theme::default());
facett_core::Facet::ui(&mut map, ui);
});
harness.run_steps(3);
assert_shows_exactly(&harness, LaneFlag::Cpu);
}
/// **The GPU lane shows GPU** — on the real device, through facett's OWN adapter policy.
///
/// Deliberately NOT `egui_kittest::wgpu::default_wgpu_setup()`: its selector prefers
/// software rasterisers, so a green there would have said "the GPU lane ran" about
/// llvmpipe while an RTX 4090 sat beside it (the argument
/// `gpu_lane_before_the_first_frame` makes at length).
///
/// RED: pass `with_gpu(false)` — the pane then shows `lane: CPU` and this fails, which is
/// also the proof that the two arms of this file are not both reading one constant.
#[cfg(feature = "wgpu")]
#[test]
fn the_gpu_lane_shows_gpu_on_the_pane() {
use egui_kittest::wgpu::{create_render_state, WgpuTestRenderer};
let setup = facett_core::render::gpu::adapter_wgpu::facett_wgpu_options().wgpu_setup;
let rs = create_render_state(setup, Default::default());
let info = rs.adapter.get_info();
eprintln!("LOOK: adapter {} [{:?}/{:?}]", info.name, info.device_type, info.backend);
facett_map3d::gpu::install_renderer(&rs);
let mut map = scene().with_gpu(true);
assert!(map.gpu_lane_selected(), "fixture: the wgpu lane is selected");
assert_eq!(map.lane_flag(), LaneFlag::Pending, "…and nothing has been observed yet");
let mut harness = egui_kittest::Harness::builder()
.with_size(CANVAS)
.renderer(WgpuTestRenderer::from_render_state(rs))
.build_ui(move |ui| {
facett_core::set_theme(ui.ctx(), Theme::default());
facett_core::Facet::ui(&mut map, ui);
});
harness.run_steps(3);
let _img = harness.render().expect("the wgpu backend produced a frame");
// One more laid-out pass AFTER the render, so the tree carries the label the pane
// painted from an observation the device had already answered.
harness.run_steps(1);
assert_shows_exactly(&harness, LaneFlag::Gpu);
}