forked from qt-creator/qt-creator
Clang: Add reset to ModifiedTimeChecker
We can reset some file once to flag a file dirty if the included file has changed. Change-Id: I8763bb80f65882fba4e70057f569234e77097927 Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
@@ -157,6 +157,7 @@ HEADERS += \
|
||||
$$PWD/refactoringserverinterface.h \
|
||||
$$PWD/refactoringserverproxy.h \
|
||||
$$PWD/referencesmessage.h \
|
||||
$$PWD/set_algorithm.h \
|
||||
$$PWD/unsavedfilesupdatedmessage.h \
|
||||
$$PWD/removeprojectpartsmessage.h \
|
||||
$$PWD/requestannotationsmessage.h \
|
||||
|
@@ -26,6 +26,8 @@
|
||||
#include "filestatuscache.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
#include <set_algorithm.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QDateTime>
|
||||
@@ -51,49 +53,15 @@ void FileStatusCache::update(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(),
|
||||
std::set_intersection(m_cacheEntries.begin(),
|
||||
m_cacheEntries.end(),
|
||||
filePathIds.begin(),
|
||||
filePathIds.end(),
|
||||
[&](auto &entry) {
|
||||
make_iterator([&](auto &entry) {
|
||||
entry.lastModified = m_fileSystem.lastModified(entry.filePathId);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
FilePathIds FileStatusCache::modified(FilePathIds filePathIds) const
|
||||
@@ -101,30 +69,30 @@ FilePathIds FileStatusCache::modified(FilePathIds filePathIds) const
|
||||
FilePathIds modifiedFilePathIds;
|
||||
modifiedFilePathIds.reserve(filePathIds.size());
|
||||
|
||||
set_intersection_call(m_cacheEntries.begin(),
|
||||
std::set_intersection(m_cacheEntries.begin(),
|
||||
m_cacheEntries.end(),
|
||||
filePathIds.begin(),
|
||||
filePathIds.end(),
|
||||
[&](auto &entry) {
|
||||
make_iterator([&](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(),
|
||||
std::set_difference(filePathIds.begin(),
|
||||
filePathIds.end(),
|
||||
m_cacheEntries.begin(),
|
||||
m_cacheEntries.end(),
|
||||
[&](FilePathId newFilePathId) {
|
||||
make_iterator([&](FilePathId newFilePathId) {
|
||||
newEntries.emplace_back(newFilePathId,
|
||||
m_fileSystem.lastModified(newFilePathId));
|
||||
modifiedFilePathIds.push_back(newFilePathId);
|
||||
});
|
||||
}));
|
||||
|
||||
if (newEntries.size()) {
|
||||
Internal::FileStatusCacheEntries mergedEntries;
|
||||
|
@@ -25,24 +25,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "clangpathwatcher.h"
|
||||
#include "filepathcachinginterface.h"
|
||||
#include "filesysteminterface.h"
|
||||
#include "modifiedtimecheckerinterface.h"
|
||||
#include "set_algorithm.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
template<typename SourceEntries = ::ClangBackEnd::SourceEntries>
|
||||
class ModifiedTimeChecker final : public ModifiedTimeCheckerInterface<SourceEntries>
|
||||
{
|
||||
using SourceEntry = typename SourceEntries::value_type;
|
||||
|
||||
public:
|
||||
using GetModifiedTime = std::function<ClangBackEnd::TimeStamp(ClangBackEnd::FilePathView filePath)>;
|
||||
ModifiedTimeChecker(GetModifiedTime &getModifiedTime, FilePathCachingInterface &filePathCache)
|
||||
: m_getModifiedTime(getModifiedTime)
|
||||
, m_filePathCache(filePathCache)
|
||||
ModifiedTimeChecker(FileSystemInterface &fileSystem)
|
||||
: m_fileSystem(fileSystem)
|
||||
{}
|
||||
|
||||
bool isUpToDate(const SourceEntries &sourceEntries) const
|
||||
@@ -52,165 +51,101 @@ public:
|
||||
|
||||
updateCurrentSourceTimeStamps(sourceEntries);
|
||||
|
||||
return compareEntries(sourceEntries);
|
||||
return compareEntries(sourceEntries) && notReseted(sourceEntries);
|
||||
}
|
||||
|
||||
void pathsChanged(const FilePathIds &filePathIds) override
|
||||
{
|
||||
using SourceTimeStampReferences = std::vector<std::reference_wrapper<SourceTimeStamp>>;
|
||||
|
||||
SourceTimeStampReferences timeStampsToUpdate;
|
||||
timeStampsToUpdate.reserve(filePathIds.size());
|
||||
|
||||
std::set_intersection(m_currentSourceTimeStamps.begin(),
|
||||
m_currentSourceTimeStamps.end(),
|
||||
filePathIds.begin(),
|
||||
filePathIds.end(),
|
||||
std::back_inserter(timeStampsToUpdate));
|
||||
make_iterator([&](SourceTimeStamp &sourceTimeStamp) {
|
||||
sourceTimeStamp.timeStamp = m_fileSystem.lastModified(
|
||||
sourceTimeStamp.sourceId);
|
||||
}));
|
||||
}
|
||||
|
||||
for (SourceTimeStamp &sourceTimeStamp : timeStampsToUpdate) {
|
||||
sourceTimeStamp.timeStamp = m_getModifiedTime(
|
||||
m_filePathCache.filePath(sourceTimeStamp.sourceId));
|
||||
}
|
||||
void reset(const FilePathIds &filePathIds)
|
||||
{
|
||||
FilePathIds newResetFilePathIds;
|
||||
newResetFilePathIds.reserve(newResetFilePathIds.size() + m_resetFilePathIds.size());
|
||||
|
||||
std::set_union(m_resetFilePathIds.begin(),
|
||||
m_resetFilePathIds.end(),
|
||||
filePathIds.begin(),
|
||||
filePathIds.end(),
|
||||
std::back_inserter(newResetFilePathIds));
|
||||
|
||||
m_resetFilePathIds = std::move(newResetFilePathIds);
|
||||
}
|
||||
|
||||
private:
|
||||
bool compareEntries(const SourceEntries &sourceEntries) const
|
||||
{
|
||||
class CompareSourceId
|
||||
{
|
||||
public:
|
||||
bool operator()(SourceTimeStamp first, SourceTimeStamp second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
};
|
||||
|
||||
SourceTimeStamps currentSourceTimeStamp;
|
||||
currentSourceTimeStamp.reserve(sourceEntries.size());
|
||||
std::set_intersection(m_currentSourceTimeStamps.begin(),
|
||||
m_currentSourceTimeStamps.end(),
|
||||
sourceEntries.begin(),
|
||||
sourceEntries.end(),
|
||||
std::back_inserter(currentSourceTimeStamp),
|
||||
CompareSourceId{});
|
||||
|
||||
class CompareTime
|
||||
{
|
||||
public:
|
||||
bool operator()(SourceTimeStamp first, SourceTimeStamp second)
|
||||
{
|
||||
return first.timeStamp <= second.timeStamp;
|
||||
}
|
||||
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.timeStamp <= second.timeStamp;
|
||||
}
|
||||
|
||||
bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.timeStamp <= second.timeStamp;
|
||||
}
|
||||
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second)
|
||||
{
|
||||
return first.timeStamp <= second.timeStamp;
|
||||
}
|
||||
};
|
||||
|
||||
return std::lexicographical_compare(currentSourceTimeStamp.begin(),
|
||||
currentSourceTimeStamp.end(),
|
||||
sourceEntries.begin(),
|
||||
sourceEntries.end(),
|
||||
CompareTime{});
|
||||
return set_intersection_compare(
|
||||
m_currentSourceTimeStamps.begin(),
|
||||
m_currentSourceTimeStamps.end(),
|
||||
sourceEntries.begin(),
|
||||
sourceEntries.end(),
|
||||
[](auto first, auto second) { return second.timeStamp > first.timeStamp; },
|
||||
[](auto first, auto second) { return first.sourceId < second.sourceId; });
|
||||
}
|
||||
|
||||
void updateCurrentSourceTimeStamps(const SourceEntries &sourceEntries) const
|
||||
{
|
||||
SourceTimeStamps sourceTimeStamps = newSourceTimeStamps(sourceEntries);
|
||||
|
||||
for (SourceTimeStamp &newSourceTimeStamp : sourceTimeStamps) {
|
||||
newSourceTimeStamp.timeStamp = m_getModifiedTime(
|
||||
m_filePathCache.filePath(newSourceTimeStamp.sourceId));
|
||||
}
|
||||
|
||||
auto split = sourceTimeStamps.insert(sourceTimeStamps.end(),
|
||||
m_currentSourceTimeStamps.begin(),
|
||||
m_currentSourceTimeStamps.end());
|
||||
std::inplace_merge(sourceTimeStamps.begin(), split, sourceTimeStamps.end());
|
||||
|
||||
m_currentSourceTimeStamps = sourceTimeStamps;
|
||||
m_currentSourceTimeStamps = std::move(sourceTimeStamps);
|
||||
}
|
||||
|
||||
SourceTimeStamps newSourceTimeStamps(const SourceEntries &sourceEntries) const
|
||||
{
|
||||
SourceEntries newSourceEntries;
|
||||
newSourceEntries.reserve(sourceEntries.size());
|
||||
|
||||
class CompareSourceId
|
||||
{
|
||||
public:
|
||||
bool operator()(SourceTimeStamp first, SourceTimeStamp second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(SourceTimeStamp first, ::ClangBackEnd::SourceEntry second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
bool operator()(::ClangBackEnd::SourceEntry first, SourceTimeStamp second)
|
||||
{
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
};
|
||||
SourceTimeStamps newTimeStamps;
|
||||
newTimeStamps.reserve(sourceEntries.size());
|
||||
|
||||
std::set_difference(sourceEntries.begin(),
|
||||
sourceEntries.end(),
|
||||
m_currentSourceTimeStamps.begin(),
|
||||
m_currentSourceTimeStamps.end(),
|
||||
std::back_inserter(newSourceEntries),
|
||||
CompareSourceId{});
|
||||
|
||||
SourceTimeStamps newTimeStamps;
|
||||
newTimeStamps.reserve(newSourceEntries.size());
|
||||
|
||||
std::transform(newSourceEntries.begin(),
|
||||
newSourceEntries.end(),
|
||||
std::back_inserter(newTimeStamps),
|
||||
[](SourceEntry entry) {
|
||||
return SourceTimeStamp{entry.sourceId, {}};
|
||||
});
|
||||
make_iterator([&](const SourceEntry &sourceEntry) {
|
||||
newTimeStamps.emplace_back(sourceEntry.sourceId,
|
||||
m_fileSystem.lastModified(
|
||||
sourceEntry.sourceId));
|
||||
}),
|
||||
[](auto first, auto second) {
|
||||
return first.sourceId < second.sourceId && first.timeStamp > 0;
|
||||
});
|
||||
|
||||
return newTimeStamps;
|
||||
}
|
||||
|
||||
bool notReseted(const SourceEntries &sourceEntries) const
|
||||
{
|
||||
auto oldSize = m_resetFilePathIds.size();
|
||||
FilePathIds newResetFilePathIds;
|
||||
newResetFilePathIds.reserve(newResetFilePathIds.size());
|
||||
|
||||
std::set_difference(m_resetFilePathIds.begin(),
|
||||
m_resetFilePathIds.end(),
|
||||
sourceEntries.begin(),
|
||||
sourceEntries.end(),
|
||||
std::back_inserter(newResetFilePathIds));
|
||||
|
||||
m_resetFilePathIds = std::move(newResetFilePathIds);
|
||||
|
||||
return oldSize == m_resetFilePathIds.size();
|
||||
}
|
||||
|
||||
private:
|
||||
mutable SourceTimeStamps m_currentSourceTimeStamps;
|
||||
GetModifiedTime &m_getModifiedTime;
|
||||
FilePathCachingInterface &m_filePathCache;
|
||||
mutable FilePathIds m_resetFilePathIds;
|
||||
FileSystemInterface &m_fileSystem;
|
||||
};
|
||||
|
||||
} // namespace ClangBackEnd
|
||||
|
101
src/libs/clangsupport/set_algorithm.h
Normal file
101
src/libs/clangsupport/set_algorithm.h
Normal file
@@ -0,0 +1,101 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <algorithm>
|
||||
|
||||
namespace ClangBackEnd {
|
||||
|
||||
template<class Callable>
|
||||
class function_output_iterator
|
||||
{
|
||||
public:
|
||||
typedef std::output_iterator_tag iterator_category;
|
||||
typedef void value_type;
|
||||
typedef void difference_type;
|
||||
typedef void pointer;
|
||||
typedef void reference;
|
||||
|
||||
explicit function_output_iterator() {}
|
||||
|
||||
explicit function_output_iterator(const Callable &callable)
|
||||
: m_callable(&callable)
|
||||
{}
|
||||
|
||||
function_output_iterator &operator=(const function_output_iterator &iterator)
|
||||
{
|
||||
m_callable = iterator.m_callable;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
struct helper
|
||||
{
|
||||
helper(const Callable *callable)
|
||||
: m_callable(callable)
|
||||
{}
|
||||
template<class T>
|
||||
helper &operator=(T &&value)
|
||||
{
|
||||
(*m_callable)(std::forward<T>(value));
|
||||
return *this;
|
||||
}
|
||||
const Callable *m_callable;
|
||||
};
|
||||
|
||||
helper operator*() { return helper(m_callable); }
|
||||
function_output_iterator &operator++() { return *this; }
|
||||
function_output_iterator &operator++(int) { return *this; }
|
||||
|
||||
private:
|
||||
const Callable *m_callable;
|
||||
};
|
||||
|
||||
template<typename Callable>
|
||||
function_output_iterator<Callable> make_iterator(const Callable &callable)
|
||||
{
|
||||
return function_output_iterator<Callable>(callable);
|
||||
}
|
||||
|
||||
template<class InputIt1, class InputIt2, class Callable, class Compare>
|
||||
bool set_intersection_compare(
|
||||
InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable call, Compare comp)
|
||||
{
|
||||
while (first1 != last1 && first2 != last2) {
|
||||
if (comp(*first1, *first2)) {
|
||||
++first1;
|
||||
} else {
|
||||
if (!comp(*first2, *first1)) {
|
||||
if (call(*first2, *first1++))
|
||||
return false;
|
||||
}
|
||||
++first2;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace ClangBackEnd
|
@@ -131,6 +131,10 @@ public:
|
||||
return first.sourceId < second.sourceId;
|
||||
}
|
||||
|
||||
friend bool operator<(SourceEntry first, FilePathId second) { return first.sourceId < second; }
|
||||
|
||||
friend bool operator<(FilePathId first, SourceEntry second) { return first < second.sourceId; }
|
||||
|
||||
friend bool operator==(SourceEntry first, SourceEntry second)
|
||||
{
|
||||
return first.sourceId == second.sourceId && first.sourceType == second.sourceType
|
||||
|
@@ -214,12 +214,7 @@ struct Data // because we have a cycle dependency
|
||||
ClangBackEnd::BuildDependencyCollector buildDependencyCollector{filePathCache,
|
||||
generatedFiles,
|
||||
environment};
|
||||
std::function<TimeStamp(FilePathView filePath)> getModifiedTime{
|
||||
[&](ClangBackEnd::FilePathView path) -> TimeStamp {
|
||||
return QFileInfo(QString(path)).lastModified().toSecsSinceEpoch();
|
||||
}};
|
||||
ClangBackEnd::ModifiedTimeChecker<ClangBackEnd::SourceEntries> modifiedTimeChecker{getModifiedTime,
|
||||
filePathCache};
|
||||
ClangBackEnd::ModifiedTimeChecker<ClangBackEnd::SourceEntries> modifiedTimeChecker{fileSystem};
|
||||
ClangBackEnd::BuildDependenciesProvider buildDependencyProvider{buildDependencyStorage,
|
||||
modifiedTimeChecker,
|
||||
buildDependencyCollector,
|
||||
|
@@ -148,12 +148,7 @@ private:
|
||||
FileStatusCache m_fileStatusCache{m_fileSytem};
|
||||
SymbolsCollectorManager m_collectorManger;
|
||||
ProgressCounter m_progressCounter;
|
||||
std::function<TimeStamp(FilePathView filePath)> getModifiedTime{
|
||||
[&](ClangBackEnd::FilePathView path) -> TimeStamp {
|
||||
return QFileInfo(QString(path)).lastModified().toSecsSinceEpoch();
|
||||
}};
|
||||
ModifiedTimeChecker<ClangBackEnd::SourceTimeStamps> m_modifiedTimeChecker{getModifiedTime,
|
||||
m_filePathCache};
|
||||
ModifiedTimeChecker<ClangBackEnd::SourceTimeStamps> m_modifiedTimeChecker{m_fileSytem};
|
||||
SymbolIndexer m_indexer;
|
||||
SymbolIndexerTaskQueue m_indexerQueue;
|
||||
SymbolIndexerTaskScheduler m_indexerScheduler;
|
||||
|
@@ -24,6 +24,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
#include "googletest.h"
|
||||
#include "mockfilesystem.h"
|
||||
|
||||
#include <filepathcaching.h>
|
||||
#include <modifiedtimechecker.h>
|
||||
@@ -39,29 +40,24 @@ using ClangBackEnd::FilePathView;
|
||||
class ModifiedTimeChecker : public testing::Test
|
||||
{
|
||||
protected:
|
||||
|
||||
ClangBackEnd::FilePathId id(const Utils::SmallStringView &path) const
|
||||
{
|
||||
return filePathCache.filePathId(ClangBackEnd::FilePathView{path});
|
||||
}
|
||||
|
||||
|
||||
ModifiedTimeChecker()
|
||||
{
|
||||
ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path1")))).WillByDefault(Return(50));
|
||||
ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path2")))).WillByDefault(Return(30));
|
||||
ON_CALL(mockFileSystem, lastModified(Eq(1))).WillByDefault(Return(50));
|
||||
ON_CALL(mockFileSystem, lastModified(Eq(2))).WillByDefault(Return(30));
|
||||
ON_CALL(mockFileSystem, lastModified(Eq(3))).WillByDefault(Return(50));
|
||||
ON_CALL(mockFileSystem, lastModified(Eq(4))).WillByDefault(Return(30));
|
||||
}
|
||||
NiceMock<MockFunction<ClangBackEnd::TimeStamp(ClangBackEnd::FilePathView filePath)>> getModifiedTimeCallback;
|
||||
Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
|
||||
ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
|
||||
ClangBackEnd::FilePathCaching filePathCache{database};
|
||||
decltype(getModifiedTimeCallback.AsStdFunction()) callback = getModifiedTimeCallback
|
||||
.AsStdFunction();
|
||||
ClangBackEnd::ModifiedTimeChecker<> checker{callback, filePathCache};
|
||||
SourceEntries upToDateEntries = {{id("/path1"), SourceType::UserInclude, 100},
|
||||
{id("/path2"), SourceType::SystemInclude, 30}};
|
||||
SourceEntries notUpToDateEntries = {{id("/path1"), SourceType::UserInclude, 50},
|
||||
{id("/path2"), SourceType::SystemInclude, 20}};
|
||||
|
||||
NiceMock<MockFileSystem> mockFileSystem;
|
||||
ClangBackEnd::ModifiedTimeChecker<> checker{mockFileSystem};
|
||||
SourceEntries upToDateEntries = {{1, SourceType::UserInclude, 100},
|
||||
{2, SourceType::SystemInclude, 30},
|
||||
{3, SourceType::UserInclude, 100},
|
||||
{4, SourceType::SystemInclude, 30}};
|
||||
SourceEntries notUpToDateEntries = {{1, SourceType::UserInclude, 50},
|
||||
{2, SourceType::SystemInclude, 20},
|
||||
{3, SourceType::UserInclude, 100},
|
||||
{4, SourceType::SystemInclude, 30}};
|
||||
};
|
||||
|
||||
TEST_F(ModifiedTimeChecker, IsUpToDate)
|
||||
@@ -71,6 +67,15 @@ TEST_F(ModifiedTimeChecker, IsUpToDate)
|
||||
ASSERT_TRUE(isUpToDate);
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, IsUpToDateSecondRun)
|
||||
{
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
|
||||
auto isUpToDate = checker.isUpToDate(upToDateEntries);
|
||||
|
||||
ASSERT_TRUE(isUpToDate);
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, IsNotUpToDateIfSourceEntriesAreEmpty)
|
||||
{
|
||||
auto isUpToDate = checker.isUpToDate({});
|
||||
@@ -80,7 +85,16 @@ TEST_F(ModifiedTimeChecker, IsNotUpToDateIfSourceEntriesAreEmpty)
|
||||
|
||||
TEST_F(ModifiedTimeChecker, IsNotUpToDate)
|
||||
{
|
||||
auto isUpToDate = checker.isUpToDate({});
|
||||
auto isUpToDate = checker.isUpToDate(notUpToDateEntries);
|
||||
|
||||
ASSERT_FALSE(isUpToDate);
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, IsNotUpToDateSecondRun)
|
||||
{
|
||||
checker.isUpToDate(notUpToDateEntries);
|
||||
|
||||
auto isUpToDate = checker.isUpToDate(notUpToDateEntries);
|
||||
|
||||
ASSERT_FALSE(isUpToDate);
|
||||
}
|
||||
@@ -89,21 +103,80 @@ TEST_F(ModifiedTimeChecker, PathChangesUpdatesTimeStamps)
|
||||
{
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
|
||||
EXPECT_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path1"))));
|
||||
EXPECT_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path2"))));
|
||||
EXPECT_CALL(mockFileSystem, lastModified(Eq(2)));
|
||||
EXPECT_CALL(mockFileSystem, lastModified(Eq(3)));
|
||||
|
||||
checker.pathsChanged({id(FilePathView("/path1")), id(FilePathView("/path2")), id(FilePathView("/path3"))});
|
||||
checker.pathsChanged({2, 3});
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, IsNotUpToDateAnyMoreAfterUpdating)
|
||||
{
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path1")))).WillByDefault(Return(120));
|
||||
ON_CALL(getModifiedTimeCallback, Call(Eq(FilePathView("/path2")))).WillByDefault(Return(30));
|
||||
ON_CALL(mockFileSystem, lastModified(Eq(1))).WillByDefault(Return(120));
|
||||
ON_CALL(mockFileSystem, lastModified(Eq(2))).WillByDefault(Return(30));
|
||||
|
||||
checker.pathsChanged({id(FilePathView("/path1")), id(FilePathView("/path2")), id(FilePathView("/path3"))});
|
||||
checker.pathsChanged({1, 2, 3});
|
||||
|
||||
ASSERT_FALSE(checker.isUpToDate(upToDateEntries));
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, Reset)
|
||||
{
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
|
||||
checker.reset({2, 3});
|
||||
|
||||
ASSERT_FALSE(checker.isUpToDate(upToDateEntries));
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, UpdateNonResetedId)
|
||||
{
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
|
||||
checker.reset({2, 3});
|
||||
|
||||
ASSERT_TRUE(checker.isUpToDate({upToDateEntries[0]}));
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, ResetTwoTimes)
|
||||
{
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
checker.reset({2, 3});
|
||||
|
||||
checker.reset({2, 3});
|
||||
|
||||
ASSERT_FALSE(checker.isUpToDate(upToDateEntries));
|
||||
ASSERT_TRUE(checker.isUpToDate(upToDateEntries));
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, ResetSecondUpdate)
|
||||
{
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
checker.reset({2, 3});
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
|
||||
auto isUpToDate = checker.isUpToDate(upToDateEntries);
|
||||
|
||||
ASSERT_TRUE(isUpToDate);
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, ResetPartialUpdate)
|
||||
{
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
checker.reset({2, 3});
|
||||
checker.isUpToDate({upToDateEntries[1]});
|
||||
|
||||
ASSERT_FALSE(checker.isUpToDate({upToDateEntries[2]}));
|
||||
}
|
||||
|
||||
TEST_F(ModifiedTimeChecker, ResetMoreIds)
|
||||
{
|
||||
checker.isUpToDate(upToDateEntries);
|
||||
checker.reset({2, 3});
|
||||
|
||||
checker.reset({1, 5});
|
||||
|
||||
ASSERT_FALSE(checker.isUpToDate({upToDateEntries[2]}));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Reference in New Issue
Block a user