blob: 7753c154100f2b8131549290b8a10ec5d113bd09 [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"
14#include "clang/Tooling/CompilationDatabase.h"
15#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 Klimekcb971c62012-04-04 12:07:46 +000041static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
42 StringRef JSONDatabase,
43 std::string &ErrorMessage) {
44 llvm::OwningPtr<CompilationDatabase> Database(
45 JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
46 if (!Database)
47 return CompileCommand();
48 std::vector<CompileCommand> Commands = Database->getCompileCommands(FileName);
49 EXPECT_LE(Commands.size(), 1u);
50 if (Commands.empty())
51 return CompileCommand();
52 return Commands[0];
53}
54
55TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
56 std::string ErrorMessage;
57 CompileCommand NotFound = findCompileArgsInJsonDatabase(
58 "a-file.cpp", "", ErrorMessage);
59 EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
60 EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
61}
62
63TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
64 StringRef Directory("/some/directory");
65 StringRef FileName("/path/to/a-file.cpp");
66 StringRef Command("/path/to/compiler and some arguments");
67 std::string ErrorMessage;
68 CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
69 FileName,
70 ("[{\"directory\":\"" + Directory + "\"," +
71 "\"command\":\"" + Command + "\","
72 "\"file\":\"" + FileName + "\"}]").str(),
73 ErrorMessage);
74 EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
75 ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
76 EXPECT_EQ("/path/to/compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
77 EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
78 EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
79 EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
80
81 CompileCommand NotFound = findCompileArgsInJsonDatabase(
82 "a-file.cpp",
83 ("[{\"directory\":\"" + Directory + "\"," +
84 "\"command\":\"" + Command + "\","
85 "\"file\":\"" + FileName + "\"}]").str(),
86 ErrorMessage);
87 EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
88 EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
89}
90
91TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
92 StringRef Directory("/some/directory");
93 StringRef FileName("/path/to/a-file.cpp");
94 StringRef Command("\\\"/path to compiler\\\" \\\"and an argument\\\"");
95 std::string ErrorMessage;
96 CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
97 FileName,
98 ("[{\"directory\":\"" + Directory + "\"," +
99 "\"command\":\"" + Command + "\","
100 "\"file\":\"" + FileName + "\"}]").str(),
101 ErrorMessage);
102 ASSERT_EQ(2u, FoundCommand.CommandLine.size());
103 EXPECT_EQ("/path to compiler", FoundCommand.CommandLine[0]) << ErrorMessage;
104 EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
105}
106
107TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
108 StringRef Directory("/some directory / with spaces");
109 StringRef FileName("/path/to/a-file.cpp");
110 StringRef Command("a command");
111 std::string ErrorMessage;
112 CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
113 FileName,
114 ("[{\"directory\":\"" + Directory + "\"," +
115 "\"command\":\"" + Command + "\","
116 "\"file\":\"" + FileName + "\"}]").str(),
117 ErrorMessage);
118 EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
119}
120
121TEST(findCompileArgsInJsonDatabase, FindsEntry) {
122 StringRef Directory("directory");
123 StringRef FileName("file");
124 StringRef Command("command");
125 std::string JsonDatabase = "[";
126 for (int I = 0; I < 10; ++I) {
127 if (I > 0) JsonDatabase += ",";
128 JsonDatabase +=
129 ("{\"directory\":\"" + Directory + Twine(I) + "\"," +
130 "\"command\":\"" + Command + Twine(I) + "\","
131 "\"file\":\"" + FileName + Twine(I) + "\"}").str();
132 }
133 JsonDatabase += "]";
134 std::string ErrorMessage;
135 CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
136 "file4", JsonDatabase, ErrorMessage);
137 EXPECT_EQ("directory4", FoundCommand.Directory) << ErrorMessage;
138 ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
139 EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
140}
141
142static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
143 std::string JsonDatabase =
144 ("[{\"directory\":\"\", \"file\":\"test\", \"command\": \"" +
145 Command + "\"}]").str();
146 std::string ErrorMessage;
147 CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
148 "test", JsonDatabase, ErrorMessage);
149 EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage;
150 return FoundCommand.CommandLine;
151}
152
153TEST(unescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
154 std::vector<std::string> Result = unescapeJsonCommandLine("");
155 EXPECT_TRUE(Result.empty());
156}
157
158TEST(unescapeJsonCommandLine, SplitsOnSpaces) {
159 std::vector<std::string> Result = unescapeJsonCommandLine("a b c");
160 ASSERT_EQ(3ul, Result.size());
161 EXPECT_EQ("a", Result[0]);
162 EXPECT_EQ("b", Result[1]);
163 EXPECT_EQ("c", Result[2]);
164}
165
166TEST(unescapeJsonCommandLine, MungesMultipleSpaces) {
167 std::vector<std::string> Result = unescapeJsonCommandLine(" a b ");
168 ASSERT_EQ(2ul, Result.size());
169 EXPECT_EQ("a", Result[0]);
170 EXPECT_EQ("b", Result[1]);
171}
172
173TEST(unescapeJsonCommandLine, UnescapesBackslashCharacters) {
174 std::vector<std::string> Backslash = unescapeJsonCommandLine("a\\\\\\\\");
175 ASSERT_EQ(1ul, Backslash.size());
176 EXPECT_EQ("a\\", Backslash[0]);
177 std::vector<std::string> Quote = unescapeJsonCommandLine("a\\\\\\\"");
178 ASSERT_EQ(1ul, Quote.size());
179 EXPECT_EQ("a\"", Quote[0]);
180}
181
182TEST(unescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
183 std::vector<std::string> Result = unescapeJsonCommandLine("\\\" a b \\\"");
184 ASSERT_EQ(1ul, Result.size());
185 EXPECT_EQ(" a b ", Result[0]);
186}
187
188TEST(unescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
189 std::vector<std::string> Result = unescapeJsonCommandLine(
190 " \\\" a \\\" \\\" b \\\" ");
191 ASSERT_EQ(2ul, Result.size());
192 EXPECT_EQ(" a ", Result[0]);
193 EXPECT_EQ(" b ", Result[1]);
194}
195
196TEST(unescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
197 std::vector<std::string> Result = unescapeJsonCommandLine(
198 "\\\"\\\"\\\"\\\"");
199 ASSERT_EQ(1ul, Result.size());
200 EXPECT_TRUE(Result[0].empty()) << Result[0];
201}
202
203TEST(unescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
204 std::vector<std::string> Result = unescapeJsonCommandLine(
205 "\\\"\\\\\\\"\\\"");
206 ASSERT_EQ(1ul, Result.size());
207 EXPECT_EQ("\"", Result[0]);
208}
209
210TEST(unescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
211 std::vector<std::string> Result = unescapeJsonCommandLine(
212 " \\\\\\\" \\\"a \\\\\\\" b \\\" \\\"and\\\\\\\\c\\\" \\\\\\\"");
213 ASSERT_EQ(4ul, Result.size());
214 EXPECT_EQ("\"", Result[0]);
215 EXPECT_EQ("a \" b ", Result[1]);
216 EXPECT_EQ("and\\c", Result[2]);
217 EXPECT_EQ("\"", Result[3]);
218}
219
220TEST(unescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
221 std::vector<std::string> QuotedNoSpaces = unescapeJsonCommandLine(
222 "\\\"a\\\"\\\"b\\\"");
223 ASSERT_EQ(1ul, QuotedNoSpaces.size());
224 EXPECT_EQ("ab", QuotedNoSpaces[0]);
225
226 std::vector<std::string> MixedNoSpaces = unescapeJsonCommandLine(
227 "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
228 ASSERT_EQ(1ul, MixedNoSpaces.size());
229 EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
230}
231
232TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
233 std::vector<std::string> Unclosed = unescapeJsonCommandLine("\\\"abc");
234 ASSERT_EQ(1ul, Unclosed.size());
235 EXPECT_EQ("abc", Unclosed[0]);
236
237 std::vector<std::string> Empty = unescapeJsonCommandLine("\\\"");
238 ASSERT_EQ(1ul, Empty.size());
239 EXPECT_EQ("", Empty[0]);
240}
241
Manuel Klimek30318e62012-04-18 07:41:50 +0000242TEST(FixedCompilationDatabase, ReturnsFixedCommandLine) {
243 std::vector<std::string> CommandLine;
244 CommandLine.push_back("one");
245 CommandLine.push_back("two");
246 FixedCompilationDatabase Database(".", CommandLine);
247 std::vector<CompileCommand> Result =
248 Database.getCompileCommands("source");
249 ASSERT_EQ(1ul, Result.size());
250 std::vector<std::string> ExpectedCommandLine(1, "clang-tool");
251 ExpectedCommandLine.insert(ExpectedCommandLine.end(),
252 CommandLine.begin(), CommandLine.end());
253 ExpectedCommandLine.push_back("source");
254 EXPECT_EQ(".", Result[0].Directory);
255 EXPECT_EQ(ExpectedCommandLine, Result[0].CommandLine);
256}
257
258TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) {
259 int Argc = 0;
260 llvm::OwningPtr<FixedCompilationDatabase> Database(
261 FixedCompilationDatabase::loadFromCommandLine(Argc, NULL));
262 EXPECT_FALSE(Database);
263 EXPECT_EQ(0, Argc);
264}
265
266TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
267 int Argc = 2;
268 const char *Argv[] = { "1", "2" };
269 llvm::OwningPtr<FixedCompilationDatabase> Database(
270 FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
271 EXPECT_FALSE(Database);
272 EXPECT_EQ(2, Argc);
273}
274
275TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
276 int Argc = 5;
277 const char *Argv[] = { "1", "2", "--\0no-constant-folding", "3", "4" };
278 llvm::OwningPtr<FixedCompilationDatabase> Database(
279 FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
280 ASSERT_TRUE(Database);
281 std::vector<CompileCommand> Result =
282 Database->getCompileCommands("source");
283 ASSERT_EQ(1ul, Result.size());
284 ASSERT_EQ(".", Result[0].Directory);
285 std::vector<std::string> CommandLine;
286 CommandLine.push_back("clang-tool");
287 CommandLine.push_back("3");
288 CommandLine.push_back("4");
289 CommandLine.push_back("source");
290 ASSERT_EQ(CommandLine, Result[0].CommandLine);
291 EXPECT_EQ(2, Argc);
292}
293
294TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
295 int Argc = 3;
296 const char *Argv[] = { "1", "2", "--\0no-constant-folding" };
297 llvm::OwningPtr<FixedCompilationDatabase> Database(
298 FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
299 ASSERT_TRUE(Database);
300 std::vector<CompileCommand> Result =
301 Database->getCompileCommands("source");
302 ASSERT_EQ(1ul, Result.size());
303 ASSERT_EQ(".", Result[0].Directory);
304 std::vector<std::string> CommandLine;
305 CommandLine.push_back("clang-tool");
306 CommandLine.push_back("source");
307 ASSERT_EQ(CommandLine, Result[0].CommandLine);
308 EXPECT_EQ(2, Argc);
309}
310
Manuel Klimekcb971c62012-04-04 12:07:46 +0000311} // end namespace tooling
312} // end namespace clang