]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
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/SmallString.h" | |
11 | #include "llvm/ADT/Twine.h" | |
12 | #include "llvm/Support/Casting.h" | |
970d7e83 | 13 | #include "llvm/Support/MemoryBuffer.h" |
223e47cc LB |
14 | #include "llvm/Support/SourceMgr.h" |
15 | #include "llvm/Support/YAMLParser.h" | |
16 | #include "gtest/gtest.h" | |
17 | ||
18 | namespace llvm { | |
19 | ||
20 | static void SuppressDiagnosticsOutput(const SMDiagnostic &, void *) { | |
1a4d82fc | 21 | // Prevent SourceMgr from writing errors to stderr |
223e47cc LB |
22 | // to reduce noise in unit test runs. |
23 | } | |
24 | ||
970d7e83 LB |
25 | // Assumes Ctx is an SMDiagnostic where Diag can be stored. |
26 | static void CollectDiagnosticsOutput(const SMDiagnostic &Diag, void *Ctx) { | |
27 | SMDiagnostic* DiagOut = static_cast<SMDiagnostic*>(Ctx); | |
28 | *DiagOut = Diag; | |
29 | } | |
30 | ||
223e47cc LB |
31 | // Checks that the given input gives a parse error. Makes sure that an error |
32 | // text is available and the parse fails. | |
33 | static void ExpectParseError(StringRef Message, StringRef Input) { | |
34 | SourceMgr SM; | |
35 | yaml::Stream Stream(Input, SM); | |
36 | SM.setDiagHandler(SuppressDiagnosticsOutput); | |
37 | EXPECT_FALSE(Stream.validate()) << Message << ": " << Input; | |
38 | EXPECT_TRUE(Stream.failed()) << Message << ": " << Input; | |
39 | } | |
40 | ||
41 | // Checks that the given input can be parsed without error. | |
42 | static void ExpectParseSuccess(StringRef Message, StringRef Input) { | |
43 | SourceMgr SM; | |
44 | yaml::Stream Stream(Input, SM); | |
45 | EXPECT_TRUE(Stream.validate()) << Message << ": " << Input; | |
46 | } | |
47 | ||
48 | TEST(YAMLParser, ParsesEmptyArray) { | |
49 | ExpectParseSuccess("Empty array", "[]"); | |
50 | } | |
51 | ||
52 | TEST(YAMLParser, FailsIfNotClosingArray) { | |
53 | ExpectParseError("Not closing array", "["); | |
54 | ExpectParseError("Not closing array", " [ "); | |
55 | ExpectParseError("Not closing array", " [x"); | |
56 | } | |
57 | ||
58 | TEST(YAMLParser, ParsesEmptyArrayWithWhitespace) { | |
59 | ExpectParseSuccess("Array with spaces", " [ ] "); | |
60 | ExpectParseSuccess("All whitespaces", "\t\r\n[\t\n \t\r ]\t\r \n\n"); | |
61 | } | |
62 | ||
63 | TEST(YAMLParser, ParsesEmptyObject) { | |
64 | ExpectParseSuccess("Empty object", "[{}]"); | |
65 | } | |
66 | ||
67 | TEST(YAMLParser, ParsesObject) { | |
68 | ExpectParseSuccess("Object with an entry", "[{\"a\":\"/b\"}]"); | |
69 | } | |
70 | ||
71 | TEST(YAMLParser, ParsesMultipleKeyValuePairsInObject) { | |
72 | ExpectParseSuccess("Multiple key, value pairs", | |
73 | "[{\"a\":\"/b\",\"c\":\"d\",\"e\":\"f\"}]"); | |
74 | } | |
75 | ||
76 | TEST(YAMLParser, FailsIfNotClosingObject) { | |
77 | ExpectParseError("Missing close on empty", "[{]"); | |
78 | ExpectParseError("Missing close after pair", "[{\"a\":\"b\"]"); | |
79 | } | |
80 | ||
81 | TEST(YAMLParser, FailsIfMissingColon) { | |
82 | ExpectParseError("Missing colon between key and value", "[{\"a\"\"/b\"}]"); | |
83 | ExpectParseError("Missing colon between key and value", "[{\"a\" \"b\"}]"); | |
84 | } | |
85 | ||
86 | TEST(YAMLParser, FailsOnMissingQuote) { | |
87 | ExpectParseError("Missing open quote", "[{a\":\"b\"}]"); | |
88 | ExpectParseError("Missing closing quote", "[{\"a\":\"b}]"); | |
89 | } | |
90 | ||
91 | TEST(YAMLParser, ParsesEscapedQuotes) { | |
92 | ExpectParseSuccess("Parses escaped string in key and value", | |
93 | "[{\"a\":\"\\\"b\\\" \\\" \\\"\"}]"); | |
94 | } | |
95 | ||
96 | TEST(YAMLParser, ParsesEmptyString) { | |
97 | ExpectParseSuccess("Parses empty string in value", "[{\"a\":\"\"}]"); | |
98 | } | |
99 | ||
100 | TEST(YAMLParser, ParsesMultipleObjects) { | |
101 | ExpectParseSuccess( | |
102 | "Multiple objects in array", | |
103 | "[" | |
104 | " { \"a\" : \"b\" }," | |
105 | " { \"a\" : \"b\" }," | |
106 | " { \"a\" : \"b\" }" | |
107 | "]"); | |
108 | } | |
109 | ||
110 | TEST(YAMLParser, FailsOnMissingComma) { | |
111 | ExpectParseError( | |
112 | "Missing comma", | |
113 | "[" | |
114 | " { \"a\" : \"b\" }" | |
115 | " { \"a\" : \"b\" }" | |
116 | "]"); | |
117 | } | |
118 | ||
119 | TEST(YAMLParser, ParsesSpacesInBetweenTokens) { | |
120 | ExpectParseSuccess( | |
121 | "Various whitespace between tokens", | |
122 | " \t \n\n \r [ \t \n\n \r" | |
123 | " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :" | |
124 | " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r,\t \n\n \r" | |
125 | " \t \n\n \r { \t \n\n \r\"a\"\t \n\n \r :" | |
126 | " \t \n\n \r \"b\"\t \n\n \r } \t \n\n \r]\t \n\n \r"); | |
127 | } | |
128 | ||
129 | TEST(YAMLParser, ParsesArrayOfArrays) { | |
130 | ExpectParseSuccess("Array of arrays", "[[]]"); | |
131 | } | |
132 | ||
133 | TEST(YAMLParser, HandlesEndOfFileGracefully) { | |
134 | ExpectParseError("In string starting with EOF", "[\""); | |
135 | ExpectParseError("In string hitting EOF", "[\" "); | |
136 | ExpectParseError("In string escaping EOF", "[\" \\"); | |
137 | ExpectParseError("In array starting with EOF", "["); | |
138 | ExpectParseError("In array element starting with EOF", "[[], "); | |
139 | ExpectParseError("In array hitting EOF", "[[] "); | |
140 | ExpectParseError("In array hitting EOF", "[[]"); | |
141 | ExpectParseError("In object hitting EOF", "{\"\""); | |
142 | } | |
143 | ||
144 | // Checks that the given string can be parsed into an identical string inside | |
145 | // of an array. | |
146 | static void ExpectCanParseString(StringRef String) { | |
147 | std::string StringInArray = (llvm::Twine("[\"") + String + "\"]").str(); | |
148 | SourceMgr SM; | |
149 | yaml::Stream Stream(StringInArray, SM); | |
150 | yaml::SequenceNode *ParsedSequence | |
151 | = dyn_cast<yaml::SequenceNode>(Stream.begin()->getRoot()); | |
152 | StringRef ParsedString | |
153 | = dyn_cast<yaml::ScalarNode>( | |
154 | static_cast<yaml::Node*>(ParsedSequence->begin()))->getRawValue(); | |
155 | ParsedString = ParsedString.substr(1, ParsedString.size() - 2); | |
156 | EXPECT_EQ(String, ParsedString.str()); | |
157 | } | |
158 | ||
159 | // Checks that parsing the given string inside an array fails. | |
160 | static void ExpectCannotParseString(StringRef String) { | |
161 | std::string StringInArray = (llvm::Twine("[\"") + String + "\"]").str(); | |
162 | ExpectParseError((Twine("When parsing string \"") + String + "\"").str(), | |
163 | StringInArray); | |
164 | } | |
165 | ||
166 | TEST(YAMLParser, ParsesStrings) { | |
167 | ExpectCanParseString(""); | |
168 | ExpectCannotParseString("\\"); | |
169 | ExpectCannotParseString("\""); | |
170 | ExpectCanParseString(" "); | |
171 | ExpectCanParseString("\\ "); | |
172 | ExpectCanParseString("\\\""); | |
173 | ExpectCannotParseString("\"\\"); | |
174 | ExpectCannotParseString(" \\"); | |
175 | ExpectCanParseString("\\\\"); | |
176 | ExpectCannotParseString("\\\\\\"); | |
177 | ExpectCanParseString("\\\\\\\\"); | |
178 | ExpectCanParseString("\\\" "); | |
179 | ExpectCannotParseString("\\\\\" "); | |
180 | ExpectCanParseString("\\\\\\\" "); | |
181 | ExpectCanParseString(" \\\\ \\\" \\\\\\\" "); | |
182 | } | |
183 | ||
184 | TEST(YAMLParser, WorksWithIteratorAlgorithms) { | |
185 | SourceMgr SM; | |
186 | yaml::Stream Stream("[\"1\", \"2\", \"3\", \"4\", \"5\", \"6\"]", SM); | |
187 | yaml::SequenceNode *Array | |
188 | = dyn_cast<yaml::SequenceNode>(Stream.begin()->getRoot()); | |
189 | EXPECT_EQ(6, std::distance(Array->begin(), Array->end())); | |
190 | } | |
191 | ||
970d7e83 LB |
192 | TEST(YAMLParser, DefaultDiagnosticFilename) { |
193 | SourceMgr SM; | |
194 | ||
195 | SMDiagnostic GeneratedDiag; | |
196 | SM.setDiagHandler(CollectDiagnosticsOutput, &GeneratedDiag); | |
197 | ||
198 | // When we construct a YAML stream over an unnamed string, | |
199 | // the filename is hard-coded as "YAML". | |
200 | yaml::Stream UnnamedStream("[]", SM); | |
201 | UnnamedStream.printError(UnnamedStream.begin()->getRoot(), "Hello, World!"); | |
202 | EXPECT_EQ("YAML", GeneratedDiag.getFilename()); | |
203 | } | |
204 | ||
205 | TEST(YAMLParser, DiagnosticFilenameFromBufferID) { | |
206 | SourceMgr SM; | |
207 | ||
208 | SMDiagnostic GeneratedDiag; | |
209 | SM.setDiagHandler(CollectDiagnosticsOutput, &GeneratedDiag); | |
210 | ||
211 | // When we construct a YAML stream over a named buffer, | |
212 | // we get its ID as filename in diagnostics. | |
1a4d82fc JJ |
213 | std::unique_ptr<MemoryBuffer> Buffer = |
214 | MemoryBuffer::getMemBuffer("[]", "buffername.yaml"); | |
215 | yaml::Stream Stream(Buffer->getMemBufferRef(), SM); | |
970d7e83 LB |
216 | Stream.printError(Stream.begin()->getRoot(), "Hello, World!"); |
217 | EXPECT_EQ("buffername.yaml", GeneratedDiag.getFilename()); | |
218 | } | |
219 | ||
223e47cc | 220 | } // end namespace llvm |