1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
43 #include <QtTest/QtTest>
45 #include <QtScript/qscriptengine.h>
46 #include <QtScript/qscriptvalueiterator.h>
51 Q_DECLARE_METATYPE(QScriptValue);
53 class tst_QScriptValueIterator : public QObject
58 tst_QScriptValueIterator();
59 virtual ~tst_QScriptValueIterator();
62 void iterateForward_data();
63 void iterateForward();
64 void iterateBackward_data();
65 void iterateBackward();
66 void iterateArray_data();
68 void iterateBackAndForth();
72 void iterateGetterSetter();
73 void assignObjectToIterator();
74 void iterateNonObject();
75 void iterateOverObjectFromDeletedEngine();
78 tst_QScriptValueIterator::tst_QScriptValueIterator()
82 tst_QScriptValueIterator::~tst_QScriptValueIterator()
86 void tst_QScriptValueIterator::iterateForward_data()
88 QTest::addColumn<QStringList>("propertyNames");
89 QTest::addColumn<QStringList>("propertyValues");
91 QTest::newRow("no properties")
92 << QStringList() << QStringList();
93 QTest::newRow("foo=bar")
94 << (QStringList() << "foo")
95 << (QStringList() << "bar");
96 QTest::newRow("foo=bar, baz=123")
97 << (QStringList() << "foo" << "baz")
98 << (QStringList() << "bar" << "123");
99 QTest::newRow("foo=bar, baz=123, rab=oof")
100 << (QStringList() << "foo" << "baz" << "rab")
101 << (QStringList() << "bar" << "123" << "oof");
104 void tst_QScriptValueIterator::iterateForward()
106 QFETCH(QStringList, propertyNames);
107 QFETCH(QStringList, propertyValues);
108 QMap<QString, QString> pmap;
109 Q_ASSERT(propertyNames.size() == propertyValues.size());
111 QScriptEngine engine;
112 QScriptValue object = engine.newObject();
113 for (int i = 0; i < propertyNames.size(); ++i) {
114 QString name = propertyNames.at(i);
115 QString value = propertyValues.at(i);
116 pmap.insert(name, value);
117 object.setProperty(name, QScriptValue(&engine, value));
119 QScriptValue otherObject = engine.newObject();
120 otherObject.setProperty("foo", QScriptValue(&engine, 123456));
121 otherObject.setProperty("protoProperty", QScriptValue(&engine, 654321));
122 object.setPrototype(otherObject); // should not affect iterator
125 QScriptValueIterator it(object);
126 while (!pmap.isEmpty()) {
127 QCOMPARE(it.hasNext(), true);
128 QCOMPARE(it.hasNext(), true);
130 QString name = it.name();
131 QCOMPARE(pmap.contains(name), true);
132 QCOMPARE(it.name(), name);
133 QCOMPARE(it.flags(), object.propertyFlags(name));
134 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
135 QCOMPARE(it.scriptName(), engine.toStringHandle(name));
140 QCOMPARE(it.hasNext(), false);
141 QCOMPARE(it.hasNext(), false);
144 for (int i = 0; i < lst.count(); ++i) {
145 QCOMPARE(it.hasNext(), true);
147 QCOMPARE(it.name(), lst.at(i));
150 for (int i = 0; i < lst.count(); ++i) {
151 QCOMPARE(it.hasPrevious(), true);
153 QCOMPARE(it.name(), lst.at(lst.count()-1-i));
155 QCOMPARE(it.hasPrevious(), false);
158 void tst_QScriptValueIterator::iterateBackward_data()
160 iterateForward_data();
163 void tst_QScriptValueIterator::iterateBackward()
165 QFETCH(QStringList, propertyNames);
166 QFETCH(QStringList, propertyValues);
167 QMap<QString, QString> pmap;
168 Q_ASSERT(propertyNames.size() == propertyValues.size());
170 QScriptEngine engine;
171 QScriptValue object = engine.newObject();
172 for (int i = 0; i < propertyNames.size(); ++i) {
173 QString name = propertyNames.at(i);
174 QString value = propertyValues.at(i);
175 pmap.insert(name, value);
176 object.setProperty(name, QScriptValue(&engine, value));
180 QScriptValueIterator it(object);
182 while (!pmap.isEmpty()) {
183 QCOMPARE(it.hasPrevious(), true);
184 QCOMPARE(it.hasPrevious(), true);
186 QString name = it.name();
187 QCOMPARE(pmap.contains(name), true);
188 QCOMPARE(it.name(), name);
189 QCOMPARE(it.flags(), object.propertyFlags(name));
190 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
195 QCOMPARE(it.hasPrevious(), false);
196 QCOMPARE(it.hasPrevious(), false);
199 for (int i = 0; i < lst.count(); ++i) {
200 QCOMPARE(it.hasPrevious(), true);
202 QCOMPARE(it.name(), lst.at(i));
205 for (int i = 0; i < lst.count(); ++i) {
206 QCOMPARE(it.hasNext(), true);
208 QCOMPARE(it.name(), lst.at(lst.count()-1-i));
210 QCOMPARE(it.hasNext(), false);
213 void tst_QScriptValueIterator::iterateArray_data()
215 QTest::addColumn<QStringList>("inputPropertyNames");
216 QTest::addColumn<QStringList>("inputPropertyValues");
217 QTest::addColumn<QStringList>("propertyNames");
218 QTest::addColumn<QStringList>("propertyValues");
219 QTest::newRow("no elements") << QStringList() << QStringList() << QStringList() << QStringList();
222 QTest::newRow("0=foo, 1=barr")
223 << (QStringList() << "0" << "1")
224 << (QStringList() << "foo" << "bar")
225 << (QStringList() << "0" << "1")
226 << (QStringList() << "foo" << "bar");
229 QTest::newRow("0=foo, 3=barr")
230 << (QStringList() << "0" << "1" << "2" << "3")
231 << (QStringList() << "foo" << "" << "" << "bar")
232 << (QStringList() << "0" << "1" << "2" << "3")
233 << (QStringList() << "foo" << "" << "" << "bar");
236 void tst_QScriptValueIterator::iterateArray()
238 QFETCH(QStringList, inputPropertyNames);
239 QFETCH(QStringList, inputPropertyValues);
240 QFETCH(QStringList, propertyNames);
241 QFETCH(QStringList, propertyValues);
243 QScriptEngine engine;
244 QScriptValue array = engine.newArray();
245 for (int i = 0; i < inputPropertyNames.size(); ++i) {
246 array.setProperty(inputPropertyNames.at(i), inputPropertyValues.at(i));
249 int length = array.property("length").toInt32();
250 QCOMPARE(length, propertyNames.size());
251 QScriptValueIterator it(array);
252 for (int i = 0; i < length; ++i) {
253 QCOMPARE(it.hasNext(), true);
255 QCOMPARE(it.name(), propertyNames.at(i));
256 QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
257 QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
258 QCOMPARE(it.value().toString(), propertyValues.at(i));
260 QVERIFY(it.hasNext());
262 QCOMPARE(it.name(), QString::fromLatin1("length"));
263 QVERIFY(it.value().isNumber());
264 QCOMPARE(it.value().toInt32(), length);
265 QCOMPARE(it.flags(), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
268 QCOMPARE(it.hasPrevious(), length > 0);
269 for (int i = length - 1; i >= 0; --i) {
271 QCOMPARE(it.name(), propertyNames.at(i));
272 QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
273 QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
274 QCOMPARE(it.value().toString(), propertyValues.at(i));
275 QCOMPARE(it.hasPrevious(), i > 0);
277 QCOMPARE(it.hasPrevious(), false);
279 // hasNext() and hasPrevious() cache their result; verify that the result is in sync
281 QVERIFY(it.hasNext());
283 QCOMPARE(it.name(), QString::fromLatin1("0"));
284 QVERIFY(it.hasNext());
286 QCOMPARE(it.name(), QString::fromLatin1("0"));
287 QVERIFY(!it.hasPrevious());
289 QCOMPARE(it.name(), QString::fromLatin1("0"));
290 QVERIFY(it.hasPrevious());
292 QCOMPARE(it.name(), QString::fromLatin1("1"));
295 // same test as object:
296 QScriptValue originalArray = engine.newArray();
297 for (int i = 0; i < inputPropertyNames.size(); ++i) {
298 originalArray.setProperty(inputPropertyNames.at(i), inputPropertyValues.at(i));
300 QScriptValue array = originalArray.toObject();
301 int length = array.property("length").toInt32();
302 QCOMPARE(length, propertyNames.size());
303 QScriptValueIterator it(array);
304 for (int i = 0; i < length; ++i) {
305 QCOMPARE(it.hasNext(), true);
307 QCOMPARE(it.name(), propertyNames.at(i));
308 QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
309 QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
310 QCOMPARE(it.value().toString(), propertyValues.at(i));
312 QCOMPARE(it.hasNext(), true);
314 QCOMPARE(it.name(), QString::fromLatin1("length"));
318 void tst_QScriptValueIterator::iterateBackAndForth()
320 QScriptEngine engine;
322 QScriptValue object = engine.newObject();
323 object.setProperty("foo", QScriptValue(&engine, "bar"));
324 object.setProperty("rab", QScriptValue(&engine, "oof"),
325 QScriptValue::SkipInEnumeration); // should not affect iterator
326 QScriptValueIterator it(object);
327 QVERIFY(it.hasNext());
329 QCOMPARE(it.name(), QLatin1String("foo"));
330 QVERIFY(it.hasPrevious());
332 QCOMPARE(it.name(), QLatin1String("foo"));
333 QVERIFY(it.hasNext());
335 QCOMPARE(it.name(), QLatin1String("foo"));
336 QVERIFY(it.hasPrevious());
338 QCOMPARE(it.name(), QLatin1String("foo"));
339 QVERIFY(it.hasNext());
341 QCOMPARE(it.name(), QLatin1String("foo"));
342 QVERIFY(it.hasNext());
344 QCOMPARE(it.name(), QLatin1String("rab"));
345 QVERIFY(it.hasPrevious());
347 QCOMPARE(it.name(), QLatin1String("rab"));
348 QVERIFY(it.hasNext());
350 QCOMPARE(it.name(), QLatin1String("rab"));
351 QVERIFY(it.hasPrevious());
353 QCOMPARE(it.name(), QLatin1String("rab"));
356 // hasNext() and hasPrevious() cache their result; verify that the result is in sync
357 QScriptValue object = engine.newObject();
358 object.setProperty("foo", QScriptValue(&engine, "bar"));
359 object.setProperty("rab", QScriptValue(&engine, "oof"));
360 QScriptValueIterator it(object);
361 QVERIFY(it.hasNext());
363 QCOMPARE(it.name(), QString::fromLatin1("foo"));
364 QVERIFY(it.hasNext());
366 QCOMPARE(it.name(), QString::fromLatin1("foo"));
367 QVERIFY(!it.hasPrevious());
369 QCOMPARE(it.name(), QString::fromLatin1("foo"));
370 QVERIFY(it.hasPrevious());
372 QCOMPARE(it.name(), QString::fromLatin1("rab"));
376 void tst_QScriptValueIterator::setValue()
378 QScriptEngine engine;
379 QScriptValue object = engine.newObject();
380 object.setProperty("foo", QScriptValue(&engine, "bar"));
381 QScriptValueIterator it(object);
383 QCOMPARE(it.name(), QLatin1String("foo"));
384 it.setValue(QScriptValue(&engine, "baz"));
385 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("baz"))), true);
386 QCOMPARE(object.property("foo").toString(), QLatin1String("baz"));
387 it.setValue(QScriptValue(&engine, "zab"));
388 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("zab"))), true);
389 QCOMPARE(object.property("foo").toString(), QLatin1String("zab"));
392 void tst_QScriptValueIterator::remove()
394 QScriptEngine engine;
395 QScriptValue object = engine.newObject();
396 object.setProperty("foo", QScriptValue(&engine, "bar"),
397 QScriptValue::SkipInEnumeration); // should not affect iterator
398 object.setProperty("rab", QScriptValue(&engine, "oof"));
399 QScriptValueIterator it(object);
401 QCOMPARE(it.name(), QLatin1String("foo"));
403 QCOMPARE(it.hasPrevious(), false);
404 QCOMPARE(object.property("foo").isValid(), false);
405 QCOMPARE(object.property("rab").toString(), QLatin1String("oof"));
407 QCOMPARE(it.name(), QLatin1String("rab"));
408 QCOMPARE(it.value().toString(), QLatin1String("oof"));
409 QCOMPARE(it.hasNext(), false);
411 QCOMPARE(object.property("rab").isValid(), false);
412 QCOMPARE(it.hasPrevious(), false);
413 QCOMPARE(it.hasNext(), false);
416 void tst_QScriptValueIterator::iterateString()
418 QScriptEngine engine;
419 QScriptValue str = QScriptValue(&engine, QString::fromLatin1("ciao"));
420 QVERIFY(str.isString());
421 QScriptValue obj = str.toObject();
422 int length = obj.property("length").toInt32();
424 QScriptValueIterator it(obj);
425 for (int i = 0; i < length; ++i) {
426 QCOMPARE(it.hasNext(), true);
427 QString indexStr = QScriptValue(&engine, i).toString();
429 QCOMPARE(it.name(), indexStr);
430 QCOMPARE(it.flags(), obj.propertyFlags(indexStr));
431 QCOMPARE(it.value().strictlyEquals(obj.property(indexStr)), true);
433 QVERIFY(it.hasNext());
435 QCOMPARE(it.name(), QString::fromLatin1("length"));
436 QVERIFY(it.value().isNumber());
437 QCOMPARE(it.value().toInt32(), length);
438 QCOMPARE(it.flags(), QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
441 QCOMPARE(it.hasPrevious(), length > 0);
442 for (int i = length - 1; i >= 0; --i) {
444 QString indexStr = QScriptValue(&engine, i).toString();
445 QCOMPARE(it.name(), indexStr);
446 QCOMPARE(it.flags(), obj.propertyFlags(indexStr));
447 QCOMPARE(it.value().strictlyEquals(obj.property(indexStr)), true);
448 QCOMPARE(it.hasPrevious(), i > 0);
450 QCOMPARE(it.hasPrevious(), false);
453 static QScriptValue myGetterSetter(QScriptContext *ctx, QScriptEngine *)
455 if (ctx->argumentCount() == 1)
456 ctx->thisObject().setProperty("bar", ctx->argument(0));
457 return ctx->thisObject().property("bar");
460 static QScriptValue myGetter(QScriptContext *ctx, QScriptEngine *)
462 return ctx->thisObject().property("bar");
465 static QScriptValue mySetter(QScriptContext *ctx, QScriptEngine *)
467 ctx->thisObject().setProperty("bar", ctx->argument(0));
468 return ctx->argument(0);
471 void tst_QScriptValueIterator::iterateGetterSetter()
473 // unified getter/setter function
476 QScriptValue obj = eng.newObject();
477 obj.setProperty("foo", eng.newFunction(myGetterSetter),
478 QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
479 QScriptValue val(&eng, 123);
480 obj.setProperty("foo", val);
481 QVERIFY(obj.property("bar").strictlyEquals(val));
482 QVERIFY(obj.property("foo").strictlyEquals(val));
484 QScriptValueIterator it(obj);
485 QVERIFY(it.hasNext());
487 QCOMPARE(it.name(), QString::fromLatin1("foo"));
488 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
489 QVERIFY(it.value().strictlyEquals(val));
490 QScriptValue val2(&eng, 456);
492 QVERIFY(obj.property("bar").strictlyEquals(val2));
493 QVERIFY(obj.property("foo").strictlyEquals(val2));
495 QVERIFY(it.hasNext());
497 QCOMPARE(it.name(), QString::fromLatin1("bar"));
498 QVERIFY(!it.hasNext());
500 QVERIFY(it.hasPrevious());
502 QCOMPARE(it.name(), QString::fromLatin1("bar"));
503 QVERIFY(it.hasPrevious());
505 QCOMPARE(it.name(), QString::fromLatin1("foo"));
506 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
507 QVERIFY(it.value().strictlyEquals(val2));
509 QVERIFY(obj.property("bar").strictlyEquals(val));
510 QVERIFY(obj.property("foo").strictlyEquals(val));
512 // separate getter/setter function
513 for (int x = 0; x < 2; ++x) {
515 QScriptValue obj = eng.newObject();
517 obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
518 obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
520 obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
521 obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
523 QScriptValue val(&eng, 123);
524 obj.setProperty("foo", val);
525 QVERIFY(obj.property("bar").strictlyEquals(val));
526 QVERIFY(obj.property("foo").strictlyEquals(val));
528 QScriptValueIterator it(obj);
529 QVERIFY(it.hasNext());
531 QCOMPARE(it.name(), QString::fromLatin1("foo"));
532 QVERIFY(it.value().strictlyEquals(val));
533 QScriptValue val2(&eng, 456);
535 QVERIFY(obj.property("bar").strictlyEquals(val2));
536 QVERIFY(obj.property("foo").strictlyEquals(val2));
538 QVERIFY(it.hasNext());
540 QCOMPARE(it.name(), QString::fromLatin1("bar"));
541 QVERIFY(!it.hasNext());
543 QVERIFY(it.hasPrevious());
545 QCOMPARE(it.name(), QString::fromLatin1("bar"));
546 QVERIFY(it.hasPrevious());
548 QCOMPARE(it.name(), QString::fromLatin1("foo"));
549 QVERIFY(it.value().strictlyEquals(val2));
551 QVERIFY(obj.property("bar").strictlyEquals(val));
552 QVERIFY(obj.property("foo").strictlyEquals(val));
556 void tst_QScriptValueIterator::assignObjectToIterator()
559 QScriptValue obj1 = eng.newObject();
560 obj1.setProperty("foo", 123);
561 QScriptValue obj2 = eng.newObject();
562 obj2.setProperty("bar", 456);
564 QScriptValueIterator it(obj1);
565 QVERIFY(it.hasNext());
568 QVERIFY(it.hasNext());
570 QCOMPARE(it.name(), QString::fromLatin1("bar"));
573 QVERIFY(it.hasNext());
575 QCOMPARE(it.name(), QString::fromLatin1("foo"));
578 QVERIFY(it.hasNext());
580 QCOMPARE(it.name(), QString::fromLatin1("bar"));
583 QVERIFY(it.hasNext());
585 QCOMPARE(it.name(), QString::fromLatin1("bar"));
588 void tst_QScriptValueIterator::iterateNonObject()
590 QScriptValueIterator it(123);
591 QVERIFY(!it.hasNext());
593 QVERIFY(!it.hasPrevious());
605 QVERIFY(!it.hasNext());
608 void tst_QScriptValueIterator::iterateOverObjectFromDeletedEngine()
610 QScriptEngine *engine = new QScriptEngine;
611 QScriptValue objet = engine->newObject();
613 // populate object with properties
614 QHash<QString, int> properties;
615 properties.insert("foo",1235);
616 properties.insert("oof",5321);
617 properties.insert("ofo",3521);
618 QHash<QString, int>::const_iterator i = properties.constBegin();
619 for(; i != properties.constEnd(); ++i) {
620 objet.setProperty(i.key(), i.value());
624 QScriptValueIterator it(objet);
626 QVERIFY(properties.contains(it.name()));
630 QVERIFY(!objet.isValid());
631 QVERIFY(it.name().isEmpty());
632 QVERIFY(!it.value().isValid());
634 QVERIFY(!it.hasNext());
637 QVERIFY(it.name().isEmpty());
638 QVERIFY(!it.scriptName().isValid());
639 QVERIFY(!it.value().isValid());
640 it.setValue("1234567");
643 QVERIFY(!it.hasPrevious());
646 QVERIFY(it.name().isEmpty());
647 QVERIFY(!it.scriptName().isValid());
648 QVERIFY(!it.value().isValid());
649 it.setValue("1234567");
653 QTEST_MAIN(tst_QScriptValueIterator)
654 #include "tst_qscriptvalueiterator.moc"