yang2 0.4.0

libyang2 bindings for Rust
Documentation
use yang2::context::{Context, ContextFlags};
use yang2::schema::{
    DataValue, DataValueType, SchemaNodeKind, SchemaPathFormat,
};

static SEARCH_DIR: &str = "./assets/yang/";

fn create_context() -> Context {
    // Initialize context.
    let mut ctx = Context::new(ContextFlags::NO_YANGLIBRARY)
        .expect("Failed to create context");
    ctx.set_searchdir(SEARCH_DIR)
        .expect("Failed to set YANG search directory");

    // Load YANG modules.
    ctx.load_module("ietf-interfaces", None, &["pre-provisioning"])
        .expect("Failed to load module");
    ctx.load_module("iana-if-type", None, &[])
        .expect("Failed to load module");

    ctx
}

#[test]
fn schema_feature_value() {
    let ctx = create_context();
    let module = ctx.get_module_latest("ietf-interfaces").unwrap();
    assert_eq!(module.feature_value("pre-provisioning"), Ok(true));
    assert_eq!(module.feature_value("if-mib"), Ok(false));
    assert!(module.feature_value("blabla").is_err());
}

#[test]
fn schema_find_xpath() {
    let ctx = create_context();

    assert_eq!(
        ctx.find_xpath("/ietf-interfaces:interfaces/*")
            .expect("Failed to lookup schema data")
            .map(|dnode| dnode.path(SchemaPathFormat::DATA))
            .collect::<Vec<String>>(),
        vec![
            "/ietf-interfaces:interfaces/interface",
            "/ietf-interfaces:interfaces-state"
        ]
    );

    assert_eq!(
        ctx.find_xpath("/ietf-interfaces:interfaces/interface/*")
            .expect("Failed to lookup schema data")
            .map(|dnode| dnode.path(SchemaPathFormat::DATA))
            .collect::<Vec<String>>(),
        vec![
            "/ietf-interfaces:interfaces/interface/name",
            "/ietf-interfaces:interfaces/interface/description",
            "/ietf-interfaces:interfaces/interface/type",
            "/ietf-interfaces:interfaces/interface/enabled",
            "/ietf-interfaces:interfaces/interface/oper-status",
            "/ietf-interfaces:interfaces/interface/last-change",
            "/ietf-interfaces:interfaces/interface/phys-address",
            "/ietf-interfaces:interfaces/interface/higher-layer-if",
            "/ietf-interfaces:interfaces/interface/lower-layer-if",
            "/ietf-interfaces:interfaces/interface/speed",
            "/ietf-interfaces:interfaces/interface/statistics",
        ]
    );
}

#[test]
fn schema_find_path() {
    let ctx = create_context();

    assert!(ctx
        .find_path("/ietf-interfaces:interfaces/interface/*")
        .is_err());
    assert!(ctx
        .find_path("/ietf-interfaces:interfaces/interface")
        .is_ok());
}

#[test]
fn schema_iterator_traverse() {
    let ctx = create_context();

    assert_eq!(
        ctx
            .traverse()
            .map(|snode| snode.path(SchemaPathFormat::DATA))
            .collect::<Vec<String>>(),
        vec![
            "/ietf-yang-schema-mount:schema-mounts",
            "/ietf-yang-schema-mount:schema-mounts/namespace",
            "/ietf-yang-schema-mount:schema-mounts/namespace/prefix",
            "/ietf-yang-schema-mount:schema-mounts/namespace/uri",
            "/ietf-yang-schema-mount:schema-mounts/mount-point",
            "/ietf-yang-schema-mount:schema-mounts/mount-point/module",
            "/ietf-yang-schema-mount:schema-mounts/mount-point/label",
            "/ietf-yang-schema-mount:schema-mounts/mount-point/config",
            "/ietf-yang-schema-mount:schema-mounts/mount-point",
            "/ietf-yang-schema-mount:schema-mounts/mount-point",
            "/ietf-yang-schema-mount:schema-mounts/mount-point/inline",
            "/ietf-yang-schema-mount:schema-mounts/mount-point",
            "/ietf-yang-schema-mount:schema-mounts/mount-point/shared-schema",
            "/ietf-yang-schema-mount:schema-mounts/mount-point/shared-schema/parent-reference",
            "/ietf-interfaces:interfaces",
            "/ietf-interfaces:interfaces/interface",
            "/ietf-interfaces:interfaces/interface/name",
            "/ietf-interfaces:interfaces/interface/description",
            "/ietf-interfaces:interfaces/interface/type",
            "/ietf-interfaces:interfaces/interface/enabled",
            "/ietf-interfaces:interfaces/interface/oper-status",
            "/ietf-interfaces:interfaces/interface/last-change",
            "/ietf-interfaces:interfaces/interface/phys-address",
            "/ietf-interfaces:interfaces/interface/higher-layer-if",
            "/ietf-interfaces:interfaces/interface/lower-layer-if",
            "/ietf-interfaces:interfaces/interface/speed",
            "/ietf-interfaces:interfaces/interface/statistics",
            "/ietf-interfaces:interfaces/interface/statistics/discontinuity-time",
            "/ietf-interfaces:interfaces/interface/statistics/in-octets",
            "/ietf-interfaces:interfaces/interface/statistics/in-unicast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/in-broadcast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/in-multicast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/in-discards",
            "/ietf-interfaces:interfaces/interface/statistics/in-errors",
            "/ietf-interfaces:interfaces/interface/statistics/in-unknown-protos",
            "/ietf-interfaces:interfaces/interface/statistics/out-octets",
            "/ietf-interfaces:interfaces/interface/statistics/out-unicast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/out-broadcast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/out-multicast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/out-discards",
            "/ietf-interfaces:interfaces/interface/statistics/out-errors",
            "/ietf-interfaces:interfaces-state",
            "/ietf-interfaces:interfaces-state/interface",
            "/ietf-interfaces:interfaces-state/interface/name",
            "/ietf-interfaces:interfaces-state/interface/type",
            "/ietf-interfaces:interfaces-state/interface/oper-status",
            "/ietf-interfaces:interfaces-state/interface/last-change",
            "/ietf-interfaces:interfaces-state/interface/phys-address",
            "/ietf-interfaces:interfaces-state/interface/higher-layer-if",
            "/ietf-interfaces:interfaces-state/interface/lower-layer-if",
            "/ietf-interfaces:interfaces-state/interface/speed",
            "/ietf-interfaces:interfaces-state/interface/statistics",
            "/ietf-interfaces:interfaces-state/interface/statistics/discontinuity-time",
            "/ietf-interfaces:interfaces-state/interface/statistics/in-octets",
            "/ietf-interfaces:interfaces-state/interface/statistics/in-unicast-pkts",
            "/ietf-interfaces:interfaces-state/interface/statistics/in-broadcast-pkts",
            "/ietf-interfaces:interfaces-state/interface/statistics/in-multicast-pkts",
            "/ietf-interfaces:interfaces-state/interface/statistics/in-discards",
            "/ietf-interfaces:interfaces-state/interface/statistics/in-errors",
            "/ietf-interfaces:interfaces-state/interface/statistics/in-unknown-protos",
            "/ietf-interfaces:interfaces-state/interface/statistics/out-octets",
            "/ietf-interfaces:interfaces-state/interface/statistics/out-unicast-pkts",
            "/ietf-interfaces:interfaces-state/interface/statistics/out-broadcast-pkts",
            "/ietf-interfaces:interfaces-state/interface/statistics/out-multicast-pkts",
            "/ietf-interfaces:interfaces-state/interface/statistics/out-discards",
            "/ietf-interfaces:interfaces-state/interface/statistics/out-errors"
        ]
    );
}

#[test]
fn schema_iterator_ancestors() {
    let ctx = create_context();

    assert_eq!(
        ctx
            .find_path("/ietf-interfaces:interfaces/interface/statistics/discontinuity-time")
            .expect("Failed to lookup schema data")
            .ancestors()
            .map(|snode| snode.path(SchemaPathFormat::DATA))
            .collect::<Vec<String>>(),
        vec![
            "/ietf-interfaces:interfaces/interface/statistics",
            "/ietf-interfaces:interfaces/interface",
            "/ietf-interfaces:interfaces",
        ]
    );
    assert_eq!(
        ctx
            .find_path("/ietf-interfaces:interfaces/interface/statistics/discontinuity-time")
            .expect("Failed to lookup schema data")
            .inclusive_ancestors()
            .map(|snode| snode.path(SchemaPathFormat::DATA))
            .collect::<Vec<String>>(),
        vec![
            "/ietf-interfaces:interfaces/interface/statistics/discontinuity-time",
            "/ietf-interfaces:interfaces/interface/statistics",
            "/ietf-interfaces:interfaces/interface",
            "/ietf-interfaces:interfaces",
        ]
    );
}

#[test]
fn schema_iterator_siblings() {
    let ctx = create_context();

    assert_eq!(
        ctx.find_path("/ietf-interfaces:interfaces/interface/name")
            .expect("Failed to lookup schema data")
            .siblings()
            .map(|snode| snode.path(SchemaPathFormat::DATA))
            .collect::<Vec<String>>(),
        vec![
            "/ietf-interfaces:interfaces/interface/description",
            "/ietf-interfaces:interfaces/interface/type",
            "/ietf-interfaces:interfaces/interface/enabled",
            "/ietf-interfaces:interfaces/interface/oper-status",
            "/ietf-interfaces:interfaces/interface/last-change",
            "/ietf-interfaces:interfaces/interface/phys-address",
            "/ietf-interfaces:interfaces/interface/higher-layer-if",
            "/ietf-interfaces:interfaces/interface/lower-layer-if",
            "/ietf-interfaces:interfaces/interface/speed",
            "/ietf-interfaces:interfaces/interface/statistics",
        ]
    );
    assert_eq!(
        ctx.find_path("/ietf-interfaces:interfaces/interface/name")
            .expect("Failed to lookup schema data")
            .inclusive_siblings()
            .map(|snode| snode.path(SchemaPathFormat::DATA))
            .collect::<Vec<String>>(),
        vec![
            "/ietf-interfaces:interfaces/interface/name",
            "/ietf-interfaces:interfaces/interface/description",
            "/ietf-interfaces:interfaces/interface/type",
            "/ietf-interfaces:interfaces/interface/enabled",
            "/ietf-interfaces:interfaces/interface/oper-status",
            "/ietf-interfaces:interfaces/interface/last-change",
            "/ietf-interfaces:interfaces/interface/phys-address",
            "/ietf-interfaces:interfaces/interface/higher-layer-if",
            "/ietf-interfaces:interfaces/interface/lower-layer-if",
            "/ietf-interfaces:interfaces/interface/speed",
            "/ietf-interfaces:interfaces/interface/statistics",
        ]
    );
}

#[test]
fn schema_iterator_children() {
    let ctx = create_context();

    assert_eq!(
        ctx
            .find_path("/ietf-interfaces:interfaces/interface/statistics")
            .expect("Failed to lookup schema data")
            .children()
            .map(|snode| snode.path(SchemaPathFormat::DATA))
            .collect::<Vec<String>>(),
        vec![
            "/ietf-interfaces:interfaces/interface/statistics/discontinuity-time",
            "/ietf-interfaces:interfaces/interface/statistics/in-octets",
            "/ietf-interfaces:interfaces/interface/statistics/in-unicast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/in-broadcast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/in-multicast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/in-discards",
            "/ietf-interfaces:interfaces/interface/statistics/in-errors",
            "/ietf-interfaces:interfaces/interface/statistics/in-unknown-protos",
            "/ietf-interfaces:interfaces/interface/statistics/out-octets",
            "/ietf-interfaces:interfaces/interface/statistics/out-unicast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/out-broadcast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/out-multicast-pkts",
            "/ietf-interfaces:interfaces/interface/statistics/out-discards",
            "/ietf-interfaces:interfaces/interface/statistics/out-errors",
        ]
    );
}

#[test]
fn schema_node_attributes() {
    let ctx = create_context();

    let snode = ctx
        .find_path("/ietf-interfaces:interfaces/interface/enabled")
        .expect("Failed to lookup schema node");
    assert_eq!(snode.kind(), SchemaNodeKind::Leaf);
    assert_eq!(snode.name(), "enabled");
    assert!(snode.description().is_some());
    assert!(snode.reference().is_some());
    assert_eq!(snode.is_config(), true);
    assert_eq!(snode.is_state(), false);
    assert_eq!(snode.is_mandatory(), false);
    assert_eq!(snode.default_value_canonical(), Some("true"));
    assert_eq!(snode.default_value(), Some(DataValue::Bool(true)));
    assert_eq!(snode.base_type(), Some(DataValueType::Bool));
    assert!(snode.units().is_none());
    assert!(snode.musts().unwrap().count() == 0);
    assert!(snode.whens().count() == 0);
    assert_eq!(snode.is_status_current(), true);
    assert_eq!(snode.is_status_deprecated(), false);
    assert_eq!(snode.is_status_obsolete(), false);

    let snode = ctx
        .find_path("/ietf-interfaces:interfaces/interface")
        .expect("Failed to lookup schema node");
    assert_eq!(snode.kind(), SchemaNodeKind::List);
    assert_eq!(snode.name(), "interface");
    assert!(snode.description().is_some());
    assert!(snode.reference().is_none());
    assert_eq!(snode.is_config(), true);
    assert_eq!(snode.is_state(), false);
    assert_eq!(snode.is_mandatory(), false);
    assert_eq!(snode.is_keyless_list(), false);
    assert_eq!(snode.is_user_ordered(), false);
    assert_eq!(snode.min_elements(), None);
    assert_eq!(snode.max_elements(), None);
    assert!(snode.musts().unwrap().count() == 0);
    assert!(snode.whens().count() == 0);
    assert!(snode.actions().unwrap().count() == 0);
    assert!(snode.notifications().unwrap().count() == 0);
    assert_eq!(snode.is_status_current(), true);
    assert_eq!(snode.is_status_deprecated(), false);
    assert_eq!(snode.is_status_obsolete(), false);

    let snode = ctx
        .find_path("/ietf-interfaces:interfaces-state/interface")
        .expect("Failed to lookup schema node");
    assert_eq!(snode.kind(), SchemaNodeKind::List);
    assert_eq!(snode.name(), "interface");
    assert!(snode.description().is_some());
    assert!(snode.reference().is_none());
    assert_eq!(snode.is_config(), false);
    assert_eq!(snode.is_state(), true);
    assert_eq!(snode.is_mandatory(), false);
    assert_eq!(snode.is_keyless_list(), false);
    assert_eq!(snode.is_user_ordered(), false);
    assert_eq!(snode.min_elements(), None);
    assert_eq!(snode.max_elements(), None);
    assert!(snode.musts().unwrap().count() == 0);
    assert!(snode.whens().count() == 0);
    assert!(snode.actions().unwrap().count() == 0);
    assert!(snode.notifications().unwrap().count() == 0);
    assert_eq!(snode.is_status_current(), false);
    assert_eq!(snode.is_status_deprecated(), true);
    assert_eq!(snode.is_status_obsolete(), false);
}