chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

102
vendor/darling/tests/accrue_errors.rs vendored Normal file
View File

@@ -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());
}

80
vendor/darling/tests/attrs_with.rs vendored Normal file
View File

@@ -0,0 +1,80 @@
use std::collections::BTreeSet;
use darling::{util, Error, FromDeriveInput, Result};
use syn::{parse_quote, Attribute};
fn unique_idents(attrs: Vec<Attribute>) -> Result<BTreeSet<String>> {
let mut errors = Error::accumulator();
let idents = attrs
.into_iter()
.filter_map(|attr| {
let path = attr.path();
errors.handle(
path.get_ident()
.map(std::string::ToString::to_string)
.ok_or_else(|| {
Error::custom(format!("`{}` is not an ident", util::path_to_string(path)))
.with_span(path)
}),
)
})
.collect();
errors.finish_with(idents)
}
#[derive(FromDeriveInput)]
#[darling(attributes(a), forward_attrs)]
struct Receiver {
#[darling(with = unique_idents)]
attrs: BTreeSet<String>,
other: Option<bool>,
}
#[test]
fn succeeds_on_no_attrs() {
let di = Receiver::from_derive_input(&parse_quote! {
struct Demo;
})
.unwrap();
assert!(di.attrs.is_empty());
}
#[test]
fn succeeds_on_valid_input() {
let di = Receiver::from_derive_input(&parse_quote! {
#[allow(dead_code)]
/// testing
#[another]
struct Demo;
})
.unwrap();
assert_eq!(di.attrs.len(), 3);
assert!(di.attrs.contains("allow"));
assert!(di.attrs.contains("another"));
assert!(di.attrs.contains("doc"));
assert_eq!(di.other, None);
}
#[test]
fn errors_combined_with_others() {
let e = Receiver::from_derive_input(&parse_quote! {
#[path::to::attr(dead_code)]
#[a(other = 5)]
struct Demo;
})
.map(|_| "Should have failed")
.unwrap_err();
let error = e.to_string();
assert_eq!(e.len(), 2);
// Look for the error on the field `other`
assert!(error.contains("at other"));
// Look for the invalid path from attrs conversion
assert!(error.contains("`path::to::attr`"));
}

View File

@@ -0,0 +1,15 @@
use darling::FromDeriveInput;
use syn::Attribute;
fn bad_converter(attrs: Vec<Attribute>) -> Vec<Attribute> {
attrs
}
#[derive(FromDeriveInput)]
#[darling(forward_attrs)]
struct Receiver {
#[darling(with = bad_converter)]
attrs: Vec<Attribute>,
}
fn main() {}

View File

@@ -0,0 +1,20 @@
error[E0308]: mismatched types
--> tests/compile-fail/attrs_with_bad_fn.rs:11:22
|
11 | #[darling(with = bad_converter)]
| ^^^^^^^^^^^^^
| |
| expected `Result<_, Error>`, found `Vec<Attribute>`
| arguments to this method are incorrect
|
= note: expected enum `Result<_, darling::Error>`
found struct `Vec<Attribute>`
note: method defined here
--> core/src/error/mod.rs
|
| pub fn handle<T>(&mut self, result: Result<T>) -> Option<T> {
| ^^^^^^
help: try wrapping the expression in `Ok`
|
11 | #[darling(with = Ok(bad_converter))]
| +++ +

View File

@@ -0,0 +1,10 @@
use darling::FromDeriveInput;
use syn::{Attribute, Ident};
#[derive(FromDeriveInput)]
struct HelloArgs {
ident: Ident,
attrs: Vec<Attribute>,
}
fn main() {}

View File

@@ -0,0 +1,5 @@
error: field will not be populated because `forward_attrs` is not set on the struct
--> tests/compile-fail/attrs_without_forward_attrs.rs:7:5
|
7 | attrs: Vec<Attribute>,
| ^^^^^

View File

@@ -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() {}

View File

@@ -0,0 +1,16 @@
error[E0308]: mismatched types
--> tests/compile-fail/default_expr_wrong_type.rs:5:25
|
5 | #[darling(default = "usize::default")]
| ^^^^^^^^^^^^^^^^- help: try using a conversion method: `.to_string()`
| |
| expected `String`, found `usize`
error[E0308]: mismatched types
--> tests/compile-fail/default_expr_wrong_type.rs:8:35
|
8 | #[darling(multiple, default = "usize::default")]
| ^^^^^^^^^^^^^^^^ expected `Vec<String>`, found `usize`
|
= note: expected struct `Vec<String>`
found type `usize`

View File

@@ -0,0 +1,12 @@
use darling::FromMeta;
#[derive(FromMeta)]
enum Choice {
#[darling(word)]
A,
#[darling(word)]
B,
C,
}
fn main() {}

View File

@@ -0,0 +1,11 @@
error: `#[darling(word)]` can only be applied to one variant
--> tests/compile-fail/duplicate_word_across_variants.rs:5:15
|
5 | #[darling(word)]
| ^^^^
error: `#[darling(word)]` can only be applied to one variant
--> tests/compile-fail/duplicate_word_across_variants.rs:7:15
|
7 | #[darling(word)]
| ^^^^

View File

@@ -0,0 +1,10 @@
use darling::FromMeta;
#[derive(FromMeta)]
enum Choice {
#[darling(word, word)]
A,
B,
}
fn main() {}

View File

@@ -0,0 +1,5 @@
error: Duplicate field `word`
--> tests/compile-fail/duplicate_word_on_variant.rs:5:21
|
5 | #[darling(word, word)]
| ^^^^

View File

@@ -0,0 +1,21 @@
use darling::FromMeta;
#[derive(FromMeta)]
struct Inner {
left: String,
right: String,
}
#[derive(FromMeta)]
struct Outer {
#[darling(flatten, multiple, with = demo, skip = true)]
field: Inner,
}
#[derive(FromMeta)]
struct ThisIsFine {
#[darling(flatten, multiple = false)]
field: Inner,
}
fn main() {}

View File

@@ -0,0 +1,17 @@
error: `flatten` and `multiple` cannot be used together
--> tests/compile-fail/flatten_meta_conflicts.rs:11:24
|
11 | #[darling(flatten, multiple, with = demo, skip = true)]
| ^^^^^^^^
error: `flatten` and `with` cannot be used together
--> tests/compile-fail/flatten_meta_conflicts.rs:11:34
|
11 | #[darling(flatten, multiple, with = demo, skip = true)]
| ^^^^
error: `flatten` and `skip` cannot be used together
--> tests/compile-fail/flatten_meta_conflicts.rs:11:47
|
11 | #[darling(flatten, multiple, with = demo, skip = true)]
| ^^^^

View File

@@ -0,0 +1,28 @@
//! Test that multiple fields cannot be marked `flatten` at once.
use darling::{FromDeriveInput, FromMeta};
#[derive(FromMeta)]
struct Inner {
left: String,
right: String,
}
#[derive(FromMeta)]
pub struct Example {
#[darling(flatten)]
first: Inner,
#[darling(flatten)]
last: Inner,
}
#[derive(FromDeriveInput)]
pub struct FdiExample {
ident: syn::Ident,
#[darling(flatten)]
first: Inner,
#[darling(flatten)]
last: Inner,
}
fn main() {}

View File

@@ -0,0 +1,23 @@
error: `#[darling(flatten)]` can only be applied to one field
--> tests/compile-fail/flatten_multiple_fields.rs:13:15
|
13 | #[darling(flatten)]
| ^^^^^^^
error: `#[darling(flatten)]` can only be applied to one field
--> tests/compile-fail/flatten_multiple_fields.rs:15:15
|
15 | #[darling(flatten)]
| ^^^^^^^
error: `#[darling(flatten)]` can only be applied to one field
--> tests/compile-fail/flatten_multiple_fields.rs:22:15
|
22 | #[darling(flatten)]
| ^^^^^^^
error: `#[darling(flatten)]` can only be applied to one field
--> tests/compile-fail/flatten_multiple_fields.rs:24:15
|
24 | #[darling(flatten)]
| ^^^^^^^

View File

@@ -0,0 +1,30 @@
use darling::FromMeta;
// This usage of `from_word` is invalid because unit structs already generate a from_word
// method, and we don't allow using the from_word override when it conflicts with the macro's
// "normal" operation.
#[derive(FromMeta)]
#[darling(from_word = || Ok(Unit))]
struct Unit;
fn newtype_from_word() -> darling::Result<Newtype> {
Ok(Newtype(true))
}
// This usage of `from_word` is invalid because newtype structs call the inner type's `from_meta`
// directly from their `from_meta`, so the custom `from_word` will never be called in normal usage.
#[derive(FromMeta)]
#[darling(from_word = newtype_from_word)]
struct Newtype(bool);
#[derive(FromMeta)]
#[darling(from_word = || Ok(Wordy::Options { thing: "Hello".to_string() }))]
enum Wordy {
#[darling(word)]
Normal,
Options {
thing: String,
},
}
fn main() {}

View File

@@ -0,0 +1,17 @@
error: `from_word` cannot be used on unit structs because it conflicts with the generated impl
--> tests/compile-fail/from_word.rs:7:23
|
7 | #[darling(from_word = || Ok(Unit))]
| ^
error: `from_word` cannot be used on newtype structs because the implementation is entirely delegated to the inner type
--> tests/compile-fail/from_word.rs:17:23
|
17 | #[darling(from_word = newtype_from_word)]
| ^^^^^^^^^^^^^^^^^
error: `from_word` cannot be used with an enum that also uses `word`
--> tests/compile-fail/from_word.rs:21:23
|
21 | #[darling(from_word = || Ok(Wordy::Options { thing: "Hello".to_string() }))]
| ^

View File

@@ -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() {}

View File

@@ -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`:
bool
char
isize
i8
i16
i32
i64
i128
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`:
bool
char
isize
i8
i16
i32
i64
i128
and $N others

View File

@@ -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() {}

View File

@@ -0,0 +1,23 @@
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)]
5 | struct NoDefault(String);
|
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)]
5 | struct NoDefault(String);
|

View File

@@ -0,0 +1,21 @@
use darling::{FromDeriveInput, FromMeta};
#[derive(FromDeriveInput)]
#[darling(attributes(demo))]
pub struct Receiver {
example1: String,
#[darling(
// This should fail because `example1` is a local that's been captured
// from the `FromDeriveInput` impl. That's disallowed because exposing
// those internals would make any change to the derived method body a
// potentially-breaking change.
with = |m| Ok(
String::from_meta(m)?.to_uppercase()
+ example1.1.as_ref().map(|s| s.as_str()).unwrap_or("")
),
default
)]
example2: String,
}
fn main() {}

View File

@@ -0,0 +1,30 @@
error[E0308]: mismatched types
--> tests/compile-fail/with_closure_capture.rs:12:16
|
12 | with = |m| Ok(
| ^ arguments to this function are incorrect
| ________________|
| |
13 | | String::from_meta(m)?.to_uppercase()
14 | | + example1.1.as_ref().map(|s| s.as_str()).unwrap_or("")
15 | | ),
| |_________^ expected fn pointer, found closure
|
= note: expected fn pointer `for<'a> fn(&'a syn::Meta) -> Result<String, darling::Error>`
found closure `{closure@$DIR/tests/compile-fail/with_closure_capture.rs:12:16: 12:19}`
note: closures can only be coerced to `fn` types if they do not capture any variables
--> tests/compile-fail/with_closure_capture.rs:14:15
|
14 | + example1.1.as_ref().map(|s| s.as_str()).unwrap_or("")
| ^^^^^^^^ `example1` captured here
help: the return type of this call is `{closure@$DIR/tests/compile-fail/with_closure_capture.rs:12:16: 12:19}` due to the type of the argument passed
--> tests/compile-fail/with_closure_capture.rs:12:16
|
12 | with = |m| Ok(
| ________________^
13 | | String::from_meta(m)?.to_uppercase()
14 | | + example1.1.as_ref().map(|s| s.as_str()).unwrap_or("")
15 | | ),
| |_________- this argument influences the return type of `{{root}}`
note: function defined here
--> $RUST/core/src/convert/mod.rs

View File

@@ -0,0 +1,10 @@
use darling::FromMeta;
#[derive(FromMeta)]
enum Meta {
Unit,
#[darling(word)]
NotUnit(String)
}
fn main() {}

View File

@@ -0,0 +1,5 @@
error: Unexpected field: `word`. `#[darling(word)]` can only be applied to a unit variant
--> tests/compile-fail/word_on_wrong_variant_type.rs:6:15
|
6 | #[darling(word)]
| ^^^^

16
vendor/darling/tests/compiletests.rs vendored Normal file
View File

@@ -0,0 +1,16 @@
#![cfg(compiletests)]
#[rustversion::stable(1.77)]
#[test]
fn compile_test() {
let t = trybuild::TestCases::new();
t.compile_fail("tests/compile-fail/*.rs");
}
#[rustversion::not(stable(1.77))]
#[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"
);
}

42
vendor/darling/tests/computed_bound.rs vendored Normal file
View File

@@ -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);
}

25
vendor/darling/tests/custom_bound.rs vendored Normal file
View File

@@ -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() {}

49
vendor/darling/tests/data_with.rs vendored Normal file
View File

@@ -0,0 +1,49 @@
use std::collections::BTreeSet;
use darling::{Error, FromDeriveInput, Result};
use syn::parse_quote;
fn field_names(data: &syn::Data) -> Result<BTreeSet<String>> {
let fields = match data {
syn::Data::Struct(data) => data.fields.iter(),
syn::Data::Enum(_) => return Err(Error::custom("Expected struct or union")),
syn::Data::Union(data) => data.fields.named.iter(),
};
Ok(fields
.filter_map(|f| f.ident.clone())
.map(|i| i.to_string())
.collect())
}
#[derive(FromDeriveInput)]
#[darling(attributes(a), forward_attrs)]
struct Receiver {
#[darling(with = field_names)]
data: BTreeSet<String>,
}
#[test]
fn succeeds_on_no_fields() {
let di = Receiver::from_derive_input(&parse_quote! {
struct Demo;
})
.unwrap();
assert!(di.data.is_empty());
}
#[test]
fn succeeds_on_valid_input() {
let di = Receiver::from_derive_input(&parse_quote! {
struct Demo {
hello: String,
world: String,
}
})
.unwrap();
assert_eq!(di.data.len(), 2);
assert!(di.data.contains("hello"));
assert!(di.data.contains("world"));
}

189
vendor/darling/tests/defaults.rs vendored Normal file
View File

@@ -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());
}
}

44
vendor/darling/tests/enums_default.rs vendored Normal file
View File

@@ -0,0 +1,44 @@
use darling::{FromDeriveInput, FromMeta};
use syn::parse_quote;
#[derive(Debug, FromMeta, PartialEq, Eq)]
enum Dolor {
Sit,
#[darling(word)]
Amet,
}
impl Default for Dolor {
fn default() -> Self {
Dolor::Sit
}
}
#[derive(FromDeriveInput)]
#[darling(attributes(hello))]
struct Receiver {
#[darling(default)]
example: Dolor,
}
#[test]
fn missing_meta() {
let di = Receiver::from_derive_input(&parse_quote! {
#[hello]
struct Example;
})
.unwrap();
assert_eq!(Dolor::Sit, di.example);
}
#[test]
fn empty_meta() {
let di = Receiver::from_derive_input(&parse_quote! {
#[hello(example)]
struct Example;
})
.unwrap();
assert_eq!(Dolor::Amet, di.example);
}

127
vendor/darling/tests/enums_newtype.rs vendored Normal file
View File

@@ -0,0 +1,127 @@
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),
OptDolor(Option<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 option_literal() {
let holder = Holder::from_derive_input(&parse_quote! {
#[hello(lorem(opt_dolor = "Hello"))]
struct Bar;
})
.unwrap();
assert_eq!(holder.lorem, Lorem::OptDolor(Some("Hello".into())));
}
/// Make sure newtype variants whose field's type's `from_none` return
/// a `Some` can be used in key-value form.
#[test]
fn option_word_only() {
let holder = Holder::from_derive_input(&parse_quote! {
#[hello(lorem = "opt_dolor")]
struct Bar;
})
.unwrap();
assert_eq!(holder.lorem, Lorem::OptDolor(None));
}
/// Make sure that newtype variants which don't produce a from_none value
/// do not allow the word form.
#[test]
#[should_panic]
fn word_only_fails_for_non_option() {
Holder::from_derive_input(&parse_quote! {
#[hello(lorem = "dolor")]
struct Bar;
})
.unwrap();
}
#[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();
}

15
vendor/darling/tests/enums_struct.rs vendored Normal file
View File

@@ -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() {}

123
vendor/darling/tests/enums_unit.rs vendored Normal file
View File

@@ -0,0 +1,123 @@
//! Test expansion of enum variants which have no associated data.
use darling::{ast::NestedMeta, FromMeta};
use syn::{parse_quote, spanned::Spanned, Meta};
#[derive(Debug, FromMeta)]
#[darling(rename_all = "snake_case")]
enum Pattern {
Owned,
Immutable,
Mutable,
}
#[test]
fn expansion() {}
#[test]
fn rejected_in_unit_enum_variants() {
#[derive(Debug, FromMeta, PartialEq)]
struct Opts {
choices: Choices,
}
#[derive(Debug, PartialEq)]
struct Choices {
values: Vec<Choice>,
}
impl FromMeta for Choices {
fn from_list(items: &[NestedMeta]) -> darling::Result<Self> {
let values = items
.iter()
.map(|item| match item {
NestedMeta::Meta(meta) => match meta {
Meta::Path(path) => Choice::from_string(
&path
.get_ident()
.ok_or(
darling::Error::custom("choice must be an ident (no colon)")
.with_span(path),
)?
.to_string(),
)
.map_err(|e| e.with_span(path)),
Meta::List(list) => Choice::from_list(&[item.clone()])
.map_err(|e| e.with_span(&list.span())),
Meta::NameValue(n) => Err(darling::Error::custom(
"choice options are not set as name-value, use parentheses",
)
.with_span(&n.eq_token)),
},
_ => {
Err(darling::Error::custom("literal is not a valid choice").with_span(item))
}
})
.collect::<Result<_, _>>()?;
Ok(Self { values })
}
}
#[derive(Debug, FromMeta, PartialEq)]
enum Choice {
One(One),
Other,
}
#[derive(Debug, FromMeta, PartialEq)]
struct One {
foo: String,
}
for (tokens, expected) in [
(
parse_quote! {
choices(one(foo = "bar"))
},
Ok(Opts {
choices: Choices {
values: vec![Choice::One(One {
foo: "bar".to_string(),
})],
},
}),
),
(
parse_quote! {
choices(other)
},
Ok(Opts {
choices: Choices {
values: vec![Choice::Other],
},
}),
),
(
parse_quote! {
choices(other, one(foo = "bar"))
},
Ok(Opts {
choices: Choices {
values: vec![
Choice::Other,
Choice::One(One {
foo: "bar".to_string(),
}),
],
},
}),
),
(
parse_quote! {
choices(other(foo = "bar"))
},
Err("Unexpected meta-item format `non-path` at choices".to_string()),
),
] {
assert_eq!(
Opts::from_list(&NestedMeta::parse_meta_list(tokens).unwrap())
.map_err(|e| e.to_string()),
expected
)
}
}

54
vendor/darling/tests/error.rs vendored Normal file
View File

@@ -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());
}

205
vendor/darling/tests/flatten.rs vendored Normal file
View File

@@ -0,0 +1,205 @@
use darling::{util::Flag, FromDeriveInput, FromMeta};
use proc_macro2::Ident;
use syn::parse_quote;
#[derive(FromMeta)]
struct Vis {
public: Flag,
private: Flag,
}
#[derive(FromDeriveInput)]
#[darling(attributes(sample))]
struct Example {
ident: Ident,
label: String,
#[darling(flatten)]
visibility: Vis,
}
#[test]
fn happy_path() {
let di = Example::from_derive_input(&parse_quote! {
#[sample(label = "Hello", public)]
struct Demo {}
});
let parsed = di.unwrap();
assert_eq!(parsed.ident, "Demo");
assert_eq!(&parsed.label, "Hello");
assert!(parsed.visibility.public.is_present());
assert!(!parsed.visibility.private.is_present());
}
#[test]
fn unknown_field_errors() {
let errors = Example::from_derive_input(&parse_quote! {
#[sample(label = "Hello", republic)]
struct Demo {}
})
.map(|_| "Should have failed")
.unwrap_err();
assert_eq!(errors.len(), 1);
}
/// This test demonstrates flatten being used recursively.
/// Fields are expected to be consumed by the outermost matching struct.
#[test]
fn recursive_flattening() {
#[derive(FromMeta)]
struct Nested2 {
above: isize,
below: isize,
port: Option<isize>,
}
#[derive(FromMeta)]
struct Nested1 {
port: isize,
starboard: isize,
#[darling(flatten)]
z_axis: Nested2,
}
#[derive(FromMeta)]
struct Nested0 {
fore: isize,
aft: isize,
#[darling(flatten)]
cross_section: Nested1,
}
#[derive(FromDeriveInput)]
#[darling(attributes(boat))]
struct BoatPosition {
#[darling(flatten)]
pos: Nested0,
}
let parsed = BoatPosition::from_derive_input(&parse_quote! {
#[boat(fore = 1, aft = 1, port = 10, starboard = 50, above = 20, below = -3)]
struct Demo;
})
.unwrap();
assert_eq!(parsed.pos.fore, 1);
assert_eq!(parsed.pos.aft, 1);
assert_eq!(parsed.pos.cross_section.port, 10);
assert_eq!(parsed.pos.cross_section.starboard, 50);
assert_eq!(parsed.pos.cross_section.z_axis.above, 20);
assert_eq!(parsed.pos.cross_section.z_axis.below, -3);
// This should be `None` because the `port` field in `Nested1` consumed
// the field before the leftovers were passed to `Nested2::from_list`.
assert_eq!(parsed.pos.cross_section.z_axis.port, None);
}
/// This test confirms that a collection - in this case a HashMap - can
/// be used with `flatten`.
#[test]
fn flattening_into_hashmap() {
#[derive(FromDeriveInput)]
#[darling(attributes(ca))]
struct Catchall {
hello: String,
volume: usize,
#[darling(flatten)]
others: std::collections::HashMap<String, String>,
}
let parsed = Catchall::from_derive_input(&parse_quote! {
#[ca(hello = "World", volume = 10, first_name = "Alice", second_name = "Bob")]
struct Demo;
})
.unwrap();
assert_eq!(parsed.hello, "World");
assert_eq!(parsed.volume, 10);
assert_eq!(parsed.others.len(), 2);
}
#[derive(FromMeta)]
#[allow(dead_code)]
struct Person {
first: String,
last: String,
parent: Option<Box<Person>>,
}
#[derive(FromDeriveInput)]
#[darling(attributes(v))]
#[allow(dead_code)]
struct Outer {
#[darling(flatten)]
owner: Person,
#[darling(default)]
blast: bool,
}
/// This test makes sure that field names from parent structs are not inappropriately
/// offered as alternates for unknown field errors in child structs.
///
/// A naive implementation that tried to offer all the flattened fields for "did you mean"
/// could inspect all errors returned by the flattened field's `from_list` call and add the
/// parent's field names as alternates to all unknown field errors.
///
/// THIS WOULD BE INCORRECT. Those unknown field errors may have already come from
/// child fields within the flattened struct, where the parent's field names are not valid.
#[test]
fn do_not_suggest_invalid_alts() {
let errors = Outer::from_derive_input(&parse_quote! {
#[v(first = "Hello", last = "World", parent(first = "Hi", last = "Earth", blasts = "off"))]
struct Demo;
})
.map(|_| "Should have failed")
.unwrap_err()
.to_string();
assert!(
!errors.contains("`blast`"),
"Should not contain `blast`: {}",
errors
);
}
#[test]
#[cfg(feature = "suggestions")]
fn suggest_valid_parent_alts() {
let errors = Outer::from_derive_input(&parse_quote! {
#[v(first = "Hello", bladt = false, last = "World", parent(first = "Hi", last = "Earth"))]
struct Demo;
})
.map(|_| "Should have failed")
.unwrap_err()
.to_string();
assert!(
errors.contains("`blast`"),
"Should contain `blast` as did-you-mean suggestion: {}",
errors
);
}
/// Make sure that flatten works with smart pointer types, e.g. `Box`.
///
/// The generated `flatten` impl directly calls `FromMeta::from_list`
/// rather than calling `from_meta`, and the default impl of `from_list`
/// will return an unsupported format error; this test ensures that the
/// smart pointer type is properly forwarding the `from_list` call.
#[test]
fn flattening_to_box() {
#[derive(FromDeriveInput)]
#[darling(attributes(v))]
struct Example {
#[darling(flatten)]
items: Box<Vis>,
}
let when_omitted = Example::from_derive_input(&parse_quote! {
struct Demo;
})
.unwrap();
assert!(!when_omitted.items.public.is_present());
}

View File

@@ -0,0 +1,45 @@
use darling::{util::Flag, Error, FromDeriveInput, FromMeta};
use proc_macro2::Ident;
use syn::parse_quote;
#[derive(FromMeta)]
#[darling(and_then = Self::validate)]
struct Vis {
public: Flag,
private: Flag,
}
impl Vis {
fn validate(self) -> darling::Result<Self> {
if self.public.is_present() && self.private.is_present() {
return Err(Error::custom("Cannot be both public and private"));
}
Ok(self)
}
}
#[derive(FromDeriveInput)]
#[darling(attributes(sample))]
#[allow(dead_code)]
struct Example {
ident: Ident,
label: String,
volume: usize,
#[darling(flatten)]
visibility: Vis,
}
#[test]
fn many_errors() {
let e = Example::from_derive_input(&parse_quote! {
#[sample(volume = 10, public, private)]
struct Demo {}
})
.map(|_| "Should have failed")
.unwrap_err();
// We are expecting an error from the Vis::validate method and an error for the
// missing `label` field.
assert_eq!(e.len(), 2);
}

View File

@@ -0,0 +1,84 @@
use darling::{ast, util::Ignored, FromDeriveInput, FromField, FromMeta};
use proc_macro2::{Ident, Span};
use syn::parse_quote;
#[derive(FromMeta)]
struct Vis {
#[darling(default)]
public: bool,
#[darling(default)]
private: bool,
}
#[derive(FromField)]
#[darling(attributes(v))]
struct Field {
ident: Option<Ident>,
example: Option<String>,
#[darling(flatten)]
visibility: Vis,
}
#[derive(FromDeriveInput)]
#[darling(attributes(v))]
struct Input {
data: ast::Data<Ignored, Field>,
}
#[test]
fn field_flattens() {
let di = Input::from_derive_input(&parse_quote! {
struct Demo {
#[v(public, example = "world")]
hello: String
}
})
.unwrap();
let fields = di.data.take_struct().unwrap();
let first_field = fields.into_iter().next().unwrap();
assert_eq!(
first_field.ident,
Some(Ident::new("hello", Span::call_site()))
);
assert!(first_field.visibility.public);
assert!(!first_field.visibility.private);
assert_eq!(first_field.example.unwrap(), "world");
}
#[test]
fn field_flattens_with_no_field_level_attributes() {
let di = Input::from_derive_input(&parse_quote! {
struct Demo {
hello: String
}
})
.unwrap();
let fields = di.data.take_struct().unwrap();
let first_field = fields.into_iter().next().unwrap();
assert_eq!(
first_field.ident,
Some(Ident::new("hello", Span::call_site()))
);
assert!(!first_field.visibility.public);
assert!(!first_field.visibility.private);
assert_eq!(first_field.example, None);
}
#[test]
fn field_flattens_across_attributes() {
let di = Input::from_derive_input(&parse_quote! {
struct Demo {
#[v(public)]
#[v(private)]
hello: String
}
})
.unwrap();
let fields = di.data.take_struct().unwrap();
let first_field = fields.into_iter().next().unwrap();
assert!(first_field.visibility.public);
assert!(first_field.visibility.private);
}

View File

@@ -0,0 +1,22 @@
use darling::FromAttributes;
use syn::parse_quote;
#[derive(Default, darling::FromAttributes)]
#[darling(attributes(builder), forward_attrs)]
struct Params {
default: Option<syn::Expr>,
attrs: Vec<syn::Attribute>,
}
#[test]
fn forward_attrs_with_field() {
let input: syn::DeriveInput = parse_quote! {
#[doc = "Hello"]
#[builder(default = 15)]
struct Example;
};
let parsed = Params::from_attributes(&input.attrs).unwrap();
assert!(parsed.default.is_some());
assert_eq!(parsed.attrs.len(), 1);
}

175
vendor/darling/tests/from_generics.rs vendored Normal file
View File

@@ -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);
}

304
vendor/darling/tests/from_meta.rs vendored Normal file
View File

@@ -0,0 +1,304 @@
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()
);
}
/// Tests behavior of FromMeta implementation for enums.
mod enum_impl {
use darling::{Error, FromMeta};
use syn::parse_quote;
/// A playback volume.
#[derive(Debug, Clone, Copy, PartialEq, Eq, FromMeta)]
enum Volume {
Normal,
Low,
High,
#[darling(rename = "dB")]
Decibels(u8),
}
#[test]
fn string_for_unit_variant() {
let volume = Volume::from_string("low").unwrap();
assert_eq!(volume, Volume::Low);
}
#[test]
fn single_value_list() {
let unit_variant = Volume::from_list(&[parse_quote!(high)]).unwrap();
assert_eq!(unit_variant, Volume::High);
let newtype_variant = Volume::from_list(&[parse_quote!(dB = 100)]).unwrap();
assert_eq!(newtype_variant, Volume::Decibels(100));
}
#[test]
fn empty_list_errors() {
let err = Volume::from_list(&[]).unwrap_err();
assert_eq!(err.to_string(), Error::too_few_items(1).to_string());
}
#[test]
fn multiple_values_list_errors() {
let err = Volume::from_list(&[parse_quote!(low), parse_quote!(dB = 20)]).unwrap_err();
assert_eq!(err.to_string(), Error::too_many_items(1).to_string());
}
}
mod from_none_struct_closure {
use darling::FromMeta;
use syn::parse_quote;
#[derive(Debug, FromMeta)]
struct Outer {
// Do NOT add `darling(default)` here; this is testing the `from_none` fallback
// invoked when a field is not declared and no `default` is specified.
speech: Example,
}
#[derive(Debug, FromMeta)]
#[darling(from_none = || Some(Default::default()))]
struct Example {
max_volume: u32,
}
impl Default for Example {
fn default() -> Self {
Example { max_volume: 3 }
}
}
#[test]
fn absent_gets_from_none() {
let thing = Outer::from_list(&[]).unwrap();
assert_eq!(thing.speech.max_volume, 3);
}
#[test]
fn word_errors() {
let error = Outer::from_list(&[parse_quote!(speech)])
.expect_err("speech should require its fields if declared");
assert_eq!(error.len(), 1);
}
#[test]
fn list_sets_field() {
let thing = Outer::from_list(&[parse_quote!(speech(max_volume = 5))]).unwrap();
assert_eq!(thing.speech.max_volume, 5);
}
}
mod from_none_struct_path {
use darling::FromMeta;
use syn::parse_quote;
#[derive(Debug, FromMeta)]
struct Outer {
// Do NOT add `darling(default)` here; this is testing the `from_none` fallback
// invoked when a field is not declared and no `default` is specified.
speech: Example,
}
fn from_none_fallback() -> Option<Example> {
Some(Example { max_volume: 3 })
}
#[derive(Debug, FromMeta)]
#[darling(from_none = from_none_fallback)]
struct Example {
max_volume: u32,
}
#[test]
fn absent_gets_from_none() {
let thing = Outer::from_list(&[]).unwrap();
assert_eq!(thing.speech.max_volume, 3);
}
#[test]
fn word_errors() {
let error = Outer::from_list(&[parse_quote!(speech)])
.expect_err("speech should require its fields if declared");
assert_eq!(error.len(), 1);
}
#[test]
fn list_sets_field() {
let thing = Outer::from_list(&[parse_quote!(speech(max_volume = 5))]).unwrap();
assert_eq!(thing.speech.max_volume, 5);
}
}
mod from_word_struct_closure {
use darling::FromMeta;
use syn::parse_quote;
#[derive(FromMeta)]
struct Outer {
#[darling(default)]
speech: Example,
}
#[derive(FromMeta, Default)]
#[darling(from_word = || Ok(Example { max_volume: 10 }))]
struct Example {
max_volume: u32,
}
#[test]
fn absent_gets_default() {
let thing = Outer::from_list(&[]).unwrap();
assert_eq!(thing.speech.max_volume, 0);
}
#[test]
fn word_gets_value() {
let thing = Outer::from_list(&[parse_quote!(speech)]).unwrap();
assert_eq!(thing.speech.max_volume, 10);
}
#[test]
fn list_sets_field() {
let thing = Outer::from_list(&[parse_quote!(speech(max_volume = 5))]).unwrap();
assert_eq!(thing.speech.max_volume, 5);
}
}
mod from_word_struct_path {
use darling::FromMeta;
use syn::parse_quote;
#[derive(FromMeta)]
struct Outer {
#[darling(default)]
speech: Example,
}
fn max_volume_10() -> darling::Result<Example> {
Ok(Example { max_volume: 10 })
}
#[derive(FromMeta, Default)]
#[darling(from_word = max_volume_10)]
struct Example {
max_volume: u32,
}
#[test]
fn absent_gets_default() {
let thing = Outer::from_list(&[]).unwrap();
assert_eq!(thing.speech.max_volume, 0);
}
#[test]
fn word_gets_value() {
let thing = Outer::from_list(&[parse_quote!(speech)]).unwrap();
assert_eq!(thing.speech.max_volume, 10);
}
#[test]
fn list_sets_field() {
let thing = Outer::from_list(&[parse_quote!(speech(max_volume = 5))]).unwrap();
assert_eq!(thing.speech.max_volume, 5);
}
}
mod from_word_enum_closure {
use darling::FromMeta;
use syn::parse_quote;
#[derive(Debug, FromMeta)]
struct Outer {
speech: Example,
}
#[derive(Debug, FromMeta, PartialEq, Eq)]
#[darling(from_word = || Ok(Example::Left { max_volume: 10 }))]
enum Example {
Left { max_volume: u32 },
Right { speed: u32 },
}
#[test]
fn word_gets_value() {
let thing = Outer::from_list(&[parse_quote!(speech)]).unwrap();
assert_eq!(thing.speech, Example::Left { max_volume: 10 });
}
#[test]
fn list_sets_field() {
let thing = Outer::from_list(&[parse_quote!(speech(left(max_volume = 5)))]).unwrap();
assert_eq!(thing.speech, Example::Left { max_volume: 5 });
}
#[test]
fn variant_word_fails() {
let thing = Outer::from_list(&[parse_quote!(speech(left))]).expect_err(
"A variant word is an error because from_word applies at the all-up enum level",
);
assert_eq!(thing.len(), 1);
}
}

59
vendor/darling/tests/from_type_param.rs vendored Normal file
View File

@@ -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);
}
}

View File

@@ -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());
}
}

57
vendor/darling/tests/from_variant.rs vendored Normal file
View File

@@ -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");
}
}

23
vendor/darling/tests/generics.rs vendored Normal file
View File

@@ -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();
}

69
vendor/darling/tests/happy_path.rs vendored Normal file
View File

@@ -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()),
}
}
);
}

42
vendor/darling/tests/hash_map.rs vendored Normal file
View File

@@ -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);
}

33
vendor/darling/tests/meta_with.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
use darling::{util::parse_expr, FromDeriveInput, FromMeta};
use syn::{parse_quote, Expr};
#[derive(FromDeriveInput)]
#[darling(attributes(demo))]
pub struct Receiver {
#[darling(with = parse_expr::preserve_str_literal, map = Some)]
example1: Option<Expr>,
#[darling(
with = |m| Ok(String::from_meta(m)?.to_uppercase()),
map = Some
)]
example2: Option<String>,
// This is deliberately strange - it keeps the field name, and ignores
// the rest of the attribute. In normal operation, this is strongly discouraged.
// It's used here to verify that the parameter type is known even if it can't be
// inferred from usage within the closure.
#[darling(with = |m| Ok(m.path().clone()))]
example3: syn::Path,
}
#[test]
fn handles_all_cases() {
let input = Receiver::from_derive_input(&parse_quote! {
#[demo(example1 = test::path, example2 = "hello", example3)]
struct Example;
})
.unwrap();
assert_eq!(input.example1, Some(parse_quote!(test::path)));
assert_eq!(input.example2, Some("HELLO".to_string()));
assert_eq!(input.example3, parse_quote!(example3));
}

30
vendor/darling/tests/multiple.rs vendored Normal file
View File

@@ -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()]
);
}

26
vendor/darling/tests/newtype.rs vendored Normal file
View File

@@ -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));
}

74
vendor/darling/tests/skip.rs vendored Normal file
View File

@@ -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) }
)
}

112
vendor/darling/tests/spanned_value.rs vendored Normal file
View File

@@ -0,0 +1,112 @@
use darling::{
util::{Override, SpannedValue},
FromAttributes,
};
use quote::quote;
use syn::{parse::Parser, Attribute, Lit};
use Override::{Explicit, Inherit};
#[derive(FromAttributes, Default)]
#[darling(attributes(test_attr))]
struct SpannedValueOverPrimitive {
string: SpannedValue<String>,
optional_int: Option<SpannedValue<u64>>,
override_literal: Override<SpannedValue<Lit>>,
optional_override_char: Option<Override<SpannedValue<char>>>,
}
macro_rules! test_cases {
($(
$name:ident : #[test_attr($($tok:tt)*)] => $result:ident $( {
string: $string:expr,
int: $int:expr,
literal: $literal:pat,
char: $char:expr,
} )?;
)*) => {$(
#[test]
fn $name() {
let quoted = quote! {
#[test_attr(
$($tok)*
)]
};
let attrs = Attribute::parse_outer
.parse2(quoted)
.expect("failed to parse tokens as an attribute list");
let result = SpannedValueOverPrimitive::from_attributes(&attrs);
test_case_result!(result, $result $({
string: $string,
int: $int,
literal: $literal,
char: $char,
})?);
}
)*}
}
macro_rules! test_case_result {
($value:expr, Err) => {
assert!($value.is_err())
};
($value:expr, Ok{
string: $string:expr,
int: $int:expr,
literal: $literal:pat,
char: $char:expr,
}) => {{
let out = $value.expect("failed to parse with from_attributes");
assert_eq!(out.string.as_ref(), $string);
assert_eq!(out.optional_int.map(|i| *i.as_ref()), $int);
assert!(matches!(out.override_literal, $literal));
assert_eq!(
out.optional_override_char.map(|c| match c {
Inherit => Inherit,
Explicit(value) => Explicit(*value.as_ref()),
}),
$char
)
}};
}
test_cases! {
basic: #[test_attr(
string = "Hello",
optional_int = 23,
override_literal = "foo",
optional_override_char = 'c'
)] => Ok{
string: "Hello",
int: Some(23),
literal: Explicit(_),
char: Some(Override::Explicit('c')),
};
omit_optionals: #[test_attr(
string = "Hello",
override_literal = "foo",
)] => Ok{
string: "Hello",
int: None,
literal: Explicit(_),
char: None,
};
omit_overrides: #[test_attr(
string = "Hello",
override_literal,
optional_override_char,
)] => Ok{
string: "Hello",
int: None,
literal: Inherit,
char: Some(Inherit),
};
}

View File

@@ -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());
}

44
vendor/darling/tests/suggestions.rs vendored Normal file
View File

@@ -0,0 +1,44 @@
#![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,
// This field is included to make sure that skipped fields aren't suggested.
#[darling(skip)]
amet: bool,
}
#[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"));
}
#[test]
fn dont_suggest_skipped_field() {
let input: syn::DeriveInput = parse_quote! {
#[suggest(ipsum = "Hello", dolor(sit), amt)]
pub struct Foo;
};
let result = Lorem::from_derive_input(&input).unwrap_err();
assert_eq!(1, result.len());
assert!(!format!("{}", result).contains("amet"));
}

90
vendor/darling/tests/supports.rs vendored Normal file
View File

@@ -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();
}

View File

@@ -0,0 +1,31 @@
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.
/// 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: Debug)]
#[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 2:
// - The parsing error caused by a where-clause body where it doesn't belong
// - The missing `st` value because the parsing failure blocked that attribute from
// being read.
assert_eq!(2, errors.len());
}