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