/**************************************************************************** ** ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** 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 #include #include #include #include #include #include #include #include #include #include "../../shared/util.h" #include class MyQmlObject : public QObject { Q_OBJECT public: MyQmlObject() {} }; QML_DECLARE_TYPE(MyQmlObject); class MyAttached : public QObject { Q_OBJECT Q_PROPERTY(int foo READ foo WRITE setFoo) public: MyAttached(QObject *parent) : QObject(parent), m_foo(13) {} int foo() const { return m_foo; } void setFoo(int f) { m_foo = f; } private: int m_foo; }; class MyContainer : public QObject { Q_OBJECT Q_PROPERTY(QDeclarativeListProperty children READ children) public: MyContainer() {} QDeclarativeListProperty children() { return QDeclarativeListProperty(this, m_children); } static MyAttached *qmlAttachedProperties(QObject *o) { return new MyAttached(o); } private: QList m_children; }; QML_DECLARE_TYPE(MyContainer); QML_DECLARE_TYPEINFO(MyContainer, QML_HAS_ATTACHED_PROPERTIES) class tst_qdeclarativeproperty : public QDeclarativeDataTest { Q_OBJECT public: tst_qdeclarativeproperty() {} private slots: void initTestCase(); // Constructors void qmlmetaproperty(); void qmlmetaproperty_object(); void qmlmetaproperty_object_string(); void qmlmetaproperty_object_context(); void qmlmetaproperty_object_string_context(); // Methods void name(); void read(); void write(); void reset(); // Functionality void writeObjectToList(); void writeListToList(); //writeToReadOnly(); void urlHandling_data(); void urlHandling(); void variantMapHandling_data(); void variantMapHandling(); // Bugs void crashOnValueProperty(); void aliasPropertyBindings(); void noContext(); void assignEmptyVariantMap(); void copy(); private: QDeclarativeEngine engine; }; void tst_qdeclarativeproperty::qmlmetaproperty() { QDeclarativeProperty prop; QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString()); QCOMPARE(prop.read(), QVariant()); QCOMPARE(prop.write(QVariant()), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), false); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QVERIFY(prop.method().signature() == 0); QCOMPARE(prop.type(), QDeclarativeProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); QCOMPARE(prop.propertyType(), 0); QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding == 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression == 0); QCOMPARE(prop.index(), -1); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } class PropertyObject : public QObject { Q_OBJECT Q_PROPERTY(int defaultProperty READ defaultProperty) Q_PROPERTY(QRect rectProperty READ rectProperty) Q_PROPERTY(QRect wrectProperty READ wrectProperty WRITE setWRectProperty) Q_PROPERTY(QUrl url READ url WRITE setUrl) Q_PROPERTY(QVariantMap variantMap READ variantMap WRITE setVariantMap) Q_PROPERTY(int resettableProperty READ resettableProperty WRITE setResettableProperty RESET resetProperty) Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal) Q_PROPERTY(MyQmlObject *qmlObject READ qmlObject) Q_CLASSINFO("DefaultProperty", "defaultProperty") public: PropertyObject() : m_resetProperty(9) {} int defaultProperty() { return 10; } QRect rectProperty() { return QRect(10, 10, 1, 209); } QRect wrectProperty() { return m_rect; } void setWRectProperty(const QRect &r) { m_rect = r; } QUrl url() { return m_url; } void setUrl(const QUrl &u) { m_url = u; } QVariantMap variantMap() const { return m_variantMap; } void setVariantMap(const QVariantMap &variantMap) { m_variantMap = variantMap; } int resettableProperty() const { return m_resetProperty; } void setResettableProperty(int r) { m_resetProperty = r; } void resetProperty() { m_resetProperty = 9; } int propertyWithNotify() const { return m_propertyWithNotify; } void setPropertyWithNotify(int i) { m_propertyWithNotify = i; emit oddlyNamedNotifySignal(); } MyQmlObject *qmlObject() { return &m_qmlObject; } signals: void clicked(); void oddlyNamedNotifySignal(); private: int m_resetProperty; QRect m_rect; QUrl m_url; QVariantMap m_variantMap; int m_propertyWithNotify; MyQmlObject m_qmlObject; }; QML_DECLARE_TYPE(PropertyObject); void tst_qdeclarativeproperty::qmlmetaproperty_object() { QObject object; // Has no default property PropertyObject dobject; // Has default property { QDeclarativeProperty prop(&object); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString()); QCOMPARE(prop.read(), QVariant()); QCOMPARE(prop.write(QVariant()), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), false); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QVERIFY(prop.method().signature() == 0); QCOMPARE(prop.type(), QDeclarativeProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); QCOMPARE(prop.propertyType(), 0); QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding == 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression == 0); QCOMPARE(prop.index(), -1); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } { QDeclarativeProperty prop(&dobject); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); binding.data()->setTarget(prop); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString("defaultProperty")); QCOMPARE(prop.read(), QVariant(10)); QCOMPARE(prop.write(QVariant()), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), true); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QVERIFY(prop.method().signature() == 0); QCOMPARE(prop.type(), QDeclarativeProperty::Property); QCOMPARE(prop.isProperty(), true); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), true); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal); QCOMPARE(prop.propertyType(), (int)QVariant::Int); QCOMPARE(prop.propertyTypeName(), "int"); QCOMPARE(QString(prop.property().name()), QString("defaultProperty")); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QTest::ignoreMessage(QtWarningMsg, ": Unable to assign null to int"); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding != 0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == binding.data()); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression == 0); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } } void tst_qdeclarativeproperty::qmlmetaproperty_object_string() { QObject object; PropertyObject dobject; { QDeclarativeProperty prop(&object, QString("defaultProperty")); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString()); QCOMPARE(prop.read(), QVariant()); QCOMPARE(prop.write(QVariant()), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), false); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QVERIFY(prop.method().signature() == 0); QCOMPARE(prop.type(), QDeclarativeProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); QCOMPARE(prop.propertyType(), 0); QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding == 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression == 0); QCOMPARE(prop.index(), -1); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } { QDeclarativeProperty prop(&dobject, QString("defaultProperty")); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); binding.data()->setTarget(prop); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString("defaultProperty")); QCOMPARE(prop.read(), QVariant(10)); QCOMPARE(prop.write(QVariant()), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), true); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QVERIFY(prop.method().signature() == 0); QCOMPARE(prop.type(), QDeclarativeProperty::Property); QCOMPARE(prop.isProperty(), true); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), true); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal); QCOMPARE(prop.propertyType(), (int)QVariant::Int); QCOMPARE(prop.propertyTypeName(), "int"); QCOMPARE(QString(prop.property().name()), QString("defaultProperty")); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QTest::ignoreMessage(QtWarningMsg, ": Unable to assign null to int"); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding != 0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == binding.data()); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression == 0); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } { QDeclarativeProperty prop(&dobject, QString("onClicked")); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); binding.data()->setTarget(prop); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString("onClicked")); QCOMPARE(prop.read(), QVariant()); QCOMPARE(prop.write(QVariant("Hello")), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), false); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QCOMPARE(QString(prop.method().signature()), QString("clicked()")); QCOMPARE(prop.type(), QDeclarativeProperty::SignalProperty); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), true); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); QCOMPARE(prop.propertyType(), 0); QCOMPARE(prop.propertyTypeName(), (const char *)0); QCOMPARE(prop.property().name(), (const char *)0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding == 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression != 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == expression.data()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()")); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } { QDeclarativeProperty prop(&dobject, QString("onPropertyWithNotifyChanged")); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); binding.data()->setTarget(prop); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString("onOddlyNamedNotifySignal")); QCOMPARE(prop.read(), QVariant()); QCOMPARE(prop.write(QVariant("Hello")), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), false); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QCOMPARE(QString(prop.method().signature()), QString("oddlyNamedNotifySignal()")); QCOMPARE(prop.type(), QDeclarativeProperty::SignalProperty); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), true); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); QCOMPARE(prop.propertyType(), 0); QCOMPARE(prop.propertyTypeName(), (const char *)0); QCOMPARE(prop.property().name(), (const char *)0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding == 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression != 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == expression.data()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()")); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } } void tst_qdeclarativeproperty::qmlmetaproperty_object_context() { QObject object; // Has no default property PropertyObject dobject; // Has default property { QDeclarativeProperty prop(&object, engine.rootContext()); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString()); QCOMPARE(prop.read(), QVariant()); QCOMPARE(prop.write(QVariant()), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), false); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QVERIFY(prop.method().signature() == 0); QCOMPARE(prop.type(), QDeclarativeProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); QCOMPARE(prop.propertyType(), 0); QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding == 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression == 0); QCOMPARE(prop.index(), -1); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } { QDeclarativeProperty prop(&dobject, engine.rootContext()); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); binding.data()->setTarget(prop); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString("defaultProperty")); QCOMPARE(prop.read(), QVariant(10)); QCOMPARE(prop.write(QVariant()), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), true); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QVERIFY(prop.method().signature() == 0); QCOMPARE(prop.type(), QDeclarativeProperty::Property); QCOMPARE(prop.isProperty(), true); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), true); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal); QCOMPARE(prop.propertyType(), (int)QVariant::Int); QCOMPARE(prop.propertyTypeName(), "int"); QCOMPARE(QString(prop.property().name()), QString("defaultProperty")); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QTest::ignoreMessage(QtWarningMsg, ": Unable to assign null to int"); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding != 0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == binding.data()); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression == 0); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } } void tst_qdeclarativeproperty::qmlmetaproperty_object_string_context() { QObject object; PropertyObject dobject; { QDeclarativeProperty prop(&object, QString("defaultProperty"), engine.rootContext()); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString()); QCOMPARE(prop.read(), QVariant()); QCOMPARE(prop.write(QVariant()), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), false); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QVERIFY(prop.method().signature() == 0); QCOMPARE(prop.type(), QDeclarativeProperty::Invalid); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), false); QCOMPARE(prop.object(), (QObject *)0); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); QCOMPARE(prop.propertyType(), 0); QCOMPARE(prop.propertyTypeName(), (const char *)0); QVERIFY(prop.property().name() == 0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding == 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression == 0); QCOMPARE(prop.index(), -1); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } { QDeclarativeProperty prop(&dobject, QString("defaultProperty"), engine.rootContext()); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); binding.data()->setTarget(prop); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString("defaultProperty")); QCOMPARE(prop.read(), QVariant(10)); QCOMPARE(prop.write(QVariant()), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), true); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QVERIFY(prop.method().signature() == 0); QCOMPARE(prop.type(), QDeclarativeProperty::Property); QCOMPARE(prop.isProperty(), true); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), true); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), false); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::Normal); QCOMPARE(prop.propertyType(), (int)QVariant::Int); QCOMPARE(prop.propertyTypeName(), "int"); QCOMPARE(QString(prop.property().name()), QString("defaultProperty")); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QTest::ignoreMessage(QtWarningMsg, ": Unable to assign null to int"); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding != 0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == binding.data()); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression == 0); QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty")); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } { QDeclarativeProperty prop(&dobject, QString("onClicked"), engine.rootContext()); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); binding.data()->setTarget(prop); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString("onClicked")); QCOMPARE(prop.read(), QVariant()); QCOMPARE(prop.write(QVariant("Hello")), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), false); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QCOMPARE(QString(prop.method().signature()), QString("clicked()")); QCOMPARE(prop.type(), QDeclarativeProperty::SignalProperty); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), true); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); QCOMPARE(prop.propertyType(), 0); QCOMPARE(prop.propertyTypeName(), (const char *)0); QCOMPARE(prop.property().name(), (const char *)0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding == 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression != 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == expression.data()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()")); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } { QDeclarativeProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext()); QWeakPointer binding(new QDeclarativeBinding(QLatin1String("null"), 0, engine.rootContext())); binding.data()->setTarget(prop); QVERIFY(binding != 0); QWeakPointer expression(new QDeclarativeExpression()); QVERIFY(expression != 0); QObject *obj = new QObject; QCOMPARE(prop.name(), QString("onOddlyNamedNotifySignal")); QCOMPARE(prop.read(), QVariant()); QCOMPARE(prop.write(QVariant("Hello")), false); QCOMPARE(prop.hasNotifySignal(), false); QCOMPARE(prop.needsNotifySignal(), false); QCOMPARE(prop.connectNotifySignal(0, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, SLOT(deleteLater())), false); QCOMPARE(prop.connectNotifySignal(obj, 0), false); QCOMPARE(prop.connectNotifySignal(0, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, obj->metaObject()->indexOfMethod("deleteLater()")), false); QCOMPARE(prop.connectNotifySignal(obj, -1), false); QCOMPARE(QString(prop.method().signature()), QString("oddlyNamedNotifySignal()")); QCOMPARE(prop.type(), QDeclarativeProperty::SignalProperty); QCOMPARE(prop.isProperty(), false); QCOMPARE(prop.isWritable(), false); QCOMPARE(prop.isDesignable(), false); QCOMPARE(prop.isResettable(), false); QCOMPARE(prop.isSignalProperty(), true); QCOMPARE(prop.isValid(), true); QCOMPARE(prop.object(), qobject_cast(&dobject)); QCOMPARE(prop.propertyTypeCategory(), QDeclarativeProperty::InvalidCategory); QCOMPARE(prop.propertyType(), 0); QCOMPARE(prop.propertyTypeName(), (const char *)0); QCOMPARE(prop.property().name(), (const char *)0); QVERIFY(QDeclarativePropertyPrivate::binding(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setBinding(prop, binding.data()) == 0); QVERIFY(binding == 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == 0); QVERIFY(QDeclarativePropertyPrivate::setSignalExpression(prop, expression.data()) == 0); QVERIFY(expression != 0); QVERIFY(QDeclarativePropertyPrivate::signalExpression(prop) == expression.data()); QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()")); QCOMPARE(QDeclarativePropertyPrivate::valueTypeCoreIndex(prop), -1); delete obj; } } void tst_qdeclarativeproperty::name() { { QDeclarativeProperty p; QCOMPARE(p.name(), QString()); } { PropertyObject o; QDeclarativeProperty p(&o); QCOMPARE(p.name(), QString("defaultProperty")); } { QObject o; QDeclarativeProperty p(&o, QString("objectName")); QCOMPARE(p.name(), QString("objectName")); } { PropertyObject o; QDeclarativeProperty p(&o, "onClicked"); QCOMPARE(p.name(), QString("onClicked")); } { QObject o; QDeclarativeProperty p(&o, "onClicked"); QCOMPARE(p.name(), QString()); } { PropertyObject o; QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged"); QCOMPARE(p.name(), QString("onOddlyNamedNotifySignal")); } { QObject o; QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged"); QCOMPARE(p.name(), QString()); } { QObject o; QDeclarativeProperty p(&o, "foo"); QCOMPARE(p.name(), QString()); } { QDeclarativeProperty p(0, "foo"); QCOMPARE(p.name(), QString()); } { PropertyObject o; QDeclarativeProperty p(&o, "rectProperty"); QCOMPARE(p.name(), QString("rectProperty")); } { PropertyObject o; QDeclarativeProperty p(&o, "rectProperty.x"); QCOMPARE(p.name(), QString("rectProperty.x")); } { PropertyObject o; QDeclarativeProperty p(&o, "rectProperty.foo"); QCOMPARE(p.name(), QString()); } } void tst_qdeclarativeproperty::read() { // Invalid { QDeclarativeProperty p; QCOMPARE(p.read(), QVariant()); } // Default prop { PropertyObject o; QDeclarativeProperty p(&o); QCOMPARE(p.read(), QVariant(10)); } // Invalid default prop { QObject o; QDeclarativeProperty p(&o); QCOMPARE(p.read(), QVariant()); } // Value prop by name { QObject o; QDeclarativeProperty p(&o, "objectName"); QCOMPARE(p.read(), QVariant(QString())); o.setObjectName("myName"); QCOMPARE(p.read(), QVariant("myName")); } // Value prop by name (static) { QObject o; QCOMPARE(QDeclarativeProperty::read(&o, "objectName"), QVariant(QString())); o.setObjectName("myName"); QCOMPARE(QDeclarativeProperty::read(&o, "objectName"), QVariant("myName")); } // Value-type prop { PropertyObject o; QDeclarativeProperty p(&o, "rectProperty.x"); QCOMPARE(p.read(), QVariant(10)); } // Invalid value-type prop { PropertyObject o; QDeclarativeProperty p(&o, "rectProperty.foo"); QCOMPARE(p.read(), QVariant()); } // Signal property { PropertyObject o; QDeclarativeProperty p(&o, "onClicked"); QCOMPARE(p.read(), QVariant()); QVERIFY(0 == QDeclarativePropertyPrivate::setSignalExpression(p, new QDeclarativeExpression())); QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p)); QCOMPARE(p.read(), QVariant()); } // Automatic signal property { PropertyObject o; QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged"); QCOMPARE(p.read(), QVariant()); QVERIFY(0 == QDeclarativePropertyPrivate::setSignalExpression(p, new QDeclarativeExpression())); QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p)); QCOMPARE(p.read(), QVariant()); } // Deleted object { PropertyObject *o = new PropertyObject; QDeclarativeProperty p(o, "rectProperty.x"); QCOMPARE(p.read(), QVariant(10)); delete o; QCOMPARE(p.read(), QVariant()); } // Object property { PropertyObject o; QDeclarativeProperty p(&o, "qmlObject"); QCOMPARE(p.propertyTypeCategory(), QDeclarativeProperty::Object); QCOMPARE(p.propertyType(), qMetaTypeId()); QVariant v = p.read(); QVERIFY(v.userType() == QMetaType::QObjectStar); QVERIFY(qvariant_cast(v) == o.qmlObject()); } { QDeclarativeComponent component(&engine, testFileUrl("readSynthesizedObject.qml")); QObject *object = component.create(); QVERIFY(object != 0); QDeclarativeProperty p(object, "test", &engine); QCOMPARE(p.propertyTypeCategory(), QDeclarativeProperty::Object); QVERIFY(p.propertyType() != QMetaType::QObjectStar); QVariant v = p.read(); QVERIFY(v.userType() == QMetaType::QObjectStar); QCOMPARE(qvariant_cast(v)->property("a").toInt(), 10); QCOMPARE(qvariant_cast(v)->property("b").toInt(), 19); } { // static QDeclarativeComponent component(&engine, testFileUrl("readSynthesizedObject.qml")); QObject *object = component.create(); QVERIFY(object != 0); QVariant v = QDeclarativeProperty::read(object, "test", &engine); QVERIFY(v.userType() == QMetaType::QObjectStar); QCOMPARE(qvariant_cast(v)->property("a").toInt(), 10); QCOMPARE(qvariant_cast(v)->property("b").toInt(), 19); } // Attached property { QDeclarativeComponent component(&engine); component.setData("import Test 1.0\nMyContainer { }", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QDeclarativeProperty p(object, "MyContainer.foo", qmlContext(object)); QCOMPARE(p.read(), QVariant(13)); delete object; } { QDeclarativeComponent component(&engine); component.setData("import Test 1.0\nMyContainer { MyContainer.foo: 10 }", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QDeclarativeProperty p(object, "MyContainer.foo", qmlContext(object)); QCOMPARE(p.read(), QVariant(10)); delete object; } { QDeclarativeComponent component(&engine); component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QDeclarativeProperty p(object, "Foo.MyContainer.foo", qmlContext(object)); QCOMPARE(p.read(), QVariant(10)); delete object; } { // static QDeclarativeComponent component(&engine); component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QCOMPARE(QDeclarativeProperty::read(object, "Foo.MyContainer.foo", qmlContext(object)), QVariant(10)); delete object; } } void tst_qdeclarativeproperty::write() { // Invalid { QDeclarativeProperty p; QCOMPARE(p.write(QVariant(10)), false); } // Read-only default prop { PropertyObject o; QDeclarativeProperty p(&o); QCOMPARE(p.write(QVariant(10)), false); } // Invalid default prop { QObject o; QDeclarativeProperty p(&o); QCOMPARE(p.write(QVariant(10)), false); } // Read-only prop by name { PropertyObject o; QDeclarativeProperty p(&o, QString("defaultProperty")); QCOMPARE(p.write(QVariant(10)), false); } // Writable prop by name { PropertyObject o; QDeclarativeProperty p(&o, QString("objectName")); QCOMPARE(o.objectName(), QString()); QCOMPARE(p.write(QVariant(QString("myName"))), true); QCOMPARE(o.objectName(), QString("myName")); } // Writable prop by name (static) { PropertyObject o; QCOMPARE(QDeclarativeProperty::write(&o, QString("objectName"), QVariant(QString("myName"))), true); QCOMPARE(o.objectName(), QString("myName")); } // Deleted object { PropertyObject *o = new PropertyObject; QDeclarativeProperty p(o, QString("objectName")); QCOMPARE(p.write(QVariant(QString("myName"))), true); QCOMPARE(o->objectName(), QString("myName")); delete o; QCOMPARE(p.write(QVariant(QString("myName"))), false); } // Signal property { PropertyObject o; QDeclarativeProperty p(&o, "onClicked"); QCOMPARE(p.write(QVariant("console.log(1921)")), false); QVERIFY(0 == QDeclarativePropertyPrivate::setSignalExpression(p, new QDeclarativeExpression())); QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p)); QCOMPARE(p.write(QVariant("console.log(1921)")), false); QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p)); } // Automatic signal property { PropertyObject o; QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged"); QCOMPARE(p.write(QVariant("console.log(1921)")), false); QVERIFY(0 == QDeclarativePropertyPrivate::setSignalExpression(p, new QDeclarativeExpression())); QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p)); QCOMPARE(p.write(QVariant("console.log(1921)")), false); QVERIFY(0 != QDeclarativePropertyPrivate::signalExpression(p)); } // Value-type property { PropertyObject o; QDeclarativeProperty p(&o, "wrectProperty"); QCOMPARE(o.wrectProperty(), QRect()); QCOMPARE(p.write(QRect(1, 13, 99, 8)), true); QCOMPARE(o.wrectProperty(), QRect(1, 13, 99, 8)); QDeclarativeProperty p2(&o, "wrectProperty.x"); QCOMPARE(p2.read(), QVariant(1)); QCOMPARE(p2.write(QVariant(6)), true); QCOMPARE(p2.read(), QVariant(6)); QCOMPARE(o.wrectProperty(), QRect(6, 13, 99, 8)); } // URL-property { PropertyObject o; QDeclarativeProperty p(&o, "url"); QCOMPARE(p.write(QUrl("main.qml")), true); QCOMPARE(o.url(), QUrl("main.qml")); QDeclarativeProperty p2(&o, "url", engine.rootContext()); QUrl result = engine.baseUrl().resolved(QUrl("main.qml")); QVERIFY(result != QUrl("main.qml")); QCOMPARE(p2.write(QUrl("main.qml")), true); QCOMPARE(o.url(), result); } { // static PropertyObject o; QCOMPARE(QDeclarativeProperty::write(&o, "url", QUrl("main.qml")), true); QCOMPARE(o.url(), QUrl("main.qml")); QUrl result = engine.baseUrl().resolved(QUrl("main.qml")); QVERIFY(result != QUrl("main.qml")); QCOMPARE(QDeclarativeProperty::write(&o, "url", QUrl("main.qml"), engine.rootContext()), true); QCOMPARE(o.url(), result); } // VariantMap-property QVariantMap vm; vm.insert("key", "value"); { PropertyObject o; QDeclarativeProperty p(&o, "variantMap"); QCOMPARE(p.write(vm), true); QCOMPARE(o.variantMap(), vm); QDeclarativeProperty p2(&o, "variantMap", engine.rootContext()); QCOMPARE(p2.write(vm), true); QCOMPARE(o.variantMap(), vm); } { // static PropertyObject o; QCOMPARE(QDeclarativeProperty::write(&o, "variantMap", vm), true); QCOMPARE(o.variantMap(), vm); QCOMPARE(QDeclarativeProperty::write(&o, "variantMap", vm, engine.rootContext()), true); QCOMPARE(o.variantMap(), vm); } // Attached property { QDeclarativeComponent component(&engine); component.setData("import Test 1.0\nMyContainer { }", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QDeclarativeProperty p(object, "MyContainer.foo", qmlContext(object)); p.write(QVariant(99)); QCOMPARE(p.read(), QVariant(99)); delete object; } { QDeclarativeComponent component(&engine); component.setData("import Test 1.0 as Foo\nFoo.MyContainer { Foo.MyContainer.foo: 10 }", QUrl()); QObject *object = component.create(); QVERIFY(object != 0); QDeclarativeProperty p(object, "Foo.MyContainer.foo", qmlContext(object)); p.write(QVariant(99)); QCOMPARE(p.read(), QVariant(99)); delete object; } } void tst_qdeclarativeproperty::reset() { // Invalid { QDeclarativeProperty p; QCOMPARE(p.isResettable(), false); QCOMPARE(p.reset(), false); } // Read-only default prop { PropertyObject o; QDeclarativeProperty p(&o); QCOMPARE(p.isResettable(), false); QCOMPARE(p.reset(), false); } // Invalid default prop { QObject o; QDeclarativeProperty p(&o); QCOMPARE(p.isResettable(), false); QCOMPARE(p.reset(), false); } // Non-resettable-only prop by name { PropertyObject o; QDeclarativeProperty p(&o, QString("defaultProperty")); QCOMPARE(p.isResettable(), false); QCOMPARE(p.reset(), false); } // Resettable prop by name { PropertyObject o; QDeclarativeProperty p(&o, QString("resettableProperty")); QCOMPARE(p.read(), QVariant(9)); QCOMPARE(p.write(QVariant(11)), true); QCOMPARE(p.read(), QVariant(11)); QCOMPARE(p.isResettable(), true); QCOMPARE(p.reset(), true); QCOMPARE(p.read(), QVariant(9)); } // Deleted object { PropertyObject *o = new PropertyObject; QDeclarativeProperty p(o, QString("resettableProperty")); QCOMPARE(p.isResettable(), true); QCOMPARE(p.reset(), true); delete o; QCOMPARE(p.isResettable(), false); QCOMPARE(p.reset(), false); } // Signal property { PropertyObject o; QDeclarativeProperty p(&o, "onClicked"); QCOMPARE(p.isResettable(), false); QCOMPARE(p.reset(), false); } // Automatic signal property { PropertyObject o; QDeclarativeProperty p(&o, "onPropertyWithNotifyChanged"); QCOMPARE(p.isResettable(), false); QCOMPARE(p.reset(), false); } } void tst_qdeclarativeproperty::writeObjectToList() { QDeclarativeComponent containerComponent(&engine); containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl()); MyContainer *container = qobject_cast(containerComponent.create()); QVERIFY(container != 0); QDeclarativeListReference list(container, "children"); QVERIFY(list.count() == 1); MyQmlObject *object = new MyQmlObject; QDeclarativeProperty prop(container, "children"); prop.write(qVariantFromValue(object)); QCOMPARE(list.count(), 1); QCOMPARE(list.at(0), qobject_cast(object)); } void tst_qdeclarativeproperty::writeListToList() { QDeclarativeComponent containerComponent(&engine); containerComponent.setData("import Test 1.0\nMyContainer { children: MyQmlObject {} }", QUrl()); MyContainer *container = qobject_cast(containerComponent.create()); QVERIFY(container != 0); QDeclarativeListReference list(container, "children"); QVERIFY(list.count() == 1); QList objList; objList << new MyQmlObject() << new MyQmlObject() << new MyQmlObject() << new MyQmlObject(); QDeclarativeProperty prop(container, "children"); prop.write(qVariantFromValue(objList)); QCOMPARE(list.count(), 4); //XXX need to try this with read/write prop (for read-only it correctly doesn't write) /*QList typedObjList; typedObjList << new MyQmlObject(); prop.write(qVariantFromValue(&typedObjList)); QCOMPARE(container->children()->size(), 1);*/ } void tst_qdeclarativeproperty::urlHandling_data() { QTest::addColumn("input"); QTest::addColumn("scheme"); QTest::addColumn("path"); QTest::addColumn("encoded"); QTest::newRow("unspecifiedFile") << QByteArray("main.qml") << QString("") << QString("main.qml") << QByteArray("main.qml"); QTest::newRow("specifiedFile") << QByteArray("file:///main.qml") << QString("file") << QString("/main.qml") << QByteArray("file:///main.qml"); QTest::newRow("httpFile") << QByteArray("http://www.example.com/main.qml") << QString("http") << QString("/main.qml") << QByteArray("http://www.example.com/main.qml"); QTest::newRow("pathFile") << QByteArray("http://www.example.com/resources/main.qml") << QString("http") << QString("/resources/main.qml") << QByteArray("http://www.example.com/resources/main.qml"); QTest::newRow("encodableName") << QByteArray("http://www.example.com/main file.qml") << QString("http") << QString("/main file.qml") << QByteArray("http://www.example.com/main%20file.qml"); QTest::newRow("preencodedName") << QByteArray("http://www.example.com/resources%7cmain%20file.qml") << QString("http") << QString("/resources|main file.qml") << QByteArray("http://www.example.com/resources%7cmain%20file.qml"); QTest::newRow("encodableQuery") << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now working?") << QString("http") << QString("/main.qml") << QByteArray("http://www.example.com/main.qml?type=text/qml&comment=now%20working?"); QTest::newRow("preencodedQuery") << QByteArray("http://www.example.com/main.qml?type=text%2fqml&comment=now working%3f") << QString("http") << QString("/main.qml") << QByteArray("http://www.example.com/main.qml?type=text%2fqml&comment=now%20working%3f"); QTest::newRow("encodableFragment") << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000|volume+50%") << QString("http") << QString("/main.qml") << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7Cvolume+50%25"); QTest::newRow("preencodedFragment") << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7cvolume%2b50%") << QString("http") << QString("/main.qml") << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%7cvolume%2b50%25"); } void tst_qdeclarativeproperty::urlHandling() { QFETCH(QByteArray, input); QFETCH(QString, scheme); QFETCH(QString, path); QFETCH(QByteArray, encoded); QString inputString(QString::fromUtf8(input)); { PropertyObject o; QDeclarativeProperty p(&o, "url"); // Test url written as QByteArray QCOMPARE(p.write(input), true); QUrl byteArrayResult(o.url()); QCOMPARE(byteArrayResult.scheme(), scheme); QCOMPARE(byteArrayResult.path(), path); QCOMPARE(byteArrayResult.toEncoded(), encoded); } { PropertyObject o; QDeclarativeProperty p(&o, "url"); // Test url written as QString QCOMPARE(p.write(inputString), true); QUrl stringResult(o.url()); QCOMPARE(stringResult.scheme(), scheme); QCOMPARE(stringResult.path(), path); QCOMPARE(stringResult.toEncoded(), encoded); } } void tst_qdeclarativeproperty::variantMapHandling_data() { QTest::addColumn("vm"); // Object literals { QVariantMap m; QTest::newRow("{}") << m; } { QVariantMap m; m["a"] = QVariantMap(); QTest::newRow("{ a:{} }") << m; } { QVariantMap m, m2; m2["b"] = 10; m2["c"] = 20; m["a"] = m2; QTest::newRow("{ a:{b:10, c:20} }") << m; } { QVariantMap m; m["a"] = 10; m["b"] = QVariantList() << 20 << 30; QTest::newRow("{ a:10, b:[20, 30]}") << m; } // Cyclic objects { QVariantMap m; m["p"] = QVariantMap(); QTest::newRow("var o={}; o.p=o") << m; } { QVariantMap m; m["p"] = 123; m["q"] = QVariantMap(); QTest::newRow("var o={}; o.p=123; o.q=o") << m; } } void tst_qdeclarativeproperty::variantMapHandling() { QFETCH(QVariantMap, vm); PropertyObject o; QDeclarativeProperty p(&o, "variantMap"); QCOMPARE(p.write(vm), true); QCOMPARE(o.variantMap(), vm); } void tst_qdeclarativeproperty::crashOnValueProperty() { QDeclarativeEngine *engine = new QDeclarativeEngine; QDeclarativeComponent component(engine); component.setData("import Test 1.0\nPropertyObject { wrectProperty.x: 10 }", QUrl()); PropertyObject *obj = qobject_cast(component.create()); QVERIFY(obj != 0); QDeclarativeProperty p(obj, "wrectProperty.x", qmlContext(obj)); QCOMPARE(p.name(), QString("wrectProperty.x")); QCOMPARE(p.read(), QVariant(10)); //don't crash once the engine is deleted delete engine; engine = 0; QCOMPARE(p.propertyTypeName(), "int"); QCOMPARE(p.read(), QVariant(10)); p.write(QVariant(20)); QCOMPARE(p.read(), QVariant(20)); } // QTBUG-13719 void tst_qdeclarativeproperty::aliasPropertyBindings() { QDeclarativeComponent component(&engine, testFileUrl("aliasPropertyBindings.qml")); QObject *object = component.create(); QVERIFY(object != 0); QCOMPARE(object->property("realProperty").toReal(), 90.); QCOMPARE(object->property("aliasProperty").toReal(), 90.); object->setProperty("test", 10); QCOMPARE(object->property("realProperty").toReal(), 110.); QCOMPARE(object->property("aliasProperty").toReal(), 110.); QDeclarativeProperty realProperty(object, QLatin1String("realProperty")); QDeclarativeProperty aliasProperty(object, QLatin1String("aliasProperty")); // Check there is a binding on these two properties QVERIFY(QDeclarativePropertyPrivate::binding(realProperty) != 0); QVERIFY(QDeclarativePropertyPrivate::binding(aliasProperty) != 0); // Check that its the same binding on these two properties QCOMPARE(QDeclarativePropertyPrivate::binding(realProperty), QDeclarativePropertyPrivate::binding(aliasProperty)); // Change the binding object->setProperty("state", QString("switch")); QVERIFY(QDeclarativePropertyPrivate::binding(realProperty) != 0); QVERIFY(QDeclarativePropertyPrivate::binding(aliasProperty) != 0); QCOMPARE(QDeclarativePropertyPrivate::binding(realProperty), QDeclarativePropertyPrivate::binding(aliasProperty)); QCOMPARE(object->property("realProperty").toReal(), 96.); QCOMPARE(object->property("aliasProperty").toReal(), 96.); // Check the old binding really has not effect any more object->setProperty("test", 4); QCOMPARE(object->property("realProperty").toReal(), 96.); QCOMPARE(object->property("aliasProperty").toReal(), 96.); object->setProperty("test2", 9); QCOMPARE(object->property("realProperty").toReal(), 288.); QCOMPARE(object->property("aliasProperty").toReal(), 288.); // Revert object->setProperty("state", QString("")); QVERIFY(QDeclarativePropertyPrivate::binding(realProperty) != 0); QVERIFY(QDeclarativePropertyPrivate::binding(aliasProperty) != 0); QCOMPARE(QDeclarativePropertyPrivate::binding(realProperty), QDeclarativePropertyPrivate::binding(aliasProperty)); QCOMPARE(object->property("realProperty").toReal(), 20.); QCOMPARE(object->property("aliasProperty").toReal(), 20.); object->setProperty("test2", 3); QCOMPARE(object->property("realProperty").toReal(), 20.); QCOMPARE(object->property("aliasProperty").toReal(), 20.); delete object; } void tst_qdeclarativeproperty::copy() { PropertyObject object; QDeclarativeProperty *property = new QDeclarativeProperty(&object, QLatin1String("defaultProperty")); QCOMPARE(property->name(), QString("defaultProperty")); QCOMPARE(property->read(), QVariant(10)); QCOMPARE(property->type(), QDeclarativeProperty::Property); QCOMPARE(property->propertyTypeCategory(), QDeclarativeProperty::Normal); QCOMPARE(property->propertyType(), (int)QVariant::Int); QDeclarativeProperty p1(*property); QCOMPARE(p1.name(), QString("defaultProperty")); QCOMPARE(p1.read(), QVariant(10)); QCOMPARE(p1.type(), QDeclarativeProperty::Property); QCOMPARE(p1.propertyTypeCategory(), QDeclarativeProperty::Normal); QCOMPARE(p1.propertyType(), (int)QVariant::Int); QDeclarativeProperty p2(&object, QLatin1String("url")); QCOMPARE(p2.name(), QString("url")); p2 = *property; QCOMPARE(p2.name(), QString("defaultProperty")); QCOMPARE(p2.read(), QVariant(10)); QCOMPARE(p2.type(), QDeclarativeProperty::Property); QCOMPARE(p2.propertyTypeCategory(), QDeclarativeProperty::Normal); QCOMPARE(p2.propertyType(), (int)QVariant::Int); delete property; property = 0; QCOMPARE(p1.name(), QString("defaultProperty")); QCOMPARE(p1.read(), QVariant(10)); QCOMPARE(p1.type(), QDeclarativeProperty::Property); QCOMPARE(p1.propertyTypeCategory(), QDeclarativeProperty::Normal); QCOMPARE(p1.propertyType(), (int)QVariant::Int); QCOMPARE(p2.name(), QString("defaultProperty")); QCOMPARE(p2.read(), QVariant(10)); QCOMPARE(p2.type(), QDeclarativeProperty::Property); QCOMPARE(p2.propertyTypeCategory(), QDeclarativeProperty::Normal); QCOMPARE(p2.propertyType(), (int)QVariant::Int); } void tst_qdeclarativeproperty::noContext() { QDeclarativeComponent compA(&engine, testFileUrl("NoContextTypeA.qml")); QDeclarativeComponent compB(&engine, testFileUrl("NoContextTypeB.qml")); QObject *a = compA.create(); QVERIFY(a != 0); QObject *b = compB.create(); QVERIFY(b != 0); QVERIFY(QDeclarativeProperty::write(b, "myTypeA", QVariant::fromValue(a), &engine)); delete a; delete b; } void tst_qdeclarativeproperty::assignEmptyVariantMap() { PropertyObject o; QVariantMap map; map.insert("key", "value"); o.setVariantMap(map); QCOMPARE(o.variantMap().count(), 1); QCOMPARE(o.variantMap().isEmpty(), false); QDeclarativeContext context(&engine); context.setContextProperty("o", &o); QDeclarativeComponent component(&engine, testFileUrl("assignEmptyVariantMap.qml")); QObject *obj = component.create(&context); QVERIFY(obj); QCOMPARE(o.variantMap().count(), 0); QCOMPARE(o.variantMap().isEmpty(), true); delete obj; } void tst_qdeclarativeproperty::initTestCase() { QDeclarativeDataTest::initTestCase(); qmlRegisterType("Test",1,0,"MyQmlObject"); qmlRegisterType("Test",1,0,"PropertyObject"); qmlRegisterType("Test",1,0,"MyContainer"); } QTEST_MAIN(tst_qdeclarativeproperty) #include "tst_qdeclarativeproperty.moc"