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

nordisk/dwarves

dwarves-gui/tests/robot_front_tree.rs

//! **🌳 Tree, end to end: UI → forge → nornir.** The tab is given ONLY the forge's
//! address; the forge (the REAL dwarves proxy with its tree lane) folds the tree from
//! the board a mock embedded nornir answers (`Coderoom.Units`) and the tab draws it on
//! the shared graph renderer.
//!
//! `live_tree_render` (ignored) does the same against a LIVE forge — a local proxy in
//! front of `$DWARVES_LIVE_FORGE` (whose code-room door carries the board to its
//! nornir) — and writes a PNG of the drawn tab to `$DWARVES_TREE_PNG`.

use std::sync::Arc;

use dwarves_gui::front_tree::FrontTree;
use facett_core::Facet;
use nornir_warehouse_embed::testkit::{spawn_mock_code_room, MockCodeRoom};
use serde_json::json;

fn board() -> serde_json::Value {
    // a crate of the workspace's own that all three repos use (a registry crate would
    // fold into the repos)
    let core = "path+ws:core/core#core@0.1.0";
    json!({
        "state": "complete",
        "members": [
            { "member": "a", "phase": "compiling", "sha": "1", "units": 2, "done": 1, "own_units": 1 },
            { "member": "b", "phase": "landed", "sha": "2", "units": 2, "done": 2, "own_units": 1 },
            { "member": "c", "phase": "queued", "sha": "3", "units": 1, "done": 1, "own_units": 0 },
        ],
        "counts": { "done": 2, "compiling": 1 },
        "distinct_units": 3,
        "units": [
            { "key": "s", "package": core, "target": "lib:core", "mode": "check", "test": false, "features": ["std"], "members": ["a", "b", "c"], "shared_by": 3, "state": "done", "deps": [] },
            { "key": "a", "package": "path+ws:a#a@0.1.0", "target": "lib:a", "mode": "check", "test": false, "features": [], "members": ["a"], "shared_by": 1, "state": "compiling", "deps": [0] },
            { "key": "b", "package": "path+ws:b#b@0.1.0", "target": "lib:b", "mode": "check", "test": false, "features": [], "members": ["b"], "shared_by": 1, "state": "done", "deps": [0] },
        ],
    })
}

#[test]
fn the_tree_tab_draws_what_the_forge_folds_from_nornirs_board() {
    let room = MockCodeRoom::answering(&[("Coderoom.Units", board())]);
    let asked = room.asked.clone();
    let nornir = spawn_mock_code_room(room);
    let forge = dwarves::warehouse_proxy::spawn_proxy(nornir.endpoint.clone(), String::new());

    let mut tab = FrontTree::new(forge.endpoint.clone(), String::new(), "w".to_string());
    tab.update_json(r#"{"wait":true}"#);
    let s = tab.state_json();
    assert_eq!(s["answer"]["state"], "complete", "{s}");
    assert_eq!(
        (s["nodes"].as_u64(), s["edges"].as_u64()),
        (Some(4), Some(3)),
        "{s}"
    );
    assert!(
        s["header"].as_str().unwrap().starts_with("2/3 units done"),
        "{s}"
    );
    assert_eq!(
        s["marks"],
        json!({ "compiling": 1, "done": 2, "queued": 1 })
    );
    assert!(
        s["answer"]["via"]
            .as_str()
            .unwrap()
            .contains(&forge.endpoint),
        "asked the forge, nothing else: {s}"
    );
    assert_eq!(
        s["first_column"],
        json!(["repo:a", "repo:b", "repo:c"]),
        "the repos line up in the first column: {s}"
    );

    // painted: the first view is framed (the fit ran on the first paint)
    let tab = std::cell::RefCell::new(tab);
    {
        let mut h = egui_kittest::Harness::builder()
            .with_size(egui::vec2(1200.0, 800.0))
            .build_ui(|ui| tab.borrow_mut().ui(ui));
        for _ in 0..4 {
            h.step();
        }
    }
    let mut tab = tab.into_inner();
    let cam = &tab.state_json()["graph"]["camera"];
    assert_eq!(cam["fit_pending"], false, "{cam}");
    assert_ne!(
        cam["zoom"].as_f64(),
        Some(1.0),
        "framed, not left at zoom 1: {cam}"
    );

    // drill into repo a: its own crate appears
    tab.update_json(r#"{"toggle":"repo:a"}"#);
    tab.update_json(r#"{"wait":true}"#);
    assert_eq!(tab.state_json()["nodes"], 5);
    let asked = asked.lock().unwrap().clone();
    assert!(
        asked.iter().all(|(_, s, _)| s == "Coderoom.Units"),
        "nornir is asked the board only: {asked:?}"
    );
}

/// The live render: `DWARVES_LIVE_FORGE=http://… DWARVES_TREE_PNG=/tmp/tree.png cargo test
/// -p dwarves-gui --test robot_front_tree live_tree_render -- --ignored --nocapture`.
#[test]
#[ignore]
fn live_tree_render() {
    let Ok(live) = std::env::var("DWARVES_LIVE_FORGE") else {
        eprintln!("DWARVES_LIVE_FORGE not set — nothing to render");
        return;
    };
    let token = std::env::var("DWARVES_LIVE_TOKEN").unwrap_or_default();
    let ws = std::env::var("DWARVES_LIVE_WORKSPACE").unwrap_or_else(|_| "nordisk".into());
    let forge = dwarves::warehouse_proxy::spawn_proxy(live, token);
    let tab = Arc::new(std::sync::Mutex::new(FrontTree::new(
        forge.endpoint.clone(),
        String::new(),
        ws,
    )));
    tab.lock().unwrap().update_json(r#"{"wait":true}"#);
    if let Ok(expand) = std::env::var("DWARVES_LIVE_EXPAND") {
        for id in expand.split(',').filter(|s| !s.is_empty()) {
            tab.lock()
                .unwrap()
                .update_json(&json!({ "toggle": id }).to_string());
            tab.lock().unwrap().update_json(r#"{"wait":true}"#);
        }
    }
    let s = tab.lock().unwrap().state_json();
    println!("{}", serde_json::to_string_pretty(&json!({
        "answer": s["answer"], "header": s["header"], "nodes": s["nodes"], "edges": s["edges"], "marks": s["marks"], "box": s["box"],
    })).unwrap());
    if let Ok(png) = std::env::var("DWARVES_TREE_PNG") {
        let t2 = tab.clone();
        let mut h = egui_kittest::Harness::builder()
            .with_size(egui::vec2(1800.0, 1100.0))
            .build_ui(move |ui| t2.lock().unwrap().ui(ui));
        for _ in 0..8 {
            h.step();
        }
        match h.render() {
            Ok(img) => {
                img.save(&png).expect("write png");
                println!("wrote {png}");
            }
            Err(e) => println!("no render: {e}"),
        }
    }
}