aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/qmldom
diff options
context:
space:
mode:
authorFawzi Mohamed <fawzi.mohamed@qt.io>2020-10-10 23:14:02 +0200
committerFawzi Mohamed <fawzi.mohamed@qt.io>2020-12-03 16:42:24 +0100
commit9f56f7f7863427445d74c5d7580e92075b767dc2 (patch)
treeaf6d339ba7899f6806e38fc400e0d37faf2b2460 /tests/auto/qmldom
parent5e491b77b91f835801d6520f3c5c4ecbb33ef9e5 (diff)
qmldom: DomItem and common API
This commit adds the main API of the Dom model: The idea of the Dom Model is to expose a simplified an uniform model, while keeping typed objects (as one is used in C++, and ideally using the modern C++ approach with containers, and avoiding manual memory management). In particular this approach avoids reducing everything to an untyped model. The central object in this is the DomItem, it is a value type that keeps a pointer to the actual element. A non empty DomItem always keeps some context (a canonicalPath) and one can explore its containers and its contents. Non existing or missing values simply translate to empty DomItems and one does not need to check at each step for invalid things. See the DomItem documentation for more information. The as() ad ownerAs() templates let one cast back the DomItem to the underlying elements. To expose an element with minimal effort one has to mainly implement the method iterateDirectSubpaths(), and iterate through all elements contained in that element (see the documentation of DomBase for more details). Containers, simple data and references can be wrapped in DomItem elements just when accessed, so the underlying C++ object can use the usual containers/datatypes. A good model should not just be easy to browse, reference and extend with new elements, it should also have a clear parallelizazion/ multithreading policy. This is less relevant for a single pass compiler, but for is relevannt for a code model. The fact that the current code model now somehow works only from the GUI thread show the importance of a clear policy when multiple people can contribute. In the Dom model there is the following idea: - During build time pointers to the elements can change (MutableDomItem should be used) - Access to sub elements normally has no locks, they should be either accessed by a single thread or immutable. - OwningItem are the unit of multithread safe updates, the have a mutex and protect the parts that need protection - A DomEnvironment can refer to a parent Environment, perform several changes (in a separate thread), and commit them all at once (in a sparate commit). This commit contains all the main API, and tests for it. The bulk of the concrete element will be in followup patches. Task-number: QTBUG-74840 Change-Id: I9e14e8560e3b4aa3268a733fed37e9090c18e3ab Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tests/auto/qmldom')
-rw-r--r--tests/auto/qmldom/CMakeLists.txt1
-rw-r--r--tests/auto/qmldom/domitem/CMakeLists.txt17
-rw-r--r--tests/auto/qmldom/domitem/domitem.pro23
-rw-r--r--tests/auto/qmldom/domitem/tst_qmldomitem.cpp190
-rw-r--r--tests/auto/qmldom/qmldom.pro1
5 files changed, 232 insertions, 0 deletions
diff --git a/tests/auto/qmldom/CMakeLists.txt b/tests/auto/qmldom/CMakeLists.txt
index 7e6acf2c4a..0aa5b19484 100644
--- a/tests/auto/qmldom/CMakeLists.txt
+++ b/tests/auto/qmldom/CMakeLists.txt
@@ -2,4 +2,5 @@
add_subdirectory(errormessage)
add_subdirectory(path)
+add_subdirectory(domitem)
add_subdirectory(stringdumper)
diff --git a/tests/auto/qmldom/domitem/CMakeLists.txt b/tests/auto/qmldom/domitem/CMakeLists.txt
new file mode 100644
index 0000000000..28bcfdefa0
--- /dev/null
+++ b/tests/auto/qmldom/domitem/CMakeLists.txt
@@ -0,0 +1,17 @@
+# Generated from domitem.pro.
+
+#####################################################################
+## tst_qmldomitem Binary:
+#####################################################################
+
+qt_internal_add_test(tst_qmldomitem
+ SOURCES
+ tst_qmldomitem.cpp
+ DEFINES
+ QT_DEPRECATED_WARNINGS
+ PUBLIC_LIBRARIES
+ Qt::Core
+ Qt::QmlDevToolsPrivate
+ Qt::QmlDomPrivate
+ Qt::Test
+)
diff --git a/tests/auto/qmldom/domitem/domitem.pro b/tests/auto/qmldom/domitem/domitem.pro
new file mode 100644
index 0000000000..87801c7b8d
--- /dev/null
+++ b/tests/auto/qmldom/domitem/domitem.pro
@@ -0,0 +1,23 @@
+QT = core qmldevtools-private qmldom-private testlib
+TARGET = tst_qmldomitem
+
+
+CONFIG += c++11 console
+CONFIG -= app_bundle
+
+# The following define makes your compiler emit warnings if you use
+# any Qt feature that has been marked deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+# You can also make your code fail to compile if it uses deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
+
+SOURCES += \
+ tst_qmldomitem.cpp
+
+
+load(qt_common)
diff --git a/tests/auto/qmldom/domitem/tst_qmldomitem.cpp b/tests/auto/qmldom/domitem/tst_qmldomitem.cpp
new file mode 100644
index 0000000000..bec8db8c4a
--- /dev/null
+++ b/tests/auto/qmldom/domitem/tst_qmldomitem.cpp
@@ -0,0 +1,190 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQml module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**/
+#include <QtQmlDom/private/qqmldomitem_p.h>
+#include <QtQmlDom/private/qqmldomtop_p.h>
+
+#include <QtTest/QtTest>
+#include <QCborValue>
+#include <QDebug>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+namespace QQmlJS {
+namespace Dom {
+
+DomItem wrapInt(const DomItem &self, Path p, const int &i){
+ return self.subDataPath(p, i).item;
+}
+
+class TestDomItem: public QObject
+{
+ Q_OBJECT
+public:
+
+private slots:
+ void initTestCase() {
+ universePtr = std::make_shared<DomUniverse>(QStringLiteral(u"dummyUniverse"));
+ envPtr = std::make_shared<DomEnvironment>(universePtr, QStringList());
+ env = DomItem(envPtr);
+ }
+
+ void testList() {
+ QList<int> l({1,2,3,4});
+ QList<int> l2 = l;
+ QList<int> l3({1});
+ QList<int> l4 = l3;
+ QCOMPARE(&(l[1]), &(l[1]));
+ QCOMPARE(&(l3[0]), &(l3[0]));
+ // QCOMPARE(&(l3[0]), &(l4[0])); // shallow copy actually copies els (QVector behavior)...
+ DomItem list1 = env.subList(
+ List::fromQListRef<int>(Path::field(u"list"), l, &wrapInt)).item;
+ DomItem list2 = env.subList(
+ List::fromQListRef<int>(Path::field(u"reverseList"), l, &wrapInt, ListOptions::Reverse)).item;
+ QCOMPARE(list1.domKind(), DomKind::List);
+ QCOMPARE(list1.indexes(), 4);
+ QCOMPARE(list1[0].value().toInteger(), 1);
+ QCOMPARE(list1[3].value().toInteger(), 4);
+ QVERIFY(!list1[4]);
+ QCOMPARE(list1[4].value().toInteger(-1), -1);
+ QVERIFY(list1[0].value() != list2[0].value());
+ QCOMPARE(list1[0].value(), list2[3].value());
+ QCOMPARE(list1[3].value(), list2[0].value());
+ QCOMPARE(list1.container(), env);
+ }
+ void testMap() {
+ QMap<QString, int> map({{QStringLiteral(u"a"),1},{QStringLiteral(u"b"),2}});
+ //QMap<QString, int> map2 = map;
+ QMap<QString, int> map3({{QStringLiteral(u"a"),1}});
+ //QMap<QString, int> map4 = map3;
+ auto it = map.find(QStringLiteral(u"a"));
+ auto it2 = map.find(QStringLiteral(u"a"));
+ auto it3 = map3.find(QStringLiteral(u"a"));
+ auto it4 = map3.find(QStringLiteral(u"a"));
+ //auto it5 = map4.find(QStringLiteral(u"a"));
+ QVERIFY(it != map.end());
+ QVERIFY(it2 != map.end());
+ QCOMPARE(&(*it), &(*it2));
+ QCOMPARE(&(*it), &(map[QStringLiteral(u"a")]));
+ QCOMPARE(&(it.value()), &(it2.value()));
+ //QCOMPARE(&(*it), &(map2[QStringLiteral(u"a")]));
+ QCOMPARE(&(*it3), &(*it4));
+ //QCOMPARE(&(*it3), &(*it5));
+ DomItem map1 = env.subMap(
+ Map::fromMapRef<int>(
+ Path::field(u"map"), map,
+ &wrapInt)).item;
+ QCOMPARE(map1.domKind(), DomKind::Map);
+ QCOMPARE(map1[u"a"].value().toInteger(), 1);
+ QCOMPARE(map1.key(QStringLiteral(u"a")).value().toInteger(), 1);
+ QCOMPARE(map1[u"b"].value().toInteger(), 2);
+ QVERIFY(!map1[u"c"]);
+ QCOMPARE(map1.container(), env);
+ }
+ void testMultiMap() {
+ QMultiMap<QString, int> mmap({{QStringLiteral(u"a"),1},{QStringLiteral(u"b"),2},{QStringLiteral(u"a"),3}});
+ //QMultiMap<QString, int> mmap2 = mmap;
+ QMultiMap<QString, int> mmap3({{QStringLiteral(u"a"),1}});
+ //QMultiMap<QString, int> mmap4 = mmap3;
+ auto it = mmap.find(QStringLiteral(u"a"));
+ auto it2 = mmap.find(QStringLiteral(u"a"));
+ //auto it3 = mmap2.find(QStringLiteral(u"a"));
+ auto it4 = mmap3.find(QStringLiteral(u"a"));
+ auto it5 = mmap3.find(QStringLiteral(u"a"));
+ //auto it6 = mmap4.find(QStringLiteral(u"a"));
+ QVERIFY(it != mmap.end());
+ QVERIFY(it2 != mmap.end());
+ QCOMPARE(&(it.value()), &(it2.value()));
+ QCOMPARE(&(*it), &(it2.value()));
+ //QCOMPARE(&(*it), &(*it2)); // copy has different address (copies elements for int)
+ //QCOMPARE(&(*it), &(*it3));
+ QCOMPARE(&(*it4), &(*it5));
+ //QCOMPARE(&(*it4), &(*it6));
+ DomItem map1 = env.subMap(
+ Map::fromMultiMapRef<int>(
+ Path::field(u"mmap"), mmap,
+ &wrapInt)).item;
+ QCOMPARE(map1[u"b"].index(0).value().toInteger(), 2);
+ QVERIFY(!map1[u"b"].index(2));
+ QVERIFY(!map1[u"c"]);
+ QCOMPARE(map1[u"a"][0].value().toInteger(), 1);
+ QCOMPARE(map1.key(QStringLiteral(u"a")).index(0).value().toInteger(), 1);
+ QCOMPARE(map1.key(QStringLiteral(u"a")).index(1).value().toInteger(), 3);
+ QCOMPARE(map1.container(), env);
+ }
+ void testReference() {
+ Path p = Path::root(u"env");
+ DomItem ref = env.subReferenceField(u"ref",p).item;
+ QCOMPARE(ref.field(u"referredObjectPath").value().toString(), p.toString());
+ QCOMPARE(ref.fields(), QList<QString>({QStringLiteral(u"referredObjectPath"), QStringLiteral(u"get")}));
+ QCOMPARE(ref.field(u"get").internalKind(), DomType::DomEnvironment);
+ }
+ void testEnvUniverse() {
+ QCOMPARE(env.internalKind(), DomType::DomEnvironment);
+ QCOMPARE(env.pathFromOwner(), Path());
+ QCOMPARE(env.containingObject().internalKind(), DomType::Empty);
+ QCOMPARE(env.container().internalKind(), DomType::Empty);
+ QCOMPARE(env.canonicalPath(), Path::root(u"env"));
+ QCOMPARE(env.path(u"$env").internalKind(), DomType::DomEnvironment);
+ QCOMPARE(env.top().internalKind(), DomType::DomEnvironment);
+ QCOMPARE(env.environment().internalKind(), DomType::DomEnvironment);
+ QCOMPARE(env.owningItemPtr(), envPtr);
+ QCOMPARE(env.topPtr(), envPtr);
+ DomItem univ = env.universe();
+ QCOMPARE(univ.internalKind(), DomType::DomUniverse);
+ QCOMPARE(univ.owningItemPtr(), universePtr);
+ DomItem univ2 = env.path(u".universe");
+ QCOMPARE(univ2.internalKind(), DomType::DomUniverse);
+ QCOMPARE(univ2.owningItemPtr(), universePtr);
+ QCOMPARE(univ2.topPtr(), universePtr);
+ DomItem univ3 = env.field(u"universe");
+ QCOMPARE(univ3.internalKind(), DomType::DomUniverse);
+ }
+private:
+ std::shared_ptr<DomUniverse> universePtr;
+ std::shared_ptr<DomEnvironment> envPtr;
+ DomItem env;
+};
+
+
+} // namespace Dom
+} // namespace QQmlJS
+QT_END_NAMESPACE
+
+QTEST_MAIN(QQmlJS::Dom::TestDomItem)
+#include "tst_qmldomitem.moc"
diff --git a/tests/auto/qmldom/qmldom.pro b/tests/auto/qmldom/qmldom.pro
index ca1340c42d..e43d224dba 100644
--- a/tests/auto/qmldom/qmldom.pro
+++ b/tests/auto/qmldom/qmldom.pro
@@ -2,5 +2,6 @@ TEMPLATE = subdirs
SUBDIRS += \
errormessage \
+ domitem \
path \
stringdumper