diff options
author | Marco Bubke <marco.bubke@qt.io> | 2017-01-31 14:21:05 +0100 |
---|---|---|
committer | Marco Bubke <marco.bubke@qt.io> | 2017-01-31 14:18:38 +0000 |
commit | ea4141ee14a0fd5a7f0711da55da261cc52e0576 (patch) | |
tree | 36b447deb6997603530be200912bf201083cd255 | |
parent | 92263a05358d8f445ea5afc0bee19a9a8424e348 (diff) | |
download | qt-creator-ea4141ee14a0fd5a7f0711da55da261cc52e0576.tar.gz |
Clang: Add Process Generator
So far we only compiled the precompiled headers only sequentially. The
process generator is creating, managing a queue of processes to compile
the PCHs parallel.
Change-Id: I8075def4ef9e6b0191bbd51b3631d1c51ec7b361
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
23 files changed, 885 insertions, 96 deletions
diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp index 45ddec5bd6..c189e148ec 100644 --- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp +++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp @@ -27,6 +27,7 @@ #include <connectionserver.h> #include <environment.h> #include <pchcreator.h> +#include <pchgenerator.h> #include <pchmanagerserver.h> #include <pchmanagerclientproxy.h> #include <projectparts.h> @@ -36,12 +37,16 @@ #include <QCoreApplication> #include <QFileSystemWatcher> #include <QLoggingCategory> +#include <QProcess> #include <QTemporaryDir> #include <QTimer> +#include <thread> + using ClangBackEnd::ClangPathWatcher; using ClangBackEnd::ConnectionServer; using ClangBackEnd::PchCreator; +using ClangBackEnd::PchGenerator; using ClangBackEnd::PchManagerClientProxy; using ClangBackEnd::PchManagerServer; using ClangBackEnd::ProjectParts; @@ -60,6 +65,11 @@ public: return QString(CLANG_COMPILER_PATH); } + uint hardwareConcurrency() const + { + return std::thread::hardware_concurrency(); + } + private: QTemporaryDir temporaryDirectory; }; @@ -96,13 +106,17 @@ int main(int argc, char *argv[]) StringCache<Utils::SmallString> filePathCache; ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher(filePathCache); ApplicationEnvironment environment; + PchGenerator<QProcess> pchGenerator(environment); PchCreator pchCreator(environment, filePathCache); + pchCreator.setGenerator(&pchGenerator); ProjectParts projectParts; PchManagerServer clangPchManagerServer(filePathCache, includeWatcher, pchCreator, projectParts); includeWatcher.setNotifier(&clangPchManagerServer); + pchGenerator.setNotifier(&clangPchManagerServer); + ConnectionServer<PchManagerServer, PchManagerClientProxy> connectionServer(connection); connectionServer.start(); connectionServer.setServer(&clangPchManagerServer); diff --git a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri index b6c36b3945..ec5714df5e 100644 --- a/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri +++ b/src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri @@ -10,7 +10,9 @@ SOURCES += \ $$PWD/pchcreatorinterface.cpp \ $$PWD/clangpathwatcherinterface.cpp \ $$PWD/projectpartsinterface.cpp \ - $$PWD/clangpathwatchernotifier.cpp + $$PWD/clangpathwatchernotifier.cpp \ + $$PWD/pchgeneratornotifierinterface.cpp \ + $$PWD/pchgeneratorinterface.cpp HEADERS += \ $$PWD/clangpchmanagerbackend_global.h \ @@ -30,4 +32,7 @@ HEADERS += \ $$PWD/clangpathwatcherinterface.h \ $$PWD/projectpartsinterface.h \ $$PWD/clangpathwatchernotifier.h \ - $$PWD/changedfilepathcompressor.h + $$PWD/changedfilepathcompressor.h \ + $$PWD/pchgenerator.h \ + $$PWD/pchgeneratornotifierinterface.h \ + $$PWD/pchgeneratorinterface.h diff --git a/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h b/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h index 4dbf0d9758..7be403006b 100644 --- a/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h +++ b/src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h @@ -64,16 +64,18 @@ public: llvm::StringRef /*relativePath*/, const clang::Module */*imported*/) override { - auto fileUID = file->getUID(); - - flagIncludeAlreadyRead(file); - - if (isNotInExcludedIncludeUID(fileUID)) { - auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID); - if (notAlreadyIncluded.first) { - m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, fileUID); - uint includeId = m_filePathCache.stringId({fileName.data(), fileName.size()}); - m_includeIds.emplace_back(includeId); + if (file) { + auto fileUID = file->getUID(); + + flagIncludeAlreadyRead(file); + + if (isNotInExcludedIncludeUID(fileUID)) { + auto notAlreadyIncluded = isNotAlreadyIncluded(fileUID); + if (notAlreadyIncluded.first) { + m_alreadyIncludedFileUIDs.insert(notAlreadyIncluded.second, fileUID); + uint includeId = m_filePathCache.stringId({fileName.data(), fileName.size()}); + m_includeIds.emplace_back(includeId); + } } } } diff --git a/src/tools/clangpchmanagerbackend/source/environment.h b/src/tools/clangpchmanagerbackend/source/environment.h index 4fe7442c17..879065093b 100644 --- a/src/tools/clangpchmanagerbackend/source/environment.h +++ b/src/tools/clangpchmanagerbackend/source/environment.h @@ -34,6 +34,7 @@ class Environment public: virtual QString pchBuildDirectory() const = 0; virtual QString clangCompilerPath() const = 0; + virtual uint hardwareConcurrency() const = 0; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp index 560e6a2bb5..0b2d1c67ae 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.cpp @@ -33,7 +33,6 @@ #include <QCryptographicHash> #include <QFile> -#include <QProcess> namespace ClangBackEnd { @@ -45,10 +44,12 @@ PchCreator::PchCreator(Environment &environment, StringCache<Utils::SmallString> PchCreator::PchCreator(V2::ProjectPartContainers &&projectsParts, Environment &environment, - StringCache<Utils::SmallString> &filePathCache) + StringCache<Utils::SmallString> &filePathCache, + PchGeneratorInterface *pchGenerator) : m_projectParts(std::move(projectsParts)), m_environment(environment), - m_filePathCache(filePathCache) + m_filePathCache(filePathCache), + m_pchGenerator(pchGenerator) { } @@ -258,23 +259,17 @@ std::unique_ptr<QFile> PchCreator::generateGlobalPchHeaderFile() generateGlobalPchHeaderFileContent()); } -void PchCreator::generatePch(const Utils::SmallStringVector &clangCompilerArguments) +void PchCreator::generatePch(Utils::SmallStringVector &&compilerArguments, + ProjectPartPch &&projectPartPch) { - QProcess process; - process.setProcessChannelMode(QProcess::ForwardedChannels); - - process.start(m_environment.clangCompilerPath(), - convertToQStringList(clangCompilerArguments)); - process.waitForFinished(100000); - - checkIfProcessHasError(process); + m_pchGenerator->startTask(std::move(compilerArguments), std::move(projectPartPch)); } void PchCreator::generateGlobalPch() { generateGlobalPchHeaderFile(); - generatePch(generateGlobalClangCompilerArguments()); + generatePch(generateGlobalClangCompilerArguments(), ProjectPartPch()); } QStringList PchCreator::convertToQStringList(const Utils::SmallStringVector &compilerArguments) @@ -310,14 +305,6 @@ QByteArray PchCreator::globalProjectHash() const return result.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); } -void PchCreator::checkIfProcessHasError(const QProcess &process) -{ - if (process.exitCode()) { - const std::string errorString = process.errorString().toStdString(); - throw PchNotCreatedError(errorString); - } -} - Utils::SmallString PchCreator::generateGlobalPchFilePathWithoutExtension() const { QByteArray fileName = m_environment.pchBuildDirectory().toUtf8(); @@ -449,27 +436,25 @@ Utils::SmallStringVector PchCreator::generateProjectPartClangCompilerArguments( return compilerArguments; } -std::pair<ProjectPartPch, IdPaths> PchCreator::generateProjectPartPch( - const V2::ProjectPartContainer &projectPart) +IdPaths PchCreator::generateProjectPartPch(const V2::ProjectPartContainer &projectPart) { auto includes = generateProjectPartPchIncludes(projectPart); auto content = generatePchIncludeFileContent(includes); auto pchIncludeFilePath = generateProjectPathPchHeaderFilePath(projectPart); auto pchFilePath = generateProjectPartPchFilePath(projectPart); - auto file = generatePchHeaderFile(pchIncludeFilePath, content); + generatePchHeaderFile(pchIncludeFilePath, content); - generatePch(generateProjectPartClangCompilerArguments(projectPart)); + generatePch(generateProjectPartClangCompilerArguments(projectPart), + {projectPart.projectPartId().clone(), std::move(pchFilePath)}); - return {{projectPart.projectPartId().clone(), std::move(pchFilePath)}, - {projectPart.projectPartId().clone(), includes}}; + return {projectPart.projectPartId().clone(), std::move(includes)}; } void PchCreator::generatePchs() { for (const V2::ProjectPartContainer &projectPart : m_projectParts) { - auto projectInfos = generateProjectPartPch(projectPart); - m_projectPartPchs.push_back(projectInfos.first); - m_projectsIncludeIds.push_back(projectInfos.second); + auto includePaths = generateProjectPartPch(projectPart); + m_projectsIncludeIds.push_back(std::move(includePaths)); } } @@ -480,14 +465,14 @@ void PchCreator::generatePchs(V2::ProjectPartContainers &&projectsParts) generatePchs(); } -std::vector<ProjectPartPch> PchCreator::takeProjectPartPchs() +std::vector<IdPaths> PchCreator::takeProjectsIncludes() { - return std::move(m_projectPartPchs); + return std::move(m_projectsIncludeIds); } -std::vector<IdPaths> PchCreator::takeProjectsIncludes() +void PchCreator::setGenerator(PchGeneratorInterface *pchGenerator) { - return std::move(m_projectsIncludeIds); + m_pchGenerator = pchGenerator; } std::unique_ptr<QFile> PchCreator::generatePchHeaderFile( diff --git a/src/tools/clangpchmanagerbackend/source/pchcreator.h b/src/tools/clangpchmanagerbackend/source/pchcreator.h index 5bc38cb58b..7affe82f6c 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreator.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreator.h @@ -27,6 +27,7 @@ #include "pchcreatorinterface.h" +#include "pchgeneratorinterface.h" #include "stringcache.h" #include "idpaths.h" @@ -50,12 +51,14 @@ public: StringCache<Utils::SmallString> &filePathCache); PchCreator(V2::ProjectPartContainers &&projectsParts, Environment &environment, - StringCache<Utils::SmallString> &filePathCache); + StringCache<Utils::SmallString> &filePathCache, + PchGeneratorInterface *pchGenerator); void generatePchs(V2::ProjectPartContainers &&projectsParts) override; - std::vector<ProjectPartPch> takeProjectPartPchs() override; std::vector<IdPaths> takeProjectsIncludes() override; + void setGenerator(PchGeneratorInterface *pchGenerator); + unitttest_public: Utils::SmallStringVector generateGlobalHeaderPaths() const; Utils::SmallStringVector generateGlobalSourcePaths() const; @@ -70,7 +73,8 @@ unitttest_public: Utils::SmallString generatePchIncludeFileContent(const std::vector<uint> &includeIds) const; Utils::SmallString generateGlobalPchHeaderFileContent() const; std::unique_ptr<QFile> generateGlobalPchHeaderFile(); - void generatePch(const Utils::SmallStringVector &commandLineArguments); + void generatePch(Utils::SmallStringVector &&commandLineArguments, + ProjectPartPch &&projectPartPch); void generateGlobalPch(); Utils::SmallString globalPchContent() const; @@ -97,7 +101,7 @@ unitttest_public: const V2::ProjectPartContainer &projectPart) const; Utils::SmallStringVector generateProjectPartClangCompilerArguments( const V2::ProjectPartContainer &projectPart) const; - std::pair<ProjectPartPch, IdPaths> generateProjectPartPch( + IdPaths generateProjectPartPch( const V2::ProjectPartContainer &projectPart); static std::unique_ptr<QFile> generatePchHeaderFile( const Utils::SmallString &filePath, @@ -108,7 +112,6 @@ unitttest_public: private: static QByteArray projectPartHash(const V2::ProjectPartContainer &projectPart); QByteArray globalProjectHash() const; - static void checkIfProcessHasError(const QProcess &process); private: V2::ProjectPartContainers m_projectParts; @@ -116,6 +119,7 @@ private: std::vector<IdPaths> m_projectsIncludeIds; Environment &m_environment; StringCache<Utils::SmallString> &m_filePathCache; + PchGeneratorInterface *m_pchGenerator = nullptr; }; } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h b/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h index 89aac39bd5..f2e6f0f6a2 100644 --- a/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h +++ b/src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h @@ -38,7 +38,6 @@ public: virtual ~PchCreatorInterface(); virtual void generatePchs(V2::ProjectPartContainers &&projectsParts) = 0; - virtual std::vector<ProjectPartPch> takeProjectPartPchs() = 0; virtual std::vector<IdPaths> takeProjectsIncludes() = 0; }; diff --git a/src/tools/clangpchmanagerbackend/source/pchgenerator.h b/src/tools/clangpchmanagerbackend/source/pchgenerator.h new file mode 100644 index 0000000000..7c5b50f13b --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/pchgenerator.h @@ -0,0 +1,165 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "environment.h" +#include "pchgeneratorinterface.h" +#include "pchgeneratornotifierinterface.h" + +#include <projectpartpch.h> + +#include <QProcess> + +#include <queue> + +namespace ClangBackEnd { + +template <typename Process> +class PchGenerator final : public PchGeneratorInterface +{ +public: + PchGenerator(Environment &environment, + PchGeneratorNotifierInterface *notifier=nullptr) + : m_environment(environment), + m_notifier(notifier) + { + } + + ~PchGenerator() + { + cleanupAllProcesses(); + } + + void startTask(Utils::SmallStringVector &&compilerArguments, ProjectPartPch &&projectPartPch) override + { + addTask(std::move(compilerArguments), std::move(projectPartPch)); + } + + void setNotifier(PchGeneratorNotifierInterface *notifier) + { + m_notifier = notifier; + } + +unitttest_public: + Process *addTask(Utils::SmallStringVector &&compilerArguments, ProjectPartPch &&projectPartPch) + { + auto process = std::make_unique<Process>(); + Process *processPointer = process.get(); + + process->setProcessChannelMode(QProcess::ForwardedChannels); + process->setArguments(compilerArguments); + process->setProgram(m_environment.clangCompilerPath()); + + connectProcess(processPointer, std::move(projectPartPch)); + + if (!deferProcess()) + startProcess(std::move(process)); + else + m_deferredProcesses.push(std::move(process)); + + return processPointer; + } + + void connectProcess(Process *process, ProjectPartPch &&projectPartPch) + { + auto finishedCallback = [=,projectPartPch=std::move(projectPartPch)] (int exitCode, QProcess::ExitStatus exitStatus) { + deleteProcess(process); + activateNextDeferredProcess(); + m_notifier->taskFinished(generateTaskFinishStatus(exitCode, exitStatus), projectPartPch); + }; + + QObject::connect(process, + static_cast<void (Process::*)(int, QProcess::ExitStatus)>(&Process::finished), + std::move(finishedCallback)); + } + + void startProcess(std::unique_ptr<Process> &&process) + { + process->start(); + m_runningProcesses.push_back(std::move(process)); + } + + const std::vector<std::unique_ptr<Process>> &runningProcesses() const + { + return m_runningProcesses; + } + + const std::queue<std::unique_ptr<Process>> &deferredProcesses() const + { + return m_deferredProcesses; + } + + void deleteProcess(Process *process) + { + auto found = std::find_if(m_runningProcesses.begin(), + m_runningProcesses.end(), + [=] (const std::unique_ptr<Process> &entry) { + return entry.get() == process; + }); + + if (found != m_runningProcesses.end()) { + std::unique_ptr<Process> avoidDoubleDeletedProcess = std::move(*found); + m_runningProcesses.erase(found); + } + } + + void cleanupAllProcesses() + { + std::vector<std::unique_ptr<Process>> runningProcesses = std::move(m_runningProcesses); + std::queue<std::unique_ptr<Process>> deferredProcesses = std::move(m_deferredProcesses); + } + + static TaskFinishStatus generateTaskFinishStatus(int exitCode, QProcess::ExitStatus exitStatus) + { + if (exitCode != 0 || exitStatus != QProcess::NormalExit) + return TaskFinishStatus::Unsuccessfully; + else + return TaskFinishStatus::Successfully; + } + + bool deferProcess() const + { + return m_environment.hardwareConcurrency() <= m_runningProcesses.size(); + } + + void activateNextDeferredProcess() + { + if (!m_deferredProcesses.empty()) { + std::unique_ptr<Process> process = std::move(m_deferredProcesses.front()); + m_deferredProcesses.pop(); + + startProcess(std::move(process)); + } + } + +private: + std::vector<std::unique_ptr<Process>> m_runningProcesses; + std::queue<std::unique_ptr<Process>> m_deferredProcesses; + Environment &m_environment; + PchGeneratorNotifierInterface *m_notifier=nullptr; +}; + +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.cpp b/src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.cpp new file mode 100644 index 0000000000..7653ed71b2 --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.cpp @@ -0,0 +1,31 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "pchgeneratorinterface.h" + +ClangBackEnd::PchGeneratorInterface::~PchGeneratorInterface() +{ + +} diff --git a/src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.h b/src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.h new file mode 100644 index 0000000000..9e942a3a06 --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <utils/smallstringvector.h> + +namespace ClangBackEnd { + +class ProjectPartPch; + +class PchGeneratorInterface +{ +public: + virtual ~PchGeneratorInterface(); + + virtual void startTask(Utils::SmallStringVector &&compilerArguments, + ProjectPartPch &&projectPartPch) = 0; + +}; + +} // namespace ClangBackEnd + diff --git a/src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.cpp b/src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.cpp new file mode 100644 index 0000000000..d37446d3a9 --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "pchgeneratornotifierinterface.h" + +#include <ostream> + +namespace ClangBackEnd { + +PchGeneratorNotifierInterface::~PchGeneratorNotifierInterface() +{ + +} + +std::ostream &operator<<(std::ostream &out, TaskFinishStatus status) +{ + enum class TaskFinishStatus + { + Successfully, + Unsuccessfully + }; + + if (status == ClangBackEnd::TaskFinishStatus::Successfully) + out << "Successfully"; + else + out << "Unsuccessfully"; + + return out; +} + +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.h b/src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.h new file mode 100644 index 0000000000..32611750ad --- /dev/null +++ b/src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.h @@ -0,0 +1,50 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <iosfwd> + +namespace ClangBackEnd { + +class ProjectPartPch; + +enum class TaskFinishStatus +{ + Successfully, + Unsuccessfully +}; + +class PchGeneratorNotifierInterface +{ +public: + virtual ~PchGeneratorNotifierInterface(); + + virtual void taskFinished(TaskFinishStatus status, const ProjectPartPch &projectPartPch) = 0; +}; + +std::ostream &operator<<(std::ostream &out, TaskFinishStatus status); + +} // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp index 71ec82e45c..271412bf36 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp @@ -58,8 +58,6 @@ void PchManagerServer::updatePchProjectParts(UpdatePchProjectPartsMessage &&mess { m_pchCreator.generatePchs(m_projectParts.update(message.takeProjectsParts())); - client()->precompiledHeadersUpdated(PrecompiledHeadersUpdatedMessage(m_pchCreator.takeProjectPartPchs())); - m_fileSystemWatcher.updateIdPaths(m_pchCreator.takeProjectsIncludes()); } @@ -74,9 +72,13 @@ void PchManagerServer::pathsWithIdsChanged(const Utils::SmallStringVector &ids) { m_pchCreator.generatePchs(m_projectParts.projects(ids)); - client()->precompiledHeadersUpdated(PrecompiledHeadersUpdatedMessage(m_pchCreator.takeProjectPartPchs())); - m_fileSystemWatcher.updateIdPaths(m_pchCreator.takeProjectsIncludes()); } +void PchManagerServer::taskFinished(TaskFinishStatus status, const ProjectPartPch &projectPartPch) +{ + if (status == TaskFinishStatus::Successfully) + client()->precompiledHeadersUpdated(PrecompiledHeadersUpdatedMessage({projectPartPch.clone()})); +} + } // namespace ClangBackEnd diff --git a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h index b12ffeca7f..2e504dfe8e 100644 --- a/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h +++ b/src/tools/clangpchmanagerbackend/source/pchmanagerserver.h @@ -28,6 +28,7 @@ #include "clangpathwatcherinterface.h" #include "clangpathwatchernotifier.h" #include "pchcreatorinterface.h" +#include "pchgeneratornotifierinterface.h" #include "pchmanagerserverinterface.h" #include "projectpartsinterface.h" #include "stringcache.h" @@ -36,7 +37,9 @@ namespace ClangBackEnd { class SourceRangesAndDiagnosticsForQueryMessage; -class PchManagerServer : public PchManagerServerInterface, public ClangPathWatcherNotifier +class PchManagerServer : public PchManagerServerInterface, + public ClangPathWatcherNotifier, + public PchGeneratorNotifierInterface { public: PchManagerServer(StringCache<Utils::SmallString> &filePathCache, @@ -50,6 +53,7 @@ public: void removePchProjectParts(RemovePchProjectPartsMessage &&message) override; void pathsWithIdsChanged(const Utils::SmallStringVector &ids) override; + void taskFinished(TaskFinishStatus status, const ProjectPartPch &projectPartPch) override; private: StringCache<Utils::SmallString> &m_filePathCache; diff --git a/tests/unit/unittest/fakeprocess.cpp b/tests/unit/unittest/fakeprocess.cpp new file mode 100644 index 0000000000..e4eb8592e6 --- /dev/null +++ b/tests/unit/unittest/fakeprocess.cpp @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "fakeprocess.h" + +FakeProcess::FakeProcess() +{ +} + +FakeProcess::~FakeProcess() +{ + if (m_isStarted && !m_isFinished) + emit finished(0, QProcess::NormalExit); +} + +void FakeProcess::finishUnsuccessfully() +{ + m_isFinished = true; + emit finished(1, QProcess::NormalExit); +} + +void FakeProcess::finishByCrash() +{ + m_isFinished = true; + emit finished(0, QProcess::CrashExit); +} + +void FakeProcess::finish() +{ + m_isFinished = true; + emit finished(0, QProcess::NormalExit); +} + +void FakeProcess::setArguments(const QStringList &arguments) +{ + m_arguments = arguments; +} + +void FakeProcess::setProgram(const QString &program) +{ + m_applicationPath = program; +} + +void FakeProcess::setProcessChannelMode(QProcess::ProcessChannelMode) +{ +} + +void FakeProcess::start() +{ + m_isStarted = true; +} + +bool FakeProcess::isStarted() const +{ + return m_isStarted; +} + +const QStringList &FakeProcess::arguments() const +{ + return m_arguments; +} + +const QString &FakeProcess::applicationPath() const +{ + return m_applicationPath; +} diff --git a/tests/unit/unittest/fakeprocess.h b/tests/unit/unittest/fakeprocess.h new file mode 100644 index 0000000000..88642b303d --- /dev/null +++ b/tests/unit/unittest/fakeprocess.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <QProcess> + +class FakeProcess : public QObject +{ + Q_OBJECT + +public: + FakeProcess(); + ~FakeProcess(); + + void finishUnsuccessfully(); + void finishByCrash(); + void finish(); + + void start(); + void setArguments(const QStringList &arguments); + void setProgram(const QString &program); + + void setProcessChannelMode(QProcess::ProcessChannelMode mode); + + + bool isStarted() const; + + const QStringList &arguments() const; + const QString &applicationPath() const; + +signals: + void finished(int exitCode, QProcess::ExitStatus exitStatus); + +private: + QStringList m_arguments; + QString m_applicationPath; + bool m_isFinished = false; + bool m_isStarted = false; +}; diff --git a/tests/unit/unittest/mockpchcreator.h b/tests/unit/unittest/mockpchcreator.h index d4cbd62793..761c10b316 100644 --- a/tests/unit/unittest/mockpchcreator.h +++ b/tests/unit/unittest/mockpchcreator.h @@ -36,8 +36,6 @@ class MockPchCreator : public ClangBackEnd::PchCreatorInterface public: MOCK_METHOD1(generatePchs, void(const std::vector<ClangBackEnd::V2::ProjectPartContainer> &projectParts)); - MOCK_METHOD0(takeProjectPartPchs, - std::vector<ClangBackEnd::ProjectPartPch>()); MOCK_METHOD0(takeProjectsIncludes, std::vector<ClangBackEnd::IdPaths>()); diff --git a/tests/unit/unittest/mockpchgeneratornotifier.h b/tests/unit/unittest/mockpchgeneratornotifier.h new file mode 100644 index 0000000000..fe5b8b2af4 --- /dev/null +++ b/tests/unit/unittest/mockpchgeneratornotifier.h @@ -0,0 +1,38 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include "googletest.h" + +#include <pchgeneratornotifierinterface.h> + +class MockPchGeneratorNotifier : public ClangBackEnd::PchGeneratorNotifierInterface +{ +public: + MOCK_METHOD2(taskFinished, + void (ClangBackEnd::TaskFinishStatus status, + const ClangBackEnd::ProjectPartPch &projectPartPch)); +}; diff --git a/tests/unit/unittest/pchcreator-test.cpp b/tests/unit/unittest/pchcreator-test.cpp index d57c2b7fe2..bf44fbdbb9 100644 --- a/tests/unit/unittest/pchcreator-test.cpp +++ b/tests/unit/unittest/pchcreator-test.cpp @@ -25,9 +25,12 @@ #include "googletest.h" +#include "fakeprocess.h" +#include "mockpchgeneratornotifier.h" #include "testenvironment.h" #include <pchcreator.h> +#include <pchgenerator.h> #include <stringcache.h> #include <QFileInfo> @@ -70,9 +73,12 @@ protected: {header2Path.clone()}, {main2Path.clone()}}; TestEnvironment environment; + NiceMock<MockPchGeneratorNotifier> mockPchGeneratorNotifier; + ClangBackEnd::PchGenerator<FakeProcess> generator{environment, &mockPchGeneratorNotifier}; ClangBackEnd::PchCreator creator{{projectPart1.clone(),projectPart2.clone()}, environment, - filePathCache}; + filePathCache, + &generator}; }; using PchCreatorSlowTest = PchCreator; @@ -116,7 +122,7 @@ TEST_F(PchCreator, CreateGlobalCommandLine) ASSERT_THAT(arguments, ElementsAre(environment.clangCompilerPath(), "-I", TESTDATA_DIR, "-Wno-pragma-once-outside-header", "-I", TESTDATA_DIR, "-x" , "c++-header", "-Wno-pragma-once-outside-header")); } -TEST_F(PchCreator, CreateGlobalPchIncludes) +TEST_F(PchCreatorVerySlowTest, CreateGlobalPchIncludes) { auto includeIds = creator.generateGlobalPchIncludeIds(); @@ -167,13 +173,6 @@ TEST_F(PchCreator, CreateGlobalClangCompilerArguments) Not(Contains(environment.clangCompilerPath())))); } -TEST_F(PchCreatorVerySlowTest, CreateGlobalPch) -{ - creator.generateGlobalPch(); - - ASSERT_TRUE(QFileInfo::exists(creator.generateGlobalPchFilePath())); -} - TEST_F(PchCreator, CreateProjectPartCommandLine) { auto commandLine = creator.generateProjectPartCommandLine(projectPart1); @@ -258,23 +257,34 @@ TEST_F(PchCreatorVerySlowTest, CreatePartPchs) { creator.generateGlobalPch(); - auto projectPartPchAndIdPath = creator.generateProjectPartPch(projectPart1); + auto includePaths = creator.generateProjectPartPch(projectPart1); - ASSERT_THAT(projectPartPchAndIdPath.first.id(), projectPart1.projectPartId()); - ASSERT_THAT(projectPartPchAndIdPath.first.path(), creator.generateProjectPartPchFilePath(projectPart1)); - ASSERT_THAT(projectPartPchAndIdPath.second.id, projectPart1.projectPartId()); - ASSERT_THAT(projectPartPchAndIdPath.second.paths, UnorderedElementsAre(1, 2, 3)); + ASSERT_THAT(includePaths.id, projectPart1.projectPartId()); + ASSERT_THAT(includePaths.paths, UnorderedElementsAre(1, 2, 3)); } -TEST_F(PchCreatorVerySlowTest, ProjectPartPchsForCreatePchsForProjectParts) +TEST_F(PchCreatorVerySlowTest, IncludesForCreatePchsForProjectParts) { creator.generatePchs(); - ASSERT_THAT(creator.takeProjectPartPchs(), - ElementsAre(Property(&ProjectPartPch::id, "project1"), - Property(&ProjectPartPch::id, "project2"))); + ASSERT_THAT(creator.takeProjectsIncludes(), + ElementsAre(Field(&IdPaths::id, "project1"), + Field(&IdPaths::id, "project2"))); +} + +TEST_F(PchCreatorVerySlowTest, ProjectPartPchsForCreatePchsForProjectParts) +{ + EXPECT_CALL(mockPchGeneratorNotifier, + taskFinished(ClangBackEnd::TaskFinishStatus::Successfully, + Property(&ProjectPartPch::id, "project1"))); + EXPECT_CALL(mockPchGeneratorNotifier, + taskFinished(ClangBackEnd::TaskFinishStatus::Successfully, + Property(&ProjectPartPch::id, "project2"))); + + creator.generatePchs(); } + TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts) { creator.generatePchs(); diff --git a/tests/unit/unittest/pchgenerator-test.cpp b/tests/unit/unittest/pchgenerator-test.cpp new file mode 100644 index 0000000000..1bb816bb59 --- /dev/null +++ b/tests/unit/unittest/pchgenerator-test.cpp @@ -0,0 +1,224 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "googletest.h" + +#include "fakeprocess.h" +#include "testenvironment.h" +#include "mockpchgeneratornotifier.h" + +#include <pchgenerator.h> + +namespace { + +using testing::_; +using testing::Contains; +using testing::Eq; +using testing::NiceMock; +using testing::Not; +using testing::PrintToString; +using ClangBackEnd::TaskFinishStatus; + +MATCHER_P(ContainsProcess, process, + std::string(negation ? "isn't" : "is") + + " process " + PrintToString(process)) +{ + auto found = std::find_if(arg.begin(), + arg.end(), + [&] (const std::unique_ptr<FakeProcess> &processOwner) { + return processOwner.get() == process; + }); + + return found != arg.end(); +} + +class PchGenerator : public testing::Test +{ +protected: + TestEnvironment environment; + NiceMock<MockPchGeneratorNotifier> mockNotifier; + ClangBackEnd::PchGenerator<FakeProcess> generator{environment, &mockNotifier}; + Utils::SmallStringVector compilerArguments = {"-DXXXX", "-Ifoo"}; + ClangBackEnd::ProjectPartPch projectPartPch{"projectPartId", "/path/to/pch"}; +}; + +bool operator==(const std::unique_ptr<FakeProcess> &first, FakeProcess *const second) +{ + return first.get() == second; +} + +TEST_F(PchGenerator, ProcessFinished) +{ + EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Successfully, std::move(projectPartPch))); + + generator.startTask(compilerArguments.clone(), projectPartPch.clone()); +} + +TEST_F(PchGenerator, ProcessFinishedForDeferredProcess) +{ + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + generator.startTask(compilerArguments.clone(), projectPartPch.clone()); + + EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Successfully, std::move(projectPartPch))) + .Times(3); + + generator.startTask(compilerArguments.clone(), projectPartPch.clone()); + process->finish(); +} + +TEST_F(PchGenerator, ProcessSuccessfullyFinished) +{ + EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Unsuccessfully, std::move(projectPartPch))); + + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + process->finishUnsuccessfully(); +} + +TEST_F(PchGenerator, ProcessSuccessfullyFinishedByWrongExitCode) +{ + EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Unsuccessfully, std::move(projectPartPch))); + + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + process->finishUnsuccessfully(); +} + +TEST_F(PchGenerator, AddTaskAddsProcessToProcesses) +{ + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + ASSERT_THAT(generator.runningProcesses(), ContainsProcess(process)); +} + +TEST_F(PchGenerator, RemoveProcessAfterFinishingProcess) +{ + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + process->finish(); + + ASSERT_THAT(generator.runningProcesses(), Not(ContainsProcess(process))); +} + +TEST_F(PchGenerator, ProcessSuccessfullyFinishedByCrash) +{ + EXPECT_CALL(mockNotifier, taskFinished(TaskFinishStatus::Unsuccessfully, std::move(projectPartPch))); + + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + process->finishByCrash(); +} + +TEST_F(PchGenerator, CreateProcess) +{ + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + ASSERT_THAT(generator.runningProcesses(), ContainsProcess(process)); +} + +TEST_F(PchGenerator, DeleteProcess) +{ + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + generator.deleteProcess(process); + + ASSERT_THAT(generator.runningProcesses(), Not(ContainsProcess(process))); +} + +TEST_F(PchGenerator, StartProcessApplicationPath) +{ + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + ASSERT_THAT(process->applicationPath(), environment.clangCompilerPath()); + +} + +TEST_F(PchGenerator, SetCompilerArguments) +{ + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + ASSERT_THAT(process->arguments(), compilerArguments); +} + +TEST_F(PchGenerator, ProcessIsStartedAfterAddingTask) +{ + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + ASSERT_TRUE(process->isStarted()); +} + +TEST_F(PchGenerator, DeferProcess) +{ + generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + auto deferProcess = generator.deferProcess(); + + ASSERT_TRUE(deferProcess); +} + +TEST_F(PchGenerator, ThirdTaskIsDeferred) +{ + generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + ASSERT_THAT(process, generator.deferredProcesses().back().get()); +} + +TEST_F(PchGenerator, ThirdTaskIsNotRunning) +{ + generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + ASSERT_THAT(generator.runningProcesses(), Not(ContainsProcess(process))); +} + +TEST_F(PchGenerator, DoNotDeferProcess) +{ + generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + auto deferProcess = generator.deferProcess(); + + ASSERT_FALSE(deferProcess); +} + +TEST_F(PchGenerator, DoNotActivateIfNothingIsDeferred) +{ + generator.activateNextDeferredProcess(); +} + +TEST_F(PchGenerator, AfterActivationProcessIsRunning) +{ + generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + auto process = generator.addTask(compilerArguments.clone(), projectPartPch.clone()); + + generator.activateNextDeferredProcess(); + + ASSERT_THAT(generator.runningProcesses(), ContainsProcess(process)); +} + +} diff --git a/tests/unit/unittest/pchmanagerserver-test.cpp b/tests/unit/unittest/pchmanagerserver-test.cpp index 7c174794c0..b1f6ca8ab0 100644 --- a/tests/unit/unittest/pchmanagerserver-test.cpp +++ b/tests/unit/unittest/pchmanagerserver-test.cpp @@ -47,6 +47,7 @@ using testing::IsEmpty; using Utils::SmallString; using ClangBackEnd::V2::ProjectPartContainer; +using ClangBackEnd::TaskFinishStatus; class PchManagerServer : public ::testing::Test { @@ -76,18 +77,28 @@ protected: {main2Path.clone()}}; std::vector<ClangBackEnd::V2::ProjectPartContainer> projectParts{projectPart1, projectPart2}; ClangBackEnd::UpdatePchProjectPartsMessage updatePchProjectPartsMessage{Utils::clone(projectParts)}; - std::vector<ClangBackEnd::ProjectPartPch> projectPartPchs{{projectPart1.projectPartId().clone(), "/path1/to/pch"}, - {projectPart2.projectPartId().clone(), "/path2/to/pch"}}; - ClangBackEnd::PrecompiledHeadersUpdatedMessage precompiledHeaderUpdatedMessage{Utils::clone(projectPartPchs)}; + ClangBackEnd::ProjectPartPch projectPartPch1{projectPart1.projectPartId().clone(), "/path1/to/pch"}; + ClangBackEnd::ProjectPartPch projectPartPch2{projectPart2.projectPartId().clone(), "/path2/to/pch"}; + std::vector<ClangBackEnd::ProjectPartPch> projectPartPchs{projectPartPch1, projectPartPch2}; + ClangBackEnd::PrecompiledHeadersUpdatedMessage precompiledHeaderUpdatedMessage1{{projectPartPch1}}; + ClangBackEnd::PrecompiledHeadersUpdatedMessage precompiledHeaderUpdatedMessage2{{projectPartPch2}}; ClangBackEnd::RemovePchProjectPartsMessage removePchProjectPartsMessage{{projectPart1.projectPartId().clone(), projectPart2.projectPartId().clone()}}; }; -TEST_F(PchManagerServer, CallPrecompiledHeadersUpdatedInClientForUpdate) +TEST_F(PchManagerServer, CallPrecompiledHeadersForSuccessfullyFinishedTask) { - EXPECT_CALL(mockPchManagerClient, precompiledHeadersUpdated(precompiledHeaderUpdatedMessage)); + EXPECT_CALL(mockPchManagerClient, precompiledHeadersUpdated(precompiledHeaderUpdatedMessage1)); - server.updatePchProjectParts(updatePchProjectPartsMessage.clone()); + server.taskFinished(TaskFinishStatus::Successfully, projectPartPch1); +} + +TEST_F(PchManagerServer, DoNotCallPrecompiledHeadersForUnsuccessfullyFinishedTask) +{ + EXPECT_CALL(mockPchManagerClient, precompiledHeadersUpdated(precompiledHeaderUpdatedMessage1)) + .Times(0); + + server.taskFinished(TaskFinishStatus::Unsuccessfully, projectPartPch1); } TEST_F(PchManagerServer, CallBuildInPchCreator) @@ -150,15 +161,6 @@ TEST_F(PchManagerServer, CallGeneratePchsInPchCreatorForIncludeChange) server.pathsWithIdsChanged({projectPartId1}); } -TEST_F(PchManagerServer, CallPrecompiledHeadersUpdatedInClientForIncludeChange) -{ - server.updatePchProjectParts(updatePchProjectPartsMessage.clone()); - - EXPECT_CALL(mockPchManagerClient, precompiledHeadersUpdated(precompiledHeaderUpdatedMessage)); - - server.pathsWithIdsChanged({projectPartId1}); -} - TEST_F(PchManagerServer, CallUpdateIdPathsInFileSystemWatcherForIncludeChange) { server.updatePchProjectParts(updatePchProjectPartsMessage.clone()); @@ -172,8 +174,6 @@ void PchManagerServer::SetUp() { server.setClient(&mockPchManagerClient); - ON_CALL(mockPchCreator, takeProjectPartPchs()) - .WillByDefault(Return(projectPartPchs)); ON_CALL(mockProjectParts, update(projectParts)) .WillByDefault(Return(projectParts)); ON_CALL(mockProjectParts, projects(Utils::SmallStringVector{{projectPartId1}})) diff --git a/tests/unit/unittest/testenvironment.h b/tests/unit/unittest/testenvironment.h index f318116972..a071b45432 100644 --- a/tests/unit/unittest/testenvironment.h +++ b/tests/unit/unittest/testenvironment.h @@ -45,6 +45,11 @@ public: return QString::fromUtf8(CLANG_COMPILER_PATH); } + uint hardwareConcurrency() const + { + return 2; + } + private: QTemporaryDir temporaryDirectory; }; diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro index fe8b68c68b..0d06c359ae 100644 --- a/tests/unit/unittest/unittest.pro +++ b/tests/unit/unittest/unittest.pro @@ -49,7 +49,9 @@ SOURCES += \ projectparts-test.cpp \ stringcache-test.cpp \ changedfilepathcompressor-test.cpp \ - faketimer.cpp + faketimer.cpp \ + pchgenerator-test.cpp \ + fakeprocess.cpp !isEmpty(LIBCLANG_LIBS) { SOURCES += \ @@ -148,7 +150,9 @@ HEADERS += \ mockprojectparts.h \ mockclangpathwatchernotifier.h \ mockchangedfilepathcompressor.h \ - faketimer.h + faketimer.h \ + mockpchgeneratornotifier.h \ + fakeprocess.h !isEmpty(LIBCLANG_LIBS) { HEADERS += \ |