diff --git a/src/lib/data/storage/PersistentStorage.cpp b/src/lib/data/storage/PersistentStorage.cpp index 453b8fb8..073ff99b 100644 --- a/src/lib/data/storage/PersistentStorage.cpp +++ b/src/lib/data/storage/PersistentStorage.cpp @@ -344,18 +344,13 @@ void PersistentStorage::clearFileElements(const std::vector& filePaths } } -std::vector PersistentStorage::getFileInfoForAllIndexedFiles() const +std::vector PersistentStorage::getFileInfoForAllFiles() const { TRACE(); std::vector fileInfos; for (StorageFile file : m_sqliteIndexStorage.getAll()) { - if (!file.indexed) - { - continue; - } - boost::posix_time::ptime modificationTime = boost::posix_time::not_a_date_time; if (file.modificationTime != "not-a-date-time") { @@ -1471,7 +1466,22 @@ std::shared_ptr PersistentStorage::getFileContent(const FilePath& fi { TRACE(); - return m_sqliteIndexStorage.getFileContentByPath(filePath.wstr()); + std::shared_ptr fileContent = m_sqliteIndexStorage.getFileContentByPath(filePath.wstr()); + if (fileContent->getLineCount() > 0) + { + return fileContent; + } + return TextAccess::createFromFile(FilePath(filePath)); +} + +bool PersistentStorage::hasContentForFile(const FilePath& filePath) const +{ + std::shared_ptr fileContent = m_sqliteIndexStorage.getFileContentByPath(filePath.wstr()); + if (fileContent->getLineCount() > 0) + { + return true; + } + return false; } FileInfo PersistentStorage::getFileInfoForFileId(Id id) const diff --git a/src/lib/data/storage/PersistentStorage.h b/src/lib/data/storage/PersistentStorage.h index 6c601f00..960ead79 100644 --- a/src/lib/data/storage/PersistentStorage.h +++ b/src/lib/data/storage/PersistentStorage.h @@ -66,7 +66,7 @@ public: void clearAllErrors(); void clearFileElements(const std::vector& filePaths, std::function updateStatusCallback); - std::vector getFileInfoForAllIndexedFiles() const; + std::vector getFileInfoForAllFiles() const; std::set getIncompleteFiles() const; bool getFilePathIndexed(const FilePath& path) const; @@ -119,6 +119,7 @@ public: std::shared_ptr getCommentLocationsInFile(const FilePath& filePath) const override; std::shared_ptr getFileContent(const FilePath& filePath) const override; + bool hasContentForFile(const FilePath& filePath) const; FileInfo getFileInfoForFileId(Id id) const override; diff --git a/src/lib/data/storage/sqlite/SqliteIndexStorage.cpp b/src/lib/data/storage/sqlite/SqliteIndexStorage.cpp index 44708223..fd0bf685 100644 --- a/src/lib/data/storage/sqlite/SqliteIndexStorage.cpp +++ b/src/lib/data/storage/sqlite/SqliteIndexStorage.cpp @@ -811,7 +811,7 @@ std::shared_ptr SqliteIndexStorage::getFileContentByPath(const std:: LOG_ERROR(std::to_string(e.errorCode()) + ": " + e.errorMessage()); } - return TextAccess::createFromFile(FilePath(filePath)); + return TextAccess::createFromString(""); } void SqliteIndexStorage::setFileIndexed(Id fileId, bool indexed) diff --git a/src/lib/project/RefreshInfoGenerator.cpp b/src/lib/project/RefreshInfoGenerator.cpp index f952e79e..56b198ff 100644 --- a/src/lib/project/RefreshInfoGenerator.cpp +++ b/src/lib/project/RefreshInfoGenerator.cpp @@ -12,15 +12,15 @@ RefreshInfo RefreshInfoGenerator::getRefreshInfoForUpdatedFiles( const std::vector>& sourceGroups, std::shared_ptr storage) { - const std::set allSourceFilePathsFromSourcegroups = getAllSourceFilePaths(sourceGroups); - - std::set unchangedFilePaths; + // 1) Divide filepaths that are already known by the storage to "unchanged and indexed", "unchanged and non-indexed" and "changed" + std::set unchangedIndexedFilePaths; + std::set unchangedNonindexedFilePaths; std::set changedFilePaths; { - const std::vector fileInfosFromStorage = storage->getFileInfoForAllIndexedFiles(); + const std::vector fileInfosFromStorage = storage->getFileInfoForAllFiles(); - std::set alreadyIndexedPaths; + std::set alreadyKnownPaths; { const std::set filePathsFromStorage = utility::toSet(utility::convert( fileInfosFromStorage, [](const FileInfo& info) { return info.path; } @@ -28,24 +28,35 @@ RefreshInfo RefreshInfoGenerator::getRefreshInfoForUpdatedFiles( for (std::shared_ptr sourceGroup : sourceGroups) { - utility::append(alreadyIndexedPaths, sourceGroup->filterToContainedFilePaths(filePathsFromStorage)); + utility::append(alreadyKnownPaths, sourceGroup->filterToContainedFilePaths(filePathsFromStorage)); } } // checking source and header files for (const FileInfo& info : fileInfosFromStorage) { - if (alreadyIndexedPaths.find(info.path) != alreadyIndexedPaths.end() && info.path.exists()) + if (alreadyKnownPaths.find(info.path) != alreadyKnownPaths.end() && info.path.exists()) { - if (didFileChange(info, storage)) + if (storage->getFilePathIndexed(info.path)) { - changedFilePaths.insert(info.path); + if (didFileChange(info, storage)) + { + changedFilePaths.insert(info.path); + } + else + { + unchangedIndexedFilePaths.insert(info.path); + } } else { - unchangedFilePaths.insert(info.path); + changedFilePaths.insert(info.path); } } + else if (!storage->getFilePathIndexed(info.path) && !didFileChange(info, storage)) + { + unchangedNonindexedFilePaths.insert(info.path); + } else // file has been removed { changedFilePaths.insert(info.path); @@ -53,56 +64,68 @@ RefreshInfo RefreshInfoGenerator::getRefreshInfoForUpdatedFiles( } } + const std::set allSourceFilePathsFromSourcegroups = getAllSourceFilePaths(sourceGroups); + + // 2) Figure out which files need to be cleared + // 2.1) Add all changed files std::set filesToClear = changedFilePaths; - // handle referencing paths + // 2.2) Add files that are reference the changed files utility::append(filesToClear, storage->getReferencing(changedFilePaths)); - // handle referenced paths + // 2.3) Handle files that are referenced by the files that will be cleared. These will be re-indexed on the fly. However, we do not + // need to clear files that are also referenced by unchanged source files, because otherwise we will lose these connections. + // 2.3.1) Get all source file paths that will not be cleared. + // - Initially this list contains all source file paths the project would index right now. + // - Then we remove all source files that will be cleared + // - NOTE: Source files that are new to the project will part of this list, but won't result in any referenced + // paths because they are not part of the DB. Source files that are new to the project but are already in the + // DB will be removed from this list if they have changed or reference changed files. std::set staticSourceFiles = allSourceFilePathsFromSourcegroups; - for (const FilePath& path : changedFilePaths) + for (const FilePath& path : filesToClear) { staticSourceFiles.erase(path); } + // 2.3.2) Get sets of referenced files const std::set staticReferencedFilePaths = storage->getReferenced(staticSourceFiles); - const std::set dynamicReferencedFilePaths = storage->getReferenced(changedFilePaths); + const std::set dynamicReferencedFilePaths = storage->getReferenced(filesToClear); + // 2.3.3) Add "dynamicReferencedFilePaths" to "filesToClear" that are not refenced by static paths, because these files may not be + // referenced anymore. If they still are, they will be re-added when encountered during re-indexing. for (const FilePath& path : dynamicReferencedFilePaths) { if (staticReferencedFilePaths.find(path) == staticReferencedFilePaths.end() && staticSourceFiles.find(path) == staticSourceFiles.end()) { - // file may not be referenced anymore and will be reindexed if still needed filesToClear.insert(path); } } - for (const FilePath& path : unchangedFilePaths) - { - staticSourceFiles.erase(path); - } - - const std::set filesToAdd = staticSourceFiles; - - std::set staticSourceFilePaths; + // 3) Figure out which files need to be indexed + std::set filesToIndex; for (const FilePath& path : allSourceFilePathsFromSourcegroups) { - if (filesToClear.find(path) == filesToClear.end() && filesToAdd.find(path) == filesToAdd.end()) + if (filesToClear.find(path) != filesToClear.end() || // file will be cleared + unchangedIndexedFilePaths.find(path) == unchangedIndexedFilePaths.end()) // file has been changed or added { - staticSourceFilePaths.insert(path); + filesToIndex.insert(path); } } + // 4) Store and return this information RefreshInfo info; info.mode = REFRESH_UPDATED_FILES; - info.filesToClear = filesToClear; - - for (const std::shared_ptr& sourceGroup : sourceGroups) + info.filesToIndex = filesToIndex; + for (const FilePath fileToClear : filesToClear) { - if (sourceGroup->getStatus() == SOURCE_GROUP_STATUS_ENABLED) + if (storage->getFilePathIndexed(fileToClear)) { - utility::append(info.filesToIndex, sourceGroup->filterToContainedSourceFilePath(staticSourceFilePaths)); + info.filesToClear.insert(fileToClear); + } + else + { + info.nonIndexedFilesToClear.insert(fileToClear); } } @@ -115,11 +138,14 @@ RefreshInfo RefreshInfoGenerator::getRefreshInfoForIncompleteFiles(const std::ve info.mode = REFRESH_UPDATED_AND_INCOMPLETE_FILES; std::set incompleteFiles; - for (const FilePath& path : storage->getIncompleteFiles()) { - if (info.filesToClear.find(path) == info.filesToClear.end()) + const std::set filesToClear = utility::concat(info.filesToClear, info.nonIndexedFilesToClear); + for (const FilePath& path : storage->getIncompleteFiles()) { - incompleteFiles.insert(path); + if (filesToClear.find(path) == filesToClear.end()) + { + incompleteFiles.insert(path); + } } } @@ -188,24 +214,30 @@ bool RefreshInfoGenerator::didFileChange(const FileInfo& info, std::shared_ptr info.lastWriteTime) { + if (!storage->hasContentForFile(info.path)) + { + return true; + } + std::shared_ptr storedFileContent = storage->getFileContent(info.path); std::shared_ptr diskFileContent = TextAccess::createFromFile(diskFileInfo.path); const std::vector& diskFileLines = diskFileContent->getAllLines(); const std::vector& storedFileLines = storedFileContent->getAllLines(); - if (diskFileLines.size() == storedFileLines.size()) + if (diskFileLines.size() != storedFileLines.size()) { - for (size_t i = 0; i < diskFileLines.size(); i++) - { - if (diskFileLines[i] != storedFileLines[i]) - { - return true; - } - } - return false; + return true; } - return true; + + for (size_t i = 0; i < diskFileLines.size(); i++) + { + if (diskFileLines[i] != storedFileLines[i]) + { + return true; + } + } + return false; } return false; } diff --git a/src/lib/project/RefreshInfoGenerator.h b/src/lib/project/RefreshInfoGenerator.h index 1692875a..8ee8477b 100644 --- a/src/lib/project/RefreshInfoGenerator.h +++ b/src/lib/project/RefreshInfoGenerator.h @@ -15,12 +15,12 @@ class RefreshInfoGenerator { public: static RefreshInfo getRefreshInfoForUpdatedFiles( - const std::vector>& sourceGroups, + const std::vector>& sourceGroups, std::shared_ptr storage ); static RefreshInfo getRefreshInfoForIncompleteFiles( - const std::vector>& sourceGroups, + const std::vector>& sourceGroups, std::shared_ptr storage ); diff --git a/src/test/RefreshInfoGeneratorTestSuite.h b/src/test/RefreshInfoGeneratorTestSuite.h index a76149be..5e89b8c3 100644 --- a/src/test/RefreshInfoGeneratorTestSuite.h +++ b/src/test/RefreshInfoGeneratorTestSuite.h @@ -29,7 +29,7 @@ public: TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); } - void test_refresh_info_for_all_files_has_nothing_to_clear_and_specified_source_files_for_basic_sourcegroup() + void test_refresh_info_for_all_files_clears_nothing_and_indexes_previously_unknown_source_file() { cleanup(); { @@ -49,7 +49,7 @@ public: TS_ASSERT(utility::containsElement( utility::toVector(refreshInfo.filesToIndex), sourceFilePath - )); + )); } cleanup(); } @@ -79,14 +79,58 @@ public: cleanup(); } - void test_refresh_info_for_updated_files_indexes_previously_unknown_file() + // Now we will test how the refresh info generator reacts to different situations when generating refresh info for updated + // files. A file can have different states in the following dimensions: + // file may be known by the storage unknown / nonindexed / indexed + // file may be changed unchanged / changed + // file may be a source file sourcefile / headerfile + // file may now be indexed by the source group nottoindex / toindex + // + // We now wite a test case that checks for the expected result for every possible combination. + // Example: test_unknown_unchanged_sourcefile_that_is_nottoindex + + enum KnownState { + UNKNOWN, + NON_INDEXED, + INDEXED + }; + enum ChangedState + { + UNCHANGED, + CHANGED + }; + enum FileState + { + SOURCE_FILE, + HEADER_FILE + }; + enum IndexingState + { + NOT_TO_INDEX, + TO_INDEX + }; + + RefreshInfo getRefreshInfo(KnownState knownState, ChangedState changedState, FileState fileState, IndexingState indexingState) + { + RefreshInfo refreshInfo; cleanup(); { - const FilePath unknownSourceFilePath = m_sourceFolder.getConcatenated(L"unknown_file.cpp"); + const FilePath filePath = m_sourceFolder.getConcatenated(L"file.extension"); + + const std::set sourceFilePaths = ((fileState == SOURCE_FILE) ? std::set({ filePath }) : std::set({})); + const std::set allFilePaths = { filePath }; std::vector> sourceGroups; - sourceGroups.push_back(std::shared_ptr(new SourceGroupTest({ unknownSourceFilePath }))); + if (indexingState == NOT_TO_INDEX) + { + // a file is "not existing" if the source group does not care about it + sourceGroups.push_back(std::shared_ptr(new SourceGroupTest({}, {}))); + } + else // if (indexingState == TO_INDEX) + { + sourceGroups.push_back(std::shared_ptr(new SourceGroupTest(sourceFilePaths, allFilePaths))); + } std::shared_ptr storage = std::make_shared( m_indexDbPath, @@ -94,123 +138,263 @@ public: ); storage->setup(); + if (knownState == UNKNOWN) + { + // do not add anything to storage + } + else if (knownState == NON_INDEXED) + { + if (changedState == UNCHANGED) + { + addVeryNewFileToStorage(filePath, false, true, storage); + } + else // if (changedState == CHANGED) + { + addVeryOldFileToStorage(filePath, false, true, storage); + } + } + else // if (knownState == INDEXED) + { + if (changedState == UNCHANGED) + { + addVeryNewFileToStorage(filePath, true, true, storage); + } + else // if (changedState == CHANGED) + { + addVeryOldFileToStorage(filePath, true, true, storage); + } + } + + addFileToFileSystem(filePath); + storage->buildCaches(); - const RefreshInfo refreshInfo = RefreshInfoGenerator::getRefreshInfoForUpdatedFiles(sourceGroups, storage); - - TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); - TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); - TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); - TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); - - TS_ASSERT(utility::containsElement( - utility::toVector(refreshInfo.filesToIndex), unknownSourceFilePath - )); + refreshInfo = RefreshInfoGenerator::getRefreshInfoForUpdatedFiles(sourceGroups, storage); } cleanup(); + + return refreshInfo; } - void test_refresh_info_for_updated_files_clears_non_existing_file() + void test_unknown_unchanged_sourcefile_that_is_nottoindex() { - cleanup(); - { - const FilePath nonexistingSourceFilePath = m_sourceFolder.getConcatenated(L"non_existing_file.cpp"); - - std::vector> sourceGroups; - sourceGroups.push_back(std::shared_ptr(new SourceGroupTest({}))); - - std::shared_ptr storage = std::make_shared( - m_indexDbPath, - m_bookmarkDbPath - ); - storage->setup(); - - addVeryOldFileToStorage(nonexistingSourceFilePath, true, true, storage); - - storage->buildCaches(); - - const RefreshInfo refreshInfo = RefreshInfoGenerator::getRefreshInfoForUpdatedFiles(sourceGroups, storage); - - TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); - TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); - TS_ASSERT_EQUALS(1, refreshInfo.filesToClear.size()); - TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); - - TS_ASSERT(utility::containsElement( - utility::toVector(refreshInfo.filesToClear), nonexistingSourceFilePath - )); - } - cleanup(); + const RefreshInfo refreshInfo = getRefreshInfo(UNKNOWN, UNCHANGED, SOURCE_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); } - void test_refresh_info_for_updated_files_clears_and_indexes_outdated_file() + void test_unknown_unchanged_sourcefile_that_is_toindex() { - cleanup(); - { - const FilePath outdatedSourceFilePath = m_sourceFolder.getConcatenated(L"outdated_file.cpp"); - - std::vector> sourceGroups; - sourceGroups.push_back(std::shared_ptr(new SourceGroupTest({ outdatedSourceFilePath }))); - - std::shared_ptr storage = std::make_shared( - m_indexDbPath, - m_bookmarkDbPath - ); - storage->setup(); - - addVeryOldFileToStorage(outdatedSourceFilePath, true, true, storage); - addFileToFileSystem(outdatedSourceFilePath); - - storage->buildCaches(); - - const RefreshInfo refreshInfo = RefreshInfoGenerator::getRefreshInfoForUpdatedFiles(sourceGroups, storage); - - TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); - TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); - TS_ASSERT_EQUALS(1, refreshInfo.filesToClear.size()); - TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); - - TS_ASSERT(utility::containsElement( - utility::toVector(refreshInfo.filesToClear), outdatedSourceFilePath - )); - TS_ASSERT(utility::containsElement( - utility::toVector(refreshInfo.filesToIndex), outdatedSourceFilePath - )); - } - cleanup(); + const RefreshInfo refreshInfo = getRefreshInfo(UNKNOWN, UNCHANGED, SOURCE_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); } - void test_refresh_info_for_updated_files_keeps_up_to_date_file() + void test_unknown_unchanged_headerfile_that_is_nottoindex() { - cleanup(); - { - const FilePath upToDateSourceFilePath = m_sourceFolder.getConcatenated(L"up_to_date_file.cpp"); - - std::vector> sourceGroups; - sourceGroups.push_back(std::shared_ptr(new SourceGroupTest({ upToDateSourceFilePath }))); - - std::shared_ptr storage = std::make_shared( - m_indexDbPath, - m_bookmarkDbPath - ); - storage->setup(); - - addVeryNewFileToStorage(upToDateSourceFilePath, true, true, storage); - addFileToFileSystem(upToDateSourceFilePath); - - storage->buildCaches(); - - const RefreshInfo refreshInfo = RefreshInfoGenerator::getRefreshInfoForUpdatedFiles(sourceGroups, storage); - - TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); - TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); - TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); - TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); - } - cleanup(); + const RefreshInfo refreshInfo = getRefreshInfo(UNKNOWN, UNCHANGED, HEADER_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); } - void test_refresh_info_for_updated_files_clears_and_reindexes_outdated_file_and_referencing_source_file() + void test_unknown_unchanged_headerfile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(UNKNOWN, UNCHANGED, HEADER_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); // the header file will only be indexed on demand + } + + void test_unknown_changed_sourcefile_that_is_nottoindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(UNKNOWN, CHANGED, SOURCE_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_unknown_changed_sourcefile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(UNKNOWN, CHANGED, SOURCE_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); + } + + void test_unknown_changed_headerfile_that_is_nottoindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(UNKNOWN, CHANGED, HEADER_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_unknown_changed_headerfile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(UNKNOWN, CHANGED, HEADER_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); // the header file will only be indexed on demand + } + + void test_nonindexed_unchanged_sourcefile_that_is_nottoindex() // this test does not really make sense + { + const RefreshInfo refreshInfo = getRefreshInfo(NON_INDEXED, UNCHANGED, SOURCE_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_nonindexed_unchanged_sourcefile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(NON_INDEXED, UNCHANGED, SOURCE_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(1, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); + } + + void test_nonindexed_unchanged_headerfile_that_is_nottoindex() // this test does not make much sense without source files + { + const RefreshInfo refreshInfo = getRefreshInfo(NON_INDEXED, UNCHANGED, HEADER_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_nonindexed_unchanged_headerfile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(NON_INDEXED, UNCHANGED, HEADER_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(1, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); // the header file will only be indexed on demand + } + + void test_nonindexed_changed_sourcefile_that_is_nottoindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(NON_INDEXED, CHANGED, SOURCE_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(1, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_nonindexed_changed_sourcefile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(NON_INDEXED, CHANGED, SOURCE_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(1, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); + } + + void test_nonindexed_changed_headerfile_that_is_nottoindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(NON_INDEXED, CHANGED, HEADER_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(1, refreshInfo.nonIndexedFilesToClear.size()); // must be cleard here and will be re-indexed on demand + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_nonindexed_changed_headerfile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(NON_INDEXED, CHANGED, HEADER_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(1, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); // the header file will only be indexed on demand + } + + void test_indexed_unchanged_sourcefile_that_is_nottoindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(INDEXED, UNCHANGED, SOURCE_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_indexed_unchanged_sourcefile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(INDEXED, UNCHANGED, SOURCE_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_indexed_unchanged_headerfile_that_is_nottoindex() // TODO: check if depending source file gets reindexed + { + const RefreshInfo refreshInfo = getRefreshInfo(INDEXED, UNCHANGED, HEADER_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_indexed_unchanged_headerfile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(INDEXED, UNCHANGED, HEADER_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_indexed_changed_sourcefile_that_is_nottoindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(INDEXED, CHANGED, SOURCE_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_indexed_changed_sourcefile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(INDEXED, CHANGED, SOURCE_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); + } + + void test_indexed_changed_headerfile_that_is_nottoindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(INDEXED, CHANGED, HEADER_FILE, NOT_TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + + void test_indexed_changed_headerfile_that_is_toindex() + { + const RefreshInfo refreshInfo = getRefreshInfo(INDEXED, CHANGED, HEADER_FILE, TO_INDEX); + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); // the header file will only be indexed on demand + } + + // Now we test some referencing stuff + + void test_refresh_info_for_updated_files_clears_and_reindexes_known_outdated_file_and_referencing_source_file() { cleanup(); { @@ -261,7 +445,7 @@ public: cleanup(); } - void test_refresh_info_for_updated_files_clears_outdated_header_file_and_reindexes_referencing_source() + void test_refresh_info_for_updated_files_clears_known_outdated_header_file_and_reindexes_referencing_source_file() { cleanup(); { @@ -269,13 +453,15 @@ public: const FilePath outdatedHeaderFilePath = m_sourceFolder.getConcatenated(L"outdated_file.h"); std::vector> sourceGroups; - sourceGroups.push_back(std::shared_ptr(new SourceGroupTest({ - upToDateSourceFilePath - }, - { - upToDateSourceFilePath, - outdatedHeaderFilePath - }))); + sourceGroups.push_back(std::shared_ptr(new SourceGroupTest( + { + upToDateSourceFilePath + }, + { + upToDateSourceFilePath, + outdatedHeaderFilePath + } + ))); std::shared_ptr storage = std::make_shared( m_indexDbPath, @@ -312,6 +498,92 @@ public: cleanup(); } + void test_refresh_info_for_updated_files_clears_unknown_outdated_header_file_and_reindexes_referencing_source() + { + cleanup(); + { + const FilePath upToDateSourceFilePath = m_sourceFolder.getConcatenated(L"up_to_date_file.cpp"); + const FilePath outdatedHeaderFilePath = m_sourceFolder.getConcatenated(L"outdated_file.h"); + + std::vector> sourceGroups; + sourceGroups.push_back(std::shared_ptr(new SourceGroupTest({ + upToDateSourceFilePath + }))); + + std::shared_ptr storage = std::make_shared( + m_indexDbPath, + m_bookmarkDbPath + ); + storage->setup(); + + const Id upToDateSourceFileId = addVeryNewFileToStorage(upToDateSourceFilePath, true, true, storage); + addFileToFileSystem(upToDateSourceFilePath); + const Id outdatedHeaderFileId = addVeryOldFileToStorage(outdatedHeaderFilePath, false, true, storage); + addFileToFileSystem(outdatedHeaderFilePath); + + storage->addEdge(StorageEdgeData(Edge::EDGE_INCLUDE, upToDateSourceFileId, outdatedHeaderFileId)); + + storage->buildCaches(); + + const RefreshInfo refreshInfo = RefreshInfoGenerator::getRefreshInfoForUpdatedFiles(sourceGroups, storage); + + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(1, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); + + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.filesToClear), upToDateSourceFilePath + )); + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.nonIndexedFilesToClear), outdatedHeaderFilePath + )); + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.filesToIndex), upToDateSourceFilePath + )); + } + cleanup(); + } + + void test_refresh_info_for_updated_files_does_not_clear_unknown_uptodate_header_file() + { + cleanup(); + { + const FilePath upToDateSourceFilePath = m_sourceFolder.getConcatenated(L"up_to_date_file.cpp"); + const FilePath upToDateHeaderFilePath = m_sourceFolder.getConcatenated(L"up_to_date_file.h"); + + std::vector> sourceGroups; + sourceGroups.push_back(std::shared_ptr(new SourceGroupTest( + { + upToDateSourceFilePath + } + ))); + + std::shared_ptr storage = std::make_shared( + m_indexDbPath, + m_bookmarkDbPath + ); + storage->setup(); + + const Id upToDateSourceFileId = addVeryNewFileToStorage(upToDateSourceFilePath, true, true, storage); + addFileToFileSystem(upToDateSourceFilePath); + const Id upToDateHeaderFileId = addVeryNewFileToStorage(upToDateHeaderFilePath, false, true, storage); + addFileToFileSystem(upToDateHeaderFilePath); + + storage->addEdge(StorageEdgeData(Edge::EDGE_INCLUDE, upToDateSourceFileId, upToDateHeaderFileId)); + + storage->buildCaches(); + + const RefreshInfo refreshInfo = RefreshInfoGenerator::getRefreshInfoForUpdatedFiles(sourceGroups, storage); + + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(0, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(0, refreshInfo.filesToIndex.size()); + } + cleanup(); + } + void test_refresh_info_for_updated_files_clears_outdated_source_file_and_referened_uptodate_header_file() { cleanup(); @@ -417,6 +689,122 @@ public: cleanup(); } + void test_clears_unchanged_files_referenced_by_unchanged_file_that_referenced_changed_indexed_file() + { + cleanup(); + { + const FilePath upToDateSourceFilePath = m_sourceFolder.getConcatenated(L"up_to_date_file.cpp"); + const FilePath upToDateHeaderFilePath = m_sourceFolder.getConcatenated(L"up_to_date_file.h"); + const FilePath outOfDateHeaderFilePath = m_sourceFolder.getConcatenated(L"out_of_date_file.h"); + + std::vector> sourceGroups; + sourceGroups.push_back(std::shared_ptr(new SourceGroupTest({ + upToDateSourceFilePath + }, + { + upToDateSourceFilePath, + outOfDateHeaderFilePath, + }))); + + std::shared_ptr storage = std::make_shared( + m_indexDbPath, + m_bookmarkDbPath + ); + storage->setup(); + + const Id upToDateSourceFileId = addVeryNewFileToStorage(upToDateSourceFilePath, true, true, storage); + addFileToFileSystem(upToDateSourceFilePath); + const Id upToDateHeaderFileId = addVeryNewFileToStorage(upToDateHeaderFilePath, false, true, storage); + addFileToFileSystem(upToDateHeaderFilePath); + const Id outOfDateHeaderFileId = addVeryOldFileToStorage(outOfDateHeaderFilePath, true, true, storage); + addFileToFileSystem(outOfDateHeaderFilePath); + + storage->addEdge(StorageEdgeData(Edge::EDGE_INCLUDE, upToDateSourceFileId, upToDateHeaderFileId)); + storage->addEdge(StorageEdgeData(Edge::EDGE_INCLUDE, upToDateSourceFileId, outOfDateHeaderFileId)); + + storage->buildCaches(); + + const RefreshInfo refreshInfo = RefreshInfoGenerator::getRefreshInfoForUpdatedFiles(sourceGroups, storage); + + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(1, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(2, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); + + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.nonIndexedFilesToClear), upToDateHeaderFilePath + )); + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.filesToClear), upToDateSourceFilePath + )); + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.filesToClear), outOfDateHeaderFilePath + )); + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.filesToIndex), upToDateSourceFilePath + )); + } + cleanup(); + } + + void test_clears_unchanged_files_referenced_by_unchanged_file_that_referenced_changed_nonindexed_file() + { + cleanup(); + { + const FilePath upToDateSourceFilePath = m_sourceFolder.getConcatenated(L"up_to_date_file.cpp"); + const FilePath upToDateHeaderFilePath = m_sourceFolder.getConcatenated(L"up_to_date_file.h"); + const FilePath outOfDateHeaderFilePath = m_sourceFolder.getConcatenated(L"out_of_date_file.h"); + + std::vector> sourceGroups; + sourceGroups.push_back(std::shared_ptr(new SourceGroupTest({ + upToDateSourceFilePath + }, + { + upToDateSourceFilePath, + upToDateHeaderFilePath, + }))); + + std::shared_ptr storage = std::make_shared( + m_indexDbPath, + m_bookmarkDbPath + ); + storage->setup(); + + const Id upToDateSourceFileId = addVeryNewFileToStorage(upToDateSourceFilePath, true, true, storage); + addFileToFileSystem(upToDateSourceFilePath); + const Id upToDateHeaderFileId = addVeryNewFileToStorage(upToDateHeaderFilePath, true, true, storage); + addFileToFileSystem(upToDateHeaderFilePath); + const Id outOfDateHeaderFileId = addVeryOldFileToStorage(outOfDateHeaderFilePath, false, true, storage); + addFileToFileSystem(outOfDateHeaderFilePath); + + storage->addEdge(StorageEdgeData(Edge::EDGE_INCLUDE, upToDateSourceFileId, upToDateHeaderFileId)); + storage->addEdge(StorageEdgeData(Edge::EDGE_INCLUDE, upToDateSourceFileId, outOfDateHeaderFileId)); + + storage->buildCaches(); + + const RefreshInfo refreshInfo = RefreshInfoGenerator::getRefreshInfoForUpdatedFiles(sourceGroups, storage); + + TS_ASSERT_EQUALS(REFRESH_UPDATED_FILES, refreshInfo.mode); + TS_ASSERT_EQUALS(1, refreshInfo.nonIndexedFilesToClear.size()); + TS_ASSERT_EQUALS(2, refreshInfo.filesToClear.size()); + TS_ASSERT_EQUALS(1, refreshInfo.filesToIndex.size()); + + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.nonIndexedFilesToClear), outOfDateHeaderFilePath + )); + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.filesToClear), upToDateSourceFilePath + )); + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.filesToClear), upToDateHeaderFilePath + )); + TS_ASSERT(utility::containsElement( + utility::toVector(refreshInfo.filesToIndex), upToDateSourceFilePath + )); + } + cleanup(); + } + private: class SourceGroupSettingsTest : public SourceGroupSettings { diff --git a/testing/project_setup/cpp_empty/checklist.txt b/testing/project_setup/cpp_empty/checklist.txt index 7de27dbb..0058e7eb 100644 --- a/testing/project_setup/cpp_empty/checklist.txt +++ b/testing/project_setup/cpp_empty/checklist.txt @@ -25,7 +25,7 @@ * Click "Cancel" * Run "2_update.sh" * Press "Refresh" button -* Validate "Files to clear" shows "2" +* Validate "Files to clear" shows "3" * Validate "source files to index" shows "1" * Click "Start" * Validate Project indexed without error diff --git a/testing/project_setup/cxx_cbp/checklist.txt b/testing/project_setup/cxx_cbp/checklist.txt index 25923fea..6273fa37 100644 --- a/testing/project_setup/cxx_cbp/checklist.txt +++ b/testing/project_setup/cxx_cbp/checklist.txt @@ -24,7 +24,7 @@ * Click "Cancel" * Run "2_update.sh" * Press "Refresh" button -* Validate "Files to clear" shows "2" +* Validate "Files to clear" shows "3" * Validate "source files to index" shows "1" * Click "Start" * Validate Project indexed without error diff --git a/testing/project_setup/cxx_cdb/checklist.txt b/testing/project_setup/cxx_cdb/checklist.txt index 3f689aa0..b09bb972 100644 --- a/testing/project_setup/cxx_cdb/checklist.txt +++ b/testing/project_setup/cxx_cdb/checklist.txt @@ -24,7 +24,7 @@ * Click "Cancel" * Run "2_update.sh" * Press "Refresh" button -* Validate "Files to clear" shows "2" +* Validate "Files to clear" shows "3" * Validate "source files to index" shows "1" * Click "Start" * Validate Project indexed without error diff --git a/testing/project_setup/cxx_sonargraph_manual/checklist.txt b/testing/project_setup/cxx_sonargraph_manual/checklist.txt index b54983ac..3a722d65 100644 --- a/testing/project_setup/cxx_sonargraph_manual/checklist.txt +++ b/testing/project_setup/cxx_sonargraph_manual/checklist.txt @@ -23,7 +23,7 @@ * Click "Cancel" * Run "2_update.sh" * Press "Refresh" button -* Validate "Files to clear" shows "2" +* Validate "Files to clear" shows "3" * Validate "source files to index" shows "1" * Click "Start" * Validate Project indexed without error