use super::*;
#[test]
fn a_cfg_gated_int_literal_initializer_resolves() {
let resolved = defaults_for(
r#"
pub struct Prefs {
#[cfg(feature = "extras")]
pub max_depth: u32,
pub width: u32,
}
impl Default for Prefs {
fn default() -> Self {
Self {
#[cfg(feature = "extras")]
max_depth: 9,
width: 2,
}
}
}
"#,
"Prefs",
&["max_depth", "width"],
);
assert_eq!(
resolved,
vec![
("max_depth".to_string(), DefaultValue::IntLiteral(9)),
("width".to_string(), DefaultValue::IntLiteral(2)),
],
"a cfg-gated initializer with a matching field-declaration gate is deterministic wherever \
the field exists, and must read exactly as its bare counterpart does"
);
}
#[test]
fn a_cfg_gated_none_initializer_resolves() {
let resolved = defaults_for(
r#"
pub struct Config {
#[cfg(feature = "pdf")]
pub pdf_options: Option<u32>,
}
impl Default for Config {
fn default() -> Self {
Self {
#[cfg(feature = "pdf")]
pdf_options: None,
}
}
}
"#,
"Config",
&["pdf_options"],
);
assert_eq!(
resolved,
vec![("pdf_options".to_string(), DefaultValue::None)],
"a bare `None` under a matching `cfg` is exactly as readable as an ungated `None`"
);
}
#[test]
fn a_cfg_gated_nested_type_default_resolves_to_empty() {
let resolved = defaults_for(
r#"
pub struct Config {
#[cfg(feature = "svg")]
pub svg: SvgOptions,
}
impl Default for Config {
fn default() -> Self {
Self {
#[cfg(feature = "svg")]
svg: SvgOptions::default(),
}
}
}
"#,
"Config",
&["svg"],
);
assert_eq!(
resolved,
vec![("svg".to_string(), DefaultValue::Empty)],
"`Type::default()` is the type's zero by definition regardless of the cfg gating its field"
);
}
#[test]
fn a_cfg_gated_function_call_initializer_resolves_to_function_call() {
let resolved = defaults_for(
r#"
pub struct Config {
#[cfg(feature = "remote")]
pub remote: RemoteConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
#[cfg(feature = "remote")]
remote: Config::default_remote_config(),
}
}
}
"#,
"Config",
&["remote"],
);
assert_eq!(
resolved,
vec![(
"remote".to_string(),
DefaultValue::FunctionCall("Config::default_remote_config".to_string())
)],
"a cfg-gated unfoldable call must read exactly as the bare version does; got {resolved:?}"
);
}
#[test]
fn a_cfg_attr_gated_struct_literal_initializer_stays_unresolved() {
let resolved = defaults_for(
r#"
pub struct Prefs {
pub max_depth: u32,
}
impl Default for Prefs {
fn default() -> Self {
Self {
#[cfg_attr(feature = "extras", allow(unused))]
max_depth: 9,
}
}
}
"#,
"Prefs",
&["max_depth"],
);
assert!(
matches!(resolved.as_slice(), [(name, DefaultValue::Unresolved(_))] if name == "max_depth"),
"cfg_attr hides an arbitrary attribute behind a condition and must stay refused; got {resolved:?}"
);
}
#[test]
fn duplicate_wasm32_cfg_arms_prefer_the_native_value() {
let resolved = defaults_for(
r#"
pub struct TesseractConfig {
pub psm: i32,
}
impl Default for TesseractConfig {
fn default() -> Self {
Self {
#[cfg(target_arch = "wasm32")]
psm: 6,
#[cfg(not(target_arch = "wasm32"))]
psm: 3,
}
}
}
"#,
"TesseractConfig",
&["psm"],
);
assert_eq!(
resolved,
vec![("psm".to_string(), DefaultValue::IntLiteral(3))],
"the native (non-wasm32) arm must win, deterministically, not whichever arm parses last"
);
}
#[test]
fn duplicate_wasm32_cfg_arms_prefer_the_native_value_regardless_of_source_order() {
let resolved = defaults_for(
r#"
pub struct TesseractConfig {
pub psm: i32,
}
impl Default for TesseractConfig {
fn default() -> Self {
Self {
#[cfg(not(target_arch = "wasm32"))]
psm: 3,
#[cfg(target_arch = "wasm32")]
psm: 6,
}
}
}
"#,
"TesseractConfig",
&["psm"],
);
assert_eq!(
resolved,
vec![("psm".to_string(), DefaultValue::IntLiteral(3))],
"source order must not decide the winner; got {resolved:?}"
);
}
#[test]
fn a_cfg_gated_initializer_beside_a_rest_base_stays_unresolved() {
let resolved = defaults_for(
r#"
pub struct Prefs {
pub max_depth: u32,
}
impl Default for Prefs {
fn default() -> Self {
Self {
#[cfg(feature = "extras")]
max_depth: 9,
..Prefs::base()
}
}
}
"#,
"Prefs",
&["max_depth"],
);
assert!(
matches!(resolved.as_slice(), [(name, DefaultValue::Unresolved(_))] if name == "max_depth"),
"a rest base can supply the field in the build where the cfg is off, so the gated \
initializer is not the only source and must not be read; got {resolved:?}"
);
}
#[test]
fn an_ungated_initializer_beside_a_rest_base_still_resolves() {
let resolved = defaults_for(
r#"
pub struct Prefs {
pub width: u32,
}
impl Default for Prefs {
fn default() -> Self {
Self {
width: 2,
..Prefs::base()
}
}
}
"#,
"Prefs",
&["width"],
);
assert_eq!(
resolved,
vec![("width".to_string(), DefaultValue::IntLiteral(2))],
"an explicit ungated initializer overrides the base in every build; got {resolved:?}"
);
}