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