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