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