Remove "All rights reserved" line from license headers.
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / 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, QJSValue(&engine, value));
113     }
114     QJSValue otherObject = engine.newObject();
115     otherObject.setProperty("foo", QJSValue(&engine, 123456));
116     otherObject.setProperty("protoProperty", QJSValue(&engine, 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(QJSValue(&engine, 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 str = QJSValue(&engine, QString::fromLatin1("ciao"));
286     QVERIFY(str.isString());
287     QJSValue obj = str.toObject();
288     QVERIFY(obj.property("length").isNumber());
289     int length = obj.property("length").toInt();
290     QCOMPARE(length, 4);
291
292     QJSValueIterator it(obj);
293     QHash<QString, QJSValue> stringProperties;
294     bool iteratedThruLength = false;
295
296     while (it.hasNext()) {
297         it.next();
298         const QString name = it.name();
299
300         if (name == QString::fromLatin1("length")) {
301             QVERIFY(it.value().isNumber());
302             QCOMPARE(it.value().toInt(), length);
303             QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
304             iteratedThruLength = true;
305             continue;
306         }
307
308         QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
309         stringProperties.insert(name, it.value());
310         QVERIFY(it.value().strictlyEquals(obj.property(name)));
311     }
312
313     QVERIFY(iteratedThruLength);
314     QCOMPARE(stringProperties.size(), length);
315 #if 0
316     // And going backwards
317     iteratedThruLength = false;
318     stringProperties.clear();
319     it.toBack();
320
321     while (it.hasPrevious()) {
322         it.previous();
323         const QString name = it.name();
324
325         if (name == QString::fromLatin1("length")) {
326             QVERIFY(it.value().isNumber());
327             QCOMPARE(it.value().toInt(), length);
328             QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
329             iteratedThruLength = true;
330             continue;
331         }
332
333         QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
334         stringProperties.insert(name, it.value());
335         QVERIFY(it.value().strictlyEquals(obj.property(name)));
336     }
337 #endif
338 }
339
340 #if 0 // FIXME what we should to keep from here?
341 static QJSValue myGetterSetter(QScriptContext *ctx, QJSEngine *)
342 {
343     if (ctx->argumentCount() == 1)
344         ctx->thisObject().setProperty("bar", ctx->argument(0));
345     return ctx->thisObject().property("bar");
346 }
347
348 static QJSValue myGetter(QScriptContext *ctx, QJSEngine *)
349 {
350     return ctx->thisObject().property("bar");
351 }
352
353 static QJSValue mySetter(QScriptContext *ctx, QJSEngine *)
354 {
355     ctx->thisObject().setProperty("bar", ctx->argument(0));
356     return ctx->argument(0);
357 }
358
359 void tst_QJSValueIterator::iterateGetterSetter()
360 {
361     // unified getter/setter function
362     {
363         QJSEngine eng;
364         QJSValue obj = eng.newObject();
365         obj.setProperty("foo", eng.newFunction(myGetterSetter),
366                         QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
367         QJSValue val(&eng, 123);
368         obj.setProperty("foo", val);
369         QVERIFY(obj.property("bar").strictlyEquals(val));
370         QVERIFY(obj.property("foo").strictlyEquals(val));
371
372         QJSValueIterator it(obj);
373         QVERIFY(it.hasNext());
374         it.next();
375         QCOMPARE(it.name(), QString::fromLatin1("foo"));
376         QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
377         QVERIFY(it.value().strictlyEquals(val));
378         QJSValue val2(&eng, 456);
379         it.setValue(val2);
380         QVERIFY(obj.property("bar").strictlyEquals(val2));
381         QVERIFY(obj.property("foo").strictlyEquals(val2));
382
383         QVERIFY(it.hasNext());
384         it.next();
385         QCOMPARE(it.name(), QString::fromLatin1("bar"));
386         QVERIFY(!it.hasNext());
387
388         QVERIFY(it.hasPrevious());
389         it.previous();
390         QCOMPARE(it.name(), QString::fromLatin1("bar"));
391         QVERIFY(it.hasPrevious());
392         it.previous();
393         QCOMPARE(it.name(), QString::fromLatin1("foo"));
394         QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
395         QVERIFY(it.value().strictlyEquals(val2));
396         it.setValue(val);
397         QVERIFY(obj.property("bar").strictlyEquals(val));
398         QVERIFY(obj.property("foo").strictlyEquals(val));
399     }
400     // separate getter/setter function
401     for (int x = 0; x < 2; ++x) {
402         QJSEngine eng;
403         QJSValue obj = eng.newObject();
404         if (x == 0) {
405             obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
406             obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
407         } else {
408             obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
409             obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
410         }
411         QJSValue val(&eng, 123);
412         obj.setProperty("foo", val);
413         QVERIFY(obj.property("bar").strictlyEquals(val));
414         QVERIFY(obj.property("foo").strictlyEquals(val));
415
416         QJSValueIterator it(obj);
417         QVERIFY(it.hasNext());
418         it.next();
419         QCOMPARE(it.name(), QString::fromLatin1("foo"));
420         QVERIFY(it.value().strictlyEquals(val));
421         QJSValue val2(&eng, 456);
422         it.setValue(val2);
423         QVERIFY(obj.property("bar").strictlyEquals(val2));
424         QVERIFY(obj.property("foo").strictlyEquals(val2));
425
426         QVERIFY(it.hasNext());
427         it.next();
428         QCOMPARE(it.name(), QString::fromLatin1("bar"));
429         QVERIFY(!it.hasNext());
430
431         QVERIFY(it.hasPrevious());
432         it.previous();
433         QCOMPARE(it.name(), QString::fromLatin1("bar"));
434         QVERIFY(it.hasPrevious());
435         it.previous();
436         QCOMPARE(it.name(), QString::fromLatin1("foo"));
437         QVERIFY(it.value().strictlyEquals(val2));
438         it.setValue(val);
439         QVERIFY(obj.property("bar").strictlyEquals(val));
440         QVERIFY(obj.property("foo").strictlyEquals(val));
441     }
442 }
443 #endif
444
445 void tst_QJSValueIterator::assignObjectToIterator()
446 {
447     QJSEngine eng;
448     QJSValue obj1 = eng.newObject();
449     obj1.setProperty("foo", 123);
450     QJSValue obj2 = eng.newObject();
451     obj2.setProperty("bar", 456);
452
453     QJSValueIterator it(obj1);
454     QVERIFY(it.hasNext());
455     it.next();
456     it = obj2;
457     QVERIFY(it.hasNext());
458     it.next();
459     QCOMPARE(it.name(), QString::fromLatin1("bar"));
460
461     it = obj1;
462     QVERIFY(it.hasNext());
463     it.next();
464     QCOMPARE(it.name(), QString::fromLatin1("foo"));
465
466     it = obj2;
467     QVERIFY(it.hasNext());
468     it.next();
469     QCOMPARE(it.name(), QString::fromLatin1("bar"));
470
471     it = obj2;
472     QVERIFY(it.hasNext());
473     it.next();
474     QCOMPARE(it.name(), QString::fromLatin1("bar"));
475 }
476
477 void tst_QJSValueIterator::iterateNonObject()
478 {
479     QJSValueIterator it(123);
480     QVERIFY(!it.hasNext());
481     it.next();
482     it.name();
483     it.value();
484     QJSValue num(5);
485     it = num;
486     QVERIFY(!it.hasNext());
487 }
488
489 void tst_QJSValueIterator::iterateOverObjectFromDeletedEngine()
490 {
491     QJSEngine *engine = new QJSEngine;
492     QJSValue objet = engine->newObject();
493
494     // populate object with properties
495     QHash<QString, int> properties;
496     properties.insert("foo",1235);
497     properties.insert("oof",5321);
498     properties.insert("ofo",3521);
499     QHash<QString, int>::const_iterator i = properties.constBegin();
500     for (; i != properties.constEnd(); ++i) {
501         objet.setProperty(i.key(), i.value());
502     }
503
504     // start iterating
505     QJSValueIterator it(objet);
506     it.next();
507     QVERIFY(properties.contains(it.name()));
508
509     delete engine;
510
511     QVERIFY(!objet.isValid());
512     QVERIFY(it.name().isEmpty());
513     QVERIFY(!it.value().isValid());
514
515     QVERIFY(!it.hasNext());
516     it.next();
517
518     QVERIFY(it.name().isEmpty());
519     QVERIFY(!it.value().isValid());
520
521 }
522
523 QTEST_MAIN(tst_QJSValueIterator)
524 #include "tst_qjsvalueiterator.moc"