1 /****************************************************************************
3 ** Copyright (C) 2009 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$
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
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 ** GNU General Public License Usage
29 ** Alternatively, this file may be used under the terms of the GNU
30 ** General Public License version 3.0 as published by the Free Software
31 ** Foundation and appearing in the file LICENSE.GPL included in the
32 ** packaging of this file. Please review the following information to
33 ** ensure the GNU General Public License version 3.0 requirements will be
34 ** met: http://www.gnu.org/copyleft/gpl.html.
36 ** If you have questions regarding the use of this file, please contact
37 ** Nokia at qt-info@nokia.com.
40 ****************************************************************************/
43 #include <QtTest/QtTest>
45 #include <QtScript/qscriptengine.h>
46 #include <QtScript/qscriptvalueiterator.h>
51 class tst_QScriptValueIterator
: public QObject
56 tst_QScriptValueIterator();
57 virtual ~tst_QScriptValueIterator();
60 void iterateForward_data();
61 void iterateForward();
62 void iterateBackward_data();
63 void iterateBackward();
65 void iterateBackAndForth();
69 void iterateGetterSetter();
70 void iterateArgumentsObject();
71 void assignObjectToIterator();
72 void undefinedBehavior();
75 tst_QScriptValueIterator::tst_QScriptValueIterator()
79 tst_QScriptValueIterator::~tst_QScriptValueIterator()
83 void tst_QScriptValueIterator::iterateForward_data()
85 QTest::addColumn
<QStringList
>("propertyNames");
86 QTest::addColumn
<QStringList
>("propertyValues");
88 QTest::newRow("no properties")
89 << QStringList() << QStringList();
90 QTest::newRow("foo=bar")
91 << (QStringList() << "foo")
92 << (QStringList() << "bar");
93 QTest::newRow("foo=bar, baz=123")
94 << (QStringList() << "foo" << "baz")
95 << (QStringList() << "bar" << "123");
96 QTest::newRow("foo=bar, baz=123, rab=oof")
97 << (QStringList() << "foo" << "baz" << "rab")
98 << (QStringList() << "bar" << "123" << "oof");
101 void tst_QScriptValueIterator::iterateForward()
103 QFETCH(QStringList
, propertyNames
);
104 QFETCH(QStringList
, propertyValues
);
105 QMap
<QString
, QString
> pmap
;
106 Q_ASSERT(propertyNames
.size() == propertyValues
.size());
108 QScriptEngine engine
;
109 QScriptValue object
= engine
.newObject();
110 for (int i
= 0; i
< propertyNames
.size(); ++i
) {
111 QString name
= propertyNames
.at(i
);
112 QString value
= propertyValues
.at(i
);
113 pmap
.insert(name
, value
);
114 object
.setProperty(name
, QScriptValue(&engine
, value
));
116 QScriptValue otherObject
= engine
.newObject();
117 otherObject
.setProperty("foo", QScriptValue(&engine
, 123456));
118 otherObject
.setProperty("protoProperty", QScriptValue(&engine
, 654321));
119 object
.setPrototype(otherObject
); // should not affect iterator
122 QScriptValueIterator
it(object
);
123 while (!pmap
.isEmpty()) {
124 QCOMPARE(it
.hasNext(), true);
125 QCOMPARE(it
.hasNext(), true);
127 QString name
= it
.name();
128 QCOMPARE(pmap
.contains(name
), true);
129 QCOMPARE(it
.name(), name
);
130 QCOMPARE(it
.flags(), object
.propertyFlags(name
));
131 QCOMPARE(it
.value().strictlyEquals(QScriptValue(&engine
, pmap
.value(name
))), true);
132 QCOMPARE(it
.scriptName(), engine
.toStringHandle(name
));
137 QCOMPARE(it
.hasNext(), false);
138 QCOMPARE(it
.hasNext(), false);
141 for (int i
= 0; i
< lst
.count(); ++i
) {
142 QCOMPARE(it
.hasNext(), true);
144 QCOMPARE(it
.name(), lst
.at(i
));
147 for (int i
= 0; i
< lst
.count(); ++i
) {
148 QCOMPARE(it
.hasPrevious(), true);
150 QCOMPARE(it
.name(), lst
.at(lst
.count()-1-i
));
152 QCOMPARE(it
.hasPrevious(), false);
155 void tst_QScriptValueIterator::iterateBackward_data()
157 iterateForward_data();
160 void tst_QScriptValueIterator::iterateBackward()
162 QFETCH(QStringList
, propertyNames
);
163 QFETCH(QStringList
, propertyValues
);
164 QMap
<QString
, QString
> pmap
;
165 Q_ASSERT(propertyNames
.size() == propertyValues
.size());
167 QScriptEngine engine
;
168 QScriptValue object
= engine
.newObject();
169 for (int i
= 0; i
< propertyNames
.size(); ++i
) {
170 QString name
= propertyNames
.at(i
);
171 QString value
= propertyValues
.at(i
);
172 pmap
.insert(name
, value
);
173 object
.setProperty(name
, QScriptValue(&engine
, value
));
177 QScriptValueIterator
it(object
);
179 while (!pmap
.isEmpty()) {
180 QCOMPARE(it
.hasPrevious(), true);
181 QCOMPARE(it
.hasPrevious(), true);
183 QString name
= it
.name();
184 QCOMPARE(pmap
.contains(name
), true);
185 QCOMPARE(it
.name(), name
);
186 QCOMPARE(it
.flags(), object
.propertyFlags(name
));
187 QCOMPARE(it
.value().strictlyEquals(QScriptValue(&engine
, pmap
.value(name
))), true);
192 QCOMPARE(it
.hasPrevious(), false);
193 QCOMPARE(it
.hasPrevious(), false);
196 for (int i
= 0; i
< lst
.count(); ++i
) {
197 QCOMPARE(it
.hasPrevious(), true);
199 QCOMPARE(it
.name(), lst
.at(i
));
202 for (int i
= 0; i
< lst
.count(); ++i
) {
203 QCOMPARE(it
.hasNext(), true);
205 QCOMPARE(it
.name(), lst
.at(lst
.count()-1-i
));
207 QCOMPARE(it
.hasNext(), false);
210 void tst_QScriptValueIterator::iterateArray()
212 QScriptEngine engine
;
213 QScriptValue array
= engine
.newArray();
214 array
.setProperty("0", QScriptValue(&engine
, 123));
215 array
.setProperty("1", QScriptValue(&engine
, 456));
216 array
.setProperty("2", QScriptValue(&engine
, 789));
217 int length
= array
.property("length").toInt32();
219 QScriptValueIterator
it(array
);
220 for (int i
= 0; i
< length
; ++i
) {
221 QCOMPARE(it
.hasNext(), true);
222 QString indexStr
= QScriptValue(&engine
, i
).toString();
224 QCOMPARE(it
.name(), indexStr
);
225 QCOMPARE(it
.flags(), array
.propertyFlags(indexStr
));
226 QCOMPARE(it
.value().strictlyEquals(array
.property(indexStr
)), true);
228 QCOMPARE(it
.hasNext(), false);
230 for (int i
= length
- 1; i
>= 0; --i
) {
232 QString indexStr
= QScriptValue(&engine
, i
).toString();
233 QCOMPARE(it
.name(), indexStr
);
234 QCOMPARE(it
.value().strictlyEquals(array
.property(indexStr
)), true);
235 QCOMPARE(it
.hasPrevious(), i
> 0);
237 QCOMPARE(it
.hasPrevious(), false);
239 // hasNext() and hasPrevious() cache their result; verify that the result is in sync
240 QVERIFY(it
.hasNext());
242 QCOMPARE(it
.name(), QString::fromLatin1("0"));
243 QVERIFY(it
.hasNext());
245 QCOMPARE(it
.name(), QString::fromLatin1("0"));
246 QVERIFY(!it
.hasPrevious());
248 QCOMPARE(it
.name(), QString::fromLatin1("0"));
249 QVERIFY(it
.hasPrevious());
251 QCOMPARE(it
.name(), QString::fromLatin1("1"));
254 void tst_QScriptValueIterator::iterateBackAndForth()
256 QScriptEngine engine
;
258 QScriptValue object
= engine
.newObject();
259 object
.setProperty("foo", QScriptValue(&engine
, "bar"));
260 object
.setProperty("rab", QScriptValue(&engine
, "oof"),
261 QScriptValue::SkipInEnumeration
); // should not affect iterator
262 QScriptValueIterator
it(object
);
264 QCOMPARE(it
.name(), QLatin1String("foo"));
266 QCOMPARE(it
.name(), QLatin1String("foo"));
268 QCOMPARE(it
.name(), QLatin1String("foo"));
270 QCOMPARE(it
.name(), QLatin1String("foo"));
272 QCOMPARE(it
.name(), QLatin1String("foo"));
274 QCOMPARE(it
.name(), QLatin1String("rab"));
276 QCOMPARE(it
.name(), QLatin1String("rab"));
278 QCOMPARE(it
.name(), QLatin1String("rab"));
280 QCOMPARE(it
.name(), QLatin1String("rab"));
283 // hasNext() and hasPrevious() cache their result; verify that the result is in sync
284 QScriptValue object
= engine
.newObject();
285 object
.setProperty("foo", QScriptValue(&engine
, "bar"));
286 object
.setProperty("rab", QScriptValue(&engine
, "oof"));
287 QScriptValueIterator
it(object
);
288 QVERIFY(it
.hasNext());
290 QCOMPARE(it
.name(), QString::fromLatin1("foo"));
291 QVERIFY(it
.hasNext());
293 QCOMPARE(it
.name(), QString::fromLatin1("foo"));
294 QVERIFY(!it
.hasPrevious());
296 QCOMPARE(it
.name(), QString::fromLatin1("foo"));
297 QVERIFY(it
.hasPrevious());
299 QCOMPARE(it
.name(), QString::fromLatin1("rab"));
303 void tst_QScriptValueIterator::setValue()
305 QScriptEngine engine
;
306 QScriptValue object
= engine
.newObject();
307 object
.setProperty("foo", QScriptValue(&engine
, "bar"));
308 QScriptValueIterator
it(object
);
310 QCOMPARE(it
.name(), QLatin1String("foo"));
311 it
.setValue(QScriptValue(&engine
, "baz"));
312 QCOMPARE(it
.value().strictlyEquals(QScriptValue(&engine
, QLatin1String("baz"))), true);
313 QCOMPARE(object
.property("foo").toString(), QLatin1String("baz"));
314 it
.setValue(QScriptValue(&engine
, "zab"));
315 QCOMPARE(it
.value().strictlyEquals(QScriptValue(&engine
, QLatin1String("zab"))), true);
316 QCOMPARE(object
.property("foo").toString(), QLatin1String("zab"));
319 void tst_QScriptValueIterator::remove()
321 QScriptEngine engine
;
322 QScriptValue object
= engine
.newObject();
323 object
.setProperty("foo", QScriptValue(&engine
, "bar"),
324 QScriptValue::SkipInEnumeration
); // should not affect iterator
325 object
.setProperty("rab", QScriptValue(&engine
, "oof"));
326 QScriptValueIterator
it(object
);
328 QCOMPARE(it
.name(), QLatin1String("foo"));
330 QCOMPARE(it
.hasPrevious(), false);
331 QCOMPARE(object
.property("foo").isValid(), false);
332 QCOMPARE(object
.property("rab").toString(), QLatin1String("oof"));
334 QCOMPARE(it
.name(), QLatin1String("rab"));
335 QCOMPARE(it
.value().toString(), QLatin1String("oof"));
336 QCOMPARE(it
.hasNext(), false);
338 QCOMPARE(object
.property("rab").isValid(), false);
339 QCOMPARE(it
.hasPrevious(), false);
340 QCOMPARE(it
.hasNext(), false);
343 void tst_QScriptValueIterator::iterateString()
345 QScriptEngine engine
;
346 QScriptValue str
= QScriptValue(&engine
, QString::fromLatin1("ciao"));
347 QVERIFY(str
.isString());
348 QScriptValue obj
= str
.toObject();
349 int length
= obj
.property("length").toInt32();
351 QScriptValueIterator
it(obj
);
352 for (int i
= 0; i
< length
; ++i
) {
353 QCOMPARE(it
.hasNext(), true);
354 QString indexStr
= QScriptValue(&engine
, i
).toString();
356 QCOMPARE(it
.name(), indexStr
);
357 QCOMPARE(it
.flags(), obj
.propertyFlags(indexStr
));
358 QCOMPARE(it
.value().strictlyEquals(obj
.property(indexStr
)), true);
360 QCOMPARE(it
.hasNext(), false);
362 for (int i
= length
- 1; i
>= 0; --i
) {
364 QString indexStr
= QScriptValue(&engine
, i
).toString();
365 QCOMPARE(it
.name(), indexStr
);
366 QCOMPARE(it
.flags(), obj
.propertyFlags(indexStr
));
367 QCOMPARE(it
.value().strictlyEquals(obj
.property(indexStr
)), true);
368 QCOMPARE(it
.hasPrevious(), i
> 0);
370 QCOMPARE(it
.hasPrevious(), false);
373 static QScriptValue
myGetterSetter(QScriptContext
*ctx
, QScriptEngine
*)
375 if (ctx
->argumentCount() == 1)
376 ctx
->thisObject().setProperty("bar", ctx
->argument(0));
377 return ctx
->thisObject().property("bar");
380 static QScriptValue
myGetter(QScriptContext
*ctx
, QScriptEngine
*)
382 return ctx
->thisObject().property("bar");
385 static QScriptValue
mySetter(QScriptContext
*ctx
, QScriptEngine
*)
387 ctx
->thisObject().setProperty("bar", ctx
->argument(0));
388 return ctx
->argument(0);
391 void tst_QScriptValueIterator::iterateGetterSetter()
393 // unified getter/setter function
396 QScriptValue obj
= eng
.newObject();
397 obj
.setProperty("foo", eng
.newFunction(myGetterSetter
),
398 QScriptValue::PropertyGetter
| QScriptValue::PropertySetter
);
399 QScriptValue
val(&eng
, 123);
400 obj
.setProperty("foo", val
);
401 QVERIFY(obj
.property("bar").strictlyEquals(val
));
402 QVERIFY(obj
.property("foo").strictlyEquals(val
));
404 QScriptValueIterator
it(obj
);
405 QVERIFY(it
.hasNext());
407 QCOMPARE(it
.name(), QString::fromLatin1("foo"));
408 QCOMPARE(it
.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter
| QScriptValue::PropertySetter
));
409 QVERIFY(it
.value().strictlyEquals(val
));
410 QScriptValue
val2(&eng
, 456);
412 QVERIFY(obj
.property("bar").strictlyEquals(val2
));
413 QVERIFY(obj
.property("foo").strictlyEquals(val2
));
415 QVERIFY(it
.hasNext());
417 QCOMPARE(it
.name(), QString::fromLatin1("bar"));
418 QVERIFY(!it
.hasNext());
420 QVERIFY(it
.hasPrevious());
422 QCOMPARE(it
.name(), QString::fromLatin1("bar"));
423 QVERIFY(it
.hasPrevious());
425 QCOMPARE(it
.name(), QString::fromLatin1("foo"));
426 QCOMPARE(it
.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter
| QScriptValue::PropertySetter
));
427 QVERIFY(it
.value().strictlyEquals(val2
));
429 QVERIFY(obj
.property("bar").strictlyEquals(val
));
430 QVERIFY(obj
.property("foo").strictlyEquals(val
));
432 // separate getter/setter function
433 for (int x
= 0; x
< 2; ++x
) {
435 QScriptValue obj
= eng
.newObject();
437 obj
.setProperty("foo", eng
.newFunction(myGetter
), QScriptValue::PropertyGetter
);
438 obj
.setProperty("foo", eng
.newFunction(mySetter
), QScriptValue::PropertySetter
);
440 obj
.setProperty("foo", eng
.newFunction(mySetter
), QScriptValue::PropertySetter
);
441 obj
.setProperty("foo", eng
.newFunction(myGetter
), QScriptValue::PropertyGetter
);
443 QScriptValue
val(&eng
, 123);
444 obj
.setProperty("foo", val
);
445 QVERIFY(obj
.property("bar").strictlyEquals(val
));
446 QVERIFY(obj
.property("foo").strictlyEquals(val
));
448 QScriptValueIterator
it(obj
);
449 QVERIFY(it
.hasNext());
451 QCOMPARE(it
.name(), QString::fromLatin1("foo"));
452 QVERIFY(it
.value().strictlyEquals(val
));
453 QScriptValue
val2(&eng
, 456);
455 QVERIFY(obj
.property("bar").strictlyEquals(val2
));
456 QVERIFY(obj
.property("foo").strictlyEquals(val2
));
458 QVERIFY(it
.hasNext());
460 QCOMPARE(it
.name(), QString::fromLatin1("bar"));
461 QVERIFY(!it
.hasNext());
463 QVERIFY(it
.hasPrevious());
465 QCOMPARE(it
.name(), QString::fromLatin1("bar"));
466 QVERIFY(it
.hasPrevious());
468 QCOMPARE(it
.name(), QString::fromLatin1("foo"));
469 QVERIFY(it
.value().strictlyEquals(val2
));
471 QVERIFY(obj
.property("bar").strictlyEquals(val
));
472 QVERIFY(obj
.property("foo").strictlyEquals(val
));
476 static QScriptValue
getArgumentsObject(QScriptContext
*ctx
, QScriptEngine
*)
478 return ctx
->argumentsObject();
481 void tst_QScriptValueIterator::iterateArgumentsObject()
484 QScriptValue fun
= eng
.newFunction(getArgumentsObject
);
485 QScriptValue ret
= fun
.call(QScriptValue(), QScriptValueList() << QScriptValue(&eng
, 123) << QScriptValue(&eng
, 456));
486 QCOMPARE(ret
.property("length").toInt32(), 2);
488 QScriptValueIterator
it(ret
);
489 QVERIFY(it
.hasNext());
491 QCOMPARE(it
.name(), QString::fromLatin1("callee"));
492 QVERIFY(it
.value().isFunction());
493 QVERIFY(it
.value().strictlyEquals(fun
));
494 QVERIFY(it
.hasNext());
497 QCOMPARE(it
.name(), QString::fromLatin1("length"));
498 QVERIFY(it
.value().isNumber());
499 QCOMPARE(it
.value().toInt32(), 2);
500 QVERIFY(it
.hasNext());
503 QCOMPARE(it
.name(), QString::fromLatin1("0"));
504 QVERIFY(it
.value().isNumber());
505 QCOMPARE(it
.value().toInt32(), 123);
506 QVERIFY(it
.hasNext());
509 QCOMPARE(it
.name(), QString::fromLatin1("1"));
510 QVERIFY(it
.value().isNumber());
511 QCOMPARE(it
.value().toInt32(), 456);
512 QVERIFY(!it
.hasNext());
514 QVERIFY(it
.hasPrevious());
516 QCOMPARE(it
.name(), QString::fromLatin1("1"));
517 QVERIFY(it
.value().isNumber());
518 QCOMPARE(it
.value().toInt32(), 456);
519 QVERIFY(it
.hasPrevious());
522 QCOMPARE(it
.name(), QString::fromLatin1("0"));
523 QVERIFY(it
.value().isNumber());
524 QCOMPARE(it
.value().toInt32(), 123);
525 QVERIFY(it
.hasPrevious());
528 QCOMPARE(it
.name(), QString::fromLatin1("length"));
529 QVERIFY(it
.value().isNumber());
530 QCOMPARE(it
.value().toInt32(), 2);
531 QVERIFY(it
.hasPrevious());
534 QCOMPARE(it
.name(), QString::fromLatin1("callee"));
535 QVERIFY(it
.value().isFunction());
536 QVERIFY(it
.value().strictlyEquals(fun
));
537 QVERIFY(!it
.hasPrevious());
540 void tst_QScriptValueIterator::undefinedBehavior()
543 QScriptValue obj
= eng
.newObject();
544 obj
.setProperty("foo", QScriptValue(&eng
, 123));
546 QScriptValueIterator
it(obj
);
547 QVERIFY(it
.hasNext());
549 // delete the property
550 obj
.setProperty("foo", QScriptValue());
553 QCOMPARE(it
.name(), QString::fromLatin1("foo"));
554 QVERIFY(!it
.value().isValid());
556 QVERIFY(!it
.hasNext());
558 obj
.setProperty("bar", QScriptValue(&eng
, 123));
559 QVERIFY(it
.hasNext());
562 QCOMPARE(it
.name(), QString::fromLatin1("bar"));
563 QVERIFY(it
.value().isNumber());
566 void tst_QScriptValueIterator::assignObjectToIterator()
569 QScriptValue obj1
= eng
.newObject();
570 obj1
.setProperty("foo", 123);
571 QScriptValue obj2
= eng
.newObject();
572 obj2
.setProperty("bar", 456);
574 QScriptValueIterator
it(obj1
);
575 QVERIFY(it
.hasNext());
578 QVERIFY(it
.hasNext());
580 QCOMPARE(it
.name(), QString::fromLatin1("bar"));
583 QVERIFY(it
.hasNext());
585 QCOMPARE(it
.name(), QString::fromLatin1("foo"));
588 QVERIFY(it
.hasNext());
590 QCOMPARE(it
.name(), QString::fromLatin1("bar"));
593 QVERIFY(it
.hasNext());
595 QCOMPARE(it
.name(), QString::fromLatin1("bar"));
598 QTEST_MAIN(tst_QScriptValueIterator
)
599 #include "tst_qscriptvalueiterator.moc"