2 Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
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.
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.
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.
20 #ifndef tst_qscriptvalueiterator_h
21 #define tst_qscriptvalueiterator_h
23 #include "qscriptengine.h"
24 #include "qscriptvalue.h"
25 #include "qscriptvalueiterator.h"
26 #include <QtCore/qhash.h>
27 #include <QtTest/QtTest>
29 class tst_QScriptValueIterator : public QObject {
33 tst_QScriptValueIterator();
34 virtual ~tst_QScriptValueIterator();
37 void iterateForward_data();
38 void iterateForward();
39 void iterateBackward_data();
40 void iterateBackward();
41 void iterateArray_data();
43 void iterateBackAndForth();
47 void removeUndeletable();
49 void assignObjectToIterator();
52 tst_QScriptValueIterator::tst_QScriptValueIterator()
56 tst_QScriptValueIterator::~tst_QScriptValueIterator()
60 void tst_QScriptValueIterator::iterateForward_data()
62 QTest::addColumn<QStringList>("propertyNames");
63 QTest::addColumn<QStringList>("propertyValues");
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");
78 void tst_QScriptValueIterator::iterateForward()
80 QFETCH(QStringList, propertyNames);
81 QFETCH(QStringList, propertyValues);
82 QMap<QString, QString> pmap;
83 Q_ASSERT(propertyNames.size() == propertyValues.size());
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));
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
99 QScriptValueIterator it(object);
100 while (!pmap.isEmpty()) {
101 QCOMPARE(it.hasNext(), true);
102 QCOMPARE(it.hasNext(), true);
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));
114 QCOMPARE(it.hasNext(), false);
115 QCOMPARE(it.hasNext(), false);
118 for (int i = 0; i < lst.count(); ++i) {
119 QCOMPARE(it.hasNext(), true);
121 QCOMPARE(it.name(), lst.at(i));
124 for (int i = 0; i < lst.count(); ++i) {
125 QCOMPARE(it.hasPrevious(), true);
127 QCOMPARE(it.name(), lst.at(lst.count()-1-i));
129 QCOMPARE(it.hasPrevious(), false);
132 void tst_QScriptValueIterator::iterateBackward_data()
134 iterateForward_data();
137 void tst_QScriptValueIterator::iterateBackward()
139 QFETCH(QStringList, propertyNames);
140 QFETCH(QStringList, propertyValues);
141 QMap<QString, QString> pmap;
142 Q_ASSERT(propertyNames.size() == propertyValues.size());
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));
154 QScriptValueIterator it(object);
156 while (!pmap.isEmpty()) {
157 QCOMPARE(it.hasPrevious(), true);
158 QCOMPARE(it.hasPrevious(), true);
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);
169 QCOMPARE(it.hasPrevious(), false);
170 QCOMPARE(it.hasPrevious(), false);
173 for (int i = 0; i < lst.count(); ++i) {
174 QCOMPARE(it.hasPrevious(), true);
176 QCOMPARE(it.name(), lst.at(i));
179 for (int i = 0; i < lst.count(); ++i) {
180 QCOMPARE(it.hasNext(), true);
182 QCOMPARE(it.name(), lst.at(lst.count()-1-i));
184 QCOMPARE(it.hasNext(), false);
187 void tst_QScriptValueIterator::iterateArray_data()
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();
195 QTest::newRow("0=foo, 1=barr")
196 << (QStringList() << "0" << "1")
197 << (QStringList() << "foo" << "bar")
198 << (QStringList() << "0" << "1")
199 << (QStringList() << "foo" << "bar");
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");
208 void tst_QScriptValueIterator::iterateArray()
210 QFETCH(QStringList, inputPropertyNames);
211 QFETCH(QStringList, inputPropertyValues);
212 QFETCH(QStringList, propertyNames);
213 QFETCH(QStringList, propertyValues);
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));
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);
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));
231 QVERIFY(it.hasNext());
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));
239 QCOMPARE(it.hasPrevious(), length > 0);
240 for (int i = length - 1; i >= 0; --i) {
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);
248 QCOMPARE(it.hasPrevious(), false);
250 // hasNext() and hasPrevious() cache their result; verify that the result is in sync
252 QVERIFY(it.hasNext());
254 QCOMPARE(it.name(), QString::fromLatin1("0"));
255 QVERIFY(it.hasNext());
257 QCOMPARE(it.name(), QString::fromLatin1("0"));
258 QVERIFY(!it.hasPrevious());
260 QCOMPARE(it.name(), QString::fromLatin1("0"));
261 QVERIFY(it.hasPrevious());
263 QCOMPARE(it.name(), QString::fromLatin1("1"));
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));
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);
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));
283 QCOMPARE(it.hasNext(), true);
285 QCOMPARE(it.name(), QString::fromLatin1("length"));
289 void tst_QScriptValueIterator::iterateBackAndForth()
291 QScriptEngine engine;
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());
300 QCOMPARE(it.name(), QLatin1String("foo"));
301 QVERIFY(it.hasPrevious());
303 QCOMPARE(it.name(), QLatin1String("foo"));
304 QVERIFY(it.hasNext());
306 QCOMPARE(it.name(), QLatin1String("foo"));
307 QVERIFY(it.hasPrevious());
309 QCOMPARE(it.name(), QLatin1String("foo"));
310 QVERIFY(it.hasNext());
312 QCOMPARE(it.name(), QLatin1String("foo"));
313 QVERIFY(it.hasNext());
315 QCOMPARE(it.name(), QLatin1String("rab"));
316 QVERIFY(it.hasPrevious());
318 QCOMPARE(it.name(), QLatin1String("rab"));
319 QVERIFY(it.hasNext());
321 QCOMPARE(it.name(), QLatin1String("rab"));
322 QVERIFY(it.hasPrevious());
324 QCOMPARE(it.name(), QLatin1String("rab"));
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());
334 QCOMPARE(it.name(), QString::fromLatin1("foo"));
335 QVERIFY(it.hasNext());
337 QCOMPARE(it.name(), QString::fromLatin1("foo"));
338 QVERIFY(!it.hasPrevious());
340 QCOMPARE(it.name(), QString::fromLatin1("foo"));
341 QVERIFY(it.hasPrevious());
343 QCOMPARE(it.name(), QString::fromLatin1("rab"));
347 void tst_QScriptValueIterator::setValue()
349 QScriptEngine engine;
350 QScriptValue object = engine.newObject();
351 object.setProperty("foo", QScriptValue(&engine, "bar"));
352 QScriptValueIterator it(object);
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"));
363 void tst_QScriptValueIterator::remove()
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);
372 QCOMPARE(it.name(), QLatin1String("foo"));
374 QCOMPARE(it.hasPrevious(), false);
375 QCOMPARE(object.property("foo").isValid(), false);
376 QCOMPARE(object.property("rab").toString(), QLatin1String("oof"));
378 QCOMPARE(it.name(), QLatin1String("rab"));
379 QCOMPARE(it.value().toString(), QLatin1String("oof"));
380 QCOMPARE(it.hasNext(), false);
382 QCOMPARE(object.property("rab").isValid(), false);
383 QCOMPARE(it.hasPrevious(), false);
384 QCOMPARE(it.hasNext(), false);
387 void tst_QScriptValueIterator::removeMixed()
389 // This test checks if QScriptValueIterator behaives correctly if an object's property got deleted
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);
399 QCOMPARE(it.name(), QLatin1String("b"));
400 QCOMPARE(it.hasPrevious(), true);
401 QCOMPARE(it.hasNext(), true);
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);
408 engine.evaluate("delete o.c");
409 QCOMPARE(it.hasPrevious(), false);
410 QCOMPARE(it.hasNext(), false);
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());
418 // Try to remove a removed property.
420 QCOMPARE(it.hasPrevious(), false);
421 QCOMPARE(it.hasNext(), false);
422 QCOMPARE(it.name(), QString());
423 QCOMPARE(it.value().toString(), QString());
425 for (int i = 0; i < 2; ++i) {
427 QCOMPARE(it.hasPrevious(), false);
428 QCOMPARE(it.hasNext(), false);
429 QCOMPARE(it.name(), QString());
430 QCOMPARE(it.value().toString(), QString());
433 for (int i = 0; i < 2; ++i) {
435 QCOMPARE(it.hasPrevious(), false);
436 QCOMPARE(it.hasNext(), false);
437 QCOMPARE(it.name(), QString());
438 QCOMPARE(it.value().toString(), QString());
442 void tst_QScriptValueIterator::removeUndeletable()
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);
455 QVERIFY(it.hasNext());
456 QVERIFY(object.property("b").isValid());
459 void tst_QScriptValueIterator::iterateString()
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();
467 QScriptValueIterator it(obj);
468 for (int i = 0; i < length; ++i) {
469 QCOMPARE(it.hasNext(), true);
470 QString indexStr = QScriptValue(&engine, i).toString();
472 QCOMPARE(it.name(), indexStr);
473 QCOMPARE(it.flags(), obj.propertyFlags(indexStr));
474 QCOMPARE(it.value().strictlyEquals(obj.property(indexStr)), true);
476 QVERIFY(it.hasNext());
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));
484 QCOMPARE(it.hasPrevious(), length > 0);
485 for (int i = length - 1; i >= 0; --i) {
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);
493 QCOMPARE(it.hasPrevious(), false);
496 void tst_QScriptValueIterator::assignObjectToIterator()
499 QScriptValue obj1 = eng.newObject();
500 obj1.setProperty("foo", 123);
501 QScriptValue obj2 = eng.newObject();
502 obj2.setProperty("bar", 456);
504 QScriptValueIterator it(obj1);
505 QVERIFY(it.hasNext());
508 QVERIFY(it.hasNext());
510 QCOMPARE(it.name(), QString::fromLatin1("bar"));
513 QVERIFY(it.hasNext());
515 QCOMPARE(it.name(), QString::fromLatin1("foo"));
518 QVERIFY(it.hasNext());
520 QCOMPARE(it.name(), QString::fromLatin1("bar"));
523 QVERIFY(it.hasNext());
525 QCOMPARE(it.name(), QString::fromLatin1("bar"));
528 QTEST_MAIN(tst_QScriptValueIterator)
529 #include "tst_qscriptvalueiterator.moc"
531 #endif // tst_qscriptvalueiterator_h