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

nordisk/facett

facett-demo/tests/sim_live.rs

//! **The live-SIMULATION wiring gate** (LAW 6 inject-assert). Proves the demo is
//! ALIVE: the in-memory [`Sim`](facett_demo::sim::Sim) ticks, and on each tick the
//! growing self-contained population REALLY flows into the in-deck facets —
//!
//! * the **warehouse** facet gains rows,
//! * the **icebergview** facet accrues a new snapshot (time-travel),
//! * the **Sverige** population facet re-takes the ticking graph,
//!
//! driven through the SAME `DemoState::draw_app` render path the eframe binary
//! uses (CLI/GUI parity), so the wiring is proven to run — not just the `Sim` unit
//! in isolation. Every assertion reads `state_json` (the observable contract), so a
//! failure is attributable, not "didn't panic".

use facett_demo::DemoState;
use facett_demo::sim::TICK_EVERY;

/// Read a facet's folded-in `state_json` from the demo's whole-app state dump.
fn facet_state(demo: &DemoState, title: &str) -> serde_json::Value {
    demo.state_json()["deck"]["facets"][title].clone()
}

/// INJECT-ASSERT: one `sim.tick()` grows the population, appends EXACTLY one
/// snapshot, and grows the warehouse table — the living-stream contract on the
/// `Sim` itself (the headless engine the UI pumps).
#[test]
fn sim_tick_grows_pop_appends_one_snapshot_and_grows_warehouse() {
    let mut demo = DemoState::new();

    // Tick 0 already seeded the facets (feed_facets_from_sim in `new`).
    let ice0 = facet_state(&demo, "icebergview");
    let wh0 = facet_state(&demo, "warehouse");
    let snaps0 = ice0["snapshots"].as_array().unwrap().len();
    let rows0 = wh0["preview"]["rows"].as_u64().unwrap();
    assert_eq!(snaps0, 1, "tick 0 seeded the icebergview with the first snapshot");
    assert_eq!(wh0["selected"], "population", "the warehouse shows the live population table");
    assert!(rows0 > 0, "tick 0 seeded a non-empty population table");
    let pop0 = demo.sim.n_persons();

    // One tick on the sim + push into the facets (the exact wiring draw_app runs).
    demo.sim.tick();
    demo.feed_facets_from_sim();

    let ice1 = facet_state(&demo, "icebergview");
    let snaps1 = ice1["snapshots"].as_array().unwrap().len();
    assert_eq!(snaps1, snaps0 + 1, "exactly one snapshot appended per tick");
    assert!(demo.sim.n_persons() > pop0, "the population grew");
}

/// INJECT-ASSERT (the headline wiring proof): drive the WHOLE demo headless through
/// `draw_app` for K ticks worth of frames; after K ticks the **icebergview** facet's
/// `state_json` reports K+1 snapshots (tick-0 seed + one per tick) and the
/// **warehouse** facet reports MORE rows than at tick 0 (or, once every kommun has a
/// row, a strictly larger population) — data really flowed into the live facets.
#[test]
fn draw_app_drives_the_live_stream_into_warehouse_and_icebergview() {
    let mut demo = DemoState::new();
    demo.show_about = false;

    // Tick-0 baseline (before any frame).
    let snaps0 = facet_state(&demo, "icebergview")["snapshots"].as_array().unwrap().len();
    let wh0 = facet_state(&demo, "warehouse");
    let rows0 = wh0["preview"]["rows"].as_u64().unwrap();
    let pop0 = demo.sim.n_persons();
    assert_eq!(snaps0, 1, "one snapshot before any tick");

    // Drive draw_app through a real headless harness for K ticks worth of frames.
    const K: u64 = 4;
    let frames = TICK_EVERY * K + 2; // a couple extra so the K-th tick lands + feeds
    let mut harness =
        egui_kittest::Harness::builder().with_size(egui::vec2(1280.0, 820.0)).build_ui_state(
            |ui, demo: &mut DemoState| demo.draw_app(ui),
            demo,
        );
    for _ in 0..frames {
        harness.run_steps(1);
    }
    let demo = harness.state();

    // The sim really ticked K times (the throttle fired once per TICK_EVERY frames).
    assert_eq!(demo.sim.ticks(), K, "exactly K ticks across K*TICK_EVERY frames");

    // The icebergview facet accrued K more snapshots (time-travel grew).
    let ice = facet_state(demo, "icebergview");
    let snaps = ice["snapshots"].as_array().unwrap().len() as u64;
    assert_eq!(snaps, snaps0 as u64 + K, "K ticks ⇒ K more snapshots in the live icebergview");
    assert_eq!(ice["table"], "population", "the live icebergview browses the population table");

    // The warehouse facet's population grew. Rows can saturate once every kommun has
    // one, so assert the underlying population strictly grew AND the table is still
    // the live one — the robust "data flowed" oracle.
    let wh = facet_state(demo, "warehouse");
    let rows = wh["preview"]["rows"].as_u64().unwrap();
    assert_eq!(wh["selected"], "population", "the warehouse still shows the live population");
    assert!(demo.sim.n_persons() > pop0, "the population grew over the run");
    assert!(rows >= rows0, "the warehouse row set never shrank ({rows} >= {rows0})");

    // The whole-app state_json carries the live sim stream (the ALIVE proof, as data).
    let s = demo.state_json();
    assert_eq!(s["sim"]["ticks"].as_u64(), Some(K));
    assert_eq!(s["sim"]["snapshots"].as_u64(), Some(snaps0 as u64 + K));
    assert_eq!(s["sim"]["self_contained"], true, "no skade — purely in-memory");
}