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" 13 #include "llvm/Support/MemoryBuffer.h" 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 *) { 21 // Prevent SourceMgr from writing errors to stderr 22 // to reduce noise in unit test runs. 23 } 24 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 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 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. 213 MemoryBuffer* Buffer = MemoryBuffer::getMemBuffer("[]", "buffername.yaml"); 214 yaml::Stream Stream(Buffer, SM); 215 Stream.printError(Stream.begin()->getRoot(), "Hello, World!"); 216 EXPECT_EQ("buffername.yaml", GeneratedDiag.getFilename()); 217 } 218 219 } // end namespace llvm 220