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

nordisk/facett

facett-helix/tests/render.rs

//! **CPU render-proof for facett-helix.** Run a real [`HelixView`] through
//! `egui_kittest` so the helix painter executes, then prove (a) each node rode into
//! the AccessKit tree as a queryable Button carrying its along-axis time `t` as the
//! numeric value (FC-4), and (b) the helix coordinates + traverse/level/wind controls
//! are observable as DATA — "renders nodes + spline edges, deterministic".

use egui::accesskit::Role;
use egui_kittest::Harness;
use egui_kittest::kittest::{NodeT, Queryable};

use facett_core::Facet;
use facett_helix::{HelixView, Msg};

#[test]
fn helix_paints_nodes_into_the_accesskit_tree() {
    let view = HelixView::demo();
    let total = view.state_json()["total_nodes"].as_u64().unwrap();
    assert!(total >= 6);

    let mut view_for_ui = HelixView::demo().with_clock(0.0); // pin the clock → deterministic frame
    let mut harness = Harness::new_ui(move |ui| {
        view_for_ui.ui(ui);
    });
    harness.run();

    // Coil A's "api" task entered the tree as a labelled Button; the node carries its
    // along-axis time `t` (=1.0) as the AccessKit numeric value.
    let api = harness.get_by_label("api · core · task").accesskit_node();
    assert_eq!(api.role(), Role::Button, "a helix node is a queryable Button");
    assert!((api.numeric_value().unwrap() - 1.0).abs() < 1e-6, "the node value is its time `t`");
    // The cross-coil "init" on the lib strand is distinct (label disambiguated by system).
    let lib_init = harness.get_by_label("init · lib · crate").accesskit_node();
    assert_eq!(lib_init.role(), Role::Button);
}

#[test]
fn helix_state_is_data_and_deterministic() {
    // Two views at the same pinned clock produce identical observable state (FC-7).
    let a = HelixView::demo().with_clock(3.0);
    let b = HelixView::demo().with_clock(3.0);
    assert_eq!(a.state_json(), b.state_json(), "pinned clock ⇒ byte-identical state");

    let st = a.state_json();
    assert_eq!(st["coil_count"], 2);
    assert_eq!(st["winds_forward"], true, "the helix winds forward through time");
    // Every node carries its helix coordinates (along-axis t + angular lane) as data.
    for coil in st["coils"].as_array().unwrap() {
        for n in coil["nodes"].as_array().unwrap() {
            assert!(n["along"].is_number() && n["theta"].is_number() && n["lane"].as_u64().is_some());
        }
    }
}

#[test]
fn traverse_advances_the_cursor_through_time() {
    // The traverse is a pure function of the injected clock: a later clock ⇒ a further
    // cursor along the time axis (it loops over the period).
    let early = HelixView::demo().with_clock(0.0).state_json()["cursor_u"].as_f64().unwrap();
    let later = HelixView::demo().with_clock(2.0).state_json()["cursor_u"].as_f64().unwrap();
    assert!((early - 0.0).abs() < 1e-9, "the cursor starts at t=0");
    assert!(later > early, "the traverse advances the time cursor along the axis");
}

#[test]
fn level_filter_and_wind_are_addressable() {
    let mut v = HelixView::demo();
    let all = v.state_json()["coils"][0]["edge_count"].as_u64().unwrap();
    v.update(Msg::SetLevel(1));
    assert!(v.state_json()["coils"][0]["edge_count"].as_u64().unwrap() < all, "direct-only thins the deps");
    v.update(Msg::SetWind(1, 1.0));
    assert_eq!(v.state_json()["coils"][1]["wind"], 1.0, "a coil reeled onto its pin");
}