use super::*;
fn named_default_field(name: &str, type_name: &str, default_path: &str) -> FieldDef {
FieldDef {
name: name.to_string(),
ty: TypeRef::Named(type_name.to_string()),
typed_default: Some(DefaultValue::PublicFunctionCall(default_path.to_string())),
..Default::default()
}
}
fn owning_type(rust_path: &str, type_name: &str, fields: Vec<FieldDef>) -> TypeDef {
TypeDef {
name: type_name.to_string(),
rust_path: rust_path.to_string(),
fields,
has_serde: true,
..Default::default()
}
}
#[test]
fn format_default_value_named_function_call_appends_into() {
let field = named_default_field("ssrf", "SsrfPolicy", "sample_crate::SsrfPolicy::from_env");
let typ = owning_type("sample_crate::CrawlConfig", "CrawlConfig", vec![field.clone()]);
assert_eq!(
format_default_value(&field, &typ, "WasmSsrfPolicy"),
"sample_crate::SsrfPolicy::from_env().into()"
);
}
#[test]
fn format_default_value_named_function_call_uses_serde_when_mapped_to_js_value() {
let field = named_default_field(
"model",
"ScoringModelType",
"sample_crate::ScoringConfig::default_scoring_model",
);
let typ = owning_type("sample_crate::ScoringConfig", "ScoringConfig", vec![field.clone()]);
let rendered = format_default_value(&field, &typ, "JsValue");
assert!(
!rendered.contains(".into()"),
"a JsValue-mapped field must not use .into(): {rendered}"
);
assert!(
rendered.starts_with("serde_wasm_bindgen::to_value(&")
&& rendered.ends_with(".unwrap_or(wasm_bindgen::JsValue::NULL)"),
"expected a serde_wasm_bindgen bridge, got: {rendered}"
);
}
#[test]
fn maps_to_js_value_accepts_every_path_spelling() {
for spelling in [
"JsValue",
"wasm_bindgen::JsValue",
"::wasm_bindgen::JsValue",
"wasm_bindgen::prelude::JsValue",
" JsValue ",
] {
assert!(maps_to_js_value(spelling), "{spelling} must be recognised as JsValue");
}
for other in ["WasmSsrfPolicy", "String", "Option<JsValue>", "Vec<JsValue>", ""] {
assert!(!maps_to_js_value(other), "{other} must not be treated as JsValue");
}
}
#[test]
fn format_default_value_uses_serde_for_qualified_js_value_spelling() {
let field = named_default_field(
"model",
"ScoringModelType",
"sample_crate::ScoringConfig::default_scoring_model",
);
let typ = owning_type("sample_crate::ScoringConfig", "ScoringConfig", vec![field.clone()]);
let rendered = format_default_value(&field, &typ, "::wasm_bindgen::prelude::JsValue");
assert!(
!rendered.contains(".into()") && rendered.starts_with("serde_wasm_bindgen::to_value(&"),
"expected a serde_wasm_bindgen bridge, got: {rendered}"
);
}
#[test]
fn format_default_value_non_named_function_call_has_no_into() {
let field = FieldDef {
name: "retry_limit".to_string(),
ty: TypeRef::Primitive(PrimitiveType::U32),
typed_default: Some(DefaultValue::PublicFunctionCall(
"sample_crate::defaults::retry_limit".to_string(),
)),
..Default::default()
};
let typ = owning_type("sample_crate::CrawlConfig", "CrawlConfig", vec![field.clone()]);
assert_eq!(
format_default_value(&field, &typ, ""),
"sample_crate::defaults::retry_limit()"
);
}
#[test]
fn wasm_constructor_recovers_private_serde_default_via_deserialize() {
let field = FieldDef {
name: "max_archive_depth".to_string(),
ty: TypeRef::Primitive(PrimitiveType::U32),
typed_default: Some(DefaultValue::FunctionCall("default_archive_depth".to_string())),
..Default::default()
};
let typ = owning_type(
"sample_crate::ExtractionConfig",
"ExtractionConfig",
vec![field.clone()],
);
let rendered = format_default_value(&field, &typ, "");
assert_eq!(
rendered,
"serde_json::from_str::<sample_crate::ExtractionConfig>(r#\"{}\"#).expect(\"alef-generated \
default JSON for `ExtractionConfig` failed to deserialize\").max_archive_depth"
);
assert!(
!rendered.contains("default_archive_depth()"),
"the private source-crate function must never be emitted as a bare callable: {rendered}"
);
}
#[test]
fn wasm_constructor_appends_into_for_named_field_default() {
let field = FieldDef {
name: "crawl".to_string(),
ty: TypeRef::Named("CrawlConfig".to_string()),
typed_default: Some(DefaultValue::FunctionCall(
"default_sample_crate_crawl_config".to_string(),
)),
..Default::default()
};
let typ = owning_type(
"sample_crate::ExtractionConfig",
"ExtractionConfig",
vec![field.clone()],
);
let rendered = format_default_value(&field, &typ, "");
assert_eq!(
rendered,
"serde_json::from_str::<sample_crate::ExtractionConfig>(r#\"{}\"#).expect(\"alef-generated \
default JSON for `ExtractionConfig` failed to deserialize\").crawl.into()"
);
}
#[test]
fn wasm_constructor_default_recovery_failure_emits_compile_error() {
let owner_field = FieldDef {
name: "owner".to_string(),
ty: TypeRef::Named("Author".to_string()),
..Default::default()
};
let retry_field = FieldDef {
name: "retry_limit".to_string(),
ty: TypeRef::Primitive(PrimitiveType::U32),
typed_default: Some(DefaultValue::FunctionCall("defaults::retry_limit".to_string())),
..Default::default()
};
let typ = owning_type(
"sample_crate::RetryHolder",
"RetryHolder",
vec![owner_field, retry_field.clone()],
);
let rendered = format_default_value(&retry_field, &typ, "");
assert!(
rendered.starts_with("compile_error!"),
"unrecoverable private default must fail generation, not a bare path call: {rendered}"
);
assert!(
rendered.contains("defaults::retry_limit") && rendered.contains("retry_limit"),
"the failure must name the uncallable function and the field: {rendered}"
);
assert!(
!rendered.contains("defaults::retry_limit()"),
"the uncallable source function must never be emitted as a callable: {rendered}"
);
}
#[test]
fn config_constructor_parts_named_default_field_applies_and_converts() {
let field = named_default_field("ssrf", "SsrfPolicy", "sample_crate::SsrfPolicy::from_env");
let fields = vec![field.clone()];
let type_mapper = |ty: &TypeRef| match ty {
TypeRef::Named(name) => format!("Wasm{name}"),
_ => "String".to_string(),
};
let typ = owning_type("sample_crate::CrawlConfig", "CrawlConfig", vec![field]);
let (_, _, assignments) = config_constructor_parts_with_options(&fields, &type_mapper, true, &typ);
assert!(
assignments.contains("ssrf.unwrap_or_else(|| sample_crate::SsrfPolicy::from_env().into())"),
"expected an unwrap_or_else default that converts via .into(), got: {assignments}"
);
}
#[test]
fn config_constructor_parts_private_default_field_recovers_via_deserialize() {
let field = FieldDef {
name: "max_archive_depth".to_string(),
ty: TypeRef::Primitive(PrimitiveType::U32),
typed_default: Some(DefaultValue::FunctionCall("default_archive_depth".to_string())),
..Default::default()
};
let fields = vec![field.clone()];
let type_mapper = |ty: &TypeRef| match ty {
TypeRef::Named(name) => format!("Wasm{name}"),
_ => "u32".to_string(),
};
let typ = owning_type("sample_crate::ExtractionConfig", "ExtractionConfig", vec![field]);
let (_, _, assignments) = config_constructor_parts_with_options(&fields, &type_mapper, true, &typ);
assert!(
assignments.contains(
"max_archive_depth.unwrap_or_else(|| serde_json::from_str::<sample_crate::ExtractionConfig>(r#\"{}\"#)"
) && assignments.contains(".max_archive_depth)"),
"expected an unwrap_or_else default that recovers via deserialize, got: {assignments}"
);
assert!(
!assignments.contains("default_archive_depth()"),
"the private source-crate function must never be emitted as a bare callable: {assignments}"
);
}
#[test]
fn config_constructor_parts_bare_zero_arg_default_drops_redundant_closure() {
let field = FieldDef {
name: "max_archive_depth".to_string(),
ty: TypeRef::Primitive(PrimitiveType::I64),
typed_default: Some(DefaultValue::PublicFunctionCall(
"sample_crate::ExtractionConfig::default_archive_depth".to_string(),
)),
..Default::default()
};
let fields = vec![field.clone()];
let type_mapper = |_: &TypeRef| "i64".to_string();
let typ = owning_type("sample_crate::ExtractionConfig", "ExtractionConfig", vec![field]);
let (_, _, assignments) = config_constructor_parts_with_options(&fields, &type_mapper, true, &typ);
assert!(
assignments.contains("max_archive_depth.unwrap_or_else(sample_crate::ExtractionConfig::default_archive_depth)"),
"expected the redundant closure dropped in favor of a bare function reference, got: {assignments}"
);
assert!(
!assignments.contains("unwrap_or_else(|| sample_crate::ExtractionConfig::default_archive_depth())"),
"clippy::redundant_closure: a bare zero-arg call must never stay wrapped in a closure, got: {assignments}"
);
}
#[test]
fn field_default_constructor_keeps_unrelated_sibling_required() {
let llm = FieldDef {
name: "llm".to_string(),
ty: TypeRef::Named("LlmConfig".to_string()),
..Default::default()
};
let alt_text = FieldDef {
name: "alt_text".to_string(),
ty: TypeRef::Named("CaptionAltTextMode".to_string()),
default: Some("/* serde(default) */".to_string()),
typed_default: Some(DefaultValue::EnumVariant("Preserve".to_string())),
..Default::default()
};
let provider = FieldDef {
name: "provider".to_string(),
ty: TypeRef::Named("CaptionProvider".to_string()),
..Default::default()
};
let typ = TypeDef {
name: "CaptioningConfig".to_string(),
rust_path: "sample_core::CaptioningConfig".to_string(),
fields: vec![llm.clone(), alt_text.clone(), provider.clone()],
..Default::default()
};
let mapper = |ty: &TypeRef| match ty {
TypeRef::Named(name) => name.clone(),
_ => unreachable!(),
};
let (params, defaults, assignments) =
constructor_parts_with_field_defaults(&[llm, alt_text, provider], &mapper, &typ);
assert_eq!(
params,
"llm: LlmConfig, alt_text: Option<CaptionAltTextMode>, provider: CaptionProvider"
);
assert!(
!params.contains("llm: Option<"),
"required sibling was widened: {params}"
);
assert!(
params.contains("alt_text: Option<CaptionAltTextMode>"),
"serde-defaulted field must admit omission: {params}"
);
assert_eq!(defaults, "alt_text=None");
assert!(
assignments.contains("llm"),
"required sibling must pass through: {assignments}"
);
assert!(
!assignments.contains("llm.unwrap"),
"required sibling must pass through: {assignments}"
);
assert!(
assignments.contains("alt_text: alt_text.unwrap_or_default()"),
"omitted bare serde default must use the field type's Default: {assignments}"
);
}
#[test]
fn field_default_constructor_preserves_ordinary_optional_sibling() {
let llm = FieldDef {
name: "llm".to_string(),
ty: TypeRef::Named("LlmConfig".to_string()),
..Default::default()
};
let output_format = FieldDef {
name: "output_format".to_string(),
ty: TypeRef::Named("OutputFormat".to_string()),
optional: true,
..Default::default()
};
let alt_text = FieldDef {
name: "alt_text".to_string(),
ty: TypeRef::Named("CaptionAltTextMode".to_string()),
default: Some("/* serde(default) */".to_string()),
typed_default: Some(DefaultValue::EnumVariant("Preserve".to_string())),
..Default::default()
};
let fields = vec![llm, output_format, alt_text];
let typ = TypeDef {
name: "CaptioningConfig".to_string(),
rust_path: "sample_core::CaptioningConfig".to_string(),
fields: fields.clone(),
..Default::default()
};
let mapper = |ty: &TypeRef| match ty {
TypeRef::Named(name) => name.clone(),
_ => unreachable!(),
};
let (params, defaults, assignments) = constructor_parts_with_field_defaults(&fields, &mapper, &typ);
assert!(
params.contains("output_format: Option<OutputFormat>"),
"ordinary optional sibling must remain optional: {params}"
);
assert_eq!(defaults, "alt_text=None, output_format=None");
assert!(
assignments.contains("output_format"),
"ordinary optional sibling must pass through: {assignments}"
);
assert!(
!assignments.contains("output_format.unwrap"),
"ordinary optional sibling must pass through: {assignments}"
);
}
#[test]
fn field_default_constructor_does_not_double_wrap_already_optional_sibling() {
let description = FieldDef {
name: "description".to_string(),
ty: TypeRef::Optional(Box::new(TypeRef::String)),
optional: true,
..Default::default()
};
let alt_text = FieldDef {
name: "alt_text".to_string(),
ty: TypeRef::Named("CaptionAltTextMode".to_string()),
default: Some("/* serde(default) */".to_string()),
typed_default: Some(DefaultValue::EnumVariant("Preserve".to_string())),
..Default::default()
};
let fields = vec![description, alt_text];
let typ = TypeDef {
name: "CaptioningConfig".to_string(),
rust_path: "sample_core::CaptioningConfig".to_string(),
fields: fields.clone(),
..Default::default()
};
let mapper = |ty: &TypeRef| match ty {
TypeRef::Optional(inner) if matches!(inner.as_ref(), TypeRef::String) => "Option<String>".to_string(),
TypeRef::Named(name) => name.clone(),
_ => unreachable!(),
};
let (params, defaults, assignments) = constructor_parts_with_field_defaults(&fields, &mapper, &typ);
assert!(
params.contains("description: Option<String>"),
"already-optional sibling must retain its mapped type: {params}"
);
assert!(
!params.contains("Option<Option<String>>"),
"already-optional sibling must not be double-wrapped: {params}"
);
assert_eq!(defaults, "alt_text=None, description=None");
assert!(
!assignments.contains("description.unwrap"),
"already-optional sibling must pass through: {assignments}"
);
}
#[test]
fn field_default_constructor_does_not_widen_non_enum_bare_defaults() {
let quality_thresholds = FieldDef {
name: "quality_thresholds".to_string(),
ty: TypeRef::Named("OcrQualityThresholds".to_string()),
default: Some("/* serde(default) */".to_string()),
typed_default: Some(DefaultValue::Empty),
..Default::default()
};
let typ = TypeDef {
name: "OcrPipelineConfig".to_string(),
fields: vec![quality_thresholds.clone()],
..Default::default()
};
let mapper = |ty: &TypeRef| match ty {
TypeRef::Named(name) => name.clone(),
_ => unreachable!(),
};
let (params, defaults, assignments) = constructor_parts_with_field_defaults(&[quality_thresholds], &mapper, &typ);
assert_eq!(params, "quality_thresholds: OcrQualityThresholds");
assert_eq!(defaults, "");
assert_eq!(assignments, "quality_thresholds");
}