From b855240b782395f94315f43ea3e7e182299fac48 Mon Sep 17 00:00:00 2001 From: Matthew Vogt Date: Thu, 16 Feb 2012 14:43:03 +1000 Subject: Rename QDeclarative symbols to QQuick and QQml Symbols beginning with QDeclarative are already exported by the quick1 module. Users can apply the bin/rename-qtdeclarative-symbols.sh script to modify client code using the previous names of the renamed symbols. Task-number: QTBUG-23737 Change-Id: Ifaa482663767634931e8711a8e9bf6e404859e66 Reviewed-by: Martin Jones --- .../data/AsynchronousIfNestedType.qml | 7 + .../qqmlincubator/data/asynchronousIfNested.1.qml | 5 + .../qqmlincubator/data/asynchronousIfNested.2.qml | 6 + .../qqmlincubator/data/asynchronousIfNested.3.qml | 5 + .../qml/qqmlincubator/data/chainInCompletion.qml | 5 + .../data/chainedAsynchronousIfNested.qml | 5 + tests/auto/qml/qqmlincubator/data/clear.qml | 8 + .../qqmlincubator/data/clearDuringCompletion.qml | 6 + .../auto/qml/qqmlincubator/data/contextDelete.qml | 5 + .../qml/qqmlincubator/data/forceCompletion.qml | 9 + .../auto/qml/qqmlincubator/data/nestedComponent.js | 1 + .../qml/qqmlincubator/data/nestedComponent.qml | 10 + .../qqmlincubator/data/noIncubationController.qml | 5 + .../qqmlincubator/data/objectDeleted.errors.txt | 1 + .../auto/qml/qqmlincubator/data/objectDeleted.qml | 8 + .../qml/qqmlincubator/data/recursiveClear.1.qml | 9 + .../qml/qqmlincubator/data/recursiveClear.2.qml | 8 + tests/auto/qml/qqmlincubator/data/selfDelete.qml | 5 + .../qml/qqmlincubator/data/setInitialState.qml | 17 + .../qqmlincubator/data/statusChanged.nested.qml | 12 + .../auto/qml/qqmlincubator/data/statusChanged.qml | 5 + tests/auto/qml/qqmlincubator/qqmlincubator.pro | 18 + tests/auto/qml/qqmlincubator/testtypes.cpp | 137 +++ tests/auto/qml/qqmlincubator/testtypes.h | 125 +++ tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp | 1030 ++++++++++++++++++++ 25 files changed, 1452 insertions(+) create mode 100644 tests/auto/qml/qqmlincubator/data/AsynchronousIfNestedType.qml create mode 100644 tests/auto/qml/qqmlincubator/data/asynchronousIfNested.1.qml create mode 100644 tests/auto/qml/qqmlincubator/data/asynchronousIfNested.2.qml create mode 100644 tests/auto/qml/qqmlincubator/data/asynchronousIfNested.3.qml create mode 100644 tests/auto/qml/qqmlincubator/data/chainInCompletion.qml create mode 100644 tests/auto/qml/qqmlincubator/data/chainedAsynchronousIfNested.qml create mode 100644 tests/auto/qml/qqmlincubator/data/clear.qml create mode 100644 tests/auto/qml/qqmlincubator/data/clearDuringCompletion.qml create mode 100644 tests/auto/qml/qqmlincubator/data/contextDelete.qml create mode 100644 tests/auto/qml/qqmlincubator/data/forceCompletion.qml create mode 100644 tests/auto/qml/qqmlincubator/data/nestedComponent.js create mode 100644 tests/auto/qml/qqmlincubator/data/nestedComponent.qml create mode 100644 tests/auto/qml/qqmlincubator/data/noIncubationController.qml create mode 100644 tests/auto/qml/qqmlincubator/data/objectDeleted.errors.txt create mode 100644 tests/auto/qml/qqmlincubator/data/objectDeleted.qml create mode 100644 tests/auto/qml/qqmlincubator/data/recursiveClear.1.qml create mode 100644 tests/auto/qml/qqmlincubator/data/recursiveClear.2.qml create mode 100644 tests/auto/qml/qqmlincubator/data/selfDelete.qml create mode 100644 tests/auto/qml/qqmlincubator/data/setInitialState.qml create mode 100644 tests/auto/qml/qqmlincubator/data/statusChanged.nested.qml create mode 100644 tests/auto/qml/qqmlincubator/data/statusChanged.qml create mode 100644 tests/auto/qml/qqmlincubator/qqmlincubator.pro create mode 100644 tests/auto/qml/qqmlincubator/testtypes.cpp create mode 100644 tests/auto/qml/qqmlincubator/testtypes.h create mode 100644 tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp (limited to 'tests/auto/qml/qqmlincubator') diff --git a/tests/auto/qml/qqmlincubator/data/AsynchronousIfNestedType.qml b/tests/auto/qml/qqmlincubator/data/AsynchronousIfNestedType.qml new file mode 100644 index 0000000000..8a3f46ee72 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/AsynchronousIfNestedType.qml @@ -0,0 +1,7 @@ +import Qt.test 1.0 + +SelfRegistering { + property int dummy1: 11 + property int dummy2: 19 +} + diff --git a/tests/auto/qml/qqmlincubator/data/asynchronousIfNested.1.qml b/tests/auto/qml/qqmlincubator/data/asynchronousIfNested.1.qml new file mode 100644 index 0000000000..18ff4aabb7 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/asynchronousIfNested.1.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property int a: 10 +} diff --git a/tests/auto/qml/qqmlincubator/data/asynchronousIfNested.2.qml b/tests/auto/qml/qqmlincubator/data/asynchronousIfNested.2.qml new file mode 100644 index 0000000000..3f6cd932de --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/asynchronousIfNested.2.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +QtObject { + property QtObject o: AsynchronousIfNestedType { } + property int dummy: 11 +} diff --git a/tests/auto/qml/qqmlincubator/data/asynchronousIfNested.3.qml b/tests/auto/qml/qqmlincubator/data/asynchronousIfNested.3.qml new file mode 100644 index 0000000000..7e5ee7cf5c --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/asynchronousIfNested.3.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +CallbackRegistering { + value: 19 +} diff --git a/tests/auto/qml/qqmlincubator/data/chainInCompletion.qml b/tests/auto/qml/qqmlincubator/data/chainInCompletion.qml new file mode 100644 index 0000000000..e79fed356a --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/chainInCompletion.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +SelfRegistering { + property variant a: CompletionCallback {} +} diff --git a/tests/auto/qml/qqmlincubator/data/chainedAsynchronousIfNested.qml b/tests/auto/qml/qqmlincubator/data/chainedAsynchronousIfNested.qml new file mode 100644 index 0000000000..1300426cfa --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/chainedAsynchronousIfNested.qml @@ -0,0 +1,5 @@ +import Qt.test 1.0 + +SelfRegistering { + property int dummy: 10 +} diff --git a/tests/auto/qml/qqmlincubator/data/clear.qml b/tests/auto/qml/qqmlincubator/data/clear.qml new file mode 100644 index 0000000000..f00f975923 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/clear.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + SelfRegistering { + value: 11 + } +} diff --git a/tests/auto/qml/qqmlincubator/data/clearDuringCompletion.qml b/tests/auto/qml/qqmlincubator/data/clearDuringCompletion.qml new file mode 100644 index 0000000000..556f460d58 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/clearDuringCompletion.qml @@ -0,0 +1,6 @@ +import Qt.test 1.0 + +SelfRegistering { + property variant a: CompletionRegistering {} + property variant b: CompletionRegistering {} +} diff --git a/tests/auto/qml/qqmlincubator/data/contextDelete.qml b/tests/auto/qml/qqmlincubator/data/contextDelete.qml new file mode 100644 index 0000000000..c3952074f1 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/contextDelete.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property int dummy: 12 +} diff --git a/tests/auto/qml/qqmlincubator/data/forceCompletion.qml b/tests/auto/qml/qqmlincubator/data/forceCompletion.qml new file mode 100644 index 0000000000..9b76701c1b --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/forceCompletion.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + property int testValue: 3499 + SelfRegistering { + property int testValue2: 19 + } +} diff --git a/tests/auto/qml/qqmlincubator/data/nestedComponent.js b/tests/auto/qml/qqmlincubator/data/nestedComponent.js new file mode 100644 index 0000000000..4b6b0bde43 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/nestedComponent.js @@ -0,0 +1 @@ +var value = 19988 diff --git a/tests/auto/qml/qqmlincubator/data/nestedComponent.qml b/tests/auto/qml/qqmlincubator/data/nestedComponent.qml new file mode 100644 index 0000000000..dd20707456 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/nestedComponent.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 +import "nestedComponent.js" as NestedJS + +QtObject { + property Component c: Component { + QtObject { + property int value: NestedJS.value + } + } +} diff --git a/tests/auto/qml/qqmlincubator/data/noIncubationController.qml b/tests/auto/qml/qqmlincubator/data/noIncubationController.qml new file mode 100644 index 0000000000..7d93e856f0 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/noIncubationController.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property int testValue: 1913 +} diff --git a/tests/auto/qml/qqmlincubator/data/objectDeleted.errors.txt b/tests/auto/qml/qqmlincubator/data/objectDeleted.errors.txt new file mode 100644 index 0000000000..eeda289d35 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/objectDeleted.errors.txt @@ -0,0 +1 @@ +-1:-1:Object destroyed during incubation diff --git a/tests/auto/qml/qqmlincubator/data/objectDeleted.qml b/tests/auto/qml/qqmlincubator/data/objectDeleted.qml new file mode 100644 index 0000000000..f00f975923 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/objectDeleted.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 +import Qt.test 1.0 + +Item { + SelfRegistering { + value: 11 + } +} diff --git a/tests/auto/qml/qqmlincubator/data/recursiveClear.1.qml b/tests/auto/qml/qqmlincubator/data/recursiveClear.1.qml new file mode 100644 index 0000000000..748a3f0cbf --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/recursiveClear.1.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +Rectangle { + objectName: "switchMe" + signal switchMe + width: 100; height: 100 + color: "green" + Component.onCompleted: switchMe() +} diff --git a/tests/auto/qml/qqmlincubator/data/recursiveClear.2.qml b/tests/auto/qml/qqmlincubator/data/recursiveClear.2.qml new file mode 100644 index 0000000000..e96ac00f21 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/recursiveClear.2.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +Rectangle { + objectName: "blue" + width: 100 + height: 100 + color: "blue" +} diff --git a/tests/auto/qml/qqmlincubator/data/selfDelete.qml b/tests/auto/qml/qqmlincubator/data/selfDelete.qml new file mode 100644 index 0000000000..c3952074f1 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/selfDelete.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property int dummy: 12 +} diff --git a/tests/auto/qml/qqmlincubator/data/setInitialState.qml b/tests/auto/qml/qqmlincubator/data/setInitialState.qml new file mode 100644 index 0000000000..0fd61abfd2 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/setInitialState.qml @@ -0,0 +1,17 @@ +import QtQuick 2.0 + +QtObject { + property int test1: (testData1 * 32 + 99) / testData2 + property int test2: myValueFunction() + + property bool myValueFunctionCalled: false + + property int testData1: 19 + property int testData2: 13 + + function myValueFunction() { + myValueFunctionCalled = true; + return 13; + } +} + diff --git a/tests/auto/qml/qqmlincubator/data/statusChanged.nested.qml b/tests/auto/qml/qqmlincubator/data/statusChanged.nested.qml new file mode 100644 index 0000000000..3a496ea6fe --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/statusChanged.nested.qml @@ -0,0 +1,12 @@ +import QtQuick 2.0 + +QtObject { + id: root + + property bool test: false + + Component.onCompleted: { + var c = Qt.createComponent("statusChanged.qml"); + c.incubateObject(root, null, Qt.Synchronous); + } +} diff --git a/tests/auto/qml/qqmlincubator/data/statusChanged.qml b/tests/auto/qml/qqmlincubator/data/statusChanged.qml new file mode 100644 index 0000000000..18ff4aabb7 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/data/statusChanged.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property int a: 10 +} diff --git a/tests/auto/qml/qqmlincubator/qqmlincubator.pro b/tests/auto/qml/qqmlincubator/qqmlincubator.pro new file mode 100644 index 0000000000..956d72402c --- /dev/null +++ b/tests/auto/qml/qqmlincubator/qqmlincubator.pro @@ -0,0 +1,18 @@ +CONFIG += testcase +TARGET = tst_qqmlincubator +macx:CONFIG -= app_bundle + +SOURCES += tst_qqmlincubator.cpp \ + testtypes.cpp + +HEADERS += testtypes.h + +include (../../shared/util.pri) + +testDataFiles.files = data +testDataFiles.path = . +DEPLOYMENT += testDataFiles + +CONFIG += parallel_test + +QT += core-private gui-private v8-private qml-private network widgets testlib diff --git a/tests/auto/qml/qqmlincubator/testtypes.cpp b/tests/auto/qml/qqmlincubator/testtypes.cpp new file mode 100644 index 0000000000..7936fc146c --- /dev/null +++ b/tests/auto/qml/qqmlincubator/testtypes.cpp @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "testtypes.h" +#include + +SelfRegisteringType *SelfRegisteringType::m_me = 0; +SelfRegisteringType::SelfRegisteringType() +: m_v(0) +{ + m_me = this; +} + +SelfRegisteringType *SelfRegisteringType::me() +{ + return m_me; +} + +void SelfRegisteringType::clearMe() +{ + m_me = 0; +} + +CompletionRegisteringType *CompletionRegisteringType::m_me = 0; +CompletionRegisteringType::CompletionRegisteringType() +{ +} + +void CompletionRegisteringType::classBegin() +{ +} + +void CompletionRegisteringType::componentComplete() +{ + m_me = this; +} + +CompletionRegisteringType *CompletionRegisteringType::me() +{ + return m_me; +} + +void CompletionRegisteringType::clearMe() +{ + m_me = 0; +} + +CallbackRegisteringType::callback CallbackRegisteringType::m_callback = 0; +void *CallbackRegisteringType::m_data = 0; +CallbackRegisteringType::CallbackRegisteringType() +: m_v(0) +{ +} + +void CallbackRegisteringType::clearCallback() +{ + m_callback = 0; + m_data = 0; +} + +void CallbackRegisteringType::registerCallback(callback c, void *d) +{ + m_callback = c; + m_data = d; +} + +CompletionCallbackType::callback CompletionCallbackType::m_callback = 0; +void *CompletionCallbackType::m_data = 0; +CompletionCallbackType::CompletionCallbackType() +{ +} + +void CompletionCallbackType::classBegin() +{ +} + +void CompletionCallbackType::componentComplete() +{ + if (m_callback) m_callback(this, m_data); +} + +void CompletionCallbackType::clearCallback() +{ + m_callback = 0; + m_data = 0; +} + +void CompletionCallbackType::registerCallback(callback c, void *d) +{ + m_callback = c; + m_data = d; +} + +void registerTypes() +{ + qmlRegisterType("Qt.test", 1,0, "SelfRegistering"); + qmlRegisterType("Qt.test", 1,0, "CompletionRegistering"); + qmlRegisterType("Qt.test", 1,0, "CallbackRegistering"); + qmlRegisterType("Qt.test", 1,0, "CompletionCallback"); +} diff --git a/tests/auto/qml/qqmlincubator/testtypes.h b/tests/auto/qml/qqmlincubator/testtypes.h new file mode 100644 index 0000000000..8ca7ee34ee --- /dev/null +++ b/tests/auto/qml/qqmlincubator/testtypes.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef TESTTYPES_H +#define TESTTYPES_H + +#include +#include + +class SelfRegisteringType : public QObject +{ +Q_OBJECT +Q_PROPERTY(int value READ value WRITE setValue); +public: + SelfRegisteringType(); + + int value() const { return m_v; } + void setValue(int v) { m_v = v; } + + static SelfRegisteringType *me(); + static void clearMe(); + +private: + static SelfRegisteringType *m_me; + + int m_v; +}; + +class CallbackRegisteringType : public QObject +{ +Q_OBJECT +Q_PROPERTY(int value READ value WRITE setValue) +public: + CallbackRegisteringType(); + + int value() const { return m_v; } + void setValue(int v) { if (m_callback) m_callback(this, m_data); m_v = v; } + + typedef void (*callback)(CallbackRegisteringType *, void *); + static void clearCallback(); + static void registerCallback(callback, void *); + +private: + static callback m_callback; + static void *m_data; + + int m_v; +}; + +class CompletionRegisteringType : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) +public: + CompletionRegisteringType(); + + virtual void classBegin(); + virtual void componentComplete(); + + static CompletionRegisteringType *me(); + static void clearMe(); + +private: + static CompletionRegisteringType *m_me; +}; + +class CompletionCallbackType : public QObject, public QQmlParserStatus +{ + Q_OBJECT + Q_INTERFACES(QQmlParserStatus) +public: + CompletionCallbackType(); + + virtual void classBegin(); + virtual void componentComplete(); + + typedef void (*callback)(CompletionCallbackType *, void *); + static void clearCallback(); + static void registerCallback(callback, void *); + +private: + static callback m_callback; + static void *m_data; +}; + +void registerTypes(); + +#endif // TESTTYPES_H diff --git a/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp new file mode 100644 index 0000000000..fc54f715c9 --- /dev/null +++ b/tests/auto/qml/qqmlincubator/tst_qqmlincubator.cpp @@ -0,0 +1,1030 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "testtypes.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../shared/util.h" + +class tst_qqmlincubator : public QQmlDataTest +{ + Q_OBJECT +public: + tst_qqmlincubator() {} + +private slots: + void initTestCase(); + + void incubationMode(); + void objectDeleted(); + void clear(); + void noIncubationController(); + void forceCompletion(); + void setInitialState(); + void clearDuringCompletion(); + void objectDeletionAfterInit(); + void recursiveClear(); + void statusChanged(); + void asynchronousIfNested(); + void nestedComponent(); + void chainedAsynchronousIfNested(); + void chainedAsynchronousIfNestedOnCompleted(); + void selfDelete(); + void contextDelete(); + +private: + QQmlIncubationController controller; + QQmlEngine engine; +}; + +#define VERIFY_ERRORS(component, errorfile) \ + if (!errorfile) { \ + if (qgetenv("DEBUG") != "" && !component.errors().isEmpty()) \ + qWarning() << "Unexpected Errors:" << component.errors(); \ + QVERIFY(!component.isError()); \ + QVERIFY(component.errors().isEmpty()); \ + } else { \ + QFile file(QQmlDataTest::instance()->testFile(errorfile)); \ + QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); \ + QByteArray data = file.readAll(); \ + file.close(); \ + QList expected = data.split('\n'); \ + expected.removeAll(QByteArray("")); \ + QList errors = component.errors(); \ + QList actual; \ + for (int ii = 0; ii < errors.count(); ++ii) { \ + const QQmlError &error = errors.at(ii); \ + QByteArray errorStr = QByteArray::number(error.line()) + ":" + \ + QByteArray::number(error.column()) + ":" + \ + error.description().toUtf8(); \ + actual << errorStr; \ + } \ + if (qgetenv("DEBUG") != "" && expected != actual) \ + qWarning() << "Expected:" << expected << "Actual:" << actual; \ + QCOMPARE(expected, actual); \ + } + +void tst_qqmlincubator::initTestCase() +{ + QQmlDataTest::initTestCase(); + registerTypes(); + engine.setIncubationController(&controller); +} + +void tst_qqmlincubator::incubationMode() +{ + { + QQmlIncubator incubator; + QCOMPARE(incubator.incubationMode(), QQmlIncubator::Asynchronous); + } + { + QQmlIncubator incubator(QQmlIncubator::Asynchronous); + QCOMPARE(incubator.incubationMode(), QQmlIncubator::Asynchronous); + } + { + QQmlIncubator incubator(QQmlIncubator::Synchronous); + QCOMPARE(incubator.incubationMode(), QQmlIncubator::Synchronous); + } + { + QQmlIncubator incubator(QQmlIncubator::AsynchronousIfNested); + QCOMPARE(incubator.incubationMode(), QQmlIncubator::AsynchronousIfNested); + } +} + +void tst_qqmlincubator::objectDeleted() +{ + SelfRegisteringType::clearMe(); + + QQmlComponent component(&engine, testFileUrl("objectDeleted.qml")); + QVERIFY(component.isReady()); + + QQmlIncubator incubator; + component.create(incubator); + + QCOMPARE(incubator.status(), QQmlIncubator::Loading); + QVERIFY(SelfRegisteringType::me() == 0); + + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator.isLoading()); + + delete SelfRegisteringType::me(); + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isError()); + VERIFY_ERRORS(incubator, "objectDeleted.errors.txt"); + QVERIFY(incubator.object() == 0); +} + +void tst_qqmlincubator::clear() +{ + SelfRegisteringType::clearMe(); + + QQmlComponent component(&engine, testFileUrl("clear.qml")); + QVERIFY(component.isReady()); + + // Clear in null state + { + QQmlIncubator incubator; + QVERIFY(incubator.isNull()); + incubator.clear(); // no effect + QVERIFY(incubator.isNull()); + } + + // Clear in loading state + { + QQmlIncubator incubator; + component.create(incubator); + QVERIFY(incubator.isLoading()); + incubator.clear(); + QVERIFY(incubator.isNull()); + } + + // Clear mid load + { + QQmlIncubator incubator; + component.create(incubator); + + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(SelfRegisteringType::me() != 0); + QPointer srt = SelfRegisteringType::me(); + + incubator.clear(); + QVERIFY(incubator.isNull()); + QVERIFY(srt.isNull()); + } + + // Clear in ready state + { + QQmlIncubator incubator; + component.create(incubator); + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object() != 0); + QPointer obj = incubator.object(); + + incubator.clear(); + QVERIFY(incubator.isNull()); + QVERIFY(incubator.object() == 0); + QVERIFY(!obj.isNull()); + + delete obj; + QVERIFY(obj.isNull()); + } +} + +void tst_qqmlincubator::noIncubationController() +{ + // All incubators should behave synchronously when there is no controller + + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("noIncubationController.qml")); + + QVERIFY(component.isReady()); + + { + QQmlIncubator incubator(QQmlIncubator::Asynchronous); + component.create(incubator); + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object()); + QCOMPARE(incubator.object()->property("testValue").toInt(), 1913); + delete incubator.object(); + } + + { + QQmlIncubator incubator(QQmlIncubator::AsynchronousIfNested); + component.create(incubator); + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object()); + QCOMPARE(incubator.object()->property("testValue").toInt(), 1913); + delete incubator.object(); + } + + { + QQmlIncubator incubator(QQmlIncubator::Synchronous); + component.create(incubator); + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object()); + QCOMPARE(incubator.object()->property("testValue").toInt(), 1913); + delete incubator.object(); + } +} + +void tst_qqmlincubator::forceCompletion() +{ + QQmlComponent component(&engine, testFileUrl("forceCompletion.qml")); + QVERIFY(component.isReady()); + + { + // forceCompletion on a null incubator does nothing + QQmlIncubator incubator; + QVERIFY(incubator.isNull()); + incubator.forceCompletion(); + QVERIFY(incubator.isNull()); + } + + { + // forceCompletion immediately after creating an asynchronous object completes it + QQmlIncubator incubator; + QVERIFY(incubator.isNull()); + component.create(incubator); + QVERIFY(incubator.isLoading()); + + incubator.forceCompletion(); + + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object() != 0); + QCOMPARE(incubator.object()->property("testValue").toInt(), 3499); + + delete incubator.object(); + } + + { + // forceCompletion during creation completes it + SelfRegisteringType::clearMe(); + + QQmlIncubator incubator; + QVERIFY(incubator.isNull()); + component.create(incubator); + QVERIFY(incubator.isLoading()); + + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator.isLoading()); + + incubator.forceCompletion(); + + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object() != 0); + QCOMPARE(incubator.object()->property("testValue").toInt(), 3499); + + delete incubator.object(); + } + + { + // forceCompletion on a ready incubator has no effect + QQmlIncubator incubator; + QVERIFY(incubator.isNull()); + component.create(incubator); + QVERIFY(incubator.isLoading()); + + incubator.forceCompletion(); + + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object() != 0); + QCOMPARE(incubator.object()->property("testValue").toInt(), 3499); + + incubator.forceCompletion(); + + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object() != 0); + QCOMPARE(incubator.object()->property("testValue").toInt(), 3499); + + delete incubator.object(); + } +} + +void tst_qqmlincubator::setInitialState() +{ + QQmlComponent component(&engine, testFileUrl("setInitialState.qml")); + QVERIFY(component.isReady()); + + struct MyIncubator : public QQmlIncubator + { + MyIncubator(QQmlIncubator::IncubationMode mode) + : QQmlIncubator(mode) {} + + virtual void setInitialState(QObject *o) { + QQmlProperty::write(o, "test2", 19); + QQmlProperty::write(o, "testData1", 201); + } + }; + + { + MyIncubator incubator(QQmlIncubator::Asynchronous); + component.create(incubator); + QVERIFY(incubator.isLoading()); + bool b = true; + controller.incubateWhile(&b); + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object()); + QCOMPARE(incubator.object()->property("myValueFunctionCalled").toBool(), false); + QCOMPARE(incubator.object()->property("test1").toInt(), 502); + QCOMPARE(incubator.object()->property("test2").toInt(), 19); + delete incubator.object(); + } + + { + MyIncubator incubator(QQmlIncubator::Synchronous); + component.create(incubator); + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object()); + QCOMPARE(incubator.object()->property("myValueFunctionCalled").toBool(), false); + QCOMPARE(incubator.object()->property("test1").toInt(), 502); + QCOMPARE(incubator.object()->property("test2").toInt(), 19); + delete incubator.object(); + } +} + +void tst_qqmlincubator::clearDuringCompletion() +{ + CompletionRegisteringType::clearMe(); + SelfRegisteringType::clearMe(); + + QQmlComponent component(&engine, testFileUrl("clearDuringCompletion.qml")); + QVERIFY(component.isReady()); + + QQmlIncubator incubator; + component.create(incubator); + + QCOMPARE(incubator.status(), QQmlIncubator::Loading); + QVERIFY(CompletionRegisteringType::me() == 0); + + while (CompletionRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(CompletionRegisteringType::me() != 0); + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator.isLoading()); + + QPointer srt = SelfRegisteringType::me(); + + incubator.clear(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + QVERIFY(incubator.isNull()); + QVERIFY(srt.isNull()); +} + +void tst_qqmlincubator::objectDeletionAfterInit() +{ + QQmlComponent component(&engine, testFileUrl("clear.qml")); + QVERIFY(component.isReady()); + + struct MyIncubator : public QQmlIncubator + { + MyIncubator(QQmlIncubator::IncubationMode mode) + : QQmlIncubator(mode), obj(0) {} + + virtual void setInitialState(QObject *o) { + obj = o; + } + + QObject *obj; + }; + + SelfRegisteringType::clearMe(); + MyIncubator incubator(QQmlIncubator::Asynchronous); + component.create(incubator); + + while (!incubator.obj && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(SelfRegisteringType::me() != 0); + + delete incubator.obj; + + incubator.clear(); + QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); + QCoreApplication::processEvents(); + QVERIFY(incubator.isNull()); +} + +class Switcher : public QObject +{ + Q_OBJECT +public: + Switcher(QQmlEngine *e) : QObject(), engine(e) { } + + struct MyIncubator : public QQmlIncubator + { + MyIncubator(QQmlIncubator::IncubationMode mode, QObject *s) + : QQmlIncubator(mode), switcher(s) {} + + virtual void setInitialState(QObject *o) { + if (o->objectName() == "switchMe") + connect(o, SIGNAL(switchMe()), switcher, SLOT(switchIt())); + } + + QObject *switcher; + }; + + void start() + { + incubator = new MyIncubator(QQmlIncubator::Synchronous, this); + component = new QQmlComponent(engine, QQmlDataTest::instance()->testFileUrl("recursiveClear.1.qml")); + component->create(*incubator); + } + + QQmlEngine *engine; + MyIncubator *incubator; + QQmlComponent *component; + +public slots: + void switchIt() { + component->deleteLater(); + incubator->clear(); + component = new QQmlComponent(engine, QQmlDataTest::instance()->testFileUrl("recursiveClear.2.qml")); + component->create(*incubator); + } +}; + +void tst_qqmlincubator::recursiveClear() +{ + Switcher switcher(&engine); + switcher.start(); +} + +void tst_qqmlincubator::statusChanged() +{ + class MyIncubator : public QQmlIncubator + { + public: + MyIncubator(QQmlIncubator::IncubationMode mode = QQmlIncubator::Asynchronous) + : QQmlIncubator(mode) {} + + QList statuses; + protected: + virtual void statusChanged(Status s) { statuses << s; } + virtual void setInitialState(QObject *) { statuses << -1; } + }; + + { + QQmlComponent component(&engine, testFileUrl("statusChanged.qml")); + QVERIFY(component.isReady()); + + MyIncubator incubator(QQmlIncubator::Synchronous); + component.create(incubator); + QVERIFY(incubator.isReady()); + QCOMPARE(incubator.statuses.count(), 3); + QCOMPARE(incubator.statuses.at(0), int(QQmlIncubator::Loading)); + QCOMPARE(incubator.statuses.at(1), -1); + QCOMPARE(incubator.statuses.at(2), int(QQmlIncubator::Ready)); + delete incubator.object(); + } + + { + QQmlComponent component(&engine, testFileUrl("statusChanged.qml")); + QVERIFY(component.isReady()); + + MyIncubator incubator(QQmlIncubator::Asynchronous); + component.create(incubator); + QVERIFY(incubator.isLoading()); + QCOMPARE(incubator.statuses.count(), 1); + QCOMPARE(incubator.statuses.at(0), int(QQmlIncubator::Loading)); + + { + bool b = true; + controller.incubateWhile(&b); + } + + QCOMPARE(incubator.statuses.count(), 3); + QCOMPARE(incubator.statuses.at(0), int(QQmlIncubator::Loading)); + QCOMPARE(incubator.statuses.at(1), -1); + QCOMPARE(incubator.statuses.at(2), int(QQmlIncubator::Ready)); + delete incubator.object(); + } + + { + QQmlComponent component2(&engine, testFileUrl("statusChanged.nested.qml")); + QVERIFY(component2.isReady()); + + MyIncubator incubator(QQmlIncubator::Asynchronous); + component2.create(incubator); + QVERIFY(incubator.isLoading()); + QCOMPARE(incubator.statuses.count(), 1); + QCOMPARE(incubator.statuses.at(0), int(QQmlIncubator::Loading)); + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isReady()); + QCOMPARE(incubator.statuses.count(), 3); + QCOMPARE(incubator.statuses.at(0), int(QQmlIncubator::Loading)); + QCOMPARE(incubator.statuses.at(1), -1); + QCOMPARE(incubator.statuses.at(2), int(QQmlIncubator::Ready)); + delete incubator.object(); + } +} + +void tst_qqmlincubator::asynchronousIfNested() +{ + // Asynchronous if nested within a finalized context behaves synchronously + { + QQmlComponent component(&engine, testFileUrl("asynchronousIfNested.1.qml")); + QVERIFY(component.isReady()); + + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("a").toInt(), 10); + + QQmlIncubator incubator(QQmlIncubator::AsynchronousIfNested); + component.create(incubator, 0, qmlContext(object)); + + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object()); + QCOMPARE(incubator.object()->property("a").toInt(), 10); + delete incubator.object(); + delete object; + } + + // Asynchronous if nested within an executing context behaves asynchronously, but prevents + // the parent from finishing + { + SelfRegisteringType::clearMe(); + + QQmlComponent component(&engine, testFileUrl("asynchronousIfNested.2.qml")); + QVERIFY(component.isReady()); + + QQmlIncubator incubator; + component.create(incubator); + + QVERIFY(incubator.isLoading()); + QVERIFY(SelfRegisteringType::me() == 0); + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator.isLoading()); + + QQmlIncubator nested(QQmlIncubator::AsynchronousIfNested); + component.create(nested, 0, qmlContext(SelfRegisteringType::me())); + QVERIFY(nested.isLoading()); + + while (nested.isLoading()) { + QVERIFY(incubator.isLoading()); + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(nested.isReady()); + QVERIFY(incubator.isLoading()); + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(nested.isReady()); + QVERIFY(incubator.isReady()); + + delete nested.object(); + delete incubator.object(); + } + + // AsynchronousIfNested within a synchronous AsynchronousIfNested behaves synchronously + { + SelfRegisteringType::clearMe(); + + QQmlComponent component(&engine, testFileUrl("asynchronousIfNested.3.qml")); + QVERIFY(component.isReady()); + + struct CallbackData { + CallbackData(QQmlEngine *e) : engine(e), pass(false) {} + QQmlEngine *engine; + bool pass; + static void callback(CallbackRegisteringType *o, void *data) { + CallbackData *d = (CallbackData *)data; + + QQmlComponent c(d->engine, QQmlDataTest::instance()->testFileUrl("asynchronousIfNested.1.qml")); + if (!c.isReady()) return; + + QQmlIncubator incubator(QQmlIncubator::AsynchronousIfNested); + c.create(incubator, 0, qmlContext(o)); + + if (!incubator.isReady()) return; + + if (incubator.object()->property("a").toInt() != 10) return; + + d->pass = true; + } + }; + + CallbackData cd(&engine); + CallbackRegisteringType::registerCallback(&CallbackData::callback, &cd); + + QQmlIncubator incubator(QQmlIncubator::AsynchronousIfNested); + component.create(incubator); + + QVERIFY(incubator.isReady()); + QCOMPARE(cd.pass, true); + + delete incubator.object(); + } +} + +void tst_qqmlincubator::nestedComponent() +{ + QQmlComponent component(&engine, testFileUrl("nestedComponent.qml")); + QVERIFY(component.isReady()); + + QObject *object = component.create(); + + QQmlComponent *nested = object->property("c").value(); + QVERIFY(nested); + QVERIFY(nested->isReady()); + + // Test without incubator + { + QObject *nestedObject = nested->create(); + QCOMPARE(nestedObject->property("value").toInt(), 19988); + delete nestedObject; + } + + // Test with incubator + { + QQmlIncubator incubator(QQmlIncubator::Synchronous); + nested->create(incubator); + QVERIFY(incubator.isReady()); + QVERIFY(incubator.object()); + QCOMPARE(incubator.object()->property("value").toInt(), 19988); + delete incubator.object(); + } + + delete object; +} + +// Checks that a new AsynchronousIfNested incubator can be correctly started in the +// statusChanged() callback of another. +void tst_qqmlincubator::chainedAsynchronousIfNested() +{ + SelfRegisteringType::clearMe(); + + QQmlComponent component(&engine, testFileUrl("chainedAsynchronousIfNested.qml")); + QVERIFY(component.isReady()); + + QQmlIncubator incubator(QQmlIncubator::Asynchronous); + component.create(incubator); + + QVERIFY(incubator.isLoading()); + QVERIFY(SelfRegisteringType::me() == 0); + + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator.isLoading()); + + struct MyIncubator : public QQmlIncubator { + MyIncubator(MyIncubator *next, QQmlComponent *component, QQmlContext *ctxt) + : QQmlIncubator(AsynchronousIfNested), next(next), component(component), ctxt(ctxt) {} + + protected: + virtual void statusChanged(Status s) { + if (s == Ready && next) + component->create(*next, 0, ctxt); + } + + private: + MyIncubator *next; + QQmlComponent *component; + QQmlContext *ctxt; + }; + + MyIncubator incubator2(0, &component, 0); + MyIncubator incubator1(&incubator2, &component, qmlContext(SelfRegisteringType::me())); + + component.create(incubator1, 0, qmlContext(SelfRegisteringType::me())); + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + + while (incubator1.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + + while (incubator2.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isReady()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); +} + +// Checks that new AsynchronousIfNested incubators can be correctly chained if started in +// componentCompleted(). +void tst_qqmlincubator::chainedAsynchronousIfNestedOnCompleted() +{ + SelfRegisteringType::clearMe(); + + QQmlComponent component(&engine, testFileUrl("chainInCompletion.qml")); + QVERIFY(component.isReady()); + + QQmlComponent c1(&engine, testFileUrl("chainedAsynchronousIfNested.qml")); + QVERIFY(c1.isReady()); + + struct MyIncubator : public QQmlIncubator { + MyIncubator(MyIncubator *next, QQmlComponent *component, QQmlContext *ctxt) + : QQmlIncubator(AsynchronousIfNested), next(next), component(component), ctxt(ctxt) {} + + protected: + virtual void statusChanged(Status s) { + if (s == Ready && next) { + component->create(*next, 0, ctxt); + } + } + + private: + MyIncubator *next; + QQmlComponent *component; + QQmlContext *ctxt; + }; + + struct CallbackData { + CallbackData(QQmlComponent *c, MyIncubator *i, QQmlContext *ct) + : component(c), incubator(i), ctxt(ct) {} + QQmlComponent *component; + MyIncubator *incubator; + QQmlContext *ctxt; + static void callback(CompletionCallbackType *, void *data) { + CallbackData *d = (CallbackData *)data; + d->component->create(*d->incubator, 0, d->ctxt); + } + }; + + QQmlIncubator incubator(QQmlIncubator::Asynchronous); + component.create(incubator); + + QVERIFY(incubator.isLoading()); + QVERIFY(SelfRegisteringType::me() == 0); + + while (SelfRegisteringType::me() == 0 && incubator.isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator.isLoading()); + + MyIncubator incubator3(0, &c1, qmlContext(SelfRegisteringType::me())); + MyIncubator incubator2(&incubator3, &c1, qmlContext(SelfRegisteringType::me())); + MyIncubator incubator1(&incubator2, &c1, qmlContext(SelfRegisteringType::me())); + + // start incubator1 in componentComplete + CallbackData cd(&c1, &incubator1, qmlContext(SelfRegisteringType::me())); + CompletionCallbackType::registerCallback(&CallbackData::callback, &cd); + + while (!incubator1.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator2.isNull()); + QVERIFY(incubator3.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + QVERIFY(incubator3.isNull()); + + while (incubator1.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isLoading()); + QVERIFY(incubator2.isNull()); + QVERIFY(incubator3.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + QVERIFY(incubator3.isNull()); + + while (incubator2.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isLoading()); + QVERIFY(incubator3.isNull()); + + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + QVERIFY(incubator3.isLoading()); + + while (incubator3.isLoading()) { + QVERIFY(incubator.isLoading()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + QVERIFY(incubator3.isLoading()); + + bool b = false; + controller.incubateWhile(&b); + } + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(incubator.isReady()); + QVERIFY(incubator1.isReady()); + QVERIFY(incubator2.isReady()); + QVERIFY(incubator3.isReady()); +} + +void tst_qqmlincubator::selfDelete() +{ + struct MyIncubator : public QQmlIncubator { + MyIncubator(bool *done, Status status, IncubationMode mode) + : QQmlIncubator(mode), done(done), status(status) {} + + protected: + virtual void statusChanged(Status s) { + if (s == status) { + *done = true; + if (s == Ready) delete object(); + delete this; + } + } + + private: + bool *done; + Status status; + }; + + { + QQmlComponent component(&engine, testFileUrl("selfDelete.qml")); + +#define DELETE_TEST(status, mode) { \ + bool done = false; \ + component.create(*(new MyIncubator(&done, status, mode))); \ + bool True = true; \ + controller.incubateWhile(&True); \ + QVERIFY(done == true); \ + } + + DELETE_TEST(QQmlIncubator::Loading, QQmlIncubator::Synchronous); + DELETE_TEST(QQmlIncubator::Ready, QQmlIncubator::Synchronous); + DELETE_TEST(QQmlIncubator::Loading, QQmlIncubator::Asynchronous); + DELETE_TEST(QQmlIncubator::Ready, QQmlIncubator::Asynchronous); + +#undef DELETE_TEST + } + + // Delete within error status + { + SelfRegisteringType::clearMe(); + + QQmlComponent component(&engine, testFileUrl("objectDeleted.qml")); + QVERIFY(component.isReady()); + + bool done = false; + MyIncubator *incubator = new MyIncubator(&done, QQmlIncubator::Error, + QQmlIncubator::Asynchronous); + component.create(*incubator); + + QCOMPARE(incubator->QQmlIncubator::status(), QQmlIncubator::Loading); + QVERIFY(SelfRegisteringType::me() == 0); + + while (SelfRegisteringType::me() == 0 && incubator->isLoading()) { + bool b = false; + controller.incubateWhile(&b); + } + + QVERIFY(SelfRegisteringType::me() != 0); + QVERIFY(incubator->isLoading()); + + delete SelfRegisteringType::me(); + + { + bool b = true; + controller.incubateWhile(&b); + } + + QVERIFY(done); + } +} + +// Test that QML doesn't crash if the context is deleted prior to the incubator +// first executing. +void tst_qqmlincubator::contextDelete() +{ + QQmlContext *context = new QQmlContext(engine.rootContext()); + QQmlComponent component(&engine, testFileUrl("contextDelete.qml")); + + QQmlIncubator incubator; + component.create(incubator, context); + + delete context; + + { + bool b = false; + controller.incubateWhile(&b); + } +} + +QTEST_MAIN(tst_qqmlincubator) + +#include "tst_qqmlincubator.moc" -- cgit v1.2.3