1 #![allow(renamed_and_removed_lints)]
2 #![allow(clippy::blacklisted_name)]
3 
4 use std::collections::HashMap;
5 use std::fmt::Debug;
6 
7 use serde::Deserialize;
8 use toml::value::Datetime;
9 use toml::Spanned;
10 
11 /// A set of good datetimes.
good_datetimes() -> Vec<&'static str>12 pub fn good_datetimes() -> Vec<&'static str> {
13     vec![
14         "1997-09-09T09:09:09Z",
15         "1997-09-09T09:09:09+09:09",
16         "1997-09-09T09:09:09-09:09",
17         "1997-09-09T09:09:09",
18         "1997-09-09",
19         "09:09:09",
20         "1997-09-09T09:09:09.09Z",
21         "1997-09-09T09:09:09.09+09:09",
22         "1997-09-09T09:09:09.09-09:09",
23         "1997-09-09T09:09:09.09",
24         "09:09:09.09",
25     ]
26 }
27 
28 #[test]
test_spanned_field()29 fn test_spanned_field() {
30     #[derive(Deserialize)]
31     struct Foo<T> {
32         foo: Spanned<T>,
33     }
34 
35     #[derive(Deserialize)]
36     struct BareFoo<T> {
37         foo: T,
38     }
39 
40     fn good<T>(s: &str, expected: &str, end: Option<usize>)
41     where
42         T: serde::de::DeserializeOwned + Debug + PartialEq,
43     {
44         let foo: Foo<T> = toml::from_str(s).unwrap();
45 
46         assert_eq!(6, foo.foo.span().start);
47         if let Some(end) = end {
48             assert_eq!(end, foo.foo.span().end);
49         } else {
50             assert_eq!(s.len(), foo.foo.span().end);
51         }
52         assert_eq!(expected, &s[foo.foo.span()]);
53 
54         // Test for Spanned<> at the top level
55         let foo_outer: Spanned<BareFoo<T>> = toml::from_str(s).unwrap();
56 
57         assert_eq!(0, foo_outer.span().start);
58         assert_eq!(s.len(), foo_outer.span().end);
59         assert_eq!(foo.foo.into_inner(), foo_outer.into_inner().foo);
60     }
61 
62     good::<String>("foo = \"foo\"", "\"foo\"", None);
63     good::<u32>("foo = 42", "42", None);
64     // leading plus
65     good::<u32>("foo = +42", "+42", None);
66     // table
67     good::<HashMap<String, u32>>(
68         "foo = {\"foo\" = 42, \"bar\" = 42}",
69         "{\"foo\" = 42, \"bar\" = 42}",
70         None,
71     );
72     // array
73     good::<Vec<u32>>("foo = [0, 1, 2, 3, 4]", "[0, 1, 2, 3, 4]", None);
74     // datetime
75     good::<String>(
76         "foo = \"1997-09-09T09:09:09Z\"",
77         "\"1997-09-09T09:09:09Z\"",
78         None,
79     );
80 
81     for expected in good_datetimes() {
82         let s = format!("foo = {}", expected);
83         good::<Datetime>(&s, expected, None);
84     }
85     // ending at something other than the absolute end
86     good::<u32>("foo = 42\nnoise = true", "42", Some(8));
87 }
88 
89 #[test]
test_inner_spanned_table()90 fn test_inner_spanned_table() {
91     #[derive(Deserialize)]
92     struct Foo {
93         foo: Spanned<HashMap<Spanned<String>, Spanned<String>>>,
94     }
95 
96     fn good(s: &str, zero: bool) {
97         let foo: Foo = toml::from_str(s).unwrap();
98 
99         if zero {
100             assert_eq!(foo.foo.span().start, 0);
101             assert_eq!(foo.foo.span().end, 73);
102         } else {
103             assert_eq!(foo.foo.span().start, s.find('{').unwrap());
104             assert_eq!(foo.foo.span().end, s.find('}').unwrap() + 1);
105         }
106         for (k, v) in foo.foo.as_ref().iter() {
107             assert_eq!(&s[k.span().start..k.span().end], k.as_ref());
108             assert_eq!(&s[(v.span().start + 1)..(v.span().end - 1)], v.as_ref());
109         }
110     }
111 
112     good(
113         "\
114         [foo]
115         a = 'b'
116         bar = 'baz'
117         c = 'd'
118         e = \"f\"
119     ",
120         true,
121     );
122 
123     good(
124         "
125         foo = { a = 'b', bar = 'baz', c = 'd', e = \"f\" }",
126         false,
127     );
128 }
129 
130 #[test]
test_outer_spanned_table()131 fn test_outer_spanned_table() {
132     #[derive(Deserialize)]
133     struct Foo {
134         foo: HashMap<Spanned<String>, Spanned<String>>,
135     }
136 
137     fn good(s: &str) {
138         let foo: Foo = toml::from_str(s).unwrap();
139 
140         for (k, v) in foo.foo.iter() {
141             assert_eq!(&s[k.span().start..k.span().end], k.as_ref());
142             assert_eq!(&s[(v.span().start + 1)..(v.span().end - 1)], v.as_ref());
143         }
144     }
145 
146     good(
147         "
148         [foo]
149         a = 'b'
150         bar = 'baz'
151         c = 'd'
152         e = \"f\"
153     ",
154     );
155 
156     good(
157         "
158         foo = { a = 'b', bar = 'baz', c = 'd', e = \"f\" }
159     ",
160     );
161 }
162 
163 #[test]
test_spanned_nested()164 fn test_spanned_nested() {
165     #[derive(Deserialize)]
166     struct Foo {
167         foo: HashMap<Spanned<String>, HashMap<Spanned<String>, Spanned<String>>>,
168     }
169 
170     fn good(s: &str) {
171         let foo: Foo = toml::from_str(s).unwrap();
172 
173         for (k, v) in foo.foo.iter() {
174             assert_eq!(&s[k.span().start..k.span().end], k.as_ref());
175             for (n_k, n_v) in v.iter() {
176                 assert_eq!(&s[n_k.span().start..n_k.span().end], n_k.as_ref());
177                 assert_eq!(
178                     &s[(n_v.span().start + 1)..(n_v.span().end - 1)],
179                     n_v.as_ref()
180                 );
181             }
182         }
183     }
184 
185     good(
186         "
187         [foo.a]
188         a = 'b'
189         c = 'd'
190         e = \"f\"
191         [foo.bar]
192         baz = 'true'
193     ",
194     );
195 
196     good(
197         "
198         [foo]
199         foo = { a = 'b', bar = 'baz', c = 'd', e = \"f\" }
200         bazz = {}
201         g = { h = 'i' }
202     ",
203     );
204 }
205 
206 #[test]
test_spanned_array()207 fn test_spanned_array() {
208     #[derive(Deserialize)]
209     struct Foo {
210         foo: Vec<Spanned<HashMap<Spanned<String>, Spanned<String>>>>,
211     }
212 
213     let toml = "\
214         [[foo]]
215         a = 'b'
216         bar = 'baz'
217         c = 'd'
218         e = \"f\"
219         [[foo]]
220         a = 'c'
221         bar = 'baz'
222         c = 'g'
223         e = \"h\"
224     ";
225     let foo_list: Foo = toml::from_str(toml).unwrap();
226 
227     for (foo, expected) in foo_list.foo.iter().zip([0..75, 84..159]) {
228         assert_eq!(foo.span(), expected);
229         for (k, v) in foo.as_ref().iter() {
230             assert_eq!(&toml[k.span().start..k.span().end], k.as_ref());
231             assert_eq!(&toml[(v.span().start + 1)..(v.span().end - 1)], v.as_ref());
232         }
233     }
234 }
235 
236 #[test]
deny_unknown_fields()237 fn deny_unknown_fields() {
238     #[derive(Debug, serde::Deserialize)]
239     #[serde(deny_unknown_fields)]
240     struct Example {
241         #[allow(dead_code)]
242         real: u32,
243     }
244 
245     let error = toml::from_str::<Example>(
246         r#"# my comment
247 # bla bla bla
248 fake = 1"#,
249     )
250     .unwrap_err();
251     snapbox::assert_eq(
252         "\
253 TOML parse error at line 3, column 1
254   |
255 3 | fake = 1
256   | ^^^^
257 unknown field `fake`, expected `real`
258 ",
259         error.to_string(),
260     );
261 }
262