greentic-ext-runtime 1.2.26

Wasmtime-based runtime for Greentic Designer Extensions
Documentation
use greentic_ext_runtime::{CapabilityRegistry, OfferedBinding};
use greentic_extension_sdk_contract::{CapabilityRef, ExtensionKind};

fn cap_ref(id: &str, v: &str) -> CapabilityRef {
    CapabilityRef {
        id: id.parse().unwrap(),
        version: v.to_string(),
        deprecated: None,
    }
}

#[test]
fn matches_caret_version() {
    let mut r = CapabilityRegistry::new();
    r.add_offering(OfferedBinding {
        extension_id: "x.offerer".into(),
        cap_id: "greentic:x/y".parse().unwrap(),
        version: "1.2.5".parse().unwrap(),
        kind: ExtensionKind::Design,
        export_path: "ext/y.func".into(),
    });
    let plan = r.resolve("x.consumer", &[cap_ref("greentic:x/y", "^1.0")]);
    assert!(plan.unresolved.is_empty());
    assert_eq!(plan.resolved.len(), 1);
}

#[test]
fn degrades_on_missing_cap() {
    let r = CapabilityRegistry::new();
    let plan = r.resolve("x.consumer", &[cap_ref("greentic:nope/here", "^1.0")]);
    assert_eq!(plan.unresolved.len(), 1);
    assert!(plan.resolved.is_empty());
}

#[test]
fn picks_highest_compatible_semver() {
    let mut r = CapabilityRegistry::new();
    for v in ["1.0.0", "1.2.0", "1.5.0", "2.0.0"] {
        r.add_offering(OfferedBinding {
            extension_id: format!("x.offer-{v}"),
            cap_id: "greentic:x/y".parse().unwrap(),
            version: v.parse().unwrap(),
            kind: ExtensionKind::Design,
            export_path: "e".into(),
        });
    }
    let plan = r.resolve("x.consumer", &[cap_ref("greentic:x/y", "^1.0")]);
    let picked = plan.resolved.values().next().unwrap();
    assert_eq!(picked.version.to_string(), "1.5.0");
}