summaryrefslogtreecommitdiffstats
path: root/third_party/rust/darling/tests
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/rust/darling/tests
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/darling/tests')
-rw-r--r--third_party/rust/darling/tests/accrue_errors.rs102
-rw-r--r--third_party/rust/darling/tests/compile-fail/default_expr_wrong_type.rs12
-rw-r--r--third_party/rust/darling/tests/compile-fail/default_expr_wrong_type.stderr21
-rw-r--r--third_party/rust/darling/tests/compile-fail/not_impl_from_meta.rs16
-rw-r--r--third_party/rust/darling/tests/compile-fail/not_impl_from_meta.stderr33
-rw-r--r--third_party/rust/darling/tests/compile-fail/skip_field_not_impl_default.rs18
-rw-r--r--third_party/rust/darling/tests/compile-fail/skip_field_not_impl_default.stderr21
-rw-r--r--third_party/rust/darling/tests/compiletests.rs16
-rw-r--r--third_party/rust/darling/tests/computed_bound.rs42
-rw-r--r--third_party/rust/darling/tests/custom_bound.rs25
-rw-r--r--third_party/rust/darling/tests/defaults.rs189
-rw-r--r--third_party/rust/darling/tests/enums_newtype.rs90
-rw-r--r--third_party/rust/darling/tests/enums_struct.rs15
-rw-r--r--third_party/rust/darling/tests/enums_unit.rs14
-rw-r--r--third_party/rust/darling/tests/error.rs54
-rw-r--r--third_party/rust/darling/tests/from_generics.rs175
-rw-r--r--third_party/rust/darling/tests/from_meta.rs66
-rw-r--r--third_party/rust/darling/tests/from_type_param.rs59
-rw-r--r--third_party/rust/darling/tests/from_type_param_default.rs53
-rw-r--r--third_party/rust/darling/tests/from_variant.rs57
-rw-r--r--third_party/rust/darling/tests/generics.rs23
-rw-r--r--third_party/rust/darling/tests/happy_path.rs69
-rw-r--r--third_party/rust/darling/tests/hash_map.rs42
-rw-r--r--third_party/rust/darling/tests/multiple.rs30
-rw-r--r--third_party/rust/darling/tests/newtype.rs26
-rw-r--r--third_party/rust/darling/tests/skip.rs74
-rw-r--r--third_party/rust/darling/tests/split_declaration.rs67
-rw-r--r--third_party/rust/darling/tests/suggestions.rs29
-rw-r--r--third_party/rust/darling/tests/supports.rs90
-rw-r--r--third_party/rust/darling/tests/unsupported_attributes.rs49
30 files changed, 1577 insertions, 0 deletions
diff --git a/third_party/rust/darling/tests/accrue_errors.rs b/third_party/rust/darling/tests/accrue_errors.rs
new file mode 100644
index 0000000000..e8799c43cb
--- /dev/null
+++ b/third_party/rust/darling/tests/accrue_errors.rs
@@ -0,0 +1,102 @@
+#![allow(dead_code)]
+//! These tests verify that multiple errors will be collected up from throughout
+//! the parsing process and returned correctly to the caller.
+
+use darling::{ast, FromDeriveInput, FromField, FromMeta};
+use syn::parse_quote;
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(attributes(accrue))]
+struct Lorem {
+ ipsum: String,
+ dolor: Dolor,
+ data: ast::Data<(), LoremField>,
+}
+
+#[derive(Debug, FromMeta)]
+struct Dolor {
+ sit: bool,
+}
+
+#[derive(Debug, FromField)]
+#[darling(attributes(accrue))]
+struct LoremField {
+ ident: Option<syn::Ident>,
+ aliased_as: syn::Ident,
+}
+
+#[test]
+fn bad_type_and_missing_fields() {
+ let input = parse_quote! {
+ #[accrue(ipsum = true, dolor(amet = "Hi"))]
+ pub struct NonConforming {
+ foo: ()
+ }
+ };
+
+ let s_result: ::darling::Error = Lorem::from_derive_input(&input).unwrap_err();
+ let err = s_result.flatten();
+ println!("{}", err);
+ assert_eq!(3, err.len());
+}
+
+#[test]
+fn body_only_issues() {
+ let input = parse_quote! {
+ #[accrue(ipsum = "Hello", dolor(sit))]
+ pub struct NonConforming {
+ foo: (),
+ bar: bool,
+ }
+ };
+
+ let s_err = Lorem::from_derive_input(&input).unwrap_err();
+ println!("{:?}", s_err);
+ assert_eq!(2, s_err.len());
+}
+
+#[derive(Debug, FromMeta)]
+enum Week {
+ Monday,
+ Tuesday { morning: bool, afternoon: String },
+ Wednesday(Dolor),
+}
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(attributes(accrue))]
+struct Month {
+ schedule: Week,
+}
+
+#[test]
+fn error_in_enum_fields() {
+ let input = parse_quote! {
+ #[accrue(schedule(tuesday(morning = "yes")))]
+ pub struct NonConforming {
+ foo: (),
+ bar: bool,
+ }
+ };
+
+ let s_err = Month::from_derive_input(&input).unwrap_err();
+ assert_eq!(2, s_err.len());
+ let err = s_err.flatten();
+ // TODO add tests to check location path is correct
+ println!("{}", err);
+}
+
+#[test]
+fn error_in_newtype_variant() {
+ let input = parse_quote! {
+ #[accrue(schedule(wednesday(sit = "yes")))]
+ pub struct NonConforming {
+ foo: (),
+ bar: bool,
+ }
+ };
+
+ let s_err = Month::from_derive_input(&input).unwrap_err();
+ assert_eq!(1, s_err.len());
+ println!("{}", s_err);
+ println!("{}", s_err.flatten());
+}
diff --git a/third_party/rust/darling/tests/compile-fail/default_expr_wrong_type.rs b/third_party/rust/darling/tests/compile-fail/default_expr_wrong_type.rs
new file mode 100644
index 0000000000..cd9a0fd1ee
--- /dev/null
+++ b/third_party/rust/darling/tests/compile-fail/default_expr_wrong_type.rs
@@ -0,0 +1,12 @@
+use darling::FromMeta;
+
+#[derive(FromMeta)]
+struct Receiver {
+ #[darling(default = "usize::default")]
+ not_u32: String,
+
+ #[darling(multiple, default = "usize::default")]
+ also_not_u32: Vec<String>,
+}
+
+fn main() {}
diff --git a/third_party/rust/darling/tests/compile-fail/default_expr_wrong_type.stderr b/third_party/rust/darling/tests/compile-fail/default_expr_wrong_type.stderr
new file mode 100644
index 0000000000..a8b7c502bf
--- /dev/null
+++ b/third_party/rust/darling/tests/compile-fail/default_expr_wrong_type.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+ --> tests/compile-fail/default_expr_wrong_type.rs:5:25
+ |
+5 | #[darling(default = "usize::default")]
+ | ^^^^^^^^^^^^^^^^ expected struct `String`, found `usize`
+ |
+help: try using a conversion method
+ |
+5 | #[darling(default = "usize::default".to_string())]
+ | ++++++++++++
+5 | #[darling(default = "usize::default".to_string())]
+ | ++++++++++++
+
+error[E0308]: mismatched types
+ --> tests/compile-fail/default_expr_wrong_type.rs:8:35
+ |
+8 | #[darling(multiple, default = "usize::default")]
+ | ^^^^^^^^^^^^^^^^ expected struct `Vec`, found `usize`
+ |
+ = note: expected struct `Vec<String>`
+ found type `usize`
diff --git a/third_party/rust/darling/tests/compile-fail/not_impl_from_meta.rs b/third_party/rust/darling/tests/compile-fail/not_impl_from_meta.rs
new file mode 100644
index 0000000000..f27d716391
--- /dev/null
+++ b/third_party/rust/darling/tests/compile-fail/not_impl_from_meta.rs
@@ -0,0 +1,16 @@
+use darling::FromMeta;
+
+struct NotImplFm;
+
+#[derive(FromMeta)]
+struct OuterFm {
+ inner: NotImplFm,
+}
+
+#[derive(darling::FromDeriveInput)]
+#[darling(attributes(hello))]
+struct OuterFdi {
+ inner: NotImplFm,
+}
+
+fn main() {}
diff --git a/third_party/rust/darling/tests/compile-fail/not_impl_from_meta.stderr b/third_party/rust/darling/tests/compile-fail/not_impl_from_meta.stderr
new file mode 100644
index 0000000000..a166a6fcff
--- /dev/null
+++ b/third_party/rust/darling/tests/compile-fail/not_impl_from_meta.stderr
@@ -0,0 +1,33 @@
+error[E0277]: the trait bound `NotImplFm: FromMeta` is not satisfied
+ --> tests/compile-fail/not_impl_from_meta.rs:7:12
+ |
+7 | inner: NotImplFm,
+ | ^^^^^^^^^ the trait `FromMeta` is not implemented for `NotImplFm`
+ |
+ = help: the following other types implement trait `FromMeta`:
+ ()
+ Arc<T>
+ AtomicBool
+ ExprArray
+ ExprPath
+ Flag
+ HashMap<String, V, S>
+ HashMap<proc_macro2::Ident, V, S>
+ and $N others
+
+error[E0277]: the trait bound `NotImplFm: FromMeta` is not satisfied
+ --> tests/compile-fail/not_impl_from_meta.rs:13:12
+ |
+13 | inner: NotImplFm,
+ | ^^^^^^^^^ the trait `FromMeta` is not implemented for `NotImplFm`
+ |
+ = help: the following other types implement trait `FromMeta`:
+ ()
+ Arc<T>
+ AtomicBool
+ ExprArray
+ ExprPath
+ Flag
+ HashMap<String, V, S>
+ HashMap<proc_macro2::Ident, V, S>
+ and $N others
diff --git a/third_party/rust/darling/tests/compile-fail/skip_field_not_impl_default.rs b/third_party/rust/darling/tests/compile-fail/skip_field_not_impl_default.rs
new file mode 100644
index 0000000000..f0d44c7798
--- /dev/null
+++ b/third_party/rust/darling/tests/compile-fail/skip_field_not_impl_default.rs
@@ -0,0 +1,18 @@
+use darling::FromMeta;
+
+#[derive(FromMeta)]
+struct NoDefault(String);
+
+#[derive(FromMeta)]
+struct Recevier {
+ #[darling(skip)]
+ skipped: NoDefault,
+
+ #[darling(skip = true)]
+ explicitly_skipped: NoDefault,
+
+ #[darling(skip = false)]
+ not_skipped_no_problem: NoDefault,
+}
+
+fn main() {}
diff --git a/third_party/rust/darling/tests/compile-fail/skip_field_not_impl_default.stderr b/third_party/rust/darling/tests/compile-fail/skip_field_not_impl_default.stderr
new file mode 100644
index 0000000000..de46982c24
--- /dev/null
+++ b/third_party/rust/darling/tests/compile-fail/skip_field_not_impl_default.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `NoDefault: std::default::Default` is not satisfied
+ --> tests/compile-fail/skip_field_not_impl_default.rs:8:15
+ |
+8 | #[darling(skip)]
+ | ^^^^ the trait `std::default::Default` is not implemented for `NoDefault`
+ |
+help: consider annotating `NoDefault` with `#[derive(Default)]`
+ |
+4 | #[derive(Default)]
+ |
+
+error[E0277]: the trait bound `NoDefault: std::default::Default` is not satisfied
+ --> tests/compile-fail/skip_field_not_impl_default.rs:11:22
+ |
+11 | #[darling(skip = true)]
+ | ^^^^ the trait `std::default::Default` is not implemented for `NoDefault`
+ |
+help: consider annotating `NoDefault` with `#[derive(Default)]`
+ |
+4 | #[derive(Default)]
+ |
diff --git a/third_party/rust/darling/tests/compiletests.rs b/third_party/rust/darling/tests/compiletests.rs
new file mode 100644
index 0000000000..00a5b3296f
--- /dev/null
+++ b/third_party/rust/darling/tests/compiletests.rs
@@ -0,0 +1,16 @@
+#![cfg(compiletests)]
+
+#[rustversion::stable(1.65)]
+#[test]
+fn compile_test() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/compile-fail/*.rs");
+}
+
+#[rustversion::not(stable(1.65))]
+#[test]
+fn wrong_rustc_version() {
+ panic!(
+ "This is not the expected version of rustc. Error messages vary across compiler versions so tests may produce spurious errors"
+ );
+}
diff --git a/third_party/rust/darling/tests/computed_bound.rs b/third_party/rust/darling/tests/computed_bound.rs
new file mode 100644
index 0000000000..abdb1022c1
--- /dev/null
+++ b/third_party/rust/darling/tests/computed_bound.rs
@@ -0,0 +1,42 @@
+use darling::{FromDeriveInput, FromMeta};
+
+fn parse<T: FromDeriveInput>(src: &str) -> T {
+ let ast = syn::parse_str(src).unwrap();
+ FromDeriveInput::from_derive_input(&ast).unwrap()
+}
+
+#[derive(FromMeta, PartialEq, Eq, Debug)]
+enum Volume {
+ Whisper,
+ Talk,
+ Shout,
+}
+
+#[derive(FromDeriveInput)]
+#[darling(attributes(speak))]
+struct SpeakingOptions<T: Default, U> {
+ max_volume: U,
+ #[darling(skip)]
+ #[allow(dead_code)]
+ additional_data: T,
+}
+
+#[derive(Default)]
+struct Phoneme {
+ #[allow(dead_code)]
+ first: String,
+}
+
+#[test]
+fn skipped_field() {
+ let parsed: SpeakingOptions<Phoneme, Volume> = parse(
+ r#"
+ #[derive(Speak)]
+ #[speak(max_volume = "shout")]
+ enum HtmlElement {
+ Div(String)
+ }
+ "#,
+ );
+ assert_eq!(parsed.max_volume, Volume::Shout);
+}
diff --git a/third_party/rust/darling/tests/custom_bound.rs b/third_party/rust/darling/tests/custom_bound.rs
new file mode 100644
index 0000000000..312f147805
--- /dev/null
+++ b/third_party/rust/darling/tests/custom_bound.rs
@@ -0,0 +1,25 @@
+#![allow(dead_code)]
+
+use std::ops::Add;
+
+use darling::{FromDeriveInput, FromMeta};
+
+#[derive(Debug, Clone, FromMeta)]
+#[darling(bound = "T: FromMeta + Add")]
+struct Wrapper<T>(pub T);
+
+impl<T: Add> Add for Wrapper<T> {
+ type Output = Wrapper<<T as Add>::Output>;
+ fn add(self, rhs: Self) -> Wrapper<<T as Add>::Output> {
+ Wrapper(self.0 + rhs.0)
+ }
+}
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(attributes(hello), bound = "Wrapper<T>: Add, T: FromMeta")]
+struct Foo<T> {
+ lorem: Wrapper<T>,
+}
+
+#[test]
+fn expansion() {}
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());
+ }
+}
diff --git a/third_party/rust/darling/tests/enums_newtype.rs b/third_party/rust/darling/tests/enums_newtype.rs
new file mode 100644
index 0000000000..c2c4ec933f
--- /dev/null
+++ b/third_party/rust/darling/tests/enums_newtype.rs
@@ -0,0 +1,90 @@
+use darling::{FromDeriveInput, FromMeta};
+use syn::parse_quote;
+
+#[derive(Debug, Default, PartialEq, Eq, FromMeta)]
+#[darling(default)]
+pub struct Amet {
+ hello: bool,
+ world: String,
+}
+
+#[derive(Debug, PartialEq, Eq, FromMeta)]
+#[darling(rename_all = "snake_case")]
+pub enum Lorem {
+ Ipsum(bool),
+ Dolor(String),
+ Sit(Amet),
+}
+
+#[derive(Debug, PartialEq, Eq, FromDeriveInput)]
+#[darling(attributes(hello))]
+pub struct Holder {
+ lorem: Lorem,
+}
+
+impl PartialEq<Lorem> for Holder {
+ fn eq(&self, other: &Lorem) -> bool {
+ self.lorem == *other
+ }
+}
+
+#[test]
+fn bool_word() {
+ let di = parse_quote! {
+ #[hello(lorem(ipsum))]
+ pub struct Bar;
+ };
+
+ let pr = Holder::from_derive_input(&di).unwrap();
+ assert_eq!(pr, Lorem::Ipsum(true));
+}
+
+#[test]
+fn bool_literal() {
+ let di = parse_quote! {
+ #[hello(lorem(ipsum = false))]
+ pub struct Bar;
+ };
+
+ let pr = Holder::from_derive_input(&di).unwrap();
+ assert_eq!(pr, Lorem::Ipsum(false));
+}
+
+#[test]
+fn string_literal() {
+ let di = parse_quote! {
+ #[hello(lorem(dolor = "Hello"))]
+ pub struct Bar;
+ };
+
+ let pr = Holder::from_derive_input(&di).unwrap();
+ assert_eq!(pr, Lorem::Dolor("Hello".to_string()));
+}
+
+#[test]
+fn struct_nested() {
+ let di = parse_quote! {
+ #[hello(lorem(sit(world = "Hello", hello = false)))]
+ pub struct Bar;
+ };
+
+ let pr = Holder::from_derive_input(&di).unwrap();
+ assert_eq!(
+ pr,
+ Lorem::Sit(Amet {
+ hello: false,
+ world: "Hello".to_string(),
+ })
+ );
+}
+
+#[test]
+#[should_panic]
+fn format_mismatch() {
+ let di = parse_quote! {
+ #[hello(lorem(dolor(world = "Hello", hello = false)))]
+ pub struct Bar;
+ };
+
+ Holder::from_derive_input(&di).unwrap();
+}
diff --git a/third_party/rust/darling/tests/enums_struct.rs b/third_party/rust/darling/tests/enums_struct.rs
new file mode 100644
index 0000000000..cae4cd5cdc
--- /dev/null
+++ b/third_party/rust/darling/tests/enums_struct.rs
@@ -0,0 +1,15 @@
+#![allow(dead_code)]
+
+//! Test expansion of enums which have struct variants.
+
+use darling::FromMeta;
+#[derive(Debug, FromMeta)]
+#[darling(rename_all = "snake_case")]
+enum Message {
+ Hello { user: String, silent: bool },
+ Ping,
+ Goodbye { user: String },
+}
+
+#[test]
+fn expansion() {}
diff --git a/third_party/rust/darling/tests/enums_unit.rs b/third_party/rust/darling/tests/enums_unit.rs
new file mode 100644
index 0000000000..34e0135657
--- /dev/null
+++ b/third_party/rust/darling/tests/enums_unit.rs
@@ -0,0 +1,14 @@
+//! Test expansion of enum variants which have no associated data.
+
+use darling::FromMeta;
+
+#[derive(Debug, FromMeta)]
+#[darling(rename_all = "snake_case")]
+enum Pattern {
+ Owned,
+ Immutable,
+ Mutable,
+}
+
+#[test]
+fn expansion() {}
diff --git a/third_party/rust/darling/tests/error.rs b/third_party/rust/darling/tests/error.rs
new file mode 100644
index 0000000000..7274e40894
--- /dev/null
+++ b/third_party/rust/darling/tests/error.rs
@@ -0,0 +1,54 @@
+//! In case of bad input, parsing should fail. The error should have locations set in derived implementations.
+
+// The use of fields in debug print commands does not count as "used",
+// which causes the fields to trigger an unwanted dead code warning.
+#![allow(dead_code)]
+
+use darling::{FromDeriveInput, FromMeta};
+use syn::parse_quote;
+
+#[derive(Debug, FromMeta)]
+struct Dolor {
+ #[darling(rename = "amet")]
+ sit: bool,
+ world: bool,
+}
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(from_ident, attributes(hello))]
+struct Lorem {
+ ident: syn::Ident,
+ ipsum: Dolor,
+}
+
+impl From<syn::Ident> for Lorem {
+ fn from(ident: syn::Ident) -> Self {
+ Lorem {
+ ident,
+ ipsum: Dolor {
+ sit: false,
+ world: true,
+ },
+ }
+ }
+}
+
+#[test]
+fn parsing_fail() {
+ let di = parse_quote! {
+ #[hello(ipsum(amet = "yes", world = false))]
+ pub struct Foo;
+ };
+
+ println!("{}", Lorem::from_derive_input(&di).unwrap_err());
+}
+
+#[test]
+fn missing_field() {
+ let di = parse_quote! {
+ #[hello(ipsum(amet = true))]
+ pub struct Foo;
+ };
+
+ println!("{}", Lorem::from_derive_input(&di).unwrap_err());
+}
diff --git a/third_party/rust/darling/tests/from_generics.rs b/third_party/rust/darling/tests/from_generics.rs
new file mode 100644
index 0000000000..e2cc99eecc
--- /dev/null
+++ b/third_party/rust/darling/tests/from_generics.rs
@@ -0,0 +1,175 @@
+//! Tests for `FromGenerics`, and - indirectly - `FromGenericParam`.
+//! These tests assume `FromTypeParam` is working and only look at whether the wrappers for magic
+//! fields are working as expected.
+
+use darling::{
+ ast::{self, GenericParamExt},
+ util::{Ignored, WithOriginal},
+ FromDeriveInput, FromTypeParam, Result,
+};
+
+#[derive(FromDeriveInput)]
+#[darling(attributes(lorem))]
+struct MyReceiver {
+ pub generics: ast::Generics<ast::GenericParam<MyTypeParam>>,
+}
+
+#[derive(FromTypeParam)]
+#[darling(attributes(lorem))]
+struct MyTypeParam {
+ pub ident: syn::Ident,
+ #[darling(default)]
+ pub foo: bool,
+ pub bar: Option<String>,
+}
+
+fn fdi<T: FromDeriveInput>(src: &str) -> Result<T> {
+ FromDeriveInput::from_derive_input(&syn::parse_str(src).expect("Source parses"))
+}
+
+/// Verify that `ast::Generics` is populated correctly when there is no generics declaration
+#[test]
+fn no_generics() {
+ let rec: MyReceiver = fdi("struct Baz;").expect("Input is well-formed");
+ assert!(rec.generics.where_clause.is_none());
+ assert_eq!(rec.generics.params.len(), 0);
+}
+
+#[test]
+#[allow(clippy::bool_assert_comparison)]
+fn expand_some() {
+ let rec: MyReceiver = fdi(r#"
+ struct Baz<
+ 'a,
+ #[lorem(foo)] T,
+ #[lorem(bar = "x")] U: Eq + ?Sized
+ >(&'a T, U);
+ "#)
+ .expect("Input is well-formed");
+ assert!(rec.generics.where_clause.is_none());
+
+ // Make sure we've preserved the lifetime param, though we don't do anything with it.
+ assert!(rec.generics.params[0].as_lifetime_param().is_some());
+
+ let mut ty_param_iter = rec.generics.type_params();
+
+ let first = ty_param_iter
+ .next()
+ .expect("type_params should not be empty");
+ assert!(first.bar.is_none());
+ assert!(first.foo);
+ assert_eq!(first.ident, "T");
+
+ let second = ty_param_iter
+ .next()
+ .expect("type_params should have a second value");
+ assert_eq!(
+ second
+ .bar
+ .as_ref()
+ .expect("Second type param should set bar"),
+ "x"
+ );
+ assert_eq!(second.foo, false);
+ assert_eq!(second.ident, "U");
+}
+
+/// Verify ≤0.4.1 behavior - where `generics` had to be `syn::Generics` - keeps working.
+#[test]
+fn passthrough() {
+ #[derive(FromDeriveInput)]
+ struct PassthroughReceiver {
+ pub generics: syn::Generics,
+ }
+
+ let rec: PassthroughReceiver = fdi(r#"
+ struct Baz<
+ 'a,
+ #[lorem(foo)] T,
+ #[lorem(bar = "x")] U: Eq + ?Sized
+ >(&'a T, U);
+ "#)
+ .expect("Input is well-formed");
+
+ let mut type_param_iter = rec.generics.type_params();
+ assert!(type_param_iter.next().is_some());
+}
+
+/// Verify that `where_clause` is passed through when it exists.
+/// As of 0.4.1, there is no `FromWhereClause` trait, so other types aren't supported
+/// for that field.
+#[test]
+fn where_clause() {
+ let rec: MyReceiver = fdi(r#"
+ struct Baz<
+ 'a,
+ #[lorem(foo)] T,
+ #[lorem(bar = "x")] U: Eq + ?Sized
+ >(&'a T, U) where T: Into<String>;
+ "#)
+ .expect("Input is well-formed");
+
+ assert!(rec.generics.where_clause.is_some());
+}
+
+/// Test that `WithOriginal` works for generics.
+#[test]
+fn with_original() {
+ #[derive(FromDeriveInput)]
+ struct WorigReceiver {
+ generics: WithOriginal<ast::Generics<ast::GenericParam<MyTypeParam>>, syn::Generics>,
+ }
+
+ let rec: WorigReceiver = fdi(r#"
+ struct Baz<
+ 'a,
+ #[lorem(foo)] T,
+ #[lorem(bar = "x")] U: Eq + ?Sized
+ >(&'a T, U) where T: Into<String>;
+ "#)
+ .expect("Input is well-formed");
+
+ // Make sure we haven't lost anything in the conversion
+ assert_eq!(rec.generics.parsed.params.len(), 3);
+ assert_eq!(rec.generics.original.params.len(), 3);
+
+ let parsed_t: &MyTypeParam = rec.generics.parsed.params[1]
+ .as_type_param()
+ .expect("Second argument should be type param");
+
+ // Make sure the first type param in each case is T
+ assert_eq!(parsed_t.ident, "T");
+ assert_eq!(
+ rec.generics
+ .original
+ .type_params()
+ .next()
+ .expect("First type param should exist")
+ .ident,
+ "T"
+ );
+
+ // Make sure we actually parsed the first type param
+ assert!(parsed_t.foo);
+ assert!(parsed_t.bar.is_none());
+}
+
+/// Make sure generics can be ignored
+#[test]
+fn ignored() {
+ #[derive(FromDeriveInput)]
+ struct IgnoredReceiver {
+ generics: Ignored,
+ }
+
+ let rec: IgnoredReceiver = fdi(r#"
+ struct Baz<
+ 'a,
+ #[lorem(foo)] T,
+ #[lorem(bar = "x")] U: Eq + ?Sized
+ >(&'a T, U) where T: Into<String>;
+ "#)
+ .expect("Input is well-formed");
+
+ assert_eq!(Ignored, rec.generics);
+}
diff --git a/third_party/rust/darling/tests/from_meta.rs b/third_party/rust/darling/tests/from_meta.rs
new file mode 100644
index 0000000000..3e7278cec8
--- /dev/null
+++ b/third_party/rust/darling/tests/from_meta.rs
@@ -0,0 +1,66 @@
+use darling::{Error, FromMeta};
+use syn::parse_quote;
+
+#[derive(Debug, FromMeta)]
+struct Meta {
+ #[darling(default)]
+ meta1: Option<String>,
+ #[darling(default)]
+ meta2: bool,
+}
+
+#[test]
+fn nested_meta_meta_value() {
+ let meta = Meta::from_list(&[parse_quote! {
+ meta1 = "thefeature"
+ }])
+ .unwrap();
+ assert_eq!(meta.meta1, Some("thefeature".to_string()));
+ assert!(!meta.meta2);
+}
+
+#[test]
+fn nested_meta_meta_bool() {
+ let meta = Meta::from_list(&[parse_quote! {
+ meta2
+ }])
+ .unwrap();
+ assert_eq!(meta.meta1, None);
+ assert!(meta.meta2);
+}
+
+#[test]
+fn nested_meta_lit_string_errors() {
+ let err = Meta::from_list(&[parse_quote! {
+ "meta2"
+ }])
+ .unwrap_err();
+ assert_eq!(
+ err.to_string(),
+ Error::unsupported_format("literal").to_string()
+ );
+}
+
+#[test]
+fn nested_meta_lit_integer_errors() {
+ let err = Meta::from_list(&[parse_quote! {
+ 2
+ }])
+ .unwrap_err();
+ assert_eq!(
+ err.to_string(),
+ Error::unsupported_format("literal").to_string()
+ );
+}
+
+#[test]
+fn nested_meta_lit_bool_errors() {
+ let err = Meta::from_list(&[parse_quote! {
+ true
+ }])
+ .unwrap_err();
+ assert_eq!(
+ err.to_string(),
+ Error::unsupported_format("literal").to_string()
+ );
+}
diff --git a/third_party/rust/darling/tests/from_type_param.rs b/third_party/rust/darling/tests/from_type_param.rs
new file mode 100644
index 0000000000..50ec3061e9
--- /dev/null
+++ b/third_party/rust/darling/tests/from_type_param.rs
@@ -0,0 +1,59 @@
+use darling::FromTypeParam;
+use syn::{parse_quote, DeriveInput, GenericParam, Ident, TypeParam};
+
+#[derive(FromTypeParam)]
+#[darling(attributes(lorem), from_ident)]
+struct Lorem {
+ ident: Ident,
+ bounds: Vec<syn::TypeParamBound>,
+ foo: bool,
+ bar: Option<String>,
+}
+
+impl From<Ident> for Lorem {
+ fn from(ident: Ident) -> Self {
+ Lorem {
+ ident,
+ foo: false,
+ bar: None,
+ bounds: Default::default(),
+ }
+ }
+}
+
+fn extract_type(param: &GenericParam) -> &TypeParam {
+ match *param {
+ GenericParam::Type(ref ty) => ty,
+ _ => unreachable!("Not a type param"),
+ }
+}
+
+#[test]
+#[allow(clippy::bool_assert_comparison)]
+fn expand_many() {
+ let di: DeriveInput = parse_quote! {
+ struct Baz<
+ #[lorem(foo)] T,
+ #[lorem(bar = "x")] U: Eq + ?Sized
+ >(T, U);
+ };
+
+ let params = di.generics.params;
+
+ {
+ let ty = extract_type(&params[0]);
+ let lorem = Lorem::from_type_param(ty).unwrap();
+ assert_eq!(lorem.ident, "T");
+ assert_eq!(lorem.foo, true);
+ assert_eq!(lorem.bar, None);
+ }
+
+ {
+ let ty = extract_type(&params[1]);
+ let lorem = Lorem::from_type_param(ty).unwrap();
+ assert_eq!(lorem.ident, "U");
+ assert_eq!(lorem.foo, false);
+ assert_eq!(lorem.bar, Some("x".to_string()));
+ assert_eq!(lorem.bounds.len(), 2);
+ }
+}
diff --git a/third_party/rust/darling/tests/from_type_param_default.rs b/third_party/rust/darling/tests/from_type_param_default.rs
new file mode 100644
index 0000000000..9d65665bb9
--- /dev/null
+++ b/third_party/rust/darling/tests/from_type_param_default.rs
@@ -0,0 +1,53 @@
+use darling::FromTypeParam;
+use syn::{parse_quote, DeriveInput, GenericParam, TypeParam};
+
+#[derive(Default, FromTypeParam)]
+#[darling(attributes(lorem), default)]
+struct Lorem {
+ foo: bool,
+ bar: Option<String>,
+ default: Option<syn::Type>,
+}
+
+fn extract_type(param: &GenericParam) -> &TypeParam {
+ match *param {
+ GenericParam::Type(ref ty) => ty,
+ _ => unreachable!("Not a type param"),
+ }
+}
+
+#[test]
+#[allow(clippy::bool_assert_comparison)]
+fn expand_many() {
+ let di: DeriveInput = parse_quote! {
+ struct Baz<
+ #[lorem(foo)] T,
+ #[lorem(bar = "x")] U: Eq + ?Sized,
+ #[lorem(foo = false)] V = (),
+ >(T, U, V);
+ };
+ let params = di.generics.params;
+
+ {
+ let ty = extract_type(&params[0]);
+ let lorem = Lorem::from_type_param(ty).unwrap();
+ assert_eq!(lorem.foo, true);
+ assert_eq!(lorem.bar, None);
+ }
+
+ {
+ let ty = extract_type(&params[1]);
+ let lorem = Lorem::from_type_param(ty).unwrap();
+ assert_eq!(lorem.foo, false);
+ assert_eq!(lorem.bar, Some("x".to_string()));
+ assert!(lorem.default.is_none());
+ }
+
+ {
+ let ty = extract_type(&params[2]);
+ let lorem = Lorem::from_type_param(ty).unwrap();
+ assert_eq!(lorem.foo, false);
+ assert_eq!(lorem.bar, None);
+ assert!(lorem.default.is_some());
+ }
+}
diff --git a/third_party/rust/darling/tests/from_variant.rs b/third_party/rust/darling/tests/from_variant.rs
new file mode 100644
index 0000000000..e89b8ff7f5
--- /dev/null
+++ b/third_party/rust/darling/tests/from_variant.rs
@@ -0,0 +1,57 @@
+use darling::FromVariant;
+use syn::{spanned::Spanned, Expr, ExprLit, LitInt};
+
+#[derive(FromVariant)]
+#[darling(from_ident, attributes(hello))]
+#[allow(dead_code)]
+pub struct Lorem {
+ ident: syn::Ident,
+ into: Option<bool>,
+ skip: Option<bool>,
+ discriminant: Option<syn::Expr>,
+ fields: darling::ast::Fields<syn::Type>,
+}
+
+impl From<syn::Ident> for Lorem {
+ fn from(ident: syn::Ident) -> Self {
+ Lorem {
+ ident,
+ into: Default::default(),
+ skip: Default::default(),
+ discriminant: None,
+ fields: darling::ast::Style::Unit.into(),
+ }
+ }
+}
+
+#[test]
+fn discriminant() {
+ let input: syn::DeriveInput = syn::parse_str(
+ r#"
+ pub enum Test {
+ Works = 1,
+ AlsoWorks = 2,
+ }
+ "#,
+ )
+ .unwrap();
+
+ let span = input.span();
+ if let syn::Data::Enum(enm) = input.data {
+ let lorem = Lorem::from_variant(
+ enm.variants
+ .first()
+ .expect("Hardcoded input has one variant"),
+ )
+ .expect("FromVariant can process the discriminant");
+ assert_eq!(
+ lorem.discriminant,
+ Some(Expr::Lit(ExprLit {
+ attrs: vec![],
+ lit: LitInt::new("1", span).into(),
+ }))
+ )
+ } else {
+ panic!("Data should be enum");
+ }
+}
diff --git a/third_party/rust/darling/tests/generics.rs b/third_party/rust/darling/tests/generics.rs
new file mode 100644
index 0000000000..ba65781fe3
--- /dev/null
+++ b/third_party/rust/darling/tests/generics.rs
@@ -0,0 +1,23 @@
+#![allow(dead_code)]
+
+use darling::{FromDeriveInput, FromMeta};
+use syn::parse_quote;
+
+#[derive(Debug, Clone, FromMeta)]
+struct Wrapper<T>(pub T);
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(attributes(hello))]
+struct Foo<T> {
+ lorem: Wrapper<T>,
+}
+
+#[test]
+fn expansion() {
+ let di = parse_quote! {
+ #[hello(lorem = "Hello")]
+ pub struct Foo;
+ };
+
+ Foo::<String>::from_derive_input(&di).unwrap();
+}
diff --git a/third_party/rust/darling/tests/happy_path.rs b/third_party/rust/darling/tests/happy_path.rs
new file mode 100644
index 0000000000..a56aee75fc
--- /dev/null
+++ b/third_party/rust/darling/tests/happy_path.rs
@@ -0,0 +1,69 @@
+use darling::{FromDeriveInput, FromMeta};
+use syn::parse_quote;
+
+#[derive(Default, FromMeta, PartialEq, Debug)]
+#[darling(default)]
+struct Lorem {
+ ipsum: bool,
+ dolor: Option<String>,
+}
+
+#[derive(FromDeriveInput, PartialEq, Debug)]
+#[darling(attributes(darling_demo))]
+struct Core {
+ ident: syn::Ident,
+ vis: syn::Visibility,
+ generics: syn::Generics,
+ lorem: Lorem,
+}
+
+#[derive(FromDeriveInput, PartialEq, Debug)]
+#[darling(attributes(darling_demo))]
+struct TraitCore {
+ ident: syn::Ident,
+ generics: syn::Generics,
+ lorem: Lorem,
+}
+
+#[test]
+fn simple() {
+ let di = parse_quote! {
+ #[derive(Foo)]
+ #[darling_demo(lorem(ipsum))]
+ pub struct Bar;
+ };
+
+ assert_eq!(
+ Core::from_derive_input(&di).unwrap(),
+ Core {
+ ident: parse_quote!(Bar),
+ vis: parse_quote!(pub),
+ generics: Default::default(),
+ lorem: Lorem {
+ ipsum: true,
+ dolor: None,
+ },
+ }
+ );
+}
+
+#[test]
+fn trait_type() {
+ let di = parse_quote! {
+ #[derive(Foo)]
+ #[darling_demo(lorem(dolor = "hello"))]
+ pub struct Bar;
+ };
+
+ assert_eq!(
+ TraitCore::from_derive_input(&di).unwrap(),
+ TraitCore {
+ ident: parse_quote!(Bar),
+ generics: Default::default(),
+ lorem: Lorem {
+ ipsum: false,
+ dolor: Some("hello".to_owned()),
+ }
+ }
+ );
+}
diff --git a/third_party/rust/darling/tests/hash_map.rs b/third_party/rust/darling/tests/hash_map.rs
new file mode 100644
index 0000000000..881cd1cf16
--- /dev/null
+++ b/third_party/rust/darling/tests/hash_map.rs
@@ -0,0 +1,42 @@
+use std::collections::HashMap;
+
+use darling::FromMeta;
+use syn::{parse_quote, Attribute, Path};
+
+#[derive(Debug, FromMeta, PartialEq, Eq)]
+struct MapValue {
+ name: String,
+ #[darling(default)]
+ option: bool,
+}
+
+#[test]
+fn parse_map() {
+ let attr: Attribute = parse_quote! {
+ #[foo(first(name = "Hello", option), the::second(name = "Second"))]
+ };
+
+ let meta = attr.meta;
+ let map: HashMap<Path, MapValue> = FromMeta::from_meta(&meta).unwrap();
+
+ let comparison: HashMap<Path, MapValue> = vec![
+ (
+ parse_quote!(first),
+ MapValue {
+ name: "Hello".into(),
+ option: true,
+ },
+ ),
+ (
+ parse_quote!(the::second),
+ MapValue {
+ name: "Second".into(),
+ option: false,
+ },
+ ),
+ ]
+ .into_iter()
+ .collect();
+
+ assert_eq!(comparison, map);
+}
diff --git a/third_party/rust/darling/tests/multiple.rs b/third_party/rust/darling/tests/multiple.rs
new file mode 100644
index 0000000000..b2243e62b6
--- /dev/null
+++ b/third_party/rust/darling/tests/multiple.rs
@@ -0,0 +1,30 @@
+use darling::{FromDeriveInput, FromMeta};
+use syn::parse_quote;
+
+#[derive(FromDeriveInput)]
+#[darling(attributes(hello))]
+#[allow(dead_code)]
+struct Lorem {
+ ident: syn::Ident,
+ ipsum: Ipsum,
+}
+
+#[derive(FromMeta)]
+struct Ipsum {
+ #[darling(multiple)]
+ dolor: Vec<String>,
+}
+
+#[test]
+fn expand_many() {
+ let di = parse_quote! {
+ #[hello(ipsum(dolor = "Hello", dolor = "World"))]
+ pub struct Baz;
+ };
+
+ let lorem: Lorem = Lorem::from_derive_input(&di).unwrap();
+ assert_eq!(
+ lorem.ipsum.dolor,
+ vec!["Hello".to_string(), "World".to_string()]
+ );
+}
diff --git a/third_party/rust/darling/tests/newtype.rs b/third_party/rust/darling/tests/newtype.rs
new file mode 100644
index 0000000000..10d0238882
--- /dev/null
+++ b/third_party/rust/darling/tests/newtype.rs
@@ -0,0 +1,26 @@
+//! A newtype struct should be able to derive `FromMeta` if its member implements it.
+
+use darling::{FromDeriveInput, FromMeta};
+use syn::parse_quote;
+
+#[derive(Debug, FromMeta, PartialEq, Eq)]
+struct Lorem(bool);
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(attributes(newtype))]
+struct DemoContainer {
+ lorem: Lorem,
+}
+
+#[test]
+fn generated() {
+ let di = parse_quote! {
+ #[derive(Baz)]
+ #[newtype(lorem = false)]
+ pub struct Foo;
+ };
+
+ let c = DemoContainer::from_derive_input(&di).unwrap();
+
+ assert_eq!(c.lorem, Lorem(false));
+}
diff --git a/third_party/rust/darling/tests/skip.rs b/third_party/rust/darling/tests/skip.rs
new file mode 100644
index 0000000000..f930ca5d31
--- /dev/null
+++ b/third_party/rust/darling/tests/skip.rs
@@ -0,0 +1,74 @@
+//! Test that skipped fields are not read into structs when they appear in input.
+
+use darling::{FromDeriveInput, FromMeta};
+use syn::parse_quote;
+
+#[derive(Debug, PartialEq, Eq, FromDeriveInput)]
+#[darling(attributes(skip_test))]
+pub struct Lorem {
+ ipsum: String,
+
+ #[darling(skip)]
+ dolor: u8,
+}
+
+/// Verify variant-level and field-level skip work correctly for enums.
+#[derive(Debug, FromMeta)]
+pub enum Sit {
+ Amet(bool),
+
+ #[darling(skip)]
+ Foo {
+ hello: bool,
+ },
+
+ Bar {
+ hello: bool,
+ #[darling(skip)]
+ world: u8,
+ },
+}
+
+#[test]
+fn verify_skipped_field_not_required() {
+ let di = parse_quote! {
+ #[skip_test(ipsum = "Hello")]
+ struct Baz;
+ };
+
+ assert_eq!(
+ Lorem::from_derive_input(&di).unwrap(),
+ Lorem {
+ ipsum: "Hello".to_string(),
+ dolor: 0,
+ }
+ );
+}
+
+/// This test verifies that a skipped field will still prefer an explicit default
+/// over the default that would come from its field type. It would be incorrect for
+/// `Defaulting::from_derive_input` to fail here, and it would be wrong for the value
+/// of `dolor` to be `None`.
+#[test]
+fn verify_default_supersedes_from_none() {
+ fn default_dolor() -> Option<u8> {
+ Some(2)
+ }
+
+ #[derive(Debug, PartialEq, Eq, FromDeriveInput)]
+ #[darling(attributes(skip_test))]
+ pub struct Defaulting {
+ #[darling(skip, default = "default_dolor")]
+ dolor: Option<u8>,
+ }
+
+ let di = parse_quote! {
+ #[skip_test]
+ struct Baz;
+ };
+
+ assert_eq!(
+ Defaulting::from_derive_input(&di).unwrap(),
+ Defaulting { dolor: Some(2) }
+ )
+}
diff --git a/third_party/rust/darling/tests/split_declaration.rs b/third_party/rust/darling/tests/split_declaration.rs
new file mode 100644
index 0000000000..8db11d0f03
--- /dev/null
+++ b/third_party/rust/darling/tests/split_declaration.rs
@@ -0,0 +1,67 @@
+//! When input is split across multiple attributes on one element,
+//! darling should collapse that into one struct.
+
+use darling::{Error, FromDeriveInput};
+use syn::parse_quote;
+
+#[derive(Debug, FromDeriveInput, PartialEq, Eq)]
+#[darling(attributes(split))]
+struct Lorem {
+ foo: String,
+ bar: bool,
+}
+
+#[test]
+fn split_attributes_accrue_to_instance() {
+ let di = parse_quote! {
+ #[split(foo = "Hello")]
+ #[split(bar)]
+ pub struct Foo;
+ };
+
+ let parsed = Lorem::from_derive_input(&di).unwrap();
+ assert_eq!(
+ parsed,
+ Lorem {
+ foo: "Hello".to_string(),
+ bar: true,
+ }
+ );
+}
+
+#[test]
+fn duplicates_across_split_attrs_error() {
+ let di = parse_quote! {
+ #[split(foo = "Hello")]
+ #[split(foo = "World", bar)]
+ pub struct Foo;
+ };
+
+ let pr = Lorem::from_derive_input(&di).unwrap_err();
+ assert!(pr.has_span());
+ assert_eq!(pr.to_string(), Error::duplicate_field("foo").to_string());
+}
+
+#[test]
+fn multiple_errors_accrue_to_instance() {
+ let di = parse_quote! {
+ #[split(foo = "Hello")]
+ #[split(foo = "World")]
+ pub struct Foo;
+ };
+
+ let pr = Lorem::from_derive_input(&di);
+ let err: Error = pr.unwrap_err();
+ assert_eq!(2, err.len());
+ let mut errs = err.into_iter().peekable();
+ assert_eq!(
+ errs.peek().unwrap().to_string(),
+ Error::duplicate_field("foo").to_string()
+ );
+ assert!(errs.next().unwrap().has_span());
+ assert_eq!(
+ errs.next().unwrap().to_string(),
+ Error::missing_field("bar").to_string()
+ );
+ assert!(errs.next().is_none());
+}
diff --git a/third_party/rust/darling/tests/suggestions.rs b/third_party/rust/darling/tests/suggestions.rs
new file mode 100644
index 0000000000..5baf76ca6c
--- /dev/null
+++ b/third_party/rust/darling/tests/suggestions.rs
@@ -0,0 +1,29 @@
+#![allow(dead_code)]
+#![cfg(feature = "suggestions")]
+
+use darling::{FromDeriveInput, FromMeta};
+use syn::parse_quote;
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(attributes(suggest))]
+struct Lorem {
+ ipsum: String,
+ dolor: Dolor,
+}
+
+#[derive(Debug, FromMeta)]
+struct Dolor {
+ sit: bool,
+}
+
+#[test]
+fn suggest_dolor() {
+ let input: syn::DeriveInput = parse_quote! {
+ #[suggest(ipsum = "Hello", dolorr(sit))]
+ pub struct Foo;
+ };
+
+ let result = Lorem::from_derive_input(&input).unwrap_err();
+ assert_eq!(2, result.len());
+ assert!(format!("{}", result).contains("Did you mean"));
+}
diff --git a/third_party/rust/darling/tests/supports.rs b/third_party/rust/darling/tests/supports.rs
new file mode 100644
index 0000000000..d6c7556722
--- /dev/null
+++ b/third_party/rust/darling/tests/supports.rs
@@ -0,0 +1,90 @@
+use darling::{ast, FromDeriveInput, FromVariant};
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(attributes(from_variants), supports(enum_any))]
+pub struct Container {
+ // The second type parameter can be anything that implements FromField, since
+ // FromDeriveInput will produce an error if given a struct.
+ data: ast::Data<Variant, ()>,
+}
+
+#[derive(Default, Debug, FromVariant)]
+#[darling(default, attributes(from_variants), supports(newtype, unit))]
+pub struct Variant {
+ into: Option<bool>,
+ skip: Option<bool>,
+}
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(attributes(from_struct), supports(struct_named))]
+pub struct StructContainer {
+ // The second type parameter can be anything that implements FromVariant, since
+ // FromDeriveInput will produce an error if given an enum.
+ data: ast::Data<(), syn::Field>,
+}
+
+mod source {
+ use syn::{parse_quote, DeriveInput};
+
+ pub fn newtype_enum() -> DeriveInput {
+ parse_quote! {
+ enum Hello {
+ World(bool),
+ String(String),
+ }
+ }
+ }
+
+ pub fn named_field_enum() -> DeriveInput {
+ parse_quote! {
+ enum Hello {
+ Foo(u16),
+ World {
+ name: String
+ },
+ }
+ }
+ }
+
+ pub fn empty_enum() -> DeriveInput {
+ parse_quote! {
+ enum Hello {}
+ }
+ }
+
+ pub fn named_struct() -> DeriveInput {
+ parse_quote! {
+ struct Hello {
+ world: bool,
+ }
+ }
+ }
+
+ pub fn tuple_struct() -> DeriveInput {
+ parse_quote! { struct Hello(String, bool); }
+ }
+}
+
+#[test]
+fn enum_newtype_or_unit() {
+ // Should pass
+ let container = Container::from_derive_input(&source::newtype_enum()).unwrap();
+ assert!(container.data.is_enum());
+
+ // Should error
+ Container::from_derive_input(&source::named_field_enum()).unwrap_err();
+ Container::from_derive_input(&source::named_struct()).unwrap_err();
+}
+
+#[test]
+fn struct_named() {
+ // Should pass
+ let container = StructContainer::from_derive_input(&source::named_struct()).unwrap();
+ assert!(container.data.is_struct());
+
+ // Should fail
+ StructContainer::from_derive_input(&source::tuple_struct()).unwrap_err();
+ StructContainer::from_derive_input(&source::named_field_enum()).unwrap_err();
+ StructContainer::from_derive_input(&source::newtype_enum()).unwrap_err();
+ StructContainer::from_derive_input(&source::empty_enum()).unwrap_err();
+}
diff --git a/third_party/rust/darling/tests/unsupported_attributes.rs b/third_party/rust/darling/tests/unsupported_attributes.rs
new file mode 100644
index 0000000000..98b190d514
--- /dev/null
+++ b/third_party/rust/darling/tests/unsupported_attributes.rs
@@ -0,0 +1,49 @@
+use darling::FromDeriveInput;
+use syn::{parse_quote, Ident, LitStr, Path};
+
+#[derive(Debug, FromDeriveInput)]
+#[darling(supports(struct_unit), attributes(bar))]
+pub struct Bar {
+ pub ident: Ident,
+ pub st: Path,
+ pub file: LitStr,
+}
+
+/// Per [#96](https://github.com/TedDriggs/darling/issues/96), make sure that an
+/// attribute which isn't a valid meta gets an error.
+#[test]
+fn non_meta_attribute_gets_own_error() {
+ let di = parse_quote! {
+ #[derive(Bar)]
+ #[bar(file = "motors/example_6.csv", st = RocketEngine)]
+ pub struct EstesC6;
+ };
+
+ let errors: darling::Error = Bar::from_derive_input(&di).unwrap_err().flatten();
+ // The number of errors here is 1 for the bad value of the `st` attribute
+ assert_eq!(1, errors.len());
+ // Make sure one of the errors propagates the syn error
+ assert!(errors
+ .into_iter()
+ .any(|e| e.to_string().contains("expected lit")));
+}
+
+/// Properties can be split across multiple attributes; this test ensures that one
+/// non-meta attribute does not interfere with the parsing of other, well-formed attributes.
+#[test]
+fn non_meta_attribute_does_not_block_others() {
+ let di = parse_quote! {
+ #[derive(Bar)]
+ #[bar(st = RocketEngine)]
+ #[bar(file = "motors/example_6.csv")]
+ pub struct EstesC6;
+ };
+
+ let errors: darling::Error = Bar::from_derive_input(&di).unwrap_err().flatten();
+ // The number of errors here is 1 for the bad value of the `st` attribute
+ assert_eq!(1, errors.len());
+ // Make sure one of the errors propagates the syn error
+ assert!(errors
+ .into_iter()
+ .any(|e| e.to_string().contains("expected lit")));
+}