aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp')
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp284
1 files changed, 284 insertions, 0 deletions
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
index f14db0a330..b732cd8193 100644
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
@@ -153,6 +153,7 @@ private slots:
void elementAssign();
void objectPassThroughSignals();
void booleanConversion();
+ void handleReferenceManagement();
void bug1();
void bug2();
@@ -188,6 +189,7 @@ private slots:
void realToInt();
void dynamicString();
void include();
+ void signalHandlers();
void callQtInvokables();
void invokableObjectArg();
@@ -687,6 +689,8 @@ void tst_qdeclarativeecmascript::attachedProperties()
QCOMPARE(object->property("b").toInt(), 26);
QCOMPARE(object->property("c").toInt(), 26);
QCOMPARE(object->property("d").toInt(), 26);
+
+ delete object;
}
{
@@ -3207,6 +3211,256 @@ void tst_qdeclarativeecmascript::booleanConversion()
delete object;
}
+void tst_qdeclarativeecmascript::handleReferenceManagement()
+{
+
+ int dtorCount = 0;
+ {
+ // Linear QObject reference
+ QDeclarativeEngine hrmEngine;
+ QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
+ cro->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object, "createReference");
+ QMetaObject::invokeMethod(object, "performGc");
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
+ delete object;
+ hrmEngine.collectGarbage();
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 3);
+ }
+
+ dtorCount = 0;
+ {
+ // Circular QObject reference
+ QDeclarativeEngine hrmEngine;
+ QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
+ cro->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object, "circularReference");
+ QMetaObject::invokeMethod(object, "performGc");
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
+ delete object;
+ hrmEngine.collectGarbage();
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 3);
+ }
+
+ dtorCount = 0;
+ {
+ // Linear handle reference
+ QDeclarativeEngine hrmEngine;
+ QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh != 0);
+ crh->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object, "createReference");
+ CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first != 0);
+ QVERIFY(second != 0);
+ first->addReference(QDeclarativeData::get(second)->v8object); // create reference
+ // now we have to reparent second and make second owned by JS.
+ second->setParent(0);
+ QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
+ QMetaObject::invokeMethod(object, "performGc");
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
+ delete object;
+ hrmEngine.collectGarbage();
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 3);
+ }
+
+ dtorCount = 0;
+ {
+ // Circular handle reference
+ QDeclarativeEngine hrmEngine;
+ QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh != 0);
+ crh->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object, "circularReference");
+ CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first != 0);
+ QVERIFY(second != 0);
+ first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
+ second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
+ // now we have to reparent and change ownership.
+ first->setParent(0);
+ second->setParent(0);
+ QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
+ QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
+ QMetaObject::invokeMethod(object, "performGc");
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
+ delete object;
+ hrmEngine.collectGarbage();
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 3);
+ }
+
+ dtorCount = 0;
+ {
+ // multiple engine interaction - linear reference
+ QDeclarativeEngine hrmEngine1;
+ QDeclarativeEngine hrmEngine2;
+ QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
+ QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
+ QObject *object1 = component1.create();
+ QObject *object2 = component2.create();
+ QVERIFY(object1 != 0);
+ QVERIFY(object2 != 0);
+ CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
+ CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh1 != 0);
+ QVERIFY(crh2 != 0);
+ crh1->setDtorCount(&dtorCount);
+ crh2->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object1, "createReference");
+ QMetaObject::invokeMethod(object2, "createReference");
+ CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first1 != 0);
+ QVERIFY(second1 != 0);
+ QVERIFY(first2 != 0);
+ QVERIFY(second2 != 0);
+ first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
+ // now we have to reparent second2 and make second2 owned by JS.
+ second2->setParent(0);
+ QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
+ QMetaObject::invokeMethod(object1, "performGc");
+ QMetaObject::invokeMethod(object2, "performGc");
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
+ delete object1;
+ delete object2;
+ hrmEngine1.collectGarbage();
+ hrmEngine2.collectGarbage();
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 6);
+ }
+
+ dtorCount = 0;
+ {
+ // multiple engine interaction - circular reference
+ QDeclarativeEngine hrmEngine1;
+ QDeclarativeEngine hrmEngine2;
+ QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
+ QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
+ QObject *object1 = component1.create();
+ QObject *object2 = component2.create();
+ QVERIFY(object1 != 0);
+ QVERIFY(object2 != 0);
+ CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
+ CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh1 != 0);
+ QVERIFY(crh2 != 0);
+ crh1->setDtorCount(&dtorCount);
+ crh2->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object1, "createReference");
+ QMetaObject::invokeMethod(object2, "createReference");
+ CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first1 != 0);
+ QVERIFY(second1 != 0);
+ QVERIFY(first2 != 0);
+ QVERIFY(second2 != 0);
+ first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
+ second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
+ second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
+ first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
+ // now we have to reparent and change ownership to JS.
+ first1->setParent(0);
+ second1->setParent(0);
+ first2->setParent(0);
+ second2->setParent(0);
+ QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
+ QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
+ QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
+ QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
+ QMetaObject::invokeMethod(object1, "performGc");
+ QMetaObject::invokeMethod(object2, "performGc");
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
+ delete object1;
+ delete object2;
+ hrmEngine1.collectGarbage();
+ hrmEngine2.collectGarbage();
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 6);
+ }
+
+ dtorCount = 0;
+ {
+ // multiple engine interaction - linear reference with engine deletion
+ QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
+ QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
+ QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
+ QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
+ QObject *object1 = component1.create();
+ QObject *object2 = component2.create();
+ QVERIFY(object1 != 0);
+ QVERIFY(object2 != 0);
+ CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
+ CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
+ QVERIFY(crh1 != 0);
+ QVERIFY(crh2 != 0);
+ crh1->setDtorCount(&dtorCount);
+ crh2->setDtorCount(&dtorCount);
+ QMetaObject::invokeMethod(object1, "createReference");
+ QMetaObject::invokeMethod(object2, "createReference");
+ CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
+ CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
+ QVERIFY(first1 != 0);
+ QVERIFY(second1 != 0);
+ QVERIFY(first2 != 0);
+ QVERIFY(second2 != 0);
+ first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
+ second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
+ second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
+ // now we have to reparent and change ownership to JS.
+ first1->setParent(crh1);
+ second1->setParent(0);
+ first2->setParent(0);
+ second2->setParent(0);
+ QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
+ QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
+ QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
+ QMetaObject::invokeMethod(object1, "performGc");
+ QMetaObject::invokeMethod(object2, "performGc");
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 0);
+ delete hrmEngine2;
+ QMetaObject::invokeMethod(object1, "performGc");
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 0);
+ delete object1;
+ delete object2;
+ hrmEngine1->collectGarbage();
+ QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCOMPARE(dtorCount, 6);
+ delete hrmEngine1;
+ }
+}
+
// Test that assigning a null object works
// Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
void tst_qdeclarativeecmascript::nullObjectBinding()
@@ -3597,6 +3851,36 @@ void tst_qdeclarativeecmascript::include()
}
}
+void tst_qdeclarativeecmascript::signalHandlers()
+{
+ QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+
+ QVERIFY(o->property("count").toInt() == 0);
+ QMetaObject::invokeMethod(o, "testSignalCall");
+ QCOMPARE(o->property("count").toInt(), 1);
+
+ QMetaObject::invokeMethod(o, "testSignalHandlerCall");
+ QCOMPARE(o->property("count").toInt(), 1);
+ QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
+
+ QVERIFY(o->property("funcCount").toInt() == 0);
+ QMetaObject::invokeMethod(o, "testSignalConnection");
+ QCOMPARE(o->property("funcCount").toInt(), 1);
+
+ QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
+ QCOMPARE(o->property("funcCount").toInt(), 2);
+
+ QMetaObject::invokeMethod(o, "testSignalDefined");
+ QCOMPARE(o->property("definedResult").toBool(), true);
+
+ QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
+ QCOMPARE(o->property("definedHandlerResult").toBool(), true);
+
+ delete o;
+}
+
void tst_qdeclarativeecmascript::qtbug_10696()
{
QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));