aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libs/clangsupport/clangpathwatcher.h214
-rw-r--r--src/libs/clangsupport/clangsupport-lib.pri10
-rw-r--r--src/libs/clangsupport/directoryandfilepathid.h90
-rw-r--r--src/libs/clangsupport/directorypathcompressor.h (renamed from src/libs/clangsupport/changedfilepathcompressor.h)48
-rw-r--r--src/libs/clangsupport/directorypathid.h81
-rw-r--r--src/libs/clangsupport/filepathcache.h48
-rw-r--r--src/libs/clangsupport/filepathcaching.cpp15
-rw-r--r--src/libs/clangsupport/filepathcaching.h3
-rw-r--r--src/libs/clangsupport/filepathcachinginterface.h6
-rw-r--r--src/libs/clangsupport/filepathexceptions.h9
-rw-r--r--src/libs/clangsupport/filepathstorage.h22
-rw-r--r--src/libs/clangsupport/filepathstoragesqlitestatementfactory.h2
-rw-r--r--src/libs/clangsupport/filestatus.h (renamed from src/tools/clangrefactoringbackend/source/filestatus.h)0
-rw-r--r--src/libs/clangsupport/filestatuscache.cpp169
-rw-r--r--src/libs/clangsupport/filestatuscache.h (renamed from src/tools/clangrefactoringbackend/source/filestatuscache.h)36
-rw-r--r--src/libs/clangsupport/filesystem.cpp61
-rw-r--r--src/libs/clangsupport/filesystem.h48
-rw-r--r--src/libs/clangsupport/filesysteminterface.h43
-rw-r--r--src/libs/utils/smallstringview.h4
-rw-r--r--src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp4
-rw-r--r--src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri5
-rw-r--r--src/tools/clangrefactoringbackend/source/filestatuscache.cpp93
-rw-r--r--src/tools/clangrefactoringbackend/source/symbolindexing.h6
-rw-r--r--tests/unit/unittest/changedfilepathcompressor-test.cpp112
-rw-r--r--tests/unit/unittest/clangpathwatcher-test.cpp281
-rw-r--r--tests/unit/unittest/directorypathcompressor-test.cpp99
-rw-r--r--tests/unit/unittest/filepathcache-test.cpp150
-rw-r--r--tests/unit/unittest/filepathstorage-test.cpp82
-rw-r--r--tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp8
-rw-r--r--tests/unit/unittest/filestatuscache-test.cpp180
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp2
-rw-r--r--tests/unit/unittest/mockfilepathcaching.h6
-rw-r--r--tests/unit/unittest/mockfilesystem.h37
-rw-r--r--tests/unit/unittest/mockqfilesystemwatcher.h1
-rw-r--r--tests/unit/unittest/mocksqlitereadstatement.cpp6
-rw-r--r--tests/unit/unittest/mocksqlitereadstatement.h11
-rw-r--r--tests/unit/unittest/symbolindexer-test.cpp17
-rw-r--r--tests/unit/unittest/unittest.pro5
38 files changed, 1479 insertions, 535 deletions
diff --git a/src/libs/clangsupport/clangpathwatcher.h b/src/libs/clangsupport/clangpathwatcher.h
index dab52996c2..7a7d6ccfcf 100644
--- a/src/libs/clangsupport/clangpathwatcher.h
+++ b/src/libs/clangsupport/clangpathwatcher.h
@@ -1,4 +1,4 @@
-/****************************************************************************
+; /****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
@@ -27,71 +27,94 @@
#include "clangpathwatcherinterface.h"
#include "clangpathwatchernotifier.h"
-#include "changedfilepathcompressor.h"
+#include "directorypathcompressor.h"
#include "filepathcachinginterface.h"
+#include "filesystem.h"
#include "stringcache.h"
+#include <utils/algorithm.h>
+
#include <QTimer>
namespace ClangBackEnd {
+template<class InputIt1, class InputIt2, class Callable>
+void set_greedy_intersection_call(
+ InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable)
+{
+ while (first1 != last1 && first2 != last2) {
+ if (*first1 < *first2) {
+ ++first1;
+ } else {
+ if (*first2 < *first1)
+ ++first2;
+ else
+ callable(*first1++);
+ }
+ }
+}
+
class WatcherEntry
{
public:
ProjectPartId id;
- FilePathId pathId;
+ DirectoryPathId directoryPathId;
+ FilePathId filePathId;
+ long long lastModified = -1;
friend bool operator==(WatcherEntry first, WatcherEntry second)
{
- return first.id == second.id && first.pathId == second.pathId;
+ return first.id == second.id && first.directoryPathId == second.directoryPathId
+ && first.filePathId == second.filePathId;
}
friend bool operator<(WatcherEntry first, WatcherEntry second)
{
- return std::tie(first.pathId, first.id) < std::tie(second.pathId, second.id);
+ return std::tie(first.directoryPathId, first.filePathId, first.id)
+ < std::tie(second.directoryPathId, second.filePathId, second.id);
}
- friend bool operator<(WatcherEntry entry, FilePathId pathId)
+ friend bool operator<(DirectoryPathId directoryPathId, WatcherEntry entry)
{
- return entry.pathId < pathId;
+ return directoryPathId < entry.directoryPathId;
}
- friend bool operator<(FilePathId pathId, WatcherEntry entry)
+ friend bool operator<(WatcherEntry entry, DirectoryPathId directoryPathId)
{
- return pathId < entry.pathId;
+ return entry.directoryPathId < directoryPathId;
}
- operator FilePathId() const
- {
- return pathId;
- }
+ operator FilePathId() const { return filePathId; }
+
+ operator DirectoryPathId() const { return directoryPathId; }
};
using WatcherEntries = std::vector<WatcherEntry>;
-template <typename FileSystemWatcher,
- typename Timer>
+template<typename FileSystemWatcher, typename Timer>
class CLANGSUPPORT_GCCEXPORT ClangPathWatcher : public ClangPathWatcherInterface
{
public:
ClangPathWatcher(FilePathCachingInterface &pathCache,
- ClangPathWatcherNotifier *notifier=nullptr)
- : m_changedFilePathCompressor(pathCache),
- m_pathCache(pathCache),
- m_notifier(notifier)
+ FileSystemInterface &fileSystem,
+ ClangPathWatcherNotifier *notifier = nullptr)
+ : m_pathCache(pathCache)
+ , m_fileStatusCache(fileSystem)
+ , m_fileSystem(fileSystem)
+ , m_notifier(notifier)
{
QObject::connect(&m_fileSystemWatcher,
- &FileSystemWatcher::fileChanged,
- [&] (const QString &filePath) { compressChangedFilePath(filePath); });
+ &FileSystemWatcher::directoryChanged,
+ [&](const QString &path) { compressChangedDirectoryPath(path); });
- m_changedFilePathCompressor.setCallback([&] (ClangBackEnd::FilePathIds &&filePathIds) {
- addChangedPathForFilePath(std::move(filePathIds));
+ m_directoryPathCompressor.setCallback([&](ClangBackEnd::DirectoryPathIds &&directoryPathIds) {
+ addChangedPathForFilePath(std::move(directoryPathIds));
});
}
~ClangPathWatcher()
{
- m_changedFilePathCompressor.setCallback([&] (FilePathIds &&) {});
+ m_directoryPathCompressor.setCallback([&](DirectoryPathIds &&) {});
}
void updateIdPaths(const std::vector<IdPaths> &idPaths) override
@@ -109,7 +132,7 @@ public:
auto filteredPaths = filterNotWatchedPaths(removedEntries);
if (!filteredPaths.empty())
- m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths));
+ m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
}
void setNotifier(ClangPathWatcherNotifier *notifier) override
@@ -164,7 +187,13 @@ public:
outputIterator = std::transform(idPath.filePathIds.begin(),
idPath.filePathIds.end(),
outputIterator,
- [&] (FilePathId pathId) { return WatcherEntry{id, pathId}; });
+ [&](FilePathId filePathId) {
+ return WatcherEntry{
+ id,
+ m_pathCache.directoryPathId(filePathId),
+ filePathId,
+ m_fileStatusCache.lastModifiedTime(filePathId)};
+ });
}
std::sort(entries.begin(), entries.end());
@@ -182,7 +211,7 @@ public:
mergeToWatchedEntries(newEntries);
if (!filteredPaths.empty())
- m_fileSystemWatcher.addPaths(convertWatcherEntriesToQStringList(filteredPaths));
+ m_fileSystemWatcher.addPaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
}
void removeUnusedEntries(const WatcherEntries &entries, const ProjectPartIds &ids)
@@ -194,33 +223,31 @@ public:
auto filteredPaths = filterNotWatchedPaths(oldEntries);
if (!filteredPaths.empty())
- m_fileSystemWatcher.removePaths(convertWatcherEntriesToQStringList(filteredPaths));
+ m_fileSystemWatcher.removePaths(convertWatcherEntriesToDirectoryPathList(filteredPaths));
}
- FileSystemWatcher &fileSystemWatcher()
+ FileSystemWatcher &fileSystemWatcher() { return m_fileSystemWatcher; }
+
+ QStringList convertWatcherEntriesToDirectoryPathList(const DirectoryPathIds &directoryPathIds) const
{
- return m_fileSystemWatcher;
+ return Utils::transform<QStringList>(directoryPathIds, [&](DirectoryPathId id) {
+ return QString(m_pathCache.directoryPath(id));
+ });
}
- QStringList convertWatcherEntriesToQStringList(
- const WatcherEntries &watcherEntries)
+ QStringList convertWatcherEntriesToDirectoryPathList(const WatcherEntries &watcherEntries) const
{
- QStringList paths;
- paths.reserve(int(watcherEntries.size()));
+ DirectoryPathIds directoryPathIds = Utils::transform<DirectoryPathIds>(
+ watcherEntries, [&](WatcherEntry entry) { return entry.directoryPathId; });
- std::transform(watcherEntries.begin(),
- watcherEntries.end(),
- std::back_inserter(paths),
- [&] (WatcherEntry entry) {
- return QString(m_pathCache.filePath(entry.pathId).path());
- });
+ std::sort(directoryPathIds.begin(), directoryPathIds.end());
+ directoryPathIds.erase(std::unique(directoryPathIds.begin(), directoryPathIds.end()),
+ directoryPathIds.end());
- return paths;
+ return convertWatcherEntriesToDirectoryPathList(directoryPathIds);
}
- template <typename Compare>
- WatcherEntries notWatchedEntries(const WatcherEntries &entries,
- Compare compare) const
+ WatcherEntries notWatchedEntries(const WatcherEntries &entries) const
{
WatcherEntries notWatchedEntries;
notWatchedEntries.reserve(entries.size());
@@ -229,24 +256,23 @@ public:
entries.end(),
m_watchedEntries.cbegin(),
m_watchedEntries.cend(),
- std::back_inserter(notWatchedEntries),
- compare);
+ std::back_inserter(notWatchedEntries));
return notWatchedEntries;
}
- WatcherEntries notWatchedEntries(const WatcherEntries &entries) const
+ DirectoryPathIds notWatchedPaths(const DirectoryPathIds &ids) const
{
- return notWatchedEntries(entries, std::less<WatcherEntry>());
- }
+ DirectoryPathIds notWatchedDirectoryIds;
+ notWatchedDirectoryIds.reserve(ids.size());
- WatcherEntries notWatchedPaths(const WatcherEntries &entries) const
- {
- auto compare = [] (WatcherEntry first, WatcherEntry second) {
- return first.pathId < second.pathId;
- };
+ std::set_difference(ids.begin(),
+ ids.end(),
+ m_watchedEntries.cbegin(),
+ m_watchedEntries.cend(),
+ std::back_inserter(notWatchedDirectoryIds));
- return notWatchedEntries(entries, compare);
+ return notWatchedDirectoryIds;
}
template <typename Compare>
@@ -297,25 +323,24 @@ public:
m_watchedEntries = std::move(newWatchedEntries);
}
- static
- WatcherEntries uniquePaths(const WatcherEntries &pathEntries)
+ static DirectoryPathIds uniquePaths(const WatcherEntries &pathEntries)
{
- WatcherEntries uniqueEntries;
- uniqueEntries.reserve(pathEntries.size());
+ DirectoryPathIds uniqueDirectoryIds;
+ uniqueDirectoryIds.reserve(pathEntries.size());
- auto compare = [] (WatcherEntry first, WatcherEntry second) {
- return first.pathId == second.pathId;
+ auto compare = [](WatcherEntry first, WatcherEntry second) {
+ return first.directoryPathId == second.directoryPathId;
};
std::unique_copy(pathEntries.begin(),
pathEntries.end(),
- std::back_inserter(uniqueEntries),
+ std::back_inserter(uniqueDirectoryIds),
compare);
- return uniqueEntries;
+ return uniqueDirectoryIds;
}
- WatcherEntries filterNotWatchedPaths(const WatcherEntries &entries)
+ DirectoryPathIds filterNotWatchedPaths(const WatcherEntries &entries) const
{
return notWatchedPaths(uniquePaths(entries));
}
@@ -351,40 +376,48 @@ public:
oldEntries.end(),
std::back_inserter(newWatchedEntries));
-
- m_watchedEntries = newWatchedEntries;
+ m_watchedEntries = std::move(newWatchedEntries);
}
- void compressChangedFilePath(const QString &filePath)
+ void compressChangedDirectoryPath(const QString &path)
{
- m_changedFilePathCompressor.addFilePath(filePath);
+ m_directoryPathCompressor.addDirectoryPathId(
+ m_pathCache.directoryPathId(Utils::PathString{path}));
}
- WatcherEntries watchedEntriesForPaths(ClangBackEnd::FilePathIds &&filePathIds)
+ WatcherEntries watchedEntriesForPaths(ClangBackEnd::DirectoryPathIds &&directoryPathIds)
{
WatcherEntries foundEntries;
- foundEntries.reserve(filePathIds.size());
-
- for (FilePathId pathId : filePathIds) {
- auto range = std::equal_range(m_watchedEntries.begin(), m_watchedEntries.end(), pathId);
- foundEntries.insert(foundEntries.end(), range.first, range.second);
- }
+ foundEntries.reserve(m_watchedEntries.size());
+
+ set_greedy_intersection_call(m_watchedEntries.begin(),
+ m_watchedEntries.end(),
+ directoryPathIds.begin(),
+ directoryPathIds.end(),
+ [&](WatcherEntry &entry) {
+ m_fileStatusCache.update(entry.filePathId);
+ auto currentLastModified = m_fileStatusCache.lastModifiedTime(
+ entry.filePathId);
+ if (entry.lastModified < currentLastModified) {
+ foundEntries.push_back(entry);
+ entry.lastModified = currentLastModified;
+ }
+ });
return foundEntries;
}
- FilePathIds watchedPaths(const FilePathIds &filePathIds) const
+ FilePathIds watchedPaths(const WatcherEntries &entries) const
{
- FilePathIds watchedFilePathIds;
- watchedFilePathIds.reserve(filePathIds.size());
+ auto filePathIds = Utils::transform<FilePathIds>(entries, [](WatcherEntry entry) {
+ return entry.filePathId;
+ });
+
+ std::sort(filePathIds.begin(), filePathIds.end());
- std::set_intersection(m_watchedEntries.begin(),
- m_watchedEntries.end(),
- filePathIds.begin(),
- filePathIds.end(),
- std::back_inserter(watchedFilePathIds));
+ filePathIds.erase(std::unique(filePathIds.begin(), filePathIds.end()), filePathIds.end());
- return watchedFilePathIds;
+ return filePathIds;
}
ProjectPartIds idsForWatcherEntries(const WatcherEntries &foundEntries)
@@ -403,21 +436,20 @@ public:
ProjectPartIds uniqueIds(ProjectPartIds &&ids)
{
std::sort(ids.begin(), ids.end());
- auto newEnd = std::unique(ids.begin(), ids.end());
- ids.erase(newEnd, ids.end());
+ ids.erase(std::unique(ids.begin(), ids.end()), ids.end());
return std::move(ids);
}
- void addChangedPathForFilePath(FilePathIds &&filePathIds)
+ void addChangedPathForFilePath(DirectoryPathIds &&directoryPathIds)
{
if (m_notifier) {
- WatcherEntries foundEntries = watchedEntriesForPaths(std::move(filePathIds));
+ WatcherEntries foundEntries = watchedEntriesForPaths(std::move(directoryPathIds));
ProjectPartIds changedIds = idsForWatcherEntries(foundEntries);
m_notifier->pathsWithIdsChanged(uniqueIds(std::move(changedIds)));
- m_notifier->pathsChanged(watchedPaths(filePathIds));
+ m_notifier->pathsChanged(watchedPaths(foundEntries));
}
}
@@ -428,10 +460,12 @@ public:
private:
WatcherEntries m_watchedEntries;
- ChangedFilePathCompressor<Timer> m_changedFilePathCompressor;
FileSystemWatcher m_fileSystemWatcher;
+ FileStatusCache m_fileStatusCache;
+ FileSystemInterface &m_fileSystem;
FilePathCachingInterface &m_pathCache;
ClangPathWatcherNotifier *m_notifier;
+ DirectoryPathCompressor<Timer> m_directoryPathCompressor;
};
} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/clangsupport-lib.pri b/src/libs/clangsupport/clangsupport-lib.pri
index df537f5848..9b6bbdf3ee 100644
--- a/src/libs/clangsupport/clangsupport-lib.pri
+++ b/src/libs/clangsupport/clangsupport-lib.pri
@@ -18,6 +18,7 @@ SOURCES += \
$$PWD/clangcodemodelserverproxy.cpp \
$$PWD/alivemessage.cpp \
$$PWD/completionsmessage.cpp \
+ $$PWD/filesystem.cpp \
$$PWD/requestcompletionsmessage.cpp \
$$PWD/echomessage.cpp \
$$PWD/endmessage.cpp \
@@ -87,7 +88,8 @@ SOURCES += \
$$PWD/removegeneratedfilesmessage.cpp \
$$PWD/generatedfiles.cpp \
$$PWD/projectpartartefact.cpp \
- $$PWD/projectpartcontainer.cpp
+ $$PWD/projectpartcontainer.cpp \
+ $$PWD/filestatuscache.cpp
HEADERS += \
$$PWD/cancelmessage.h \
@@ -109,7 +111,11 @@ HEADERS += \
$$PWD/alivemessage.h \
$$PWD/clangsupportexceptions.h \
$$PWD/completionsmessage.h \
+ $$PWD/directoryandfilepathid.h \
+ $$PWD/directorypathid.h \
$$PWD/executeinloop.h \
+ $$PWD/filesystem.h \
+ $$PWD/filesysteminterface.h \
$$PWD/pchpaths.h \
$$PWD/projectpartid.h \
$$PWD/projectpartsstorage.h \
@@ -217,6 +223,8 @@ HEADERS += \
$$PWD/sourceentry.h \
$$PWD/modifiedtimecheckerinterface.h \
$$PWD/environment.h \
+ $$PWD/filestatus.h \
+ $$PWD/filestatuscache.h \
$$PWD/modifiedtimechecker.h
contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols
diff --git a/src/libs/clangsupport/directoryandfilepathid.h b/src/libs/clangsupport/directoryandfilepathid.h
new file mode 100644
index 0000000000..8969372919
--- /dev/null
+++ b/src/libs/clangsupport/directoryandfilepathid.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "directorypathid.h"
+#include "filepathid.h"
+
+#include <QDataStream>
+
+#include <vector>
+
+namespace ClangBackEnd {
+class DirectoryAndFilePathId
+{
+public:
+ constexpr DirectoryAndFilePathId() = default;
+
+ DirectoryAndFilePathId(const char *) = delete;
+
+ DirectoryAndFilePathId(int directoryPathId, int filePathId)
+ : directoryPathId(directoryPathId)
+ , filePathId(filePathId)
+ {}
+
+ bool isValid() const { return directoryPathId.isValid() && filePathId.isValid(); }
+
+ friend bool operator==(DirectoryAndFilePathId first, DirectoryAndFilePathId second)
+ {
+ return first.isValid() && first.directoryPathId == second.directoryPathId
+ && first.filePathId == second.filePathId;
+ }
+
+ friend bool operator!=(DirectoryAndFilePathId first, DirectoryAndFilePathId second)
+ {
+ return !(first == second);
+ }
+
+ friend bool operator<(DirectoryAndFilePathId first, DirectoryAndFilePathId second)
+ {
+ return std::tie(first.directoryPathId, first.filePathId)
+ < std::tie(second.directoryPathId, second.filePathId);
+ }
+
+ friend QDataStream &operator<<(QDataStream &out,
+ const DirectoryAndFilePathId &directoryAndFilePathId)
+ {
+ out << directoryAndFilePathId.directoryPathId;
+ out << directoryAndFilePathId.filePathId;
+
+ return out;
+ }
+
+ friend QDataStream &operator>>(QDataStream &in, DirectoryAndFilePathId &directoryAndFilePathId)
+ {
+ in >> directoryAndFilePathId.directoryPathId;
+ in >> directoryAndFilePathId.filePathId;
+ return in;
+ }
+
+public:
+ DirectoryPathId directoryPathId;
+ FilePathId filePathId;
+};
+
+using DirectoryAndFilePathIds = std::vector<DirectoryAndFilePathId>;
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/changedfilepathcompressor.h b/src/libs/clangsupport/directorypathcompressor.h
index aa8e1ec71a..cd02948e83 100644
--- a/src/libs/clangsupport/changedfilepathcompressor.h
+++ b/src/libs/clangsupport/directorypathcompressor.h
@@ -27,53 +27,44 @@
#include "clangsupport_global.h"
-#include <filepathid.h>
-#include <filepathcache.h>
+#include "filepathcachinginterface.h"
+#include <QDir>
#include <QTimer>
-#include <filepathcachinginterface.h>
+#include <utils/algorithm.h>
#include <functional>
namespace ClangBackEnd {
-template <typename Timer>
-class ChangedFilePathCompressor
+template<typename Timer>
+class DirectoryPathCompressor
{
public:
- ChangedFilePathCompressor(FilePathCachingInterface &filePathCache)
- : m_filePathCache(filePathCache)
- {
- m_timer.setSingleShot(true);
- }
+ DirectoryPathCompressor() { m_timer.setSingleShot(true); }
- virtual ~ChangedFilePathCompressor()
- {
- }
+ virtual ~DirectoryPathCompressor() = default;
- void addFilePath(const QString &filePath)
+ void addDirectoryPathId(DirectoryPathId directoryPathIdId)
{
- FilePathId filePathId = m_filePathCache.filePathId(FilePath(filePath));
+ auto found = std::lower_bound(m_directoryPathIds.begin(),
+ m_directoryPathIds.end(),
+ directoryPathIdId);
- auto found = std::lower_bound(m_filePaths.begin(), m_filePaths.end(), filePathId);
-
- if (found == m_filePaths.end() || *found != filePathId)
- m_filePaths.insert(found, filePathId);
+ if (found == m_directoryPathIds.end() || *found != directoryPathIdId)
+ m_directoryPathIds.insert(found, directoryPathIdId);
restartTimer();
}
- FilePathIds takeFilePathIds()
- {
- return std::move(m_filePaths);
- }
+ DirectoryPathIds takeDirectoryPathIds() { return std::move(m_directoryPathIds); }
- virtual void setCallback(std::function<void(ClangBackEnd::FilePathIds &&)> &&callback)
+ virtual void setCallback(std::function<void(ClangBackEnd::DirectoryPathIds &&)> &&callback)
{
- QObject::connect(&m_timer,
- &Timer::timeout,
- [this, callback=std::move(callback)] { callback(takeFilePathIds()); });
+ QObject::connect(&m_timer, &Timer::timeout, [this, callback = std::move(callback)] {
+ callback(takeDirectoryPathIds());
+ });
}
unittest_public:
@@ -88,9 +79,8 @@ unittest_public:
}
private:
- FilePathIds m_filePaths;
+ DirectoryPathIds m_directoryPathIds;
Timer m_timer;
- FilePathCachingInterface &m_filePathCache;
};
} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/directorypathid.h b/src/libs/clangsupport/directorypathid.h
new file mode 100644
index 0000000000..2fd0b5847e
--- /dev/null
+++ b/src/libs/clangsupport/directorypathid.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 <QDataStream>
+
+#include <vector>
+
+namespace ClangBackEnd {
+class DirectoryPathId
+{
+public:
+ constexpr DirectoryPathId() = default;
+
+ DirectoryPathId(const char *) = delete;
+
+ DirectoryPathId(int directoryPathId)
+ : directoryPathId(directoryPathId)
+ {}
+
+ bool isValid() const { return directoryPathId >= 0; }
+
+ friend bool operator==(DirectoryPathId first, DirectoryPathId second)
+ {
+ return first.isValid() && first.directoryPathId == second.directoryPathId;
+ }
+
+ friend bool operator!=(DirectoryPathId first, DirectoryPathId second)
+ {
+ return !(first == second);
+ }
+
+ friend bool operator<(DirectoryPathId first, DirectoryPathId second)
+ {
+ return first.directoryPathId < second.directoryPathId;
+ }
+
+ friend QDataStream &operator<<(QDataStream &out, const DirectoryPathId &directoryPathId)
+ {
+ out << directoryPathId.directoryPathId;
+
+ return out;
+ }
+
+ friend QDataStream &operator>>(QDataStream &in, DirectoryPathId &directoryPathId)
+ {
+ in >> directoryPathId.directoryPathId;
+
+ return in;
+ }
+
+public:
+ int directoryPathId = -1;
+};
+
+using DirectoryPathIds = std::vector<DirectoryPathId>;
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filepathcache.h b/src/libs/clangsupport/filepathcache.h
index bdd925a79c..4845416d22 100644
--- a/src/libs/clangsupport/filepathcache.h
+++ b/src/libs/clangsupport/filepathcache.h
@@ -25,9 +25,10 @@
#pragma once
+#include "directorypathid.h"
+#include "filepath.h"
#include "filepathexceptions.h"
#include "filepathid.h"
-#include "filepath.h"
#include "filepathview.h"
#include "stringcache.h"
@@ -121,10 +122,10 @@ public:
{
Utils::SmallStringView directoryPath = filePath.directory();
- int directoryId = m_directoryPathCache.stringId(directoryPath,
- [&] (const Utils::SmallStringView) {
- return m_filePathStorage.fetchDirectoryId(directoryPath);
- });
+ int directoryId = m_directoryPathCache.stringId(
+ directoryPath, [&](const Utils::SmallStringView directoryPath) {
+ return m_filePathStorage.fetchDirectoryId(directoryPath);
+ });
Utils::SmallStringView fileName = filePath.name();
@@ -136,6 +137,17 @@ public:
return fileNameId;
}
+ DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const
+ {
+ Utils::SmallStringView path = directoryPath.back() == '/'
+ ? directoryPath.mid(0, directoryPath.size() - 1)
+ : directoryPath;
+
+ return m_directoryPathCache.stringId(path, [&](const Utils::SmallStringView directoryPath) {
+ return m_filePathStorage.fetchDirectoryId(directoryPath);
+ });
+ }
+
FilePath filePath(FilePathId filePathId) const
{
if (Q_UNLIKELY(!filePathId.isValid()))
@@ -157,6 +169,32 @@ public:
return FilePath{directoryPath, entry.fileName};
}
+ Utils::PathString directoryPath(DirectoryPathId directoryPathId) const
+ {
+ if (Q_UNLIKELY(!directoryPathId.isValid()))
+ throw NoDirectoryPathForInvalidDirectoryPathId();
+
+ auto fetchDirectoryPath = [&](int id) { return m_filePathStorage.fetchDirectoryPath(id); };
+
+ return m_directoryPathCache.string(directoryPathId.directoryPathId, fetchDirectoryPath);
+ }
+
+ DirectoryPathId directoryPathId(FilePathId filePathId) const
+ {
+ if (Q_UNLIKELY(!filePathId.isValid()))
+ throw NoFilePathForInvalidFilePathId();
+
+ auto fetchSoureNameAndDirectoryId = [&](int id) {
+ auto entry = m_filePathStorage.fetchSourceNameAndDirectoryId(id);
+ return FileNameEntry{entry.sourceName, entry.directoryId};
+ };
+
+ FileNameEntry entry = m_fileNameCache.string(filePathId.filePathId,
+ fetchSoureNameAndDirectoryId);
+
+ return m_fileNameCache.string(filePathId.filePathId, fetchSoureNameAndDirectoryId).directoryId;
+ }
+
private:
mutable DirectoryPathCache m_directoryPathCache;
mutable FileNameCache m_fileNameCache;
diff --git a/src/libs/clangsupport/filepathcaching.cpp b/src/libs/clangsupport/filepathcaching.cpp
index 0a3fc6ee41..372ed86bd3 100644
--- a/src/libs/clangsupport/filepathcaching.cpp
+++ b/src/libs/clangsupport/filepathcaching.cpp
@@ -37,4 +37,19 @@ FilePath FilePathCaching::filePath(FilePathId filePathId) const
return m_cache.filePath(filePathId);
}
+DirectoryPathId FilePathCaching::directoryPathId(Utils::SmallStringView directoryPath) const
+{
+ return m_cache.directoryPathId(directoryPath);
+}
+
+Utils::PathString FilePathCaching::directoryPath(DirectoryPathId directoryPathId) const
+{
+ return m_cache.directoryPath(directoryPathId);
+}
+
+DirectoryPathId FilePathCaching::directoryPathId(FilePathId filePathId) const
+{
+ return m_cache.directoryPathId(filePathId);
+}
+
} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filepathcaching.h b/src/libs/clangsupport/filepathcaching.h
index a3337755fd..f69b940b15 100644
--- a/src/libs/clangsupport/filepathcaching.h
+++ b/src/libs/clangsupport/filepathcaching.h
@@ -50,6 +50,9 @@ public:
FilePathId filePathId(FilePathView filePath) const override;
FilePath filePath(FilePathId filePathId) const override;
+ DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const override;
+ Utils::PathString directoryPath(DirectoryPathId directoryPathId) const override;
+ DirectoryPathId directoryPathId(FilePathId filePathId) const override;
private:
Factory m_factory;
diff --git a/src/libs/clangsupport/filepathcachinginterface.h b/src/libs/clangsupport/filepathcachinginterface.h
index b9668362f7..098fd39ca9 100644
--- a/src/libs/clangsupport/filepathcachinginterface.h
+++ b/src/libs/clangsupport/filepathcachinginterface.h
@@ -25,6 +25,7 @@
#pragma once
+#include "directorypathid.h"
#include "filepath.h"
#include "filepathid.h"
#include "filepathview.h"
@@ -40,8 +41,11 @@ public:
virtual FilePathId filePathId(FilePathView filePath) const = 0;
virtual FilePath filePath(FilePathId filePathId) const = 0;
+ virtual DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const = 0;
+ virtual DirectoryPathId directoryPathId(FilePathId filePathId) const = 0;
+ virtual Utils::PathString directoryPath(DirectoryPathId directoryPathId) const = 0;
- template <typename Container>
+ template<typename Container>
FilePathIds filePathIds(Container &&filePaths) const
{
FilePathIds filePathIds;
diff --git a/src/libs/clangsupport/filepathexceptions.h b/src/libs/clangsupport/filepathexceptions.h
index 80bded0c66..3174d89479 100644
--- a/src/libs/clangsupport/filepathexceptions.h
+++ b/src/libs/clangsupport/filepathexceptions.h
@@ -38,6 +38,15 @@ public:
}
};
+class NoDirectoryPathForInvalidDirectoryPathId : std::exception
+{
+public:
+ const char *what() const noexcept override
+ {
+ return "You cannot get a directory path for an invalid directory path id!";
+ }
+};
+
class SourceNameIdDoesNotExists : std::exception
{
public:
diff --git a/src/libs/clangsupport/filepathstorage.h b/src/libs/clangsupport/filepathstorage.h
index 5917504dbf..8aba2ef6d2 100644
--- a/src/libs/clangsupport/filepathstorage.h
+++ b/src/libs/clangsupport/filepathstorage.h
@@ -179,12 +179,32 @@ public:
transaction.commit();
- return optionalSourceName.value();
+ return *optionalSourceName;
} catch (const Sqlite::StatementIsBusy &) {
return fetchSourceNameAndDirectoryId(sourceId);
}
}
+ int fetchDirectoryId(int sourceId)
+ {
+ try {
+ Sqlite::DeferredTransaction transaction{m_statementFactory.database};
+
+ ReadStatement &statement = m_statementFactory.selectDirectoryIdFromSourcesBySourceId;
+
+ auto optionalDirectoryId = statement.template value<int>(sourceId);
+
+ if (!optionalDirectoryId)
+ throw SourceNameIdDoesNotExists();
+
+ transaction.commit();
+
+ return *optionalDirectoryId;
+ } catch (const Sqlite::StatementIsBusy &) {
+ return fetchDirectoryId(sourceId);
+ }
+ }
+
std::vector<Sources::Source> fetchAllSources()
{
try {
diff --git a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h
index dbf8071775..27296a1df6 100644
--- a/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h
+++ b/src/libs/clangsupport/filepathstoragesqlitestatementfactory.h
@@ -69,6 +69,8 @@ public:
"SELECT sourceName, directoryId FROM sources WHERE sourceId = ?",
database
};
+ ReadStatement selectDirectoryIdFromSourcesBySourceId{
+ "SELECT directoryId FROM sources WHERE sourceId = ?", database};
WriteStatement insertIntoSources{
"INSERT INTO sources(directoryId, sourceName) VALUES (?,?)",
database
diff --git a/src/tools/clangrefactoringbackend/source/filestatus.h b/src/libs/clangsupport/filestatus.h
index da2be4a304..da2be4a304 100644
--- a/src/tools/clangrefactoringbackend/source/filestatus.h
+++ b/src/libs/clangsupport/filestatus.h
diff --git a/src/libs/clangsupport/filestatuscache.cpp b/src/libs/clangsupport/filestatuscache.cpp
new file mode 100644
index 0000000000..480b745525
--- /dev/null
+++ b/src/libs/clangsupport/filestatuscache.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 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 "filestatuscache.h"
+#include "filesystem.h"
+
+#include <utils/algorithm.h>
+
+#include <QDateTime>
+#include <QFileInfo>
+
+namespace ClangBackEnd {
+
+long long FileStatusCache::lastModifiedTime(FilePathId filePathId) const
+{
+ return findEntry(filePathId).lastModified;
+}
+
+void FileStatusCache::update(FilePathId filePathId)
+{
+ auto found = std::lower_bound(m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ Internal::FileStatusCacheEntry{filePathId},
+ [] (const auto &first, const auto &second) {
+ return first.filePathId < second.filePathId;
+ });
+
+ if (found != m_cacheEntries.end() && found->filePathId == filePathId)
+ found->lastModified = m_fileSystem.lastModified(filePathId);
+}
+
+namespace {
+template<class InputIt1, class InputIt2, class Callable>
+void set_intersection_call(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable)
+{
+ while (first1 != last1 && first2 != last2) {
+ if (*first1 < *first2) {
+ ++first1;
+ } else {
+ if (!(*first2 < *first1))
+ callable(*first1++);
+ ++first2;
+ }
+ }
+}
+
+template<class InputIt1, class InputIt2, class Callable>
+void set_difference_call(InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable)
+{
+ while (first1 != last1) {
+ if (first2 == last2) {
+ std::for_each(first1, last1, callable);
+ return;
+ }
+ if (*first1 < *first2) {
+ callable(*first1++);
+ } else {
+ if (!(*first2 < *first1))
+ ++first1;
+ ++first2;
+ }
+ }
+}
+} // namespace
+
+void FileStatusCache::update(FilePathIds filePathIds)
+{
+ set_intersection_call(m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ filePathIds.begin(),
+ filePathIds.end(),
+ [&](auto &entry) {
+ entry.lastModified = m_fileSystem.lastModified(entry.filePathId);
+ });
+}
+
+FilePathIds FileStatusCache::modified(FilePathIds filePathIds) const
+{
+ FilePathIds modifiedFilePathIds;
+ modifiedFilePathIds.reserve(filePathIds.size());
+
+ set_intersection_call(m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ filePathIds.begin(),
+ filePathIds.end(),
+ [&](auto &entry) {
+ auto newLastModified = m_fileSystem.lastModified(entry.filePathId);
+ if (newLastModified > entry.lastModified) {
+ modifiedFilePathIds.push_back(entry.filePathId);
+ entry.lastModified = newLastModified;
+ }
+ });
+
+ Internal::FileStatusCacheEntries newEntries;
+ newEntries.reserve(filePathIds.size());
+
+ set_difference_call(filePathIds.begin(),
+ filePathIds.end(),
+ m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ [&](FilePathId newFilePathId) {
+ newEntries.emplace_back(newFilePathId,
+ m_fileSystem.lastModified(newFilePathId));
+ modifiedFilePathIds.push_back(newFilePathId);
+ });
+
+ if (newEntries.size()) {
+ Internal::FileStatusCacheEntries mergedEntries;
+ mergedEntries.reserve(m_cacheEntries.size() + newEntries.size());
+
+ std::set_union(newEntries.begin(),
+ newEntries.end(),
+ m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ std::back_inserter(mergedEntries));
+
+ m_cacheEntries = std::move(mergedEntries);
+ }
+
+ std::sort(modifiedFilePathIds.begin(), modifiedFilePathIds.end());
+
+ return modifiedFilePathIds;
+}
+
+FileStatusCache::size_type FileStatusCache::size() const
+{
+ return m_cacheEntries.size();
+}
+
+Internal::FileStatusCacheEntry FileStatusCache::findEntry(FilePathId filePathId) const
+{
+ auto found = std::lower_bound(m_cacheEntries.begin(),
+ m_cacheEntries.end(),
+ Internal::FileStatusCacheEntry{filePathId},
+ [] (const auto &first, const auto &second) {
+ return first.filePathId < second.filePathId;
+ });
+
+ if (found != m_cacheEntries.end() && found->filePathId == filePathId)
+ return *found;
+
+ auto inserted = m_cacheEntries.emplace(found, filePathId, m_fileSystem.lastModified(filePathId));
+
+ return *inserted;
+}
+
+} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/filestatuscache.h b/src/libs/clangsupport/filestatuscache.h
index 23195da605..3f0af56b3a 100644
--- a/src/tools/clangrefactoringbackend/source/filestatuscache.h
+++ b/src/libs/clangsupport/filestatuscache.h
@@ -31,6 +31,8 @@ QT_FORWARD_DECLARE_CLASS(QFileInfo)
namespace ClangBackEnd {
+class FileSystemInterface;
+
namespace Internal {
class FileStatusCacheEntry
{
@@ -41,8 +43,23 @@ public:
lastModified(lastModified)
{}
+ friend bool operator<(FileStatusCacheEntry first, FileStatusCacheEntry second)
+ {
+ return first.filePathId < second.filePathId;
+ }
+
+ friend bool operator<(FileStatusCacheEntry first, FilePathId second)
+ {
+ return first.filePathId < second;
+ }
+
+ friend bool operator<(FilePathId first, FileStatusCacheEntry second)
+ {
+ return first < second.filePathId;
+ }
+
public:
- ClangBackEnd::FilePathId filePathId;
+ FilePathId filePathId;
long long lastModified;
};
@@ -50,27 +67,30 @@ using FileStatusCacheEntries = std::vector<FileStatusCacheEntry>;
}
-class FileStatusCache
+class CLANGSUPPORT_EXPORT FileStatusCache
{
public:
using size_type = Internal::FileStatusCacheEntries::size_type;
- FileStatusCache(FilePathCachingInterface &filePathCache);
+ FileStatusCache(FileSystemInterface &fileSystem)
+ : m_fileSystem(fileSystem)
+ {}
FileStatusCache &operator=(const FileStatusCache &) = delete;
FileStatusCache(const FileStatusCache &) = delete;
- long long lastModifiedTime(ClangBackEnd::FilePathId filePathId) const;
- void update(ClangBackEnd::FilePathId filePathId);
+ long long lastModifiedTime(FilePathId filePathId) const;
+ void update(FilePathId filePathId);
+ void update(FilePathIds filePathIds);
+ FilePathIds modified(FilePathIds filePathIds) const;
size_type size() const;
private:
- Internal::FileStatusCacheEntry findEntry(ClangBackEnd::FilePathId filePathId) const;
- QFileInfo qFileInfo(ClangBackEnd::FilePathId filePathId) const;
+ Internal::FileStatusCacheEntry findEntry(FilePathId filePathId) const;
private:
mutable Internal::FileStatusCacheEntries m_cacheEntries;
- FilePathCachingInterface &m_filePathCache;
+ FileSystemInterface &m_fileSystem;
};
} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filesystem.cpp b/src/libs/clangsupport/filesystem.cpp
new file mode 100644
index 0000000000..5b8c037f80
--- /dev/null
+++ b/src/libs/clangsupport/filesystem.cpp
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "filesystem.h"
+#include "filepathcachinginterface.h"
+
+#include <utils/algorithm.h>
+
+#include <QDateTime>
+#include <QDir>
+#include <QFileInfo>
+
+namespace ClangBackEnd {
+
+FilePathIds FileSystem::directoryEntries(const QString &directoryPath) const
+{
+ QDir directory{directoryPath};
+
+ QFileInfoList fileInfos = directory.entryInfoList();
+
+ FilePathIds filePathIds = Utils::transform<FilePathIds>(fileInfos, [&](const QFileInfo &fileInfo) {
+ return m_filePathCache.filePathId(FilePath{fileInfo.path()});
+ });
+
+ std::sort(filePathIds.begin(), filePathIds.end());
+
+ return filePathIds;
+}
+
+long long FileSystem::lastModified(FilePathId filePathId) const
+{
+ QFileInfo fileInfo(QString(m_filePathCache.filePath(filePathId)));
+
+ fileInfo.refresh();
+
+ return fileInfo.lastModified().toMSecsSinceEpoch() / 1000;
+}
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filesystem.h b/src/libs/clangsupport/filesystem.h
new file mode 100644
index 0000000000..ecf332de55
--- /dev/null
+++ b/src/libs/clangsupport/filesystem.h
@@ -0,0 +1,48 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "filestatuscache.h"
+#include "filesysteminterface.h"
+
+namespace ClangBackEnd {
+class FilePathCachingInterface;
+
+class CLANGSUPPORT_EXPORT FileSystem final : public FileSystemInterface
+{
+public:
+ FileSystem(FilePathCachingInterface &filePathCache)
+ : m_filePathCache(filePathCache)
+ {}
+
+ FilePathIds directoryEntries(const QString &directoryPath) const override;
+ long long lastModified(FilePathId filePathId) const override;
+
+private:
+ FilePathCachingInterface &m_filePathCache;
+};
+
+} // namespace ClangBackEnd
diff --git a/src/libs/clangsupport/filesysteminterface.h b/src/libs/clangsupport/filesysteminterface.h
new file mode 100644
index 0000000000..9d64d2a93a
--- /dev/null
+++ b/src/libs/clangsupport/filesysteminterface.h
@@ -0,0 +1,43 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "filepathid.h"
+
+#include <utils/smallstringview.h>
+
+namespace ClangBackEnd {
+
+class FileSystemInterface
+{
+public:
+ virtual FilePathIds directoryEntries(const QString &directoryPath) const = 0;
+ virtual long long lastModified(FilePathId filePathId) const = 0;
+
+protected:
+ ~FileSystemInterface() = default;
+};
+} // namespace ClangBackEnd
diff --git a/src/libs/utils/smallstringview.h b/src/libs/utils/smallstringview.h
index 6052ff8777..911ba2eafd 100644
--- a/src/libs/utils/smallstringview.h
+++ b/src/libs/utils/smallstringview.h
@@ -179,6 +179,10 @@ public:
return m_pointer[0] == characterToSearch;
}
+ char back() const { return m_pointer[m_size - 1]; }
+
+ char operator[](std::size_t index) { return m_pointer[index]; }
+
private:
const char *m_pointer = "";
size_type m_size = 0;
diff --git a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp
index 0ce49e829d..d9e7dd3175 100644
--- a/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp
+++ b/src/tools/clangpchmanagerbackend/clangpchmanagerbackendmain.cpp
@@ -31,6 +31,7 @@
#include <environment.h>
#include <executeinloop.h>
#include <filepathcaching.h>
+#include <filesystem.h>
#include <generatedfiles.h>
#include <modifiedtimechecker.h>
#include <pchcreator.h>
@@ -179,7 +180,8 @@ struct Data // because we have a cycle dependency
Sqlite::Database database;
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
ClangBackEnd::FilePathCaching filePathCache{database};
- ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher{filePathCache};
+ ClangBackEnd::FileSystem fileSystem{filePathCache};
+ ClangPathWatcher<QFileSystemWatcher, QTimer> includeWatcher{filePathCache, fileSystem};
ApplicationEnvironment environment;
ProjectPartsStorage<> projectPartsStorage{database};
PrecompiledHeaderStorage<> preCompiledHeaderStorage{database};
diff --git a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri
index e7e83da788..a3da84d83b 100644
--- a/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri
+++ b/src/tools/clangrefactoringbackend/source/clangrefactoringbackend-source.pri
@@ -17,8 +17,6 @@ HEADERS += \
$$PWD/symbolsvisitorbase.h \
$$PWD/usedmacro.h \
$$PWD/sourcedependency.h \
- $$PWD/filestatus.h \
- $$PWD/filestatuscache.h \
$$PWD/indexdataconsumer.h \
$$PWD/sourcesmanager.h \
$$PWD/symbolindexertaskqueue.h \
@@ -67,5 +65,4 @@ HEADERS += \
SOURCES += \
$$PWD/filestatuspreprocessorcallbacks.cpp \
$$PWD/sourcerangefilter.cpp \
- $$PWD/symbolindexer.cpp \
- $$PWD/filestatuscache.cpp
+ $$PWD/symbolindexer.cpp
diff --git a/src/tools/clangrefactoringbackend/source/filestatuscache.cpp b/src/tools/clangrefactoringbackend/source/filestatuscache.cpp
deleted file mode 100644
index 14ad48da14..0000000000
--- a/src/tools/clangrefactoringbackend/source/filestatuscache.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 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 "filestatuscache.h"
-
-#include <QDateTime>
-#include <QFileInfo>
-
-namespace ClangBackEnd {
-
-FileStatusCache::FileStatusCache(FilePathCachingInterface &filePathCache)
- : m_filePathCache(filePathCache)
-{
-
-}
-
-long long FileStatusCache::lastModifiedTime(FilePathId filePathId) const
-{
- return findEntry(filePathId).lastModified;
-}
-
-void FileStatusCache::update(FilePathId filePathId)
-{
- auto found = std::lower_bound(m_cacheEntries.begin(),
- m_cacheEntries.end(),
- Internal::FileStatusCacheEntry{filePathId},
- [] (const auto &first, const auto &second) {
- return first.filePathId < second.filePathId;
- });
-
- if (found != m_cacheEntries.end() && found->filePathId == filePathId) {
- QFileInfo fileInfo = qFileInfo(filePathId);
- found->lastModified = fileInfo.lastModified().toMSecsSinceEpoch() / 1000;
- }
-}
-
-FileStatusCache::size_type FileStatusCache::size() const
-{
- return m_cacheEntries.size();
-}
-
-Internal::FileStatusCacheEntry FileStatusCache::findEntry(FilePathId filePathId) const
-{
- auto found = std::lower_bound(m_cacheEntries.begin(),
- m_cacheEntries.end(),
- Internal::FileStatusCacheEntry{filePathId},
- [] (const auto &first, const auto &second) {
- return first.filePathId < second.filePathId;
- });
-
- if (found != m_cacheEntries.end() && found->filePathId == filePathId)
- return *found;
-
- QFileInfo fileInfo = qFileInfo(filePathId);
- auto inserted = m_cacheEntries.emplace(found,
- filePathId,
- fileInfo.lastModified().toMSecsSinceEpoch() / 1000);
-
- return *inserted;
-}
-
-QFileInfo FileStatusCache::qFileInfo(FilePathId filePathId) const
-{
- QFileInfo fileInfo(QString(m_filePathCache.filePath(filePathId)));
-
- fileInfo.refresh();
-
- return fileInfo;
-}
-
-} // namespace ClangBackEnd
diff --git a/src/tools/clangrefactoringbackend/source/symbolindexing.h b/src/tools/clangrefactoringbackend/source/symbolindexing.h
index 5c391503bf..bed279904d 100644
--- a/src/tools/clangrefactoringbackend/source/symbolindexing.h
+++ b/src/tools/clangrefactoringbackend/source/symbolindexing.h
@@ -39,6 +39,7 @@
#include <projectpartsstorage.h>
#include <filepathcachingfwd.h>
+#include <filesystem.h>
#include <modifiedtimechecker.h>
#include <refactoringdatabaseinitializer.h>
@@ -142,8 +143,9 @@ private:
PrecompiledHeaderStorage<Sqlite::Database> m_precompiledHeaderStorage;
ProjectPartsStorage<Sqlite::Database> m_projectPartsStorage;
SymbolStorage m_symbolStorage;
- ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache};
- FileStatusCache m_fileStatusCache{m_filePathCache};
+ FileSystem m_fileSytem{m_filePathCache};
+ ClangPathWatcher<QFileSystemWatcher, QTimer> m_sourceWatcher{m_filePathCache, m_fileSytem};
+ FileStatusCache m_fileStatusCache{m_fileSytem};
SymbolsCollectorManager m_collectorManger;
ProgressCounter m_progressCounter;
std::function<TimeStamp(FilePathView filePath)> getModifiedTime{
diff --git a/tests/unit/unittest/changedfilepathcompressor-test.cpp b/tests/unit/unittest/changedfilepathcompressor-test.cpp
deleted file mode 100644
index 08e66a2541..0000000000
--- a/tests/unit/unittest/changedfilepathcompressor-test.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/****************************************************************************
-**
-** 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 "mocktimer.h"
-
-#include <changedfilepathcompressor.h>
-#include <filepathcaching.h>
-#include <refactoringdatabaseinitializer.h>
-
-namespace {
-
-using testing::ElementsAre;
-using testing::Invoke;
-using testing::IsEmpty;
-using testing::NiceMock;
-
-using ClangBackEnd::FilePath;
-using ClangBackEnd::FilePathId;
-
-class ChangedFilePathCompressor : public testing::Test
-{
-protected:
- void SetUp()
- {
- compressor.setCallback(mockCompressorCallback.AsStdFunction());
- }
-
- FilePathId filePathId(const QString &filePath)
- {
- Utils::SmallString utf8FilePath{filePath};
-
- return filePathCache.filePathId(ClangBackEnd::FilePathView{utf8FilePath});
- }
-
-protected:
- Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
- ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> initializer{database};
- ClangBackEnd::FilePathCaching filePathCache{database};
- NiceMock<MockFunction<void (const ClangBackEnd::FilePathIds &filePathIds)>> mockCompressorCallback;
- ClangBackEnd::ChangedFilePathCompressor<NiceMock<MockTimer>> compressor{filePathCache};
- NiceMock<MockTimer> &mockTimer = compressor.timer();
- QString filePath1{"filePath1"};
- QString filePath2{"filePath2"};
- FilePathId filePathId1 = filePathId(filePath1);
- FilePathId filePathId2 = filePathId(filePath2);
-};
-
-TEST_F(ChangedFilePathCompressor, AddFilePath)
-{
- compressor.addFilePath(filePath1);
-
- ASSERT_THAT(compressor.takeFilePathIds(), ElementsAre(filePathId(filePath1)));
-}
-
-TEST_F(ChangedFilePathCompressor, NoFilePathsAferTakenThem)
-{
- compressor.addFilePath(filePath1);
-
- compressor.takeFilePathIds();
-
- ASSERT_THAT(compressor.takeFilePathIds(), IsEmpty());
-}
-
-TEST_F(ChangedFilePathCompressor, CallRestartTimerAfterAddingPath)
-{
- EXPECT_CALL(mockTimer, start(20));
-
- compressor.addFilePath(filePath1);
-}
-
-TEST_F(ChangedFilePathCompressor, CallTimeOutAfterAddingPath)
-{
- EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(filePathId1, filePathId2)));
-
- compressor.addFilePath(filePath1);
- compressor.addFilePath(filePath2);
-}
-
-TEST_F(ChangedFilePathCompressor, RemoveDuplicates)
-{
- EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(filePathId1, filePathId2)));
-
- compressor.addFilePath(filePath1);
- compressor.addFilePath(filePath2);
- compressor.addFilePath(filePath1);
-}
-
-}
diff --git a/tests/unit/unittest/clangpathwatcher-test.cpp b/tests/unit/unittest/clangpathwatcher-test.cpp
index 00fe91dc49..f4d99e358d 100644
--- a/tests/unit/unittest/clangpathwatcher-test.cpp
+++ b/tests/unit/unittest/clangpathwatcher-test.cpp
@@ -25,10 +25,11 @@
#include "googletest.h"
-#include "mocktimer.h"
+#include "mockclangpathwatchernotifier.h"
#include "mockfilepathcaching.h"
+#include "mockfilesystem.h"
#include "mockqfilesystemwatcher.h"
-#include "mockclangpathwatchernotifier.h"
+#include "mocktimer.h"
#include <clangpathwatcher.h>
@@ -55,91 +56,126 @@ using ClangBackEnd::WatcherEntry;
class ClangPathWatcher : public testing::Test
{
protected:
- void SetUp();
+ void SetUp()
+ {
+ ON_CALL(mockFilePathCache, filePathId(Eq(path1))).WillByDefault(Return(pathIds[0]));
+ ON_CALL(mockFilePathCache, filePathId(Eq(path2))).WillByDefault(Return(pathIds[1]));
+ ON_CALL(mockFilePathCache, filePathId(Eq(path3))).WillByDefault(Return(pathIds[2]));
+ ON_CALL(mockFilePathCache, filePathId(Eq(path4))).WillByDefault(Return(pathIds[3]));
+ ON_CALL(mockFilePathCache, filePathId(Eq(path5))).WillByDefault(Return(pathIds[4]));
+ ON_CALL(mockFilePathCache, filePath(Eq(pathIds[0]))).WillByDefault(Return(FilePath{path1}));
+ ON_CALL(mockFilePathCache, filePath(Eq(pathIds[1]))).WillByDefault(Return(FilePath{path2}));
+ ON_CALL(mockFilePathCache, filePath(Eq(pathIds[2]))).WillByDefault(Return(FilePath{path3}));
+ ON_CALL(mockFilePathCache, filePath(Eq(pathIds[3]))).WillByDefault(Return(FilePath{path4}));
+ ON_CALL(mockFilePathCache, filePath(Eq(pathIds[4]))).WillByDefault(Return(FilePath{path5}));
+ ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[0])))
+ .WillByDefault(Return(directoryPaths[0]));
+ ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[1])))
+ .WillByDefault(Return(directoryPaths[0]));
+ ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[2])))
+ .WillByDefault(Return(directoryPaths[1]));
+ ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[3])))
+ .WillByDefault(Return(directoryPaths[1]));
+ ON_CALL(mockFilePathCache, directoryPathId(TypedEq<FilePathId>(pathIds[4])))
+ .WillByDefault(Return(directoryPaths[2]));
+ ON_CALL(mockFileSystem, lastModified(_)).WillByDefault(Return(1));
+ ON_CALL(mockFilePathCache,
+ directoryPathId(TypedEq<Utils::SmallStringView>(directoryPathString)))
+ .WillByDefault(Return(directoryPaths[0]));
+ ON_CALL(mockFilePathCache,
+ directoryPathId(TypedEq<Utils::SmallStringView>(directoryPathString2)))
+ .WillByDefault(Return(directoryPaths[1]));
+ ON_CALL(mockFilePathCache, directoryPath(Eq(directoryPaths[0])))
+ .WillByDefault(Return(directoryPath));
+ ON_CALL(mockFilePathCache, directoryPath(Eq(directoryPaths[1])))
+ .WillByDefault(Return(directoryPath2));
+ ON_CALL(mockFilePathCache, directoryPath(Eq(directoryPaths[2])))
+ .WillByDefault(Return(directoryPath3));
+ ON_CALL(mockFileSystem, directoryEntries(Eq(directoryPath)))
+ .WillByDefault(Return(FilePathIds{pathIds[0], pathIds[1]}));
+ ON_CALL(mockFileSystem, directoryEntries(Eq(directoryPath2)))
+ .WillByDefault(Return(FilePathIds{pathIds[2], pathIds[3]}));
+ ON_CALL(mockFileSystem, directoryEntries(Eq(directoryPath3)))
+ .WillByDefault(Return(FilePathIds{pathIds[4]}));
+ }
static WatcherEntries sorted(WatcherEntries &&entries)
{
std::stable_sort(entries.begin(), entries.end());
- return entries;
+ return std::move(entries);
}
protected:
- NiceMock<MockFilePathCaching> filePathCache;
+ NiceMock<MockFilePathCaching> mockFilePathCache;
NiceMock<MockClangPathWatcherNotifier> notifier;
- Watcher watcher{filePathCache, &notifier};
+ NiceMock<MockFileSystem> mockFileSystem;
+ Watcher watcher{mockFilePathCache, mockFileSystem, &notifier};
NiceMock<MockQFileSytemWatcher> &mockQFileSytemWatcher = watcher.fileSystemWatcher();
ProjectPartId id1{2};
ProjectPartId id2{3};
ProjectPartId id3{4};
FilePathView path1{"/path/path1"};
FilePathView path2{"/path/path2"};
+ FilePathView path3{"/path2/path1"};
+ FilePathView path4{"/path2/path2"};
+ FilePathView path5{"/path3/path"};
QString path1QString = QString(path1.toStringView());
QString path2QString = QString(path2.toStringView());
- FilePathIds pathIds = {1, 2};
+ QString directoryPath = "/path";
+ QString directoryPath2 = "/path2";
+ QString directoryPath3 = "/path3";
+ Utils::PathString directoryPathString = directoryPath;
+ Utils::PathString directoryPathString2 = directoryPath2;
+ FilePathIds pathIds = {1, 2, 3, 4, 5};
+ ClangBackEnd::DirectoryPathIds directoryPaths = {1, 2, 3};
ClangBackEnd::ProjectPartIds ids{id1, id2, id3};
- WatcherEntry watcherEntry1{ids[0], pathIds[0]};
- WatcherEntry watcherEntry2{ids[1], pathIds[0]};
- WatcherEntry watcherEntry3{ids[0], pathIds[1]};
- WatcherEntry watcherEntry4{ids[1], pathIds[1]};
- WatcherEntry watcherEntry5{ids[2], pathIds[1]};
+ WatcherEntry watcherEntry1{ids[0], directoryPaths[0], pathIds[0]};
+ WatcherEntry watcherEntry2{ids[1], directoryPaths[0], pathIds[0]};
+ WatcherEntry watcherEntry3{ids[0], directoryPaths[0], pathIds[1]};
+ WatcherEntry watcherEntry4{ids[1], directoryPaths[0], pathIds[1]};
+ WatcherEntry watcherEntry5{ids[2], directoryPaths[0], pathIds[1]};
+ WatcherEntry watcherEntry6{ids[0], directoryPaths[1], pathIds[2]};
+ WatcherEntry watcherEntry7{ids[1], directoryPaths[1], pathIds[3]};
};
-TEST_F(ClangPathWatcher, ConvertWatcherEntriesToQStringList)
-{
- auto convertedList = watcher.convertWatcherEntriesToQStringList(sorted({watcherEntry1, watcherEntry3}));
-
- ASSERT_THAT(convertedList, ElementsAre(path1QString, path2QString));
-}
-
-TEST_F(ClangPathWatcher, UniquePaths)
-{
- auto uniqueEntries = watcher.uniquePaths(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4}));
-
- ASSERT_THAT(uniqueEntries, ElementsAre(watcherEntry1, watcherEntry3));
-}
-
-TEST_F(ClangPathWatcher, NotWatchedEntries)
-{
- watcher.addEntries({watcherEntry1, watcherEntry4});
-
- auto newEntries = watcher.notWatchedEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4}));
-
- ASSERT_THAT(newEntries, ElementsAre(watcherEntry2, watcherEntry3));
-}
-
TEST_F(ClangPathWatcher, AddIdPaths)
{
- EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString, path2QString}));
+ EXPECT_CALL(mockQFileSytemWatcher,
+ addPaths(UnorderedElementsAre(QString(directoryPath), QString(directoryPath2))));
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}});
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
}
TEST_F(ClangPathWatcher, UpdateIdPathsCallsAddPathInFileWatcher)
{
- watcher.updateIdPaths({{id1, {pathIds[0]}}, {id2, {pathIds[0]}}});
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}});
- EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path2QString}));
+ EXPECT_CALL(mockQFileSytemWatcher, addPaths(UnorderedElementsAre(QString(directoryPath2))));
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}});
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
}
TEST_F(ClangPathWatcher, UpdateIdPathsAndRemoveUnusedPathsCallsRemovePathInFileWatcher)
{
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[0]}}});
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
- EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path2QString}));
+ EXPECT_CALL(mockQFileSytemWatcher, removePaths(UnorderedElementsAre(QString(directoryPath2))));
- watcher.updateIdPaths({{id1, {pathIds[0]}}, {id2, {pathIds[0]}}});
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}});
}
TEST_F(ClangPathWatcher, UpdateIdPathsAndRemoveUnusedPathsDoNotCallsRemovePathInFileWatcher)
{
- watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[0]}}});
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2]}},
+ {id2, {pathIds[0], pathIds[1], pathIds[3]}},
+ {id3, {pathIds[0]}}});
- EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path2QString}))
- .Times(0);
+ EXPECT_CALL(mockQFileSytemWatcher, removePaths(_)).Times(0);
- watcher.updateIdPaths({{id1, {pathIds[1]}}, {id2, {pathIds[0]}}});
+ watcher.updateIdPaths({{id1, {pathIds[1]}}, {id2, {pathIds[3]}}});
}
TEST_F(ClangPathWatcher, UpdateIdPathsAndRemoveUnusedPaths)
@@ -165,36 +201,18 @@ TEST_F(ClangPathWatcher, ExtractSortedIdsFromConvertIdPaths)
ASSERT_THAT(entriesAndIds.second, ElementsAre(ids[0], ids[1], ids[2]));
}
-TEST_F(ClangPathWatcher, NotWatchedPaths)
-{
- watcher.mergeToWatchedEntries(sorted({watcherEntry1}));
-
- auto newEntries = watcher.notWatchedPaths({watcherEntry2, watcherEntry3});
-
- ASSERT_THAT(newEntries, ElementsAre(watcherEntry3));
-}
-
-TEST_F(ClangPathWatcher, AddedPaths)
-{
- watcher.mergeToWatchedEntries(sorted({watcherEntry1, watcherEntry2}));
-
- auto filteredEntries = watcher.filterNotWatchedPaths({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4});
-
- ASSERT_THAT(filteredEntries, ElementsAre(watcherEntry3));
-}
-
TEST_F(ClangPathWatcher, MergeEntries)
{
- watcher.mergeToWatchedEntries(sorted({watcherEntry1, watcherEntry4}));
+ watcher.updateIdPaths({{id1, {pathIds[0]}}, {id2, {pathIds[1]}}});
ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry1, watcherEntry4));
}
TEST_F(ClangPathWatcher, MergeMoreEntries)
{
- watcher.mergeToWatchedEntries(sorted({watcherEntry1, watcherEntry4}));
+ watcher.updateIdPaths({{id2, {pathIds[0], pathIds[1]}}});
- watcher.mergeToWatchedEntries(sorted({watcherEntry2, watcherEntry3}));
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}});
ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4));
}
@@ -204,48 +222,48 @@ TEST_F(ClangPathWatcher, AddEmptyEntries)
EXPECT_CALL(mockQFileSytemWatcher, addPaths(_))
.Times(0);
- watcher.addEntries({});
+ watcher.updateIdPaths({});
}
TEST_F(ClangPathWatcher, AddEntriesWithSameIdAndDifferentPaths)
{
- EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString, path2QString}));
+ EXPECT_CALL(mockQFileSytemWatcher,
+ addPaths(ElementsAre(directoryPath, directoryPath2, directoryPath3)));
- watcher.addEntries({watcherEntry1, watcherEntry3});
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[4]}}});
}
TEST_F(ClangPathWatcher, AddEntriesWithDifferentIdAndSamePaths)
{
- EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString}));
+ EXPECT_CALL(mockQFileSytemWatcher, addPaths(ElementsAre(directoryPath)));
- watcher.addEntries({watcherEntry1, watcherEntry2});
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1]}}});
}
TEST_F(ClangPathWatcher, DontAddNewEntriesWithSameIdAndSamePaths)
{
- watcher.addEntries({watcherEntry1});
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}});
- EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString}))
- .Times(0);
+ EXPECT_CALL(mockQFileSytemWatcher, addPaths(_)).Times(0);
- watcher.addEntries({watcherEntry1});
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}});
}
TEST_F(ClangPathWatcher, DontAddNewEntriesWithDifferentIdAndSamePaths)
{
- watcher.addEntries({watcherEntry1});
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}});
- EXPECT_CALL(mockQFileSytemWatcher, addPaths(QStringList{path1QString}))
- .Times(0);
+ EXPECT_CALL(mockQFileSytemWatcher, addPaths(_)).Times(0);
- watcher.addEntries({watcherEntry2});
+ watcher.updateIdPaths({{id2, {pathIds[0], pathIds[1], pathIds[2], pathIds[3], pathIds[4]}}});
}
TEST_F(ClangPathWatcher, RemoveEntriesWithId)
{
- watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5}));
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[1]}}});
- watcher.removeIdsFromWatchedEntries({ids[0]});
+ watcher.removeIds({id1});
ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry2, watcherEntry4, watcherEntry5));
}
@@ -260,37 +278,52 @@ TEST_F(ClangPathWatcher, RemoveNoPathsForEmptyIds)
TEST_F(ClangPathWatcher, RemoveNoPathsForOneId)
{
- watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4}));
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
EXPECT_CALL(mockQFileSytemWatcher, removePaths(_))
.Times(0);
- watcher.removeIds({id1});
+ watcher.removeIds({id3});
}
TEST_F(ClangPathWatcher, RemovePathForOneId)
{
- watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3}));
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
- EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path2QString}));
+ EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(directoryPath2)));
- watcher.removeIds({id1});
+ watcher.removeIds({id2});
+}
+
+TEST_F(ClangPathWatcher, RemoveNoPathSecondTime)
+{
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
+ watcher.removeIds({id2});
+
+ EXPECT_CALL(mockQFileSytemWatcher, removePaths(_)).Times(0);
+
+ watcher.removeIds({id2});
}
TEST_F(ClangPathWatcher, RemoveAllPathsForThreeId)
{
- watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5}));
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
- EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path1QString, path2QString}));
+ EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(directoryPath, directoryPath2)));
watcher.removeIds({id1, id2, id3});
}
TEST_F(ClangPathWatcher, RemoveOnePathForTwoId)
{
- watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5}));
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1]}}, {id2, {pathIds[0], pathIds[1]}}, {id3, {pathIds[3]}}});
- EXPECT_CALL(mockQFileSytemWatcher, removePaths(QStringList{path1QString}));
+ EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(directoryPath)));
watcher.removeIds({id1, id2});
}
@@ -313,71 +346,51 @@ TEST_F(ClangPathWatcher, RemoveUnusedEntries)
ASSERT_THAT(watcher.watchedEntries(), ElementsAre(watcherEntry1, watcherEntry4, watcherEntry5));
}
-TEST_F(ClangPathWatcher, EmptyVectorNotifyFileChange)
-{
- watcher.addEntries({watcherEntry3});
-
- EXPECT_CALL(notifier, pathsWithIdsChanged(IsEmpty()));
-
- mockQFileSytemWatcher.fileChanged(path1QString);
-}
-
-TEST_F(ClangPathWatcher, NotifyFileChange)
-{
- watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5}));
-
- EXPECT_CALL(notifier, pathsWithIdsChanged(ElementsAre(id1, id2)));
-
- mockQFileSytemWatcher.fileChanged(path1QString);
-}
-
TEST_F(ClangPathWatcher, TwoNotifyFileChanges)
{
- watcher.addEntries(sorted({watcherEntry1, watcherEntry2, watcherEntry3, watcherEntry4, watcherEntry5}));
+ watcher.updateIdPaths({{id1, {pathIds[0], pathIds[1], pathIds[2]}},
+ {id2, {pathIds[0], pathIds[1], pathIds[3]}},
+ {id3, {pathIds[4]}}});
+ ON_CALL(mockFileSystem, lastModified(Eq(pathIds[0]))).WillByDefault(Return(2));
+ ON_CALL(mockFileSystem, lastModified(Eq(pathIds[1]))).WillByDefault(Return(2));
+ ON_CALL(mockFileSystem, lastModified(Eq(pathIds[3]))).WillByDefault(Return(2));
- EXPECT_CALL(notifier, pathsWithIdsChanged(ElementsAre(id1, id2, id3)));
+ EXPECT_CALL(notifier, pathsWithIdsChanged(ElementsAre(id1, id2)));
- mockQFileSytemWatcher.fileChanged(path2QString);
- mockQFileSytemWatcher.fileChanged(path1QString);
+ mockQFileSytemWatcher.directoryChanged(directoryPath);
+ mockQFileSytemWatcher.directoryChanged(directoryPath2);
}
TEST_F(ClangPathWatcher, NotifyForPathChanges)
{
- watcher.addEntries({watcherEntry1});
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
+ ON_CALL(mockFileSystem, lastModified(Eq(pathIds[0]))).WillByDefault(Return(2));
+ ON_CALL(mockFileSystem, lastModified(Eq(pathIds[3]))).WillByDefault(Return(2));
EXPECT_CALL(notifier, pathsChanged(ElementsAre(pathIds[0])));
- mockQFileSytemWatcher.fileChanged(path1QString);
+ mockQFileSytemWatcher.directoryChanged(directoryPath);
}
TEST_F(ClangPathWatcher, NoNotifyForUnwatchedPathChanges)
{
- watcher.addEntries({watcherEntry3});
+ watcher.updateIdPaths({{id1, {pathIds[3]}}, {id2, {pathIds[3]}}});
EXPECT_CALL(notifier, pathsChanged(IsEmpty()));
- mockQFileSytemWatcher.fileChanged(path1QString);
+ mockQFileSytemWatcher.directoryChanged(directoryPath);
}
TEST_F(ClangPathWatcher, NoDuplicatePathChanges)
{
- watcher.addEntries({watcherEntry1});
+ watcher.updateIdPaths(
+ {{id1, {pathIds[0], pathIds[1], pathIds[2]}}, {id2, {pathIds[0], pathIds[1], pathIds[3]}}});
+ ON_CALL(mockFileSystem, lastModified(Eq(pathIds[0]))).WillByDefault(Return(2));
EXPECT_CALL(notifier, pathsChanged(ElementsAre(pathIds[0])));
- mockQFileSytemWatcher.fileChanged(path1QString);
- mockQFileSytemWatcher.fileChanged(path1QString);
-}
-
-void ClangPathWatcher::SetUp()
-{
- ON_CALL(filePathCache, filePathId(Eq(path1)))
- .WillByDefault(Return(pathIds[0]));
- ON_CALL(filePathCache, filePathId(Eq(path2)))
- .WillByDefault(Return(pathIds[1]));
- ON_CALL(filePathCache, filePath(pathIds[0]))
- .WillByDefault(Return(FilePath{path1}));
- ON_CALL(filePathCache, filePath(Eq(pathIds[1])))
- .WillByDefault(Return(FilePath{path2}));
-}
+ mockQFileSytemWatcher.directoryChanged(directoryPath);
+ mockQFileSytemWatcher.directoryChanged(directoryPath);
}
+} // namespace
diff --git a/tests/unit/unittest/directorypathcompressor-test.cpp b/tests/unit/unittest/directorypathcompressor-test.cpp
new file mode 100644
index 0000000000..50853e8e1c
--- /dev/null
+++ b/tests/unit/unittest/directorypathcompressor-test.cpp
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** 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 "mockfilesystem.h"
+#include "mocktimer.h"
+
+#include <directorypathcompressor.h>
+
+namespace {
+
+using testing::ElementsAre;
+using testing::Invoke;
+using testing::IsEmpty;
+using testing::NiceMock;
+
+using ClangBackEnd::DirectoryPathId;
+using ClangBackEnd::DirectoryPathIds;
+
+class DirectoryPathCompressor : public testing::Test
+{
+protected:
+ void SetUp()
+ {
+ compressor.setCallback(mockCompressorCallback.AsStdFunction());
+ }
+
+protected:
+ NiceMock<MockFunction<void(const DirectoryPathIds &directoryPathIds)>> mockCompressorCallback;
+ ClangBackEnd::DirectoryPathCompressor<NiceMock<MockTimer>> compressor;
+ NiceMock<MockTimer> &mockTimer = compressor.timer();
+ DirectoryPathId directoryPathId1{1};
+ DirectoryPathId directoryPathId2{2};
+};
+
+TEST_F(DirectoryPathCompressor, AddFilePath)
+{
+ compressor.addDirectoryPathId(directoryPathId1);
+
+ ASSERT_THAT(compressor.takeDirectoryPathIds(), ElementsAre(directoryPathId1));
+}
+
+TEST_F(DirectoryPathCompressor, NoFilePathsAferTakenThem)
+{
+ compressor.addDirectoryPathId(directoryPathId1);
+
+ compressor.takeDirectoryPathIds();
+
+ ASSERT_THAT(compressor.takeDirectoryPathIds(), IsEmpty());
+}
+
+TEST_F(DirectoryPathCompressor, CallRestartTimerAfterAddingPath)
+{
+ EXPECT_CALL(mockTimer, start(20));
+
+ compressor.addDirectoryPathId(directoryPathId1);
+}
+
+TEST_F(DirectoryPathCompressor, CallTimeOutAfterAddingPath)
+{
+ EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(directoryPathId1, directoryPathId2)));
+
+ compressor.addDirectoryPathId(directoryPathId1);
+ compressor.addDirectoryPathId(directoryPathId2);
+}
+
+TEST_F(DirectoryPathCompressor, RemoveDuplicates)
+{
+ EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(directoryPathId1, directoryPathId2)));
+
+ compressor.addDirectoryPathId(directoryPathId1);
+ compressor.addDirectoryPathId(directoryPathId2);
+ compressor.addDirectoryPathId(directoryPathId1);
+}
+
+}
diff --git a/tests/unit/unittest/filepathcache-test.cpp b/tests/unit/unittest/filepathcache-test.cpp
index 43b5b026bb..478e5f0215 100644
--- a/tests/unit/unittest/filepathcache-test.cpp
+++ b/tests/unit/unittest/filepathcache-test.cpp
@@ -31,6 +31,7 @@
namespace {
+using ClangBackEnd::DirectoryPathId;
using ClangBackEnd::FilePathId;
using Cache = ClangBackEnd::FilePathCache<NiceMock<MockFilePathStorage>>;
using ClangBackEnd::FilePathId;
@@ -166,4 +167,153 @@ TEST_F(FilePathCache, DuplicateFilePathsAreEqual)
ASSERT_THAT(filePath2Id, Eq(filePath1Id));
}
+TEST_F(FilePathCache, DirectoryPathIdCallsFetchDirectoryId)
+{
+ EXPECT_CALL(mockStorage, fetchDirectoryId(Eq("/path/to")));
+
+ cache.directoryPathId(Utils::SmallString("/path/to"));
+}
+
+TEST_F(FilePathCache, SecondDirectoryPathIdCallsNotFetchDirectoryId)
+{
+ cache.directoryPathId(Utils::SmallString("/path/to"));
+
+ EXPECT_CALL(mockStorage, fetchDirectoryId(Eq("/path/to"))).Times(0);
+
+ cache.directoryPathId(Utils::SmallString("/path/to"));
+}
+
+TEST_F(FilePathCache, DirectoryPathIdWithTrailingSlash)
+{
+ EXPECT_CALL(mockStorage, fetchDirectoryId(Eq("/path/to")));
+
+ cache.directoryPathId(Utils::SmallString("/path/to/"));
+}
+
+TEST_F(FilePathCache, DirectoryPathId)
+{
+ auto id = cache.directoryPathId(Utils::SmallString("/path/to"));
+
+ ASSERT_THAT(id, Eq(DirectoryPathId{5}));
+}
+
+TEST_F(FilePathCache, DirectoryPathIdIsAlreadyInCache)
+{
+ auto firstId = cache.directoryPathId(Utils::SmallString("/path/to"));
+
+ auto secondId = cache.directoryPathId(Utils::SmallString("/path/to"));
+
+ ASSERT_THAT(secondId, firstId);
+}
+
+TEST_F(FilePathCache, DirectoryPathIdIsAlreadyInCacheWithTrailingSlash)
+{
+ auto firstId = cache.directoryPathId(Utils::SmallString("/path/to/"));
+
+ auto secondId = cache.directoryPathId(Utils::SmallString("/path/to/"));
+
+ ASSERT_THAT(secondId, firstId);
+}
+
+TEST_F(FilePathCache, DirectoryPathIdIsAlreadyInCacheWithAndWithoutTrailingSlash)
+{
+ auto firstId = cache.directoryPathId(Utils::SmallString("/path/to/"));
+
+ auto secondId = cache.directoryPathId(Utils::SmallString("/path/to"));
+
+ ASSERT_THAT(secondId, firstId);
+}
+
+TEST_F(FilePathCache, DirectoryPathIdIsAlreadyInCacheWithoutAndWithTrailingSlash)
+{
+ auto firstId = cache.directoryPathId(Utils::SmallString("/path/to"));
+
+ auto secondId = cache.directoryPathId(Utils::SmallString("/path/to/"));
+
+ ASSERT_THAT(secondId, firstId);
+}
+
+TEST_F(FilePathCache, ThrowForGettingADirectoryPathWithAnInvalidId)
+{
+ DirectoryPathId directoryPathId;
+
+ ASSERT_THROW(cache.directoryPath(directoryPathId),
+ ClangBackEnd::NoDirectoryPathForInvalidDirectoryPathId);
+}
+
+TEST_F(FilePathCache, GetADirectoryPath)
+{
+ DirectoryPathId directoryPathId{5};
+
+ auto directoryPath = cache.directoryPath(directoryPathId);
+
+ ASSERT_THAT(directoryPath, Eq(Utils::SmallStringView{"/path/to"}));
+}
+
+TEST_F(FilePathCache, GetADirectoryPathWithCachedDirectoryPathId)
+{
+ DirectoryPathId directoryPathId{5};
+ cache.directoryPath(directoryPathId);
+
+ auto directoryPath = cache.directoryPath(directoryPathId);
+
+ ASSERT_THAT(directoryPath, Eq(Utils::SmallStringView{"/path/to"}));
+}
+
+TEST_F(FilePathCache, DirectoryPathCallsFetchDirectoryPath)
+{
+ EXPECT_CALL(mockStorage, fetchDirectoryPath(Eq(DirectoryPathId{5})));
+
+ cache.directoryPath(5);
+}
+
+TEST_F(FilePathCache, SecondDirectoryPathCallsNotFetchDirectoryPath)
+{
+ cache.directoryPath(5);
+
+ EXPECT_CALL(mockStorage, fetchDirectoryPath(_)).Times(0);
+
+ cache.directoryPath(5);
+}
+
+TEST_F(FilePathCache, ThrowForGettingADirectoryPathIdWithAnInvalidFilePathId)
+{
+ FilePathId filePathId;
+
+ ASSERT_THROW(cache.directoryPathId(filePathId), ClangBackEnd::NoFilePathForInvalidFilePathId);
+}
+
+TEST_F(FilePathCache, FetchDirectoryPathIdByFilePathId)
+{
+ auto directoryId = cache.directoryPathId(42);
+
+ ASSERT_THAT(directoryId, Eq(5));
+}
+
+TEST_F(FilePathCache, FetchDirectoryPathIdByFilePathIdCached)
+{
+ cache.directoryPathId(42);
+
+ auto directoryId = cache.directoryPathId(42);
+
+ ASSERT_THAT(directoryId, Eq(5));
+}
+
+TEST_F(FilePathCache, FetchFilePathAfterFetchingDirectoryIdByFilePathId)
+{
+ cache.directoryPathId(42);
+
+ auto filePath = cache.filePath(42);
+
+ ASSERT_THAT(filePath, Eq("/path/to/file.cpp"));
+}
+
+TEST_F(FilePathCache, FetchDirectoryPathIdAfterFetchingFilePathByFilePathId)
+{
+ cache.filePath(42);
+
+ auto directoryId = cache.directoryPathId(42);
+
+ ASSERT_THAT(directoryId, Eq(5));
}
+} // namespace
diff --git a/tests/unit/unittest/filepathstorage-test.cpp b/tests/unit/unittest/filepathstorage-test.cpp
index 37f325daf0..fb60e32512 100644
--- a/tests/unit/unittest/filepathstorage-test.cpp
+++ b/tests/unit/unittest/filepathstorage-test.cpp
@@ -46,8 +46,8 @@ protected:
void SetUp()
{
ON_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
- valueReturnInt32(_))
- .WillByDefault(Return(Utils::optional<int>()));
+ valueReturnInt32(A<Utils::SmallStringView>()))
+ .WillByDefault(Return(Utils::optional<int>()));
ON_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
valueReturnInt32(Utils::SmallStringView("")))
.WillByDefault(Return(Utils::optional<int>(0)));
@@ -77,9 +77,12 @@ protected:
ON_CALL(selectSourceNameAndDirectoryIdFromSourcesBySourceId,
valueReturnSourceNameAndDirectoryId(42))
.WillByDefault(Return(Utils::optional<ClangBackEnd::Sources::SourceNameAndDirectoryId>({"file.cpp", 5})));
+ ON_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq<int>(42)))
+ .WillByDefault(Return(Utils::optional<int>(5)));
- EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath, valueReturnInt32(_))
- .Times(AnyNumber());
+ EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
+ valueReturnInt32(A<Utils::SmallStringView>()))
+ .Times(AnyNumber());
EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName, valueReturnInt32(_, _))
.Times(AnyNumber());
EXPECT_CALL(insertIntoDirectories, write(An<Utils::SmallStringView>()))
@@ -107,6 +110,7 @@ protected:
MockSqliteWriteStatement &insertIntoDirectories = factory.insertIntoDirectories;
MockSqliteWriteStatement &insertIntoSources = factory.insertIntoSources;
MockSqliteReadStatement &selectAllSources = factory.selectAllSources;
+ MockSqliteReadStatement &selectDirectoryIdFromSourcesBySourceId = factory.selectDirectoryIdFromSourcesBySourceId;
Storage storage{factory};
};
@@ -229,7 +233,7 @@ TEST_F(FilePathStorage, CallSelectForFetchingDirectoryIdForKnownPath)
EXPECT_CALL(mockDatabase, deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
- valueReturnInt32(Eq("/path/to")));
+ valueReturnInt32(TypedEq<Utils::SmallStringView>("/path/to")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchDirectoryId("/path/to");
@@ -267,7 +271,7 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdForUnknownPath)
EXPECT_CALL(mockDatabase, deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
- valueReturnInt32(Eq("/some/not/known/path")));
+ valueReturnInt32(TypedEq<Utils::SmallStringView>("/some/not/known/path")));
EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/some/not/known/path")));
EXPECT_CALL(mockDatabase, commit());
@@ -296,7 +300,7 @@ TEST_F(FilePathStorage, RestartFetchDirectoryIDIfTheStatementIsBusyInBeginBecaus
EXPECT_CALL(mockDatabase, rollback()).Times(0);
EXPECT_CALL(mockDatabase, deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
- valueReturnInt32(Eq("/other/unknow/path")));
+ valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
EXPECT_CALL(mockDatabase, commit());
@@ -310,13 +314,13 @@ TEST_F(FilePathStorage,
EXPECT_CALL(mockDatabase, deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
- valueReturnInt32(Eq("/other/unknow/path")));
+ valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path")))
.WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
EXPECT_CALL(mockDatabase, rollback());
EXPECT_CALL(mockDatabase, deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
- valueReturnInt32(Eq("/other/unknow/path")));
+ valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
EXPECT_CALL(mockDatabase, commit());
@@ -329,13 +333,13 @@ TEST_F(FilePathStorage, CallSelectAndWriteForFetchingDirectoryIdTwoTimesIfTheInd
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
- valueReturnInt32(Eq("/other/unknow/path")));
+ valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
EXPECT_CALL(insertIntoDirectories, write(TypedEq<Utils::SmallStringView>("/other/unknow/path")))
.WillOnce(Throw(Sqlite::ConstraintPreventsModification("busy")));
EXPECT_CALL(mockDatabase, rollback());
EXPECT_CALL(mockDatabase,deferredBegin());
EXPECT_CALL(selectDirectoryIdFromDirectoriesByDirectoryPath,
- valueReturnInt32(Eq("/other/unknow/path")));
+ valueReturnInt32(TypedEq<Utils::SmallStringView>("/other/unknow/path")));
EXPECT_CALL(mockDatabase, commit());
storage.fetchDirectoryId("/other/unknow/path");
@@ -368,7 +372,6 @@ TEST_F(FilePathStorage,
EXPECT_CALL(insertIntoSources,
write(TypedEq<int>(5), TypedEq<Utils::SmallStringView>("otherunknownfile.h")))
.WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
- ;
EXPECT_CALL(mockDatabase, rollback());
EXPECT_CALL(mockDatabase, deferredBegin());
EXPECT_CALL(selectSourceIdFromSourcesByDirectoryIdAndSourceName,
@@ -545,4 +548,59 @@ TEST_F(FilePathStorage, RestartFetchAllSourcesIfBeginIsBusy)
storage.fetchAllSources();
}
+TEST_F(FilePathStorage, FetchDirectoryIdForUnknownFileID)
+{
+ ASSERT_THROW(storage.fetchDirectoryId(1111), ClangBackEnd::SourceNameIdDoesNotExists);
+}
+
+TEST_F(FilePathStorage, FetchDirectoryId)
+{
+ auto directoryId = storage.fetchDirectoryId(42);
+
+ ASSERT_THAT(directoryId, 5);
+}
+
+TEST_F(FilePathStorage, FetchDirectoryIdCalls)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockDatabase, lock());
+ EXPECT_CALL(mockDatabase, deferredBegin());
+ EXPECT_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq<int>(42)));
+ EXPECT_CALL(mockDatabase, commit());
+ EXPECT_CALL(mockDatabase, unlock());
+
+ storage.fetchDirectoryId(42);
}
+
+TEST_F(FilePathStorage, FetchDirectoryIdCallsDatabaseIsBusy)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockDatabase, lock());
+ EXPECT_CALL(mockDatabase, deferredBegin()).WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
+ EXPECT_CALL(mockDatabase, rollback()).Times(0);
+ EXPECT_CALL(mockDatabase, unlock());
+ EXPECT_CALL(mockDatabase, lock());
+ EXPECT_CALL(mockDatabase, deferredBegin());
+ EXPECT_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq<int>(42)));
+ EXPECT_CALL(mockDatabase, commit());
+ EXPECT_CALL(mockDatabase, unlock());
+
+ storage.fetchDirectoryId(42);
+}
+
+TEST_F(FilePathStorage, FetchDirectoryIdCallsThrows)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockDatabase, lock());
+ EXPECT_CALL(mockDatabase, deferredBegin());
+ EXPECT_CALL(selectDirectoryIdFromSourcesBySourceId, valueReturnInt32(TypedEq<int>(41)));
+ EXPECT_CALL(mockDatabase, rollback());
+ EXPECT_CALL(mockDatabase, unlock());
+
+ ASSERT_ANY_THROW(storage.fetchDirectoryId(41));
+}
+
+} // namespace
diff --git a/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp b/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp
index ac902fa700..40af2d99c3 100644
--- a/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp
+++ b/tests/unit/unittest/filepathstoragesqlitestatementfactory-test.cpp
@@ -61,7 +61,13 @@ TEST_F(FilePathStorageSqliteStatementFactory, SelectSourceIdFromSourcesByDirecto
Eq("SELECT sourceId FROM sources WHERE directoryId = ? AND sourceName = ?"));
}
-TEST_F(FilePathStorageSqliteStatementFactory, SelectSourceNameFromSourcesByDirectoryIdAndSourceId)
+TEST_F(FilePathStorageSqliteStatementFactory, SelectSourceNameAndDirectoryIdFromSourcesByAndSourceId)
+{
+ ASSERT_THAT(factory.selectSourceNameAndDirectoryIdFromSourcesBySourceId.sqlStatement,
+ Eq("SELECT sourceName, directoryId FROM sources WHERE sourceId = ?"));
+}
+
+TEST_F(FilePathStorageSqliteStatementFactory, SelectSourceNameAndDirectoryIdBySourceId)
{
ASSERT_THAT(factory.selectSourceNameAndDirectoryIdFromSourcesBySourceId.sqlStatement,
Eq("SELECT sourceName, directoryId FROM sources WHERE sourceId = ?"));
diff --git a/tests/unit/unittest/filestatuscache-test.cpp b/tests/unit/unittest/filestatuscache-test.cpp
index db13bc28a7..07ba02655b 100644
--- a/tests/unit/unittest/filestatuscache-test.cpp
+++ b/tests/unit/unittest/filestatuscache-test.cpp
@@ -24,6 +24,7 @@
****************************************************************************/
#include "googletest.h"
+#include "mockfilesystem.h"
#include <filepathcaching.h>
#include <filestatuscache.h>
@@ -37,31 +38,33 @@
namespace {
using ClangBackEnd::FilePathId;
+using ClangBackEnd::FilePathIds;
class FileStatusCache : public testing::Test
{
protected:
- FilePathId filePathId(Utils::SmallStringView path) const
+ FileStatusCache()
{
- return filePathCache.filePathId(ClangBackEnd::FilePathView(path));
- }
-
- void touchFile(FilePathId filePathId)
- {
- std::ofstream ostream(std::string(filePathCache.filePath(filePathId)), std::ios::binary);
- ostream.write("\n", 1);
- ostream.close();
+ ON_CALL(fileSystem, lastModified(Eq(header))).WillByDefault(Return(headerLastModifiedTime));
+ ON_CALL(fileSystem, lastModified(Eq(source))).WillByDefault(Return(sourceLastModifiedTime));
+ ON_CALL(fileSystem, lastModified(Eq(header2))).WillByDefault(Return(header2LastModifiedTime));
+ ON_CALL(fileSystem, lastModified(Eq(source2))).WillByDefault(Return(source2LastModifiedTime));
}
protected:
- Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
- ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
- ClangBackEnd::FilePathCaching filePathCache{database};
- ClangBackEnd::FileStatusCache cache{filePathCache};
- FilePathId header{filePathId(TESTDATA_DIR "/filestatuscache_header.h")};
- FilePathId source{filePathId(TESTDATA_DIR "/filestatuscache_header.cpp")};
- long long headerLastModifiedTime = QFileInfo(TESTDATA_DIR "/filestatuscache_header.h").lastModified().toSecsSinceEpoch();
- long long sourceLastModifiedTime = QFileInfo(TESTDATA_DIR "/filestatuscache_header.cpp").lastModified().toSecsSinceEpoch();
+ NiceMock<MockFileSystem> fileSystem;
+ ClangBackEnd::FileStatusCache cache{fileSystem};
+ FilePathId header{1};
+ FilePathId source{2};
+ FilePathId header2{3};
+ FilePathId source2{4};
+ FilePathIds entries{header, source, header2, source2};
+ long long headerLastModifiedTime = 100;
+ long long headerLastModifiedTime2 = 110;
+ long long header2LastModifiedTime = 300;
+ long long header2LastModifiedTime2 = 310;
+ long long sourceLastModifiedTime = 200;
+ long long source2LastModifiedTime = 400;
};
TEST_F(FileStatusCache, CreateEntry)
@@ -134,18 +137,24 @@ TEST_F(FileStatusCache, AskNewEntryReverseOrderAddedForLastModifiedTime)
TEST_F(FileStatusCache, UpdateFile)
{
- auto oldLastModified = cache.lastModifiedTime(header);
- touchFile(header);
+ EXPECT_CALL(fileSystem, lastModified(Eq(header)))
+ .Times(2)
+ .WillOnce(Return(headerLastModifiedTime))
+ .WillOnce(Return(headerLastModifiedTime2));
+ cache.lastModifiedTime(header);
cache.update(header);
- ASSERT_THAT(cache.lastModifiedTime(header), Gt(oldLastModified));
+ ASSERT_THAT(cache.lastModifiedTime(header), headerLastModifiedTime2);
}
TEST_F(FileStatusCache, UpdateFileDoesNotChangeEntryCount)
{
+ EXPECT_CALL(fileSystem, lastModified(Eq(header)))
+ .Times(2)
+ .WillOnce(Return(headerLastModifiedTime))
+ .WillOnce(Return(headerLastModifiedTime2));
cache.lastModifiedTime(header);
- touchFile(header);
cache.update(header);
@@ -154,11 +163,136 @@ TEST_F(FileStatusCache, UpdateFileDoesNotChangeEntryCount)
TEST_F(FileStatusCache, UpdateFileForNonExistingEntry)
{
- touchFile(header);
-
cache.update(header);
ASSERT_THAT(cache, SizeIs(0));
}
+TEST_F(FileStatusCache, UpdateFiles)
+{
+ EXPECT_CALL(fileSystem, lastModified(Eq(header)))
+ .Times(2)
+ .WillOnce(Return(headerLastModifiedTime))
+ .WillOnce(Return(headerLastModifiedTime2));
+ EXPECT_CALL(fileSystem, lastModified(Eq(header2)))
+ .Times(2)
+ .WillOnce(Return(header2LastModifiedTime))
+ .WillOnce(Return(header2LastModifiedTime2));
+ cache.lastModifiedTime(header);
+ cache.lastModifiedTime(header2);
+
+ cache.update(entries);
+
+ ASSERT_THAT(cache.lastModifiedTime(header), headerLastModifiedTime2);
+ ASSERT_THAT(cache.lastModifiedTime(header2), header2LastModifiedTime2);
}
+
+TEST_F(FileStatusCache, UpdateFilesDoesNotChangeEntryCount)
+{
+ EXPECT_CALL(fileSystem, lastModified(Eq(header)))
+ .Times(2)
+ .WillOnce(Return(headerLastModifiedTime))
+ .WillOnce(Return(headerLastModifiedTime2));
+ EXPECT_CALL(fileSystem, lastModified(Eq(header2)))
+ .Times(2)
+ .WillOnce(Return(header2LastModifiedTime))
+ .WillOnce(Return(header2LastModifiedTime2));
+ cache.lastModifiedTime(header);
+ cache.lastModifiedTime(header2);
+
+ cache.update(entries);
+
+ ASSERT_THAT(cache, SizeIs(2));
+}
+
+TEST_F(FileStatusCache, UpdateFilesForNonExistingEntry)
+{
+ cache.update(entries);
+
+ ASSERT_THAT(cache, SizeIs(0));
+}
+
+TEST_F(FileStatusCache, NewModifiedEntries)
+{
+ auto modifiedIds = cache.modified(entries);
+
+ ASSERT_THAT(modifiedIds, entries);
+}
+
+TEST_F(FileStatusCache, NoNewModifiedEntries)
+{
+ cache.modified(entries);
+
+ auto modifiedIds = cache.modified(entries);
+
+ ASSERT_THAT(modifiedIds, IsEmpty());
+}
+
+TEST_F(FileStatusCache, SomeNewModifiedEntries)
+{
+ cache.modified({source, header2});
+
+ auto modifiedIds = cache.modified(entries);
+
+ ASSERT_THAT(modifiedIds, ElementsAre(header, source2));
+}
+
+TEST_F(FileStatusCache, SomeAlreadyExistingModifiedEntries)
+{
+ EXPECT_CALL(fileSystem, lastModified(Eq(header)))
+ .Times(2)
+ .WillOnce(Return(headerLastModifiedTime))
+ .WillOnce(Return(headerLastModifiedTime2));
+ EXPECT_CALL(fileSystem, lastModified(Eq(header2)))
+ .Times(2)
+ .WillOnce(Return(header2LastModifiedTime))
+ .WillOnce(Return(header2LastModifiedTime2));
+ EXPECT_CALL(fileSystem, lastModified(Eq(source))).Times(2).WillRepeatedly(Return(sourceLastModifiedTime));
+ EXPECT_CALL(fileSystem, lastModified(Eq(source2)))
+ .Times(2)
+ .WillRepeatedly(Return(source2LastModifiedTime));
+ cache.modified(entries);
+
+ auto modifiedIds = cache.modified(entries);
+
+ ASSERT_THAT(modifiedIds, ElementsAre(header, header2));
+}
+
+TEST_F(FileStatusCache, SomeAlreadyExistingAndSomeNewModifiedEntries)
+{
+ EXPECT_CALL(fileSystem, lastModified(Eq(header))).WillRepeatedly(Return(headerLastModifiedTime));
+ EXPECT_CALL(fileSystem, lastModified(Eq(header2)))
+ .Times(2)
+ .WillOnce(Return(header2LastModifiedTime))
+ .WillOnce(Return(header2LastModifiedTime2));
+ EXPECT_CALL(fileSystem, lastModified(Eq(source))).Times(2).WillRepeatedly(Return(sourceLastModifiedTime));
+ EXPECT_CALL(fileSystem, lastModified(Eq(source2))).WillRepeatedly(Return(source2LastModifiedTime));
+ cache.modified({source, header2});
+
+ auto modifiedIds = cache.modified(entries);
+
+ ASSERT_THAT(modifiedIds, ElementsAre(header, header2, source2));
+}
+
+TEST_F(FileStatusCache, TimeIsUpdatedForSomeAlreadyExistingModifiedEntries)
+{
+ EXPECT_CALL(fileSystem, lastModified(Eq(header)))
+ .Times(2)
+ .WillOnce(Return(headerLastModifiedTime))
+ .WillOnce(Return(headerLastModifiedTime2));
+ EXPECT_CALL(fileSystem, lastModified(Eq(header2)))
+ .Times(2)
+ .WillOnce(Return(header2LastModifiedTime))
+ .WillOnce(Return(header2LastModifiedTime2));
+ EXPECT_CALL(fileSystem, lastModified(Eq(source))).Times(2).WillRepeatedly(Return(sourceLastModifiedTime));
+ EXPECT_CALL(fileSystem, lastModified(Eq(source2)))
+ .Times(2)
+ .WillRepeatedly(Return(source2LastModifiedTime));
+ cache.modified(entries);
+
+ cache.modified(entries);
+
+ ASSERT_THAT(cache.lastModifiedTime(header), headerLastModifiedTime2);
+}
+
+} // namespace
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 7ac4a676e3..0ab962dfa5 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -361,7 +361,7 @@ std::ostream &operator<<(std::ostream &out, const WatcherEntry &entry)
{
out << "("
<< entry.id << ", "
- << entry.pathId
+ << entry.filePathId
<< ")";
return out;
diff --git a/tests/unit/unittest/mockfilepathcaching.h b/tests/unit/unittest/mockfilepathcaching.h
index 1b22e910ee..ca7960513e 100644
--- a/tests/unit/unittest/mockfilepathcaching.h
+++ b/tests/unit/unittest/mockfilepathcaching.h
@@ -36,5 +36,11 @@ public:
ClangBackEnd::FilePathId (ClangBackEnd::FilePathView filePath));
MOCK_CONST_METHOD1(filePath,
ClangBackEnd::FilePath (ClangBackEnd::FilePathId filePathId));
+ MOCK_CONST_METHOD1(directoryPathId,
+ ClangBackEnd::DirectoryPathId(Utils::SmallStringView directoryPath));
+ MOCK_CONST_METHOD1(directoryPath,
+ Utils::PathString(ClangBackEnd::DirectoryPathId directoryPathId));
+ MOCK_CONST_METHOD1(directoryPathId,
+ ClangBackEnd::DirectoryPathId(ClangBackEnd::FilePathId filePathId));
};
diff --git a/tests/unit/unittest/mockfilesystem.h b/tests/unit/unittest/mockfilesystem.h
new file mode 100644
index 0000000000..688edbcae5
--- /dev/null
+++ b/tests/unit/unittest/mockfilesystem.h
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 <filesysteminterface.h>
+
+class MockFileSystem : public ClangBackEnd::FileSystemInterface
+{
+public:
+ MOCK_CONST_METHOD1(directoryEntries, ClangBackEnd::FilePathIds(const QString &directoryPath));
+ MOCK_CONST_METHOD1(lastModified, long long(ClangBackEnd::FilePathId filePathId));
+};
diff --git a/tests/unit/unittest/mockqfilesystemwatcher.h b/tests/unit/unittest/mockqfilesystemwatcher.h
index 1bb90b2c37..00f4c600b4 100644
--- a/tests/unit/unittest/mockqfilesystemwatcher.h
+++ b/tests/unit/unittest/mockqfilesystemwatcher.h
@@ -41,4 +41,5 @@ public:
signals:
void fileChanged(const QString &);
+ void directoryChanged(const QString &);
};
diff --git a/tests/unit/unittest/mocksqlitereadstatement.cpp b/tests/unit/unittest/mocksqlitereadstatement.cpp
index b0df1ab75d..1e800e2be1 100644
--- a/tests/unit/unittest/mocksqlitereadstatement.cpp
+++ b/tests/unit/unittest/mocksqlitereadstatement.cpp
@@ -137,6 +137,12 @@ MockSqliteReadStatement::value<int>(const int &directoryId, const Utils::SmallSt
return valueReturnInt32(directoryId, text);
}
+template<>
+Utils::optional<int> MockSqliteReadStatement::value<int>(const int &value)
+{
+ return valueReturnInt32(value);
+}
+
template <>
Utils::optional<long long>
MockSqliteReadStatement::value<long long>(const int &sourceId)
diff --git a/tests/unit/unittest/mocksqlitereadstatement.h b/tests/unit/unittest/mocksqlitereadstatement.h
index d952c90dec..191c38accd 100644
--- a/tests/unit/unittest/mocksqlitereadstatement.h
+++ b/tests/unit/unittest/mocksqlitereadstatement.h
@@ -92,11 +92,11 @@ public:
MOCK_METHOD1(valueReturnInt32, Utils::optional<int>(Utils::SmallStringView));
- MOCK_METHOD2(valueReturnInt32,
- Utils::optional<int>(int, Utils::SmallStringView));
+ MOCK_METHOD2(valueReturnInt32, Utils::optional<int>(int, Utils::SmallStringView));
- MOCK_METHOD1(valueReturnInt64,
- Utils::optional<long long>(int));
+ MOCK_METHOD1(valueReturnInt32, Utils::optional<int>(int));
+
+ MOCK_METHOD1(valueReturnInt64, Utils::optional<long long>(int));
MOCK_METHOD1(valueReturnPathString,
Utils::optional<Utils::PathString>(int));
@@ -244,6 +244,9 @@ template <>
Utils::optional<int>
MockSqliteReadStatement::value<int>(const int&, const Utils::SmallStringView&);
+template<>
+Utils::optional<int> MockSqliteReadStatement::value<int>(const int &);
+
template <>
Utils::optional<long long>
MockSqliteReadStatement::value<long long>(const ClangBackEnd::FilePathId&);
diff --git a/tests/unit/unittest/symbolindexer-test.cpp b/tests/unit/unittest/symbolindexer-test.cpp
index 2db11dc5fb..0bfcf13188 100644
--- a/tests/unit/unittest/symbolindexer-test.cpp
+++ b/tests/unit/unittest/symbolindexer-test.cpp
@@ -28,6 +28,7 @@
#include "mockbuilddependenciesstorage.h"
#include "mockclangpathwatcher.h"
#include "mockfilepathcaching.h"
+#include "mockfilesystem.h"
#include "mockmodifiedtimechecker.h"
#include "mockprecompiledheaderstorage.h"
#include "mockprojectpartsstorage.h"
@@ -149,13 +150,6 @@ protected:
data.reset();
}
- void touchFile(FilePathId filePathId)
- {
- std::ofstream ostream(std::string(filePathCache.filePath(filePathId)), std::ios::binary);
- ostream.write("\n", 1);
- ostream.close();
- }
-
FilePathId filePathId(Utils::SmallStringView path) const
{
return filePathCache.filePathId(ClangBackEnd::FilePathView(path));
@@ -249,7 +243,8 @@ protected:
NiceMock<MockPrecompiledHeaderStorage> mockPrecompiledHeaderStorage;
NiceMock<MockProjectPartsStorage> mockProjectPartsStorage;
NiceMock<MockClangPathWatcher> mockPathWatcher;
- ClangBackEnd::FileStatusCache fileStatusCache{filePathCache};
+ NiceMock<MockFileSystem> mockFileSystem;
+ ClangBackEnd::FileStatusCache fileStatusCache{mockFileSystem};
ClangBackEnd::GeneratedFiles generatedFiles;
Manager collectorManger{generatedFiles};
NiceMock<MockFunction<void(int, int)>> mockSetProgressCallback;
@@ -1664,13 +1659,12 @@ TEST_F(SymbolIndexer, DISABLED_DontReparseInUpdateProjectPartsIfDefinesAreTheSam
TEST_F(SymbolIndexer, PathsChangedUpdatesFileStatusCache)
{
auto sourceId = filePathId(TESTDATA_DIR "/symbolindexer_pathChanged.cpp");
- auto oldLastModified = fileStatusCache.lastModifiedTime(sourceId);
- touchFile(sourceId);
+ ON_CALL(mockFileSystem, lastModified(Eq(sourceId))).WillByDefault(Return(65));
ON_CALL(mockSymbolStorage, fetchDependentSourceIds(_)).WillByDefault(Return(FilePathIds{sourceId}));
indexer.pathsChanged({sourceId});
- ASSERT_THAT(fileStatusCache.lastModifiedTime(sourceId), Gt(oldLastModified));
+ ASSERT_THAT(fileStatusCache.lastModifiedTime(sourceId), 65);
}
TEST_F(SymbolIndexer, GetUpdatableFilePathIdsIfCompilerMacrosAreDifferent)
@@ -1706,6 +1700,7 @@ TEST_F(SymbolIndexer, GetNoUpdatableFilePathIdsIfArtefactsAreTheSame)
TEST_F(SymbolIndexer, OutdatedFilesPassUpdatableFilePathIds)
{
+ ON_CALL(mockFileSystem, lastModified(Eq(main1PathId))).WillByDefault(Return(65));
indexer.pathsChanged({main1PathId});
ON_CALL(mockProjectPartsStorage, fetchProjectPartArtefact(A<ProjectPartId>()))
.WillByDefault(Return(artefact));
diff --git a/tests/unit/unittest/unittest.pro b/tests/unit/unittest/unittest.pro
index 63980ab055..d9cef683e7 100644
--- a/tests/unit/unittest/unittest.pro
+++ b/tests/unit/unittest/unittest.pro
@@ -46,7 +46,7 @@ QMAKE_SUBSTITUTES += cpptoolsjson
DEFINES += CPPTOOLS_JSON=\"R\\\"xxx($${cpptoolsjson.output})xxx\\\"\"
SOURCES += \
- changedfilepathcompressor-test.cpp \
+ directorypathcompressor-test.cpp \
clangpathwatcher-test.cpp \
clangqueryexamplehighlightmarker-test.cpp \
clangqueryhighlightmarker-test.cpp \
@@ -175,7 +175,7 @@ SOURCES += \
translationunitupdater-test.cpp \
unsavedfiles-test.cpp \
unsavedfile-test.cpp \
- utf8positionfromlinecolumn-test.cpp \
+ utf8positionfromlinecolumn-test.cpp
}
!isEmpty(LIBTOOLING_LIBS) {
@@ -226,6 +226,7 @@ HEADERS += \
mockclangcodemodelserver.h \
mockclangpathwatcher.h \
mockclangpathwatchernotifier.h \
+ mockfilesystem.h \
mockpchcreator.h \
mockpchmanagerclient.h \
mockpchmanagernotifier.h \