summaryrefslogtreecommitdiffstats
path: root/third_party/rust/darling/tests/defaults.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/darling/tests/defaults.rs
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/darling/tests/defaults.rs')
-rw-r--r--third_party/rust/darling/tests/defaults.rs189
1 files changed, 189 insertions, 0 deletions
diff --git a/third_party/rust/darling/tests/defaults.rs b/third_party/rust/darling/tests/defaults.rs
new file mode 100644
index 0000000000..05ab1ed1db
--- /dev/null
+++ b/third_party/rust/darling/tests/defaults.rs
@@ -0,0 +1,189 @@
+use darling::FromDeriveInput;
+use syn::parse_quote;
+
+mod foo {
+ pub mod bar {
+ pub fn init() -> String {
+ String::from("hello")
+ }
+ }
+}
+
+#[derive(FromDeriveInput)]
+#[darling(attributes(speak))]
+pub struct SpeakerOpts {
+ #[darling(default = "foo::bar::init")]
+ first_word: String,
+}
+
+#[test]
+fn path_default() {
+ let speaker: SpeakerOpts = FromDeriveInput::from_derive_input(&parse_quote! {
+ struct Foo;
+ })
+ .expect("Unit struct with no attrs should parse");
+
+ assert_eq!(speaker.first_word, "hello");
+}
+
+/// Tests in this module capture the somewhat-confusing behavior observed when defaults
+/// are set at both the field and container level.
+///
+/// The general rule is that more-specific declarations preempt less-specific ones; this is
+/// unsurprising and allows for granular control over what happens when parsing an AST.
+mod stacked_defaults {
+ use darling::{FromDeriveInput, FromMeta};
+ use syn::parse_quote;
+
+ fn jane() -> String {
+ "Jane".into()
+ }
+
+ #[derive(FromMeta)]
+ #[darling(default)]
+ struct PersonName {
+ #[darling(default = "jane")]
+ first: String,
+ #[darling(default)]
+ middle: String,
+ last: String,
+ }
+
+ impl Default for PersonName {
+ fn default() -> Self {
+ Self {
+ first: "John".into(),
+ middle: "T".into(),
+ last: "Doe".into(),
+ }
+ }
+ }
+
+ #[derive(FromDeriveInput)]
+ #[darling(attributes(person))]
+ struct Person {
+ #[darling(default)]
+ name: PersonName,
+ age: u8,
+ }
+
+ #[test]
+ fn name_first_only() {
+ let person = Person::from_derive_input(&parse_quote! {
+ #[person(name(first = "Bill"), age = 5)]
+ struct Foo;
+ })
+ .unwrap();
+
+ assert_eq!(person.name.first, "Bill");
+ assert_eq!(
+ person.name.middle, "",
+ "Explicit field-level default should preempt container-level default"
+ );
+ assert_eq!(
+ person.name.last, "Doe",
+ "Absence of a field-level default falls back to container-level default"
+ );
+ }
+
+ /// This is the most surprising case. The presence of `name()` means we invoke
+ /// `PersonName::from_list(&[])`. When that finishes parsing each of the zero nested
+ /// items it has received, it will then start filling in missing fields, using the
+ /// explicit field-level defaults for `first` and `middle`, while for `last` it will
+ /// use the `last` field from the container-level default.
+ #[test]
+ fn name_empty_list() {
+ let person = Person::from_derive_input(&parse_quote! {
+ #[person(name(), age = 5)]
+ struct Foo;
+ })
+ .unwrap();
+
+ assert_eq!(person.name.first, "Jane");
+ assert_eq!(person.name.middle, "");
+ assert_eq!(person.name.last, "Doe");
+ }
+
+ #[test]
+ fn no_name() {
+ let person = Person::from_derive_input(&parse_quote! {
+ #[person(age = 5)]
+ struct Foo;
+ })
+ .unwrap();
+
+ assert_eq!(person.age, 5);
+ assert_eq!(
+ person.name.first, "John",
+ "If `name` is not specified, `Person`'s field-level default should be used"
+ );
+ assert_eq!(person.name.middle, "T");
+ assert_eq!(person.name.last, "Doe");
+ }
+}
+
+mod implicit_default {
+ use darling::{util::Flag, FromDeriveInput};
+ use syn::parse_quote;
+
+ // No use of `darling(default)` here at all!
+ // This struct will fill in missing fields using FromMeta::from_none.
+ #[derive(FromDeriveInput)]
+ #[darling(attributes(person))]
+ struct Person {
+ first_name: String,
+ last_name: Option<String>,
+ lefty: Flag,
+ }
+
+ #[test]
+ fn missing_fields_fill() {
+ let person = Person::from_derive_input(&parse_quote! {
+ #[person(first_name = "James")]
+ struct Foo;
+ })
+ .unwrap();
+
+ assert_eq!(person.first_name, "James");
+ assert_eq!(person.last_name, None);
+ assert!(!person.lefty.is_present());
+ }
+}
+
+/// Test that a field-level implicit default using FromMeta::from_none is superseded
+/// by the parent declaring `#[darling(default)]`.
+mod overridden_implicit_default {
+ use darling::{util::Flag, FromDeriveInput};
+ use syn::parse_quote;
+
+ #[derive(FromDeriveInput)]
+ #[darling(default, attributes(person))]
+ struct Person {
+ first_name: String,
+ last_name: Option<String>,
+ lefty: Flag,
+ }
+
+ impl Default for Person {
+ fn default() -> Self {
+ Self {
+ first_name: "Jane".into(),
+ last_name: Some("Doe".into()),
+ lefty: Flag::default(),
+ }
+ }
+ }
+
+ #[test]
+ fn fill_missing() {
+ let person = Person::from_derive_input(&parse_quote!(
+ #[person(last_name = "Archer")]
+ struct Foo;
+ ))
+ .unwrap();
+
+ assert_eq!(person.first_name, "Jane");
+ assert_eq!(person.last_name, Some("Archer".into()));
+ assert!(!person.lefty.is_present());
+ }
+}