hamelin_lib 0.7.13

Core library for Hamelin query language
Documentation
#[cfg(test)]
mod tests {
    use crate::tree::{
        ast::{
            expression::ExpressionKind,
            identifier::{ParsedSimpleIdentifier, SimpleIdentifier},
        },
        builder::*,
    };
    use rstest::rstest;

    #[test]
    fn test_builder_chaining() {
        // Test fluent API works
        let expr = array().element(1).element(2).element(3);

        let ast = expr.build();
        match &ast.kind {
            ExpressionKind::ArrayLiteral(arr) => {
                assert_eq!(arr.elements.len(), 3);
            }
            _ => panic!("Expected ArrayLiteral"),
        }
    }

    #[rstest]
    #[case(42)]
    #[case(3.14)]
    #[case("hello")]
    #[case(true)]
    fn test_into_expression_builder<T: IntoExpressionBuilder>(#[case] value: T) {
        let _: Box<dyn ExpressionBuilder> = value.into_expression_builder();
    }

    #[test]
    fn test_builder_produces_valid_ast() {
        // Test that builders produce valid AST nodes
        let int_ast = int(42).build();
        assert!(matches!(int_ast.kind, ExpressionKind::IntLiteral(_)));

        let str_ast = string("hello").build();
        assert!(matches!(str_ast.kind, ExpressionKind::StringLiteral(_)));

        let bool_ast = boolean(true).build();
        assert!(matches!(bool_ast.kind, ExpressionKind::BooleanLiteral(_)));

        let arr_ast = array().element(1).element(2).build();
        assert!(matches!(arr_ast.kind, ExpressionKind::ArrayLiteral(_)));

        let binary_ast = add(1, 2).build();
        assert!(matches!(binary_ast.kind, ExpressionKind::BinaryOperator(_)));

        let func_ast = call("test").arg(1).build();
        assert!(matches!(func_ast.kind, ExpressionKind::FunctionCall(_)));
    }

    #[test]
    fn test_builder_roundtripping() {
        // Test that AST/TypedExpression can be converted back to builders
        let original = add(1, 2);
        let ast = original.build();

        // Convert AST back to builder and rebuild
        let builder_from_ast = ast.clone().into_expression_builder();
        let ast2 = builder_from_ast.build();

        // Both should produce BinaryOperator
        assert!(matches!(ast.kind, ExpressionKind::BinaryOperator(_)));
        assert!(matches!(ast2.kind, ExpressionKind::BinaryOperator(_)));
    }

    #[test]
    fn test_nested_builder_composition() {
        // Test that builders can be composed arbitrarily
        let complex = struct_literal()
            .field("array", array().element(1).element(2))
            .field("tuple", tuple().element("a").element(true))
            .field("nested", struct_literal().field("x", 10));

        let ast = complex.build();
        match &ast.kind {
            ExpressionKind::StructLiteral(s) => {
                assert_eq!(s.fields.len(), 3);
            }
            _ => panic!("Expected StructLiteral"),
        }
    }

    #[test]
    fn test_function_builder_arguments() {
        // Test positional arguments
        let func1 = call("test").arg(1).arg(2).arg(3).build();
        match &func1.kind {
            ExpressionKind::FunctionCall(f) => {
                assert_eq!(f.positional_args.len(), 3);
                assert_eq!(f.named_args.len(), 0);
            }
            _ => panic!("Expected FunctionCall"),
        }

        // Test named arguments
        let func2 = call("test")
            .named_arg("param1", 1)
            .named_arg("param2", 2)
            .build();
        match &func2.kind {
            ExpressionKind::FunctionCall(f) => {
                assert_eq!(f.positional_args.len(), 0);
                assert_eq!(f.named_args.len(), 2);
                assert!(f.named_args.contains_key(&ParsedSimpleIdentifier::Valid(
                    SimpleIdentifier::new("param1")
                )));
                assert!(f.named_args.contains_key(&ParsedSimpleIdentifier::Valid(
                    SimpleIdentifier::new("param2")
                )));
            }
            _ => panic!("Expected FunctionCall"),
        }

        // Test mixed arguments
        let func3 = call("test").arg(1).named_arg("param", 2).arg(3).build();
        match &func3.kind {
            ExpressionKind::FunctionCall(f) => {
                assert_eq!(f.positional_args.len(), 2);
                assert_eq!(f.named_args.len(), 1);
            }
            _ => panic!("Expected FunctionCall"),
        }
    }

    #[test]
    fn test_collection_element_methods() {
        // Test array element addition
        let arr = array()
            .element(1)
            .element("string")
            .element(true)
            .element(array().element(2).element(3));

        let ast = arr.build();
        match &ast.kind {
            ExpressionKind::ArrayLiteral(a) => {
                assert_eq!(a.elements.len(), 4);
            }
            _ => panic!("Expected ArrayLiteral"),
        }

        // Test tuple element addition
        let tup = tuple().element(42).element(3.14).element("test");

        let ast = tup.build();
        match &ast.kind {
            ExpressionKind::TupleLiteral(t) => {
                assert_eq!(t.elements.len(), 3);
            }
            _ => panic!("Expected TupleLiteral"),
        }

        // Test struct field addition
        let s = struct_literal()
            .field("a", 1)
            .field("b", "test")
            .field("c", true);

        let ast = s.build();
        match &ast.kind {
            ExpressionKind::StructLiteral(s) => {
                assert_eq!(s.fields.len(), 3);
            }
            _ => panic!("Expected StructLiteral"),
        }
    }
}