sim-nest 0.1.5

The SIM constellation umbrella facade: one crate that re-exports the runtime kernel, codecs, number domains, and libraries behind features.
Documentation
use std::sync::Arc;

use sim_kernel::{
    Args, Cx, DefaultFactory, Expr, NoopEvalPolicy, Ref, Symbol, Value,
    registry_catalog_read_capability,
};

use crate::runtime::{
    browse::schema::{
        BROWSE_TEST_FIELDS, BrowseTestBuilder, CARD_V2_FIELDS, COVERAGE_FIELDS, CoverageBuilder,
        FACET_FIELDS, FacetBuilder, HELP_FIELDS, HelpBuilder, REDACTION_FIELDS, RedactionBuilder,
        TEST_REPORT_FIELDS, TestReportBuilder, card_v2_for_ref,
    },
    install_core_runtime,
};

use super::support::table_value;

#[test]
fn card_v2_builder_preserves_spine_and_appends_b6_fields() {
    let mut cx = test_cx();
    let subject = Symbol::qualified("core", "help");
    let card = card_v2_for_ref(&mut cx, Ref::Symbol(subject.clone())).unwrap();
    let expr = table_expr(&mut cx, &card);

    assert_eq!(table_keys(&expr), symbols(CARD_V2_FIELDS));
    assert_eq!(
        table_value(&expr, &Symbol::new("subject")),
        Some(&Expr::Symbol(subject))
    );
    assert_eq!(
        table_value(&expr, &Symbol::new("kind")),
        Some(&Expr::Symbol(Symbol::qualified("core", "function")))
    );
    assert_eq!(
        table_keys(table_value(&expr, &Symbol::new("coverage")).expect("coverage")),
        symbols(COVERAGE_FIELDS)
    );
    assert_eq!(
        table_value(&expr, &Symbol::new("freshness")),
        Some(&Expr::Symbol(Symbol::new("unknown")))
    );
}

#[test]
fn registry_catalog_card_preserves_card_v2_spine() {
    let mut cx = test_cx();
    cx.grant(registry_catalog_read_capability());
    let subject = Symbol::qualified("registry", "catalog");
    let subject_value = cx.factory().symbol(subject.clone()).unwrap();
    let card = cx
        .call_function(
            &Symbol::qualified("core", "browse"),
            Args::new(vec![subject_value]),
        )
        .unwrap();
    let expr = table_expr(&mut cx, &card);

    assert_eq!(table_keys(&expr), symbols(CARD_V2_FIELDS));
    assert_eq!(
        table_value(&expr, &Symbol::new("subject")),
        Some(&Expr::Symbol(subject))
    );
    assert_eq!(
        table_value(&expr, &Symbol::new("kind")),
        Some(&Expr::Symbol(Symbol::qualified("registry", "catalog")))
    );
}

#[test]
fn help_builder_emits_exact_key_order() {
    let mut cx = test_cx();
    let subject = cx
        .factory()
        .symbol(Symbol::qualified("core", "help"))
        .unwrap();
    let value = HelpBuilder::new(subject).build(&mut cx).unwrap();

    assert_eq!(value_keys(&mut cx, &value), symbols(HELP_FIELDS));
}

#[test]
fn test_builder_emits_exact_key_order() {
    let mut cx = test_cx();
    let value = BrowseTestBuilder::new(
        Symbol::qualified("test", "sample"),
        Symbol::qualified("test", "runtime"),
    )
    .build(&mut cx)
    .unwrap();

    assert_eq!(value_keys(&mut cx, &value), symbols(BROWSE_TEST_FIELDS));
}

#[test]
fn coverage_facet_redaction_and_report_builders_emit_exact_key_order() {
    let mut cx = test_cx();
    let coverage = CoverageBuilder::default().build(&mut cx).unwrap();
    let facet = FacetBuilder::new(Symbol::qualified("browse", "schema"))
        .build(&mut cx)
        .unwrap();
    let redaction = RedactionBuilder::unavailable().build(&mut cx).unwrap();
    let report = TestReportBuilder::new(Symbol::qualified("test", "sample"))
        .build(&mut cx)
        .unwrap();

    assert_eq!(value_keys(&mut cx, &coverage), symbols(COVERAGE_FIELDS));
    assert_eq!(value_keys(&mut cx, &facet), symbols(FACET_FIELDS));
    assert_eq!(value_keys(&mut cx, &redaction), symbols(REDACTION_FIELDS));
    assert_eq!(value_keys(&mut cx, &report), symbols(TEST_REPORT_FIELDS));
}

#[test]
fn browse_schema_shapes_are_registered() {
    let cx = test_cx();

    for symbol in [
        Symbol::qualified("core", "Card"),
        Symbol::qualified("browse", "Help"),
        Symbol::qualified("browse", "Test"),
        Symbol::qualified("browse", "Coverage"),
        Symbol::qualified("browse", "Facet"),
        Symbol::qualified("browse", "Redaction"),
        Symbol::qualified("browse", "TestReport"),
    ] {
        assert!(
            cx.registry().shape_by_symbol(&symbol).is_some(),
            "{symbol} shape should be registered"
        );
    }
}

fn test_cx() -> Cx {
    let mut cx = Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
    install_core_runtime(&mut cx);
    cx
}

fn value_keys(cx: &mut Cx, value: &Value) -> Vec<Symbol> {
    table_keys(&table_expr(cx, value))
}

fn table_expr(cx: &mut Cx, value: &Value) -> Expr {
    let expr = value.object().as_expr(cx).unwrap();
    assert!(matches!(expr, Expr::Map(_)), "expected table expr");
    expr
}

fn table_keys(expr: &Expr) -> Vec<Symbol> {
    let Expr::Map(entries) = expr else {
        panic!("expected map");
    };
    entries
        .iter()
        .map(|(key, _)| match key {
            Expr::Symbol(symbol) => symbol.clone(),
            other => panic!("expected symbol key, got {other:?}"),
        })
        .collect()
}

fn symbols(fields: &[&str]) -> Vec<Symbol> {
    fields.iter().map(|field| Symbol::new(*field)).collect()
}