/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 3105 lines · 2349 code · 583 blank · 173 comment · 167 complexity · 5701bd03e8cf76f0470690b49807748f MD5 · raw file

Large files are truncated click here to view the full file

  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
  4. ** All rights reserved.
  5. ** Contact: Nokia Corporation (qt-info@nokia.com)
  6. **
  7. ** This file is part of the test suite of the Qt Toolkit.
  8. **
  9. ** $QT_BEGIN_LICENSE:LGPL$
  10. ** GNU Lesser General Public License Usage
  11. ** This file may be used under the terms of the GNU Lesser General Public
  12. ** License version 2.1 as published by the Free Software Foundation and
  13. ** appearing in the file LICENSE.LGPL included in the packaging of this
  14. ** file. Please review the following information to ensure the GNU Lesser
  15. ** General Public License version 2.1 requirements will be met:
  16. ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  17. **
  18. ** In addition, as a special exception, Nokia gives you certain additional
  19. ** rights. These rights are described in the Nokia Qt LGPL Exception
  20. ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  21. **
  22. ** GNU General Public License Usage
  23. ** Alternatively, this file may be used under the terms of the GNU General
  24. ** Public License version 3.0 as published by the Free Software Foundation
  25. ** and appearing in the file LICENSE.GPL included in the packaging of this
  26. ** file. Please review the following information to ensure the GNU General
  27. ** Public License version 3.0 requirements will be met:
  28. ** http://www.gnu.org/copyleft/gpl.html.
  29. **
  30. ** Other Usage
  31. ** Alternatively, this file may be used in accordance with the terms and
  32. ** conditions contained in a signed written agreement between you and Nokia.
  33. **
  34. **
  35. **
  36. **
  37. **
  38. ** $QT_END_LICENSE$
  39. **
  40. ****************************************************************************/
  41. #include <qtest.h>
  42. #include <QtDeclarative/qdeclarativecomponent.h>
  43. #include <QtDeclarative/qdeclarativeengine.h>
  44. #include <QtDeclarative/qdeclarativeexpression.h>
  45. #include <QtDeclarative/qdeclarativecontext.h>
  46. #include <QtCore/qfileinfo.h>
  47. #include <QtCore/qdebug.h>
  48. #include <QtDeclarative/private/qdeclarativeguard_p.h>
  49. #include <QtCore/qdir.h>
  50. #include <QtCore/qnumeric.h>
  51. #include <private/qdeclarativeengine_p.h>
  52. #include <private/qdeclarativeglobalscriptclass_p.h>
  53. #include <private/qscriptdeclarativeclass_p.h>
  54. #include "testtypes.h"
  55. #include "testhttpserver.h"
  56. #include "../../../shared/util.h"
  57. #ifdef Q_OS_SYMBIAN
  58. // In Symbian OS test data is located in applications private dir
  59. #define SRCDIR "."
  60. #endif
  61. /*
  62. This test covers evaluation of ECMAScript expressions and bindings from within
  63. QML. This does not include static QML language issues.
  64. Static QML language issues are covered in qmllanguage
  65. */
  66. inline QUrl TEST_FILE(const QString &filename)
  67. {
  68. QFileInfo fileInfo(__FILE__);
  69. return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
  70. }
  71. inline QUrl TEST_FILE(const char *filename)
  72. {
  73. return TEST_FILE(QLatin1String(filename));
  74. }
  75. class tst_qdeclarativeecmascript : public QObject
  76. {
  77. Q_OBJECT
  78. public:
  79. tst_qdeclarativeecmascript() {}
  80. private slots:
  81. void initTestCase();
  82. void assignBasicTypes();
  83. void idShortcutInvalidates();
  84. void boolPropertiesEvaluateAsBool();
  85. void methods();
  86. void signalAssignment();
  87. void bindingLoop();
  88. void basicExpressions();
  89. void basicExpressions_data();
  90. void arrayExpressions();
  91. void contextPropertiesTriggerReeval();
  92. void objectPropertiesTriggerReeval();
  93. void deferredProperties();
  94. void deferredPropertiesErrors();
  95. void extensionObjects();
  96. void overrideExtensionProperties();
  97. void attachedProperties();
  98. void enums();
  99. void valueTypeFunctions();
  100. void constantsOverrideBindings();
  101. void outerBindingOverridesInnerBinding();
  102. void aliasPropertyAndBinding();
  103. void nonExistentAttachedObject();
  104. void scope();
  105. void signalParameterTypes();
  106. void objectsCompareAsEqual();
  107. void dynamicCreation_data();
  108. void dynamicCreation();
  109. void dynamicDestruction();
  110. void objectToString();
  111. void selfDeletingBinding();
  112. void extendedObjectPropertyLookup();
  113. void scriptErrors();
  114. void functionErrors();
  115. void propertyAssignmentErrors();
  116. void signalTriggeredBindings();
  117. void listProperties();
  118. void exceptionClearsOnReeval();
  119. void exceptionSlotProducesWarning();
  120. void exceptionBindingProducesWarning();
  121. void transientErrors();
  122. void shutdownErrors();
  123. void compositePropertyType();
  124. void jsObject();
  125. void undefinedResetsProperty();
  126. void listToVariant();
  127. void multiEngineObject();
  128. void deletedObject();
  129. void attachedPropertyScope();
  130. void scriptConnect();
  131. void scriptDisconnect();
  132. void ownership();
  133. void cppOwnershipReturnValue();
  134. void ownershipCustomReturnValue();
  135. void qlistqobjectMethods();
  136. void strictlyEquals();
  137. void compiled();
  138. void numberAssignment();
  139. void propertySplicing();
  140. void signalWithUnknownTypes();
  141. void bug1();
  142. void bug2();
  143. void dynamicCreationCrash();
  144. void regExpBug();
  145. void nullObjectBinding();
  146. void deletedEngine();
  147. void libraryScriptAssert();
  148. void variantsAssignedUndefined();
  149. void qtbug_9792();
  150. void qtcreatorbug_1289();
  151. void noSpuriousWarningsAtShutdown();
  152. void canAssignNullToQObject();
  153. void functionAssignment_fromBinding();
  154. void functionAssignment_fromJS();
  155. void functionAssignment_fromJS_data();
  156. void functionAssignmentfromJS_invalid();
  157. void eval();
  158. void function();
  159. void qtbug_10696();
  160. void qtbug_11606();
  161. void qtbug_11600();
  162. void nonscriptable();
  163. void deleteLater();
  164. void in();
  165. void sharedAttachedObject();
  166. void objectName();
  167. void writeRemovesBinding();
  168. void aliasBindingsAssignCorrectly();
  169. void aliasBindingsOverrideTarget();
  170. void aliasWritesOverrideBindings();
  171. void pushCleanContext();
  172. void realToInt();
  173. void qtbug_20648();
  174. void include();
  175. void callQtInvokables();
  176. void invokableObjectArg();
  177. void invokableObjectRet();
  178. void revisionErrors();
  179. void revision();
  180. private:
  181. QDeclarativeEngine engine;
  182. };
  183. void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
  184. void tst_qdeclarativeecmascript::assignBasicTypes()
  185. {
  186. {
  187. QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
  188. MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
  189. QVERIFY(object != 0);
  190. QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
  191. QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
  192. QCOMPARE(object->stringProperty(), QString("Hello World!"));
  193. QCOMPARE(object->uintProperty(), uint(10));
  194. QCOMPARE(object->intProperty(), -19);
  195. QCOMPARE((float)object->realProperty(), float(23.2));
  196. QCOMPARE((float)object->doubleProperty(), float(-19.75));
  197. QCOMPARE((float)object->floatProperty(), float(8.5));
  198. QCOMPARE(object->colorProperty(), QColor("red"));
  199. QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
  200. QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
  201. QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
  202. QCOMPARE(object->pointProperty(), QPoint(99,13));
  203. QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
  204. QCOMPARE(object->sizeProperty(), QSize(99, 13));
  205. QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
  206. QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
  207. QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
  208. QCOMPARE(object->boolProperty(), true);
  209. QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
  210. QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
  211. QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
  212. delete object;
  213. }
  214. {
  215. QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
  216. MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
  217. QVERIFY(object != 0);
  218. QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
  219. QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
  220. QCOMPARE(object->stringProperty(), QString("Hello World!"));
  221. QCOMPARE(object->uintProperty(), uint(10));
  222. QCOMPARE(object->intProperty(), -19);
  223. QCOMPARE((float)object->realProperty(), float(23.2));
  224. QCOMPARE((float)object->doubleProperty(), float(-19.75));
  225. QCOMPARE((float)object->floatProperty(), float(8.5));
  226. QCOMPARE(object->colorProperty(), QColor("red"));
  227. QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
  228. QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
  229. QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
  230. QCOMPARE(object->pointProperty(), QPoint(99,13));
  231. QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
  232. QCOMPARE(object->sizeProperty(), QSize(99, 13));
  233. QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
  234. QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
  235. QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
  236. QCOMPARE(object->boolProperty(), true);
  237. QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
  238. QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
  239. QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
  240. delete object;
  241. }
  242. }
  243. void tst_qdeclarativeecmascript::idShortcutInvalidates()
  244. {
  245. {
  246. QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
  247. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  248. QVERIFY(object != 0);
  249. QVERIFY(object->objectProperty() != 0);
  250. delete object->objectProperty();
  251. QVERIFY(object->objectProperty() == 0);
  252. }
  253. {
  254. QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
  255. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  256. QVERIFY(object != 0);
  257. QVERIFY(object->objectProperty() != 0);
  258. delete object->objectProperty();
  259. QVERIFY(object->objectProperty() == 0);
  260. }
  261. }
  262. void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
  263. {
  264. {
  265. QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
  266. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  267. QVERIFY(object != 0);
  268. QCOMPARE(object->stringProperty(), QLatin1String("pass"));
  269. }
  270. {
  271. QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
  272. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  273. QVERIFY(object != 0);
  274. QCOMPARE(object->stringProperty(), QLatin1String("pass"));
  275. }
  276. }
  277. void tst_qdeclarativeecmascript::signalAssignment()
  278. {
  279. {
  280. QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
  281. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  282. QVERIFY(object != 0);
  283. QCOMPARE(object->string(), QString());
  284. emit object->basicSignal();
  285. QCOMPARE(object->string(), QString("pass"));
  286. }
  287. {
  288. QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
  289. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  290. QVERIFY(object != 0);
  291. QCOMPARE(object->string(), QString());
  292. emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
  293. QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
  294. }
  295. }
  296. void tst_qdeclarativeecmascript::methods()
  297. {
  298. {
  299. QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
  300. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  301. QVERIFY(object != 0);
  302. QCOMPARE(object->methodCalled(), false);
  303. QCOMPARE(object->methodIntCalled(), false);
  304. emit object->basicSignal();
  305. QCOMPARE(object->methodCalled(), true);
  306. QCOMPARE(object->methodIntCalled(), false);
  307. }
  308. {
  309. QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
  310. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  311. QVERIFY(object != 0);
  312. QCOMPARE(object->methodCalled(), false);
  313. QCOMPARE(object->methodIntCalled(), false);
  314. emit object->basicSignal();
  315. QCOMPARE(object->methodCalled(), false);
  316. QCOMPARE(object->methodIntCalled(), true);
  317. }
  318. {
  319. QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
  320. QObject *object = component.create();
  321. QVERIFY(object != 0);
  322. QCOMPARE(object->property("test").toInt(), 19);
  323. }
  324. {
  325. QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
  326. QObject *object = component.create();
  327. QVERIFY(object != 0);
  328. QCOMPARE(object->property("test").toInt(), 19);
  329. QCOMPARE(object->property("test2").toInt(), 17);
  330. QCOMPARE(object->property("test3").toInt(), 16);
  331. }
  332. {
  333. QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
  334. QObject *object = component.create();
  335. QVERIFY(object != 0);
  336. QCOMPARE(object->property("test").toInt(), 9);
  337. }
  338. }
  339. void tst_qdeclarativeecmascript::bindingLoop()
  340. {
  341. QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
  342. QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
  343. QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
  344. QObject *object = component.create();
  345. QVERIFY(object != 0);
  346. }
  347. void tst_qdeclarativeecmascript::basicExpressions_data()
  348. {
  349. QTest::addColumn<QString>("expression");
  350. QTest::addColumn<QVariant>("result");
  351. QTest::addColumn<bool>("nest");
  352. QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
  353. QTest::newRow("Context property") << "a" << QVariant(1944) << false;
  354. QTest::newRow("Context property") << "a" << QVariant(1944) << true;
  355. QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
  356. QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
  357. QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
  358. QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
  359. QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
  360. QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
  361. QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
  362. QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
  363. QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
  364. QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
  365. QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
  366. QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
  367. QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
  368. QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
  369. QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
  370. QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
  371. }
  372. void tst_qdeclarativeecmascript::basicExpressions()
  373. {
  374. QFETCH(QString, expression);
  375. QFETCH(QVariant, result);
  376. QFETCH(bool, nest);
  377. MyQmlObject object1;
  378. MyQmlObject object2;
  379. MyQmlObject object3;
  380. MyDefaultObject1 default1;
  381. MyDefaultObject3 default3;
  382. object1.setStringProperty("Object1");
  383. object2.setStringProperty("Object2");
  384. object3.setStringProperty("Object3");
  385. QDeclarativeContext context(engine.rootContext());
  386. QDeclarativeContext nestedContext(&context);
  387. context.setContextObject(&default1);
  388. context.setContextProperty("a", QVariant(1944));
  389. context.setContextProperty("b", QVariant("Milk"));
  390. context.setContextProperty("object", &object1);
  391. context.setContextProperty("objectOverride", &object2);
  392. nestedContext.setContextObject(&default3);
  393. nestedContext.setContextProperty("b", QVariant("Cow"));
  394. nestedContext.setContextProperty("objectOverride", &object3);
  395. nestedContext.setContextProperty("millipedeLegs", QVariant(100));
  396. MyExpression expr(nest?&nestedContext:&context, expression);
  397. QCOMPARE(expr.evaluate(), result);
  398. }
  399. void tst_qdeclarativeecmascript::arrayExpressions()
  400. {
  401. QObject obj1;
  402. QObject obj2;
  403. QObject obj3;
  404. QDeclarativeContext context(engine.rootContext());
  405. context.setContextProperty("a", &obj1);
  406. context.setContextProperty("b", &obj2);
  407. context.setContextProperty("c", &obj3);
  408. MyExpression expr(&context, "[a, b, c, 10]");
  409. QVariant result = expr.evaluate();
  410. QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
  411. QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
  412. QCOMPARE(list.count(), 4);
  413. QCOMPARE(list.at(0), &obj1);
  414. QCOMPARE(list.at(1), &obj2);
  415. QCOMPARE(list.at(2), &obj3);
  416. QCOMPARE(list.at(3), (QObject *)0);
  417. }
  418. // Tests that modifying a context property will reevaluate expressions
  419. void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
  420. {
  421. QDeclarativeContext context(engine.rootContext());
  422. MyQmlObject object1;
  423. MyQmlObject object2;
  424. MyQmlObject *object3 = new MyQmlObject;
  425. object1.setStringProperty("Hello");
  426. object2.setStringProperty("World");
  427. context.setContextProperty("testProp", QVariant(1));
  428. context.setContextProperty("testObj", &object1);
  429. context.setContextProperty("testObj2", object3);
  430. {
  431. MyExpression expr(&context, "testProp + 1");
  432. QCOMPARE(expr.changed, false);
  433. QCOMPARE(expr.evaluate(), QVariant(2));
  434. context.setContextProperty("testProp", QVariant(2));
  435. QCOMPARE(expr.changed, true);
  436. QCOMPARE(expr.evaluate(), QVariant(3));
  437. }
  438. {
  439. MyExpression expr(&context, "testProp + testProp + testProp");
  440. QCOMPARE(expr.changed, false);
  441. QCOMPARE(expr.evaluate(), QVariant(6));
  442. context.setContextProperty("testProp", QVariant(4));
  443. QCOMPARE(expr.changed, true);
  444. QCOMPARE(expr.evaluate(), QVariant(12));
  445. }
  446. {
  447. MyExpression expr(&context, "testObj.stringProperty");
  448. QCOMPARE(expr.changed, false);
  449. QCOMPARE(expr.evaluate(), QVariant("Hello"));
  450. context.setContextProperty("testObj", &object2);
  451. QCOMPARE(expr.changed, true);
  452. QCOMPARE(expr.evaluate(), QVariant("World"));
  453. }
  454. {
  455. MyExpression expr(&context, "testObj.stringProperty /**/");
  456. QCOMPARE(expr.changed, false);
  457. QCOMPARE(expr.evaluate(), QVariant("World"));
  458. context.setContextProperty("testObj", &object1);
  459. QCOMPARE(expr.changed, true);
  460. QCOMPARE(expr.evaluate(), QVariant("Hello"));
  461. }
  462. {
  463. MyExpression expr(&context, "testObj2");
  464. QCOMPARE(expr.changed, false);
  465. QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
  466. }
  467. }
  468. void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
  469. {
  470. QDeclarativeContext context(engine.rootContext());
  471. MyQmlObject object1;
  472. MyQmlObject object2;
  473. MyQmlObject object3;
  474. context.setContextProperty("testObj", &object1);
  475. object1.setStringProperty(QLatin1String("Hello"));
  476. object2.setStringProperty(QLatin1String("Dog"));
  477. object3.setStringProperty(QLatin1String("Cat"));
  478. {
  479. MyExpression expr(&context, "testObj.stringProperty");
  480. QCOMPARE(expr.changed, false);
  481. QCOMPARE(expr.evaluate(), QVariant("Hello"));
  482. object1.setStringProperty(QLatin1String("World"));
  483. QCOMPARE(expr.changed, true);
  484. QCOMPARE(expr.evaluate(), QVariant("World"));
  485. }
  486. {
  487. MyExpression expr(&context, "testObj.objectProperty.stringProperty");
  488. QCOMPARE(expr.changed, false);
  489. QCOMPARE(expr.evaluate(), QVariant());
  490. object1.setObjectProperty(&object2);
  491. QCOMPARE(expr.changed, true);
  492. expr.changed = false;
  493. QCOMPARE(expr.evaluate(), QVariant("Dog"));
  494. object1.setObjectProperty(&object3);
  495. QCOMPARE(expr.changed, true);
  496. expr.changed = false;
  497. QCOMPARE(expr.evaluate(), QVariant("Cat"));
  498. object1.setObjectProperty(0);
  499. QCOMPARE(expr.changed, true);
  500. expr.changed = false;
  501. QCOMPARE(expr.evaluate(), QVariant());
  502. object1.setObjectProperty(&object3);
  503. QCOMPARE(expr.changed, true);
  504. expr.changed = false;
  505. QCOMPARE(expr.evaluate(), QVariant("Cat"));
  506. object3.setStringProperty("Donkey");
  507. QCOMPARE(expr.changed, true);
  508. expr.changed = false;
  509. QCOMPARE(expr.evaluate(), QVariant("Donkey"));
  510. }
  511. }
  512. void tst_qdeclarativeecmascript::deferredProperties()
  513. {
  514. QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
  515. MyDeferredObject *object =
  516. qobject_cast<MyDeferredObject *>(component.create());
  517. QVERIFY(object != 0);
  518. QCOMPARE(object->value(), 0);
  519. QVERIFY(object->objectProperty() == 0);
  520. QVERIFY(object->objectProperty2() != 0);
  521. qmlExecuteDeferred(object);
  522. QCOMPARE(object->value(), 10);
  523. QVERIFY(object->objectProperty() != 0);
  524. MyQmlObject *qmlObject =
  525. qobject_cast<MyQmlObject *>(object->objectProperty());
  526. QVERIFY(qmlObject != 0);
  527. QCOMPARE(qmlObject->value(), 10);
  528. object->setValue(19);
  529. QCOMPARE(qmlObject->value(), 19);
  530. }
  531. // Check errors on deferred properties are correctly emitted
  532. void tst_qdeclarativeecmascript::deferredPropertiesErrors()
  533. {
  534. QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
  535. MyDeferredObject *object =
  536. qobject_cast<MyDeferredObject *>(component.create());
  537. QVERIFY(object != 0);
  538. QCOMPARE(object->value(), 0);
  539. QVERIFY(object->objectProperty() == 0);
  540. QVERIFY(object->objectProperty2() == 0);
  541. QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
  542. QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
  543. qmlExecuteDeferred(object);
  544. delete object;
  545. }
  546. void tst_qdeclarativeecmascript::extensionObjects()
  547. {
  548. QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
  549. MyExtendedObject *object =
  550. qobject_cast<MyExtendedObject *>(component.create());
  551. QVERIFY(object != 0);
  552. QCOMPARE(object->baseProperty(), 13);
  553. QCOMPARE(object->coreProperty(), 9);
  554. object->setProperty("extendedProperty", QVariant(11));
  555. object->setProperty("baseExtendedProperty", QVariant(92));
  556. QCOMPARE(object->coreProperty(), 11);
  557. QCOMPARE(object->baseProperty(), 92);
  558. MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
  559. QVERIFY(nested);
  560. QCOMPARE(nested->baseProperty(), 13);
  561. QCOMPARE(nested->coreProperty(), 9);
  562. nested->setProperty("extendedProperty", QVariant(11));
  563. nested->setProperty("baseExtendedProperty", QVariant(92));
  564. QCOMPARE(nested->coreProperty(), 11);
  565. QCOMPARE(nested->baseProperty(), 92);
  566. }
  567. void tst_qdeclarativeecmascript::overrideExtensionProperties()
  568. {
  569. QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
  570. OverrideDefaultPropertyObject *object =
  571. qobject_cast<OverrideDefaultPropertyObject *>(component.create());
  572. QVERIFY(object != 0);
  573. QVERIFY(object->secondProperty() != 0);
  574. QVERIFY(object->firstProperty() == 0);
  575. }
  576. void tst_qdeclarativeecmascript::attachedProperties()
  577. {
  578. {
  579. QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
  580. QObject *object = component.create();
  581. QVERIFY(object != 0);
  582. QCOMPARE(object->property("a").toInt(), 19);
  583. QCOMPARE(object->property("b").toInt(), 19);
  584. QCOMPARE(object->property("c").toInt(), 19);
  585. QCOMPARE(object->property("d").toInt(), 19);
  586. }
  587. {
  588. QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
  589. QObject *object = component.create();
  590. QVERIFY(object != 0);
  591. QCOMPARE(object->property("a").toInt(), 26);
  592. QCOMPARE(object->property("b").toInt(), 26);
  593. QCOMPARE(object->property("c").toInt(), 26);
  594. QCOMPARE(object->property("d").toInt(), 26);
  595. }
  596. {
  597. QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
  598. QObject *object = component.create();
  599. QVERIFY(object != 0);
  600. QMetaObject::invokeMethod(object, "writeValue2");
  601. MyQmlAttachedObject *attached =
  602. qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
  603. QVERIFY(attached != 0);
  604. QCOMPARE(attached->value2(), 9);
  605. }
  606. }
  607. void tst_qdeclarativeecmascript::enums()
  608. {
  609. // Existent enums
  610. {
  611. QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
  612. QObject *object = component.create();
  613. QVERIFY(object != 0);
  614. QCOMPARE(object->property("a").toInt(), 0);
  615. QCOMPARE(object->property("b").toInt(), 1);
  616. QCOMPARE(object->property("c").toInt(), 2);
  617. QCOMPARE(object->property("d").toInt(), 3);
  618. QCOMPARE(object->property("e").toInt(), 0);
  619. QCOMPARE(object->property("f").toInt(), 1);
  620. QCOMPARE(object->property("g").toInt(), 2);
  621. QCOMPARE(object->property("h").toInt(), 3);
  622. QCOMPARE(object->property("i").toInt(), 19);
  623. QCOMPARE(object->property("j").toInt(), 19);
  624. }
  625. // Non-existent enums
  626. {
  627. QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
  628. QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
  629. QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
  630. QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
  631. QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
  632. QObject *object = component.create();
  633. QVERIFY(object != 0);
  634. QCOMPARE(object->property("a").toInt(), 0);
  635. QCOMPARE(object->property("b").toInt(), 0);
  636. }
  637. }
  638. void tst_qdeclarativeecmascript::valueTypeFunctions()
  639. {
  640. QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
  641. MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
  642. QVERIFY(obj != 0);
  643. QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
  644. QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
  645. }
  646. /*
  647. Tests that writing a constant to a property with a binding on it disables the
  648. binding.
  649. */
  650. void tst_qdeclarativeecmascript::constantsOverrideBindings()
  651. {
  652. // From ECMAScript
  653. {
  654. QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
  655. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  656. QVERIFY(object != 0);
  657. QCOMPARE(object->property("c2").toInt(), 0);
  658. object->setProperty("c1", QVariant(9));
  659. QCOMPARE(object->property("c2").toInt(), 9);
  660. emit object->basicSignal();
  661. QCOMPARE(object->property("c2").toInt(), 13);
  662. object->setProperty("c1", QVariant(8));
  663. QCOMPARE(object->property("c2").toInt(), 13);
  664. }
  665. // During construction
  666. {
  667. QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
  668. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  669. QVERIFY(object != 0);
  670. QCOMPARE(object->property("c1").toInt(), 0);
  671. QCOMPARE(object->property("c2").toInt(), 10);
  672. object->setProperty("c1", QVariant(9));
  673. QCOMPARE(object->property("c1").toInt(), 9);
  674. QCOMPARE(object->property("c2").toInt(), 10);
  675. }
  676. #if 0
  677. // From C++
  678. {
  679. QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
  680. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  681. QVERIFY(object != 0);
  682. QCOMPARE(object->property("c2").toInt(), 0);
  683. object->setProperty("c1", QVariant(9));
  684. QCOMPARE(object->property("c2").toInt(), 9);
  685. object->setProperty("c2", QVariant(13));
  686. QCOMPARE(object->property("c2").toInt(), 13);
  687. object->setProperty("c1", QVariant(7));
  688. QCOMPARE(object->property("c1").toInt(), 7);
  689. QCOMPARE(object->property("c2").toInt(), 13);
  690. }
  691. #endif
  692. // Using an alias
  693. {
  694. QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
  695. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  696. QVERIFY(object != 0);
  697. QCOMPARE(object->property("c1").toInt(), 0);
  698. QCOMPARE(object->property("c3").toInt(), 10);
  699. object->setProperty("c1", QVariant(9));
  700. QCOMPARE(object->property("c1").toInt(), 9);
  701. QCOMPARE(object->property("c3").toInt(), 10);
  702. }
  703. }
  704. /*
  705. Tests that assigning a binding to a property that already has a binding causes
  706. the original binding to be disabled.
  707. */
  708. void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
  709. {
  710. QDeclarativeComponent component(&engine,
  711. TEST_FILE("outerBindingOverridesInnerBinding.qml"));
  712. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  713. QVERIFY(object != 0);
  714. QCOMPARE(object->property("c1").toInt(), 0);
  715. QCOMPARE(object->property("c2").toInt(), 0);
  716. QCOMPARE(object->property("c3").toInt(), 0);
  717. object->setProperty("c1", QVariant(9));
  718. QCOMPARE(object->property("c1").toInt(), 9);
  719. QCOMPARE(object->property("c2").toInt(), 0);
  720. QCOMPARE(object->property("c3").toInt(), 0);
  721. object->setProperty("c3", QVariant(8));
  722. QCOMPARE(object->property("c1").toInt(), 9);
  723. QCOMPARE(object->property("c2").toInt(), 8);
  724. QCOMPARE(object->property("c3").toInt(), 8);
  725. }
  726. /*
  727. Access a non-existent attached object.
  728. Tests for a regression where this used to crash.
  729. */
  730. void tst_qdeclarativeecmascript::nonExistentAttachedObject()
  731. {
  732. QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
  733. QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
  734. QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
  735. QObject *object = component.create();
  736. QVERIFY(object != 0);
  737. }
  738. void tst_qdeclarativeecmascript::scope()
  739. {
  740. {
  741. QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
  742. QObject *object = component.create();
  743. QVERIFY(object != 0);
  744. QCOMPARE(object->property("test1").toInt(), 1);
  745. QCOMPARE(object->property("test2").toInt(), 2);
  746. QCOMPARE(object->property("test3").toString(), QString("1Test"));
  747. QCOMPARE(object->property("test4").toString(), QString("2Test"));
  748. QCOMPARE(object->property("test5").toInt(), 1);
  749. QCOMPARE(object->property("test6").toInt(), 1);
  750. QCOMPARE(object->property("test7").toInt(), 2);
  751. QCOMPARE(object->property("test8").toInt(), 2);
  752. QCOMPARE(object->property("test9").toInt(), 1);
  753. QCOMPARE(object->property("test10").toInt(), 3);
  754. }
  755. {
  756. QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
  757. QObject *object = component.create();
  758. QVERIFY(object != 0);
  759. QCOMPARE(object->property("test1").toInt(), 19);
  760. QCOMPARE(object->property("test2").toInt(), 19);
  761. QCOMPARE(object->property("test3").toInt(), 14);
  762. QCOMPARE(object->property("test4").toInt(), 14);
  763. QCOMPARE(object->property("test5").toInt(), 24);
  764. QCOMPARE(object->property("test6").toInt(), 24);
  765. }
  766. {
  767. QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
  768. QObject *object = component.create();
  769. QVERIFY(object != 0);
  770. QCOMPARE(object->property("test1").toBool(), true);
  771. QCOMPARE(object->property("test2").toBool(), true);
  772. QCOMPARE(object->property("test3").toBool(), true);
  773. }
  774. // Signal argument scope
  775. {
  776. QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
  777. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  778. QVERIFY(object != 0);
  779. QCOMPARE(object->property("test").toInt(), 0);
  780. QCOMPARE(object->property("test2").toString(), QString());
  781. emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
  782. QCOMPARE(object->property("test").toInt(), 13);
  783. QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
  784. delete object;
  785. }
  786. }
  787. /*
  788. Tests that "any" type passes through a synthesized signal parameter. This
  789. is essentially a test of QDeclarativeMetaType::copy()
  790. */
  791. void tst_qdeclarativeecmascript::signalParameterTypes()
  792. {
  793. QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
  794. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  795. QVERIFY(object != 0);
  796. emit object->basicSignal();
  797. QCOMPARE(object->property("intProperty").toInt(), 10);
  798. QCOMPARE(object->property("realProperty").toReal(), 19.2);
  799. QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
  800. QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
  801. QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
  802. QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
  803. }
  804. /*
  805. Test that two JS objects for the same QObject compare as equal.
  806. */
  807. void tst_qdeclarativeecmascript::objectsCompareAsEqual()
  808. {
  809. QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
  810. QObject *object = component.create();
  811. QVERIFY(object != 0);
  812. QCOMPARE(object->property("test1").toBool(), true);
  813. QCOMPARE(object->property("test2").toBool(), true);
  814. QCOMPARE(object->property("test3").toBool(), true);
  815. QCOMPARE(object->property("test4").toBool(), true);
  816. QCOMPARE(object->property("test5").toBool(), true);
  817. }
  818. /*
  819. Confirm bindings and alias properties can coexist.
  820. Tests for a regression where the binding would not reevaluate.
  821. */
  822. void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
  823. {
  824. QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
  825. QObject *object = component.create();
  826. QVERIFY(object != 0);
  827. QCOMPARE(object->property("c2").toInt(), 3);
  828. QCOMPARE(object->property("c3").toInt(), 3);
  829. object->setProperty("c2", QVariant(19));
  830. QCOMPARE(object->property("c2").toInt(), 19);
  831. QCOMPARE(object->property("c3").toInt(), 19);
  832. }
  833. void tst_qdeclarativeecmascript::dynamicCreation_data()
  834. {
  835. QTest::addColumn<QString>("method");
  836. QTest::addColumn<QString>("createdName");
  837. QTest::newRow("One") << "createOne" << "objectOne";
  838. QTest::newRow("Two") << "createTwo" << "objectTwo";
  839. QTest::newRow("Three") << "createThree" << "objectThree";
  840. }
  841. /*
  842. Test using createQmlObject to dynamically generate an item
  843. Also using createComponent is tested.
  844. */
  845. void tst_qdeclarativeecmascript::dynamicCreation()
  846. {
  847. QFETCH(QString, method);
  848. QFETCH(QString, createdName);
  849. QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
  850. MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
  851. QVERIFY(object != 0);
  852. QMetaObject::invokeMethod(object, method.toUtf8());
  853. QObject *created = object->objectProperty();
  854. QVERIFY(created);
  855. QCOMPARE(created->objectName(), createdName);
  856. }
  857. /*
  858. Tests the destroy function
  859. */
  860. void tst_qdeclarativeecmascript::dynamicDestruction()
  861. {
  862. QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
  863. QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
  864. QVERIFY(object != 0);
  865. QDeclarativeGuard<QObject> createdQmlObject = 0;
  866. QMetaObject::invokeMethod(object, "create");
  867. createdQmlObject = object->objectProperty();
  868. QVERIFY(createdQmlObject);
  869. QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
  870. QMetaObject::invokeMethod(object, "killOther");
  871. QVERIFY(createdQmlObject);
  872. QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
  873. QVERIFY(createdQmlObject);
  874. for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
  875. if (createdQmlObject) {
  876. QTest::qWait(100);
  877. QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
  878. }
  879. }
  880. QVERIFY(!createdQmlObject);
  881. QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
  882. QMetaObject::invokeMethod(object, "killMe");
  883. QVERIFY(object);
  884. QTest::qWait(0);
  885. QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
  886. QVERIFY(!object);
  887. }
  888. /*
  889. tests that id.toString() works
  890. */
  891. void tst_qdeclarativeecmascript::objectToString()
  892. {
  893. QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
  894. MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
  895. QVERIFY(object != 0);
  896. QMetaObject::invokeMethod(object, "testToString");
  897. QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
  898. QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
  899. }
  900. /*
  901. Tests bindings that indirectly cause their own deletion work.
  902. This test is best run under valgrind to ensure no invalid memory access occur.
  903. */
  904. void tst_qdeclarativeecmascript::selfDeletingBinding()
  905. {
  906. {
  907. QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
  908. QObject *object = component.create();
  909. QVERIFY(object != 0);
  910. object->setProperty("triggerDelete", true);
  911. }
  912. {
  913. QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
  914. QObject *object = component.create();
  915. QVERIFY(object != 0);
  916. object->setProperty("triggerDelete", true);
  917. }
  918. }
  919. /*
  920. Test that extended object properties can be accessed.
  921. This test a regression where this used to crash. The issue was specificially
  922. for extended objects that did not include a synthesized meta object (so non-root
  923. and no synthesiszed properties).
  924. */
  925. void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
  926. {
  927. QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
  928. QObject *object = component.create();
  929. QVERIFY(object != 0);
  930. }
  931. /*
  932. Test file/lineNumbers for binding/Script errors.
  933. */
  934. void tst_qdeclarativeecmascript::scriptErrors()
  935. {
  936. QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
  937. QString url = component.url().toString();
  938. QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
  939. QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
  940. QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
  941. QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
  942. QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
  943. QString warning6 = url + ":7: Unable to assign [undefined] to int x";
  944. QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
  945. QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
  946. QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
  947. QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
  948. QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
  949. QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
  950. QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
  951. MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
  952. QVERIFY(object != 0);
  953. QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
  954. emit object->basicSignal();
  955. QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
  956. emit object->anotherBasicSignal();
  957. QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
  958. emit object->thirdBasicSignal();
  959. }
  960. /*
  961. Test file/lineNumbers for inline functions.
  962. */
  963. void tst_qdeclarativeecmascript::functionErrors()
  964. {
  965. QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
  966. QString url = component.url().toString();
  967. QString warning = url + ":5: Error: Invalid write to global property \"a\"";
  968. QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
  969. QObject *object = component.create();
  970. QVERIFY(object != 0);
  971. delete object;
  972. }
  973. /*
  974. Test various errors that can occur when assigning a property from script
  975. */
  976. void tst_qdeclarativeecmascript::propertyAssignmentErrors()
  977. {
  978. QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
  979. QString url = component.url().toString();
  980. QString warning1 = url + ":11:Error: Cannot assign [undefined] to int";
  981. QString warning2 = url + ":17:Error: Cannot assign QString to int";
  982. QTest::ignoreMessage(QtDebugMsg, warning1.toLatin1().constData());
  983. QTest::ignoreMessage(QtDebugMsg, warning2.toLatin1().constData());
  984. QObject *object = component.create();
  985. QVERIFY(object != 0);
  986. delete object;
  987. }
  988. /*
  989. Test bindings still work when the reeval is triggered from within
  990. a signal script.
  991. */
  992. void tst_qdeclarativeecmascript::signalTriggeredBindings()
  993. {
  994. QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
  995. MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
  996. QVERIFY(object != 0);
  997. QCOMPARE(object->property("base").toReal(), 50.);
  998. QCOMPARE(object->property("test1").toReal(), 50.);
  999. QCOMPARE(object->property("test2").toReal(), 50.);
  1000. object->basicSignal();
  1001. QCOMPARE(object->property("base").toReal(), 200.);
  1002. QCOMPARE(object->property("test1").toReal(), 200.);
  1003. QCOMPARE(object->property("test2").toReal(), 200.);
  1004. object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
  1005. QCOMPARE(object->property("base").toReal(), 400.);
  1006. QCOMPARE(object->property("test1").toReal(), 400.);
  1007. QCOMPARE(object->property("test2").toReal(), 400.);
  1008. }
  1009. /*
  1010. Test that list properties can be iterated from ECMAScript
  1011. */
  1012. void tst_qdeclarativeecmascript::listProperties()
  1013. {
  1014. QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
  1015. MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
  1016. QVERIFY(object != 0);
  1017. QCOMPARE(object->property("test1").toInt(), 21);
  1018. QCOMPARE(object->property("test2").toInt(), 2);
  1019. QCOMPARE(object->property("test3").toBool(), true);
  1020. QCOMPARE(object->property("test4").toBool(), true);
  1021. }
  1022. void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
  1023. {
  1024. QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
  1025. QString url = component.url().toString();
  1026. QString warning = url + ":4: TypeError: Result of expression 'objectProperty' [null] is not an object.";
  1027. QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
  1028. MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
  1029. QVERIFY(object != 0);
  1030. QCOMPARE(object->property("test").toBool(), false);
  1031. MyQmlObject object2;
  1032. MyQmlObject object3;
  1033. object2.setObjectProperty(&object3);
  1034. object->setObjectProperty(&object2);
  1035. QCOMPARE(object->property("test").toBool(), true);
  1036. }
  1037. void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
  1038. {
  1039. QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
  1040. QString url = component.url().toString();
  1041. QString warning = component.url().toString() + ":6: Error: JS exception";
  1042. QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
  1043. MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
  1044. QVERIFY(object != 0);
  1045. }
  1046. void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
  1047. {
  1048. QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
  1049. QString url = component.url().toString();
  1050. QString warning = component.url().toString() + ":5: Error: JS exception";
  1051. QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
  1052. MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
  1053. QVERIFY(object != 0);
  1054. }
  1055. static int transientErrorsMsgCount = 0;
  1056. static void transientErrorsMsgHandler(QtMsgType, const char *)
  1057. {
  1058. ++transientErrorsMsgCount;
  1059. }
  1060. // Check that transient binding errors are not displayed
  1061. void tst_qdeclarativeecmascript::transientErrors()
  1062. {
  1063. {
  1064. QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
  1065. transientErrorsMsgCount = 0;
  1066. QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
  1067. QObject *object = component.create();
  1068. QVERIFY(object != 0);
  1069. qInstallMsgHandler(old);
  1070. QCOMPARE(transientErrorsMsgCount, 0);
  1071. }
  1072. // One binding erroring multiple times, but then resolving
  1073. {
  1074. QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
  1075. transientErrorsMsgCount = 0;
  1076. QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
  1077. QObject *object = component.create();
  1078. QVERIFY(object != 0);
  1079. qInstallMsgHandler(old);
  1080. QCOMPARE(transientErrorsMsgCount, 0);
  1081. }
  1082. }
  1083. // Check that errors during shutdown are minimized
  1084. void tst_qdeclarativeecmascript::shutdownErrors()
  1085. {
  1086. QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
  1087. QObject *object = component.create();
  1088. QVERIFY(object != 0);
  1089. transientErrorsMsgCount = 0;
  1090. QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
  1091. delete object;
  1092. qInstallMsgHandler(old);
  1093. QCOMPARE(transientErrorsMsgCount, 0);
  1094. }
  1095. void tst_qdeclarativeecmascript::compositePropertyType()
  1096. {
  1097. QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
  1098. QTest::ignoreMessage(QtDebugMsg, "hello world");
  1099. QObject *object = qobject_cast<QObject *>(component.create());
  1100. delete object;
  1101. }
  1102. // QTBUG-5759
  1103. void tst_qdeclarativeecmascript::jsObject()
  1104. {
  1105. QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
  1106. QObject *object = component.create();
  1107. QVERIFY(object != 0);
  1108. QCOMPARE(object->property("test").toInt(), 92);
  1109. delete object;
  1110. }
  1111. void tst_qdeclarativeecmascript::undefinedResetsProperty()
  1112. {
  1113. {
  1114. QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
  1115. QObject *object = component.create();
  1116. QVERIFY(object != 0);
  1117. QCOMPARE(object->property("resettableProperty").toInt(), 92);
  1118. object->setProperty("setUndefined", true);
  1119. QCOMPARE(object->property("resettableProperty").toInt(), 13);
  1120. object->setProperty("setUndefined", false);
  1121. QCOMPARE(object->property("resettableProperty").toInt(), 92);
  1122. delete object;
  1123. }
  1124. {
  1125. QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
  1126. QObject *object = component.create();
  1127. QVERIFY(object != 0);
  1128. QCOMPARE(object->property("resettableProperty").toInt(), 19);
  1129. QMetaObject::invokeMethod(object, "doReset");
  1130. QCOMPARE(object->property("resettableProperty").toInt(), 13);
  1131. delete object;
  1132. }
  1133. }
  1134. // QTBUG-6781
  1135. void tst_qdeclarativeecmascript::bug1()
  1136. {
  1137. QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
  1138. QObject *object = component.create();
  1139. QVERIFY(object != 0);
  1140. QCOMPARE(object->property("test").toInt(), 14);
  1141. object->setProperty("a", 11);
  1142. QCOMPARE(object->property("test").toInt(), 3);
  1143. object->setProperty("b", true);
  1144. QCOMPARE(object->property("test").toInt(), 9);
  1145. delete object;
  1146. }
  1147. void tst_qdeclarativeecmascript::bug2()
  1148. {
  1149. QDeclarativeComponent component(&engine);
  1150. component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
  1151. QObject *object = component.create();
  1152. QVERIFY(object != 0);
  1153. delete object;
  1154. }
  1155. // Don't crash in createObject when the component has errors.
  1156. void tst_qdeclarativeecmascript::dynamicCreationCrash()
  1157. {
  1158. QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
  1159. MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
  1160. QVERIFY(object != 0);
  1161. QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
  1162. QMetaObject::invokeMethod(object, "dontCrash");
  1163. QObject *created = object->objectProperty();
  1164. QVERIFY(created == 0);
  1165. }
  1166. //QTBUG-9367
  1167. void tst_qdeclarativeecmascript::regExpBug()
  1168. {
  1169. QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
  1170. MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
  1171. QVERIFY(object != 0);
  1172. QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
  1173. }
  1174. void tst_qdeclarativeecmascript::callQtInvokables()
  1175. {
  1176. MyInvokableObject o;
  1177. QDeclarativeEngine qmlengine;
  1178. QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
  1179. QScriptEngine *engine = &ep->scriptEngine;
  1180. QStringList names; QList<QScriptValue> values;
  1181. names << QLatin1String("object"); values << ep->objectClass->newQObject(&o);
  1182. names << QLatin1String("undefined"); values << engine->undefinedValue();
  1183. ep->globalClass->explicitSetProperty(names, values);
  1184. // Non-existent methods
  1185. o.reset();
  1186. QCOMPARE(engine->evaluate("object.method_nonexistent()").isError(