aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-10-03 15:45:51 +1000
committerQt by Nokia <qt-info@nokia.com>2011-10-03 11:43:03 +0200
commit95cd185fa4bfe872458988d0b5ffb36fd1b56bd3 (patch)
tree2e8091c278db670eddb09ebc060581ccb208d27e
parent0eec42dff07073d9e0cb955b0888f63e073f2a2a (diff)
QDeclarativeIncubator::clear() and autotests
Change-Id: I2a14c01c7f9412459572e9960cb95a4c24e068aa Task-number: QTBUG-21151 Reviewed-on: http://codereview.qt-project.org/5911 Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
-rw-r--r--src/declarative/qml/qdeclarativeincubator.cpp29
-rw-r--r--src/declarative/qml/qdeclarativeincubator_p.h1
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp119
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h32
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp2
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/data/clear.qml8
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/data/objectDeleted.errors.txt1
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/data/objectDeleted.qml8
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/qdeclarativeincubator.pro13
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/testtypes.cpp64
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/testtypes.h67
-rw-r--r--tests/auto/declarative/qdeclarativeincubator/tst_qdeclarativeincubator.cpp239
12 files changed, 556 insertions, 27 deletions
diff --git a/src/declarative/qml/qdeclarativeincubator.cpp b/src/declarative/qml/qdeclarativeincubator.cpp
index 053a026882..b6eb4e478a 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 <private/qdeclarativecompiler_p.h>
@@ -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 57c54d3a07..e736aabd5c 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 f8405be2db..bf8bd29c34 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<const QDeclarativeInstruction *>(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<QDeclarativeError> *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<QDeclarativeParserStatus *> &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<QObject>[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 80c02b1b89..771a2b4c21 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<QDeclarativeError> *errors, const Interrupt & = Interrupt());
bool complete(const Interrupt & = Interrupt());
private:
+ friend class QDeclarativeVMEGuard;
+
QObject *run(QList<QDeclarativeError> *errors, const Interrupt &
#ifdef QML_THREADED_VME_INTERPRETER
, void ***storeJumpTable = 0
@@ -138,15 +141,19 @@ private:
#endif
QDeclarativeEngine *engine;
+
QFiniteStack<QObject *> objects;
QFiniteStack<QDeclarativeVMETypes::List> lists;
QFiniteStack<QDeclarativeAbstractBinding *> bindValues;
QFiniteStack<QDeclarativeParserStatus *> 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<QDeclarativeAbstractBinding *> &);
};
+// 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<QObject> *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 9200e0f5f2..c66005435b 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 0000000000..f00f975923
--- /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 0000000000..eeda289d35
--- /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 0000000000..f00f975923
--- /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 0000000000..35776a6889
--- /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 0000000000..c1f07acb76
--- /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 <QtDeclarative/qdeclarative.h>
+
+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<SelfRegisteringType>("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 0000000000..a023410d1a
--- /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 <QtCore/qobject.h>
+
+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 0000000000..25e6c6ef52
--- /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 <QUrl>
+#include <QDir>
+#include <QDebug>
+#include <qtest.h>
+#include <QPointer>
+#include <QFileInfo>
+#include <QDeclarativeEngine>
+#include <QDeclarativeComponent>
+#include <QDeclarativeIncubator>
+
+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<QByteArray> expected = data.split('\n'); \
+ expected.removeAll(QByteArray("")); \
+ QList<QDeclarativeError> errors = component.errors(); \
+ QList<QByteArray> 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<SelfRegisteringType> 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<QObject> 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"