1 module toml_foolery.decode.parse_toml_test; 2 3 import std.conv; 4 import std.datetime; 5 6 import toml_foolery.attributes.toml_name; 7 import toml_foolery.decode.parse_toml; 8 import toml_foolery.decode.exceptions; 9 10 11 version (unittest) 12 { 13 import std.array : staticArray; 14 import std.datetime; 15 16 import exceeds_expectations; 17 } 18 19 20 @("key re-declared as table from TOML readme") 21 unittest 22 { 23 struct S 24 { 25 struct Fruit { string apple; } 26 27 Fruit fruit; 28 } 29 30 try 31 { 32 S s = parseToml!S(` 33 [fruit] 34 apple = "red" 35 36 [fruit.apple] 37 texture = "smooth" 38 39 `); 40 assert(false, "Expected a TomlDecodingException to be thrown."); 41 } 42 catch (TomlDecodingException e) 43 { 44 // As expected 45 } 46 } 47 48 @("table re-declared as key") 49 unittest 50 { 51 struct S 52 { 53 struct Fruit 54 { 55 struct Apple { string texture; } 56 Apple apple; 57 } 58 59 Fruit fruit; 60 } 61 62 try 63 { 64 S s = parseToml!S(` 65 [fruit.apple] 66 texture = "smooth" 67 68 [fruit] 69 apple = "red" 70 `); 71 assert(false, "Expected a TomlDecodingException to be thrown."); 72 } 73 catch (TomlDecodingException e) 74 { 75 // As expected 76 } 77 } 78 79 @("super-table declared after sub-tables is ok (from TOML readme)") 80 unittest 81 { 82 struct S 83 { 84 struct X 85 { 86 struct Y 87 { 88 struct Z 89 { 90 struct W 91 { 92 int test1; 93 } 94 W w; 95 } 96 Z z; 97 } 98 Y y; // y, delilah? 99 int test2; 100 } 101 X x; 102 } 103 104 S s = parseToml!S(` 105 # [x] you 106 # [x.y] don't 107 # [x.y.z] need these 108 [x.y.z.w] # for this to work 109 test1 = 1 110 111 [x] # defining a super-table afterwards is ok 112 test2 = 2 113 `); 114 115 expect(s.x.y.z.w.test1).toEqual(1); 116 expect(s.x.test2).toEqual(2); 117 } 118 119 @("Simple Integer -> int") 120 unittest 121 { 122 struct S 123 { 124 int myInt; 125 } 126 127 S result = parseToml!S("myInt = 5123456"); 128 129 expect(result.myInt).toEqual(5_123_456); 130 } 131 132 @("Hex Integer -> long") 133 unittest 134 { 135 struct S 136 { 137 long hex; 138 } 139 140 S result = parseToml!S("hex = 0xbeadface"); 141 142 expect(result.hex).toEqual(0xbeadface); 143 } 144 145 @("Binary Integer -> ubyte") 146 unittest 147 { 148 struct S 149 { 150 ubyte bin; 151 } 152 153 S result = parseToml!S("bin = 0b00110010"); 154 155 expect(result.bin).toEqual(50); 156 } 157 158 @("Octal Integer -> short") 159 unittest 160 { 161 struct S 162 { 163 short oct; 164 } 165 166 S result = parseToml!S("oct = 0o501"); 167 168 expect(result.oct).toEqual(321); 169 } 170 171 @("Integers with underscores (all bases)") 172 unittest 173 { 174 struct S 175 { 176 int a; 177 int b; 178 int c; 179 int d; 180 } 181 182 S result = parseToml!S(` 183 a = 1_000 184 b = 0x0000_00ff 185 c = 0o7_7_7 186 d = 0b0_0_0_1_0_0_0_1 187 `); 188 189 expect(result.a).toEqual(1000); 190 expect(result.b).toEqual(255); 191 expect(result.c).toEqual(511); 192 expect(result.d).toEqual(17); 193 } 194 195 @("Floating Point -> float") 196 unittest 197 { 198 struct S 199 { 200 float f; 201 } 202 203 S result = parseToml!S("f = 1.1234"); 204 205 expect(result.f).toApproximatelyEqual(1.1234); 206 } 207 208 @("Floating Point -> real") 209 unittest 210 { 211 struct S 212 { 213 real r; 214 } 215 216 S result = parseToml!S("r = 12_232.008_2"); 217 218 expect(result.r).toApproximatelyEqual(12_232.0082); 219 } 220 221 @("Floating Point -> double") 222 unittest 223 { 224 struct S 225 { 226 real d; 227 } 228 229 S result = parseToml!S("d = -3.141_6e-01"); 230 231 expect(result.d).toApproximatelyEqual(-3.141_6e-01); 232 } 233 234 @("Floating Point — Infinities") 235 unittest 236 { 237 struct S 238 { 239 real pi; 240 double ni; 241 float i; 242 } 243 244 S result = parseToml!S(` 245 pi = +inf 246 ni = -inf 247 i = inf 248 `); 249 250 expect(result.pi).toEqual(real.infinity); 251 expect(result.ni).toEqual(-double.infinity); 252 expect(result.i).toEqual(float.infinity); 253 } 254 255 @("Floating Point — NaNs") 256 unittest 257 { 258 import std.math : isNaN; 259 260 struct S 261 { 262 real pNan; 263 double nNan; 264 float nan; 265 } 266 267 S result = parseToml!S(` 268 pNan = +nan 269 nNan = -nan 270 nan = nan 271 `); 272 273 assert(result.pNan.isNaN, "Expected result.pNan to be NaN, but got: " ~ result.pNan.to!string); 274 assert(result.nNan.isNaN, "Expected result.nNan to be NaN, but got: " ~ result.nNan.to!string); 275 assert(result.nan.isNaN, "Expected result.nan to be NaN, but got: " ~ result.nan.to!string); 276 } 277 278 @("Boolean -> bool") 279 unittest 280 { 281 struct S 282 { 283 bool t; 284 bool f; 285 } 286 287 S result = parseToml!S(` 288 t = true 289 f = false 290 `); 291 292 expect(result.t).toEqual(true); 293 expect(result.f).toEqual(false); 294 } 295 296 @("Basic String -> string") 297 unittest 298 { 299 struct S 300 { 301 string s; 302 } 303 304 S result = parseToml!S(` 305 s = "Appel" 306 `); 307 308 expect(result.s).toEqual("Appel"); 309 } 310 311 @("Basic Multiline String -> string") 312 unittest 313 { 314 struct S 315 { 316 string s; 317 } 318 319 S result = parseToml!S(` 320 s = """ 321 Phlogiston\tX""" 322 `); 323 324 expect(result.s).toEqual(" Phlogiston\tX"); 325 } 326 327 @("Literal String -> string") 328 unittest 329 { 330 struct S 331 { 332 string s; 333 } 334 335 S result = parseToml!S(` 336 s = 'Abc\tde' 337 `); 338 339 expect(result.s).toEqual("Abc\\tde"); 340 } 341 342 @("Literal Multiline String -> string") 343 unittest 344 { 345 struct S 346 { 347 string s; 348 } 349 350 S result = parseToml!S(` 351 s = ''' 352 Abc\t''de 353 ''' 354 `); 355 356 expect(result.s).toEqual("Abc\\t''de\n"); 357 } 358 359 @("String Unicode test (string, wstring, and dstring)") 360 unittest 361 { 362 struct S 363 { 364 string s; 365 wstring w; 366 dstring d; 367 } 368 369 S result = parseToml!S(` 370 s = "\U0001F9A2" 371 w = "🐃" 372 d = "🦆" 373 `); 374 375 expect(result.s).toEqual("🦢"); 376 expect(result.w).toEqual("🐃"w); 377 expect(result.d).toEqual("🦆"d); 378 } 379 380 @("Offset Date-Time -> SysTime") 381 unittest 382 { 383 struct S 384 { 385 SysTime t; 386 } 387 388 S result = parseToml!S(` 389 t = 2020-01-26 12:09:59Z 390 `); 391 392 expect(result.t).toEqual(SysTime( 393 DateTime( 394 2020, 395 1, 396 26, 397 12, 398 9, 399 59 400 ), 401 nsecs(0), 402 UTC() 403 )); 404 } 405 406 @("Local Date-Time -> SysTime where tz = LocalTime") 407 unittest 408 { 409 struct S 410 { 411 SysTime t; 412 } 413 414 S result = parseToml!S(` 415 t = 2020-01-26 12:09:59 416 `); 417 418 expect(result.t).toEqual(SysTime( 419 DateTime( 420 2020, 421 1, 422 26, 423 12, 424 9, 425 59 426 ), 427 nsecs(0), 428 null 429 )); 430 } 431 432 @("Local Date -> Date") 433 unittest 434 { 435 struct S 436 { 437 Date t; 438 } 439 440 S result = parseToml!S(` 441 t = 2020-01-26 442 `); 443 444 expect(result.t).toEqual(Date(2020, 1, 26)); 445 } 446 447 @("Local Time -> TimeOfDay") 448 unittest 449 { 450 struct S 451 { 452 TimeOfDay t; 453 } 454 455 S result = parseToml!S(` 456 t = 12:09:59 457 `); 458 459 expect(result.t).toEqual(TimeOfDay(12, 9, 59)); 460 } 461 462 @("Array of Integers -> static long[]") 463 unittest 464 { 465 struct S 466 { 467 long[11] t; 468 } 469 470 S result = parseToml!S(` 471 t = [ 472 123, 473 +111, 474 -82, 475 0, 476 +0, 477 -0, 478 525_600, 479 -189_912, 480 0xbEaD_fAcE, 481 0o777, 482 0b11001101 483 ] 484 `); 485 486 expect(result.t).toEqual([ 487 123L, 488 +111L, 489 -82L, 490 0L, 491 +0L, 492 -0L, 493 525_600L, 494 -189_912L, 495 0xbEaD_fAcEL, 496 511L, 497 0b11001101L, 498 ].staticArray!(long, 11)); 499 } 500 501 @("Array of Integers -> static int[]") 502 unittest 503 { 504 struct S 505 { 506 int[10] t; 507 } 508 509 S result = parseToml!S(` 510 t = [ 511 123, 512 +111, 513 -82, 514 0, 515 +0, 516 -0, 517 525_600, 518 -189_912, 519 0o777, 520 0b11001101 521 ] 522 `); 523 524 expect(result.t).toEqual([ 525 123, 526 +111, 527 -82, 528 0, 529 +0, 530 -0, 531 525_600, 532 -189_912, 533 511, 534 0b11001101, 535 ].staticArray!(int, 10)); 536 } 537 538 @("Array of Integers -> static short[]") 539 unittest 540 { 541 struct S 542 { 543 short[10] t; 544 } 545 546 S result = parseToml!S(` 547 t = [ 548 123, 549 +111, 550 -82, 551 0, 552 +0, 553 -0, 554 5_600, 555 -9_912, 556 0o777, 557 0b11001101 558 ] 559 `); 560 561 expect(result.t).toEqual([ 562 123, 563 +111, 564 -82, 565 0, 566 +0, 567 -0, 568 5_600, 569 -9_912, 570 511, 571 0b11001101, 572 ].staticArray!(short, 10)); 573 } 574 575 @("Array of Integers -> static byte[]") 576 unittest 577 { 578 struct S 579 { 580 byte[7] t; 581 } 582 583 S result = parseToml!S(` 584 t = [ 585 1_2_3, 586 +1_1_1, 587 -82, 588 0, 589 +0, 590 -0, 591 0b01001101 592 ] 593 `); 594 595 expect(result.t).toEqual([ 596 123, 597 +111, 598 -82, 599 0, 600 +0, 601 -0, 602 0b01001101, 603 ].staticArray!(byte, 7)); 604 } 605 606 @("Array of Integers -> static ulong[]") 607 unittest 608 { 609 struct S 610 { 611 ulong[9] t; 612 } 613 614 S result = parseToml!S(` 615 t = [ 616 123, 617 +111, 618 0, 619 +0, 620 -0, # This should still work (both the -0 and this comment). 621 525_600, 622 0xbEaD_fAcE, 623 0o777, 624 0b11001101 625 ] 626 `); 627 628 expect(result.t).toEqual([ 629 123L, 630 +111L, 631 0L, 632 +0L, 633 -0L, 634 525_600L, 635 0xbEaD_fAcEL, 636 511L, 637 0b11001101L, 638 ].staticArray!(ulong, 9)); 639 } 640 641 @("Array of Integers -> static uint[]") 642 unittest 643 { 644 struct S 645 { 646 uint[8] t; 647 } 648 649 S result = parseToml!S(` 650 t = [ 651 123, 652 +111, 653 0, 654 +0, 655 -0, 656 525_600, 657 0o777, 658 0b11001101 659 ] 660 `); 661 662 expect(result.t).toEqual([ 663 123, 664 +111, 665 0, 666 +0, 667 -0, 668 525_600, 669 511, 670 0b11001101, 671 ].staticArray!(uint, 8)); 672 } 673 674 @("Array of Integers -> static ushort[]") 675 unittest 676 { 677 struct S 678 { 679 ushort[8] t; 680 } 681 682 S result = parseToml!S(` 683 t = [ 684 123, 685 +111, 686 0, 687 +0, 688 -0, 689 5_600, 690 0o777, 691 0b11001101 692 ] 693 `); 694 695 expect(result.t).toEqual([ 696 123, 697 +111, 698 0, 699 +0, 700 -0, 701 5_600, 702 511, 703 0b11001101, 704 ].staticArray!(ushort, 8)); 705 } 706 707 @("Array of Integers -> static ubyte[]") 708 unittest 709 { 710 struct S 711 { 712 ubyte[6] t; 713 } 714 715 S result = parseToml!S(` 716 t = [ 717 1_2_3, 718 +1_1_1, 719 0, 720 +0, 721 -0, 722 0b11001101 723 ] 724 `); 725 726 expect(result.t).toEqual([ 727 123, 728 +111, 729 0, 730 +0, 731 -0, 732 0b11001101, 733 ].staticArray!(ubyte, 6)); 734 } 735 736 @("Array of Integers -> dynamic int[]") 737 unittest 738 { 739 struct S 740 { 741 int[] t; 742 } 743 744 S result = parseToml!S(` 745 t = [ 746 123, 747 +111, 748 -82, 749 # 0, 750 # +0, 751 # -0, 752 # 525_600, 753 # -189_912, 754 # 0o777, 755 # 0b11001101 756 ] 757 `); 758 759 expect(result.t).toEqual([ 123, +111, -82, ]); 760 761 result = parseToml!S(` 762 t = [ 763 # 123, 764 # +111, 765 # -82, 766 # 0, 767 # +0, 768 # -0, 769 # 525_600, 770 -189_912, 771 0o777, 772 0b11001101 773 ] 774 `); 775 776 expect(result.t).toEqual([ -189_912, 511, 0b11001101 ]); 777 } 778 779 @("Array of Strings -> dynamic string[]") 780 unittest 781 { 782 struct S 783 { 784 string[] t; 785 } 786 787 S result = parseToml!S(` 788 t = [ "do", "re", "mi" ] 789 `); 790 791 expect(result.t).toEqual([ "do", "re", "mi" ]); 792 } 793 794 @("Array of Floats -> dynamic float[]") 795 unittest 796 { 797 struct S 798 { 799 float[] t; 800 } 801 802 S result = parseToml!S(` 803 t = [ 0.0, 2e5, -3.6e-2 ] 804 `); 805 806 expect(result.t).toEqual([ 0.0f, 2e5f, -3.6e-2f ]); 807 } 808 809 @("Array of Booleans -> dynamic bool[]") 810 unittest 811 { 812 struct S 813 { 814 bool[] t; 815 } 816 817 S result = parseToml!S(` 818 t = [ true, false, false, true, 819 ] 820 `); 821 822 expect(result.t).toEqual([ true, false, false, true ]); 823 } 824 825 @("Array of Offset Date-Times -> dynamic SysTime[]") 826 unittest 827 { 828 struct S 829 { 830 SysTime[] t; 831 } 832 833 S result = parseToml!S(` 834 t = [ 2020-02-02 12:51:05Z ] 835 `); 836 837 expect(result.t).toEqual([ SysTime(DateTime(2020, 2, 2, 12, 51, 5), UTC()) ]); 838 } 839 840 @("Array of Local Date-Times -> dynamic SysTime[]") 841 unittest 842 { 843 struct S 844 { 845 SysTime[] t; 846 } 847 848 S result = parseToml!S(` 849 t = [ 2020-02-02 12:51:05 ] 850 `); 851 852 expect(result.t).toEqual([ SysTime(DateTime(2020, 2, 2, 12, 51, 5), LocalTime()) ]); 853 } 854 855 @("Array of Local Dates -> dynamic Date[]") 856 unittest 857 { 858 struct S 859 { 860 Date[] t; 861 } 862 863 S result = parseToml!S(` 864 t = [ 2020-02-02, 2020-10-31 ] 865 `); 866 867 expect(result.t).toEqual([ Date(2020, 2, 2), Date(2020, 10, 31) ]); 868 } 869 870 @("Array of Local Times -> dynamic TimeOfDay[]") 871 unittest 872 { 873 struct S 874 { 875 TimeOfDay[] t; 876 } 877 878 S result = parseToml!S(` 879 t = [ 12:53:23, 00:20:01, 19:22:54 ] 880 `); 881 882 expect(result.t).toEqual([ TimeOfDay(12, 53, 23), TimeOfDay(0, 20, 1), TimeOfDay(19, 22, 54), ]); 883 } 884 885 @("Arrays — Empty") 886 unittest 887 { 888 struct S 889 { 890 int[] i; 891 float[] f; 892 string[] s; 893 TimeOfDay[] t; 894 } 895 896 S s; 897 898 s = parseToml!S(` 899 i = [] 900 f = [] 901 s = [] 902 t = [] 903 `); 904 905 expect(s.i.length).toEqual(0); 906 expect(s.f.length).toEqual(0); 907 expect(s.s.length).toEqual(0); 908 expect(s.t.length).toEqual(0); 909 } 910 911 @("Array of Inline Tables -> Array of Structs") 912 unittest 913 { 914 struct S 915 { 916 struct Musician 917 { 918 string name; 919 Date dob; 920 } 921 922 Musician[3] musicians; 923 } 924 925 S s = parseToml!S(` 926 musicians = [ 927 { name = "Bob Dylan", dob = 1941-05-24 }, 928 { name = "Frank Sinatra", dob = 1915-12-12 }, 929 { name = "Scott Joplin", dob = 1868-11-24 } 930 ] 931 `); 932 933 expect(s.musicians[0]).toEqual(S.Musician("Bob Dylan", Date(1941, 5, 24))); 934 expect(s.musicians[1]).toEqual(S.Musician("Frank Sinatra", Date(1915, 12, 12))); 935 expect(s.musicians[2]).toEqual(S.Musician("Scott Joplin", Date(1868, 11, 24))); 936 } 937 938 @("Table - one level") 939 unittest 940 { 941 struct Inner 942 { 943 int x; 944 } 945 946 struct Outer 947 { 948 Inner inn; 949 int x; 950 } 951 952 Outer o = parseToml!Outer(` 953 x = 5 954 955 [inn] 956 x = 10 957 `); 958 959 expect(o.x).toEqual(5); 960 expect(o.inn.x).toEqual(10); 961 } 962 963 @("Table - two levels") 964 unittest 965 { 966 struct Nucleus 967 { 968 int c; 969 } 970 971 struct Inner 972 { 973 Nucleus nuc; 974 } 975 976 struct Outer 977 { 978 Inner inn; 979 } 980 981 Outer o = parseToml!Outer(` 982 [inn.nuc] 983 c = 2 984 `); 985 986 expect(o.inn.nuc.c).toEqual(2); 987 } 988 989 @("Table - three level + unicode") 990 unittest 991 { 992 struct InnerCore 993 { 994 int heat; 995 } 996 997 struct OuterCore 998 { 999 InnerCore iñner; 1000 } 1001 1002 struct Mantle 1003 { 1004 OuterCore outer; 1005 } 1006 1007 struct Earth 1008 { 1009 Mantle mantle; 1010 } 1011 1012 Earth earth = parseToml!Earth(` 1013 1014 [mantle.outer."iñner"] 1015 heat = 9001 1016 1017 `); 1018 1019 expect(earth.mantle.outer.iñner.heat).toEqual(9001); 1020 } 1021 1022 @("Table - dotted keys") 1023 unittest 1024 { 1025 struct InnerCore 1026 { 1027 int heat; 1028 } 1029 1030 struct OuterCore 1031 { 1032 InnerCore iñner; 1033 } 1034 1035 struct Mantle 1036 { 1037 OuterCore outer; 1038 } 1039 1040 struct Earth 1041 { 1042 Mantle mantle; 1043 } 1044 1045 Earth earth = parseToml!Earth(` 1046 1047 [mantle.outer] 1048 "iñner".heat = 9001 1049 1050 `); 1051 1052 expect(earth.mantle.outer.iñner.heat).toEqual(9001); 1053 } 1054 1055 @("Table - inline") 1056 unittest 1057 { 1058 struct InnerCore 1059 { 1060 int heat; 1061 } 1062 1063 struct OuterCore 1064 { 1065 InnerCore iñner; 1066 } 1067 1068 struct Mantle 1069 { 1070 OuterCore outer; 1071 } 1072 1073 struct Earth 1074 { 1075 Mantle mantle; 1076 } 1077 1078 Earth earth = parseToml!Earth(` 1079 mantle = { outer = { "iñner" = { heat = 9001 } } } 1080 `); 1081 1082 expect(earth.mantle.outer.iñner.heat).toEqual(9001); 1083 } 1084 1085 @("Table Array") 1086 unittest 1087 { 1088 struct S 1089 { 1090 struct Musician 1091 { 1092 string name; 1093 Date dob; 1094 } 1095 1096 Musician[3] musicians; 1097 } 1098 1099 S s = parseToml!S(` 1100 [[musicians]] 1101 name = "Bob Dylan" 1102 dob = 1941-05-24 1103 1104 [[musicians]] 1105 name = "Frank Sinatra" 1106 dob = 1915-12-12 1107 1108 [[musicians]] 1109 name = "Scott Joplin" 1110 dob = 1868-11-24 1111 `); 1112 1113 expect(s.musicians[0]).toEqual(S.Musician("Bob Dylan", Date(1941, 5, 24))); 1114 expect(s.musicians[1]).toEqual(S.Musician("Frank Sinatra", Date(1915, 12, 12))); 1115 expect(s.musicians[2]).toEqual(S.Musician("Scott Joplin", Date(1868, 11, 24))); 1116 } 1117 1118 @("Table Array — dotted keys") 1119 unittest 1120 { 1121 struct Country 1122 { 1123 string nameEnglish; 1124 string nameLocal; 1125 } 1126 1127 struct S 1128 { 1129 struct Countries 1130 { 1131 Country[2] republics; 1132 Country[2] monarchies; 1133 1134 size_t count; 1135 } 1136 1137 Countries countries; 1138 } 1139 1140 S s = parseToml!S(` 1141 1142 countries.count = 4 1143 1144 [[countries.republics]] 1145 nameEnglish = "Ireland" 1146 nameLocal = "Éire" 1147 1148 [[countries.republics]] 1149 nameEnglish = "Greece" 1150 nameLocal = "Ελλάδα" 1151 1152 [[countries.monarchies]] 1153 nameEnglish = "Bhutan" 1154 nameLocal = "འབྲུག་ཡུལ་" 1155 1156 [[countries.monarchies]] 1157 nameEnglish = "Denmark" 1158 nameLocal = "Danmark" 1159 1160 `); 1161 1162 expect(s.countries.count).toEqual(4); 1163 expect(s.countries.republics[0]).toEqual(Country("Ireland", "Éire")); 1164 expect(s.countries.republics[1]).toEqual(Country("Greece", "Ελλάδα")); 1165 expect(s.countries.monarchies[0]).toEqual(Country("Bhutan", "འབྲུག་ཡུལ་")); 1166 expect(s.countries.monarchies[1]).toEqual(Country("Denmark", "Danmark")); 1167 } 1168 1169 @("Table Array — empty entry") 1170 unittest 1171 { 1172 struct S 1173 { 1174 struct Musician 1175 { 1176 string name; 1177 Date dob; 1178 } 1179 1180 Musician[3] musicians; 1181 } 1182 1183 S s = parseToml!S(` 1184 [[musicians]] 1185 name = "Bob Dylan" 1186 dob = 1941-05-24 1187 1188 [[musicians]] 1189 1190 [[musicians]] 1191 name = "Scott Joplin" 1192 dob = 1868-11-24 1193 `); 1194 1195 expect(s.musicians[0]).toEqual(S.Musician("Bob Dylan", Date(1941, 5, 24))); 1196 expect(s.musicians[1]).toEqual(S.Musician()); 1197 expect(s.musicians[2]).toEqual(S.Musician("Scott Joplin", Date(1868, 11, 24))); 1198 } 1199 1200 @("Integer can't fit into a byte") 1201 unittest 1202 { 1203 struct S 1204 { 1205 byte i; 1206 } 1207 1208 expect({ parseToml!S(`i = 128`); }).toThrow!TomlDecodingException; 1209 } 1210 1211 @("Integer can't fit into a ubyte") 1212 unittest 1213 { 1214 struct S 1215 { 1216 byte i; 1217 } 1218 1219 expect({ parseToml!S(`i = 256`); }).toThrow!TomlDecodingException; 1220 } 1221 1222 @("Integer can't fit into a short") 1223 unittest 1224 { 1225 struct S 1226 { 1227 short i; 1228 } 1229 1230 expect({ parseToml!S(`i = 32768`); }).toThrow!TomlDecodingException; 1231 } 1232 1233 @("Integer can't fit into a ushort") 1234 unittest 1235 { 1236 struct S 1237 { 1238 ushort i; 1239 } 1240 1241 expect({ parseToml!S(`i = 65536`); }).toThrow!TomlDecodingException; 1242 } 1243 1244 @("Integer too small (ushort)") 1245 unittest 1246 { 1247 struct S 1248 { 1249 ushort i; 1250 } 1251 1252 expect({ parseToml!S(`i = -1`); }).toThrow!TomlDecodingException; 1253 } 1254 1255 @("Integer too small (short)") 1256 unittest 1257 { 1258 struct S 1259 { 1260 ushort i; 1261 } 1262 1263 expect({ parseToml!S(`i = -32769`); }).toThrow!TomlDecodingException; 1264 } 1265 1266 @("Offset date-time before year 0") 1267 unittest 1268 { 1269 struct S 1270 { 1271 SysTime timestamp; 1272 } 1273 1274 expect({ parseToml!S(`timestamp = -0001-01-01 00:00:00Z`); }).toThrow!TomlDecodingException; 1275 } 1276 1277 @("Offset date-time after year 9999") 1278 unittest 1279 { 1280 struct S 1281 { 1282 SysTime timestamp; 1283 } 1284 1285 expect({ parseToml!S(`timestamp = 10000-01-01 00:00:00Z`); }).toThrow!TomlDecodingException; 1286 } 1287 1288 @("Date before year 0") 1289 unittest 1290 { 1291 struct S 1292 { 1293 SysTime date; 1294 } 1295 1296 expect({ parseToml!S(`date = -0001-01-01`); }).toThrow!TomlDecodingException; 1297 } 1298 1299 @("Date after year 9999") 1300 unittest 1301 { 1302 struct S 1303 { 1304 Date date; 1305 } 1306 1307 expect({ parseToml!S(`date = 10000-01-01`); }).toThrow!TomlDecodingException; 1308 } 1309 1310 @("Invalid month 0") 1311 unittest 1312 { 1313 struct S 1314 { 1315 Date date; 1316 } 1317 1318 expect({ parseToml!S(`date = 2020-00-01`); }).toThrow!TomlDecodingException; 1319 } 1320 1321 @("Invalid month 13") 1322 unittest 1323 { 1324 struct S 1325 { 1326 Date date; 1327 } 1328 1329 expect({ parseToml!S(`date = 2020-13-01`); }).toThrow!TomlDecodingException; 1330 } 1331 1332 @("Invalid day of month") 1333 unittest 1334 { 1335 struct S 1336 { 1337 Date date; 1338 } 1339 1340 expect({ parseToml!S(`date = 2011-02-29`); }).toThrow!TomlDecodingException; 1341 } 1342 1343 @("Invalid time") 1344 unittest 1345 { 1346 struct S 1347 { 1348 TimeOfDay time; 1349 } 1350 1351 expect({ parseToml!S(`time = 22:61:00`); }).toThrow!TomlDecodingException; 1352 expect({ parseToml!S(`time = 24:01:00`); }).toThrow!TomlDecodingException; 1353 expect({ parseToml!S(`time = 22:01:60`); }).toThrow!TomlDecodingException; 1354 } 1355 1356 @("Overly precise floating point") 1357 unittest 1358 { 1359 struct S 1360 { 1361 float f; 1362 } 1363 1364 expect({ parseToml!S(`f = 3.1415926535897932384626`); }).not.toThrow!Exception; 1365 } 1366 1367 @("Integer outside of [long.max, long.min]") 1368 unittest 1369 { 1370 struct S 1371 { 1372 ulong x; 1373 } 1374 1375 expect({ parseToml!S(`x = 18446744073709551615`); }).toThrow!TomlDecodingException; 1376 expect({ parseToml!S(`x = -18446744073709551615`); }).toThrow!TomlDecodingException; 1377 } 1378 1379 @("Integer keys as array indices") 1380 unittest 1381 { 1382 struct S 1383 { 1384 int[5] x; 1385 } 1386 1387 expect(parseToml!S(` 1388 [x] 1389 0 = 11 1390 1 = 22 1391 2 = 33 1392 3 = 44 1393 4 = 55 1394 `)).toEqual(S([11, 22, 33, 44, 55])); 1395 } 1396 1397 @("Integer keys as named fields") 1398 unittest 1399 { 1400 struct S 1401 { 1402 struct X 1403 { 1404 @TomlName("1") int a; 1405 @TomlName("2") int b; 1406 @TomlName("3") int c; 1407 @TomlName("4") int d; 1408 @TomlName("5") int e; 1409 } 1410 1411 X x; 1412 } 1413 1414 expect(parseToml!S(` 1415 [x] 1416 1 = 11 1417 2 = 22 1418 3 = 33 1419 4 = 44 1420 5 = 55 1421 `)).toEqual(S(S.X(11, 22, 33, 44, 55))); 1422 } 1423 1424 @("Non-existent keys should be ignored") 1425 unittest 1426 { 1427 struct S 1428 { 1429 int a; 1430 } 1431 1432 expect(parseToml!S(` 1433 a = 5 1434 b = 6 1435 `)).toEqual(S(5)); 1436 } 1437 1438 @("Non-existent tables should be ignored") 1439 unittest 1440 { 1441 struct S 1442 { 1443 int a; 1444 } 1445 1446 expect(parseToml!S(` 1447 a = 5 1448 1449 [x] 1450 b = 6 1451 `)).toEqual(S(5)); 1452 } 1453 1454 @("A key corresponding to a non-struct property should work") 1455 unittest 1456 { 1457 struct S 1458 { 1459 private int _a; 1460 int a() @property const { return _a; } 1461 void a(int newA) @property { _a = newA; } 1462 } 1463 1464 S s; 1465 1466 parseToml!S(` 1467 a = 5 1468 `, s); 1469 1470 expect(s).toEqual(S(5)); 1471 } 1472 1473 @("A key corresponding to a public property of a struct type should not compile") 1474 unittest 1475 { 1476 struct S 1477 { 1478 private struct Inner 1479 { 1480 int x; 1481 } 1482 1483 private Inner _inner; 1484 Inner inner() @property const { return _inner; } 1485 void inner(Inner newInner) @property { _inner = newInner; } 1486 } 1487 1488 S s; 1489 1490 static assert( 1491 !__traits(compiles, parseToml!S(` 1492 blah 1493 `, s)), 1494 "Expected compilation to fail when struct contains public property that is itself a struct." 1495 ); 1496 } 1497 1498 @("If TOML array length exceeds static array length, ignore additional entries.") 1499 unittest 1500 { 1501 struct S 1502 { 1503 int[5] arr; 1504 } 1505 1506 expect(parseToml!S(` 1507 arr = [11, 22, 33, 44, 55, 66, 77, 88] 1508 `)).toEqual(S([11, 22, 33, 44, 55])); 1509 } 1510 1511 @("Don't assign non-public fields") 1512 unittest 1513 { 1514 struct S 1515 { 1516 private int x; 1517 } 1518 1519 expect(parseToml!S(`x = 3`)).toEqual(S()); 1520 }