1 use std::collections::BTreeSet;
2 
3 use darling::{util, Error, FromDeriveInput, Result};
4 use syn::{parse_quote, Attribute};
5 
unique_idents(attrs: Vec<Attribute>) -> Result<BTreeSet<String>>6 fn unique_idents(attrs: Vec<Attribute>) -> Result<BTreeSet<String>> {
7     let mut errors = Error::accumulator();
8     let idents = attrs
9         .into_iter()
10         .filter_map(|attr| {
11             let path = attr.path();
12             errors.handle(
13                 path.get_ident()
14                     .map(std::string::ToString::to_string)
15                     .ok_or_else(|| {
16                         Error::custom(format!("`{}` is not an ident", util::path_to_string(path)))
17                             .with_span(path)
18                     }),
19             )
20         })
21         .collect();
22 
23     errors.finish_with(idents)
24 }
25 
26 #[derive(FromDeriveInput)]
27 #[darling(attributes(a), forward_attrs)]
28 struct Receiver {
29     #[darling(with = unique_idents)]
30     attrs: BTreeSet<String>,
31     other: Option<bool>,
32 }
33 
34 #[test]
succeeds_on_no_attrs()35 fn succeeds_on_no_attrs() {
36     let di = Receiver::from_derive_input(&parse_quote! {
37         struct Demo;
38     })
39     .unwrap();
40 
41     assert!(di.attrs.is_empty());
42 }
43 
44 #[test]
succeeds_on_valid_input()45 fn succeeds_on_valid_input() {
46     let di = Receiver::from_derive_input(&parse_quote! {
47         #[allow(dead_code)]
48         /// testing
49         #[another]
50         struct Demo;
51     })
52     .unwrap();
53 
54     assert_eq!(di.attrs.len(), 3);
55     assert!(di.attrs.contains("allow"));
56     assert!(di.attrs.contains("another"));
57     assert!(di.attrs.contains("doc"));
58     assert_eq!(di.other, None);
59 }
60 
61 #[test]
errors_combined_with_others()62 fn errors_combined_with_others() {
63     let e = Receiver::from_derive_input(&parse_quote! {
64         #[path::to::attr(dead_code)]
65         #[a(other = 5)]
66         struct Demo;
67     })
68     .map(|_| "Should have failed")
69     .unwrap_err();
70 
71     let error = e.to_string();
72 
73     assert_eq!(e.len(), 2);
74 
75     // Look for the error on the field `other`
76     assert!(error.contains("at other"));
77 
78     // Look for the invalid path from attrs conversion
79     assert!(error.contains("`path::to::attr`"));
80 }
81