gpui-form-derive 0.7.0

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

#[test]
fn test_hidden_inventory_emits_validations_and_omits_skipped_fields() {
    let tokens = quote! {
        #[derive(GpuiForm)]
        #[gpui_form(koruma)]
        struct TestForm {
            #[gpui_form(component(crate::Input))]
            visible: String,

            #[gpui_form(hidden(default = HiddenId::new()))]
            #[koruma(newtype)]
            account_id: HiddenId,

            #[gpui_form(skip)]
            skipped_secret: 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("FieldVariant::hidden_for_field(\"account_id\",::gpui_form::schema::registry::FieldValueSpec::new(::gpui_form::schema::registry::RustType::from_macro_tokens_unchecked(\"HiddenId\"),::gpui_form::schema::registry::RustType::from_macro_tokens_unchecked(\"HiddenId\"),::gpui_form::schema::registry::FieldValuePresence::DirectStorage)")
            && compact.contains(".with_validations(&[::gpui_form::schema::registry::ValidationRuleId::Newtype])")
            && compact.contains(".with_default(::gpui_form::schema::registry::RustExpr::from_macro_tokens_unchecked(\"HiddenId::new()\"))"),
        "hidden fields should publish validation IDs and defaults in inventory: {compact}"
    );
    assert!(
        compact.contains("FieldVariant::component_for_field(\"visible\""),
        "component field inventory should remain emitted: {compact}"
    );
    assert!(
        !compact.contains("FieldVariant::hidden_for_field(\"skipped_secret\")")
            && !compact.contains("FieldVariant::component_for_field(\"skipped_secret\")"),
        "skipped fields should stay out of field inventory: {compact}"
    );
    assert!(
        compact.contains("with_holder_conversion(::gpui_form::schema::registry::HolderConversionMetadata::new(::gpui_form::schema::registry::HolderConversionShape::NeedsSkippedFields,true))"),
        "skipped fields should be represented by holder conversion metadata: {compact}"
    );
}

#[test]
fn test_field_variant_metadata_records_form_value_holder_conversion_shape() {
    let tokens = quote! {
        #[derive(GpuiForm)]
        struct TestForm {
            #[gpui_form(component(
                crate::Input,
                value(
                    type = crate::types::AccountCode,
                    from_source = crate::types::AccountCode::new,
                    into_source = crate::types::AccountCode::into_string
                )
            ))]
            account_no: 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(
            "FieldVariant::component_for_field(\"account_no\",::gpui_form::schema::registry::FieldValueSpec::new(::gpui_form::schema::registry::RustType::from_macro_tokens_unchecked(\"crate::types::AccountCode\"),::gpui_form::schema::registry::RustType::from_macro_tokens_unchecked(\"String\"),if<<crate::Inputas::gpui_form::runtime::shape::GpuiFormComponentShapePolicy>::ValueStoragePolicy"
        ),
        "FieldVariant should store the form-side value type: {compact}"
    );
    assert!(
        compact.contains("RustType::from_macro_tokens_unchecked(\"String\")"),
        "FieldVariant should store the source model value type: {compact}"
    );
    assert!(
        compact.contains(
            "if<<crate::Inputas::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}"
        ),
        "FieldVariant should inherit generated value-storage policy from the shape: {compact}"
    );
    assert!(
        compact.contains("with_conversions(::gpui_form::schema::registry::ConversionMetadata::new(Some(::gpui_form::schema::registry::RustExpr::from_macro_tokens_unchecked(\"crate::types::AccountCode::new\")),Some(::gpui_form::schema::registry::RustExpr::from_macro_tokens_unchecked(\"crate::types::AccountCode::into_string\"))))"),
        "FieldVariant should store source/form conversion expressions: {compact}"
    );
}

#[test]
fn test_generic_forms_require_inventory_opt_out() {
    let tokens = quote! {
        #[derive(GpuiForm)]
        struct TestForm<T>
        where
            T: Default,
        {
            #[gpui_form(hidden)]
            value: T,
        }
    };

    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("cannotregistergenericformsininventory")
            && compact.contains("gpui_form(no_inventory)"),
        "generic inventory registration should require an explicit opt-out: {compact}"
    );
}