sim-lib-server 0.1.0

SIM workspace package for sim lib server.
Documentation
use super::*;

#[test]
fn all_shared_example_reuses_the_callers_env() {
    let mut cx = cx();
    install_server_lib(&mut cx).unwrap();
    cx.grant(eval_fabric_capability());

    let shared = cx.factory().string("shared".to_owned()).unwrap();
    cx.env_mut().define(Symbol::new("shared"), shared);

    let server = cx
        .eval_expr(Expr::Call {
            operator: Box::new(Expr::Symbol(Symbol::qualified("server", "start"))),
            args: vec![
                Expr::Symbol(Symbol::new(":address")),
                Expr::Symbol(Symbol::new("local")),
                Expr::Symbol(Symbol::new(":isolate")),
                Expr::Symbol(Symbol::new("all-shared")),
            ],
        })
        .unwrap();
    cx.registry_mut()
        .register_value(Symbol::qualified("test", "shared-server"), server)
        .unwrap();

    let connection = cx
        .call_exprs(
            cx.resolve_function(&Symbol::qualified("server", "connect"))
                .unwrap(),
            vec![Expr::Symbol(Symbol::qualified("test", "shared-server"))],
        )
        .unwrap();
    cx.registry_mut()
        .register_value(Symbol::qualified("test", "shared-conn"), connection)
        .unwrap();

    let value = cx
        .call_exprs(
            cx.resolve_function(&Symbol::qualified("server", "request"))
                .unwrap(),
            vec![
                Expr::Symbol(Symbol::qualified("test", "shared-conn")),
                Expr::Symbol(Symbol::new("shared")),
            ],
        )
        .unwrap();
    assert_eq!(
        value.object().as_expr(&mut cx).unwrap(),
        Expr::String("shared".to_owned())
    );
}

#[test]
fn full_sandbox_example_fails_closed_without_env_or_capability_sharing() {
    let mut cx = strict_name_cx();
    install_server_lib(&mut cx).unwrap();
    cx.grant(eval_fabric_capability());
    cx.grant_named("sandbox.cap");

    let callable = cx
        .factory()
        .opaque(Arc::new(ConstantFn { value: "outside" }))
        .unwrap();
    cx.env_mut().define(Symbol::new("outside"), callable);

    let server = cx
        .eval_expr(Expr::Call {
            operator: Box::new(Expr::Symbol(Symbol::qualified("server", "start"))),
            args: vec![
                Expr::Symbol(Symbol::new(":address")),
                Expr::Symbol(Symbol::new("local")),
                Expr::Symbol(Symbol::new(":isolate")),
                Expr::List(vec![
                    Expr::Symbol(Symbol::new(":env")),
                    Expr::Symbol(Symbol::new("isolate")),
                    Expr::Symbol(Symbol::new(":capabilities")),
                    Expr::Symbol(Symbol::new("isolate")),
                ]),
            ],
        })
        .unwrap();
    cx.registry_mut()
        .register_value(Symbol::qualified("test", "sandbox-server"), server)
        .unwrap();

    let connection = cx
        .call_exprs(
            cx.resolve_function(&Symbol::qualified("server", "connect"))
                .unwrap(),
            vec![Expr::Symbol(Symbol::qualified("test", "sandbox-server"))],
        )
        .unwrap();
    cx.registry_mut()
        .register_value(Symbol::qualified("test", "sandbox-conn"), connection)
        .unwrap();

    let missing_symbol = cx
        .call_exprs(
            cx.resolve_function(&Symbol::qualified("server", "request"))
                .unwrap(),
            vec![
                Expr::Symbol(Symbol::qualified("test", "sandbox-conn")),
                Expr::Call {
                    operator: Box::new(Expr::Symbol(Symbol::new("outside"))),
                    args: Vec::new(),
                },
            ],
        )
        .unwrap_err();
    assert!(!format!("{missing_symbol}").is_empty());

    let denied = cx
        .call_exprs(
            cx.resolve_function(&Symbol::qualified("server", "request"))
                .unwrap(),
            vec![
                Expr::Symbol(Symbol::qualified("test", "sandbox-conn")),
                Expr::Nil,
                Expr::Symbol(Symbol::new(":requires")),
                Expr::List(vec![Expr::String("sandbox.cap".to_owned())]),
            ],
        )
        .unwrap_err();
    assert!(matches!(
        denied,
        sim_kernel::Error::CapabilityDenied { capability }
            if capability == CapabilityName::new("sandbox.cap")
    ));
}

#[test]
fn server_lisp_roundtrips_reflection_except_for_id_and_uptime() {
    let mut cx = cx();
    install_server_lib(&mut cx).unwrap();

    let original = cx
        .eval_expr(Expr::Call {
            operator: Box::new(Expr::Symbol(Symbol::qualified("server", "start"))),
            args: vec![
                Expr::Symbol(Symbol::new(":address")),
                Expr::Symbol(Symbol::new("local")),
                Expr::Symbol(Symbol::new(":codec")),
                Expr::Symbol(Symbol::qualified("codec", "json")),
                Expr::Symbol(Symbol::new(":name")),
                Expr::Symbol(Symbol::qualified("demo", "srv")),
                Expr::Symbol(Symbol::new(":isolate")),
                Expr::List(vec![
                    Expr::Symbol(Symbol::new(":env")),
                    Expr::Symbol(Symbol::new("child")),
                ]),
            ],
        })
        .unwrap();

    let lisp = cx
        .call_function(
            &Symbol::qualified("server", "lisp"),
            sim_kernel::Args::new(vec![original.clone()]),
        )
        .unwrap();
    let lisp_expr = lisp.object().as_expr(&mut cx).unwrap();
    let rebuilt = cx.eval_expr(lisp_expr).unwrap();

    let original_reflect = cx
        .call_function(
            &Symbol::qualified("server", "reflect"),
            sim_kernel::Args::new(vec![original]),
        )
        .unwrap();
    let rebuilt_reflect = cx
        .call_function(
            &Symbol::qualified("server", "reflect"),
            sim_kernel::Args::new(vec![rebuilt]),
        )
        .unwrap();

    let original_map = normalized_reflect_table(&mut cx, original_reflect);
    let rebuilt_map = normalized_reflect_table(&mut cx, rebuilt_reflect);
    assert_eq!(original_map, rebuilt_map);
}