1 use serde::Deserialize;
2 use serde::Deserializer;
3 use serde::Serialize;
4 use std::collections::BTreeMap;
5 
6 use toml::map::Map;
7 use toml::Table;
8 use toml::Value;
9 
10 macro_rules! t {
11     ($e:expr) => {
12         match $e {
13             Ok(t) => t,
14             Err(e) => panic!("{} failed with {}", stringify!($e), e),
15         }
16     };
17 }
18 
19 macro_rules! equivalent {
20     ($literal:expr, $toml:expr,) => {{
21         let toml = $toml;
22         let literal = $literal;
23 
24         // Through a string equivalent
25         println!("to_string");
26         snapbox::assert_eq(t!(toml::to_string(&literal)), t!(toml::to_string(&toml)));
27         println!("literal, from_str(toml)");
28         assert_eq!(literal, t!(toml::from_str(&t!(toml::to_string(&toml)))));
29         println!("toml, from_str(literal)");
30         assert_eq!(toml, t!(toml::from_str(&t!(toml::to_string(&literal)))));
31 
32         // In/out of Value is equivalent
33         println!("Table::try_from(literal)");
34         assert_eq!(toml, t!(Table::try_from(literal.clone())));
35         println!("Value::try_from(literal)");
36         assert_eq!(
37             Value::Table(toml.clone()),
38             t!(Value::try_from(literal.clone()))
39         );
40         println!("toml.try_into()");
41         assert_eq!(literal, t!(toml.clone().try_into()));
42         println!("Value::Table(toml).try_into()");
43         assert_eq!(literal, t!(Value::Table(toml.clone()).try_into()));
44     }};
45 }
46 
47 macro_rules! error {
48     ($ty:ty, $toml:expr, $msg_parse:expr, $msg_decode:expr) => {{
49         println!("attempting parsing");
50         match toml::from_str::<$ty>(&$toml.to_string()) {
51             Ok(_) => panic!("successful"),
52             Err(e) => snapbox::assert_eq($msg_parse, e.to_string()),
53         }
54 
55         println!("attempting toml decoding");
56         match $toml.try_into::<$ty>() {
57             Ok(_) => panic!("successful"),
58             Err(e) => snapbox::assert_eq($msg_decode, e.to_string()),
59         }
60     }};
61 }
62 
63 macro_rules! map( ($($k:ident: $v:expr),*) => ({
64     let mut _m = Map::new();
65     $(_m.insert(stringify!($k).to_string(), t!(Value::try_from($v)));)*
66     _m
67 }) );
68 
69 #[test]
smoke()70 fn smoke() {
71     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
72     struct Foo {
73         a: isize,
74     }
75 
76     equivalent!(Foo { a: 2 }, map! { a: Value::Integer(2) },);
77 }
78 
79 #[test]
smoke_hyphen()80 fn smoke_hyphen() {
81     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
82     struct Foo {
83         a_b: isize,
84     }
85 
86     equivalent! {
87         Foo { a_b: 2 },
88         map! { a_b: Value::Integer(2)},
89     }
90 
91     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
92     struct Foo2 {
93         #[serde(rename = "a-b")]
94         a_b: isize,
95     }
96 
97     let mut m = Map::new();
98     m.insert("a-b".to_string(), Value::Integer(2));
99     equivalent! {
100         Foo2 { a_b: 2 },
101         m,
102     }
103 }
104 
105 #[test]
nested()106 fn nested() {
107     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
108     struct Foo {
109         a: isize,
110         b: Bar,
111     }
112     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
113     struct Bar {
114         a: String,
115     }
116 
117     equivalent! {
118         Foo { a: 2, b: Bar { a: "test".to_string() } },
119         map! {
120             a: Value::Integer(2),
121             b: map! {
122                 a: Value::String("test".to_string())
123             }
124         },
125     }
126 }
127 
128 #[test]
application_decode_error()129 fn application_decode_error() {
130     #[derive(PartialEq, Debug)]
131     struct Range10(usize);
132     impl<'de> serde::Deserialize<'de> for Range10 {
133         fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Range10, D::Error> {
134             let x: usize = serde::Deserialize::deserialize(d)?;
135             if x > 10 {
136                 Err(serde::de::Error::custom("more than 10"))
137             } else {
138                 Ok(Range10(x))
139             }
140         }
141     }
142     let d_good = Value::Integer(5);
143     let d_bad1 = Value::String("not an isize".to_string());
144     let d_bad2 = Value::Integer(11);
145 
146     assert_eq!(Range10(5), d_good.try_into().unwrap());
147 
148     let err1: Result<Range10, _> = d_bad1.try_into();
149     assert!(err1.is_err());
150     let err2: Result<Range10, _> = d_bad2.try_into();
151     assert!(err2.is_err());
152 }
153 
154 #[test]
array()155 fn array() {
156     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
157     struct Foo {
158         a: Vec<isize>,
159     }
160 
161     equivalent! {
162         Foo { a: vec![1, 2, 3, 4] },
163         map! {
164             a: Value::Array(vec![
165                 Value::Integer(1),
166                 Value::Integer(2),
167                 Value::Integer(3),
168                 Value::Integer(4)
169             ])
170         },
171     };
172 }
173 
174 #[test]
inner_structs_with_options()175 fn inner_structs_with_options() {
176     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
177     struct Foo {
178         a: Option<Box<Foo>>,
179         b: Bar,
180     }
181     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
182     struct Bar {
183         a: String,
184         b: f64,
185     }
186 
187     equivalent! {
188         Foo {
189             a: Some(Box::new(Foo {
190                 a: None,
191                 b: Bar { a: "foo".to_string(), b: 4.5 },
192             })),
193             b: Bar { a: "bar".to_string(), b: 1.0 },
194         },
195         map! {
196             a: map! {
197                 b: map! {
198                     a: Value::String("foo".to_string()),
199                     b: Value::Float(4.5)
200                 }
201             },
202             b: map! {
203                 a: Value::String("bar".to_string()),
204                 b: Value::Float(1.0)
205             }
206         },
207     }
208 }
209 
210 #[test]
211 #[cfg(feature = "preserve_order")]
hashmap()212 fn hashmap() {
213     use std::collections::HashSet;
214 
215     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
216     struct Foo {
217         set: HashSet<char>,
218         map: BTreeMap<String, isize>,
219     }
220 
221     equivalent! {
222         Foo {
223             set: {
224                 let mut s = HashSet::new();
225                 s.insert('a');
226                 s
227             },
228             map: {
229                 let mut m = BTreeMap::new();
230                 m.insert("bar".to_string(), 4);
231                 m.insert("foo".to_string(), 10);
232                 m
233             }
234         },
235         map! {
236             set: Value::Array(vec![Value::String("a".to_string())]),
237             map: map! {
238                 bar: Value::Integer(4),
239                 foo: Value::Integer(10)
240             }
241         },
242     }
243 }
244 
245 #[test]
table_array()246 fn table_array() {
247     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
248     struct Foo {
249         a: Vec<Bar>,
250     }
251     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
252     struct Bar {
253         a: isize,
254     }
255 
256     equivalent! {
257         Foo { a: vec![Bar { a: 1 }, Bar { a: 2 }] },
258         map! {
259             a: Value::Array(vec![
260                 Value::Table(map!{ a: Value::Integer(1) }),
261                 Value::Table(map!{ a: Value::Integer(2) }),
262             ])
263         },
264     }
265 }
266 
267 #[test]
type_errors()268 fn type_errors() {
269     #[derive(Deserialize)]
270     #[allow(dead_code)]
271     struct Foo {
272         bar: isize,
273     }
274 
275     error! {
276         Foo,
277         map! {
278             bar: Value::String("a".to_string())
279         },
280         r#"TOML parse error at line 1, column 7
281   |
282 1 | bar = "a"
283   |       ^^^
284 invalid type: string "a", expected isize
285 "#,
286         "invalid type: string \"a\", expected isize\nin `bar`\n"
287     }
288 
289     #[derive(Deserialize)]
290     #[allow(dead_code)]
291     struct Bar {
292         foo: Foo,
293     }
294 
295     error! {
296         Bar,
297         map! {
298             foo: map! {
299                 bar: Value::String("a".to_string())
300             }
301         },
302         r#"TOML parse error at line 2, column 7
303   |
304 2 | bar = "a"
305   |       ^^^
306 invalid type: string "a", expected isize
307 "#,
308         "invalid type: string \"a\", expected isize\nin `foo.bar`\n"
309     }
310 }
311 
312 #[test]
missing_errors()313 fn missing_errors() {
314     #[derive(Serialize, Deserialize, PartialEq, Debug)]
315     struct Foo {
316         bar: isize,
317     }
318 
319     error! {
320         Foo,
321         map! { },
322         r#"TOML parse error at line 1, column 1
323   |
324 1 |
325   | ^
326 missing field `bar`
327 "#,
328         "missing field `bar`\n"
329     }
330 }
331 
332 #[test]
parse_enum()333 fn parse_enum() {
334     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
335     struct Foo {
336         a: E,
337     }
338     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
339     #[serde(untagged)]
340     enum E {
341         Bar(isize),
342         Baz(String),
343         Last(Foo2),
344     }
345     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
346     struct Foo2 {
347         test: String,
348     }
349 
350     equivalent! {
351         Foo { a: E::Bar(10) },
352         map! { a: Value::Integer(10) },
353     }
354 
355     equivalent! {
356         Foo { a: E::Baz("foo".to_string()) },
357         map! { a: Value::String("foo".to_string()) },
358     }
359 
360     equivalent! {
361         Foo { a: E::Last(Foo2 { test: "test".to_string() }) },
362         map! { a: map! { test: Value::String("test".to_string()) } },
363     }
364 }
365 
366 #[test]
parse_enum_string()367 fn parse_enum_string() {
368     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
369     struct Foo {
370         a: Sort,
371     }
372 
373     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
374     #[serde(rename_all = "lowercase")]
375     enum Sort {
376         Asc,
377         Desc,
378     }
379 
380     equivalent! {
381         Foo { a: Sort::Desc },
382         map! { a: Value::String("desc".to_string()) },
383     }
384 }
385 
386 #[test]
parse_tuple_variant()387 fn parse_tuple_variant() {
388     #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
389     struct Document {
390         inner: Vec<Enum>,
391     }
392 
393     #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
394     enum Enum {
395         Int(i32, i32),
396         String(String, String),
397     }
398 
399     let input = Document {
400         inner: vec![
401             Enum::Int(1, 1),
402             Enum::String("2".to_owned(), "2".to_owned()),
403         ],
404     };
405     let expected = "[[inner]]
406 Int = [1, 1]
407 
408 [[inner]]
409 String = [\"2\", \"2\"]
410 ";
411     let raw = toml::to_string(&input).unwrap();
412     snapbox::assert_eq(expected, raw);
413 
414     equivalent! {
415         Document {
416             inner: vec![
417                 Enum::Int(1, 1),
418                 Enum::String("2".to_owned(), "2".to_owned()),
419             ],
420         },
421         map! {
422             inner: vec![
423                 map! { Int: [1, 1] },
424                 map! { String: ["2".to_owned(), "2".to_owned()] },
425             ]
426         },
427     }
428 }
429 
430 #[test]
parse_struct_variant()431 fn parse_struct_variant() {
432     #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
433     struct Document {
434         inner: Vec<Enum>,
435     }
436 
437     #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
438     enum Enum {
439         Int { first: i32, second: i32 },
440         String { first: String, second: String },
441     }
442 
443     let input = Document {
444         inner: vec![
445             Enum::Int {
446                 first: 1,
447                 second: 1,
448             },
449             Enum::String {
450                 first: "2".to_owned(),
451                 second: "2".to_owned(),
452             },
453         ],
454     };
455     let expected = "[[inner]]
456 
457 [inner.Int]
458 first = 1
459 second = 1
460 
461 [[inner]]
462 
463 [inner.String]
464 first = \"2\"
465 second = \"2\"
466 ";
467     let raw = toml::to_string(&input).unwrap();
468     snapbox::assert_eq(expected, raw);
469 
470     equivalent! {
471         Document {
472             inner: vec![
473                 Enum::Int { first: 1, second: 1 },
474                 Enum::String { first: "2".to_owned(), second: "2".to_owned() },
475             ],
476         },
477         map! {
478             inner: vec![
479                 map! { Int: map! { first: 1, second: 1 } },
480                 map! { String: map! { first: "2".to_owned(), second: "2".to_owned() } },
481             ]
482         },
483     }
484 }
485 
486 #[test]
487 #[cfg(feature = "preserve_order")]
map_key_unit_variants()488 fn map_key_unit_variants() {
489     #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, PartialOrd, Ord)]
490     enum Sort {
491         #[serde(rename = "ascending")]
492         Asc,
493         Desc,
494     }
495 
496     let mut map = BTreeMap::new();
497     map.insert(Sort::Asc, 1);
498     map.insert(Sort::Desc, 2);
499 
500     equivalent! {
501         map,
502         map! { ascending: Value::Integer(1), Desc: Value::Integer(2) },
503     }
504 }
505 
506 // #[test]
507 // fn unused_fields() {
508 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
509 //     struct Foo { a: isize }
510 //
511 //     let v = Foo { a: 2 };
512 //     let mut d = Decoder::new(Table(map! {
513 //         a, Integer(2),
514 //         b, Integer(5)
515 //     }));
516 //     assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
517 //
518 //     assert_eq!(d.toml, Some(Table(map! {
519 //         b, Integer(5)
520 //     })));
521 // }
522 //
523 // #[test]
524 // fn unused_fields2() {
525 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
526 //     struct Foo { a: Bar }
527 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
528 //     struct Bar { a: isize }
529 //
530 //     let v = Foo { a: Bar { a: 2 } };
531 //     let mut d = Decoder::new(Table(map! {
532 //         a, Table(map! {
533 //             a, Integer(2),
534 //             b, Integer(5)
535 //         })
536 //     }));
537 //     assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
538 //
539 //     assert_eq!(d.toml, Some(Table(map! {
540 //         a, Table(map! {
541 //             b, Integer(5)
542 //         })
543 //     })));
544 // }
545 //
546 // #[test]
547 // fn unused_fields3() {
548 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
549 //     struct Foo { a: Bar }
550 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
551 //     struct Bar { a: isize }
552 //
553 //     let v = Foo { a: Bar { a: 2 } };
554 //     let mut d = Decoder::new(Table(map! {
555 //         a, Table(map! {
556 //             a, Integer(2)
557 //         })
558 //     }));
559 //     assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
560 //
561 //     assert_eq!(d.toml, None);
562 // }
563 //
564 // #[test]
565 // fn unused_fields4() {
566 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
567 //     struct Foo { a: BTreeMap<String, String> }
568 //
569 //     let v = Foo { a: map! { a, "foo".to_string() } };
570 //     let mut d = Decoder::new(Table(map! {
571 //         a, Table(map! {
572 //             a, Value::String("foo".to_string())
573 //         })
574 //     }));
575 //     assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
576 //
577 //     assert_eq!(d.toml, None);
578 // }
579 //
580 // #[test]
581 // fn unused_fields5() {
582 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
583 //     struct Foo { a: Vec<String> }
584 //
585 //     let v = Foo { a: vec!["a".to_string()] };
586 //     let mut d = Decoder::new(Table(map! {
587 //         a, Array(vec![Value::String("a".to_string())])
588 //     }));
589 //     assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
590 //
591 //     assert_eq!(d.toml, None);
592 // }
593 //
594 // #[test]
595 // fn unused_fields6() {
596 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
597 //     struct Foo { a: Option<Vec<String>> }
598 //
599 //     let v = Foo { a: Some(vec![]) };
600 //     let mut d = Decoder::new(Table(map! {
601 //         a, Array(vec![])
602 //     }));
603 //     assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
604 //
605 //     assert_eq!(d.toml, None);
606 // }
607 //
608 // #[test]
609 // fn unused_fields7() {
610 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
611 //     struct Foo { a: Vec<Bar> }
612 //     #[derive(Serialize, Deserialize, PartialEq, Debug)]
613 //     struct Bar { a: isize }
614 //
615 //     let v = Foo { a: vec![Bar { a: 1 }] };
616 //     let mut d = Decoder::new(Table(map! {
617 //         a, Array(vec![Table(map! {
618 //             a, Integer(1),
619 //             b, Integer(2)
620 //         })])
621 //     }));
622 //     assert_eq!(v, t!(Deserialize::deserialize(&mut d)));
623 //
624 //     assert_eq!(d.toml, Some(Table(map! {
625 //         a, Array(vec![Table(map! {
626 //             b, Integer(2)
627 //         })])
628 //     })));
629 // }
630 
631 #[test]
empty_arrays()632 fn empty_arrays() {
633     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
634     struct Foo {
635         a: Vec<Bar>,
636     }
637     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
638     struct Bar;
639 
640     equivalent! {
641         Foo { a: vec![] },
642         map! {a: Value::Array(Vec::new())},
643     }
644 }
645 
646 #[test]
empty_arrays2()647 fn empty_arrays2() {
648     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
649     struct Foo {
650         a: Option<Vec<Bar>>,
651     }
652     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
653     struct Bar;
654 
655     equivalent! {
656         Foo { a: None },
657         map! {},
658     }
659 
660     equivalent! {
661         Foo { a: Some(vec![]) },
662         map! { a: Value::Array(vec![]) },
663     }
664 }
665 
666 #[test]
extra_keys()667 fn extra_keys() {
668     #[derive(Serialize, Deserialize)]
669     struct Foo {
670         a: isize,
671     }
672 
673     let toml = map! { a: Value::Integer(2), b: Value::Integer(2) };
674     assert!(toml.clone().try_into::<Foo>().is_ok());
675     assert!(toml::from_str::<Foo>(&toml.to_string()).is_ok());
676 }
677 
678 #[test]
newtypes()679 fn newtypes() {
680     #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
681     struct A {
682         b: B,
683     }
684 
685     #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
686     struct B(u32);
687 
688     equivalent! {
689         A { b: B(2) },
690         map! { b: Value::Integer(2) },
691     }
692 }
693 
694 #[test]
newtypes2()695 fn newtypes2() {
696     #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
697     struct A {
698         b: B,
699     }
700 
701     #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
702     struct B(Option<C>);
703 
704     #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)]
705     struct C {
706         x: u32,
707         y: u32,
708         z: u32,
709     }
710 
711     equivalent! {
712         A { b: B(Some(C { x: 0, y: 1, z: 2 })) },
713         map! {
714             b: map! {
715                 x: Value::Integer(0),
716                 y: Value::Integer(1),
717                 z: Value::Integer(2)
718             }
719         },
720     }
721 }
722 
723 #[test]
newtype_variant()724 fn newtype_variant() {
725     #[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
726     struct Struct {
727         field: Enum,
728     }
729 
730     #[derive(Copy, Clone, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
731     enum Enum {
732         Variant(u8),
733     }
734 
735     equivalent! {
736         Struct { field: Enum::Variant(21) },
737         map! {
738             field: map! {
739                 Variant: Value::Integer(21)
740             }
741         },
742     }
743 }
744 
745 #[test]
newtype_key()746 fn newtype_key() {
747     #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Clone, Serialize, Deserialize)]
748     struct NewType(String);
749 
750     type CustomKeyMap = std::collections::BTreeMap<NewType, u32>;
751 
752     equivalent! {
753         [
754             (NewType("x".to_owned()), 1),
755             (NewType("y".to_owned()), 2),
756         ].into_iter().collect::<CustomKeyMap>(),
757         map! {
758             x: Value::Integer(1),
759             y: Value::Integer(2)
760         },
761     }
762 }
763 
764 #[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
765 struct CanBeEmpty {
766     a: Option<String>,
767     b: Option<String>,
768 }
769 
770 #[test]
table_structs_empty()771 fn table_structs_empty() {
772     let text = "[bar]\n\n[baz]\n\n[bazv]\na = \"foo\"\n\n[foo]\n";
773     let value: BTreeMap<String, CanBeEmpty> = toml::from_str(text).unwrap();
774     let mut expected: BTreeMap<String, CanBeEmpty> = BTreeMap::new();
775     expected.insert("bar".to_string(), CanBeEmpty::default());
776     expected.insert("baz".to_string(), CanBeEmpty::default());
777     expected.insert(
778         "bazv".to_string(),
779         CanBeEmpty {
780             a: Some("foo".to_string()),
781             b: None,
782         },
783     );
784     expected.insert("foo".to_string(), CanBeEmpty::default());
785     assert_eq!(value, expected);
786     snapbox::assert_eq(text, toml::to_string(&value).unwrap());
787 }
788 
789 #[test]
fixed_size_array()790 fn fixed_size_array() {
791     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
792     struct Entity {
793         pos: [i32; 2],
794     }
795 
796     equivalent! {
797         Entity { pos: [1, 2] },
798         map! {
799             pos: Value::Array(vec![
800                 Value::Integer(1),
801                 Value::Integer(2),
802             ])
803         },
804     }
805 }
806 
807 #[test]
homogeneous_tuple()808 fn homogeneous_tuple() {
809     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
810     struct Collection {
811         elems: (i64, i64, i64),
812     }
813 
814     equivalent! {
815         Collection { elems: (0, 1, 2) },
816         map! {
817             elems: Value::Array(vec![
818                 Value::Integer(0),
819                 Value::Integer(1),
820                 Value::Integer(2),
821             ])
822         },
823     }
824 }
825 
826 #[test]
homogeneous_tuple_struct()827 fn homogeneous_tuple_struct() {
828     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
829     struct Object(Vec<String>, Vec<String>, Vec<String>);
830 
831     equivalent! {
832         map! {
833             obj: Object(vec!["foo".to_string()], vec![], vec!["bar".to_string(), "baz".to_string()])
834         },
835         map! {
836             obj: Value::Array(vec![
837                 Value::Array(vec![
838                     Value::String("foo".to_string()),
839                 ]),
840                 Value::Array(vec![]),
841                 Value::Array(vec![
842                     Value::String("bar".to_string()),
843                     Value::String("baz".to_string()),
844                 ]),
845             ])
846         },
847     }
848 }
849 
850 #[test]
json_interoperability()851 fn json_interoperability() {
852     #[derive(Serialize, Deserialize)]
853     struct Foo {
854         any: toml::Value,
855     }
856 
857     let _foo: Foo = serde_json::from_str(
858         r#"
859         {"any":1}
860     "#,
861     )
862     .unwrap();
863 }
864 
865 #[test]
error_includes_key()866 fn error_includes_key() {
867     #[derive(Debug, Serialize, Deserialize)]
868     struct Package {
869         name: String,
870         version: String,
871         authors: Vec<String>,
872         profile: Profile,
873     }
874 
875     #[derive(Debug, Serialize, Deserialize)]
876     struct Profile {
877         dev: Dev,
878     }
879 
880     #[derive(Debug, Serialize, Deserialize)]
881     struct Dev {
882         debug: U32OrBool,
883     }
884 
885     #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
886     #[serde(untagged, expecting = "expected a boolean or an integer")]
887     pub enum U32OrBool {
888         U32(u32),
889         Bool(bool),
890     }
891 
892     let res: Result<Package, _> = toml::from_str(
893         r#"
894 [package]
895 name = "foo"
896 version = "0.0.0"
897 authors = []
898 
899 [profile.dev]
900 debug = 'a'
901 "#,
902     );
903     let err = res.unwrap_err();
904     snapbox::assert_eq(
905         r#"TOML parse error at line 8, column 9
906   |
907 8 | debug = 'a'
908   |         ^^^
909 expected a boolean or an integer
910 "#,
911         err.to_string(),
912     );
913 
914     let res: Result<Package, _> = toml::from_str(
915         r#"
916 [package]
917 name = "foo"
918 version = "0.0.0"
919 authors = []
920 
921 [profile]
922 dev = { debug = 'a' }
923 "#,
924     );
925     let err = res.unwrap_err();
926     snapbox::assert_eq(
927         r#"TOML parse error at line 8, column 17
928   |
929 8 | dev = { debug = 'a' }
930   |                 ^^^
931 expected a boolean or an integer
932 "#,
933         err.to_string(),
934     );
935 }
936 
937 #[test]
newline_key_value()938 fn newline_key_value() {
939     #[derive(Debug, Serialize, Deserialize)]
940     struct Package {
941         name: String,
942     }
943 
944     let package = Package {
945         name: "foo".to_owned(),
946     };
947     let raw = toml::to_string_pretty(&package).unwrap();
948     snapbox::assert_eq(
949         r#"name = "foo"
950 "#,
951         raw,
952     );
953 }
954 
955 #[test]
newline_table()956 fn newline_table() {
957     #[derive(Debug, Serialize, Deserialize)]
958     struct Manifest {
959         package: Package,
960     }
961 
962     #[derive(Debug, Serialize, Deserialize)]
963     struct Package {
964         name: String,
965     }
966 
967     let package = Manifest {
968         package: Package {
969             name: "foo".to_owned(),
970         },
971     };
972     let raw = toml::to_string_pretty(&package).unwrap();
973     snapbox::assert_eq(
974         r#"[package]
975 name = "foo"
976 "#,
977         raw,
978     );
979 }
980 
981 #[test]
newline_dotted_table()982 fn newline_dotted_table() {
983     #[derive(Debug, Serialize, Deserialize)]
984     struct Manifest {
985         profile: Profile,
986     }
987 
988     #[derive(Debug, Serialize, Deserialize)]
989     struct Profile {
990         dev: Dev,
991     }
992 
993     #[derive(Debug, Serialize, Deserialize)]
994     struct Dev {
995         debug: U32OrBool,
996     }
997 
998     #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
999     #[serde(untagged, expecting = "expected a boolean or an integer")]
1000     pub enum U32OrBool {
1001         U32(u32),
1002         Bool(bool),
1003     }
1004 
1005     let package = Manifest {
1006         profile: Profile {
1007             dev: Dev {
1008                 debug: U32OrBool::Bool(true),
1009             },
1010         },
1011     };
1012     let raw = toml::to_string_pretty(&package).unwrap();
1013     snapbox::assert_eq(
1014         r#"[profile.dev]
1015 debug = true
1016 "#,
1017         raw,
1018     );
1019 }
1020 
1021 #[test]
newline_mixed_tables()1022 fn newline_mixed_tables() {
1023     #[derive(Debug, Serialize, Deserialize)]
1024     struct Manifest {
1025         cargo_features: Vec<String>,
1026         package: Package,
1027         profile: Profile,
1028     }
1029 
1030     #[derive(Debug, Serialize, Deserialize)]
1031     struct Package {
1032         name: String,
1033         version: String,
1034         authors: Vec<String>,
1035     }
1036 
1037     #[derive(Debug, Serialize, Deserialize)]
1038     struct Profile {
1039         dev: Dev,
1040     }
1041 
1042     #[derive(Debug, Serialize, Deserialize)]
1043     struct Dev {
1044         debug: U32OrBool,
1045     }
1046 
1047     #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)]
1048     #[serde(untagged, expecting = "expected a boolean or an integer")]
1049     pub enum U32OrBool {
1050         U32(u32),
1051         Bool(bool),
1052     }
1053 
1054     let package = Manifest {
1055         cargo_features: vec![],
1056         package: Package {
1057             name: "foo".to_owned(),
1058             version: "1.0.0".to_owned(),
1059             authors: vec![],
1060         },
1061         profile: Profile {
1062             dev: Dev {
1063                 debug: U32OrBool::Bool(true),
1064             },
1065         },
1066     };
1067     let raw = toml::to_string_pretty(&package).unwrap();
1068     snapbox::assert_eq(
1069         r#"cargo_features = []
1070 
1071 [package]
1072 name = "foo"
1073 version = "1.0.0"
1074 authors = []
1075 
1076 [profile.dev]
1077 debug = true
1078 "#,
1079         raw,
1080     );
1081 }
1082 
1083 #[test]
integer_min()1084 fn integer_min() {
1085     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
1086     struct Foo {
1087         a_b: i64,
1088     }
1089 
1090     equivalent! {
1091         Foo { a_b: i64::MIN },
1092         map! { a_b: Value::Integer(i64::MIN) },
1093     }
1094 }
1095 
1096 #[test]
integer_too_big()1097 fn integer_too_big() {
1098     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
1099     struct Foo {
1100         a_b: u64,
1101     }
1102 
1103     let native = Foo { a_b: u64::MAX };
1104     let err = Table::try_from(native.clone()).unwrap_err();
1105     snapbox::assert_eq("u64 value was too large", err.to_string());
1106     let err = toml::to_string(&native).unwrap_err();
1107     snapbox::assert_eq("out-of-range value for u64 type", err.to_string());
1108 }
1109 
1110 #[test]
integer_max()1111 fn integer_max() {
1112     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
1113     struct Foo {
1114         a_b: i64,
1115     }
1116 
1117     equivalent! {
1118         Foo { a_b: i64::MAX },
1119         map! { a_b: Value::Integer(i64::MAX) },
1120     }
1121 }
1122 
1123 #[test]
float_min()1124 fn float_min() {
1125     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
1126     struct Foo {
1127         a_b: f64,
1128     }
1129 
1130     equivalent! {
1131         Foo { a_b: f64::MIN },
1132         map! { a_b: Value::Float(f64::MIN) },
1133     }
1134 }
1135 
1136 #[test]
float_max()1137 fn float_max() {
1138     #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
1139     struct Foo {
1140         a_b: f64,
1141     }
1142 
1143     equivalent! {
1144         Foo { a_b: f64::MAX },
1145         map! { a_b: Value::Float(f64::MAX) },
1146     }
1147 }
1148 
1149 #[test]
unsupported_root_type()1150 fn unsupported_root_type() {
1151     let native = "value";
1152     let err = toml::to_string_pretty(&native).unwrap_err();
1153     snapbox::assert_eq("unsupported rust type", err.to_string());
1154 }
1155 
1156 #[test]
unsupported_nested_type()1157 fn unsupported_nested_type() {
1158     #[derive(Debug, Serialize, Deserialize)]
1159     struct Foo {
1160         unused: (),
1161     }
1162 
1163     let native = Foo { unused: () };
1164     let err = toml::to_string_pretty(&native).unwrap_err();
1165     snapbox::assert_eq("unsupported unit type", err.to_string());
1166 }
1167 
1168 #[test]
table_type_enum_regression_issue_388()1169 fn table_type_enum_regression_issue_388() {
1170     #[derive(Deserialize)]
1171     struct DataFile {
1172         #[allow(dead_code)]
1173         data: Compare,
1174     }
1175 
1176     #[derive(Deserialize)]
1177     enum Compare {
1178         Gt(u32),
1179     }
1180 
1181     let dotted_table = r#"
1182         data.Gt = 5
1183         "#;
1184     assert!(toml::from_str::<DataFile>(dotted_table).is_ok());
1185 
1186     let inline_table = r#"
1187         data = { Gt = 5 }
1188         "#;
1189     assert!(toml::from_str::<DataFile>(inline_table).is_ok());
1190 }
1191 
1192 #[test]
serialize_datetime_issue_333()1193 fn serialize_datetime_issue_333() {
1194     use toml::{to_string, value::Date, value::Datetime};
1195 
1196     #[derive(Serialize)]
1197     struct Struct {
1198         date: Datetime,
1199     }
1200 
1201     let toml = to_string(&Struct {
1202         date: Datetime {
1203             date: Some(Date {
1204                 year: 2022,
1205                 month: 1,
1206                 day: 1,
1207             }),
1208             time: None,
1209             offset: None,
1210         },
1211     })
1212     .unwrap();
1213     assert_eq!(toml, "date = 2022-01-01\n");
1214 }
1215 
1216 #[test]
datetime_offset_issue_496()1217 fn datetime_offset_issue_496() {
1218     let original = "value = 1911-01-01T10:11:12-00:36\n";
1219     let toml = original.parse::<toml::Table>().unwrap();
1220     let output = toml.to_string();
1221     snapbox::assert_eq(original, output);
1222 }
1223 
1224 #[test]
serialize_array_with_none_value()1225 fn serialize_array_with_none_value() {
1226     #[derive(Serialize)]
1227     struct Document {
1228         values: Vec<Option<usize>>,
1229     }
1230 
1231     let input = Document {
1232         values: vec![Some(1), Some(2), Some(3)],
1233     };
1234     let expected = "values = [1, 2, 3]\n";
1235     let raw = toml::to_string(&input).unwrap();
1236     snapbox::assert_eq(expected, raw);
1237 
1238     let input = Document {
1239         values: vec![Some(1), None, Some(3)],
1240     };
1241     let err = toml::to_string(&input).unwrap_err();
1242     snapbox::assert_eq("unsupported None value", err.to_string());
1243 }
1244 
1245 #[test]
serialize_array_with_optional_struct_field()1246 fn serialize_array_with_optional_struct_field() {
1247     #[derive(Debug, Deserialize, Serialize)]
1248     struct Document {
1249         values: Vec<OptionalField>,
1250     }
1251 
1252     #[derive(Debug, Deserialize, Serialize)]
1253     struct OptionalField {
1254         x: u8,
1255         y: Option<u8>,
1256     }
1257 
1258     let input = Document {
1259         values: vec![
1260             OptionalField { x: 0, y: Some(4) },
1261             OptionalField { x: 2, y: Some(5) },
1262             OptionalField { x: 3, y: Some(7) },
1263         ],
1264     };
1265     let expected = "\
1266 [[values]]
1267 x = 0
1268 y = 4
1269 
1270 [[values]]
1271 x = 2
1272 y = 5
1273 
1274 [[values]]
1275 x = 3
1276 y = 7
1277 ";
1278     let raw = toml::to_string(&input).unwrap();
1279     snapbox::assert_eq(expected, raw);
1280 
1281     let input = Document {
1282         values: vec![
1283             OptionalField { x: 0, y: Some(4) },
1284             OptionalField { x: 2, y: None },
1285             OptionalField { x: 3, y: Some(7) },
1286         ],
1287     };
1288     let expected = "\
1289 [[values]]
1290 x = 0
1291 y = 4
1292 
1293 [[values]]
1294 x = 2
1295 
1296 [[values]]
1297 x = 3
1298 y = 7
1299 ";
1300     let raw = toml::to_string(&input).unwrap();
1301     snapbox::assert_eq(expected, raw);
1302 }
1303 
1304 #[test]
serialize_array_with_enum_of_optional_struct_field()1305 fn serialize_array_with_enum_of_optional_struct_field() {
1306     #[derive(Debug, Deserialize, Serialize)]
1307     struct Document {
1308         values: Vec<Choice>,
1309     }
1310 
1311     #[derive(Debug, Deserialize, Serialize)]
1312     enum Choice {
1313         Optional(OptionalField),
1314         Empty,
1315     }
1316 
1317     #[derive(Debug, Deserialize, Serialize)]
1318     struct OptionalField {
1319         x: u8,
1320         y: Option<u8>,
1321     }
1322 
1323     let input = Document {
1324         values: vec![
1325             Choice::Optional(OptionalField { x: 0, y: Some(4) }),
1326             Choice::Empty,
1327             Choice::Optional(OptionalField { x: 2, y: Some(5) }),
1328             Choice::Optional(OptionalField { x: 3, y: Some(7) }),
1329         ],
1330     };
1331     let expected = "values = [{ Optional = { x = 0, y = 4 } }, \"Empty\", { Optional = { x = 2, y = 5 } }, { Optional = { x = 3, y = 7 } }]
1332 ";
1333     let raw = toml::to_string(&input).unwrap();
1334     snapbox::assert_eq(expected, raw);
1335 
1336     let input = Document {
1337         values: vec![
1338             Choice::Optional(OptionalField { x: 0, y: Some(4) }),
1339             Choice::Empty,
1340             Choice::Optional(OptionalField { x: 2, y: None }),
1341             Choice::Optional(OptionalField { x: 3, y: Some(7) }),
1342         ],
1343     };
1344     let expected = "values = [{ Optional = { x = 0, y = 4 } }, \"Empty\", { Optional = { x = 2 } }, { Optional = { x = 3, y = 7 } }]
1345 ";
1346     let raw = toml::to_string(&input).unwrap();
1347     snapbox::assert_eq(expected, raw);
1348 }
1349 
1350 #[test]
span_for_sequence_as_map()1351 fn span_for_sequence_as_map() {
1352     #[allow(dead_code)]
1353     #[derive(Deserialize)]
1354     struct Manifest {
1355         package: Package,
1356         bench: Vec<Bench>,
1357     }
1358 
1359     #[derive(Deserialize)]
1360     struct Package {}
1361 
1362     #[derive(Deserialize)]
1363     struct Bench {}
1364 
1365     let raw = r#"
1366 [package]
1367 name = "foo"
1368 version = "0.1.0"
1369 edition = "2021"
1370 [[bench.foo]]
1371 "#;
1372     let err = match toml::from_str::<Manifest>(raw) {
1373         Ok(_) => panic!("should fail"),
1374         Err(err) => err,
1375     };
1376     assert_eq!(err.span(), Some(61..66));
1377 }
1378