ritual 0.0.0

Automatic generator of C++ library wrappers
Documentation
use crate::cpp_data::CppPath;
use crate::cpp_data::CppVisibility;
use crate::cpp_ffi_data::CppFfiArgumentMeaning;
use crate::cpp_ffi_data::CppFfiFunction;
use crate::cpp_ffi_data::CppTypeConversionToFfi;
use crate::cpp_function::*;
use crate::cpp_type::*;

#[test]
fn cpp_method_kind() {
    assert!(!CppFunctionKind::Constructor.is_destructor());
    assert!(CppFunctionKind::Constructor.is_constructor());
    assert!(!CppFunctionKind::Constructor.is_regular());

    assert!(CppFunctionKind::Destructor.is_destructor());
    assert!(!CppFunctionKind::Destructor.is_constructor());
    assert!(!CppFunctionKind::Destructor.is_regular());

    assert!(!CppFunctionKind::Regular.is_destructor());
    assert!(!CppFunctionKind::Regular.is_constructor());
    assert!(CppFunctionKind::Regular.is_regular());
}

pub fn empty_membership() -> CppFunctionMemberData {
    CppFunctionMemberData {
        kind: CppFunctionKind::Regular,
        is_virtual: false,
        is_pure_virtual: false,
        is_const: false,
        is_static: false,
        visibility: CppVisibility::Public,
        is_signal: false,
        is_slot: false,
    }
}

pub fn empty_regular_method() -> CppFunction {
    CppFunction {
        path: CppPath::from_str_unchecked("empty"),
        member: None,
        return_type: CppType::Void,
        arguments: vec![],
        doc: None,
        allows_variadic_arguments: false,
        operator: None,
        declaration_code: None,
    }
}

#[test]
fn argument_types_equal1() {
    let method1 = empty_regular_method();
    let method2 = empty_regular_method();
    assert!(method1.argument_types_equal(&method2));
    assert!(method2.argument_types_equal(&method1));
}

#[test]
fn argument_types_equal2() {
    let mut method1 = empty_regular_method();
    let method2 = empty_regular_method();
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        name: "arg1".to_string(),
        has_default_value: false,
    });
    assert!(!method1.argument_types_equal(&method2));
    assert!(!method2.argument_types_equal(&method1));
}

#[test]
fn argument_types_equal3() {
    let mut method1 = empty_regular_method();
    let mut method2 = empty_regular_method();
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        name: "arg1".to_string(),
        has_default_value: false,
    });
    method2.arguments.push(CppFunctionArgument {
        argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        name: "x".to_string(),
        has_default_value: false,
    });
    assert!(method1.argument_types_equal(&method2));
    assert!(method2.argument_types_equal(&method1));
}

#[test]
fn argument_types_equal4() {
    let mut method1 = empty_regular_method();
    let mut method2 = empty_regular_method();
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        name: "arg1".to_string(),
        has_default_value: false,
    });
    method2.arguments.push(CppFunctionArgument {
        argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        name: "arg1".to_string(),
        has_default_value: true,
    });
    assert!(method1.argument_types_equal(&method2));
    assert!(method2.argument_types_equal(&method1));
}

#[test]
fn argument_types_equal5() {
    let mut method1 = empty_regular_method();
    let mut method2 = empty_regular_method();
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        name: "arg1".to_string(),
        has_default_value: false,
    });
    method2.arguments.push(CppFunctionArgument {
        argument_type: CppType::Enum {
            path: CppPath::from_str_unchecked("Enum1"),
        },
        name: "arg1".to_string(),
        has_default_value: false,
    });
    assert!(!method1.argument_types_equal(&method2));
    assert!(!method2.argument_types_equal(&method1));
}

#[test]
fn argument_types_equal6() {
    let mut method1 = empty_regular_method();
    let mut method2 = empty_regular_method();
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        name: "arg1".to_string(),
        has_default_value: false,
    });
    method2.arguments.push(CppFunctionArgument {
        argument_type: CppType::new_pointer(
            false,
            CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        ),
        name: "arg1".to_string(),
        has_default_value: false,
    });
    assert!(!method1.argument_types_equal(&method2));
    assert!(!method2.argument_types_equal(&method1));
}

#[test]
fn argument_types_equal7() {
    let mut method1 = empty_regular_method();
    let int = CppFunctionArgument {
        argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        name: "arg1".to_string(),
        has_default_value: false,
    };
    let mut method2 = empty_regular_method();
    method1.arguments.push(int.clone());
    method2.arguments.push(int.clone());
    method2.arguments.push(int.clone());
    assert!(!method1.argument_types_equal(&method2));
    assert!(!method2.argument_types_equal(&method1));
}

#[test]
fn argument_types_equal8() {
    let mut method1 = empty_regular_method();
    let method2 = empty_regular_method();
    method1.return_type = CppType::BuiltInNumeric(CppBuiltInNumericType::Int);
    assert!(method1.argument_types_equal(&method2));
    assert!(method2.argument_types_equal(&method1));
}

fn to_ffi(function: &CppFunction, force_stack: Option<CppPath>) -> CppFfiFunction {
    let movable_types: Vec<_> = force_stack.into_iter().collect();
    crate::cpp_ffi_generator::to_ffi_method(
        function,
        &movable_types,
        &mut crate::cpp_ffi_generator::FfiNameProvider::new(String::new(), 0),
    )
    .unwrap()
}

#[test]
fn c_signature_empty() {
    let mut method1 = empty_regular_method();
    method1.return_type = CppType::Void;

    assert!(!method1.is_constructor());
    assert!(!method1.is_destructor());
    assert!(!method1.is_operator());
    assert_eq!(method1.class_type(), None);

    let r = to_ffi(&method1, None);
    assert!(r.arguments.is_empty());
    assert!(r.return_type.ffi_type.is_void());
}

#[test]
fn c_signature_simple_func() {
    let mut method1 = empty_regular_method();
    method1.return_type = CppType::BuiltInNumeric(CppBuiltInNumericType::Int);
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::Enum {
            path: CppPath::from_str_unchecked("Enum1"),
        },
        name: "arg1".to_string(),
        has_default_value: false,
    });
    let r = to_ffi(&method1, None);
    assert!(r.arguments.len() == 1);
    assert_eq!(r.arguments[0].name, "arg1");
    assert_eq!(
        r.arguments[0].argument_type.ffi_type,
        method1.arguments[0].argument_type
    );
    assert_eq!(
        r.arguments[0].argument_type.conversion,
        CppTypeConversionToFfi::NoChange
    );
    assert_eq!(r.arguments[0].meaning, CppFfiArgumentMeaning::Argument(0));
    assert_eq!(r.return_type.ffi_type, method1.return_type);
    assert_eq!(r.return_type.conversion, CppTypeConversionToFfi::NoChange);
}

#[test]
fn c_signature_method_with_this() {
    let mut method1 = empty_regular_method();
    method1.path = CppPath::from_str_unchecked("MyClass::empty");
    method1.member = Some(empty_membership());
    method1.return_type = CppType::BuiltInNumeric(CppBuiltInNumericType::Int);
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::Class(CppPath::from_str_unchecked("MyClass2")),
        name: "my_arg".to_string(),
        has_default_value: false,
    });

    assert!(!method1.is_constructor());
    assert!(!method1.is_destructor());
    assert!(!method1.is_operator());
    assert_eq!(
        method1.class_type(),
        Some(CppPath::from_str_unchecked("MyClass"))
    );

    let r = to_ffi(&method1, None);
    assert!(r.arguments.len() == 2);
    assert_eq!(r.arguments[0].name, "this_ptr");
    assert_eq!(
        r.arguments[0].argument_type.ffi_type,
        CppType::new_pointer(false, CppType::Class(method1.class_type().unwrap()))
    );
    assert_eq!(
        r.arguments[0].argument_type.conversion,
        CppTypeConversionToFfi::NoChange
    );
    assert_eq!(r.arguments[0].meaning, CppFfiArgumentMeaning::This);

    assert_eq!(r.arguments[1].name, "my_arg");
    assert_eq!(
        r.arguments[1].argument_type.ffi_type,
        CppType::new_pointer(true, method1.arguments[0].argument_type.clone())
    );
    assert_eq!(
        r.arguments[1].argument_type.conversion,
        CppTypeConversionToFfi::ValueToPointer
    );
    assert_eq!(r.arguments[1].meaning, CppFfiArgumentMeaning::Argument(0));
    assert_eq!(r.return_type.ffi_type, method1.return_type);
}

#[test]
fn c_signature_static_method() {
    let mut method1 = empty_regular_method();
    method1.path = CppPath::from_str_unchecked("MyClass::empty");
    method1.member = Some({
        let mut info = empty_membership();
        info.is_static = true;
        info
    });
    method1.return_type = CppType::BuiltInNumeric(CppBuiltInNumericType::Int);
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::Enum {
            path: CppPath::from_str_unchecked("Enum1"),
        },
        name: "arg1".to_string(),
        has_default_value: false,
    });
    let r = to_ffi(&method1, None);
    assert!(r.arguments.len() == 1);
    assert_eq!(r.arguments[0].name, "arg1");
    assert_eq!(
        r.arguments[0].argument_type.ffi_type,
        method1.arguments[0].argument_type
    );
    assert_eq!(
        r.arguments[0].argument_type.conversion,
        CppTypeConversionToFfi::NoChange
    );
    assert_eq!(r.arguments[0].meaning, CppFfiArgumentMeaning::Argument(0));
    assert_eq!(r.return_type.ffi_type, method1.return_type);
}

#[test]
fn c_signature_constructor() {
    let mut method1 = empty_regular_method();
    method1.path = CppPath::from_str_unchecked("MyClass::empty");
    method1.member = Some({
        let mut info = empty_membership();
        info.kind = CppFunctionKind::Constructor;
        info
    });
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::new_reference(
            true,
            CppType::Enum {
                path: CppPath::from_str_unchecked("Enum1"),
            },
        ),
        name: "arg1".to_string(),
        has_default_value: true,
    });

    assert!(method1.is_constructor());
    assert!(!method1.is_destructor());
    assert!(!method1.is_operator());
    assert_eq!(
        method1.class_type(),
        Some(CppPath::from_str_unchecked("MyClass"))
    );

    let r_stack = to_ffi(&method1, Some(CppPath::from_str_unchecked("MyClass")));

    assert!(r_stack.arguments.len() == 2);
    assert_eq!(r_stack.arguments[0].name, "arg1");
    assert_eq!(
        r_stack.arguments[0].argument_type.ffi_type,
        CppType::new_pointer(
            true,
            CppType::Enum {
                path: CppPath::from_str_unchecked("Enum1"),
            }
        )
    );
    assert_eq!(
        r_stack.arguments[0].argument_type.conversion,
        CppTypeConversionToFfi::ReferenceToPointer
    );
    assert_eq!(
        r_stack.arguments[0].meaning,
        CppFfiArgumentMeaning::Argument(0)
    );

    assert_eq!(r_stack.arguments[1].name, "output");
    assert_eq!(
        r_stack.arguments[1].argument_type.ffi_type,
        CppType::new_pointer(
            false,
            CppType::Class(CppPath::from_str_unchecked("MyClass"))
        ),
    );
    assert_eq!(
        r_stack.arguments[1].argument_type.conversion,
        CppTypeConversionToFfi::ValueToPointer
    );
    assert_eq!(
        r_stack.arguments[1].meaning,
        CppFfiArgumentMeaning::ReturnValue
    );

    assert!(r_stack.return_type.ffi_type.is_void());

    let r_heap = to_ffi(&method1, None);
    assert!(r_heap.arguments.len() == 1);
    assert_eq!(r_heap.arguments[0].name, "arg1");
    assert_eq!(
        r_heap.arguments[0].argument_type.ffi_type,
        CppType::new_pointer(
            true,
            CppType::Enum {
                path: CppPath::from_str_unchecked("Enum1"),
            }
        ),
    );
    assert_eq!(
        r_heap.arguments[0].argument_type.conversion,
        CppTypeConversionToFfi::ReferenceToPointer
    );
    assert_eq!(
        r_heap.arguments[0].meaning,
        CppFfiArgumentMeaning::Argument(0)
    );
    assert_eq!(
        r_heap.return_type.ffi_type,
        CppType::new_pointer(
            false,
            CppType::Class(CppPath::from_str_unchecked("MyClass"))
        ),
    );
    assert_eq!(
        r_heap.return_type.conversion,
        CppTypeConversionToFfi::ValueToPointer
    );
}

#[test]
fn c_signature_destructor() {
    let mut method1 = empty_regular_method();
    method1.path = CppPath::from_str_unchecked("MyClass::empty");
    method1.member = Some({
        let mut info = empty_membership();
        info.kind = CppFunctionKind::Destructor;
        info
    });

    assert!(!method1.is_constructor());
    assert!(method1.is_destructor());
    assert!(!method1.is_operator());
    assert_eq!(
        method1.class_type(),
        Some(CppPath::from_str_unchecked("MyClass"))
    );

    let r_stack = to_ffi(&method1, Some(CppPath::from_str_unchecked("MyClass")));
    assert_eq!(r_stack.arguments.len(), 1);
    assert_eq!(r_stack.arguments[0].name, "this_ptr");
    assert_eq!(
        r_stack.arguments[0].argument_type.ffi_type,
        CppType::new_pointer(false, CppType::Class(method1.class_type().unwrap()))
    );
    assert_eq!(
        r_stack.arguments[0].argument_type.conversion,
        CppTypeConversionToFfi::NoChange
    );
    assert_eq!(r_stack.arguments[0].meaning, CppFfiArgumentMeaning::This);

    assert!(r_stack.return_type.ffi_type.is_void());

    let r_heap = to_ffi(&method1, None);
    assert!(r_heap.arguments.len() == 1);
    assert_eq!(r_heap.arguments[0].name, "this_ptr");
    assert_eq!(
        r_heap.arguments[0].argument_type.ffi_type,
        CppType::new_pointer(false, CppType::Class(method1.class_type().unwrap()))
    );
    assert_eq!(
        r_heap.arguments[0].argument_type.conversion,
        CppTypeConversionToFfi::NoChange
    );
    assert_eq!(r_heap.arguments[0].meaning, CppFfiArgumentMeaning::This);

    assert!(r_heap.return_type.ffi_type.is_void());
}

#[test]
#[allow(clippy::cyclomatic_complexity)]
fn c_signature_method_returning_class() {
    let mut method1 = empty_regular_method();
    method1.path = CppPath::from_str_unchecked("MyClass::empty");
    method1.member = Some(empty_membership());
    method1.return_type = CppType::Class(CppPath::from_str_unchecked("MyClass3"));
    method1.arguments.push(CppFunctionArgument {
        argument_type: CppType::Class(CppPath::from_str_unchecked("MyClass2")),
        name: "my_arg".to_string(),
        has_default_value: false,
    });
    let r_stack = to_ffi(&method1, Some(CppPath::from_str_unchecked("MyClass3")));
    assert!(r_stack.arguments.len() == 3);
    assert_eq!(r_stack.arguments[0].name, "this_ptr");
    assert_eq!(
        r_stack.arguments[0].argument_type.ffi_type,
        CppType::new_pointer(false, CppType::Class(method1.class_type().unwrap()))
    );
    assert_eq!(
        r_stack.arguments[0].argument_type.conversion,
        CppTypeConversionToFfi::NoChange
    );
    assert_eq!(r_stack.arguments[0].meaning, CppFfiArgumentMeaning::This);

    assert_eq!(r_stack.arguments[1].name, "my_arg");
    assert_eq!(
        r_stack.arguments[1].argument_type.ffi_type,
        CppType::new_pointer(true, method1.arguments[0].argument_type.clone())
    );
    assert_eq!(
        r_stack.arguments[1].argument_type.conversion,
        CppTypeConversionToFfi::ValueToPointer
    );
    assert_eq!(
        r_stack.arguments[1].meaning,
        CppFfiArgumentMeaning::Argument(0)
    );

    assert_eq!(r_stack.arguments[2].name, "output");
    assert_eq!(
        r_stack.arguments[2].argument_type.ffi_type,
        CppType::new_pointer(
            false,
            CppType::Class(CppPath::from_str_unchecked("MyClass3"))
        ),
    );
    assert_eq!(
        r_stack.arguments[2].argument_type.conversion,
        CppTypeConversionToFfi::ValueToPointer
    );
    assert_eq!(
        r_stack.arguments[2].meaning,
        CppFfiArgumentMeaning::ReturnValue
    );

    assert!(r_stack.return_type.ffi_type.is_void());

    let r_heap = to_ffi(&method1, None);
    assert!(r_heap.arguments.len() == 2);
    assert_eq!(r_heap.arguments[0].name, "this_ptr");
    assert_eq!(
        r_heap.arguments[0].argument_type.ffi_type,
        CppType::new_pointer(false, CppType::Class(method1.class_type().unwrap()))
    );
    assert_eq!(
        r_heap.arguments[0].argument_type.conversion,
        CppTypeConversionToFfi::NoChange
    );
    assert_eq!(r_heap.arguments[0].meaning, CppFfiArgumentMeaning::This);

    assert_eq!(r_heap.arguments[1].name, "my_arg");
    assert_eq!(
        r_heap.arguments[1].argument_type.ffi_type,
        CppType::new_pointer(true, method1.arguments[0].argument_type.clone())
    );
    assert_eq!(
        r_heap.arguments[1].argument_type.conversion,
        CppTypeConversionToFfi::ValueToPointer
    );
    assert_eq!(
        r_heap.arguments[1].meaning,
        CppFfiArgumentMeaning::Argument(0)
    );

    assert_eq!(
        r_heap.return_type.ffi_type,
        CppType::new_pointer(
            false,
            CppType::Class(CppPath::from_str_unchecked("MyClass3"))
        ),
    );
    assert_eq!(
        r_heap.return_type.conversion,
        CppTypeConversionToFfi::ValueToPointer
    );
}

#[test]
fn full_name_free_function_in_namespace() {
    let mut method1 = empty_regular_method();
    method1.path = CppPath::from_str_unchecked("ns::func1");
    assert_eq!(method1.class_type(), None);
}

#[test]
fn full_name_method() {
    let mut method1 = empty_regular_method();
    method1.path = CppPath::from_str_unchecked("MyClass::func1");
    method1.member = Some(empty_membership());
    assert_eq!(
        method1.class_type(),
        Some(CppPath::from_str_unchecked("MyClass"))
    );
}

#[test]
fn full_name_static_method() {
    let mut method1 = empty_regular_method();
    method1.path = CppPath::from_str_unchecked("MyClass::func1");
    method1.member = Some({
        let mut info = empty_membership();
        info.is_static = true;
        info
    });
    assert_eq!(
        method1.class_type(),
        Some(CppPath::from_str_unchecked("MyClass"))
    );
}

#[test]
fn full_name_nested_class_method() {
    let mut method1 = empty_regular_method();
    method1.path = CppPath::from_str_unchecked("MyClass::Iterator::func1");
    method1.member = Some(empty_membership());
    assert_eq!(
        method1.class_type(),
        Some(CppPath::from_str_unchecked("MyClass::Iterator"))
    );
}

#[test]
fn short_text1() {
    let method = CppFunction {
        path: CppPath::from_str_unchecked("Class1::method1"),
        member: Some(CppFunctionMemberData {
            kind: CppFunctionKind::Regular,
            is_virtual: false,
            is_pure_virtual: false,
            is_const: true,
            is_static: false,
            visibility: CppVisibility::Protected,
            is_signal: false,
            is_slot: false,
        }),
        operator: None,
        return_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
        arguments: vec![
            CppFunctionArgument {
                argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Int),
                name: "arg1".to_string(),
                has_default_value: false,
            },
            CppFunctionArgument {
                argument_type: CppType::BuiltInNumeric(CppBuiltInNumericType::Double),
                name: "arg2".to_string(),
                has_default_value: true,
            },
        ],
        doc: None,
        allows_variadic_arguments: false,
        declaration_code: None,
    };
    assert_eq!(
        method.short_text(),
        "protected int Class1::method1(int arg1, double arg2 = ?) const"
    );
}