xidl-parser 0.97.0

A IDL codegen.
Documentation
use std::collections::HashSet;

use super::recursive_schema_types;
use crate::hir::Specification;

fn parse(source: &str) -> Specification {
    let typed = crate::parser::parser_text(source).expect("parse typed ast");
    Specification::from_typed_ast_with_properties(typed, Default::default())
}

fn assert_recursive(source: &str, expected: &[&str]) {
    let spec = parse(source);
    let recursive = recursive_schema_types(&spec);
    let expected = expected
        .iter()
        .map(|value| value.split("::").map(str::to_string).collect::<Vec<_>>())
        .collect::<HashSet<_>>();
    assert_eq!(recursive, expected, "unexpected recursive schema types");
}

#[test]
fn self_reference_through_sequence_is_recursive() {
    assert_recursive(
        r#"
        struct Node {
            string id;
            @optional
            sequence<Node> children;
        };
        "#,
        &["Node"],
    );
}

#[test]
fn direct_self_reference_is_recursive() {
    assert_recursive(
        r#"
        struct Node {
            @optional Node next;
        };
        "#,
        &["Node"],
    );
}

#[test]
fn mutual_reference_is_recursive() {
    assert_recursive(
        r#"
        struct Left {
            Right right;
        };
        struct Right {
            Left left;
        };
        "#,
        &["Left", "Right"],
    );
}

#[test]
fn typedef_alias_cycle_through_sequence_is_recursive() {
    assert_recursive(
        r#"
        typedef sequence<Node> NodeList;
        struct Node {
            @optional sequence<NodeList> children;
        };
        "#,
        &["Node", "NodeList"],
    );
}

#[test]
fn union_case_reference_is_recursive() {
    assert_recursive(
        r#"
        union TreeNode switch (long) {
            case 1: sequence<TreeNode> children;
        };
        "#,
        &["TreeNode"],
    );
}

#[test]
fn module_nested_recursion_uses_canonical_path() {
    assert_recursive(
        r#"
        module graph {
            struct Node {
                @optional sequence<Node> children;
            };
        };
        "#,
        &["graph::Node"],
    );
}

#[test]
fn plain_structs_are_not_recursive() {
    assert_recursive(
        r#"
        struct A {
            long value;
        };
        struct B {
            A a;
        };
        "#,
        &[],
    );
}

#[test]
fn typedef_chain_into_cycle_marks_cycle_members_only() {
    assert_recursive(
        r#"
        typedef Node NodeAlias;
        struct Node {
            @optional sequence<Node> children;
        };
        "#,
        &["Node"],
    );
}

#[test]
fn recursive_exception_is_detected() {
    assert_recursive(
        r#"
        exception NodeError {
            string message;
            @optional
            sequence<NodeError> causes;
        };
        "#,
        &["NodeError"],
    );
}

#[test]
fn union_case_inline_struct_cycle_is_recursive() {
    assert_recursive(
        r#"
        union Tree switch (long) {
            case 1:
                struct Item {
                    @optional Tree parent;
                    sequence<Tree> children;
                } item;
        };
        "#,
        &["Tree"],
    );
}

#[test]
fn union_case_inline_struct_into_typedef_cycle_is_recursive() {
    assert_recursive(
        r#"
        typedef sequence<Tree> TreeList;
        union Tree switch (long) {
            case 1:
                struct Item {
                    @optional Tree parent;
                    TreeList children;
                } item;
        };
        "#,
        &["Tree", "TreeList"],
    );
}