QML_RUNTIME_TESTING should be disabled by default.
[profile/ivi/qtdeclarative.git] / tests / auto / qml / qjsvalueiterator / tst_qjsvalueiterator.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44
45 #include <QJSEngine>
46 #include <QJSValue>
47 #include <QJSValueIterator>
48
49 Q_DECLARE_METATYPE(QJSValue);
50
51 class tst_QJSValueIterator : public QObject
52 {
53     Q_OBJECT
54
55 public:
56     tst_QJSValueIterator();
57     virtual ~tst_QJSValueIterator();
58
59 private slots:
60     void iterateForward_data();
61     void iterateForward();
62     void iterateArray_data();
63     void iterateArray();
64     void iterateString();
65 #if 0
66     void iterateGetterSetter();
67 #endif
68     void assignObjectToIterator();
69     void iterateNonObject();
70     void iterateOverObjectFromDeletedEngine();
71 };
72
73 tst_QJSValueIterator::tst_QJSValueIterator()
74 {
75 }
76
77 tst_QJSValueIterator::~tst_QJSValueIterator()
78 {
79 }
80
81 void tst_QJSValueIterator::iterateForward_data()
82 {
83     QTest::addColumn<QStringList>("propertyNames");
84     QTest::addColumn<QStringList>("propertyValues");
85
86     QTest::newRow("no properties")
87         << QStringList() << QStringList();
88     QTest::newRow("foo=bar")
89         << (QStringList() << "foo")
90         << (QStringList() << "bar");
91     QTest::newRow("foo=bar, baz=123")
92         << (QStringList() << "foo" << "baz")
93         << (QStringList() << "bar" << "123");
94     QTest::newRow("foo=bar, baz=123, rab=oof")
95         << (QStringList() << "foo" << "baz" << "rab")
96         << (QStringList() << "bar" << "123" << "oof");
97 }
98
99 void tst_QJSValueIterator::iterateForward()
100 {
101     QFETCH(QStringList, propertyNames);
102     QFETCH(QStringList, propertyValues);
103     QMap<QString, QString> pmap;
104     QVERIFY(propertyNames.size() == propertyValues.size());
105
106     QJSEngine engine;
107     QJSValue object = engine.newObject();
108     for (int i = 0; i < propertyNames.size(); ++i) {
109         QString name = propertyNames.at(i);
110         QString value = propertyValues.at(i);
111         pmap.insert(name, value);
112         object.setProperty(name, engine.toScriptValue(value));
113     }
114     QJSValue otherObject = engine.newObject();
115     otherObject.setProperty("foo", engine.toScriptValue(123456));
116     otherObject.setProperty("protoProperty", engine.toScriptValue(654321));
117     object.setPrototype(otherObject); // should not affect iterator
118
119     QStringList lst;
120     QJSValueIterator it(object);
121     while (!pmap.isEmpty()) {
122         QCOMPARE(it.hasNext(), true);
123         QCOMPARE(it.hasNext(), true);
124         it.next();
125         QString name = it.name();
126         QCOMPARE(pmap.contains(name), true);
127         QCOMPARE(it.name(), name);
128         QCOMPARE(it.value().strictlyEquals(engine.toScriptValue(pmap.value(name))), true);
129         pmap.remove(name);
130         lst.append(name);
131     }
132
133     QCOMPARE(it.hasNext(), false);
134     QCOMPARE(it.hasNext(), false);
135
136     it = object;
137     for (int i = 0; i < lst.count(); ++i) {
138         QCOMPARE(it.hasNext(), true);
139         it.next();
140         QCOMPARE(it.name(), lst.at(i));
141     }
142 }
143
144 void tst_QJSValueIterator::iterateArray_data()
145 {
146     QTest::addColumn<QStringList>("propertyNames");
147     QTest::addColumn<QStringList>("propertyValues");
148
149     QTest::newRow("no elements") << QStringList() << QStringList();
150
151     QTest::newRow("0=foo, 1=barr")
152         << (QStringList() << "0" << "1")
153         << (QStringList() << "foo" << "bar");
154
155
156     QTest::newRow("0=foo, 3=barr")
157         << (QStringList() << "0" << "1" << "2" << "3")
158         << (QStringList() << "foo" << "" << "" << "bar");
159 }
160
161 void tst_QJSValueIterator::iterateArray()
162 {
163     QFETCH(QStringList, propertyNames);
164     QFETCH(QStringList, propertyValues);
165
166     QJSEngine engine;
167     QJSValue array = engine.newArray();
168
169     // Fill the array
170     for (int i = 0; i < propertyNames.size(); ++i) {
171         array.setProperty(propertyNames.at(i), propertyValues.at(i));
172     }
173
174     // Iterate thru array properties. Note that the QJSValueIterator doesn't guarantee
175     // any order on the iteration!
176     int length = array.property("length").toInt();
177     QCOMPARE(length, propertyNames.size());
178
179     bool iteratedThruLength = false;
180     QHash<QString, QJSValue> arrayProperties;
181     QJSValueIterator it(array);
182
183     // Iterate forward
184     while (it.hasNext()) {
185         it.next();
186
187         const QString name = it.name();
188         if (name == QString::fromLatin1("length")) {
189             QVERIFY(it.value().isNumber());
190             QCOMPARE(it.value().toInt(), length);
191             QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
192             iteratedThruLength = true;
193             continue;
194         }
195
196         // Storing the properties we iterate in a hash to compare with test data.
197         QVERIFY2(!arrayProperties.contains(name), "property appeared more than once during iteration.");
198         arrayProperties.insert(name, it.value());
199         QVERIFY(it.value().strictlyEquals(array.property(name)));
200     }
201
202     // Verify properties
203     QVERIFY(iteratedThruLength);
204     QCOMPARE(arrayProperties.size(), propertyNames.size());
205     for (int i = 0; i < propertyNames.size(); ++i) {
206         QVERIFY(arrayProperties.contains(propertyNames.at(i)));
207         QCOMPARE(arrayProperties.value(propertyNames.at(i)).toString(), propertyValues.at(i));
208     }
209
210 #if 0
211
212     // Iterate backwards
213     arrayProperties.clear();
214     iteratedThruLength = false;
215     it.toBack();
216
217     while (it.hasPrevious()) {
218         it.previous();
219
220         const QString name = it.name();
221         if (name == QString::fromLatin1("length")) {
222             QVERIFY(it.value().isNumber());
223             QCOMPARE(it.value().toInt(), length);
224             QCOMPARE(it.flags(), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
225             QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
226             iteratedThruLength = true;
227             continue;
228         }
229
230         // Storing the properties we iterate in a hash to compare with test data.
231         QVERIFY2(!arrayProperties.contains(name), "property appeared more than once during iteration.");
232         arrayProperties.insert(name, it.value());
233         QCOMPARE(it.flags(), array.propertyFlags(name));
234         QVERIFY(it.value().strictlyEquals(array.property(name)));
235     }
236
237     // Verify properties
238     QVERIFY(iteratedThruLength);
239     QCOMPARE(arrayProperties.size(), propertyNames.size());
240     for (int i = 0; i < propertyNames.size(); ++i) {
241         QVERIFY(arrayProperties.contains(propertyNames.at(i)));
242         QCOMPARE(arrayProperties.value(propertyNames.at(i)).toString(), propertyValues.at(i));
243     }
244
245     // ### Do we still need this test?
246     // Forward test again but as object
247     arrayProperties.clear();
248     iteratedThruLength = false;
249     QJSValue arrayObject = engine.toObject(array);
250     QJSValueIterator it2(arrayObject);
251
252     while (it2.hasNext()) {
253         it2.next();
254
255         const QString name = it2.name();
256         if (name == QString::fromLatin1("length")) {
257             QVERIFY(it2.value().isNumber());
258             QCOMPARE(it2.value().toInt(), length);
259             QCOMPARE(it2.flags(), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
260             QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
261             iteratedThruLength = true;
262             continue;
263         }
264
265         // Storing the properties we iterate in a hash to compare with test data.
266         QVERIFY2(!arrayProperties.contains(name), "property appeared more than once during iteration.");
267         arrayProperties.insert(name, it2.value());
268         QCOMPARE(it2.flags(), arrayObject.propertyFlags(name));
269         QVERIFY(it2.value().strictlyEquals(arrayObject.property(name)));
270     }
271
272     // Verify properties
273     QVERIFY(iteratedThruLength);
274     QCOMPARE(arrayProperties.size(), propertyNames.size());
275     for (int i = 0; i < propertyNames.size(); ++i) {
276         QVERIFY(arrayProperties.contains(propertyNames.at(i)));
277         QCOMPARE(arrayProperties.value(propertyNames.at(i)).toString(), propertyValues.at(i));
278     }
279 #endif
280 }
281
282 void tst_QJSValueIterator::iterateString()
283 {
284     QJSEngine engine;
285     QJSValue obj = engine.evaluate("new String('ciao')");
286     QVERIFY(obj.property("length").isNumber());
287     int length = obj.property("length").toInt();
288     QCOMPARE(length, 4);
289
290     QJSValueIterator it(obj);
291     QHash<QString, QJSValue> stringProperties;
292     bool iteratedThruLength = false;
293
294     while (it.hasNext()) {
295         it.next();
296         const QString name = it.name();
297
298         if (name == QString::fromLatin1("length")) {
299             QVERIFY(it.value().isNumber());
300             QCOMPARE(it.value().toInt(), length);
301             QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
302             iteratedThruLength = true;
303             continue;
304         }
305
306         QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
307         stringProperties.insert(name, it.value());
308         QVERIFY(it.value().strictlyEquals(obj.property(name)));
309     }
310
311     QVERIFY(iteratedThruLength);
312     QCOMPARE(stringProperties.size(), length);
313 #if 0
314     // And going backwards
315     iteratedThruLength = false;
316     stringProperties.clear();
317     it.toBack();
318
319     while (it.hasPrevious()) {
320         it.previous();
321         const QString name = it.name();
322
323         if (name == QString::fromLatin1("length")) {
324             QVERIFY(it.value().isNumber());
325             QCOMPARE(it.value().toInt(), length);
326             QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
327             iteratedThruLength = true;
328             continue;
329         }
330
331         QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
332         stringProperties.insert(name, it.value());
333         QVERIFY(it.value().strictlyEquals(obj.property(name)));
334     }
335 #endif
336 }
337
338 #if 0 // FIXME what we should to keep from here?
339 static QJSValue myGetterSetter(QScriptContext *ctx, QJSEngine *)
340 {
341     if (ctx->argumentCount() == 1)
342         ctx->thisObject().setProperty("bar", ctx->argument(0));
343     return ctx->thisObject().property("bar");
344 }
345
346 static QJSValue myGetter(QScriptContext *ctx, QJSEngine *)
347 {
348     return ctx->thisObject().property("bar");
349 }
350
351 static QJSValue mySetter(QScriptContext *ctx, QJSEngine *)
352 {
353     ctx->thisObject().setProperty("bar", ctx->argument(0));
354     return ctx->argument(0);
355 }
356
357 void tst_QJSValueIterator::iterateGetterSetter()
358 {
359     // unified getter/setter function
360     {
361         QJSEngine eng;
362         QJSValue obj = eng.newObject();
363         obj.setProperty("foo", eng.newFunction(myGetterSetter),
364                         QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
365         QJSValue val(&eng, 123);
366         obj.setProperty("foo", val);
367         QVERIFY(obj.property("bar").strictlyEquals(val));
368         QVERIFY(obj.property("foo").strictlyEquals(val));
369
370         QJSValueIterator it(obj);
371         QVERIFY(it.hasNext());
372         it.next();
373         QCOMPARE(it.name(), QString::fromLatin1("foo"));
374         QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
375         QVERIFY(it.value().strictlyEquals(val));
376         QJSValue val2(&eng, 456);
377         it.setValue(val2);
378         QVERIFY(obj.property("bar").strictlyEquals(val2));
379         QVERIFY(obj.property("foo").strictlyEquals(val2));
380
381         QVERIFY(it.hasNext());
382         it.next();
383         QCOMPARE(it.name(), QString::fromLatin1("bar"));
384         QVERIFY(!it.hasNext());
385
386         QVERIFY(it.hasPrevious());
387         it.previous();
388         QCOMPARE(it.name(), QString::fromLatin1("bar"));
389         QVERIFY(it.hasPrevious());
390         it.previous();
391         QCOMPARE(it.name(), QString::fromLatin1("foo"));
392         QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
393         QVERIFY(it.value().strictlyEquals(val2));
394         it.setValue(val);
395         QVERIFY(obj.property("bar").strictlyEquals(val));
396         QVERIFY(obj.property("foo").strictlyEquals(val));
397     }
398     // separate getter/setter function
399     for (int x = 0; x < 2; ++x) {
400         QJSEngine eng;
401         QJSValue obj = eng.newObject();
402         if (x == 0) {
403             obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
404             obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
405         } else {
406             obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
407             obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
408         }
409         QJSValue val(&eng, 123);
410         obj.setProperty("foo", val);
411         QVERIFY(obj.property("bar").strictlyEquals(val));
412         QVERIFY(obj.property("foo").strictlyEquals(val));
413
414         QJSValueIterator it(obj);
415         QVERIFY(it.hasNext());
416         it.next();
417         QCOMPARE(it.name(), QString::fromLatin1("foo"));
418         QVERIFY(it.value().strictlyEquals(val));
419         QJSValue val2(&eng, 456);
420         it.setValue(val2);
421         QVERIFY(obj.property("bar").strictlyEquals(val2));
422         QVERIFY(obj.property("foo").strictlyEquals(val2));
423
424         QVERIFY(it.hasNext());
425         it.next();
426         QCOMPARE(it.name(), QString::fromLatin1("bar"));
427         QVERIFY(!it.hasNext());
428
429         QVERIFY(it.hasPrevious());
430         it.previous();
431         QCOMPARE(it.name(), QString::fromLatin1("bar"));
432         QVERIFY(it.hasPrevious());
433         it.previous();
434         QCOMPARE(it.name(), QString::fromLatin1("foo"));
435         QVERIFY(it.value().strictlyEquals(val2));
436         it.setValue(val);
437         QVERIFY(obj.property("bar").strictlyEquals(val));
438         QVERIFY(obj.property("foo").strictlyEquals(val));
439     }
440 }
441 #endif
442
443 void tst_QJSValueIterator::assignObjectToIterator()
444 {
445     QJSEngine eng;
446     QJSValue obj1 = eng.newObject();
447     obj1.setProperty("foo", 123);
448     QJSValue obj2 = eng.newObject();
449     obj2.setProperty("bar", 456);
450
451     QJSValueIterator it(obj1);
452     QVERIFY(it.hasNext());
453     it.next();
454     it = obj2;
455     QVERIFY(it.hasNext());
456     it.next();
457     QCOMPARE(it.name(), QString::fromLatin1("bar"));
458
459     it = obj1;
460     QVERIFY(it.hasNext());
461     it.next();
462     QCOMPARE(it.name(), QString::fromLatin1("foo"));
463
464     it = obj2;
465     QVERIFY(it.hasNext());
466     it.next();
467     QCOMPARE(it.name(), QString::fromLatin1("bar"));
468
469     it = obj2;
470     QVERIFY(it.hasNext());
471     it.next();
472     QCOMPARE(it.name(), QString::fromLatin1("bar"));
473 }
474
475 void tst_QJSValueIterator::iterateNonObject()
476 {
477     QJSValueIterator it(123);
478     QVERIFY(!it.hasNext());
479     it.next();
480     it.name();
481     it.value();
482     QJSValue num(5);
483     it = num;
484     QVERIFY(!it.hasNext());
485 }
486
487 void tst_QJSValueIterator::iterateOverObjectFromDeletedEngine()
488 {
489     QJSEngine *engine = new QJSEngine;
490     QJSValue objet = engine->newObject();
491
492     // populate object with properties
493     QHash<QString, int> properties;
494     properties.insert("foo",1235);
495     properties.insert("oof",5321);
496     properties.insert("ofo",3521);
497     QHash<QString, int>::const_iterator i = properties.constBegin();
498     for (; i != properties.constEnd(); ++i) {
499         objet.setProperty(i.key(), i.value());
500     }
501
502     // start iterating
503     QJSValueIterator it(objet);
504     it.next();
505     QVERIFY(properties.contains(it.name()));
506
507     delete engine;
508
509     QVERIFY(objet.isUndefined());
510     QVERIFY(it.name().isEmpty());
511     QVERIFY(it.value().isUndefined());
512
513     QVERIFY(!it.hasNext());
514     it.next();
515
516     QVERIFY(it.name().isEmpty());
517     QVERIFY(it.value().isUndefined());
518
519 }
520
521 QTEST_MAIN(tst_QJSValueIterator)
522 #include "tst_qjsvalueiterator.moc"