aboutsummaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorMarco Bubke <marco.bubke@qt.io>2021-09-28 17:05:23 +0200
committerMarco Bubke <marco.bubke@qt.io>2021-10-14 07:40:49 +0000
commit1b16eb209ce05aa6e36215a79d21931b164926d6 (patch)
treea362cb43c13827059df00342edd84f1a4602f474 /tests
parentcbf96341a1681de0898706a7c3896b69d4b6d362 (diff)
QmlDesigner: Add QmlDocumentParser and QmlTypesParser
Task-number: QDS-5174 Task-number: QDS-5228 Change-Id: I0889e8d63b0260aeb0efae1b3c8a373c18ea1f03 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'tests')
-rw-r--r--tests/unit/unittest/CMakeLists.txt18
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp29
-rw-r--r--tests/unit/unittest/gtest-creator-printing.h2
-rw-r--r--tests/unit/unittest/projectstorageupdater-test.cpp15
-rw-r--r--tests/unit/unittest/qmldocumentparser-test.cpp243
-rw-r--r--tests/unit/unittest/qmldom-test.cpp51
-rw-r--r--tests/unit/unittest/qmltypesparser-test.cpp410
-rw-r--r--tests/unit/unittest/qmltypesparsermock.h3
8 files changed, 701 insertions, 70 deletions
diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt
index 6252f4517d..36aa86e631 100644
--- a/tests/unit/unittest/CMakeLists.txt
+++ b/tests/unit/unittest/CMakeLists.txt
@@ -481,8 +481,7 @@ get_filename_component(
ABSOLUTE
)
-
-if (EXISTS ../../../../qmldom_standalone/src/qmldom/standalone)
+if(EXISTS ${QMLDOM_STANDALONE_CMAKELISTS} AND Qt6_FOUND)
add_subdirectory(
../../../../qmldom_standalone/src/qmldom/standalone
${CMAKE_CURRENT_BINARY_DIR}/qmldom_standalone)
@@ -491,9 +490,16 @@ if (EXISTS ../../../../qmldom_standalone/src/qmldom/standalone)
RUNTIME_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,RUNTIME_OUTPUT_DIRECTORY>"
LIBRARY_OUTPUT_DIRECTORY "$<TARGET_PROPERTY:QmlJS,LIBRARY_OUTPUT_DIRECTORY>")
- extend_qtc_test(unittest
- DEPENDS qmldomlib
- SOURCES
- qmldom-test.cpp
+ extend_qtc_test(unittest
+ DEPENDS qmldomlib
+ SOURCES
+ qmldocumentparser-test.cpp
+ qmltypesparser-test.cpp
+ )
+ extend_qtc_test(unittest
+ SOURCES_PREFIX "${QmlDesignerDir}/designercore"
+ SOURCES
+ projectstorage/qmldocumentparser.cpp projectstorage/qmldocumentparser.h
+ projectstorage/qmltypesparser.cpp projectstorage/qmltypesparser.h
)
endif()
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 89577c1f05..85ff406f95 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -934,7 +934,7 @@ std::ostream &operator<<(std::ostream &out, const Diagnostic &diag) {
} // namespace ClangTools
namespace QmlDesigner {
-
+namespace {
const char *sourceTypeToText(SourceType sourceType)
{
switch (sourceType) {
@@ -950,6 +950,7 @@ const char *sourceTypeToText(SourceType sourceType)
return "";
}
+} // namespace
std::ostream &operator<<(std::ostream &out, const FileStatus &fileStatus)
{
@@ -1015,8 +1016,8 @@ TypeAccessSemantics cleanFlags(TypeAccessSemantics accessSemantics)
const char *typeAccessSemanticsToString(TypeAccessSemantics accessSemantics)
{
switch (cleanFlags(accessSemantics)) {
- case TypeAccessSemantics::Invalid:
- return "Invalid";
+ case TypeAccessSemantics::None:
+ return "None";
case TypeAccessSemantics::Reference:
return "Reference";
case TypeAccessSemantics::Sequence:
@@ -1055,6 +1056,20 @@ const char *isQualifiedToString(IsQualified isQualified)
return "";
}
+const char *importKindToText(ImportKind kind)
+{
+ switch (kind) {
+ case ImportKind::Module:
+ return "Module";
+ case ImportKind::Directory:
+ return "Directory";
+ case ImportKind::QmlTypesDependency:
+ return "QmlTypesDependency";
+ }
+
+ return "";
+}
+
} // namespace
std::ostream &operator<<(std::ostream &out, TypeAccessSemantics accessSemantics)
@@ -1176,9 +1191,15 @@ std::ostream &operator<<(std::ostream &out, const Module &module)
return out << "(" << module.name << ", " << module.sourceId << ")";
}
+std::ostream &operator<<(std::ostream &out, const ImportKind &importKind)
+{
+ return out << importKindToText(importKind);
+}
+
std::ostream &operator<<(std::ostream &out, const Import &import)
{
- return out << "(" << import.name << ", " << import.version << ", " << import.sourceId << ")";
+ return out << "(" << import.name << ", " << import.version << ", " << import.sourceId << ", "
+ << import.moduleId << ", " << import.kind << ")";
}
} // namespace Storage
diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h
index d2c20d92b5..5b8cb51e8e 100644
--- a/tests/unit/unittest/gtest-creator-printing.h
+++ b/tests/unit/unittest/gtest-creator-printing.h
@@ -262,6 +262,7 @@ class EnumerationDeclaration;
class EnumeratorDeclaration;
class Module;
class ModuleDependency;
+enum class ImportKind : char;
class Import;
enum class IsQualified : int;
@@ -282,6 +283,7 @@ std::ostream &operator<<(std::ostream &out, const EnumerationDeclaration &enumer
std::ostream &operator<<(std::ostream &out, const EnumeratorDeclaration &enumeratorDeclaration);
std::ostream &operator<<(std::ostream &out, const Module &module);
std::ostream &operator<<(std::ostream &out, const ModuleDependency &module);
+std::ostream &operator<<(std::ostream &out, const ImportKind &importKind);
std::ostream &operator<<(std::ostream &out, const Import &import);
std::ostream &operator<<(std::ostream &out, IsQualified isQualified);
diff --git a/tests/unit/unittest/projectstorageupdater-test.cpp b/tests/unit/unittest/projectstorageupdater-test.cpp
index d198587821..d6a26bb109 100644
--- a/tests/unit/unittest/projectstorageupdater-test.cpp
+++ b/tests/unit/unittest/projectstorageupdater-test.cpp
@@ -305,8 +305,8 @@ TEST_F(ProjectStorageUpdater, ParseQmlTypes)
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example2.qmltypes"))))
.WillByDefault(Return(qmltypes2));
- EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _));
- EXPECT_CALL(qmlTypesParserMock, parse(qmltypes2, _, _, _));
+ EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _));
+ EXPECT_CALL(qmlTypesParserMock, parse(qmltypes2, _, _, _, _));
updater.update();
}
@@ -334,8 +334,8 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
QString qmltypes{"Module {\ndependencies: []}"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
.WillByDefault(Return(qmltypes));
- ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _))
- .WillByDefault([&](auto, auto &imports, auto &types, auto &sourceIds) {
+ ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _))
+ .WillByDefault([&](auto, auto &imports, auto &types, auto, auto) {
types.push_back(objectType);
imports.push_back(import);
});
@@ -356,10 +356,9 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesAreEmptyIfFileDoesNotChanged)
QString qmltypes{"Module {\ndependencies: []}"};
ON_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes"))))
.WillByDefault(Return(qmltypes));
- ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _))
- .WillByDefault([&](auto, auto &imports, auto &types, auto &sourceIds) {
- types.push_back(objectType);
- });
+ ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _))
+ .WillByDefault(
+ [&](auto, auto &imports, auto &types, auto, auto) { types.push_back(objectType); });
ON_CALL(fileSystemMock, fileStatus(Eq(qmltypesPathSourceId)))
.WillByDefault(Return(FileStatus{qmltypesPathSourceId, 2, 421}));
ON_CALL(fileSystemMock, fileStatus(Eq(qmltypes2PathSourceId)))
diff --git a/tests/unit/unittest/qmldocumentparser-test.cpp b/tests/unit/unittest/qmldocumentparser-test.cpp
new file mode 100644
index 0000000000..4cadf8253d
--- /dev/null
+++ b/tests/unit/unittest/qmldocumentparser-test.cpp
@@ -0,0 +1,243 @@
+/****************************************************************************
+**
+** 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 <sqlitedatabase.h>
+
+#include <projectstorage/projectstorage.h>
+#include <projectstorage/qmldocumentparser.h>
+#include <projectstorage/sourcepathcache.h>
+
+namespace {
+
+namespace Storage = QmlDesigner::Storage;
+using QmlDesigner::ModuleId;
+using QmlDesigner::SourceContextId;
+using QmlDesigner::SourceId;
+
+MATCHER_P(HasPrototype, prototype, std::string(negation ? "isn't " : "is ") + PrintToString(prototype))
+{
+ const Storage::Type &type = arg;
+
+ return Storage::ImportedTypeName{prototype} == type.prototype;
+}
+
+MATCHER_P3(IsPropertyDeclaration,
+ name,
+ typeName,
+ traits,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::PropertyDeclaration{name, typeName, traits}))
+{
+ const Storage::PropertyDeclaration &propertyDeclaration = arg;
+
+ return propertyDeclaration.name == name
+ && Storage::ImportedTypeName{typeName} == propertyDeclaration.typeName
+ && propertyDeclaration.traits == traits;
+}
+
+MATCHER_P2(IsFunctionDeclaration,
+ name,
+ returnTypeName,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::FunctionDeclaration{name, returnTypeName}))
+{
+ const Storage::FunctionDeclaration &declaration = arg;
+
+ return declaration.name == name && declaration.returnTypeName == returnTypeName;
+}
+
+MATCHER_P(IsSignalDeclaration,
+ name,
+ std::string(negation ? "isn't " : "is ") + PrintToString(Storage::SignalDeclaration{name}))
+{
+ const Storage::SignalDeclaration &declaration = arg;
+
+ return declaration.name == name;
+}
+
+MATCHER_P2(IsParameter,
+ name,
+ typeName,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::ParameterDeclaration{name, typeName}))
+{
+ const Storage::ParameterDeclaration &declaration = arg;
+
+ return declaration.name == name && declaration.typeName == typeName;
+}
+
+MATCHER_P(IsEnumeration,
+ name,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::EnumerationDeclaration{name, {}}))
+{
+ const Storage::EnumerationDeclaration &declaration = arg;
+
+ return declaration.name == name;
+}
+
+MATCHER_P(IsEnumerator,
+ name,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::EnumeratorDeclaration{name}))
+{
+ const Storage::EnumeratorDeclaration &declaration = arg;
+
+ return declaration.name == name && !declaration.hasValue;
+}
+
+MATCHER_P2(IsEnumerator,
+ name,
+ value,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::EnumeratorDeclaration{name, value, true}))
+{
+ const Storage::EnumeratorDeclaration &declaration = arg;
+
+ return declaration.name == name && declaration.value == value && declaration.hasValue;
+}
+
+class QmlDocumentParser : public ::testing::Test
+{
+public:
+protected:
+ Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
+ QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
+ QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
+ storage};
+ QmlDesigner::QmlDocumentParser parser{sourcePathCache};
+ Storage::Imports imports;
+ SourceId qmlFileSourceId{sourcePathCache.sourceId("path/to/qmlfile.qml")};
+ SourceContextId qmlFileSourceContextId{sourcePathCache.sourceContextId(qmlFileSourceId)};
+ SourceId directorySourceId{sourcePathCache.sourceId("path/to/.")};
+ ModuleId directoryModuleId{&directorySourceId};
+};
+
+TEST_F(QmlDocumentParser, Prototype)
+{
+ auto type = parser.parse("Example{}", imports, qmlFileSourceId, qmlFileSourceContextId);
+
+ ASSERT_THAT(type, HasPrototype(Storage::ImportedType("Example")));
+}
+
+TEST_F(QmlDocumentParser, DISABLED_QualifiedPrototype)
+{
+ auto type = parser.parse("import Example as Example\n Example.Item{}",
+ imports,
+ qmlFileSourceId,
+ qmlFileSourceContextId);
+
+ ASSERT_THAT(type,
+ HasPrototype(Storage::QualifiedImportedType(
+ "Item", Storage::Import{"Example", Storage::Version{}, qmlFileSourceId})));
+}
+
+TEST_F(QmlDocumentParser, Properties)
+{
+ auto type = parser.parse("Example{\n property int foo\n}",
+ imports,
+ qmlFileSourceId,
+ qmlFileSourceContextId);
+
+ ASSERT_THAT(type.propertyDeclarations,
+ UnorderedElementsAre(IsPropertyDeclaration("foo",
+ Storage::ImportedType{"int"},
+ Storage::PropertyDeclarationTraits::None)));
+}
+
+TEST_F(QmlDocumentParser, DISABLED_Imports)
+{
+ ModuleId fooDirectoryModuleId{&sourcePathCache.sourceId("path/to/foo/.")};
+ auto type = parser.parse("import QtQuick\n import \"../foo\"\nExample{}",
+ imports,
+ qmlFileSourceId,
+ qmlFileSourceContextId);
+
+ ASSERT_THAT(imports,
+ UnorderedElementsAre(
+ Storage::Import{Storage::Version{}, directoryModuleId, qmlFileSourceId},
+ Storage::Import{Storage::Version{}, fooDirectoryModuleId, qmlFileSourceId},
+ Storage::Import{"QML", Storage::Version{1, 0}, qmlFileSourceId},
+ Storage::Import{"QtQml", Storage::Version{6, 0}, qmlFileSourceId},
+ Storage::Import{"QtQuick", Storage::Version{}, qmlFileSourceId}));
+}
+
+TEST_F(QmlDocumentParser, Functions)
+{
+ auto type = parser.parse(
+ "Example{\n function someScript(x, y) {}\n function otherFunction() {}\n}",
+ imports,
+ qmlFileSourceId,
+ qmlFileSourceContextId);
+
+ ASSERT_THAT(type.functionDeclarations,
+ UnorderedElementsAre(AllOf(IsFunctionDeclaration("otherFunction", ""),
+ Field(&Storage::FunctionDeclaration::parameters, IsEmpty())),
+ AllOf(IsFunctionDeclaration("someScript", ""),
+ Field(&Storage::FunctionDeclaration::parameters,
+ ElementsAre(IsParameter("x", ""),
+ IsParameter("y", ""))))));
+}
+
+TEST_F(QmlDocumentParser, Signals)
+{
+ auto type = parser.parse("Example{\n signal someSignal(int x, real y)\n signal signal2()\n}",
+ imports,
+ qmlFileSourceId,
+ qmlFileSourceContextId);
+
+ ASSERT_THAT(type.signalDeclarations,
+ UnorderedElementsAre(AllOf(IsSignalDeclaration("someSignal"),
+ Field(&Storage::SignalDeclaration::parameters,
+ ElementsAre(IsParameter("x", "int"),
+ IsParameter("y", "real")))),
+ AllOf(IsSignalDeclaration("signal2"),
+ Field(&Storage::SignalDeclaration::parameters, IsEmpty()))));
+}
+
+TEST_F(QmlDocumentParser, Enumeration)
+{
+ auto type = parser.parse("Example{\n enum Color{red, green, blue=10, white}\n enum "
+ "State{On,Off}\n}",
+ imports,
+ qmlFileSourceId,
+ qmlFileSourceContextId);
+
+ ASSERT_THAT(type.enumerationDeclarations,
+ UnorderedElementsAre(
+ AllOf(IsEnumeration("Color"),
+ Field(&Storage::EnumerationDeclaration::enumeratorDeclarations,
+ ElementsAre(IsEnumerator("red", 0),
+ IsEnumerator("green", 1),
+ IsEnumerator("blue", 10),
+ IsEnumerator("white", 11)))),
+ AllOf(IsEnumeration("State"),
+ Field(&Storage::EnumerationDeclaration::enumeratorDeclarations,
+ ElementsAre(IsEnumerator("On", 0), IsEnumerator("Off", 1))))));
+}
+
+} // namespace
diff --git a/tests/unit/unittest/qmldom-test.cpp b/tests/unit/unittest/qmldom-test.cpp
deleted file mode 100644
index b7e8557f10..0000000000
--- a/tests/unit/unittest/qmldom-test.cpp
+++ /dev/null
@@ -1,51 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of Qt Creator.
-**
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-****************************************************************************/
-
-#include "googletest.h"
-
-// cast of the top level items (DomEnvironments,...)
-#include <qmldom/qqmldomtop_p.h>
-
-// everything is in the QQmlJS::Dom namespace
-using namespace QQmlJS::Dom;
-
-namespace {
-
-class QmlDom : public ::testing::Test
-{
-public:
-// static void SetUpTestCase();
-// static void TearDownTestCase();
-
-protected:
-};
-
-TEST_F(QmlDom, First)
-{
- DomItem env = DomEnvironment::create({}, DomEnvironment::Option::SingleThreaded
- | DomEnvironment::Option::NoDependencies);
-}
-
-} // anonymous
diff --git a/tests/unit/unittest/qmltypesparser-test.cpp b/tests/unit/unittest/qmltypesparser-test.cpp
new file mode 100644
index 0000000000..fcd182b920
--- /dev/null
+++ b/tests/unit/unittest/qmltypesparser-test.cpp
@@ -0,0 +1,410 @@
+/****************************************************************************
+**
+** 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 <sqlitedatabase.h>
+
+#include <projectstorage/projectstorage.h>
+#include <projectstorage/projectstoragetypes.h>
+#include <projectstorage/qmltypesparser.h>
+#include <projectstorage/sourcepathcache.h>
+
+namespace {
+
+namespace Storage = QmlDesigner::Storage;
+using QmlDesigner::ModuleId;
+using QmlDesigner::SourceContextId;
+using QmlDesigner::SourceId;
+
+MATCHER_P4(IsImport,
+ name,
+ version,
+ sourceId,
+ kind,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::Import{name, version, sourceId, kind}))
+{
+ const Storage::Import &import = arg;
+
+ return import.name == name && import.version == version && import.sourceId == sourceId
+ && import.kind == kind;
+}
+
+MATCHER_P(HasPrototype, prototype, std::string(negation ? "isn't " : "is ") + PrintToString(prototype))
+{
+ const Storage::Type &type = arg;
+
+ return Storage::ImportedTypeName{prototype} == type.prototype;
+}
+
+MATCHER_P5(IsType,
+ moduleId,
+ typeName,
+ prototype,
+ accessSemantics,
+ sourceId,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::Type{moduleId, typeName, prototype, accessSemantics, sourceId}))
+{
+ const Storage::Type &type = arg;
+
+ return type.moduleId == moduleId && type.typeName == typeName
+ && type.prototype == Storage::ImportedTypeName{prototype}
+ && type.accessSemantics == accessSemantics && type.sourceId == sourceId;
+}
+
+MATCHER_P3(IsPropertyDeclaration,
+ name,
+ typeName,
+ traits,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::PropertyDeclaration{name, typeName, traits}))
+{
+ const Storage::PropertyDeclaration &propertyDeclaration = arg;
+
+ return propertyDeclaration.name == name
+ && Storage::ImportedTypeName{typeName} == propertyDeclaration.typeName
+ && propertyDeclaration.traits == traits
+ && propertyDeclaration.kind == Storage::PropertyKind::Property;
+}
+
+MATCHER_P2(IsFunctionDeclaration,
+ name,
+ returnTypeName,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::FunctionDeclaration{name, returnTypeName}))
+{
+ const Storage::FunctionDeclaration &declaration = arg;
+
+ return declaration.name == name && declaration.returnTypeName == returnTypeName;
+}
+
+MATCHER_P(IsSignalDeclaration,
+ name,
+ std::string(negation ? "isn't " : "is ") + PrintToString(Storage::SignalDeclaration{name}))
+{
+ const Storage::SignalDeclaration &declaration = arg;
+
+ return declaration.name == name;
+}
+
+MATCHER_P2(IsParameter,
+ name,
+ typeName,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::ParameterDeclaration{name, typeName}))
+{
+ const Storage::ParameterDeclaration &declaration = arg;
+
+ return declaration.name == name && declaration.typeName == typeName;
+}
+
+MATCHER_P(IsEnumeration,
+ name,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::EnumerationDeclaration{name, {}}))
+{
+ const Storage::EnumerationDeclaration &declaration = arg;
+
+ return declaration.name == name;
+}
+
+MATCHER_P(IsEnumerator,
+ name,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::EnumeratorDeclaration{name}))
+{
+ const Storage::EnumeratorDeclaration &declaration = arg;
+
+ return declaration.name == name && !declaration.hasValue;
+}
+
+MATCHER_P2(IsEnumerator,
+ name,
+ value,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::EnumeratorDeclaration{name, value, true}))
+{
+ const Storage::EnumeratorDeclaration &declaration = arg;
+
+ return declaration.name == name && declaration.value == value && declaration.hasValue;
+}
+
+MATCHER_P3(IsExportedType,
+ moduleId,
+ name,
+ version,
+ std::string(negation ? "isn't " : "is ")
+ + PrintToString(Storage::ExportedType{moduleId, name, version}))
+{
+ const Storage::ExportedType &type = arg;
+
+ return type.name == name && type.moduleId == moduleId && type.version == version;
+}
+
+class QmlTypesParser : public ::testing::Test
+{
+public:
+protected:
+ Sqlite::Database database{":memory:", Sqlite::JournalMode::Memory};
+ QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
+ QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
+ storage};
+ QmlDesigner::QmlTypesParser parser{sourcePathCache};
+ Storage::Imports imports;
+ Storage::Types types;
+ SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")};
+ SourceContextId qmltypesFileSourceContextId{sourcePathCache.sourceContextId(qmltypesFileSourceId)};
+ SourceId directorySourceId{sourcePathCache.sourceId("path/to/.")};
+ ModuleId directoryModuleId{&directorySourceId};
+};
+
+TEST_F(QmlTypesParser, Imports)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ dependencies:
+ ["QtQuick 2.15", "QtQuick.Window 2.1", "QtFoo 6"]})"};
+
+ parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId);
+
+ ASSERT_THAT(imports,
+ UnorderedElementsAre(IsImport("QtQuick",
+ Storage::Version{2, 15},
+ qmltypesFileSourceId,
+ Storage::ImportKind::QmlTypesDependency),
+ IsImport("QtQuick.Window",
+ Storage::Version{2, 1},
+ qmltypesFileSourceId,
+ Storage::ImportKind::QmlTypesDependency),
+ IsImport("QML",
+ Storage::Version{},
+ qmltypesFileSourceId,
+ Storage::ImportKind::QmlTypesDependency),
+ IsImport("QtQml",
+ Storage::Version{},
+ qmltypesFileSourceId,
+ Storage::ImportKind::QmlTypesDependency),
+ IsImport("QtFoo",
+ Storage::Version{6},
+ qmltypesFileSourceId,
+ Storage::ImportKind::QmlTypesDependency)));
+}
+
+TEST_F(QmlTypesParser, Types)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ Component { name: "QObject"}
+ Component { name: "QQmlComponent"
+ prototype: "QObject"}})"};
+
+ parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId);
+
+ ASSERT_THAT(types,
+ UnorderedElementsAre(IsType(directoryModuleId,
+ "QObject",
+ Storage::NativeType{},
+ Storage::TypeAccessSemantics::Reference,
+ qmltypesFileSourceId),
+ IsType(directoryModuleId,
+ "QQmlComponent",
+ Storage::NativeType{"QObject"},
+ Storage::TypeAccessSemantics::Reference,
+ qmltypesFileSourceId)));
+}
+
+TEST_F(QmlTypesParser, ExportedTypes)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ Component { name: "QObject"
+ exports: ["QtQml/QtObject 1.0", "QtQml/QtObject 2.1"]
+ }})"};
+
+ parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId);
+
+ ASSERT_THAT(
+ types,
+ ElementsAre(
+ Field(&Storage::Type::exportedTypes,
+ ElementsAre(IsExportedType(directoryModuleId, "QtObject", Storage::Version{1, 0}),
+ IsExportedType(directoryModuleId, "QtObject", Storage::Version{2, 1})))));
+}
+
+TEST_F(QmlTypesParser, Properties)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ Component { name: "QObject"
+ Property { name: "objectName"; type: "string" }
+ Property { name: "target"; type: "QObject"; isPointer: true }
+ Property { name: "progress"; type: "double"; isReadonly: true }
+ Property { name: "targets"; type: "QQuickItem"; isList: true; isReadonly: true; isPointer: true }
+ }})"};
+
+ parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId);
+
+ ASSERT_THAT(types,
+ ElementsAre(Field(
+ &Storage::Type::propertyDeclarations,
+ UnorderedElementsAre(
+ IsPropertyDeclaration("objectName",
+ Storage::NativeType{"string"},
+ Storage::PropertyDeclarationTraits::None),
+ IsPropertyDeclaration("target",
+ Storage::NativeType{"QObject"},
+ Storage::PropertyDeclarationTraits::IsPointer),
+ IsPropertyDeclaration("progress",
+ Storage::NativeType{"double"},
+ Storage::PropertyDeclarationTraits::IsReadOnly),
+ IsPropertyDeclaration("targets",
+ Storage::NativeType{"QQuickItem"},
+ Storage::PropertyDeclarationTraits::IsReadOnly
+ | Storage::PropertyDeclarationTraits::IsList
+ | Storage::PropertyDeclarationTraits::IsPointer)))));
+}
+
+TEST_F(QmlTypesParser, Functions)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ Component { name: "QObject"
+ Method { name: "movieUpdate" }
+ Method {
+ name: "advance"
+ Parameter { name: "frames"; type: "int" }
+ Parameter { name: "fps"; type: "double" }
+ }
+ Method {
+ name: "isImageLoading"
+ type: "bool"
+ Parameter { name: "url"; type: "QUrl" }
+ }
+ Method {
+ name: "getContext"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ }})"};
+
+ parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId);
+
+ ASSERT_THAT(types,
+ ElementsAre(
+ Field(&Storage::Type::functionDeclarations,
+ UnorderedElementsAre(
+ AllOf(IsFunctionDeclaration("advance", ""),
+ Field(&Storage::FunctionDeclaration::parameters,
+ UnorderedElementsAre(IsParameter("frames", "int"),
+ IsParameter("fps", "double")))),
+ AllOf(IsFunctionDeclaration("isImageLoading", "bool"),
+ Field(&Storage::FunctionDeclaration::parameters,
+ UnorderedElementsAre(IsParameter("url", "QUrl")))),
+ AllOf(IsFunctionDeclaration("getContext", ""),
+ Field(&Storage::FunctionDeclaration::parameters,
+ UnorderedElementsAre(IsParameter("args", "QQmlV4Function")))),
+ AllOf(IsFunctionDeclaration("movieUpdate", ""),
+ Field(&Storage::FunctionDeclaration::parameters, IsEmpty()))))));
+}
+
+TEST_F(QmlTypesParser, Signals)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ Component { name: "QObject"
+ Method { name: "movieUpdate" }
+ Signal {
+ name: "advance"
+ Parameter { name: "frames"; type: "int" }
+ Parameter { name: "fps"; type: "double" }
+ }
+ Signal {
+ name: "isImageLoading"
+ Parameter { name: "url"; type: "QUrl" }
+ }
+ Signal {
+ name: "getContext"
+ Parameter { name: "args"; type: "QQmlV4Function"; isPointer: true }
+ }
+ }})"};
+
+ parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId);
+
+ ASSERT_THAT(types,
+ ElementsAre(Field(&Storage::Type::signalDeclarations,
+ UnorderedElementsAre(
+ AllOf(IsSignalDeclaration("advance"),
+ Field(&Storage::SignalDeclaration::parameters,
+ UnorderedElementsAre(IsParameter("frames", "int"),
+ IsParameter("fps", "double")))),
+ AllOf(IsSignalDeclaration("isImageLoading"),
+ Field(&Storage::SignalDeclaration::parameters,
+ UnorderedElementsAre(IsParameter("url", "QUrl")))),
+ AllOf(IsSignalDeclaration("getContext"),
+ Field(&Storage::SignalDeclaration::parameters,
+ UnorderedElementsAre(
+ IsParameter("args", "QQmlV4Function"))))))));
+}
+
+TEST_F(QmlTypesParser, Enumerations)
+{
+ QString source{R"(import QtQuick.tooling 1.2
+ Module{
+ Component { name: "QObject"
+ Enum {
+ name: "NamedColorSpace"
+ values: [
+ "Unknown",
+ "SRgb",
+ "AdobeRgb",
+ "DisplayP3",
+ ]
+ }
+ Enum {
+ name: "VerticalLayoutDirection"
+ values: ["TopToBottom", "BottomToTop"]
+ }
+ }})"};
+
+ parser.parse(source, imports, types, qmltypesFileSourceId, directoryModuleId);
+
+ ASSERT_THAT(types,
+ ElementsAre(
+ Field(&Storage::Type::enumerationDeclarations,
+ UnorderedElementsAre(
+ AllOf(IsEnumeration("NamedColorSpace"),
+ Field(&Storage::EnumerationDeclaration::enumeratorDeclarations,
+ UnorderedElementsAre(IsEnumerator("Unknown"),
+ IsEnumerator("SRgb"),
+ IsEnumerator("AdobeRgb"),
+ IsEnumerator("DisplayP3")))),
+ AllOf(IsEnumeration("VerticalLayoutDirection"),
+ Field(&Storage::EnumerationDeclaration::enumeratorDeclarations,
+ UnorderedElementsAre(IsEnumerator("TopToBottom"),
+ IsEnumerator("BottomToTop"))))))));
+}
+
+} // namespace
diff --git a/tests/unit/unittest/qmltypesparsermock.h b/tests/unit/unittest/qmltypesparsermock.h
index 337c0f05ff..cfbb872984 100644
--- a/tests/unit/unittest/qmltypesparsermock.h
+++ b/tests/unit/unittest/qmltypesparsermock.h
@@ -37,6 +37,7 @@ public:
(const QString &sourceContent,
QmlDesigner::Storage::Imports &imports,
QmlDesigner::Storage::Types &types,
- QmlDesigner::SourceIds &sourceIds),
+ QmlDesigner::SourceId sourceId,
+ QmlDesigner::ModuleId moduleId),
(override));
};