Implement strict mode for qmldir modules

Allow a module's qmldir to contain a module directive, which when
present specifies 'strict mode' import processing.  In strict mode,
type registrations are only permitted into the namespace identified
in the qmldir file's module directive.  In addition, any type
registrations to that namespace originating from other modules are
treated as error conditions.

Task-number: QTBUG-26551

Change-Id: I081bde2d3b83d3f28524440177fb2cd1ccee34ad
Reviewed-by: Chris Adams <christopher.adams@nokia.com>
Reviewed-by: Roberto Raggi <roberto.raggi@nokia.com>
This commit is contained in:
Matthew Vogt 2012-07-25 16:59:17 +10:00 committed by Qt by Nokia
parent 2e6accbbbb
commit c9b7582a2e
60 changed files with 1142 additions and 17 deletions

View File

@ -1 +1,2 @@
module Qt.labs.folderlistmodel
plugin qmlfolderlistmodelplugin

View File

@ -1 +1,2 @@
plugin qmllocalstorageplugin
module QtQuick.LocalStorage
plugin qmllocalstorageplugin

View File

@ -1 +1,2 @@
module QtQuick.Particles
plugin particlesplugin

View File

@ -1 +1,2 @@
module QtQuick
plugin qtquick2plugin

View File

@ -1,3 +1,4 @@
module QtTest
plugin qmltestplugin
TestCase 1.0 TestCase.qml
SignalSpy 1.0 SignalSpy.qml

View File

@ -1 +1,2 @@
module QtQuick.Window
plugin windowplugin

View File

@ -1 +1,2 @@
plugin qmlxmllistmodelplugin
module QtQuick.XmlListModel
plugin qmlxmllistmodelplugin

View File

@ -99,11 +99,13 @@ bool QQmlDirParser::parse(const QString &source)
_scripts.clear();
int lineNumber = 0;
bool firstLine = true;
const QChar *ch = source.constData();
while (!ch->isNull()) {
++lineNumber;
bool invalidLine = false;
const QChar *lineStart = ch;
scanSpace(ch);
@ -129,6 +131,7 @@ bool QQmlDirParser::parse(const QString &source)
} else {
reportError(lineNumber, start-lineStart, QLatin1String("unexpected token"));
scanToEnd(ch);
invalidLine = true;
break;
}
scanSpace(ch);
@ -137,9 +140,32 @@ bool QQmlDirParser::parse(const QString &source)
if (!ch->isNull())
++ch;
if (sectionCount == 0) {
if (invalidLine) {
reportError(lineNumber, -1,
QString::fromUtf8("invalid qmldir directive contains too many tokens"));
continue;
} else if (sectionCount == 0) {
continue; // no sections, no party.
} else if (sections[0] == QLatin1String("module")) {
if (sectionCount != 2) {
reportError(lineNumber, -1,
QString::fromUtf8("module directive requires one argument, but %1 were provided").arg(sectionCount - 1));
continue;
}
if (!_typeNamespace.isEmpty()) {
reportError(lineNumber, -1,
QString::fromUtf8("only one module directive may be defined in a qmldir file"));
continue;
}
if (!firstLine) {
reportError(lineNumber, -1,
QString::fromUtf8("module directive must be the first directive in a qmldir file"));
continue;
}
_typeNamespace = sections[1];
} else if (sections[0] == QLatin1String("plugin")) {
if (sectionCount < 2) {
reportError(lineNumber, -1,
@ -209,6 +235,8 @@ bool QQmlDirParser::parse(const QString &source)
reportError(lineNumber, -1,
QString::fromUtf8("a component declaration requires two or three arguments, but %1 were provided").arg(sectionCount));
}
firstLine = false;
}
return hasError();
@ -239,16 +267,28 @@ void QQmlDirParser::setError(const QQmlError &e)
QList<QQmlError> QQmlDirParser::errors(const QString &uri) const
{
QUrl url(uri);
QList<QQmlError> errors = _errors;
for (int i = 0; i < errors.size(); ++i) {
QQmlError &e = errors[i];
QString description = e.description();
description.replace(QLatin1String("$$URI$$"), uri);
e.setDescription(description);
e.setUrl(url);
}
return errors;
}
QString QQmlDirParser::typeNamespace() const
{
return _typeNamespace;
}
void QQmlDirParser::setTypeNamespace(const QString &s)
{
_typeNamespace = s;
}
QList<QQmlDirParser::Plugin> QQmlDirParser::plugins() const
{
return _plugins;

View File

@ -62,7 +62,7 @@ QT_BEGIN_NAMESPACE
class QQmlError;
class QQmlEngine;
class QQmlDirParser
class Q_AUTOTEST_EXPORT QQmlDirParser
{
Q_DISABLE_COPY(QQmlDirParser)
@ -76,6 +76,9 @@ public:
void setError(const QQmlError &);
QList<QQmlError> errors(const QString &uri) const;
QString typeNamespace() const;
void setTypeNamespace(const QString &s);
struct Plugin
{
Plugin() {}
@ -139,6 +142,7 @@ private:
private:
QList<QQmlError> _errors;
QString _typeNamespace;
QHash<QHashedStringRef,Component> _components; // multi hash
QList<Script> _scripts;
QList<Plugin> _plugins;

View File

@ -1729,7 +1729,7 @@ void QQmlEngine::setPluginPathList(const QStringList &paths)
bool QQmlEngine::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
{
Q_D(QQmlEngine);
return d->importDatabase.importPlugin(filePath, uri, errors);
return d->importDatabase.importPlugin(filePath, uri, QString(), errors);
}
/*!

View File

@ -47,6 +47,7 @@
#include <QtCore/qfileinfo.h>
#include <QtCore/qpluginloader.h>
#include <QtCore/qlibraryinfo.h>
#include <QtCore/qreadwritelock.h>
#include <QtQml/qqmlextensioninterface.h>
#include <private/qqmlglobal_p.h>
#include <private/qqmltypenamecache_p.h>
@ -734,7 +735,7 @@ bool QQmlImportsPrivate::importExtension(const QString &qmldirFilePath,
QString resolvedFilePath = database->resolvePlugin(typeLoader, qmldirPath,
plugin.path, plugin.name);
if (!resolvedFilePath.isEmpty()) {
if (!database->importPlugin(resolvedFilePath, uri, errors)) {
if (!database->importPlugin(resolvedFilePath, uri, qmldir->typeNamespace(), errors)) {
if (errors) {
// XXX TODO: should we leave the import plugin error alone?
// Here, we pop it off the top and coalesce it into this error's message.
@ -1590,7 +1591,7 @@ void QQmlImportDatabase::setImportPathList(const QStringList &paths)
/*!
\internal
*/
bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors)
bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &uri, const QString &typeNamespace, QList<QQmlError> *errors)
{
if (qmlImportTrace())
qDebug().nospace() << "QQmlImportDatabase::importPlugin: " << uri << " from " << filePath;
@ -1635,9 +1636,53 @@ bool QQmlImportDatabase::importPlugin(const QString &filePath, const QString &ur
const char *moduleId = bytes.constData();
if (!typesRegistered) {
// XXX thread this code should probably be protected with a mutex.
qmlEnginePluginsWithRegisteredTypes()->insert(absoluteFilePath, uri);
iface->registerTypes(moduleId);
QStringList registrationFailures;
{
QWriteLocker lock(QQmlMetaType::typeRegistrationLock());
if (!typeNamespace.isEmpty()) {
// This is a 'strict' module
if (typeNamespace != uri) {
// The namespace for type registrations must match the URI for locating the module
QQmlError error;
error.setDescription(tr("Module namespace '%1' does not match import URI '%2'").arg(typeNamespace).arg(uri));
errors->prepend(error);
return false;
}
if (QQmlMetaType::namespaceContainsRegistrations(typeNamespace)) {
// Other modules have already installed to this namespace
QQmlError error;
error.setDescription(tr("Namespace '%1' has already been used for type registration").arg(typeNamespace));
errors->prepend(error);
return false;
} else {
QQmlMetaType::protectNamespace(typeNamespace);
}
} else {
// This is not a stict module - provide a warning
qWarning().nospace() << qPrintable(tr("Module '%1' does not contain a module directive - it cannot be protected from external registrations.").arg(uri));
}
QQmlMetaType::setTypeRegistrationNamespace(typeNamespace);
iface->registerTypes(moduleId);
registrationFailures = QQmlMetaType::typeRegistrationFailures();
QQmlMetaType::setTypeRegistrationNamespace(QString());
}
if (!registrationFailures.isEmpty()) {
foreach (const QString &failure, registrationFailures) {
QQmlError error;
error.setDescription(failure);
errors->prepend(error);
}
return false;
}
}
if (!engineInitialized) {
// things on the engine (eg. adding new global objects) have to be done for every

View File

@ -143,7 +143,7 @@ public:
QQmlImportDatabase(QQmlEngine *);
~QQmlImportDatabase();
bool importPlugin(const QString &filePath, const QString &uri, QList<QQmlError> *errors);
bool importPlugin(const QString &filePath, const QString &uri, const QString &importNamespace, QList<QQmlError> *errors);
QStringList importPathList(PathType type = LocalOrRemote) const;
void setImportPathList(const QStringList &paths);

View File

@ -108,6 +108,11 @@ struct QQmlMetaTypeData
QBitArray lists;
QList<QQmlPrivate::AutoParentFunction> parentFunctions;
QSet<QString> protectedNamespaces;
QString typeRegistrationNamespace;
QStringList typeRegistrationFailures;
};
class QQmlTypeModulePrivate
@ -128,7 +133,7 @@ public:
};
Q_GLOBAL_STATIC(QQmlMetaTypeData, metaTypeData)
Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock)
Q_GLOBAL_STATIC_WITH_ARGS(QReadWriteLock, metaTypeDataLock, (QReadWriteLock::Recursive))
static uint qHash(const QQmlMetaTypeData::VersionedUri &v)
{
@ -193,7 +198,7 @@ public:
// Avoid multiple fromUtf8(), copies and hashing of the module name.
// This is only called when metaTypeDataLock is locked.
static QHashedString moduletoUtf8(const char *module)
static QHashedString moduleFromUtf8(const char *module)
{
if (!module)
return QHashedString();
@ -241,7 +246,7 @@ QQmlType::QQmlType(int index, const QQmlPrivate::RegisterInterface &interface)
QQmlType::QQmlType(int index, const QQmlPrivate::RegisterType &type)
: d(new QQmlTypePrivate)
{
d->m_module = moduletoUtf8(type.uri);
d->m_module = moduleFromUtf8(type.uri);
d->m_elementName = QString::fromUtf8(type.elementName);
d->m_version_maj = type.versionMajor;
@ -902,6 +907,29 @@ int registerType(const QQmlPrivate::RegisterType &type)
QWriteLocker lock(metaTypeDataLock());
QQmlMetaTypeData *data = metaTypeData();
if (type.uri && type.elementName) {
QString nameSpace = moduleFromUtf8(type.uri);
if (!data->typeRegistrationNamespace.isEmpty()) {
// We can only install types into the registered namespace
if (nameSpace != data->typeRegistrationNamespace) {
QString failure(QCoreApplication::translate("qmlRegisterType",
"Cannot install element '%1' into unregistered namespace '%2'"));
data->typeRegistrationFailures.append(failure.arg(QString::fromUtf8(type.elementName)).arg(nameSpace));
return -1;
}
} else if (data->typeRegistrationNamespace != nameSpace) {
// Is the target namespace protected against further registrations?
if (data->protectedNamespaces.contains(nameSpace)) {
QString failure(QCoreApplication::translate("qmlRegisterType",
"Cannot install element '%1' into protected namespace '%2'"));
data->typeRegistrationFailures.append(failure.arg(QString::fromUtf8(type.elementName)).arg(nameSpace));
return -1;
}
}
}
int index = data->types.count();
QQmlType *dtype = new QQmlType(index, type);
@ -985,6 +1013,46 @@ int QQmlPrivate::qmlregister(RegistrationType type, void *data)
return -1;
}
bool QQmlMetaType::namespaceContainsRegistrations(const QString &uri)
{
QQmlMetaTypeData *data = metaTypeData();
// Has any type previously been installed to this namespace?
QHashedString nameSpace(uri);
foreach (const QQmlType *type, data->types)
if (type->module() == nameSpace)
return true;
return false;
}
void QQmlMetaType::protectNamespace(const QString &uri)
{
QQmlMetaTypeData *data = metaTypeData();
data->protectedNamespaces.insert(uri);
}
void QQmlMetaType::setTypeRegistrationNamespace(const QString &uri)
{
QQmlMetaTypeData *data = metaTypeData();
data->typeRegistrationNamespace = uri;
data->typeRegistrationFailures.clear();
}
QStringList QQmlMetaType::typeRegistrationFailures()
{
QQmlMetaTypeData *data = metaTypeData();
return data->typeRegistrationFailures;
}
QReadWriteLock *QQmlMetaType::typeRegistrationLock()
{
return metaTypeDataLock();
}
/*
Returns true if a module \a uri of any version is installed.
*/

View File

@ -69,6 +69,7 @@ class QQmlTypePrivate;
class QQmlTypeModule;
class QHashedString;
class QHashedStringRef;
class QReadWriteLock;
class Q_QML_PRIVATE_EXPORT QQmlMetaType
{
@ -139,6 +140,15 @@ public:
static ModuleApi moduleApi(const QString &, int, int);
static QHash<QString, QList<ModuleApi> > moduleApis();
static bool namespaceContainsRegistrations(const QString &);
static void protectNamespace(const QString &);
static void setTypeRegistrationNamespace(const QString &);
static QStringList typeRegistrationFailures();
static QReadWriteLock *typeRegistrationLock();
private:
static CompareFunction anchorLineCompareFunction;
};

View File

@ -1381,6 +1381,11 @@ QList<QQmlError> QQmlTypeLoader::QmldirContent::errors(const QString &uri) const
return m_parser.errors(uri);
}
QString QQmlTypeLoader::QmldirContent::typeNamespace() const
{
return m_parser.typeNamespace();
}
void QQmlTypeLoader::QmldirContent::setContent(const QString &location, const QString &content)
{
m_location = location;

View File

@ -302,6 +302,8 @@ public:
bool hasError() const;
QList<QQmlError> errors(const QString &uri) const;
QString typeNamespace() const;
QQmlDirComponents components() const;
QQmlDirScripts scripts() const;
QQmlDirPlugins plugins() const;

View File

@ -1 +1,2 @@
module bundletest
plugin plugin1

View File

@ -0,0 +1 @@
module foo bar

View File

@ -0,0 +1 @@
plugin foo bar baz

View File

@ -0,0 +1 @@
foo bar baz qux

View File

@ -0,0 +1 @@
module

View File

@ -0,0 +1 @@
plugin

View File

@ -0,0 +1 @@
foo 100 bar

View File

@ -0,0 +1,15 @@
#
# Comment
module ModuleNamespace
plugin PluginA plugina.so # More comment
ComponentA 1.0 componenta-1_0.qml
ScriptA 1.0 scripta-1_0.js
#
ComponentA 1.5 componenta-1_5.qml
ComponentB 1.5 componentb-1_5.qml

View File

@ -0,0 +1 @@
plugin foo bar

View File

@ -0,0 +1 @@
plugin foo

View File

@ -0,0 +1,4 @@
# only empty lines
# and comments

View File

@ -0,0 +1,2 @@
plugin foo
module bar

View File

@ -0,0 +1 @@
foo

View File

@ -0,0 +1,2 @@
module foo
module bar

View File

@ -0,0 +1 @@
foo bar

View File

@ -0,0 +1 @@
foo 33.66 bar

View File

@ -0,0 +1 @@
foo 33.66 bar.js

View File

@ -0,0 +1,10 @@
CONFIG += testcase
TARGET = tst_qqmldirparser
QT += qml testlib v8-private
macx:CONFIG -= app_bundle
SOURCES += tst_qqmldirparser.cpp
include (../../shared/util.pri)
CONFIG += parallel_test

View File

@ -0,0 +1,288 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "../../shared/util.h"
#include <qtest.h>
#include <QObject>
#include <QQmlEngine>
#include <QQmlComponent>
#include <private/v8.h>
#include <private/qqmldirparser_p.h>
#include <QDebug>
// Test the parsing of qmldir files
class tst_qqmldirparser : public QQmlDataTest
{
Q_OBJECT
public:
tst_qqmldirparser();
private slots:
void parse_data();
void parse();
};
tst_qqmldirparser::tst_qqmldirparser()
{
}
namespace {
QStringList toStringList(const QList<QQmlError> &errors)
{
QStringList rv;
foreach (const QQmlError &e, errors)
rv.append(e.toString());
return rv;
}
QString toString(const QQmlDirParser::Plugin &p)
{
return p.name + "|" + p.path;
}
QStringList toStringList(const QList<QQmlDirParser::Plugin> &plugins)
{
QStringList rv;
foreach (const QQmlDirParser::Plugin &p, plugins)
rv.append(toString(p));
return rv;
}
QString toString(const QQmlDirParser::Component &c)
{
return c.typeName + "|" + c.fileName + "|" + QString::number(c.majorVersion) + "|" + QString::number(c.minorVersion) + "|" + (c.internal ? "true" : "false");
}
QStringList toStringList(const QQmlDirComponents &components)
{
QStringList rv;
foreach (const QQmlDirParser::Component &c, components.values())
rv.append(toString(c));
qSort(rv);
return rv;
}
QString toString(const QQmlDirParser::Script &s)
{
return s.nameSpace + "|" + s.fileName + "|" + QString::number(s.majorVersion) + "|" + QString::number(s.minorVersion);
}
QStringList toStringList(const QList<QQmlDirParser::Script> &scripts)
{
QStringList rv;
foreach (const QQmlDirParser::Script &s, scripts)
rv.append(toString(s));
return rv;
}
}
void tst_qqmldirparser::parse_data()
{
QTest::addColumn<QString>("file");
QTest::addColumn<QStringList>("errors");
QTest::addColumn<QStringList>("plugins");
QTest::addColumn<QStringList>("components");
QTest::addColumn<QStringList>("scripts");
QTest::newRow("empty")
<< "empty/qmldir"
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("no-content")
<< "no-content/qmldir"
<< QStringList()
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("one-section")
<< "one-section/qmldir"
<< (QStringList() << "qmldir:1: a component declaration requires two or three arguments, but 1 were provided")
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("four-sections")
<< "four-sections/qmldir"
<< (QStringList() << "qmldir:1:12: unexpected token"
<< "qmldir:1: invalid qmldir directive contains too many tokens")
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("incomplete-module")
<< "incomplete-module/qmldir"
<< (QStringList() << "qmldir:1: module directive requires one argument, but 0 were provided")
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("excessive-module")
<< "excessive-module/qmldir"
<< (QStringList() << "qmldir:1: module directive requires one argument, but 2 were provided")
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("repeated-module")
<< "repeated-module/qmldir"
<< (QStringList() << "qmldir:2: only one module directive may be defined in a qmldir file")
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("non-first-module")
<< "non-first-module/qmldir"
<< (QStringList() << "qmldir:2: module directive must be the first directive in a qmldir file")
<< (QStringList() << "foo|")
<< QStringList()
<< QStringList();
QTest::newRow("incomplete-plugin")
<< "incomplete-plugin/qmldir"
<< (QStringList() << "qmldir:1: plugin directive requires one or two arguments, but 0 were provided")
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("excessive-plugin")
<< "excessive-plugin/qmldir"
<< (QStringList() << "qmldir:1:15: unexpected token"
<< "qmldir:1: invalid qmldir directive contains too many tokens")
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("name-plugin")
<< "name-plugin/qmldir"
<< QStringList()
<< (QStringList() << "foo|")
<< QStringList()
<< QStringList();
QTest::newRow("name-path-plugin")
<< "name-path-plugin/qmldir"
<< QStringList()
<< (QStringList() << "foo|bar")
<< QStringList()
<< QStringList();
QTest::newRow("unversioned-component")
<< "unversioned-component/qmldir"
<< QStringList()
<< QStringList()
<< (QStringList() << "foo|bar|-1|-1|false")
<< QStringList();
QTest::newRow("invalid-versioned-component")
<< "invalid-versioned-component/qmldir"
<< (QStringList() << "qmldir:1: expected '.'")
<< QStringList()
<< QStringList()
<< QStringList();
QTest::newRow("versioned-component")
<< "versioned-component/qmldir"
<< QStringList()
<< QStringList()
<< (QStringList() << "foo|bar|33|66|false")
<< QStringList();
QTest::newRow("versioned-script")
<< "versioned-script/qmldir"
<< QStringList()
<< QStringList()
<< QStringList()
<< (QStringList() << "foo|bar.js|33|66");
QTest::newRow("multiple")
<< "multiple/qmldir"
<< QStringList()
<< (QStringList() << "PluginA|plugina.so")
<< (QStringList() << "ComponentA|componenta-1_0.qml|1|0|false"
<< "ComponentA|componenta-1_5.qml|1|5|false"
<< "ComponentB|componentb-1_5.qml|1|5|false")
<< (QStringList() << "ScriptA|scripta-1_0.js|1|0");
}
void tst_qqmldirparser::parse()
{
QFETCH(QString, file);
QFETCH(QStringList, errors);
QFETCH(QStringList, plugins);
QFETCH(QStringList, components);
QFETCH(QStringList, scripts);
QFile f(testFile(file));
f.open(QIODevice::ReadOnly);
QQmlDirParser p;
p.parse(f.readAll());
if (errors.isEmpty()) {
QCOMPARE(p.hasError(), false);
} else {
QCOMPARE(p.hasError(), true);
QCOMPARE(toStringList(p.errors("qmldir")), errors);
}
QCOMPARE(toStringList(p.plugins()), plugins);
QCOMPARE(toStringList(p.components()), components);
QCOMPARE(toStringList(p.scripts()), scripts);
}
QTEST_MAIN(tst_qqmldirparser)
#include "tst_qqmldirparser.moc"

View File

@ -1,3 +1,4 @@
1:12:unexpected token
1:-1:expected '.'
1:-1:invalid qmldir directive contains too many tokens
2:17:unexpected token
2:-1:invalid qmldir directive contains too many tokens

View File

@ -0,0 +1,12 @@
TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
DESTDIR = ../imports/com/nokia/InvalidNamespaceModule
QT += core-private gui-private qml-private
IMPORT_FILES = \
qmldir
include (../../../shared/imports.pri)

View File

@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QStringList>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <QDebug>
class MyPluginType : public QObject
{
Q_OBJECT
public:
MyPluginType(QObject *parent=0) : QObject(parent) {}
};
class MyPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
MyPlugin() {}
void registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == "com.nokia.InvalidStrictModule");
qmlRegisterType<MyPluginType>("com.nokia.SomeOtherModule", 1, 0, "MyPluginType");
}
};
#include "plugin.moc"

View File

@ -0,0 +1,2 @@
module com.nokia.AwesomeModule
plugin invalidNamespaceModule

View File

@ -0,0 +1,12 @@
TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
DESTDIR = ../imports/com/nokia/InvalidStrictModule
QT += core-private gui-private qml-private
IMPORT_FILES = \
qmldir
include (../../../shared/imports.pri)

View File

@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QStringList>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <QDebug>
class MyPluginType : public QObject
{
Q_OBJECT
public:
MyPluginType(QObject *parent=0) : QObject(parent) {}
};
class MyPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
MyPlugin() {}
void registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == "com.nokia.InvalidStrictModule");
qmlRegisterType<MyPluginType>("com.nokia.SomeOtherModule", 1, 0, "MyPluginType");
}
};
#include "plugin.moc"

View File

@ -0,0 +1,2 @@
module com.nokia.InvalidStrictModule
plugin invalidStrictModule

View File

@ -0,0 +1,12 @@
TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
DESTDIR = ../imports/com/nokia/NonstrictModule
QT += core-private gui-private qml-private
IMPORT_FILES = \
qmldir
include (../../../shared/imports.pri)

View File

@ -0,0 +1,71 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QStringList>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <QDebug>
class MyPluginType : public QObject
{
Q_OBJECT
public:
MyPluginType(QObject *parent=0) : QObject(parent) {}
};
class MyPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
MyPlugin() {}
void registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == "com.nokia.NonstrictModule");
// Install into a namespace that should be protected
qmlRegisterType<MyPluginType>("com.nokia.StrictModule", 1, 0, "MyPluginType");
}
};
#include "plugin.moc"

View File

@ -0,0 +1 @@
plugin nonstrictModule

View File

@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QStringList>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <QDebug>
class MyPluginType : public QObject
{
Q_OBJECT
public:
MyPluginType(QObject *parent=0) : QObject(parent) {}
};
class MyPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
MyPlugin() {}
void registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == "com.nokia.PreemptedStrictModule");
qmlRegisterType<MyPluginType>(uri, 1, 0, "MyPluginType");
}
};
#include "plugin.moc"

View File

@ -0,0 +1,12 @@
TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
DESTDIR = ../imports/com/nokia/PreemptedStrictModule
QT += core-private gui-private qml-private
IMPORT_FILES = \
qmldir
include (../../../shared/imports.pri)

View File

@ -0,0 +1,2 @@
module com.nokia.PreemptedStrictModule
plugin preemptedStrictModule

View File

@ -0,0 +1,72 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QStringList>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <QDebug>
class MyPluginType : public QObject
{
Q_OBJECT
public:
MyPluginType(QObject *parent=0) : QObject(parent) {}
};
class MyPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
MyPlugin() {}
void registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == "com.nokia.PreemptiveModule");
qmlRegisterType<MyPluginType>("com.nokia.PreemptiveModule", 1, 0, "MyPluginType");
// Install into another namespace that should be protected
qmlRegisterType<MyPluginType>("com.nokia.PreemptedStrictModule", 1, 0, "MyPluginType");
}
};
#include "plugin.moc"

View File

@ -0,0 +1,12 @@
TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
DESTDIR = ../imports/com/nokia/PreemptiveModule
QT += core-private gui-private qml-private
IMPORT_FILES = \
qmldir
include (../../../shared/imports.pri)

View File

@ -0,0 +1 @@
plugin preemptiveModule

View File

@ -1,6 +1,21 @@
QT = core
TEMPLATE = subdirs
SUBDIRS = plugin plugin.2 plugin.2.1 pluginWrongCase pluginWithQmlFile pluginMixed pluginVersion nestedPlugin
SUBDIRS =\
plugin\
plugin.2\
plugin.2.1\
pluginWrongCase\
pluginWithQmlFile\
pluginMixed\
pluginVersion\
nestedPlugin\
strictModule\
invalidStrictModule\
nonstrictModule\
preemptiveModule\
preemptedStrictModule\
invalidNamespaceModule
tst_qqmlmoduleplugin_pro.depends += plugin
SUBDIRS += tst_qqmlmoduleplugin.pro

View File

@ -0,0 +1,69 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QStringList>
#include <QtQml/qqmlextensionplugin.h>
#include <QtQml/qqml.h>
#include <QDebug>
class MyPluginType : public QObject
{
Q_OBJECT
public:
MyPluginType(QObject *parent=0) : QObject(parent) {}
};
class MyPlugin : public QQmlExtensionPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
public:
MyPlugin() {}
void registerTypes(const char *uri)
{
Q_ASSERT(QLatin1String(uri) == "com.nokia.StrictModule");
qmlRegisterType<MyPluginType>(uri, 1, 0, "MyPluginType");
}
};
#include "plugin.moc"

View File

@ -0,0 +1,2 @@
module com.nokia.StrictModule
plugin strictModule

View File

@ -0,0 +1,12 @@
TEMPLATE = lib
CONFIG += plugin
SOURCES = plugin.cpp
QT = core qml
DESTDIR = ../imports/com/nokia/StrictModule
QT += core-private gui-private qml-private
IMPORT_FILES = \
qmldir
include (../../../shared/imports.pri)

View File

@ -50,6 +50,10 @@
#define SERVER_ADDR "http://127.0.0.1:14456"
#define SERVER_PORT 14456
// Note: this test does not use module directives in the qmldir files, because
// it would result in repeated attempts to insert types into the same namespace.
// This occurs because type registration is process-global, while the test
// cases should really be run in proper per-process isolation.
class tst_qqmlmoduleplugin : public QQmlDataTest
{
@ -74,6 +78,8 @@ private slots:
void importsNested_data();
void importLocalModule();
void importLocalModule_data();
void importStrictModule();
void importStrictModule_data();
private:
QString m_importsDirectory;
@ -135,6 +141,7 @@ void tst_qqmlmoduleplugin::importsPlugin()
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "plugin created");
QTest::ignoreMessage(QtWarningMsg, "import worked");
QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlPluginType' does not contain a module directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
@ -151,6 +158,7 @@ void tst_qqmlmoduleplugin::importsPlugin2()
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "plugin2 created");
QTest::ignoreMessage(QtWarningMsg, "import2 worked");
QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlPluginType' does not contain a module directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works2.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
@ -167,6 +175,7 @@ void tst_qqmlmoduleplugin::importsPlugin21()
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "plugin2.1 created");
QTest::ignoreMessage(QtWarningMsg, "import2.1 worked");
QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlPluginType' does not contain a module directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works21.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
@ -215,6 +224,8 @@ void tst_qqmlmoduleplugin::importPluginWithQmlFile()
QQmlEngine engine;
engine.addImportPath(path);
QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestPluginWithQmlFile' does not contain a module directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("pluginWithQmlFile.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
@ -275,6 +286,8 @@ void tst_qqmlmoduleplugin::importsMixedQmlCppPlugin()
QQmlEngine engine;
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlMixedPluginType' does not contain a module directive - it cannot be protected from external registrations.");
{
QQmlComponent component(&engine, testFileUrl(QStringLiteral("importsMixedQmlCppPlugin.qml")));
@ -314,6 +327,10 @@ void tst_qqmlmoduleplugin::versionNotInstalled()
QQmlEngine engine;
engine.addImportPath(m_importsDirectory);
static int count = 0;
if (++count == 1)
QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlVersionPluginType' does not contain a module directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(file));
VERIFY_ERRORS(errorFile.toLatin1().constData());
}
@ -382,6 +399,10 @@ void tst_qqmlmoduleplugin::importsNested()
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
}
static int count = 0;
if (++count == 1)
QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlNestedPluginType' does not contain a module directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFile(file));
QObject *obj = component.create();
@ -446,6 +467,71 @@ void tst_qqmlmoduleplugin::importLocalModule_data()
<< 2 << 0;
}
void tst_qqmlmoduleplugin::importStrictModule()
{
QFETCH(QString, qml);
QFETCH(QString, warning);
QFETCH(QString, error);
if (!warning.isEmpty())
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QQmlEngine engine;
engine.addImportPath(m_importsDirectory);
QUrl url(testFileUrl("empty.qml"));
QQmlComponent component(&engine);
component.setData(qml.toUtf8(), url);
if (error.isEmpty()) {
QScopedPointer<QObject> object(component.create());
QVERIFY(object != 0);
} else {
QVERIFY(!component.isReady());
QCOMPARE(component.errors().count(), 1);
QCOMPARE(component.errors().first().toString(), url.toString() + error);
}
}
void tst_qqmlmoduleplugin::importStrictModule_data()
{
QTest::addColumn<QString>("qml");
QTest::addColumn<QString>("warning");
QTest::addColumn<QString>("error");
QTest::newRow("success")
<< "import com.nokia.StrictModule 1.0\n"
"MyPluginType {}"
<< QString()
<< QString();
QTest::newRow("wrong target")
<< "import com.nokia.InvalidStrictModule 1.0\n"
"MyPluginType {}"
<< QString()
<< ":1:1: plugin cannot be loaded for module \"com.nokia.InvalidStrictModule\": Cannot install element 'MyPluginType' into unregistered namespace 'com.nokia.SomeOtherModule'";
QTest::newRow("non-strict clash")
<< "import com.nokia.NonstrictModule 1.0\n"
"MyPluginType {}"
<< "Module 'com.nokia.NonstrictModule' does not contain a module directive - it cannot be protected from external registrations."
<< ":1:1: plugin cannot be loaded for module \"com.nokia.NonstrictModule\": Cannot install element 'MyPluginType' into protected namespace 'com.nokia.StrictModule'";
QTest::newRow("non-strict preemption")
<< "import com.nokia.PreemptiveModule 1.0\n"
"import com.nokia.PreemptedStrictModule 1.0\n"
"MyPluginType {}"
<< "Module 'com.nokia.PreemptiveModule' does not contain a module directive - it cannot be protected from external registrations."
<< ":2:1: plugin cannot be loaded for module \"com.nokia.PreemptedStrictModule\": Namespace 'com.nokia.PreemptedStrictModule' has already been used for type registration";
QTest::newRow("invalid namespace")
<< "import com.nokia.InvalidNamespaceModule 1.0\n"
"MyPluginType {}"
<< QString()
<< ":1:1: plugin cannot be loaded for module \"com.nokia.InvalidNamespaceModule\": Module namespace 'com.nokia.AwesomeModule' does not match import URI 'com.nokia.InvalidNamespaceModule'";
}
QTEST_MAIN(tst_qqmlmoduleplugin)
#include "tst_qqmlmoduleplugin.moc"

View File

@ -642,7 +642,13 @@ void tst_qquickanimations::resume()
QVERIFY(!animation.isPaused());
QCOMPARE(spy.count(), 2);
qmlRegisterType<QQuickPropertyAnimation>("QtQuick",2,0,"PropertyAnimation"); //make sure QQuickPropertyAnimation has correct qml type name
// Load QtQuick to ensure that QQuickPropertyAnimation is registered as PropertyAnimation
{
QQmlEngine engine;
QQmlComponent component(&engine);
component.setData("import QtQuick 2.0\nQtObject {}\n", QUrl());
}
QByteArray message = "<Unknown File>: QML PropertyAnimation: setPaused() cannot be used when animation isn't running.";
QTest::ignoreMessage(QtWarningMsg, message);
animation.pause();

View File

@ -1,5 +1,6 @@
import QtQuick 2.0
import QtQuick.Window 2.0 as Window
import Test 1.0
Window.Window {
RootItemAccessor {

View File

@ -1046,7 +1046,7 @@ void tst_qquickwindow::ignoreUnhandledMouseEvents()
void tst_qquickwindow::ownershipRootItem()
{
qmlRegisterType<RootItemAccessor>("QtQuick", 2, 0, "RootItemAccessor");
qmlRegisterType<RootItemAccessor>("Test", 1, 0, "RootItemAccessor");
QQmlEngine engine;
QQmlComponent component(&engine);