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/Support/YAMLParser.h" 11 #include "llvm/ADT/Twine.h" 12 #include "llvm/Support/Casting.h" 13 #include "llvm/Support/MemoryBuffer.h" 14 #include "llvm/Support/SourceMgr.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 key", "? \"\n:"); 184 ExpectParseError("KeyValueNode with null value", "test: '"); 185 } 186 187 // Checks that the given string can be parsed into an identical string inside 188 // of an array. 189 static void ExpectCanParseString(StringRef String) { 190 std::string StringInArray = (llvm::Twine("[\"") + String + "\"]").str(); 191 SourceMgr SM; 192 yaml::Stream Stream(StringInArray, SM); 193 yaml::SequenceNode *ParsedSequence 194 = dyn_cast<yaml::SequenceNode>(Stream.begin()->getRoot()); 195 StringRef ParsedString 196 = dyn_cast<yaml::ScalarNode>( 197 static_cast<yaml::Node*>(ParsedSequence->begin()))->getRawValue(); 198 ParsedString = ParsedString.substr(1, ParsedString.size() - 2); 199 EXPECT_EQ(String, ParsedString.str()); 200 } 201 202 // Checks that parsing the given string inside an array fails. 203 static void ExpectCannotParseString(StringRef String) { 204 std::string StringInArray = (llvm::Twine("[\"") + String + "\"]").str(); 205 ExpectParseError((Twine("When parsing string \"") + String + "\"").str(), 206 StringInArray); 207 } 208 209 TEST(YAMLParser, ParsesStrings) { 210 ExpectCanParseString(""); 211 ExpectCannotParseString("\\"); 212 ExpectCannotParseString("\""); 213 ExpectCanParseString(" "); 214 ExpectCanParseString("\\ "); 215 ExpectCanParseString("\\\""); 216 ExpectCannotParseString("\"\\"); 217 ExpectCannotParseString(" \\"); 218 ExpectCanParseString("\\\\"); 219 ExpectCannotParseString("\\\\\\"); 220 ExpectCanParseString("\\\\\\\\"); 221 ExpectCanParseString("\\\" "); 222 ExpectCannotParseString("\\\\\" "); 223 ExpectCanParseString("\\\\\\\" "); 224 ExpectCanParseString(" \\\\ \\\" \\\\\\\" "); 225 } 226 227 TEST(YAMLParser, WorksWithIteratorAlgorithms) { 228 SourceMgr SM; 229 yaml::Stream Stream("[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]", SM); 230 yaml::SequenceNode *Array 231 = dyn_cast<yaml::SequenceNode>(Stream.begin()->getRoot()); 232 EXPECT_EQ(6, std::distance(Array->begin(), Array->end())); 233 } 234 235 TEST(YAMLParser, DefaultDiagnosticFilename) { 236 SourceMgr SM; 237 238 SMDiagnostic GeneratedDiag; 239 SM.setDiagHandler(CollectDiagnosticsOutput, &GeneratedDiag); 240 241 // When we construct a YAML stream over an unnamed string, 242 // the filename is hard-coded as "YAML". 243 yaml::Stream UnnamedStream("[]", SM); 244 UnnamedStream.printError(UnnamedStream.begin()->getRoot(), "Hello, World!"); 245 EXPECT_EQ("YAML", GeneratedDiag.getFilename()); 246 } 247 248 TEST(YAMLParser, DiagnosticFilenameFromBufferID) { 249 SourceMgr SM; 250 251 SMDiagnostic GeneratedDiag; 252 SM.setDiagHandler(CollectDiagnosticsOutput, &GeneratedDiag); 253 254 // When we construct a YAML stream over a named buffer, 255 // we get its ID as filename in diagnostics. 256 std::unique_ptr<MemoryBuffer> Buffer = 257 MemoryBuffer::getMemBuffer("[]", "buffername.yaml"); 258 yaml::Stream Stream(Buffer->getMemBufferRef(), SM); 259 Stream.printError(Stream.begin()->getRoot(), "Hello, World!"); 260 EXPECT_EQ("buffername.yaml", GeneratedDiag.getFilename()); 261 } 262 263 TEST(YAMLParser, SameNodeIteratorOperatorNotEquals) { 264 SourceMgr SM; 265 yaml::Stream Stream("[\"1\", \"2\"]", SM); 266 267 yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( 268 Stream.begin()->getRoot()); 269 270 auto Begin = Node->begin(); 271 auto End = Node->end(); 272 273 EXPECT_TRUE(Begin != End); 274 EXPECT_FALSE(Begin != Begin); 275 EXPECT_FALSE(End != End); 276 } 277 278 TEST(YAMLParser, SameNodeIteratorOperatorEquals) { 279 SourceMgr SM; 280 yaml::Stream Stream("[\"1\", \"2\"]", SM); 281 282 yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( 283 Stream.begin()->getRoot()); 284 285 auto Begin = Node->begin(); 286 auto End = Node->end(); 287 288 EXPECT_FALSE(Begin == End); 289 EXPECT_TRUE(Begin == Begin); 290 EXPECT_TRUE(End == End); 291 } 292 293 TEST(YAMLParser, DifferentNodesIteratorOperatorNotEquals) { 294 SourceMgr SM; 295 yaml::Stream Stream("[\"1\", \"2\"]", SM); 296 yaml::Stream AnotherStream("[\"1\", \"2\"]", SM); 297 298 yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( 299 Stream.begin()->getRoot()); 300 yaml::SequenceNode *AnotherNode = dyn_cast<yaml::SequenceNode>( 301 AnotherStream.begin()->getRoot()); 302 303 auto Begin = Node->begin(); 304 auto End = Node->end(); 305 306 auto AnotherBegin = AnotherNode->begin(); 307 auto AnotherEnd = AnotherNode->end(); 308 309 EXPECT_TRUE(Begin != AnotherBegin); 310 EXPECT_TRUE(Begin != AnotherEnd); 311 EXPECT_FALSE(End != AnotherEnd); 312 } 313 314 TEST(YAMLParser, DifferentNodesIteratorOperatorEquals) { 315 SourceMgr SM; 316 yaml::Stream Stream("[\"1\", \"2\"]", SM); 317 yaml::Stream AnotherStream("[\"1\", \"2\"]", SM); 318 319 yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( 320 Stream.begin()->getRoot()); 321 yaml::SequenceNode *AnotherNode = dyn_cast<yaml::SequenceNode>( 322 AnotherStream.begin()->getRoot()); 323 324 auto Begin = Node->begin(); 325 auto End = Node->end(); 326 327 auto AnotherBegin = AnotherNode->begin(); 328 auto AnotherEnd = AnotherNode->end(); 329 330 EXPECT_FALSE(Begin == AnotherBegin); 331 EXPECT_FALSE(Begin == AnotherEnd); 332 EXPECT_TRUE(End == AnotherEnd); 333 } 334 335 } // end namespace llvm 336