1387 lines
66 KiB
C++
1387 lines
66 KiB
C++
// Copyright (C) 2020 The Qt Company Ltd.
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
|
|
|
#ifndef TST_QMLDOMITEM_H
|
|
#define TST_QMLDOMITEM_H
|
|
#include <QtQmlDom/private/qqmldomitem_p.h>
|
|
#include <QtQmlDom/private/qqmldomtop_p.h>
|
|
#include <QtQmlDom/private/qqmldomastdumper_p.h>
|
|
#include <QtQmlDom/private/qqmldommock_p.h>
|
|
#include <QtQmlDom/private/qqmldomcompare_p.h>
|
|
#include <QtQmlDom/private/qqmldomfieldfilter_p.h>
|
|
#include <QtQmlDom/private/qqmldomscriptelements_p.h>
|
|
|
|
#include <QtTest/QtTest>
|
|
#include <QtCore/QCborValue>
|
|
#include <QtCore/QDebug>
|
|
#include <QtCore/QLibraryInfo>
|
|
#include <QtCore/QFileInfo>
|
|
|
|
#include <memory>
|
|
#include <variant>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
namespace QQmlJS {
|
|
namespace Dom {
|
|
|
|
inline DomItem wrapInt(DomItem &self, const PathEls::PathComponent &p, const int &i)
|
|
{
|
|
return self.subDataItem(p, i);
|
|
}
|
|
|
|
class DomTestClass
|
|
{
|
|
public:
|
|
std::shared_ptr<int> i;
|
|
};
|
|
|
|
class TestDomItem : public QObject
|
|
{
|
|
Q_OBJECT
|
|
public:
|
|
static ErrorGroups myErrors()
|
|
{
|
|
static ErrorGroups res { { NewErrorGroup("tests"), NewErrorGroup("domitem") } };
|
|
return res;
|
|
}
|
|
|
|
private slots:
|
|
void initTestCase()
|
|
{
|
|
baseDir = QLatin1String(QT_QMLTEST_DATADIR) + QLatin1String("/domitem");
|
|
qmltypeDirs = QStringList({ baseDir, QLibraryInfo::path(QLibraryInfo::QmlImportsPath) });
|
|
universePtr =
|
|
std::shared_ptr<DomUniverse>(new DomUniverse(QStringLiteral(u"dummyUniverse")));
|
|
envPtr = std::shared_ptr<DomEnvironment>(new DomEnvironment(
|
|
QStringList(), DomEnvironment::Option::SingleThreaded, universePtr));
|
|
env = DomItem(envPtr);
|
|
testOwnerPtr = std::shared_ptr<MockOwner>(new MockOwner(
|
|
Path::Root(u"env").field(u"testOwner"), 0,
|
|
QMap<QString, MockObject> {
|
|
MockObject(
|
|
Path::Field(u"obj1"),
|
|
QMap<QString, MockObject> {
|
|
MockObject(
|
|
Path::Field(u"obj1").field(u"obj1_2"),
|
|
QMap<QString, MockObject> {},
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(3) },
|
|
{ QLatin1String("val2"), QCborValue(4) } })
|
|
.asStringPair() },
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(1) },
|
|
{ QLatin1String("val2"), QCborValue(2) } })
|
|
.asStringPair(),
|
|
MockObject(
|
|
Path::Field(u"obj2"),
|
|
QMap<QString, MockObject> {
|
|
MockObject(
|
|
Path::Field(u"obj2").field(u"obj2_2"),
|
|
QMap<QString, MockObject> {},
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(5) },
|
|
{ QLatin1String("val2"), QCborValue(6) },
|
|
{ QLatin1String("valX"),
|
|
QCborValue(QStringLiteral(u"pippo")) } })
|
|
.asStringPair() },
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(7) },
|
|
{ QLatin1String("val2"), QCborValue(8) } })
|
|
.asStringPair() },
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(9) },
|
|
},
|
|
QMap<QString, QMap<QString, MockObject>> {
|
|
{ QStringLiteral(u"map"),
|
|
QMap<QString, MockObject> {
|
|
MockObject(Path::Field(u"map").key(u"a"),
|
|
QMap<QString, MockObject> {},
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(10) },
|
|
{ QLatin1String("val2"), QCborValue(11) } })
|
|
.asStringPair(),
|
|
MockObject(Path::Field(u"map").key(u"b"),
|
|
QMap<QString, MockObject> {},
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(12) },
|
|
{ QLatin1String("val2"), QCborValue(13) } })
|
|
.asStringPair() } } },
|
|
QMap<QString, QMultiMap<QString, MockObject>> {
|
|
{ QStringLiteral(u"mmap"),
|
|
QMultiMap<QString, MockObject> {
|
|
{ QStringLiteral(u"a"),
|
|
MockObject(
|
|
Path::Field(u"mmap").key(u"a").index(0),
|
|
QMap<QString, MockObject> {},
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(14) },
|
|
{ QLatin1String("val2"), QCborValue(15) } }) },
|
|
{ QStringLiteral(u"a"),
|
|
MockObject(Path::Field(u"mmap").key(u"a").index(1),
|
|
QMap<QString, MockObject> {},
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(16) },
|
|
{ QLatin1String("val2"),
|
|
QCborValue(17) } }) } } } },
|
|
QMap<QString, QList<MockObject>> {
|
|
{ QStringLiteral(u"list"),
|
|
QList<MockObject> {
|
|
MockObject(Path::Field(u"list").index(0),
|
|
QMap<QString, MockObject> {},
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(18) },
|
|
{ QLatin1String("val2"), QCborValue(19) } }),
|
|
MockObject(Path::Field(u"list").index(1),
|
|
QMap<QString, MockObject> {},
|
|
QMap<QString, QCborValue> {
|
|
{ QStringLiteral(u"val1"), QCborValue(20) },
|
|
{ QLatin1String("val2"),
|
|
QCborValue(21) } }) } } }));
|
|
envPtr->setExtraOwningItem(QStringLiteral(u"testOwner"), testOwnerPtr);
|
|
tOwner = env.field(u"testOwner");
|
|
}
|
|
|
|
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.subListItem(List::fromQListRef<int>(Path::Field(u"list"), l, &wrapInt));
|
|
DomItem list2 = env.subListItem(List::fromQListRef<int>(Path::Field(u"reverseList"), l,
|
|
&wrapInt, ListOptions::Reverse));
|
|
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());
|
|
}
|
|
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.subMapItem(Map::fromMapRef<int>(Path::Field(u"map"), map, &wrapInt));
|
|
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"]);
|
|
}
|
|
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.subMapItem(Map::fromMultiMapRef<int>(Path::Field(u"mmap"), mmap));
|
|
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);
|
|
{
|
|
QMultiMap<QString, DomTestClass> m1;
|
|
m1.insert(QStringLiteral(u"xx"), DomTestClass { std::shared_ptr<int>(new int(4)) });
|
|
QCOMPARE(m1.begin().value().i.use_count(), 1);
|
|
QMultiMap<QString, DomTestClass> m2 = m1;
|
|
m1.clear();
|
|
auto it = m2.cbegin();
|
|
auto end = m2.cend();
|
|
while (it != end) {
|
|
QCOMPARE(it.value().i.use_count(), 1);
|
|
m1.insert(it.key(), it.value());
|
|
QCOMPARE(it.value().i.use_count(), 2);
|
|
++it;
|
|
}
|
|
m2.insert(QStringLiteral(u"xy"), DomTestClass { std::shared_ptr<int>(new int(8)) });
|
|
QMultiMap<QString, DomTestClass> m3 = m2;
|
|
m3.begin().value() = DomTestClass { std::shared_ptr<int>(new int(2)) };
|
|
auto it2 = m2.begin();
|
|
auto it3 = m3.begin();
|
|
QCOMPARE(*it2.value().i, 4);
|
|
QCOMPARE(*it3.value().i, 2);
|
|
QCOMPARE(it2.value().i.use_count(), 2);
|
|
QCOMPARE(it3.value().i.use_count(), 1);
|
|
m3.insert(QStringLiteral(u"xz"), DomTestClass { std::shared_ptr<int>(new int(16)) });
|
|
it2 = m2.begin();
|
|
it3 = m3.begin();
|
|
QCOMPARE(*it2.value().i, 4);
|
|
QCOMPARE(*it3.value().i, 2);
|
|
QCOMPARE(it2.value().i.use_count(), 2);
|
|
QCOMPARE(it3.value().i.use_count(), 1);
|
|
++it2;
|
|
++it3;
|
|
QCOMPARE(*it2.value().i, 8);
|
|
QCOMPARE(*it3.value().i, 8);
|
|
QCOMPARE(it2.value().i.use_count(), 2);
|
|
QCOMPARE(it3.value().i.use_count(), 2);
|
|
++it2;
|
|
++it3;
|
|
QVERIFY(it2 == m2.end());
|
|
QVERIFY(it3 != m3.end());
|
|
QCOMPARE(*it3.value().i, 16);
|
|
QCOMPARE(it3.value().i.use_count(), 1);
|
|
++it3;
|
|
QVERIFY(it3 == m3.end());
|
|
}
|
|
}
|
|
void testReference()
|
|
{
|
|
Path p = Path::Root(u"env");
|
|
DomItem ref = env.subReferenceItem(PathEls::Field(u"ref"), p);
|
|
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);
|
|
// test stability (cache)
|
|
QCOMPARE(ref.field(u"get").internalKind(), DomType::DomEnvironment);
|
|
}
|
|
void testRefCache()
|
|
{
|
|
Path refPath = env.canonicalPath().field(u"dummyRef");
|
|
RefCacheEntry e0 = RefCacheEntry::forPath(env, refPath);
|
|
QCOMPARE(e0.cached, RefCacheEntry::Cached::None);
|
|
bool didAdd1 = RefCacheEntry::addForPath(
|
|
env, refPath, RefCacheEntry { RefCacheEntry::Cached::First, {} });
|
|
QVERIFY(didAdd1);
|
|
RefCacheEntry e1 = RefCacheEntry::forPath(env, refPath);
|
|
QCOMPARE(e1.cached, RefCacheEntry::Cached::All);
|
|
QCOMPARE(e1.canonicalPaths.isEmpty(), true);
|
|
bool didAdd2 = RefCacheEntry::addForPath(
|
|
env, refPath,
|
|
RefCacheEntry { RefCacheEntry::Cached::First, { env.canonicalPath() } },
|
|
AddOption::Overwrite);
|
|
QVERIFY(didAdd2);
|
|
RefCacheEntry e2 = RefCacheEntry::forPath(env, refPath);
|
|
QCOMPARE(e2.cached, RefCacheEntry::Cached::First);
|
|
QCOMPARE(e2.canonicalPaths.size(), 1);
|
|
QCOMPARE(e2.canonicalPaths.first().toString(), env.canonicalPath().toString());
|
|
bool didAdd3 = RefCacheEntry::addForPath(
|
|
env, refPath,
|
|
RefCacheEntry { RefCacheEntry::Cached::All,
|
|
{ env.canonicalPath(), tOwner.canonicalPath() } },
|
|
AddOption::Overwrite);
|
|
QVERIFY(didAdd3);
|
|
RefCacheEntry e3 = RefCacheEntry::forPath(env, refPath);
|
|
QCOMPARE(e3.cached, RefCacheEntry::Cached::All);
|
|
QCOMPARE(e3.canonicalPaths.size(), 2);
|
|
QCOMPARE(e3.canonicalPaths.first().toString(), env.canonicalPath().toString());
|
|
QCOMPARE(e3.canonicalPaths.last().toString(), tOwner.canonicalPath().toString());
|
|
}
|
|
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);
|
|
}
|
|
|
|
void testTOwner()
|
|
{
|
|
QVERIFY(env.fields().contains(QLatin1String("testOwner")));
|
|
QCOMPARE(tOwner.internalKind(), DomType::MockOwner);
|
|
QCOMPARE(tOwner.pathFromOwner(), Path());
|
|
DomItem map = tOwner.field(u"map");
|
|
QCOMPARE(map[u"b"].field(u"val1").value().toInteger(), 12);
|
|
QCOMPARE(map[u"b"].container(), map);
|
|
QCOMPARE(map[u"b"].container()[u"b"].field(u"val1").value().toInteger(), 12);
|
|
QCOMPARE(map[u"b"].containingObject(), tOwner);
|
|
DomItem mmap = tOwner.field(u"mmap");
|
|
QCOMPARE(mmap[u"a"].index(0).field(u"val1").value().toInteger(), 14);
|
|
QCOMPARE(mmap[u"a"].container(), mmap);
|
|
QCOMPARE(mmap[u"a"].container()[u"a"].index(0).field(u"val1").value().toInteger(), 14);
|
|
QCOMPARE(mmap[u"a"].containingObject(), tOwner);
|
|
QCOMPARE(mmap[u"a"].index(0).container(), mmap[u"a"]);
|
|
QCOMPARE(mmap[u"a"].index(0).containingObject(), tOwner);
|
|
DomItem list = tOwner.field(u"list");
|
|
QCOMPARE(list[0].field(u"val1").value().toInteger(), 18);
|
|
QCOMPARE(list.container(), tOwner);
|
|
QCOMPARE(list[0].container(), list);
|
|
QCOMPARE(list[0].containingObject(), tOwner);
|
|
QCOMPARE(list[0].container()[0].field(u"val1").value().toInteger(), 18);
|
|
QCOMPARE(tOwner.containingObject().internalKind(), DomType::DomEnvironment);
|
|
QCOMPARE(tOwner.container().internalKind(), DomType::DomEnvironment);
|
|
QCOMPARE(tOwner.fields(),
|
|
QStringList({ QStringLiteral(u"val1"), QStringLiteral(u"obj1"),
|
|
QStringLiteral(u"obj2"), QStringLiteral(u"map"),
|
|
QStringLiteral(u"mmap"), QStringLiteral(u"list") }));
|
|
auto tOwner2 = env.path(u"$env.testOwner");
|
|
QCOMPARE(tOwner2.internalKind(), DomType::MockOwner);
|
|
auto tOwner3 = tOwner.path(u"$env.testOwner");
|
|
QCOMPARE(tOwner3.internalKind(), DomType::MockOwner);
|
|
QList<qint64> values;
|
|
tOwner.visitTree(Path(), [&values](Path p, DomItem i, bool) {
|
|
if (i.pathFromOwner() != p)
|
|
myErrors()
|
|
.error(QStringLiteral(u"unexpected path %1 %2")
|
|
.arg(i.pathFromOwner().toString(), p.toString()))
|
|
.handle(defaultErrorHandler);
|
|
Q_ASSERT(i == i.path(i.canonicalPath()));
|
|
if (DomItem v1 = i.path(u".val1"))
|
|
values.append(v1.value().toInteger());
|
|
return true;
|
|
});
|
|
QCOMPARE(values, QList<qint64>({ 9, 1, 3, 7, 5, 10, 12, 14, 16, 18, 20 }));
|
|
}
|
|
void testSubObj()
|
|
{
|
|
auto obj1 = tOwner.field(u"obj1");
|
|
QCOMPARE(obj1.internalKind(), DomType::MockObject);
|
|
auto obj1_1 = env.path(u".testOwner.obj1.obj1_2");
|
|
QCOMPARE(obj1_1.internalKind(), DomType::MockObject);
|
|
QCOMPARE(obj1_1.field(u"val1").value().toInteger(), 3);
|
|
}
|
|
void testEquality()
|
|
{
|
|
auto obj1 = tOwner.field(u"obj1");
|
|
auto obj1_1 = env.path(u".testOwner.obj1.obj1_2");
|
|
QCOMPARE(obj1_1.container(), obj1);
|
|
QCOMPARE(obj1_1.environment(), env);
|
|
QCOMPARE(obj1_1.owner(), tOwner);
|
|
}
|
|
void testLoadNoDep()
|
|
{
|
|
#ifdef Q_OS_ANDROID
|
|
QSKIP("Test uncompatible with Android (QTBUG-100171)");
|
|
#endif
|
|
auto univPtr = std::shared_ptr<QQmlJS::Dom::DomUniverse>(
|
|
new QQmlJS::Dom::DomUniverse(QLatin1String("univ1")));
|
|
auto envPtr = std::shared_ptr<QQmlJS::Dom::DomEnvironment>(new QQmlJS::Dom::DomEnvironment(
|
|
qmltypeDirs,
|
|
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
|
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies,
|
|
univPtr));
|
|
QQmlJS::Dom::DomItem env(envPtr);
|
|
QVERIFY(env);
|
|
QString testFile1 = baseDir + QLatin1String("/test1.qml");
|
|
DomItem tFile;
|
|
// env.loadBuiltins();
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(envPtr, testFile1),
|
|
[&tFile](Path, const DomItem &, const DomItem &newIt) { tFile = newIt; },
|
|
LoadOption::DefaultLoad);
|
|
env.loadFile(FileToLoad::fromFileSystem(envPtr, baseDir), {}, LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
|
|
QVERIFY(tFile);
|
|
tFile = tFile.field(Fields::currentItem);
|
|
QVERIFY(tFile);
|
|
DomItem comp1 = tFile.field(Fields::components).key(QString()).index(0);
|
|
QVERIFY(comp1);
|
|
DomItem obj1 = comp1.field(Fields::objects).index(0);
|
|
QVERIFY(obj1);
|
|
|
|
tFile.visitTree(Path(), [&tFile](Path p, DomItem i, bool) {
|
|
if (!(i == i.path(i.canonicalPath()))) {
|
|
DomItem i2 = i.path(i.canonicalPath());
|
|
qDebug() << p << i.canonicalPath() << i.internalKindStr() << i2.internalKindStr()
|
|
<< i.id() << i2.id() << i.pathFromOwner() << i2.pathFromOwner();
|
|
}
|
|
Q_ASSERT(i == i.path(i.canonicalPath()));
|
|
Q_ASSERT(!i || i == tFile.path(i.canonicalPath()));
|
|
Q_ASSERT(!i || i.containingObject());
|
|
|
|
return true;
|
|
});
|
|
|
|
{
|
|
DomItem width = obj1.field(Fields::bindings).key(QLatin1String("width")).index(0);
|
|
QCOMPARE(width.field(Fields::value).qmlObject(), obj1);
|
|
DomItem w = obj1.bindings().key(QLatin1String("width"));
|
|
QVERIFY(w.indexes() > 0);
|
|
QCOMPARE(w.indexes(), 1);
|
|
QVERIFY(w.index(0).as<Binding>());
|
|
QVERIFY(w.index(0).as<Binding>()->scriptExpressionValue());
|
|
QCOMPARE(w.index(0).as<Binding>()->scriptExpressionValue()->code(), u"640");
|
|
PropertyInfo mPInfo;
|
|
mPInfo.bindings = { width };
|
|
mPInfo.propertyDefs.append(width);
|
|
DomItem wrappedPInfo = obj1.wrapField(Fields::propertyInfos, mPInfo);
|
|
QVERIFY(wrappedPInfo);
|
|
const SimpleObjectWrapBase *wrappedPInfoPtr =
|
|
static_cast<const SimpleObjectWrapBase *>(wrappedPInfo.base());
|
|
QVERIFY(wrappedPInfoPtr);
|
|
const PropertyInfo *p1 =
|
|
reinterpret_cast<const PropertyInfo *>(wrappedPInfoPtr->m_value.data());
|
|
PropertyInfo p2 = wrappedPInfoPtr->m_value.value<PropertyInfo>();
|
|
QCOMPARE(mPInfo.bindings.size(), 1);
|
|
QCOMPARE(mPInfo.propertyDefs.size(), 1);
|
|
QCOMPARE(mPInfo.bindings.first().toString(), mPInfo.bindings.first().toString());
|
|
QCOMPARE(mPInfo.propertyDefs.first().toString(),
|
|
mPInfo.propertyDefs.first().toString());
|
|
|
|
QCOMPARE(p2.bindings.size(), 1);
|
|
QCOMPARE(p2.propertyDefs.size(), 1);
|
|
QCOMPARE(p2.bindings.first().toString(), mPInfo.bindings.first().toString());
|
|
QCOMPARE(p2.propertyDefs.first().toString(), mPInfo.propertyDefs.first().toString());
|
|
QCOMPARE(p1->bindings.size(), 1);
|
|
QCOMPARE(p1->propertyDefs.size(), 1);
|
|
QCOMPARE(p1->bindings.first().toString(), mPInfo.bindings.first().toString());
|
|
QCOMPARE(p1->propertyDefs.first().toString(), mPInfo.propertyDefs.first().toString());
|
|
}
|
|
QString bPath = QFileInfo(baseDir).canonicalPath();
|
|
if (!bPath.isEmpty()) {
|
|
Path p = tFile.canonicalPath();
|
|
Q_ASSERT(env.path(p));
|
|
env.ownerAs<DomEnvironment>()->removePath(bPath);
|
|
Q_ASSERT(!env.path(p));
|
|
}
|
|
}
|
|
|
|
void testLoadDep()
|
|
{
|
|
#ifdef Q_OS_ANDROID
|
|
QSKIP("Test uncompatible with Android (QTBUG-100171)");
|
|
#endif
|
|
auto univPtr = std::shared_ptr<QQmlJS::Dom::DomUniverse>(
|
|
new QQmlJS::Dom::DomUniverse(QLatin1String("univ1")));
|
|
auto envPtr = std::shared_ptr<QQmlJS::Dom::DomEnvironment>(new QQmlJS::Dom::DomEnvironment(
|
|
qmltypeDirs, QQmlJS::Dom::DomEnvironment::Option::SingleThreaded, univPtr));
|
|
QQmlJS::Dom::DomItem env(envPtr);
|
|
QVERIFY(env);
|
|
QString testFile1 = baseDir + QLatin1String("/test1.qml");
|
|
DomItem tFile;
|
|
env.loadBuiltins();
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(envPtr, testFile1),
|
|
[&tFile](Path, const DomItem &, const DomItem &newIt) { tFile = newIt; },
|
|
LoadOption::DefaultLoad);
|
|
env.loadFile(FileToLoad::fromFileSystem(envPtr, baseDir), {}, LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
|
|
QVERIFY(tFile);
|
|
tFile = tFile.field(Fields::currentItem);
|
|
QVERIFY(tFile);
|
|
DomItem comp1 = tFile.field(Fields::components).key(QString()).index(0);
|
|
QVERIFY(comp1);
|
|
DomItem obj1 = comp1.field(Fields::objects).index(0);
|
|
QVERIFY(obj1);
|
|
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
|
|
QList<DomItem> rect =
|
|
obj1.lookup(u"Rectangle"_s, LookupType::Type, LookupOption::Normal);
|
|
QList<DomItem> rect2 =
|
|
obj1.lookup(u"Rectangle"_s, LookupType::Symbol, LookupOption::Normal);
|
|
QList<DomItem> rectAs =
|
|
obj1.lookup(u"QQ.Rectangle"_s, LookupType::Symbol, LookupOption::Normal);
|
|
|
|
QVERIFY(rect.size() == 1);
|
|
QVERIFY(rect2.size() == 1);
|
|
QVERIFY(rectAs.size() == 1);
|
|
QCOMPARE(rect.first().internalKind(), DomType::Export);
|
|
QCOMPARE(rect.first(), rect2.first());
|
|
QCOMPARE(rect.first(), rectAs.first());
|
|
DomItem rect3 = rect.first().proceedToScope();
|
|
QCOMPARE(rect3.internalKind(), DomType::QmlObject);
|
|
QList<DomItem> rects;
|
|
obj1.resolve(
|
|
Path::Current(PathCurrent::Lookup).field(Fields::type).key(u"Rectangle"_s),
|
|
[&rects](Path, DomItem &el) {
|
|
rects.append(el);
|
|
return true;
|
|
},
|
|
{});
|
|
QVERIFY(rects.size() == 1);
|
|
for (DomItem &el : rects) {
|
|
QCOMPARE(rect.first(), el);
|
|
}
|
|
}
|
|
{
|
|
QString fPath = tFile.canonicalFilePath();
|
|
QString fPath2 = fPath.mid(0, fPath.lastIndexOf(u'/')) % u"/MySingleton.qml";
|
|
Path p2 = Paths::qmlFileObjectPath(fPath2);
|
|
DomItem f2 = env.path(p2);
|
|
QVERIFY2(f2, "Directory dependencies did not load MySingleton.qml");
|
|
}
|
|
}
|
|
|
|
void testImports()
|
|
{
|
|
#ifdef Q_OS_ANDROID
|
|
QSKIP("Test uncompatible with Android (QTBUG-100171)");
|
|
#endif
|
|
using namespace Qt::StringLiterals;
|
|
|
|
QString testFile1 = baseDir + QLatin1String("/TestImports.qml");
|
|
DomItem env = DomEnvironment::create(
|
|
QStringList(),
|
|
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
|
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
|
|
|
|
DomItem tFile;
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(env.ownerAs<DomEnvironment>(), testFile1),
|
|
[&tFile](Path, DomItem &, DomItem &newIt) { tFile = newIt.fileObject(); },
|
|
LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
|
|
QVERIFY(tFile);
|
|
QList<QmlUri> importedModules;
|
|
for (auto &import : tFile.field(Fields::imports).values()) {
|
|
if (const Import *importPtr = import.as<Import>()) {
|
|
if (!importPtr->implicit)
|
|
importedModules.append(importPtr->uri);
|
|
}
|
|
}
|
|
QCOMPARE(importedModules.at(0).moduleUri(), u"QtQuick"_s);
|
|
QCOMPARE(importedModules.at(0).directoryString(), u""_s);
|
|
QCOMPARE(importedModules.at(1).directoryString(), u"../.."_s);
|
|
QCOMPARE(importedModules.at(1).localPath(), u"../.."_s);
|
|
QCOMPARE(importedModules.at(1).absoluteLocalPath(), QString());
|
|
QCOMPARE(importedModules.at(1).absoluteLocalPath(u"/bla/bla"_s), u"/bla/bla/../..");
|
|
QCOMPARE(importedModules.at(2).directoryString(), u"../dommerging"_s);
|
|
QCOMPARE(importedModules.at(2).localPath(), u"../dommerging"_s);
|
|
QCOMPARE(importedModules.at(2).absoluteLocalPath(), QString());
|
|
QCOMPARE(importedModules.at(2).absoluteLocalPath(u"/bla/bla"_s),
|
|
u"/bla/bla/../dommerging");
|
|
QCOMPARE(importedModules.at(3).directoryString(), u"C:/some/path"_s);
|
|
QCOMPARE(importedModules.at(3).localPath(), u"C:/some/path"_s);
|
|
QCOMPARE(importedModules.at(4).directoryString(), u"http://bla.com/"_s);
|
|
QCOMPARE(importedModules.at(4).directoryUrl().toString(), u"http://bla.com/"_s);
|
|
QCOMPARE(importedModules.at(5).absoluteLocalPath(), u"/absolute/path"_s);
|
|
QVERIFY(QmlUri::fromDirectoryString("QtQuick") != importedModules.at(0));
|
|
QCOMPARE(QmlUri::fromUriString("QtQuick"), importedModules.at(0));
|
|
}
|
|
void testDeepCopy()
|
|
{
|
|
QString testFile = baseDir + QLatin1String("/test1.qml");
|
|
|
|
DomItem env = DomEnvironment::create(
|
|
qmltypeDirs,
|
|
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
|
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
|
|
|
|
DomItem tFile; // place where to store the loaded file
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(env.ownerAs<DomEnvironment>(), testFile),
|
|
[&tFile](Path, const DomItem &, const DomItem &newIt) { tFile = newIt; },
|
|
LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
DomItem f = tFile.fileObject();
|
|
QString dump1;
|
|
f.dump([&dump1](QStringView v) { dump1.append(v); });
|
|
MutableDomItem copy = f.makeCopy();
|
|
QString dump2;
|
|
copy.item().dump([&dump2](QStringView v) { dump2.append(v); });
|
|
QString diff = lineDiff(dump1, dump2, 2);
|
|
if (!diff.isEmpty())
|
|
qDebug().nospace().noquote() << diff;
|
|
QCOMPARE(dump1, dump2);
|
|
QStringList diffs = domCompareStrList(f, copy, FieldFilter::compareFilter());
|
|
if (!diffs.isEmpty())
|
|
qDebug() << "testDeepCopy.diffs:" << diffs;
|
|
QVERIFY(diffs.isEmpty());
|
|
DomItem univFile = env.universe().path(f.canonicalPath());
|
|
MutableDomItem univFileCopy = univFile.makeCopy();
|
|
QStringList univFileDiffs =
|
|
domCompareStrList(univFile, univFileCopy, FieldFilter::compareFilter());
|
|
if (!univFileDiffs.isEmpty())
|
|
qDebug() << "testDeepCopy.univFileDiffs:" << univFileDiffs;
|
|
QVERIFY(univFileDiffs.isEmpty());
|
|
QString bPath = QFileInfo(baseDir).canonicalFilePath();
|
|
if (!bPath.isEmpty()) {
|
|
Path p = f.canonicalPath();
|
|
Q_ASSERT(env.path(p));
|
|
env.ownerAs<DomEnvironment>()->removePath(bPath);
|
|
Q_ASSERT(!env.path(p));
|
|
}
|
|
}
|
|
|
|
void testInMemory()
|
|
{
|
|
DomItem res = DomItem::fromCode("MyItem{}");
|
|
DomItem obj = res.qmlObject(GoTo::MostLikely);
|
|
QCOMPARE(obj.name(), u"MyItem");
|
|
}
|
|
|
|
static void checkAliases(DomItem &qmlObj)
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
|
|
if (const QmlObject *qmlObjPtr = qmlObj.as<QmlObject>()) {
|
|
auto pDefs = qmlObjPtr->propertyDefs();
|
|
auto i = pDefs.constBegin();
|
|
while (i != pDefs.constEnd()) {
|
|
if (i.value().isAlias()) {
|
|
QString propName = i.key();
|
|
DomItem value = qmlObj.bindings().key(propName).index(0).field(Fields::value);
|
|
LocallyResolvedAlias rAlias =
|
|
qmlObjPtr->resolveAlias(qmlObj, value.ownerAs<ScriptExpression>());
|
|
if (propName.startsWith(u"a")) {
|
|
QCOMPARE(rAlias.baseObject.internalKind(), DomType::QmlObject);
|
|
switch (propName.last(1).at(0).unicode()) {
|
|
case u'i':
|
|
QCOMPARE(rAlias.status, LocallyResolvedAlias::Status::ResolvedProperty);
|
|
QCOMPARE(rAlias.typeName, u"int"_s);
|
|
QVERIFY(rAlias.accessedPath.isEmpty());
|
|
QCOMPARE(rAlias.localPropertyDef.internalKind(),
|
|
DomType::PropertyDefinition);
|
|
break;
|
|
case u'r':
|
|
QCOMPARE(rAlias.status, LocallyResolvedAlias::Status::ResolvedProperty);
|
|
QCOMPARE(rAlias.typeName, u"real"_s);
|
|
QVERIFY(rAlias.accessedPath.isEmpty());
|
|
QCOMPARE(rAlias.localPropertyDef.internalKind(),
|
|
DomType::PropertyDefinition);
|
|
break;
|
|
case u'I':
|
|
QCOMPARE(rAlias.status, LocallyResolvedAlias::Status::ResolvedObject);
|
|
QCOMPARE(rAlias.typeName, u"Item"_s);
|
|
QCOMPARE(rAlias.accessedPath, QStringList { u"objectName"_s });
|
|
QVERIFY(!rAlias.localPropertyDef);
|
|
break;
|
|
case u'q':
|
|
QCOMPARE(rAlias.status, LocallyResolvedAlias::Status::ResolvedObject);
|
|
QCOMPARE(rAlias.typeName, u"QtObject"_s);
|
|
QCOMPARE(rAlias.accessedPath, QStringList { u"objectName"_s });
|
|
QVERIFY(!rAlias.localPropertyDef);
|
|
break;
|
|
case u'Q':
|
|
QCOMPARE(rAlias.status, LocallyResolvedAlias::Status::ResolvedObject);
|
|
QCOMPARE(rAlias.typeName, u"QtObject"_s);
|
|
QCOMPARE(rAlias.accessedPath, QStringList { u"objectName"_s });
|
|
QVERIFY(rAlias.localPropertyDef);
|
|
break;
|
|
default:
|
|
Q_ASSERT(false);
|
|
}
|
|
} else if (propName.startsWith(u"loop")) {
|
|
QCOMPARE(rAlias.status, LocallyResolvedAlias::Status::Loop);
|
|
} else if (propName.startsWith(u"tooDeep")) {
|
|
QCOMPARE(rAlias.status, LocallyResolvedAlias::Status::TooDeep);
|
|
} else if (propName.startsWith(u"invalid")) {
|
|
QCOMPARE(rAlias.status, LocallyResolvedAlias::Status::Invalid);
|
|
} else if (propName.startsWith(u"objRef")) {
|
|
QCOMPARE(rAlias.status, LocallyResolvedAlias::Status::ResolvedObject);
|
|
} else {
|
|
Q_ASSERT(false);
|
|
}
|
|
}
|
|
++i;
|
|
}
|
|
for (DomItem obj : qmlObj.children().values()) {
|
|
if (obj.as<QmlObject>())
|
|
checkAliases(obj);
|
|
}
|
|
}
|
|
}
|
|
|
|
void testAliasResolve_data()
|
|
{
|
|
QTest::addColumn<QString>("inFile");
|
|
|
|
QTest::newRow("aliasProperties") << QStringLiteral(u"aliasProperties.qml");
|
|
QTest::newRow("invalidAliasProperties") << QStringLiteral(u"invalidAliasProperties.qml");
|
|
}
|
|
void testAliasResolve()
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
|
|
QFETCH(QString, inFile);
|
|
QString testFile1 = baseDir + u"/"_s + inFile;
|
|
DomItem env = DomEnvironment::create(
|
|
QStringList(),
|
|
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
|
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
|
|
|
|
DomItem tFile;
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(env.ownerAs<DomEnvironment>(), testFile1),
|
|
[&tFile](Path, DomItem &, DomItem &newIt) { tFile = newIt.fileObject(); },
|
|
LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
|
|
DomItem rootObj = tFile.qmlObject(GoTo::MostLikely);
|
|
checkAliases(rootObj);
|
|
}
|
|
|
|
void inlineComponents()
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
|
|
QString testFile = baseDir + u"/inlineComponents.qml"_s;
|
|
|
|
DomItem env = DomEnvironment::create(
|
|
QStringList(),
|
|
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
|
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
|
|
|
|
DomItem tFile;
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(env.ownerAs<DomEnvironment>(), testFile),
|
|
[&tFile](Path, DomItem &, DomItem &newIt) { tFile = newIt.fileObject(); },
|
|
LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
|
|
auto rootQmlObject = tFile.rootQmlObject(GoTo::MostLikely);
|
|
|
|
// check if the lookup can find the inline components correctly, to see if the
|
|
// visitScopeChain also visit them.
|
|
auto ic3 = rootQmlObject.lookup("IC3", LookupType::Type, LookupOption::Normal,
|
|
[](const ErrorMessage &) {});
|
|
|
|
QCOMPARE(ic3.size(), 1);
|
|
QCOMPARE(ic3.front().name(), "inlineComponents.IC3");
|
|
|
|
auto ic1 = rootQmlObject.lookup("IC1", LookupType::Type, LookupOption::Normal,
|
|
[](const ErrorMessage &) {});
|
|
|
|
QCOMPARE(ic1.size(), 1);
|
|
QCOMPARE(ic1.front().name(), "inlineComponents.IC1");
|
|
}
|
|
|
|
void inlineObject()
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
QString testFile = baseDir + u"/inlineObject.qml"_s;
|
|
|
|
DomItem env = DomEnvironment::create(
|
|
QStringList(),
|
|
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
|
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
|
|
|
|
DomItem tFile;
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(env.ownerAs<DomEnvironment>(), testFile),
|
|
[&tFile](Path, DomItem &, DomItem &newIt) { tFile = newIt.fileObject(); },
|
|
LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
|
|
auto rootQmlObject = tFile.rootQmlObject(GoTo::MostLikely);
|
|
|
|
// check that the inline objects have their prototypes set.
|
|
|
|
{
|
|
auto prototypes = rootQmlObject.propertyInfos()
|
|
.key(u"myItem"_s)
|
|
.field(Fields::bindings)
|
|
.index(0)
|
|
.field(Fields::value)
|
|
.field(Fields::prototypes);
|
|
QVERIFY(prototypes.internalKind() != DomType::Empty);
|
|
QCOMPARE(prototypes.indexes(), 1);
|
|
QCOMPARE(prototypes.index(0)
|
|
.field(Fields::referredObjectPath)
|
|
.as<ConstantData>()
|
|
->value()
|
|
.toString(),
|
|
u"@lookup.type[\"Item\"]"_s);
|
|
}
|
|
|
|
{
|
|
auto prototypes2 = rootQmlObject.propertyInfos()
|
|
.key(u"myItem2"_s)
|
|
.field(Fields::bindings)
|
|
.index(0)
|
|
.field(Fields::value)
|
|
.field(Fields::prototypes);
|
|
QVERIFY(prototypes2.internalKind() != DomType::Empty);
|
|
QCOMPARE(prototypes2.indexes(), 1);
|
|
QCOMPARE(prototypes2.index(0)
|
|
.field(Fields::referredObjectPath)
|
|
.as<ConstantData>()
|
|
->value()
|
|
.toString(),
|
|
u"@lookup.type[\"IC\"]"_s);
|
|
}
|
|
}
|
|
|
|
void scopesInDom()
|
|
{
|
|
QString fileName = baseDir + u"/checkScopes.qml"_s;
|
|
|
|
const QStringList importPaths = {
|
|
QLibraryInfo::path(QLibraryInfo::QmlImportsPath),
|
|
};
|
|
|
|
DomItem tFile;
|
|
|
|
DomItem env = DomEnvironment::create(
|
|
importPaths,
|
|
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
|
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
|
|
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(env.ownerAs<DomEnvironment>(), fileName,
|
|
WithSemanticAnalysis),
|
|
[&tFile](Path, DomItem &, DomItem &newIt) { tFile = newIt.fileObject(); },
|
|
LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
|
|
auto root = tFile.rootQmlObject(GoTo::MostLikely);
|
|
|
|
{
|
|
auto rootQmlObject = root.as<QmlObject>();
|
|
QVERIFY(rootQmlObject);
|
|
auto rootScope = rootQmlObject->semanticScope();
|
|
QVERIFY(rootScope);
|
|
QVERIFY(rootScope->hasOwnProperty("myInt"));
|
|
QVERIFY(rootScope->hasOwnProperty("myInt2"));
|
|
QVERIFY(rootScope->hasOwnPropertyBindings("myInt"));
|
|
QVERIFY(rootScope->hasOwnPropertyBindings("myInt2"));
|
|
}
|
|
}
|
|
|
|
void domConstructionTime_data()
|
|
{
|
|
QTest::addColumn<QString>("fileName");
|
|
QTest::addColumn<DomCreationOptions>("withScope");
|
|
|
|
DomCreationOptions withScope = DomCreationOption::WithSemanticAnalysis;
|
|
DomCreationOptions noScope = DomCreationOption::None;
|
|
DomCreationOptions withScopeAndScriptExpressions;
|
|
withScopeAndScriptExpressions.setFlag(DomCreationOption::WithSemanticAnalysis);
|
|
withScopeAndScriptExpressions.setFlag(DomCreationOption::WithScriptExpressions);
|
|
|
|
QTest::addRow("tiger.qml") << baseDir + u"/longQmlFile.qml"_s << noScope;
|
|
QTest::addRow("tiger.qml-with-scope") << baseDir + u"/longQmlFile.qml"_s << withScope;
|
|
QTest::addRow("tiger.qml-with-scope-and-scriptexpressions")
|
|
<< baseDir + u"/longQmlFile.qml"_s << withScopeAndScriptExpressions;
|
|
|
|
QTest::addRow("deeplyNested.qml") << baseDir + u"/deeplyNested.qml"_s << noScope;
|
|
QTest::addRow("deeplyNested.qml-with-scope")
|
|
<< baseDir + u"/deeplyNested.qml"_s << withScope;
|
|
QTest::addRow("deeplyNested.qml-with-scope-and-scriptexpressions")
|
|
<< baseDir + u"/deeplyNested.qml"_s << withScopeAndScriptExpressions;
|
|
}
|
|
|
|
void domConstructionTime()
|
|
{
|
|
QFETCH(QString, fileName);
|
|
QFETCH(DomCreationOptions, withScope);
|
|
|
|
const QStringList importPaths = {
|
|
QLibraryInfo::path(QLibraryInfo::QmlImportsPath),
|
|
};
|
|
|
|
DomItem tFile;
|
|
QBENCHMARK {
|
|
DomItem env = DomEnvironment::create(
|
|
importPaths,
|
|
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
|
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
|
|
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(env.ownerAs<DomEnvironment>(), fileName, withScope),
|
|
[&tFile](Path, DomItem &, DomItem &newIt) { tFile = newIt.fileObject(); },
|
|
LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
}
|
|
}
|
|
|
|
void propertyBindings()
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
QString testFile = baseDir + u"/propertyBindings.qml"_s;
|
|
DomItem rootQmlObject = rootQmlObjectFromFile(testFile, qmltypeDirs);
|
|
// check the binding to a and b
|
|
DomItem a = rootQmlObject.path(".bindings[\"a\"][0].value.scriptElement.value");
|
|
QCOMPARE(a.value().toDouble(), 42);
|
|
|
|
DomItem b = rootQmlObject.path(".bindings[\"b\"][0].value.scriptElement.identifier");
|
|
QCOMPARE(b.value().toString(), "a");
|
|
}
|
|
|
|
void variableDeclarations()
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
QString testFile = baseDir + u"/variableDeclarations.qml"_s;
|
|
DomItem rootQmlObject = rootQmlObjectFromFile(testFile, qmltypeDirs);
|
|
DomItem block = rootQmlObject.path(".methods[\"f\"][0].body.scriptElement");
|
|
|
|
// This block should have a semantic scope that defines sum and helloWorld
|
|
auto blockSemanticScope = block.semanticScope();
|
|
QVERIFY(blockSemanticScope);
|
|
QVERIFY(*blockSemanticScope);
|
|
QVERIFY(blockSemanticScope.value()->JSIdentifier(u"sum"_s));
|
|
QVERIFY(blockSemanticScope.value()->JSIdentifier(u"helloWorld"_s));
|
|
QVERIFY(blockSemanticScope.value()->JSIdentifier(u"a"_s));
|
|
QVERIFY(blockSemanticScope.value()->JSIdentifier(u"b"_s));
|
|
QVERIFY(blockSemanticScope.value()->JSIdentifier(u"aa"_s));
|
|
QVERIFY(blockSemanticScope.value()->JSIdentifier(u"bb"_s));
|
|
QVERIFY(blockSemanticScope.value()->JSIdentifier(u"bool1"_s));
|
|
QVERIFY(blockSemanticScope.value()->JSIdentifier(u"bool2"_s));
|
|
QVERIFY(blockSemanticScope.value()->JSIdentifier(u"nullVar"_s));
|
|
DomItem statements = block.field(Fields::statements);
|
|
QCOMPARE(statements.indexes(), 8);
|
|
|
|
{
|
|
// let sum = 0, helloWorld = "hello"
|
|
DomItem variableDeclaration = statements.index(0).field(Fields::declarations);
|
|
QCOMPARE(variableDeclaration.indexes(), 2);
|
|
DomItem sumInitialization = variableDeclaration.index(0);
|
|
QCOMPARE(sumInitialization.field(Fields::scopeType).value().toInteger(),
|
|
ScriptElements::VariableDeclarationEntry::ScopeType::Let);
|
|
QCOMPARE(sumInitialization.field(Fields::identifier).value().toString(), "sum");
|
|
QCOMPARE(sumInitialization.field(Fields::initializer)
|
|
.field(Fields::value)
|
|
.value()
|
|
.toDouble(),
|
|
0);
|
|
|
|
DomItem helloWorldInitialization = variableDeclaration.index(1);
|
|
QCOMPARE(helloWorldInitialization.field(Fields::scopeType).value().toInteger(),
|
|
ScriptElements::VariableDeclarationEntry::ScopeType::Let);
|
|
QCOMPARE(helloWorldInitialization.field(Fields::identifier).value().toString(),
|
|
"helloWorld");
|
|
QCOMPARE(helloWorldInitialization.field(Fields::initializer)
|
|
.field(Fields::value)
|
|
.value()
|
|
.toString(),
|
|
"hello");
|
|
}
|
|
{
|
|
// const a = 3
|
|
DomItem a = statements.index(1).field(Fields::declarations).index(0);
|
|
QCOMPARE(a.field(Fields::scopeType).value().toInteger(),
|
|
ScriptElements::VariableDeclarationEntry::ScopeType::Const);
|
|
QCOMPARE(a.field(Fields::identifier).value().toString(), "a");
|
|
QCOMPARE(a.field(Fields::initializer).internalKind(), DomType::ScriptLiteral);
|
|
QCOMPARE(a.field(Fields::initializer).field(Fields::value).value().toInteger(), 3);
|
|
}
|
|
{
|
|
// const b = "patron"
|
|
DomItem b = statements.index(2).field(Fields::declarations).index(0);
|
|
QCOMPARE(b.field(Fields::scopeType).value().toInteger(),
|
|
ScriptElements::VariableDeclarationEntry::ScopeType::Const);
|
|
QCOMPARE(b.field(Fields::identifier).value().toString(), "b");
|
|
QCOMPARE(b.field(Fields::initializer).internalKind(), DomType::ScriptLiteral);
|
|
QCOMPARE(b.field(Fields::initializer).field(Fields::value).value().toString(),
|
|
"patron");
|
|
}
|
|
{
|
|
// var aa = helloWorld
|
|
DomItem aa = statements.index(3).field(Fields::declarations).index(0);
|
|
QCOMPARE(aa.field(Fields::scopeType).value().toInteger(),
|
|
ScriptElements::VariableDeclarationEntry::ScopeType::Var);
|
|
QCOMPARE(aa.field(Fields::identifier).value().toString(), "aa");
|
|
QCOMPARE(aa.field(Fields::initializer).internalKind(),
|
|
DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(aa.field(Fields::initializer).field(Fields::identifier).value().toString(),
|
|
"helloWorld");
|
|
// var bb = aa
|
|
DomItem bb = statements.index(3).field(Fields::declarations).index(1);
|
|
QCOMPARE(bb.field(Fields::scopeType).value().toInteger(),
|
|
ScriptElements::VariableDeclarationEntry::ScopeType::Var);
|
|
QCOMPARE(bb.field(Fields::identifier).value().toString(), "bb");
|
|
QCOMPARE(bb.field(Fields::initializer).internalKind(),
|
|
DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(bb.field(Fields::initializer).field(Fields::identifier).value().toString(),
|
|
"aa");
|
|
}
|
|
{
|
|
// const bool1 = true
|
|
DomItem bool1 = statements.index(4).field(Fields::declarations).index(0);
|
|
QCOMPARE(bool1.field(Fields::scopeType).value().toInteger(),
|
|
ScriptElements::VariableDeclarationEntry::ScopeType::Const);
|
|
QCOMPARE(bool1.field(Fields::identifier).value().toString(), "bool1");
|
|
QCOMPARE(bool1.field(Fields::initializer).internalKind(), DomType::ScriptLiteral);
|
|
QVERIFY(bool1.field(Fields::initializer).field(Fields::value).value().isTrue());
|
|
}
|
|
{
|
|
// let bool2 = false
|
|
DomItem bool2 = statements.index(5).field(Fields::declarations).index(0);
|
|
QCOMPARE(bool2.field(Fields::scopeType).value().toInteger(),
|
|
ScriptElements::VariableDeclarationEntry::ScopeType::Let);
|
|
QCOMPARE(bool2.field(Fields::identifier).value().toString(), "bool2");
|
|
QCOMPARE(bool2.field(Fields::initializer).internalKind(), DomType::ScriptLiteral);
|
|
QVERIFY(bool2.field(Fields::initializer).field(Fields::value).value().isFalse());
|
|
}
|
|
{
|
|
// var nullVar = null
|
|
DomItem nullVar = statements.index(6).field(Fields::declarations).index(0);
|
|
QCOMPARE(nullVar.field(Fields::scopeType).value().toInteger(),
|
|
ScriptElements::VariableDeclarationEntry::ScopeType::Var);
|
|
QCOMPARE(nullVar.field(Fields::identifier).value().toString(), "nullVar");
|
|
QCOMPARE(nullVar.field(Fields::initializer).internalKind(), DomType::ScriptLiteral);
|
|
QVERIFY(nullVar.field(Fields::initializer).field(Fields::value).value().isNull());
|
|
}
|
|
}
|
|
|
|
void ifStatements()
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
QString testFile = baseDir + u"/ifStatements.qml"_s;
|
|
DomItem rootQmlObject = rootQmlObjectFromFile(testFile, qmltypeDirs);
|
|
DomItem block = rootQmlObject.path(".methods[\"conditional\"][0].body.scriptElement");
|
|
DomItem statements = block.field(Fields::statements);
|
|
QCOMPARE(statements.indexes(), 5);
|
|
|
|
// let i = 5
|
|
DomItem iDeclaration = statements.index(0);
|
|
QCOMPARE(iDeclaration.internalKind(), DomType::ScriptVariableDeclaration);
|
|
|
|
{
|
|
// if (i)
|
|
// i = 42
|
|
DomItem conditional = statements.index(1);
|
|
DomItem condition = conditional.field(Fields::condition);
|
|
QCOMPARE(condition.internalKind(), DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(condition.field(Fields::identifier).value().toString(), u"i"_s);
|
|
|
|
DomItem consequence = conditional.field(Fields::consequence);
|
|
QCOMPARE(consequence.internalKind(), DomType::ScriptBinaryExpression);
|
|
QCOMPARE(consequence.field(Fields::left).field(Fields::identifier).value().toString(),
|
|
u"i"_s);
|
|
QCOMPARE(consequence.field(Fields::right).field(Fields::value).value().toDouble(), 42);
|
|
|
|
QCOMPARE(conditional.field(Fields::alternative).internalKind(), DomType::Empty);
|
|
}
|
|
{
|
|
// if (i == 55)
|
|
// i = 32
|
|
// else
|
|
// i = i - 1
|
|
DomItem conditional = statements.index(2);
|
|
DomItem condition = conditional.field(Fields::condition);
|
|
QCOMPARE(condition.internalKind(), DomType::ScriptBinaryExpression);
|
|
QCOMPARE(condition.field(Fields::right).field(Fields::value).value().toDouble(), 55);
|
|
|
|
DomItem consequence = conditional.field(Fields::consequence);
|
|
QCOMPARE(consequence.internalKind(), DomType::ScriptBinaryExpression);
|
|
QCOMPARE(consequence.field(Fields::left).field(Fields::identifier).value().toString(),
|
|
u"i"_s);
|
|
QCOMPARE(consequence.field(Fields::right).field(Fields::value).value().toDouble(), 32);
|
|
|
|
DomItem alternative = conditional.field(Fields::alternative);
|
|
QCOMPARE(alternative.internalKind(), DomType::ScriptBinaryExpression);
|
|
QCOMPARE(alternative.field(Fields::left).field(Fields::identifier).value().toString(),
|
|
u"i"_s);
|
|
QCOMPARE(alternative.field(Fields::right).internalKind(),
|
|
DomType::ScriptBinaryExpression);
|
|
}
|
|
{
|
|
// if (i == 42) {
|
|
// i = 111
|
|
// }
|
|
DomItem conditional = statements.index(3);
|
|
DomItem condition = conditional.field(Fields::condition);
|
|
QCOMPARE(condition.internalKind(), DomType::ScriptBinaryExpression);
|
|
QCOMPARE(condition.field(Fields::right).field(Fields::value).value().toDouble(), 42);
|
|
|
|
DomItem consequence = conditional.field(Fields::consequence);
|
|
auto blockSemanticScope = consequence.semanticScope();
|
|
QVERIFY(blockSemanticScope);
|
|
QVERIFY(*blockSemanticScope);
|
|
QCOMPARE(consequence.internalKind(), DomType::ScriptBlockStatement);
|
|
QCOMPARE(consequence.field(Fields::statements).indexes(), 1);
|
|
DomItem consequence1 = consequence.field(Fields::statements).index(0);
|
|
QCOMPARE(consequence1.field(Fields::left).field(Fields::identifier).value().toString(),
|
|
u"i"_s);
|
|
QCOMPARE(consequence1.field(Fields::right).field(Fields::value).value().toDouble(),
|
|
111);
|
|
|
|
QCOMPARE(conditional.field(Fields::alternative).internalKind(), DomType::Empty);
|
|
}
|
|
{
|
|
// if (i == 746) {
|
|
// i = 123
|
|
// } else {
|
|
// i = 456
|
|
// }
|
|
|
|
DomItem conditional = statements.index(4);
|
|
DomItem condition = conditional.field(Fields::condition);
|
|
QCOMPARE(condition.internalKind(), DomType::ScriptBinaryExpression);
|
|
QCOMPARE(condition.field(Fields::right).field(Fields::value).value().toDouble(), 746);
|
|
|
|
{
|
|
DomItem consequence = conditional.field(Fields::consequence);
|
|
auto blockSemanticScope = consequence.semanticScope();
|
|
QVERIFY(blockSemanticScope);
|
|
QVERIFY(*blockSemanticScope);
|
|
QCOMPARE(consequence.internalKind(), DomType::ScriptBlockStatement);
|
|
QCOMPARE(consequence.field(Fields::statements).indexes(), 1);
|
|
DomItem consequence1 = consequence.field(Fields::statements).index(0);
|
|
QCOMPARE(consequence1.field(Fields::left)
|
|
.field(Fields::identifier)
|
|
.value()
|
|
.toString(),
|
|
u"i"_s);
|
|
QCOMPARE(consequence1.field(Fields::right).field(Fields::value).value().toDouble(),
|
|
123);
|
|
}
|
|
|
|
{
|
|
DomItem alternative = conditional.field(Fields::alternative);
|
|
auto blockSemanticScope = alternative.semanticScope();
|
|
QVERIFY(blockSemanticScope);
|
|
QVERIFY(*blockSemanticScope);
|
|
QCOMPARE(alternative.internalKind(), DomType::ScriptBlockStatement);
|
|
QCOMPARE(alternative.field(Fields::statements).indexes(), 1);
|
|
DomItem alternative1 = alternative.field(Fields::statements).index(0);
|
|
QCOMPARE(alternative1.field(Fields::left)
|
|
.field(Fields::identifier)
|
|
.value()
|
|
.toString(),
|
|
u"i"_s);
|
|
QCOMPARE(alternative1.field(Fields::right).field(Fields::value).value().toDouble(),
|
|
456);
|
|
}
|
|
}
|
|
}
|
|
|
|
void returnStatement()
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
QString testFile = baseDir + u"/returnStatements.qml"_s;
|
|
DomItem rootQmlObject = rootQmlObjectFromFile(testFile, qmltypeDirs);
|
|
DomItem block = rootQmlObject.path(".methods[\"returningFunction\"][0].body.scriptElement");
|
|
QCOMPARE(block.internalKind(), DomType::ScriptBlockStatement);
|
|
QCOMPARE(block.field(Fields::statements).indexes(), 1);
|
|
DomItem conditional = block.field(Fields::statements).index(0);
|
|
DomItem consequence = conditional.field(Fields::consequence);
|
|
QCOMPARE(consequence.internalKind(), DomType::ScriptReturnStatement);
|
|
{
|
|
DomItem returnValue = consequence.field(Fields::expression);
|
|
QCOMPARE(returnValue.internalKind(), DomType::ScriptLiteral);
|
|
QCOMPARE(returnValue.field(Fields::value).value().toDouble(), 123);
|
|
}
|
|
DomItem alternative = conditional.field(Fields::alternative);
|
|
QCOMPARE(alternative.internalKind(), DomType::ScriptReturnStatement);
|
|
{
|
|
DomItem returnValue = alternative.field(Fields::expression);
|
|
QCOMPARE(returnValue.internalKind(), DomType::ScriptBinaryExpression);
|
|
QCOMPARE(returnValue.field(Fields::left).field(Fields::value).value().toDouble(), 1);
|
|
QCOMPARE(returnValue.field(Fields::right).field(Fields::value).value().toDouble(), 2);
|
|
}
|
|
}
|
|
|
|
void forStatements()
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
QString testFile = baseDir + u"/forStatements.qml"_s;
|
|
DomItem rootQmlObject = rootQmlObjectFromFile(testFile, qmltypeDirs);
|
|
DomItem block = rootQmlObject.path(".methods[\"f\"][0].body.scriptElement");
|
|
DomItem statements = block.field(Fields::statements);
|
|
DomItem forLoop = statements.index(1);
|
|
{
|
|
// for ( >> let i = 0 << ; i < 100; i = i + 1) {
|
|
DomItem declarationList =
|
|
forLoop.field(Fields::declarations).field(Fields::declarations);
|
|
QCOMPARE(declarationList.internalKind(), DomType::List);
|
|
|
|
QCOMPARE(declarationList.indexes(), 1);
|
|
DomItem declaration = declarationList.index(0);
|
|
|
|
QCOMPARE(declaration.internalKind(), DomType::ScriptVariableDeclarationEntry);
|
|
QCOMPARE(declaration.field(Fields::initializer).internalKind(), DomType::ScriptLiteral);
|
|
|
|
QCOMPARE(declaration.field(Fields::identifier).value().toString(), "i");
|
|
QCOMPARE(declaration.field(Fields::initializer).field(Fields::value).value().toDouble(),
|
|
0);
|
|
}
|
|
{
|
|
// for ( let i = 0; >> i < 100 <<; i = i + 1) {
|
|
DomItem condition = forLoop.field(Fields::condition);
|
|
QCOMPARE(condition.internalKind(), DomType::ScriptBinaryExpression);
|
|
|
|
QCOMPARE(condition.field(Fields::left).internalKind(),
|
|
DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(condition.field(Fields::left).field(Fields::identifier).value().toString(),
|
|
"i");
|
|
|
|
QCOMPARE(condition.field(Fields::right).internalKind(), DomType::ScriptLiteral);
|
|
QCOMPARE(condition.field(Fields::right).field(Fields::value).value().toDouble(), 100);
|
|
}
|
|
{
|
|
// for ( let i = 0; i < 100; >> i = i + 1 << ) {
|
|
DomItem expression = forLoop.field(Fields::expression);
|
|
QCOMPARE(expression.internalKind(), DomType::ScriptBinaryExpression);
|
|
DomItem left = expression.field(Fields::left);
|
|
QCOMPARE(left.internalKind(), DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(left.field(Fields::identifier).value().toString(), "i");
|
|
|
|
// for ( let i = 0; i < 100; i = >> i + 1 << ) {
|
|
DomItem right = expression.field(Fields::right);
|
|
QCOMPARE(right.internalKind(), DomType::ScriptBinaryExpression);
|
|
DomItem left2 = right.field(Fields::left);
|
|
QCOMPARE(left2.internalKind(), DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(left2.field(Fields::identifier).value().toString(), "i");
|
|
|
|
DomItem right2 = right.field(Fields::right);
|
|
QCOMPARE(right2.internalKind(), DomType::ScriptLiteral);
|
|
QCOMPARE(right2.field(Fields::value).value().toDouble(), 1);
|
|
}
|
|
{
|
|
// test the body of the for-loop
|
|
DomItem body = forLoop.field(Fields::body);
|
|
auto blockSemanticScope = body.semanticScope();
|
|
QVERIFY(blockSemanticScope);
|
|
QVERIFY(*blockSemanticScope);
|
|
QCOMPARE(body.internalKind(), DomType::ScriptBlockStatement);
|
|
DomItem statementList = body.field(Fields::statements);
|
|
QCOMPARE(statementList.indexes(), 2);
|
|
{
|
|
// >> sum = sum + 1 <<
|
|
DomItem binaryExpression = statementList.index(0);
|
|
QCOMPARE(binaryExpression.internalKind(), DomType::ScriptBinaryExpression);
|
|
|
|
DomItem left = binaryExpression.field(Fields::left);
|
|
QCOMPARE(left.internalKind(), DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(left.field(Fields::identifier).value().toString(), "sum");
|
|
|
|
// sum = >> sum + 1 <<
|
|
DomItem right = binaryExpression.field(Fields::right);
|
|
QCOMPARE(right.internalKind(), DomType::ScriptBinaryExpression);
|
|
|
|
DomItem left2 = right.field(Fields::left);
|
|
QCOMPARE(left2.internalKind(), DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(left2.field(Fields::identifier).value().toString(), "sum");
|
|
|
|
DomItem right2 = right.field(Fields::right);
|
|
QCOMPARE(right2.internalKind(), DomType::ScriptLiteral);
|
|
QCOMPARE(right2.field(Fields::value).value().toDouble(), 1);
|
|
}
|
|
|
|
{
|
|
// >> for (;;) <<
|
|
// i = 42
|
|
DomItem innerForLoop = statementList.index(1);
|
|
QCOMPARE(innerForLoop.internalKind(), DomType::ScriptForStatement);
|
|
QCOMPARE(innerForLoop.field(Fields::declarations).indexes(), 0);
|
|
QVERIFY(!innerForLoop.field(Fields::initializer));
|
|
QVERIFY(!innerForLoop.field(Fields::condition));
|
|
QVERIFY(!innerForLoop.field(Fields::expression));
|
|
QVERIFY(innerForLoop.field(Fields::body));
|
|
|
|
// for (;;)
|
|
// >> i = 42 <<
|
|
DomItem expression = innerForLoop.field(Fields::body);
|
|
QCOMPARE(expression.internalKind(), DomType::ScriptBinaryExpression);
|
|
|
|
DomItem left = expression.field(Fields::left);
|
|
QCOMPARE(left.internalKind(), DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(left.field(Fields::identifier).value().toString(), "i");
|
|
|
|
DomItem right = expression.field(Fields::right);
|
|
QCOMPARE(right.internalKind(), DomType::ScriptLiteral);
|
|
QCOMPARE(right.field(Fields::value).value().toDouble(), 42);
|
|
}
|
|
}
|
|
}
|
|
|
|
void nullStatements()
|
|
{
|
|
using namespace Qt::StringLiterals;
|
|
QString testFile = baseDir + u"/nullStatements.qml"_s;
|
|
DomItem rootQmlObject = rootQmlObjectFromFile(testFile, qmltypeDirs);
|
|
DomItem block = rootQmlObject.methods()
|
|
.key(u"testForNull"_s)
|
|
.index(0)
|
|
.field(Fields::body)
|
|
.field(Fields::scriptElement);
|
|
|
|
QVERIFY(block);
|
|
// First for
|
|
DomItem statements = block.field(Fields::statements);
|
|
QCOMPARE(statements.internalKind(), DomType::List);
|
|
QVERIFY(statements.index(0).field(Fields::body).field(Fields::statements).internalKind()
|
|
!= DomType::Empty);
|
|
QCOMPARE(statements.index(0).field(Fields::body).field(Fields::statements).length(), 0);
|
|
|
|
// Second for
|
|
DomItem secondFor = statements.index(1).field(Fields::body);
|
|
QVERIFY(secondFor.internalKind() == DomType::ScriptIdentifierExpression);
|
|
QCOMPARE(secondFor.field(Fields::identifier).value().toString(), u"x"_s);
|
|
|
|
// Empty block
|
|
QVERIFY(statements.index(3).field(Fields::statements).internalKind() != DomType::Empty);
|
|
QCOMPARE(statements.index(3).field(Fields::statements).length(), 0);
|
|
}
|
|
|
|
private:
|
|
static DomItem rootQmlObjectFromFile(const QString &path, const QStringList &qmltypeDirs)
|
|
{
|
|
DomItem env = DomEnvironment::create(
|
|
qmltypeDirs,
|
|
QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
|
|
| QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
|
|
|
|
DomItem tFile;
|
|
DomCreationOptions options;
|
|
options.setFlag(DomCreationOption::WithScriptExpressions);
|
|
options.setFlag(DomCreationOption::WithSemanticAnalysis);
|
|
|
|
env.loadFile(
|
|
FileToLoad::fromFileSystem(env.ownerAs<DomEnvironment>(), path, options),
|
|
[&tFile](Path, DomItem &, DomItem &newIt) { tFile = newIt.fileObject(); },
|
|
LoadOption::DefaultLoad);
|
|
env.loadPendingDependencies();
|
|
|
|
return tFile.rootQmlObject(GoTo::MostLikely);
|
|
}
|
|
|
|
private:
|
|
QString baseDir;
|
|
QStringList qmltypeDirs;
|
|
std::shared_ptr<DomUniverse> universePtr;
|
|
std::shared_ptr<DomEnvironment> envPtr;
|
|
DomItem env;
|
|
std::shared_ptr<MockOwner> testOwnerPtr;
|
|
DomItem tOwner;
|
|
};
|
|
|
|
} // namespace Dom
|
|
} // namespace QQmlJS
|
|
QT_END_NAMESPACE
|
|
|
|
#endif
|