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