X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=unittests%2FSupport%2FYAMLIOTest.cpp;h=e7affa1698dcc7989ca59bdf23549f9164fac76d;hb=21577c0682a8c0a3073cf970eeb3fd8dde2bcb21;hp=ffabbcfe055d1bd452946fef9f573f6a5791d221;hpb=08e66be96d6b019e574d7d0801d198cd9c584f21;p=oota-llvm.git diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp index ffabbcfe055..e7affa1698d 100644 --- a/unittests/Support/YAMLIOTest.cpp +++ b/unittests/Support/YAMLIOTest.cpp @@ -46,6 +46,9 @@ typedef std::vector FooBarSequence; LLVM_YAML_IS_SEQUENCE_VECTOR(FooBar) +struct FooBarContainer { + FooBarSequence fbs; +}; namespace llvm { namespace yaml { @@ -56,6 +59,12 @@ namespace yaml { io.mapRequired("bar", fb.bar); } }; + + template <> struct MappingTraits { + static void mapping(IO &io, FooBarContainer &fb) { + io.mapRequired("fbs", fb.fbs); + } + }; } } @@ -84,6 +93,13 @@ TEST(YAMLIO, TestMapRead) { } } +TEST(YAMLIO, TestMalformedMapRead) { + FooBar doc; + Input yin("{foo: 3; bar: 5}", nullptr, suppressErrorMessages); + yin >> doc; + EXPECT_TRUE(!!yin.error()); +} + // // Test the reading of a yaml sequence of mappings // @@ -102,6 +118,83 @@ TEST(YAMLIO, TestSequenceMapRead) { EXPECT_EQ(map2.bar, 9); } +// +// Test the reading of a map containing a yaml sequence of mappings +// +TEST(YAMLIO, TestContainerSequenceMapRead) { + { + FooBarContainer cont; + Input yin2("---\nfbs:\n - foo: 3\n bar: 5\n - foo: 7\n bar: 9\n...\n"); + yin2 >> cont; + + EXPECT_FALSE(yin2.error()); + EXPECT_EQ(cont.fbs.size(), 2UL); + EXPECT_EQ(cont.fbs[0].foo, 3); + EXPECT_EQ(cont.fbs[0].bar, 5); + EXPECT_EQ(cont.fbs[1].foo, 7); + EXPECT_EQ(cont.fbs[1].bar, 9); + } + + { + FooBarContainer cont; + Input yin("---\nfbs:\n...\n"); + yin >> cont; + // Okay: Empty node represents an empty array. + EXPECT_FALSE(yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } + + { + FooBarContainer cont; + Input yin("---\nfbs: !!null null\n...\n"); + yin >> cont; + // Okay: null represents an empty array. + EXPECT_FALSE(yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } + + { + FooBarContainer cont; + Input yin("---\nfbs: ~\n...\n"); + yin >> cont; + // Okay: null represents an empty array. + EXPECT_FALSE(yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } + + { + FooBarContainer cont; + Input yin("---\nfbs: null\n...\n"); + yin >> cont; + // Okay: null represents an empty array. + EXPECT_FALSE(yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } +} + +// +// Test the reading of a map containing a malformed yaml sequence +// +TEST(YAMLIO, TestMalformedContainerSequenceMapRead) { + { + FooBarContainer cont; + Input yin("---\nfbs:\n foo: 3\n bar: 5\n...\n", nullptr, + suppressErrorMessages); + yin >> cont; + // Error: fbs is not a sequence. + EXPECT_TRUE(!!yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } + + { + FooBarContainer cont; + Input yin("---\nfbs: 'scalar'\n...\n", nullptr, suppressErrorMessages); + yin >> cont; + // This should be an error. + EXPECT_TRUE(!!yin.error()); + EXPECT_EQ(cont.fbs.size(), 0UL); + } +} // // Test writing then reading back a sequence of mappings @@ -686,6 +779,146 @@ TEST(YAMLIO, TestReadWriteMyCustomType) { } +//===----------------------------------------------------------------------===// +// Test BlockScalarTraits +//===----------------------------------------------------------------------===// + +struct MultilineStringType { + std::string str; +}; + +struct MultilineStringTypeMap { + MultilineStringType name; + MultilineStringType description; + MultilineStringType ingredients; + MultilineStringType recipes; + MultilineStringType warningLabels; + MultilineStringType documentation; + int price; +}; + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits { + static void mapping(IO &io, MultilineStringTypeMap& s) { + io.mapRequired("name", s.name); + io.mapRequired("description", s.description); + io.mapRequired("ingredients", s.ingredients); + io.mapRequired("recipes", s.recipes); + io.mapRequired("warningLabels", s.warningLabels); + io.mapRequired("documentation", s.documentation); + io.mapRequired("price", s.price); + } + }; + + // MultilineStringType is formatted as a yaml block literal scalar. A value of + // "Hello\nWorld" would be represented in yaml as + // | + // Hello + // World + template <> + struct BlockScalarTraits { + static void output(const MultilineStringType &value, void *ctxt, + llvm::raw_ostream &out) { + out << value.str; + } + static StringRef input(StringRef scalar, void *ctxt, + MultilineStringType &value) { + value.str = scalar.str(); + return StringRef(); + } + }; +} +} + +LLVM_YAML_IS_DOCUMENT_LIST_VECTOR(MultilineStringType) + +// +// Test writing then reading back custom values +// +TEST(YAMLIO, TestReadWriteMultilineStringType) { + std::string intermediate; + { + MultilineStringTypeMap map; + map.name.str = "An Item"; + map.description.str = "Hello\nWorld"; + map.ingredients.str = "SubItem 1\nSub Item 2\n\nSub Item 3\n"; + map.recipes.str = "\n\nTest 1\n\n\n"; + map.warningLabels.str = ""; + map.documentation.str = "\n\n"; + map.price = 350; + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << map; + } + { + Input yin(intermediate); + MultilineStringTypeMap map2; + yin >> map2; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(map2.name.str, "An Item\n"); + EXPECT_EQ(map2.description.str, "Hello\nWorld\n"); + EXPECT_EQ(map2.ingredients.str, "SubItem 1\nSub Item 2\n\nSub Item 3\n"); + EXPECT_EQ(map2.recipes.str, "\n\nTest 1\n"); + EXPECT_TRUE(map2.warningLabels.str.empty()); + EXPECT_TRUE(map2.documentation.str.empty()); + EXPECT_EQ(map2.price, 350); + } +} + +// +// Test writing then reading back custom values +// +TEST(YAMLIO, TestReadWriteBlockScalarDocuments) { + std::string intermediate; + { + std::vector documents; + MultilineStringType doc; + doc.str = "Hello\nWorld"; + documents.push_back(doc); + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << documents; + + // Verify that the block scalar header was written out on the same line + // as the document marker. + EXPECT_NE(llvm::StringRef::npos, llvm::StringRef(ostr.str()).find("--- |")); + } + { + Input yin(intermediate); + std::vector documents2; + yin >> documents2; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(documents2.size(), size_t(1)); + EXPECT_EQ(documents2[0].str, "Hello\nWorld\n"); + } +} + +TEST(YAMLIO, TestReadWriteBlockScalarValue) { + std::string intermediate; + { + MultilineStringType doc; + doc.str = "Just a block\nscalar doc"; + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << doc; + } + { + Input yin(intermediate); + MultilineStringType doc; + yin >> doc; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(doc.str, "Just a block\nscalar doc\n"); + } +} + //===----------------------------------------------------------------------===// // Test flow sequences //===----------------------------------------------------------------------===// @@ -736,6 +969,26 @@ namespace yaml { } } +typedef std::vector MyNumberFlowSequence; + +LLVM_YAML_IS_SEQUENCE_VECTOR(MyNumberFlowSequence) + +struct NameAndNumbersFlow { + llvm::StringRef name; + std::vector sequenceOfNumbers; +}; + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits { + static void mapping(IO &io, NameAndNumbersFlow& nn) { + io.mapRequired("name", nn.name); + io.mapRequired("sequenceOfNumbers", nn.sequenceOfNumbers); + } + }; +} +} // // Test writing then reading back custom values @@ -783,6 +1036,51 @@ TEST(YAMLIO, TestReadWriteMyFlowSequence) { } +// +// Test writing then reading back a sequence of flow sequences. +// +TEST(YAMLIO, TestReadWriteSequenceOfMyFlowSequence) { + std::string intermediate; + { + NameAndNumbersFlow map; + map.name = "hello"; + MyNumberFlowSequence single = { 0 }; + MyNumberFlowSequence numbers = { 12, 1, -512 }; + map.sequenceOfNumbers.push_back(single); + map.sequenceOfNumbers.push_back(numbers); + map.sequenceOfNumbers.push_back(MyNumberFlowSequence()); + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << map; + + // Verify sequences were written in flow style + // and that the parent sequence used '-'. + ostr.flush(); + llvm::StringRef flowOut(intermediate); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 0 ]")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ 12, 1, -512 ]")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- [ ]")); + } + + { + Input yin(intermediate); + NameAndNumbersFlow map2; + yin >> map2; + + EXPECT_FALSE(yin.error()); + EXPECT_TRUE(map2.name.equals("hello")); + EXPECT_EQ(map2.sequenceOfNumbers.size(), 3UL); + EXPECT_EQ(map2.sequenceOfNumbers[0].size(), 1UL); + EXPECT_EQ(0, map2.sequenceOfNumbers[0][0]); + EXPECT_EQ(map2.sequenceOfNumbers[1].size(), 3UL); + EXPECT_EQ(12, map2.sequenceOfNumbers[1][0]); + EXPECT_EQ(1, map2.sequenceOfNumbers[1][1]); + EXPECT_EQ(-512, map2.sequenceOfNumbers[1][2]); + EXPECT_TRUE(map2.sequenceOfNumbers[2].empty()); + } +} + //===----------------------------------------------------------------------===// // Test normalizing/denormalizing //===----------------------------------------------------------------------===// @@ -1204,11 +1502,96 @@ TEST(YAMLIO, TestValidatingInput) { std::vector docList; Input yin("--- \nvalue: 3.0\n" "--- \nvalue: -1.0\n...\n", - NULL, suppressErrorMessages); + nullptr, suppressErrorMessages); yin >> docList; EXPECT_TRUE(!!yin.error()); } +//===----------------------------------------------------------------------===// +// Test flow mapping +//===----------------------------------------------------------------------===// + +struct FlowFooBar { + int foo; + int bar; + + FlowFooBar() : foo(0), bar(0) {} + FlowFooBar(int foo, int bar) : foo(foo), bar(bar) {} +}; + +typedef std::vector FlowFooBarSequence; + +LLVM_YAML_IS_SEQUENCE_VECTOR(FlowFooBar) + +struct FlowFooBarDoc { + FlowFooBar attribute; + FlowFooBarSequence seq; +}; + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits { + static void mapping(IO &io, FlowFooBar &fb) { + io.mapRequired("foo", fb.foo); + io.mapRequired("bar", fb.bar); + } + + static const bool flow = true; + }; + + template <> + struct MappingTraits { + static void mapping(IO &io, FlowFooBarDoc &fb) { + io.mapRequired("attribute", fb.attribute); + io.mapRequired("seq", fb.seq); + } + }; +} +} + +// +// Test writing then reading back custom mappings +// +TEST(YAMLIO, TestReadWriteMyFlowMapping) { + std::string intermediate; + { + FlowFooBarDoc doc; + doc.attribute = FlowFooBar(42, 907); + doc.seq.push_back(FlowFooBar(1, 2)); + doc.seq.push_back(FlowFooBar(0, 0)); + doc.seq.push_back(FlowFooBar(-1, 1024)); + + llvm::raw_string_ostream ostr(intermediate); + Output yout(ostr); + yout << doc; + + // Verify that mappings were written in flow style + ostr.flush(); + llvm::StringRef flowOut(intermediate); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("{ foo: 42, bar: 907 }")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 1, bar: 2 }")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: 0, bar: 0 }")); + EXPECT_NE(llvm::StringRef::npos, flowOut.find("- { foo: -1, bar: 1024 }")); + } + + { + Input yin(intermediate); + FlowFooBarDoc doc2; + yin >> doc2; + + EXPECT_FALSE(yin.error()); + EXPECT_EQ(doc2.attribute.foo, 42); + EXPECT_EQ(doc2.attribute.bar, 907); + EXPECT_EQ(doc2.seq.size(), 3UL); + EXPECT_EQ(doc2.seq[0].foo, 1); + EXPECT_EQ(doc2.seq[0].bar, 2); + EXPECT_EQ(doc2.seq[1].foo, 0); + EXPECT_EQ(doc2.seq[1].bar, 0); + EXPECT_EQ(doc2.seq[2].foo, -1); + EXPECT_EQ(doc2.seq[2].bar, 1024); + } +} //===----------------------------------------------------------------------===// // Test error handling @@ -1224,7 +1607,7 @@ TEST(YAMLIO, TestColorsReadError) { "c2: purple\n" "c3: green\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> map; EXPECT_TRUE(!!yin.error()); @@ -1241,7 +1624,7 @@ TEST(YAMLIO, TestFlagsReadError) { "f2: [ round, hollow ]\n" "f3: []\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> map; @@ -1260,7 +1643,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint8Error) { "- 0\n" "- 257\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1279,7 +1662,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint16Error) { "- 0\n" "- 66000\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1298,7 +1681,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint32Error) { "- 0\n" "- 5000000000\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1317,7 +1700,7 @@ TEST(YAMLIO, TestReadBuiltInTypesUint64Error) { "- 0\n" "- 19446744073709551615\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1337,7 +1720,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint8OverError) { "- 127\n" "- 128\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1355,7 +1738,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint8UnderError) { "- 127\n" "- -129\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1375,7 +1758,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint16UnderError) { "- -32768\n" "- -32769\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1394,7 +1777,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint16OverError) { "- -32768\n" "- 32768\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1414,7 +1797,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint32UnderError) { "- -2147483648\n" "- -2147483649\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1432,7 +1815,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint32OverError) { "- -2147483648\n" "- 2147483649\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1452,7 +1835,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint64UnderError) { "- 9223372036854775807\n" "- -9223372036854775809\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1470,7 +1853,7 @@ TEST(YAMLIO, TestReadBuiltInTypesint64OverError) { "- 9223372036854775807\n" "- 9223372036854775809\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1489,7 +1872,7 @@ TEST(YAMLIO, TestReadBuiltInTypesFloatError) { "- -123.456\n" "- 1.2.3\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1508,7 +1891,7 @@ TEST(YAMLIO, TestReadBuiltInTypesDoubleError) { "- -123.456\n" "- 1.2.3\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1526,7 +1909,7 @@ TEST(YAMLIO, TestReadBuiltInTypesHex8Error) { "- 0xFE\n" "- 0x123\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1545,7 +1928,7 @@ TEST(YAMLIO, TestReadBuiltInTypesHex16Error) { "- 0xFEFF\n" "- 0x12345\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1563,7 +1946,7 @@ TEST(YAMLIO, TestReadBuiltInTypesHex32Error) { "- 0xFEFF0000\n" "- 0x1234556789\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1581,7 +1964,7 @@ TEST(YAMLIO, TestReadBuiltInTypesHex64Error) { "- 0xFFEEDDCCBBAA9988\n" "- 0x12345567890ABCDEF0\n" "...\n", - /*Ctxt=*/NULL, + /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; @@ -1593,13 +1976,13 @@ TEST(YAMLIO, TestMalformedMapFailsGracefully) { { // We pass the suppressErrorMessages handler to handle the error // message generated in the constructor of Input. - Input yin("{foo:3, bar: 5}", /*Ctxt=*/NULL, suppressErrorMessages); + Input yin("{foo:3, bar: 5}", /*Ctxt=*/nullptr, suppressErrorMessages); yin >> doc; EXPECT_TRUE(!!yin.error()); } { - Input yin("---\nfoo:3\nbar: 5\n...\n", /*Ctxt=*/NULL, suppressErrorMessages); + Input yin("---\nfoo:3\nbar: 5\n...\n", /*Ctxt=*/nullptr, suppressErrorMessages); yin >> doc; EXPECT_TRUE(!!yin.error()); } @@ -1685,9 +2068,129 @@ TEST(YAMLIO, TestEmptyStringSucceedsForMapWithOptionalFields) { TEST(YAMLIO, TestEmptyStringSucceedsForSequence) { std::vector seq; - Input yin("", /*Ctxt=*/NULL, suppressErrorMessages); + Input yin("", /*Ctxt=*/nullptr, suppressErrorMessages); yin >> seq; EXPECT_FALSE(yin.error()); EXPECT_TRUE(seq.empty()); } + +struct FlowMap { + llvm::StringRef str1, str2, str3; + FlowMap(llvm::StringRef str1, llvm::StringRef str2, llvm::StringRef str3) + : str1(str1), str2(str2), str3(str3) {} +}; + +struct FlowSeq { + llvm::StringRef str; + FlowSeq(llvm::StringRef S) : str(S) {} + FlowSeq() = default; +}; + +namespace llvm { +namespace yaml { + template <> + struct MappingTraits { + static void mapping(IO &io, FlowMap &fm) { + io.mapRequired("str1", fm.str1); + io.mapRequired("str2", fm.str2); + io.mapRequired("str3", fm.str3); + } + + static const bool flow = true; + }; + +template <> +struct ScalarTraits { + static void output(const FlowSeq &value, void*, llvm::raw_ostream &out) { + out << value.str; + } + static StringRef input(StringRef scalar, void*, FlowSeq &value) { + value.str = scalar; + return ""; + } + + static bool mustQuote(StringRef S) { return false; } +}; +} +} + +LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(FlowSeq) + +TEST(YAMLIO, TestWrapFlow) { + std::string out; + llvm::raw_string_ostream ostr(out); + FlowMap Map("This is str1", "This is str2", "This is str3"); + std::vector Seq; + Seq.emplace_back("This is str1"); + Seq.emplace_back("This is str2"); + Seq.emplace_back("This is str3"); + + { + // 20 is just bellow the total length of the first mapping field. + // We should wreap at every element. + Output yout(ostr, nullptr, 15); + + yout << Map; + ostr.flush(); + EXPECT_EQ(out, + "---\n" + "{ str1: This is str1, \n" + " str2: This is str2, \n" + " str3: This is str3 }\n" + "...\n"); + out.clear(); + + yout << Seq; + ostr.flush(); + EXPECT_EQ(out, + "---\n" + "[ This is str1, \n" + " This is str2, \n" + " This is str3 ]\n" + "...\n"); + out.clear(); + } + { + // 25 will allow the second field to be output on the first line. + Output yout(ostr, nullptr, 25); + + yout << Map; + ostr.flush(); + EXPECT_EQ(out, + "---\n" + "{ str1: This is str1, str2: This is str2, \n" + " str3: This is str3 }\n" + "...\n"); + out.clear(); + + yout << Seq; + ostr.flush(); + EXPECT_EQ(out, + "---\n" + "[ This is str1, This is str2, \n" + " This is str3 ]\n" + "...\n"); + out.clear(); + } + { + // 0 means no wrapping. + Output yout(ostr, nullptr, 0); + + yout << Map; + ostr.flush(); + EXPECT_EQ(out, + "---\n" + "{ str1: This is str1, str2: This is str2, str3: This is str3 }\n" + "...\n"); + out.clear(); + + yout << Seq; + ostr.flush(); + EXPECT_EQ(out, + "---\n" + "[ This is str1, This is str2, This is str3 ]\n" + "...\n"); + out.clear(); + } +}