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