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_build_scene_features.rs

//! **ROBOT-UI: a cargo feature picked in the Build Thing tab reaches the build.**
//!
//! Owner report 2026-10-16 (loki, dwarves 0aa9c50): an open cargo feature's node
//! said "öppen cargo-feature: `dwarves buildthing` har ingen flagga för den, och ⚒
//! skickar den inte till bygget — klicket n…" (clipped). Through the REAL widgets:
//! tick the feature, press BYGG, and a real cargo build of a crate whose
//! non-default feature changes its output runs WITH it — the outcome says which
//! features built it (the build's own record), and no such notice is on screen.

use facett_core::Facet;
use nornir_robotui::egui_kittest::Harness;
use nornir_robotui::{Observable, RobotSession};

use dwarves_gui::build_forge::DeclaredForge;
use dwarves_gui::build_scene::BuildScene;

struct SceneApp(BuildScene);

impl Observable for SceneApp {
    fn state_json(&self) -> serde_json::Value {
        Facet::state_json(&self.0)
    }
}

fn staged() -> tempfile::TempDir {
    let dir = tempfile::tempdir().unwrap();
    let root = dir.path().join("featured");
    std::fs::create_dir_all(root.join("src")).unwrap();
    std::fs::create_dir_all(root.join(".nornir")).unwrap();
    std::fs::write(
        root.join("Cargo.toml"),
        "[package]\nname = \"featured\"\nversion = \"0.1.0\"\nedition = \"2021\"\n\n[[bin]]\nname = \"featured\"\npath = \"src/main.rs\"\n\n[features]\ndefault = []\nextra = []\n\n[workspace]\n",
    )
    .unwrap();
    std::fs::write(root.join("Cargo.lock"), "version = 4\n\n[[package]]\nname = \"featured\"\nversion = \"0.1.0\"\n").unwrap();
    std::fs::write(
        root.join("src/main.rs"),
        "fn main() {\n    #[cfg(feature = \"extra\")]\n    println!(\"extra\");\n}\n",
    )
    .unwrap();
    std::fs::write(
        root.join(".nornir/build-variants.toml"),
        "[build]\nbase_suite = \"ORIGINAL\"\n\n[[build.variant]]\nname = \"featured\"\nrole = \"server\"\ndefault = true\nsuites = [\"ORIGINAL\"]\npackage = \"featured\"\nbin = \"featured\"\nkind = \"exe\"\nopen = [\"extra\"]\n",
    )
    .unwrap();
    dir
}

#[test]
fn ticking_a_cargo_feature_and_pressing_bygg_builds_with_it() {
    let dir = staged();
    let scene = BuildScene::new(Box::new(DeclaredForge::at(dir.path().to_path_buf())));
    let harness = Harness::builder()
        .with_size(nornir_robotui::egui::Vec2::new(1400.0, 1200.0))
        .build_ui_state(|ui, app: &mut SceneApp| Facet::ui(&mut app.0, ui), SceneApp(scene));
    let mut robot = RobotSession::new(harness, "dwarves-gui");
    robot.run(2);
    robot.type_into("artefakt", "featured").expect("the artefakt field");
    robot.click_label("sök").expect("the sök button");
    robot.run(2);
    robot.click_label("featured").expect("the row");
    robot.run(2);
    robot.click_label("exe").expect("the exe column");
    robot.run(3);

    let state = robot.state();
    assert!(
        !state.to_string().contains("ingen flagga"),
        "the 'no flag' notice is gone — the feature has one now: {state}"
    );
    robot.click_label("extra").expect("the open feature's checkbox");
    robot.run(3);
    assert!(
        robot.state().to_string().contains("--features extra"),
        "ticked, the node shows the flag the build gets"
    );
    robot.click_label("BYGG").expect("BYGG is armed");

    // a real cargo build: pump frames with wall clock until it is terminal
    let deadline = std::time::Instant::now() + std::time::Duration::from_secs(300);
    let outcome = loop {
        robot.run(1);
        if let Some(o) = robot.state_at("/outcome").filter(|o| !o.is_null()) {
            break o;
        }
        assert!(std::time::Instant::now() < deadline, "no outcome: {}", robot.state());
        std::thread::sleep(std::time::Duration::from_millis(200));
    };
    assert_eq!(outcome["ok"], true, "{outcome}");
    let features = outcome["features"].as_str().unwrap_or_default();
    assert!(features.contains("extra"), "the outcome says the build used the feature: {outcome}");
    let artifact = outcome["artifact"].as_str().unwrap_or_default();
    let printed = std::process::Command::new(artifact).output().map(|o| String::from_utf8_lossy(&o.stdout).trim().to_string()).unwrap_or_default();
    assert_eq!(printed, "extra", "the artifact was built WITH the feature ({artifact})");
}