forked from qt-creator/qt-creator
		
	We optimal indexer is only reindexing if the index would be changed. This patch is a step in that direction. We only reindex now if the file or project has changed. It fixes some typos too. Task-number: QTCREATORBUG-21150 Change-Id: I6ea1c13282fbcd70253b9b2939aed37580dbd160 Reviewed-by: Ivan Donchevskii <ivan.donchevskii@qt.io>
		
			
				
	
	
		
			528 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			528 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/****************************************************************************
 | 
						|
**
 | 
						|
** Copyright (C) 2018 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 "mocksqlitedatabase.h"
 | 
						|
 | 
						|
#include <builddependenciesstorage.h>
 | 
						|
#include <projectpartsstorage.h>
 | 
						|
#include <refactoringdatabaseinitializer.h>
 | 
						|
#include <sqlitedatabase.h>
 | 
						|
#include <sqlitereadstatement.h>
 | 
						|
#include <sqlitewritestatement.h>
 | 
						|
#include <symbolstorage.h>
 | 
						|
namespace {
 | 
						|
 | 
						|
using ClangBackEnd::FilePathId;
 | 
						|
using ClangBackEnd::IncludeSearchPath;
 | 
						|
using ClangBackEnd::IncludeSearchPaths;
 | 
						|
using ClangBackEnd::IncludeSearchPathType;
 | 
						|
using ClangBackEnd::ProjectPartId;
 | 
						|
using ClangBackEnd::ProjectPartIds;
 | 
						|
 | 
						|
class Data
 | 
						|
{
 | 
						|
protected:
 | 
						|
    ClangBackEnd::ProjectPartContainer projectPart1{1,
 | 
						|
                                                    {"-m32"},
 | 
						|
                                                    {{"FOO", "1", 1}},
 | 
						|
                                                    {{"/include", 1, IncludeSearchPathType::System}},
 | 
						|
                                                    {{"/home/yi", 2, IncludeSearchPathType::User}},
 | 
						|
                                                    {1, 2},
 | 
						|
                                                    {3, 4},
 | 
						|
                                                    Utils::Language::Cxx,
 | 
						|
                                                    Utils::LanguageVersion::CXX14,
 | 
						|
                                                    Utils::LanguageExtension::Microsoft};
 | 
						|
    ClangBackEnd::ProjectPartContainer projectPart2{2,
 | 
						|
                                                    {"-m64"},
 | 
						|
                                                    {{"BAR", "2", 1}},
 | 
						|
                                                    {{"/usr/include", 1, IncludeSearchPathType::System}},
 | 
						|
                                                    {{"/home/er", 2, IncludeSearchPathType::User}},
 | 
						|
                                                    {5, 6},
 | 
						|
                                                    {7, 8},
 | 
						|
                                                    Utils::Language::C,
 | 
						|
                                                    Utils::LanguageVersion::C11,
 | 
						|
                                                    Utils::LanguageExtension::Gnu};
 | 
						|
};
 | 
						|
 | 
						|
class ProjectPartsStorage : public testing::Test, public Data
 | 
						|
{
 | 
						|
    using Storage = ClangBackEnd::ProjectPartsStorage<MockSqliteDatabase>;
 | 
						|
 | 
						|
protected:
 | 
						|
    ProjectPartsStorage()
 | 
						|
    {
 | 
						|
        ON_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(1)))
 | 
						|
            .WillByDefault(Return(projectPart1));
 | 
						|
        ON_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(2)))
 | 
						|
            .WillByDefault(Return(projectPart2));
 | 
						|
        ON_CALL(fetchProjectPartsHeadersByIdStatement, valuesReturnFilePathIds(_, Eq(1)))
 | 
						|
            .WillByDefault(Return(projectPart1.headerPathIds));
 | 
						|
        ON_CALL(fetchProjectPartsHeadersByIdStatement, valuesReturnFilePathIds(_, Eq(2)))
 | 
						|
            .WillByDefault(Return(projectPart2.headerPathIds));
 | 
						|
        ON_CALL(fetchProjectPartsSourcesByIdStatement, valuesReturnFilePathIds(_, Eq(1)))
 | 
						|
            .WillByDefault(Return(projectPart1.sourcePathIds));
 | 
						|
        ON_CALL(fetchProjectPartsSourcesByIdStatement, valuesReturnFilePathIds(_, Eq(2)))
 | 
						|
            .WillByDefault(Return(projectPart2.sourcePathIds));
 | 
						|
    }
 | 
						|
    NiceMock<MockSqliteDatabase> mockDatabase;
 | 
						|
    Storage storage{mockDatabase};
 | 
						|
    MockSqliteReadStatement &fetchProjectPartIdStatement = storage.fetchProjectPartIdStatement;
 | 
						|
    MockSqliteWriteStatement &insertProjectPartNameStatement = storage.insertProjectPartNameStatement;
 | 
						|
    MockSqliteReadStatement &fetchProjectPartNameStatement = storage.fetchProjectPartNameStatement;
 | 
						|
    MockSqliteReadStatement &fetchProjectPartsStatement = storage.fetchProjectPartsStatement;
 | 
						|
    MockSqliteReadStatement &fetchProjectPartByIdStatement = storage.fetchProjectPartByIdStatement;
 | 
						|
    MockSqliteWriteStatement &updateProjectPartStatement = storage.updateProjectPartStatement;
 | 
						|
    MockSqliteReadStatement &getProjectPartArtefactsBySourceId = storage.getProjectPartArtefactsBySourceId;
 | 
						|
    MockSqliteReadStatement &getProjectPartArtefactsByProjectPartId = storage.getProjectPartArtefactsByProjectPartId;
 | 
						|
    MockSqliteWriteStatement &deleteProjectPartsHeadersByIdStatement = storage.deleteProjectPartsHeadersByIdStatement;
 | 
						|
    MockSqliteWriteStatement &deleteProjectPartsSourcesByIdStatement = storage.deleteProjectPartsSourcesByIdStatement;
 | 
						|
    MockSqliteWriteStatement &insertProjectPartsHeadersStatement = storage.insertProjectPartsHeadersStatement;
 | 
						|
    MockSqliteWriteStatement &insertProjectPartsSourcesStatement = storage.insertProjectPartsSourcesStatement;
 | 
						|
    MockSqliteReadStatement &fetchProjectPartsHeadersByIdStatement = storage.fetchProjectPartsHeadersByIdStatement;
 | 
						|
    MockSqliteReadStatement &fetchProjectPartsSourcesByIdStatement = storage.fetchProjectPartsSourcesByIdStatement;
 | 
						|
    MockSqliteReadStatement &fetchProjectPrecompiledHeaderPathStatement = storage.fetchProjectPrecompiledHeaderPathStatement;
 | 
						|
    MockSqliteWriteStatement &resetDependentIndexingTimeStampsStatement = storage.resetDependentIndexingTimeStampsStatement;
 | 
						|
    IncludeSearchPaths systemIncludeSearchPaths{{"/includes", 1, IncludeSearchPathType::BuiltIn},
 | 
						|
                                                {"/other/includes", 2, IncludeSearchPathType::System}};
 | 
						|
    IncludeSearchPaths projectIncludeSearchPaths{{"/project/includes", 1, IncludeSearchPathType::User},
 | 
						|
                                                 {"/other/project/includes",
 | 
						|
                                                  2,
 | 
						|
                                                  IncludeSearchPathType::User}};
 | 
						|
    Utils::SmallString systemIncludeSearchPathsText{R"([["/includes",1,2],["/other/includes",2,3]])"};
 | 
						|
    Utils::SmallString projectIncludeSearchPathsText{
 | 
						|
        R"([["/project/includes",1,1],["/other/project/includes",2,1]])"};
 | 
						|
    ClangBackEnd::ProjectPartArtefact artefact{R"(["-DFOO"])",
 | 
						|
                                               R"([["FOO","1",1]])",
 | 
						|
                                               systemIncludeSearchPathsText,
 | 
						|
                                               projectIncludeSearchPathsText,
 | 
						|
                                               74,
 | 
						|
                                               Utils::Language::Cxx,
 | 
						|
                                               Utils::LanguageVersion::CXX11,
 | 
						|
                                               Utils::LanguageExtension::None};
 | 
						|
};
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, CallsFetchProjectIdWithNonExistingProjectPartName)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartIdStatement,
 | 
						|
                valueReturnProjectPartId(TypedEq<Utils::SmallStringView>("test")));
 | 
						|
    EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq<Utils::SmallStringView>("test")));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.fetchProjectPartId("test");
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, CallsFetchProjectIdWithExistingProjectPart)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartIdStatement,
 | 
						|
                valueReturnProjectPartId(TypedEq<Utils::SmallStringView>("test")))
 | 
						|
        .WillOnce(Return(Utils::optional<ProjectPartId>{20}));
 | 
						|
    EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq<Utils::SmallStringView>("test"))).Times(0);
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.fetchProjectPartId("test");
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, CallsFetchProjectIdWithBusyDatabaset)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartIdStatement,
 | 
						|
                valueReturnProjectPartId(TypedEq<Utils::SmallStringView>("test")));
 | 
						|
    EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq<Utils::SmallStringView>("test")))
 | 
						|
        .WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
 | 
						|
    EXPECT_CALL(mockDatabase, rollback());
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartIdStatement,
 | 
						|
                valueReturnProjectPartId(TypedEq<Utils::SmallStringView>("test")));
 | 
						|
    EXPECT_CALL(insertProjectPartNameStatement, write(TypedEq<Utils::SmallStringView>("test")));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.fetchProjectPartId("test");
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectIdWithNonExistingProjectPartName)
 | 
						|
{
 | 
						|
    ON_CALL(fetchProjectPartIdStatement,
 | 
						|
            valueReturnProjectPartId(TypedEq<Utils::SmallStringView>("test")))
 | 
						|
        .WillByDefault(Return(Utils::optional<ProjectPartId>{}));
 | 
						|
    ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(21));
 | 
						|
 | 
						|
    auto id = storage.fetchProjectPartId("test");
 | 
						|
 | 
						|
    ASSERT_THAT(id.projectPathId, 21);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectIdWithNonExistingProjectPartNameAndIsBusy)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
    EXPECT_CALL(fetchProjectPartIdStatement,
 | 
						|
                valueReturnProjectPartId(TypedEq<Utils::SmallStringView>("test")))
 | 
						|
        .WillOnce(Throw(Sqlite::StatementIsBusy("busy")));
 | 
						|
    EXPECT_CALL(fetchProjectPartIdStatement,
 | 
						|
                valueReturnProjectPartId(TypedEq<Utils::SmallStringView>("test")))
 | 
						|
        .WillOnce(Return(ClangBackEnd::ProjectPartId{21}));
 | 
						|
    ON_CALL(mockDatabase, lastInsertedRowId()).WillByDefault(Return(21));
 | 
						|
 | 
						|
    auto id = storage.fetchProjectPartId("test");
 | 
						|
 | 
						|
    ASSERT_THAT(id.projectPathId, 21);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectIdWithExistingProjectPartName)
 | 
						|
{
 | 
						|
    ON_CALL(fetchProjectPartIdStatement,
 | 
						|
            valueReturnProjectPartId(TypedEq<Utils::SmallStringView>("test")))
 | 
						|
        .WillByDefault(Return(Utils::optional<ProjectPartId>{20}));
 | 
						|
 | 
						|
    auto id = storage.fetchProjectPartId("test");
 | 
						|
 | 
						|
    ASSERT_THAT(id.projectPathId, 20);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartName)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartNameStatement, valueReturnPathString(TypedEq<int>(12)))
 | 
						|
        .WillOnce(Return(Utils::optional<Utils::PathString>{"test"}));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.fetchProjectPartName(12);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartNameStatementIsBusy)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartNameStatement, valueReturnPathString(TypedEq<int>(12)))
 | 
						|
        .WillOnce(Throw(Sqlite::StatementIsBusy{""}));
 | 
						|
    EXPECT_CALL(mockDatabase, rollback());
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartNameStatement, valueReturnPathString(TypedEq<int>(12)))
 | 
						|
        .WillOnce(Return(Utils::optional<Utils::PathString>{"test"}));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.fetchProjectPartName(12);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectParts)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartsStatement, valuesReturnProjectPartContainers(4096));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.fetchProjectParts();
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartsByIds)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(1)));
 | 
						|
    EXPECT_CALL(fetchProjectPartsHeadersByIdStatement, valuesReturnFilePathIds(1024, Eq(1)));
 | 
						|
    EXPECT_CALL(fetchProjectPartsSourcesByIdStatement, valuesReturnFilePathIds(1024, Eq(1)));
 | 
						|
    EXPECT_CALL(fetchProjectPrecompiledHeaderPathStatement, valueReturnSmallString(Eq(1)));
 | 
						|
    EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(2)));
 | 
						|
    EXPECT_CALL(fetchProjectPartsHeadersByIdStatement, valuesReturnFilePathIds(1024, Eq(2)));
 | 
						|
    EXPECT_CALL(fetchProjectPartsSourcesByIdStatement, valuesReturnFilePathIds(1024, Eq(2)));
 | 
						|
    EXPECT_CALL(fetchProjectPrecompiledHeaderPathStatement, valueReturnSmallString(Eq(2)));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.fetchProjectParts({1, 2});
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartsByIdsIsBusy)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(1)));
 | 
						|
    EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(2)))
 | 
						|
        .WillOnce(Throw(Sqlite::StatementIsBusy{""}));
 | 
						|
    EXPECT_CALL(mockDatabase, rollback());
 | 
						|
    EXPECT_CALL(mockDatabase, deferredBegin());
 | 
						|
    EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(1)));
 | 
						|
    EXPECT_CALL(fetchProjectPartByIdStatement, valueReturnProjectPartContainer(Eq(2)));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.fetchProjectParts({1, 2});
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartsByIdsHasPrecompiledNullOptional)
 | 
						|
{
 | 
						|
    ON_CALL(fetchProjectPrecompiledHeaderPathStatement, valueReturnSmallString(Eq(1)))
 | 
						|
        .WillByDefault(Return(Utils::optional<Utils::SmallString>{}));
 | 
						|
 | 
						|
    auto projectParts = storage.fetchProjectParts({1});
 | 
						|
 | 
						|
    ASSERT_FALSE(projectParts.front().hasPrecompiledHeader);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartsByIdsHasPrecompiledEmptyString)
 | 
						|
{
 | 
						|
    ON_CALL(fetchProjectPrecompiledHeaderPathStatement, valueReturnSmallString(Eq(1)))
 | 
						|
        .WillByDefault(Return(Utils::optional<Utils::SmallString>{""}));
 | 
						|
 | 
						|
    auto projectParts = storage.fetchProjectParts({1});
 | 
						|
 | 
						|
    ASSERT_FALSE(projectParts.front().hasPrecompiledHeader);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartsByIdsHasPrecompiledStringWithContent)
 | 
						|
{
 | 
						|
    ON_CALL(fetchProjectPrecompiledHeaderPathStatement, valueReturnSmallString(Eq(1)))
 | 
						|
        .WillByDefault(Return(Utils::optional<Utils::SmallString>{"/some/path"}));
 | 
						|
 | 
						|
    auto projectParts = storage.fetchProjectParts({1});
 | 
						|
 | 
						|
    ASSERT_TRUE(projectParts.front().hasPrecompiledHeader);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartsByIdsHasMissingId)
 | 
						|
{
 | 
						|
    auto projectParts = storage.fetchProjectParts({1, 2, 3});
 | 
						|
 | 
						|
    ASSERT_THAT(projectParts, ElementsAre(projectPart1, projectPart2));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, ConvertStringsToJson)
 | 
						|
{
 | 
						|
    Utils::SmallStringVector strings{"foo", "bar", "foo"};
 | 
						|
 | 
						|
    auto jsonText = storage.toJson(strings);
 | 
						|
 | 
						|
    ASSERT_THAT(jsonText, Eq("[\"foo\",\"bar\",\"foo\"]"));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, UpdateProjectParts)
 | 
						|
{
 | 
						|
    InSequence sequence;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, immediateBegin());
 | 
						|
    EXPECT_CALL(updateProjectPartStatement,
 | 
						|
                write(TypedEq<int>(1),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"(["-m32"])"),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"([["FOO","1",1]])"),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"([["/include",1,3]])"),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"([["/home/yi",2,1]])"),
 | 
						|
                      2,
 | 
						|
                      35,
 | 
						|
                      2));
 | 
						|
    EXPECT_CALL(deleteProjectPartsHeadersByIdStatement, write(TypedEq<int>(1)));
 | 
						|
    EXPECT_CALL(insertProjectPartsHeadersStatement, write(TypedEq<int>(1), TypedEq<int>(1)));
 | 
						|
    EXPECT_CALL(insertProjectPartsHeadersStatement, write(TypedEq<int>(1), TypedEq<int>(2)));
 | 
						|
    EXPECT_CALL(deleteProjectPartsSourcesByIdStatement, write(TypedEq<int>(1)));
 | 
						|
    EXPECT_CALL(insertProjectPartsSourcesStatement, write(TypedEq<int>(1), TypedEq<int>(3)));
 | 
						|
    EXPECT_CALL(insertProjectPartsSourcesStatement, write(TypedEq<int>(1), TypedEq<int>(4)));
 | 
						|
    EXPECT_CALL(updateProjectPartStatement,
 | 
						|
                write(TypedEq<int>(2),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"(["-m64"])"),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"([["BAR","2",1]])"),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"([["/usr/include",1,3]])"),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"([["/home/er",2,1]])"),
 | 
						|
                      1,
 | 
						|
                      3,
 | 
						|
                      1));
 | 
						|
    EXPECT_CALL(deleteProjectPartsHeadersByIdStatement, write(TypedEq<int>(2)));
 | 
						|
    EXPECT_CALL(insertProjectPartsHeadersStatement, write(TypedEq<int>(2), TypedEq<int>(5)));
 | 
						|
    EXPECT_CALL(insertProjectPartsHeadersStatement, write(TypedEq<int>(2), TypedEq<int>(6)));
 | 
						|
    EXPECT_CALL(deleteProjectPartsSourcesByIdStatement, write(TypedEq<int>(2)));
 | 
						|
    EXPECT_CALL(insertProjectPartsSourcesStatement, write(TypedEq<int>(2), TypedEq<int>(7)));
 | 
						|
    EXPECT_CALL(insertProjectPartsSourcesStatement, write(TypedEq<int>(2), TypedEq<int>(8)));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.updateProjectParts({projectPart1, projectPart2});
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, UpdateProjectPartsIsBusy)
 | 
						|
{
 | 
						|
    InSequence sequence;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""}));
 | 
						|
    EXPECT_CALL(mockDatabase, immediateBegin());
 | 
						|
    EXPECT_CALL(updateProjectPartStatement,
 | 
						|
                write(TypedEq<int>(1),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"(["-m32"])"),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"([["FOO","1",1]])"),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"([["/include",1,3]])"),
 | 
						|
                      TypedEq<Utils::SmallStringView>(R"([["/home/yi",2,1]])"),
 | 
						|
                      2,
 | 
						|
                      35,
 | 
						|
                      2));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.updateProjectParts({projectPart1});
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartArtefactBySourceIdCallsValueInStatement)
 | 
						|
{
 | 
						|
    EXPECT_CALL(getProjectPartArtefactsBySourceId, valueReturnProjectPartArtefact(1))
 | 
						|
        .WillRepeatedly(Return(artefact));
 | 
						|
 | 
						|
    storage.fetchProjectPartArtefact(FilePathId{1});
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartArtefactBySourceIdReturnArtefact)
 | 
						|
{
 | 
						|
    EXPECT_CALL(getProjectPartArtefactsBySourceId, valueReturnProjectPartArtefact(1))
 | 
						|
        .WillRepeatedly(Return(artefact));
 | 
						|
 | 
						|
    auto result = storage.fetchProjectPartArtefact(FilePathId{1});
 | 
						|
 | 
						|
    ASSERT_THAT(result, Eq(artefact));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartArtefactByProjectPartIdCallsValueInStatement)
 | 
						|
{
 | 
						|
    EXPECT_CALL(getProjectPartArtefactsByProjectPartId, valueReturnProjectPartArtefact(74))
 | 
						|
        .WillRepeatedly(Return(artefact));
 | 
						|
 | 
						|
    storage.fetchProjectPartArtefact(ProjectPartId{74});
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, FetchProjectPartArtefactByProjectPartIdReturnArtefact)
 | 
						|
{
 | 
						|
    EXPECT_CALL(getProjectPartArtefactsByProjectPartId, valueReturnProjectPartArtefact(74))
 | 
						|
        .WillRepeatedly(Return(artefact));
 | 
						|
 | 
						|
    auto result = storage.fetchProjectPartArtefact(ProjectPartId{74});
 | 
						|
 | 
						|
    ASSERT_THAT(result, Eq(artefact));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, ResetDependentIndexingTimeStamps)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, immediateBegin());
 | 
						|
    EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(3)));
 | 
						|
    EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(4)));
 | 
						|
    EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(7)));
 | 
						|
    EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(8)));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.resetIndexingTimeStamps({projectPart1, projectPart2});
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorage, ResetDependentIndexingTimeStampsIsBusy)
 | 
						|
{
 | 
						|
    InSequence s;
 | 
						|
 | 
						|
    EXPECT_CALL(mockDatabase, immediateBegin()).WillOnce(Throw(Sqlite::StatementIsBusy{""}));
 | 
						|
    EXPECT_CALL(mockDatabase, immediateBegin());
 | 
						|
    EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(3)));
 | 
						|
    EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(4)));
 | 
						|
    EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(7)));
 | 
						|
    EXPECT_CALL(resetDependentIndexingTimeStampsStatement, write(TypedEq<int>(8)));
 | 
						|
    EXPECT_CALL(mockDatabase, commit());
 | 
						|
 | 
						|
    storage.resetIndexingTimeStamps({projectPart1, projectPart2});
 | 
						|
}
 | 
						|
 | 
						|
class ProjectPartsStorageSlow : public testing::Test, public Data
 | 
						|
{
 | 
						|
    using Storage = ClangBackEnd::ProjectPartsStorage<Sqlite::Database>;
 | 
						|
 | 
						|
protected:
 | 
						|
    Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
 | 
						|
    ClangBackEnd::RefactoringDatabaseInitializer<Sqlite::Database> databaseInitializer{database};
 | 
						|
    Storage storage{database};
 | 
						|
    ClangBackEnd::SymbolStorage<> symbolStorage{database};
 | 
						|
    ClangBackEnd::BuildDependenciesStorage<> buildDependenciesStorage{database};
 | 
						|
};
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorageSlow, FetchProjectPartName)
 | 
						|
{
 | 
						|
    auto id = storage.fetchProjectPartId("test");
 | 
						|
 | 
						|
    auto name = storage.fetchProjectPartName(id);
 | 
						|
 | 
						|
    ASSERT_THAT(name, "test");
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorageSlow, FetchNonExistingProjectPartName)
 | 
						|
{
 | 
						|
    ASSERT_THROW(storage.fetchProjectPartName(ClangBackEnd::ProjectPartId{1}),
 | 
						|
                 ClangBackEnd::ProjectPartDoesNotExists);
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorageSlow, FetchProjectPartId)
 | 
						|
{
 | 
						|
    auto first = storage.fetchProjectPartId("test");
 | 
						|
 | 
						|
    auto second = storage.fetchProjectPartId("test");
 | 
						|
 | 
						|
    ASSERT_THAT(first, Eq(second));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorageSlow, FetchProjectParts)
 | 
						|
{
 | 
						|
    projectPart1.projectPartId = storage.fetchProjectPartId("project1");
 | 
						|
    projectPart2.projectPartId = storage.fetchProjectPartId("project2");
 | 
						|
    storage.updateProjectParts({projectPart1, projectPart2});
 | 
						|
 | 
						|
    auto projectParts = storage.fetchProjectParts(
 | 
						|
        {projectPart1.projectPartId, projectPart2.projectPartId});
 | 
						|
 | 
						|
    ASSERT_THAT(projectParts, ElementsAre(projectPart1, projectPart2));
 | 
						|
}
 | 
						|
 | 
						|
TEST_F(ProjectPartsStorageSlow, ResetDependentIndexingTimeStamps)
 | 
						|
{
 | 
						|
    symbolStorage.insertOrUpdateIndexingTimeStamps({1, 2, 3, 4, 5, 6, 7, 8, 9, 10}, 34);
 | 
						|
    buildDependenciesStorage.insertOrUpdateSourceDependencies(
 | 
						|
        {{3, 1}, {4, 1}, {1, 2}, {7, 5}, {8, 6}, {6, 5}, {9, 10}});
 | 
						|
 | 
						|
    storage.resetIndexingTimeStamps({projectPart1, projectPart2});
 | 
						|
 | 
						|
    ASSERT_THAT(symbolStorage.fetchIndexingTimeStamps(),
 | 
						|
                ElementsAre(SourceTimeStamp{1, 0},
 | 
						|
                            SourceTimeStamp{2, 0},
 | 
						|
                            SourceTimeStamp{3, 0},
 | 
						|
                            SourceTimeStamp{4, 0},
 | 
						|
                            SourceTimeStamp{5, 0},
 | 
						|
                            SourceTimeStamp{6, 0},
 | 
						|
                            SourceTimeStamp{7, 0},
 | 
						|
                            SourceTimeStamp{8, 0},
 | 
						|
                            SourceTimeStamp{9, 34},
 | 
						|
                            SourceTimeStamp{10, 34}));
 | 
						|
}
 | 
						|
 | 
						|
} // namespace
 |