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>
This commit is contained in:
Marco Bubke
2017-01-31 14:21:05 +01:00
parent 92263a0535
commit ea4141ee14
23 changed files with 884 additions and 95 deletions

View File

@@ -27,6 +27,7 @@
#include <connectionserver.h> #include <connectionserver.h>
#include <environment.h> #include <environment.h>
#include <pchcreator.h> #include <pchcreator.h>
#include <pchgenerator.h>
#include <pchmanagerserver.h> #include <pchmanagerserver.h>
#include <pchmanagerclientproxy.h> #include <pchmanagerclientproxy.h>
#include <projectparts.h> #include <projectparts.h>
@@ -36,12 +37,16 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QProcess>
#include <QTemporaryDir> #include <QTemporaryDir>
#include <QTimer> #include <QTimer>
#include <thread>
using ClangBackEnd::ClangPathWatcher; using ClangBackEnd::ClangPathWatcher;
using ClangBackEnd::ConnectionServer; using ClangBackEnd::ConnectionServer;
using ClangBackEnd::PchCreator; using ClangBackEnd::PchCreator;
using ClangBackEnd::PchGenerator;
using ClangBackEnd::PchManagerClientProxy; using ClangBackEnd::PchManagerClientProxy;
using ClangBackEnd::PchManagerServer; using ClangBackEnd::PchManagerServer;
using ClangBackEnd::ProjectParts; using ClangBackEnd::ProjectParts;
@@ -60,6 +65,11 @@ public:
return QString(CLANG_COMPILER_PATH); return QString(CLANG_COMPILER_PATH);
} }
uint hardwareConcurrency() const
{
return std::thread::hardware_concurrency();
}
private: private:
QTemporaryDir temporaryDirectory; QTemporaryDir temporaryDirectory;
}; };
@@ -96,13 +106,17 @@ int main(int argc, char *argv[])
StringCache<Utils::SmallString> filePathCache; StringCache<Utils::SmallString> filePathCache;
ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher(filePathCache); ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher(filePathCache);
ApplicationEnvironment environment; ApplicationEnvironment environment;
PchGenerator<QProcess> pchGenerator(environment);
PchCreator pchCreator(environment, filePathCache); PchCreator pchCreator(environment, filePathCache);
pchCreator.setGenerator(&pchGenerator);
ProjectParts projectParts; ProjectParts projectParts;
PchManagerServer clangPchManagerServer(filePathCache, PchManagerServer clangPchManagerServer(filePathCache,
includeWatcher, includeWatcher,
pchCreator, pchCreator,
projectParts); projectParts);
includeWatcher.setNotifier(&clangPchManagerServer); includeWatcher.setNotifier(&clangPchManagerServer);
pchGenerator.setNotifier(&clangPchManagerServer);
ConnectionServer<PchManagerServer, PchManagerClientProxy> connectionServer(connection); ConnectionServer<PchManagerServer, PchManagerClientProxy> connectionServer(connection);
connectionServer.start(); connectionServer.start();
connectionServer.setServer(&clangPchManagerServer); connectionServer.setServer(&clangPchManagerServer);

View File

@@ -10,7 +10,9 @@ SOURCES += \
$$PWD/pchcreatorinterface.cpp \ $$PWD/pchcreatorinterface.cpp \
$$PWD/clangpathwatcherinterface.cpp \ $$PWD/clangpathwatcherinterface.cpp \
$$PWD/projectpartsinterface.cpp \ $$PWD/projectpartsinterface.cpp \
$$PWD/clangpathwatchernotifier.cpp $$PWD/clangpathwatchernotifier.cpp \
$$PWD/pchgeneratornotifierinterface.cpp \
$$PWD/pchgeneratorinterface.cpp
HEADERS += \ HEADERS += \
$$PWD/clangpchmanagerbackend_global.h \ $$PWD/clangpchmanagerbackend_global.h \
@@ -30,4 +32,7 @@ HEADERS += \
$$PWD/clangpathwatcherinterface.h \ $$PWD/clangpathwatcherinterface.h \
$$PWD/projectpartsinterface.h \ $$PWD/projectpartsinterface.h \
$$PWD/clangpathwatchernotifier.h \ $$PWD/clangpathwatchernotifier.h \
$$PWD/changedfilepathcompressor.h $$PWD/changedfilepathcompressor.h \
$$PWD/pchgenerator.h \
$$PWD/pchgeneratornotifierinterface.h \
$$PWD/pchgeneratorinterface.h

View File

@@ -64,6 +64,7 @@ public:
llvm::StringRef /*relativePath*/, llvm::StringRef /*relativePath*/,
const clang::Module */*imported*/) override const clang::Module */*imported*/) override
{ {
if (file) {
auto fileUID = file->getUID(); auto fileUID = file->getUID();
flagIncludeAlreadyRead(file); flagIncludeAlreadyRead(file);
@@ -77,6 +78,7 @@ public:
} }
} }
} }
}
bool isNotInExcludedIncludeUID(uint uid) const bool isNotInExcludedIncludeUID(uint uid) const
{ {

View File

@@ -34,6 +34,7 @@ class Environment
public: public:
virtual QString pchBuildDirectory() const = 0; virtual QString pchBuildDirectory() const = 0;
virtual QString clangCompilerPath() const = 0; virtual QString clangCompilerPath() const = 0;
virtual uint hardwareConcurrency() const = 0;
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -33,7 +33,6 @@
#include <QCryptographicHash> #include <QCryptographicHash>
#include <QFile> #include <QFile>
#include <QProcess>
namespace ClangBackEnd { namespace ClangBackEnd {
@@ -45,10 +44,12 @@ PchCreator::PchCreator(Environment &environment, StringCache<Utils::SmallString>
PchCreator::PchCreator(V2::ProjectPartContainers &&projectsParts, PchCreator::PchCreator(V2::ProjectPartContainers &&projectsParts,
Environment &environment, Environment &environment,
StringCache<Utils::SmallString> &filePathCache) StringCache<Utils::SmallString> &filePathCache,
PchGeneratorInterface *pchGenerator)
: m_projectParts(std::move(projectsParts)), : m_projectParts(std::move(projectsParts)),
m_environment(environment), m_environment(environment),
m_filePathCache(filePathCache) m_filePathCache(filePathCache),
m_pchGenerator(pchGenerator)
{ {
} }
@@ -258,23 +259,17 @@ std::unique_ptr<QFile> PchCreator::generateGlobalPchHeaderFile()
generateGlobalPchHeaderFileContent()); generateGlobalPchHeaderFileContent());
} }
void PchCreator::generatePch(const Utils::SmallStringVector &clangCompilerArguments) void PchCreator::generatePch(Utils::SmallStringVector &&compilerArguments,
ProjectPartPch &&projectPartPch)
{ {
QProcess process; m_pchGenerator->startTask(std::move(compilerArguments), std::move(projectPartPch));
process.setProcessChannelMode(QProcess::ForwardedChannels);
process.start(m_environment.clangCompilerPath(),
convertToQStringList(clangCompilerArguments));
process.waitForFinished(100000);
checkIfProcessHasError(process);
} }
void PchCreator::generateGlobalPch() void PchCreator::generateGlobalPch()
{ {
generateGlobalPchHeaderFile(); generateGlobalPchHeaderFile();
generatePch(generateGlobalClangCompilerArguments()); generatePch(generateGlobalClangCompilerArguments(), ProjectPartPch());
} }
QStringList PchCreator::convertToQStringList(const Utils::SmallStringVector &compilerArguments) QStringList PchCreator::convertToQStringList(const Utils::SmallStringVector &compilerArguments)
@@ -310,14 +305,6 @@ QByteArray PchCreator::globalProjectHash() const
return result.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals); 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 Utils::SmallString PchCreator::generateGlobalPchFilePathWithoutExtension() const
{ {
QByteArray fileName = m_environment.pchBuildDirectory().toUtf8(); QByteArray fileName = m_environment.pchBuildDirectory().toUtf8();
@@ -449,27 +436,25 @@ Utils::SmallStringVector PchCreator::generateProjectPartClangCompilerArguments(
return compilerArguments; return compilerArguments;
} }
std::pair<ProjectPartPch, IdPaths> PchCreator::generateProjectPartPch( IdPaths PchCreator::generateProjectPartPch(const V2::ProjectPartContainer &projectPart)
const V2::ProjectPartContainer &projectPart)
{ {
auto includes = generateProjectPartPchIncludes(projectPart); auto includes = generateProjectPartPchIncludes(projectPart);
auto content = generatePchIncludeFileContent(includes); auto content = generatePchIncludeFileContent(includes);
auto pchIncludeFilePath = generateProjectPathPchHeaderFilePath(projectPart); auto pchIncludeFilePath = generateProjectPathPchHeaderFilePath(projectPart);
auto pchFilePath = generateProjectPartPchFilePath(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)}, return {projectPart.projectPartId().clone(), std::move(includes)};
{projectPart.projectPartId().clone(), includes}};
} }
void PchCreator::generatePchs() void PchCreator::generatePchs()
{ {
for (const V2::ProjectPartContainer &projectPart : m_projectParts) { for (const V2::ProjectPartContainer &projectPart : m_projectParts) {
auto projectInfos = generateProjectPartPch(projectPart); auto includePaths = generateProjectPartPch(projectPart);
m_projectPartPchs.push_back(projectInfos.first); m_projectsIncludeIds.push_back(std::move(includePaths));
m_projectsIncludeIds.push_back(projectInfos.second);
} }
} }
@@ -480,16 +465,16 @@ void PchCreator::generatePchs(V2::ProjectPartContainers &&projectsParts)
generatePchs(); generatePchs();
} }
std::vector<ProjectPartPch> PchCreator::takeProjectPartPchs()
{
return std::move(m_projectPartPchs);
}
std::vector<IdPaths> PchCreator::takeProjectsIncludes() std::vector<IdPaths> PchCreator::takeProjectsIncludes()
{ {
return std::move(m_projectsIncludeIds); return std::move(m_projectsIncludeIds);
} }
void PchCreator::setGenerator(PchGeneratorInterface *pchGenerator)
{
m_pchGenerator = pchGenerator;
}
std::unique_ptr<QFile> PchCreator::generatePchHeaderFile( std::unique_ptr<QFile> PchCreator::generatePchHeaderFile(
const Utils::SmallString &filePath, const Utils::SmallString &filePath,
const Utils::SmallString &content) const Utils::SmallString &content)

View File

@@ -27,6 +27,7 @@
#include "pchcreatorinterface.h" #include "pchcreatorinterface.h"
#include "pchgeneratorinterface.h"
#include "stringcache.h" #include "stringcache.h"
#include "idpaths.h" #include "idpaths.h"
@@ -50,12 +51,14 @@ public:
StringCache<Utils::SmallString> &filePathCache); StringCache<Utils::SmallString> &filePathCache);
PchCreator(V2::ProjectPartContainers &&projectsParts, PchCreator(V2::ProjectPartContainers &&projectsParts,
Environment &environment, Environment &environment,
StringCache<Utils::SmallString> &filePathCache); StringCache<Utils::SmallString> &filePathCache,
PchGeneratorInterface *pchGenerator);
void generatePchs(V2::ProjectPartContainers &&projectsParts) override; void generatePchs(V2::ProjectPartContainers &&projectsParts) override;
std::vector<ProjectPartPch> takeProjectPartPchs() override;
std::vector<IdPaths> takeProjectsIncludes() override; std::vector<IdPaths> takeProjectsIncludes() override;
void setGenerator(PchGeneratorInterface *pchGenerator);
unitttest_public: unitttest_public:
Utils::SmallStringVector generateGlobalHeaderPaths() const; Utils::SmallStringVector generateGlobalHeaderPaths() const;
Utils::SmallStringVector generateGlobalSourcePaths() const; Utils::SmallStringVector generateGlobalSourcePaths() const;
@@ -70,7 +73,8 @@ unitttest_public:
Utils::SmallString generatePchIncludeFileContent(const std::vector<uint> &includeIds) const; Utils::SmallString generatePchIncludeFileContent(const std::vector<uint> &includeIds) const;
Utils::SmallString generateGlobalPchHeaderFileContent() const; Utils::SmallString generateGlobalPchHeaderFileContent() const;
std::unique_ptr<QFile> generateGlobalPchHeaderFile(); std::unique_ptr<QFile> generateGlobalPchHeaderFile();
void generatePch(const Utils::SmallStringVector &commandLineArguments); void generatePch(Utils::SmallStringVector &&commandLineArguments,
ProjectPartPch &&projectPartPch);
void generateGlobalPch(); void generateGlobalPch();
Utils::SmallString globalPchContent() const; Utils::SmallString globalPchContent() const;
@@ -97,7 +101,7 @@ unitttest_public:
const V2::ProjectPartContainer &projectPart) const; const V2::ProjectPartContainer &projectPart) const;
Utils::SmallStringVector generateProjectPartClangCompilerArguments( Utils::SmallStringVector generateProjectPartClangCompilerArguments(
const V2::ProjectPartContainer &projectPart) const; const V2::ProjectPartContainer &projectPart) const;
std::pair<ProjectPartPch, IdPaths> generateProjectPartPch( IdPaths generateProjectPartPch(
const V2::ProjectPartContainer &projectPart); const V2::ProjectPartContainer &projectPart);
static std::unique_ptr<QFile> generatePchHeaderFile( static std::unique_ptr<QFile> generatePchHeaderFile(
const Utils::SmallString &filePath, const Utils::SmallString &filePath,
@@ -108,7 +112,6 @@ unitttest_public:
private: private:
static QByteArray projectPartHash(const V2::ProjectPartContainer &projectPart); static QByteArray projectPartHash(const V2::ProjectPartContainer &projectPart);
QByteArray globalProjectHash() const; QByteArray globalProjectHash() const;
static void checkIfProcessHasError(const QProcess &process);
private: private:
V2::ProjectPartContainers m_projectParts; V2::ProjectPartContainers m_projectParts;
@@ -116,6 +119,7 @@ private:
std::vector<IdPaths> m_projectsIncludeIds; std::vector<IdPaths> m_projectsIncludeIds;
Environment &m_environment; Environment &m_environment;
StringCache<Utils::SmallString> &m_filePathCache; StringCache<Utils::SmallString> &m_filePathCache;
PchGeneratorInterface *m_pchGenerator = nullptr;
}; };
} // namespace ClangBackEnd } // namespace ClangBackEnd

View File

@@ -38,7 +38,6 @@ public:
virtual ~PchCreatorInterface(); virtual ~PchCreatorInterface();
virtual void generatePchs(V2::ProjectPartContainers &&projectsParts) = 0; virtual void generatePchs(V2::ProjectPartContainers &&projectsParts) = 0;
virtual std::vector<ProjectPartPch> takeProjectPartPchs() = 0;
virtual std::vector<IdPaths> takeProjectsIncludes() = 0; virtual std::vector<IdPaths> takeProjectsIncludes() = 0;
}; };

View File

@@ -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

View File

@@ -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()
{
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -58,8 +58,6 @@ void PchManagerServer::updatePchProjectParts(UpdatePchProjectPartsMessage &&mess
{ {
m_pchCreator.generatePchs(m_projectParts.update(message.takeProjectsParts())); m_pchCreator.generatePchs(m_projectParts.update(message.takeProjectsParts()));
client()->precompiledHeadersUpdated(PrecompiledHeadersUpdatedMessage(m_pchCreator.takeProjectPartPchs()));
m_fileSystemWatcher.updateIdPaths(m_pchCreator.takeProjectsIncludes()); m_fileSystemWatcher.updateIdPaths(m_pchCreator.takeProjectsIncludes());
} }
@@ -74,9 +72,13 @@ void PchManagerServer::pathsWithIdsChanged(const Utils::SmallStringVector &ids)
{ {
m_pchCreator.generatePchs(m_projectParts.projects(ids)); m_pchCreator.generatePchs(m_projectParts.projects(ids));
client()->precompiledHeadersUpdated(PrecompiledHeadersUpdatedMessage(m_pchCreator.takeProjectPartPchs()));
m_fileSystemWatcher.updateIdPaths(m_pchCreator.takeProjectsIncludes()); 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 } // namespace ClangBackEnd

View File

@@ -28,6 +28,7 @@
#include "clangpathwatcherinterface.h" #include "clangpathwatcherinterface.h"
#include "clangpathwatchernotifier.h" #include "clangpathwatchernotifier.h"
#include "pchcreatorinterface.h" #include "pchcreatorinterface.h"
#include "pchgeneratornotifierinterface.h"
#include "pchmanagerserverinterface.h" #include "pchmanagerserverinterface.h"
#include "projectpartsinterface.h" #include "projectpartsinterface.h"
#include "stringcache.h" #include "stringcache.h"
@@ -36,7 +37,9 @@ namespace ClangBackEnd {
class SourceRangesAndDiagnosticsForQueryMessage; class SourceRangesAndDiagnosticsForQueryMessage;
class PchManagerServer : public PchManagerServerInterface, public ClangPathWatcherNotifier class PchManagerServer : public PchManagerServerInterface,
public ClangPathWatcherNotifier,
public PchGeneratorNotifierInterface
{ {
public: public:
PchManagerServer(StringCache<Utils::SmallString> &filePathCache, PchManagerServer(StringCache<Utils::SmallString> &filePathCache,
@@ -50,6 +53,7 @@ public:
void removePchProjectParts(RemovePchProjectPartsMessage &&message) override; void removePchProjectParts(RemovePchProjectPartsMessage &&message) override;
void pathsWithIdsChanged(const Utils::SmallStringVector &ids) override; void pathsWithIdsChanged(const Utils::SmallStringVector &ids) override;
void taskFinished(TaskFinishStatus status, const ProjectPartPch &projectPartPch) override;
private: private:
StringCache<Utils::SmallString> &m_filePathCache; StringCache<Utils::SmallString> &m_filePathCache;

View File

@@ -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;
}

View File

@@ -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;
};

View File

@@ -36,8 +36,6 @@ class MockPchCreator : public ClangBackEnd::PchCreatorInterface
public: public:
MOCK_METHOD1(generatePchs, MOCK_METHOD1(generatePchs,
void(const std::vector<ClangBackEnd::V2::ProjectPartContainer> &projectParts)); void(const std::vector<ClangBackEnd::V2::ProjectPartContainer> &projectParts));
MOCK_METHOD0(takeProjectPartPchs,
std::vector<ClangBackEnd::ProjectPartPch>());
MOCK_METHOD0(takeProjectsIncludes, MOCK_METHOD0(takeProjectsIncludes,
std::vector<ClangBackEnd::IdPaths>()); std::vector<ClangBackEnd::IdPaths>());

View File

@@ -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));
};

View File

@@ -25,9 +25,12 @@
#include "googletest.h" #include "googletest.h"
#include "fakeprocess.h"
#include "mockpchgeneratornotifier.h"
#include "testenvironment.h" #include "testenvironment.h"
#include <pchcreator.h> #include <pchcreator.h>
#include <pchgenerator.h>
#include <stringcache.h> #include <stringcache.h>
#include <QFileInfo> #include <QFileInfo>
@@ -70,9 +73,12 @@ protected:
{header2Path.clone()}, {header2Path.clone()},
{main2Path.clone()}}; {main2Path.clone()}};
TestEnvironment environment; TestEnvironment environment;
NiceMock<MockPchGeneratorNotifier> mockPchGeneratorNotifier;
ClangBackEnd::PchGenerator<FakeProcess> generator{environment, &mockPchGeneratorNotifier};
ClangBackEnd::PchCreator creator{{projectPart1.clone(),projectPart2.clone()}, ClangBackEnd::PchCreator creator{{projectPart1.clone(),projectPart2.clone()},
environment, environment,
filePathCache}; filePathCache,
&generator};
}; };
using PchCreatorSlowTest = PchCreator; 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")); 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(); auto includeIds = creator.generateGlobalPchIncludeIds();
@@ -167,13 +173,6 @@ TEST_F(PchCreator, CreateGlobalClangCompilerArguments)
Not(Contains(environment.clangCompilerPath())))); Not(Contains(environment.clangCompilerPath()))));
} }
TEST_F(PchCreatorVerySlowTest, CreateGlobalPch)
{
creator.generateGlobalPch();
ASSERT_TRUE(QFileInfo::exists(creator.generateGlobalPchFilePath()));
}
TEST_F(PchCreator, CreateProjectPartCommandLine) TEST_F(PchCreator, CreateProjectPartCommandLine)
{ {
auto commandLine = creator.generateProjectPartCommandLine(projectPart1); auto commandLine = creator.generateProjectPartCommandLine(projectPart1);
@@ -258,23 +257,34 @@ TEST_F(PchCreatorVerySlowTest, CreatePartPchs)
{ {
creator.generateGlobalPch(); creator.generateGlobalPch();
auto projectPartPchAndIdPath = creator.generateProjectPartPch(projectPart1); auto includePaths = creator.generateProjectPartPch(projectPart1);
ASSERT_THAT(projectPartPchAndIdPath.first.id(), projectPart1.projectPartId()); ASSERT_THAT(includePaths.id, projectPart1.projectPartId());
ASSERT_THAT(projectPartPchAndIdPath.first.path(), creator.generateProjectPartPchFilePath(projectPart1)); ASSERT_THAT(includePaths.paths, UnorderedElementsAre(1, 2, 3));
ASSERT_THAT(projectPartPchAndIdPath.second.id, projectPart1.projectPartId()); }
ASSERT_THAT(projectPartPchAndIdPath.second.paths, UnorderedElementsAre(1, 2, 3));
TEST_F(PchCreatorVerySlowTest, IncludesForCreatePchsForProjectParts)
{
creator.generatePchs();
ASSERT_THAT(creator.takeProjectsIncludes(),
ElementsAre(Field(&IdPaths::id, "project1"),
Field(&IdPaths::id, "project2")));
} }
TEST_F(PchCreatorVerySlowTest, ProjectPartPchsForCreatePchsForProjectParts) TEST_F(PchCreatorVerySlowTest, ProjectPartPchsForCreatePchsForProjectParts)
{ {
creator.generatePchs(); EXPECT_CALL(mockPchGeneratorNotifier,
taskFinished(ClangBackEnd::TaskFinishStatus::Successfully,
ASSERT_THAT(creator.takeProjectPartPchs(), Property(&ProjectPartPch::id, "project1")));
ElementsAre(Property(&ProjectPartPch::id, "project1"), EXPECT_CALL(mockPchGeneratorNotifier,
taskFinished(ClangBackEnd::TaskFinishStatus::Successfully,
Property(&ProjectPartPch::id, "project2"))); Property(&ProjectPartPch::id, "project2")));
creator.generatePchs();
} }
TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts) TEST_F(PchCreatorVerySlowTest, IdPathsForCreatePchsForProjectParts)
{ {
creator.generatePchs(); creator.generatePchs();

View File

@@ -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));
}
}

View File

@@ -47,6 +47,7 @@ using testing::IsEmpty;
using Utils::SmallString; using Utils::SmallString;
using ClangBackEnd::V2::ProjectPartContainer; using ClangBackEnd::V2::ProjectPartContainer;
using ClangBackEnd::TaskFinishStatus;
class PchManagerServer : public ::testing::Test class PchManagerServer : public ::testing::Test
{ {
@@ -76,18 +77,28 @@ protected:
{main2Path.clone()}}; {main2Path.clone()}};
std::vector<ClangBackEnd::V2::ProjectPartContainer> projectParts{projectPart1, projectPart2}; std::vector<ClangBackEnd::V2::ProjectPartContainer> projectParts{projectPart1, projectPart2};
ClangBackEnd::UpdatePchProjectPartsMessage updatePchProjectPartsMessage{Utils::clone(projectParts)}; ClangBackEnd::UpdatePchProjectPartsMessage updatePchProjectPartsMessage{Utils::clone(projectParts)};
std::vector<ClangBackEnd::ProjectPartPch> projectPartPchs{{projectPart1.projectPartId().clone(), "/path1/to/pch"}, ClangBackEnd::ProjectPartPch projectPartPch1{projectPart1.projectPartId().clone(), "/path1/to/pch"};
{projectPart2.projectPartId().clone(), "/path2/to/pch"}}; ClangBackEnd::ProjectPartPch projectPartPch2{projectPart2.projectPartId().clone(), "/path2/to/pch"};
ClangBackEnd::PrecompiledHeadersUpdatedMessage precompiledHeaderUpdatedMessage{Utils::clone(projectPartPchs)}; std::vector<ClangBackEnd::ProjectPartPch> projectPartPchs{projectPartPch1, projectPartPch2};
ClangBackEnd::PrecompiledHeadersUpdatedMessage precompiledHeaderUpdatedMessage1{{projectPartPch1}};
ClangBackEnd::PrecompiledHeadersUpdatedMessage precompiledHeaderUpdatedMessage2{{projectPartPch2}};
ClangBackEnd::RemovePchProjectPartsMessage removePchProjectPartsMessage{{projectPart1.projectPartId().clone(), ClangBackEnd::RemovePchProjectPartsMessage removePchProjectPartsMessage{{projectPart1.projectPartId().clone(),
projectPart2.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) TEST_F(PchManagerServer, CallBuildInPchCreator)
@@ -150,15 +161,6 @@ TEST_F(PchManagerServer, CallGeneratePchsInPchCreatorForIncludeChange)
server.pathsWithIdsChanged({projectPartId1}); server.pathsWithIdsChanged({projectPartId1});
} }
TEST_F(PchManagerServer, CallPrecompiledHeadersUpdatedInClientForIncludeChange)
{
server.updatePchProjectParts(updatePchProjectPartsMessage.clone());
EXPECT_CALL(mockPchManagerClient, precompiledHeadersUpdated(precompiledHeaderUpdatedMessage));
server.pathsWithIdsChanged({projectPartId1});
}
TEST_F(PchManagerServer, CallUpdateIdPathsInFileSystemWatcherForIncludeChange) TEST_F(PchManagerServer, CallUpdateIdPathsInFileSystemWatcherForIncludeChange)
{ {
server.updatePchProjectParts(updatePchProjectPartsMessage.clone()); server.updatePchProjectParts(updatePchProjectPartsMessage.clone());
@@ -172,8 +174,6 @@ void PchManagerServer::SetUp()
{ {
server.setClient(&mockPchManagerClient); server.setClient(&mockPchManagerClient);
ON_CALL(mockPchCreator, takeProjectPartPchs())
.WillByDefault(Return(projectPartPchs));
ON_CALL(mockProjectParts, update(projectParts)) ON_CALL(mockProjectParts, update(projectParts))
.WillByDefault(Return(projectParts)); .WillByDefault(Return(projectParts));
ON_CALL(mockProjectParts, projects(Utils::SmallStringVector{{projectPartId1}})) ON_CALL(mockProjectParts, projects(Utils::SmallStringVector{{projectPartId1}}))

View File

@@ -45,6 +45,11 @@ public:
return QString::fromUtf8(CLANG_COMPILER_PATH); return QString::fromUtf8(CLANG_COMPILER_PATH);
} }
uint hardwareConcurrency() const
{
return 2;
}
private: private:
QTemporaryDir temporaryDirectory; QTemporaryDir temporaryDirectory;
}; };

View File

@@ -49,7 +49,9 @@ SOURCES += \
projectparts-test.cpp \ projectparts-test.cpp \
stringcache-test.cpp \ stringcache-test.cpp \
changedfilepathcompressor-test.cpp \ changedfilepathcompressor-test.cpp \
faketimer.cpp faketimer.cpp \
pchgenerator-test.cpp \
fakeprocess.cpp
!isEmpty(LIBCLANG_LIBS) { !isEmpty(LIBCLANG_LIBS) {
SOURCES += \ SOURCES += \
@@ -148,7 +150,9 @@ HEADERS += \
mockprojectparts.h \ mockprojectparts.h \
mockclangpathwatchernotifier.h \ mockclangpathwatchernotifier.h \
mockchangedfilepathcompressor.h \ mockchangedfilepathcompressor.h \
faketimer.h faketimer.h \
mockpchgeneratornotifier.h \
fakeprocess.h
!isEmpty(LIBCLANG_LIBS) { !isEmpty(LIBCLANG_LIBS) {
HEADERS += \ HEADERS += \