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