]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - unittests/Tooling/CompilationDatabaseTest.cpp
Vendor import of clang trunk r161861:
[FreeBSD/FreeBSD.git] / unittests / Tooling / CompilationDatabaseTest.cpp
1 //===- unittest/Tooling/CompilationDatabaseTest.cpp -----------------------===//
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 "clang/AST/ASTConsumer.h"
11 #include "clang/AST/DeclCXX.h"
12 #include "clang/AST/DeclGroup.h"
13 #include "clang/Frontend/FrontendAction.h"
14 #include "clang/Tooling/CompilationDatabase.h"
15 #include "clang/Tooling/Tooling.h"
16 #include "gtest/gtest.h"
17
18 namespace clang {
19 namespace tooling {
20
21 static void expectFailure(StringRef JSONDatabase, StringRef Explanation) {
22   std::string ErrorMessage;
23   EXPECT_EQ(NULL, JSONCompilationDatabase::loadFromBuffer(JSONDatabase,
24                                                           ErrorMessage))
25     << "Expected an error because of: " << Explanation;
26 }
27
28 TEST(JSONCompilationDatabase, ErrsOnInvalidFormat) {
29   expectFailure("", "Empty database");
30   expectFailure("{", "Invalid JSON");
31   expectFailure("[[]]", "Array instead of object");
32   expectFailure("[{\"a\":[]}]", "Array instead of value");
33   expectFailure("[{\"a\":\"b\"}]", "Unknown key");
34   expectFailure("[{[]:\"\"}]", "Incorrectly typed entry");
35   expectFailure("[{}]", "Empty entry");
36   expectFailure("[{\"directory\":\"\",\"command\":\"\"}]", "Missing file");
37   expectFailure("[{\"directory\":\"\",\"file\":\"\"}]", "Missing command");
38   expectFailure("[{\"command\":\"\",\"file\":\"\"}]", "Missing directory");
39 }
40
41 static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
42                                             std::string &ErrorMessage) {
43   llvm::OwningPtr<CompilationDatabase> Database(
44       JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
45   if (!Database) {
46     ADD_FAILURE() << ErrorMessage;
47     return std::vector<std::string>();
48   }
49   return Database->getAllFiles();
50 }
51
52 TEST(JSONCompilationDatabase, GetAllFiles) {
53   std::string ErrorMessage;
54   EXPECT_EQ(std::vector<std::string>(),
55             getAllFiles("[]", ErrorMessage)) << ErrorMessage;
56
57   std::vector<std::string> expected_files;
58   expected_files.push_back("file1");
59   expected_files.push_back("file2");
60   EXPECT_EQ(expected_files, getAllFiles(
61     "[{\"directory\":\"dir\","
62       "\"command\":\"command\","
63       "\"file\":\"file1\"},"
64     " {\"directory\":\"dir\","
65       "\"command\":\"command\","
66       "\"file\":\"file2\"}]",
67     ErrorMessage)) << ErrorMessage;
68 }
69
70 static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
71                                                     StringRef JSONDatabase,
72                                                     std::string &ErrorMessage) {
73   llvm::OwningPtr<CompilationDatabase> Database(
74       JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
75   if (!Database)
76     return CompileCommand();
77   std::vector<CompileCommand> Commands = Database->getCompileCommands(FileName);
78   EXPECT_LE(Commands.size(), 1u);
79   if (Commands.empty())
80     return CompileCommand();
81   return Commands[0];
82 }
83
84 TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
85   std::string ErrorMessage;
86   CompileCommand NotFound = findCompileArgsInJsonDatabase(
87     "a-file.cpp", "", ErrorMessage);
88   EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
89   EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
90 }
91
92 TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
93   StringRef Directory("/some/directory");
94   StringRef FileName("/path/to/a-file.cpp");
95   StringRef Command("/path/to/compiler and some arguments");
96   std::string ErrorMessage;
97   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
98     FileName,
99     ("[{\"directory\":\"" + Directory + "\"," +
100        "\"command\":\"" + Command + "\","
101        "\"file\":\"" + FileName + "\"}]").str(),
102     ErrorMessage);
103   EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
104   ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
105   EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
106   EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
107   EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
108   EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
109
110   CompileCommand NotFound = findCompileArgsInJsonDatabase(
111     "a-file.cpp",
112     ("[{\"directory\":\"" + Directory + "\"," +
113        "\"command\":\"" + Command + "\","
114        "\"file\":\"" + FileName + "\"}]").str(),
115     ErrorMessage);
116   EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
117   EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
118 }
119
120 TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
121   StringRef Directory("/some/directory");
122   StringRef FileName("/path/to/a-file.cpp");
123   StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\"");
124   std::string ErrorMessage;
125   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
126     FileName,
127     ("[{\"directory\":\"" + Directory + "\"," +
128        "\"command\":\"" + Command + "\","
129        "\"file\":\"" + FileName + "\"}]").str(),
130     ErrorMessage);
131   ASSERT_EQ(2u, FoundCommand.CommandLine.size());
132   EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
133   EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
134 }
135
136 TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
137   StringRef Directory("/some directory / with spaces");
138   StringRef FileName("/path/to/a-file.cpp");
139   StringRef Command("a command");
140   std::string ErrorMessage;
141   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
142     FileName,
143     ("[{\"directory\":\"" + Directory + "\"," +
144        "\"command\":\"" + Command + "\","
145        "\"file\":\"" + FileName + "\"}]").str(),
146     ErrorMessage);
147   EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
148 }
149
150 TEST(findCompileArgsInJsonDatabase, FindsEntry) {
151   StringRef Directory("directory");
152   StringRef FileName("file");
153   StringRef Command("command");
154   std::string JsonDatabase = "[";
155   for (int I = 0; I < 10; ++I) {
156     if (I > 0) JsonDatabase += ",";
157     JsonDatabase +=
158       ("{\"directory\":\"" + Directory + Twine(I) + "\"," +
159         "\"command\":\"" + Command + Twine(I) + "\","
160         "\"file\":\"" + FileName + Twine(I) + "\"}").str();
161   }
162   JsonDatabase += "]";
163   std::string ErrorMessage;
164   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
165     "file4", JsonDatabase, ErrorMessage);
166   EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
167   ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
168   EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
169 }
170
171 static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
172   std::string JsonDatabase =
173     ("[{\"directory\":\"\", \"file\":\"test\", \"command\": \"" +
174      Command + "\"}]").str();
175   std::string ErrorMessage;
176   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
177     "test", JsonDatabase, ErrorMessage);
178   EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage;
179   return FoundCommand.CommandLine;
180 }
181
182 TEST(unescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
183   std::vector<std::string> Result = unescapeJsonCommandLine("");
184   EXPECT_TRUE(Result.empty());
185 }
186
187 TEST(unescapeJsonCommandLine, SplitsOnSpaces) {
188   std::vector<std::string> Result = unescapeJsonCommandLine("a b c");
189   ASSERT_EQ(3ul, Result.size());
190   EXPECT_EQ("a", Result[0]);
191   EXPECT_EQ("b", Result[1]);
192   EXPECT_EQ("c", Result[2]);
193 }
194
195 TEST(unescapeJsonCommandLine, MungesMultipleSpaces) {
196   std::vector<std::string> Result = unescapeJsonCommandLine("   a   b   ");
197   ASSERT_EQ(2ul, Result.size());
198   EXPECT_EQ("a", Result[0]);
199   EXPECT_EQ("b", Result[1]);
200 }
201
202 TEST(unescapeJsonCommandLine, UnescapesBackslashCharacters) {
203   std::vector<std::string> Backslash = unescapeJsonCommandLine("a\\\\\\\\");
204   ASSERT_EQ(1ul, Backslash.size());
205   EXPECT_EQ("a\\", Backslash[0]);
206   std::vector<std::string> Quote = unescapeJsonCommandLine("a\\\\\\\"");
207   ASSERT_EQ(1ul, Quote.size());
208   EXPECT_EQ("a\"", Quote[0]);
209 }
210
211 TEST(unescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
212   std::vector<std::string> Result = unescapeJsonCommandLine("\\\"  a  b  \\\"");
213   ASSERT_EQ(1ul, Result.size());
214   EXPECT_EQ("  a  b  ", Result[0]);
215 }
216
217 TEST(unescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
218   std::vector<std::string> Result = unescapeJsonCommandLine(
219       "  \\\" a \\\"  \\\" b \\\"  ");
220   ASSERT_EQ(2ul, Result.size());
221   EXPECT_EQ(" a ", Result[0]);
222   EXPECT_EQ(" b ", Result[1]);
223 }
224
225 TEST(unescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
226   std::vector<std::string> Result = unescapeJsonCommandLine(
227       "\\\"\\\"\\\"\\\"");
228   ASSERT_EQ(1ul, Result.size());
229   EXPECT_TRUE(Result[0].empty()) << Result[0];
230 }
231
232 TEST(unescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
233   std::vector<std::string> Result = unescapeJsonCommandLine(
234       "\\\"\\\\\\\"\\\"");
235   ASSERT_EQ(1ul, Result.size());
236   EXPECT_EQ("\"", Result[0]);
237 }
238
239 TEST(unescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
240   std::vector<std::string> Result = unescapeJsonCommandLine(
241       "  \\\\\\\"  \\\"a \\\\\\\" b \\\"     \\\"and\\\\\\\\c\\\"   \\\\\\\"");
242   ASSERT_EQ(4ul, Result.size());
243   EXPECT_EQ("\"", Result[0]);
244   EXPECT_EQ("a \" b ", Result[1]);
245   EXPECT_EQ("and\\c", Result[2]);
246   EXPECT_EQ("\"", Result[3]);
247 }
248
249 TEST(unescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
250   std::vector<std::string> QuotedNoSpaces = unescapeJsonCommandLine(
251       "\\\"a\\\"\\\"b\\\"");
252   ASSERT_EQ(1ul, QuotedNoSpaces.size());
253   EXPECT_EQ("ab", QuotedNoSpaces[0]);
254
255   std::vector<std::string> MixedNoSpaces = unescapeJsonCommandLine(
256       "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
257   ASSERT_EQ(1ul, MixedNoSpaces.size());
258   EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
259 }
260
261 TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
262   std::vector<std::string> Unclosed = unescapeJsonCommandLine("\\\"abc");
263   ASSERT_EQ(1ul, Unclosed.size());
264   EXPECT_EQ("abc", Unclosed[0]);
265
266   std::vector<std::string> Empty = unescapeJsonCommandLine("\\\"");
267   ASSERT_EQ(1ul, Empty.size());
268   EXPECT_EQ("", Empty[0]);
269 }
270
271 TEST(FixedCompilationDatabase, ReturnsFixedCommandLine) {
272   std::vector<std::string> CommandLine;
273   CommandLine.push_back("one");
274   CommandLine.push_back("two");
275   FixedCompilationDatabase Database(".", CommandLine);
276   std::vector<CompileCommand> Result =
277     Database.getCompileCommands("source");
278   ASSERT_EQ(1ul, Result.size());
279   std::vector<std::string> ExpectedCommandLine(1, "clang-tool");
280   ExpectedCommandLine.insert(ExpectedCommandLine.end(),
281                              CommandLine.begin(), CommandLine.end());
282   ExpectedCommandLine.push_back("source");
283   EXPECT_EQ(".", Result[0].Directory);
284   EXPECT_EQ(ExpectedCommandLine, Result[0].CommandLine);
285 }
286
287 TEST(FixedCompilationDatabase, GetAllFiles) {
288   std::vector<std::string> CommandLine;
289   CommandLine.push_back("one");
290   CommandLine.push_back("two");
291   FixedCompilationDatabase Database(".", CommandLine);
292
293   EXPECT_EQ(0ul, Database.getAllFiles().size());
294 }
295
296 TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) {
297   int Argc = 0;
298   llvm::OwningPtr<FixedCompilationDatabase> Database(
299       FixedCompilationDatabase::loadFromCommandLine(Argc, NULL));
300   EXPECT_FALSE(Database);
301   EXPECT_EQ(0, Argc);
302 }
303
304 TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
305   int Argc = 2;
306   const char *Argv[] = { "1", "2" };
307   llvm::OwningPtr<FixedCompilationDatabase> Database(
308       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
309   EXPECT_FALSE(Database);
310   EXPECT_EQ(2, Argc);
311 }
312
313 TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
314   int Argc = 5;
315   const char *Argv[] = { "1", "2", "--\0no-constant-folding", "3", "4" };
316   llvm::OwningPtr<FixedCompilationDatabase> Database(
317       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
318   ASSERT_TRUE(Database);
319   std::vector<CompileCommand> Result =
320     Database->getCompileCommands("source");
321   ASSERT_EQ(1ul, Result.size());
322   ASSERT_EQ(".", Result[0].Directory);
323   std::vector<std::string> CommandLine;
324   CommandLine.push_back("clang-tool");
325   CommandLine.push_back("3");
326   CommandLine.push_back("4");
327   CommandLine.push_back("source");
328   ASSERT_EQ(CommandLine, Result[0].CommandLine);
329   EXPECT_EQ(2, Argc);
330 }
331
332 TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
333   int Argc = 3;
334   const char *Argv[] = { "1", "2", "--\0no-constant-folding" };
335   llvm::OwningPtr<FixedCompilationDatabase> Database(
336       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
337   ASSERT_TRUE(Database);
338   std::vector<CompileCommand> Result =
339     Database->getCompileCommands("source");
340   ASSERT_EQ(1ul, Result.size());
341   ASSERT_EQ(".", Result[0].Directory);
342   std::vector<std::string> CommandLine;
343   CommandLine.push_back("clang-tool");
344   CommandLine.push_back("source");
345   ASSERT_EQ(CommandLine, Result[0].CommandLine);
346   EXPECT_EQ(2, Argc);
347 }
348
349 } // end namespace tooling
350 } // end namespace clang