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, QJSValue(&engine, value));
114 QJSValue otherObject = engine.newObject();
115 otherObject.setProperty("foo", QJSValue(&engine, 123456));
116 otherObject.setProperty("protoProperty", QJSValue(&engine, 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(QJSValue(&engine, 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 str = QJSValue(&engine, QString::fromLatin1("ciao"));
286 QVERIFY(str.isString());
287 QJSValue obj = str.toObject();
288 QVERIFY(obj.property("length").isNumber());
289 int length = obj.property("length").toInt();
292 QJSValueIterator it(obj);
293 QHash<QString, QJSValue> stringProperties;
294 bool iteratedThruLength = false;
296 while (it.hasNext()) {
298 const QString name = it.name();
300 if (name == QString::fromLatin1("length")) {
301 QVERIFY(it.value().isNumber());
302 QCOMPARE(it.value().toInt(), length);
303 QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
304 iteratedThruLength = true;
308 QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
309 stringProperties.insert(name, it.value());
310 QVERIFY(it.value().strictlyEquals(obj.property(name)));
313 QVERIFY(iteratedThruLength);
314 QCOMPARE(stringProperties.size(), length);
316 // And going backwards
317 iteratedThruLength = false;
318 stringProperties.clear();
321 while (it.hasPrevious()) {
323 const QString name = it.name();
325 if (name == QString::fromLatin1("length")) {
326 QVERIFY(it.value().isNumber());
327 QCOMPARE(it.value().toInt(), length);
328 QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
329 iteratedThruLength = true;
333 QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
334 stringProperties.insert(name, it.value());
335 QVERIFY(it.value().strictlyEquals(obj.property(name)));
340 #if 0 // FIXME what we should to keep from here?
341 static QJSValue myGetterSetter(QScriptContext *ctx, QJSEngine *)
343 if (ctx->argumentCount() == 1)
344 ctx->thisObject().setProperty("bar", ctx->argument(0));
345 return ctx->thisObject().property("bar");
348 static QJSValue myGetter(QScriptContext *ctx, QJSEngine *)
350 return ctx->thisObject().property("bar");
353 static QJSValue mySetter(QScriptContext *ctx, QJSEngine *)
355 ctx->thisObject().setProperty("bar", ctx->argument(0));
356 return ctx->argument(0);
359 void tst_QJSValueIterator::iterateGetterSetter()
361 // unified getter/setter function
364 QJSValue obj = eng.newObject();
365 obj.setProperty("foo", eng.newFunction(myGetterSetter),
366 QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
367 QJSValue val(&eng, 123);
368 obj.setProperty("foo", val);
369 QVERIFY(obj.property("bar").strictlyEquals(val));
370 QVERIFY(obj.property("foo").strictlyEquals(val));
372 QJSValueIterator it(obj);
373 QVERIFY(it.hasNext());
375 QCOMPARE(it.name(), QString::fromLatin1("foo"));
376 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
377 QVERIFY(it.value().strictlyEquals(val));
378 QJSValue val2(&eng, 456);
380 QVERIFY(obj.property("bar").strictlyEquals(val2));
381 QVERIFY(obj.property("foo").strictlyEquals(val2));
383 QVERIFY(it.hasNext());
385 QCOMPARE(it.name(), QString::fromLatin1("bar"));
386 QVERIFY(!it.hasNext());
388 QVERIFY(it.hasPrevious());
390 QCOMPARE(it.name(), QString::fromLatin1("bar"));
391 QVERIFY(it.hasPrevious());
393 QCOMPARE(it.name(), QString::fromLatin1("foo"));
394 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
395 QVERIFY(it.value().strictlyEquals(val2));
397 QVERIFY(obj.property("bar").strictlyEquals(val));
398 QVERIFY(obj.property("foo").strictlyEquals(val));
400 // separate getter/setter function
401 for (int x = 0; x < 2; ++x) {
403 QJSValue obj = eng.newObject();
405 obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
406 obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
408 obj.setProperty("foo", eng.newFunction(mySetter), QScriptValue::PropertySetter);
409 obj.setProperty("foo", eng.newFunction(myGetter), QScriptValue::PropertyGetter);
411 QJSValue val(&eng, 123);
412 obj.setProperty("foo", val);
413 QVERIFY(obj.property("bar").strictlyEquals(val));
414 QVERIFY(obj.property("foo").strictlyEquals(val));
416 QJSValueIterator it(obj);
417 QVERIFY(it.hasNext());
419 QCOMPARE(it.name(), QString::fromLatin1("foo"));
420 QVERIFY(it.value().strictlyEquals(val));
421 QJSValue val2(&eng, 456);
423 QVERIFY(obj.property("bar").strictlyEquals(val2));
424 QVERIFY(obj.property("foo").strictlyEquals(val2));
426 QVERIFY(it.hasNext());
428 QCOMPARE(it.name(), QString::fromLatin1("bar"));
429 QVERIFY(!it.hasNext());
431 QVERIFY(it.hasPrevious());
433 QCOMPARE(it.name(), QString::fromLatin1("bar"));
434 QVERIFY(it.hasPrevious());
436 QCOMPARE(it.name(), QString::fromLatin1("foo"));
437 QVERIFY(it.value().strictlyEquals(val2));
439 QVERIFY(obj.property("bar").strictlyEquals(val));
440 QVERIFY(obj.property("foo").strictlyEquals(val));
445 void tst_QJSValueIterator::assignObjectToIterator()
448 QJSValue obj1 = eng.newObject();
449 obj1.setProperty("foo", 123);
450 QJSValue obj2 = eng.newObject();
451 obj2.setProperty("bar", 456);
453 QJSValueIterator it(obj1);
454 QVERIFY(it.hasNext());
457 QVERIFY(it.hasNext());
459 QCOMPARE(it.name(), QString::fromLatin1("bar"));
462 QVERIFY(it.hasNext());
464 QCOMPARE(it.name(), QString::fromLatin1("foo"));
467 QVERIFY(it.hasNext());
469 QCOMPARE(it.name(), QString::fromLatin1("bar"));
472 QVERIFY(it.hasNext());
474 QCOMPARE(it.name(), QString::fromLatin1("bar"));
477 void tst_QJSValueIterator::iterateNonObject()
479 QJSValueIterator it(123);
480 QVERIFY(!it.hasNext());
486 QVERIFY(!it.hasNext());
489 void tst_QJSValueIterator::iterateOverObjectFromDeletedEngine()
491 QJSEngine *engine = new QJSEngine;
492 QJSValue objet = engine->newObject();
494 // populate object with properties
495 QHash<QString, int> properties;
496 properties.insert("foo",1235);
497 properties.insert("oof",5321);
498 properties.insert("ofo",3521);
499 QHash<QString, int>::const_iterator i = properties.constBegin();
500 for (; i != properties.constEnd(); ++i) {
501 objet.setProperty(i.key(), i.value());
505 QJSValueIterator it(objet);
507 QVERIFY(properties.contains(it.name()));
511 QVERIFY(!objet.isValid());
512 QVERIFY(it.name().isEmpty());
513 QVERIFY(!it.value().isValid());
515 QVERIFY(!it.hasNext());
518 QVERIFY(it.name().isEmpty());
519 QVERIFY(!it.value().isValid());
523 QTEST_MAIN(tst_QJSValueIterator)
524 #include "tst_qjsvalueiterator.moc"