/****************************************************************************
**
-** 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 <QtCore/qdir.h>
#include <QtCore/qnumeric.h>
#include <private/qdeclarativeengine_p.h>
-#include <private/qv8gccallback_p.h>
#include <private/qdeclarativevmemetaobject_p.h>
#include <private/qv4compiler_p.h>
#include "testtypes.h"
#include "testhttpserver.h"
-#include "../shared/util.h"
+#include "../../shared/util.h"
/*
This test covers evaluation of ECMAScript expressions and bindings from within
Static QML language issues are covered in qmllanguage
*/
-inline QUrl TEST_FILE(const QString &filename)
-{
- return QUrl::fromLocalFile(TESTDATA(filename));
-}
-inline QUrl TEST_FILE(const char *filename)
-{
- return TEST_FILE(QLatin1String(filename));
-}
-
-class tst_qdeclarativeecmascript : public QObject
+class tst_qdeclarativeecmascript : public QDeclarativeDataTest
{
Q_OBJECT
public:
void objectHasOwnProperty();
void selfDeletingBinding();
void extendedObjectPropertyLookup();
+ void extendedObjectPropertyLookup2();
void scriptErrors();
void functionErrors();
void propertyAssignmentErrors();
void signalWithJSValueInVariant();
void signalWithJSValueInVariant_twoEngines_data();
void signalWithJSValueInVariant_twoEngines();
+ void signalWithQJSValue_data();
+ void signalWithQJSValue();
void moduleApi_data();
void moduleApi();
void importScripts_data();
void importScripts();
void scarceResources();
+ void scarceResources_data();
+ void scarceResources_other();
void propertyChangeSlots();
void propertyVar_data();
void propertyVar();
void sequenceConversionThreads();
void sequenceConversionBindings();
void sequenceConversionCopy();
+ void assignSequenceTypes();
+ void qtbug_22464();
+ void qtbug_21580();
void bug1();
void bug2();
void qtbug_10696();
void qtbug_11606();
void qtbug_11600();
+ void qtbug_21864();
+ void qobjectConnectionListExceptionHandling();
void nonscriptable();
void deleteLater();
void in();
void aliasWritesOverrideBindings();
void aliasToCompositeElement();
void realToInt();
+ void urlProperty();
+ void urlPropertyWithEncoding();
+ void urlListPropertyWithEncoding();
void dynamicString();
void include();
void signalHandlers();
void invokableObjectArg();
void invokableObjectRet();
void qtbug_20344();
+ void qtbug_22679();
+ void qtbug_22843_data();
+ void qtbug_22843();
void revisionErrors();
void revision();
void automaticSemicolon();
+ void unaryExpression();
+ void switchStatement();
+ void withStatement();
+ void tryStatement();
private:
static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
QDeclarativeEngine engine;
};
-void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
+void tst_qdeclarativeecmascript::initTestCase()
+{
+ QDeclarativeDataTest::initTestCase();
+ registerTypes();
+}
void tst_qdeclarativeecmascript::assignBasicTypes()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
delete object;
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
void tst_qdeclarativeecmascript::idShortcutInvalidates()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QVERIFY(object->objectProperty() != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QVERIFY(object->objectProperty() != 0);
void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->stringProperty(), QLatin1String("pass"));
delete object;
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->stringProperty(), QLatin1String("pass"));
void tst_qdeclarativeecmascript::signalAssignment()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->string(), QString());
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->string(), QString());
void tst_qdeclarativeecmascript::methods()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("methods.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->methodCalled(), false);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("methods.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QCOMPARE(object->methodCalled(), false);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("methods.3.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("test").toInt(), 19);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("methods.4.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("test").toInt(), 19);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("methods.5.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("test").toInt(), 9);
void tst_qdeclarativeecmascript::bindingLoop()
{
- QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("bindingLoop.qml"));
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();
void tst_qdeclarativeecmascript::deferredProperties()
{
- QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("deferredProperties.qml"));
MyDeferredObject *object =
qobject_cast<MyDeferredObject *>(component.create());
QVERIFY(object != 0);
// Check errors on deferred properties are correctly emitted
void tst_qdeclarativeecmascript::deferredPropertiesErrors()
{
- QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
MyDeferredObject *object =
qobject_cast<MyDeferredObject *>(component.create());
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::extensionObjects()
{
- QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("extensionObjects.qml"));
MyExtendedObject *object =
qobject_cast<MyExtendedObject *>(component.create());
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::overrideExtensionProperties()
{
- QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
OverrideDefaultPropertyObject *object =
qobject_cast<OverrideDefaultPropertyObject *>(component.create());
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::attachedProperties()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("a").toInt(), 19);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("a").toInt(), 26);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
{
// Existent enums
{
- QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("enums.1.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
}
// Non-existent enums
{
- QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("enums.2.qml"));
QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
void tst_qdeclarativeecmascript::valueTypeFunctions()
{
- QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
QVERIFY(obj != 0);
QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
{
// From ECMAScript
{
- QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
// During construction
{
- QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
#if 0
// From C++
{
- QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.3.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
// Using an alias
{
- QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
{
QDeclarativeComponent component(&engine,
- TEST_FILE("outerBindingOverridesInnerBinding.qml"));
+ testFileUrl("outerBindingOverridesInnerBinding.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
*/
void tst_qdeclarativeecmascript::nonExistentAttachedObject()
{
- QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
void tst_qdeclarativeecmascript::scope()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scope.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scope.2.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scope.3.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// Signal argument scope
{
- QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scope.4.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scope.5.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scope.6.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// importing context
void tst_qdeclarativeecmascript::importScope()
{
- QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("importScope.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
*/
void tst_qdeclarativeecmascript::signalParameterTypes()
{
- QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
*/
void tst_qdeclarativeecmascript::objectsCompareAsEqual()
{
- QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
*/
void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
{
- QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QObject *object = 0;
// test that a manual write (of undefined) to a resettable aliased property succeeds
- QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
+ QDeclarativeComponent c1(&engine, testFileUrl("aliasreset/aliasPropertyReset.1.qml"));
object = c1.create();
QVERIFY(object != 0);
QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
delete object;
// test that a manual write (of undefined) to a resettable alias property succeeds
- QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
+ QDeclarativeComponent c2(&engine, testFileUrl("aliasreset/aliasPropertyReset.2.qml"));
object = c2.create();
QVERIFY(object != 0);
QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
delete object;
// test that an alias to a bound property works correctly
- QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
+ QDeclarativeComponent c3(&engine, testFileUrl("aliasreset/aliasPropertyReset.3.qml"));
object = c3.create();
QVERIFY(object != 0);
QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
// test that a manual write (of undefined) to a resettable alias property
// whose aliased property's object has been deleted, does not crash.
- QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
+ QDeclarativeComponent c4(&engine, testFileUrl("aliasreset/aliasPropertyReset.4.qml"));
object = c4.create();
QVERIFY(object != 0);
QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
delete object;
// test that binding an alias property to an undefined value works correctly
- QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
+ QDeclarativeComponent c5(&engine, testFileUrl("aliasreset/aliasPropertyReset.5.qml"));
object = c5.create();
QVERIFY(object != 0);
QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
delete object;
// test that a manual write (of undefined) to a non-resettable property fails properly
- QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
+ QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
QDeclarativeComponent e1(&engine, url);
object = e1.create();
QFETCH(QString, method);
QFETCH(QString, createdName);
- QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::dynamicDestruction()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
QDeclarativeGuard<QObject> createdQmlObject = 0;
QMetaObject::invokeMethod(object, "killOther");
QVERIFY(createdQmlObject);
- QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
+
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QVERIFY(createdQmlObject);
for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
if (createdQmlObject) {
QTest::qWait(100);
- QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
}
}
QVERIFY(!createdQmlObject);
QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
QMetaObject::invokeMethod(object, "killMe");
QVERIFY(object);
- QTest::qWait(0);
- QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QVERIFY(!object);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
QMetaObject::invokeMethod(o, "destroy");
- QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
*/
void tst_qdeclarativeecmascript::objectToString()
{
- QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("declarativeToString.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "testToString");
*/
void tst_qdeclarativeecmascript::objectHasOwnProperty()
{
- QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
+ QUrl url = testFileUrl("declarativeHasOwnProperty.qml");
QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
void tst_qdeclarativeecmascript::selfDeletingBinding()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
object->setProperty("triggerDelete", true);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
object->setProperty("triggerDelete", true);
*/
void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
{
- QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
delete object;
}
/*
+Test that extended object properties can be accessed correctly.
+*/
+void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
+{
+ QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QVariant returnValue;
+ QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
+ QCOMPARE(returnValue.toInt(), 42);
+
+ delete object;
+}
+/*
Test file/lineNumbers for binding/Script errors.
*/
void tst_qdeclarativeecmascript::scriptErrors()
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptErrors.qml"));
QString url = component.url().toString();
QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
- QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
- QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
- QString warning6 = url + ":7: Unable to assign [undefined] to int";
- QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
- QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
+ QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
+ QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
+ QString warning6 = url + ":10: Unable to assign [undefined] to int";
+ QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
+ QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
*/
void tst_qdeclarativeecmascript::functionErrors()
{
- QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("functionErrors.qml"));
QString url = component.url().toString();
QString warning = url + ":5: Error: Invalid write to global property \"a\"";
delete object;
// test that if an exception occurs while invoking js function from cpp, it is reported as expected.
- QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
+ QDeclarativeComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
url = componentTwo.url().toString();
object = componentTwo.create();
QVERIFY(object != 0);
QString srpname = object->property("srp_name").toString();
- warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
- QLatin1String(" is not a function");
+ warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
+ + QLatin1String(" is not a function");
QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
QMetaObject::invokeMethod(object, "retrieveScarceResource");
delete object;
*/
void tst_qdeclarativeecmascript::propertyAssignmentErrors()
{
- QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
QString url = component.url().toString();
*/
void tst_qdeclarativeecmascript::signalTriggeredBindings()
{
- QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
*/
void tst_qdeclarativeecmascript::listProperties()
{
- QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("listProperties.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
{
- QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
QString url = component.url().toString();
QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
{
- QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
QString url = component.url().toString();
QString warning = component.url().toString() + ":6: Error: JS exception";
void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
{
- QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
QString url = component.url().toString();
QString warning = component.url().toString() + ":5: Error: JS exception";
void tst_qdeclarativeecmascript::transientErrors()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
transientErrorsMsgCount = 0;
QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
// One binding erroring multiple times, but then resolving
{
- QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
transientErrorsMsgCount = 0;
QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
// Check that errors during shutdown are minimized
void tst_qdeclarativeecmascript::shutdownErrors()
{
- QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::compositePropertyType()
{
- QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
+
QTest::ignoreMessage(QtDebugMsg, "hello world");
QObject *object = qobject_cast<QObject *>(component.create());
delete object;
// QTBUG-5759
void tst_qdeclarativeecmascript::jsObject()
{
- QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::undefinedResetsProperty()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
delete object;
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
}
}
+// Aliases to variant properties should work
+void tst_qdeclarativeecmascript::qtbug_22464()
+{
+ QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
+void tst_qdeclarativeecmascript::qtbug_21580()
+{
+ QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
+
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->property("test").toBool(), true);
+
+ delete object;
+}
+
// QTBUG-6781
void tst_qdeclarativeecmascript::bug1()
{
- QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// Don't crash in createObject when the component has errors.
void tst_qdeclarativeecmascript::dynamicCreationCrash()
{
- QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
// allow the engine to go out of scope too.
{
QDeclarativeEngine dcoEngine;
- QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
+ QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
QMetaObject::invokeMethod(object, "performGc");
}
if (i % 10 == 0) {
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
}
}
delete object;
}
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QCOMPARE(dtorCount, expectedDtorCount);
}
-//QTBUG-9367
void tst_qdeclarativeecmascript::regExpBug()
{
- QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
- delete object;
+ //QTBUG-9367
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
+ delete object;
+ }
+
+ //QTBUG-23068
+ {
+ QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
+ QDeclarativeComponent component(&engine, testFileUrl("regExp.2.qml"));
+ QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(!object);
+ QCOMPARE(component.errorString(), err);
+ }
}
static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
// QTBUG-13047 (check that you can pass registered object types as args)
void tst_qdeclarativeecmascript::invokableObjectArg()
{
- QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
QObject *o = component.create();
QVERIFY(o);
// QTBUG-13047 (check that you can return registered object types from methods)
void tst_qdeclarativeecmascript::invokableObjectRet()
{
- QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
QObject *o = component.create();
QVERIFY(o);
// QTBUG-5675
void tst_qdeclarativeecmascript::listToVariant()
{
- QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
MyQmlContainer container;
Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
void tst_qdeclarativeecmascript::listAssignment()
{
- QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
QObject *obj = component.create();
QCOMPARE(obj->property("list1length").toInt(), 2);
QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
QDeclarativeEngine e1;
e1.rootContext()->setContextProperty("thing", &obj);
- QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
+ QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
QDeclarativeEngine e2;
e2.rootContext()->setContextProperty("thing", &obj);
- QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
+ QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
QObject *o1 = c1.create();
QObject *o2 = c2.create();
// Test that references to QObjects are cleanup when the object is destroyed
void tst_qdeclarativeecmascript::deletedObject()
{
- QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
QObject *object = component.create();
void tst_qdeclarativeecmascript::attachedPropertyScope()
{
- QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::scriptConnect()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::scriptDisconnect()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
delete object;
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
context->setContextObject(&own);
{
- QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
QVERIFY(own.object != 0);
engine.collectGarbage();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QVERIFY(own.object == 0);
own.object = new QObject(&own);
{
- QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
QVERIFY(own.object != 0);
engine.collectGarbage();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QVERIFY(own.object != 0);
delete object;
}
- QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QVERIFY(source.value != 0);
}
}
engine.collectGarbage();
- QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QVERIFY(source.value == 0);
}
QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
context->setContextObject(&obj);
- QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
QObject *object = component.create(context);
// QTBUG-9205
void tst_qdeclarativeecmascript::strictlyEquals()
{
- QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::compiled()
{
- QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// Test that numbers assigned in bindings as strings work consistently
void tst_qdeclarativeecmascript::numberAssignment()
{
- QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::propertySplicing()
{
- QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// QTBUG-16683
void tst_qdeclarativeecmascript::signalWithUnknownTypes()
{
- QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(object != 0);
QFETCH(QString, expression);
QFETCH(QString, compare);
- QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != 0);
QFETCH(QString, expression);
QFETCH(QString, compare);
- QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
QVERIFY(object != 0);
QVERIFY(!object->property("pass").toBool());
}
+void tst_qdeclarativeecmascript::signalWithQJSValue_data()
+{
+ signalWithJSValueInVariant_data();
+}
+
+void tst_qdeclarativeecmascript::signalWithQJSValue()
+{
+ QFETCH(QString, expression);
+ QFETCH(QString, compare);
+
+ QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
+ QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
+ QVERIFY(object != 0);
+
+ QJSValue value = engine.evaluate(expression);
+ QVERIFY(!engine.hasUncaughtException());
+ object->setProperty("expression", expression);
+ object->setProperty("compare", compare);
+ object->setProperty("pass", false);
+
+ emit object->signalWithQJSValue(value);
+
+ QVERIFY(object->property("pass").toBool());
+ QVERIFY(object->qjsvalue().strictlyEquals(value));
+}
+
void tst_qdeclarativeecmascript::moduleApi_data()
{
QTest::addColumn<QUrl>("testfile");
QTest::addColumn<QVariantList>("readBackExpectedValues");
QTest::newRow("qobject, register + read + method")
- << TEST_FILE("moduleapi/qobjectModuleApi.qml")
+ << testFileUrl("moduleapi/qobjectModuleApi.qml")
<< QString()
<< QStringList()
<< (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
<< QVariantList();
QTest::newRow("script, register + read")
- << TEST_FILE("moduleapi/scriptModuleApi.qml")
+ << testFileUrl("moduleapi/scriptModuleApi.qml")
<< QString()
<< QStringList()
<< (QStringList() << "scriptTest")
<< QVariantList();
QTest::newRow("qobject, caching + read")
- << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
+ << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
<< QString()
<< QStringList()
<< (QStringList() << "existingUriTest" << "qobjectParentedTest")
<< QVariantList();
QTest::newRow("script, caching + read")
- << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
+ << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
<< QString()
<< QStringList()
<< (QStringList() << "scriptTest")
<< QVariantList();
QTest::newRow("qobject, writing + readonly constraints")
- << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
+ << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
<< QString()
- << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
<< (QStringList() << "readOnlyProperty" << "writableProperty")
<< (QVariantList() << 20 << 50)
<< (QStringList() << "firstProperty" << "writableProperty")
<< (QVariantList() << 20 << 30);
QTest::newRow("script, writing + readonly constraints")
- << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
+ << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
<< QString()
- << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
<< (QStringList() << "readBack" << "unchanged")
<< (QVariantList() << 13 << 42)
<< (QStringList() << "firstProperty" << "secondProperty")
<< (QVariantList() << 30 << 42);
QTest::newRow("qobject module API enum values in JS")
- << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
+ << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
<< QString()
<< QStringList()
<< (QStringList() << "enumValue" << "enumMethod")
<< QVariantList();
QTest::newRow("qobject, invalid major version fail")
- << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
+ << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
<< QString("QDeclarativeComponent: Component is not ready")
<< QStringList()
<< QStringList()
<< QVariantList();
QTest::newRow("qobject, invalid minor version fail")
- << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
+ << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
<< QString("QDeclarativeComponent: Component is not ready")
<< QStringList()
<< QStringList()
QTest::addColumn<QVariantList>("propertyValues");
QTest::newRow("basic functionality")
- << TEST_FILE("jsimport/testImport.qml")
+ << testFileUrl("jsimport/testImport.qml")
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("importedScriptStringValue")
<< QVariant(2));
QTest::newRow("import scoping")
- << TEST_FILE("jsimport/testImportScoping.qml")
+ << testFileUrl("jsimport/testImportScoping.qml")
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("componentError"))
<< (QVariantList() << QVariant(5));
QTest::newRow("parent scope shouldn't be inherited by import with imports")
- << TEST_FILE("jsimportfail/failOne.qml")
+ << testFileUrl("jsimportfail/failOne.qml")
<< QString()
- << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
<< (QStringList() << QLatin1String("importScriptFunctionValue"))
<< (QVariantList() << QVariant(QString()));
QTest::newRow("javascript imports in an import should be private to the import scope")
- << TEST_FILE("jsimportfail/failTwo.qml")
+ << testFileUrl("jsimportfail/failTwo.qml")
<< QString()
- << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
<< (QStringList() << QLatin1String("importScriptFunctionValue"))
<< (QVariantList() << QVariant(QString()));
QTest::newRow("module imports in an import should be private to the import scope")
- << TEST_FILE("jsimportfail/failThree.qml")
+ << testFileUrl("jsimportfail/failThree.qml")
<< QString()
- << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
<< (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
<< (QVariantList() << QVariant(false));
QTest::newRow("typenames in an import should be private to the import scope")
- << TEST_FILE("jsimportfail/failFour.qml")
+ << testFileUrl("jsimportfail/failFour.qml")
<< QString()
- << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
<< (QStringList() << QLatin1String("importedModuleEnumValue"))
<< (QVariantList() << QVariant(0));
QTest::newRow("import with imports has it's own activation scope")
- << TEST_FILE("jsimportfail/failFive.qml")
+ << testFileUrl("jsimportfail/failFive.qml")
<< QString()
- << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
- << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
+ << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
+ << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
<< (QStringList() << QLatin1String("componentError"))
<< (QVariantList() << QVariant(0));
QTest::newRow("import pragma library script")
- << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
+ << testFileUrl("jsimport/testImportPragmaLibrary.qml")
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("testValue"))
<< (QVariantList() << QVariant(31));
QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
- << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
+ << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("testValue"))
<< (QVariantList() << QVariant(0));
QTest::newRow("import pragma library script which has an import")
- << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
+ << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("testValue"))
<< (QVariantList() << QVariant(55));
QTest::newRow("import pragma library script which has a pragma library import")
- << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
+ << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
<< QString()
<< QStringList()
<< (QStringList() << QLatin1String("testValue"))
}
}
-void tst_qdeclarativeecmascript::scarceResources()
+void tst_qdeclarativeecmascript::scarceResources_other()
{
+ /* These tests require knowledge of state, since we test values after
+ performing signal or function invocation. */
+
QPixmap origPixmap(100, 100);
origPixmap.fill(Qt::blue);
-
+ QString srp_name, expectedWarning;
QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
ScarceResourceObject *eo = 0;
+ QObject *srsc = 0;
QObject *object = 0;
- // in the following three cases, the instance created from the component
- // has a property which is a copy of the scarce resource; hence, the
- // resource should NOT be detached prior to deletion of the object instance,
- // unless the resource is destroyed explicitly.
- QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
- object = component.create();
- QVERIFY(object != 0);
- QVERIFY(object->property("scarceResourceCopy").isValid());
- QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ /* property var semantics */
+
+ // test that scarce resources are handled properly in signal invocation
+ QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
+ object = varComponentTen.create();
+ srsc = object->findChild<QObject*>("srsc");
+ QVERIFY(srsc);
+ QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
+ QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QMetaObject::invokeMethod(srsc, "testSignal");
+ QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
+ QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
+ QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
+ QVERIFY(srsc->property("scarceResourceCopy").isValid());
+ QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
+ QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
delete object;
- QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
- object = componentTwo.create();
+ // test that scarce resources are handled properly from js functions in qml files
+ QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
+ object = varComponentEleven.create();
QVERIFY(object != 0);
- QVERIFY(object->property("scarceResourceCopy").isValid());
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
- delete object;
-
- QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
- object = componentThree.create();
- QVERIFY(object != 0);
- QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
+ QMetaObject::invokeMethod(object, "releaseScarceResource");
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
- delete object;
-
- // in the following three cases, no other copy should exist in memory,
- // and so it should be detached (unless explicitly preserved).
- QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
- object = componentFour.create();
- QVERIFY(object != 0);
- QVERIFY(object->property("scarceResourceTest").isValid());
- QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
delete object;
- QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
- object = componentFive.create();
+ // test that if an exception occurs while invoking js function from cpp, that the resources are released.
+ QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
+ object = varComponentTwelve.create();
QVERIFY(object != 0);
- QVERIFY(object->property("scarceResourceTest").isValid());
- QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
- delete object;
-
- QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
- object = componentSix.create();
- QVERIFY(object != 0);
- QVERIFY(object->property("scarceResourceTest").isValid());
- QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
+ srp_name = object->property("srp_name").toString();
+ expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
+ QMetaObject::invokeMethod(object, "retrieveScarceResource");
+ QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
- delete object;
-
- // test that scarce resources are handled correctly for imports
- QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
- object = componentSeven.create();
- QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
- QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
- delete object;
-
- QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
- object = componentEight.create();
- QVERIFY(object != 0);
- QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
+ QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
delete object;
- QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
- object = componentNine.create();
+ // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
+ // that the scarce resource is removed from the engine's list of scarce resources to clean up.
+ QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
+ object = varComponentThirteen.create();
QVERIFY(object != 0);
- QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
- QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
- QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
- QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
- QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
- QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
+ QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
+ QMetaObject::invokeMethod(object, "assignVarProperty");
+ QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
+ QMetaObject::invokeMethod(object, "deassignVarProperty");
+ QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
delete object;
+ /* property variant semantics */
+
// test that scarce resources are handled properly in signal invocation
- QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
- object = componentTen.create();
+ QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
+ object = variantComponentTen.create();
QVERIFY(object != 0);
- QObject *srsc = object->findChild<QObject*>("srsc");
+ srsc = object->findChild<QObject*>("srsc");
QVERIFY(srsc);
QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
delete object;
// test that scarce resources are handled properly from js functions in qml files
- QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
- object = componentEleven.create();
+ QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
+ object = variantComponentEleven.create();
QVERIFY(object != 0);
QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
delete object;
// test that if an exception occurs while invoking js function from cpp, that the resources are released.
- QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
- object = componentTwelve.create();
+ QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
+ object = variantComponentTwelve.create();
QVERIFY(object != 0);
QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QString srp_name = object->property("srp_name").toString();
- QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
+ srp_name = object->property("srp_name").toString();
+ expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
QMetaObject::invokeMethod(object, "retrieveScarceResource");
QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
delete object;
}
+void tst_qdeclarativeecmascript::scarceResources_data()
+{
+ QTest::addColumn<QUrl>("qmlFile");
+ QTest::addColumn<bool>("readDetachStatus");
+ QTest::addColumn<bool>("expectedDetachStatus");
+ QTest::addColumn<QStringList>("propertyNames");
+ QTest::addColumn<QVariantList>("expectedValidity");
+ QTest::addColumn<QVariantList>("expectedValues");
+ QTest::addColumn<QStringList>("expectedErrors");
+
+ QPixmap origPixmap(100, 100);
+ origPixmap.fill(Qt::blue);
+
+ /* property var semantics */
+
+ // in the following three cases, the instance created from the component
+ // has a property which is a copy of the scarce resource; hence, the
+ // resource should NOT be detached prior to deletion of the object instance,
+ // unless the resource is destroyed explicitly.
+ QTest::newRow("var: import scarce resource copy directly")
+ << testFileUrl("scarceResourceCopy.var.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("var: import scarce resource copy from JS")
+ << testFileUrl("scarceResourceCopyFromJs.var.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("var: import released scarce resource copy from JS")
+ << testFileUrl("scarceResourceDestroyedCopy.var.qml")
+ << true
+ << true // explicitly released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false)
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+
+ // in the following three cases, no other copy should exist in memory,
+ // and so it should be detached (unless explicitly preserved).
+ QTest::newRow("var: import auto-release SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTest.var.qml")
+ << true
+ << true // auto released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTestPreserve.var.qml")
+ << true
+ << false // won't be detached because we explicitly preserve it
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTestMultiple.var.qml")
+ << true
+ << true // will be detached because all resources were released manually or automatically.
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+
+ // In the following three cases, test that scarce resources are handled
+ // correctly for imports.
+ QTest::newRow("var: import with no binding")
+ << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
+ << false // cannot check detach status.
+ << false
+ << QStringList()
+ << QList<QVariant>()
+ << QList<QVariant>()
+ << QStringList();
+ QTest::newRow("var: import with binding without explicit preserve")
+ << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+ QTest::newRow("var: import with explicit release after binding evaluation")
+ << testFileUrl("scarceResourceCopyImport.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
+ << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
+ << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
+ << QStringList();
+ QTest::newRow("var: import with different js objects")
+ << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
+ << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
+ << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
+ << QStringList();
+ QTest::newRow("var: import with different js objects and explicit release")
+ << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+ << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
+ << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
+ << QStringList();
+ QTest::newRow("var: import with same js objects and explicit release")
+ << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+ << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
+ << (QList<QVariant>() << QVariant() << QVariant())
+ << QStringList();
+ QTest::newRow("var: binding with same js objects and explicit release")
+ << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
+ << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
+ << (QList<QVariant>() << QVariant() << QVariant())
+ << QStringList();
+
+
+ /* property variant semantics */
+
+ // in the following three cases, the instance created from the component
+ // has a property which is a copy of the scarce resource; hence, the
+ // resource should NOT be detached prior to deletion of the object instance,
+ // unless the resource is destroyed explicitly.
+ QTest::newRow("variant: import scarce resource copy directly")
+ << testFileUrl("scarceResourceCopy.variant.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("variant: import scarce resource copy from JS")
+ << testFileUrl("scarceResourceCopyFromJs.variant.qml")
+ << true
+ << false // won't be detached, because assigned to property and not explicitly released
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << origPixmap)
+ << QStringList();
+
+ QTest::newRow("variant: import released scarce resource copy from JS")
+ << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
+ << true
+ << true // explicitly released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false)
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+
+ // in the following three cases, no other copy should exist in memory,
+ // and so it should be detached (unless explicitly preserved).
+ QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTest.variant.qml")
+ << true
+ << true // auto released, so it will be detached
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
+ << testFileUrl("scarceResourceTestPreserve.variant.qml")
+ << true
+ << false // won't be detached because we explicitly preserve it
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+ QTest::newRow("variant: import multiple scarce resources")
+ << testFileUrl("scarceResourceTestMultiple.variant.qml")
+ << true
+ << true // will be detached because all resources were released manually or automatically.
+ << (QStringList() << QLatin1String("scarceResourceTest"))
+ << (QList<QVariant>() << true)
+ << (QList<QVariant>() << QVariant(100))
+ << QStringList();
+
+ // In the following three cases, test that scarce resources are handled
+ // correctly for imports.
+ QTest::newRow("variant: import with no binding")
+ << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
+ << false // cannot check detach status.
+ << false
+ << QStringList()
+ << QList<QVariant>()
+ << QList<QVariant>()
+ << QStringList();
+ QTest::newRow("variant: import with binding without explicit preserve")
+ << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceCopy"))
+ << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
+ << (QList<QVariant>() << QVariant())
+ << QStringList();
+ QTest::newRow("variant: import with explicit release after binding evaluation")
+ << testFileUrl("scarceResourceCopyImport.variant.qml")
+ << false
+ << false
+ << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
+ << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
+ << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
+ << QStringList();
+}
+
+void tst_qdeclarativeecmascript::scarceResources()
+{
+ QFETCH(QUrl, qmlFile);
+ QFETCH(bool, readDetachStatus);
+ QFETCH(bool, expectedDetachStatus);
+ QFETCH(QStringList, propertyNames);
+ QFETCH(QVariantList, expectedValidity);
+ QFETCH(QVariantList, expectedValues);
+ QFETCH(QStringList, expectedErrors);
+
+ QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
+ ScarceResourceObject *eo = 0;
+ QObject *object = 0;
+
+ QDeclarativeComponent c(&engine, qmlFile);
+ object = c.create();
+ QVERIFY(object != 0);
+ for (int i = 0; i < propertyNames.size(); ++i) {
+ QString prop = propertyNames.at(i);
+ bool validity = expectedValidity.at(i).toBool();
+ QVariant value = expectedValues.at(i);
+
+ QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
+ if (value.type() == QVariant::Int) {
+ QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
+ } else if (value.type() == QVariant::Pixmap) {
+ QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
+ }
+ }
+
+ if (readDetachStatus) {
+ eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
+ QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
+ }
+
+ QVERIFY(ep->scarceResources.isEmpty());
+ delete object;
+}
+
void tst_qdeclarativeecmascript::propertyChangeSlots()
{
// ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
- QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
delete object;
// ensure that invalid property names fail properly.
QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
+ QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
object = e1.create();
delete object;
QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
+ QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
object = e2.create();
delete object;
QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
+ QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
object = e3.create();
delete object;
QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
+ QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
object = e4.create();
QTest::addColumn<QUrl>("qmlFile");
// valid
- QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
- QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
- QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
- QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
- QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
- QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
- QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
- QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
- QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
+ QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
+ QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
+ QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
+ QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
+ QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
+ QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
+ QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
+ QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
+ QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
+ QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
}
void tst_qdeclarativeecmascript::propertyVar()
// ensure that writing to and reading from a var property from cpp works as required.
// Literal values stored in var properties can be read and written as QVariants
// of a specific type, whereas object values are read as QVariantMaps.
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
object = component.create();
QVERIFY(object != 0);
// assign int to property var that currently has int assigned
static void gc(QDeclarativeEngine &engine)
{
engine.collectGarbage();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
}
void tst_qdeclarativeecmascript::propertyVarOwnership()
{
// Referenced JS objects are not collected
{
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("test").toBool(), false);
}
// Referenced JS objects are not collected
{
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("test").toBool(), false);
}
// Qt objects are not collected until they've been dereferenced
{
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
}
// Self reference does not prevent Qt object collection
{
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// The childObject has a reference to a different QObject. We want to ensure
// that the different item will not be cleaned up until required. IE, the childObject
// has implicit ownership of the constructed QObject.
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "assignCircular");
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QObject *rootObject = object->property("vp").value<QObject*>();
QVERIFY(rootObject != 0);
QObject *childObject = rootObject->findChild<QObject*>("text");
QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
QVERIFY(!qobjectGuard.isNull());
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QVERIFY(!qobjectGuard.isNull());
QMetaObject::invokeMethod(object, "deassignCircular");
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QVERIFY(qobjectGuard.isNull()); // should have been collected now.
delete object;
}
void tst_qdeclarativeecmascript::propertyVarReparent()
{
// ensure that nothing breaks if we re-parent objects
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "assignVarProp");
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QObject *rect = object->property("vp").value<QObject*>();
QObject *text = rect->findChild<QObject*>("textOne");
QObject *text2 = rect->findChild<QObject*>("textTwo");
// now reparent the "Image" object (currently, it has JS ownership)
image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
QMetaObject::invokeMethod(text2, "deassignVp");
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QCOMPARE(text->property("textCanary").toInt(), 11);
QCOMPARE(text2->property("textCanary").toInt(), 22);
QVERIFY(!imageGuard.isNull()); // should still be alive.
QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
delete object;
}
// sometimes reparenting can cause problems
// (eg, if the ctxt is collected, varproperties are no longer available)
// this test ensures that no crash occurs in that situation.
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "assignVarProp");
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QObject *rect = object->property("vp").value<QObject*>();
QObject *text = rect->findChild<QObject*>("textOne");
QObject *text2 = rect->findChild<QObject*>("textTwo");
// now reparent the "Image" object (currently, it has JS ownership)
image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QVERIFY(!imageGuard.isNull()); // should still be alive.
QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
delete object;
void tst_qdeclarativeecmascript::propertyVarCircular()
{
// enforce behaviour regarding circular references - ensure qdvmemo deletion.
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QCOMPARE(object->property("canaryInt"), QVariant(5));
QVariant canaryResourceVariant = object->property("canaryResource");
QVERIFY(canaryResourceVariant.isValid());
QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QCOMPARE(object->property("canaryInt"), QVariant(2));
QCOMPARE(object->property("canaryResource"), QVariant(1));
QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
{
// track deletion of JS-owned parent item with Cpp-owned child
// where the child has a var property referencing its parent.
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "assignCircular");
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QObject *rootObject = object->property("vp").value<QObject*>();
QVERIFY(rootObject != 0);
QObject *childObject = rootObject->findChild<QObject*>("text");
QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
QCOMPARE(childObject->property("textCanary").toInt(), 10);
QMetaObject::invokeMethod(object, "deassignCircular");
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QVERIFY(rootObjectTracker.isNull()); // should have been collected
QVERIFY(childObjectTracker.isNull()); // should have been collected
delete object;
// enforce behaviour regarding element inheritance - ensure handle disposal.
// The particular component under test here has a chain of references.
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
// we want to be able to track when the varProperties array of the last metaobject is disposed
QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
QObject *ico5 = object->property("varProperty").value<QObject*>()->property("inheritanceVarProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
v8::HandleScope hs;
// XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
// public function which can return us a handle to something in the varProperties array.
- icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
- ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
+ icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
+ ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
// we make them weak and invoke the gc, but we should not hit the weak-callback yet
// as the varproperties array of each vmemo still references the resource.
icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
}
// now we deassign the var prop, which should trigger collection of item subtrees.
QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
// ensure that there are only weak handles to the underlying varProperties array remaining.
gc(engine);
QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
// The particular component under test here does NOT have a chain of references; the
// only link between rootObject and childObject is that rootObject is the parent of childObject.
- QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "assignCircular");
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QObject *rootObject = object->property("vp").value<QObject*>();
QVERIFY(rootObject != 0);
QObject *childObject = rootObject->findChild<QObject*>("text");
{
v8::HandleScope hs;
propertyVarWeakRefCallbackCount = 0; // reset callback count.
- childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
+ childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
gc(engine);
QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
+ QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
QCOMPARE(childObject->property("textCanary").toInt(), 10);
}
QMetaObject::invokeMethod(object, "deassignCircular");
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
+ QCoreApplication::processEvents();
QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
delete object;
}
// Ensure that QObject type conversion works on binding assignment
void tst_qdeclarativeecmascript::elementAssign()
{
- QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// QTBUG-12457
void tst_qdeclarativeecmascript::objectPassThroughSignals()
{
- QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// QTBUG-21626
void tst_qdeclarativeecmascript::objectConversion()
{
- QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// QTBUG-20242
void tst_qdeclarativeecmascript::booleanConversion()
{
- QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
{
// Linear QObject reference
QDeclarativeEngine hrmEngine;
- QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
+ QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
+ cro->setEngine(&hrmEngine);
cro->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "createReference");
gc(engine);
QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
delete object;
hrmEngine.collectGarbage();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QCOMPARE(dtorCount, 3);
}
{
// Circular QObject reference
QDeclarativeEngine hrmEngine;
- QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
+ QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
+ cro->setEngine(&hrmEngine);
cro->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "circularReference");
gc(engine);
QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
delete object;
hrmEngine.collectGarbage();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QCOMPARE(dtorCount, 3);
}
{
// Linear handle reference
QDeclarativeEngine hrmEngine;
- QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
+ QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh != 0);
+ crh->setEngine(&hrmEngine);
crh->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "createReference");
CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
delete object;
hrmEngine.collectGarbage();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QCOMPARE(dtorCount, 3);
}
{
// Circular handle reference
QDeclarativeEngine hrmEngine;
- QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
+ QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh != 0);
+ crh->setEngine(&hrmEngine);
crh->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object, "circularReference");
CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
delete object;
hrmEngine.collectGarbage();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QCOMPARE(dtorCount, 3);
}
// 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"));
+ QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
QObject *object1 = component1.create();
QObject *object2 = component2.create();
QVERIFY(object1 != 0);
CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh1 != 0);
QVERIFY(crh2 != 0);
+ crh1->setEngine(&hrmEngine1);
+ crh2->setEngine(&hrmEngine2);
crh1->setDtorCount(&dtorCount);
crh2->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object1, "createReference");
second2->setParent(0);
QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
gc(engine);
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
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);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QCOMPARE(dtorCount, 6);
}
// 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"));
+ QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
QObject *object1 = component1.create();
QObject *object2 = component2.create();
QVERIFY(object1 != 0);
CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh1 != 0);
QVERIFY(crh2 != 0);
+ crh1->setEngine(&hrmEngine1);
+ crh2->setEngine(&hrmEngine2);
crh1->setDtorCount(&dtorCount);
crh2->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object1, "createReference");
QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
gc(engine);
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
delete object1;
delete object2;
hrmEngine1.collectGarbage();
hrmEngine2.collectGarbage();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QCOMPARE(dtorCount, 6);
}
// 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"));
+ QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
+ QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
QObject *object1 = component1.create();
QObject *object2 = component2.create();
QVERIFY(object1 != 0);
CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
QVERIFY(crh1 != 0);
QVERIFY(crh2 != 0);
+ crh1->setEngine(hrmEngine1);
+ crh2->setEngine(hrmEngine2);
crh1->setDtorCount(&dtorCount);
crh2->setDtorCount(&dtorCount);
QMetaObject::invokeMethod(object1, "createReference");
delete object1;
delete object2;
hrmEngine1->collectGarbage();
- QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
+ QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
+ QCoreApplication::processEvents();
QCOMPARE(dtorCount, 6);
delete hrmEngine1;
}
void tst_qdeclarativeecmascript::stringArg()
{
- QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "success");
QVERIFY(object->property("returnValue").toBool());
- QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
+ QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
QMetaObject::invokeMethod(object, "failure");
QVERIFY(object->property("returnValue").toBool());
void tst_qdeclarativeecmascript::readonlyDeclaration()
{
- QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::sequenceConversionRead()
{
{
- QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
+ QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
QDeclarativeComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != 0);
}
{
- QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
+ QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
QDeclarativeComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::sequenceConversionWrite()
{
{
- QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
+ QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
QDeclarativeComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != 0);
}
{
- QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
+ QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
QDeclarativeComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::sequenceConversionArray()
{
// ensure that in JS the returned sequences act just like normal JS Arrays.
- QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
+ QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
QDeclarativeComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != 0);
- //QMetaObject::invokeMethod(object, "indexedAccess");
- //QVERIFY(object->property("success").toBool());
- //QMetaObject::invokeMethod(object, "arrayOperations");
- //QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "indexedAccess");
+ QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "arrayOperations");
+ QVERIFY(object->property("success").toBool());
QMetaObject::invokeMethod(object, "testEqualitySemantics");
QVERIFY(object->property("success").toBool());
- //QMetaObject::invokeMethod(object, "testReferenceDeletion");
- //QCOMPARE(object->property("referenceDeletion").toBool(), true);
+ QMetaObject::invokeMethod(object, "testReferenceDeletion");
+ QCOMPARE(object->property("referenceDeletion").toBool(), true);
delete object;
}
{
// ensure that sequence conversion operations work correctly in a worker thread
// and that serialisation between the main and worker thread succeeds.
- QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
+ QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
QDeclarativeComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != 0);
QTRY_VERIFY(object->property("finished").toBool());
QVERIFY(object->property("success").toBool());
+ QMetaObject::invokeMethod(object, "testVariantSequence");
+ QTRY_VERIFY(object->property("finished").toBool());
+ QVERIFY(object->property("success").toBool());
+
delete object;
}
void tst_qdeclarativeecmascript::sequenceConversionBindings()
{
{
- QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
+ QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
QDeclarativeComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != 0);
}
{
- QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
+ QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
QDeclarativeComponent component(&engine, qmlFile);
void tst_qdeclarativeecmascript::sequenceConversionCopy()
{
- QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
+ QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
QDeclarativeComponent component(&engine, qmlFile);
QObject *object = component.create();
QVERIFY(object != 0);
delete object;
}
+void tst_qdeclarativeecmascript::assignSequenceTypes()
+{
+ // test binding array to sequence type property
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
+ QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
+ QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
+ delete object;
+ }
+
+ // test binding literal to sequence type property
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
+ QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
+ QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
+ delete object;
+ }
+
+ // test binding single value to sequence type property
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
+ delete object;
+ }
+
+ // test assigning array to sequence type property in js function
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
+ QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
+ QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
+ delete object;
+ }
+
+ // test assigning literal to sequence type property in js function
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
+ QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
+ QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
+ delete object;
+ }
+
+ // test assigning single value to sequence type property in js function
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
+ MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->intListProperty(), (QList<int>() << 1));
+ QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
+ QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
+ QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
+ delete object;
+ }
+
+ // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
+ MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
+ MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
+ MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
+ MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
+ QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
+ QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
+ QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
+ QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
+ QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
+ QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
+ delete object;
+ }
+}
+
// Test that assigning a null object works
// Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
void tst_qdeclarativeecmascript::nullObjectBinding()
{
- QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::deletedEngine()
{
QDeclarativeEngine *engine = new QDeclarativeEngine;
- QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
+ QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// Test the crashing part of QTBUG-9705
void tst_qdeclarativeecmascript::libraryScriptAssert()
{
- QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::variantsAssignedUndefined()
{
- QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::qtbug_9792()
{
- QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
// Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
void tst_qdeclarativeecmascript::qtcreatorbug_1289()
{
- QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
QObject *o = component.create();
{
- QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
QObject *o = component.create();
void tst_qdeclarativeecmascript::canAssignNullToQObject()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(o != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
QVERIFY(o != 0);
void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
{
- QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
QString url = component.url().toString();
QString warning = url + ":4: Unable to assign a function to a property.";
{
QFETCH(QString, triggerProperty);
- QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
{
- QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
void tst_qdeclarativeecmascript::eval()
{
- QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
void tst_qdeclarativeecmascript::function()
{
- QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
{
// Non-library relative include
{
- QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
// Library relative include
{
- QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
// Callback
{
- QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
// Including file with ".pragma library"
{
- QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
QCOMPARE(o->property("test1").toInt(), 100);
{
TestHTTPServer server(8111);
QVERIFY(server.isValid());
- server.serveDirectory(TESTDATA(""));
+ server.serveDirectory(dataDirectory());
- QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
{
TestHTTPServer server(8111);
QVERIFY(server.isValid());
- server.serveDirectory(TESTDATA(""));
+ server.serveDirectory(dataDirectory());
- QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
void tst_qdeclarativeecmascript::signalHandlers()
{
- QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
void tst_qdeclarativeecmascript::qtbug_10696()
{
- QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
delete o;
void tst_qdeclarativeecmascript::qtbug_11606()
{
- QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
QCOMPARE(o->property("test").toBool(), true);
void tst_qdeclarativeecmascript::qtbug_11600()
{
- QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("test").toBool(), true);
+ delete o;
+}
+
+void tst_qdeclarativeecmascript::qtbug_21864()
+{
+ QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(o->property("test").toBool(), true);
+ delete o;
+}
+
+void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
+{
+ // QTBUG-23375
+ QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
+ QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
QObject *o = component.create();
QVERIFY(o != 0);
QCOMPARE(o->property("test").toBool(), true);
// Reading and writing non-scriptable properties should fail
void tst_qdeclarativeecmascript::nonscriptable()
{
- QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
QCOMPARE(o->property("readOk").toBool(), true);
// deleteLater() should not be callable from QML
void tst_qdeclarativeecmascript::deleteLater()
{
- QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
QCOMPARE(o->property("test").toBool(), true);
void tst_qdeclarativeecmascript::in()
{
- QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
QCOMPARE(o->property("test1").toBool(), true);
void tst_qdeclarativeecmascript::typeOf()
{
- QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
+
+ // These warnings should not happen once QTBUG-21864 is fixed
+ QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
+ QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
+
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+
QObject *o = component.create();
QVERIFY(o != 0);
- QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
+
QEXPECT_FAIL("", "QTBUG-21864", Abort);
+ QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
void tst_qdeclarativeecmascript::sharedAttachedObject()
{
- QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
QCOMPARE(o->property("test1").toBool(), true);
// QTBUG-13999
void tst_qdeclarativeecmascript::objectName()
{
- QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
void tst_qdeclarativeecmascript::writeRemovesBinding()
{
- QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
// Test bindings assigned to alias properties actually assign to the alias' target
void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
{
- QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
QObject *o = component.create();
QVERIFY(o != 0);
// QTBUG-20200
void tst_qdeclarativeecmascript::aliasToCompositeElement()
{
- QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::qtbug_20344()
{
- QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
void tst_qdeclarativeecmascript::revisionErrors()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
QString url = component.url().toString();
QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
delete object;
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
QString url = component.url().toString();
// MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
delete object;
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
QString url = component.url().toString();
// MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
void tst_qdeclarativeecmascript::revision()
{
{
- QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
QString url = component.url().toString();
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
delete object;
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
QString url = component.url().toString();
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
delete object;
}
{
- QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
QString url = component.url().toString();
MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
}
// Test that non-root classes can resolve revisioned methods
{
- QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
void tst_qdeclarativeecmascript::realToInt()
{
- QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
QVERIFY(object != 0);
QMetaObject::invokeMethod(object, "test2");
QCOMPARE(object->value(), int(8));
}
+
+void tst_qdeclarativeecmascript::urlProperty()
+{
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ object->setStringProperty("http://qt-project.org");
+ QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
+ QCOMPARE(object->intProperty(), 123);
+ QCOMPARE(object->value(), 1);
+ QCOMPARE(object->property("result").toBool(), true);
+ }
+}
+
+void tst_qdeclarativeecmascript::urlPropertyWithEncoding()
+{
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("urlProperty.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
+ QVERIFY(object != 0);
+ object->setStringProperty("http://qt-project.org");
+ QUrl encoded;
+ encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
+ QCOMPARE(object->urlProperty(), encoded);
+ QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
+ QCOMPARE(object->property("result").toBool(), true);
+ }
+}
+
+void tst_qdeclarativeecmascript::urlListPropertyWithEncoding()
+{
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("urlListProperty.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
+ MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
+ MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
+ MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
+ QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
+ QUrl encoded;
+ encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
+ QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
+ QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
+ QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
+ QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
+ delete object;
+ }
+}
+
void tst_qdeclarativeecmascript::dynamicString()
{
- QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
QCOMPARE(object->property("stringProperty").toString(),
void tst_qdeclarativeecmascript::automaticSemicolon()
{
- QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+}
+
+void tst_qdeclarativeecmascript::unaryExpression()
+{
+ QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
}
// Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
void tst_qdeclarativeecmascript::doubleEvaluate()
{
- QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
WriteCounter *wc = qobject_cast<WriteCounter *>(object);
void tst_qdeclarativeecmascript::nonNotifyable()
{
QV4Compiler::enableV4(false);
- QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
QV4Compiler::enableV4(true);
QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
void tst_qdeclarativeecmascript::forInLoop()
{
- QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
// An object the binding depends on is deleted while the binding is still running
void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
{
- QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
+ QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
QObject *object = component.create();
QVERIFY(object != 0);
delete object;
}
+void tst_qdeclarativeecmascript::qtbug_22679()
+{
+ MyQmlObject object;
+ object.setStringProperty(QLatin1String("Please work correctly"));
+ engine.rootContext()->setContextProperty("contextProp", &object);
+
+ QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
+ qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
+ QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
+
+ QObject *o = component.create();
+ QVERIFY(o != 0);
+ QCOMPARE(warningsSpy.count(), 0);
+ delete o;
+}
+
+void tst_qdeclarativeecmascript::qtbug_22843_data()
+{
+ QTest::addColumn<bool>("library");
+
+ QTest::newRow("without .pragma library") << false;
+ QTest::newRow("with .pragma library") << true;
+}
+
+void tst_qdeclarativeecmascript::qtbug_22843()
+{
+ QFETCH(bool, library);
+
+ QString fileName("qtbug_22843");
+ if (library)
+ fileName += QLatin1String(".library");
+ fileName += QLatin1String(".qml");
+
+ QDeclarativeComponent component(&engine, testFileUrl(fileName));
+ QString url = component.url().toString();
+ QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
+ QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
+
+ qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
+ QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
+ for (int x = 0; x < 3; ++x) {
+ warningsSpy.clear();
+ // For libraries, only the first import attempt should produce a
+ // SyntaxError warning; subsequent component creation should not
+ // attempt to reload the script.
+ bool expectSyntaxError = !library || (x == 0);
+ if (expectSyntaxError)
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
+ QObject *object = component.create();
+ QVERIFY(object != 0);
+ QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
+ delete object;
+ }
+}
+
+
+void tst_qdeclarativeecmascript::switchStatement()
+{
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 5);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 4);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 1);
+ }
+
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 5);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 4);
+ }
+
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 5);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 6);
+ }
+
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
+
+ QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 5);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 3);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 3);
+
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+ object->setStringProperty("something else");
+ }
+
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 1);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 1);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 1);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 1);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 1);
+ }
+
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ // `object->value()' is the number of executed statements
+
+ object->setStringProperty("A");
+ QCOMPARE(object->value(), 123);
+
+ object->setStringProperty("S");
+ QCOMPARE(object->value(), 123);
+
+ object->setStringProperty("D");
+ QCOMPARE(object->value(), 321);
+
+ object->setStringProperty("F");
+ QCOMPARE(object->value(), 321);
+
+ object->setStringProperty("something else");
+ QCOMPARE(object->value(), 0);
+ }
+}
+
+void tst_qdeclarativeecmascript::withStatement()
+{
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 123);
+ }
+}
+
+void tst_qdeclarativeecmascript::tryStatement()
+{
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 123);
+ }
+
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 321);
+ }
+
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 1);
+ }
+
+ {
+ QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
+ MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
+ QVERIFY(object != 0);
+
+ QCOMPARE(object->value(), 1);
+ }
+}
+
QTEST_MAIN(tst_qdeclarativeecmascript)
#include "tst_qdeclarativeecmascript.moc"