1 | //===- unittest/Support/YAMLParserTest ------------------------------------===// |
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-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/Support/YAMLParser.h" |
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 "gtest/gtest.h" |
15 | |
16 | namespace llvm { |
17 | |
18 | static void SuppressDiagnosticsOutput(const SMDiagnostic &, void *) { |
19 | // Prevent SourceMgr from writing errors to stderr |
20 | // to reduce noise in unit test runs. |
21 | } |
22 | |
23 | // Assumes Ctx is an SMDiagnostic where Diag can be stored. |
24 | static void CollectDiagnosticsOutput(const SMDiagnostic &Diag, void *Ctx) { |
25 | SMDiagnostic* DiagOut = static_cast<SMDiagnostic*>(Ctx); |
26 | *DiagOut = Diag; |
27 | } |
28 | |
29 | // Checks that the given input gives a parse error. Makes sure that an error |
30 | // text is available and the parse fails. |
31 | static void ExpectParseError(StringRef Message, StringRef Input) { |
32 | SourceMgr SM; |
33 | yaml::Stream Stream(Input, SM); |
34 | SM.setDiagHandler(DH: SuppressDiagnosticsOutput); |
35 | EXPECT_FALSE(Stream.validate()) << Message << ": " << Input; |
36 | EXPECT_TRUE(Stream.failed()) << Message << ": " << Input; |
37 | } |
38 | |
39 | // Checks that the given input can be parsed without error. |
40 | static void ExpectParseSuccess(StringRef Message, StringRef Input) { |
41 | SourceMgr SM; |
42 | yaml::Stream Stream(Input, SM); |
43 | EXPECT_TRUE(Stream.validate()) << Message << ": " << Input; |
44 | } |
45 | |
46 | TEST(YAMLParser, ParsesEmptyArray) { |
47 | ExpectParseSuccess(Message: "Empty array" , Input: "[]" ); |
48 | } |
49 | |
50 | TEST(YAMLParser, ParsesComplexMap) { |
51 | ExpectParseSuccess(Message: "Complex block map" , Input: "? a\n: b" ); |
52 | } |
53 | |
54 | TEST(YAMLParser, FailsIfNotClosingArray) { |
55 | ExpectParseError(Message: "Not closing array" , Input: "[" ); |
56 | ExpectParseError(Message: "Not closing array" , Input: " [ " ); |
57 | ExpectParseError(Message: "Not closing array" , Input: " [x" ); |
58 | } |
59 | |
60 | TEST(YAMLParser, ParsesEmptyArrayWithWhitespace) { |
61 | ExpectParseSuccess(Message: "Array with spaces" , Input: " [ ] " ); |
62 | ExpectParseSuccess(Message: "All whitespaces" , Input: "\t\r\n[\t\n \t\r ]\t\r \n\n" ); |
63 | } |
64 | |
65 | TEST(YAMLParser, ParsesEmptyObject) { |
66 | ExpectParseSuccess(Message: "Empty object" , Input: "[{}]" ); |
67 | } |
68 | |
69 | TEST(YAMLParser, ParsesObject) { |
70 | ExpectParseSuccess(Message: "Object with an entry" , Input: "[{\"a\":\"/b\"}]" ); |
71 | } |
72 | |
73 | TEST(YAMLParser, ParsesMultipleKeyValuePairsInObject) { |
74 | ExpectParseSuccess(Message: "Multiple key, value pairs" , |
75 | Input: "[{\"a\":\"/b\",\"c\":\"d\",\"e\":\"f\"}]" ); |
76 | } |
77 | |
78 | TEST(YAMLParser, FailsIfNotClosingObject) { |
79 | ExpectParseError(Message: "Missing close on empty" , Input: "[{]" ); |
80 | ExpectParseError(Message: "Missing close after pair" , Input: "[{\"a\":\"b\"]" ); |
81 | } |
82 | |
83 | TEST(YAMLParser, FailsIfMissingColon) { |
84 | ExpectParseError(Message: "Missing colon between key and value" , Input: "[{\"a\"\"/b\"}]" ); |
85 | ExpectParseError(Message: "Missing colon between key and value" , Input: "[{\"a\" \"b\"}]" ); |
86 | } |
87 | |
88 | TEST(YAMLParser, FailsOnMissingQuote) { |
89 | // Missing open quote counts as a plain scalar per YAML spec |
90 | // (Following is equivalent to JSON [{"a\":\"b\"": null}]) |
91 | ExpectParseSuccess(Message: "Missing open quote" , Input: "[{a\":\"b\"}]" ); |
92 | // Closing quote is more strict -- plain scalars cannot start with a quote |
93 | ExpectParseError(Message: "Missing closing quote" , Input: "[{\"a\":\"b}]" ); |
94 | } |
95 | |
96 | TEST(YAMLParser, ParsesEscapedQuotes) { |
97 | ExpectParseSuccess(Message: "Parses escaped string in key and value" , |
98 | Input: "[{\"a\":\"\\\"b\\\" \\\" \\\"\"}]" ); |
99 | } |
100 | |
101 | TEST(YAMLParser, ParsesEmptyString) { |
102 | ExpectParseSuccess(Message: "Parses empty string in value" , Input: "[{\"a\":\"\"}]" ); |
103 | } |
104 | |
105 | TEST(YAMLParser, ParsesMultipleObjects) { |
106 | ExpectParseSuccess( |
107 | Message: "Multiple objects in array" , |
108 | Input: "[" |
109 | " { \"a\" : \"b\" }," |
110 | " { \"a\" : \"b\" }," |
111 | " { \"a\" : \"b\" }" |
112 | "]" ); |
113 | } |
114 | |
115 | TEST(YAMLParser, FailsOnMissingComma) { |
116 | ExpectParseError( |
117 | Message: "Missing comma" , |
118 | Input: "[" |
119 | " { \"a\" : \"b\" }" |
120 | " { \"a\" : \"b\" }" |
121 | "]" ); |
122 | } |
123 | |
124 | TEST(YAMLParser, ParsesSpacesInBetweenTokens) { |
125 | ExpectParseSuccess( |
126 | Message: "Various whitespace between tokens" , |
127 | Input: " \t \n\n \r [ \t \n\n \r" |
128 | " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :" |
129 | " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r,\t \n\n \r" |
130 | " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :" |
131 | " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r]\t \n\n \r" ); |
132 | } |
133 | |
134 | TEST(YAMLParser, ParsesArrayOfArrays) { |
135 | ExpectParseSuccess(Message: "Array of arrays" , Input: "[[]]" ); |
136 | } |
137 | |
138 | TEST(YAMLParser, ParsesPlainScalars) { |
139 | ExpectParseSuccess(Message: "Plain scalar" , Input: "hello" ); |
140 | ExpectParseSuccess(Message: "Plain scalar beginning with a question mark" , Input: "?hello" ); |
141 | ExpectParseSuccess(Message: "Plain scalar beginning with a colon" , Input: ":hello" ); |
142 | ExpectParseSuccess(Message: "Plain scalar beginning with two colons" , Input: "::hello" ); |
143 | ExpectParseSuccess(Message: "Plain scalar beginning with a hyphen" , Input: "-hello" ); |
144 | ExpectParseSuccess(Message: "Multi-line plain scalar" , Input: "Hello\nworld" ); |
145 | ExpectParseSuccess(Message: "Plain scalar with indicator characters" , |
146 | Input: "He-!l*lo, []world{}" ); |
147 | ExpectParseSuccess(Message: "Plain scalar with indicator characters used as block key" , |
148 | Input: "He-!l*lo, []world{}: value" ); |
149 | ExpectParseSuccess(Message: "Plain scalar in flow sequence" , Input: "hello" ); |
150 | ExpectParseSuccess( |
151 | Message: "Plain scalar beginning with a question mark in flow sequence" , |
152 | Input: "[ ?hello ]" ); |
153 | ExpectParseSuccess(Message: "Plain scalar beginning with a colon in flow sequence" , |
154 | Input: "[ :hello ]" ); |
155 | ExpectParseSuccess(Message: "Plain scalar beginning with two colons in flow sequence" , |
156 | Input: "[ ::hello ]" ); |
157 | ExpectParseSuccess(Message: "Plain scalar beginning with a hyphen in flow sequence" , |
158 | Input: "[ -hello ]" ); |
159 | ExpectParseSuccess(Message: "Multi-line plain scalar in flow sequence" , |
160 | Input: "[ Hello\nworld ]" ); |
161 | ExpectParseSuccess( |
162 | Message: "Plain scalar with non-flow indicator characters in flow sequence" , |
163 | Input: "[ He-!l*lo, world ]" ); |
164 | ExpectParseSuccess( |
165 | Message: "Plain scalar with non-flow indicator characters used as flow key" , |
166 | Input: "{ He-!l*lo, world: value } " ); |
167 | ExpectParseError( |
168 | Message: "Plain scalar with flow indicator characters inside flow sequence" , |
169 | Input: "[ Hello[world ]" ); |
170 | ExpectParseError( |
171 | Message: "Plain scalar with flow indicator characters inside flow key" , |
172 | Input: "{ Hello[world: value }" ); |
173 | // Multi-line plain scalar in keys is strictly invalid per the spec, but many |
174 | // implementations accept it in flow keys nonetheless. Block keys are not |
175 | // accepted by any other implementation I can find. |
176 | ExpectParseSuccess(Message: "Multi-line plain scalar in block key" , Input: "a\nb: c" ); |
177 | ExpectParseSuccess(Message: "Multi-line plain scalar in flow key" , Input: "{\na\nb: c\n}" ); |
178 | } |
179 | |
180 | TEST(YAMLParser, ParsesBlockLiteralScalars) { |
181 | ExpectParseSuccess(Message: "Block literal scalar" , Input: "test: |\n Hello\n World\n" ); |
182 | ExpectParseSuccess(Message: "Block literal scalar EOF" , Input: "test: |\n Hello\n World" ); |
183 | ExpectParseSuccess(Message: "Empty block literal scalar header EOF" , Input: "test: | " ); |
184 | ExpectParseSuccess(Message: "Empty block literal scalar" , Input: "test: |\ntest2: 20" ); |
185 | ExpectParseSuccess(Message: "Empty block literal scalar 2" , Input: "- | \n \n\n \n- 42" ); |
186 | ExpectParseSuccess(Message: "Block literal scalar in sequence" , |
187 | Input: "- |\n Testing\n Out\n\n- 22" ); |
188 | ExpectParseSuccess(Message: "Block literal scalar in document" , |
189 | Input: "--- |\n Document\n..." ); |
190 | ExpectParseSuccess(Message: "Empty non indented lines still count" , |
191 | Input: "- |\n First line\n \n\n Another line\n\n- 2" ); |
192 | ExpectParseSuccess(Message: "Comment in block literal scalar header" , |
193 | Input: "test: | # Comment \n No Comment\ntest 2: | # Void" ); |
194 | ExpectParseSuccess(Message: "Chomping indicators in block literal scalar header" , |
195 | Input: "test: |- \n Hello\n\ntest 2: |+ \n\n World\n\n\n" ); |
196 | ExpectParseSuccess(Message: "Indent indicators in block literal scalar header" , |
197 | Input: "test: |1 \n \n Hello \n World\n" ); |
198 | ExpectParseSuccess(Message: "Chomping and indent indicators in block literals" , |
199 | Input: "test: |-1\n Hello\ntest 2: |9+\n World" ); |
200 | ExpectParseSuccess(Message: "Trailing comments in block literals" , |
201 | Input: "test: |\n Content\n # Trailing\n #Comment\ntest 2: 3" ); |
202 | ExpectParseError(Message: "Invalid block scalar header" , Input: "test: | failure" ); |
203 | ExpectParseError(Message: "Invalid line indentation" , Input: "test: |\n First line\n Error" ); |
204 | ExpectParseError(Message: "Long leading space line" , Input: "test: |\n \n Test\n" ); |
205 | } |
206 | |
207 | TEST(YAMLParser, NullTerminatedBlockScalars) { |
208 | SourceMgr SM; |
209 | yaml::Stream Stream("test: |\n Hello\n World\n" , SM); |
210 | yaml::Document &Doc = *Stream.begin(); |
211 | yaml::MappingNode *Map = cast<yaml::MappingNode>(Val: Doc.getRoot()); |
212 | StringRef Value = |
213 | cast<yaml::BlockScalarNode>(Val: Map->begin()->getValue())->getValue(); |
214 | |
215 | EXPECT_EQ(Value, "Hello\nWorld\n" ); |
216 | EXPECT_EQ(Value.data()[Value.size()], '\0'); |
217 | } |
218 | |
219 | TEST(YAMLParser, HandlesEndOfFileGracefully) { |
220 | ExpectParseError(Message: "In string starting with EOF" , Input: "[\"" ); |
221 | ExpectParseError(Message: "In string hitting EOF" , Input: "[\" " ); |
222 | ExpectParseError(Message: "In string escaping EOF" , Input: "[\" \\" ); |
223 | ExpectParseError(Message: "In array starting with EOF" , Input: "[" ); |
224 | ExpectParseError(Message: "In array element starting with EOF" , Input: "[[], " ); |
225 | ExpectParseError(Message: "In array hitting EOF" , Input: "[[] " ); |
226 | ExpectParseError(Message: "In array hitting EOF" , Input: "[[]" ); |
227 | ExpectParseError(Message: "In object hitting EOF" , Input: "{\"\"" ); |
228 | // This one is valid, equivalent to the JSON {"": null} |
229 | ExpectParseSuccess(Message: "In complex block map hitting EOF" , Input: "?" ); |
230 | // Equivalent to JSON [null] |
231 | ExpectParseSuccess(Message: "In block sequence hitting EOF" , Input: "-" ); |
232 | } |
233 | |
234 | TEST(YAMLParser, HandlesNullValuesInKeyValueNodesGracefully) { |
235 | ExpectParseError(Message: "KeyValueNode with null key" , Input: "? \"\n:" ); |
236 | ExpectParseError(Message: "KeyValueNode with null value" , Input: "test: '" ); |
237 | } |
238 | |
239 | TEST(YAMLParser, BlockSequenceEOF) { |
240 | SourceMgr SM; |
241 | yaml::Stream Stream("-" , SM); |
242 | EXPECT_TRUE(isa_and_present<yaml::SequenceNode>(Stream.begin()->getRoot())); |
243 | } |
244 | |
245 | // Checks that the given string can be parsed into an identical string inside |
246 | // of an array. |
247 | static void ExpectCanParseString(StringRef String) { |
248 | std::string StringInArray = (llvm::Twine("[\"" ) + String + "\"]" ).str(); |
249 | SourceMgr SM; |
250 | yaml::Stream Stream(StringInArray, SM); |
251 | yaml::SequenceNode *ParsedSequence |
252 | = dyn_cast<yaml::SequenceNode>(Val: Stream.begin()->getRoot()); |
253 | StringRef ParsedString |
254 | = dyn_cast<yaml::ScalarNode>( |
255 | Val: static_cast<yaml::Node*>(ParsedSequence->begin()))->getRawValue(); |
256 | ParsedString = ParsedString.substr(Start: 1, N: ParsedString.size() - 2); |
257 | EXPECT_EQ(String, ParsedString.str()); |
258 | } |
259 | |
260 | // Checks that parsing the given string inside an array fails. |
261 | static void ExpectCannotParseString(StringRef String) { |
262 | std::string StringInArray = (llvm::Twine("[\"" ) + String + "\"]" ).str(); |
263 | ExpectParseError(Message: (Twine("When parsing string \"" ) + String + "\"" ).str(), |
264 | Input: StringInArray); |
265 | } |
266 | |
267 | TEST(YAMLParser, ParsesStrings) { |
268 | ExpectCanParseString(String: "" ); |
269 | ExpectCannotParseString(String: "\\" ); |
270 | ExpectCannotParseString(String: "\"" ); |
271 | ExpectCanParseString(String: " " ); |
272 | ExpectCanParseString(String: "\\ " ); |
273 | ExpectCanParseString(String: "\\\"" ); |
274 | ExpectCannotParseString(String: "\"\\" ); |
275 | ExpectCannotParseString(String: " \\" ); |
276 | ExpectCanParseString(String: "\\\\" ); |
277 | ExpectCannotParseString(String: "\\\\\\" ); |
278 | ExpectCanParseString(String: "\\\\\\\\" ); |
279 | ExpectCanParseString(String: "\\\" " ); |
280 | ExpectCannotParseString(String: "\\\\\" " ); |
281 | ExpectCanParseString(String: "\\\\\\\" " ); |
282 | ExpectCanParseString(String: " \\\\ \\\" \\\\\\\" " ); |
283 | } |
284 | |
285 | TEST(YAMLParser, WorksWithIteratorAlgorithms) { |
286 | SourceMgr SM; |
287 | yaml::Stream Stream("[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]" , SM); |
288 | yaml::SequenceNode *Array |
289 | = dyn_cast<yaml::SequenceNode>(Val: Stream.begin()->getRoot()); |
290 | EXPECT_EQ(6, std::distance(Array->begin(), Array->end())); |
291 | } |
292 | |
293 | TEST(YAMLParser, DefaultDiagnosticFilename) { |
294 | SourceMgr SM; |
295 | |
296 | SMDiagnostic GeneratedDiag; |
297 | SM.setDiagHandler(DH: CollectDiagnosticsOutput, Ctx: &GeneratedDiag); |
298 | |
299 | // When we construct a YAML stream over an unnamed string, |
300 | // the filename is hard-coded as "YAML". |
301 | yaml::Stream UnnamedStream("[]" , SM); |
302 | UnnamedStream.printError(N: UnnamedStream.begin()->getRoot(), Msg: "Hello, World!" ); |
303 | EXPECT_EQ("YAML" , GeneratedDiag.getFilename()); |
304 | } |
305 | |
306 | TEST(YAMLParser, DiagnosticFilenameFromBufferID) { |
307 | SourceMgr SM; |
308 | |
309 | SMDiagnostic GeneratedDiag; |
310 | SM.setDiagHandler(DH: CollectDiagnosticsOutput, Ctx: &GeneratedDiag); |
311 | |
312 | // When we construct a YAML stream over a named buffer, |
313 | // we get its ID as filename in diagnostics. |
314 | std::unique_ptr<MemoryBuffer> Buffer = |
315 | MemoryBuffer::getMemBuffer(InputData: "[]" , BufferName: "buffername.yaml" ); |
316 | yaml::Stream Stream(Buffer->getMemBufferRef(), SM); |
317 | Stream.printError(N: Stream.begin()->getRoot(), Msg: "Hello, World!" ); |
318 | EXPECT_EQ("buffername.yaml" , GeneratedDiag.getFilename()); |
319 | } |
320 | |
321 | TEST(YAMLParser, SameNodeIteratorOperatorNotEquals) { |
322 | SourceMgr SM; |
323 | yaml::Stream Stream("[\"1\", \"2\"]" , SM); |
324 | |
325 | yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( |
326 | Val: Stream.begin()->getRoot()); |
327 | |
328 | auto Begin = Node->begin(); |
329 | auto End = Node->end(); |
330 | |
331 | EXPECT_NE(Begin, End); |
332 | EXPECT_EQ(Begin, Begin); |
333 | EXPECT_EQ(End, End); |
334 | } |
335 | |
336 | TEST(YAMLParser, SameNodeIteratorOperatorEquals) { |
337 | SourceMgr SM; |
338 | yaml::Stream Stream("[\"1\", \"2\"]" , SM); |
339 | |
340 | yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( |
341 | Val: Stream.begin()->getRoot()); |
342 | |
343 | auto Begin = Node->begin(); |
344 | auto End = Node->end(); |
345 | |
346 | EXPECT_NE(Begin, End); |
347 | EXPECT_EQ(Begin, Begin); |
348 | EXPECT_EQ(End, End); |
349 | } |
350 | |
351 | TEST(YAMLParser, DifferentNodesIteratorOperatorNotEquals) { |
352 | SourceMgr SM; |
353 | yaml::Stream Stream("[\"1\", \"2\"]" , SM); |
354 | yaml::Stream AnotherStream("[\"1\", \"2\"]" , SM); |
355 | |
356 | yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( |
357 | Val: Stream.begin()->getRoot()); |
358 | yaml::SequenceNode *AnotherNode = dyn_cast<yaml::SequenceNode>( |
359 | Val: AnotherStream.begin()->getRoot()); |
360 | |
361 | auto Begin = Node->begin(); |
362 | auto End = Node->end(); |
363 | |
364 | auto AnotherBegin = AnotherNode->begin(); |
365 | auto AnotherEnd = AnotherNode->end(); |
366 | |
367 | EXPECT_NE(Begin, AnotherBegin); |
368 | EXPECT_NE(Begin, AnotherEnd); |
369 | EXPECT_EQ(End, AnotherEnd); |
370 | } |
371 | |
372 | TEST(YAMLParser, DifferentNodesIteratorOperatorEquals) { |
373 | SourceMgr SM; |
374 | yaml::Stream Stream("[\"1\", \"2\"]" , SM); |
375 | yaml::Stream AnotherStream("[\"1\", \"2\"]" , SM); |
376 | |
377 | yaml::SequenceNode *Node = dyn_cast<yaml::SequenceNode>( |
378 | Val: Stream.begin()->getRoot()); |
379 | yaml::SequenceNode *AnotherNode = dyn_cast<yaml::SequenceNode>( |
380 | Val: AnotherStream.begin()->getRoot()); |
381 | |
382 | auto Begin = Node->begin(); |
383 | auto End = Node->end(); |
384 | |
385 | auto AnotherBegin = AnotherNode->begin(); |
386 | auto AnotherEnd = AnotherNode->end(); |
387 | |
388 | EXPECT_NE(Begin, AnotherBegin); |
389 | EXPECT_NE(Begin, AnotherEnd); |
390 | EXPECT_EQ(End, AnotherEnd); |
391 | } |
392 | |
393 | TEST(YAMLParser, FlowSequenceTokensOutsideFlowSequence) { |
394 | auto FlowSequenceStrs = {"," , "]" , "}" }; |
395 | SourceMgr SM; |
396 | |
397 | for (auto &Str : FlowSequenceStrs) { |
398 | yaml::Stream Stream(Str, SM); |
399 | yaml::Document &Doc = *Stream.begin(); |
400 | EXPECT_FALSE(Doc.skip()); |
401 | } |
402 | } |
403 | |
404 | static void expectCanParseBool(StringRef S, bool Expected) { |
405 | std::optional<bool> Parsed = yaml::parseBool(S); |
406 | EXPECT_TRUE(Parsed.has_value()); |
407 | EXPECT_EQ(*Parsed, Expected); |
408 | } |
409 | |
410 | static void expectCannotParseBool(StringRef S) { |
411 | EXPECT_FALSE(yaml::parseBool(S).has_value()); |
412 | } |
413 | |
414 | TEST(YAMLParser, ParsesBools) { |
415 | // Test true values. |
416 | expectCanParseBool(S: "ON" , Expected: true); |
417 | expectCanParseBool(S: "On" , Expected: true); |
418 | expectCanParseBool(S: "on" , Expected: true); |
419 | expectCanParseBool(S: "TRUE" , Expected: true); |
420 | expectCanParseBool(S: "True" , Expected: true); |
421 | expectCanParseBool(S: "true" , Expected: true); |
422 | expectCanParseBool(S: "Y" , Expected: true); |
423 | expectCanParseBool(S: "y" , Expected: true); |
424 | expectCanParseBool(S: "YES" , Expected: true); |
425 | expectCanParseBool(S: "Yes" , Expected: true); |
426 | expectCanParseBool(S: "yes" , Expected: true); |
427 | expectCannotParseBool(S: "1" ); |
428 | |
429 | // Test false values. |
430 | expectCanParseBool(S: "FALSE" , Expected: false); |
431 | expectCanParseBool(S: "False" , Expected: false); |
432 | expectCanParseBool(S: "false" , Expected: false); |
433 | expectCanParseBool(S: "N" , Expected: false); |
434 | expectCanParseBool(S: "n" , Expected: false); |
435 | expectCanParseBool(S: "NO" , Expected: false); |
436 | expectCanParseBool(S: "No" , Expected: false); |
437 | expectCanParseBool(S: "no" , Expected: false); |
438 | expectCanParseBool(S: "OFF" , Expected: false); |
439 | expectCanParseBool(S: "Off" , Expected: false); |
440 | expectCanParseBool(S: "off" , Expected: false); |
441 | expectCannotParseBool(S: "0" ); |
442 | } |
443 | |
444 | // Checks that the given string can be parsed into an expected scalar value. |
445 | static void expectCanParseScalar(StringRef Input, StringRef Expected) { |
446 | SourceMgr SM; |
447 | yaml::Stream Stream(Input, SM); |
448 | yaml::Node *Root = Stream.begin()->getRoot(); |
449 | ASSERT_NE(Root, nullptr); |
450 | auto *ScalarNode = dyn_cast<yaml::ScalarNode>(Val: Root); |
451 | ASSERT_NE(ScalarNode, nullptr); |
452 | SmallVector<char> Storage; |
453 | StringRef Result = ScalarNode->getValue(Storage); |
454 | EXPECT_EQ(Result, Expected); |
455 | } |
456 | |
457 | TEST(YAMLParser, UnfoldsScalarValue) { |
458 | // Double-quoted values |
459 | expectCanParseScalar(Input: "\"\"" , Expected: "" ); |
460 | expectCanParseScalar(Input: "\" \t\t \t\t \"" , Expected: " \t\t \t\t " ); |
461 | expectCanParseScalar(Input: "\"\n\"" , Expected: " " ); |
462 | expectCanParseScalar(Input: "\"\r\"" , Expected: " " ); |
463 | expectCanParseScalar(Input: "\"\r\n\"" , Expected: " " ); |
464 | expectCanParseScalar(Input: "\"\n\n\"" , Expected: "\n" ); |
465 | expectCanParseScalar(Input: "\"\r\r\"" , Expected: "\n" ); |
466 | expectCanParseScalar(Input: "\"\n\r\"" , Expected: "\n" ); |
467 | expectCanParseScalar(Input: "\"\r\n\r\n\"" , Expected: "\n" ); |
468 | expectCanParseScalar(Input: "\"\n\n\n\"" , Expected: "\n\n" ); |
469 | expectCanParseScalar(Input: "\"\r\r\r\"" , Expected: "\n\n" ); |
470 | expectCanParseScalar(Input: "\"\r\n\r\n\r\n\"" , Expected: "\n\n" ); |
471 | expectCanParseScalar(Input: "\" \t \t \n\t \t \t\r \t \t \"" , Expected: "\n" ); |
472 | expectCanParseScalar(Input: "\" \t A \t \n \t B \t \"" , Expected: " \t A B \t " ); |
473 | expectCanParseScalar(Input: "\" \t \\ \r\r\t \\ \t \"" , Expected: " \t \n \t " ); |
474 | expectCanParseScalar(Input: "\"A\nB\"" , Expected: "A B" ); |
475 | expectCanParseScalar(Input: "\"A\rB\"" , Expected: "A B" ); |
476 | expectCanParseScalar(Input: "\"A\r\nB\"" , Expected: "A B" ); |
477 | expectCanParseScalar(Input: "\"A\n\nB\"" , Expected: "A\nB" ); |
478 | expectCanParseScalar(Input: "\"A\r\rB\"" , Expected: "A\nB" ); |
479 | expectCanParseScalar(Input: "\"A\n\rB\"" , Expected: "A\nB" ); |
480 | expectCanParseScalar(Input: "\"A\r\n\r\nB\"" , Expected: "A\nB" ); |
481 | expectCanParseScalar(Input: "\"A\n\n\nB\"" , Expected: "A\n\nB" ); |
482 | expectCanParseScalar(Input: "\"A\r\r\rB\"" , Expected: "A\n\nB" ); |
483 | expectCanParseScalar(Input: "\"A\r\n\r\n\r\nB\"" , Expected: "A\n\nB" ); |
484 | expectCanParseScalar(Input: "\"A \t \t \n\t \t \t B\"" , Expected: "A B" ); |
485 | expectCanParseScalar(Input: "\"A \t \t \n\t \t \t\r \t \t B\"" , Expected: "A\nB" ); |
486 | expectCanParseScalar(Input: "\"A \t \t \n\t \t \t\r\n \t \r \t B\"" , Expected: "A\n\nB" ); |
487 | expectCanParseScalar(Input: "\"A\\\rB\"" , Expected: "AB" ); |
488 | expectCanParseScalar(Input: "\"A\\\nB\"" , Expected: "AB" ); |
489 | expectCanParseScalar(Input: "\"A\\\r\nB\"" , Expected: "AB" ); |
490 | expectCanParseScalar(Input: "\"A \t \\\rB\"" , Expected: "A \t B" ); |
491 | expectCanParseScalar(Input: "\"A \t\\\nB\"" , Expected: "A \tB" ); |
492 | expectCanParseScalar(Input: "\"A\t \\\r\nB\"" , Expected: "A\t B" ); |
493 | expectCanParseScalar(Input: "\"A\\\r\rB\"" , Expected: "A B" ); |
494 | expectCanParseScalar(Input: "\"A\\\n\nB\"" , Expected: "A B" ); |
495 | expectCanParseScalar(Input: "\"A\\\r\n\r\nB\"" , Expected: "A B" ); |
496 | expectCanParseScalar(Input: "\"A\\\r\r\rB\"" , Expected: "A\nB" ); |
497 | expectCanParseScalar(Input: "\"A\\\n\n\nB\"" , Expected: "A\nB" ); |
498 | expectCanParseScalar(Input: "\"A\\\r\n\r\n\r\nB\"" , Expected: "A\nB" ); |
499 | expectCanParseScalar(Input: "\"A\r\\ \rB\"" , Expected: "A B" ); |
500 | // Single-quoted values |
501 | expectCanParseScalar(Input: "''" , Expected: "" ); |
502 | expectCanParseScalar(Input: "' \t\t \t\t '" , Expected: " \t\t \t\t " ); |
503 | expectCanParseScalar(Input: "'\n'" , Expected: " " ); |
504 | expectCanParseScalar(Input: "'\r'" , Expected: " " ); |
505 | expectCanParseScalar(Input: "'\r\n'" , Expected: " " ); |
506 | expectCanParseScalar(Input: "'\n\n'" , Expected: "\n" ); |
507 | expectCanParseScalar(Input: "'\r\r'" , Expected: "\n" ); |
508 | expectCanParseScalar(Input: "'\n\r'" , Expected: "\n" ); |
509 | expectCanParseScalar(Input: "'\r\n\r\n'" , Expected: "\n" ); |
510 | expectCanParseScalar(Input: "'\n\n\n'" , Expected: "\n\n" ); |
511 | expectCanParseScalar(Input: "'\r\r\r'" , Expected: "\n\n" ); |
512 | expectCanParseScalar(Input: "'\r\n\r\n\r\n'" , Expected: "\n\n" ); |
513 | expectCanParseScalar(Input: "' \t \t \n\t \t \t\r \t \t '" , Expected: "\n" ); |
514 | expectCanParseScalar(Input: "' \t A \t \n \t B \t '" , Expected: " \t A B \t " ); |
515 | expectCanParseScalar(Input: "'A\nB'" , Expected: "A B" ); |
516 | expectCanParseScalar(Input: "'A\rB'" , Expected: "A B" ); |
517 | expectCanParseScalar(Input: "'A\r\nB'" , Expected: "A B" ); |
518 | expectCanParseScalar(Input: "'A\n\nB'" , Expected: "A\nB" ); |
519 | expectCanParseScalar(Input: "'A\r\rB'" , Expected: "A\nB" ); |
520 | expectCanParseScalar(Input: "'A\n\rB'" , Expected: "A\nB" ); |
521 | expectCanParseScalar(Input: "'A\r\n\r\nB'" , Expected: "A\nB" ); |
522 | expectCanParseScalar(Input: "'A\n\n\nB'" , Expected: "A\n\nB" ); |
523 | expectCanParseScalar(Input: "'A\r\r\rB'" , Expected: "A\n\nB" ); |
524 | expectCanParseScalar(Input: "'A\r\n\r\n\r\nB'" , Expected: "A\n\nB" ); |
525 | expectCanParseScalar(Input: "'A \t \t \n\t \t \t B'" , Expected: "A B" ); |
526 | expectCanParseScalar(Input: "'A \t \t \n\t \t \t\r \t \t B'" , Expected: "A\nB" ); |
527 | expectCanParseScalar(Input: "'A \t \t \n\t \t \t\r\n \t \r \t B'" , Expected: "A\n\nB" ); |
528 | // Plain values |
529 | expectCanParseScalar(Input: "A \t \r \n \t \r\n \t\r\r\t " , Expected: "A" ); |
530 | expectCanParseScalar(Input: "A \t \n \t B" , Expected: "A B" ); |
531 | expectCanParseScalar(Input: "A\nB" , Expected: "A B" ); |
532 | expectCanParseScalar(Input: "A\rB" , Expected: "A B" ); |
533 | expectCanParseScalar(Input: "A\r\nB" , Expected: "A B" ); |
534 | expectCanParseScalar(Input: "A\n\nB" , Expected: "A\nB" ); |
535 | expectCanParseScalar(Input: "A\r\rB" , Expected: "A\nB" ); |
536 | expectCanParseScalar(Input: "A\n\rB" , Expected: "A\nB" ); |
537 | expectCanParseScalar(Input: "A\r\n\r\nB" , Expected: "A\nB" ); |
538 | expectCanParseScalar(Input: "A\n\n\nB" , Expected: "A\n\nB" ); |
539 | expectCanParseScalar(Input: "A\r\r\rB" , Expected: "A\n\nB" ); |
540 | expectCanParseScalar(Input: "A\r\n\r\n\r\nB" , Expected: "A\n\nB" ); |
541 | expectCanParseScalar(Input: "A \t \t \n\t \t \t B" , Expected: "A B" ); |
542 | expectCanParseScalar(Input: "A \t \t \n\t \t \t\r \t \t B" , Expected: "A\nB" ); |
543 | expectCanParseScalar(Input: "A \t \t \n\t \t \t\r\n \t \r \t B" , Expected: "A\n\nB" ); |
544 | } |
545 | |
546 | } // end namespace llvm |
547 | |