xidl-parser 0.105.0

A IDL codegen.
Documentation
use super::*;
use crate::versioning::{
    API_VERSION_PROPERTY, API_VERSIONS_PROPERTY, VersionSelection, VersionTimeline, VersioningError,
};

fn timeline() -> VersionTimeline {
    VersionTimeline::from_members(
        "Versions".to_string(),
        &[
            member("v1", Some("1.0")),
            member("v2", Some("2.0")),
            member("v3", None),
        ],
    )
    .expect("timeline")
}

#[test]
fn values_default_to_the_member_ident() {
    let values = timeline()
        .iter()
        .map(|(_, def)| (def.ident.clone(), def.value.clone()))
        .collect::<Vec<_>>();

    assert_eq!(
        values,
        vec![
            ("v1".to_string(), "1.0".to_string()),
            ("v2".to_string(), "2.0".to_string()),
            ("v3".to_string(), "v3".to_string()),
        ]
    );
}

#[test]
fn members_are_found_by_ident_and_value() {
    let timeline = timeline();
    let by_ident = timeline.find("v2").expect("ident");
    let by_value = timeline.find("2.0").expect("value");

    assert_eq!(by_ident, by_value);
    assert_eq!(by_ident.index(), 1);
    assert_eq!(timeline.declared(), "v1 (1.0), v2 (2.0), v3 (v3)");
}

#[test]
fn unknown_and_ambiguous_selections_are_rejected() {
    let timeline = timeline();
    assert!(matches!(
        timeline.find("9.9"),
        Err(VersioningError::UnknownSelectedVersion { .. })
    ));

    let ambiguous = VersionTimeline::from_members(
        "Versions".to_string(),
        &[member("v1", Some("v2")), member("v2", Some("v3"))],
    )
    .expect("timeline");
    assert!(matches!(
        ambiguous.find("v2"),
        Err(VersioningError::AmbiguousSelectedVersion { .. })
    ));
}

#[test]
fn duplicate_values_and_empty_enums_are_rejected() {
    assert!(matches!(
        VersionTimeline::from_members(
            "Versions".to_string(),
            &[member("v1", Some("2.0")), member("v2", Some("2.0"))]
        ),
        Err(VersioningError::DuplicateVersionValue { .. })
    ));
    assert!(matches!(
        VersionTimeline::from_members("Versions".to_string(), &[]),
        Err(VersioningError::EmptyVersionEnum { .. })
    ));
}

#[test]
fn scoped_references_resolve_to_declared_members() {
    let timeline = timeline();

    assert_eq!(
        timeline
            .resolve(&reference("Versions", "v3"))
            .map(|id| id.index()),
        Some(2)
    );
    assert!(timeline.resolve(&reference("Other", "v3")).is_none());
    assert!(timeline.resolve(&reference("Versions", "v9")).is_none());
    assert!(
        timeline
            .resolve(&ScopedName {
                name: vec!["v1".to_string()],
                is_root: false,
            })
            .is_none()
    );
}

#[test]
fn selection_reads_both_properties() {
    let single = VersionSelection::from_properties(&properties(&[(API_VERSION_PROPERTY, "v2")]))
        .expect("selection")
        .expect("present");
    assert_eq!(single, VersionSelection::Versions(vec!["v2".to_string()]));

    let many = VersionSelection::from_properties(&properties(&[(API_VERSIONS_PROPERTY, "v1, v3")]))
        .expect("selection")
        .expect("present");
    assert_eq!(
        many,
        VersionSelection::Versions(vec!["v1".to_string(), "v3".to_string()])
    );

    let all = VersionSelection::from_properties(&properties(&[(API_VERSIONS_PROPERTY, "*")]))
        .expect("selection")
        .expect("present");
    assert_eq!(all, VersionSelection::All);

    let none = VersionSelection::from_properties(&properties(&[])).expect("selection");
    assert!(none.is_none());
}

#[test]
fn selection_rejects_conflicts_and_empty_requests() {
    assert!(matches!(
        VersionSelection::from_properties(&properties(&[
            (API_VERSION_PROPERTY, "v1"),
            (API_VERSIONS_PROPERTY, "v2"),
        ])),
        Err(crate::error::ParseError::Versioning(
            VersioningError::ConflictingSelection { .. }
        ))
    ));
    assert!(matches!(
        VersionSelection::from_properties(&properties(&[(API_VERSIONS_PROPERTY, " , ")])),
        Err(crate::error::ParseError::Versioning(
            VersioningError::EmptySelection
        ))
    ));
}

#[test]
fn selection_resolves_and_sorts_by_declaration_order() {
    let timeline = timeline();
    let selection = VersionSelection::Versions(vec!["v3".to_string(), "1.0".to_string()]);
    let resolved = selection.resolve(&timeline).expect("resolve");

    assert_eq!(
        resolved.iter().map(|id| id.index()).collect::<Vec<_>>(),
        vec![0, 2]
    );
    assert!(matches!(
        VersionSelection::Versions(vec!["9.9".to_string()]).resolve(&timeline),
        Err(crate::error::ParseError::Versioning(
            VersioningError::UnknownSelectedVersion { .. }
        ))
    ));
}

#[test]
fn nested_version_enums_resolve_by_ident_or_path() {
    let timeline = VersionTimeline::from_members(
        "core::ApiVersions".to_string(),
        &[member("v1", None), member("v2", None)],
    )
    .expect("timeline");

    assert_eq!(timeline.enum_ident(), "ApiVersions");
    assert_eq!(
        timeline
            .resolve(&reference("ApiVersions", "v2"))
            .map(|id| id.index()),
        Some(1)
    );
    assert_eq!(
        timeline
            .resolve(&ScopedName {
                name: vec![
                    "core".to_string(),
                    "ApiVersions".to_string(),
                    "v2".to_string()
                ],
                is_root: false,
            })
            .map(|id| id.index()),
        Some(1)
    );
    assert!(timeline.resolve(&reference("Other", "v2")).is_none());
}