Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativecontext / tst_qdeclarativecontext.cpp
index 97cd0c9..edb025e 100644 (file)
@@ -1,8 +1,7 @@
 /****************************************************************************
 **
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
 **
 ** This file is part of the test suite of the Qt Toolkit.
 **
@@ -35,6 +34,7 @@
 **
 **
 **
+**
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
 #include <QDeclarativeContext>
 #include <QDeclarativeComponent>
 #include <QDeclarativeExpression>
+#include <private/qdeclarativecontext_p.h>
+#include "../../shared/util.h"
 
-#ifdef Q_OS_SYMBIAN
-// In Symbian OS test data is located in applications private dir
-#define SRCDIR "."
-#endif
-
-class tst_qdeclarativecontext : public QObject
+class tst_qdeclarativecontext : public QDeclarativeDataTest
 {
     Q_OBJECT
 public:
@@ -67,7 +64,13 @@ private slots:
     void destruction();
     void idAsContextProperty();
     void readOnlyContexts();
+    void nameForObject();
+
+    void refreshExpressions();
+    void refreshExpressionsCrash();
+    void refreshExpressionsRootContext();
 
+    void qtbug_22535();
 private:
     QDeclarativeEngine engine;
 };
@@ -342,7 +345,7 @@ void tst_qdeclarativecontext::setContextProperty()
         QDeclarativeContext ctxt(engine.rootContext());
         ctxt.setContextProperty("ctxtProp", QVariant());
 
-        QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1: TypeError: Result of expression 'ctxtProp' [undefined] is not an object.");
+        QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1: TypeError: Cannot read property 'a' of undefined");
         QObject *obj = component.create(&ctxt);
 
         QVariant v = obj->property("obj");
@@ -463,6 +466,187 @@ void tst_qdeclarativecontext::readOnlyContexts()
     delete obj;
 }
 
+void tst_qdeclarativecontext::nameForObject()
+{
+    QObject o1;
+    QObject o2;
+    QObject o3;
+
+    QDeclarativeEngine engine;
+
+    // As a context property
+    engine.rootContext()->setContextProperty("o1", &o1);
+    engine.rootContext()->setContextProperty("o2", &o2);
+    engine.rootContext()->setContextProperty("o1_2", &o1);
+
+    QCOMPARE(engine.rootContext()->nameForObject(&o1), QString("o1"));
+    QCOMPARE(engine.rootContext()->nameForObject(&o2), QString("o2"));
+    QCOMPARE(engine.rootContext()->nameForObject(&o3), QString());
+
+    // As an id
+    QDeclarativeComponent component(&engine);
+    component.setData("import QtQuick 1.0; QtObject { id: root; property QtObject o: QtObject { id: nested } }", QUrl());
+
+    QObject *o = component.create();
+    QVERIFY(o != 0);
+
+    QCOMPARE(qmlContext(o)->nameForObject(o), QString("root"));
+    QCOMPARE(qmlContext(o)->nameForObject(qvariant_cast<QObject*>(o->property("o"))), QString("nested"));
+    QCOMPARE(qmlContext(o)->nameForObject(&o1), QString());
+
+    delete o;
+}
+
+class DeleteCommand : public QObject
+{
+Q_OBJECT
+public:
+    DeleteCommand() : object(0) {}
+
+    QObject *object;
+
+public slots:
+    void doCommand() { if (object) delete object; object = 0; }
+};
+
+// Calling refresh expressions would crash if an expression or context was deleted during
+// the refreshing
+void tst_qdeclarativecontext::refreshExpressionsCrash()
+{
+    {
+    QDeclarativeEngine engine;
+
+    DeleteCommand command;
+    engine.rootContext()->setContextProperty("deleteCommand", &command);
+    // We use a fresh context here to bypass any root-context optimizations in
+    // the engine
+    QDeclarativeContext ctxt(engine.rootContext());
+
+    QDeclarativeComponent component(&engine);
+    component.setData("import QtQuick 2.0; QtObject { property var binding: deleteCommand.doCommand() }", QUrl());
+    QVERIFY(component.isReady());
+
+    QObject *o1 = component.create(&ctxt);
+    QObject *o2 = component.create(&ctxt);
+
+    command.object = o2;
+
+    QDeclarativeContextData::get(&ctxt)->refreshExpressions();
+
+    delete o1;
+    }
+    {
+    QDeclarativeEngine engine;
+
+    DeleteCommand command;
+    engine.rootContext()->setContextProperty("deleteCommand", &command);
+    // We use a fresh context here to bypass any root-context optimizations in
+    // the engine
+    QDeclarativeContext ctxt(engine.rootContext());
+
+    QDeclarativeComponent component(&engine);
+    component.setData("import QtQuick 2.0; QtObject { property var binding: deleteCommand.doCommand() }", QUrl());
+    QVERIFY(component.isReady());
+
+    QObject *o1 = component.create(&ctxt);
+    QObject *o2 = component.create(&ctxt);
+
+    command.object = o1;
+
+    QDeclarativeContextData::get(&ctxt)->refreshExpressions();
+
+    delete o2;
+    }
+}
+
+class CountCommand : public QObject
+{
+Q_OBJECT
+public:
+    CountCommand() : count(0) {}
+
+    int count;
+
+public slots:
+    void doCommand() { ++count; }
+};
+
+
+// Test that calling refresh expressions causes all the expressions to refresh
+void tst_qdeclarativecontext::refreshExpressions()
+{
+    QDeclarativeEngine engine;
+    QDeclarativeComponent component(&engine, testFileUrl("refreshExpressions.qml"));
+    QDeclarativeComponent component2(&engine, testFileUrl("RefreshExpressionsType.qml"));
+
+    CountCommand command;
+    engine.rootContext()->setContextProperty("countCommand", &command);
+
+    // We use a fresh context here to bypass any root-context optimizations in
+    // the engine
+    QDeclarativeContext context(engine.rootContext());
+    QDeclarativeContext context2(&context);
+
+    QObject *o1 = component.create(&context);
+    QObject *o2 = component.create(&context2);
+    QObject *o3 = component2.create(&context);
+
+    QCOMPARE(command.count, 5);
+
+    QDeclarativeContextData::get(&context)->refreshExpressions();
+
+    QCOMPARE(command.count, 10);
+
+    delete o3;
+    delete o2;
+    delete o1;
+}
+
+// Test that updating the root context, only causes expressions in contexts with an
+// unresolved name to reevaluate
+void tst_qdeclarativecontext::refreshExpressionsRootContext()
+{
+    QDeclarativeEngine engine;
+
+    CountCommand command;
+    engine.rootContext()->setContextProperty("countCommand", &command);
+
+    QDeclarativeComponent component(&engine, testFileUrl("refreshExpressions.qml"));
+    QDeclarativeComponent component2(&engine, testFileUrl("refreshExpressionsRootContext.qml"));
+
+    QDeclarativeContext context(engine.rootContext());
+    QDeclarativeContext context2(engine.rootContext());
+
+    QString warning = component2.url().toString() + QLatin1String(":4: ReferenceError: Can't find variable: unresolvedName");
+
+    QObject *o1 = component.create(&context);
+
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+    QObject *o2 = component2.create(&context2);
+
+    QCOMPARE(command.count, 3);
+
+    QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+    QDeclarativeContextData::get(engine.rootContext())->refreshExpressions();
+
+    QCOMPARE(command.count, 4);
+
+    delete o2;
+    delete o1;
+}
+
+void tst_qdeclarativecontext::qtbug_22535()
+{
+    QDeclarativeEngine engine;
+    QDeclarativeComponent component(&engine, testFileUrl("qtbug_22535.qml"));
+    QDeclarativeContext context(engine.rootContext());
+
+    QObject *o = component.create(&context);
+
+    // Don't crash!
+    delete o;
+}
+
 QTEST_MAIN(tst_qdeclarativecontext)
 
 #include "tst_qdeclarativecontext.moc"