diff options
author | Ilya Biryukov <ibiryukov@google.com> | 2018-05-30 10:40:11 +0000 |
---|---|---|
committer | Ilya Biryukov <ibiryukov@google.com> | 2018-05-30 10:40:11 +0000 |
commit | cab5faf1e22c36a6ff561001ce830910cee4de76 (patch) | |
tree | 8b4ba071a63fbffcdd456a99ae4eb2d7d2d020f8 | |
parent | adcf643e71823ecd2e9abe12b52e5a06c13ac1fd (diff) |
[YAML] Quote multiline string scalars
Summary:
Otherwise, the YAML parser breaks when trying to read them back in
'key: multiline_string_value' cases.
This patch fixes a problem when serializing structs which contain multi-line strings.
E.g., if we try to serialize the following struct
```
{ "key1": "first line\nsecond line",
"key2": "another string" }`
```
Before this patch, we got the YAML output that failed to parse:
```
key1: first line
second line
key2: another string
```
After the patch, we get:
```
key1: 'first line
second line'
key2: another string
```
Reviewers: sammccall
Reviewed By: sammccall
Subscribers: llvm-commits
Differential Revision: https://reviews.llvm.org/D47468
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@333527 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/Support/YAMLTraits.h | 7 | ||||
-rw-r--r-- | unittests/Support/YAMLIOTest.cpp | 68 |
2 files changed, 73 insertions, 2 deletions
diff --git a/include/llvm/Support/YAMLTraits.h b/include/llvm/Support/YAMLTraits.h index 06eafc0dfd8..4b8c4e95828 100644 --- a/include/llvm/Support/YAMLTraits.h +++ b/include/llvm/Support/YAMLTraits.h @@ -540,11 +540,14 @@ inline QuotingType needsQuotes(StringRef S) { case '.': case ',': case ' ': - // TAB (0x9), LF (0xA), CR (0xD) and NEL (0x85) are allowed. + // TAB (0x9) is allowed in unquoted strings. case 0x9: + continue; + // LF(0xA) and CR(0xD) may delimit values and so require at least single + // quotes. case 0xA: case 0xD: - case 0x85: + MaxQuotingNeeded = QuotingType::Single; continue; // DEL (0x7F) are excluded from the allowed character range. case 0x7F: diff --git a/unittests/Support/YAMLIOTest.cpp b/unittests/Support/YAMLIOTest.cpp index 378662c7923..13364806524 100644 --- a/unittests/Support/YAMLIOTest.cpp +++ b/unittests/Support/YAMLIOTest.cpp @@ -13,6 +13,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/Format.h" #include "llvm/Support/YAMLTraits.h" +#include "gmock/gmock.h" #include "gtest/gtest.h" using llvm::yaml::Input; @@ -25,6 +26,7 @@ using llvm::yaml::Hex8; using llvm::yaml::Hex16; using llvm::yaml::Hex32; using llvm::yaml::Hex64; +using ::testing::StartsWith; @@ -249,6 +251,72 @@ TEST(YAMLIO, TestGivenFilename) { EXPECT_TRUE(!!yin.error()); } +struct WithStringField { + std::string str1; + std::string str2; + std::string str3; +}; + +namespace llvm { +namespace yaml { +template <> struct MappingTraits<WithStringField> { + static void mapping(IO &io, WithStringField &fb) { + io.mapRequired("str1", fb.str1); + io.mapRequired("str2", fb.str2); + io.mapRequired("str3", fb.str3); + } +}; +} // namespace yaml +} // namespace llvm + +TEST(YAMLIO, MultilineStrings) { + WithStringField Original; + Original.str1 = "a multiline string\nfoobarbaz"; + Original.str2 = "another one\rfoobarbaz"; + Original.str3 = "a one-line string"; + + std::string Serialized; + { + llvm::raw_string_ostream OS(Serialized); + Output YOut(OS); + YOut << Original; + } + auto Expected = "---\n" + "str1: 'a multiline string\n" + "foobarbaz'\n" + "str2: 'another one\r" + "foobarbaz'\n" + "str3: a one-line string\n" + "...\n"; + ASSERT_EQ(Serialized, Expected); + + // Also check it parses back without the errors. + WithStringField Deserialized; + { + Input YIn(Serialized); + YIn >> Deserialized; + ASSERT_FALSE(YIn.error()) + << "Parsing error occurred during deserialization. Serialized string:\n" + << Serialized; + } + EXPECT_EQ(Original.str1, Deserialized.str1); + EXPECT_EQ(Original.str2, Deserialized.str2); + EXPECT_EQ(Original.str3, Deserialized.str3); +} + +TEST(YAMLIO, NoQuotesForTab) { + WithStringField WithTab; + WithTab.str1 = "aba\tcaba"; + std::string Serialized; + { + llvm::raw_string_ostream OS(Serialized); + Output YOut(OS); + YOut << WithTab; + } + auto ExpectedPrefix = "---\n" + "str1: aba\tcaba\n"; + EXPECT_THAT(Serialized, StartsWith(ExpectedPrefix)); +} //===----------------------------------------------------------------------===// // Test built-in types |