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

nordisk/dwarves

crates/nornir-warehouse-nav/tests/robot_world_3d_rotate.rs

//! **robot_world_3d_rotate** — the RED-when-broken proof that the "3D rotating" showpiece spins
//! the CAMERA, not the LAYOUT.
//!
//! The world graph gained a 3D mode (a nested-spherical `galaxy_3d` layout + an orthographic
//! camera) and a **"3D rotating"** checkbox that auto-advances the camera azimuth over time so the
//! galaxy spins slowly around its vertical axis. The one invariant that keeps it a *live* showpiece
//! instead of a stutter-box: rotation must re-run only the cheap PROJECTION each frame — the
//! Barnes–Hut/`galaxy_3d` layout stays cached (0 rebuilds across rotation frames).
//!
//! This guard lives in its OWN test binary so the process-wide `world_build_calls()` counter
//! reflects only this test (each `cargo test` integration file is a separate process). It toggles
//! 3D + rotate on, asserts `state_json` reports both true, then runs N repaint frames and asserts
//! the projection angle CHANGED while the layout rebuild count stayed EXACTLY 0 — the same
//! frame-budget pattern as `robot_world_frame_budget.rs`.
//!
//! NOTE: with rotation on, `ui()` calls `ctx.request_repaint()` every frame, so `Harness::run()`
//! (which loops until no immediate repaint is requested) would never settle — the rotation frames
//! use `run_steps(N)`, which runs EXACTLY N frames and advances the animation clock each step.

#![cfg(not(target_arch = "wasm32"))]

use std::cell::RefCell;
use std::rc::Rc;

use egui::vec2;
use egui_kittest::kittest::Queryable;
use egui_kittest::Harness;
use facett_core::Facet;
use nornir_warehouse_nav::{world_build_calls, WarehouseNav};

/// ROBOT SCENARIO — enter the world graph at the 1000-node preview the demo uses, turn on 3D + the
/// "3D rotating" checkbox, and prove the spin is PROJECTION-ONLY: over N repaint frames the camera
/// azimuth (`rotate_angle`) sweeps while `world_build_calls()` stays flat (0 relayouts).
#[test]
fn world_3d_rotation_spins_the_camera_not_the_layout() {
    let nav = Rc::new(RefCell::new(WarehouseNav::from_fixture_with_functions(
        1000,
    )));
    let n = nav.clone();
    let mut h = Harness::builder()
        .with_size(vec2(1200.0, 800.0))
        .build_ui(move |ui| {
            n.borrow_mut().ui(ui);
        });

    // ── Enter the world graph at the 1000-node preview, in 3D, rotating. ──
    nav.borrow_mut().update_json(r#"{"world_target":1000}"#);
    nav.borrow_mut().update_json(r#"{"world":true}"#);
    nav.borrow_mut().update_json(r#"{"world_3d":true}"#);
    h.run(); // renders + builds the galaxy_3d layout once (rotate still off → run() settles)

    // The 3D layout is live: the preview lane reads galaxy_3d and all three tiers are present.
    let s = Facet::state_json(&*nav.borrow());
    assert_eq!(s["world"], true, "world mode on: {s}");
    assert_eq!(s["world_3d"], true, "3D mode on: {s}");
    assert_eq!(
        s["preview_lane"], "galaxy_3d",
        "the 3D galaxy layout lane is active: {s}"
    );
    assert!(
        s["preview_repo_nodes"].as_u64().unwrap() >= 1,
        "repos tier present: {s}"
    );
    assert!(
        s["preview_crate_nodes"].as_u64().unwrap() >= 1,
        "crates tier present: {s}"
    );
    assert!(
        s["preview_fn_nodes"].as_u64().unwrap() >= 1,
        "functions tier present: {s}"
    );
    // The demo's 1000-node preview really is populated here.
    assert!(
        s["preview_nodes"].as_u64().unwrap() >= 100,
        "the 1000-node preview is populated: {s}"
    );

    // The "3D rotating" checkbox is actually rendered in the pane (wired into `ui()`), not off in a
    // code path nobody reaches.
    assert!(
        h.query_by_label("3D rotating").is_some(),
        "the '3D rotating' checkbox renders in the world controls"
    );

    // Turn the spin on through the headless twin of the checkbox.
    nav.borrow_mut().update_json(r#"{"world_rotate":true}"#);
    let s = Facet::state_json(&*nav.borrow());
    assert_eq!(
        s["world_rotate"], true,
        "the 3D rotating checkbox reads on: {s}"
    );

    // ── The invariant: N rotation frames advance the ANGLE but rebuild the layout 0 times. ──
    let angle0 = s["rotate_angle"]
        .as_f64()
        .expect("rotate_angle is reported");
    let base_builds = world_build_calls();

    const FRAMES: usize = 24;
    h.run_steps(FRAMES); // EXACTLY N frames (run() would spin forever while rotating)

    let builds_delta = world_build_calls() - base_builds;
    let s = Facet::state_json(&*nav.borrow());
    let angle1 = s["rotate_angle"]
        .as_f64()
        .expect("rotate_angle is reported");

    // 0 layout rebuilds across the whole spin — the camera moved, the galaxy_3d layout did not.
    assert_eq!(
        builds_delta, 0,
        "rotation is projection-only: {FRAMES} spin frames rebuilt the layout {builds_delta} times (must be 0)"
    );
    // The projection angle genuinely advanced (a live, moving showpiece — not a frozen frame).
    let moved = (angle1 - angle0).abs();
    assert!(
        moved > 1e-3,
        "the camera azimuth advanced over {FRAMES} frames (Δ={moved:.4} rad, was {angle0:.4} → {angle1:.4})"
    );

    // Turning rotation OFF freezes the angle — no further drift, still 0 rebuilds.
    nav.borrow_mut().update_json(r#"{"world_rotate":false}"#);
    let steady = world_build_calls();
    h.run_steps(6);
    let s = Facet::state_json(&*nav.borrow());
    let angle2 = s["rotate_angle"].as_f64().unwrap();
    assert_eq!(
        world_build_calls() - steady,
        0,
        "a static 3D world does not rebuild either"
    );
    assert!(
        (angle2 - angle1).abs() < 1e-4,
        "azimuth is frozen once rotation is off"
    );

    let ok = builds_delta == 0 && moved > 1e-3 && (angle2 - angle1).abs() < 1e-4;

    // This is a SHIPPED surface (the warehouse landing pane's live 3D showpiece), so it owes the
    // coverage board a row — reuse edda's testmatrix rather than hand-roll a harness.
    #[cfg(feature = "testmatrix")]
    nornir_testmatrix::functional_status(
        "nornir-warehouse-nav",
        "world_3d_rotation_spins_the_camera_not_the_layout",
        ok,
        "the '3D rotating' checkbox auto-spins the world galaxy around its vertical axis by advancing \
         only the orthographic camera azimuth: over 24 repaint frames at the 1000-node preview the \
         projection angle sweeps (Δ>1e-3 rad) while world_build_calls() stays EXACTLY 0 — proving the \
         galaxy_3d layout is reused from cache, never rebuilt per frame; turning rotation off freezes \
         the angle with 0 further rebuilds",
    );
    let _ = ok;
}