blob: 560b931718a334fff24b63577083e4ad28a91305 [file] [log] [blame]
Manuel Klimekcb971c62012-04-04 12:07:46 +00001//===- 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"
Daniel Jasper7fd90b02012-08-24 05:50:27 +000014#include "clang/Tooling/JSONCompilationDatabase.h"
Manuel Klimekcb971c62012-04-04 12:07:46 +000015#include "clang/Tooling/Tooling.h"
16#include "gtest/gtest.h"
17
18namespace clang {
19namespace tooling {
20
Manuel Klimek1a8d6862012-05-15 11:46:07 +000021static 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
28TEST(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
Manuel Klimeka3c70962012-07-13 12:31:45 +000041static 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
52TEST(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
Manuel Klimekcb971c62012-04-04 12:07:46 +000070static 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
84TEST(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
92TEST(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
120TEST(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
136TEST(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
150TEST(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
171static 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
182TEST(unescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
183 std::vector<std::string> Result = unescapeJsonCommandLine("");
184 EXPECT_TRUE(Result.empty());
185}
186
187TEST(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
195TEST(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
202TEST(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
211TEST(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
217TEST(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
225TEST(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
232TEST(unescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
233 std::vector<std::string> Result = unescapeJsonCommandLine(
234 "\\\"\\\\\\\"\\\"");
235 ASSERT_EQ(1ul, Result.size());
236 EXPECT_EQ("\"", Result[0]);
237}
238
239TEST(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
249TEST(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
261TEST(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
Manuel Klimek30318e62012-04-18 07:41:50 +0000271TEST(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
Manuel Klimeka3c70962012-07-13 12:31:45 +0000287TEST(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
Manuel Klimek30318e62012-04-18 07:41:50 +0000296TEST(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
304TEST(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
313TEST(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
332TEST(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
Manuel Klimekcb971c62012-04-04 12:07:46 +0000349} // end namespace tooling
350} // end namespace clang