From: Aaron Kennedy Date: Mon, 3 Oct 2011 05:45:51 +0000 (+1000) Subject: QDeclarativeIncubator::clear() and autotests X-Git-Tag: qt-v5.0.0-alpha1~1500 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=95cd185fa4bfe872458988d0b5ffb36fd1b56bd3;p=profile%2Fivi%2Fqtdeclarative.git QDeclarativeIncubator::clear() and autotests Change-Id: I2a14c01c7f9412459572e9960cb95a4c24e068aa Task-number: QTBUG-21151 Reviewed-on: http://codereview.qt-project.org/5911 Reviewed-by: Aaron Kennedy --- diff --git a/src/declarative/qml/qdeclarativeincubator.cpp b/src/declarative/qml/qdeclarativeincubator.cpp index 053a026..b6eb4e4 100644 --- a/src/declarative/qml/qdeclarativeincubator.cpp +++ b/src/declarative/qml/qdeclarativeincubator.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qdeclarativeincubator.h" +#include "qdeclarativecomponent.h" #include "qdeclarativeincubator_p.h" #include @@ -121,7 +122,6 @@ QDeclarativeIncubatorPrivate::QDeclarativeIncubatorPrivate(QDeclarativeIncubator QDeclarativeIncubatorPrivate::~QDeclarativeIncubatorPrivate() { - clear(); } void QDeclarativeIncubatorPrivate::clear() @@ -236,13 +236,26 @@ void QDeclarativeIncubatorPrivate::incubate(QDeclarativeVME::Interrupt &i) QDeclarativeEngine *engine = component->engine; QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine); + bool guardOk = vmeGuard.isOK(); + vmeGuard.clear(); + + if (!guardOk) { + QDeclarativeError error; + error.setUrl(component->url); + error.setDescription(QDeclarativeComponent::tr("Object destroyed during incubation")); + errors << error; + progress = QDeclarativeIncubatorPrivate::Completed; + + goto finishIncubate; + } + if (progress == QDeclarativeIncubatorPrivate::Execute) { enginePriv->referenceScarceResources(); result = vme.execute(&errors, i); enginePriv->dereferenceScarceResources(); if (errors.isEmpty() && result == 0) - return; // Interrupted + goto finishIncubate; if (result) { QDeclarativeData *ddata = QDeclarativeData::get(result); @@ -288,6 +301,8 @@ finishIncubate: enginePriv->erroredBindings->removeError(); } } + } else { + vmeGuard.guard(&vme); } } @@ -419,6 +434,8 @@ QDeclarativeIncubator::QDeclarativeIncubator(IncubationMode mode) /*! \internal */ QDeclarativeIncubator::~QDeclarativeIncubator() { + clear(); + delete d; d = 0; } @@ -456,12 +473,14 @@ void QDeclarativeIncubator::clear() { Status s = status(); - if (s == Loading) - qFatal("QDeclarativeIncubator::clear(): Clear not implemented for loading incubator"); - if (s == Null) return; + d->clear(); + + d->vme.reset(); + d->vmeGuard.clear(); + Q_ASSERT(d->component == 0); Q_ASSERT(d->waitingOnMe == 0); Q_ASSERT(d->waitingFor.isEmpty()); diff --git a/src/declarative/qml/qdeclarativeincubator_p.h b/src/declarative/qml/qdeclarativeincubator_p.h index 57c54d3..e736aab 100644 --- a/src/declarative/qml/qdeclarativeincubator_p.h +++ b/src/declarative/qml/qdeclarativeincubator_p.h @@ -79,6 +79,7 @@ public: QObject *result; QDeclarativeCompiledData *component; QDeclarativeVME vme; + QDeclarativeVMEGuard vmeGuard; typedef QDeclarativeIncubatorPrivate QIP; QIP *waitingOnMe; diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp index f8405be..bf8bd29 100644 --- a/src/declarative/qml/qdeclarativevme.cpp +++ b/src/declarative/qml/qdeclarativevme.cpp @@ -130,6 +130,7 @@ bool QDeclarativeVME::initDeferred(QObject *object) int start = data->deferredIdx; State initState; + initState.flags = State::Deferred; initState.context = ctxt; initState.compiledData = comp; initState.instructionStream = comp->bytecode.constData() + start; @@ -195,7 +196,6 @@ static void removeBindingOnProperty(QObject *o, int index) // XXX we probably need some form of "work count" here to prevent us checking this // for every instruction. #define QML_BEGIN_INSTR_COMMON(I) { \ - if (interrupt.shouldInterrupt()) return 0; \ const QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::DataType &instr = QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::data(*genericInstr); \ INSTRUCTIONSTREAM += QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::Size; \ Q_UNUSED(instr); @@ -211,6 +211,7 @@ static void removeBindingOnProperty(QObject *o, int index) # define QML_END_INSTR(I) } \ genericInstr = reinterpret_cast(INSTRUCTIONSTREAM); \ + if (interrupt.shouldInterrupt()) return 0; \ goto *genericInstr->common.code; #else @@ -219,7 +220,9 @@ static void removeBindingOnProperty(QObject *o, int index) QML_BEGIN_INSTR_COMMON(I) # define QML_NEXT_INSTR(I) break; -# define QML_END_INSTR(I) } break; +# define QML_END_INSTR(I) \ + if (interrupt.shouldInterrupt()) return 0; \ + } break; #endif #define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index) @@ -1099,23 +1102,10 @@ QObject *QDeclarativeVME::run(QList *errors, #endif exceptionExit: - if (!objects.isEmpty()) - delete objects.at(0); // XXX What about failures in deferred creation? - - // XXX does context get leaked in this case? - + Q_ASSERT(!states.isEmpty()); Q_ASSERT(!errors->isEmpty()); - // Remove the QDeclarativeParserStatus and QDeclarativeAbstractBinding back pointers - blank(parserStatus); - blank(bindValues); - - objects.deallocate(); - lists.deallocate(); - states.clear(); - bindValues.deallocate(); - parserStatus.deallocate(); - finalizeCallbacks.clear(); + reset(); return 0; @@ -1131,6 +1121,35 @@ normalExit: return rv; } +void QDeclarativeVME::reset() +{ + Q_ASSERT(!states.isEmpty() || objects.isEmpty()); + + if (!objects.isEmpty() && !(states.at(0).flags & State::Deferred)) + delete objects.at(0); + + if (!rootContext.isNull()) + rootContext->activeVME = 0; + + // Remove the QDeclarativeParserStatus and QDeclarativeAbstractBinding back pointers + blank(parserStatus); + blank(bindValues); + + while (componentAttached) { + QDeclarativeComponentAttached *a = componentAttached; + a->rem(); + } + + engine = 0; + objects.deallocate(); + lists.deallocate(); + bindValues.deallocate(); + parserStatus.deallocate(); + finalizeCallbacks.clear(); + states.clear(); + rootContext = 0; +} + // Must be called with a handle scope and context void QDeclarativeScriptData::initialize(QDeclarativeEngine *engine) { @@ -1242,6 +1261,16 @@ void **QDeclarativeVME::instructionJumpTable() bool QDeclarativeVME::complete(const Interrupt &interrupt) { + Q_ASSERT(engine || + (bindValues.isEmpty() && + parserStatus.isEmpty() && + componentAttached == 0 && + rootContext.isNull() && + finalizeCallbacks.isEmpty())); + + if (!engine) + return true; + ActiveVMERestorer restore(this, QDeclarativeEnginePrivate::get(engine)); while (!bindValues.isEmpty()) { @@ -1284,8 +1313,7 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt) return false; } - // XXX (what if its deleted?) - if (rootContext) + if (!rootContext.isNull()) rootContext->activeVME = 0; for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) { @@ -1298,6 +1326,8 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt) } finalizeCallbacks.clear(); + reset(); + return true; } @@ -1317,4 +1347,55 @@ void QDeclarativeVME::blank(QFiniteStack &pss) } } +QDeclarativeVMEGuard::QDeclarativeVMEGuard() +: m_objectCount(0), m_objects(0), m_contextCount(0), m_contexts(0) +{ +} + +QDeclarativeVMEGuard::~QDeclarativeVMEGuard() +{ + clear(); +} + +void QDeclarativeVMEGuard::guard(QDeclarativeVME *vme) +{ + clear(); + + m_objectCount = vme->objects.count(); + m_objects = new QDeclarativeGuard[m_objectCount]; + for (int ii = 0; ii < m_objectCount; ++ii) + m_objects[ii] = vme->objects[ii]; + + m_contextCount = (vme->rootContext.isNull())?0:1 + vme->states.count(); + m_contexts = new QDeclarativeGuardedContextData[m_contextCount]; + for (int ii = 0; ii < vme->states.count(); ++ii) + m_contexts[ii] = vme->states.at(ii).context; + if (!vme->rootContext.isNull()) + m_contexts[m_contextCount - 1] = vme->rootContext.contextData(); +} + +void QDeclarativeVMEGuard::clear() +{ + delete [] m_objects; + delete [] m_contexts; + + m_objectCount = 0; + m_objects = 0; + m_contextCount = 0; + m_contexts = 0; +} + +bool QDeclarativeVMEGuard::isOK() const +{ + for (int ii = 0; ii < m_objectCount; ++ii) + if (m_objects[ii].isNull()) + return false; + + for (int ii = 0; ii < m_contextCount; ++ii) + if (m_contexts[ii].isNull()) + return false; + + return true; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h index 80c02b1..771a2b4 100644 --- a/src/declarative/qml/qdeclarativevme_p.h +++ b/src/declarative/qml/qdeclarativevme_p.h @@ -120,11 +120,14 @@ public: void init(QDeclarativeContextData *, QDeclarativeCompiledData *, int start); bool initDeferred(QObject *); + void reset(); QObject *execute(QList *errors, const Interrupt & = Interrupt()); bool complete(const Interrupt & = Interrupt()); private: + friend class QDeclarativeVMEGuard; + QObject *run(QList *errors, const Interrupt & #ifdef QML_THREADED_VME_INTERPRETER , void ***storeJumpTable = 0 @@ -138,15 +141,19 @@ private: #endif QDeclarativeEngine *engine; + QFiniteStack objects; QFiniteStack lists; QFiniteStack bindValues; QFiniteStack parserStatus; - QDeclarativeContextData *rootContext; + QDeclarativeGuardedContextData rootContext; struct State { - State() : context(0), compiledData(0), instructionStream(0) {} + enum Flag { Deferred = 0x00000001 }; + + State() : flags(0), context(0), compiledData(0), instructionStream(0) {} + quint32 flags; QDeclarativeContextData *context; QDeclarativeCompiledData *compiledData; const char *instructionStream; @@ -159,6 +166,27 @@ private: static void blank(QFiniteStack &); }; +// Used to check that a QDeclarativeVME that is interrupted mid-execution +// is still valid. Checks all the objects and contexts have not been +// deleted. +class QDeclarativeVMEGuard +{ +public: + QDeclarativeVMEGuard(); + ~QDeclarativeVMEGuard(); + + void guard(QDeclarativeVME *); + void clear(); + + bool isOK() const; + +private: + int m_objectCount; + QDeclarativeGuard *m_objects; + int m_contextCount; + QDeclarativeGuardedContextData *m_contexts; +}; + QDeclarativeVME::Interrupt::Interrupt() : mode(None) { diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 9200e0f..c660054 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -389,7 +389,7 @@ void tst_qdeclarativeecmascript::methods() void tst_qdeclarativeecmascript::bindingLoop() { QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml")); - QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\""; + QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\""; QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); QObject *object = component.create(); QVERIFY(object != 0); diff --git a/tests/auto/declarative/qdeclarativeincubator/data/clear.qml b/tests/auto/declarative/qdeclarativeincubator/data/clear.qml new file mode 100644 index 0000000..f00f975 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/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/declarative/qdeclarativeincubator/data/objectDeleted.errors.txt b/tests/auto/declarative/qdeclarativeincubator/data/objectDeleted.errors.txt new file mode 100644 index 0000000..eeda289 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/data/objectDeleted.errors.txt @@ -0,0 +1 @@ +-1:-1:Object destroyed during incubation diff --git a/tests/auto/declarative/qdeclarativeincubator/data/objectDeleted.qml b/tests/auto/declarative/qdeclarativeincubator/data/objectDeleted.qml new file mode 100644 index 0000000..f00f975 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/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/declarative/qdeclarativeincubator/qdeclarativeincubator.pro b/tests/auto/declarative/qdeclarativeincubator/qdeclarativeincubator.pro new file mode 100644 index 0000000..35776a6 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/qdeclarativeincubator.pro @@ -0,0 +1,13 @@ +load(qttest_p4) +contains(QT_CONFIG,declarative): QT += declarative network widgets +macx:CONFIG -= app_bundle + +SOURCES += tst_qdeclarativeincubator.cpp \ + testtypes.cpp +HEADERS += testtypes.h + +DEFINES += SRCDIR=\\\"$$PWD\\\" + +CONFIG += parallel_test + +QT += core-private gui-private v8-private declarative-private diff --git a/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp b/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp new file mode 100644 index 0000000..c1f07ac --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/testtypes.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "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; +} + +void registerTypes() +{ + qmlRegisterType("Qt.test", 1,0, "SelfRegistering"); +} diff --git a/tests/auto/declarative/qdeclarativeincubator/testtypes.h b/tests/auto/declarative/qdeclarativeincubator/testtypes.h new file mode 100644 index 0000000..a023410 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/testtypes.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef TESTTYPES_H +#define TESTTYPES_H + +#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; +}; + +void registerTypes(); + +#endif // TESTTYPES_H diff --git a/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp new file mode 100644 index 0000000..25e6c6e --- /dev/null +++ b/tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp @@ -0,0 +1,239 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "testtypes.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +inline QUrl TEST_FILE(const QString &filename) +{ + QFileInfo fileInfo(__FILE__); + return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename)); +} + +inline QUrl TEST_FILE(const char *filename) +{ + return TEST_FILE(QLatin1String(filename)); +} + +class tst_qdeclarativeincubator : public QObject +{ + Q_OBJECT +public: + tst_qdeclarativeincubator() {} + +private slots: + void initTestCase(); + + void incubationMode(); + void objectDeleted(); + void clear(); + +private: + QDeclarativeIncubationController controller; + QDeclarativeEngine 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(QLatin1String(SRCDIR) + QLatin1String("/data/") + QLatin1String(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 QDeclarativeError &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_qdeclarativeincubator::initTestCase() +{ + registerTypes(); + engine.setIncubationController(&controller); +} + +void tst_qdeclarativeincubator::incubationMode() +{ + { + QDeclarativeIncubator incubator; + QCOMPARE(incubator.incubationMode(), QDeclarativeIncubator::Asynchronous); + } + { + QDeclarativeIncubator incubator(QDeclarativeIncubator::Asynchronous); + QCOMPARE(incubator.incubationMode(), QDeclarativeIncubator::Asynchronous); + } + { + QDeclarativeIncubator incubator(QDeclarativeIncubator::Synchronous); + QCOMPARE(incubator.incubationMode(), QDeclarativeIncubator::Synchronous); + } + { + QDeclarativeIncubator incubator(QDeclarativeIncubator::AsynchronousIfNested); + QCOMPARE(incubator.incubationMode(), QDeclarativeIncubator::AsynchronousIfNested); + } +} + +void tst_qdeclarativeincubator::objectDeleted() +{ + SelfRegisteringType::clearMe(); + + QDeclarativeComponent component(&engine, TEST_FILE("objectDeleted.qml")); + QVERIFY(component.isReady()); + + QDeclarativeIncubator incubator; + component.create(incubator); + + QCOMPARE(incubator.status(), QDeclarativeIncubator::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_qdeclarativeincubator::clear() +{ + SelfRegisteringType::clearMe(); + + QDeclarativeComponent component(&engine, TEST_FILE("clear.qml")); + QVERIFY(component.isReady()); + + // Clear in null state + { + QDeclarativeIncubator incubator; + QVERIFY(incubator.isNull()); + incubator.clear(); // no effect + QVERIFY(incubator.isNull()); + } + + // Clear in loading state + { + QDeclarativeIncubator incubator; + component.create(incubator); + QVERIFY(incubator.isLoading()); + incubator.clear(); + QVERIFY(incubator.isNull()); + } + + // Clear mid load + { + QDeclarativeIncubator 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 + { + QDeclarativeIncubator 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()); + } + + // XXX Clear in error state +} + +QTEST_MAIN(tst_qdeclarativeincubator) + +#include "tst_qdeclarativeincubator.moc"