1 //===- unittest/Support/YAMLParserTest ------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/ADT/Twine.h" 11 #include "llvm/Support/Casting.h" 12 #include "llvm/Support/MemoryBuffer.h" 13 #include "llvm/Support/SourceMgr.h" 14 #include "llvm/Support/YAMLParser.h" 15 #include "gtest/gtest.h" 16 17 namespace llvm { 18 19 static void SuppressDiagnosticsOutput(const SMDiagnostic &, void *) { 20 // Prevent SourceMgr from writing errors to stderr 21 // to reduce noise in unit test runs. 22 } 23 24 // Assumes Ctx is an SMDiagnostic where Diag can be stored. 25 static void CollectDiagnosticsOutput(const SMDiagnostic &Diag, void *Ctx) { 26 SMDiagnostic* DiagOut = static_cast<SMDiagnostic*>(Ctx); 27 *DiagOut = Diag; 28 } 29 30 // Checks that the given input gives a parse error. Makes sure that an error 31 // text is available and the parse fails. 32 static void ExpectParseError(StringRef Message, StringRef Input) { 33 SourceMgr SM; 34 yaml::Stream Stream(Input, SM); 35 SM.setDiagHandler(SuppressDiagnosticsOutput); 36 EXPECT_FALSE(Stream.validate()) << Message << ": " << Input; 37 EXPECT_TRUE(Stream.failed()) << Message << ": " << Input; 38 } 39 40 // Checks that the given input can be parsed without error. 41 static void ExpectParseSuccess(StringRef Message, StringRef Input) { 42 SourceMgr SM; 43 yaml::Stream Stream(Input, SM); 44 EXPECT_TRUE(Stream.validate()) << Message << ": " << Input; 45 } 46 47 TEST(YAMLParser, ParsesEmptyArray) { 48 ExpectParseSuccess("Empty array", "[]"); 49 } 50 51 TEST(YAMLParser, FailsIfNotClosingArray) { 52 ExpectParseError("Not closing array", "["); 53 ExpectParseError("Not closing array", " [ "); 54 ExpectParseError("Not closing array", " [x"); 55 } 56 57 TEST(YAMLParser, ParsesEmptyArrayWithWhitespace) { 58 ExpectParseSuccess("Array with spaces", " [ ] "); 59 ExpectParseSuccess("All whitespaces", "\t\r\n[\t\n \t\r ]\t\r \n\n"); 60 } 61 62 TEST(YAMLParser, ParsesEmptyObject) { 63 ExpectParseSuccess("Empty object", "[{}]"); 64 } 65 66 TEST(YAMLParser, ParsesObject) { 67 ExpectParseSuccess("Object with an entry", "[{\"a\":\"/b\"}]"); 68 } 69 70 TEST(YAMLParser, ParsesMultipleKeyValuePairsInObject) { 71 ExpectParseSuccess("Multiple key, value pairs", 72 "[{\"a\":\"/b\",\"c\":\"d\",\"e\":\"f\"}]"); 73 } 74 75 TEST(YAMLParser, FailsIfNotClosingObject) { 76 ExpectParseError("Missing close on empty", "[{]"); 77 ExpectParseError("Missing close after pair", "[{\"a\":\"b\"]"); 78 } 79 80 TEST(YAMLParser, FailsIfMissingColon) { 81 ExpectParseError("Missing colon between key and value", "[{\"a\"\"/b\"}]"); 82 ExpectParseError("Missing colon between key and value", "[{\"a\" \"b\"}]"); 83 } 84 85 TEST(YAMLParser, FailsOnMissingQuote) { 86 ExpectParseError("Missing open quote", "[{a\":\"b\"}]"); 87 ExpectParseError("Missing closing quote", "[{\"a\":\"b}]"); 88 } 89 90 TEST(YAMLParser, ParsesEscapedQuotes) { 91 ExpectParseSuccess("Parses escaped string in key and value", 92 "[{\"a\":\"\\\"b\\\" \\\" \\\"\"}]"); 93 } 94 95 TEST(YAMLParser, ParsesEmptyString) { 96 ExpectParseSuccess("Parses empty string in value", "[{\"a\":\"\"}]"); 97 } 98 99 TEST(YAMLParser, ParsesMultipleObjects) { 100 ExpectParseSuccess( 101 "Multiple objects in array", 102 "[" 103 " { \"a\" : \"b\" }," 104 " { \"a\" : \"b\" }," 105 " { \"a\" : \"b\" }" 106 "]"); 107 } 108 109 TEST(YAMLParser, FailsOnMissingComma) { 110 ExpectParseError( 111 "Missing comma", 112 "[" 113 " { \"a\" : \"b\" }" 114 " { \"a\" : \"b\" }" 115 "]"); 116 } 117 118 TEST(YAMLParser, ParsesSpacesInBetweenTokens) { 119 ExpectParseSuccess( 120 "Various whitespace between tokens", 121 " \t \n\n \r [ \t \n\n \r" 122 " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :" 123 " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r,\t \n\n \r" 124 " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :" 125 " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r]\t \n\n \r"); 126 } 127 128 TEST(YAMLParser, ParsesArrayOfArrays) { 129 ExpectParseSuccess("Array of arrays", "[[]]"); 130 } 131 132 TEST(YAMLParser, ParsesBlockLiteralScalars) { 133 ExpectParseSuccess("Block literal scalar", "test: |\n Hello\n World\n"); 134 ExpectParseSuccess("Block literal scalar EOF", "test: |\n Hello\n World"); 135 ExpectParseSuccess("Empty block literal scalar header EOF", "test: | "); 136 ExpectParseSuccess("Empty block literal scalar", "test: |\ntest2: 20"); 137 ExpectParseSuccess("Empty block literal scalar 2", "- | \n \n\n \n- 42"); 138 ExpectParseSuccess("Block literal scalar in sequence", 139 "- |\n Testing\n Out\n\n- 22"); 140 ExpectParseSuccess("Block literal scalar in document", 141 "--- |\n Document\n..."); 142 ExpectParseSuccess("Empty non indented lines still count", 143 "- |\n First line\n \n\n Another line\n\n- 2"); 144 ExpectParseSuccess("Comment in block literal scalar header", 145 "test: | # Comment \n No Comment\ntest 2: | # Void"); 146 ExpectParseSuccess("Chomping indicators in block literal scalar header", 147 "test: |- \n Hello\n\ntest 2: |+ \n\n World\n\n\n"); 148 ExpectParseSuccess("Indent indicators in block literal scalar header", 149 "test: |1 \n \n Hello \n World\n"); 150 ExpectParseSuccess("Chomping and indent indicators in block literals", 151 "test: |-1\n Hello\ntest 2: |9+\n World"); 152 ExpectParseSuccess("Trailing comments in block literals", 153 "test: |\n Content\n # Trailing\n #Comment\ntest 2: 3"); 154 ExpectParseError("Invalid block scalar header", "test: | failure"); 155 ExpectParseError("Invalid line indentation", "test: |\n First line\n Error"); 156 ExpectParseError("Long leading space line", "test: |\n \n Test\n"); 157 } 158 159 TEST(YAMLParser, NullTerminatedBlockScalars) { 160 SourceMgr SM; 161 yaml::Stream Stream("test: |\n Hello\n World\n", SM); 162 yaml::Document &Doc = *Stream.begin(); 163 yaml::MappingNode *Map = cast<yaml::MappingNode>(Doc.getRoot()); 164 StringRef Value = 165 cast<yaml::BlockScalarNode>(Map->begin()->getValue())->getValue(); 166 167 EXPECT_EQ(Value, "Hello\nWorld\n"); 168 EXPECT_EQ(Value.data()[Value.size()], '\0'); 169 } 170 171 TEST(YAMLParser, HandlesEndOfFileGracefully) { 172 ExpectParseError("In string starting with EOF", "[\""); 173 ExpectParseError("In string hitting EOF", "[\" "); 174 ExpectParseError("In string escaping EOF", "[\" \\"); 175 ExpectParseError("In array starting with EOF", "["); 176 ExpectParseError("In array element starting with EOF", "[[], "); 177 ExpectParseError("In array hitting EOF", "[[] "); 178 ExpectParseError("In array hitting EOF", "[[]"); 179 ExpectParseError("In object hitting EOF", "{\"\""); 180 } 181 182 TEST(YAMLParser, HandlesNullValuesInKeyValueNodesGracefully) { 183 ExpectParseError("KeyValueNode with null value", "test: '"); 184 } 185 186 // Checks that the given string can be parsed into an identical string inside 187 // of an array. 188 static void ExpectCanParseString(StringRef String) { 189 std::string StringInArray = (llvm::Twine("[\"") + String + "\"]").str(); 190 SourceMgr SM; 191 yaml::Stream Stream(StringInArray, SM); 192 yaml::SequenceNode *ParsedSequence 193 = dyn_cast<yaml::SequenceNode>(Stream.begin()->getRoot()); 194 StringRef ParsedString 195 = dyn_cast<yaml::ScalarNode>( 196 static_cast<yaml::Node*>(ParsedSequence->begin()))->getRawValue(); 197 ParsedString = ParsedString.substr(1, ParsedString.size() - 2); 198 EXPECT_EQ(String, ParsedString.str()); 199 } 200 201 // Checks that parsing the given string inside an array fails. 202 static void ExpectCannotParseString(StringRef String) { 203 std::string StringInArray = (llvm::Twine("[\"") + String + "\"]").str(); 204 ExpectParseError((Twine("When parsing string \"") + String + "\"").str(), 205 StringInArray); 206 } 207 208 TEST(YAMLParser, ParsesStrings) { 209 ExpectCanParseString(""); 210 ExpectCannotParseString("\\"); 211 ExpectCannotParseString("\""); 212 ExpectCanParseString(" "); 213 ExpectCanParseString("\\ "); 214 ExpectCanParseString("\\\""); 215 ExpectCannotParseString("\"\\"); 216 ExpectCannotParseString(" \\"); 217 ExpectCanParseString("\\\\"); 218 ExpectCannotParseString("\\\\\\"); 219 ExpectCanParseString("\\\\\\\\"); 220 ExpectCanParseString("\\\" "); 221 ExpectCannotParseString("\\\\\" "); 222 ExpectCanParseString("\\\\\\\" "); 223 ExpectCanParseString(" \\\\ \\\" \\\\\\\" "); 224 } 225 226 TEST(YAMLParser, WorksWithIteratorAlgorithms) { 227 SourceMgr SM; 228 yaml::Stream Stream("[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]", SM); 229 yaml::SequenceNode *Array 230 = dyn_cast<yaml::SequenceNode>(Stream.begin()->getRoot()); 231 EXPECT_EQ(6, std::distance(Array->begin(), Array->end())); 232 } 233 234 TEST(YAMLParser, DefaultDiagnosticFilename) { 235 SourceMgr SM; 236 237 SMDiagnostic GeneratedDiag; 238 SM.setDiagHandler(CollectDiagnosticsOutput, &GeneratedDiag); 239 240 // When we construct a YAML stream over an unnamed string, 241 // the filename is hard-coded as "YAML". 242 yaml::Stream UnnamedStream("[]", SM); 243 UnnamedStream.printError(UnnamedStream.begin()->getRoot(), "Hello, World!"); 244 EXPECT_EQ("YAML", GeneratedDiag.getFilename()); 245 } 246 247 TEST(YAMLParser, DiagnosticFilenameFromBufferID) { 248 SourceMgr SM; 249 250 SMDiagnostic GeneratedDiag; 251 SM.setDiagHandler(CollectDiagnosticsOutput, &GeneratedDiag); 252 253 // When we construct a YAML stream over a named buffer, 254 // we get its ID as filename in diagnostics. 255 std::unique_ptr<MemoryBuffer> Buffer = 256 MemoryBuffer::getMemBuffer("[]", "buffername.yaml"); 257 yaml::Stream Stream(Buffer->getMemBufferRef(), SM); 258 Stream.printError(Stream.begin()->getRoot(), "Hello, World!"); 259 EXPECT_EQ("buffername.yaml", GeneratedDiag.getFilename()); 260 } 261 262 TEST(YAMLParser, SameNodeIteratorOperatorNotEquals) { 263 SourceMgr SM; 264 yaml::Stream Stream("[\"1\", \"2\"]", SM); 265 266 yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( 267 Stream.begin()->getRoot()); 268 269 auto Begin = Node->begin(); 270 auto End = Node->end(); 271 272 EXPECT_TRUE(Begin != End); 273 EXPECT_FALSE(Begin != Begin); 274 EXPECT_FALSE(End != End); 275 } 276 277 TEST(YAMLParser, SameNodeIteratorOperatorEquals) { 278 SourceMgr SM; 279 yaml::Stream Stream("[\"1\", \"2\"]", SM); 280 281 yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( 282 Stream.begin()->getRoot()); 283 284 auto Begin = Node->begin(); 285 auto End = Node->end(); 286 287 EXPECT_FALSE(Begin == End); 288 EXPECT_TRUE(Begin == Begin); 289 EXPECT_TRUE(End == End); 290 } 291 292 TEST(YAMLParser, DifferentNodesIteratorOperatorNotEquals) { 293 SourceMgr SM; 294 yaml::Stream Stream("[\"1\", \"2\"]", SM); 295 yaml::Stream AnotherStream("[\"1\", \"2\"]", SM); 296 297 yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( 298 Stream.begin()->getRoot()); 299 yaml::SequenceNode *AnotherNode = dyn_cast<yaml::SequenceNode>( 300 AnotherStream.begin()->getRoot()); 301 302 auto Begin = Node->begin(); 303 auto End = Node->end(); 304 305 auto AnotherBegin = AnotherNode->begin(); 306 auto AnotherEnd = AnotherNode->end(); 307 308 EXPECT_TRUE(Begin != AnotherBegin); 309 EXPECT_TRUE(Begin != AnotherEnd); 310 EXPECT_FALSE(End != AnotherEnd); 311 } 312 313 TEST(YAMLParser, DifferentNodesIteratorOperatorEquals) { 314 SourceMgr SM; 315 yaml::Stream Stream("[\"1\", \"2\"]", SM); 316 yaml::Stream AnotherStream("[\"1\", \"2\"]", SM); 317 318 yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( 319 Stream.begin()->getRoot()); 320 yaml::SequenceNode *AnotherNode = dyn_cast<yaml::SequenceNode>( 321 AnotherStream.begin()->getRoot()); 322 323 auto Begin = Node->begin(); 324 auto End = Node->end(); 325 326 auto AnotherBegin = AnotherNode->begin(); 327 auto AnotherEnd = AnotherNode->end(); 328 329 EXPECT_FALSE(Begin == AnotherBegin); 330 EXPECT_FALSE(Begin == AnotherEnd); 331 EXPECT_TRUE(End == AnotherEnd); 332 } 333 334 } // end namespace llvm 335