Home | History | Annotate | Download | only in Tooling
      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");
     40   expectFailure("[{\"command\":\"\",\"file\":\"\"}]", "Missing directory");
     41 }
     42 
     43 static std::vector<std::string> getAllFiles(StringRef JSONDatabase,
     44                                             std::string &ErrorMessage) {
     45   std::unique_ptr<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   std::unique_ptr<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   std::unique_ptr<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   std::unique_ptr<FixedCompilationDatabase> Database(
    437       FixedCompilationDatabase::loadFromCommandLine(Argc, nullptr));
    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   std::unique_ptr<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   std::unique_ptr<FixedCompilationDatabase> Database(
    457       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
    458   ASSERT_TRUE((bool)Database);
    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   std::unique_ptr<FixedCompilationDatabase> Database(
    476       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
    477   ASSERT_TRUE((bool)Database);
    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   std::unique_ptr<FixedCompilationDatabase> Database(
    493       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
    494   ASSERT_TRUE((bool)Database);
    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   std::unique_ptr<FixedCompilationDatabase> Database(
    512       FixedCompilationDatabase::loadFromCommandLine(Argc, Argv));
    513   ASSERT_TRUE((bool)Database);
    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