summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2017-01-31 14:21:05 +0100
committerMarco Bubke <marco.bubke@qt.io>2017-01-31 14:18:38 +0000
commitea4141ee14a0fd5a7f0711da55da261cc52e0576 (patch)
tree36b447deb6997603530be200912bf201083cd255
parent92263a05358d8f445ea5afc0bee19a9a8424e348 (diff)
downloadqt-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>
-rw-r--r--src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp14
-rw-r--r--src/tools/clangpchmanagerbackend/source/clangpchmanagerbackend-source.pri9
-rw-r--r--src/tools/clangpchmanagerbackend/source/collectincludespreprocessorcallbacks.h22
-rw-r--r--src/tools/clangpchmanagerbackend/source/environment.h1
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchcreator.cpp53
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchcreator.h14
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchcreatorinterface.h1
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchgenerator.h165
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.cpp31
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchgeneratorinterface.h45
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.cpp53
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchgeneratornotifierinterface.h50
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchmanagerserver.cpp10
-rw-r--r--src/tools/clangpchmanagerbackend/source/pchmanagerserver.h6
-rw-r--r--tests/unit/unittest/fakeprocess.cpp88
-rw-r--r--tests/unit/unittest/fakeprocess.h62
-rw-r--r--tests/unit/unittest/mockpchcreator.h2
-rw-r--r--tests/unit/unittest/mockpchgeneratornotifier.h38
-rw-r--r--tests/unit/unittest/pchcreator-test.cpp46
-rw-r--r--tests/unit/unittest/pchgenerator-test.cpp224
-rw-r--r--tests/unit/unittest/pchmanagerserver-test.cpp34
-rw-r--r--tests/unit/unittest/testenvironment.h5
-rw-r--r--tests/unit/unittest/unittest.pro8
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 += \