/****************************************************************************
**
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
**
** This file is part of the test suite of the Qt Toolkit.
**
**
**
**
+**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QPointer>
#include <QFileInfo>
#include <QDeclarativeEngine>
+#include <QDeclarativeContext>
#include <QDeclarativeProperty>
#include <QDeclarativeComponent>
#include <QDeclarativeIncubator>
-#include "../shared/util.h"
-#include "../../../shared/util.h"
-
-inline QUrl TEST_FILE(const QString &filename)
-{
- return QUrl::fromLocalFile(TESTDATA(filename));
-}
-
-inline QUrl TEST_FILE(const char *filename)
-{
- return TEST_FILE(QLatin1String(filename));
-}
+#include "../../shared/util.h"
-class tst_qdeclarativeincubator : public QObject
+class tst_qdeclarativeincubator : public QDeclarativeDataTest
{
Q_OBJECT
public:
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:
QDeclarativeIncubationController controller;
QVERIFY(!component.isError()); \
QVERIFY(component.errors().isEmpty()); \
} else { \
- QFile file(TESTDATA(errorfile)); \
+ QFile file(QDeclarativeDataTest::instance()->testFile(errorfile)); \
QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); \
QByteArray data = file.readAll(); \
file.close(); \
void tst_qdeclarativeincubator::initTestCase()
{
+ QDeclarativeDataTest::initTestCase();
registerTypes();
engine.setIncubationController(&controller);
}
{
SelfRegisteringType::clearMe();
- QDeclarativeComponent component(&engine, TEST_FILE("objectDeleted.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("objectDeleted.qml"));
QVERIFY(component.isReady());
QDeclarativeIncubator incubator;
{
SelfRegisteringType::clearMe();
- QDeclarativeComponent component(&engine, TEST_FILE("clear.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("clear.qml"));
QVERIFY(component.isReady());
// Clear in null state
// All incubators should behave synchronously when there is no controller
QDeclarativeEngine engine;
- QDeclarativeComponent component(&engine, TEST_FILE("noIncubationController.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("noIncubationController.qml"));
QVERIFY(component.isReady());
void tst_qdeclarativeincubator::forceCompletion()
{
- QDeclarativeComponent component(&engine, TEST_FILE("forceCompletion.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("forceCompletion.qml"));
QVERIFY(component.isReady());
{
void tst_qdeclarativeincubator::setInitialState()
{
- QDeclarativeComponent component(&engine, TEST_FILE("setInitialState.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("setInitialState.qml"));
QVERIFY(component.isReady());
struct MyIncubator : public QDeclarativeIncubator
CompletionRegisteringType::clearMe();
SelfRegisteringType::clearMe();
- QDeclarativeComponent component(&engine, TEST_FILE("clearDuringCompletion.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("clearDuringCompletion.qml"));
QVERIFY(component.isReady());
QDeclarativeIncubator incubator;
QPointer<QObject> srt = SelfRegisteringType::me();
incubator.clear();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QVERIFY(incubator.isNull());
QVERIFY(srt.isNull());
}
+void tst_qdeclarativeincubator::objectDeletionAfterInit()
+{
+ QDeclarativeComponent component(&engine, testFileUrl("clear.qml"));
+ QVERIFY(component.isReady());
+
+ struct MyIncubator : public QDeclarativeIncubator
+ {
+ MyIncubator(QDeclarativeIncubator::IncubationMode mode)
+ : QDeclarativeIncubator(mode), obj(0) {}
+
+ virtual void setInitialState(QObject *o) {
+ obj = o;
+ }
+
+ QObject *obj;
+ };
+
+ SelfRegisteringType::clearMe();
+ MyIncubator incubator(QDeclarativeIncubator::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
void start()
{
incubator = new MyIncubator(QDeclarativeIncubator::Synchronous, this);
- component = new QDeclarativeComponent(engine, TEST_FILE("recursiveClear.1.qml"));
+ component = new QDeclarativeComponent(engine, QDeclarativeDataTest::instance()->testFileUrl("recursiveClear.1.qml"));
component->create(*incubator);
}
void switchIt() {
component->deleteLater();
incubator->clear();
- component = new QDeclarativeComponent(engine, TEST_FILE("recursiveClear.2.qml"));
+ component = new QDeclarativeComponent(engine, QDeclarativeDataTest::instance()->testFileUrl("recursiveClear.2.qml"));
component->create(*incubator);
}
};
};
{
- QDeclarativeComponent component(&engine, TEST_FILE("statusChanged.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("statusChanged.qml"));
QVERIFY(component.isReady());
MyIncubator incubator(QDeclarativeIncubator::Synchronous);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("statusChanged.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("statusChanged.qml"));
QVERIFY(component.isReady());
MyIncubator incubator(QDeclarativeIncubator::Asynchronous);
}
{
- QDeclarativeComponent component2(&engine, TEST_FILE("statusChanged.nested.qml"));
+ QDeclarativeComponent component2(&engine, testFileUrl("statusChanged.nested.qml"));
QVERIFY(component2.isReady());
MyIncubator incubator(QDeclarativeIncubator::Asynchronous);
{
// Asynchronous if nested within a finalized context behaves synchronously
{
- QDeclarativeComponent component(&engine, TEST_FILE("asynchronousIfNested.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("asynchronousIfNested.1.qml"));
QVERIFY(component.isReady());
QObject *object = component.create();
{
SelfRegisteringType::clearMe();
- QDeclarativeComponent component(&engine, TEST_FILE("asynchronousIfNested.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("asynchronousIfNested.2.qml"));
QVERIFY(component.isReady());
QDeclarativeIncubator incubator;
{
SelfRegisteringType::clearMe();
- QDeclarativeComponent component(&engine, TEST_FILE("asynchronousIfNested.3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("asynchronousIfNested.3.qml"));
QVERIFY(component.isReady());
struct CallbackData {
static void callback(CallbackRegisteringType *o, void *data) {
CallbackData *d = (CallbackData *)data;
- QDeclarativeComponent c(d->engine, TEST_FILE("asynchronousIfNested.1.qml"));
+ QDeclarativeComponent c(d->engine, QDeclarativeDataTest::instance()->testFileUrl("asynchronousIfNested.1.qml"));
if (!c.isReady()) return;
QDeclarativeIncubator incubator(QDeclarativeIncubator::AsynchronousIfNested);
void tst_qdeclarativeincubator::nestedComponent()
{
- QDeclarativeComponent component(&engine, TEST_FILE("nestedComponent.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("nestedComponent.qml"));
QVERIFY(component.isReady());
QObject *object = component.create();
{
SelfRegisteringType::clearMe();
- QDeclarativeComponent component(&engine, TEST_FILE("chainedAsynchronousIfNested.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("chainedAsynchronousIfNested.qml"));
QVERIFY(component.isReady());
QDeclarativeIncubator incubator(QDeclarativeIncubator::Asynchronous);
QVERIFY(incubator2.isReady());
}
+// Checks that new AsynchronousIfNested incubators can be correctly chained if started in
+// componentCompleted().
+void tst_qdeclarativeincubator::chainedAsynchronousIfNestedOnCompleted()
+{
+ SelfRegisteringType::clearMe();
+
+ QDeclarativeComponent component(&engine, testFileUrl("chainInCompletion.qml"));
+ QVERIFY(component.isReady());
+
+ QDeclarativeComponent c1(&engine, testFileUrl("chainedAsynchronousIfNested.qml"));
+ QVERIFY(c1.isReady());
+
+ struct MyIncubator : public QDeclarativeIncubator {
+ MyIncubator(MyIncubator *next, QDeclarativeComponent *component, QDeclarativeContext *ctxt)
+ : QDeclarativeIncubator(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;
+ QDeclarativeComponent *component;
+ QDeclarativeContext *ctxt;
+ };
+
+ struct CallbackData {
+ CallbackData(QDeclarativeComponent *c, MyIncubator *i, QDeclarativeContext *ct)
+ : component(c), incubator(i), ctxt(ct) {}
+ QDeclarativeComponent *component;
+ MyIncubator *incubator;
+ QDeclarativeContext *ctxt;
+ static void callback(CompletionCallbackType *, void *data) {
+ CallbackData *d = (CallbackData *)data;
+ d->component->create(*d->incubator, 0, d->ctxt);
+ }
+ };
+
+ QDeclarativeIncubator incubator(QDeclarativeIncubator::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_qdeclarativeincubator::selfDelete()
{
struct MyIncubator : public QDeclarativeIncubator {
};
{
- QDeclarativeComponent component(&engine, TEST_FILE("selfDelete.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("selfDelete.qml"));
#define DELETE_TEST(status, mode) { \
bool done = false; \
{
SelfRegisteringType::clearMe();
- QDeclarativeComponent component(&engine, TEST_FILE("objectDeleted.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("objectDeleted.qml"));
QVERIFY(component.isReady());
bool done = false;
}
}
+// Test that QML doesn't crash if the context is deleted prior to the incubator
+// first executing.
+void tst_qdeclarativeincubator::contextDelete()
+{
+ QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
+ QDeclarativeComponent component(&engine, testFileUrl("contextDelete.qml"));
+
+ QDeclarativeIncubator incubator;
+ component.create(incubator, context);
+
+ delete context;
+
+ {
+ bool b = false;
+ controller.incubateWhile(&b);
+ }
+}
+
QTEST_MAIN(tst_qdeclarativeincubator)
#include "tst_qdeclarativeincubator.moc"