1#[doc(hidden)]
267pub use toml_example_derive::TomlExample;
268pub mod traits;
269pub use traits::*;
270
271#[cfg(test)]
272mod tests {
273 use crate as toml_example;
274 use serde_derive::Deserialize;
275 use std::collections::HashMap;
276 use toml_example::TomlExample;
277
278 #[test]
279 fn basic() {
280 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
281 #[allow(dead_code)]
282 struct Config {
283 a: usize,
285 b: String,
287 }
288 assert_eq!(
289 Config::toml_example(),
290 r#"# Config.a should be a number
291a = 0
292
293# Config.b should be a string
294b = ""
295
296"#
297 );
298 assert_eq!(
299 toml::from_str::<Config>(&Config::toml_example()).unwrap(),
300 Config::default()
301 );
302 let mut tmp_file = std::env::temp_dir();
303 tmp_file.push("config.toml");
304 Config::to_toml_example(&tmp_file.as_path().to_str().unwrap()).unwrap();
305 assert_eq!(
306 std::fs::read_to_string(tmp_file).unwrap(),
307 r#"# Config.a should be a number
308a = 0
309
310# Config.b should be a string
311b = ""
312
313"#
314 );
315 }
316
317 #[test]
318 fn hinden_doc() {
319 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
320 #[allow(dead_code)]
321 struct Config {
322 a: usize,
325
326 b: String,
329 }
330 assert_eq!(
331 Config::toml_example(),
332 r#"# Config.a should be a number
333a = 0
334
335# Config.b should be a string
336b = ""
337
338"#
339 );
340 }
341
342 #[test]
343 fn option() {
344 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
345 #[allow(dead_code)]
346 struct Config {
347 a: Option<usize>,
349 b: Option<String>,
351 }
352 assert_eq!(
353 Config::toml_example(),
354 r#"# Config.a is an optional number
355# a = 0
356
357# Config.b is an optional string
358# b = ""
359
360"#
361 );
362 assert_eq!(
363 toml::from_str::<Config>(&Config::toml_example()).unwrap(),
364 Config::default()
365 )
366 }
367
368 #[test]
369 fn vec() {
370 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
371 #[allow(dead_code)]
372 struct Config {
373 a: Vec<usize>,
375 b: Vec<String>,
377 c: Vec<Option<usize>>,
379 d: Option<Vec<usize>>,
381 }
382 assert_eq!(
383 Config::toml_example(),
384 r#"# Config.a is a list of number
385a = [ 0, ]
386
387# Config.b is a list of string
388b = [ "", ]
389
390# Config.c
391c = [ 0, ]
392
393# Config.d
394# d = [ 0, ]
395
396"#
397 );
398 assert!(toml::from_str::<Config>(&Config::toml_example()).is_ok())
399 }
400
401 #[test]
402 fn hashset_btreeset() {
403 use std::collections::{BTreeSet, HashSet};
404
405 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
406 #[allow(dead_code)]
407 struct Config {
408 a: HashSet<String>,
410 b: BTreeSet<usize>,
412 c: Option<HashSet<String>>,
414 }
415 assert_eq!(
416 Config::toml_example(),
417 r#"# Config.a is a set of string
418a = [ "", ]
419
420# Config.b is a set of number
421b = [ 0, ]
422
423# Config.c is optional
424# c = [ "", ]
425
426"#
427 );
428 assert!(toml::from_str::<Config>(&Config::toml_example()).is_ok())
429 }
430
431 #[test]
432 fn struct_doc() {
433 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
436 #[allow(dead_code)]
437 struct Config {
438 a: usize,
441 }
442 assert_eq!(
443 Config::toml_example(),
444 r#"# Config is to arrange something or change the controls on a computer or other device
445# so that it can be used in a particular way
446# Config.a should be a number
447# the number should be greater or equal zero
448a = 0
449
450"#
451 );
452 assert_eq!(
453 toml::from_str::<Config>(&Config::toml_example()).unwrap(),
454 Config::default()
455 )
456 }
457
458 #[test]
459 fn struct_doc_skip() {
460 #[derive(TomlExample)]
461 #[toml_example(doc_skip_prefix = "\\")]
462 #[allow(dead_code)]
463 struct Config {
464 a: u8,
469 #[toml_example(doc_skip_prefix = "dev-doc:")]
470 b: u8,
475 }
476 assert_eq!(
477 Config::toml_example(),
478 r#"# This comment will be shown.
479# dev-doc: this was only specified for b
480a = 0
481
482# This is a toml comment.
483b = 0
484
485"#
486 );
487 }
488
489 #[test]
490 fn serde_default() {
491 fn default_a() -> usize {
492 7
493 }
494 fn default_b() -> String {
495 "default".into()
496 }
497 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
498 #[allow(dead_code)]
499 struct Config {
500 #[serde(default = "default_a")]
502 a: usize,
503 #[serde(default = "default_b")]
505 b: String,
506 #[serde(default)]
508 c: usize,
509 #[serde(default)]
511 d: String,
512 #[serde(default)]
513 e: Option<usize>,
514 }
515 assert_eq!(
516 Config::toml_example(),
517 r#"# Config.a should be a number
518a = 7
519
520# Config.b should be a string
521b = "default"
522
523# Config.c should be a number
524c = 0
525
526# Config.d should be a string
527d = ""
528
529# e = 0
530
531"#
532 );
533 }
534
535 #[test]
536 fn toml_example_default() {
537 fn default_str() -> String {
538 "seven".into()
539 }
540 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
541 #[allow(dead_code)]
542 struct Config {
543 #[toml_example(default = 7)]
545 a: usize,
546 #[toml_example(default = "default")]
548 #[serde(default = "default_str")]
549 b: String,
550 #[serde(default = "default_str")]
551 #[toml_example(default = "default")]
552 c: String,
553 #[toml_example(default = [ "default", ])]
554 e: Vec<String>,
555 #[toml_example(
556 default = "super looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong string"
557 )]
558 f: String,
559 #[toml_example(default = [ "super looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong string",
560 "second",
561 "third",
562 ])]
563 g: Vec<String>,
564 #[toml_example(default = "#FAFAFA")]
566 color: String,
567 }
568 assert_eq!(
569 Config::toml_example(),
570 r##"# Config.a should be a number
571a = 7
572
573# Config.b should be a string
574b = "seven"
575
576c = "default"
577
578e = ["default",]
579
580f = "super looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong string"
581
582g = ["super looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong string",
583"second", "third",]
584
585# Config.color should be a hex color code
586color = "#FAFAFA"
587
588"##
589 );
590 }
591
592 #[test]
593 fn struct_serde_default() {
594 #[derive(TomlExample, Deserialize, PartialEq)]
595 #[serde(default)]
596 struct Foo {
597 bar: String,
598 #[serde(default)]
599 x: usize,
600 }
601 impl Default for Foo {
602 fn default() -> Self {
603 Foo {
604 bar: String::from("hello world"),
605 x: 12,
606 }
607 }
608 }
609 assert_eq!(
610 Foo::toml_example(),
611 r##"bar = "hello world"
612
613x = 0
614
615"##
616 );
617 }
618
619 #[test]
620 fn struct_serde_default_fn() {
621 #[derive(TomlExample, Deserialize, PartialEq)]
622 #[serde(default = "default")]
623 struct Foo {
624 bar: String,
625 #[toml_example(default = "field override")]
626 baz: String,
627 }
628 fn default() -> Foo {
629 Foo {
630 bar: String::from("hello world"),
631 baz: String::from("custom default"),
632 }
633 }
634 assert_eq!(
635 Foo::toml_example(),
636 r##"bar = "hello world"
637
638baz = "field override"
639
640"##
641 );
642 }
643
644 #[test]
645 fn struct_toml_example_default() {
646 #[derive(TomlExample, Deserialize, PartialEq)]
647 #[toml_example(default)]
648 struct Foo {
649 #[serde(default = "paru")]
650 yay: &'static str,
651 aur_is_useful: bool,
652 }
653 impl Default for Foo {
654 fn default() -> Self {
655 Foo {
656 yay: "yay!",
657 aur_is_useful: true,
658 }
659 }
660 }
661 fn paru() -> &'static str {
662 "no, paru!"
663 }
664 assert_eq!(
665 Foo::toml_example(),
666 r##"yay = "no, paru!"
667
668aur_is_useful = true
669
670"##
671 );
672 }
673
674 #[test]
675 fn no_nesting() {
676 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
678 #[allow(dead_code)]
679 struct Inner {
680 a: usize,
682 }
683 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
684 #[allow(dead_code)]
685 struct Outer {
686 inner: Inner,
688 }
689 assert_eq!(
690 Outer::toml_example(),
691 r#"# Outer.inner is a complex struct
692inner = ""
693
694"#
695 );
696 }
697
698 #[test]
699 fn nesting() {
700 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
702 #[allow(dead_code)]
703 struct Inner {
704 a: usize,
706 }
707 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
708 #[allow(dead_code)]
709 struct Outer {
710 #[toml_example(nesting)]
712 inner: Inner,
713 }
714 assert_eq!(
715 Outer::toml_example(),
716 r#"# Outer.inner is a complex struct
717# Inner is a config live in Outer
718[inner]
719# Inner.a should be a number
720a = 0
721
722"#
723 );
724 assert_eq!(
725 toml::from_str::<Outer>(&Outer::toml_example()).unwrap(),
726 Outer::default()
727 );
728 }
729
730 #[test]
731 fn nesting_by_section() {
732 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
734 #[allow(dead_code)]
735 struct Inner {
736 a: usize,
738 }
739 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
740 #[allow(dead_code)]
741 struct Outer {
742 #[toml_example(nesting = section)]
744 inner: Inner,
745 }
746 assert_eq!(
747 Outer::toml_example(),
748 r#"# Outer.inner is a complex struct
749# Inner is a config live in Outer
750[inner]
751# Inner.a should be a number
752a = 0
753
754"#
755 );
756 assert_eq!(
757 toml::from_str::<Outer>(&Outer::toml_example()).unwrap(),
758 Outer::default()
759 );
760 }
761
762 #[test]
763 fn nesting_by_prefix() {
764 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
766 #[allow(dead_code)]
767 struct Inner {
768 a: usize,
770 }
771 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
772 #[allow(dead_code)]
773 struct Outer {
774 #[toml_example(nesting = prefix)]
776 inner: Inner,
777 }
778 assert_eq!(
779 Outer::toml_example(),
780 r#"# Outer.inner is a complex struct
781# Inner is a config live in Outer
782# Inner.a should be a number
783inner.a = 0
784
785"#
786 );
787 assert_eq!(
788 toml::from_str::<Outer>(&Outer::toml_example()).unwrap(),
789 Outer::default()
790 );
791 }
792
793 #[test]
794 fn nesting_vector() {
795 #[derive(TomlExample, Deserialize)]
797 #[allow(dead_code)]
798 struct Service {
799 port: usize,
801 }
802 #[derive(TomlExample, Deserialize)]
803 #[allow(dead_code)]
804 struct Node {
805 #[toml_example(nesting)]
807 services: Vec<Service>,
808 }
809 assert_eq!(
810 Node::toml_example(),
811 r#"# Services are running in the node
812# Service with specific port
813[[services]]
814# port should be a number
815port = 0
816
817"#
818 );
819 assert!(toml::from_str::<Node>(&Node::toml_example()).is_ok());
820 }
821
822 #[test]
823 fn nesting_hashmap() {
824 #[derive(TomlExample, Deserialize)]
826 #[allow(dead_code)]
827 struct Service {
828 port: usize,
830 }
831 #[derive(TomlExample, Deserialize)]
832 #[allow(dead_code)]
833 struct Node {
834 #[toml_example(nesting)]
836 services: HashMap<String, Service>,
837 }
838 assert_eq!(
839 Node::toml_example(),
840 r#"# Services are running in the node
841# Service with specific port
842[services.example]
843# port should be a number
844port = 0
845
846"#
847 );
848 assert!(toml::from_str::<Node>(&Node::toml_example()).is_ok());
849 }
850
851 #[test]
852 fn optional_nesting() {
853 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
855 #[allow(dead_code)]
856 struct Inner {
857 a: usize,
859 }
860 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
861 #[allow(dead_code)]
862 struct Outer {
863 #[toml_example(nesting)]
865 inner: Option<Inner>,
866 }
867 assert_eq!(
868 Outer::toml_example(),
869 r#"# Outer.inner is a complex struct
870# Inner is a config live in Outer
871# [inner]
872# Inner.a should be a number
873# a = 0
874
875"#
876 );
877 assert_eq!(
878 toml::from_str::<Outer>(&Outer::toml_example()).unwrap(),
879 Outer::default()
880 );
881 }
882
883 #[test]
884 fn optional_nesting_by_section() {
885 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
887 #[allow(dead_code)]
888 struct Inner {
889 a: usize,
891 }
892 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
893 #[allow(dead_code)]
894 struct Outer {
895 #[toml_example(nesting = section)]
897 inner: Option<Inner>,
898 }
899 assert_eq!(
900 Outer::toml_example(),
901 r#"# Outer.inner is a complex struct
902# Inner is a config live in Outer
903# [inner]
904# Inner.a should be a number
905# a = 0
906
907"#
908 );
909 assert_eq!(
910 toml::from_str::<Outer>(&Outer::toml_example()).unwrap(),
911 Outer::default()
912 );
913 }
914
915 #[test]
916 fn optional_nesting_by_prefix() {
917 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
919 #[allow(dead_code)]
920 struct Inner {
921 a: usize,
923 }
924 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
925 #[allow(dead_code)]
926 struct Outer {
927 #[toml_example(nesting = prefix)]
929 inner: Option<Inner>,
930 }
931 assert_eq!(
932 Outer::toml_example(),
933 r#"# Outer.inner is a complex struct
934# Inner is a config live in Outer
935# Inner.a should be a number
936# inner.a = 0
937
938"#
939 );
940 assert_eq!(
941 toml::from_str::<Outer>(&Outer::toml_example()).unwrap(),
942 Outer::default()
943 );
944 }
945
946 #[test]
947 fn optional_nesting_vector() {
948 #[derive(TomlExample, Deserialize)]
950 #[allow(dead_code)]
951 struct Service {
952 port: usize,
954 }
955 #[derive(TomlExample, Deserialize)]
956 #[allow(dead_code)]
957 struct Node {
958 #[toml_example(nesting)]
960 services: Option<Vec<Service>>,
961 }
962 assert_eq!(
963 Node::toml_example(),
964 r#"# Services are running in the node
965# Service with specific port
966# [[services]]
967# port should be a number
968# port = 0
969
970"#
971 );
972 assert!(toml::from_str::<Node>(&Node::toml_example()).is_ok());
973 }
974
975 #[test]
976 fn optional_nesting_hashmap() {
977 #[derive(TomlExample, Deserialize)]
979 #[allow(dead_code)]
980 struct Service {
981 port: usize,
983 }
984 #[derive(TomlExample, Deserialize)]
985 #[allow(dead_code)]
986 struct Node {
987 #[toml_example(nesting)]
989 services: Option<HashMap<String, Service>>,
990 }
991 assert_eq!(
992 Node::toml_example(),
993 r#"# Services are running in the node
994# Service with specific port
995# [services.example]
996# port should be a number
997# port = 0
998
999"#
1000 );
1001 assert!(toml::from_str::<Node>(&Node::toml_example()).is_ok());
1002 }
1003
1004 #[test]
1005 fn nesting_hashmap_with_default_name() {
1006 #[derive(TomlExample, Deserialize)]
1008 #[allow(dead_code)]
1009 struct Service {
1010 #[toml_example(default = 80)]
1012 port: usize,
1013 }
1014 #[derive(TomlExample, Deserialize)]
1015 #[allow(dead_code)]
1016 struct Node {
1017 #[toml_example(nesting)]
1019 #[toml_example(default = http)]
1020 services: HashMap<String, Service>,
1021 }
1022 assert_eq!(
1023 Node::toml_example(),
1024 r#"# Services are running in the node
1025# Service with specific port
1026[services.http]
1027# port should be a number
1028port = 80
1029
1030"#
1031 );
1032 assert!(toml::from_str::<Node>(&Node::toml_example()).is_ok());
1033 }
1034
1035 #[test]
1036 fn nesting_hashmap_with_dash_name() {
1037 #[derive(TomlExample, Deserialize)]
1039 #[allow(dead_code)]
1040 struct Service {
1041 #[toml_example(default = 80)]
1043 port: usize,
1044 }
1045 #[derive(TomlExample, Deserialize)]
1046 #[allow(dead_code)]
1047 struct Node {
1048 #[toml_example(nesting)]
1050 #[toml_example(default = http.01)]
1051 services: HashMap<String, Service>,
1052 }
1053 assert_eq!(
1054 Node::toml_example(),
1055 r#"# Services are running in the node
1056# Service with specific port
1057[services.http-01]
1058# port should be a number
1059port = 80
1060
1061"#
1062 );
1063 assert!(toml::from_str::<Node>(&Node::toml_example()).is_ok());
1064 }
1065
1066 #[test]
1067 fn recursive_nesting() {
1068 #[derive(TomlExample, Default, Debug, Deserialize, PartialEq)]
1069 struct Outer {
1070 #[toml_example(nesting)]
1071 _middle: Middle,
1072 }
1073 #[derive(TomlExample, Default, Debug, Deserialize, PartialEq)]
1074 struct Middle {
1075 #[toml_example(nesting)]
1076 _inner: Inner,
1077 }
1078 #[derive(TomlExample, Default, Debug, Deserialize, PartialEq)]
1079 struct Inner {
1080 _value: usize,
1081 }
1082 let example = Outer::toml_example();
1083 assert_eq!(toml::from_str::<Outer>(&example).unwrap(), Outer::default());
1084 assert_eq!(
1085 example,
1086 r#"[_middle]
1087[_middle._inner]
1088_value = 0
1089
1090"#
1091 );
1092 }
1093
1094 #[test]
1095 fn recursive_nesting_and_flatten() {
1096 #[derive(TomlExample, Default, Debug, Deserialize, PartialEq)]
1097 struct Outer {
1098 #[toml_example(nesting)]
1099 middle: Middle,
1100 #[toml_example(default = false)]
1101 flag: bool,
1103 }
1104 #[derive(TomlExample, Default, Debug, Deserialize, PartialEq)]
1105 struct Middle {
1106 #[serde(flatten)]
1107 #[toml_example(nesting)]
1108 inner: Inner,
1110 }
1111 #[derive(TomlExample, Default, Debug, Deserialize, PartialEq)]
1112 struct Inner {
1113 #[toml_example(nesting)]
1114 extra: Extra,
1116 value: usize,
1118 }
1119 #[derive(TomlExample, Debug, Deserialize, PartialEq)]
1120 #[toml_example(default)]
1121 struct Extra {
1122 name: String,
1123 }
1124 impl Default for Extra {
1125 fn default() -> Self {
1126 Self {
1127 name: String::from("ferris"),
1128 }
1129 }
1130 }
1131 let example = Outer::toml_example();
1132 assert_eq!(toml::from_str::<Outer>(&example).unwrap(), Outer::default());
1133 assert_eq!(
1134 example,
1135 r#"# Some toggle
1136flag = false
1137
1138[middle]
1139# Values of [Inner] are flattened into [Middle]
1140# `value` is defined below `extra`, but shown above
1141value = 0
1142
1143# [Extra] is flattened into [Middle]
1144[middle.extra]
1145name = "ferris"
1146
1147"#
1148 );
1149 }
1150
1151 #[test]
1152 fn require() {
1153 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
1154 #[allow(dead_code)]
1155 struct Config {
1156 #[toml_example(require)]
1158 a: Option<usize>,
1159 #[toml_example(require)]
1161 b: Option<String>,
1162 #[toml_example(require)]
1163 #[toml_example(default = "third")]
1164 c: Option<String>,
1165 }
1166 assert_eq!(
1167 Config::toml_example(),
1168 r#"# Config.a is an optional number
1169a = 0
1170
1171# Config.b is an optional string
1172b = ""
1173
1174c = "third"
1175
1176"#
1177 );
1178 }
1179
1180 #[test]
1181 fn skip() {
1182 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
1183 #[allow(dead_code)]
1184 struct Config {
1185 a: usize,
1187 #[toml_example(skip)]
1188 b: usize,
1189 #[serde(skip)]
1190 c: usize,
1191 #[serde(skip_deserializing)]
1192 d: usize,
1193 }
1194 assert_eq!(
1195 Config::toml_example(),
1196 r#"# Config.a is a number
1197a = 0
1198
1199"#
1200 );
1201 }
1202
1203 #[test]
1204 fn is_enum() {
1205 fn b() -> AB {
1206 AB::B
1207 }
1208 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
1209 #[allow(dead_code)]
1210 struct Config {
1211 #[toml_example(enum, default)]
1213 ab: AB,
1214 #[toml_example(is_enum)]
1216 #[serde(default)]
1217 ab2: AB,
1218 #[toml_example(is_enum)]
1220 #[serde(default = "b")]
1221 ab3: AB,
1222 }
1223 #[derive(Debug, Default, Deserialize, PartialEq)]
1224 enum AB {
1225 #[default]
1226 A,
1227 B,
1228 }
1229 assert_eq!(
1230 Config::toml_example(),
1231 r#"# Config.ab is an enum
1232ab = "A"
1233
1234# Config.ab2 is an enum too
1235ab2 = "A"
1236
1237# Config.ab3 is an enum as well
1238ab3 = "B"
1239
1240"#
1241 );
1242 }
1243
1244 #[test]
1245 fn flatten() {
1246 #[derive(TomlExample)]
1247 struct ItemWrapper {
1248 #[toml_example(flatten, nesting)]
1249 _item: Item,
1250 }
1251 #[derive(TomlExample)]
1252 struct Item {
1253 _value: String,
1254 }
1255 assert_eq!(ItemWrapper::toml_example(), Item::toml_example());
1256 }
1257
1258 #[test]
1259 fn flatten_order() {
1260 #[derive(TomlExample)]
1261 struct Outer {
1262 #[toml_example(nesting)]
1263 _nested: Item,
1264 #[toml_example(flatten, nesting)]
1265 _flattened: Item,
1266 }
1267 #[derive(TomlExample)]
1268 struct Item {
1269 _value: String,
1270 }
1271 assert_eq!(
1272 Outer::toml_example(),
1273 r#"_value = ""
1274
1275[_nested]
1276_value = ""
1277
1278"#
1279 );
1280 }
1281
1282 #[test]
1283 fn multi_attr_escaping() {
1284 #[derive(TomlExample, Deserialize, PartialEq)]
1285 struct ConfigWrapper {
1286 #[toml_example(default = ["hello", "{nice :)\""], require)]
1287 vec: Option<Vec<String>>,
1288
1289 #[toml_example(require, default = ["\"\\\n}])", "super (fancy\\! :-) )"])]
1290 list: Option<[String; 2]>,
1291 }
1292
1293 assert_eq!(
1294 ConfigWrapper::toml_example(),
1295 r#"vec = ["hello", "{nice :)\""]
1296
1297list = ["\"\\\n}])", "super (fancy\\! :-) )"]
1298
1299"#
1300 );
1301 }
1302
1303 #[test]
1304 fn r_sharp_field() {
1305 #[derive(TomlExample)]
1306 #[allow(dead_code)]
1307 struct Config {
1308 r#type: usize,
1310 }
1311 assert_eq!(
1312 Config::toml_example(),
1313 r#"# Config.type is a number
1314type = 0
1315
1316"#
1317 );
1318 }
1319
1320 #[test]
1321 fn non_nesting_field_should_be_first() {
1322 #[derive(TomlExample)]
1323 #[allow(dead_code)]
1324 struct Foo {
1325 a: String,
1326 }
1327
1328 #[derive(TomlExample)]
1329 #[allow(dead_code)]
1330 struct Bar {
1331 #[toml_example(nesting)]
1332 foo: Foo,
1333 b: String,
1334 }
1335
1336 assert_eq!(
1337 Bar::toml_example(),
1338 r#"b = ""
1339
1340[foo]
1341a = ""
1342
1343"#
1344 );
1345 }
1346
1347 #[test]
1348 fn rename() {
1349 use serde::Serialize;
1350
1351 #[derive(Deserialize, Serialize, TomlExample)]
1352 struct Config {
1353 #[serde(rename = "bb")]
1354 b: usize,
1355 }
1356 assert_eq!(
1357 Config::toml_example(),
1358 r#"bb = 0
1359
1360"#
1361 );
1362 }
1363
1364 #[test]
1365 fn rename_all() {
1366 use serde::Serialize;
1367
1368 #[derive(Deserialize, Serialize, TomlExample)]
1369 #[serde(rename_all = "kebab-case")]
1370 struct Config {
1371 a_a: usize,
1372 }
1373 assert_eq!(
1374 Config::toml_example(),
1375 r#"a-a = 0
1376
1377"#
1378 );
1379 }
1380
1381 #[test]
1382 fn hashset_and_struct() {
1383 use std::collections::HashMap;
1384
1385 #[derive(TomlExample)]
1386 #[allow(dead_code)]
1387 struct Foo {
1388 a: String,
1389 }
1390
1391 #[derive(TomlExample)]
1392 #[allow(dead_code)]
1393 struct Bar {
1394 #[toml_example(nesting)]
1396 default: Foo,
1397
1398 #[toml_example(nesting)]
1400 instance: HashMap<String, Foo>,
1401 }
1402
1403 assert_eq!(
1404 Bar::toml_example(),
1405 r#"# Default instances doc
1406[default]
1407a = ""
1408
1409# Instances doc
1410[instance.example]
1411a = ""
1412
1413"#
1414 );
1415 }
1416
1417 #[test]
1418 fn optional_long_vector_field() {
1419 #[derive(TomlExample)]
1420 #[allow(dead_code)]
1421 struct Foo {
1422 #[toml_example(default = ["a", "b", "c"])]
1424 array_value_example: Option<Vec<String>>,
1425
1426 #[toml_example(default = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
1428 "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
1429 "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
1430 "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
1431 ])]
1432 array_long_value_example: Option<Vec<String>>,
1433
1434 #[toml_example(default = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"])]
1436 array_long_value_no_space_example: Option<Vec<String>>,
1437 }
1438 assert_eq!(
1439 Foo::toml_example(),
1440 r#"# Option<Vec<String>>, with small default values
1441# array_value_example = ["a", "b", "c"]
1442
1443# Option<Vec<String>>, with long default values
1444# array_long_value_example = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
1445# "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
1446# "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
1447# "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"]
1448
1449# Option<Vec<String>>, with a long default value but no space after comma
1450# array_long_value_no_space_example = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"]
1451
1452"#
1453 );
1454 }
1455
1456 #[test]
1457 fn help() {
1458 #[derive(TomlExample, Deserialize, Default, PartialEq, Debug)]
1459 #[allow(dead_code)]
1460 #[toml_example(help = "This is the struct help text")]
1461 struct Config {
1462 #[toml_example(help = "This is the help text for a")]
1464 a: usize,
1465 #[toml_example(help = r#"This is the help text for b
1467Line two of help"#)]
1468 b: String,
1469 #[toml_example(help = "This is the help text for c", default = 42)]
1471 c: Option<usize>,
1472 }
1473 assert_eq!(
1474 Config::toml_example(),
1475 r#"# This is the struct help text
1476# This is the help text for a
1477a = 0
1478
1479# This is the help text for b
1480# Line two of help
1481b = ""
1482
1483# This is the help text for c
1484# c = 42
1485
1486"#
1487 );
1488 }
1489
1490 #[test]
1491 fn help_with_nesting() {
1492 use std::collections::HashMap;
1493
1494 #[derive(TomlExample)]
1496 #[allow(dead_code)]
1497 struct Service {
1498 #[toml_example(help = "Port number help text", default = 80)]
1500 port: usize,
1501 }
1502 #[derive(TomlExample)]
1503 #[allow(dead_code)]
1504 struct Node {
1505 #[toml_example(help = "Services help text", default = http, nesting)]
1507 services: HashMap<String, Service>,
1508 }
1509 assert_eq!(
1510 Node::toml_example(),
1511 r#"# Services help text
1512# Service doc string
1513[services.http]
1514# Port number help text
1515port = 80
1516
1517"#
1518 );
1519 }
1520}