Improve composite property type unit test
[profile/ivi/qtdeclarative.git] / tests / auto / qml / qqmlproperty / tst_qqmlproperty.cpp
index 13ea1ab..12a8325 100644 (file)
@@ -45,6 +45,7 @@
 #include <QtQml/qqmlproperty.h>
 #include <QtQml/private/qqmlproperty_p.h>
 #include <private/qqmlbinding_p.h>
+#include <private/qqmlboundsignal_p.h>
 #include <QtWidgets/QLineEdit>
 #include <QtCore/qfileinfo.h>
 #include <QtCore/qdir.h>
@@ -133,6 +134,8 @@ private slots:
     void aliasPropertyBindings();
     void noContext();
     void assignEmptyVariantMap();
+    void warnOnInvalidBinding();
+    void registeredCompositeTypeProperty();
 
     void copy();
 private:
@@ -143,10 +146,11 @@ void tst_qqmlproperty::qmlmetaproperty()
 {
     QQmlProperty prop;
 
-    QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+    QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
     QVERIFY(binding != 0);
-    QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-    QVERIFY(expression != 0);
+    QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+    QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+    QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
     QObject *obj = new QObject;
 
@@ -161,7 +165,7 @@ void tst_qqmlproperty::qmlmetaproperty()
     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);
+    QVERIFY(!prop.method().isValid());
     QCOMPARE(prop.type(), QQmlProperty::Invalid);
     QCOMPARE(prop.isProperty(), false);
     QCOMPARE(prop.isWritable(), false);
@@ -178,14 +182,128 @@ void tst_qqmlproperty::qmlmetaproperty()
     QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
     QVERIFY(binding == 0);
     QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-    QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-    QVERIFY(expression == 0);
+    QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+    QVERIFY(sigExprWatcher.wasDeleted());
     QCOMPARE(prop.index(), -1);
     QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
     delete obj;
 }
 
+// 1 = equal, 0 = unknown, -1 = not equal.
+static int compareVariantAndListReference(const QVariant &v, QQmlListReference &r)
+{
+    if (QLatin1String(v.typeName()) != QLatin1String("QQmlListReference"))
+        return -1;
+
+    QQmlListReference lhs = v.value<QQmlListReference>();
+    if (lhs.isValid() != r.isValid())
+        return -1;
+
+    if (lhs.canCount() != r.canCount())
+        return -1;
+
+    if (!lhs.canCount()) {
+        if (lhs.canAt() != r.canAt())
+            return -1; // not equal.
+        return 0; // not sure if they're equal or not, and no way to tell.
+    }
+
+    // if we get here, we must be able to count.
+    if (lhs.count() != r.count())
+        return -1;
+
+    if (lhs.canAt() != r.canAt())
+        return -1;
+
+    if (!lhs.canAt())
+        return 0; // can count, but can't check element equality.
+
+    for (int i = 0; i < lhs.count(); ++i) {
+        if (lhs.at(i) != r.at(i)) {
+            return -1; // different elements :. not equal.
+        }
+    }
+
+    return 1; // equal.
+}
+
+void tst_qqmlproperty::registeredCompositeTypeProperty()
+{
+    // Composite type properties
+    {
+        QQmlEngine engine;
+        QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeProperty.qml"));
+        QObject *obj = component.create();
+        QVERIFY(obj);
+
+        // create property accessors and check types.
+        QQmlProperty p1(obj, "first");
+        QQmlProperty p2(obj, "second");
+        QQmlProperty p3(obj, "third");
+        QQmlProperty p1e(obj, "first", &engine);
+        QQmlProperty p2e(obj, "second", &engine);
+        QQmlProperty p3e(obj, "third", &engine);
+        QVERIFY(p1.propertyType() == p2.propertyType());
+        QVERIFY(p1.propertyType() != p3.propertyType());
+
+        // check that the values are retrievable from CPP
+        QVariant first = obj->property("first");
+        QVariant second = obj->property("second");
+        QVariant third = obj->property("third");
+        QVERIFY(first.isValid());
+        QVERIFY(second.isValid());
+        QVERIFY(third.isValid());
+        // ensure that conversion from qobject-derived-ptr to qobject-ptr works.
+        QVERIFY(first.value<QObject*>());
+        QVERIFY(second.value<QObject*>());
+        QVERIFY(third.value<QObject*>());
+
+        // check that the values retrieved via QQmlProperty match those retrieved via QMetaProperty::read().
+        QCOMPARE(p1.read().value<QObject*>(), first.value<QObject*>());
+        QCOMPARE(p2.read().value<QObject*>(), second.value<QObject*>());
+        QCOMPARE(p3.read().value<QObject*>(), third.value<QObject*>());
+        QCOMPARE(p1e.read().value<QObject*>(), first.value<QObject*>());
+        QCOMPARE(p2e.read().value<QObject*>(), second.value<QObject*>());
+        QCOMPARE(p3e.read().value<QObject*>(), third.value<QObject*>());
+
+        delete obj;
+    }
+
+    // List-of-composite-type type properties
+    {
+        QQmlEngine engine;
+        QQmlComponent component(&engine, testFileUrl("registeredCompositeTypeProperty.qml"));
+        QObject *obj = component.create();
+        QVERIFY(obj);
+
+        // create list property accessors and check types
+        QQmlProperty lp1e(obj, "fclist", &engine);
+        QQmlProperty lp2e(obj, "sclistOne", &engine);
+        QQmlProperty lp3e(obj, "sclistTwo", &engine);
+        QVERIFY(lp1e.propertyType() != lp2e.propertyType());
+        QVERIFY(lp2e.propertyType() == lp3e.propertyType());
+
+        // check that the list values are retrievable from CPP
+        QVariant firstList = obj->property("fclist");
+        QVariant secondList = obj->property("sclistOne");
+        QVariant thirdList = obj->property("sclistTwo");
+        QVERIFY(firstList.isValid());
+        QVERIFY(secondList.isValid());
+        QVERIFY(thirdList.isValid());
+
+        // check that the value returned by QQmlProperty::read() is equivalent to the list reference.
+        QQmlListReference r1(obj, "fclist", &engine);
+        QQmlListReference r2(obj, "sclistOne", &engine);
+        QQmlListReference r3(obj, "sclistTwo", &engine);
+        QCOMPARE(compareVariantAndListReference(lp1e.read(), r1), 1);
+        QCOMPARE(compareVariantAndListReference(lp2e.read(), r2), 1);
+        QCOMPARE(compareVariantAndListReference(lp3e.read(), r3), 1);
+
+        delete obj;
+    }
+}
+
 class PropertyObject : public QObject
 {
     Q_OBJECT
@@ -246,10 +364,11 @@ void tst_qqmlproperty::qmlmetaproperty_object()
     {
         QQmlProperty prop(&object);
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -264,7 +383,7 @@ void tst_qqmlproperty::qmlmetaproperty_object()
         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);
+        QVERIFY(!prop.method().isValid());
         QCOMPARE(prop.type(), QQmlProperty::Invalid);
         QCOMPARE(prop.isProperty(), false);
         QCOMPARE(prop.isWritable(), false);
@@ -281,8 +400,8 @@ void tst_qqmlproperty::qmlmetaproperty_object()
         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
         QVERIFY(binding == 0);
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression == 0);
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(sigExprWatcher.wasDeleted());
         QCOMPARE(prop.index(), -1);
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -292,11 +411,12 @@ void tst_qqmlproperty::qmlmetaproperty_object()
     {
         QQmlProperty prop(&dobject);
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
-        binding.data()->setTarget(prop);
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
+        static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -311,7 +431,7 @@ void tst_qqmlproperty::qmlmetaproperty_object()
         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);
+        QVERIFY(!prop.method().isValid());
         QCOMPARE(prop.type(), QQmlProperty::Property);
         QCOMPARE(prop.isProperty(), true);
         QCOMPARE(prop.isWritable(), false);
@@ -330,8 +450,8 @@ void tst_qqmlproperty::qmlmetaproperty_object()
         QVERIFY(binding != 0);
         QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data());
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression == 0);
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(sigExprWatcher.wasDeleted());
         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -347,10 +467,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
     {
         QQmlProperty prop(&object, QString("defaultProperty"));
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -365,7 +486,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
         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);
+        QVERIFY(!prop.method().isValid());
         QCOMPARE(prop.type(), QQmlProperty::Invalid);
         QCOMPARE(prop.isProperty(), false);
         QCOMPARE(prop.isWritable(), false);
@@ -382,8 +503,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
         QVERIFY(binding == 0);
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression == 0);
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(sigExprWatcher.wasDeleted());
         QCOMPARE(prop.index(), -1);
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -393,11 +514,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
     {
         QQmlProperty prop(&dobject, QString("defaultProperty"));
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
-        binding.data()->setTarget(prop);
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
+        static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -412,7 +534,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
         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);
+        QVERIFY(!prop.method().isValid());
         QCOMPARE(prop.type(), QQmlProperty::Property);
         QCOMPARE(prop.isProperty(), true);
         QCOMPARE(prop.isWritable(), false);
@@ -431,8 +553,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
         QVERIFY(binding != 0);
         QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data());
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression == 0);
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(sigExprWatcher.wasDeleted());
         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -442,11 +564,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
     {
         QQmlProperty prop(&dobject, QString("onClicked"));
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
-        binding.data()->setTarget(prop);
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
+        static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -461,7 +584,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
         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(QString(prop.method().methodSignature()), QString("clicked()"));
         QCOMPARE(prop.type(), QQmlProperty::SignalProperty);
         QCOMPARE(prop.isProperty(), false);
         QCOMPARE(prop.isWritable(), false);
@@ -478,9 +601,9 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
         QVERIFY(binding == 0);
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression != 0);
-        QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == expression.data());
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(!sigExprWatcher.wasDeleted());
+        QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr);
         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()"));
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -490,11 +613,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
     {
         QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"));
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
-        binding.data()->setTarget(prop);
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
+        static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -509,7 +633,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
         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(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()"));
         QCOMPARE(prop.type(), QQmlProperty::SignalProperty);
         QCOMPARE(prop.isProperty(), false);
         QCOMPARE(prop.isWritable(), false);
@@ -526,9 +650,9 @@ void tst_qqmlproperty::qmlmetaproperty_object_string()
         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
         QVERIFY(binding == 0);
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression != 0);
-        QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == expression.data());
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(!sigExprWatcher.wasDeleted());
+        QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr);
         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()"));
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -544,10 +668,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
     {
         QQmlProperty prop(&object, engine.rootContext());
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -562,7 +687,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
         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);
+        QVERIFY(!prop.method().isValid());
         QCOMPARE(prop.type(), QQmlProperty::Invalid);
         QCOMPARE(prop.isProperty(), false);
         QCOMPARE(prop.isWritable(), false);
@@ -579,8 +704,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
         QVERIFY(binding == 0);
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression == 0);
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(sigExprWatcher.wasDeleted());
         QCOMPARE(prop.index(), -1);
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -590,11 +715,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
     {
         QQmlProperty prop(&dobject, engine.rootContext());
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
-        binding.data()->setTarget(prop);
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
+        static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -609,7 +735,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
         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);
+        QVERIFY(!prop.method().isValid());
         QCOMPARE(prop.type(), QQmlProperty::Property);
         QCOMPARE(prop.isProperty(), true);
         QCOMPARE(prop.isWritable(), false);
@@ -628,8 +754,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_context()
         QVERIFY(binding != 0);
         QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data());
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression == 0);
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(sigExprWatcher.wasDeleted());
         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -645,10 +771,11 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
     {
         QQmlProperty prop(&object, QString("defaultProperty"), engine.rootContext());
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -663,7 +790,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
         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);
+        QVERIFY(!prop.method().isValid());
         QCOMPARE(prop.type(), QQmlProperty::Invalid);
         QCOMPARE(prop.isProperty(), false);
         QCOMPARE(prop.isWritable(), false);
@@ -680,8 +807,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
         QVERIFY(binding == 0);
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression == 0);
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(sigExprWatcher.wasDeleted());
         QCOMPARE(prop.index(), -1);
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -691,11 +818,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
     {
         QQmlProperty prop(&dobject, QString("defaultProperty"), engine.rootContext());
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
-        binding.data()->setTarget(prop);
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
+        static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -710,7 +838,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
         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);
+        QVERIFY(!prop.method().isValid());
         QCOMPARE(prop.type(), QQmlProperty::Property);
         QCOMPARE(prop.isProperty(), true);
         QCOMPARE(prop.isWritable(), false);
@@ -729,8 +857,8 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
         QVERIFY(binding != 0);
         QVERIFY(QQmlPropertyPrivate::binding(prop) == binding.data());
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression == 0);
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(sigExprWatcher.wasDeleted());
         QCOMPARE(prop.index(), dobject.metaObject()->indexOfProperty("defaultProperty"));
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -740,11 +868,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
     {
         QQmlProperty prop(&dobject, QString("onClicked"), engine.rootContext());
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
-        binding.data()->setTarget(prop);
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
+        static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -759,7 +888,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
         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(QString(prop.method().methodSignature()), QString("clicked()"));
         QCOMPARE(prop.type(), QQmlProperty::SignalProperty);
         QCOMPARE(prop.isProperty(), false);
         QCOMPARE(prop.isWritable(), false);
@@ -776,9 +905,9 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
         QVERIFY(binding == 0);
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression != 0);
-        QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == expression.data());
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(!sigExprWatcher.wasDeleted());
+        QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr);
         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("clicked()"));
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -788,11 +917,12 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
     {
         QQmlProperty prop(&dobject, QString("onPropertyWithNotifyChanged"), engine.rootContext());
 
-        QWeakPointer<QQmlBinding> binding(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext()));
-        binding.data()->setTarget(prop);
+        QWeakPointer<QQmlAbstractBinding> binding(QQmlAbstractBinding::getPointer(new QQmlBinding(QLatin1String("null"), 0, engine.rootContext())));
+        static_cast<QQmlBinding *>(binding.data())->setTarget(prop);
         QVERIFY(binding != 0);
-        QWeakPointer<QQmlExpression> expression(new QQmlExpression());
-        QVERIFY(expression != 0);
+        QQmlBoundSignalExpression *sigExpr = new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1);
+        QQmlAbstractExpression::DeleteWatcher sigExprWatcher(sigExpr);
+        QVERIFY(sigExpr != 0 && !sigExprWatcher.wasDeleted());
 
         QObject *obj = new QObject;
 
@@ -807,7 +937,7 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
         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(QString(prop.method().methodSignature()), QString("oddlyNamedNotifySignal()"));
         QCOMPARE(prop.type(), QQmlProperty::SignalProperty);
         QCOMPARE(prop.isProperty(), false);
         QCOMPARE(prop.isWritable(), false);
@@ -824,9 +954,9 @@ void tst_qqmlproperty::qmlmetaproperty_object_string_context()
         QVERIFY(QQmlPropertyPrivate::setBinding(prop, binding.data()) == 0);
         QVERIFY(binding == 0);
         QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == 0);
-        QVERIFY(QQmlPropertyPrivate::setSignalExpression(prop, expression.data()) == 0);
-        QVERIFY(expression != 0);
-        QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == expression.data());
+        QVERIFY(QQmlPropertyPrivate::takeSignalExpression(prop, sigExpr) == 0);
+        QVERIFY(!sigExprWatcher.wasDeleted());
+        QVERIFY(QQmlPropertyPrivate::signalExpression(prop) == sigExpr);
         QCOMPARE(prop.index(), dobject.metaObject()->indexOfMethod("oddlyNamedNotifySignal()"));
         QCOMPARE(QQmlPropertyPrivate::valueTypeCoreIndex(prop), -1);
 
@@ -972,7 +1102,7 @@ void tst_qqmlproperty::read()
         QQmlProperty p(&o, "onClicked");
         QCOMPARE(p.read(), QVariant());
 
-        QVERIFY(0 == QQmlPropertyPrivate::setSignalExpression(p, new QQmlExpression()));
+        QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1)));
         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
 
         QCOMPARE(p.read(), QVariant());
@@ -984,7 +1114,7 @@ void tst_qqmlproperty::read()
         QQmlProperty p(&o, "onPropertyWithNotifyChanged");
         QCOMPARE(p.read(), QVariant());
 
-        QVERIFY(0 == QQmlPropertyPrivate::setSignalExpression(p, new QQmlExpression()));
+        QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1)));
         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
 
         QCOMPARE(p.read(), QVariant());
@@ -1140,7 +1270,7 @@ void tst_qqmlproperty::write()
         QQmlProperty p(&o, "onClicked");
         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
 
-        QVERIFY(0 == QQmlPropertyPrivate::setSignalExpression(p, new QQmlExpression()));
+        QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1)));
         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
 
         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
@@ -1154,7 +1284,7 @@ void tst_qqmlproperty::write()
         QQmlProperty p(&o, "onPropertyWithNotifyChanged");
         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
 
-        QVERIFY(0 == QQmlPropertyPrivate::setSignalExpression(p, new QQmlExpression()));
+        QVERIFY(0 == QQmlPropertyPrivate::takeSignalExpression(p, new QQmlBoundSignalExpression(QQmlContextData::get(engine.rootContext()), 0, QLatin1String("null"), false, QString(), -1, -1)));
         QVERIFY(0 != QQmlPropertyPrivate::signalExpression(p));
 
         QCOMPARE(p.write(QVariant("console.log(1921)")), false);
@@ -1416,10 +1546,10 @@ void tst_qqmlproperty::urlHandling_data()
         << QByteArray("http://www.example.com/main%20file.qml");
 
     QTest::newRow("preencodedName")
-        << QByteArray("http://www.example.com/resources%7cmain%20file.qml")
+        << 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");
+        << 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?")
@@ -1428,10 +1558,10 @@ void tst_qqmlproperty::urlHandling_data()
         << 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")
+        << 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");
+        << 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%")
@@ -1439,11 +1569,11 @@ void tst_qqmlproperty::urlHandling_data()
         << 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%")
+    QTest::newRow("improperlyEncodedFragment")
+        << 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");
+        << QByteArray("http://www.example.com/main.qml?type=text/qml#start+30000%257Cvolume%252B50%25");
 }
 
 void tst_qqmlproperty::urlHandling()
@@ -1465,6 +1595,7 @@ void tst_qqmlproperty::urlHandling()
 
         QCOMPARE(byteArrayResult.scheme(), scheme);
         QCOMPARE(byteArrayResult.path(), path);
+        QCOMPARE(byteArrayResult.toString(QUrl::FullyEncoded), QString::fromUtf8(encoded));
         QCOMPARE(byteArrayResult.toEncoded(), encoded);
     }
 
@@ -1478,6 +1609,7 @@ void tst_qqmlproperty::urlHandling()
 
         QCOMPARE(stringResult.scheme(), scheme);
         QCOMPARE(stringResult.path(), path);
+        QCOMPARE(stringResult.toString(QUrl::FullyEncoded), QString::fromUtf8(encoded));
         QCOMPARE(stringResult.toEncoded(), encoded);
     }
 }
@@ -1553,8 +1685,6 @@ void tst_qqmlproperty::crashOnValueProperty()
     delete engine;
     engine = 0;
 
-    QSKIP("QTBUG-24734: test accesses deleted QML engine from QQmlProperty::propertyTypeName()");
-
     QCOMPARE(p.propertyTypeName(), "int");
     QCOMPARE(p.read(), QVariant(10));
     p.write(QVariant(20));
@@ -1710,6 +1840,29 @@ void tst_qqmlproperty::assignEmptyVariantMap()
     delete obj;
 }
 
+void tst_qqmlproperty::warnOnInvalidBinding()
+{
+    QUrl testUrl(testFileUrl("invalidBinding.qml"));
+    QString expectedWarning;
+
+    // V4 error message for property-to-property binding
+    expectedWarning = testUrl.toString() + QString::fromLatin1(":6:36: Unable to assign QQuickText to QQuickRectangle");
+    QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
+
+    // V8 error message for function-to-property binding
+    expectedWarning = testUrl.toString() + QString::fromLatin1(":7:36: Unable to assign QQuickText to QQuickRectangle");
+    QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
+
+    // V8 error message for invalid binding to anchor
+    expectedWarning = testUrl.toString() + QString::fromLatin1(":14: Unable to assign QQuickItem_QML_7 to QQuickAnchorLine");
+    QTest::ignoreMessage(QtWarningMsg, expectedWarning.toLatin1().constData());
+
+    QQmlComponent component(&engine, testUrl);
+    QObject *obj = component.create();
+    QVERIFY(obj);
+    delete obj;
+}
+
 void tst_qqmlproperty::initTestCase()
 {
     QQmlDataTest::initTestCase();