forked from qt-creator/qt-creator
QmlDesigner: Add project storage
Task-number: QDS-4252 Change-Id: Ic74e027b20bc41f3712e3ae155cddc64f8972cb0 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 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 <vector>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
template<auto Type, typename InternalIntergerType = long long>
|
||||
class BasicId
|
||||
{
|
||||
public:
|
||||
using DatabaseType = InternalIntergerType;
|
||||
|
||||
constexpr explicit BasicId() = default;
|
||||
|
||||
BasicId(const char *) = delete;
|
||||
|
||||
constexpr explicit BasicId(InternalIntergerType id)
|
||||
: id{id}
|
||||
{}
|
||||
|
||||
constexpr friend bool operator==(BasicId first, BasicId second)
|
||||
{
|
||||
return first.id == second.id && first.isValid() && second.isValid();
|
||||
}
|
||||
|
||||
constexpr friend bool operator!=(BasicId first, BasicId second) { return !(first == second); }
|
||||
|
||||
constexpr friend bool operator<(BasicId first, BasicId second) { return first.id < second.id; }
|
||||
constexpr friend bool operator>(BasicId first, BasicId second) { return first.id > second.id; }
|
||||
constexpr friend bool operator<=(BasicId first, BasicId second)
|
||||
{
|
||||
return first.id <= second.id;
|
||||
}
|
||||
constexpr friend bool operator>=(BasicId first, BasicId second)
|
||||
{
|
||||
return first.id >= second.id;
|
||||
}
|
||||
|
||||
constexpr bool isValid() const { return id >= 0; }
|
||||
|
||||
explicit operator bool() const { return isValid(); }
|
||||
|
||||
explicit operator std::size_t() const { return static_cast<std::size_t>(id); }
|
||||
|
||||
InternalIntergerType operator&() const { return id; }
|
||||
|
||||
public:
|
||||
InternalIntergerType id = -1;
|
||||
};
|
||||
|
||||
enum class BasicIdType {
|
||||
Type,
|
||||
PropertyType,
|
||||
PropertyDeclaration,
|
||||
SourceId,
|
||||
SourceContextId,
|
||||
StorageCacheIndex
|
||||
};
|
||||
|
||||
using TypeId = BasicId<BasicIdType::Type>;
|
||||
using TypeIds = std::vector<TypeId>;
|
||||
|
||||
using PropertyDeclarationId = BasicId<BasicIdType::PropertyDeclaration>;
|
||||
using PropertyDeclarationIds = std::vector<PropertyDeclarationId>;
|
||||
|
||||
using SourceContextId = BasicId<BasicIdType::SourceContextId, int>;
|
||||
using SourceContextIds = std::vector<SourceContextId>;
|
||||
|
||||
using SourceId = BasicId<BasicIdType::SourceId, int>;
|
||||
using SourceIds = std::vector<SourceId>;
|
||||
|
||||
enum class TypeAccessSemantics { Reference, Value, Sequence, IsEnum = 0xF };
|
||||
|
||||
} // namespace QmlDesigner
|
||||
446
src/plugins/qmldesigner/designercore/metainfo/projectstorage.h
Normal file
446
src/plugins/qmldesigner/designercore/metainfo/projectstorage.h
Normal file
@@ -0,0 +1,446 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 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 "projectstorageexceptions.h"
|
||||
#include "projectstorageids.h"
|
||||
#include "projectstoragetypes.h"
|
||||
|
||||
#include <sqlitetable.h>
|
||||
#include <sqlitetransaction.h>
|
||||
|
||||
#include <utils/optional.h>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
template<typename Database>
|
||||
class ProjectStorage
|
||||
{
|
||||
public:
|
||||
template<int ResultCount>
|
||||
using ReadStatement = typename Database::template ReadStatement<ResultCount>;
|
||||
template<int ResultCount>
|
||||
using ReadWriteStatement = typename Database::template ReadWriteStatement<ResultCount>;
|
||||
using WriteStatement = typename Database::WriteStatement;
|
||||
|
||||
ProjectStorage(Database &database, bool isInitialized)
|
||||
: database{database}
|
||||
, initializer{database, isInitialized}
|
||||
{}
|
||||
|
||||
template<typename Container>
|
||||
TypeId upsertType(Utils::SmallStringView name,
|
||||
TypeId prototype,
|
||||
TypeAccessSemantics accessSemantics,
|
||||
const Container &qualifiedNames)
|
||||
{
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
|
||||
auto typeId = upsertTypeStatement.template value<TypeId>(name,
|
||||
static_cast<long long>(accessSemantics),
|
||||
&prototype);
|
||||
|
||||
for (Utils::SmallStringView qualifiedName : qualifiedNames)
|
||||
upsertQualifiedTypeNameStatement.write(qualifiedName, &typeId);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return typeId;
|
||||
}
|
||||
|
||||
PropertyDeclarationId upsertPropertyDeclaration(TypeId typeId,
|
||||
Utils::SmallStringView name,
|
||||
TypeId propertyTypeId)
|
||||
{
|
||||
Sqlite::ImmediateTransaction transaction{database};
|
||||
|
||||
auto propertyDeclarationId = upsertPropertyDeclarationStatement
|
||||
.template value<PropertyDeclarationId>(&typeId,
|
||||
name,
|
||||
&propertyTypeId);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return propertyDeclarationId;
|
||||
}
|
||||
|
||||
PropertyDeclarationId fetchPropertyDeclarationByTypeIdAndName(TypeId typeId,
|
||||
Utils::SmallStringView name)
|
||||
{
|
||||
return selectPropertyDeclarationByTypeIdAndNameStatement
|
||||
.template valueWithTransaction<PropertyDeclarationId>(&typeId, name);
|
||||
}
|
||||
|
||||
TypeId fetchTypeIdByQualifiedName(Utils::SmallStringView name)
|
||||
{
|
||||
return selectTypeIdByQualifiedNameStatement.template valueWithTransaction<TypeId>(name);
|
||||
}
|
||||
|
||||
bool fetchIsProtype(TypeId type, TypeId prototype)
|
||||
{
|
||||
return bool(
|
||||
selectPrototypeIdStatement.template valueWithTransaction<TypeId>(&type, &prototype));
|
||||
}
|
||||
|
||||
auto fetchPrototypes(TypeId type)
|
||||
{
|
||||
return selectPrototypeIdsStatement.template rangeWithTransaction<TypeId>(&type);
|
||||
}
|
||||
|
||||
SourceContextId fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath)
|
||||
{
|
||||
auto sourceContextId = readSourceContextId(sourceContextPath);
|
||||
|
||||
return sourceContextId ? sourceContextId : writeSourceContextId(sourceContextPath);
|
||||
}
|
||||
|
||||
SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath)
|
||||
{
|
||||
try {
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto sourceContextId = fetchSourceContextIdUnguarded(sourceContextPath);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return sourceContextId;
|
||||
} catch (const Sqlite::ConstraintPreventsModification &) {
|
||||
return fetchSourceContextId(sourceContextPath);
|
||||
}
|
||||
}
|
||||
|
||||
Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const
|
||||
{
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement
|
||||
.template optionalValue<Utils::PathString>(
|
||||
&sourceContextId);
|
||||
|
||||
if (!optionalSourceContextPath)
|
||||
throw SourceContextIdDoesNotExists();
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return std::move(*optionalSourceContextPath);
|
||||
}
|
||||
|
||||
auto fetchAllSourceContexts() const
|
||||
{
|
||||
return selectAllSourceContextsStatement.template rangeWithTransaction<Sources::SourceContext>();
|
||||
}
|
||||
|
||||
SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
|
||||
{
|
||||
Sqlite::DeferredTransaction transaction{database};
|
||||
|
||||
auto sourceId = fetchSourceIdUnguarded(sourceContextId, sourceName);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
return sourceId;
|
||||
}
|
||||
|
||||
Sources::SourceNameAndSourceContextId fetchSourceNameAndSourceContextId(SourceId sourceId) const
|
||||
{
|
||||
auto value = selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement
|
||||
.template valueWithTransaction<Sources::SourceNameAndSourceContextId>(
|
||||
&sourceId);
|
||||
|
||||
if (!value.sourceContextId)
|
||||
throw SourceIdDoesNotExists();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
SourceContextId fetchSourceContextId(SourceId sourceId) const
|
||||
{
|
||||
auto sourceContextId = selectSourceContextIdFromSourcesBySourceIdStatement
|
||||
.template valueWithTransaction<SourceContextId>(sourceId.id);
|
||||
|
||||
if (!sourceContextId)
|
||||
throw SourceIdDoesNotExists();
|
||||
|
||||
return sourceContextId;
|
||||
}
|
||||
|
||||
auto fetchAllSources() const
|
||||
{
|
||||
return selectAllSourcesStatement.template rangeWithTransaction<Sources::Source>();
|
||||
}
|
||||
|
||||
SourceId fetchSourceIdUnguarded(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
|
||||
{
|
||||
auto sourceId = readSourceId(sourceContextId, sourceName);
|
||||
|
||||
if (sourceId)
|
||||
return sourceId;
|
||||
|
||||
return writeSourceId(sourceContextId, sourceName);
|
||||
}
|
||||
|
||||
private:
|
||||
SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath)
|
||||
{
|
||||
return selectSourceContextIdFromSourceContextsBySourceContextPathStatement
|
||||
.template value<SourceContextId>(sourceContextPath);
|
||||
}
|
||||
|
||||
SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath)
|
||||
{
|
||||
insertIntoSourceContextsStatement.write(sourceContextPath);
|
||||
|
||||
return SourceContextId(database.lastInsertedRowId());
|
||||
}
|
||||
|
||||
SourceId writeSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
|
||||
{
|
||||
insertIntoSourcesStatement.write(&sourceContextId, sourceName);
|
||||
|
||||
return SourceId(database.lastInsertedRowId());
|
||||
}
|
||||
|
||||
SourceId readSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
|
||||
{
|
||||
return selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement
|
||||
.template value<SourceId>(&sourceContextId, sourceName);
|
||||
}
|
||||
|
||||
class Initializer
|
||||
{
|
||||
public:
|
||||
Initializer(Database &database, bool isInitialized)
|
||||
{
|
||||
if (!isInitialized) {
|
||||
Sqlite::ExclusiveTransaction transaction{database};
|
||||
|
||||
createTypesTable(database);
|
||||
createQualifiedTypeNamesTable(database);
|
||||
createPropertyDeclarationsTable(database);
|
||||
createEnumValuesTable(database);
|
||||
createMethodsTable(database);
|
||||
createSignalsTable(database);
|
||||
createSourceContextsTable(database);
|
||||
createSourcesTable(database);
|
||||
|
||||
transaction.commit();
|
||||
|
||||
database.walCheckpointFull();
|
||||
}
|
||||
}
|
||||
|
||||
void createPropertyDeclarationsTable(Database &database)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("propertyDeclarations");
|
||||
table.addColumn("propertyDeclarationId",
|
||||
Sqlite::ColumnType::Integer,
|
||||
{Sqlite::PrimaryKey{}});
|
||||
auto &typeIdColumn = table.addColumn("typeId");
|
||||
auto &nameColumn = table.addColumn("name");
|
||||
table.addColumn("propertyTypeId");
|
||||
|
||||
table.addUniqueIndex({typeIdColumn, nameColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
void createTypesTable(Database &database)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("types");
|
||||
table.addColumn("typeId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
auto &nameColumn = table.addColumn("name");
|
||||
table.addColumn("accessSemantics");
|
||||
table.addColumn("prototype");
|
||||
table.addColumn("defaultProperty");
|
||||
|
||||
table.addUniqueIndex({nameColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
void createQualifiedTypeNamesTable(Database &database)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setUseWithoutRowId(true);
|
||||
table.setName("qualifiedTypeNames");
|
||||
auto &qualifiedNameColumn = table.addColumn("qualifiedName");
|
||||
table.addColumn("typeId");
|
||||
|
||||
table.addPrimaryKeyContraint({qualifiedNameColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
void createEnumValuesTable(Database &database)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("enumerationValues");
|
||||
table.addColumn("enumerationValueId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
auto &enumIdColumn = table.addColumn("typeId");
|
||||
auto &nameColumn = table.addColumn("name");
|
||||
|
||||
table.addUniqueIndex({enumIdColumn, nameColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
void createMethodsTable(Database &database)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("methods");
|
||||
table.addColumn("methodId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
auto &nameColumn = table.addColumn("name");
|
||||
|
||||
table.addUniqueIndex({nameColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
void createSignalsTable(Database &database)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("signals");
|
||||
table.addColumn("signalId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
auto &nameColumn = table.addColumn("name");
|
||||
|
||||
table.addUniqueIndex({nameColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
void createSourceContextsTable(Database &database)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("sourceContexts");
|
||||
table.addColumn("sourceContextId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
const Sqlite::Column &sourceContextPathColumn = table.addColumn("sourceContextPath");
|
||||
|
||||
table.addUniqueIndex({sourceContextPathColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
|
||||
void createSourcesTable(Database &database)
|
||||
{
|
||||
Sqlite::Table table;
|
||||
table.setUseIfNotExists(true);
|
||||
table.setName("sources");
|
||||
table.addColumn("sourceId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}});
|
||||
const Sqlite::Column &sourceContextIdColumn = table.addColumn(
|
||||
"sourceContextId",
|
||||
Sqlite::ColumnType::Integer,
|
||||
{Sqlite::NotNull{},
|
||||
Sqlite::ForeignKey{"sourceContexts",
|
||||
"sourceContextId",
|
||||
Sqlite::ForeignKeyAction::NoAction,
|
||||
Sqlite::ForeignKeyAction::Cascade}});
|
||||
const Sqlite::Column &sourceNameColumn = table.addColumn("sourceName",
|
||||
Sqlite::ColumnType::Text);
|
||||
table.addUniqueIndex({sourceContextIdColumn, sourceNameColumn});
|
||||
|
||||
table.initialize(database);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
Database &database;
|
||||
Initializer initializer;
|
||||
ReadWriteStatement<1> upsertTypeStatement{
|
||||
"INSERT INTO types(name, accessSemantics, prototype) VALUES(?1, ?2, nullif(?3, -1)) ON "
|
||||
"CONFLICT DO UPDATE SET "
|
||||
"prototype=excluded.prototype, accessSemantics=excluded.accessSemantics RETURNING typeId",
|
||||
database};
|
||||
mutable ReadStatement<1> selectTypeIdByQualifiedNameStatement{
|
||||
"SELECT typeId FROM qualifiedTypeNames WHERE qualifiedName=?", database};
|
||||
mutable ReadStatement<1> selectPrototypeIdStatement{
|
||||
"WITH RECURSIVE "
|
||||
" typeSelection(typeId) AS ("
|
||||
" VALUES(?1) "
|
||||
" UNION ALL "
|
||||
" SELECT prototype FROM types JOIN typeSelection USING(typeId)) "
|
||||
"SELECT typeId FROM typeSelection WHERE typeId=?2 LIMIT 1",
|
||||
database};
|
||||
ReadWriteStatement<1> upsertPropertyDeclarationStatement{
|
||||
"INSERT INTO propertyDeclarations(typeId, name, propertyTypeId) VALUES(?1, ?2, ?3) ON "
|
||||
"CONFLICT DO UPDATE SET "
|
||||
"typeId=excluded.typeId, name=excluded.name, propertyTypeId=excluded.propertyTypeId "
|
||||
"RETURNING propertyDeclarationId",
|
||||
database};
|
||||
mutable ReadStatement<1> selectPropertyDeclarationByTypeIdAndNameStatement{
|
||||
"WITH RECURSIVE "
|
||||
" typeSelection(typeId) AS ("
|
||||
" VALUES(?1) "
|
||||
" UNION ALL "
|
||||
" SELECT prototype FROM types JOIN typeSelection USING(typeId)) "
|
||||
"SELECT propertyDeclarationId FROM propertyDeclarations JOIN typeSelection USING(typeId) "
|
||||
" WHERE name=?2 LIMIT 1",
|
||||
database};
|
||||
WriteStatement upsertQualifiedTypeNameStatement{
|
||||
"INSERT INTO qualifiedTypeNames(qualifiedName, typeId) VALUES(?1, ?2) ON CONFLICT DO "
|
||||
"UPDATE SET typeId=excluded.typeId",
|
||||
database};
|
||||
mutable ReadStatement<1> selectAccessSemanticsStatement{
|
||||
"SELECT typeId FROM qualifiedTypeNames WHERE qualifiedName=?", database};
|
||||
mutable ReadStatement<1> selectPrototypeIdsStatement{
|
||||
"WITH RECURSIVE "
|
||||
" typeSelection(typeId) AS ("
|
||||
" VALUES(?1) "
|
||||
" UNION ALL "
|
||||
" SELECT prototype FROM types JOIN typeSelection USING(typeId)) "
|
||||
"SELECT typeId FROM typeSelection",
|
||||
database};
|
||||
mutable ReadStatement<1> selectSourceContextIdFromSourceContextsBySourceContextPathStatement{
|
||||
"SELECT sourceContextId FROM sourceContexts WHERE sourceContextPath = ?", database};
|
||||
mutable ReadStatement<1> selectSourceContextPathFromSourceContextsBySourceContextIdStatement{
|
||||
"SELECT sourceContextPath FROM sourceContexts WHERE sourceContextId = ?", database};
|
||||
mutable ReadStatement<2> selectAllSourceContextsStatement{
|
||||
"SELECT sourceContextPath, sourceContextId FROM sourceContexts", database};
|
||||
WriteStatement insertIntoSourceContextsStatement{
|
||||
"INSERT INTO sourceContexts(sourceContextPath) VALUES (?)", database};
|
||||
mutable ReadStatement<1> selectSourceIdFromSourcesBySourceContextIdAndSourceNameStatement{
|
||||
"SELECT sourceId FROM sources WHERE sourceContextId = ? AND sourceName = ?", database};
|
||||
mutable ReadStatement<2> selectSourceNameAndSourceContextIdFromSourcesBySourceIdStatement{
|
||||
"SELECT sourceName, sourceContextId FROM sources WHERE sourceId = ?", database};
|
||||
mutable ReadStatement<1> selectSourceContextIdFromSourcesBySourceIdStatement{
|
||||
"SELECT sourceContextId FROM sources WHERE sourceId = ?", database};
|
||||
WriteStatement insertIntoSourcesStatement{
|
||||
"INSERT INTO sources(sourceContextId, sourceName) VALUES (?,?)", database};
|
||||
mutable ReadStatement<3> selectAllSourcesStatement{
|
||||
"SELECT sourceName, sourceContextId, sourceId FROM sources", database};
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,68 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class NoFilePathForInvalidFilePathId : std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
return "You cannot get a file path for an invalid file path id!";
|
||||
}
|
||||
};
|
||||
|
||||
class NoSourceContextPathForInvalidSourceContextId : std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
return "You cannot get a directory path for an invalid directory path id!";
|
||||
}
|
||||
};
|
||||
|
||||
class SourceContextIdDoesNotExists : std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
return "The source context id does not exist in the database!";
|
||||
}
|
||||
};
|
||||
|
||||
class SourceIdDoesNotExists : std::exception
|
||||
{
|
||||
public:
|
||||
const char *what() const noexcept override
|
||||
{
|
||||
return "The source id does not exist in the database!";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,167 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "projectstorageids.h"
|
||||
#include "storagecacheentry.h"
|
||||
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class FileNameView
|
||||
{
|
||||
public:
|
||||
friend bool operator==(const FileNameView &first, const FileNameView &second)
|
||||
{
|
||||
return first.sourceContextId == second.sourceContextId && first.fileName == second.fileName;
|
||||
}
|
||||
|
||||
static int compare(FileNameView first, FileNameView second) noexcept
|
||||
{
|
||||
int directoryDifference = first.sourceContextId.id - second.sourceContextId.id;
|
||||
|
||||
if (directoryDifference)
|
||||
return directoryDifference;
|
||||
|
||||
return Utils::compare(first.fileName, second.fileName);
|
||||
}
|
||||
|
||||
public:
|
||||
Utils::SmallStringView fileName;
|
||||
SourceContextId sourceContextId;
|
||||
};
|
||||
|
||||
class FileNameEntry
|
||||
{
|
||||
public:
|
||||
FileNameEntry(Utils::SmallStringView fileName, int sourceContextId)
|
||||
: fileName(fileName)
|
||||
, sourceContextId(sourceContextId)
|
||||
{}
|
||||
|
||||
FileNameEntry(Utils::SmallStringView fileName, SourceContextId sourceContextId)
|
||||
: fileName(fileName)
|
||||
, sourceContextId(sourceContextId)
|
||||
{}
|
||||
|
||||
FileNameEntry(FileNameView view)
|
||||
: fileName(view.fileName)
|
||||
, sourceContextId(view.sourceContextId)
|
||||
{}
|
||||
|
||||
friend bool operator==(const FileNameEntry &first, const FileNameEntry &second)
|
||||
{
|
||||
return first.sourceContextId == second.sourceContextId && first.fileName == second.fileName;
|
||||
}
|
||||
|
||||
friend bool operator!=(const FileNameEntry &first, const FileNameEntry &second)
|
||||
{
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
friend bool operator==(const FileNameEntry &first, const FileNameView &second)
|
||||
{
|
||||
return first.sourceContextId == second.sourceContextId && first.fileName == second.fileName;
|
||||
}
|
||||
|
||||
friend bool operator!=(const FileNameEntry &first, const FileNameView &second)
|
||||
{
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
operator FileNameView() const { return {fileName, sourceContextId}; }
|
||||
|
||||
operator Utils::SmallString() && { return std::move(fileName); }
|
||||
|
||||
public:
|
||||
Utils::SmallString fileName;
|
||||
SourceContextId sourceContextId;
|
||||
};
|
||||
|
||||
namespace Sources {
|
||||
class SourceContext
|
||||
: public StorageCacheEntry<Utils::PathString, Utils::SmallStringView, SourceContextId>
|
||||
{
|
||||
using Base = StorageCacheEntry<Utils::PathString, Utils::SmallStringView, SourceContextId>;
|
||||
|
||||
public:
|
||||
using Base::Base;
|
||||
|
||||
friend bool operator==(const SourceContext &first, const SourceContext &second)
|
||||
{
|
||||
return first.id == second.id && first.value == second.value;
|
||||
}
|
||||
};
|
||||
|
||||
using SourceContexts = std::vector<SourceContext>;
|
||||
|
||||
class Source : public StorageCacheEntry<FileNameEntry, FileNameView, SourceId>
|
||||
{
|
||||
using Base = StorageCacheEntry<FileNameEntry, FileNameView, SourceId>;
|
||||
|
||||
public:
|
||||
using Base::Base;
|
||||
Source(Utils::SmallStringView sourceName, SourceContextId sourceContextId, SourceId sourceId)
|
||||
: Base{{sourceName, sourceContextId}, sourceId}
|
||||
{}
|
||||
|
||||
Source(Utils::SmallStringView sourceName, int sourceContextId, int sourceId)
|
||||
: Base{{sourceName, SourceContextId{sourceContextId}}, SourceId{sourceId}}
|
||||
{}
|
||||
|
||||
friend bool operator==(const Source &first, const Source &second)
|
||||
{
|
||||
return first.id == second.id && first.value == second.value;
|
||||
}
|
||||
};
|
||||
|
||||
using Sources = std::vector<Source>;
|
||||
|
||||
class SourceNameAndSourceContextId
|
||||
{
|
||||
public:
|
||||
constexpr SourceNameAndSourceContextId() = default;
|
||||
SourceNameAndSourceContextId(Utils::SmallStringView sourceName, int sourceContextId)
|
||||
: sourceName(sourceName)
|
||||
, sourceContextId(sourceContextId)
|
||||
{}
|
||||
SourceNameAndSourceContextId(Utils::SmallStringView sourceName, SourceContextId sourceContextId)
|
||||
: sourceName{sourceName}
|
||||
, sourceContextId{sourceContextId}
|
||||
{}
|
||||
|
||||
Utils::SmallString sourceName;
|
||||
SourceContextId sourceContextId;
|
||||
};
|
||||
} // namespace ClangBackEnd
|
||||
|
||||
} // namespace QmlDesigner
|
||||
73
src/plugins/qmldesigner/designercore/metainfo/sourceid.h
Normal file
73
src/plugins/qmldesigner/designercore/metainfo/sourceid.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class SourceId
|
||||
{
|
||||
public:
|
||||
constexpr SourceId() = default;
|
||||
|
||||
SourceId(const char *) = delete;
|
||||
|
||||
explicit SourceId(int id)
|
||||
: id(id)
|
||||
{}
|
||||
|
||||
bool isValid() const { return id >= 0; }
|
||||
|
||||
friend bool operator==(SourceId first, SourceId second)
|
||||
{
|
||||
return first.isValid() && first.id == second.id;
|
||||
}
|
||||
|
||||
friend bool operator!=(SourceId first, SourceId second) { return !(first == second); }
|
||||
|
||||
friend bool operator<(SourceId first, SourceId second) { return first.id < second.id; }
|
||||
|
||||
public:
|
||||
int id = -1;
|
||||
};
|
||||
|
||||
using SourceIds = std::vector<SourceId>;
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<QmlDesigner::SourceId>
|
||||
{
|
||||
using argument_type = QmlDesigner::SourceId;
|
||||
using result_type = std::size_t;
|
||||
result_type operator()(const argument_type &id) const { return std::hash<int>{}(id.id); }
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
148
src/plugins/qmldesigner/designercore/metainfo/sourcepath.h
Normal file
148
src/plugins/qmldesigner/designercore/metainfo/sourcepath.h
Normal file
@@ -0,0 +1,148 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2016 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "sourcepathview.h"
|
||||
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class SourcePath : public Utils::PathString
|
||||
{
|
||||
using size_type = Utils::PathString::size_type;
|
||||
|
||||
public:
|
||||
SourcePath() = default;
|
||||
explicit SourcePath(Utils::PathString &&sourcePath)
|
||||
: Utils::PathString(std::move(sourcePath))
|
||||
{
|
||||
SourcePathView view{*this};
|
||||
|
||||
m_slashIndex = view.slashIndex();
|
||||
}
|
||||
|
||||
explicit SourcePath(Utils::SmallStringView &&sourcePath)
|
||||
: Utils::PathString(sourcePath)
|
||||
{
|
||||
SourcePathView view{*this};
|
||||
|
||||
m_slashIndex = view.slashIndex();
|
||||
}
|
||||
|
||||
SourcePath(SourcePathView sourcePathView)
|
||||
: Utils::PathString(sourcePathView.toStringView())
|
||||
, m_slashIndex(sourcePathView.slashIndex())
|
||||
{
|
||||
}
|
||||
|
||||
template<size_type Size>
|
||||
SourcePath(const char (&string)[Size]) noexcept
|
||||
: SourcePath(SourcePathView(string, Size - 1))
|
||||
{
|
||||
static_assert(Size >= 1, "Invalid string literal! Length is zero!");
|
||||
}
|
||||
|
||||
explicit SourcePath(const Utils::PathString &sourcePath)
|
||||
: SourcePath(sourcePath.clone())
|
||||
{
|
||||
}
|
||||
|
||||
explicit SourcePath(Utils::PathString &&sourcePath, std::ptrdiff_t slashIndex)
|
||||
: Utils::PathString(std::move(sourcePath))
|
||||
, m_slashIndex(slashIndex)
|
||||
{
|
||||
}
|
||||
|
||||
explicit SourcePath(const QString &sourcePath)
|
||||
: SourcePath(Utils::PathString(sourcePath))
|
||||
{
|
||||
}
|
||||
|
||||
SourcePath(Utils::SmallStringView directory, Utils::SmallStringView name)
|
||||
: Utils::PathString({directory, "/", name})
|
||||
, m_slashIndex(std::ptrdiff_t(directory.size()))
|
||||
{}
|
||||
|
||||
bool isValid() const { return size() > 0 && m_slashIndex >= 0; }
|
||||
|
||||
Utils::SmallStringView directory() const noexcept
|
||||
{
|
||||
return mid(0, std::size_t(std::max(std::ptrdiff_t(0), m_slashIndex)));
|
||||
}
|
||||
|
||||
Utils::SmallStringView name() const noexcept
|
||||
{
|
||||
return mid(std::size_t(m_slashIndex + 1),
|
||||
std::size_t(std::ptrdiff_t(size()) - m_slashIndex - std::ptrdiff_t(1)));
|
||||
}
|
||||
|
||||
const Utils::PathString &path() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator SourcePathView() const noexcept { return SourcePathView(toStringView()); }
|
||||
|
||||
operator Utils::SmallStringView() const noexcept
|
||||
{
|
||||
return toStringView();
|
||||
}
|
||||
|
||||
friend bool operator==(const SourcePath &first, const SourcePath &second)
|
||||
{
|
||||
return first.slashIndex() == second.slashIndex()
|
||||
&& first.name() == second.name()
|
||||
&& first.directory() == second.directory();
|
||||
}
|
||||
|
||||
friend bool operator==(const SourcePath &first, const SourcePathView &second)
|
||||
{
|
||||
return first.toStringView() == second.toStringView();
|
||||
}
|
||||
|
||||
friend bool operator==(const SourcePathView &first, const SourcePath &second)
|
||||
{
|
||||
return second == first;
|
||||
}
|
||||
|
||||
friend bool operator<(const SourcePath &first, const SourcePath &second)
|
||||
{
|
||||
return std::make_tuple(first.slashIndex(), first.name(), first.directory())
|
||||
< std::make_tuple(second.slashIndex(), second.name(), second.directory());
|
||||
}
|
||||
|
||||
SourcePath clone() const { return *this; }
|
||||
|
||||
std::ptrdiff_t slashIndex() const { return m_slashIndex; }
|
||||
|
||||
private:
|
||||
std::ptrdiff_t m_slashIndex = -1;
|
||||
};
|
||||
|
||||
using SourcePaths = std::vector<SourcePath>;
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,66 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** 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 <vector>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class SourcePathContextId
|
||||
{
|
||||
public:
|
||||
constexpr SourcePathContextId() = default;
|
||||
|
||||
SourcePathContextId(const char *) = delete;
|
||||
|
||||
SourcePathContextId(int directoryPathId)
|
||||
: directoryPathId(directoryPathId)
|
||||
{}
|
||||
|
||||
bool isValid() const { return directoryPathId >= 0; }
|
||||
|
||||
friend bool operator==(SourcePathContextId first, SourcePathContextId second)
|
||||
{
|
||||
return first.isValid() && first.directoryPathId == second.directoryPathId;
|
||||
}
|
||||
|
||||
friend bool operator!=(SourcePathContextId first, SourcePathContextId second)
|
||||
{
|
||||
return !(first == second);
|
||||
}
|
||||
|
||||
friend bool operator<(SourcePathContextId first, SourcePathContextId second)
|
||||
{
|
||||
return first.directoryPathId < second.directoryPathId;
|
||||
}
|
||||
|
||||
public:
|
||||
int directoryPathId = -1;
|
||||
};
|
||||
|
||||
using SourcePathContextIds = std::vector<SourcePathContextId>;
|
||||
|
||||
} // namespace QmlDesigner
|
||||
107
src/plugins/qmldesigner/designercore/metainfo/sourcepathview.h
Normal file
107
src/plugins/qmldesigner/designercore/metainfo/sourcepathview.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <utils/smallstringview.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
template<char separator>
|
||||
class AbstractSourcePathView : public Utils::SmallStringView
|
||||
{
|
||||
public:
|
||||
constexpr AbstractSourcePathView() = default;
|
||||
explicit AbstractSourcePathView(const char *const string, const size_type size) noexcept
|
||||
: AbstractSourcePathView{Utils::SmallStringView{string, size}}
|
||||
{
|
||||
}
|
||||
|
||||
explicit AbstractSourcePathView(Utils::SmallStringView filePath)
|
||||
: Utils::SmallStringView(filePath)
|
||||
, m_slashIndex(lastSlashIndex(filePath))
|
||||
{
|
||||
}
|
||||
|
||||
template<typename String, typename = std::enable_if_t<std::is_lvalue_reference<String>::value>>
|
||||
explicit AbstractSourcePathView(String &&filePath)
|
||||
: AbstractSourcePathView(filePath.data(), filePath.size())
|
||||
{
|
||||
}
|
||||
|
||||
template<size_type Size>
|
||||
AbstractSourcePathView(const char (&string)[Size]) noexcept
|
||||
: AbstractSourcePathView(string, Size - 1)
|
||||
{
|
||||
static_assert(Size >= 1, "Invalid string literal! Length is zero!");
|
||||
}
|
||||
|
||||
Utils::SmallStringView toStringView() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::ptrdiff_t slashIndex() const
|
||||
{
|
||||
return m_slashIndex;
|
||||
}
|
||||
|
||||
Utils::SmallStringView directory() const noexcept
|
||||
{
|
||||
return mid(0, std::size_t(std::max(std::ptrdiff_t(0), m_slashIndex)));
|
||||
}
|
||||
|
||||
Utils::SmallStringView name() const noexcept
|
||||
{
|
||||
return mid(std::size_t(m_slashIndex + 1),
|
||||
std::size_t(std::ptrdiff_t(size()) - m_slashIndex - std::ptrdiff_t(1)));
|
||||
}
|
||||
|
||||
static
|
||||
std::ptrdiff_t lastSlashIndex(Utils::SmallStringView filePath)
|
||||
{
|
||||
auto foundReverse = std::find(filePath.rbegin(), filePath.rend(), separator);
|
||||
auto found = foundReverse.base();
|
||||
|
||||
auto distance = std::distance(filePath.begin(), found);
|
||||
|
||||
return distance - 1;
|
||||
}
|
||||
|
||||
friend bool operator==(const AbstractSourcePathView &first, const AbstractSourcePathView &second)
|
||||
{
|
||||
return first.toStringView() == second.toStringView();
|
||||
}
|
||||
|
||||
private:
|
||||
std::ptrdiff_t m_slashIndex = -1;
|
||||
};
|
||||
|
||||
using SourcePathView = AbstractSourcePathView<'/'>;
|
||||
using SourcePathViews = std::vector<SourcePathView>;
|
||||
} // namespace QmlDesigner
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "projectstorageids.h"
|
||||
#include "storagecacheentry.h"
|
||||
#include "storagecachefwd.h"
|
||||
|
||||
@@ -51,8 +52,8 @@ class NonLockingMutex
|
||||
{
|
||||
public:
|
||||
constexpr NonLockingMutex() noexcept {}
|
||||
NonLockingMutex(const NonLockingMutex&) = delete;
|
||||
NonLockingMutex& operator=(const NonLockingMutex&) = delete;
|
||||
NonLockingMutex(const NonLockingMutex &) = delete;
|
||||
NonLockingMutex &operator=(const NonLockingMutex &) = delete;
|
||||
void lock() {}
|
||||
void unlock() {}
|
||||
void lock_shared() {}
|
||||
@@ -71,6 +72,57 @@ class StorageCache
|
||||
friend StorageCache;
|
||||
|
||||
using ResultType = std::conditional_t<std::is_base_of<NonLockingMutex, Mutex>::value, ViewType, Type>;
|
||||
using IndexDatabaseType = typename IndexType::DatabaseType;
|
||||
class StorageCacheIndex
|
||||
{
|
||||
public:
|
||||
constexpr explicit StorageCacheIndex() = default;
|
||||
|
||||
StorageCacheIndex(const char *) = delete;
|
||||
|
||||
constexpr explicit StorageCacheIndex(int id)
|
||||
: id{id}
|
||||
{}
|
||||
|
||||
constexpr explicit StorageCacheIndex(std::size_t id)
|
||||
: id{static_cast<int>(id)}
|
||||
{}
|
||||
|
||||
constexpr explicit StorageCacheIndex(std::ptrdiff_t id)
|
||||
: id{static_cast<int>(id)}
|
||||
{}
|
||||
|
||||
constexpr StorageCacheIndex operator=(std::ptrdiff_t newId)
|
||||
{
|
||||
id = static_cast<int>(newId);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr StorageCacheIndex operator+(int amount) { return StorageCacheIndex{id + amount}; }
|
||||
|
||||
constexpr friend bool operator==(StorageCacheIndex first, StorageCacheIndex second)
|
||||
{
|
||||
return first.id == second.id && first.isValid() && second.isValid();
|
||||
}
|
||||
|
||||
constexpr friend bool operator<(StorageCacheIndex first, StorageCacheIndex second)
|
||||
{
|
||||
return first.id < second.id;
|
||||
}
|
||||
|
||||
constexpr friend bool operator>=(StorageCacheIndex first, StorageCacheIndex second)
|
||||
{
|
||||
return first.id >= second.id;
|
||||
}
|
||||
|
||||
constexpr bool isValid() const { return id >= 0; }
|
||||
|
||||
explicit operator std::size_t() const { return static_cast<std::size_t>(id); }
|
||||
|
||||
public:
|
||||
int id = -1;
|
||||
};
|
||||
|
||||
public:
|
||||
using MutexType = Mutex;
|
||||
@@ -127,7 +179,7 @@ public:
|
||||
|
||||
m_entries = std::move(entries);
|
||||
|
||||
int max_id = 0;
|
||||
std::size_t max_id = 0;
|
||||
|
||||
auto found = std::max_element(m_entries.begin(),
|
||||
m_entries.end(),
|
||||
@@ -136,9 +188,9 @@ public:
|
||||
});
|
||||
|
||||
if (found != m_entries.end())
|
||||
max_id = found->id + 1;
|
||||
max_id = static_cast<std::size_t>(found->id) + 1;
|
||||
|
||||
m_indices.resize(max_id, -1);
|
||||
m_indices.resize(max_id);
|
||||
|
||||
updateIndices();
|
||||
}
|
||||
@@ -171,10 +223,10 @@ public:
|
||||
return first.id < second.id;
|
||||
});
|
||||
|
||||
int max_id = found->id + 1;
|
||||
auto max_id = static_cast<std::size_t>(found->id) + 1;
|
||||
|
||||
if (max_id > int(m_indices.size()))
|
||||
m_indices.resize(max_id, -1);
|
||||
if (max_id > m_indices.size())
|
||||
m_indices.resize(max_id);
|
||||
|
||||
CacheEntries mergedCacheEntries;
|
||||
mergedCacheEntries.reserve(newCacheEntries.size() + m_entries.size());
|
||||
@@ -234,8 +286,11 @@ public:
|
||||
{
|
||||
std::shared_lock<Mutex> sharedLock(m_mutex);
|
||||
|
||||
if (IndexType(m_indices.size()) > id && m_indices.at(id) >= 0)
|
||||
return m_entries.at(m_indices.at(id)).value;
|
||||
if (IndexType{static_cast<IndexDatabaseType>(m_indices.size())} > id) {
|
||||
if (auto indirectionIndex = m_indices.at(static_cast<std::size_t>(id));
|
||||
indirectionIndex.isValid())
|
||||
return m_entries.at(static_cast<std::size_t>(indirectionIndex)).value;
|
||||
}
|
||||
|
||||
sharedLock.unlock();
|
||||
std::lock_guard<Mutex> exclusiveLock(m_mutex);
|
||||
@@ -253,25 +308,23 @@ public:
|
||||
std::vector<ResultType> values;
|
||||
values.reserve(ids.size());
|
||||
|
||||
for (IndexType id : ids)
|
||||
values.emplace_back(m_entries.at(m_indices.at(id)).value);
|
||||
|
||||
for (IndexType id : ids) {
|
||||
values.emplace_back(
|
||||
m_entries.at(static_cast<std::size_t>(m_indices.at(static_cast<std::size_t>(id)))).value);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
bool isEmpty() const { return m_entries.empty() && m_indices.empty(); }
|
||||
|
||||
Mutex &mutex() const
|
||||
{
|
||||
return m_mutex;
|
||||
}
|
||||
Mutex &mutex() const { return m_mutex; }
|
||||
|
||||
private:
|
||||
void updateIndices()
|
||||
{
|
||||
auto begin = m_entries.cbegin();
|
||||
for (auto current = begin; current != m_entries.cend(); ++current)
|
||||
m_indices[current->id] = std::distance(begin, current);
|
||||
m_indices[static_cast<std::size_t>(current->id)] = std::distance(begin, current);
|
||||
}
|
||||
|
||||
auto find(ViewType view)
|
||||
@@ -287,32 +340,30 @@ private:
|
||||
return m_entries.end();
|
||||
}
|
||||
|
||||
void incrementLargerOrEqualIndicesByOne(IndexType newIndex)
|
||||
void incrementLargerOrEqualIndicesByOne(StorageCacheIndex newIndirectionIndex)
|
||||
{
|
||||
std::transform(m_indices.begin(),
|
||||
m_indices.end(),
|
||||
m_indices.begin(),
|
||||
[&] (IndexType index) {
|
||||
return index >= newIndex ? ++index : index;
|
||||
std::transform(m_indices.begin(), m_indices.end(), m_indices.begin(), [&](StorageCacheIndex index) {
|
||||
return index >= newIndirectionIndex ? index + 1 : index;
|
||||
});
|
||||
}
|
||||
|
||||
void ensureSize(IndexType id)
|
||||
void ensureSize(std::size_t size)
|
||||
{
|
||||
if (m_indices.size() <= std::size_t(id))
|
||||
m_indices.resize(id + 1, -1);
|
||||
if (m_indices.size() <= size)
|
||||
m_indices.resize(size + 1);
|
||||
}
|
||||
|
||||
auto insertEntry(const_iterator beforeIterator, ViewType view, IndexType id)
|
||||
{
|
||||
auto inserted = m_entries.emplace(beforeIterator, view, id);
|
||||
|
||||
auto newIndex = IndexType(std::distance(m_entries.begin(), inserted));
|
||||
StorageCacheIndex newIndirectionIndex{std::distance(m_entries.begin(), inserted)};
|
||||
|
||||
incrementLargerOrEqualIndicesByOne(newIndex);
|
||||
incrementLargerOrEqualIndicesByOne(newIndirectionIndex);
|
||||
|
||||
ensureSize(id);
|
||||
m_indices.at(id) = newIndex;
|
||||
auto indirectionIndex = static_cast<std::size_t>(id);
|
||||
ensureSize(indirectionIndex);
|
||||
m_indices.at(indirectionIndex) = newIndirectionIndex;
|
||||
|
||||
return inserted;
|
||||
}
|
||||
@@ -327,7 +378,7 @@ private:
|
||||
|
||||
private:
|
||||
CacheEntries m_entries;
|
||||
std::vector<IndexType> m_indices;
|
||||
std::vector<StorageCacheIndex> m_indices;
|
||||
mutable Mutex m_mutex;
|
||||
Storage m_storage;
|
||||
};
|
||||
|
||||
@@ -36,6 +36,11 @@ public:
|
||||
, id(id)
|
||||
{}
|
||||
|
||||
StorageCacheEntry(ViewType value, typename IndexType::DatabaseType id)
|
||||
: value(value)
|
||||
, id{id}
|
||||
{}
|
||||
|
||||
operator ViewType() const { return value; }
|
||||
friend bool operator==(const StorageCacheEntry &first, const StorageCacheEntry &second)
|
||||
{
|
||||
|
||||
@@ -56,6 +56,11 @@ HEADERS += \
|
||||
$$PWD/designercore/metainfo/storagecache.h \
|
||||
$$PWD/designercore/metainfo/storagecacheentry.h \
|
||||
$$PWD/designercore/metainfo/storagecachefwd.h \
|
||||
$$PWD/designercore/metainfo/sourceid.h \
|
||||
$$PWD/designercore/metainfo/sourcepathcontextid.h \
|
||||
$$PWD/designercore/metainfo/sourcepath.h \
|
||||
$$PWD/designercore/metainfo/sourcepathview.h \
|
||||
$$PWD/designercore/metainfo/sourcepathcache.h \
|
||||
$$PWD/designercore/model/model_p.h \
|
||||
$$PWD/designercore/include/qmldesignercorelib_global.h \
|
||||
$$PWD/designercore/model/internalbindingproperty.h \
|
||||
@@ -73,4 +78,7 @@ HEADERS += \
|
||||
$$PWD/designercore/include/signalhandlerproperty.h \
|
||||
$$PWD/designercore/include/variantproperty.h \
|
||||
$$PWD/designercore/rewritertransaction.h \
|
||||
$$PWD/components/listmodeleditor/listmodeleditormodel.h
|
||||
$$PWD/components/listmodeleditor/listmodeleditormodel.h \
|
||||
$$PWD/designercore/metainfo/projectstorage.h \
|
||||
$$PWD/designercore/include/projectstorageids.h \
|
||||
$$PWD/designercore/metainfo/projectstoragetypes.h
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include <filepathview.h>
|
||||
#include <filestatus.h>
|
||||
#include <includesearchpath.h>
|
||||
#include <metainfo/projectstoragetypes.h>
|
||||
#include <modelnode.h>
|
||||
#include <nativefilepath.h>
|
||||
#include <pchpaths.h>
|
||||
@@ -1570,6 +1571,13 @@ std::ostream &operator<<(std::ostream &out, const VariantProperty &property)
|
||||
return out << "(" << property.parentModelNode() << ", " << property.name() << ", "
|
||||
<< property.value() << ")";
|
||||
}
|
||||
namespace Sources {
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const SourceContext &sourceContext)
|
||||
{
|
||||
return out << "(" << sourceContext.id << ", " << sourceContext.value << ")";
|
||||
}
|
||||
} // namespace Sources
|
||||
|
||||
namespace Internal {
|
||||
std::ostream &operator<<(std::ostream &out, const ImageCacheStorageImageEntry &entry)
|
||||
|
||||
@@ -374,10 +374,24 @@ std::ostream &operator<<(std::ostream &out, const Diagnostic &diag);
|
||||
namespace QmlDesigner {
|
||||
class ModelNode;
|
||||
class VariantProperty;
|
||||
template<auto Type, typename InternalIntergerType>
|
||||
class BasicId;
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const ModelNode &node);
|
||||
std::ostream &operator<<(std::ostream &out, const VariantProperty &property);
|
||||
|
||||
template<auto Type, typename InternalIntergerType>
|
||||
std::ostream &operator<<(std::ostream &out, const BasicId<Type, InternalIntergerType> &id)
|
||||
{
|
||||
return out << "(" << &id << ")";
|
||||
}
|
||||
|
||||
namespace Sources {
|
||||
class SourceContext;
|
||||
|
||||
std::ostream &operator<<(std::ostream &out, const SourceContext &sourceContext);
|
||||
} // namespace Sources
|
||||
|
||||
namespace Internal {
|
||||
class ImageCacheStorageImageEntry;
|
||||
class ImageCacheStorageIconEntry;
|
||||
|
||||
1034
tests/unit/unittest/projectstorage-test.cpp
Normal file
1034
tests/unit/unittest/projectstorage-test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
63
tests/unit/unittest/projectstoragemock.h
Normal file
63
tests/unit/unittest/projectstoragemock.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include "sqlitedatabasemock.h"
|
||||
|
||||
#include <metainfo/projectstoragetypes.h>
|
||||
#include <projectstorageids.h>
|
||||
|
||||
class ProjectStorageMock
|
||||
{
|
||||
public:
|
||||
ProjectStorageMock(SqliteDatabaseMock &databaseMock)
|
||||
: databaseMock{databaseMock}
|
||||
{}
|
||||
|
||||
MOCK_METHOD1(fetchSourceContextId,
|
||||
QmlDesigner::SourceContextId(Utils::SmallStringView SourceContextPath));
|
||||
MOCK_METHOD2(fetchSourceId,
|
||||
QmlDesigner::SourceId(QmlDesigner::SourceContextId SourceContextId,
|
||||
Utils::SmallStringView sourceName));
|
||||
MOCK_METHOD1(fetchSourceContextIdUnguarded,
|
||||
QmlDesigner::SourceContextId(Utils::SmallStringView SourceContextPath));
|
||||
MOCK_METHOD2(fetchSourceIdUnguarded,
|
||||
QmlDesigner::SourceId(QmlDesigner::SourceContextId SourceContextId,
|
||||
Utils::SmallStringView sourceName));
|
||||
MOCK_METHOD1(fetchSourceContextPath,
|
||||
Utils::PathString(QmlDesigner::SourceContextId sourceContextId));
|
||||
MOCK_METHOD1(fetchSourceNameAndSourceContextId,
|
||||
QmlDesigner::Sources::SourceNameAndSourceContextId(QmlDesigner::SourceId sourceId));
|
||||
MOCK_METHOD0(fetchAllSourceContexts, std::vector<QmlDesigner::Sources::SourceContext>());
|
||||
MOCK_METHOD0(fetchAllSources, std::vector<ClangBackEnd::Sources::Source>());
|
||||
|
||||
SqliteDatabaseMock &database() { return databaseMock; }
|
||||
|
||||
SqliteDatabaseMock &databaseMock;
|
||||
};
|
||||
|
||||
89
tests/unit/unittest/sourcepath-test.cpp
Normal file
89
tests/unit/unittest/sourcepath-test.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include <metainfo/sourcepath.h>
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(SourcePath, CreateFromPathString)
|
||||
{
|
||||
QmlDesigner::SourcePath sourcePath{Utils::PathString{"/file/pathOne"}};
|
||||
|
||||
ASSERT_THAT(sourcePath.directory(), "/file");
|
||||
ASSERT_THAT(sourcePath.name(), "pathOne");
|
||||
}
|
||||
|
||||
TEST(FilePath, CreateFromDirectoryAndFileName)
|
||||
{
|
||||
QmlDesigner::SourcePath sourcePath{Utils::PathString{"/file"}, Utils::PathString{"pathOne"}};
|
||||
|
||||
ASSERT_THAT(sourcePath.directory(), "/file");
|
||||
ASSERT_THAT(sourcePath.name(), "pathOne");
|
||||
ASSERT_THAT(sourcePath.path(), "/file/pathOne");
|
||||
}
|
||||
|
||||
TEST(FilePath, CreateFromCString)
|
||||
{
|
||||
QmlDesigner::SourcePath sourcePath{"/file/pathOne"};
|
||||
|
||||
ASSERT_THAT(sourcePath.directory(), "/file");
|
||||
ASSERT_THAT(sourcePath.name(), "pathOne");
|
||||
}
|
||||
|
||||
TEST(FilePath, CreateFromFilePathView)
|
||||
{
|
||||
QmlDesigner::SourcePath sourcePath{QmlDesigner::SourcePathView{"/file/pathOne"}};
|
||||
|
||||
ASSERT_THAT(sourcePath.directory(), "/file");
|
||||
ASSERT_THAT(sourcePath.name(), "pathOne");
|
||||
}
|
||||
|
||||
TEST(FilePath, CreateFromQString)
|
||||
{
|
||||
QmlDesigner::SourcePath sourcePath{QString{"/file/pathOne"}};
|
||||
|
||||
ASSERT_THAT(sourcePath.directory(), "/file");
|
||||
ASSERT_THAT(sourcePath.name(), "pathOne");
|
||||
}
|
||||
|
||||
TEST(FilePath, DefaultFilePath)
|
||||
{
|
||||
QmlDesigner::SourcePath sourcePath;
|
||||
|
||||
ASSERT_THAT(sourcePath.directory(), "");
|
||||
ASSERT_THAT(sourcePath.name(), "");
|
||||
}
|
||||
|
||||
TEST(FilePath, EmptyFilePath)
|
||||
{
|
||||
QmlDesigner::SourcePath sourcePath("");
|
||||
|
||||
ASSERT_THAT(sourcePath.directory(), "");
|
||||
ASSERT_THAT(sourcePath.name(), "");
|
||||
}
|
||||
|
||||
}
|
||||
123
tests/unit/unittest/sourcepathview-test.cpp
Normal file
123
tests/unit/unittest/sourcepathview-test.cpp
Normal file
@@ -0,0 +1,123 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2017 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include <metainfo/sourcepathview.h>
|
||||
|
||||
namespace {
|
||||
|
||||
TEST(SourcePathView, FilePathSlashForEmptyPath)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath("");
|
||||
|
||||
ASSERT_THAT(filePath.slashIndex(), -1);
|
||||
}
|
||||
|
||||
TEST(SourcePathView, FilePathSlashForSingleSlash)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath("/");
|
||||
|
||||
ASSERT_THAT(filePath.slashIndex(), 0);
|
||||
}
|
||||
|
||||
TEST(SourcePathView, FilePathSlashForFileInRoot)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath("/file.h");
|
||||
|
||||
ASSERT_THAT(filePath.slashIndex(), 0);
|
||||
}
|
||||
|
||||
TEST(SourcePathView, FilePathSlashForSomeLongerPath)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath("/path/to/some/file.h");
|
||||
|
||||
ASSERT_THAT(filePath.slashIndex(), 13);
|
||||
}
|
||||
|
||||
TEST(SourcePathView, FilePathSlashForFileNameOnly)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath("file.h");
|
||||
|
||||
ASSERT_THAT(filePath.slashIndex(), -1);
|
||||
}
|
||||
|
||||
TEST(SourcePathView, DirectoryPathForEmptyPath)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath("");
|
||||
|
||||
ASSERT_THAT(filePath.directory(), "");
|
||||
}
|
||||
|
||||
TEST(SourcePathView, DirectoryPathForSingleSlashPath)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath{"/"};
|
||||
|
||||
ASSERT_THAT(filePath.directory(), "");
|
||||
}
|
||||
|
||||
TEST(SourcePathView, DirectoryPathForLongerPath)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath{"/path/to/some/file.h"};
|
||||
|
||||
ASSERT_THAT(filePath.directory(), "/path/to/some");
|
||||
}
|
||||
|
||||
TEST(SourcePathView, DirectoryPathForFileNameOnly)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath{"file.h"};
|
||||
|
||||
ASSERT_THAT(filePath.directory(), IsEmpty());
|
||||
}
|
||||
|
||||
TEST(SourcePathView, FileNameForEmptyPath)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath("");
|
||||
|
||||
ASSERT_THAT(filePath.name(), "");
|
||||
}
|
||||
|
||||
TEST(SourcePathView, FileNameForSingleSlashPath)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath{"/"};
|
||||
|
||||
ASSERT_THAT(filePath.name(), "");
|
||||
}
|
||||
|
||||
TEST(SourcePathView, FileNameForLongerPath)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath{"/path/to/some/file.h"};
|
||||
|
||||
ASSERT_THAT(filePath.name(), "file.h");
|
||||
}
|
||||
|
||||
TEST(SourcePathView, FileNameForFileNameOnly)
|
||||
{
|
||||
QmlDesigner::SourcePathView filePath{"file.h"};
|
||||
|
||||
ASSERT_THAT(filePath.name(), "file.h");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "googletest.h"
|
||||
|
||||
#include "sqlitereadstatementmock.h"
|
||||
#include "sqlitereadwritestatementmock.h"
|
||||
#include "sqlitetransactionbackendmock.h"
|
||||
#include "sqlitewritestatementmock.h"
|
||||
|
||||
@@ -43,6 +44,8 @@ public:
|
||||
template<int ResultCount>
|
||||
using ReadStatement = NiceMock<SqliteReadStatementMock<ResultCount>>;
|
||||
using WriteStatement = NiceMock<SqliteWriteStatementMock>;
|
||||
template<int ResultCount>
|
||||
using ReadWriteStatement = NiceMock<SqliteReadWriteStatementMock<ResultCount>>;
|
||||
|
||||
MOCK_METHOD(void, prepare, (Utils::SmallStringView sqlStatement), ());
|
||||
|
||||
|
||||
@@ -29,11 +29,13 @@
|
||||
|
||||
#include <cpptools/usages.h>
|
||||
#include <filepathstoragesources.h>
|
||||
#include <metainfo/projectstoragetypes.h>
|
||||
#include <pchpaths.h>
|
||||
#include <projectpartartefact.h>
|
||||
#include <projectpartcontainer.h>
|
||||
#include <projectpartpch.h>
|
||||
#include <projectpartstoragestructs.h>
|
||||
#include <projectstorageids.h>
|
||||
#include <sourceentry.h>
|
||||
#include <sourcelocations.h>
|
||||
#include <sqliteblob.h>
|
||||
@@ -160,6 +162,33 @@ public:
|
||||
valuesReturnPrecompiledHeaderTimeStamps,
|
||||
(int projectPartId));
|
||||
|
||||
MOCK_METHOD(QmlDesigner::TypeId, valueReturnsTypeId, (Utils::SmallStringView name), ());
|
||||
MOCK_METHOD(QmlDesigner::TypeId, valueWithTransactionReturnsTypeId, (long long, long long), ());
|
||||
MOCK_METHOD(QmlDesigner::PropertyDeclarationId,
|
||||
valueWithTransactionReturnsPropertyDeclarationId,
|
||||
(long long, Utils::SmallStringView),
|
||||
());
|
||||
MOCK_METHOD((std::tuple<QmlDesigner::PropertyDeclarationId, QmlDesigner::TypeId>),
|
||||
valueReturnsPropertyDeclaration,
|
||||
(long long, Utils::SmallStringView),
|
||||
());
|
||||
|
||||
MOCK_METHOD(std::vector<QmlDesigner::Sources::SourceContext>,
|
||||
valuesReturnSourcesSourceContexts,
|
||||
(std::size_t),
|
||||
());
|
||||
|
||||
MOCK_METHOD(std::vector<QmlDesigner::Sources::Source>, valuesReturnSourcesSources, (std::size_t), ());
|
||||
|
||||
MOCK_METHOD(QmlDesigner::Sources::SourceNameAndSourceContextId,
|
||||
valueReturnSourcesSourceNameAndSourceContextId,
|
||||
(int) );
|
||||
|
||||
MOCK_METHOD(QmlDesigner::SourceContextId, valueReturnsSourceContextId, (Utils::SmallStringView), ());
|
||||
MOCK_METHOD(QmlDesigner::SourceContextId, valueWithTransactionReturnsSourceContextId, (int), ());
|
||||
|
||||
MOCK_METHOD(QmlDesigner::SourceId, valueReturnsSourceId, (int, Utils::SmallStringView), ());
|
||||
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto optionalValue(const QueryTypes &...queryValues)
|
||||
{
|
||||
@@ -199,8 +228,38 @@ public:
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto value(const QueryTypes &...queryValues)
|
||||
{
|
||||
static_assert(!std::is_same_v<ResultType, ResultType>,
|
||||
"SqliteReadStatementMock::value does not handle result type!");
|
||||
if constexpr (std::is_same_v<ResultType, QmlDesigner::TypeId>)
|
||||
return valueReturnsTypeId(queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType, QmlDesigner::PropertyDeclarationId>)
|
||||
return valueReturnsPropertyDeclarationId(queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType,
|
||||
std::tuple<QmlDesigner::PropertyDeclarationId, QmlDesigner::TypeId>>)
|
||||
return valueReturnsPropertyDeclaration(queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType, QmlDesigner::Sources::SourceNameAndSourceContextId>)
|
||||
return valueReturnSourcesSourceNameAndSourceContextId(queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType, QmlDesigner::SourceContextId>)
|
||||
return valueReturnsSourceContextId(queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType, QmlDesigner::SourceId>)
|
||||
return valueReturnsSourceId(queryValues...);
|
||||
else
|
||||
static_assert(!std::is_same_v<ResultType, ResultType>,
|
||||
"SqliteReadStatementMock::value does not handle result type!");
|
||||
}
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto valueWithTransaction(const QueryTypes &...queryValues)
|
||||
{
|
||||
if constexpr (std::is_same_v<ResultType, QmlDesigner::TypeId>)
|
||||
return valueWithTransactionReturnsTypeId(queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType, QmlDesigner::PropertyDeclarationId>)
|
||||
return valueWithTransactionReturnsPropertyDeclarationId(queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType,
|
||||
std::tuple<QmlDesigner::PropertyDeclarationId, QmlDesigner::TypeId>>)
|
||||
return valueReturnsPropertyDeclaration(queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType, QmlDesigner::SourceContextId>)
|
||||
return valueWithTransactionReturnsSourceContextId(queryValues...);
|
||||
else
|
||||
static_assert(!std::is_same_v<ResultType, ResultType>,
|
||||
"SqliteReadStatementMock::value does not handle result type!");
|
||||
}
|
||||
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
@@ -240,11 +299,29 @@ public:
|
||||
return valuesReturnSourceEntries(reserveSize, queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType, SourceTimeStamp>)
|
||||
return valuesReturnSourceTimeStamps(reserveSize, queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType, QmlDesigner::Sources::SourceContext>)
|
||||
return valuesReturnSourcesSourceContexts(reserveSize);
|
||||
else if constexpr (std::is_same_v<ResultType, QmlDesigner::Sources::Source>)
|
||||
return valuesReturnSourcesSources(reserveSize);
|
||||
else
|
||||
static_assert(!std::is_same_v<ResultType, ResultType>,
|
||||
"SqliteReadStatementMock::values does not handle result type!");
|
||||
}
|
||||
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto range(const QueryTypes &...queryValues)
|
||||
{
|
||||
static_assert(!std::is_same_v<ResultType, ResultType>,
|
||||
"SqliteReadStatementMock::values does not handle result type!");
|
||||
}
|
||||
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto rangeWithTransaction(const QueryTypes &...queryValues)
|
||||
{
|
||||
static_assert(!std::is_same_v<ResultType, ResultType>,
|
||||
"SqliteReadStatementMock::values does not handle result type!");
|
||||
}
|
||||
|
||||
public:
|
||||
Utils::SmallString sqlStatement;
|
||||
};
|
||||
|
||||
35
tests/unit/unittest/sqlitereadwritestatementmock.cpp
Normal file
35
tests/unit/unittest/sqlitereadwritestatementmock.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 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 "sqlitereadwritestatementmock.h"
|
||||
|
||||
#include "sqlitedatabasemock.h"
|
||||
|
||||
SqliteReadWriteStatementMockBase::SqliteReadWriteStatementMockBase(Utils::SmallStringView sqlStatement,
|
||||
SqliteDatabaseMock &databaseMock)
|
||||
: sqlStatement{sqlStatement}
|
||||
{
|
||||
databaseMock.prepare(sqlStatement);
|
||||
}
|
||||
86
tests/unit/unittest/sqlitereadwritestatementmock.h
Normal file
86
tests/unit/unittest/sqlitereadwritestatementmock.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2021 The Qt Company Ltd.
|
||||
** Contact: https://www.qt.io/licensing/
|
||||
**
|
||||
** This file is part of Qt Creator.
|
||||
**
|
||||
** Commercial License Usage
|
||||
** Licensees holding valid commercial Qt licenses may use this file in
|
||||
** accordance with the commercial license agreement provided with the
|
||||
** Software or, alternatively, in accordance with the terms contained in
|
||||
** a written agreement between you and The Qt Company. For licensing terms
|
||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||
** information use the contact form at https://www.qt.io/contact-us.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU
|
||||
** General Public License version 3 as published by the Free Software
|
||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
||||
** included in the packaging of this file. Please review the following
|
||||
** information to ensure the GNU General Public License requirements will
|
||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include <projectstorageids.h>
|
||||
|
||||
#include <sqlite/sqlitevalue.h>
|
||||
#include <utils/optional.h>
|
||||
#include <utils/smallstring.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
class SqliteDatabaseMock;
|
||||
|
||||
class SqliteReadWriteStatementMockBase
|
||||
{
|
||||
public:
|
||||
SqliteReadWriteStatementMockBase() = default;
|
||||
SqliteReadWriteStatementMockBase(Utils::SmallStringView sqlStatement,
|
||||
SqliteDatabaseMock &databaseMock);
|
||||
|
||||
MOCK_METHOD(QmlDesigner::TypeId,
|
||||
valueReturnsTypeId,
|
||||
(Utils::SmallStringView name, long long id, long long),
|
||||
());
|
||||
MOCK_METHOD(QmlDesigner::PropertyDeclarationId,
|
||||
valueReturnsPropertyDeclarationId,
|
||||
(long long, Utils::SmallStringView, long long),
|
||||
());
|
||||
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto optionalValue(const QueryTypes &...queryValues)
|
||||
{
|
||||
static_assert(!std::is_same_v<ResultType, ResultType>,
|
||||
"SqliteReadStatementMock::value does not handle result type!");
|
||||
}
|
||||
|
||||
template<typename ResultType, typename... QueryTypes>
|
||||
auto value(const QueryTypes &...queryValues)
|
||||
{
|
||||
if constexpr (std::is_same_v<ResultType, QmlDesigner::TypeId>)
|
||||
return valueReturnsTypeId(queryValues...);
|
||||
else if constexpr (std::is_same_v<ResultType, QmlDesigner::PropertyDeclarationId>)
|
||||
return valueReturnsPropertyDeclarationId(queryValues...);
|
||||
else
|
||||
static_assert(!std::is_same_v<ResultType, ResultType>,
|
||||
"SqliteReadStatementMock::value does not handle result type!");
|
||||
}
|
||||
|
||||
public:
|
||||
Utils::SmallString sqlStatement;
|
||||
};
|
||||
|
||||
template<int ResultCount>
|
||||
class SqliteReadWriteStatementMock : public SqliteReadWriteStatementMockBase
|
||||
{
|
||||
public:
|
||||
using SqliteReadWriteStatementMockBase::SqliteReadWriteStatementMockBase;
|
||||
};
|
||||
@@ -42,6 +42,8 @@ public:
|
||||
|
||||
MOCK_METHOD(void, write, (Utils::SmallStringView), ());
|
||||
MOCK_METHOD(void, write, (long long), ());
|
||||
MOCK_METHOD(void, write, (long long, long long), ());
|
||||
MOCK_METHOD(void, write, (Utils::SmallStringView, long long), ());
|
||||
MOCK_METHOD(void, write, (Utils::SmallStringView, Utils::SmallStringView), ());
|
||||
MOCK_METHOD(void, write, (long long, Utils::SmallStringView), ());
|
||||
MOCK_METHOD(void,
|
||||
|
||||
@@ -25,31 +25,30 @@
|
||||
|
||||
#include "googletest.h"
|
||||
|
||||
#include "mockfilepathstorage.h"
|
||||
#include "mockmutex.h"
|
||||
#include "projectstoragemock.h"
|
||||
#include "sqlitedatabasemock.h"
|
||||
|
||||
#include <metainfo/storagecache.h>
|
||||
#include <projectstorageids.h>
|
||||
|
||||
#include <utils/smallstringio.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using QmlDesigner::SourceContextId;
|
||||
using QmlDesigner::StorageCacheException;
|
||||
|
||||
using uint64 = unsigned long long;
|
||||
|
||||
using Utils::compare;
|
||||
using Utils::reverseCompare;
|
||||
|
||||
class StorageAdapter
|
||||
{
|
||||
public:
|
||||
auto fetchId(Utils::SmallStringView view) { return storage.fetchDirectoryId(view); }
|
||||
auto fetchId(Utils::SmallStringView view) { return storage.fetchSourceContextId(view); }
|
||||
|
||||
auto fetchValue(int id) { return storage.fetchDirectoryPath(id); }
|
||||
auto fetchValue(SourceContextId id) { return storage.fetchSourceContextPath(id); }
|
||||
|
||||
MockFilePathStorage &storage;
|
||||
ProjectStorageMock &storage;
|
||||
};
|
||||
|
||||
auto less(Utils::SmallStringView first, Utils::SmallStringView second) -> bool
|
||||
@@ -58,10 +57,14 @@ auto less(Utils::SmallStringView first, Utils::SmallStringView second) -> bool
|
||||
};
|
||||
|
||||
using CacheWithMockLocking = QmlDesigner::
|
||||
StorageCache<Utils::PathString, Utils::SmallStringView, int, StorageAdapter, NiceMock<MockMutex>, less>;
|
||||
StorageCache<Utils::PathString, Utils::SmallStringView, SourceContextId, StorageAdapter, NiceMock<MockMutex>, less>;
|
||||
|
||||
using CacheWithoutLocking = QmlDesigner::
|
||||
StorageCache<Utils::PathString, Utils::SmallStringView, int, StorageAdapter, NiceMock<MockMutexNonLocking>, less>;
|
||||
using CacheWithoutLocking = QmlDesigner::StorageCache<Utils::PathString,
|
||||
Utils::SmallStringView,
|
||||
SourceContextId,
|
||||
StorageAdapter,
|
||||
NiceMock<MockMutexNonLocking>,
|
||||
less>;
|
||||
|
||||
template<typename Cache>
|
||||
class StorageCache : public testing::Test
|
||||
@@ -76,21 +79,22 @@ protected:
|
||||
return reverseCompare(f, l) < 0;
|
||||
});
|
||||
|
||||
ON_CALL(this->mockStorage, fetchDirectoryId(Eq("foo"))).WillByDefault(Return(42));
|
||||
ON_CALL(this->mockStorage, fetchDirectoryId(Eq("bar"))).WillByDefault(Return(43));
|
||||
ON_CALL(this->mockStorage, fetchDirectoryId(Eq("poo"))).WillByDefault(Return(44));
|
||||
ON_CALL(this->mockStorage, fetchDirectoryId(Eq("taa"))).WillByDefault(Return(45));
|
||||
ON_CALL(this->mockStorage, fetchDirectoryPath(41)).WillByDefault(Return(Utils::PathString("bar")));
|
||||
ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath1))).WillByDefault(Return(0));
|
||||
ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath2))).WillByDefault(Return(1));
|
||||
ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath3))).WillByDefault(Return(2));
|
||||
ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath4))).WillByDefault(Return(3));
|
||||
ON_CALL(this->mockStorage, fetchDirectoryId(Eq(filePath5))).WillByDefault(Return(4));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))).WillByDefault(Return(id42));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextId(Eq("bar"))).WillByDefault(Return(id43));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextId(Eq("poo"))).WillByDefault(Return(id44));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextId(Eq("taa"))).WillByDefault(Return(id45));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextPath(this->id41))
|
||||
.WillByDefault(Return(Utils::PathString("bar")));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath1))).WillByDefault(Return(id1));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath2))).WillByDefault(Return(id2));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath3))).WillByDefault(Return(id3));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath4))).WillByDefault(Return(id4));
|
||||
ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath5))).WillByDefault(Return(id5));
|
||||
}
|
||||
|
||||
protected:
|
||||
NiceMock<SqliteDatabaseMock> databaseMock;
|
||||
NiceMock<MockFilePathStorage> mockStorage{databaseMock};
|
||||
NiceMock<ProjectStorageMock> mockStorage{databaseMock};
|
||||
StorageAdapter storageAdapter{mockStorage};
|
||||
Cache cache{storageAdapter};
|
||||
typename Cache::MutexType &mockMutex = cache.mutex();
|
||||
@@ -99,16 +103,18 @@ protected:
|
||||
Utils::PathString filePath3{"/file/pathThree"};
|
||||
Utils::PathString filePath4{"/file/pathFour"};
|
||||
Utils::PathString filePath5{"/file/pathFife"};
|
||||
Utils::PathStringVector filePaths{filePath1,
|
||||
filePath2,
|
||||
filePath3,
|
||||
filePath4,
|
||||
filePath5};
|
||||
Utils::PathStringVector reverseFilePaths{filePath1,
|
||||
filePath2,
|
||||
filePath3,
|
||||
filePath4,
|
||||
filePath5};
|
||||
Utils::PathStringVector filePaths{filePath1, filePath2, filePath3, filePath4, filePath5};
|
||||
Utils::PathStringVector reverseFilePaths{filePath1, filePath2, filePath3, filePath4, filePath5};
|
||||
SourceContextId id1{0};
|
||||
SourceContextId id2{1};
|
||||
SourceContextId id3{2};
|
||||
SourceContextId id4{3};
|
||||
SourceContextId id5{4};
|
||||
SourceContextId id41{41};
|
||||
SourceContextId id42{42};
|
||||
SourceContextId id43{43};
|
||||
SourceContextId id44{44};
|
||||
SourceContextId id45{45};
|
||||
};
|
||||
|
||||
using CacheTypes = ::testing::Types<CacheWithMockLocking, CacheWithoutLocking>;
|
||||
@@ -118,7 +124,7 @@ TYPED_TEST(StorageCache, AddFilePath)
|
||||
{
|
||||
auto id = this->cache.id(this->filePath1);
|
||||
|
||||
ASSERT_THAT(id, 0);
|
||||
ASSERT_THAT(id, this->id1);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, AddSecondFilePath)
|
||||
@@ -127,7 +133,7 @@ TYPED_TEST(StorageCache, AddSecondFilePath)
|
||||
|
||||
auto id = this->cache.id(this->filePath2);
|
||||
|
||||
ASSERT_THAT(id, 1);
|
||||
ASSERT_THAT(id, this->id2);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, AddDuplicateFilePath)
|
||||
@@ -136,7 +142,7 @@ TYPED_TEST(StorageCache, AddDuplicateFilePath)
|
||||
|
||||
auto id = this->cache.id(this->filePath1);
|
||||
|
||||
ASSERT_THAT(id, 0);
|
||||
ASSERT_THAT(id, this->id1);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, AddDuplicateFilePathBetweenOtherEntries)
|
||||
@@ -148,14 +154,14 @@ TYPED_TEST(StorageCache, AddDuplicateFilePathBetweenOtherEntries)
|
||||
|
||||
auto id = this->cache.id(this->filePath3);
|
||||
|
||||
ASSERT_THAT(id, 2);
|
||||
ASSERT_THAT(id, this->id3);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, GetFilePathForIdWithOneEntry)
|
||||
{
|
||||
this->cache.id(this->filePath1);
|
||||
|
||||
auto filePath = this->cache.value(0);
|
||||
auto filePath = this->cache.value(this->id1);
|
||||
|
||||
ASSERT_THAT(filePath, this->filePath1);
|
||||
}
|
||||
@@ -167,7 +173,7 @@ TYPED_TEST(StorageCache, GetFilePathForIdWithSomeEntries)
|
||||
this->cache.id(this->filePath3);
|
||||
this->cache.id(this->filePath4);
|
||||
|
||||
auto filePath = this->cache.value(2);
|
||||
auto filePath = this->cache.value(this->id3);
|
||||
|
||||
ASSERT_THAT(filePath, this->filePath3);
|
||||
}
|
||||
@@ -179,7 +185,7 @@ TYPED_TEST(StorageCache, GetAllFilePaths)
|
||||
this->cache.id(this->filePath3);
|
||||
this->cache.id(this->filePath4);
|
||||
|
||||
auto filePaths = this->cache.values({0, 1, 2, 3});
|
||||
auto filePaths = this->cache.values({this->id1, this->id2, this->id3, this->id4});
|
||||
|
||||
ASSERT_THAT(filePaths,
|
||||
ElementsAre(this->filePath1, this->filePath2, this->filePath3, this->filePath4));
|
||||
@@ -189,14 +195,14 @@ TYPED_TEST(StorageCache, AddFilePaths)
|
||||
{
|
||||
auto ids = this->cache.ids({this->filePath1, this->filePath2, this->filePath3, this->filePath4});
|
||||
|
||||
ASSERT_THAT(ids, ElementsAre(0, 1, 2, 3));
|
||||
ASSERT_THAT(ids, ElementsAre(this->id1, this->id2, this->id3, this->id4));
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, AddFilePathsWithStorageFunction)
|
||||
{
|
||||
auto ids = this->cache.ids({"foo", "taa", "poo", "bar"});
|
||||
|
||||
ASSERT_THAT(ids, UnorderedElementsAre(42, 43, 44, 45));
|
||||
ASSERT_THAT(ids, UnorderedElementsAre(this->id42, this->id43, this->id44, this->id45));
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, IsEmpty)
|
||||
@@ -226,10 +232,10 @@ TYPED_TEST(StorageCache, PopulateWithEmptyVector)
|
||||
|
||||
TYPED_TEST(StorageCache, IsNotEmptyAfterPopulateWithSomeEntries)
|
||||
{
|
||||
typename TypeParam::CacheEntries entries{{this->filePath1.clone(), 0},
|
||||
{this->filePath2.clone(), 3},
|
||||
{this->filePath3.clone(), 2},
|
||||
{this->filePath4.clone(), 5}};
|
||||
typename TypeParam::CacheEntries entries{{this->filePath1.clone(), this->id1},
|
||||
{this->filePath2.clone(), this->id4},
|
||||
{this->filePath3.clone(), this->id3},
|
||||
{this->filePath4.clone(), SourceContextId{5}}};
|
||||
|
||||
this->cache.uncheckedPopulate(std::move(entries));
|
||||
|
||||
@@ -238,33 +244,33 @@ TYPED_TEST(StorageCache, IsNotEmptyAfterPopulateWithSomeEntries)
|
||||
|
||||
TYPED_TEST(StorageCache, GetEntryAfterPopulateWithSomeEntries)
|
||||
{
|
||||
typename TypeParam::CacheEntries entries{{this->filePath1.clone(), 0},
|
||||
{this->filePath2.clone(), 1},
|
||||
{this->filePath3.clone(), 7},
|
||||
{this->filePath4.clone(), 3}};
|
||||
typename TypeParam::CacheEntries entries{{this->filePath1.clone(), this->id1},
|
||||
{this->filePath2.clone(), this->id2},
|
||||
{this->filePath3.clone(), SourceContextId{7}},
|
||||
{this->filePath4.clone(), this->id4}};
|
||||
this->cache.uncheckedPopulate(std::move(entries));
|
||||
|
||||
auto value = this->cache.value(7);
|
||||
auto value = this->cache.value(SourceContextId{7});
|
||||
|
||||
ASSERT_THAT(value, this->filePath3);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, EntriesHaveUniqueIds)
|
||||
{
|
||||
typename TypeParam::CacheEntries entries{{this->filePath1.clone(), 0},
|
||||
{this->filePath2.clone(), 1},
|
||||
{this->filePath3.clone(), 2},
|
||||
{this->filePath4.clone(), 2}};
|
||||
typename TypeParam::CacheEntries entries{{this->filePath1.clone(), this->id1},
|
||||
{this->filePath2.clone(), this->id2},
|
||||
{this->filePath3.clone(), this->id3},
|
||||
{this->filePath4.clone(), this->id3}};
|
||||
|
||||
ASSERT_THROW(this->cache.populate(std::move(entries)), StorageCacheException);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, MultipleEntries)
|
||||
{
|
||||
typename TypeParam::CacheEntries entries{{this->filePath1.clone(), 0},
|
||||
{this->filePath1.clone(), 1},
|
||||
{this->filePath3.clone(), 2},
|
||||
{this->filePath4.clone(), 3}};
|
||||
typename TypeParam::CacheEntries entries{{this->filePath1.clone(), this->id1},
|
||||
{this->filePath1.clone(), this->id2},
|
||||
{this->filePath3.clone(), this->id3},
|
||||
{this->filePath4.clone(), this->id4}};
|
||||
|
||||
ASSERT_THROW(this->cache.populate(std::move(entries)), StorageCacheException);
|
||||
}
|
||||
@@ -288,7 +294,7 @@ TYPED_TEST(StorageCache, IdWithStorageFunctionIsReadAndWriteLockedForUnknownEntr
|
||||
EXPECT_CALL(this->mockMutex, lock_shared());
|
||||
EXPECT_CALL(this->mockMutex, unlock_shared());
|
||||
EXPECT_CALL(this->mockMutex, lock());
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo")));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo")));
|
||||
EXPECT_CALL(this->mockMutex, unlock());
|
||||
|
||||
this->cache.id("foo");
|
||||
@@ -302,7 +308,7 @@ TYPED_TEST(StorageCache, IdWithStorageFunctionIsReadLockedForKnownEntry)
|
||||
EXPECT_CALL(this->mockMutex, lock_shared());
|
||||
EXPECT_CALL(this->mockMutex, unlock_shared());
|
||||
EXPECT_CALL(this->mockMutex, lock()).Times(0);
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo"))).Times(0);
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))).Times(0);
|
||||
EXPECT_CALL(this->mockMutex, unlock()).Times(0);
|
||||
|
||||
this->cache.id("foo");
|
||||
@@ -363,29 +369,29 @@ TYPED_TEST(StorageCache, ValueWithStorageFunctionIsReadAndWriteLockedForUnknownI
|
||||
EXPECT_CALL(this->mockMutex, lock_shared());
|
||||
EXPECT_CALL(this->mockMutex, unlock_shared());
|
||||
EXPECT_CALL(this->mockMutex, lock());
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(41)));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextPath(Eq(this->id41)));
|
||||
EXPECT_CALL(this->mockMutex, unlock());
|
||||
|
||||
this->cache.value(41);
|
||||
this->cache.value(this->id41);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, ValueWithStorageFunctionIsReadLockedForKnownId)
|
||||
{
|
||||
InSequence s;
|
||||
this->cache.value(41);
|
||||
this->cache.value(this->id41);
|
||||
|
||||
EXPECT_CALL(this->mockMutex, lock_shared());
|
||||
EXPECT_CALL(this->mockMutex, unlock_shared());
|
||||
EXPECT_CALL(this->mockMutex, lock()).Times(0);
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(41))).Times(0);
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextPath(Eq(this->id41))).Times(0);
|
||||
EXPECT_CALL(this->mockMutex, unlock()).Times(0);
|
||||
|
||||
this->cache.value(41);
|
||||
this->cache.value(this->id41);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, IdWithStorageFunctionWhichHasNoEntryIsCallingStorageFunction)
|
||||
{
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo")));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo")));
|
||||
|
||||
this->cache.id("foo");
|
||||
}
|
||||
@@ -394,7 +400,7 @@ TYPED_TEST(StorageCache, IdWithStorageFunctionWhichHasEntryIsNotCallingStorageFu
|
||||
{
|
||||
this->cache.id("foo");
|
||||
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo"))).Times(0);
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))).Times(0);
|
||||
|
||||
this->cache.id("foo");
|
||||
}
|
||||
@@ -405,14 +411,14 @@ TYPED_TEST(StorageCache, IndexOfIdWithStorageFunctionWhichHasEntry)
|
||||
|
||||
auto index = this->cache.id("foo");
|
||||
|
||||
ASSERT_THAT(index, 42);
|
||||
ASSERT_THAT(index, this->id42);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, IndexOfIdWithStorageFunctionWhichHasNoEntry)
|
||||
{
|
||||
auto index = this->cache.id("foo");
|
||||
|
||||
ASSERT_THAT(index, 42);
|
||||
ASSERT_THAT(index, this->id42);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, GetEntryByIndexAfterInsertingByCustomIndex)
|
||||
@@ -424,34 +430,35 @@ TYPED_TEST(StorageCache, GetEntryByIndexAfterInsertingByCustomIndex)
|
||||
ASSERT_THAT(value, Eq("foo"));
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, CallFetchDirectoryPathForLowerIndex)
|
||||
TYPED_TEST(StorageCache, CallFetchSourceContextPathForLowerIndex)
|
||||
{
|
||||
auto index = this->cache.id("foo");
|
||||
SourceContextId lowerIndex{&index - 1};
|
||||
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(index - 1)));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextPath(Eq(lowerIndex)));
|
||||
|
||||
this->cache.value(index - 1);
|
||||
this->cache.value(lowerIndex);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, CallFetchDirectoryPathForUnknownIndex)
|
||||
TYPED_TEST(StorageCache, CallFetchSourceContextPathForUnknownIndex)
|
||||
{
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(0)));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextPath(Eq(this->id1)));
|
||||
|
||||
this->cache.value(0);
|
||||
this->cache.value(this->id1);
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, FetchDirectoryPathForUnknownIndex)
|
||||
TYPED_TEST(StorageCache, FetchSourceContextPathForUnknownIndex)
|
||||
{
|
||||
auto value = this->cache.value(41);
|
||||
auto value = this->cache.value(this->id41);
|
||||
|
||||
ASSERT_THAT(value, Eq("bar"));
|
||||
}
|
||||
|
||||
TYPED_TEST(StorageCache, AddCalls)
|
||||
{
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo")));
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("bar")));
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("poo")));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo")));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("bar")));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("poo")));
|
||||
|
||||
this->cache.add({"foo", "bar", "poo"});
|
||||
}
|
||||
@@ -460,8 +467,8 @@ TYPED_TEST(StorageCache, AddCallsOnlyForNewValues)
|
||||
{
|
||||
this->cache.add({"foo", "poo"});
|
||||
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("taa")));
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("bar")));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("taa")));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("bar")));
|
||||
|
||||
this->cache.add({"foo", "bar", "poo", "taa"});
|
||||
}
|
||||
@@ -508,12 +515,12 @@ TYPED_TEST(StorageCache, FetchIdsFromStorageCalls)
|
||||
EXPECT_CALL(this->mockMutex, lock_shared());
|
||||
EXPECT_CALL(this->mockMutex, unlock_shared());
|
||||
EXPECT_CALL(this->mockMutex, lock());
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("foo")));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo")));
|
||||
EXPECT_CALL(this->mockMutex, unlock());
|
||||
EXPECT_CALL(this->mockMutex, lock_shared());
|
||||
EXPECT_CALL(this->mockMutex, unlock_shared());
|
||||
EXPECT_CALL(this->mockMutex, lock());
|
||||
EXPECT_CALL(this->mockStorage, fetchDirectoryId(Eq("bar")));
|
||||
EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("bar")));
|
||||
EXPECT_CALL(this->mockMutex, unlock());
|
||||
|
||||
this->cache.ids({"foo", "bar"});
|
||||
|
||||
@@ -144,7 +144,11 @@ SOURCES += \
|
||||
sqlstatementbuilder-test.cpp \
|
||||
createtablesqlstatementbuilder-test.cpp \
|
||||
sqlitereadstatementmock.cpp \
|
||||
sqlitewritestatementmock.cpp
|
||||
sqlitewritestatementmock.cpp \
|
||||
sqlitereadwritestatementmock.cpp \
|
||||
sourcepath-test.cpp \
|
||||
sourcepathview-test.cpp \
|
||||
projectstorage-test.cpp
|
||||
|
||||
!isEmpty(QTC_UNITTEST_BUILD_CPP_PARSER):SOURCES += matchingtext-test.cpp
|
||||
|
||||
@@ -319,7 +323,9 @@ HEADERS += \
|
||||
sqlitereadstatementmock.h \
|
||||
sqlitestatementmock.h \
|
||||
sqlitetransactionbackendmock.h \
|
||||
sqlitewritestatementmock.h
|
||||
sqlitewritestatementmock.h \
|
||||
sqlitereadwritestatementmock.h \
|
||||
projectstoragemock.h
|
||||
|
||||
|
||||
!isEmpty(LIBCLANG_LIBS) {
|
||||
|
||||
Reference in New Issue
Block a user