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