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

nordisk/facett

facett-map/tests/feature_count_memo.rs

//! **GG #12 — the applied-output count is memoised: a still frame walks no layer.**
//!
//! korp's flat canvas reads, after every paint, *how many features each layer drew* — the
//! "applied output" its Quality table and its robot drives assert on. It read that through
//! `MapLayer::feature_count(&cam)` per enabled layer, i.e. a second `ways.iter().filter(draws)`
//! walk over every way on every frame (the audit's "two walks per frame", row 12): the paint
//! walked the ways once through the draw-list memo, and the count walked them again, still
//! screen or not.
//!
//! The answer's inputs are exactly the draw list's — the layer epoch (geometry, enabled set)
//! and the camera — so the counts are memoised on `(layer_epoch, view)`, and a walk counter
//! is the oracle. Stated as WORK ELIMINATED, not milliseconds, for the reason
//! `tests/draw_list_memo.rs` gives at length (contention-dominated boxes).
//!
//! Driven RED first against `feature_counts` without the memo: 100 identical asks over 3
//! layers walked **300** layers; the memo's contract is **3**.

use egui::Color32;
use facett_map::Way;
use facett_map::layer::{LatLon, MapFacet, MapTheme, MapView, PointsLayer, WaysLayer};

const PANE: (f32, f32) = (1600.0, 1000.0);

fn ways(n: usize, seed: f64) -> Vec<Way> {
    (0..n)
        .map(|k| {
            let f = k as f64;
            let y = 59.0 + (f * 0.00013 + seed) % 0.20;
            let x = 18.0 + (f * 0.00021 + seed) % 0.30;
            let line: Vec<(f64, f64)> =
                (0..12).map(|j| (x + j as f64 * 0.0004, y + ((j % 5) as f64) * 0.0003)).collect();
            Way::line(k as i64, "road", line, Color32::GRAY, 1.0)
        })
        .collect()
}

fn facet() -> MapFacet {
    let view = MapView::new(LatLon::new(59.10, 18.15), 11.0, PANE);
    let pts: Vec<(f64, f64)> = (0..500).map(|k| (18.0 + k as f64 * 0.0005, 59.05 + (k % 7) as f64 * 0.01)).collect();
    MapFacet::new("gg12", view, MapTheme::default())
        .with_layer(Box::new(WaysLayer::new("roads-a", ways(4_000, 0.0))))
        .with_layer(Box::new(WaysLayer::new("roads-b", ways(4_000, 0.07))))
        .with_layer(Box::new(PointsLayer::new("points", pts, Color32::RED)))
}

#[test]
fn a_hundred_still_frames_walk_the_layers_once_and_the_counts_are_the_layers_own() {
    let f = facet();
    let first = f.feature_counts();
    assert_eq!(first.len(), 3, "one row per enabled layer");
    // The memo must answer with the SAME numbers the un-memoised per-layer read gives.
    for (id, n) in first.iter() {
        let lay = f.layers().iter().find(|l| l.id() == id).expect("a layer with that id");
        assert_eq!(*n, lay.feature_count(f.view()), "layer {id}: memo vs direct count");
    }
    let total: usize = first.iter().map(|(_, n)| n).sum();
    assert!(total > 0, "the fixture must be in view, or the test measures nothing");
    assert_eq!(f.feature_count(), total, "the facet total is the sum of the rows");

    let walks_after_first = f.feature_count_walk_count();
    assert_eq!(walks_after_first, 3, "the first ask walks each of the 3 layers exactly once");

    for _ in 0..100 {
        let again = f.feature_counts();
        assert_eq!(*again, *first, "a still frame answers the same rows");
    }
    assert_eq!(
        f.feature_count_walk_count(),
        walks_after_first,
        "100 still frames walked {} layer(s); the contract is 0",
        f.feature_count_walk_count() - walks_after_first
    );
}

#[test]
fn a_camera_move_and_a_toggle_each_re_walk_once_and_nothing_else_does() {
    let mut f = facet();
    let _ = f.feature_counts();
    let base = f.feature_count_walk_count();

    // A pan: the answer can change, so the layers are walked again — once each.
    f.view_mut().center.lon += 0.05;
    let moved = f.feature_counts();
    assert_eq!(f.feature_count_walk_count(), base + 3, "a pan re-walks the 3 layers once");
    let _ = f.feature_counts();
    assert_eq!(f.feature_count_walk_count(), base + 3, "the frame after the pan is still");

    // A toggle: one layer fewer is enabled, so 2 walks, and the row for it is GONE — the
    // caller must read disabled as absent, not as a stale count.
    assert!(f.set_layer_enabled("roads-b", false));
    let toggled = f.feature_counts();
    assert_eq!(f.feature_count_walk_count(), base + 5, "a toggle re-walks the 2 enabled layers");
    assert_eq!(toggled.len(), 2);
    assert!(toggled.iter().all(|(id, _)| id != "roads-b"), "a disabled layer has no row");
    assert_ne!(*toggled, *moved);

    // A theme change is NOT an input to the count — no walk.
    f.set_theme(MapTheme::default());
    let _ = f.feature_counts();
    assert_eq!(f.feature_count_walk_count(), base + 5, "the theme is not a count input");
}