Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

facett-graph/tests/scale_lane.rs

//! **`GraphView` above `SCALE_ABOVE` nodes** — one layout and one resident upload per
//! scene, camera-only frames upload nothing, and the FC-4 tree holds the ON-SCREEN nodes
//! under the stated budget (and says so in `state_json`).
//!
//! The installed-renderer gate is opened without a device (`cloud-test-gate`): the
//! paint callbacks land in the frame's shapes and are never executed, so this counts
//! what the lane SENDS on a box with no GPU. The pixels are proven by facett-demo's
//! pages probe on a real adapter (`graph` at 100k, t14s).
#![cfg(feature = "wgpu")]

use egui::{Pos2, Vec2};
use facett_core::render::gpu::graphcloud::cloud;
use facett_core::{Facet, Scene};
use facett_graph::{GraphView, Msg, A11Y_BUDGET, SCALE_ABOVE};

fn ring_scene(n: usize) -> Scene {
    let mut s = Scene::new();
    for i in 0..n {
        s.node(format!("svc {i}"), egui::Color32::from_rgb((i % 251) as u8, 120, 200));
    }
    for i in 0..n {
        s.edge(i, (i + 1) % n);
        s.edge(i, (i * 7 + 3) % n);
    }
    s
}

fn frame(ctx: &egui::Context, g: &mut GraphView) -> Vec<egui::epaint::ClippedShape> {
    let input = egui::RawInput { screen_rect: Some(egui::Rect::from_min_size(Pos2::ZERO, Vec2::new(1200.0, 800.0))), ..Default::default() };
    let mut out = ctx.run_ui(input, |ui| {
        egui::CentralPanel::default().show(ui, |ui| g.ui(ui));
    });
    out.textures_delta.clear();
    out.shapes
}

#[test]
fn a_100k_scene_uploads_once_and_exposes_a_budgeted_tree() {
    cloud::assume_renderer_installed_for_tests();
    let n = 100_000;
    let mut g = GraphView::new(ring_scene(n)).with_gpu(true);
    assert!(g.at_scale() && n > SCALE_ABOVE);
    let ctx = egui::Context::default();
    ctx.set_pixels_per_point(1.0);

    let t0 = std::time::Instant::now();
    let _ = frame(&ctx, &mut g);
    let first = t0.elapsed();
    assert_eq!((g.scale_layouts(), g.resident_uploads()), (1, 1), "the first frame lays out and uploads once");
    let s = g.state_json();
    assert_eq!(s["lane"]["lane_flag"], "gpu", "{}", s["lane"]);
    assert_eq!(s["a11y"]["budget"], A11Y_BUDGET);
    assert_eq!(s["a11y"]["on_screen"], n, "zoom 1: the whole circle is on screen");
    assert_eq!(s["a11y"]["emitted"], A11Y_BUDGET, "…but only the budget is in the tree");
    assert_eq!(s["node_targets"].as_array().unwrap().len(), A11Y_BUDGET, "node_targets is what the tree holds");
    assert!(s.get("nodes").is_some() && s["a11y"]["policy"].as_str().unwrap().contains("ON-SCREEN"));

    // Camera-only frames: pan + zoom. No relayout, no upload.
    let t1 = std::time::Instant::now();
    for i in 0..20 {
        let mut c = g.camera();
        c.pan += Vec2::new(3.0, -1.0);
        if i % 4 == 0 {
            c.zoom *= 1.1;
        }
        g.set_camera(c);
        let _ = frame(&ctx, &mut g);
        assert_eq!((g.scale_layouts(), g.resident_uploads()), (1, 1), "camera frame {i} uploaded nothing");
    }
    let per = t1.elapsed() / 20;
    eprintln!("graph 100k: first frame {first:?}, camera frame {per:?}");

    // Zoom far in on node 0: a handful on screen, every one of them in the tree, labelled.
    assert!(g.focus_node("svc 0", 2_000.0));
    let shapes = frame(&ctx, &mut g);
    let a = g.a11y_json();
    let on = a["on_screen"].as_u64().unwrap() as usize;
    assert!((1..=60).contains(&on), "zoomed in: {a}");
    assert_eq!(a["emitted"].as_u64().unwrap() as usize, on, "under the budget every on-screen node is in the tree");
    assert_eq!(a["labels"].as_u64().unwrap() as usize, on, "and labelled");
    let texts = shapes.iter().filter(|s| matches!(&s.shape, egui::Shape::Text(_))).count();
    assert!(texts >= on, "{texts} text shapes for {on} on-screen labels");
    let targets: Vec<String> = serde_json::from_value(g.state_json()["node_targets"].clone()).unwrap();
    assert!(targets.contains(&"svc 0".to_string()), "{targets:?}");
    assert_eq!(g.resident_uploads(), 1, "still one upload");

    // Selection: an overlay, no upload; SelectNode reaches a node that is off screen.
    let _ = g.update(Msg::SelectNode("svc 50000".into()));
    let _ = frame(&ctx, &mut g);
    assert_eq!(g.selected(), Some("svc 50000"));
    assert_eq!(g.resident_uploads(), 1);

    // A scene change is ONE relayout and ONE upload.
    g.scene.edge(0, 50_000);
    let _ = frame(&ctx, &mut g);
    let _ = frame(&ctx, &mut g);
    assert_eq!((g.scale_layouts(), g.resident_uploads()), (2, 2));
}

#[test]
fn below_the_threshold_every_node_is_in_the_tree_as_before() {
    cloud::assume_renderer_installed_for_tests();
    let mut g = GraphView::new(ring_scene(200)).with_gpu(true);
    let ctx = egui::Context::default();
    let _ = frame(&ctx, &mut g);
    assert!(!g.at_scale());
    let s = g.state_json();
    assert_eq!(s["node_targets"].as_array().unwrap().len(), 200);
    assert!(s.get("a11y").is_none(), "the fixture state keeps its seven keys");
    assert_eq!(g.a11y_json()["budget"], serde_json::Value::Null);
    assert_eq!(g.resident_uploads(), 0, "the fixture painter is not on the resident lane");
}