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