1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
43 #include <QtTest/QtTest>
47 #include <QJSValueIterator>
49 Q_DECLARE_METATYPE(QJSValue);
51 class tst_QJSValueIterator : public QObject
56 tst_QJSValueIterator();
57 virtual ~tst_QJSValueIterator();
60 void iterateForward_data();
61 void iterateForward();
62 void iterateArray_data();
66 void iterateGetterSetter();
68 void assignObjectToIterator();
69 void iterateNonObject();
70 void iterateOverObjectFromDeletedEngine();
73 tst_QJSValueIterator::tst_QJSValueIterator()
77 tst_QJSValueIterator::~tst_QJSValueIterator()
81 void tst_QJSValueIterator::iterateForward_data()
83 QTest::addColumn<QStringList>("propertyNames");
84 QTest::addColumn<QStringList>("propertyValues");
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");
99 void tst_QJSValueIterator::iterateForward()
101 QFETCH(QStringList, propertyNames);
102 QFETCH(QStringList, propertyValues);
103 QMap<QString, QString> pmap;
104 QVERIFY(propertyNames.size() == propertyValues.size());
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, engine.toScriptValue(value));
114 QJSValue otherObject = engine.newObject();
115 otherObject.setProperty("foo", engine.toScriptValue(123456));
116 otherObject.setProperty("protoProperty", engine.toScriptValue(654321));
117 object.setPrototype(otherObject); // should not affect iterator
120 QJSValueIterator it(object);
121 while (!pmap.isEmpty()) {
122 QCOMPARE(it.hasNext(), true);
123 QCOMPARE(it.hasNext(), true);
125 QString name = it.name();
126 QCOMPARE(pmap.contains(name), true);
127 QCOMPARE(it.name(), name);
128 QCOMPARE(it.value().strictlyEquals(engine.toScriptValue(pmap.value(name))), true);
133 QCOMPARE(it.hasNext(), false);
134 QCOMPARE(it.hasNext(), false);
137 for (int i = 0; i < lst.count(); ++i) {
138 QCOMPARE(it.hasNext(), true);
140 QCOMPARE(it.name(), lst.at(i));
144 void tst_QJSValueIterator::iterateArray_data()
146 QTest::addColumn<QStringList>("propertyNames");
147 QTest::addColumn<QStringList>("propertyValues");
149 QTest::newRow("no elements") << QStringList() << QStringList();
151 QTest::newRow("0=foo, 1=barr")
152 << (QStringList() << "0" << "1")
153 << (QStringList() << "foo" << "bar");
156 QTest::newRow("0=foo, 3=barr")
157 << (QStringList() << "0" << "1" << "2" << "3")
158 << (QStringList() << "foo" << "" << "" << "bar");
161 void tst_QJSValueIterator::iterateArray()
163 QFETCH(QStringList, propertyNames);
164 QFETCH(QStringList, propertyValues);
167 QJSValue array = engine.newArray();
170 for (int i = 0; i < propertyNames.size(); ++i) {
171 array.setProperty(propertyNames.at(i), propertyValues.at(i));
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());
179 bool iteratedThruLength = false;
180 QHash<QString, QJSValue> arrayProperties;
181 QJSValueIterator it(array);
184 while (it.hasNext()) {
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;
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)));
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));
213 arrayProperties.clear();
214 iteratedThruLength = false;
217 while (it.hasPrevious()) {
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;
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)));
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));
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);
252 while (it2.hasNext()) {
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;
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)));
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));
282 void tst_QJSValueIterator::iterateString()
285 QJSValue obj = engine.evaluate("new String('ciao')");
286 QVERIFY(obj.property("length").isNumber());
287 int length = obj.property("length").toInt();
290 QJSValueIterator it(obj);
291 QHash<QString, QJSValue> stringProperties;
292 bool iteratedThruLength = false;
294 while (it.hasNext()) {
296 const QString name = it.name();
298 if (name == QString::fromLatin1("length")) {
299 QVERIFY(it.value().isNumber());
300 QCOMPARE(it.value().toInt(), length);
301 QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
302 iteratedThruLength = true;
306 QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
307 stringProperties.insert(name, it.value());
308 QVERIFY(it.value().strictlyEquals(obj.property(name)));
311 QVERIFY(iteratedThruLength);
312 QCOMPARE(stringProperties.size(), length);
314 // And going backwards
315 iteratedThruLength = false;
316 stringProperties.clear();
319 while (it.hasPrevious()) {
321 const QString name = it.name();
323 if (name == QString::fromLatin1("length")) {
324 QVERIFY(it.value().isNumber());
325 QCOMPARE(it.value().toInt(), length);
326 QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
327 iteratedThruLength = true;
331 QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
332 stringProperties.insert(name, it.value());
333 QVERIFY(it.value().strictlyEquals(obj.property(name)));
338 #if 0 // FIXME what we should to keep from here?
339 static QJSValue myGetterSetter(QScriptContext *ctx, QJSEngine *)
341 if (ctx->argumentCount() == 1)
342 ctx->thisObject().setProperty("bar", ctx->argument(0));
343 return ctx->thisObject().property("bar");
346 static QJSValue myGetter(QScriptContext *ctx, QJSEngine *)
348 return ctx->thisObject().property("bar");
351 static QJSValue mySetter(QScriptContext *ctx, QJSEngine *)
353 ctx->thisObject().setProperty("bar", ctx->argument(0));
354 return ctx->argument(0);
357 void tst_QJSValueIterator::iterateGetterSetter()
359 // unified getter/setter function
362 QJSValue obj = eng.newObject();
363 obj.setProperty("foo", eng.newFunction(myGetterSetter),
364 QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
365 QJSValue val(&eng, 123);
366 obj.setProperty("foo", val);
367 QVERIFY(obj.property("bar").strictlyEquals(val));
368 QVERIFY(obj.property("foo").strictlyEquals(val));
370 QJSValueIterator it(obj);
371 QVERIFY(it.hasNext());
373 QCOMPARE(it.name(), QString::fromLatin1("foo"));
374 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
375 QVERIFY(it.value().strictlyEquals(val));
376 QJSValue val2(&eng, 456);
378 QVERIFY(obj.property("bar").strictlyEquals(val2));
379 QVERIFY(obj.property("foo").strictlyEquals(val2));
381 QVERIFY(it.hasNext());
383 QCOMPARE(it.name(), QString::fromLatin1("bar"));
384 QVERIFY(!it.hasNext());
386 QVERIFY(it.hasPrevious());
388 QCOMPARE(it.name(), QString::fromLatin1("bar"));
389 QVERIFY(it.hasPrevious());
391 QCOMPARE(it.name(), QString::fromLatin1("foo"));
392 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
393 QVERIFY(it.value().strictlyEquals(val2));
395 QVERIFY(obj.property("bar").strictlyEquals(val));
396 QVERIFY(obj.property("foo").strictlyEquals(val));
398 // separate getter/setter function
399 for (int x = 0; x < 2; ++x) {
401 QJSValue obj = eng.newObject();
403 obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
404 obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
406 obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
407 obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
409 QJSValue val(&eng, 123);
410 obj.setProperty("foo", val);
411 QVERIFY(obj.property("bar").strictlyEquals(val));
412 QVERIFY(obj.property("foo").strictlyEquals(val));
414 QJSValueIterator it(obj);
415 QVERIFY(it.hasNext());
417 QCOMPARE(it.name(), QString::fromLatin1("foo"));
418 QVERIFY(it.value().strictlyEquals(val));
419 QJSValue val2(&eng, 456);
421 QVERIFY(obj.property("bar").strictlyEquals(val2));
422 QVERIFY(obj.property("foo").strictlyEquals(val2));
424 QVERIFY(it.hasNext());
426 QCOMPARE(it.name(), QString::fromLatin1("bar"));
427 QVERIFY(!it.hasNext());
429 QVERIFY(it.hasPrevious());
431 QCOMPARE(it.name(), QString::fromLatin1("bar"));
432 QVERIFY(it.hasPrevious());
434 QCOMPARE(it.name(), QString::fromLatin1("foo"));
435 QVERIFY(it.value().strictlyEquals(val2));
437 QVERIFY(obj.property("bar").strictlyEquals(val));
438 QVERIFY(obj.property("foo").strictlyEquals(val));
443 void tst_QJSValueIterator::assignObjectToIterator()
446 QJSValue obj1 = eng.newObject();
447 obj1.setProperty("foo", 123);
448 QJSValue obj2 = eng.newObject();
449 obj2.setProperty("bar", 456);
451 QJSValueIterator it(obj1);
452 QVERIFY(it.hasNext());
455 QVERIFY(it.hasNext());
457 QCOMPARE(it.name(), QString::fromLatin1("bar"));
460 QVERIFY(it.hasNext());
462 QCOMPARE(it.name(), QString::fromLatin1("foo"));
465 QVERIFY(it.hasNext());
467 QCOMPARE(it.name(), QString::fromLatin1("bar"));
470 QVERIFY(it.hasNext());
472 QCOMPARE(it.name(), QString::fromLatin1("bar"));
475 void tst_QJSValueIterator::iterateNonObject()
477 QJSValueIterator it(123);
478 QVERIFY(!it.hasNext());
484 QVERIFY(!it.hasNext());
487 void tst_QJSValueIterator::iterateOverObjectFromDeletedEngine()
489 QJSEngine *engine = new QJSEngine;
490 QJSValue objet = engine->newObject();
492 // populate object with properties
493 QHash<QString, int> properties;
494 properties.insert("foo",1235);
495 properties.insert("oof",5321);
496 properties.insert("ofo",3521);
497 QHash<QString, int>::const_iterator i = properties.constBegin();
498 for (; i != properties.constEnd(); ++i) {
499 objet.setProperty(i.key(), i.value());
503 QJSValueIterator it(objet);
505 QVERIFY(properties.contains(it.name()));
509 QVERIFY(objet.isUndefined());
510 QVERIFY(it.name().isEmpty());
511 QVERIFY(it.value().isUndefined());
513 QVERIFY(!it.hasNext());
516 QVERIFY(it.name().isEmpty());
517 QVERIFY(it.value().isUndefined());
521 QTEST_MAIN(tst_QJSValueIterator)
522 #include "tst_qjsvalueiterator.moc"