Clang: Add timer based path notification compression

QFileWatcher is only reporting one path per signal which is suboptimal if
you change many files at once. This patch is introducing a timer which is
waiting some time time to see if more path changes are reported and is
collecting them in a vector.

Change-Id: I50f7c21186353b199634e7b3cd5a41f8d581a31d
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Marco Bubke
2017-01-31 11:14:54 +01:00
parent 9678c09355
commit 2c55a9c569
12 changed files with 426 additions and 51 deletions

View File

@@ -37,6 +37,7 @@
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QLoggingCategory> #include <QLoggingCategory>
#include <QTemporaryDir> #include <QTemporaryDir>
#include <QTimer>
using ClangBackEnd::ClangPathWatcher; using ClangBackEnd::ClangPathWatcher;
using ClangBackEnd::ConnectionServer; using ClangBackEnd::ConnectionServer;
@@ -93,11 +94,15 @@ int main(int argc, char *argv[])
const QString connection = processArguments(application); const QString connection = processArguments(application);
StringCache<Utils::SmallString> filePathCache; StringCache<Utils::SmallString> filePathCache;
ClangPathWatcher<QFileSystemWatcher> includeWatcher(filePathCache); ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher(filePathCache);
ApplicationEnvironment environment; ApplicationEnvironment environment;
PchCreator pchCreator(environment, filePathCache); PchCreator pchCreator(environment, filePathCache);
ProjectParts projectParts; ProjectParts projectParts;
PchManagerServer clangPchManagerServer(filePathCache, includeWatcher, pchCreator, projectParts); PchManagerServer clangPchManagerServer(filePathCache,
includeWatcher,
pchCreator,
projectParts);
includeWatcher.setNotifier(&clangPchManagerServer);
ConnectionServer<PchManagerServer, PchManagerClientProxy> connectionServer(connection); ConnectionServer<PchManagerServer, PchManagerClientProxy> connectionServer(connection);
connectionServer.start(); connectionServer.start();
connectionServer.setServer(&clangPchManagerServer); connectionServer.setServer(&clangPchManagerServer);

View File

@@ -0,0 +1,86 @@
/****************************************************************************
**
** 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 <clangpchmanagerbackend_global.h>
#include <utils/smallstringvector.h>
#include <QTimer>
#include <functional>
namespace ClangBackEnd {
template <typename Timer>
class ChangedFilePathCompressor non_unittest_final
{
public:
ChangedFilePathCompressor()
{
m_timer.setSingleShot(true);
}
virtual ~ChangedFilePathCompressor()
{
}
void addFilePath(const QString &filePath)
{
m_filePaths.push_back(filePath);
restartTimer();
}
Utils::SmallStringVector takeFilePaths()
{
return std::move(m_filePaths);
}
virtual void setCallback(std::function<void(Utils::SmallStringVector &&)> &&callback)
{
QObject::connect(&m_timer,
&Timer::timeout,
[this, callback=std::move(callback)] { callback(takeFilePaths()); });
}
unitttest_public:
virtual void restartTimer()
{
m_timer.start(20);
}
Timer &timer()
{
return m_timer;
}
private:
Utils::SmallStringVector m_filePaths;
Timer m_timer;
};
} // namespace ClangBackEnd

View File

@@ -27,9 +27,10 @@
#include "clangpathwatcherinterface.h" #include "clangpathwatcherinterface.h"
#include "clangpathwatchernotifier.h" #include "clangpathwatchernotifier.h"
#include "changedfilepathcompressor.h"
#include "stringcache.h" #include "stringcache.h"
#include <QObject> #include <QTimer>
namespace ClangBackEnd { namespace ClangBackEnd {
@@ -60,7 +61,10 @@ public:
} }
}; };
template <typename FileSystemWatcher> using WatcherEntries = std::vector<WatcherEntry>;
template <typename FileSystemWatcher,
typename Timer>
class ClangPathWatcher : public ClangPathWatcherInterface class ClangPathWatcher : public ClangPathWatcherInterface
{ {
public: public:
@@ -71,7 +75,16 @@ public:
{ {
QObject::connect(&m_fileSystemWatcher, QObject::connect(&m_fileSystemWatcher,
&FileSystemWatcher::fileChanged, &FileSystemWatcher::fileChanged,
[&] (const QString &filePath) { addChangedPathForFilePath(filePath); }); [&] (const QString &filePath) { compressChangedFilePath(filePath); });
m_changedFilePathCompressor.setCallback([&] (Utils::SmallStringVector &&filePaths) {
addChangedPathForFilePath(std::move(filePaths));
});
}
~ClangPathWatcher()
{
m_changedFilePathCompressor.setCallback([&] (Utils::SmallStringVector &&) {});
} }
void updateIdPaths(const std::vector<IdPaths> &idPaths) override void updateIdPaths(const std::vector<IdPaths> &idPaths) override
@@ -136,10 +149,10 @@ unitttest_public:
} }
std::pair<std::vector<WatcherEntry>,std::vector<uint>> std::pair<WatcherEntries,std::vector<uint>>
convertIdPathsToWatcherEntriesAndIds(const std::vector<IdPaths> &idPaths) convertIdPathsToWatcherEntriesAndIds(const std::vector<IdPaths> &idPaths)
{ {
std::vector<WatcherEntry> entries; WatcherEntries entries;
entries.reserve(sizeOfIdPaths(idPaths)); entries.reserve(sizeOfIdPaths(idPaths));
std::vector<uint> ids; std::vector<uint> ids;
ids.reserve(ids.size()); ids.reserve(ids.size());
@@ -164,7 +177,7 @@ unitttest_public:
return {entries, ids}; return {entries, ids};
} }
void addEntries(const std::vector<WatcherEntry> &entries) void addEntries(const WatcherEntries &entries)
{ {
auto newEntries = notWatchedEntries(entries); auto newEntries = notWatchedEntries(entries);
@@ -176,7 +189,7 @@ unitttest_public:
m_fileSystemWatcher.addPaths(convertWatcherEntriesToQStringList(filteredPaths)); m_fileSystemWatcher.addPaths(convertWatcherEntriesToQStringList(filteredPaths));
} }
void removeUnusedEntries(const std::vector<WatcherEntry> &entries, void removeUnusedEntries(const WatcherEntries &entries,
const std::vector<uint> &ids) const std::vector<uint> &ids)
{ {
auto oldEntries = notAnymoreWatchedEntriesWithIds(entries, ids); auto oldEntries = notAnymoreWatchedEntriesWithIds(entries, ids);
@@ -195,7 +208,7 @@ unitttest_public:
} }
QStringList convertWatcherEntriesToQStringList( QStringList convertWatcherEntriesToQStringList(
const std::vector<WatcherEntry> &watcherEntries) const WatcherEntries &watcherEntries)
{ {
QStringList paths; QStringList paths;
paths.reserve(int(watcherEntries.size())); paths.reserve(int(watcherEntries.size()));
@@ -209,10 +222,10 @@ unitttest_public:
} }
template <typename Compare> template <typename Compare>
std::vector<WatcherEntry> notWatchedEntries(const std::vector<WatcherEntry> &entries, WatcherEntries notWatchedEntries(const WatcherEntries &entries,
Compare compare) const Compare compare) const
{ {
std::vector<WatcherEntry> notWatchedEntries; WatcherEntries notWatchedEntries;
notWatchedEntries.reserve(entries.size()); notWatchedEntries.reserve(entries.size());
std::set_difference(entries.begin(), std::set_difference(entries.begin(),
@@ -225,12 +238,12 @@ unitttest_public:
return notWatchedEntries; return notWatchedEntries;
} }
std::vector<WatcherEntry> notWatchedEntries(const std::vector<WatcherEntry> &entries) const WatcherEntries notWatchedEntries(const WatcherEntries &entries) const
{ {
return notWatchedEntries(entries, std::less<WatcherEntry>()); return notWatchedEntries(entries, std::less<WatcherEntry>());
} }
std::vector<WatcherEntry> notWatchedPaths(const std::vector<WatcherEntry> &entries) const WatcherEntries notWatchedPaths(const WatcherEntries &entries) const
{ {
auto compare = [] (const WatcherEntry &first, const WatcherEntry &second) { auto compare = [] (const WatcherEntry &first, const WatcherEntry &second) {
return first.path < second.path; return first.path < second.path;
@@ -240,11 +253,11 @@ unitttest_public:
} }
template <typename Compare> template <typename Compare>
std::vector<WatcherEntry> notAnymoreWatchedEntries( WatcherEntries notAnymoreWatchedEntries(
const std::vector<WatcherEntry> &newEntries, const WatcherEntries &newEntries,
Compare compare) const Compare compare) const
{ {
std::vector<WatcherEntry> notAnymoreWatchedEntries; WatcherEntries notAnymoreWatchedEntries;
notAnymoreWatchedEntries.reserve(m_watchedEntries.size()); notAnymoreWatchedEntries.reserve(m_watchedEntries.size());
std::set_difference(m_watchedEntries.cbegin(), std::set_difference(m_watchedEntries.cbegin(),
@@ -257,8 +270,8 @@ unitttest_public:
return notAnymoreWatchedEntries; return notAnymoreWatchedEntries;
} }
std::vector<WatcherEntry> notAnymoreWatchedEntriesWithIds( WatcherEntries notAnymoreWatchedEntriesWithIds(
const std::vector<WatcherEntry> &newEntries, const WatcherEntries &newEntries,
const std::vector<uint> &ids) const const std::vector<uint> &ids) const
{ {
auto oldEntries = notAnymoreWatchedEntries(newEntries, std::less<WatcherEntry>()); auto oldEntries = notAnymoreWatchedEntries(newEntries, std::less<WatcherEntry>());
@@ -274,9 +287,9 @@ unitttest_public:
return oldEntries; return oldEntries;
} }
void mergeToWatchedEntries(const std::vector<WatcherEntry> &newEntries) void mergeToWatchedEntries(const WatcherEntries &newEntries)
{ {
std::vector<WatcherEntry> newWatchedEntries; WatcherEntries newWatchedEntries;
newWatchedEntries.reserve(m_watchedEntries.size() + newEntries.size()); newWatchedEntries.reserve(m_watchedEntries.size() + newEntries.size());
std::merge(m_watchedEntries.cbegin(), std::merge(m_watchedEntries.cbegin(),
@@ -289,9 +302,9 @@ unitttest_public:
} }
static static
std::vector<WatcherEntry> uniquePaths(const std::vector<WatcherEntry> &pathEntries) WatcherEntries uniquePaths(const WatcherEntries &pathEntries)
{ {
std::vector<WatcherEntry> uniqueEntries; WatcherEntries uniqueEntries;
auto compare = [] (const WatcherEntry &first, const WatcherEntry &second) { auto compare = [] (const WatcherEntry &first, const WatcherEntry &second) {
return first.path == second.path; return first.path == second.path;
@@ -305,17 +318,17 @@ unitttest_public:
return uniqueEntries; return uniqueEntries;
} }
std::vector<WatcherEntry> filterNotWatchedPaths(const std::vector<WatcherEntry> &entries) WatcherEntries filterNotWatchedPaths(const WatcherEntries &entries)
{ {
return notWatchedPaths(uniquePaths(entries)); return notWatchedPaths(uniquePaths(entries));
} }
const std::vector<WatcherEntry> &watchedEntries() const const WatcherEntries &watchedEntries() const
{ {
return m_watchedEntries; return m_watchedEntries;
} }
std::vector<WatcherEntry> removeIdsFromWatchedEntries(const std::vector<uint> &ids) WatcherEntries removeIdsFromWatchedEntries(const std::vector<uint> &ids)
{ {
auto keep = [&] (const WatcherEntry &entry) { auto keep = [&] (const WatcherEntry &entry) {
@@ -326,16 +339,16 @@ unitttest_public:
m_watchedEntries.end(), m_watchedEntries.end(),
keep); keep);
std::vector<WatcherEntry> removedEntries(found, m_watchedEntries.end()); WatcherEntries removedEntries(found, m_watchedEntries.end());
m_watchedEntries.erase(found, m_watchedEntries.end()); m_watchedEntries.erase(found, m_watchedEntries.end());
return removedEntries; return removedEntries;
} }
void removeFromWatchedEntries(const std::vector<WatcherEntry> &oldEntries) void removeFromWatchedEntries(const WatcherEntries &oldEntries)
{ {
std::vector<WatcherEntry> newWatchedEntries; WatcherEntries newWatchedEntries;
newWatchedEntries.reserve(m_watchedEntries.size() - oldEntries.size()); newWatchedEntries.reserve(m_watchedEntries.size() - oldEntries.size());
std::set_difference(m_watchedEntries.cbegin(), std::set_difference(m_watchedEntries.cbegin(),
@@ -348,25 +361,57 @@ unitttest_public:
m_watchedEntries = newWatchedEntries; m_watchedEntries = newWatchedEntries;
} }
void addChangedPathForFilePath(const QString &filePath) void compressChangedFilePath(const QString &filePath)
{ {
uint pathId = m_pathCache.stringId(Utils::SmallString(filePath)); m_changedFilePathCompressor.addFilePath(filePath);
}
auto range = std::equal_range(m_watchedEntries.begin(), m_watchedEntries.end(), pathId); WatcherEntries watchedEntriesForPaths(Utils::SmallStringVector &&filePaths)
{
std::vector<uint> pathIds = m_pathCache.stringIds(filePaths);
Utils::SmallStringVector changedIds; WatcherEntries foundEntries;
std::transform(range.first, for (uint pathId : pathIds) {
range.second, auto range = std::equal_range(m_watchedEntries.begin(), m_watchedEntries.end(), pathId);
std::back_inserter(changedIds), foundEntries.insert(foundEntries.end(), range.first, range.second);
}
return foundEntries;
}
Utils::SmallStringVector idsForWatcherEntries(const WatcherEntries &foundEntries)
{
Utils::SmallStringVector ids;
std::transform(foundEntries.begin(),
foundEntries.end(),
std::back_inserter(ids),
[&] (const WatcherEntry &entry) { [&] (const WatcherEntry &entry) {
return m_idCache.string(entry.id); return m_idCache.string(entry.id);
}); });
std::sort(changedIds.begin(), changedIds.end()); return ids;
}
if (m_notifier) Utils::SmallStringVector uniqueIds(Utils::SmallStringVector &&ids)
m_notifier->pathsWithIdsChanged(changedIds); {
std::sort(ids.begin(), ids.end());
auto newEnd = std::unique(ids.begin(), ids.end());
ids.erase(newEnd, ids.end());
return std::move(ids);
}
void addChangedPathForFilePath(Utils::SmallStringVector &&filePaths)
{
if (m_notifier) {
WatcherEntries foundEntries = watchedEntriesForPaths(std::move(filePaths));
Utils::SmallStringVector changedIds = idsForWatcherEntries(foundEntries);
m_notifier->pathsWithIdsChanged(uniqueIds(std::move(changedIds)));
}
} }
StringCache<Utils::SmallString> &pathCache() StringCache<Utils::SmallString> &pathCache()
@@ -381,7 +426,8 @@ unitttest_public:
private: private:
StringCache<Utils::SmallString> m_idCache; StringCache<Utils::SmallString> m_idCache;
std::vector<WatcherEntry> m_watchedEntries; WatcherEntries m_watchedEntries;
ChangedFilePathCompressor<Timer> m_changedFilePathCompressor;
FileSystemWatcher m_fileSystemWatcher; FileSystemWatcher m_fileSystemWatcher;
StringCache<Utils::SmallString> &m_pathCache; StringCache<Utils::SmallString> &m_pathCache;
ClangPathWatcherNotifier *m_notifier; ClangPathWatcherNotifier *m_notifier;

View File

@@ -29,4 +29,5 @@ HEADERS += \
$$PWD/pchcreatorinterface.h \ $$PWD/pchcreatorinterface.h \
$$PWD/clangpathwatcherinterface.h \ $$PWD/clangpathwatcherinterface.h \
$$PWD/projectpartsinterface.h \ $$PWD/projectpartsinterface.h \
$$PWD/clangpathwatchernotifier.h $$PWD/clangpathwatchernotifier.h \
$$PWD/changedfilepathcompressor.h

View File

@@ -27,8 +27,10 @@
#ifdef UNIT_TESTS #ifdef UNIT_TESTS
#define unitttest_public public #define unitttest_public public
#define non_unittest_final
#else #else
#define unitttest_public private #define unitttest_public private
#define non_unittest_final final
#endif #endif
namespace llvm { namespace llvm {

View File

@@ -65,14 +65,12 @@ std::vector<uint> IncludeCollector::generateExcludedIncludeFileUIDs(clang::FileM
std::vector<uint> fileUIDs; std::vector<uint> fileUIDs;
fileUIDs.reserve(m_excludedIncludes.size()); fileUIDs.reserve(m_excludedIncludes.size());
auto generateUID = [&] (const Utils::SmallString &filePath) { for (const Utils::SmallString &filePath : m_excludedIncludes) {
return fileManager.getFile({filePath.data(), filePath.size()})->getUID(); const clang::FileEntry *file = fileManager.getFile({filePath.data(), filePath.size()});
};
std::transform(m_excludedIncludes.begin(), if (file)
m_excludedIncludes.end(), fileUIDs.push_back(file->getUID());
std::back_inserter(fileUIDs), }
generateUID);
std::sort(fileUIDs.begin(), fileUIDs.end()); std::sort(fileUIDs.begin(), fileUIDs.end());

View File

@@ -0,0 +1,87 @@
/****************************************************************************
**
** 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 <mockchangedfilepathcompressor.h>
namespace {
using testing::ElementsAre;
using testing::Invoke;
using testing::IsEmpty;
using testing::NiceMock;
class ChangedFilePathCompressor : public testing::Test
{
protected:
void SetUp();
protected:
NiceMock<MockChangedFilePathCompressor> mockCompressor;
ClangBackEnd::ChangedFilePathCompressor<FakeTimer> compressor;
QString filePath1{"filePath1"};
QString filePath2{"filePath2"};
};
TEST_F(ChangedFilePathCompressor, AddFilePath)
{
mockCompressor.addFilePath(filePath1);
ASSERT_THAT(mockCompressor.takeFilePaths(), ElementsAre(filePath1));
}
TEST_F(ChangedFilePathCompressor, NoFilePathsAferTakenThem)
{
mockCompressor.addFilePath(filePath1);
mockCompressor.takeFilePaths();
ASSERT_THAT(mockCompressor.takeFilePaths(), IsEmpty());
}
TEST_F(ChangedFilePathCompressor, CallRestartTimerAfterAddingPath)
{
EXPECT_CALL(mockCompressor, restartTimer());
mockCompressor.addFilePath(filePath1);
}
TEST_F(ChangedFilePathCompressor, CallTimeOutAfterAddingPath)
{
EXPECT_CALL(mockCompressor, callbackCalled(ElementsAre(filePath1, filePath2)));
compressor.addFilePath(filePath1);
compressor.addFilePath(filePath2);
}
void ChangedFilePathCompressor::SetUp()
{
compressor.setCallback([&] (Utils::SmallStringVector &&filePaths) {
mockCompressor.callbackCalled(filePaths);
});
}
}

View File

@@ -25,6 +25,7 @@
#include "googletest.h" #include "googletest.h"
#include "faketimer.h"
#include "mockqfilesystemwatcher.h" #include "mockqfilesystemwatcher.h"
#include "mockclangpathwatchernotifier.h" #include "mockclangpathwatchernotifier.h"
@@ -39,7 +40,7 @@ using testing::IsEmpty;
using testing::SizeIs; using testing::SizeIs;
using testing::NiceMock; using testing::NiceMock;
using Watcher = ClangBackEnd::ClangPathWatcher<NiceMock<MockQFileSytemWatcher>>; using Watcher = ClangBackEnd::ClangPathWatcher<NiceMock<MockQFileSytemWatcher>, FakeTimer>;
using ClangBackEnd::WatcherEntry; using ClangBackEnd::WatcherEntry;
class ClangPathWatcher : public testing::Test class ClangPathWatcher : public testing::Test
@@ -310,4 +311,14 @@ TEST_F(ClangPathWatcher, NotifyFileChange)
mockQFileSytemWatcher.fileChanged(path1.toQString()); mockQFileSytemWatcher.fileChanged(path1.toQString());
} }
TEST_F(ClangPathWatcher, TwoNotifyFileChanges)
{
watcher.addEntries({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5});
EXPECT_CALL(notifier, pathsWithIdsChanged(ElementsAre(id2, id3, id1)));
mockQFileSytemWatcher.fileChanged(path2.toQString());
mockQFileSytemWatcher.fileChanged(path1.toQString());
}
} }

View File

@@ -0,0 +1,46 @@
/****************************************************************************
**
** 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 "faketimer.h"
FakeTimer::~FakeTimer()
{
emitTimoutIfStarted();
}
void FakeTimer::start(int)
{
m_isStarted = true;
}
void FakeTimer::setSingleShot(bool)
{
}
void FakeTimer::emitTimoutIfStarted()
{
if (m_isStarted)
emit timeout();
}

View File

@@ -0,0 +1,46 @@
/****************************************************************************
**
** 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 <QObject>
class FakeTimer : public QObject
{
Q_OBJECT
public:
~FakeTimer();
void start(int interval);
void setSingleShot(bool);
void emitTimoutIfStarted();
signals:
void timeout();
private:
bool m_isStarted = false;
};

View File

@@ -0,0 +1,43 @@
/****************************************************************************
**
** 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 "faketimer.h"
#include <changedfilepathcompressor.h>
class MockChangedFilePathCompressor : public ClangBackEnd::ChangedFilePathCompressor<FakeTimer>
{
public:
MOCK_METHOD0(restartTimer,
void ());
MOCK_METHOD1(callbackCalled,
void (const Utils::SmallStringVector &filePaths));
};

View File

@@ -47,7 +47,9 @@ SOURCES += \
clientserveroutsideprocess-test.cpp \ clientserveroutsideprocess-test.cpp \
clangpathwatcher-test.cpp \ clangpathwatcher-test.cpp \
projectparts-test.cpp \ projectparts-test.cpp \
stringcache-test.cpp stringcache-test.cpp \
changedfilepathcompressor-test.cpp \
faketimer.cpp
!isEmpty(LIBCLANG_LIBS) { !isEmpty(LIBCLANG_LIBS) {
SOURCES += \ SOURCES += \
@@ -144,7 +146,9 @@ HEADERS += \
mockqfilesystemwatcher.h \ mockqfilesystemwatcher.h \
mockclangpathwatcher.h \ mockclangpathwatcher.h \
mockprojectparts.h \ mockprojectparts.h \
mockclangpathwatchernotifier.h mockclangpathwatchernotifier.h \
mockchangedfilepathcompressor.h \
faketimer.h
!isEmpty(LIBCLANG_LIBS) { !isEmpty(LIBCLANG_LIBS) {
HEADERS += \ HEADERS += \