use crate::backends::swift::gen_bindings::dto::swift_typed_default_literal;
use crate::codegen::config_gen::default_value_for_field;
use crate::codegen::shared::config_constructor_parts_with_options;
use crate::core::config::Language;
use crate::core::ir::{DefaultValue, FieldDef, PrimitiveType, TypeDef, TypeRef};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum DefaultCarrier {
PerFieldLiteral,
DelegatesToRust,
NoUserFacingStruct,
}
const fn carries_per_field_default(language: Language) -> DefaultCarrier {
match language {
Language::Csharp | Language::Java | Language::Kotlin | Language::KotlinAndroid | Language::Swift => {
DefaultCarrier::PerFieldLiteral
}
Language::Python | Language::Dart | Language::Ruby | Language::Elixir | Language::Go | Language::Wasm => {
DefaultCarrier::PerFieldLiteral
}
Language::Node | Language::R | Language::Php => DefaultCarrier::DelegatesToRust,
Language::Gleam | Language::Zig => DefaultCarrier::DelegatesToRust,
Language::Ffi | Language::Jni | Language::Rust | Language::C => DefaultCarrier::NoUserFacingStruct,
}
}
fn scalar_field(ty: TypeRef, value: DefaultValue) -> FieldDef {
FieldDef {
name: "fixture".to_string(),
ty,
typed_default: Some(value),
..Default::default()
}
}
fn agreement_fixture() -> Vec<(&'static str, FieldDef)> {
vec![
(
"bool true",
scalar_field(TypeRef::Primitive(PrimitiveType::Bool), DefaultValue::BoolLiteral(true)),
),
(
"fractional float",
scalar_field(TypeRef::Primitive(PrimitiveType::F32), DefaultValue::FloatLiteral(0.7)),
),
(
"whole-valued float",
scalar_field(TypeRef::Primitive(PrimitiveType::F64), DefaultValue::FloatLiteral(2.0)),
),
(
"large integer",
scalar_field(
TypeRef::Primitive(PrimitiveType::U64),
DefaultValue::IntLiteral(10_485_760),
),
),
(
"string",
scalar_field(TypeRef::String, DefaultValue::StringLiteral("balanced".to_string())),
),
]
}
const SHARED_RENDERER_LANGUAGES: [&str; 8] = ["python", "ruby", "go", "java", "csharp", "php", "r", "rust"];
fn normalize_literal(rendered: &str) -> String {
rendered.trim_end_matches(".to_string()").to_lowercase()
}
#[test]
fn every_language_states_how_it_carries_a_rust_default() {
for language in Language::ALL {
let carrier = carries_per_field_default(language);
if crate::cli::registry::try_get_backend(language).is_none() {
assert_eq!(
carrier,
DefaultCarrier::NoUserFacingStruct,
"{language} has no backend, so it cannot be classified as emitting anything"
);
}
}
}
#[test]
fn the_oracle_renders_every_fixture_value() {
for (label, field) in agreement_fixture() {
let value = field.typed_default.as_ref().expect("fixture field carries a default");
assert!(
swift_typed_default_literal(value).is_some(),
"the oracle must render `{label}` or it cannot referee anything"
);
}
}
#[test]
fn the_shared_renderer_agrees_with_the_oracle_for_every_language_it_serves() {
for (label, field) in agreement_fixture() {
let value = field.typed_default.as_ref().expect("fixture field carries a default");
let expected = normalize_literal(&swift_typed_default_literal(value).expect("oracle renders the fixture"));
for language in SHARED_RENDERER_LANGUAGES {
let rendered = normalize_literal(&default_value_for_field(&field, language));
assert_eq!(
rendered, expected,
"`{language}` and the Swift oracle disagree on the default for `{label}`"
);
}
}
}
#[test]
fn every_language_renders_an_enum_variant_default_as_something() {
let field = FieldDef {
name: "mode".to_string(),
ty: TypeRef::Named("Mode".to_string()),
typed_default: Some(DefaultValue::EnumVariant("Fast".to_string())),
..Default::default()
};
for language in SHARED_RENDERER_LANGUAGES {
let rendered = default_value_for_field(&field, language);
assert!(
rendered.to_lowercase().contains("fast"),
"`{language}` dropped the enum-variant default, rendering `{rendered}`"
);
assert!(
rendered.contains("Mode"),
"`{language}` rendered the variant without its enum, giving `{rendered}`"
);
}
}
#[test]
fn a_default_that_carries_no_value_is_declined_by_the_oracle() {
for unreadable in [
DefaultValue::Empty,
DefaultValue::Unresolved("Self::new(\"en\")".to_string()),
DefaultValue::FunctionCall("crate::defaults::limit".to_string()),
DefaultValue::PublicFunctionCall("crate::defaults::limit".to_string()),
] {
assert!(
swift_typed_default_literal(&unreadable).is_none(),
"`{unreadable:?}` carries no value, so the oracle must decline to referee it"
);
}
}
#[test]
fn empty_and_unresolved_are_distinct_values() {
assert_ne!(
DefaultValue::Empty,
DefaultValue::Unresolved(String::new()),
"`Empty` asserts the default IS the type-zero; `Unresolved` asserts alef does not know it"
);
assert!(
matches!(DefaultValue::Unresolved("body".to_string()), DefaultValue::Unresolved(body) if body == "body"),
"`Unresolved` must retain the unreadable body so the diagnostic can name it"
);
}
#[test]
fn a_derived_default_still_renders_as_the_target_language_zero() {
let bool_field = scalar_field(TypeRef::Primitive(PrimitiveType::Bool), DefaultValue::Empty);
for (language, expected) in [("python", "False"), ("go", "false"), ("csharp", "false")] {
assert_eq!(
default_value_for_field(&bool_field, language),
expected,
"a `#[derive(Default)]` bool field must still render `{language}`'s zero"
);
}
let int_field = scalar_field(TypeRef::Primitive(PrimitiveType::U64), DefaultValue::Empty);
for (language, expected) in [("python", "0"), ("go", "0"), ("csharp", "0")] {
assert_eq!(
default_value_for_field(&int_field, language),
expected,
"a `#[derive(Default)]` integer field must still render `{language}`'s zero"
);
}
}
#[test]
fn the_shared_renderer_receives_unresolved_without_it_being_rewritten() {
let field = scalar_field(
TypeRef::Primitive(PrimitiveType::F32),
DefaultValue::Unresolved("Self::new(\"en\")".to_string()),
);
assert!(
matches!(field.typed_default, Some(DefaultValue::Unresolved(_))),
"the fixture itself must carry `Unresolved`, or this referees nothing"
);
for language in SHARED_RENDERER_LANGUAGES {
let rendered = default_value_for_field(&field, language);
assert!(
!rendered.is_empty(),
"`{language}` must produce a defined rendering for a suppressed `Unresolved`"
);
}
}
#[test]
fn the_normalizer_does_not_erase_a_real_disagreement() {
assert_ne!(normalize_literal("0.7"), normalize_literal("0.0"));
assert_ne!(normalize_literal("true"), normalize_literal("false"));
assert_ne!(
normalize_literal("\"balanced\".to_string()"),
normalize_literal("\"\".to_string()")
);
assert_eq!(
normalize_literal("\"balanced\".to_string()"),
normalize_literal("\"balanced\"")
);
assert_eq!(normalize_literal("True"), normalize_literal("true"));
}
fn function_call_field(name: &str, ty: TypeRef) -> FieldDef {
FieldDef {
name: name.to_string(),
ty,
default: Some("serde(default = \"default_stop_words\")".to_string()),
typed_default: Some(DefaultValue::FunctionCall("default_stop_words".to_string())),
..Default::default()
}
}
fn same_field_without_any_default(field: &FieldDef) -> FieldDef {
FieldDef {
default: None,
typed_default: None,
..field.clone()
}
}
#[test]
fn the_no_default_rendering_is_a_real_value_for_every_language_it_is_compared_against() {
for ty in [
TypeRef::Primitive(PrimitiveType::U64),
TypeRef::Vec(Box::new(TypeRef::String)),
] {
let bare = same_field_without_any_default(&function_call_field("stop_words", ty.clone()));
for language in SHARED_RENDERER_LANGUAGES {
let zero = default_value_for_field(&bare, language);
assert!(
!zero.trim().is_empty(),
"`{language}` renders nothing for a bare `{ty:?}`, so comparing against it proves nothing"
);
}
}
}
#[test]
fn a_function_call_default_is_never_answered_with_the_no_default_value() {
for ty in [
TypeRef::Primitive(PrimitiveType::U64),
TypeRef::Vec(Box::new(TypeRef::String)),
] {
let field = function_call_field("stop_words", ty.clone());
let bare = same_field_without_any_default(&field);
for language in SHARED_RENDERER_LANGUAGES {
let rendered = default_value_for_field(&field, language);
let zero = default_value_for_field(&bare, language);
assert_ne!(
rendered, zero,
"`{language}` answered a `#[serde(default = \"...\")]` on `{ty:?}` with the same `{zero}` a field \
with no default gets — the default was dropped, not carried"
);
}
}
}
fn owning_type_with_default(rust_path: &str, fields: Vec<FieldDef>) -> TypeDef {
TypeDef {
name: "Settings".to_string(),
rust_path: rust_path.to_string(),
has_default: true,
has_serde: true,
fields,
..Default::default()
}
}
fn wasm_style_mapper() -> impl Fn(&TypeRef) -> String {
|ty: &TypeRef| match ty {
TypeRef::Named(name) => format!("Wasm{name}"),
_ => "String".to_string(),
}
}
#[test]
fn an_enum_variant_default_is_read_off_the_owning_types_default() {
let field = FieldDef {
name: "mode".to_string(),
ty: TypeRef::Named("Mode".to_string()),
typed_default: Some(DefaultValue::EnumVariant("Fast".to_string())),
..Default::default()
};
let typ = owning_type_with_default("demo::Settings", vec![field.clone()]);
let (_, _, assignments) = config_constructor_parts_with_options(&[field], &wasm_style_mapper(), false, &typ);
assert!(
assignments.contains("<demo::Settings as ::core::default::Default>::default().mode"),
"the variant must be read off the owning type, not guessed: {assignments}"
);
assert!(
!assignments.contains("mode.unwrap_or_default()"),
"`unwrap_or_default()` calls `Mode::default()`, which is not necessarily `Mode::Fast`: {assignments}"
);
assert!(
assignments.contains(".into()"),
"the recovered value is the core enum and the binding field is the wrapper: {assignments}"
);
}
#[test]
fn an_enum_variant_default_falls_back_only_when_the_owning_type_cannot_be_named() {
let field = FieldDef {
name: "mode".to_string(),
ty: TypeRef::Named("Mode".to_string()),
typed_default: Some(DefaultValue::EnumVariant("Fast".to_string())),
..Default::default()
};
let typ = owning_type_with_default("", vec![field.clone()]);
let (_, _, assignments) = config_constructor_parts_with_options(&[field], &wasm_style_mapper(), false, &typ);
assert!(
assignments.contains("mode.unwrap_or_default()"),
"an unnameable owning type leaves nothing to read the variant off: {assignments}"
);
}
#[test]
fn an_empty_default_still_delegates_to_the_binding_types_own_default() {
let field = FieldDef {
name: "tags".to_string(),
ty: TypeRef::Vec(Box::new(TypeRef::String)),
typed_default: Some(DefaultValue::Empty),
..Default::default()
};
let typ = owning_type_with_default("demo::Settings", vec![field.clone()]);
let (_, _, assignments) = config_constructor_parts_with_options(&[field], &wasm_style_mapper(), false, &typ);
assert!(
assignments.contains("tags.unwrap_or_default()"),
"`Empty` is exactly `Default::default()` and needs no recovery: {assignments}"
);
}