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