From 56d611e0a3847dc477ec940edcf48cb821eee7b5 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 31 Jul 2019 16:54:39 +0200 Subject: [PATCH] ClangPchManager: Update PCHs if time stamps of dependencies changed If there is a newer file than the last indexing or if a file is added or removed from the project or system PCH we have to reindex the project and maybe the system PCH. Change-Id: Ibce2a244190a79b5c422c469c065ddc11e44b2cb Reviewed-by: Tim Jenssen --- src/libs/utils/smallstring.h | 4 +- src/libs/utils/smallstringvector.h | 11 +- .../clangpchmanagerbackendmain.cpp | 10 +- .../source/pchmanagerserver.cpp | 31 +- .../source/precompiledheaderstorage.h | 19 + .../precompiledheaderstorageinterface.h | 1 + .../source/projectpartsmanager.cpp | 259 ++++++++-- .../source/projectpartsmanager.h | 16 +- .../source/projectpartsmanagerinterface.h | 8 +- .../unittest/mockprecompiledheaderstorage.h | 2 + tests/unit/unittest/mockprojectpartsmanager.h | 13 +- tests/unit/unittest/pchmanagerserver-test.cpp | 40 +- tests/unit/unittest/pchtaskqueue-test.cpp | 2 +- .../precompiledheaderstorage-test.cpp | 26 + .../unittest/projectpartsmanager-test.cpp | 478 ++++++++++++++++-- 15 files changed, 788 insertions(+), 132 deletions(-) diff --git a/src/libs/utils/smallstring.h b/src/libs/utils/smallstring.h index d3fa44aa78a..e473378ffe3 100644 --- a/src/libs/utils/smallstring.h +++ b/src/libs/utils/smallstring.h @@ -945,8 +945,8 @@ clone(const std::unordered_map &map) return clonedMap; } -template -std::vector clone(const std::vector &vector) +template +Type clone(const Type &vector) { return vector; } diff --git a/src/libs/utils/smallstringvector.h b/src/libs/utils/smallstringvector.h index ed1acc2e7bc..724cf7e7179 100644 --- a/src/libs/utils/smallstringvector.h +++ b/src/libs/utils/smallstringvector.h @@ -117,16 +117,7 @@ public: push_back(std::move(string)); } - BasicSmallStringVector clone() const - { - BasicSmallStringVector clonedVector; - clonedVector.reserve(Base::size()); - - for (auto &&entry : *this) - clonedVector.push_back(entry.clone()); - - return clonedVector; - } + BasicSmallStringVector clone() const { return *this; } operator std::vector() const { diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index 5a634f8fe14..8c2023834d9 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -185,8 +185,12 @@ struct Data // because we have a cycle dependency ApplicationEnvironment environment; ProjectPartsStorage<> projectPartsStorage{database}; PrecompiledHeaderStorage<> preCompiledHeaderStorage{database}; - ProjectPartsManager projectParts{projectPartsStorage, preCompiledHeaderStorage}; GeneratedFiles generatedFiles; + ProjectPartsManager projectParts{projectPartsStorage, + preCompiledHeaderStorage, + buildDependencyProvider, + filePathCache, + generatedFiles}; PchCreatorManager pchCreatorManager{generatedFiles, environment, database, @@ -227,7 +231,9 @@ struct Data // because we have a cycle dependency pchTaskGenerator, projectParts, generatedFiles, - buildDependencyStorage}; + buildDependencyStorage/*, + buildDependencyProvider, + filePathCache*/}; TaskScheduler systemTaskScheduler{pchCreatorManager, pchTaskQueue, pchCreationProgressCounter, diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp index b393a8e4650..47ac3587658 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp @@ -26,6 +26,7 @@ #include "pchmanagerserver.h" #include +#include #include #include #include @@ -54,6 +55,7 @@ PchManagerServer::PchManagerServer(ClangPathWatcherInterface &fileSystemWatcher, , m_projectPartsManager(projectParts) , m_generatedFiles(generatedFiles) , m_buildDependenciesStorage(buildDependenciesStorage) + { m_fileSystemWatcher.setNotifier(this); } @@ -79,10 +81,13 @@ void PchManagerServer::updateProjectParts(UpdateProjectPartsMessage &&message) auto upToDateProjectParts = m_projectPartsManager.update(message.takeProjectsParts()); if (m_generatedFiles.isValid()) { - m_pchTaskGenerator.addProjectParts(std::move(upToDateProjectParts.notUpToDate), - std::move(message.toolChainArguments)); + m_pchTaskGenerator.addProjectParts(std::move(upToDateProjectParts.updateSystem), + message.toolChainArguments.clone()); + m_pchTaskGenerator.addNonSystemProjectParts(std::move(upToDateProjectParts.updateProject), + std::move(message.toolChainArguments)); } else { - m_projectPartsManager.updateDeferred(upToDateProjectParts.notUpToDate); + m_projectPartsManager.updateDeferred(std::move(upToDateProjectParts.updateSystem), + std::move(upToDateProjectParts.updateProject)); } client()->precompiledHeadersUpdated(toProjectPartIds(upToDateProjectParts.upToDate)); @@ -119,13 +124,21 @@ void PchManagerServer::updateGeneratedFiles(UpdateGeneratedFilesMessage &&messag m_generatedFiles.update(message.takeGeneratedFiles()); if (m_generatedFiles.isValid()) { - ProjectPartContainers deferredProjectParts = m_projectPartsManager.deferredUpdates(); - ArgumentsEntries entries = m_toolChainsArgumentsCache.arguments( - projectPartIds(deferredProjectParts)); + ProjectPartContainers deferredSystems = m_projectPartsManager.deferredSystemUpdates(); + ArgumentsEntries systemEntries = m_toolChainsArgumentsCache.arguments( + projectPartIds(deferredSystems)); - for (ArgumentsEntry &entry : entries) { - m_pchTaskGenerator.addProjectParts(std::move(deferredProjectParts), - std::move(entry.arguments)); + for (ArgumentsEntry &entry : systemEntries) { + m_pchTaskGenerator.addProjectParts(std::move(deferredSystems), std::move(entry.arguments)); + } + + ProjectPartContainers deferredProjects = m_projectPartsManager.deferredProjectUpdates(); + ArgumentsEntries projectEntries = m_toolChainsArgumentsCache.arguments( + projectPartIds(deferredProjects)); + + for (ArgumentsEntry &entry : projectEntries) { + m_pchTaskGenerator.addNonSystemProjectParts(std::move(deferredProjects), + std::move(entry.arguments)); } } } diff --git a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h index a65ab803df0..d781c96e529 100644 --- a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h +++ b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorage.h @@ -125,6 +125,20 @@ public: } } + void deleteSystemAndProjectPrecompiledHeaders(const ProjectPartIds &projectPartIds) override + { + try { + Sqlite::ImmediateTransaction transaction{database}; + + for (ProjectPartId projectPartId : projectPartIds) + deleteSystemAndProjectPrecompiledHeaderStatement.write(projectPartId.projectPathId); + + transaction.commit(); + } catch (const Sqlite::StatementIsBusy) { + deleteSystemAndProjectPrecompiledHeaders(projectPartIds); + } + } + FilePath fetchSystemPrecompiledHeaderPath(ProjectPartId projectPartId) override { try { @@ -230,6 +244,11 @@ public: "UPDATE OR IGNORE precompiledHeaders SET systemPchPath=NULL,systemPchBuildTime=NULL " "WHERE projectPartId = ?", database}; + WriteStatement deleteSystemAndProjectPrecompiledHeaderStatement{ + "UPDATE OR IGNORE precompiledHeaders SET " + "systemPchPath=NULL,systemPchBuildTime=NULL,projectPchPath=NULL,projectPchBuildTime=NULL " + "WHERE projectPartId = ?", + database}; ReadStatement fetchSystemPrecompiledHeaderPathStatement{ "SELECT systemPchPath FROM precompiledHeaders WHERE projectPartId = ?", database}; mutable ReadStatement fetchPrecompiledHeaderStatement{ diff --git a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h index dacdbe9e177..92b3604cdc4 100644 --- a/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h +++ b/src/tools/clangpchmanagerbackend/source/precompiledheaderstorageinterface.h @@ -55,6 +55,7 @@ public: TimeStamp pchBuildTime) = 0; virtual void deleteSystemPrecompiledHeaders(const ProjectPartIds &projectPartIds) = 0; + virtual void deleteSystemAndProjectPrecompiledHeaders(const ProjectPartIds &projectPartIds) = 0; virtual FilePath fetchSystemPrecompiledHeaderPath(ProjectPartId projectPartId) = 0; virtual FilePath fetchPrecompiledHeader(ProjectPartId projectPartId) const = 0; virtual PchPaths fetchPrecompiledHeaders(ProjectPartId projectPartId) const = 0; diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp index 191a13e16b9..f618559e401 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.cpp @@ -25,7 +25,11 @@ #include "projectpartsmanager.h" +#include +#include +#include #include +#include #include @@ -44,38 +48,171 @@ ProjectPartIds toProjectPartIds(const ProjectPartContainers &projectsParts) return ids; } -ProjectPartsManager::UpToDataProjectParts ProjectPartsManager::update(ProjectPartContainers &&projectsParts) +namespace { + +enum class Change { System, Project, No }; + +Change changedSourceType(const SourceEntries &sources) { - auto notUpToDateProjectParts = filterProjectParts(projectsParts, m_projectParts); - - if (notUpToDateProjectParts.empty()) - return {std::move(projectsParts), {}}; - - auto persistentProjectParts = m_projectPartsStorage.fetchProjectParts( - toProjectPartIds(notUpToDateProjectParts)); - - if (persistentProjectParts.size() > 0) { - mergeProjectParts(persistentProjectParts); - - notUpToDateProjectParts = filterProjectParts(notUpToDateProjectParts, persistentProjectParts); - - if (notUpToDateProjectParts.empty()) - return {}; + Change change = Change::No; + for (SourceEntry sourceEntry : sources) { + switch (sourceEntry.sourceType) { + case SourceType::SystemInclude: + case SourceType::TopSystemInclude: + return Change::System; + case SourceType::ProjectInclude: + case SourceType::TopProjectInclude: + change = Change::Project; + break; + case SourceType::Source: + case SourceType::UserInclude: + break; + } } - m_projectPartsStorage.updateProjectParts(notUpToDateProjectParts); - m_projectPartsStorage.resetIndexingTimeStamps(notUpToDateProjectParts); - m_precompiledHeaderStorage.deleteProjectPrecompiledHeaders( - toProjectPartIds(notUpToDateProjectParts)); - - mergeProjectParts(notUpToDateProjectParts); - - auto upToDateProjectParts = filterProjectParts(projectsParts, notUpToDateProjectParts); - - return {upToDateProjectParts, notUpToDateProjectParts}; + return change; } -void ProjectPartsManager::remove(const ProjectPartIds &projectPartIds) +} // namespace + +ProjectPartsManager::UpToDataProjectParts ProjectPartsManager::update(ProjectPartContainers &&projectsParts) +{ + auto updateSystemProjectParts = filterProjectParts(projectsParts, m_projectParts); + + if (!updateSystemProjectParts.empty()) { + auto persistentProjectParts = m_projectPartsStorage.fetchProjectParts( + toProjectPartIds(updateSystemProjectParts)); + + if (persistentProjectParts.size() > 0) { + mergeProjectParts(persistentProjectParts); + + updateSystemProjectParts = filterProjectParts(updateSystemProjectParts, + persistentProjectParts); + } + + if (updateSystemProjectParts.size()) { + m_projectPartsStorage.updateProjectParts(updateSystemProjectParts); + + mergeProjectParts(updateSystemProjectParts); + } + } + + auto upToDateProjectParts = filterProjectParts(projectsParts, updateSystemProjectParts); + + auto updates = checkDependeciesAndTime(std::move(upToDateProjectParts), + std::move(updateSystemProjectParts)); + + if (updates.updateSystem.size()) { + m_projectPartsStorage.resetIndexingTimeStamps(updates.updateSystem); + m_precompiledHeaderStorage.deleteSystemAndProjectPrecompiledHeaders( + toProjectPartIds(updates.updateSystem)); + } + if (updates.updateProject.size()) { + m_projectPartsStorage.resetIndexingTimeStamps(updates.updateProject); + m_precompiledHeaderStorage.deleteProjectPrecompiledHeaders( + toProjectPartIds(updates.updateProject)); + } + + return updates; +} + +ProjectPartsManagerInterface::UpToDataProjectParts ProjectPartsManager::checkDependeciesAndTime( + ProjectPartContainers &&upToDateProjectParts, ProjectPartContainers &&updateSystemProjectParts) +{ + ProjectPartContainerReferences changeProjectParts; + changeProjectParts.reserve(upToDateProjectParts.size()); + + ProjectPartContainers updateProjectProjectParts; + updateProjectProjectParts.reserve(upToDateProjectParts.size()); + + updateSystemProjectParts.reserve(updateProjectProjectParts.size() + upToDateProjectParts.size()); + + auto systemSplit = updateSystemProjectParts.end(); + + for (ProjectPartContainer &projectPart : upToDateProjectParts) { + auto oldSources = m_buildDependenciesProvider.createSourceEntriesFromStorage( + projectPart.sourcePathIds, projectPart.projectPartId); + + BuildDependency buildDependency = m_buildDependenciesProvider.create(projectPart, + Utils::clone(oldSources)); + + auto newSources = buildDependency.sources; + + SourceEntries updatedSourceTyes; + updatedSourceTyes.reserve(newSources.size()); + + std::set_symmetric_difference(newSources.begin(), + newSources.end(), + oldSources.begin(), + oldSources.end(), + std::back_inserter(updatedSourceTyes), + [](SourceEntry first, SourceEntry second) { + return std::tie(first.sourceId, first.sourceType) + < std::tie(second.sourceId, second.sourceType); + }); + + auto change = changedSourceType(updatedSourceTyes); + + switch (change) { + case Change::Project: + updateProjectProjectParts.emplace_back(std::move(projectPart)); + projectPart.projectPartId = -1; + break; + case Change::System: + updateSystemProjectParts.emplace_back(std::move(projectPart)); + projectPart.projectPartId = -1; + break; + case Change::No: + break; + } + + if (change == Change::No) { + SourceEntries updatedTimeStamps; + updatedTimeStamps.reserve(newSources.size()); + + std::set_difference(newSources.begin(), + newSources.end(), + oldSources.begin(), + oldSources.end(), + std::back_inserter(updatedTimeStamps), + [](SourceEntry first, SourceEntry second) { + return std::tie(first.sourceId, first.timeStamp) + < std::tie(second.sourceId, second.timeStamp); + }); + + auto change = changedSourceType(updatedTimeStamps); + + switch (change) { + case Change::Project: + updateProjectProjectParts.emplace_back(std::move(projectPart)); + projectPart.projectPartId = -1; + break; + case Change::System: + updateSystemProjectParts.emplace_back(std::move(projectPart)); + projectPart.projectPartId = -1; + break; + case Change::No: + break; + } + } + } + + std::inplace_merge(updateSystemProjectParts.begin(), systemSplit, updateSystemProjectParts.end()); + upToDateProjectParts.erase(std::remove_if(upToDateProjectParts.begin(), + upToDateProjectParts.end(), + [](const ProjectPartContainer &projectPart) { + return !projectPart.projectPartId.isValid(); + }), + upToDateProjectParts.end()); + + return {std::move(upToDateProjectParts), + std::move(updateSystemProjectParts), + updateProjectProjectParts}; +} + +namespace { +ProjectPartContainers removed(ProjectPartContainers &&projectParts, + const ProjectPartIds &projectPartIds) { ProjectPartContainers projectPartsWithoutIds; @@ -99,14 +236,22 @@ void ProjectPartsManager::remove(const ProjectPartIds &projectPartIds) } }; - std::set_difference(std::make_move_iterator(m_projectParts.begin()), - std::make_move_iterator(m_projectParts.end()), + std::set_difference(std::make_move_iterator(projectParts.begin()), + std::make_move_iterator(projectParts.end()), projectPartIds.begin(), projectPartIds.end(), std::back_inserter(projectPartsWithoutIds), Compare{}); - m_projectParts = std::move(projectPartsWithoutIds); + return projectPartsWithoutIds; +} +} // namespace + +void ProjectPartsManager::remove(const ProjectPartIds &projectPartIds) +{ + m_projectParts = removed(std::move(m_projectParts), projectPartIds); + m_systemDeferredProjectParts = removed(std::move(m_systemDeferredProjectParts), projectPartIds); + m_projectDeferredProjectParts = removed(std::move(m_projectDeferredProjectParts), projectPartIds); } ProjectPartContainers ProjectPartsManager::projects(const ProjectPartIds &projectPartIds) const @@ -143,38 +288,42 @@ ProjectPartContainers ProjectPartsManager::projects(const ProjectPartIds &projec return projectPartsWithIds; } -void ProjectPartsManager::updateDeferred(const ProjectPartContainers &deferredProjectsParts) +namespace { +ProjectPartContainers merge(ProjectPartContainers &&newProjectParts, + ProjectPartContainers &&oldProjectParts) { - ProjectPartContainerReferences deferredProjectPartPointers; - deferredProjectPartPointers.reserve(deferredProjectsParts.size()); + ProjectPartContainers mergedProjectParts; + mergedProjectParts.reserve(newProjectParts.size() + oldProjectParts.size()); - std::set_intersection(m_projectParts.begin(), - m_projectParts.end(), - deferredProjectsParts.begin(), - deferredProjectsParts.end(), - std::back_inserter(deferredProjectPartPointers), - [](const ProjectPartContainer &first, const ProjectPartContainer &second) { - return first.projectPartId < second.projectPartId; - }); + std::set_union(std::make_move_iterator(newProjectParts.begin()), + std::make_move_iterator(newProjectParts.end()), + std::make_move_iterator(oldProjectParts.begin()), + std::make_move_iterator(oldProjectParts.end()), + std::back_inserter(mergedProjectParts), + [](const ProjectPartContainer &first, const ProjectPartContainer &second) { + return first.projectPartId < second.projectPartId; + }); - for (ProjectPartContainer &projectPart : deferredProjectPartPointers) - projectPart.updateIsDeferred = true; + return mergedProjectParts; +} +} // namespace + +void ProjectPartsManager::updateDeferred(ProjectPartContainers &&system, + ProjectPartContainers &&project) +{ + m_systemDeferredProjectParts = merge(std::move(system), std::move(m_systemDeferredProjectParts)); + m_projectDeferredProjectParts = merge(std::move(project), + std::move(m_projectDeferredProjectParts)); } -ProjectPartContainers ProjectPartsManager::deferredUpdates() +ProjectPartContainers ProjectPartsManager::deferredSystemUpdates() { - ProjectPartContainers deferredProjectParts; - deferredProjectParts.reserve(m_projectParts.size()); + return std::move(m_systemDeferredProjectParts); +} - std::copy_if(m_projectParts.cbegin(), - m_projectParts.cend(), - std::back_inserter(deferredProjectParts), - [](const ProjectPartContainer &projectPart) { return projectPart.updateIsDeferred; }); - - for (ProjectPartContainer &projectPart : m_projectParts) - projectPart.updateIsDeferred = false; - - return deferredProjectParts; +ProjectPartContainers ProjectPartsManager::deferredProjectUpdates() +{ + return std::move(m_projectDeferredProjectParts); } ProjectPartContainers ProjectPartsManager::filterProjectParts( diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h index 35d9e41c1cc..e32c41fde18 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanager.h @@ -35,32 +35,42 @@ namespace ClangBackEnd { +class BuildDependenciesProviderInterface; + inline namespace Pch { class ProjectPartsManager final : public ProjectPartsManagerInterface { public: ProjectPartsManager(ProjectPartsStorageInterface &projectPartsStorage, - PrecompiledHeaderStorageInterface &precompiledHeaderStorage) + PrecompiledHeaderStorageInterface &precompiledHeaderStorage, + BuildDependenciesProviderInterface &buildDependenciesProvider) : m_projectPartsStorage(projectPartsStorage) , m_precompiledHeaderStorage(precompiledHeaderStorage) + , m_buildDependenciesProvider(buildDependenciesProvider) {} UpToDataProjectParts update(ProjectPartContainers &&projectsParts) override; void remove(const ProjectPartIds &projectPartIds) override; ProjectPartContainers projects(const ProjectPartIds &projectPartIds) const override; - void updateDeferred(const ProjectPartContainers &projectsParts) override; - ProjectPartContainers deferredUpdates() override; + void updateDeferred(ProjectPartContainers &&system, ProjectPartContainers &&project) override; + ProjectPartContainers deferredSystemUpdates() override; + ProjectPartContainers deferredProjectUpdates() override; static ProjectPartContainers filterProjectParts(const ProjectPartContainers &newProjectsParts, const ProjectPartContainers &oldProjectParts); void mergeProjectParts(const ProjectPartContainers &projectsParts); const ProjectPartContainers &projectParts() const; + UpToDataProjectParts checkDependeciesAndTime(ProjectPartContainers &&upToDateProjectParts, + ProjectPartContainers &&updateSystemProjectParts); private: ProjectPartContainers m_projectParts; + ProjectPartContainers m_systemDeferredProjectParts; + ProjectPartContainers m_projectDeferredProjectParts; ProjectPartsStorageInterface &m_projectPartsStorage; PrecompiledHeaderStorageInterface &m_precompiledHeaderStorage; + BuildDependenciesProviderInterface &m_buildDependenciesProvider; }; } // namespace Pch diff --git a/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h b/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h index 54bae58c1ad..696839c4b8d 100644 --- a/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h +++ b/src/tools/clangpchmanagerbackend/source/projectpartsmanagerinterface.h @@ -36,7 +36,8 @@ public: { public: ProjectPartContainers upToDate; - ProjectPartContainers notUpToDate; + ProjectPartContainers updateSystem; + ProjectPartContainers updateProject; }; ProjectPartsManagerInterface() = default; @@ -46,8 +47,9 @@ public: virtual UpToDataProjectParts update(ProjectPartContainers &&projectsParts) = 0; virtual void remove(const ProjectPartIds &projectPartIds) = 0; virtual ProjectPartContainers projects(const ProjectPartIds &projectPartIds) const = 0; - virtual void updateDeferred(const ProjectPartContainers &projectsParts) = 0; - virtual ProjectPartContainers deferredUpdates() = 0; + virtual void updateDeferred(ProjectPartContainers &&system, ProjectPartContainers &&project) = 0; + virtual ProjectPartContainers deferredSystemUpdates() = 0; + virtual ProjectPartContainers deferredProjectUpdates() = 0; protected: ~ProjectPartsManagerInterface() = default; diff --git a/tests/unit/unittest/mockprecompiledheaderstorage.h b/tests/unit/unittest/mockprecompiledheaderstorage.h index 4d6fecbbfe3..de755e07eb7 100644 --- a/tests/unit/unittest/mockprecompiledheaderstorage.h +++ b/tests/unit/unittest/mockprecompiledheaderstorage.h @@ -46,6 +46,8 @@ public: ClangBackEnd::TimeStamp pchBuildTime)); MOCK_METHOD1(deleteSystemPrecompiledHeaders, void(const ClangBackEnd::ProjectPartIds &projectPartIds)); + MOCK_METHOD1(deleteSystemAndProjectPrecompiledHeaders, + void(const ClangBackEnd::ProjectPartIds &projectPartIds)); MOCK_METHOD1(fetchSystemPrecompiledHeaderPath, ClangBackEnd::FilePath(ClangBackEnd::ProjectPartId projectPartId)); MOCK_CONST_METHOD1(fetchPrecompiledHeader, diff --git a/tests/unit/unittest/mockprojectpartsmanager.h b/tests/unit/unittest/mockprojectpartsmanager.h index 613faf7dfca..d458cb7231e 100644 --- a/tests/unit/unittest/mockprojectpartsmanager.h +++ b/tests/unit/unittest/mockprojectpartsmanager.h @@ -39,12 +39,21 @@ public: MOCK_CONST_METHOD1( projects, ClangBackEnd::ProjectPartContainers(const ClangBackEnd::ProjectPartIds &projectPartIds)); - MOCK_METHOD1(updateDeferred, void(const ClangBackEnd::ProjectPartContainers &projectsParts)); - MOCK_METHOD0(deferredUpdates, ClangBackEnd::ProjectPartContainers()); + MOCK_METHOD2(updateDeferred, + void(const ClangBackEnd::ProjectPartContainers &system, + const ClangBackEnd::ProjectPartContainers &project)); + MOCK_METHOD0(deferredSystemUpdates, ClangBackEnd::ProjectPartContainers()); + MOCK_METHOD0(deferredProjectUpdates, ClangBackEnd::ProjectPartContainers()); ClangBackEnd::ProjectPartsManagerInterface::UpToDataProjectParts update( ClangBackEnd::ProjectPartContainers &&projectsParts) override { return update(projectsParts); } + + void updateDeferred(ClangBackEnd::ProjectPartContainers &&system, + ClangBackEnd::ProjectPartContainers &&project) override + { + return updateDeferred(system, project); + } }; diff --git a/tests/unit/unittest/pchmanagerserver-test.cpp b/tests/unit/unittest/pchmanagerserver-test.cpp index 94b7d82e286..d7e6c492f9a 100644 --- a/tests/unit/unittest/pchmanagerserver-test.cpp +++ b/tests/unit/unittest/pchmanagerserver-test.cpp @@ -59,7 +59,7 @@ class PchManagerServer : public ::testing::Test server.setClient(&mockPchManagerClient); ON_CALL(mockProjectPartsManager, update(projectParts)) - .WillByDefault(Return(UpToDataProjectParts{{}, projectParts})); + .WillByDefault(Return(UpToDataProjectParts{{}, projectParts, projectParts4})); ON_CALL(mockGeneratedFiles, isValid()).WillByDefault(Return(true)); } @@ -163,6 +163,8 @@ protected: std::vector projectParts{projectPart1, projectPart2}; std::vector projectParts1{projectPart1}; std::vector projectParts2{projectPart2}; + std::vector projectParts3{projectPart3}; + std::vector projectParts4{projectPart3, projectPart4}; FileContainer generatedFile{{"/path/to/", "file"}, "content", {}}; ClangBackEnd::UpdateProjectPartsMessage updateProjectPartsMessage{ Utils::clone(projectParts), {"toolChainArgument"}}; @@ -175,9 +177,11 @@ TEST_F(PchManagerServer, FilterProjectPartsAndSendThemToQueue) InSequence s; EXPECT_CALL(mockProjectPartsManager, update(updateProjectPartsMessage.projectsParts)) - .WillOnce(Return(UpToDataProjectParts{{}, projectParts2})); + .WillOnce(Return(UpToDataProjectParts{{}, projectParts2, projectParts4})); EXPECT_CALL( mockPchTaskGenerator, addProjectParts(Eq(projectParts2), ElementsAre("toolChainArgument"))); + EXPECT_CALL(mockPchTaskGenerator, + addNonSystemProjectParts(Eq(projectParts4), ElementsAre("toolChainArgument"))); server.updateProjectParts(updateProjectPartsMessage.clone()); } @@ -267,6 +271,7 @@ TEST_F(PchManagerServer, DontUpdateProjectPartQueueByPathIdsIfItUserFile) EXPECT_CALL(mockProjectPartsManager, projects(_)).Times(0); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); + EXPECT_CALL(mockPchTaskGenerator, addNonSystemProjectParts(_, _)).Times(0); server.pathsWithIdsChanged({{{projectPartId1, ClangBackEnd::SourceType::UserInclude}, {}}, {{projectPartId2, ClangBackEnd::SourceType::Source}, {}}}); @@ -323,6 +328,7 @@ TEST_F(PchManagerServer, RemoveToolChainsArguments) ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); + EXPECT_CALL(mockPchTaskGenerator, addNonSystemProjectParts(_, _)).Times(0); server.removeProjectParts(removeProjectPartsMessage.clone()); server.pathsWithIdsChanged({{{projectPart1.projectPartId, ClangBackEnd::SourceType::Source}, {}}}); @@ -333,10 +339,12 @@ TEST_F(PchManagerServer, DontGeneratePchIfGeneratedFilesAreNotValid) InSequence s; EXPECT_CALL(mockProjectPartsManager, update(ElementsAre(projectPart1))) - .WillOnce(Return(UpToDataProjectParts{{}, ProjectPartContainers{projectPart1}})); + .WillOnce(Return(UpToDataProjectParts{{}, {projectPart1}, {projectPart2}})); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(false)); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); - EXPECT_CALL(mockProjectPartsManager, updateDeferred(ElementsAre(projectPart1))); + EXPECT_CALL(mockPchTaskGenerator, addNonSystemProjectParts(_, _)).Times(0); + EXPECT_CALL(mockProjectPartsManager, + updateDeferred(ElementsAre(projectPart1), ElementsAre(projectPart2))); server.updateProjectParts( ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); @@ -347,10 +355,11 @@ TEST_F(PchManagerServer, GeneratePchIfGeneratedFilesAreValid) InSequence s; EXPECT_CALL(mockProjectPartsManager, update(ElementsAre(projectPart1))) - .WillOnce(Return(UpToDataProjectParts{{}, ProjectPartContainers{projectPart1}})); + .WillOnce(Return(UpToDataProjectParts{{}, {projectPart1}, {projectPart2}})); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(true)); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)); - EXPECT_CALL(mockProjectPartsManager, updateDeferred(_)).Times(0); + EXPECT_CALL(mockPchTaskGenerator, addNonSystemProjectParts(_, _)); + EXPECT_CALL(mockProjectPartsManager, updateDeferred(_, _)).Times(0); server.updateProjectParts( ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); @@ -361,15 +370,19 @@ TEST_F(PchManagerServer, AfterUpdatingGeneratedFilesAreValidSoGeneratePchs) InSequence s; ClangBackEnd::UpdateGeneratedFilesMessage updateGeneratedFilesMessage{{generatedFile}}; ON_CALL(mockGeneratedFiles, isValid()).WillByDefault(Return(false)); - server.updateProjectParts( - ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); + server.updateProjectParts(ClangBackEnd::UpdateProjectPartsMessage{{projectPart1, projectPart2}, + {"toolChainArgument"}}); EXPECT_CALL(mockGeneratedFiles, update(updateGeneratedFilesMessage.generatedFiles)); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(true)); - EXPECT_CALL(mockProjectPartsManager, deferredUpdates()) + EXPECT_CALL(mockProjectPartsManager, deferredSystemUpdates()) .WillOnce(Return(ClangBackEnd::ProjectPartContainers{projectPart1})); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(ElementsAre(projectPart1), ElementsAre("toolChainArgument"))); + EXPECT_CALL(mockProjectPartsManager, deferredProjectUpdates()) + .WillOnce(Return(ClangBackEnd::ProjectPartContainers{projectPart2})); + EXPECT_CALL(mockPchTaskGenerator, + addNonSystemProjectParts(ElementsAre(projectPart2), ElementsAre("toolChainArgument"))); server.updateGeneratedFiles(updateGeneratedFilesMessage.clone()); } @@ -379,13 +392,14 @@ TEST_F(PchManagerServer, AfterUpdatingGeneratedFilesAreStillInvalidSoNoPchsGener InSequence s; ClangBackEnd::UpdateGeneratedFilesMessage updateGeneratedFilesMessage{{generatedFile}}; ON_CALL(mockGeneratedFiles, isValid()).WillByDefault(Return(false)); - server.updateProjectParts( - ClangBackEnd::UpdateProjectPartsMessage{{projectPart1}, {"toolChainArgument"}}); + server.updateProjectParts(ClangBackEnd::UpdateProjectPartsMessage{{projectPart1, projectPart2}, + {"toolChainArgument"}}); EXPECT_CALL(mockGeneratedFiles, update(updateGeneratedFilesMessage.generatedFiles)); EXPECT_CALL(mockGeneratedFiles, isValid()).WillOnce(Return(false)); - EXPECT_CALL(mockProjectPartsManager, deferredUpdates()).Times(0); + EXPECT_CALL(mockProjectPartsManager, deferredSystemUpdates()).Times(0); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(_, _)).Times(0); + EXPECT_CALL(mockPchTaskGenerator, addNonSystemProjectParts(_, _)).Times(0); server.updateGeneratedFiles(updateGeneratedFilesMessage.clone()); } @@ -395,7 +409,7 @@ TEST_F(PchManagerServer, SentUpToDateProjectPartIdsToClient) InSequence s; EXPECT_CALL(mockProjectPartsManager, update(updateProjectPartsMessage.projectsParts)) - .WillOnce(Return(UpToDataProjectParts{projectParts1, projectParts2})); + .WillOnce(Return(UpToDataProjectParts{projectParts1, projectParts2, projectParts3})); EXPECT_CALL(mockPchTaskGenerator, addProjectParts(Eq(projectParts2), ElementsAre("toolChainArgument"))); EXPECT_CALL(mockPchManagerClient, diff --git a/tests/unit/unittest/pchtaskqueue-test.cpp b/tests/unit/unittest/pchtaskqueue-test.cpp index efb4eae2da6..f5168588624 100644 --- a/tests/unit/unittest/pchtaskqueue-test.cpp +++ b/tests/unit/unittest/pchtaskqueue-test.cpp @@ -47,7 +47,7 @@ class PchTaskQueue : public testing::Test protected: NiceMock> mockSytemPchTaskScheduler; NiceMock> mockProjectPchTaskScheduler; - MockPrecompiledHeaderStorage mockPrecompiledHeaderStorage; + NiceMock mockPrecompiledHeaderStorage; MockSqliteTransactionBackend mockSqliteTransactionBackend; NiceMock> mockSetProgressCallback; ClangBackEnd::ProgressCounter progressCounter{mockSetProgressCallback.AsStdFunction()}; diff --git a/tests/unit/unittest/precompiledheaderstorage-test.cpp b/tests/unit/unittest/precompiledheaderstorage-test.cpp index 9153e92afac..8b3727decd8 100644 --- a/tests/unit/unittest/precompiledheaderstorage-test.cpp +++ b/tests/unit/unittest/precompiledheaderstorage-test.cpp @@ -48,6 +48,7 @@ protected: = storage.deleteProjectPrecompiledHeaderPathAndSetBuildTimeStatement; MockSqliteWriteStatement &insertSystemPrecompiledHeaderStatement = storage.insertSystemPrecompiledHeaderStatement; MockSqliteWriteStatement &deleteSystemPrecompiledHeaderStatement = storage.deleteSystemPrecompiledHeaderStatement; + MockSqliteWriteStatement &deleteSystemAndProjectPrecompiledHeaderStatement = storage.deleteSystemAndProjectPrecompiledHeaderStatement; MockSqliteReadStatement &fetchSystemPrecompiledHeaderPathStatement = storage.fetchSystemPrecompiledHeaderPathStatement; MockSqliteReadStatement &fetchPrecompiledHeaderStatement = storage.fetchPrecompiledHeaderStatement; MockSqliteReadStatement &fetchPrecompiledHeadersStatement = storage.fetchPrecompiledHeadersStatement; @@ -205,6 +206,31 @@ TEST_F(PrecompiledHeaderStorage, DeleteSystemPrecompiledHeadersStatementIsBusy) storage.deleteSystemPrecompiledHeaders({1, 2}); } +TEST_F(PrecompiledHeaderStorage, DeleteSystemAndProjectPrecompiledHeaders) +{ + InSequence s; + + EXPECT_CALL(database, immediateBegin()); + EXPECT_CALL(deleteSystemAndProjectPrecompiledHeaderStatement, write(TypedEq(1))); + EXPECT_CALL(deleteSystemAndProjectPrecompiledHeaderStatement, write(TypedEq(2))); + EXPECT_CALL(database, commit()); + + storage.deleteSystemAndProjectPrecompiledHeaders({1, 2}); +} + +TEST_F(PrecompiledHeaderStorage, DeleteSystemAndProjectPrecompiledHeadersStatementIsBusy) +{ + InSequence s; + + EXPECT_CALL(database, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy"))); + EXPECT_CALL(database, immediateBegin()); + EXPECT_CALL(deleteSystemAndProjectPrecompiledHeaderStatement, write(TypedEq(1))); + EXPECT_CALL(deleteSystemAndProjectPrecompiledHeaderStatement, write(TypedEq(2))); + EXPECT_CALL(database, commit()); + + storage.deleteSystemAndProjectPrecompiledHeaders({1, 2}); +} + TEST_F(PrecompiledHeaderStorage, CompilePrecompiledHeaderStatements) { Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory}; diff --git a/tests/unit/unittest/projectpartsmanager-test.cpp b/tests/unit/unittest/projectpartsmanager-test.cpp index 27d1142689a..877c28f8a80 100644 --- a/tests/unit/unittest/projectpartsmanager-test.cpp +++ b/tests/unit/unittest/projectpartsmanager-test.cpp @@ -24,6 +24,9 @@ ****************************************************************************/ #include "googletest.h" +#include "mockbuilddependenciesprovider.h" +#include "mockfilepathcaching.h" +#include "mockgeneratedfiles.h" #include "mockprecompiledheaderstorage.h" #include "mockprojectpartsstorage.h" @@ -37,6 +40,8 @@ using ClangBackEnd::FilePathId; using ClangBackEnd::ProjectPartContainer; using ClangBackEnd::ProjectPartContainers; using UpToDataProjectParts = ClangBackEnd::ProjectPartsManagerInterface::UpToDataProjectParts; +using ClangBackEnd::SourceEntries; +using ClangBackEnd::SourceType; class ProjectPartsManager : public testing::Test { @@ -47,8 +52,10 @@ protected: } NiceMock mockProjectPartsStorage; NiceMock mockPrecompiledHeaderStorage; - - ClangBackEnd::ProjectPartsManager manager{mockProjectPartsStorage, mockPrecompiledHeaderStorage}; + NiceMock mockBuildDependenciesProvider; + ClangBackEnd::ProjectPartsManager manager{mockProjectPartsStorage, + mockPrecompiledHeaderStorage, + mockBuildDependenciesProvider}; FilePathId firstHeader{1}; FilePathId secondHeader{2}; FilePathId firstSource{11}; @@ -101,13 +108,36 @@ protected: 2, {"-DUNIX", "-O2"}, {{"DEFINE", "1", 1}}, - {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::BuiltIn}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::System}}, {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, - {firstHeader, secondHeader}, - {firstSource, secondSource}, - Utils::Language::C, - Utils::LanguageVersion::C11, + {firstHeader}, + {firstSource}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX14, Utils::LanguageExtension::All}; + ProjectPartContainer projectPartContainer3{ + 3, + {"-DUNIX", "-O2"}, + {{"DEFINE", "1", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::Framework}}, + {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {secondHeader}, + {firstSource}, + Utils::Language::C, + Utils::LanguageVersion::C18, + Utils::LanguageExtension::All}; + ProjectPartContainer projectPartContainer4{ + 4, + {"-DUNIX", "-O2"}, + {{"DEFINE", "1", 1}}, + {{"/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {{"/project/includes", 1, ClangBackEnd::IncludeSearchPathType::User}}, + {firstHeader}, + {firstSource}, + Utils::Language::Cxx, + Utils::LanguageVersion::CXX03, + Utils::LanguageExtension::All}; + ClangBackEnd::V2::FileContainers generatedFiles; }; TEST_F(ProjectPartsManager, GetNoProjectPartsForAddingEmptyProjectParts) @@ -116,7 +146,7 @@ TEST_F(ProjectPartsManager, GetNoProjectPartsForAddingEmptyProjectParts) ASSERT_THAT(projectParts, AllOf(Field(&UpToDataProjectParts::upToDate, IsEmpty()), - Field(&UpToDataProjectParts::notUpToDate, IsEmpty()))); + Field(&UpToDataProjectParts::updateSystem, IsEmpty()))); } TEST_F(ProjectPartsManager, GetProjectPartForAddingProjectPart) @@ -125,7 +155,7 @@ TEST_F(ProjectPartsManager, GetProjectPartForAddingProjectPart) ASSERT_THAT(projectParts, AllOf(Field(&UpToDataProjectParts::upToDate, IsEmpty()), - Field(&UpToDataProjectParts::notUpToDate, ElementsAre(projectPartContainer1)))); + Field(&UpToDataProjectParts::updateSystem, ElementsAre(projectPartContainer1)))); } TEST_F(ProjectPartsManager, GetProjectPartForAddingProjectPartWithProjectPartAlreadyInTheDatabase) @@ -137,7 +167,7 @@ TEST_F(ProjectPartsManager, GetProjectPartForAddingProjectPartWithProjectPartAlr ASSERT_THAT(projectParts, AllOf(Field(&UpToDataProjectParts::upToDate, ElementsAre(projectPartContainer1)), - Field(&UpToDataProjectParts::notUpToDate, ElementsAre(projectPartContainer2)))); + Field(&UpToDataProjectParts::updateSystem, ElementsAre(projectPartContainer2)))); } TEST_F(ProjectPartsManager, GetProjectPartForAddingProjectPartWithOlderProjectPartAlreadyInTheDatabase) @@ -149,7 +179,7 @@ TEST_F(ProjectPartsManager, GetProjectPartForAddingProjectPartWithOlderProjectPa ASSERT_THAT(projectParts, AllOf(Field(&UpToDataProjectParts::upToDate, IsEmpty()), - Field(&UpToDataProjectParts::notUpToDate, + Field(&UpToDataProjectParts::updateSystem, ElementsAre(updatedProjectPartContainer1, projectPartContainer2)))); } @@ -198,7 +228,7 @@ TEST_F(ProjectPartsManager, DoNotUpdateNotNewProjectPart) ASSERT_THAT(projectParts, AllOf(Field(&UpToDataProjectParts::upToDate, ElementsAre(projectPartContainer1)), - Field(&UpToDataProjectParts::notUpToDate, IsEmpty()))); + Field(&UpToDataProjectParts::updateSystem, IsEmpty()))); } TEST_F(ProjectPartsManager, NoDuplicateProjectPartAfterUpdatingWithNotNewProjectPart) @@ -242,7 +272,7 @@ TEST_F(ProjectPartsManager, GetUpdatedProjectPart) ASSERT_THAT(projectParts, AllOf(Field(&UpToDataProjectParts::upToDate, IsEmpty()), - Field(&UpToDataProjectParts::notUpToDate, + Field(&UpToDataProjectParts::updateSystem, ElementsAre(updatedProjectPartContainer1)))); } @@ -265,6 +295,24 @@ TEST_F(ProjectPartsManager, Remove) ASSERT_THAT(manager.projectParts(), ElementsAre(projectPartContainer2)); } +TEST_F(ProjectPartsManager, RemoveSystemDeferred) +{ + manager.updateDeferred({projectPartContainer1, projectPartContainer2}, {}); + + manager.remove({projectPartContainer1.projectPartId}); + + ASSERT_THAT(manager.deferredSystemUpdates(), ElementsAre(projectPartContainer2)); +} + +TEST_F(ProjectPartsManager, RemoveProjectDeferred) +{ + manager.updateDeferred({}, {projectPartContainer1, projectPartContainer2}); + + manager.remove({projectPartContainer1.projectPartId}); + + ASSERT_THAT(manager.deferredProjectUpdates(), ElementsAre(projectPartContainer2)); +} + TEST_F(ProjectPartsManager, GetProjectById) { manager.update({projectPartContainer1, projectPartContainer2}); @@ -284,40 +332,84 @@ TEST_F(ProjectPartsManager, GetProjectsByIds) ASSERT_THAT(projectPartContainers, UnorderedElementsAre(projectPartContainer1, projectPartContainer2)); } -TEST_F(ProjectPartsManager, UpdateDeferred) +TEST_F(ProjectPartsManager, UpdateSystemDeferred) { - auto projectPartContainers = manager.update({projectPartContainer1, projectPartContainer2}); + manager.updateDeferred({projectPartContainer1}, {}); - manager.updateDeferred({projectPartContainer1}); - - ASSERT_THAT(manager.deferredUpdates(), ElementsAre(projectPartContainer1)); + ASSERT_THAT(manager.deferredSystemUpdates(), ElementsAre(projectPartContainer1)); } -TEST_F(ProjectPartsManager, NotUpdateDeferred) +TEST_F(ProjectPartsManager, UpdateProjectDeferred) { - manager.update({projectPartContainer1, projectPartContainer2}); + manager.updateDeferred({}, {projectPartContainer1}); - ASSERT_THAT(manager.deferredUpdates(), IsEmpty()); + ASSERT_THAT(manager.deferredProjectUpdates(), ElementsAre(projectPartContainer1)); } -TEST_F(ProjectPartsManager, UpdateDeferredCleansDeferredUpdates) +TEST_F(ProjectPartsManager, NotUpdateSystemDeferred) { - manager.update({projectPartContainer1, projectPartContainer2}); - manager.updateDeferred({projectPartContainer1}); - - manager.deferredUpdates(); - - ASSERT_THAT(manager.deferredUpdates(), IsEmpty()); + ASSERT_THAT(manager.deferredSystemUpdates(), IsEmpty()); } +TEST_F(ProjectPartsManager, NotUpdateProjectDeferred) +{ + ASSERT_THAT(manager.deferredProjectUpdates(), IsEmpty()); +} + +TEST_F(ProjectPartsManager, UpdateSystemDeferredCleansDeferredUpdates) +{ + manager.updateDeferred({projectPartContainer1}, {}); + + manager.deferredSystemUpdates(); + + ASSERT_THAT(manager.deferredSystemUpdates(), IsEmpty()); +} + +TEST_F(ProjectPartsManager, UpdateProjectDeferredCleansDeferredUpdates) +{ + manager.updateDeferred({}, {projectPartContainer1}); + + manager.deferredProjectUpdates(); + + ASSERT_THAT(manager.deferredProjectUpdates(), IsEmpty()); +} + +TEST_F(ProjectPartsManager, UpdateSystemDeferredMultiple) +{ + manager.updateDeferred({projectPartContainer1, projectPartContainer3}, {}); + + manager.updateDeferred({updatedProjectPartContainer1, projectPartContainer2, projectPartContainer4}, + {}); + + ASSERT_THAT(manager.deferredSystemUpdates(), + ElementsAre(updatedProjectPartContainer1, + projectPartContainer2, + projectPartContainer3, + projectPartContainer4)); +} + +TEST_F(ProjectPartsManager, UpdateProjectDeferredMultiple) +{ + manager.updateDeferred({}, {projectPartContainer1, projectPartContainer3}); + + manager.updateDeferred({}, + {updatedProjectPartContainer1, projectPartContainer2, projectPartContainer4}); + + ASSERT_THAT(manager.deferredProjectUpdates(), + ElementsAre(updatedProjectPartContainer1, + projectPartContainer2, + projectPartContainer3, + projectPartContainer4)); +} TEST_F(ProjectPartsManager, UpdateCallsIfNewProjectPartIsAdded) { EXPECT_CALL(mockProjectPartsStorage, fetchProjectParts(ElementsAre(Eq(projectPartContainer1.projectPartId)))); EXPECT_CALL(mockProjectPartsStorage, updateProjectParts(ElementsAre(projectPartContainer1))); - EXPECT_CALL(mockPrecompiledHeaderStorage, - deleteProjectPrecompiledHeaders(ElementsAre(projectPartContainer1.projectPartId))); EXPECT_CALL(mockProjectPartsStorage, resetIndexingTimeStamps(ElementsAre(projectPartContainer1))); + EXPECT_CALL(mockPrecompiledHeaderStorage, + deleteSystemAndProjectPrecompiledHeaders( + ElementsAre(projectPartContainer1.projectPartId))); manager.update({projectPartContainer1}); } @@ -353,6 +445,19 @@ TEST_F(ProjectPartsManager, UpdateCallsNotDeleteProjectPrecompiledHeadersIfNoNew manager.update({projectPartContainer1}); } +TEST_F(ProjectPartsManager, + UpdateCallsNotDeleteSystemAndProjectPrecompiledHeadersIfNoNewerProjectPartsExists) +{ + manager.update({projectPartContainer1}); + + EXPECT_CALL(mockPrecompiledHeaderStorage, + deleteSystemAndProjectPrecompiledHeaders( + ElementsAre(projectPartContainer1.projectPartId))) + .Times(0); + + manager.update({projectPartContainer1}); +} + TEST_F(ProjectPartsManager, UpdateCallsNotResetIndexingTimeStampsIfNoNewerProjectPartsExists) { manager.update({projectPartContainer1}); @@ -388,7 +493,8 @@ TEST_F(ProjectPartsManager, UpdateCallsIfUpdatedProjectPartIsAdded) EXPECT_CALL(mockProjectPartsStorage, updateProjectParts(ElementsAre(updatedProjectPartContainer1))); EXPECT_CALL(mockPrecompiledHeaderStorage, - deleteProjectPrecompiledHeaders(ElementsAre(projectPartContainer1.projectPartId))); + deleteSystemAndProjectPrecompiledHeaders( + ElementsAre(projectPartContainer1.projectPartId))); EXPECT_CALL(mockProjectPartsStorage, resetIndexingTimeStamps(ElementsAre(updatedProjectPartContainer1))); @@ -405,7 +511,7 @@ TEST_F(ProjectPartsManager, ASSERT_THAT(projectParts, AllOf(Field(&UpToDataProjectParts::upToDate, IsEmpty()), - Field(&UpToDataProjectParts::notUpToDate, ElementsAre(projectPartContainer1)))); + Field(&UpToDataProjectParts::updateSystem, ElementsAre(projectPartContainer1)))); } TEST_F(ProjectPartsManager, ProjectPartAddedWithProjectPartAlreadyInTheDatabaseButWithoutEntries) @@ -418,4 +524,312 @@ TEST_F(ProjectPartsManager, ProjectPartAddedWithProjectPartAlreadyInTheDatabaseB ASSERT_THAT(manager.projectParts(), ElementsAre(projectPartContainer1)); } +TEST_F(ProjectPartsManager, SystemSourcesTimeChanged) +{ + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}, + {2, SourceType::ProjectInclude, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 101}, + {2, SourceType::ProjectInclude, 101}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.updateSystem, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); + ASSERT_THAT(upToDate.upToDate, IsEmpty()); +} + +TEST_F(ProjectPartsManager, TopSystemSourcesTimeChanged) +{ + SourceEntries oldSources{{1, SourceType::TopSystemInclude, 100}, + {2, SourceType::ProjectInclude, 100}}; + SourceEntries newSources{{1, SourceType::TopSystemInclude, 101}, + {2, SourceType::ProjectInclude, 101}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.updateSystem, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); + ASSERT_THAT(upToDate.upToDate, IsEmpty()); +} + +TEST_F(ProjectPartsManager, ProjectSourcesTimeChanged) +{ + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}, + {2, SourceType::ProjectInclude, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 100}, + {2, SourceType::ProjectInclude, 101}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.updateProject, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateSystem, IsEmpty()); + ASSERT_THAT(upToDate.upToDate, IsEmpty()); +} + +TEST_F(ProjectPartsManager, TopProjectSourcesTimeChanged) +{ + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}, + {2, SourceType::TopProjectInclude, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 100}, + {2, SourceType::TopProjectInclude, 101}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.updateProject, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateSystem, IsEmpty()); + ASSERT_THAT(upToDate.upToDate, IsEmpty()); +} + +TEST_F(ProjectPartsManager, UserIncludeSourcesTimeChanged) +{ + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}, {2, SourceType::UserInclude, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 100}, {2, SourceType::UserInclude, 101}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.upToDate, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); + ASSERT_THAT(upToDate.updateSystem, IsEmpty()); +} + +TEST_F(ProjectPartsManager, SourcesTimeChanged) +{ + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}, {2, SourceType::Source, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 100}, {2, SourceType::Source, 101}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.upToDate, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); + ASSERT_THAT(upToDate.updateSystem, IsEmpty()); +} + +TEST_F(ProjectPartsManager, SourcesTimeNotChanged) +{ + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 100}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.upToDate, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateSystem, IsEmpty()); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); +} + +TEST_F(ProjectPartsManager, TimeChangedForOneProject) +{ + manager.update({projectPartContainer1, projectPartContainer2}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(SourceEntries{{1, SourceType::SystemInclude, 100}})); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer2.sourcePathIds), + Eq(projectPartContainer2.projectPartId))) + .WillByDefault(Return(SourceEntries{{4, SourceType::SystemInclude, 100}})); + ON_CALL(mockBuildDependenciesProvider, + create(Eq(projectPartContainer1), Eq(SourceEntries{{1, SourceType::SystemInclude, 100}}))) + .WillByDefault(Return( + ClangBackEnd::BuildDependency{{{1, SourceType::SystemInclude, 101}}, {}, {}, {}, {}})); + ON_CALL(mockBuildDependenciesProvider, + create(Eq(projectPartContainer2), Eq(SourceEntries{{4, SourceType::SystemInclude, 100}}))) + .WillByDefault(Return( + ClangBackEnd::BuildDependency{{{4, SourceType::SystemInclude, 100}}, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1, projectPartContainer2}); + + ASSERT_THAT(upToDate.updateSystem, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); + ASSERT_THAT(upToDate.upToDate, ElementsAre(projectPartContainer2)); +} + +TEST_F(ProjectPartsManager, AddSystemInclude) +{ + manager.update({projectPartContainer1}); + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 100}, {2, SourceType::SystemInclude, 100}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.updateSystem, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); + ASSERT_THAT(upToDate.upToDate, IsEmpty()); +} + +TEST_F(ProjectPartsManager, ChangeFromProjectToSystemInclude) +{ + manager.update({projectPartContainer1}); + SourceEntries oldSources{{1, SourceType::ProjectInclude, 100}}; + SourceEntries newSources{{1, SourceType::SystemInclude, 100}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.updateSystem, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); + ASSERT_THAT(upToDate.upToDate, IsEmpty()); +} + +TEST_F(ProjectPartsManager, ChangeFromSystemToProjectInclude) +{ + manager.update({projectPartContainer1}); + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}}; + SourceEntries newSources{{1, SourceType::ProjectInclude, 100}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.updateSystem, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); + ASSERT_THAT(upToDate.upToDate, IsEmpty()); +} + +TEST_F(ProjectPartsManager, ChangeFromProjectToUserInclude) +{ + manager.update({projectPartContainer1}); + SourceEntries oldSources{{1, SourceType::ProjectInclude, 100}}; + SourceEntries newSources{{1, SourceType::UserInclude, 100}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.updateProject, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.upToDate, IsEmpty()); + ASSERT_THAT(upToDate.updateSystem, IsEmpty()); +} + +TEST_F(ProjectPartsManager, ChangeFromSystemToUserInclude) +{ + manager.update({projectPartContainer1}); + SourceEntries oldSources{{1, SourceType::SystemInclude, 100}}; + SourceEntries newSources{{1, SourceType::UserInclude, 100}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.updateSystem, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.upToDate, IsEmpty()); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); +} + +TEST_F(ProjectPartsManager, ChangeFromSourceToUserInclude) +{ + manager.update({projectPartContainer1}); + SourceEntries oldSources{{1, SourceType::Source, 100}}; + SourceEntries newSources{{1, SourceType::UserInclude, 100}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.upToDate, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateSystem, IsEmpty()); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); +} + +TEST_F(ProjectPartsManager, ChangeFromUserIncludeToSource) +{ + manager.update({projectPartContainer1}); + SourceEntries oldSources{{1, SourceType::UserInclude, 100}}; + SourceEntries newSources{{1, SourceType::Source, 100}}; + manager.update({projectPartContainer1}); + ON_CALL(mockBuildDependenciesProvider, + createSourceEntriesFromStorage(Eq(projectPartContainer1.sourcePathIds), + Eq(projectPartContainer1.projectPartId))) + .WillByDefault(Return(oldSources)); + ON_CALL(mockBuildDependenciesProvider, create(Eq(projectPartContainer1), Eq(oldSources))) + .WillByDefault(Return(ClangBackEnd::BuildDependency{newSources, {}, {}, {}, {}})); + + auto upToDate = manager.update({projectPartContainer1}); + + ASSERT_THAT(upToDate.upToDate, ElementsAre(projectPartContainer1)); + ASSERT_THAT(upToDate.updateSystem, IsEmpty()); + ASSERT_THAT(upToDate.updateProject, IsEmpty()); +} + } // namespace