initial import
[vuplus_webkit] / Source / JavaScriptCore / qt / tests / qscriptvalueiterator / tst_qscriptvalueiterator.cpp
1 /*
2     Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3
4     This library is free software; you can redistribute it and/or
5     modify it under the terms of the GNU Library General Public
6     License as published by the Free Software Foundation; either
7     version 2 of the License, or (at your option) any later version.
8
9     This library is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12     Library General Public License for more details.
13
14     You should have received a copy of the GNU Library General Public License
15     along with this library; see the file COPYING.LIB.  If not, write to
16     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17     Boston, MA 02110-1301, USA.
18 */
19
20 #ifndef tst_qscriptvalueiterator_h
21 #define tst_qscriptvalueiterator_h
22
23 #include "qscriptengine.h"
24 #include "qscriptvalue.h"
25 #include "qscriptvalueiterator.h"
26 #include <QtCore/qhash.h>
27 #include <QtTest/QtTest>
28
29 class tst_QScriptValueIterator : public QObject {
30     Q_OBJECT
31
32 public:
33     tst_QScriptValueIterator();
34     virtual ~tst_QScriptValueIterator();
35
36 private slots:
37     void iterateForward_data();
38     void iterateForward();
39     void iterateBackward_data();
40     void iterateBackward();
41     void iterateArray_data();
42     void iterateArray();
43     void iterateBackAndForth();
44     void setValue();
45     void remove();
46     void removeMixed();
47     void removeUndeletable();
48     void iterateString();
49     void assignObjectToIterator();
50 };
51
52 tst_QScriptValueIterator::tst_QScriptValueIterator()
53 {
54 }
55
56 tst_QScriptValueIterator::~tst_QScriptValueIterator()
57 {
58 }
59
60 void tst_QScriptValueIterator::iterateForward_data()
61 {
62     QTest::addColumn<QStringList>("propertyNames");
63     QTest::addColumn<QStringList>("propertyValues");
64
65     QTest::newRow("no properties")
66         << QStringList() << QStringList();
67     QTest::newRow("foo=bar")
68         << (QStringList() << "foo")
69         << (QStringList() << "bar");
70     QTest::newRow("foo=bar, baz=123")
71         << (QStringList() << "foo" << "baz")
72         << (QStringList() << "bar" << "123");
73     QTest::newRow("foo=bar, baz=123, rab=oof")
74         << (QStringList() << "foo" << "baz" << "rab")
75         << (QStringList() << "bar" << "123" << "oof");
76 }
77
78 void tst_QScriptValueIterator::iterateForward()
79 {
80     QFETCH(QStringList, propertyNames);
81     QFETCH(QStringList, propertyValues);
82     QMap<QString, QString> pmap;
83     Q_ASSERT(propertyNames.size() == propertyValues.size());
84
85     QScriptEngine engine;
86     QScriptValue object = engine.newObject();
87     for (int i = 0; i < propertyNames.size(); ++i) {
88         QString name = propertyNames.at(i);
89         QString value = propertyValues.at(i);
90         pmap.insert(name, value);
91         object.setProperty(name, QScriptValue(&engine, value));
92     }
93     QScriptValue otherObject = engine.newObject();
94     otherObject.setProperty("foo", QScriptValue(&engine, 123456));
95     otherObject.setProperty("protoProperty", QScriptValue(&engine, 654321));
96     object.setPrototype(otherObject); // should not affect iterator
97
98     QStringList lst;
99     QScriptValueIterator it(object);
100     while (!pmap.isEmpty()) {
101         QCOMPARE(it.hasNext(), true);
102         QCOMPARE(it.hasNext(), true);
103         it.next();
104         QString name = it.name();
105         QCOMPARE(pmap.contains(name), true);
106         QCOMPARE(it.name(), name);
107         QCOMPARE(it.flags(), object.propertyFlags(name));
108         QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
109         QCOMPARE(it.scriptName(), engine.toStringHandle(name));
110         pmap.remove(name);
111         lst.append(name);
112     }
113
114     QCOMPARE(it.hasNext(), false);
115     QCOMPARE(it.hasNext(), false);
116
117     it.toFront();
118     for (int i = 0; i < lst.count(); ++i) {
119         QCOMPARE(it.hasNext(), true);
120         it.next();
121         QCOMPARE(it.name(), lst.at(i));
122     }
123
124     for (int i = 0; i < lst.count(); ++i) {
125         QCOMPARE(it.hasPrevious(), true);
126         it.previous();
127         QCOMPARE(it.name(), lst.at(lst.count()-1-i));
128     }
129     QCOMPARE(it.hasPrevious(), false);
130 }
131
132 void tst_QScriptValueIterator::iterateBackward_data()
133 {
134     iterateForward_data();
135 }
136
137 void tst_QScriptValueIterator::iterateBackward()
138 {
139     QFETCH(QStringList, propertyNames);
140     QFETCH(QStringList, propertyValues);
141     QMap<QString, QString> pmap;
142     Q_ASSERT(propertyNames.size() == propertyValues.size());
143
144     QScriptEngine engine;
145     QScriptValue object = engine.newObject();
146     for (int i = 0; i < propertyNames.size(); ++i) {
147         QString name = propertyNames.at(i);
148         QString value = propertyValues.at(i);
149         pmap.insert(name, value);
150         object.setProperty(name, QScriptValue(&engine, value));
151     }
152
153     QStringList lst;
154     QScriptValueIterator it(object);
155     it.toBack();
156     while (!pmap.isEmpty()) {
157         QCOMPARE(it.hasPrevious(), true);
158         QCOMPARE(it.hasPrevious(), true);
159         it.previous();
160         QString name = it.name();
161         QCOMPARE(pmap.contains(name), true);
162         QCOMPARE(it.name(), name);
163         QCOMPARE(it.flags(), object.propertyFlags(name));
164         QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
165         pmap.remove(name);
166         lst.append(name);
167     }
168
169     QCOMPARE(it.hasPrevious(), false);
170     QCOMPARE(it.hasPrevious(), false);
171
172     it.toBack();
173     for (int i = 0; i < lst.count(); ++i) {
174         QCOMPARE(it.hasPrevious(), true);
175         it.previous();
176         QCOMPARE(it.name(), lst.at(i));
177     }
178
179     for (int i = 0; i < lst.count(); ++i) {
180         QCOMPARE(it.hasNext(), true);
181         it.next();
182         QCOMPARE(it.name(), lst.at(lst.count()-1-i));
183     }
184     QCOMPARE(it.hasNext(), false);
185 }
186
187 void tst_QScriptValueIterator::iterateArray_data()
188 {
189     QTest::addColumn<QStringList>("inputPropertyNames");
190     QTest::addColumn<QStringList>("inputPropertyValues");
191     QTest::addColumn<QStringList>("propertyNames");
192     QTest::addColumn<QStringList>("propertyValues");
193     QTest::newRow("no elements") << QStringList() << QStringList() << QStringList() << QStringList();
194
195     QTest::newRow("0=foo, 1=barr")
196         << (QStringList() << "0" << "1")
197         << (QStringList() << "foo" << "bar")
198         << (QStringList() << "0" << "1")
199         << (QStringList() << "foo" << "bar");
200
201     QTest::newRow("0=foo, 3=barr")
202         << (QStringList() << "0" << "1" << "2" << "3")
203         << (QStringList() << "foo" << "" << "" << "bar")
204         << (QStringList() << "0" << "1" << "2" << "3")
205         << (QStringList() << "foo" << "" << "" << "bar");
206 }
207
208 void tst_QScriptValueIterator::iterateArray()
209 {
210     QFETCH(QStringList, inputPropertyNames);
211     QFETCH(QStringList, inputPropertyValues);
212     QFETCH(QStringList, propertyNames);
213     QFETCH(QStringList, propertyValues);
214
215     QScriptEngine engine;
216     QScriptValue array = engine.newArray();
217     for (int i = 0; i < inputPropertyNames.size(); ++i)
218         array.setProperty(inputPropertyNames.at(i), inputPropertyValues.at(i));
219
220     int length = array.property("length").toInt32();
221     QCOMPARE(length, propertyNames.size());
222     QScriptValueIterator it(array);
223     for (int i = 0; i < length; ++i) {
224         QCOMPARE(it.hasNext(), true);
225         it.next();
226         QCOMPARE(it.name(), propertyNames.at(i));
227         QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
228         QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
229         QCOMPARE(it.value().toString(), propertyValues.at(i));
230     }
231     QVERIFY(it.hasNext());
232     it.next();
233     QCOMPARE(it.name(), QString::fromLatin1("length"));
234     QVERIFY(it.value().isNumber());
235     QCOMPARE(it.value().toInt32(), length);
236     QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::SkipInEnumeration | QScriptValue::Undeletable));
237
238     it.previous();
239     QCOMPARE(it.hasPrevious(), length > 0);
240     for (int i = length - 1; i >= 0; --i) {
241         it.previous();
242         QCOMPARE(it.name(), propertyNames.at(i));
243         QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
244         QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
245         QCOMPARE(it.value().toString(), propertyValues.at(i));
246         QCOMPARE(it.hasPrevious(), i > 0);
247     }
248     QCOMPARE(it.hasPrevious(), false);
249
250     // hasNext() and hasPrevious() cache their result; verify that the result is in sync
251     if (length > 1) {
252         QVERIFY(it.hasNext());
253         it.next();
254         QCOMPARE(it.name(), QString::fromLatin1("0"));
255         QVERIFY(it.hasNext());
256         it.previous();
257         QCOMPARE(it.name(), QString::fromLatin1("0"));
258         QVERIFY(!it.hasPrevious());
259         it.next();
260         QCOMPARE(it.name(), QString::fromLatin1("0"));
261         QVERIFY(it.hasPrevious());
262         it.next();
263         QCOMPARE(it.name(), QString::fromLatin1("1"));
264     }
265     {
266         // same test as object:
267         QScriptValue originalArray = engine.newArray();
268         for (int i = 0; i < inputPropertyNames.size(); ++i)
269             originalArray.setProperty(inputPropertyNames.at(i), inputPropertyValues.at(i));
270
271         QScriptValue array = originalArray.toObject();
272         int length = array.property("length").toInt32();
273         QCOMPARE(length, propertyNames.size());
274         QScriptValueIterator it(array);
275         for (int i = 0; i < length; ++i) {
276             QCOMPARE(it.hasNext(), true);
277             it.next();
278             QCOMPARE(it.name(), propertyNames.at(i));
279             QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
280             QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
281             QCOMPARE(it.value().toString(), propertyValues.at(i));
282         }
283         QCOMPARE(it.hasNext(), true);
284         it.next();
285         QCOMPARE(it.name(), QString::fromLatin1("length"));
286     }
287 }
288
289 void tst_QScriptValueIterator::iterateBackAndForth()
290 {
291     QScriptEngine engine;
292     {
293         QScriptValue object = engine.newObject();
294         object.setProperty("foo", QScriptValue(&engine, "bar"));
295         object.setProperty("rab", QScriptValue(&engine, "oof"),
296                            QScriptValue::SkipInEnumeration); // should not affect iterator
297         QScriptValueIterator it(object);
298         QVERIFY(it.hasNext());
299         it.next();
300         QCOMPARE(it.name(), QLatin1String("foo"));
301         QVERIFY(it.hasPrevious());
302         it.previous();
303         QCOMPARE(it.name(), QLatin1String("foo"));
304         QVERIFY(it.hasNext());
305         it.next();
306         QCOMPARE(it.name(), QLatin1String("foo"));
307         QVERIFY(it.hasPrevious());
308         it.previous();
309         QCOMPARE(it.name(), QLatin1String("foo"));
310         QVERIFY(it.hasNext());
311         it.next();
312         QCOMPARE(it.name(), QLatin1String("foo"));
313         QVERIFY(it.hasNext());
314         it.next();
315         QCOMPARE(it.name(), QLatin1String("rab"));
316         QVERIFY(it.hasPrevious());
317         it.previous();
318         QCOMPARE(it.name(), QLatin1String("rab"));
319         QVERIFY(it.hasNext());
320         it.next();
321         QCOMPARE(it.name(), QLatin1String("rab"));
322         QVERIFY(it.hasPrevious());
323         it.previous();
324         QCOMPARE(it.name(), QLatin1String("rab"));
325     }
326     {
327         // hasNext() and hasPrevious() cache their result; verify that the result is in sync
328         QScriptValue object = engine.newObject();
329         object.setProperty("foo", QScriptValue(&engine, "bar"));
330         object.setProperty("rab", QScriptValue(&engine, "oof"));
331         QScriptValueIterator it(object);
332         QVERIFY(it.hasNext());
333         it.next();
334         QCOMPARE(it.name(), QString::fromLatin1("foo"));
335         QVERIFY(it.hasNext());
336         it.previous();
337         QCOMPARE(it.name(), QString::fromLatin1("foo"));
338         QVERIFY(!it.hasPrevious());
339         it.next();
340         QCOMPARE(it.name(), QString::fromLatin1("foo"));
341         QVERIFY(it.hasPrevious());
342         it.next();
343         QCOMPARE(it.name(), QString::fromLatin1("rab"));
344     }
345 }
346
347 void tst_QScriptValueIterator::setValue()
348 {
349     QScriptEngine engine;
350     QScriptValue object = engine.newObject();
351     object.setProperty("foo", QScriptValue(&engine, "bar"));
352     QScriptValueIterator it(object);
353     it.next();
354     QCOMPARE(it.name(), QLatin1String("foo"));
355     it.setValue(QScriptValue(&engine, "baz"));
356     QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("baz"))), true);
357     QCOMPARE(object.property("foo").toString(), QLatin1String("baz"));
358     it.setValue(QScriptValue(&engine, "zab"));
359     QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("zab"))), true);
360     QCOMPARE(object.property("foo").toString(), QLatin1String("zab"));
361 }
362
363 void tst_QScriptValueIterator::remove()
364 {
365     QScriptEngine engine;
366     QScriptValue object = engine.newObject();
367     object.setProperty("foo", QScriptValue(&engine, "bar"),
368                        QScriptValue::SkipInEnumeration); // should not affect iterator
369     object.setProperty("rab", QScriptValue(&engine, "oof"));
370     QScriptValueIterator it(object);
371     it.next();
372     QCOMPARE(it.name(), QLatin1String("foo"));
373     it.remove();
374     QCOMPARE(it.hasPrevious(), false);
375     QCOMPARE(object.property("foo").isValid(), false);
376     QCOMPARE(object.property("rab").toString(), QLatin1String("oof"));
377     it.next();
378     QCOMPARE(it.name(), QLatin1String("rab"));
379     QCOMPARE(it.value().toString(), QLatin1String("oof"));
380     QCOMPARE(it.hasNext(), false);
381     it.remove();
382     QCOMPARE(object.property("rab").isValid(), false);
383     QCOMPARE(it.hasPrevious(), false);
384     QCOMPARE(it.hasNext(), false);
385 }
386
387 void tst_QScriptValueIterator::removeMixed()
388 {
389     // This test checks if QScriptValueIterator behaives correctly if an object's property got deleted
390     // in different way.
391     QScriptEngine engine;
392     QScriptValue object = engine.evaluate("o = new Object; o");
393     object.setProperty("a", QScriptValue(124), QScriptValue::SkipInEnumeration);
394     object.setProperty("b", QScriptValue(816));
395     object.setProperty("c", QScriptValue(3264));
396     QScriptValueIterator it(object);
397     it.next();
398     it.next();
399     QCOMPARE(it.name(), QLatin1String("b"));
400     QCOMPARE(it.hasPrevious(), true);
401     QCOMPARE(it.hasNext(), true);
402     // Remove 'a'
403     object.setProperty("a", QScriptValue());
404     QEXPECT_FAIL("", "That would be a significant behavioral and performance change, new QtScript API should be developed (QTBUG-12087)", Abort);
405     QCOMPARE(it.hasPrevious(), false);
406     QCOMPARE(it.hasNext(), true);
407     // Remove 'c'
408     engine.evaluate("delete o.c");
409     QCOMPARE(it.hasPrevious(), false);
410     QCOMPARE(it.hasNext(), false);
411     // Remove 'b'
412     object.setProperty("b", QScriptValue());
413     QCOMPARE(it.hasPrevious(), false);
414     QCOMPARE(it.hasNext(), false);
415     QCOMPARE(it.name(), QString());
416     QCOMPARE(it.value().toString(), QString());
417
418     // Try to remove a removed property.
419     it.remove();
420     QCOMPARE(it.hasPrevious(), false);
421     QCOMPARE(it.hasNext(), false);
422     QCOMPARE(it.name(), QString());
423     QCOMPARE(it.value().toString(), QString());
424
425     for (int i = 0; i < 2; ++i) {
426         it.next();
427         QCOMPARE(it.hasPrevious(), false);
428         QCOMPARE(it.hasNext(), false);
429         QCOMPARE(it.name(), QString());
430         QCOMPARE(it.value().toString(), QString());
431     }
432
433     for (int i = 0; i < 2; ++i) {
434         it.previous();
435         QCOMPARE(it.hasPrevious(), false);
436         QCOMPARE(it.hasNext(), false);
437         QCOMPARE(it.name(), QString());
438         QCOMPARE(it.value().toString(), QString());
439     }
440 }
441
442 void tst_QScriptValueIterator::removeUndeletable()
443 {
444     // Undeletable property can't be deleted via iterator.
445     QScriptEngine engine;
446     QScriptValue object = engine.evaluate("o = new Object; o");
447     object.setProperty("a", QScriptValue(&engine, 124));
448     object.setProperty("b", QScriptValue(&engine, 816), QScriptValue::Undeletable);
449     QVERIFY(object.property("b").isValid());
450     QScriptValueIterator it(object);
451     it.next();
452     it.next();
453     it.remove();
454     it.toFront();
455     QVERIFY(it.hasNext());
456     QVERIFY(object.property("b").isValid());
457 }
458
459 void tst_QScriptValueIterator::iterateString()
460 {
461     QScriptEngine engine;
462     QScriptValue str = QScriptValue(&engine, QString::fromLatin1("ciao"));
463     QVERIFY(str.isString());
464     QScriptValue obj = str.toObject();
465     int length = obj.property("length").toInt32();
466     QCOMPARE(length, 4);
467     QScriptValueIterator it(obj);
468     for (int i = 0; i < length; ++i) {
469         QCOMPARE(it.hasNext(), true);
470         QString indexStr = QScriptValue(&engine, i).toString();
471         it.next();
472         QCOMPARE(it.name(), indexStr);
473         QCOMPARE(it.flags(), obj.propertyFlags(indexStr));
474         QCOMPARE(it.value().strictlyEquals(obj.property(indexStr)), true);
475     }
476     QVERIFY(it.hasNext());
477     it.next();
478     QCOMPARE(it.name(), QString::fromLatin1("length"));
479     QVERIFY(it.value().isNumber());
480     QCOMPARE(it.value().toInt32(), length);
481     QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration | QScriptValue::Undeletable));
482
483     it.previous();
484     QCOMPARE(it.hasPrevious(), length > 0);
485     for (int i = length - 1; i >= 0; --i) {
486         it.previous();
487         QString indexStr = QScriptValue(&engine, i).toString();
488         QCOMPARE(it.name(), indexStr);
489         QCOMPARE(it.flags(), obj.propertyFlags(indexStr));
490         QCOMPARE(it.value().strictlyEquals(obj.property(indexStr)), true);
491         QCOMPARE(it.hasPrevious(), i > 0);
492     }
493     QCOMPARE(it.hasPrevious(), false);
494 }
495
496 void tst_QScriptValueIterator::assignObjectToIterator()
497 {
498     QScriptEngine eng;
499     QScriptValue obj1 = eng.newObject();
500     obj1.setProperty("foo", 123);
501     QScriptValue obj2 = eng.newObject();
502     obj2.setProperty("bar", 456);
503
504     QScriptValueIterator it(obj1);
505     QVERIFY(it.hasNext());
506     it.next();
507     it = obj2;
508     QVERIFY(it.hasNext());
509     it.next();
510     QCOMPARE(it.name(), QString::fromLatin1("bar"));
511
512     it = obj1;
513     QVERIFY(it.hasNext());
514     it.next();
515     QCOMPARE(it.name(), QString::fromLatin1("foo"));
516
517     it = obj2;
518     QVERIFY(it.hasNext());
519     it.next();
520     QCOMPARE(it.name(), QString::fromLatin1("bar"));
521
522     it = obj2;
523     QVERIFY(it.hasNext());
524     it.next();
525     QCOMPARE(it.name(), QString::fromLatin1("bar"));
526 }
527
528 QTEST_MAIN(tst_QScriptValueIterator)
529 #include "tst_qscriptvalueiterator.moc"
530
531 #endif // tst_qscriptvalueiterator_h