gpui-form-derive 0.7.0

Macro crate for gpui-form
Documentation
use super::support::*;

#[test]
fn test_component_shape_generates_shape_based_state_and_constructor() {
    let tokens = quote! {
        #[derive(GpuiForm)]
        struct TestForm {
            #[gpui_form(component(crate::ui::BioInput))]
            bio: String,
        }
    };

    let derive_input: DeriveInput = syn::parse2(tokens).unwrap();
    let expanded = expansion::expand_gpui_form(
        derive_input,
        structs::GpuiFormOptions {
            generate_shape: true,
            generate_mcp: false,
        },
    );

    let compact = compact_tokens(&expanded.to_string());

    assert!(
        compact.contains("pubbio:::gpui_kit::Entity<")
            && compact.contains(
                "<crate::ui::BioInputas::gpui_form::runtime::shape::GpuiComponentShape>::State"
            ),
        "Component shape field should use the source field name and shape state type"
    );

    assert!(
        compact.contains(
            "<crate::ui::BioInputas::gpui_form::runtime::shape::GpuiComponentShape>::new(window,cx)"
        ),
        "Component shape constructor should delegate to shape::new"
    );

    assert!(
        compact.contains(
            "FieldVariant::component_for_field(\"bio\",::gpui_form::schema::registry::FieldValueSpec::new(::gpui_form::schema::registry::RustType::from_macro_tokens_unchecked(\"String\"),::gpui_form::schema::registry::RustType::from_macro_tokens_unchecked(\"String\"),if<<crate::ui::BioInputas::gpui_form::runtime::shape::GpuiFormComponentShapePolicy>::ValueStoragePolicy"
        ),
        "FieldVariant metadata should come from the declared component shape"
    );

    assert!(
        compact.contains("with_render(if<<crate::ui::BioInputas::gpui_form::runtime::shape::GpuiComponentShape>::RenderComponentas::gpui_form::runtime::shape::GpuiComponentRender<"),
        "FieldVariant should inherit render component metadata from the shape: {compact}"
    );
    assert!(
        compact.contains(
            "FieldComponentVariant::new(::gpui_form::schema::registry::RustPath::from_macro_tokens_unchecked(\"crate::ui::BioInput\"))"
        ),
        "FieldVariant should carry the component shape path: {compact}"
    );
    assert!(
        compact.contains("with_value_binding(if<crate::ui::BioInputas::gpui_form::runtime::shape::ComponentShapeMetadata>::CAPABILITIES.value_binding().enabled()"),
        "FieldVariant should inherit component value binding metadata from the shape: {compact}"
    );
    assert!(
        compact.contains("PROTOTYPING.field_suffix")
            && compact.contains("ComponentSuffix::new(\"input\")"),
        "FieldVariant should inherit shape prototyping metadata with a generated fallback: {compact}"
    );
}

#[test]
fn test_component_shape_generates_fields() {
    let tokens = quote! {
        #[derive(GpuiForm)]
        struct TestForm {
            #[gpui_form(component(crate::shapes::Input::<_>, default = "test@example.com"))]
            email: String,

            #[gpui_form(component(crate::shapes::Switch))]
            enabled: bool,
        }
    };

    let derive_input: DeriveInput = syn::parse2(tokens).unwrap();
    let expanded = expansion::expand_gpui_form(
        derive_input,
        structs::GpuiFormOptions {
            generate_shape: true,
            generate_mcp: false,
        },
    );

    let compact = compact_tokens(&expanded.to_string());

    assert!(
        compact.contains("pubemail:::gpui_kit::Entity<"),
        "explicit component shape syntax should generate a source-named entity field: {compact}"
    );
    assert!(
        compact.contains("Into::into(\"test@example.com\")"),
        "explicit component syntax should compose with key-value field helpers"
    );
    assert!(
        compact.contains("pubenabled:"),
        "explicit component syntax should generate a value-holder field: {compact}"
    );
    assert!(
        compact.contains(
            "if<<crate::shapes::Switchas::gpui_form::runtime::shape::GpuiFormComponentShapePolicy>::ValueStoragePolicyas::gpui_form::runtime::shape::ComponentValueStoragePolicy>::REQUIRES_VALUE{::gpui_form::schema::registry::FieldValuePresence::RequiresValue}else{::gpui_form::schema::registry::FieldValuePresence::DirectStorage}"
        ),
        "explicit component syntax should inherit required-value metadata from the shape"
    );
    assert!(
        compact.contains("PROTOTYPING.field_suffix")
            && compact.contains("ComponentSuffix::new(\"input\")"),
        "component inventory metadata should inherit shape prototyping metadata with a generated fallback"
    );
}

#[test]
fn test_component_shape_rejects_duplicate_component_expression() {
    let tokens = quote! {
        #[derive(GpuiForm)]
        struct TestForm {
            #[gpui_form(
                component(crate::shapes::Input::<_>),
                component(crate::Input)
            )]
            email: String,
        }
    };

    let derive_input: DeriveInput = syn::parse2(tokens).unwrap();
    let expanded = expansion::expand_gpui_form(
        derive_input,
        structs::GpuiFormOptions {
            generate_shape: true,
            generate_mcp: false,
        },
    );

    let compact = compact_tokens(&expanded.to_string());

    assert!(
        compact.contains("duplicate`component`option"),
        "duplicate component syntax should produce an actionable error: {compact}"
    );
}

#[test]
fn test_component_value_binding_metadata_assertion_is_generated() {
    let tokens = quote! {
        #[derive(GpuiForm)]
        struct TestForm {
            #[gpui_form(component(crate::Input))]
            name: String,
        }
    };

    let derive_input: DeriveInput = syn::parse2(tokens).unwrap();
    let expanded = expansion::expand_gpui_form(
        derive_input,
        structs::GpuiFormOptions {
            generate_shape: true,
            generate_mcp: false,
        },
    );

    let compact = compact_tokens(&expanded.to_string());
    let removed_binding_policy_helper =
        ["Assert", "Component", "Value", "Binding", "Policy"].concat();

    assert!(
        compact.contains("Shape:::gpui_form::runtime::shape::GpuiComponentShape+::gpui_form::runtime::shape::ComponentShapeMetadata")
            && compact.contains(
                "__gpui_form_assert_name_component_value_binding::<crate::Input,String"
            )
            && !compact.contains(&removed_binding_policy_helper),
        "shape value-binding metadata should emit a derive-time metadata assertion using shape metadata: {compact}"
    );
    assert!(
        compact.contains("__gpui_form_assert_name_declared_component_shape")
            && compact.contains("__gpui_form_assert_name_component_value_compatibility")
            && compact.contains("__gpui_form_assert_name_component_value_binding"),
        "component type checks should be split into field-named assertions: {compact}"
    );
}

#[test]
fn test_component_shape_infers_field_type_generic() {
    let tokens = quote! {
        #[derive(GpuiForm)]
        struct TestForm {
            #[gpui_form(component(crate::shapes::Input::<_>))]
            account_no: crate::types::AccountCode,
        }
    };

    let derive_input: DeriveInput = syn::parse2(tokens).unwrap();
    let expanded = expansion::expand_gpui_form(
        derive_input,
        structs::GpuiFormOptions {
            generate_shape: true,
            generate_mcp: false,
        },
    );

    let compact = compact_tokens(&expanded.to_string());

    assert!(
        compact.contains(
            "<crate::shapes::Input<crate::types::AccountCode>as::gpui_form::runtime::shape::GpuiComponentShape>::State"
        ),
        "component shape `_` should be resolved to the field type in FormFields: {compact}"
    );
    assert!(
        compact.contains("pubaccount_no:::gpui_kit::Entity<"),
        "generated FormFields identifiers should use the source field name: {compact}"
    );
    assert!(
        compact.contains("PROTOTYPING.field_suffix")
            && compact.contains("ComponentSuffix::new(\"input\")"),
        "inventory metadata should use the resolved generated suffix: {compact}"
    );
    assert!(
        compact.contains(
            "FieldComponentVariant::new(::gpui_form::schema::registry::RustPath::from_macro_tokens_unchecked(\"crate::shapes::Input<crate::types::AccountCode>\"))"
        ),
        "component shape metadata should store the resolved shape path: {compact}"
    );
}

#[test]
fn test_component_shape_generates_multiword_component_suffix() {
    let tokens = quote! {
        #[derive(GpuiForm)]
        struct TestForm {
            #[gpui_form(component(crate::shapes::DatePicker))]
            birth_date: chrono::NaiveDate,
        }
    };

    let derive_input: DeriveInput = syn::parse2(tokens).unwrap();
    let expanded = expansion::expand_gpui_form(
        derive_input,
        structs::GpuiFormOptions {
            generate_shape: true,
            generate_mcp: false,
        },
    );

    let compact = compact_tokens(&expanded.to_string());

    assert!(
        compact.contains("pubbirth_date:::gpui_kit::Entity<"),
        "multiword shape names should not affect generated component entity fields: {compact}"
    );
    assert!(
        compact.contains("PROTOTYPING.field_suffix")
            && compact.contains("ComponentSuffix::new(\"date_picker\")"),
        "inventory metadata should use the resolved generated suffix: {compact}"
    );
}