use super::*;
#[test]
fn scalar_assignment_after_the_literal_replaces_the_initial_value() {
let resolved = defaults_for(
r#"
pub struct Prefs { pub max_depth: u32 }
impl Default for Prefs {
fn default() -> Self {
let mut prefs = Self { max_depth: 0 };
prefs.max_depth = 9;
prefs
}
}
"#,
"Prefs",
&["max_depth"],
);
assert_eq!(
resolved,
vec![("max_depth".to_string(), DefaultValue::IntLiteral(9))],
"the assignment after the literal is the default; reading only the literal records 0"
);
}
#[test]
fn repeated_vec_push_becomes_a_list_literal_in_source_order() {
let resolved = defaults_for_typed(
r#"
pub struct Prefs { pub deny_list: Vec<String> }
impl Default for Prefs {
fn default() -> Self {
let mut prefs = Self { deny_list: Vec::new() };
prefs.deny_list.push("alpha".to_string());
prefs.deny_list.push("beta".to_string());
prefs
}
}
"#,
"Prefs",
&[("deny_list", TypeRef::Vec(Box::new(TypeRef::String)))],
);
assert_eq!(
resolved,
vec![(
"deny_list".to_string(),
DefaultValue::ListLiteral(vec![
DefaultValue::StringLiteral("alpha".to_string()),
DefaultValue::StringLiteral("beta".to_string()),
]),
)],
"pushed elements are the default; `Empty` would claim the vector is empty"
);
}
#[test]
fn vec_extend_appends_to_the_literals_own_elements() {
let resolved = defaults_for_typed(
r#"
pub struct Prefs { pub deny_list: Vec<String> }
impl Default for Prefs {
fn default() -> Self {
let mut prefs = Self { deny_list: vec!["alpha".to_string()] };
prefs.deny_list.extend(vec!["beta".to_string()]);
prefs
}
}
"#,
"Prefs",
&[("deny_list", TypeRef::Vec(Box::new(TypeRef::String)))],
);
assert_eq!(
resolved,
vec![(
"deny_list".to_string(),
DefaultValue::ListLiteral(vec![
DefaultValue::StringLiteral("alpha".to_string()),
DefaultValue::StringLiteral("beta".to_string()),
]),
)],
"extend appends to the literal's elements rather than discarding the extension"
);
}
#[test]
fn extending_with_an_empty_collection_leaves_the_field_at_its_literal_value() {
let resolved = defaults_for_typed(
r#"
pub struct Prefs { pub deny_list: Vec<String> }
impl Default for Prefs {
fn default() -> Self {
let mut prefs = Self { deny_list: Vec::new() };
prefs.deny_list.extend(vec![]);
prefs
}
}
"#,
"Prefs",
&[("deny_list", TypeRef::Vec(Box::new(TypeRef::String)))],
);
assert_eq!(
resolved,
vec![("deny_list".to_string(), DefaultValue::Empty)],
"an empty extension changes nothing, so the known-zero claim stays true"
);
}
#[test]
fn a_scalar_assignment_and_a_push_in_one_body_are_both_applied() {
let resolved = defaults_for_typed(
r#"
pub struct Prefs { pub max_depth: u32, pub deny_list: Vec<String> }
impl Default for Prefs {
fn default() -> Self {
let mut prefs = Self { max_depth: 0, deny_list: Vec::new() };
prefs.deny_list.push("alpha".to_string());
prefs.max_depth = 9;
prefs
}
}
"#,
"Prefs",
&[
("max_depth", TypeRef::Unit),
("deny_list", TypeRef::Vec(Box::new(TypeRef::String))),
],
);
assert_eq!(
resolved,
vec![
("max_depth".to_string(), DefaultValue::IntLiteral(9)),
(
"deny_list".to_string(),
DefaultValue::ListLiteral(vec![DefaultValue::StringLiteral("alpha".to_string())]),
),
],
"every mutation in the body applies, not just the ones of one kind"
);
}
#[test]
fn a_constructor_that_mutates_before_returning_is_read_through_the_delegation() {
let resolved = defaults_for_typed(
r#"
pub struct Prefs { pub limit: u32, pub tags: Vec<String> }
impl Prefs {
pub fn with_limit(limit: u32) -> Self {
let mut prefs = Self { limit: 0, tags: Vec::new() };
prefs.limit = limit;
prefs.tags.push("seed".to_string());
prefs
}
}
impl Default for Prefs {
fn default() -> Self { Self::with_limit(7) }
}
"#,
"Prefs",
&[
("limit", TypeRef::Unit),
("tags", TypeRef::Vec(Box::new(TypeRef::String))),
],
);
assert_eq!(
resolved,
vec![
("limit".to_string(), DefaultValue::IntLiteral(7)),
(
"tags".to_string(),
DefaultValue::ListLiteral(vec![DefaultValue::StringLiteral("seed".to_string())]),
),
],
"the delegated constructor's mutations count exactly as the default's own would"
);
}
#[test]
fn an_explicit_return_of_the_binding_is_read_like_a_bare_tail() {
let resolved = defaults_for(
r#"
pub struct Prefs { pub max_depth: u32 }
impl Default for Prefs {
fn default() -> Self {
let mut prefs = Self { max_depth: 0 };
prefs.max_depth = 3;
return prefs;
}
}
"#,
"Prefs",
&["max_depth"],
);
assert_eq!(
resolved,
vec![("max_depth".to_string(), DefaultValue::IntLiteral(3))],
"an explicit return of the binding does not hide the mutations before it"
);
}
#[test]
fn a_type_annotated_binding_is_read_the_same_as_an_untyped_one() {
let resolved = defaults_for(
r#"
pub struct Prefs { pub max_depth: u32 }
impl Default for Prefs {
fn default() -> Self {
let mut prefs: Self = Self { max_depth: 0 };
prefs.max_depth = 5;
prefs
}
}
"#,
"Prefs",
&["max_depth"],
);
assert_eq!(
resolved,
vec![("max_depth".to_string(), DefaultValue::IntLiteral(5))],
"`let prefs: Self = ..` binds the same value as `let prefs = ..`"
);
}
#[test]
fn a_binding_returned_without_mutations_keeps_the_literal_values() {
let resolved = defaults_for(
r#"
pub struct Prefs { pub max_depth: u32 }
impl Default for Prefs {
fn default() -> Self {
let prefs = Self { max_depth: 4 };
prefs
}
}
"#,
"Prefs",
&["max_depth"],
);
assert_eq!(
resolved,
vec![("max_depth".to_string(), DefaultValue::IntLiteral(4))],
"no mutation means the literal is the whole answer"
);
}
#[test]
fn a_plain_tail_struct_literal_is_unaffected() {
let resolved = defaults_for(
r#"
pub struct Prefs { pub max_depth: u32 }
impl Default for Prefs {
fn default() -> Self { Self { max_depth: 1 } }
}
"#,
"Prefs",
&["max_depth"],
);
assert_eq!(
resolved,
vec![("max_depth".to_string(), DefaultValue::IntLiteral(1))],
"the tail-literal reading must survive the mutation-aware reader"
);
}
#[test]
fn a_preceding_unrelated_let_before_a_tail_literal_is_unaffected() {
let resolved = defaults_for(
r#"
pub struct Prefs { pub max_depth: u32 }
impl Default for Prefs {
fn default() -> Self {
let ceiling = 5;
Self { max_depth: 1 }
}
}
"#,
"Prefs",
&["max_depth"],
);
assert_eq!(
resolved,
vec![("max_depth".to_string(), DefaultValue::IntLiteral(1))],
"the tail expression is what the function returns, whatever precedes it"
);
}
#[test]
fn a_return_inside_a_closure_does_not_poison_the_rest_of_the_body() {
let resolved = defaults_for_typed(
r#"
pub struct Prefs { pub max_depth: u32, pub hook: Hook }
impl Default for Prefs {
fn default() -> Self {
let mut prefs = Self { max_depth: 0, hook: Hook::None };
prefs.max_depth = 9;
prefs.hook = || { return 1; };
prefs
}
}
"#,
"Prefs",
&[
("max_depth", TypeRef::Unit),
("hook", TypeRef::Named("Hook".to_string())),
],
);
assert_eq!(
resolved[0],
("max_depth".to_string(), DefaultValue::IntLiteral(9)),
"a closure's own `return` is not an early return of `fn default()`"
);
assert!(
matches!(resolved[1].1, DefaultValue::Unresolved(_)),
"the closure is still an unreadable value, got {:?}",
resolved[1].1
);
}