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/FileMatchTrie.h"
15 #include "clang/Tooling/JSONCompilationDatabase.h"
16 #include "clang/Tooling/Tooling.h"
17 #include "llvm/Support/Path.h"
18 #include "gtest/gtest.h"
19 
20 namespace clang {
21 namespace tooling {
22 
23 static void expectFailure(StringRef JSONDatabase, StringRef Explanation) {
24   std::string ErrorMessage;
25   EXPECT_EQ(nullptr, JSONCompilationDatabase::loadFromBuffer(JSONDatabase,
26                                                              ErrorMessage))
27     << "Expected an error because of: " << Explanation.str();
28 }
29 
30 TEST(JSONCompilationDatabase, ErrsOnInvalidFormat) {
31   expectFailure("", "Empty database");
32   expectFailure("{", "Invalid JSON");
33   expectFailure("[[]]", "Array instead of object");
34   expectFailure("[{\"a\":[]}]", "Array instead of value");
35   expectFailure("[{\"a\":\"b\"}]", "Unknown key");
36   expectFailure("[{[]:\"\"}]", "Incorrectly typed entry");
37   expectFailure("[{}]", "Empty entry");
38   expectFailure("[{\"directory\":\"\",\"command\":\"\"}]", "Missing file");
39   expectFailure("[{\"directory\":\"\",\"file\":\"\"}]", "Missing command or arguments");
40   expectFailure("[{\"command\":\"\",\"file\":\"\"}]", "Missing directory");
41   expectFailure("[{\"directory\":\"\",\"arguments\":[]}]", "Missing file");
42   expectFailure("[{\"arguments\":\"\",\"file\":\"\"}]", "Missing directory");
43   expectFailure("[{\"directory\":\"\",\"arguments\":\"\",\"file\":\"\"}]", "Arguments not array");
44   expectFailure("[{\"directory\":\"\",\"command\":[],\"file\":\"\"}]", "Command not string");
45 }
46 
47 static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
48                                             std::string &ErrorMessage) {
49   std::unique_ptr<CompilationDatabase> Database(
50       JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
51   if (!Database) {
52     ADD_FAILURE() << ErrorMessage;
53     return std::vector<std::string>();
54   }
55   return Database->getAllFiles();
56 }
57 
58 static std::vector<CompileCommand> getAllCompileCommands(StringRef JSONDatabase,
59                                                     std::string &ErrorMessage) {
60   std::unique_ptr<CompilationDatabase> Database(
61       JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
62   if (!Database) {
63     ADD_FAILURE() << ErrorMessage;
64     return std::vector<CompileCommand>();
65   }
66   return Database->getAllCompileCommands();
67 }
68 
69 TEST(JSONCompilationDatabase, GetAllFiles) {
70   std::string ErrorMessage;
71   EXPECT_EQ(std::vector<std::string>(),
72             getAllFiles("[]", ErrorMessage)) << ErrorMessage;
73 
74   std::vector<std::string> expected_files;
75   SmallString<16> PathStorage;
76   llvm::sys::path::native("//net/dir/file1", PathStorage);
77   expected_files.push_back(PathStorage.str());
78   llvm::sys::path::native("//net/dir/file2", PathStorage);
79   expected_files.push_back(PathStorage.str());
80   EXPECT_EQ(expected_files, getAllFiles(
81     "[{\"directory\":\"//net/dir\","
82       "\"command\":\"command\","
83       "\"file\":\"file1\"},"
84     " {\"directory\":\"//net/dir\","
85       "\"command\":\"command\","
86       "\"file\":\"file2\"}]",
87     ErrorMessage)) << ErrorMessage;
88 }
89 
90 TEST(JSONCompilationDatabase, GetAllCompileCommands) {
91   std::string ErrorMessage;
92   EXPECT_EQ(0u,
93             getAllCompileCommands("[]", ErrorMessage).size()) << ErrorMessage;
94 
95   StringRef Directory1("//net/dir1");
96   StringRef FileName1("file1");
97   StringRef Command1("command1");
98   StringRef Directory2("//net/dir2");
99   StringRef FileName2("file1");
100   StringRef Command2("command1");
101 
102   std::vector<CompileCommand> Commands = getAllCompileCommands(
103       ("[{\"directory\":\"" + Directory1 + "\"," +
104              "\"command\":\"" + Command1 + "\","
105              "\"file\":\"" + FileName1 + "\"},"
106        " {\"directory\":\"" + Directory2 + "\"," +
107              "\"command\":\"" + Command2 + "\","
108              "\"file\":\"" + FileName2 + "\"}]").str(),
109       ErrorMessage);
110   EXPECT_EQ(2U, Commands.size()) << ErrorMessage;
111   EXPECT_EQ(Directory1, Commands[0].Directory) << ErrorMessage;
112   ASSERT_EQ(1u, Commands[0].CommandLine.size());
113   EXPECT_EQ(Command1, Commands[0].CommandLine[0]) << ErrorMessage;
114   EXPECT_EQ(Directory2, Commands[1].Directory) << ErrorMessage;
115   ASSERT_EQ(1u, Commands[1].CommandLine.size());
116   EXPECT_EQ(Command2, Commands[1].CommandLine[0]) << ErrorMessage;
117 }
118 
119 static CompileCommand findCompileArgsInJsonDatabase(StringRef FileName,
120                                                     StringRef JSONDatabase,
121                                                     std::string &ErrorMessage) {
122   std::unique_ptr<CompilationDatabase> Database(
123       JSONCompilationDatabase::loadFromBuffer(JSONDatabase, ErrorMessage));
124   if (!Database)
125     return CompileCommand();
126   std::vector<CompileCommand> Commands = Database->getCompileCommands(FileName);
127   EXPECT_LE(Commands.size(), 1u);
128   if (Commands.empty())
129     return CompileCommand();
130   return Commands[0];
131 }
132 
133 TEST(JSONCompilationDatabase, ArgumentsPreferredOverCommand) {
134    StringRef Directory("//net/dir");
135    StringRef FileName("//net/dir/filename");
136    StringRef Command("command");
137    StringRef Arguments = "arguments";
138    Twine ArgumentsAccumulate;
139    std::string ErrorMessage;
140    CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
141       FileName,
142       ("[{\"directory\":\"" + Directory + "\","
143          "\"command\":\"" + Command + "\","
144          "\"arguments\":[\"" + Arguments + "\"],"
145          "\"file\":\"" + FileName + "\"}]").str(),
146       ErrorMessage);
147    EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
148    EXPECT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
149    EXPECT_EQ(Arguments, FoundCommand.CommandLine[0]) << ErrorMessage;
150 }
151 
152 struct FakeComparator : public PathComparator {
153   ~FakeComparator() override {}
154   bool equivalent(StringRef FileA, StringRef FileB) const override {
155     return FileA.equals_lower(FileB);
156   }
157 };
158 
159 class FileMatchTrieTest : public ::testing::Test {
160 protected:
161   FileMatchTrieTest() : Trie(new FakeComparator()) {}
162 
163   StringRef find(StringRef Path) {
164     llvm::raw_string_ostream ES(Error);
165     return Trie.findEquivalent(Path, ES);
166   }
167 
168   FileMatchTrie Trie;
169   std::string Error;
170 };
171 
172 TEST_F(FileMatchTrieTest, InsertingRelativePath) {
173   Trie.insert("//net/path/file.cc");
174   Trie.insert("file.cc");
175   EXPECT_EQ("//net/path/file.cc", find("//net/path/file.cc"));
176 }
177 
178 TEST_F(FileMatchTrieTest, MatchingRelativePath) {
179   EXPECT_EQ("", find("file.cc"));
180 }
181 
182 TEST_F(FileMatchTrieTest, ReturnsBestResults) {
183   Trie.insert("//net/d/c/b.cc");
184   Trie.insert("//net/d/b/b.cc");
185   EXPECT_EQ("//net/d/b/b.cc", find("//net/d/b/b.cc"));
186 }
187 
188 TEST_F(FileMatchTrieTest, HandlesSymlinks) {
189   Trie.insert("//net/AA/file.cc");
190   EXPECT_EQ("//net/AA/file.cc", find("//net/aa/file.cc"));
191 }
192 
193 TEST_F(FileMatchTrieTest, ReportsSymlinkAmbiguity) {
194   Trie.insert("//net/Aa/file.cc");
195   Trie.insert("//net/aA/file.cc");
196   EXPECT_TRUE(find("//net/aa/file.cc").empty());
197   EXPECT_EQ("Path is ambiguous", Error);
198 }
199 
200 TEST_F(FileMatchTrieTest, LongerMatchingSuffixPreferred) {
201   Trie.insert("//net/src/Aa/file.cc");
202   Trie.insert("//net/src/aA/file.cc");
203   Trie.insert("//net/SRC/aa/file.cc");
204   EXPECT_EQ("//net/SRC/aa/file.cc", find("//net/src/aa/file.cc"));
205 }
206 
207 TEST_F(FileMatchTrieTest, EmptyTrie) {
208   EXPECT_TRUE(find("//net/some/path").empty());
209 }
210 
211 TEST_F(FileMatchTrieTest, NoResult) {
212   Trie.insert("//net/somepath/otherfile.cc");
213   Trie.insert("//net/otherpath/somefile.cc");
214   EXPECT_EQ("", find("//net/somepath/somefile.cc"));
215 }
216 
217 TEST_F(FileMatchTrieTest, RootElementDifferent) {
218   Trie.insert("//net/path/file.cc");
219   Trie.insert("//net/otherpath/file.cc");
220   EXPECT_EQ("//net/path/file.cc", find("//net/path/file.cc"));
221 }
222 
223 TEST_F(FileMatchTrieTest, CannotResolveRelativePath) {
224   EXPECT_EQ("", find("relative-path.cc"));
225   EXPECT_EQ("Cannot resolve relative paths", Error);
226 }
227 
228 TEST(findCompileArgsInJsonDatabase, FindsNothingIfEmpty) {
229   std::string ErrorMessage;
230   CompileCommand NotFound = findCompileArgsInJsonDatabase(
231     "a-file.cpp", "", ErrorMessage);
232   EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
233   EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
234 }
235 
236 TEST(findCompileArgsInJsonDatabase, ReadsSingleEntry) {
237   StringRef Directory("//net/some/directory");
238   StringRef FileName("//net/path/to/a-file.cpp");
239   StringRef Command("//net/path/to/compiler and some arguments");
240   std::string ErrorMessage;
241   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
242     FileName,
243     ("[{\"directory\":\"" + Directory + "\"," +
244        "\"command\":\"" + Command + "\","
245        "\"file\":\"" + FileName + "\"}]").str(),
246     ErrorMessage);
247   EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
248   ASSERT_EQ(4u, FoundCommand.CommandLine.size()) << ErrorMessage;
249   EXPECT_EQ("//net/path/to/compiler",
250             FoundCommand.CommandLine[0]) << ErrorMessage;
251   EXPECT_EQ("and", FoundCommand.CommandLine[1]) << ErrorMessage;
252   EXPECT_EQ("some", FoundCommand.CommandLine[2]) << ErrorMessage;
253   EXPECT_EQ("arguments", FoundCommand.CommandLine[3]) << ErrorMessage;
254 
255   CompileCommand NotFound = findCompileArgsInJsonDatabase(
256     "a-file.cpp",
257     ("[{\"directory\":\"" + Directory + "\"," +
258        "\"command\":\"" + Command + "\","
259        "\"file\":\"" + FileName + "\"}]").str(),
260     ErrorMessage);
261   EXPECT_TRUE(NotFound.Directory.empty()) << ErrorMessage;
262   EXPECT_TRUE(NotFound.CommandLine.empty()) << ErrorMessage;
263 }
264 
265 TEST(findCompileArgsInJsonDatabase, ReadsCompileCommandLinesWithSpaces) {
266   StringRef Directory("//net/some/directory");
267   StringRef FileName("//net/path/to/a-file.cpp");
268   StringRef Command("\\\"//net/path to compiler\\\" \\\"and an argument\\\"");
269   std::string ErrorMessage;
270   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
271     FileName,
272     ("[{\"directory\":\"" + Directory + "\"," +
273        "\"command\":\"" + Command + "\","
274        "\"file\":\"" + FileName + "\"}]").str(),
275     ErrorMessage);
276   ASSERT_EQ(2u, FoundCommand.CommandLine.size());
277   EXPECT_EQ("//net/path to compiler",
278             FoundCommand.CommandLine[0]) << ErrorMessage;
279   EXPECT_EQ("and an argument", FoundCommand.CommandLine[1]) << ErrorMessage;
280 }
281 
282 TEST(findCompileArgsInJsonDatabase, ReadsDirectoryWithSpaces) {
283   StringRef Directory("//net/some directory / with spaces");
284   StringRef FileName("//net/path/to/a-file.cpp");
285   StringRef Command("a command");
286   std::string ErrorMessage;
287   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
288     FileName,
289     ("[{\"directory\":\"" + Directory + "\"," +
290        "\"command\":\"" + Command + "\","
291        "\"file\":\"" + FileName + "\"}]").str(),
292     ErrorMessage);
293   EXPECT_EQ(Directory, FoundCommand.Directory) << ErrorMessage;
294 }
295 
296 TEST(findCompileArgsInJsonDatabase, FindsEntry) {
297   StringRef Directory("//net/directory");
298   StringRef FileName("file");
299   StringRef Command("command");
300   std::string JsonDatabase = "[";
301   for (int I = 0; I < 10; ++I) {
302     if (I > 0) JsonDatabase += ",";
303     JsonDatabase +=
304       ("{\"directory\":\"" + Directory + Twine(I) + "\"," +
305         "\"command\":\"" + Command + Twine(I) + "\","
306         "\"file\":\"" + FileName + Twine(I) + "\"}").str();
307   }
308   JsonDatabase += "]";
309   std::string ErrorMessage;
310   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
311     "//net/directory4/file4", JsonDatabase, ErrorMessage);
312   EXPECT_EQ("//net/directory4", FoundCommand.Directory) << ErrorMessage;
313   ASSERT_EQ(1u, FoundCommand.CommandLine.size()) << ErrorMessage;
314   EXPECT_EQ("command4", FoundCommand.CommandLine[0]) << ErrorMessage;
315 }
316 
317 static std::vector<std::string> unescapeJsonCommandLine(StringRef Command) {
318   std::string JsonDatabase =
319     ("[{\"directory\":\"//net/root\", \"file\":\"test\", \"command\": \"" +
320      Command + "\"}]").str();
321   std::string ErrorMessage;
322   CompileCommand FoundCommand = findCompileArgsInJsonDatabase(
323     "//net/root/test", JsonDatabase, ErrorMessage);
324   EXPECT_TRUE(ErrorMessage.empty()) << ErrorMessage;
325   return FoundCommand.CommandLine;
326 }
327 
328 TEST(unescapeJsonCommandLine, ReturnsEmptyArrayOnEmptyString) {
329   std::vector<std::string> Result = unescapeJsonCommandLine("");
330   EXPECT_TRUE(Result.empty());
331 }
332 
333 TEST(unescapeJsonCommandLine, SplitsOnSpaces) {
334   std::vector<std::string> Result = unescapeJsonCommandLine("a b c");
335   ASSERT_EQ(3ul, Result.size());
336   EXPECT_EQ("a", Result[0]);
337   EXPECT_EQ("b", Result[1]);
338   EXPECT_EQ("c", Result[2]);
339 }
340 
341 TEST(unescapeJsonCommandLine, MungesMultipleSpaces) {
342   std::vector<std::string> Result = unescapeJsonCommandLine("   a   b   ");
343   ASSERT_EQ(2ul, Result.size());
344   EXPECT_EQ("a", Result[0]);
345   EXPECT_EQ("b", Result[1]);
346 }
347 
348 TEST(unescapeJsonCommandLine, UnescapesBackslashCharacters) {
349   std::vector<std::string> Backslash = unescapeJsonCommandLine("a\\\\\\\\");
350   ASSERT_EQ(1ul, Backslash.size());
351   EXPECT_EQ("a\\", Backslash[0]);
352   std::vector<std::string> Quote = unescapeJsonCommandLine("a\\\\\\\"");
353   ASSERT_EQ(1ul, Quote.size());
354   EXPECT_EQ("a\"", Quote[0]);
355 }
356 
357 TEST(unescapeJsonCommandLine, DoesNotMungeSpacesBetweenQuotes) {
358   std::vector<std::string> Result = unescapeJsonCommandLine("\\\"  a  b  \\\"");
359   ASSERT_EQ(1ul, Result.size());
360   EXPECT_EQ("  a  b  ", Result[0]);
361 }
362 
363 TEST(unescapeJsonCommandLine, AllowsMultipleQuotedArguments) {
364   std::vector<std::string> Result = unescapeJsonCommandLine(
365       "  \\\" a \\\"  \\\" b \\\"  ");
366   ASSERT_EQ(2ul, Result.size());
367   EXPECT_EQ(" a ", Result[0]);
368   EXPECT_EQ(" b ", Result[1]);
369 }
370 
371 TEST(unescapeJsonCommandLine, AllowsEmptyArgumentsInQuotes) {
372   std::vector<std::string> Result = unescapeJsonCommandLine(
373       "\\\"\\\"\\\"\\\"");
374   ASSERT_EQ(1ul, Result.size());
375   EXPECT_TRUE(Result[0].empty()) << Result[0];
376 }
377 
378 TEST(unescapeJsonCommandLine, ParsesEscapedQuotesInQuotedStrings) {
379   std::vector<std::string> Result = unescapeJsonCommandLine(
380       "\\\"\\\\\\\"\\\"");
381   ASSERT_EQ(1ul, Result.size());
382   EXPECT_EQ("\"", Result[0]);
383 }
384 
385 TEST(unescapeJsonCommandLine, ParsesMultipleArgumentsWithEscapedCharacters) {
386   std::vector<std::string> Result = unescapeJsonCommandLine(
387       "  \\\\\\\"  \\\"a \\\\\\\" b \\\"     \\\"and\\\\\\\\c\\\"   \\\\\\\"");
388   ASSERT_EQ(4ul, Result.size());
389   EXPECT_EQ("\"", Result[0]);
390   EXPECT_EQ("a \" b ", Result[1]);
391   EXPECT_EQ("and\\c", Result[2]);
392   EXPECT_EQ("\"", Result[3]);
393 }
394 
395 TEST(unescapeJsonCommandLine, ParsesStringsWithoutSpacesIntoSingleArgument) {
396   std::vector<std::string> QuotedNoSpaces = unescapeJsonCommandLine(
397       "\\\"a\\\"\\\"b\\\"");
398   ASSERT_EQ(1ul, QuotedNoSpaces.size());
399   EXPECT_EQ("ab", QuotedNoSpaces[0]);
400 
401   std::vector<std::string> MixedNoSpaces = unescapeJsonCommandLine(
402       "\\\"a\\\"bcd\\\"ef\\\"\\\"\\\"\\\"g\\\"");
403   ASSERT_EQ(1ul, MixedNoSpaces.size());
404   EXPECT_EQ("abcdefg", MixedNoSpaces[0]);
405 }
406 
407 TEST(unescapeJsonCommandLine, ParsesQuotedStringWithoutClosingQuote) {
408   std::vector<std::string> Unclosed = unescapeJsonCommandLine("\\\"abc");
409   ASSERT_EQ(1ul, Unclosed.size());
410   EXPECT_EQ("abc", Unclosed[0]);
411 
412   std::vector<std::string> Empty = unescapeJsonCommandLine("\\\"");
413   ASSERT_EQ(1ul, Empty.size());
414   EXPECT_EQ("", Empty[0]);
415 }
416 
417 TEST(unescapeJsonCommandLine, ParsesSingleQuotedString) {
418   std::vector<std::string> Args = unescapeJsonCommandLine("a'\\\\b \\\"c\\\"'");
419   ASSERT_EQ(1ul, Args.size());
420   EXPECT_EQ("a\\b \"c\"", Args[0]);
421 }
422 
423 TEST(FixedCompilationDatabase, ReturnsFixedCommandLine) {
424   std::vector<std::string> CommandLine;
425   CommandLine.push_back("one");
426   CommandLine.push_back("two");
427   FixedCompilationDatabase Database(".", CommandLine);
428   std::vector<CompileCommand> Result =
429     Database.getCompileCommands("source");
430   ASSERT_EQ(1ul, Result.size());
431   std::vector<std::string> ExpectedCommandLine(1, "clang-tool");
432   ExpectedCommandLine.insert(ExpectedCommandLine.end(),
433                              CommandLine.begin(), CommandLine.end());
434   ExpectedCommandLine.push_back("source");
435   EXPECT_EQ(".", Result[0].Directory);
436   EXPECT_EQ(ExpectedCommandLine, Result[0].CommandLine);
437 }
438 
439 TEST(FixedCompilationDatabase, GetAllFiles) {
440   std::vector<std::string> CommandLine;
441   CommandLine.push_back("one");
442   CommandLine.push_back("two");
443   FixedCompilationDatabase Database(".", CommandLine);
444 
445   EXPECT_EQ(0ul, Database.getAllFiles().size());
446 }
447 
448 TEST(FixedCompilationDatabase, GetAllCompileCommands) {
449   std::vector<std::string> CommandLine;
450   CommandLine.push_back("one");
451   CommandLine.push_back("two");
452   FixedCompilationDatabase Database(".", CommandLine);
453 
454   EXPECT_EQ(0ul, Database.getAllCompileCommands().size());
455 }
456 
457 TEST(ParseFixedCompilationDatabase, ReturnsNullOnEmptyArgumentList) {
458   int Argc = 0;
459   std::unique_ptr<FixedCompilationDatabase> Database(
460       FixedCompilationDatabase::loadFromCommandLine(Argc, nullptr));
461   EXPECT_FALSE(Database);
462   EXPECT_EQ(0, Argc);
463 }
464 
465 TEST(ParseFixedCompilationDatabase, ReturnsNullWithoutDoubleDash) {
466   int Argc = 2;
467   const char *Argv[] = { "1", "2" };
468   std::unique_ptr<FixedCompilationDatabase> Database(
469       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
470   EXPECT_FALSE(Database);
471   EXPECT_EQ(2, Argc);
472 }
473 
474 TEST(ParseFixedCompilationDatabase, ReturnsArgumentsAfterDoubleDash) {
475   int Argc = 5;
476   const char *Argv[] = {
477     "1", "2", "--\0no-constant-folding", "-DDEF3", "-DDEF4"
478   };
479   std::unique_ptr<FixedCompilationDatabase> Database(
480       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
481   ASSERT_TRUE((bool)Database);
482   std::vector<CompileCommand> Result =
483     Database->getCompileCommands("source");
484   ASSERT_EQ(1ul, Result.size());
485   ASSERT_EQ(".", Result[0].Directory);
486   std::vector<std::string> CommandLine;
487   CommandLine.push_back("clang-tool");
488   CommandLine.push_back("-DDEF3");
489   CommandLine.push_back("-DDEF4");
490   CommandLine.push_back("source");
491   ASSERT_EQ(CommandLine, Result[0].CommandLine);
492   EXPECT_EQ(2, Argc);
493 }
494 
495 TEST(ParseFixedCompilationDatabase, ReturnsEmptyCommandLine) {
496   int Argc = 3;
497   const char *Argv[] = { "1", "2", "--\0no-constant-folding" };
498   std::unique_ptr<FixedCompilationDatabase> Database(
499       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
500   ASSERT_TRUE((bool)Database);
501   std::vector<CompileCommand> Result =
502     Database->getCompileCommands("source");
503   ASSERT_EQ(1ul, Result.size());
504   ASSERT_EQ(".", Result[0].Directory);
505   std::vector<std::string> CommandLine;
506   CommandLine.push_back("clang-tool");
507   CommandLine.push_back("source");
508   ASSERT_EQ(CommandLine, Result[0].CommandLine);
509   EXPECT_EQ(2, Argc);
510 }
511 
512 TEST(ParseFixedCompilationDatabase, HandlesPositionalArgs) {
513   const char *Argv[] = {"1", "2", "--", "-c", "somefile.cpp", "-DDEF3"};
514   int Argc = sizeof(Argv) / sizeof(char*);
515   std::unique_ptr<FixedCompilationDatabase> Database(
516       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
517   ASSERT_TRUE((bool)Database);
518   std::vector<CompileCommand> Result =
519     Database->getCompileCommands("source");
520   ASSERT_EQ(1ul, Result.size());
521   ASSERT_EQ(".", Result[0].Directory);
522   std::vector<std::string> Expected;
523   Expected.push_back("clang-tool");
524   Expected.push_back("-c");
525   Expected.push_back("-DDEF3");
526   Expected.push_back("source");
527   ASSERT_EQ(Expected, Result[0].CommandLine);
528   EXPECT_EQ(2, Argc);
529 }
530 
531 TEST(ParseFixedCompilationDatabase, HandlesArgv0) {
532   const char *Argv[] = {"1", "2", "--", "mytool", "somefile.cpp"};
533   int Argc = sizeof(Argv) / sizeof(char*);
534   std::unique_ptr<FixedCompilationDatabase> Database(
535       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
536   ASSERT_TRUE((bool)Database);
537   std::vector<CompileCommand> Result =
538     Database->getCompileCommands("source");
539   ASSERT_EQ(1ul, Result.size());
540   ASSERT_EQ(".", Result[0].Directory);
541   std::vector<std::string> Expected;
542   Expected.push_back("clang-tool");
543   Expected.push_back("source");
544   ASSERT_EQ(Expected, Result[0].CommandLine);
545   EXPECT_EQ(2, Argc);
546 }
547 
548 } // end namespace tooling
549 } // end namespace clang
550