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