1 //===- unittest/Support/YAMLIOTest.cpp ------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "llvm/ADT/BitmaskEnum.h" 10 #include "llvm/ADT/StringMap.h" 11 #include "llvm/ADT/StringRef.h" 12 #include "llvm/ADT/StringSwitch.h" 13 #include "llvm/ADT/Twine.h" 14 #include "llvm/Support/Casting.h" 15 #include "llvm/Support/Endian.h" 16 #include "llvm/Support/Format.h" 17 #include "llvm/Support/YAMLTraits.h" 18 #include "gmock/gmock.h" 19 #include "gtest/gtest.h" 20 21 using llvm::yaml::Hex16; 22 using llvm::yaml::Hex32; 23 using llvm::yaml::Hex64; 24 using llvm::yaml::Hex8; 25 using llvm::yaml::Input; 26 using llvm::yaml::IO; 27 using llvm::yaml::isNumeric; 28 using llvm::yaml::MappingNormalization; 29 using llvm::yaml::MappingTraits; 30 using llvm::yaml::Output; 31 using llvm::yaml::ScalarTraits; 32 using ::testing::StartsWith; 33 34 35 36 37 static void suppressErrorMessages(const llvm::SMDiagnostic &, void *) { 38 } 39 40 41 42 //===----------------------------------------------------------------------===// 43 // Test MappingTraits 44 //===----------------------------------------------------------------------===// 45 46 struct FooBar { 47 int foo; 48 int bar; 49 }; 50 typedef std::vector<FooBar> FooBarSequence; 51 52 LLVM_YAML_IS_SEQUENCE_VECTOR(FooBar) 53 54 struct FooBarContainer { 55 FooBarSequence fbs; 56 }; 57 58 namespace llvm { 59 namespace yaml { 60 template <> 61 struct MappingTraits<FooBar> { 62 static void mapping(IO &io, FooBar& fb) { 63 io.mapRequired("foo", fb.foo); 64 io.mapRequired("bar", fb.bar); 65 } 66 }; 67 68 template <> struct MappingTraits<FooBarContainer> { 69 static void mapping(IO &io, FooBarContainer &fb) { 70 io.mapRequired("fbs", fb.fbs); 71 } 72 }; 73 } 74 } 75 76 77 // 78 // Test the reading of a yaml mapping 79 // 80 TEST(YAMLIO, TestMapRead) { 81 FooBar doc; 82 { 83 Input yin("---\nfoo: 3\nbar: 5\n...\n"); 84 yin >> doc; 85 86 EXPECT_FALSE(yin.error()); 87 EXPECT_EQ(doc.foo, 3); 88 EXPECT_EQ(doc.bar, 5); 89 } 90 91 { 92 Input yin("{foo: 3, bar: 5}"); 93 yin >> doc; 94 95 EXPECT_FALSE(yin.error()); 96 EXPECT_EQ(doc.foo, 3); 97 EXPECT_EQ(doc.bar, 5); 98 } 99 } 100 101 TEST(YAMLIO, TestMalformedMapRead) { 102 FooBar doc; 103 Input yin("{foo: 3; bar: 5}", nullptr, suppressErrorMessages); 104 yin >> doc; 105 EXPECT_TRUE(!!yin.error()); 106 } 107 108 // 109 // Test the reading of a yaml sequence of mappings 110 // 111 TEST(YAMLIO, TestSequenceMapRead) { 112 FooBarSequence seq; 113 Input yin("---\n - foo: 3\n bar: 5\n - foo: 7\n bar: 9\n...\n"); 114 yin >> seq; 115 116 EXPECT_FALSE(yin.error()); 117 EXPECT_EQ(seq.size(), 2UL); 118 FooBar& map1 = seq[0]; 119 FooBar& map2 = seq[1]; 120 EXPECT_EQ(map1.foo, 3); 121 EXPECT_EQ(map1.bar, 5); 122 EXPECT_EQ(map2.foo, 7); 123 EXPECT_EQ(map2.bar, 9); 124 } 125 126 // 127 // Test the reading of a map containing a yaml sequence of mappings 128 // 129 TEST(YAMLIO, TestContainerSequenceMapRead) { 130 { 131 FooBarContainer cont; 132 Input yin2("---\nfbs:\n - foo: 3\n bar: 5\n - foo: 7\n bar: 9\n...\n"); 133 yin2 >> cont; 134 135 EXPECT_FALSE(yin2.error()); 136 EXPECT_EQ(cont.fbs.size(), 2UL); 137 EXPECT_EQ(cont.fbs[0].foo, 3); 138 EXPECT_EQ(cont.fbs[0].bar, 5); 139 EXPECT_EQ(cont.fbs[1].foo, 7); 140 EXPECT_EQ(cont.fbs[1].bar, 9); 141 } 142 143 { 144 FooBarContainer cont; 145 Input yin("---\nfbs:\n...\n"); 146 yin >> cont; 147 // Okay: Empty node represents an empty array. 148 EXPECT_FALSE(yin.error()); 149 EXPECT_EQ(cont.fbs.size(), 0UL); 150 } 151 152 { 153 FooBarContainer cont; 154 Input yin("---\nfbs: !!null null\n...\n"); 155 yin >> cont; 156 // Okay: null represents an empty array. 157 EXPECT_FALSE(yin.error()); 158 EXPECT_EQ(cont.fbs.size(), 0UL); 159 } 160 161 { 162 FooBarContainer cont; 163 Input yin("---\nfbs: ~\n...\n"); 164 yin >> cont; 165 // Okay: null represents an empty array. 166 EXPECT_FALSE(yin.error()); 167 EXPECT_EQ(cont.fbs.size(), 0UL); 168 } 169 170 { 171 FooBarContainer cont; 172 Input yin("---\nfbs: null\n...\n"); 173 yin >> cont; 174 // Okay: null represents an empty array. 175 EXPECT_FALSE(yin.error()); 176 EXPECT_EQ(cont.fbs.size(), 0UL); 177 } 178 } 179 180 // 181 // Test the reading of a map containing a malformed yaml sequence 182 // 183 TEST(YAMLIO, TestMalformedContainerSequenceMapRead) { 184 { 185 FooBarContainer cont; 186 Input yin("---\nfbs:\n foo: 3\n bar: 5\n...\n", nullptr, 187 suppressErrorMessages); 188 yin >> cont; 189 // Error: fbs is not a sequence. 190 EXPECT_TRUE(!!yin.error()); 191 EXPECT_EQ(cont.fbs.size(), 0UL); 192 } 193 194 { 195 FooBarContainer cont; 196 Input yin("---\nfbs: 'scalar'\n...\n", nullptr, suppressErrorMessages); 197 yin >> cont; 198 // This should be an error. 199 EXPECT_TRUE(!!yin.error()); 200 EXPECT_EQ(cont.fbs.size(), 0UL); 201 } 202 } 203 204 // 205 // Test writing then reading back a sequence of mappings 206 // 207 TEST(YAMLIO, TestSequenceMapWriteAndRead) { 208 std::string intermediate; 209 { 210 FooBar entry1; 211 entry1.foo = 10; 212 entry1.bar = -3; 213 FooBar entry2; 214 entry2.foo = 257; 215 entry2.bar = 0; 216 FooBarSequence seq; 217 seq.push_back(entry1); 218 seq.push_back(entry2); 219 220 llvm::raw_string_ostream ostr(intermediate); 221 Output yout(ostr); 222 yout << seq; 223 } 224 225 { 226 Input yin(intermediate); 227 FooBarSequence seq2; 228 yin >> seq2; 229 230 EXPECT_FALSE(yin.error()); 231 EXPECT_EQ(seq2.size(), 2UL); 232 FooBar& map1 = seq2[0]; 233 FooBar& map2 = seq2[1]; 234 EXPECT_EQ(map1.foo, 10); 235 EXPECT_EQ(map1.bar, -3); 236 EXPECT_EQ(map2.foo, 257); 237 EXPECT_EQ(map2.bar, 0); 238 } 239 } 240 241 // 242 // Test YAML filename handling. 243 // 244 static void testErrorFilename(const llvm::SMDiagnostic &Error, void *) { 245 EXPECT_EQ(Error.getFilename(), "foo.yaml"); 246 } 247 248 TEST(YAMLIO, TestGivenFilename) { 249 auto Buffer = llvm::MemoryBuffer::getMemBuffer("{ x: 42 }", "foo.yaml"); 250 Input yin(*Buffer, nullptr, testErrorFilename); 251 FooBar Value; 252 yin >> Value; 253 254 EXPECT_TRUE(!!yin.error()); 255 } 256 257 struct WithStringField { 258 std::string str1; 259 std::string str2; 260 std::string str3; 261 }; 262 263 namespace llvm { 264 namespace yaml { 265 template <> struct MappingTraits<WithStringField> { 266 static void mapping(IO &io, WithStringField &fb) { 267 io.mapRequired("str1", fb.str1); 268 io.mapRequired("str2", fb.str2); 269 io.mapRequired("str3", fb.str3); 270 } 271 }; 272 } // namespace yaml 273 } // namespace llvm 274 275 TEST(YAMLIO, MultilineStrings) { 276 WithStringField Original; 277 Original.str1 = "a multiline string\nfoobarbaz"; 278 Original.str2 = "another one\rfoobarbaz"; 279 Original.str3 = "a one-line string"; 280 281 std::string Serialized; 282 { 283 llvm::raw_string_ostream OS(Serialized); 284 Output YOut(OS); 285 YOut << Original; 286 } 287 auto Expected = "---\n" 288 "str1: \"a multiline string\\nfoobarbaz\"\n" 289 "str2: \"another one\\rfoobarbaz\"\n" 290 "str3: a one-line string\n" 291 "...\n"; 292 ASSERT_EQ(Serialized, Expected); 293 294 // Also check it parses back without the errors. 295 WithStringField Deserialized; 296 { 297 Input YIn(Serialized); 298 YIn >> Deserialized; 299 ASSERT_FALSE(YIn.error()) 300 << "Parsing error occurred during deserialization. Serialized string:\n" 301 << Serialized; 302 } 303 EXPECT_EQ(Original.str1, Deserialized.str1); 304 EXPECT_EQ(Original.str2, Deserialized.str2); 305 EXPECT_EQ(Original.str3, Deserialized.str3); 306 } 307 308 TEST(YAMLIO, NoQuotesForTab) { 309 WithStringField WithTab; 310 WithTab.str1 = "aba\tcaba"; 311 std::string Serialized; 312 { 313 llvm::raw_string_ostream OS(Serialized); 314 Output YOut(OS); 315 YOut << WithTab; 316 } 317 auto ExpectedPrefix = "---\n" 318 "str1: aba\tcaba\n"; 319 EXPECT_THAT(Serialized, StartsWith(ExpectedPrefix)); 320 } 321 322 //===----------------------------------------------------------------------===// 323 // Test built-in types 324 //===----------------------------------------------------------------------===// 325 326 struct BuiltInTypes { 327 llvm::StringRef str; 328 std::string stdstr; 329 uint64_t u64; 330 uint32_t u32; 331 uint16_t u16; 332 uint8_t u8; 333 bool b; 334 int64_t s64; 335 int32_t s32; 336 int16_t s16; 337 int8_t s8; 338 float f; 339 double d; 340 Hex8 h8; 341 Hex16 h16; 342 Hex32 h32; 343 Hex64 h64; 344 }; 345 346 namespace llvm { 347 namespace yaml { 348 template <> 349 struct MappingTraits<BuiltInTypes> { 350 static void mapping(IO &io, BuiltInTypes& bt) { 351 io.mapRequired("str", bt.str); 352 io.mapRequired("stdstr", bt.stdstr); 353 io.mapRequired("u64", bt.u64); 354 io.mapRequired("u32", bt.u32); 355 io.mapRequired("u16", bt.u16); 356 io.mapRequired("u8", bt.u8); 357 io.mapRequired("b", bt.b); 358 io.mapRequired("s64", bt.s64); 359 io.mapRequired("s32", bt.s32); 360 io.mapRequired("s16", bt.s16); 361 io.mapRequired("s8", bt.s8); 362 io.mapRequired("f", bt.f); 363 io.mapRequired("d", bt.d); 364 io.mapRequired("h8", bt.h8); 365 io.mapRequired("h16", bt.h16); 366 io.mapRequired("h32", bt.h32); 367 io.mapRequired("h64", bt.h64); 368 } 369 }; 370 } 371 } 372 373 374 // 375 // Test the reading of all built-in scalar conversions 376 // 377 TEST(YAMLIO, TestReadBuiltInTypes) { 378 BuiltInTypes map; 379 Input yin("---\n" 380 "str: hello there\n" 381 "stdstr: hello where?\n" 382 "u64: 5000000000\n" 383 "u32: 4000000000\n" 384 "u16: 65000\n" 385 "u8: 255\n" 386 "b: false\n" 387 "s64: -5000000000\n" 388 "s32: -2000000000\n" 389 "s16: -32000\n" 390 "s8: -127\n" 391 "f: 137.125\n" 392 "d: -2.8625\n" 393 "h8: 0xFF\n" 394 "h16: 0x8765\n" 395 "h32: 0xFEDCBA98\n" 396 "h64: 0xFEDCBA9876543210\n" 397 "...\n"); 398 yin >> map; 399 400 EXPECT_FALSE(yin.error()); 401 EXPECT_TRUE(map.str.equals("hello there")); 402 EXPECT_TRUE(map.stdstr == "hello where?"); 403 EXPECT_EQ(map.u64, 5000000000ULL); 404 EXPECT_EQ(map.u32, 4000000000U); 405 EXPECT_EQ(map.u16, 65000); 406 EXPECT_EQ(map.u8, 255); 407 EXPECT_EQ(map.b, false); 408 EXPECT_EQ(map.s64, -5000000000LL); 409 EXPECT_EQ(map.s32, -2000000000L); 410 EXPECT_EQ(map.s16, -32000); 411 EXPECT_EQ(map.s8, -127); 412 EXPECT_EQ(map.f, 137.125); 413 EXPECT_EQ(map.d, -2.8625); 414 EXPECT_EQ(map.h8, Hex8(255)); 415 EXPECT_EQ(map.h16, Hex16(0x8765)); 416 EXPECT_EQ(map.h32, Hex32(0xFEDCBA98)); 417 EXPECT_EQ(map.h64, Hex64(0xFEDCBA9876543210LL)); 418 } 419 420 421 // 422 // Test writing then reading back all built-in scalar types 423 // 424 TEST(YAMLIO, TestReadWriteBuiltInTypes) { 425 std::string intermediate; 426 { 427 BuiltInTypes map; 428 map.str = "one two"; 429 map.stdstr = "three four"; 430 map.u64 = 6000000000ULL; 431 map.u32 = 3000000000U; 432 map.u16 = 50000; 433 map.u8 = 254; 434 map.b = true; 435 map.s64 = -6000000000LL; 436 map.s32 = -2000000000; 437 map.s16 = -32000; 438 map.s8 = -128; 439 map.f = 3.25; 440 map.d = -2.8625; 441 map.h8 = 254; 442 map.h16 = 50000; 443 map.h32 = 3000000000U; 444 map.h64 = 6000000000LL; 445 446 llvm::raw_string_ostream ostr(intermediate); 447 Output yout(ostr); 448 yout << map; 449 } 450 451 { 452 Input yin(intermediate); 453 BuiltInTypes map; 454 yin >> map; 455 456 EXPECT_FALSE(yin.error()); 457 EXPECT_TRUE(map.str.equals("one two")); 458 EXPECT_TRUE(map.stdstr == "three four"); 459 EXPECT_EQ(map.u64, 6000000000ULL); 460 EXPECT_EQ(map.u32, 3000000000U); 461 EXPECT_EQ(map.u16, 50000); 462 EXPECT_EQ(map.u8, 254); 463 EXPECT_EQ(map.b, true); 464 EXPECT_EQ(map.s64, -6000000000LL); 465 EXPECT_EQ(map.s32, -2000000000L); 466 EXPECT_EQ(map.s16, -32000); 467 EXPECT_EQ(map.s8, -128); 468 EXPECT_EQ(map.f, 3.25); 469 EXPECT_EQ(map.d, -2.8625); 470 EXPECT_EQ(map.h8, Hex8(254)); 471 EXPECT_EQ(map.h16, Hex16(50000)); 472 EXPECT_EQ(map.h32, Hex32(3000000000U)); 473 EXPECT_EQ(map.h64, Hex64(6000000000LL)); 474 } 475 } 476 477 //===----------------------------------------------------------------------===// 478 // Test endian-aware types 479 //===----------------------------------------------------------------------===// 480 481 struct EndianTypes { 482 typedef llvm::support::detail::packed_endian_specific_integral< 483 float, llvm::support::little, llvm::support::unaligned> 484 ulittle_float; 485 typedef llvm::support::detail::packed_endian_specific_integral< 486 double, llvm::support::little, llvm::support::unaligned> 487 ulittle_double; 488 489 llvm::support::ulittle64_t u64; 490 llvm::support::ulittle32_t u32; 491 llvm::support::ulittle16_t u16; 492 llvm::support::little64_t s64; 493 llvm::support::little32_t s32; 494 llvm::support::little16_t s16; 495 ulittle_float f; 496 ulittle_double d; 497 }; 498 499 namespace llvm { 500 namespace yaml { 501 template <> struct MappingTraits<EndianTypes> { 502 static void mapping(IO &io, EndianTypes &et) { 503 io.mapRequired("u64", et.u64); 504 io.mapRequired("u32", et.u32); 505 io.mapRequired("u16", et.u16); 506 io.mapRequired("s64", et.s64); 507 io.mapRequired("s32", et.s32); 508 io.mapRequired("s16", et.s16); 509 io.mapRequired("f", et.f); 510 io.mapRequired("d", et.d); 511 } 512 }; 513 } 514 } 515 516 // 517 // Test the reading of all endian scalar conversions 518 // 519 TEST(YAMLIO, TestReadEndianTypes) { 520 EndianTypes map; 521 Input yin("---\n" 522 "u64: 5000000000\n" 523 "u32: 4000000000\n" 524 "u16: 65000\n" 525 "s64: -5000000000\n" 526 "s32: -2000000000\n" 527 "s16: -32000\n" 528 "f: 3.25\n" 529 "d: -2.8625\n" 530 "...\n"); 531 yin >> map; 532 533 EXPECT_FALSE(yin.error()); 534 EXPECT_EQ(map.u64, 5000000000ULL); 535 EXPECT_EQ(map.u32, 4000000000U); 536 EXPECT_EQ(map.u16, 65000); 537 EXPECT_EQ(map.s64, -5000000000LL); 538 EXPECT_EQ(map.s32, -2000000000L); 539 EXPECT_EQ(map.s16, -32000); 540 EXPECT_EQ(map.f, 3.25f); 541 EXPECT_EQ(map.d, -2.8625); 542 } 543 544 // 545 // Test writing then reading back all endian-aware scalar types 546 // 547 TEST(YAMLIO, TestReadWriteEndianTypes) { 548 std::string intermediate; 549 { 550 EndianTypes map; 551 map.u64 = 6000000000ULL; 552 map.u32 = 3000000000U; 553 map.u16 = 50000; 554 map.s64 = -6000000000LL; 555 map.s32 = -2000000000; 556 map.s16 = -32000; 557 map.f = 3.25f; 558 map.d = -2.8625; 559 560 llvm::raw_string_ostream ostr(intermediate); 561 Output yout(ostr); 562 yout << map; 563 } 564 565 { 566 Input yin(intermediate); 567 EndianTypes map; 568 yin >> map; 569 570 EXPECT_FALSE(yin.error()); 571 EXPECT_EQ(map.u64, 6000000000ULL); 572 EXPECT_EQ(map.u32, 3000000000U); 573 EXPECT_EQ(map.u16, 50000); 574 EXPECT_EQ(map.s64, -6000000000LL); 575 EXPECT_EQ(map.s32, -2000000000L); 576 EXPECT_EQ(map.s16, -32000); 577 EXPECT_EQ(map.f, 3.25f); 578 EXPECT_EQ(map.d, -2.8625); 579 } 580 } 581 582 enum class Enum : uint16_t { One, Two }; 583 enum class BitsetEnum : uint16_t { 584 ZeroOne = 0x01, 585 OneZero = 0x10, 586 LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue*/ OneZero), 587 }; 588 LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); 589 struct EndianEnums { 590 llvm::support::little_t<Enum> LittleEnum; 591 llvm::support::big_t<Enum> BigEnum; 592 llvm::support::little_t<BitsetEnum> LittleBitset; 593 llvm::support::big_t<BitsetEnum> BigBitset; 594 }; 595 namespace llvm { 596 namespace yaml { 597 template <> struct ScalarEnumerationTraits<Enum> { 598 static void enumeration(IO &io, Enum &E) { 599 io.enumCase(E, "One", Enum::One); 600 io.enumCase(E, "Two", Enum::Two); 601 } 602 }; 603 604 template <> struct ScalarBitSetTraits<BitsetEnum> { 605 static void bitset(IO &io, BitsetEnum &E) { 606 io.bitSetCase(E, "ZeroOne", BitsetEnum::ZeroOne); 607 io.bitSetCase(E, "OneZero", BitsetEnum::OneZero); 608 } 609 }; 610 611 template <> struct MappingTraits<EndianEnums> { 612 static void mapping(IO &io, EndianEnums &EE) { 613 io.mapRequired("LittleEnum", EE.LittleEnum); 614 io.mapRequired("BigEnum", EE.BigEnum); 615 io.mapRequired("LittleBitset", EE.LittleBitset); 616 io.mapRequired("BigBitset", EE.BigBitset); 617 } 618 }; 619 } // namespace yaml 620 } // namespace llvm 621 622 TEST(YAMLIO, TestReadEndianEnums) { 623 EndianEnums map; 624 Input yin("---\n" 625 "LittleEnum: One\n" 626 "BigEnum: Two\n" 627 "LittleBitset: [ ZeroOne ]\n" 628 "BigBitset: [ ZeroOne, OneZero ]\n" 629 "...\n"); 630 yin >> map; 631 632 EXPECT_FALSE(yin.error()); 633 EXPECT_EQ(Enum::One, map.LittleEnum); 634 EXPECT_EQ(Enum::Two, map.BigEnum); 635 EXPECT_EQ(BitsetEnum::ZeroOne, map.LittleBitset); 636 EXPECT_EQ(BitsetEnum::ZeroOne | BitsetEnum::OneZero, map.BigBitset); 637 } 638 639 TEST(YAMLIO, TestReadWriteEndianEnums) { 640 std::string intermediate; 641 { 642 EndianEnums map; 643 map.LittleEnum = Enum::Two; 644 map.BigEnum = Enum::One; 645 map.LittleBitset = BitsetEnum::OneZero | BitsetEnum::ZeroOne; 646 map.BigBitset = BitsetEnum::OneZero; 647 648 llvm::raw_string_ostream ostr(intermediate); 649 Output yout(ostr); 650 yout << map; 651 } 652 653 { 654 Input yin(intermediate); 655 EndianEnums map; 656 yin >> map; 657 658 EXPECT_FALSE(yin.error()); 659 EXPECT_EQ(Enum::Two, map.LittleEnum); 660 EXPECT_EQ(Enum::One, map.BigEnum); 661 EXPECT_EQ(BitsetEnum::OneZero | BitsetEnum::ZeroOne, map.LittleBitset); 662 EXPECT_EQ(BitsetEnum::OneZero, map.BigBitset); 663 } 664 } 665 666 struct StringTypes { 667 llvm::StringRef str1; 668 llvm::StringRef str2; 669 llvm::StringRef str3; 670 llvm::StringRef str4; 671 llvm::StringRef str5; 672 llvm::StringRef str6; 673 llvm::StringRef str7; 674 llvm::StringRef str8; 675 llvm::StringRef str9; 676 llvm::StringRef str10; 677 llvm::StringRef str11; 678 std::string stdstr1; 679 std::string stdstr2; 680 std::string stdstr3; 681 std::string stdstr4; 682 std::string stdstr5; 683 std::string stdstr6; 684 std::string stdstr7; 685 std::string stdstr8; 686 std::string stdstr9; 687 std::string stdstr10; 688 std::string stdstr11; 689 std::string stdstr12; 690 std::string stdstr13; 691 }; 692 693 namespace llvm { 694 namespace yaml { 695 template <> 696 struct MappingTraits<StringTypes> { 697 static void mapping(IO &io, StringTypes& st) { 698 io.mapRequired("str1", st.str1); 699 io.mapRequired("str2", st.str2); 700 io.mapRequired("str3", st.str3); 701 io.mapRequired("str4", st.str4); 702 io.mapRequired("str5", st.str5); 703 io.mapRequired("str6", st.str6); 704 io.mapRequired("str7", st.str7); 705 io.mapRequired("str8", st.str8); 706 io.mapRequired("str9", st.str9); 707 io.mapRequired("str10", st.str10); 708 io.mapRequired("str11", st.str11); 709 io.mapRequired("stdstr1", st.stdstr1); 710 io.mapRequired("stdstr2", st.stdstr2); 711 io.mapRequired("stdstr3", st.stdstr3); 712 io.mapRequired("stdstr4", st.stdstr4); 713 io.mapRequired("stdstr5", st.stdstr5); 714 io.mapRequired("stdstr6", st.stdstr6); 715 io.mapRequired("stdstr7", st.stdstr7); 716 io.mapRequired("stdstr8", st.stdstr8); 717 io.mapRequired("stdstr9", st.stdstr9); 718 io.mapRequired("stdstr10", st.stdstr10); 719 io.mapRequired("stdstr11", st.stdstr11); 720 io.mapRequired("stdstr12", st.stdstr12); 721 io.mapRequired("stdstr13", st.stdstr13); 722 } 723 }; 724 } 725 } 726 727 TEST(YAMLIO, TestReadWriteStringTypes) { 728 std::string intermediate; 729 { 730 StringTypes map; 731 map.str1 = "'aaa"; 732 map.str2 = "\"bbb"; 733 map.str3 = "`ccc"; 734 map.str4 = "@ddd"; 735 map.str5 = ""; 736 map.str6 = "0000000004000000"; 737 map.str7 = "true"; 738 map.str8 = "FALSE"; 739 map.str9 = "~"; 740 map.str10 = "0.2e20"; 741 map.str11 = "0x30"; 742 map.stdstr1 = "'eee"; 743 map.stdstr2 = "\"fff"; 744 map.stdstr3 = "`ggg"; 745 map.stdstr4 = "@hhh"; 746 map.stdstr5 = ""; 747 map.stdstr6 = "0000000004000000"; 748 map.stdstr7 = "true"; 749 map.stdstr8 = "FALSE"; 750 map.stdstr9 = "~"; 751 map.stdstr10 = "0.2e20"; 752 map.stdstr11 = "0x30"; 753 map.stdstr12 = "- match"; 754 map.stdstr13.assign("\0a\0b\0", 5); 755 756 llvm::raw_string_ostream ostr(intermediate); 757 Output yout(ostr); 758 yout << map; 759 } 760 761 llvm::StringRef flowOut(intermediate); 762 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'''aaa")); 763 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'\"bbb'")); 764 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'`ccc'")); 765 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'@ddd'")); 766 EXPECT_NE(llvm::StringRef::npos, flowOut.find("''\n")); 767 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0000000004000000'\n")); 768 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'true'\n")); 769 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'FALSE'\n")); 770 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'~'\n")); 771 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0.2e20'\n")); 772 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'0x30'\n")); 773 EXPECT_NE(llvm::StringRef::npos, flowOut.find("'- match'\n")); 774 EXPECT_NE(std::string::npos, flowOut.find("'''eee")); 775 EXPECT_NE(std::string::npos, flowOut.find("'\"fff'")); 776 EXPECT_NE(std::string::npos, flowOut.find("'`ggg'")); 777 EXPECT_NE(std::string::npos, flowOut.find("'@hhh'")); 778 EXPECT_NE(std::string::npos, flowOut.find("''\n")); 779 EXPECT_NE(std::string::npos, flowOut.find("'0000000004000000'\n")); 780 EXPECT_NE(std::string::npos, flowOut.find("\"\\0a\\0b\\0\"")); 781 782 { 783 Input yin(intermediate); 784 StringTypes map; 785 yin >> map; 786 787 EXPECT_FALSE(yin.error()); 788 EXPECT_TRUE(map.str1.equals("'aaa")); 789 EXPECT_TRUE(map.str2.equals("\"bbb")); 790 EXPECT_TRUE(map.str3.equals("`ccc")); 791 EXPECT_TRUE(map.str4.equals("@ddd")); 792 EXPECT_TRUE(map.str5.equals("")); 793 EXPECT_TRUE(map.str6.equals("0000000004000000")); 794 EXPECT_TRUE(map.stdstr1 == "'eee"); 795 EXPECT_TRUE(map.stdstr2 == "\"fff"); 796 EXPECT_TRUE(map.stdstr3 == "`ggg"); 797 EXPECT_TRUE(map.stdstr4 == "@hhh"); 798 EXPECT_TRUE(map.stdstr5 == ""); 799 EXPECT_TRUE(map.stdstr6 == "0000000004000000"); 800 EXPECT_EQ(std::string("\0a\0b\0", 5), map.stdstr13); 801 } 802 } 803 804 //===----------------------------------------------------------------------===// 805 // Test ScalarEnumerationTraits 806 //===----------------------------------------------------------------------===// 807 808 enum Colors { 809 cRed, 810 cBlue, 811 cGreen, 812 cYellow 813 }; 814 815 struct ColorMap { 816 Colors c1; 817 Colors c2; 818 Colors c3; 819 Colors c4; 820 Colors c5; 821 Colors c6; 822 }; 823 824 namespace llvm { 825 namespace yaml { 826 template <> 827 struct ScalarEnumerationTraits<Colors> { 828 static void enumeration(IO &io, Colors &value) { 829 io.enumCase(value, "red", cRed); 830 io.enumCase(value, "blue", cBlue); 831 io.enumCase(value, "green", cGreen); 832 io.enumCase(value, "yellow",cYellow); 833 } 834 }; 835 template <> 836 struct MappingTraits<ColorMap> { 837 static void mapping(IO &io, ColorMap& c) { 838 io.mapRequired("c1", c.c1); 839 io.mapRequired("c2", c.c2); 840 io.mapRequired("c3", c.c3); 841 io.mapOptional("c4", c.c4, cBlue); // supplies default 842 io.mapOptional("c5", c.c5, cYellow); // supplies default 843 io.mapOptional("c6", c.c6, cRed); // supplies default 844 } 845 }; 846 } 847 } 848 849 850 // 851 // Test reading enumerated scalars 852 // 853 TEST(YAMLIO, TestEnumRead) { 854 ColorMap map; 855 Input yin("---\n" 856 "c1: blue\n" 857 "c2: red\n" 858 "c3: green\n" 859 "c5: yellow\n" 860 "...\n"); 861 yin >> map; 862 863 EXPECT_FALSE(yin.error()); 864 EXPECT_EQ(cBlue, map.c1); 865 EXPECT_EQ(cRed, map.c2); 866 EXPECT_EQ(cGreen, map.c3); 867 EXPECT_EQ(cBlue, map.c4); // tests default 868 EXPECT_EQ(cYellow,map.c5); // tests overridden 869 EXPECT_EQ(cRed, map.c6); // tests default 870 } 871 872 873 874 //===----------------------------------------------------------------------===// 875 // Test ScalarBitSetTraits 876 //===----------------------------------------------------------------------===// 877 878 enum MyFlags { 879 flagNone = 0, 880 flagBig = 1 << 0, 881 flagFlat = 1 << 1, 882 flagRound = 1 << 2, 883 flagPointy = 1 << 3 884 }; 885 inline MyFlags operator|(MyFlags a, MyFlags b) { 886 return static_cast<MyFlags>( 887 static_cast<uint32_t>(a) | static_cast<uint32_t>(b)); 888 } 889 890 struct FlagsMap { 891 MyFlags f1; 892 MyFlags f2; 893 MyFlags f3; 894 MyFlags f4; 895 }; 896 897 898 namespace llvm { 899 namespace yaml { 900 template <> 901 struct ScalarBitSetTraits<MyFlags> { 902 static void bitset(IO &io, MyFlags &value) { 903 io.bitSetCase(value, "big", flagBig); 904 io.bitSetCase(value, "flat", flagFlat); 905 io.bitSetCase(value, "round", flagRound); 906 io.bitSetCase(value, "pointy",flagPointy); 907 } 908 }; 909 template <> 910 struct MappingTraits<FlagsMap> { 911 static void mapping(IO &io, FlagsMap& c) { 912 io.mapRequired("f1", c.f1); 913 io.mapRequired("f2", c.f2); 914 io.mapRequired("f3", c.f3); 915 io.mapOptional("f4", c.f4, flagRound); 916 } 917 }; 918 } 919 } 920 921 922 // 923 // Test reading flow sequence representing bit-mask values 924 // 925 TEST(YAMLIO, TestFlagsRead) { 926 FlagsMap map; 927 Input yin("---\n" 928 "f1: [ big ]\n" 929 "f2: [ round, flat ]\n" 930 "f3: []\n" 931 "...\n"); 932 yin >> map; 933 934 EXPECT_FALSE(yin.error()); 935 EXPECT_EQ(flagBig, map.f1); 936 EXPECT_EQ(flagRound|flagFlat, map.f2); 937 EXPECT_EQ(flagNone, map.f3); // check empty set 938 EXPECT_EQ(flagRound, map.f4); // check optional key 939 } 940 941 942 // 943 // Test writing then reading back bit-mask values 944 // 945 TEST(YAMLIO, TestReadWriteFlags) { 946 std::string intermediate; 947 { 948 FlagsMap map; 949 map.f1 = flagBig; 950 map.f2 = flagRound | flagFlat; 951 map.f3 = flagNone; 952 map.f4 = flagNone; 953 954 llvm::raw_string_ostream ostr(intermediate); 955 Output yout(ostr); 956 yout << map; 957 } 958 959 { 960 Input yin(intermediate); 961 FlagsMap map2; 962 yin >> map2; 963 964 EXPECT_FALSE(yin.error()); 965 EXPECT_EQ(flagBig, map2.f1); 966 EXPECT_EQ(flagRound|flagFlat, map2.f2); 967 EXPECT_EQ(flagNone, map2.f3); 968 //EXPECT_EQ(flagRound, map2.f4); // check optional key 969 } 970 } 971 972 973 974 //===----------------------------------------------------------------------===// 975 // Test ScalarTraits 976 //===----------------------------------------------------------------------===// 977 978 struct MyCustomType { 979 int length; 980 int width; 981 }; 982 983 struct MyCustomTypeMap { 984 MyCustomType f1; 985 MyCustomType f2; 986 int f3; 987 }; 988 989 990 namespace llvm { 991 namespace yaml { 992 template <> 993 struct MappingTraits<MyCustomTypeMap> { 994 static void mapping(IO &io, MyCustomTypeMap& s) { 995 io.mapRequired("f1", s.f1); 996 io.mapRequired("f2", s.f2); 997 io.mapRequired("f3", s.f3); 998 } 999 }; 1000 // MyCustomType is formatted as a yaml scalar. A value of 1001 // {length=3, width=4} would be represented in yaml as "3 by 4". 1002 template<> 1003 struct ScalarTraits<MyCustomType> { 1004 static void output(const MyCustomType &value, void* ctxt, llvm::raw_ostream &out) { 1005 out << llvm::format("%d by %d", value.length, value.width); 1006 } 1007 static StringRef input(StringRef scalar, void* ctxt, MyCustomType &value) { 1008 size_t byStart = scalar.find("by"); 1009 if ( byStart != StringRef::npos ) { 1010 StringRef lenStr = scalar.slice(0, byStart); 1011 lenStr = lenStr.rtrim(); 1012 if ( lenStr.getAsInteger(0, value.length) ) { 1013 return "malformed length"; 1014 } 1015 StringRef widthStr = scalar.drop_front(byStart+2); 1016 widthStr = widthStr.ltrim(); 1017 if ( widthStr.getAsInteger(0, value.width) ) { 1018 return "malformed width"; 1019 } 1020 return StringRef(); 1021 } 1022 else { 1023 return "malformed by"; 1024 } 1025 } 1026 static QuotingType mustQuote(StringRef) { return QuotingType::Single; } 1027 }; 1028 } 1029 } 1030 1031 1032 // 1033 // Test writing then reading back custom values 1034 // 1035 TEST(YAMLIO, TestReadWriteMyCustomType) { 1036 std::string intermediate; 1037 { 1038 MyCustomTypeMap map; 1039 map.f1.length = 1; 1040 map.f1.width = 4; 1041 map.f2.length = 100; 1042 map.f2.width = 400; 1043 map.f3 = 10; 1044 1045 llvm::raw_string_ostream ostr(intermediate); 1046 Output yout(ostr); 1047 yout << map; 1048 } 1049 1050 { 1051 Input yin(intermediate); 1052 MyCustomTypeMap map2; 1053 yin >> map2; 1054 1055 EXPECT_FALSE(yin.error()); 1056 EXPECT_EQ(1, map2.f1.length); 1057 EXPECT_EQ(4, map2.f1.width); 1058 EXPECT_EQ(100, map2.f2.length); 1059 EXPECT_EQ(400, map2.f2.width); 1060 EXPECT_EQ(10, map2.f3); 1061 } 1062 } 1063 1064 1065 //===----------------------------------------------------------------------===// 1066 // Test BlockScalarTraits 1067 //===----------------------------------------------------------------------===// 1068 1069 struct MultilineStringType { 1070 std::string str; 1071 }; 1072 1073 struct MultilineStringTypeMap { 1074 MultilineStringType name; 1075 MultilineStringType description; 1076 MultilineStringType ingredients; 1077 MultilineStringType recipes; 1078 MultilineStringType warningLabels; 1079 MultilineStringType documentation; 1080 int price; 1081 }; 1082 1083 namespace llvm { 1084 namespace yaml { 1085 template <> 1086 struct MappingTraits<MultilineStringTypeMap> { 1087 static void mapping(IO &io, MultilineStringTypeMap& s) { 1088 io.mapRequired("name", s.name); 1089 io.mapRequired("description", s.description); 1090 io.mapRequired("ingredients", s.ingredients); 1091 io.mapRequired("recipes", s.recipes); 1092 io.mapRequired("warningLabels", s.warningLabels); 1093 io.mapRequired("documentation", s.documentation); 1094 io.mapRequired("price", s.price); 1095 } 1096 }; 1097 1098 // MultilineStringType is formatted as a yaml block literal scalar. A value of 1099 // "Hello\nWorld" would be represented in yaml as 1100 // | 1101 // Hello 1102 // World 1103 template <> 1104 struct BlockScalarTraits<MultilineStringType> { 1105 static void output(const MultilineStringType &value, void *ctxt, 1106 llvm::raw_ostream &out) { 1107 out << value.str; 1108 } 1109 static StringRef input(StringRef scalar, void *ctxt, 1110 MultilineStringType &value) { 1111 value.str = scalar.str(); 1112 return StringRef(); 1113 } 1114 }; 1115 } 1116 } 1117 1118 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MultilineStringType) 1119 1120 // 1121 // Test writing then reading back custom values 1122 // 1123 TEST(YAMLIO, TestReadWriteMultilineStringType) { 1124 std::string intermediate; 1125 { 1126 MultilineStringTypeMap map; 1127 map.name.str = "An Item"; 1128 map.description.str = "Hello\nWorld"; 1129 map.ingredients.str = "SubItem 1\nSub Item 2\n\nSub Item 3\n"; 1130 map.recipes.str = "\n\nTest 1\n\n\n"; 1131 map.warningLabels.str = ""; 1132 map.documentation.str = "\n\n"; 1133 map.price = 350; 1134 1135 llvm::raw_string_ostream ostr(intermediate); 1136 Output yout(ostr); 1137 yout << map; 1138 } 1139 { 1140 Input yin(intermediate); 1141 MultilineStringTypeMap map2; 1142 yin >> map2; 1143 1144 EXPECT_FALSE(yin.error()); 1145 EXPECT_EQ(map2.name.str, "An Item\n"); 1146 EXPECT_EQ(map2.description.str, "Hello\nWorld\n"); 1147 EXPECT_EQ(map2.ingredients.str, "SubItem 1\nSub Item 2\n\nSub Item 3\n"); 1148 EXPECT_EQ(map2.recipes.str, "\n\nTest 1\n"); 1149 EXPECT_TRUE(map2.warningLabels.str.empty()); 1150 EXPECT_TRUE(map2.documentation.str.empty()); 1151 EXPECT_EQ(map2.price, 350); 1152 } 1153 } 1154 1155 // 1156 // Test writing then reading back custom values 1157 // 1158 TEST(YAMLIO, TestReadWriteBlockScalarDocuments) { 1159 std::string intermediate; 1160 { 1161 std::vector<MultilineStringType> documents; 1162 MultilineStringType doc; 1163 doc.str = "Hello\nWorld"; 1164 documents.push_back(doc); 1165 1166 llvm::raw_string_ostream ostr(intermediate); 1167 Output yout(ostr); 1168 yout << documents; 1169 1170 // Verify that the block scalar header was written out on the same line 1171 // as the document marker. 1172 EXPECT_NE(llvm::StringRef::npos, llvm::StringRef(ostr.str()).find("--- |")); 1173 } 1174 { 1175 Input yin(intermediate); 1176 std::vector<MultilineStringType> documents2; 1177 yin >> documents2; 1178 1179 EXPECT_FALSE(yin.error()); 1180 EXPECT_EQ(documents2.size(), size_t(1)); 1181 EXPECT_EQ(documents2[0].str, "Hello\nWorld\n"); 1182 } 1183 } 1184 1185 TEST(YAMLIO, TestReadWriteBlockScalarValue) { 1186 std::string intermediate; 1187 { 1188 MultilineStringType doc; 1189 doc.str = "Just a block\nscalar doc"; 1190 1191 llvm::raw_string_ostream ostr(intermediate); 1192 Output yout(ostr); 1193 yout << doc; 1194 } 1195 { 1196 Input yin(intermediate); 1197 MultilineStringType doc; 1198 yin >> doc; 1199 1200 EXPECT_FALSE(yin.error()); 1201 EXPECT_EQ(doc.str, "Just a block\nscalar doc\n"); 1202 } 1203 } 1204 1205 //===----------------------------------------------------------------------===// 1206 // Test flow sequences 1207 //===----------------------------------------------------------------------===// 1208 1209 LLVM_YAML_STRONG_TYPEDEF(int, MyNumber) 1210 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(MyNumber) 1211 LLVM_YAML_STRONG_TYPEDEF(llvm::StringRef, MyString) 1212 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(MyString) 1213 1214 namespace llvm { 1215 namespace yaml { 1216 template<> 1217 struct ScalarTraits<MyNumber> { 1218 static void output(const MyNumber &value, void *, llvm::raw_ostream &out) { 1219 out << value; 1220 } 1221 1222 static StringRef input(StringRef scalar, void *, MyNumber &value) { 1223 long long n; 1224 if ( getAsSignedInteger(scalar, 0, n) ) 1225 return "invalid number"; 1226 value = n; 1227 return StringRef(); 1228 } 1229 1230 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 1231 }; 1232 1233 template <> struct ScalarTraits<MyString> { 1234 using Impl = ScalarTraits<StringRef>; 1235 static void output(const MyString &V, void *Ctx, raw_ostream &OS) { 1236 Impl::output(V, Ctx, OS); 1237 } 1238 static StringRef input(StringRef S, void *Ctx, MyString &V) { 1239 return Impl::input(S, Ctx, V.value); 1240 } 1241 static QuotingType mustQuote(StringRef S) { 1242 return Impl::mustQuote(S); 1243 } 1244 }; 1245 } 1246 } 1247 1248 struct NameAndNumbers { 1249 llvm::StringRef name; 1250 std::vector<MyString> strings; 1251 std::vector<MyNumber> single; 1252 std::vector<MyNumber> numbers; 1253 }; 1254 1255 namespace llvm { 1256 namespace yaml { 1257 template <> 1258 struct MappingTraits<NameAndNumbers> { 1259 static void mapping(IO &io, NameAndNumbers& nn) { 1260 io.mapRequired("name", nn.name); 1261 io.mapRequired("strings", nn.strings); 1262 io.mapRequired("single", nn.single); 1263 io.mapRequired("numbers", nn.numbers); 1264 } 1265 }; 1266 } 1267 } 1268 1269 typedef std::vector<MyNumber> MyNumberFlowSequence; 1270 1271 LLVM_YAML_IS_SEQUENCE_VECTOR(MyNumberFlowSequence) 1272 1273 struct NameAndNumbersFlow { 1274 llvm::StringRef name; 1275 std::vector<MyNumberFlowSequence> sequenceOfNumbers; 1276 }; 1277 1278 namespace llvm { 1279 namespace yaml { 1280 template <> 1281 struct MappingTraits<NameAndNumbersFlow> { 1282 static void mapping(IO &io, NameAndNumbersFlow& nn) { 1283 io.mapRequired("name", nn.name); 1284 io.mapRequired("sequenceOfNumbers", nn.sequenceOfNumbers); 1285 } 1286 }; 1287 } 1288 } 1289 1290 // 1291 // Test writing then reading back custom values 1292 // 1293 TEST(YAMLIO, TestReadWriteMyFlowSequence) { 1294 std::string intermediate; 1295 { 1296 NameAndNumbers map; 1297 map.name = "hello"; 1298 map.strings.push_back(llvm::StringRef("one")); 1299 map.strings.push_back(llvm::StringRef("two")); 1300 map.single.push_back(1); 1301 map.numbers.push_back(10); 1302 map.numbers.push_back(-30); 1303 map.numbers.push_back(1024); 1304 1305 llvm::raw_string_ostream ostr(intermediate); 1306 Output yout(ostr); 1307 yout << map; 1308 1309 // Verify sequences were written in flow style 1310 ostr.flush(); 1311 llvm::StringRef flowOut(intermediate); 1312 EXPECT_NE(llvm::StringRef::npos, flowOut.find("one, two")); 1313 EXPECT_NE(llvm::StringRef::npos, flowOut.find("10, -30, 1024")); 1314 } 1315 1316 { 1317 Input yin(intermediate); 1318 NameAndNumbers map2; 1319 yin >> map2; 1320 1321 EXPECT_FALSE(yin.error()); 1322 EXPECT_TRUE(map2.name.equals("hello")); 1323 EXPECT_EQ(map2.strings.size(), 2UL); 1324 EXPECT_TRUE(map2.strings[0].value.equals("one")); 1325 EXPECT_TRUE(map2.strings[1].value.equals("two")); 1326 EXPECT_EQ(map2.single.size(), 1UL); 1327 EXPECT_EQ(1, map2.single[0]); 1328 EXPECT_EQ(map2.numbers.size(), 3UL); 1329 EXPECT_EQ(10, map2.numbers[0]); 1330 EXPECT_EQ(-30, map2.numbers[1]); 1331 EXPECT_EQ(1024, map2.numbers[2]); 1332 } 1333 } 1334 1335 1336 // 1337 // Test writing then reading back a sequence of flow sequences. 1338 // 1339 TEST(YAMLIO, TestReadWriteSequenceOfMyFlowSequence) { 1340 std::string intermediate; 1341 { 1342 NameAndNumbersFlow map; 1343 map.name = "hello"; 1344 MyNumberFlowSequence single = { 0 }; 1345 MyNumberFlowSequence numbers = { 12, 1, -512 }; 1346 map.sequenceOfNumbers.push_back(single); 1347 map.sequenceOfNumbers.push_back(numbers); 1348 map.sequenceOfNumbers.push_back(MyNumberFlowSequence()); 1349 1350 llvm::raw_string_ostream ostr(intermediate); 1351 Output yout(ostr); 1352 yout << map; 1353 1354 // Verify sequences were written in flow style 1355 // and that the parent sequence used '-'. 1356 ostr.flush(); 1357 llvm::StringRef flowOut(intermediate); 1358 EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 0 ]")); 1359 EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 12, 1, -512 ]")); 1360 EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ ]")); 1361 } 1362 1363 { 1364 Input yin(intermediate); 1365 NameAndNumbersFlow map2; 1366 yin >> map2; 1367 1368 EXPECT_FALSE(yin.error()); 1369 EXPECT_TRUE(map2.name.equals("hello")); 1370 EXPECT_EQ(map2.sequenceOfNumbers.size(), 3UL); 1371 EXPECT_EQ(map2.sequenceOfNumbers[0].size(), 1UL); 1372 EXPECT_EQ(0, map2.sequenceOfNumbers[0][0]); 1373 EXPECT_EQ(map2.sequenceOfNumbers[1].size(), 3UL); 1374 EXPECT_EQ(12, map2.sequenceOfNumbers[1][0]); 1375 EXPECT_EQ(1, map2.sequenceOfNumbers[1][1]); 1376 EXPECT_EQ(-512, map2.sequenceOfNumbers[1][2]); 1377 EXPECT_TRUE(map2.sequenceOfNumbers[2].empty()); 1378 } 1379 } 1380 1381 //===----------------------------------------------------------------------===// 1382 // Test normalizing/denormalizing 1383 //===----------------------------------------------------------------------===// 1384 1385 LLVM_YAML_STRONG_TYPEDEF(uint32_t, TotalSeconds) 1386 1387 typedef std::vector<TotalSeconds> SecondsSequence; 1388 1389 LLVM_YAML_IS_SEQUENCE_VECTOR(TotalSeconds) 1390 1391 1392 namespace llvm { 1393 namespace yaml { 1394 template <> 1395 struct MappingTraits<TotalSeconds> { 1396 1397 class NormalizedSeconds { 1398 public: 1399 NormalizedSeconds(IO &io) 1400 : hours(0), minutes(0), seconds(0) { 1401 } 1402 NormalizedSeconds(IO &, TotalSeconds &secs) 1403 : hours(secs/3600), 1404 minutes((secs - (hours*3600))/60), 1405 seconds(secs % 60) { 1406 } 1407 TotalSeconds denormalize(IO &) { 1408 return TotalSeconds(hours*3600 + minutes*60 + seconds); 1409 } 1410 1411 uint32_t hours; 1412 uint8_t minutes; 1413 uint8_t seconds; 1414 }; 1415 1416 static void mapping(IO &io, TotalSeconds &secs) { 1417 MappingNormalization<NormalizedSeconds, TotalSeconds> keys(io, secs); 1418 1419 io.mapOptional("hours", keys->hours, 0); 1420 io.mapOptional("minutes", keys->minutes, 0); 1421 io.mapRequired("seconds", keys->seconds); 1422 } 1423 }; 1424 } 1425 } 1426 1427 1428 // 1429 // Test the reading of a yaml sequence of mappings 1430 // 1431 TEST(YAMLIO, TestReadMySecondsSequence) { 1432 SecondsSequence seq; 1433 Input yin("---\n - hours: 1\n seconds: 5\n - seconds: 59\n...\n"); 1434 yin >> seq; 1435 1436 EXPECT_FALSE(yin.error()); 1437 EXPECT_EQ(seq.size(), 2UL); 1438 EXPECT_EQ(seq[0], 3605U); 1439 EXPECT_EQ(seq[1], 59U); 1440 } 1441 1442 1443 // 1444 // Test writing then reading back custom values 1445 // 1446 TEST(YAMLIO, TestReadWriteMySecondsSequence) { 1447 std::string intermediate; 1448 { 1449 SecondsSequence seq; 1450 seq.push_back(4000); 1451 seq.push_back(500); 1452 seq.push_back(59); 1453 1454 llvm::raw_string_ostream ostr(intermediate); 1455 Output yout(ostr); 1456 yout << seq; 1457 } 1458 { 1459 Input yin(intermediate); 1460 SecondsSequence seq2; 1461 yin >> seq2; 1462 1463 EXPECT_FALSE(yin.error()); 1464 EXPECT_EQ(seq2.size(), 3UL); 1465 EXPECT_EQ(seq2[0], 4000U); 1466 EXPECT_EQ(seq2[1], 500U); 1467 EXPECT_EQ(seq2[2], 59U); 1468 } 1469 } 1470 1471 1472 //===----------------------------------------------------------------------===// 1473 // Test dynamic typing 1474 //===----------------------------------------------------------------------===// 1475 1476 enum AFlags { 1477 a1, 1478 a2, 1479 a3 1480 }; 1481 1482 enum BFlags { 1483 b1, 1484 b2, 1485 b3 1486 }; 1487 1488 enum Kind { 1489 kindA, 1490 kindB 1491 }; 1492 1493 struct KindAndFlags { 1494 KindAndFlags() : kind(kindA), flags(0) { } 1495 KindAndFlags(Kind k, uint32_t f) : kind(k), flags(f) { } 1496 Kind kind; 1497 uint32_t flags; 1498 }; 1499 1500 typedef std::vector<KindAndFlags> KindAndFlagsSequence; 1501 1502 LLVM_YAML_IS_SEQUENCE_VECTOR(KindAndFlags) 1503 1504 namespace llvm { 1505 namespace yaml { 1506 template <> 1507 struct ScalarEnumerationTraits<AFlags> { 1508 static void enumeration(IO &io, AFlags &value) { 1509 io.enumCase(value, "a1", a1); 1510 io.enumCase(value, "a2", a2); 1511 io.enumCase(value, "a3", a3); 1512 } 1513 }; 1514 template <> 1515 struct ScalarEnumerationTraits<BFlags> { 1516 static void enumeration(IO &io, BFlags &value) { 1517 io.enumCase(value, "b1", b1); 1518 io.enumCase(value, "b2", b2); 1519 io.enumCase(value, "b3", b3); 1520 } 1521 }; 1522 template <> 1523 struct ScalarEnumerationTraits<Kind> { 1524 static void enumeration(IO &io, Kind &value) { 1525 io.enumCase(value, "A", kindA); 1526 io.enumCase(value, "B", kindB); 1527 } 1528 }; 1529 template <> 1530 struct MappingTraits<KindAndFlags> { 1531 static void mapping(IO &io, KindAndFlags& kf) { 1532 io.mapRequired("kind", kf.kind); 1533 // Type of "flags" field varies depending on "kind" field. 1534 // Use memcpy here to avoid breaking strict aliasing rules. 1535 if (kf.kind == kindA) { 1536 AFlags aflags = static_cast<AFlags>(kf.flags); 1537 io.mapRequired("flags", aflags); 1538 kf.flags = aflags; 1539 } else { 1540 BFlags bflags = static_cast<BFlags>(kf.flags); 1541 io.mapRequired("flags", bflags); 1542 kf.flags = bflags; 1543 } 1544 } 1545 }; 1546 } 1547 } 1548 1549 1550 // 1551 // Test the reading of a yaml sequence dynamic types 1552 // 1553 TEST(YAMLIO, TestReadKindAndFlagsSequence) { 1554 KindAndFlagsSequence seq; 1555 Input yin("---\n - kind: A\n flags: a2\n - kind: B\n flags: b1\n...\n"); 1556 yin >> seq; 1557 1558 EXPECT_FALSE(yin.error()); 1559 EXPECT_EQ(seq.size(), 2UL); 1560 EXPECT_EQ(seq[0].kind, kindA); 1561 EXPECT_EQ(seq[0].flags, (uint32_t)a2); 1562 EXPECT_EQ(seq[1].kind, kindB); 1563 EXPECT_EQ(seq[1].flags, (uint32_t)b1); 1564 } 1565 1566 // 1567 // Test writing then reading back dynamic types 1568 // 1569 TEST(YAMLIO, TestReadWriteKindAndFlagsSequence) { 1570 std::string intermediate; 1571 { 1572 KindAndFlagsSequence seq; 1573 seq.push_back(KindAndFlags(kindA,a1)); 1574 seq.push_back(KindAndFlags(kindB,b1)); 1575 seq.push_back(KindAndFlags(kindA,a2)); 1576 seq.push_back(KindAndFlags(kindB,b2)); 1577 seq.push_back(KindAndFlags(kindA,a3)); 1578 1579 llvm::raw_string_ostream ostr(intermediate); 1580 Output yout(ostr); 1581 yout << seq; 1582 } 1583 { 1584 Input yin(intermediate); 1585 KindAndFlagsSequence seq2; 1586 yin >> seq2; 1587 1588 EXPECT_FALSE(yin.error()); 1589 EXPECT_EQ(seq2.size(), 5UL); 1590 EXPECT_EQ(seq2[0].kind, kindA); 1591 EXPECT_EQ(seq2[0].flags, (uint32_t)a1); 1592 EXPECT_EQ(seq2[1].kind, kindB); 1593 EXPECT_EQ(seq2[1].flags, (uint32_t)b1); 1594 EXPECT_EQ(seq2[2].kind, kindA); 1595 EXPECT_EQ(seq2[2].flags, (uint32_t)a2); 1596 EXPECT_EQ(seq2[3].kind, kindB); 1597 EXPECT_EQ(seq2[3].flags, (uint32_t)b2); 1598 EXPECT_EQ(seq2[4].kind, kindA); 1599 EXPECT_EQ(seq2[4].flags, (uint32_t)a3); 1600 } 1601 } 1602 1603 1604 //===----------------------------------------------------------------------===// 1605 // Test document list 1606 //===----------------------------------------------------------------------===// 1607 1608 struct FooBarMap { 1609 int foo; 1610 int bar; 1611 }; 1612 typedef std::vector<FooBarMap> FooBarMapDocumentList; 1613 1614 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(FooBarMap) 1615 1616 1617 namespace llvm { 1618 namespace yaml { 1619 template <> 1620 struct MappingTraits<FooBarMap> { 1621 static void mapping(IO &io, FooBarMap& fb) { 1622 io.mapRequired("foo", fb.foo); 1623 io.mapRequired("bar", fb.bar); 1624 } 1625 }; 1626 } 1627 } 1628 1629 1630 // 1631 // Test the reading of a yaml mapping 1632 // 1633 TEST(YAMLIO, TestDocRead) { 1634 FooBarMap doc; 1635 Input yin("---\nfoo: 3\nbar: 5\n...\n"); 1636 yin >> doc; 1637 1638 EXPECT_FALSE(yin.error()); 1639 EXPECT_EQ(doc.foo, 3); 1640 EXPECT_EQ(doc.bar,5); 1641 } 1642 1643 1644 1645 // 1646 // Test writing then reading back a sequence of mappings 1647 // 1648 TEST(YAMLIO, TestSequenceDocListWriteAndRead) { 1649 std::string intermediate; 1650 { 1651 FooBarMap doc1; 1652 doc1.foo = 10; 1653 doc1.bar = -3; 1654 FooBarMap doc2; 1655 doc2.foo = 257; 1656 doc2.bar = 0; 1657 std::vector<FooBarMap> docList; 1658 docList.push_back(doc1); 1659 docList.push_back(doc2); 1660 1661 llvm::raw_string_ostream ostr(intermediate); 1662 Output yout(ostr); 1663 yout << docList; 1664 } 1665 1666 1667 { 1668 Input yin(intermediate); 1669 std::vector<FooBarMap> docList2; 1670 yin >> docList2; 1671 1672 EXPECT_FALSE(yin.error()); 1673 EXPECT_EQ(docList2.size(), 2UL); 1674 FooBarMap& map1 = docList2[0]; 1675 FooBarMap& map2 = docList2[1]; 1676 EXPECT_EQ(map1.foo, 10); 1677 EXPECT_EQ(map1.bar, -3); 1678 EXPECT_EQ(map2.foo, 257); 1679 EXPECT_EQ(map2.bar, 0); 1680 } 1681 } 1682 1683 //===----------------------------------------------------------------------===// 1684 // Test document tags 1685 //===----------------------------------------------------------------------===// 1686 1687 struct MyDouble { 1688 MyDouble() : value(0.0) { } 1689 MyDouble(double x) : value(x) { } 1690 double value; 1691 }; 1692 1693 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyDouble) 1694 1695 1696 namespace llvm { 1697 namespace yaml { 1698 template <> 1699 struct MappingTraits<MyDouble> { 1700 static void mapping(IO &io, MyDouble &d) { 1701 if (io.mapTag("!decimal", true)) { 1702 mappingDecimal(io, d); 1703 } else if (io.mapTag("!fraction")) { 1704 mappingFraction(io, d); 1705 } 1706 } 1707 static void mappingDecimal(IO &io, MyDouble &d) { 1708 io.mapRequired("value", d.value); 1709 } 1710 static void mappingFraction(IO &io, MyDouble &d) { 1711 double num, denom; 1712 io.mapRequired("numerator", num); 1713 io.mapRequired("denominator", denom); 1714 // convert fraction to double 1715 d.value = num/denom; 1716 } 1717 }; 1718 } 1719 } 1720 1721 1722 // 1723 // Test the reading of two different tagged yaml documents. 1724 // 1725 TEST(YAMLIO, TestTaggedDocuments) { 1726 std::vector<MyDouble> docList; 1727 Input yin("--- !decimal\nvalue: 3.0\n" 1728 "--- !fraction\nnumerator: 9.0\ndenominator: 2\n...\n"); 1729 yin >> docList; 1730 EXPECT_FALSE(yin.error()); 1731 EXPECT_EQ(docList.size(), 2UL); 1732 EXPECT_EQ(docList[0].value, 3.0); 1733 EXPECT_EQ(docList[1].value, 4.5); 1734 } 1735 1736 1737 1738 // 1739 // Test writing then reading back tagged documents 1740 // 1741 TEST(YAMLIO, TestTaggedDocumentsWriteAndRead) { 1742 std::string intermediate; 1743 { 1744 MyDouble a(10.25); 1745 MyDouble b(-3.75); 1746 std::vector<MyDouble> docList; 1747 docList.push_back(a); 1748 docList.push_back(b); 1749 1750 llvm::raw_string_ostream ostr(intermediate); 1751 Output yout(ostr); 1752 yout << docList; 1753 } 1754 1755 { 1756 Input yin(intermediate); 1757 std::vector<MyDouble> docList2; 1758 yin >> docList2; 1759 1760 EXPECT_FALSE(yin.error()); 1761 EXPECT_EQ(docList2.size(), 2UL); 1762 EXPECT_EQ(docList2[0].value, 10.25); 1763 EXPECT_EQ(docList2[1].value, -3.75); 1764 } 1765 } 1766 1767 1768 //===----------------------------------------------------------------------===// 1769 // Test mapping validation 1770 //===----------------------------------------------------------------------===// 1771 1772 struct MyValidation { 1773 double value; 1774 }; 1775 1776 LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MyValidation) 1777 1778 namespace llvm { 1779 namespace yaml { 1780 template <> 1781 struct MappingTraits<MyValidation> { 1782 static void mapping(IO &io, MyValidation &d) { 1783 io.mapRequired("value", d.value); 1784 } 1785 static std::string validate(IO &io, MyValidation &d) { 1786 if (d.value < 0) 1787 return "negative value"; 1788 return {}; 1789 } 1790 }; 1791 } 1792 } 1793 1794 1795 // 1796 // Test that validate() is called and complains about the negative value. 1797 // 1798 TEST(YAMLIO, TestValidatingInput) { 1799 std::vector<MyValidation> docList; 1800 Input yin("--- \nvalue: 3.0\n" 1801 "--- \nvalue: -1.0\n...\n", 1802 nullptr, suppressErrorMessages); 1803 yin >> docList; 1804 EXPECT_TRUE(!!yin.error()); 1805 } 1806 1807 //===----------------------------------------------------------------------===// 1808 // Test flow mapping 1809 //===----------------------------------------------------------------------===// 1810 1811 struct FlowFooBar { 1812 int foo; 1813 int bar; 1814 1815 FlowFooBar() : foo(0), bar(0) {} 1816 FlowFooBar(int foo, int bar) : foo(foo), bar(bar) {} 1817 }; 1818 1819 typedef std::vector<FlowFooBar> FlowFooBarSequence; 1820 1821 LLVM_YAML_IS_SEQUENCE_VECTOR(FlowFooBar) 1822 1823 struct FlowFooBarDoc { 1824 FlowFooBar attribute; 1825 FlowFooBarSequence seq; 1826 }; 1827 1828 namespace llvm { 1829 namespace yaml { 1830 template <> 1831 struct MappingTraits<FlowFooBar> { 1832 static void mapping(IO &io, FlowFooBar &fb) { 1833 io.mapRequired("foo", fb.foo); 1834 io.mapRequired("bar", fb.bar); 1835 } 1836 1837 static const bool flow = true; 1838 }; 1839 1840 template <> 1841 struct MappingTraits<FlowFooBarDoc> { 1842 static void mapping(IO &io, FlowFooBarDoc &fb) { 1843 io.mapRequired("attribute", fb.attribute); 1844 io.mapRequired("seq", fb.seq); 1845 } 1846 }; 1847 } 1848 } 1849 1850 // 1851 // Test writing then reading back custom mappings 1852 // 1853 TEST(YAMLIO, TestReadWriteMyFlowMapping) { 1854 std::string intermediate; 1855 { 1856 FlowFooBarDoc doc; 1857 doc.attribute = FlowFooBar(42, 907); 1858 doc.seq.push_back(FlowFooBar(1, 2)); 1859 doc.seq.push_back(FlowFooBar(0, 0)); 1860 doc.seq.push_back(FlowFooBar(-1, 1024)); 1861 1862 llvm::raw_string_ostream ostr(intermediate); 1863 Output yout(ostr); 1864 yout << doc; 1865 1866 // Verify that mappings were written in flow style 1867 ostr.flush(); 1868 llvm::StringRef flowOut(intermediate); 1869 EXPECT_NE(llvm::StringRef::npos, flowOut.find("{ foo: 42, bar: 907 }")); 1870 EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 1, bar: 2 }")); 1871 EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 0, bar: 0 }")); 1872 EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: -1, bar: 1024 }")); 1873 } 1874 1875 { 1876 Input yin(intermediate); 1877 FlowFooBarDoc doc2; 1878 yin >> doc2; 1879 1880 EXPECT_FALSE(yin.error()); 1881 EXPECT_EQ(doc2.attribute.foo, 42); 1882 EXPECT_EQ(doc2.attribute.bar, 907); 1883 EXPECT_EQ(doc2.seq.size(), 3UL); 1884 EXPECT_EQ(doc2.seq[0].foo, 1); 1885 EXPECT_EQ(doc2.seq[0].bar, 2); 1886 EXPECT_EQ(doc2.seq[1].foo, 0); 1887 EXPECT_EQ(doc2.seq[1].bar, 0); 1888 EXPECT_EQ(doc2.seq[2].foo, -1); 1889 EXPECT_EQ(doc2.seq[2].bar, 1024); 1890 } 1891 } 1892 1893 //===----------------------------------------------------------------------===// 1894 // Test error handling 1895 //===----------------------------------------------------------------------===// 1896 1897 // 1898 // Test error handling of unknown enumerated scalar 1899 // 1900 TEST(YAMLIO, TestColorsReadError) { 1901 ColorMap map; 1902 Input yin("---\n" 1903 "c1: blue\n" 1904 "c2: purple\n" 1905 "c3: green\n" 1906 "...\n", 1907 /*Ctxt=*/nullptr, 1908 suppressErrorMessages); 1909 yin >> map; 1910 EXPECT_TRUE(!!yin.error()); 1911 } 1912 1913 1914 // 1915 // Test error handling of flow sequence with unknown value 1916 // 1917 TEST(YAMLIO, TestFlagsReadError) { 1918 FlagsMap map; 1919 Input yin("---\n" 1920 "f1: [ big ]\n" 1921 "f2: [ round, hollow ]\n" 1922 "f3: []\n" 1923 "...\n", 1924 /*Ctxt=*/nullptr, 1925 suppressErrorMessages); 1926 yin >> map; 1927 1928 EXPECT_TRUE(!!yin.error()); 1929 } 1930 1931 1932 // 1933 // Test error handling reading built-in uint8_t type 1934 // 1935 TEST(YAMLIO, TestReadBuiltInTypesUint8Error) { 1936 std::vector<uint8_t> seq; 1937 Input yin("---\n" 1938 "- 255\n" 1939 "- 0\n" 1940 "- 257\n" 1941 "...\n", 1942 /*Ctxt=*/nullptr, 1943 suppressErrorMessages); 1944 yin >> seq; 1945 1946 EXPECT_TRUE(!!yin.error()); 1947 } 1948 1949 1950 // 1951 // Test error handling reading built-in uint16_t type 1952 // 1953 TEST(YAMLIO, TestReadBuiltInTypesUint16Error) { 1954 std::vector<uint16_t> seq; 1955 Input yin("---\n" 1956 "- 65535\n" 1957 "- 0\n" 1958 "- 66000\n" 1959 "...\n", 1960 /*Ctxt=*/nullptr, 1961 suppressErrorMessages); 1962 yin >> seq; 1963 1964 EXPECT_TRUE(!!yin.error()); 1965 } 1966 1967 1968 // 1969 // Test error handling reading built-in uint32_t type 1970 // 1971 TEST(YAMLIO, TestReadBuiltInTypesUint32Error) { 1972 std::vector<uint32_t> seq; 1973 Input yin("---\n" 1974 "- 4000000000\n" 1975 "- 0\n" 1976 "- 5000000000\n" 1977 "...\n", 1978 /*Ctxt=*/nullptr, 1979 suppressErrorMessages); 1980 yin >> seq; 1981 1982 EXPECT_TRUE(!!yin.error()); 1983 } 1984 1985 1986 // 1987 // Test error handling reading built-in uint64_t type 1988 // 1989 TEST(YAMLIO, TestReadBuiltInTypesUint64Error) { 1990 std::vector<uint64_t> seq; 1991 Input yin("---\n" 1992 "- 18446744073709551615\n" 1993 "- 0\n" 1994 "- 19446744073709551615\n" 1995 "...\n", 1996 /*Ctxt=*/nullptr, 1997 suppressErrorMessages); 1998 yin >> seq; 1999 2000 EXPECT_TRUE(!!yin.error()); 2001 } 2002 2003 2004 // 2005 // Test error handling reading built-in int8_t type 2006 // 2007 TEST(YAMLIO, TestReadBuiltInTypesint8OverError) { 2008 std::vector<int8_t> seq; 2009 Input yin("---\n" 2010 "- -128\n" 2011 "- 0\n" 2012 "- 127\n" 2013 "- 128\n" 2014 "...\n", 2015 /*Ctxt=*/nullptr, 2016 suppressErrorMessages); 2017 yin >> seq; 2018 2019 EXPECT_TRUE(!!yin.error()); 2020 } 2021 2022 // 2023 // Test error handling reading built-in int8_t type 2024 // 2025 TEST(YAMLIO, TestReadBuiltInTypesint8UnderError) { 2026 std::vector<int8_t> seq; 2027 Input yin("---\n" 2028 "- -128\n" 2029 "- 0\n" 2030 "- 127\n" 2031 "- -129\n" 2032 "...\n", 2033 /*Ctxt=*/nullptr, 2034 suppressErrorMessages); 2035 yin >> seq; 2036 2037 EXPECT_TRUE(!!yin.error()); 2038 } 2039 2040 2041 // 2042 // Test error handling reading built-in int16_t type 2043 // 2044 TEST(YAMLIO, TestReadBuiltInTypesint16UnderError) { 2045 std::vector<int16_t> seq; 2046 Input yin("---\n" 2047 "- 32767\n" 2048 "- 0\n" 2049 "- -32768\n" 2050 "- -32769\n" 2051 "...\n", 2052 /*Ctxt=*/nullptr, 2053 suppressErrorMessages); 2054 yin >> seq; 2055 2056 EXPECT_TRUE(!!yin.error()); 2057 } 2058 2059 2060 // 2061 // Test error handling reading built-in int16_t type 2062 // 2063 TEST(YAMLIO, TestReadBuiltInTypesint16OverError) { 2064 std::vector<int16_t> seq; 2065 Input yin("---\n" 2066 "- 32767\n" 2067 "- 0\n" 2068 "- -32768\n" 2069 "- 32768\n" 2070 "...\n", 2071 /*Ctxt=*/nullptr, 2072 suppressErrorMessages); 2073 yin >> seq; 2074 2075 EXPECT_TRUE(!!yin.error()); 2076 } 2077 2078 2079 // 2080 // Test error handling reading built-in int32_t type 2081 // 2082 TEST(YAMLIO, TestReadBuiltInTypesint32UnderError) { 2083 std::vector<int32_t> seq; 2084 Input yin("---\n" 2085 "- 2147483647\n" 2086 "- 0\n" 2087 "- -2147483648\n" 2088 "- -2147483649\n" 2089 "...\n", 2090 /*Ctxt=*/nullptr, 2091 suppressErrorMessages); 2092 yin >> seq; 2093 2094 EXPECT_TRUE(!!yin.error()); 2095 } 2096 2097 // 2098 // Test error handling reading built-in int32_t type 2099 // 2100 TEST(YAMLIO, TestReadBuiltInTypesint32OverError) { 2101 std::vector<int32_t> seq; 2102 Input yin("---\n" 2103 "- 2147483647\n" 2104 "- 0\n" 2105 "- -2147483648\n" 2106 "- 2147483649\n" 2107 "...\n", 2108 /*Ctxt=*/nullptr, 2109 suppressErrorMessages); 2110 yin >> seq; 2111 2112 EXPECT_TRUE(!!yin.error()); 2113 } 2114 2115 2116 // 2117 // Test error handling reading built-in int64_t type 2118 // 2119 TEST(YAMLIO, TestReadBuiltInTypesint64UnderError) { 2120 std::vector<int64_t> seq; 2121 Input yin("---\n" 2122 "- -9223372036854775808\n" 2123 "- 0\n" 2124 "- 9223372036854775807\n" 2125 "- -9223372036854775809\n" 2126 "...\n", 2127 /*Ctxt=*/nullptr, 2128 suppressErrorMessages); 2129 yin >> seq; 2130 2131 EXPECT_TRUE(!!yin.error()); 2132 } 2133 2134 // 2135 // Test error handling reading built-in int64_t type 2136 // 2137 TEST(YAMLIO, TestReadBuiltInTypesint64OverError) { 2138 std::vector<int64_t> seq; 2139 Input yin("---\n" 2140 "- -9223372036854775808\n" 2141 "- 0\n" 2142 "- 9223372036854775807\n" 2143 "- 9223372036854775809\n" 2144 "...\n", 2145 /*Ctxt=*/nullptr, 2146 suppressErrorMessages); 2147 yin >> seq; 2148 2149 EXPECT_TRUE(!!yin.error()); 2150 } 2151 2152 // 2153 // Test error handling reading built-in float type 2154 // 2155 TEST(YAMLIO, TestReadBuiltInTypesFloatError) { 2156 std::vector<float> seq; 2157 Input yin("---\n" 2158 "- 0.0\n" 2159 "- 1000.1\n" 2160 "- -123.456\n" 2161 "- 1.2.3\n" 2162 "...\n", 2163 /*Ctxt=*/nullptr, 2164 suppressErrorMessages); 2165 yin >> seq; 2166 2167 EXPECT_TRUE(!!yin.error()); 2168 } 2169 2170 // 2171 // Test error handling reading built-in float type 2172 // 2173 TEST(YAMLIO, TestReadBuiltInTypesDoubleError) { 2174 std::vector<double> seq; 2175 Input yin("---\n" 2176 "- 0.0\n" 2177 "- 1000.1\n" 2178 "- -123.456\n" 2179 "- 1.2.3\n" 2180 "...\n", 2181 /*Ctxt=*/nullptr, 2182 suppressErrorMessages); 2183 yin >> seq; 2184 2185 EXPECT_TRUE(!!yin.error()); 2186 } 2187 2188 // 2189 // Test error handling reading built-in Hex8 type 2190 // 2191 TEST(YAMLIO, TestReadBuiltInTypesHex8Error) { 2192 std::vector<Hex8> seq; 2193 Input yin("---\n" 2194 "- 0x12\n" 2195 "- 0xFE\n" 2196 "- 0x123\n" 2197 "...\n", 2198 /*Ctxt=*/nullptr, 2199 suppressErrorMessages); 2200 yin >> seq; 2201 EXPECT_TRUE(!!yin.error()); 2202 2203 std::vector<Hex8> seq2; 2204 Input yin2("---\n" 2205 "[ 0x12, 0xFE, 0x123 ]\n" 2206 "...\n", 2207 /*Ctxt=*/nullptr, suppressErrorMessages); 2208 yin2 >> seq2; 2209 EXPECT_TRUE(!!yin2.error()); 2210 2211 EXPECT_TRUE(seq.size() == 3); 2212 EXPECT_TRUE(seq.size() == seq2.size()); 2213 for (size_t i = 0; i < seq.size(); ++i) 2214 EXPECT_TRUE(seq[i] == seq2[i]); 2215 } 2216 2217 2218 // 2219 // Test error handling reading built-in Hex16 type 2220 // 2221 TEST(YAMLIO, TestReadBuiltInTypesHex16Error) { 2222 std::vector<Hex16> seq; 2223 Input yin("---\n" 2224 "- 0x0012\n" 2225 "- 0xFEFF\n" 2226 "- 0x12345\n" 2227 "...\n", 2228 /*Ctxt=*/nullptr, 2229 suppressErrorMessages); 2230 yin >> seq; 2231 EXPECT_TRUE(!!yin.error()); 2232 2233 std::vector<Hex16> seq2; 2234 Input yin2("---\n" 2235 "[ 0x0012, 0xFEFF, 0x12345 ]\n" 2236 "...\n", 2237 /*Ctxt=*/nullptr, suppressErrorMessages); 2238 yin2 >> seq2; 2239 EXPECT_TRUE(!!yin2.error()); 2240 2241 EXPECT_TRUE(seq.size() == 3); 2242 EXPECT_TRUE(seq.size() == seq2.size()); 2243 for (size_t i = 0; i < seq.size(); ++i) 2244 EXPECT_TRUE(seq[i] == seq2[i]); 2245 } 2246 2247 // 2248 // Test error handling reading built-in Hex32 type 2249 // 2250 TEST(YAMLIO, TestReadBuiltInTypesHex32Error) { 2251 std::vector<Hex32> seq; 2252 Input yin("---\n" 2253 "- 0x0012\n" 2254 "- 0xFEFF0000\n" 2255 "- 0x1234556789\n" 2256 "...\n", 2257 /*Ctxt=*/nullptr, 2258 suppressErrorMessages); 2259 yin >> seq; 2260 2261 EXPECT_TRUE(!!yin.error()); 2262 2263 std::vector<Hex32> seq2; 2264 Input yin2("---\n" 2265 "[ 0x0012, 0xFEFF0000, 0x1234556789 ]\n" 2266 "...\n", 2267 /*Ctxt=*/nullptr, suppressErrorMessages); 2268 yin2 >> seq2; 2269 EXPECT_TRUE(!!yin2.error()); 2270 2271 EXPECT_TRUE(seq.size() == 3); 2272 EXPECT_TRUE(seq.size() == seq2.size()); 2273 for (size_t i = 0; i < seq.size(); ++i) 2274 EXPECT_TRUE(seq[i] == seq2[i]); 2275 } 2276 2277 // 2278 // Test error handling reading built-in Hex64 type 2279 // 2280 TEST(YAMLIO, TestReadBuiltInTypesHex64Error) { 2281 std::vector<Hex64> seq; 2282 Input yin("---\n" 2283 "- 0x0012\n" 2284 "- 0xFFEEDDCCBBAA9988\n" 2285 "- 0x12345567890ABCDEF0\n" 2286 "...\n", 2287 /*Ctxt=*/nullptr, 2288 suppressErrorMessages); 2289 yin >> seq; 2290 EXPECT_TRUE(!!yin.error()); 2291 2292 std::vector<Hex64> seq2; 2293 Input yin2("---\n" 2294 "[ 0x0012, 0xFFEEDDCCBBAA9988, 0x12345567890ABCDEF0 ]\n" 2295 "...\n", 2296 /*Ctxt=*/nullptr, suppressErrorMessages); 2297 yin2 >> seq2; 2298 EXPECT_TRUE(!!yin2.error()); 2299 2300 EXPECT_TRUE(seq.size() == 3); 2301 EXPECT_TRUE(seq.size() == seq2.size()); 2302 for (size_t i = 0; i < seq.size(); ++i) 2303 EXPECT_TRUE(seq[i] == seq2[i]); 2304 } 2305 2306 TEST(YAMLIO, TestMalformedMapFailsGracefully) { 2307 FooBar doc; 2308 { 2309 // We pass the suppressErrorMessages handler to handle the error 2310 // message generated in the constructor of Input. 2311 Input yin("{foo:3, bar: 5}", /*Ctxt=*/nullptr, suppressErrorMessages); 2312 yin >> doc; 2313 EXPECT_TRUE(!!yin.error()); 2314 } 2315 2316 { 2317 Input yin("---\nfoo:3\nbar: 5\n...\n", /*Ctxt=*/nullptr, suppressErrorMessages); 2318 yin >> doc; 2319 EXPECT_TRUE(!!yin.error()); 2320 } 2321 } 2322 2323 struct OptionalTest { 2324 std::vector<int> Numbers; 2325 }; 2326 2327 struct OptionalTestSeq { 2328 std::vector<OptionalTest> Tests; 2329 }; 2330 2331 LLVM_YAML_IS_SEQUENCE_VECTOR(OptionalTest) 2332 namespace llvm { 2333 namespace yaml { 2334 template <> 2335 struct MappingTraits<OptionalTest> { 2336 static void mapping(IO& IO, OptionalTest &OT) { 2337 IO.mapOptional("Numbers", OT.Numbers); 2338 } 2339 }; 2340 2341 template <> 2342 struct MappingTraits<OptionalTestSeq> { 2343 static void mapping(IO &IO, OptionalTestSeq &OTS) { 2344 IO.mapOptional("Tests", OTS.Tests); 2345 } 2346 }; 2347 } 2348 } 2349 2350 TEST(YAMLIO, SequenceElideTest) { 2351 // Test that writing out a purely optional structure with its fields set to 2352 // default followed by other data is properly read back in. 2353 OptionalTestSeq Seq; 2354 OptionalTest One, Two, Three, Four; 2355 int N[] = {1, 2, 3}; 2356 Three.Numbers.assign(N, N + 3); 2357 Seq.Tests.push_back(One); 2358 Seq.Tests.push_back(Two); 2359 Seq.Tests.push_back(Three); 2360 Seq.Tests.push_back(Four); 2361 2362 std::string intermediate; 2363 { 2364 llvm::raw_string_ostream ostr(intermediate); 2365 Output yout(ostr); 2366 yout << Seq; 2367 } 2368 2369 Input yin(intermediate); 2370 OptionalTestSeq Seq2; 2371 yin >> Seq2; 2372 2373 EXPECT_FALSE(yin.error()); 2374 2375 EXPECT_EQ(4UL, Seq2.Tests.size()); 2376 2377 EXPECT_TRUE(Seq2.Tests[0].Numbers.empty()); 2378 EXPECT_TRUE(Seq2.Tests[1].Numbers.empty()); 2379 2380 EXPECT_EQ(1, Seq2.Tests[2].Numbers[0]); 2381 EXPECT_EQ(2, Seq2.Tests[2].Numbers[1]); 2382 EXPECT_EQ(3, Seq2.Tests[2].Numbers[2]); 2383 2384 EXPECT_TRUE(Seq2.Tests[3].Numbers.empty()); 2385 } 2386 2387 TEST(YAMLIO, TestEmptyStringFailsForMapWithRequiredFields) { 2388 FooBar doc; 2389 Input yin(""); 2390 yin >> doc; 2391 EXPECT_TRUE(!!yin.error()); 2392 } 2393 2394 TEST(YAMLIO, TestEmptyStringSucceedsForMapWithOptionalFields) { 2395 OptionalTest doc; 2396 Input yin(""); 2397 yin >> doc; 2398 EXPECT_FALSE(yin.error()); 2399 } 2400 2401 TEST(YAMLIO, TestEmptyStringSucceedsForSequence) { 2402 std::vector<uint8_t> seq; 2403 Input yin("", /*Ctxt=*/nullptr, suppressErrorMessages); 2404 yin >> seq; 2405 2406 EXPECT_FALSE(yin.error()); 2407 EXPECT_TRUE(seq.empty()); 2408 } 2409 2410 struct FlowMap { 2411 llvm::StringRef str1, str2, str3; 2412 FlowMap(llvm::StringRef str1, llvm::StringRef str2, llvm::StringRef str3) 2413 : str1(str1), str2(str2), str3(str3) {} 2414 }; 2415 2416 struct FlowSeq { 2417 llvm::StringRef str; 2418 FlowSeq(llvm::StringRef S) : str(S) {} 2419 FlowSeq() = default; 2420 }; 2421 2422 namespace llvm { 2423 namespace yaml { 2424 template <> 2425 struct MappingTraits<FlowMap> { 2426 static void mapping(IO &io, FlowMap &fm) { 2427 io.mapRequired("str1", fm.str1); 2428 io.mapRequired("str2", fm.str2); 2429 io.mapRequired("str3", fm.str3); 2430 } 2431 2432 static const bool flow = true; 2433 }; 2434 2435 template <> 2436 struct ScalarTraits<FlowSeq> { 2437 static void output(const FlowSeq &value, void*, llvm::raw_ostream &out) { 2438 out << value.str; 2439 } 2440 static StringRef input(StringRef scalar, void*, FlowSeq &value) { 2441 value.str = scalar; 2442 return ""; 2443 } 2444 2445 static QuotingType mustQuote(StringRef S) { return QuotingType::None; } 2446 }; 2447 } 2448 } 2449 2450 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FlowSeq) 2451 2452 TEST(YAMLIO, TestWrapFlow) { 2453 std::string out; 2454 llvm::raw_string_ostream ostr(out); 2455 FlowMap Map("This is str1", "This is str2", "This is str3"); 2456 std::vector<FlowSeq> Seq; 2457 Seq.emplace_back("This is str1"); 2458 Seq.emplace_back("This is str2"); 2459 Seq.emplace_back("This is str3"); 2460 2461 { 2462 // 20 is just bellow the total length of the first mapping field. 2463 // We should wreap at every element. 2464 Output yout(ostr, nullptr, 15); 2465 2466 yout << Map; 2467 ostr.flush(); 2468 EXPECT_EQ(out, 2469 "---\n" 2470 "{ str1: This is str1, \n" 2471 " str2: This is str2, \n" 2472 " str3: This is str3 }\n" 2473 "...\n"); 2474 out.clear(); 2475 2476 yout << Seq; 2477 ostr.flush(); 2478 EXPECT_EQ(out, 2479 "---\n" 2480 "[ This is str1, \n" 2481 " This is str2, \n" 2482 " This is str3 ]\n" 2483 "...\n"); 2484 out.clear(); 2485 } 2486 { 2487 // 25 will allow the second field to be output on the first line. 2488 Output yout(ostr, nullptr, 25); 2489 2490 yout << Map; 2491 ostr.flush(); 2492 EXPECT_EQ(out, 2493 "---\n" 2494 "{ str1: This is str1, str2: This is str2, \n" 2495 " str3: This is str3 }\n" 2496 "...\n"); 2497 out.clear(); 2498 2499 yout << Seq; 2500 ostr.flush(); 2501 EXPECT_EQ(out, 2502 "---\n" 2503 "[ This is str1, This is str2, \n" 2504 " This is str3 ]\n" 2505 "...\n"); 2506 out.clear(); 2507 } 2508 { 2509 // 0 means no wrapping. 2510 Output yout(ostr, nullptr, 0); 2511 2512 yout << Map; 2513 ostr.flush(); 2514 EXPECT_EQ(out, 2515 "---\n" 2516 "{ str1: This is str1, str2: This is str2, str3: This is str3 }\n" 2517 "...\n"); 2518 out.clear(); 2519 2520 yout << Seq; 2521 ostr.flush(); 2522 EXPECT_EQ(out, 2523 "---\n" 2524 "[ This is str1, This is str2, This is str3 ]\n" 2525 "...\n"); 2526 out.clear(); 2527 } 2528 } 2529 2530 struct MappingContext { 2531 int A = 0; 2532 }; 2533 struct SimpleMap { 2534 int B = 0; 2535 int C = 0; 2536 }; 2537 2538 struct NestedMap { 2539 NestedMap(MappingContext &Context) : Context(Context) {} 2540 SimpleMap Simple; 2541 MappingContext &Context; 2542 }; 2543 2544 namespace llvm { 2545 namespace yaml { 2546 template <> struct MappingContextTraits<SimpleMap, MappingContext> { 2547 static void mapping(IO &io, SimpleMap &sm, MappingContext &Context) { 2548 io.mapRequired("B", sm.B); 2549 io.mapRequired("C", sm.C); 2550 ++Context.A; 2551 io.mapRequired("Context", Context.A); 2552 } 2553 }; 2554 2555 template <> struct MappingTraits<NestedMap> { 2556 static void mapping(IO &io, NestedMap &nm) { 2557 io.mapRequired("Simple", nm.Simple, nm.Context); 2558 } 2559 }; 2560 } 2561 } 2562 2563 TEST(YAMLIO, TestMapWithContext) { 2564 MappingContext Context; 2565 NestedMap Nested(Context); 2566 std::string out; 2567 llvm::raw_string_ostream ostr(out); 2568 2569 Output yout(ostr, nullptr, 15); 2570 2571 yout << Nested; 2572 ostr.flush(); 2573 EXPECT_EQ(1, Context.A); 2574 EXPECT_EQ("---\n" 2575 "Simple:\n" 2576 " B: 0\n" 2577 " C: 0\n" 2578 " Context: 1\n" 2579 "...\n", 2580 out); 2581 2582 out.clear(); 2583 2584 Nested.Simple.B = 2; 2585 Nested.Simple.C = 3; 2586 yout << Nested; 2587 ostr.flush(); 2588 EXPECT_EQ(2, Context.A); 2589 EXPECT_EQ("---\n" 2590 "Simple:\n" 2591 " B: 2\n" 2592 " C: 3\n" 2593 " Context: 2\n" 2594 "...\n", 2595 out); 2596 out.clear(); 2597 } 2598 2599 LLVM_YAML_IS_STRING_MAP(int) 2600 2601 TEST(YAMLIO, TestCustomMapping) { 2602 std::map<std::string, int> x; 2603 2604 std::string out; 2605 llvm::raw_string_ostream ostr(out); 2606 Output xout(ostr, nullptr, 0); 2607 2608 xout << x; 2609 ostr.flush(); 2610 EXPECT_EQ("---\n" 2611 "{}\n" 2612 "...\n", 2613 out); 2614 2615 x["foo"] = 1; 2616 x["bar"] = 2; 2617 2618 out.clear(); 2619 xout << x; 2620 ostr.flush(); 2621 EXPECT_EQ("---\n" 2622 "bar: 2\n" 2623 "foo: 1\n" 2624 "...\n", 2625 out); 2626 2627 Input yin(out); 2628 std::map<std::string, int> y; 2629 yin >> y; 2630 EXPECT_EQ(2ul, y.size()); 2631 EXPECT_EQ(1, y["foo"]); 2632 EXPECT_EQ(2, y["bar"]); 2633 } 2634 2635 LLVM_YAML_IS_STRING_MAP(FooBar) 2636 2637 TEST(YAMLIO, TestCustomMappingStruct) { 2638 std::map<std::string, FooBar> x; 2639 x["foo"].foo = 1; 2640 x["foo"].bar = 2; 2641 x["bar"].foo = 3; 2642 x["bar"].bar = 4; 2643 2644 std::string out; 2645 llvm::raw_string_ostream ostr(out); 2646 Output xout(ostr, nullptr, 0); 2647 2648 xout << x; 2649 ostr.flush(); 2650 EXPECT_EQ("---\n" 2651 "bar:\n" 2652 " foo: 3\n" 2653 " bar: 4\n" 2654 "foo:\n" 2655 " foo: 1\n" 2656 " bar: 2\n" 2657 "...\n", 2658 out); 2659 2660 Input yin(out); 2661 std::map<std::string, FooBar> y; 2662 yin >> y; 2663 EXPECT_EQ(2ul, y.size()); 2664 EXPECT_EQ(1, y["foo"].foo); 2665 EXPECT_EQ(2, y["foo"].bar); 2666 EXPECT_EQ(3, y["bar"].foo); 2667 EXPECT_EQ(4, y["bar"].bar); 2668 } 2669 2670 struct FooBarMapMap { 2671 std::map<std::string, FooBar> fbm; 2672 }; 2673 2674 namespace llvm { 2675 namespace yaml { 2676 template <> struct MappingTraits<FooBarMapMap> { 2677 static void mapping(IO &io, FooBarMapMap &x) { 2678 io.mapRequired("fbm", x.fbm); 2679 } 2680 }; 2681 } 2682 } 2683 2684 TEST(YAMLIO, TestEmptyMapWrite) { 2685 FooBarMapMap cont; 2686 std::string str; 2687 llvm::raw_string_ostream OS(str); 2688 Output yout(OS); 2689 yout << cont; 2690 EXPECT_EQ(OS.str(), "---\nfbm: {}\n...\n"); 2691 } 2692 2693 TEST(YAMLIO, TestEmptySequenceWrite) { 2694 { 2695 FooBarContainer cont; 2696 std::string str; 2697 llvm::raw_string_ostream OS(str); 2698 Output yout(OS); 2699 yout << cont; 2700 EXPECT_EQ(OS.str(), "---\nfbs: []\n...\n"); 2701 } 2702 2703 { 2704 FooBarSequence seq; 2705 std::string str; 2706 llvm::raw_string_ostream OS(str); 2707 Output yout(OS); 2708 yout << seq; 2709 EXPECT_EQ(OS.str(), "---\n[]\n...\n"); 2710 } 2711 } 2712 2713 static void TestEscaped(llvm::StringRef Input, llvm::StringRef Expected) { 2714 std::string out; 2715 llvm::raw_string_ostream ostr(out); 2716 Output xout(ostr, nullptr, 0); 2717 2718 llvm::yaml::EmptyContext Ctx; 2719 yamlize(xout, Input, true, Ctx); 2720 2721 ostr.flush(); 2722 2723 // Make a separate StringRef so we get nice byte-by-byte output. 2724 llvm::StringRef Got(out); 2725 EXPECT_EQ(Expected, Got); 2726 } 2727 2728 TEST(YAMLIO, TestEscaped) { 2729 // Single quote 2730 TestEscaped("@abc@", "'@abc@'"); 2731 // No quote 2732 TestEscaped("abc", "abc"); 2733 // Forward slash quoted 2734 TestEscaped("abc/", "'abc/'"); 2735 // Double quote non-printable 2736 TestEscaped("\01@abc@", "\"\\x01@abc@\""); 2737 // Double quote inside single quote 2738 TestEscaped("abc\"fdf", "'abc\"fdf'"); 2739 // Double quote inside double quote 2740 TestEscaped("\01bc\"fdf", "\"\\x01bc\\\"fdf\""); 2741 // Single quote inside single quote 2742 TestEscaped("abc'fdf", "'abc''fdf'"); 2743 // UTF8 2744 TestEscaped("/*параметр*/", "\"/*параметр*/\""); 2745 // UTF8 with single quote inside double quote 2746 TestEscaped("parameter 'параметр' is unused", 2747 "\"parameter 'параметр' is unused\""); 2748 2749 // String with embedded non-printable multibyte UTF-8 sequence (U+200B 2750 // zero-width space). The thing to test here is that we emit a 2751 // unicode-scalar level escape like \uNNNN (at the YAML level), and don't 2752 // just pass the UTF-8 byte sequence through as with quoted printables. 2753 { 2754 const unsigned char foobar[10] = {'f', 'o', 'o', 2755 0xE2, 0x80, 0x8B, // UTF-8 of U+200B 2756 'b', 'a', 'r', 2757 0x0}; 2758 TestEscaped((char const *)foobar, "\"foo\\u200Bbar\""); 2759 } 2760 } 2761 2762 TEST(YAMLIO, Numeric) { 2763 EXPECT_TRUE(isNumeric(".inf")); 2764 EXPECT_TRUE(isNumeric(".INF")); 2765 EXPECT_TRUE(isNumeric(".Inf")); 2766 EXPECT_TRUE(isNumeric("-.inf")); 2767 EXPECT_TRUE(isNumeric("+.inf")); 2768 2769 EXPECT_TRUE(isNumeric(".nan")); 2770 EXPECT_TRUE(isNumeric(".NaN")); 2771 EXPECT_TRUE(isNumeric(".NAN")); 2772 2773 EXPECT_TRUE(isNumeric("0")); 2774 EXPECT_TRUE(isNumeric("0.")); 2775 EXPECT_TRUE(isNumeric("0.0")); 2776 EXPECT_TRUE(isNumeric("-0.0")); 2777 EXPECT_TRUE(isNumeric("+0.0")); 2778 2779 EXPECT_TRUE(isNumeric("12345")); 2780 EXPECT_TRUE(isNumeric("012345")); 2781 EXPECT_TRUE(isNumeric("+12.0")); 2782 EXPECT_TRUE(isNumeric(".5")); 2783 EXPECT_TRUE(isNumeric("+.5")); 2784 EXPECT_TRUE(isNumeric("-1.0")); 2785 2786 EXPECT_TRUE(isNumeric("2.3e4")); 2787 EXPECT_TRUE(isNumeric("-2E+05")); 2788 EXPECT_TRUE(isNumeric("+12e03")); 2789 EXPECT_TRUE(isNumeric("6.8523015e+5")); 2790 2791 EXPECT_TRUE(isNumeric("1.e+1")); 2792 EXPECT_TRUE(isNumeric(".0e+1")); 2793 2794 EXPECT_TRUE(isNumeric("0x2aF3")); 2795 EXPECT_TRUE(isNumeric("0o01234567")); 2796 2797 EXPECT_FALSE(isNumeric("not a number")); 2798 EXPECT_FALSE(isNumeric(".")); 2799 EXPECT_FALSE(isNumeric(".e+1")); 2800 EXPECT_FALSE(isNumeric(".1e")); 2801 EXPECT_FALSE(isNumeric(".1e+")); 2802 EXPECT_FALSE(isNumeric(".1e++1")); 2803 2804 EXPECT_FALSE(isNumeric("ABCD")); 2805 EXPECT_FALSE(isNumeric("+0x2AF3")); 2806 EXPECT_FALSE(isNumeric("-0x2AF3")); 2807 EXPECT_FALSE(isNumeric("0x2AF3Z")); 2808 EXPECT_FALSE(isNumeric("0o012345678")); 2809 EXPECT_FALSE(isNumeric("0xZ")); 2810 EXPECT_FALSE(isNumeric("-0o012345678")); 2811 EXPECT_FALSE(isNumeric("000003A8229434B839616A25C16B0291F77A438B")); 2812 2813 EXPECT_FALSE(isNumeric("")); 2814 EXPECT_FALSE(isNumeric(".")); 2815 EXPECT_FALSE(isNumeric(".e+1")); 2816 EXPECT_FALSE(isNumeric(".e+")); 2817 EXPECT_FALSE(isNumeric(".e")); 2818 EXPECT_FALSE(isNumeric("e1")); 2819 2820 // Deprecated formats: as for YAML 1.2 specification, the following are not 2821 // valid numbers anymore: 2822 // 2823 // * Sexagecimal numbers 2824 // * Decimal numbers with comma s the delimiter 2825 // * "inf", "nan" without '.' prefix 2826 EXPECT_FALSE(isNumeric("3:25:45")); 2827 EXPECT_FALSE(isNumeric("+12,345")); 2828 EXPECT_FALSE(isNumeric("-inf")); 2829 EXPECT_FALSE(isNumeric("1,230.15")); 2830 } 2831 2832 //===----------------------------------------------------------------------===// 2833 // Test PolymorphicTraits and TaggedScalarTraits 2834 //===----------------------------------------------------------------------===// 2835 2836 struct Poly { 2837 enum NodeKind { 2838 NK_Scalar, 2839 NK_Seq, 2840 NK_Map, 2841 } Kind; 2842 2843 Poly(NodeKind Kind) : Kind(Kind) {} 2844 2845 virtual ~Poly() = default; 2846 2847 NodeKind getKind() const { return Kind; } 2848 }; 2849 2850 struct Scalar : Poly { 2851 enum ScalarKind { 2852 SK_Unknown, 2853 SK_Double, 2854 SK_Bool, 2855 } SKind; 2856 2857 union { 2858 double DoubleValue; 2859 bool BoolValue; 2860 }; 2861 2862 Scalar() : Poly(NK_Scalar), SKind(SK_Unknown) {} 2863 Scalar(double DoubleValue) 2864 : Poly(NK_Scalar), SKind(SK_Double), DoubleValue(DoubleValue) {} 2865 Scalar(bool BoolValue) 2866 : Poly(NK_Scalar), SKind(SK_Bool), BoolValue(BoolValue) {} 2867 2868 static bool classof(const Poly *N) { return N->getKind() == NK_Scalar; } 2869 }; 2870 2871 struct Seq : Poly, std::vector<std::unique_ptr<Poly>> { 2872 Seq() : Poly(NK_Seq) {} 2873 2874 static bool classof(const Poly *N) { return N->getKind() == NK_Seq; } 2875 }; 2876 2877 struct Map : Poly, llvm::StringMap<std::unique_ptr<Poly>> { 2878 Map() : Poly(NK_Map) {} 2879 2880 static bool classof(const Poly *N) { return N->getKind() == NK_Map; } 2881 }; 2882 2883 namespace llvm { 2884 namespace yaml { 2885 2886 template <> struct PolymorphicTraits<std::unique_ptr<Poly>> { 2887 static NodeKind getKind(const std::unique_ptr<Poly> &N) { 2888 if (isa<Scalar>(*N)) 2889 return NodeKind::Scalar; 2890 if (isa<Seq>(*N)) 2891 return NodeKind::Sequence; 2892 if (isa<Map>(*N)) 2893 return NodeKind::Map; 2894 llvm_unreachable("unsupported node type"); 2895 } 2896 2897 static Scalar &getAsScalar(std::unique_ptr<Poly> &N) { 2898 if (!N || !isa<Scalar>(*N)) 2899 N = std::make_unique<Scalar>(); 2900 return *cast<Scalar>(N.get()); 2901 } 2902 2903 static Seq &getAsSequence(std::unique_ptr<Poly> &N) { 2904 if (!N || !isa<Seq>(*N)) 2905 N = std::make_unique<Seq>(); 2906 return *cast<Seq>(N.get()); 2907 } 2908 2909 static Map &getAsMap(std::unique_ptr<Poly> &N) { 2910 if (!N || !isa<Map>(*N)) 2911 N = std::make_unique<Map>(); 2912 return *cast<Map>(N.get()); 2913 } 2914 }; 2915 2916 template <> struct TaggedScalarTraits<Scalar> { 2917 static void output(const Scalar &S, void *Ctxt, raw_ostream &ScalarOS, 2918 raw_ostream &TagOS) { 2919 switch (S.SKind) { 2920 case Scalar::SK_Unknown: 2921 report_fatal_error("output unknown scalar"); 2922 break; 2923 case Scalar::SK_Double: 2924 TagOS << "!double"; 2925 ScalarTraits<double>::output(S.DoubleValue, Ctxt, ScalarOS); 2926 break; 2927 case Scalar::SK_Bool: 2928 TagOS << "!bool"; 2929 ScalarTraits<bool>::output(S.BoolValue, Ctxt, ScalarOS); 2930 break; 2931 } 2932 } 2933 2934 static StringRef input(StringRef ScalarStr, StringRef Tag, void *Ctxt, 2935 Scalar &S) { 2936 S.SKind = StringSwitch<Scalar::ScalarKind>(Tag) 2937 .Case("!double", Scalar::SK_Double) 2938 .Case("!bool", Scalar::SK_Bool) 2939 .Default(Scalar::SK_Unknown); 2940 switch (S.SKind) { 2941 case Scalar::SK_Unknown: 2942 return StringRef("unknown scalar tag"); 2943 case Scalar::SK_Double: 2944 return ScalarTraits<double>::input(ScalarStr, Ctxt, S.DoubleValue); 2945 case Scalar::SK_Bool: 2946 return ScalarTraits<bool>::input(ScalarStr, Ctxt, S.BoolValue); 2947 } 2948 llvm_unreachable("unknown scalar kind"); 2949 } 2950 2951 static QuotingType mustQuote(const Scalar &S, StringRef Str) { 2952 switch (S.SKind) { 2953 case Scalar::SK_Unknown: 2954 report_fatal_error("quote unknown scalar"); 2955 case Scalar::SK_Double: 2956 return ScalarTraits<double>::mustQuote(Str); 2957 case Scalar::SK_Bool: 2958 return ScalarTraits<bool>::mustQuote(Str); 2959 } 2960 llvm_unreachable("unknown scalar kind"); 2961 } 2962 }; 2963 2964 template <> struct CustomMappingTraits<Map> { 2965 static void inputOne(IO &IO, StringRef Key, Map &M) { 2966 IO.mapRequired(Key.str().c_str(), M[Key]); 2967 } 2968 2969 static void output(IO &IO, Map &M) { 2970 for (auto &N : M) 2971 IO.mapRequired(N.getKey().str().c_str(), N.getValue()); 2972 } 2973 }; 2974 2975 template <> struct SequenceTraits<Seq> { 2976 static size_t size(IO &IO, Seq &A) { return A.size(); } 2977 2978 static std::unique_ptr<Poly> &element(IO &IO, Seq &A, size_t Index) { 2979 if (Index >= A.size()) 2980 A.resize(Index + 1); 2981 return A[Index]; 2982 } 2983 }; 2984 2985 } // namespace yaml 2986 } // namespace llvm 2987 2988 TEST(YAMLIO, TestReadWritePolymorphicScalar) { 2989 std::string intermediate; 2990 std::unique_ptr<Poly> node = std::make_unique<Scalar>(true); 2991 2992 llvm::raw_string_ostream ostr(intermediate); 2993 Output yout(ostr); 2994 #ifdef GTEST_HAS_DEATH_TEST 2995 #ifndef NDEBUG 2996 EXPECT_DEATH(yout << node, "plain scalar documents are not supported"); 2997 #endif 2998 #endif 2999 } 3000 3001 TEST(YAMLIO, TestReadWritePolymorphicSeq) { 3002 std::string intermediate; 3003 { 3004 auto seq = std::make_unique<Seq>(); 3005 seq->push_back(std::make_unique<Scalar>(true)); 3006 seq->push_back(std::make_unique<Scalar>(1.0)); 3007 auto node = llvm::unique_dyn_cast<Poly>(seq); 3008 3009 llvm::raw_string_ostream ostr(intermediate); 3010 Output yout(ostr); 3011 yout << node; 3012 } 3013 { 3014 Input yin(intermediate); 3015 std::unique_ptr<Poly> node; 3016 yin >> node; 3017 3018 EXPECT_FALSE(yin.error()); 3019 auto seq = llvm::dyn_cast<Seq>(node.get()); 3020 ASSERT_TRUE(seq); 3021 ASSERT_EQ(seq->size(), 2u); 3022 auto first = llvm::dyn_cast<Scalar>((*seq)[0].get()); 3023 ASSERT_TRUE(first); 3024 EXPECT_EQ(first->SKind, Scalar::SK_Bool); 3025 EXPECT_TRUE(first->BoolValue); 3026 auto second = llvm::dyn_cast<Scalar>((*seq)[1].get()); 3027 ASSERT_TRUE(second); 3028 EXPECT_EQ(second->SKind, Scalar::SK_Double); 3029 EXPECT_EQ(second->DoubleValue, 1.0); 3030 } 3031 } 3032 3033 TEST(YAMLIO, TestReadWritePolymorphicMap) { 3034 std::string intermediate; 3035 { 3036 auto map = std::make_unique<Map>(); 3037 (*map)["foo"] = std::make_unique<Scalar>(false); 3038 (*map)["bar"] = std::make_unique<Scalar>(2.0); 3039 std::unique_ptr<Poly> node = llvm::unique_dyn_cast<Poly>(map); 3040 3041 llvm::raw_string_ostream ostr(intermediate); 3042 Output yout(ostr); 3043 yout << node; 3044 } 3045 { 3046 Input yin(intermediate); 3047 std::unique_ptr<Poly> node; 3048 yin >> node; 3049 3050 EXPECT_FALSE(yin.error()); 3051 auto map = llvm::dyn_cast<Map>(node.get()); 3052 ASSERT_TRUE(map); 3053 auto foo = llvm::dyn_cast<Scalar>((*map)["foo"].get()); 3054 ASSERT_TRUE(foo); 3055 EXPECT_EQ(foo->SKind, Scalar::SK_Bool); 3056 EXPECT_FALSE(foo->BoolValue); 3057 auto bar = llvm::dyn_cast<Scalar>((*map)["bar"].get()); 3058 ASSERT_TRUE(bar); 3059 EXPECT_EQ(bar->SKind, Scalar::SK_Double); 3060 EXPECT_EQ(bar->DoubleValue, 2.0); 3061 } 3062 } 3063 3064 TEST(YAMLIO, TestAnchorMapError) { 3065 Input yin("& & &: "); 3066 yin.setCurrentDocument(); 3067 EXPECT_TRUE(yin.error()); 3068 } 3069 3070 TEST(YAMLIO, TestFlowSequenceTokenErrors) { 3071 Input yin(","); 3072 EXPECT_FALSE(yin.setCurrentDocument()); 3073 EXPECT_TRUE(yin.error()); 3074 3075 Input yin2("]"); 3076 EXPECT_FALSE(yin2.setCurrentDocument()); 3077 EXPECT_TRUE(yin2.error()); 3078 3079 Input yin3("}"); 3080 EXPECT_FALSE(yin3.setCurrentDocument()); 3081 EXPECT_TRUE(yin3.error()); 3082 } 3083 3084 TEST(YAMLIO, TestDirectiveMappingNoValue) { 3085 Input yin("%YAML\n{5:"); 3086 EXPECT_FALSE(yin.setCurrentDocument()); 3087 EXPECT_TRUE(yin.error()); 3088 3089 Input yin2("%TAG\n'\x98!< :\n"); 3090 yin2.setCurrentDocument(); 3091 EXPECT_TRUE(yin2.error()); 3092 } 3093 3094 TEST(YAMLIO, TestUnescapeInfiniteLoop) { 3095 Input yin("\"\\u\\^#\\\\\""); 3096 yin.setCurrentDocument(); 3097 EXPECT_TRUE(yin.error()); 3098 } 3099 3100 TEST(YAMLIO, TestScannerUnexpectedCharacter) { 3101 Input yin("!<$\x9F."); 3102 EXPECT_FALSE(yin.setCurrentDocument()); 3103 EXPECT_TRUE(yin.error()); 3104 } 3105 3106 TEST(YAMLIO, TestUnknownDirective) { 3107 Input yin("%"); 3108 EXPECT_FALSE(yin.setCurrentDocument()); 3109 EXPECT_TRUE(yin.error()); 3110 3111 Input yin2("%)"); 3112 EXPECT_FALSE(yin2.setCurrentDocument()); 3113 EXPECT_TRUE(yin2.error()); 3114 } 3115 3116 TEST(YAMLIO, TestEmptyAlias) { 3117 Input yin("&"); 3118 EXPECT_FALSE(yin.setCurrentDocument()); 3119 EXPECT_TRUE(yin.error()); 3120 } 3121 3122 TEST(YAMLIO, TestEmptyAnchor) { 3123 Input yin("*"); 3124 EXPECT_FALSE(yin.setCurrentDocument()); 3125 } 3126 3127 TEST(YAMLIO, TestScannerNoNullEmpty) { 3128 std::vector<char> str{}; 3129 Input yin(llvm::StringRef(str.data(), str.size())); 3130 yin.setCurrentDocument(); 3131 EXPECT_FALSE(yin.error()); 3132 } 3133 3134 TEST(YAMLIO, TestScannerNoNullSequenceOfNull) { 3135 std::vector<char> str{'-'}; 3136 Input yin(llvm::StringRef(str.data(), str.size())); 3137 yin.setCurrentDocument(); 3138 EXPECT_FALSE(yin.error()); 3139 } 3140 3141 TEST(YAMLIO, TestScannerNoNullSimpleSequence) { 3142 std::vector<char> str{'-', ' ', 'a'}; 3143 Input yin(llvm::StringRef(str.data(), str.size())); 3144 yin.setCurrentDocument(); 3145 EXPECT_FALSE(yin.error()); 3146 } 3147 3148 TEST(YAMLIO, TestScannerNoNullUnbalancedMap) { 3149 std::vector<char> str{'{'}; 3150 Input yin(llvm::StringRef(str.data(), str.size())); 3151 yin.setCurrentDocument(); 3152 EXPECT_TRUE(yin.error()); 3153 } 3154 3155 TEST(YAMLIO, TestScannerNoNullEmptyMap) { 3156 std::vector<char> str{'{', '}'}; 3157 Input yin(llvm::StringRef(str.data(), str.size())); 3158 yin.setCurrentDocument(); 3159 EXPECT_FALSE(yin.error()); 3160 } 3161 3162 TEST(YAMLIO, TestScannerNoNullUnbalancedSequence) { 3163 std::vector<char> str{'['}; 3164 Input yin(llvm::StringRef(str.data(), str.size())); 3165 yin.setCurrentDocument(); 3166 EXPECT_TRUE(yin.error()); 3167 } 3168 3169 TEST(YAMLIO, TestScannerNoNullEmptySequence) { 3170 std::vector<char> str{'[', ']'}; 3171 Input yin(llvm::StringRef(str.data(), str.size())); 3172 yin.setCurrentDocument(); 3173 EXPECT_FALSE(yin.error()); 3174 } 3175 3176 TEST(YAMLIO, TestScannerNoNullScalarUnbalancedDoubleQuote) { 3177 std::vector<char> str{'"'}; 3178 Input yin(llvm::StringRef(str.data(), str.size())); 3179 yin.setCurrentDocument(); 3180 EXPECT_TRUE(yin.error()); 3181 } 3182 3183 TEST(YAMLIO, TestScannerNoNullScalarUnbalancedSingleQuote) { 3184 std::vector<char> str{'\''}; 3185 Input yin(llvm::StringRef(str.data(), str.size())); 3186 yin.setCurrentDocument(); 3187 EXPECT_TRUE(yin.error()); 3188 } 3189 3190 TEST(YAMLIO, TestScannerNoNullEmptyAlias) { 3191 std::vector<char> str{'&'}; 3192 Input yin(llvm::StringRef(str.data(), str.size())); 3193 yin.setCurrentDocument(); 3194 EXPECT_TRUE(yin.error()); 3195 } 3196 3197 TEST(YAMLIO, TestScannerNoNullEmptyAnchor) { 3198 std::vector<char> str{'*'}; 3199 Input yin(llvm::StringRef(str.data(), str.size())); 3200 yin.setCurrentDocument(); 3201 EXPECT_TRUE(yin.error()); 3202 } 3203 3204 TEST(YAMLIO, TestScannerNoNullDecodeInvalidUTF8) { 3205 std::vector<char> str{'\xef'}; 3206 Input yin(llvm::StringRef(str.data(), str.size())); 3207 yin.setCurrentDocument(); 3208 EXPECT_TRUE(yin.error()); 3209 } 3210 3211 TEST(YAMLIO, TestScannerNoNullScanPlainScalarInFlow) { 3212 std::vector<char> str{'{', 'a', ':'}; 3213 Input yin(llvm::StringRef(str.data(), str.size())); 3214 yin.setCurrentDocument(); 3215 EXPECT_TRUE(yin.error()); 3216 } 3217