File indexing completed on 2024-05-19 05:42:00
0001 // ct_lvtclp_tool.t.cpp -*-C++-*- 0002 0003 /* 0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk> 0005 // SPDX-License-Identifier: Apache-2.0 0006 // 0007 // Licensed under the Apache License, Version 2.0 (the "License"); 0008 // you may not use this file except in compliance with the License. 0009 // You may obtain a copy of the License at 0010 // 0011 // http://www.apache.org/licenses/LICENSE-2.0 0012 // 0013 // Unless required by applicable law or agreed to in writing, software 0014 // distributed under the License is distributed on an "AS IS" BASIS, 0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0016 // See the License for the specific language governing permissions and 0017 // limitations under the License. 0018 */ 0019 0020 #include <ct_lvtclp_cpp_tool.h> 0021 0022 #include <ct_lvtclp_testutil.h> 0023 0024 #include <ct_lvtmdb_componentobject.h> 0025 #include <ct_lvtmdb_fileobject.h> 0026 #include <ct_lvtmdb_objectstore.h> 0027 #include <ct_lvtmdb_packageobject.h> 0028 #include <ct_lvtmdb_typeobject.h> 0029 0030 #include <fstream> 0031 #include <initializer_list> 0032 0033 #include <catch2-local-includes.h> 0034 0035 #include <autogen-test-variables.h> 0036 0037 using namespace Codethink::lvtclp; 0038 using namespace Codethink::lvtmdb; 0039 0040 const PyDefaultGilReleasedContext defaultGilContextForTesting; 0041 0042 static void createTop(const std::filesystem::path& topLevel) 0043 { 0044 bool created = std::filesystem::create_directories(topLevel / "groups/one/onetop"); 0045 REQUIRE(created); 0046 0047 created = Test_Util::createFile(topLevel / "groups/one/onetop/onetop_top.h", R"( 0048 // onetop_top.h 0049 0050 namespace onetop { 0051 0052 class Base 0053 { 0054 }; 0055 0056 class Top : public Base { 0057 public: 0058 int method(); 0059 }; 0060 0061 })"); 0062 REQUIRE(created); 0063 0064 created = Test_Util::createFile(topLevel / "groups/one/onetop/onetop_top.cpp", R"( 0065 // onetop_top.cpp 0066 0067 #include <onetop_top.h> 0068 0069 namespace onetop { 0070 0071 int Top::method() 0072 { 0073 return 2; 0074 } 0075 0076 })"); 0077 0078 REQUIRE(created); 0079 } 0080 0081 static void createDep(const std::filesystem::path& topLevel) 0082 { 0083 assert(std::filesystem::create_directories(topLevel / "groups/one/onedep")); 0084 0085 Test_Util::createFile(topLevel / "groups/one/onedep/onedep_dep.h", R"( 0086 // onedep_dep.h 0087 0088 #include <onetop_top.h> 0089 0090 namespace onedep { 0091 0092 class Dep { 0093 onetop::Top top; 0094 0095 int method(); 0096 }; 0097 0098 })"); 0099 Test_Util::createFile(topLevel / "groups/one/onedep/onedep_dep.cpp", R"( 0100 // onedep_dep.cpp 0101 0102 #include <onedep_dep.h> 0103 0104 namespace onedep { 0105 0106 int Dep::method() 0107 { 0108 return top.method(); 0109 } 0110 0111 })"); 0112 } 0113 0114 static void createTestEnv(const std::filesystem::path& topLevel) 0115 { 0116 if (std::filesystem::exists(topLevel / "groups")) { 0117 REQUIRE(std::filesystem::remove_all(topLevel / "groups")); 0118 } 0119 0120 createTop(topLevel); 0121 createDep(topLevel); 0122 } 0123 0124 static void checkDatabaseOriginal(ObjectStore& session) 0125 // check the database before any files are removed 0126 { 0127 const std::initializer_list<ModelUtil::SourceFileModel> files = {{"groups/one/onedep/onedep_dep.cpp", 0128 false, 0129 "groups/one/onedep", 0130 "groups/one/onedep/onedep_dep", 0131 {"onedep"}, 0132 {}, 0133 {"groups/one/onedep/onedep_dep.h"}}, 0134 {"groups/one/onedep/onedep_dep.h", 0135 true, 0136 "groups/one/onedep", 0137 "groups/one/onedep/onedep_dep", 0138 {"onedep"}, 0139 {"onedep::Dep"}, 0140 {"groups/one/onetop/onetop_top.h"}}, 0141 {"groups/one/onetop/onetop_top.cpp", 0142 false, 0143 "groups/one/onetop", 0144 "groups/one/onetop/onetop_top", 0145 {"onetop"}, 0146 {}, 0147 {"groups/one/onetop/onetop_top.h"}}, 0148 {"groups/one/onetop/onetop_top.h", 0149 true, 0150 "groups/one/onetop", 0151 "groups/one/onetop/onetop_top", 0152 {"onetop"}, 0153 {"onetop::Base", "onetop::Top"}, 0154 {}}}; 0155 0156 const std::initializer_list<ModelUtil::ComponentModel> comps = { 0157 {"groups/one/onedep/onedep_dep", 0158 "onedep_dep", 0159 {"groups/one/onedep/onedep_dep.h", "groups/one/onedep/onedep_dep.cpp"}, 0160 {"groups/one/onetop/onetop_top"}}, 0161 {"groups/one/onetop/onetop_top", 0162 "onetop_top", 0163 {"groups/one/onetop/onetop_top.h", "groups/one/onetop/onetop_top.cpp"}, 0164 {}}, 0165 }; 0166 0167 const std::initializer_list<ModelUtil::PackageModel> pkgs = { 0168 {"groups/one/onedep", "groups/one", {"onedep::Dep"}, {"groups/one/onedep/onedep_dep"}, {"groups/one/onetop"}}, 0169 {"groups/one/onetop", "groups/one", {"onetop::Base", "onetop::Top"}, {"groups/one/onetop/onetop_top"}, {}}}; 0170 0171 const std::initializer_list<ModelUtil::UDTModel> udts = { 0172 { 0173 "onedep::Dep", 0174 "onedep", 0175 "groups/one/onedep", 0176 {"onetop::Top"}, 0177 {}, 0178 {}, 0179 {"onedep::Dep::method"}, 0180 {"onedep::Dep::top"}, 0181 }, 0182 { 0183 "onetop::Base", 0184 "onetop", 0185 "groups/one/onetop", 0186 {}, 0187 {}, 0188 {}, 0189 {}, 0190 {}, 0191 }, 0192 { 0193 "onetop::Top", 0194 "onetop", 0195 "groups/one/onetop", 0196 {}, 0197 {}, 0198 {"onetop::Base"}, 0199 {"onetop::Top::method"}, 0200 {}, 0201 }, 0202 }; 0203 0204 ModelUtil::checkSourceFiles(session, files); 0205 ModelUtil::checkComponents(session, comps); 0206 ModelUtil::checkPackages(session, pkgs); 0207 ModelUtil::checkUDTs(session, udts); 0208 } 0209 0210 static void checkDatabaseModifiedFile(ObjectStore& session, bool printToConsole = false) 0211 { 0212 const std::initializer_list<ModelUtil::SourceFileModel> files = { 0213 {"groups/one/onedep/onedep_dep.cpp", 0214 false, 0215 "groups/one/onedep", 0216 "groups/one/onedep/onedep_dep", 0217 {"onedep"}, 0218 {}, 0219 {"groups/one/onedep/onedep_dep.h"}}, 0220 {"groups/one/onedep/onedep_dep.h", 0221 true, 0222 "groups/one/onedep", 0223 "groups/one/onedep/onedep_dep", 0224 {"onedep"}, 0225 {"onedep::Dep"}, 0226 {"groups/one/onetop/onetop_top.h"}}, 0227 {"groups/one/onetop/onetop_top.cpp", 0228 false, 0229 "groups/one/onetop", 0230 "groups/one/onetop/onetop_top", 0231 {"onetop"}, 0232 {}, 0233 {"groups/one/onetop/onetop_top.h"}}, 0234 // NewClass added: 0235 {"groups/one/onetop/onetop_top.h", 0236 true, 0237 "groups/one/onetop", 0238 "groups/one/onetop/onetop_top", 0239 {"onetop"}, 0240 {"onetop::Base", "onetop::Top", "onetop::NewClass"}, 0241 {}}}; 0242 0243 const std::initializer_list<ModelUtil::ComponentModel> comps = { 0244 {"groups/one/onedep/onedep_dep", 0245 "onedep_dep", 0246 {"groups/one/onedep/onedep_dep.h", "groups/one/onedep/onedep_dep.cpp"}, 0247 {"groups/one/onetop/onetop_top"}}, 0248 {"groups/one/onetop/onetop_top", 0249 "onetop_top", 0250 {"groups/one/onetop/onetop_top.h", "groups/one/onetop/onetop_top.cpp"}, 0251 {}}, 0252 }; 0253 0254 const std::initializer_list<ModelUtil::PackageModel> pkgs = { 0255 {"groups/one/onedep", "groups/one", {"onedep::Dep"}, {"groups/one/onedep/onedep_dep"}, {"groups/one/onetop"}}, 0256 {"groups/one/onetop", 0257 "groups/one", 0258 {"onetop::Base", "onetop::Top", "onetop::NewClass"}, 0259 {"groups/one/onetop/onetop_top"}, 0260 {}}}; 0261 0262 const std::initializer_list<ModelUtil::UDTModel> udts = { 0263 { 0264 "onedep::Dep", 0265 "onedep", 0266 "groups/one/onedep", 0267 {"onetop::Top"}, 0268 {}, 0269 {}, 0270 {"onedep::Dep::method"}, 0271 {"onedep::Dep::top"}, 0272 }, 0273 { 0274 "onetop::Base", 0275 "onetop", 0276 "groups/one/onetop", 0277 {}, 0278 {}, 0279 {}, 0280 {}, 0281 {}, 0282 }, 0283 { 0284 "onetop::Top", 0285 "onetop", 0286 "groups/one/onetop", 0287 {}, 0288 {}, 0289 {"onetop::Base"}, 0290 {"onetop::Top::method"}, 0291 {}, 0292 }, 0293 { 0294 "onetop::NewClass", 0295 "onetop", 0296 "groups/one/onetop", 0297 {}, 0298 {}, 0299 {}, 0300 {}, 0301 {}, 0302 }, 0303 }; 0304 0305 ModelUtil::checkSourceFiles(session, files); 0306 ModelUtil::checkComponents(session, comps); 0307 ModelUtil::checkPackages(session, pkgs); 0308 ModelUtil::checkUDTs(session, udts); 0309 } 0310 0311 static void checkDatabaseNewFiles(ObjectStore& session) 0312 // check the database after onedep_newfile has been added 0313 { 0314 const std::initializer_list<ModelUtil::SourceFileModel> files = {{"groups/one/onedep/onedep_dep.cpp", 0315 false, 0316 "groups/one/onedep", 0317 "groups/one/onedep/onedep_dep", 0318 {"onedep"}, 0319 {}, 0320 {"groups/one/onedep/onedep_dep.h"}}, 0321 {"groups/one/onedep/onedep_dep.h", 0322 true, 0323 "groups/one/onedep", 0324 "groups/one/onedep/onedep_dep", 0325 {"onedep"}, 0326 {"onedep::Dep"}, 0327 {"groups/one/onetop/onetop_top.h"}}, 0328 {"groups/one/onedep/onedep_newfile.cpp", 0329 false, 0330 "groups/one/onedep", 0331 "groups/one/onedep/onedep_newfile", 0332 {}, 0333 {}, 0334 {"groups/one/onedep/onedep_newfile.h"}}, 0335 {"groups/one/onedep/onedep_newfile.h", 0336 true, 0337 "groups/one/onedep", 0338 "groups/one/onedep/onedep_newfile", 0339 {"onedep"}, 0340 {"onedep::NewFile"}, 0341 {}}, 0342 {"groups/one/onetop/onetop_top.cpp", 0343 false, 0344 "groups/one/onetop", 0345 "groups/one/onetop/onetop_top", 0346 {"onetop"}, 0347 {}, 0348 {"groups/one/onetop/onetop_top.h"}}, 0349 {"groups/one/onetop/onetop_top.h", 0350 true, 0351 "groups/one/onetop", 0352 "groups/one/onetop/onetop_top", 0353 {"onetop"}, 0354 {"onetop::Base", "onetop::Top"}, 0355 {}}}; 0356 0357 const std::initializer_list<ModelUtil::ComponentModel> comps = { 0358 {"groups/one/onedep/onedep_dep", 0359 "onedep_dep", 0360 {"groups/one/onedep/onedep_dep.h", "groups/one/onedep/onedep_dep.cpp"}, 0361 {"groups/one/onetop/onetop_top"}}, 0362 {"groups/one/onedep/onedep_newfile", 0363 "onedep_newfile", 0364 {"groups/one/onedep/onedep_newfile.h", "groups/one/onedep/onedep_newfile.cpp"}, 0365 {}}, 0366 {"groups/one/onetop/onetop_top", 0367 "onetop_top", 0368 {"groups/one/onetop/onetop_top.h", "groups/one/onetop/onetop_top.cpp"}, 0369 {}}, 0370 }; 0371 0372 const std::initializer_list<ModelUtil::PackageModel> pkgs = { 0373 {"groups/one/onedep", 0374 "groups/one", 0375 {"onedep::Dep", "onedep::NewFile"}, 0376 {"groups/one/onedep/onedep_dep", "groups/one/onedep/onedep_newfile"}, 0377 {"groups/one/onetop"}}, 0378 {"groups/one/onetop", "groups/one", {"onetop::Base", "onetop::Top"}, {"groups/one/onetop/onetop_top"}, {}}}; 0379 0380 const std::initializer_list<ModelUtil::UDTModel> udts = { 0381 { 0382 "onedep::Dep", 0383 "onedep", 0384 "groups/one/onedep", 0385 {"onetop::Top"}, 0386 {}, 0387 {}, 0388 {"onedep::Dep::method"}, 0389 {"onedep::Dep::top"}, 0390 }, 0391 { 0392 "onedep::NewFile", 0393 "onedep", 0394 "groups/one/onedep", 0395 {}, 0396 {}, 0397 {}, 0398 {}, 0399 {}, 0400 }, 0401 { 0402 "onetop::Base", 0403 "onetop", 0404 "groups/one/onetop", 0405 {}, 0406 {}, 0407 {}, 0408 {}, 0409 {}, 0410 }, 0411 { 0412 "onetop::Top", 0413 "onetop", 0414 "groups/one/onetop", 0415 {}, 0416 {}, 0417 {"onetop::Base"}, 0418 {"onetop::Top::method"}, 0419 {}, 0420 }, 0421 }; 0422 0423 ModelUtil::checkSourceFiles(session, files); 0424 ModelUtil::checkComponents(session, comps); 0425 ModelUtil::checkPackages(session, pkgs); 0426 ModelUtil::checkUDTs(session, udts); 0427 } 0428 0429 static void runTool(CppTool& tool, const bool madeChanges, const unsigned numRuns = 1, bool verbose = false) 0430 { 0431 tool.setPrintToConsole(verbose); 0432 for (unsigned i = 0; i < numRuns; i++) { 0433 REQUIRE(tool.runFull()); 0434 REQUIRE(tool.lastRunMadeChanges() == madeChanges); 0435 } 0436 } 0437 0438 struct CppToolTestFixture { 0439 CppToolTestFixture(): topLevel(std::filesystem::temp_directory_path() / "ct_lvtclp_tool_test") 0440 { 0441 createTestEnv(topLevel); 0442 } 0443 0444 ~CppToolTestFixture() 0445 { 0446 REQUIRE(std::filesystem::remove_all(topLevel)); 0447 } 0448 0449 std::filesystem::path topLevel; 0450 }; 0451 0452 TEST_CASE_METHOD(CppToolTestFixture, "Tool") 0453 { 0454 constexpr unsigned NUM_RERUNS = 2; 0455 0456 { 0457 StaticCompilationDatabase cmds({{"groups/one/onetop/onetop_top.cpp", "build/onetop_top.o"}, 0458 {"groups/one/onedep/onedep_dep.cpp", "build/onedep_dep.o"}}, 0459 "placeholder", 0460 {"-Igroups/one/onetop", "-Igroups/one/onedep"}, 0461 topLevel); 0462 0463 CppTool tool(topLevel, cmds, topLevel / "database"); 0464 ObjectStore& session = tool.getObjectStore(); 0465 0466 // initial parse 0467 runTool(tool, true); 0468 checkDatabaseOriginal(session); 0469 0470 // re-run incrementally 0471 runTool(tool, false, NUM_RERUNS); 0472 checkDatabaseOriginal(session); 0473 0474 // modify a file, adding a class 0475 std::filesystem::path fileToChange = topLevel / "groups/one/onetop/onetop_top.h"; 0476 { 0477 // open for appending 0478 std::ofstream of(fileToChange.string(), std::ios_base::out | std::ios_base::app); 0479 REQUIRE(!of.fail()); 0480 of << "namespace onetop { class NewClass {}; }" << std::endl; 0481 } 0482 runTool(tool, true); 0483 checkDatabaseModifiedFile(session); 0484 0485 // re-run incrementally 0486 runTool(tool, false, NUM_RERUNS); 0487 checkDatabaseModifiedFile(session); 0488 0489 // change modified file back again, run again, and re-run 0490 createTestEnv(topLevel); 0491 runTool(tool, true); 0492 checkDatabaseOriginal(session); 0493 runTool(tool, false, NUM_RERUNS); 0494 checkDatabaseOriginal(session); 0495 } 0496 0497 // add a new component (already in the above compilation database) 0498 { 0499 StaticCompilationDatabase cmdsPlus( 0500 // cmds plus the new component 0501 {{"groups/one/onetop/onetop_top.cpp", "build/onetop_top.o"}, 0502 {"groups/one/onedep/onedep_dep.cpp", "build/onedep_dep.o"}, 0503 {"groups/one/onedep/onedep_newfile.cpp", "build/onedep_newfile.o"}}, 0504 "placeholder", 0505 {"-Igroups/one/onetop", "-Igroups/one/onedep"}, 0506 topLevel.string()); 0507 0508 CppTool toolPlus(topLevel, cmdsPlus, topLevel / "database"); 0509 0510 Test_Util::createFile(topLevel / "groups/one/onedep/onedep_newfile.h", R"( 0511 // onedep_newfile.h 0512 namespace onedep { 0513 class NewFile {}; 0514 } 0515 )"); 0516 Test_Util::createFile(topLevel / "groups/one/onedep/onedep_newfile.cpp", R"( 0517 // onedep_newfile.cpp 0518 #include <onedep_newfile.h> 0519 )"); 0520 ObjectStore& session = toolPlus.getObjectStore(); 0521 runTool(toolPlus, true); 0522 checkDatabaseNewFiles(session); 0523 runTool(toolPlus, false, NUM_RERUNS); 0524 checkDatabaseNewFiles(session); 0525 0526 // delete the new component and re-run 0527 createTestEnv(topLevel); 0528 runTool(toolPlus, true); 0529 checkDatabaseOriginal(session); 0530 runTool(toolPlus, false, NUM_RERUNS); 0531 checkDatabaseOriginal(session); 0532 } 0533 } 0534 0535 TEST_CASE("Run Tool on example project") 0536 { 0537 StaticCompilationDatabase cmds({{"hello.m.cpp", "hello.m.o"}}, "placeholder", {}, PREFIX + "/hello_world/"); 0538 CppTool tool(PREFIX + "/hello_world/", cmds, PREFIX + "/hello_world/database"); 0539 ObjectStore& session = tool.getObjectStore(); 0540 0541 REQUIRE(tool.runFull()); 0542 0543 FileObject *file = nullptr; 0544 session.withROLock([&] { 0545 file = session.getFile("hello.m.cpp"); 0546 }); 0547 REQUIRE(file); 0548 } 0549 0550 TEST_CASE("Run Tool on example project incrementally") 0551 { 0552 auto sourcePath = PREFIX + "/package_circular_dependency/"; 0553 0554 auto files = std::initializer_list<std::pair<std::string, std::string>>{ 0555 {"groups/one/onepkg/ct_onepkg_circle.cpp", "ct_onepkg_circle.o"}, 0556 {"groups/one/onepkg/ct_onepkg_thing.cpp", "ct_onepkg_thing.o"}}; 0557 0558 StaticCompilationDatabase cmds( 0559 files, 0560 "placeholder", 0561 {"-I" + sourcePath + "/groups/one/onepkg/", "-I" + sourcePath + "/groups/two/twodmo/"}, 0562 sourcePath); 0563 CppTool tool(sourcePath, cmds, sourcePath + "database"); 0564 ObjectStore& session = tool.getObjectStore(); 0565 0566 REQUIRE(tool.runPhysical()); 0567 session.withROLock([&] { 0568 REQUIRE(session.getAllFiles().size() == 5); 0569 REQUIRE(session.getAllPackages().size() == 2); 0570 auto *e = session.getPackage("groups/one/onepkg"); 0571 e->withROLock([&]() { 0572 REQUIRE(e->components().size() == 2); 0573 for (auto&& c : e->components()) { 0574 c->withROLock([&]() { 0575 if (c->qualifiedName() == "groups/one/onepkg/ct_onepkg_circle") { 0576 REQUIRE(c->forwardDependencies().size() == 2); 0577 } else if (c->qualifiedName() == "groups/one/onepkg/ct_onepkg_thing") { 0578 REQUIRE(c->forwardDependencies().empty()); 0579 } else { 0580 FAIL("Unexpected component: " + c->qualifiedName()); 0581 } 0582 }); 0583 } 0584 }); 0585 }); 0586 0587 // There was a bug where a logical parse after a only-physical parse would remove physical connections from 0588 // components. This test has been added to avoid regression. 0589 REQUIRE(tool.runFull(true)); 0590 session.withROLock([&] { 0591 REQUIRE(session.getAllFiles().size() == 5); 0592 REQUIRE(session.getAllPackages().size() == 2); 0593 auto *e = session.getPackage("groups/one/onepkg"); 0594 e->withROLock([&]() { 0595 REQUIRE(e->components().size() == 2); 0596 for (auto&& c : e->components()) { 0597 c->withROLock([&]() { 0598 if (c->qualifiedName() == "groups/one/onepkg/ct_onepkg_circle") { 0599 REQUIRE(c->forwardDependencies().size() == 2); 0600 } else if (c->qualifiedName() == "groups/one/onepkg/ct_onepkg_thing") { 0601 REQUIRE(c->forwardDependencies().empty()); 0602 } else { 0603 FAIL("Unexpected component: " + c->qualifiedName()); 0604 } 0605 }); 0606 } 0607 }); 0608 }); 0609 } 0610 0611 TEST_CASE("Run Tool on project including other lakosian project") 0612 { 0613 auto const prjAPath = PREFIX + "/project_with_includes_outside_src/prjA"; 0614 auto const prjBPath = PREFIX + "/project_with_includes_outside_src/prjB"; 0615 StaticCompilationDatabase cmds({{"groups/one/oneaaa/oneaaa_comp.cpp", "oneaaa_comp.o"}}, 0616 "placeholder", 0617 {"-I" + prjAPath + "/groups/one/oneaaa/", "-I" + prjBPath + "/groups/two/twoaaa/"}, 0618 prjAPath); 0619 CppTool tool(prjAPath, cmds, prjAPath + "/database"); 0620 ObjectStore& session = tool.getObjectStore(); 0621 0622 REQUIRE(tool.runFull()); 0623 session.withROLock([&] { 0624 REQUIRE(session.getFile("groups/one/oneaaa/oneaaa_comp.cpp")); 0625 REQUIRE(session.getFile("groups/one/oneaaa/oneaaa_comp.h")); 0626 REQUIRE(session.getComponent("groups/one/oneaaa/oneaaa_comp")); 0627 REQUIRE(session.getComponent("groups/two/twoaaa/twoaaa_comp")); 0628 }); 0629 } 0630 0631 struct HashFunc { 0632 size_t operator()(const std::tuple<std::string, unsigned>& data) const 0633 { 0634 return std::hash<std::string>{}(std::get<0>(data)) ^ std::hash<unsigned>{}(std::get<1>(data)); 0635 } 0636 }; 0637 0638 TEST_CASE("Run Tool store test-only dependencies") 0639 { 0640 auto const prjAPath = PREFIX + "/test_only_dependencies/prjA"; 0641 StaticCompilationDatabase cmds( 0642 { 0643 {"groups/one/oneaaa/oneaaa_comp.cpp", "oneaaa_comp.o"}, 0644 {"groups/one/oneaaa/oneaaa_comp.t.cpp", "oneaaa_comp.t.o"}, 0645 {"groups/one/oneaaa/oneaaa_othercomp.cpp", "oneaaa_othercomp.o"}, 0646 {"groups/one/oneaaa/oneaaa_othercomp2.cpp", "oneaaa_othercomp2.o"}, 0647 }, 0648 "placeholder", 0649 {"-I" + prjAPath + "/groups/one/oneaaa/", "-fparse-all-comments"}, 0650 prjAPath); 0651 CppTool tool(prjAPath, cmds, prjAPath + "/database"); 0652 0653 using Filename = std::string; 0654 using LineNo = unsigned; 0655 using FileAndLine = std::tuple<Filename, LineNo>; 0656 auto includesInFile = std::unordered_map<Filename, std::unordered_set<FileAndLine, HashFunc>>{}; 0657 tool.setHeaderLocationCallback( 0658 [&includesInFile](Filename const& sourceFile, Filename const& includedFile, LineNo lineNo) { 0659 if (includesInFile.find(sourceFile) == includesInFile.end()) { 0660 includesInFile[sourceFile] = std::unordered_set<FileAndLine, HashFunc>{}; 0661 } 0662 includesInFile[sourceFile].insert(std::make_tuple(includedFile, lineNo)); 0663 }); 0664 0665 auto testOnlyDepComments = std::unordered_map<Filename, std::unordered_set<LineNo>>{}; 0666 tool.setHandleCppCommentsCallback([&testOnlyDepComments](Filename const& filename, 0667 std::string const& briefText, 0668 LineNo startLine, 0669 LineNo endLine) { 0670 if (briefText != "Test only dependency") { 0671 return; 0672 } 0673 0674 if (testOnlyDepComments.find(filename) == testOnlyDepComments.end()) { 0675 testOnlyDepComments[filename] = std::unordered_set<LineNo>{}; 0676 } 0677 testOnlyDepComments[filename].insert(startLine); 0678 }); 0679 0680 ObjectStore& session = tool.getObjectStore(); 0681 0682 REQUIRE(tool.runFull()); 0683 session.withROLock([&] { 0684 REQUIRE(session.getFile("groups/one/oneaaa/oneaaa_comp.cpp")); 0685 REQUIRE(session.getFile("groups/one/oneaaa/oneaaa_comp.h")); 0686 REQUIRE(session.getFile("groups/one/oneaaa/oneaaa_othercomp.cpp")); 0687 REQUIRE(session.getFile("groups/one/oneaaa/oneaaa_othercomp.h")); 0688 REQUIRE(session.getFile("groups/one/oneaaa/oneaaa_othercomp2.cpp")); 0689 REQUIRE(session.getFile("groups/one/oneaaa/oneaaa_othercomp2.h")); 0690 0691 REQUIRE(session.getComponent("groups/one/oneaaa/oneaaa_comp")); 0692 REQUIRE(session.getComponent("groups/one/oneaaa/oneaaa_comp.t")); 0693 REQUIRE(session.getComponent("groups/one/oneaaa/oneaaa_othercomp")); 0694 REQUIRE(session.getComponent("groups/one/oneaaa/oneaaa_othercomp2")); 0695 }); 0696 0697 auto fileHasIncludeAtLine = [&includesInFile](Filename const& file, Filename const& included_file, LineNo line) { 0698 auto& set = includesInFile.at(file); 0699 return set.find(std::make_tuple(included_file, line)) != set.end(); 0700 }; 0701 REQUIRE(fileHasIncludeAtLine("oneaaa_othercomp2.cpp", "oneaaa_othercomp2.h", 1)); 0702 REQUIRE(fileHasIncludeAtLine("oneaaa_othercomp.cpp", "oneaaa_othercomp.h", 1)); 0703 REQUIRE(fileHasIncludeAtLine("oneaaa_comp.t.cpp", "oneaaa_comp.h", 1)); 0704 REQUIRE(fileHasIncludeAtLine("oneaaa_comp.t.cpp", "oneaaa_othercomp.h", 2)); 0705 REQUIRE(fileHasIncludeAtLine("oneaaa_comp.t.cpp", "oneaaa_othercomp2.h", 3)); 0706 REQUIRE(fileHasIncludeAtLine("oneaaa_comp.cpp", "oneaaa_comp.h", 1)); 0707 REQUIRE(fileHasIncludeAtLine("oneaaa_comp.cpp", "oneaaa_othercomp2.h", 2)); 0708 0709 auto fileHasTestOnlyCommentAtLine = [&testOnlyDepComments](Filename const& file, LineNo line) { 0710 auto& set = testOnlyDepComments.at(file); 0711 return set.find(line) != set.end(); 0712 }; 0713 REQUIRE(fileHasTestOnlyCommentAtLine("oneaaa_comp.cpp", 2)); 0714 }