alef 0.104.4

Opinionated polyglot binding generator for Rust libraries
Documentation
use super::*;

#[test]
fn nested_named_jsvalue_recovery_uses_surface_rust_path() {
    let mapper = WasmMapper::new(HashMap::new(), "Wasm".to_string());
    let mut func = async_function(vec![param(
        "values",
        TypeRef::Vec(Box::new(TypeRef::Optional(Box::new(TypeRef::Named(
            "NestedThing".to_string(),
        ))))),
    )]);
    func.is_async = false;
    func.error_type = None;
    let api = crate::core::ir::ApiSurface {
        types: vec![crate::core::ir::TypeDef {
            name: "NestedThing".to_string(),
            rust_path: "sample_fixture::nested::NestedThing".to_string(),
            ..Default::default()
        }],
        ..empty_surface()
    };

    let out = gen_function_with_emitted_dtos(
        &func,
        &mapper,
        "sample_fixture",
        &AHashSet::new(),
        "Wasm",
        &AHashSet::new(),
        &api,
        &AHashSet::new(),
    );

    assert!(
        out.contains("Vec<Option<sample_fixture::nested::NestedThing>>"),
        "nested named recovery must use TypeDef.rust_path: {out}"
    );
}

#[test]
fn async_vec_named_recovery_uses_surface_rust_path() {
    let mapper = WasmMapper::new(HashMap::new(), "Wasm".to_string());
    let func = async_function(vec![param(
        "values",
        TypeRef::Vec(Box::new(TypeRef::Named("NestedThing".to_string()))),
    )]);
    let api = crate::core::ir::ApiSurface {
        types: vec![crate::core::ir::TypeDef {
            name: "NestedThing".to_string(),
            rust_path: "sample_fixture::nested::NestedThing".to_string(),
            ..Default::default()
        }],
        ..empty_surface()
    };

    let out = gen_function_with_emitted_dtos(
        &func,
        &mapper,
        "sample_fixture",
        &AHashSet::new(),
        "Wasm",
        &AHashSet::new(),
        &api,
        &AHashSet::new(),
    );

    assert!(out.contains("Vec<sample_fixture::nested::NestedThing>"), "{out}");
}

#[test]
fn input_dto_conversion_uses_resolved_nested_type_path() {
    let type_def = crate::core::ir::TypeDef {
        name: "NestedConfig".to_string(),
        rust_path: "sample_fixture::nested::NestedConfig".to_string(),
        fields: vec![crate::core::ir::FieldDef {
            name: "child".to_string(),
            ty: TypeRef::Named("NestedChild".to_string()),
            ..Default::default()
        }],
        has_serde: true,
        ..Default::default()
    };
    let type_paths = ahash::AHashMap::from_iter([(
        "NestedChild".to_string(),
        "sample_fixture::nested::NestedChild".to_string(),
    )]);

    let (out, _) = gen_input_dto_for_type_at_path(
        "NestedConfig",
        "sample_fixture::nested::NestedConfig",
        "sample_fixture",
        &type_paths,
        &type_def,
    );

    assert!(
        out.contains("impl From<NestedConfigInput> for sample_fixture::nested::NestedConfig"),
        "{out}"
    );
    assert!(out.contains("Option<sample_fixture::nested::NestedChild>"), "{out}");
}

#[test]
fn input_dto_uses_field_wire_name_and_rebuilds_transparent_wrapper() {
    let type_def = crate::core::ir::TypeDef {
        name: "Credentials".to_string(),
        rust_path: "sample_fixture::Credentials".to_string(),
        fields: vec![crate::core::ir::FieldDef {
            name: "secret_value".to_string(),
            ty: TypeRef::String,
            is_boxed: true,
            serde_rename: Some("credential".to_string()),
            newtype_wrapper: Some(transparent_string_wrapper(vec![])),
            ..Default::default()
        }],
        has_default: true,
        has_serde: true,
        ..Default::default()
    };

    let (out, _) = gen_input_dto_for_type("Credentials", "sample_fixture", &type_def);

    assert!(out.contains("#[serde(rename = \"credential\")]"), "{out}");
    assert!(out.contains("let mut out = Self::default();"), "{out}");
    assert!(
        out.contains("out.secret_value = Box::new(sample_fixture::SecretString::from(v));"),
        "{out}"
    );
}

#[test]
fn sanitized_fallible_named_recovery_uses_surface_rust_path() {
    let mapper = WasmMapper::new(HashMap::new(), "Wasm".to_string());
    let mut value = param("value", TypeRef::Named("NestedThing".to_string()));
    value.sanitized = true;
    let mut func = async_function(vec![value]);
    func.is_async = false;
    func.sanitized = true;
    let api = crate::core::ir::ApiSurface {
        types: vec![crate::core::ir::TypeDef {
            name: "NestedThing".to_string(),
            rust_path: "sample_fixture::nested::NestedThing".to_string(),
            has_serde: true,
            ..Default::default()
        }],
        ..empty_surface()
    };

    let out = gen_function_with_emitted_dtos(
        &func,
        &mapper,
        "sample_fixture",
        &AHashSet::new(),
        "Wasm",
        &AHashSet::new(),
        &api,
        &AHashSet::new(),
    );

    assert!(out.contains("sample_fixture::nested::NestedThing"), "{out}");
    assert!(!out.contains("sample_fixture::NestedThing"), "{out}");
}

#[test]
fn deep_optional_wrapper_return_serializes_as_jsvalue() {
    use crate::core::ir::NewtypeContainer::Optional;

    let mapper = WasmMapper::new(HashMap::new(), "Wasm".to_string());
    let mut func = async_function(vec![]);
    func.is_async = false;
    func.error_type = None;
    func.return_type = TypeRef::Optional(Box::new(TypeRef::Optional(Box::new(TypeRef::String))));
    func.return_newtype_wrapper = Some(transparent_string_wrapper(vec![Optional, Optional]));

    let out = gen_function_with_emitted_dtos(
        &func,
        &mapper,
        "sample_fixture",
        &AHashSet::new(),
        "Wasm",
        &AHashSet::new(),
        &empty_surface(),
        &AHashSet::new(),
    );

    assert!(out.contains("-> JsValue"), "{out}");
    assert!(out.contains("serde_wasm_bindgen::to_value"), "{out}");
}

#[test]
fn nested_jsvalue_return_wrapping_recurses_through_optional_and_vec_containers() {
    let wrapped = wrap_jsvalue_mapped_return("result", "Option<Vec<Option<JsValue>>>")
        .expect("nested JsValue must require wrapping");

    assert!(
        wrapped.contains("result.map(|value| value.into_iter().map(|value| value.map(|value|"),
        "{wrapped}"
    );
    assert!(wrapped.contains("serde_wasm_bindgen::to_value"), "{wrapped}");
}