syner/
lib.rs

1pub use syner_derive::Syner;
2
3pub mod __private {
4    pub use proc_macro2;
5    pub use syn;
6}
7
8pub trait Syner {
9    /// Parse this struct from an iterator of attributes.
10    fn parse_attrs<'a>(
11        attrs: impl IntoIterator<Item = &'a syn::Attribute> + 'a,
12    ) -> Result<Self, Vec<syn::Error>>
13    where
14        Self: Sized;
15
16    /// Parse this struct from a [syn::Meta].
17    fn parse_meta(input: &syn::Meta) -> Result<Self, Vec<syn::Error>>
18    where
19        Self: Sized;
20
21    /// The expected attributes of this struct.
22    fn expected() -> String;
23
24    /// The expected inner attributes of this struct.
25    fn expected_meta() -> String;
26
27    /// The name of the attribute that this struct is expecting.
28    fn name() -> &'static str;
29}
30
31#[cfg(test)]
32mod tests {
33    use syn::{parse_quote, DeriveInput};
34
35    use super::*;
36
37    // Definitions for the tests
38    mod syner {
39        pub use crate::Syner;
40        pub use crate::__private;
41    }
42
43    #[derive(Syner)]
44    #[syner(name = "test_attribute")]
45    struct Test {
46        pub some: String,
47        pub maybe: Option<String>,
48        #[syner(default)]
49        pub is_default: bool,
50        #[syner(default = "String::from(\"default\")")]
51        pub default: String,
52        pub inner: Inner,
53        pub inner_list: Vec<Inner>,
54        pub inner_bools: Vec<bool>,
55        pub inner_maybe: Option<Inner>,
56    }
57
58    #[derive(Syner, PartialEq, Debug)]
59    struct Inner {
60        pub some: String,
61        pub is_default: bool,
62    }
63
64    #[test]
65    fn test_correct() {
66        let input: DeriveInput = parse_quote! {
67            #[test_attribute(
68                some = "hello",
69                inner(
70                    some = "inner",
71                    is_default = true
72                ),
73                inner_list(
74                    inner(
75                        some = "inner_list0",
76                        is_default = true
77                    ),
78                    inner(
79                        some = "inner_list1",
80                        is_default = false
81                    ),
82                    inner(
83                        some = "inner_list2",
84                        is_default = true
85                    )
86                ),
87                inner_bools(true, false, true)
88            )]
89            struct Test;
90        };
91        let test = Test::parse_attrs(&input.attrs).unwrap();
92        assert_eq!(test.some, "hello");
93        assert_eq!(test.maybe, None);
94        assert_eq!(test.is_default, false);
95        assert_eq!(test.default, "default");
96        assert_eq!(test.inner.some, "inner");
97        assert_eq!(test.inner.is_default, true);
98        assert_eq!(test.inner_list.len(), 3);
99        assert_eq!(test.inner_list[0].some, "inner_list0");
100        assert_eq!(test.inner_list[0].is_default, true);
101        assert_eq!(test.inner_list[1].some, "inner_list1");
102        assert_eq!(test.inner_list[1].is_default, false);
103        assert_eq!(test.inner_list[2].some, "inner_list2");
104        assert_eq!(test.inner_list[2].is_default, true);
105        assert_eq!(test.inner_bools.len(), 3);
106        assert_eq!(test.inner_bools[0], true);
107        assert_eq!(test.inner_bools[1], false);
108        assert_eq!(test.inner_bools[2], true);
109        assert_eq!(test.inner_maybe, None);
110    }
111
112    #[test]
113    fn test_duplicate() {
114        let input: DeriveInput = parse_quote! {
115            #[test_attribute(
116                some = "hello",
117                some = "hello",
118                inner(
119                    some = "inner",
120                    is_default = true
121                ),
122                inner(
123                    some = "inner",
124                    is_default = true
125                )
126            )]
127            struct Test;
128        };
129        let test = Test::parse_attrs(&input.attrs);
130        assert!(test.is_err());
131        assert_eq!(test.err().unwrap().len(), 2);
132    }
133
134    #[test]
135    fn test_missing() {
136        let input: DeriveInput = parse_quote! {
137            #[test_attribute(
138                inner(
139                    some = "inner",
140                    is_default = true
141                ),
142                inner_list(
143                    inner(
144                        some = "inner_list0",
145                        is_default = true
146                    ),
147                    inner(
148                        some = "inner_list1",
149                        is_default = false
150                    ),
151                    inner(
152                        some = "inner_list2",
153                        is_default = true
154                    )
155                ),
156                inner_bools(true, false, true)
157            )]
158            struct Test;
159        };
160        let test = Test::parse_attrs(&input.attrs);
161        assert!(test.is_err());
162        assert_eq!(test.err().unwrap().len(), 1);
163    }
164
165    #[test]
166    fn test_wrong_type() {
167        let input: DeriveInput = parse_quote! {
168            #[test_attribute(
169                some = "hello",
170                inner(
171                    some = "inner",
172                    is_default = true
173                ),
174                inner_list(
175                    inner(
176                        some = "inner_list0",
177                        is_default = true
178                    ),
179                    inner(
180                        some = "inner_list1",
181                        is_default = false
182                    ),
183                    inner(
184                        some = "inner_list2",
185                        is_default = true
186                    )
187                ),
188                inner_bools(true, false, true),
189                inner_maybe = "hello"
190            )]
191            struct Test;
192        };
193        let test = Test::parse_attrs(&input.attrs);
194        assert!(test.is_err());
195        assert_eq!(test.err().unwrap().len(), 1);
196    }
197
198    #[test]
199    fn test_wrong_type_meta() {
200        let input: DeriveInput = parse_quote! {
201            #[test_attribute(
202                some = "hello",
203                inner(
204                    some = "inner",
205                    is_default = true
206                ),
207                inner_list(
208                    inner(
209                        some = "inner_list0",
210                        is_default = true
211                    ),
212                    inner(
213                        some = "inner_list1",
214                        is_default = false
215                    ),
216                    inner(
217                        some = "inner_list2",
218                        is_default = true
219                    )
220                ),
221                inner_bools(meta(true), false, true),
222            )]
223            struct Test;
224        };
225        let test = Test::parse_attrs(&input.attrs);
226        assert!(test.is_err());
227        assert_eq!(test.err().unwrap().len(), 1);
228    }
229}