1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31
32#include <QtScript/qscriptengine.h>
33#include <QtScript/qscriptvalueiterator.h>
34
35Q_DECLARE_METATYPE(QScriptValue);
36
37class tst_QScriptValueIterator : public QObject
38{
39 Q_OBJECT
40
41public:
42 tst_QScriptValueIterator();
43 virtual ~tst_QScriptValueIterator();
44
45private slots:
46 void iterateForward_data();
47 void iterateForward();
48 void iterateBackward_data();
49 void iterateBackward();
50 void iterateArray_data();
51 void iterateArray();
52 void iterateBackAndForth();
53 void setValue();
54 void remove();
55 void iterateString();
56 void iterateGetterSetter();
57 void assignObjectToIterator();
58 void iterateNonObject();
59 void iterateOverObjectFromDeletedEngine();
60};
61
62tst_QScriptValueIterator::tst_QScriptValueIterator()
63{
64}
65
66tst_QScriptValueIterator::~tst_QScriptValueIterator()
67{
68}
69
70void tst_QScriptValueIterator::iterateForward_data()
71{
72 QTest::addColumn<QStringList>(name: "propertyNames");
73 QTest::addColumn<QStringList>(name: "propertyValues");
74
75 QTest::newRow(dataTag: "no properties")
76 << QStringList() << QStringList();
77 QTest::newRow(dataTag: "foo=bar")
78 << (QStringList() << "foo")
79 << (QStringList() << "bar");
80 QTest::newRow(dataTag: "foo=bar, baz=123")
81 << (QStringList() << "foo" << "baz")
82 << (QStringList() << "bar" << "123");
83 QTest::newRow(dataTag: "foo=bar, baz=123, rab=oof")
84 << (QStringList() << "foo" << "baz" << "rab")
85 << (QStringList() << "bar" << "123" << "oof");
86}
87
88void tst_QScriptValueIterator::iterateForward()
89{
90 QFETCH(QStringList, propertyNames);
91 QFETCH(QStringList, propertyValues);
92 QMap<QString, QString> pmap;
93 QVERIFY(propertyNames.size() == propertyValues.size());
94
95 QScriptEngine engine;
96 QScriptValue object = engine.newObject();
97 for (int i = 0; i < propertyNames.size(); ++i) {
98 QString name = propertyNames.at(i);
99 QString value = propertyValues.at(i);
100 pmap.insert(akey: name, avalue: value);
101 object.setProperty(name, value: QScriptValue(&engine, value));
102 }
103 QScriptValue otherObject = engine.newObject();
104 otherObject.setProperty(name: "foo", value: QScriptValue(&engine, 123456));
105 otherObject.setProperty(name: "protoProperty", value: QScriptValue(&engine, 654321));
106 object.setPrototype(otherObject); // should not affect iterator
107
108 QStringList lst;
109 QScriptValueIterator it(object);
110 while (!pmap.isEmpty()) {
111 QCOMPARE(it.hasNext(), true);
112 QCOMPARE(it.hasNext(), true);
113 it.next();
114 QString name = it.name();
115 QCOMPARE(pmap.contains(name), true);
116 QCOMPARE(it.name(), name);
117 QCOMPARE(it.flags(), object.propertyFlags(name));
118 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
119 QCOMPARE(it.scriptName(), engine.toStringHandle(name));
120 pmap.remove(akey: name);
121 lst.append(t: name);
122 }
123
124 QCOMPARE(it.hasNext(), false);
125 QCOMPARE(it.hasNext(), false);
126
127 it.toFront();
128 for (int i = 0; i < lst.count(); ++i) {
129 QCOMPARE(it.hasNext(), true);
130 it.next();
131 QCOMPARE(it.name(), lst.at(i));
132 }
133
134 for (int i = 0; i < lst.count(); ++i) {
135 QCOMPARE(it.hasPrevious(), true);
136 it.previous();
137 QCOMPARE(it.name(), lst.at(lst.count()-1-i));
138 }
139 QCOMPARE(it.hasPrevious(), false);
140}
141
142void tst_QScriptValueIterator::iterateBackward_data()
143{
144 iterateForward_data();
145}
146
147void tst_QScriptValueIterator::iterateBackward()
148{
149 QFETCH(QStringList, propertyNames);
150 QFETCH(QStringList, propertyValues);
151 QMap<QString, QString> pmap;
152 QVERIFY(propertyNames.size() == propertyValues.size());
153
154 QScriptEngine engine;
155 QScriptValue object = engine.newObject();
156 for (int i = 0; i < propertyNames.size(); ++i) {
157 QString name = propertyNames.at(i);
158 QString value = propertyValues.at(i);
159 pmap.insert(akey: name, avalue: value);
160 object.setProperty(name, value: QScriptValue(&engine, value));
161 }
162
163 QStringList lst;
164 QScriptValueIterator it(object);
165 it.toBack();
166 while (!pmap.isEmpty()) {
167 QCOMPARE(it.hasPrevious(), true);
168 QCOMPARE(it.hasPrevious(), true);
169 it.previous();
170 QString name = it.name();
171 QCOMPARE(pmap.contains(name), true);
172 QCOMPARE(it.name(), name);
173 QCOMPARE(it.flags(), object.propertyFlags(name));
174 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
175 pmap.remove(akey: name);
176 lst.append(t: name);
177 }
178
179 QCOMPARE(it.hasPrevious(), false);
180 QCOMPARE(it.hasPrevious(), false);
181
182 it.toBack();
183 for (int i = 0; i < lst.count(); ++i) {
184 QCOMPARE(it.hasPrevious(), true);
185 it.previous();
186 QCOMPARE(it.name(), lst.at(i));
187 }
188
189 for (int i = 0; i < lst.count(); ++i) {
190 QCOMPARE(it.hasNext(), true);
191 it.next();
192 QCOMPARE(it.name(), lst.at(lst.count()-1-i));
193 }
194 QCOMPARE(it.hasNext(), false);
195}
196
197void tst_QScriptValueIterator::iterateArray_data()
198{
199 QTest::addColumn<QStringList>(name: "propertyNames");
200 QTest::addColumn<QStringList>(name: "propertyValues");
201
202 QTest::newRow(dataTag: "no elements") << QStringList() << QStringList();
203
204 QTest::newRow(dataTag: "0=foo, 1=barr")
205 << (QStringList() << "0" << "1")
206 << (QStringList() << "foo" << "bar");
207
208
209 QTest::newRow(dataTag: "0=foo, 3=barr")
210 << (QStringList() << "0" << "1" << "2" << "3")
211 << (QStringList() << "foo" << "" << "" << "bar");
212}
213
214void tst_QScriptValueIterator::iterateArray()
215{
216 QFETCH(QStringList, propertyNames);
217 QFETCH(QStringList, propertyValues);
218
219 QScriptEngine engine;
220 QScriptValue array = engine.newArray();
221
222 // Fill the array
223 for (int i = 0; i < propertyNames.size(); ++i) {
224 array.setProperty(name: propertyNames.at(i), value: propertyValues.at(i));
225 }
226
227 // Iterate thru array properties. Note that the QScriptValueIterator doesn't guarantee
228 // any order on the iteration!
229 int length = array.property(name: "length").toInt32();
230 QCOMPARE(length, propertyNames.size());
231
232 bool iteratedThruLength = false;
233 QHash<QString, QScriptValue> arrayProperties;
234 QScriptValueIterator it(array);
235
236 // Iterate forward
237 while (it.hasNext()) {
238 it.next();
239
240 const QString name = it.name();
241 if (name == QString::fromLatin1(str: "length")) {
242 QVERIFY(it.value().isNumber());
243 QCOMPARE(it.value().toInt32(), length);
244 QCOMPARE(it.flags(), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
245 QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
246 iteratedThruLength = true;
247 continue;
248 }
249
250 // Storing the properties we iterate in a hash to compare with test data.
251 QVERIFY2(!arrayProperties.contains(name), "property appeared more than once during iteration.");
252 arrayProperties.insert(akey: name, avalue: it.value());
253 QCOMPARE(it.flags(), array.propertyFlags(name));
254 QVERIFY(it.value().strictlyEquals(array.property(name)));
255 }
256
257 // Verify properties
258 QVERIFY(iteratedThruLength);
259 QCOMPARE(arrayProperties.size(), propertyNames.size());
260 for (int i = 0; i < propertyNames.size(); ++i) {
261 QVERIFY(arrayProperties.contains(propertyNames.at(i)));
262 QCOMPARE(arrayProperties.value(propertyNames.at(i)).toString(), propertyValues.at(i));
263 }
264
265 // Iterate backwards
266 arrayProperties.clear();
267 iteratedThruLength = false;
268 it.toBack();
269
270 while (it.hasPrevious()) {
271 it.previous();
272
273 const QString name = it.name();
274 if (name == QString::fromLatin1(str: "length")) {
275 QVERIFY(it.value().isNumber());
276 QCOMPARE(it.value().toInt32(), length);
277 QCOMPARE(it.flags(), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
278 QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
279 iteratedThruLength = true;
280 continue;
281 }
282
283 // Storing the properties we iterate in a hash to compare with test data.
284 QVERIFY2(!arrayProperties.contains(name), "property appeared more than once during iteration.");
285 arrayProperties.insert(akey: name, avalue: it.value());
286 QCOMPARE(it.flags(), array.propertyFlags(name));
287 QVERIFY(it.value().strictlyEquals(array.property(name)));
288 }
289
290 // Verify properties
291 QVERIFY(iteratedThruLength);
292 QCOMPARE(arrayProperties.size(), propertyNames.size());
293 for (int i = 0; i < propertyNames.size(); ++i) {
294 QVERIFY(arrayProperties.contains(propertyNames.at(i)));
295 QCOMPARE(arrayProperties.value(propertyNames.at(i)).toString(), propertyValues.at(i));
296 }
297
298 // ### Do we still need this test?
299 // Forward test again but as object
300 arrayProperties.clear();
301 iteratedThruLength = false;
302 QScriptValue arrayObject = engine.toObject(value: array);
303 QScriptValueIterator it2(arrayObject);
304
305 while (it2.hasNext()) {
306 it2.next();
307
308 const QString name = it2.name();
309 if (name == QString::fromLatin1(str: "length")) {
310 QVERIFY(it2.value().isNumber());
311 QCOMPARE(it2.value().toInt32(), length);
312 QCOMPARE(it2.flags(), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
313 QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
314 iteratedThruLength = true;
315 continue;
316 }
317
318 // Storing the properties we iterate in a hash to compare with test data.
319 QVERIFY2(!arrayProperties.contains(name), "property appeared more than once during iteration.");
320 arrayProperties.insert(akey: name, avalue: it2.value());
321 QCOMPARE(it2.flags(), arrayObject.propertyFlags(name));
322 QVERIFY(it2.value().strictlyEquals(arrayObject.property(name)));
323 }
324
325 // Verify properties
326 QVERIFY(iteratedThruLength);
327 QCOMPARE(arrayProperties.size(), propertyNames.size());
328 for (int i = 0; i < propertyNames.size(); ++i) {
329 QVERIFY(arrayProperties.contains(propertyNames.at(i)));
330 QCOMPARE(arrayProperties.value(propertyNames.at(i)).toString(), propertyValues.at(i));
331 }
332}
333
334void tst_QScriptValueIterator::iterateBackAndForth()
335{
336 QScriptEngine engine;
337 {
338 QScriptValue object = engine.newObject();
339 object.setProperty(name: "foo", value: QScriptValue(&engine, "bar"));
340 object.setProperty(name: "rab", value: QScriptValue(&engine, "oof"),
341 flags: QScriptValue::SkipInEnumeration); // should not affect iterator
342 QScriptValueIterator it(object);
343 QVERIFY(it.hasNext());
344 it.next();
345 QCOMPARE(it.name(), QLatin1String("foo"));
346 QVERIFY(it.hasPrevious());
347 it.previous();
348 QCOMPARE(it.name(), QLatin1String("foo"));
349 QVERIFY(it.hasNext());
350 it.next();
351 QCOMPARE(it.name(), QLatin1String("foo"));
352 QVERIFY(it.hasPrevious());
353 it.previous();
354 QCOMPARE(it.name(), QLatin1String("foo"));
355 QVERIFY(it.hasNext());
356 it.next();
357 QCOMPARE(it.name(), QLatin1String("foo"));
358 QVERIFY(it.hasNext());
359 it.next();
360 QCOMPARE(it.name(), QLatin1String("rab"));
361 QVERIFY(it.hasPrevious());
362 it.previous();
363 QCOMPARE(it.name(), QLatin1String("rab"));
364 QVERIFY(it.hasNext());
365 it.next();
366 QCOMPARE(it.name(), QLatin1String("rab"));
367 QVERIFY(it.hasPrevious());
368 it.previous();
369 QCOMPARE(it.name(), QLatin1String("rab"));
370 }
371 {
372 // hasNext() and hasPrevious() cache their result; verify that the result is in sync
373 QScriptValue object = engine.newObject();
374 object.setProperty(name: "foo", value: QScriptValue(&engine, "bar"));
375 object.setProperty(name: "rab", value: QScriptValue(&engine, "oof"));
376 QScriptValueIterator it(object);
377 QVERIFY(it.hasNext());
378 it.next();
379 QCOMPARE(it.name(), QString::fromLatin1("foo"));
380 QVERIFY(it.hasNext());
381 it.previous();
382 QCOMPARE(it.name(), QString::fromLatin1("foo"));
383 QVERIFY(!it.hasPrevious());
384 it.next();
385 QCOMPARE(it.name(), QString::fromLatin1("foo"));
386 QVERIFY(it.hasPrevious());
387 it.next();
388 QCOMPARE(it.name(), QString::fromLatin1("rab"));
389 }
390}
391
392void tst_QScriptValueIterator::setValue()
393{
394 QScriptEngine engine;
395 QScriptValue object = engine.newObject();
396 object.setProperty(name: "foo", value: QScriptValue(&engine, "bar"));
397 QScriptValueIterator it(object);
398 it.next();
399 QCOMPARE(it.name(), QLatin1String("foo"));
400 it.setValue(QScriptValue(&engine, "baz"));
401 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("baz"))), true);
402 QCOMPARE(object.property("foo").toString(), QLatin1String("baz"));
403 it.setValue(QScriptValue(&engine, "zab"));
404 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("zab"))), true);
405 QCOMPARE(object.property("foo").toString(), QLatin1String("zab"));
406}
407
408void tst_QScriptValueIterator::remove()
409{
410 QScriptEngine engine;
411 QScriptValue object = engine.newObject();
412 object.setProperty(name: "foo", value: QScriptValue(&engine, "bar"),
413 flags: QScriptValue::SkipInEnumeration); // should not affect iterator
414 object.setProperty(name: "rab", value: QScriptValue(&engine, "oof"));
415 QScriptValueIterator it(object);
416 it.next();
417 QCOMPARE(it.name(), QLatin1String("foo"));
418 it.remove();
419 QCOMPARE(it.hasPrevious(), false);
420 QCOMPARE(object.property("foo").isValid(), false);
421 QCOMPARE(object.property("rab").toString(), QLatin1String("oof"));
422 it.next();
423 QCOMPARE(it.name(), QLatin1String("rab"));
424 QCOMPARE(it.value().toString(), QLatin1String("oof"));
425 QCOMPARE(it.hasNext(), false);
426 it.remove();
427 QCOMPARE(object.property("rab").isValid(), false);
428 QCOMPARE(it.hasPrevious(), false);
429 QCOMPARE(it.hasNext(), false);
430}
431
432void tst_QScriptValueIterator::iterateString()
433{
434 QScriptEngine engine;
435 QScriptValue str = QScriptValue(&engine, QString::fromLatin1(str: "ciao"));
436 QVERIFY(str.isString());
437 QScriptValue obj = str.toObject();
438 QVERIFY(obj.property("length").isNumber());
439 int length = obj.property(name: "length").toInt32();
440 QCOMPARE(length, 4);
441
442 QScriptValueIterator it(obj);
443 QHash<QString, QScriptValue> stringProperties;
444 bool iteratedThruLength = false;
445
446 while (it.hasNext()) {
447 it.next();
448 const QString name = it.name();
449
450 if (name == QString::fromLatin1(str: "length")) {
451 QVERIFY(it.value().isNumber());
452 QCOMPARE(it.value().toInt32(), length);
453 QCOMPARE(it.flags(), QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
454 QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
455 iteratedThruLength = true;
456 continue;
457 }
458
459 QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
460 stringProperties.insert(akey: name, avalue: it.value());
461 QCOMPARE(it.flags(), obj.propertyFlags(name));
462 QVERIFY(it.value().strictlyEquals(obj.property(name)));
463 }
464
465 QVERIFY(iteratedThruLength);
466 QCOMPARE(stringProperties.size(), length);
467
468 // And going backwards
469 iteratedThruLength = false;
470 stringProperties.clear();
471 it.toBack();
472
473 while (it.hasPrevious()) {
474 it.previous();
475 const QString name = it.name();
476
477 if (name == QString::fromLatin1(str: "length")) {
478 QVERIFY(it.value().isNumber());
479 QCOMPARE(it.value().toInt32(), length);
480 QCOMPARE(it.flags(), QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
481 QVERIFY2(!iteratedThruLength, "'length' appeared more than once during iteration.");
482 iteratedThruLength = true;
483 continue;
484 }
485
486 QVERIFY2(!stringProperties.contains(name), "property appeared more than once during iteration.");
487 stringProperties.insert(akey: name, avalue: it.value());
488 QCOMPARE(it.flags(), obj.propertyFlags(name));
489 QVERIFY(it.value().strictlyEquals(obj.property(name)));
490 }
491}
492
493static QScriptValue myGetterSetter(QScriptContext *ctx, QScriptEngine *)
494{
495 if (ctx->argumentCount() == 1)
496 ctx->thisObject().setProperty(name: "bar", value: ctx->argument(index: 0));
497 return ctx->thisObject().property(name: "bar");
498}
499
500static QScriptValue myGetter(QScriptContext *ctx, QScriptEngine *)
501{
502 return ctx->thisObject().property(name: "bar");
503}
504
505static QScriptValue mySetter(QScriptContext *ctx, QScriptEngine *)
506{
507 ctx->thisObject().setProperty(name: "bar", value: ctx->argument(index: 0));
508 return ctx->argument(index: 0);
509}
510
511void tst_QScriptValueIterator::iterateGetterSetter()
512{
513 // unified getter/setter function
514 {
515 QScriptEngine eng;
516 QScriptValue obj = eng.newObject();
517 obj.setProperty(name: "foo", value: eng.newFunction(signature: myGetterSetter),
518 flags: QScriptValue::PropertyGetter | QScriptValue::PropertySetter);
519 QScriptValue val(&eng, 123);
520 obj.setProperty(name: "foo", value: val);
521 QVERIFY(obj.property("bar").strictlyEquals(val));
522 QVERIFY(obj.property("foo").strictlyEquals(val));
523
524 QScriptValueIterator it(obj);
525 QVERIFY(it.hasNext());
526 it.next();
527 QCOMPARE(it.name(), QString::fromLatin1("foo"));
528 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
529 QVERIFY(it.value().strictlyEquals(val));
530 QScriptValue val2(&eng, 456);
531 it.setValue(val2);
532 QVERIFY(obj.property("bar").strictlyEquals(val2));
533 QVERIFY(obj.property("foo").strictlyEquals(val2));
534
535 QVERIFY(it.hasNext());
536 it.next();
537 QCOMPARE(it.name(), QString::fromLatin1("bar"));
538 QVERIFY(!it.hasNext());
539
540 QVERIFY(it.hasPrevious());
541 it.previous();
542 QCOMPARE(it.name(), QString::fromLatin1("bar"));
543 QVERIFY(it.hasPrevious());
544 it.previous();
545 QCOMPARE(it.name(), QString::fromLatin1("foo"));
546 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::PropertyGetter | QScriptValue::PropertySetter));
547 QVERIFY(it.value().strictlyEquals(val2));
548 it.setValue(val);
549 QVERIFY(obj.property("bar").strictlyEquals(val));
550 QVERIFY(obj.property("foo").strictlyEquals(val));
551 }
552 // separate getter/setter function
553 for (int x = 0; x < 2; ++x) {
554 QScriptEngine eng;
555 QScriptValue obj = eng.newObject();
556 if (x == 0) {
557 obj.setProperty(name: "foo", value: eng.newFunction(signature: myGetter), flags: QScriptValue::PropertyGetter);
558 obj.setProperty(name: "foo", value: eng.newFunction(signature: mySetter), flags: QScriptValue::PropertySetter);
559 } else {
560 obj.setProperty(name: "foo", value: eng.newFunction(signature: mySetter), flags: QScriptValue::PropertySetter);
561 obj.setProperty(name: "foo", value: eng.newFunction(signature: myGetter), flags: QScriptValue::PropertyGetter);
562 }
563 QScriptValue val(&eng, 123);
564 obj.setProperty(name: "foo", value: val);
565 QVERIFY(obj.property("bar").strictlyEquals(val));
566 QVERIFY(obj.property("foo").strictlyEquals(val));
567
568 QScriptValueIterator it(obj);
569 QVERIFY(it.hasNext());
570 it.next();
571 QCOMPARE(it.name(), QString::fromLatin1("foo"));
572 QVERIFY(it.value().strictlyEquals(val));
573 QScriptValue val2(&eng, 456);
574 it.setValue(val2);
575 QVERIFY(obj.property("bar").strictlyEquals(val2));
576 QVERIFY(obj.property("foo").strictlyEquals(val2));
577
578 QVERIFY(it.hasNext());
579 it.next();
580 QCOMPARE(it.name(), QString::fromLatin1("bar"));
581 QVERIFY(!it.hasNext());
582
583 QVERIFY(it.hasPrevious());
584 it.previous();
585 QCOMPARE(it.name(), QString::fromLatin1("bar"));
586 QVERIFY(it.hasPrevious());
587 it.previous();
588 QCOMPARE(it.name(), QString::fromLatin1("foo"));
589 QVERIFY(it.value().strictlyEquals(val2));
590 it.setValue(val);
591 QVERIFY(obj.property("bar").strictlyEquals(val));
592 QVERIFY(obj.property("foo").strictlyEquals(val));
593 }
594}
595
596void tst_QScriptValueIterator::assignObjectToIterator()
597{
598 QScriptEngine eng;
599 QScriptValue obj1 = eng.newObject();
600 obj1.setProperty(name: "foo", value: 123);
601 QScriptValue obj2 = eng.newObject();
602 obj2.setProperty(name: "bar", value: 456);
603
604 QScriptValueIterator it(obj1);
605 QVERIFY(it.hasNext());
606 it.next();
607 it = obj2;
608 QVERIFY(it.hasNext());
609 it.next();
610 QCOMPARE(it.name(), QString::fromLatin1("bar"));
611
612 it = obj1;
613 QVERIFY(it.hasNext());
614 it.next();
615 QCOMPARE(it.name(), QString::fromLatin1("foo"));
616
617 it = obj2;
618 QVERIFY(it.hasNext());
619 it.next();
620 QCOMPARE(it.name(), QString::fromLatin1("bar"));
621
622 it = obj2;
623 QVERIFY(it.hasNext());
624 it.next();
625 QCOMPARE(it.name(), QString::fromLatin1("bar"));
626}
627
628void tst_QScriptValueIterator::iterateNonObject()
629{
630 QScriptValueIterator it(123);
631 QVERIFY(!it.hasNext());
632 it.next();
633 QVERIFY(!it.hasPrevious());
634 it.previous();
635 it.toFront();
636 it.toBack();
637 it.name();
638 it.scriptName();
639 it.flags();
640 it.value();
641 it.setValue(1);
642 it.remove();
643 QScriptValue num(5);
644 it = num;
645 QVERIFY(!it.hasNext());
646}
647
648void tst_QScriptValueIterator::iterateOverObjectFromDeletedEngine()
649{
650 QScriptEngine *engine = new QScriptEngine;
651 QScriptValue objet = engine->newObject();
652
653 // populate object with properties
654 QHash<QString, int> properties;
655 properties.insert(akey: "foo",avalue: 1235);
656 properties.insert(akey: "oof",avalue: 5321);
657 properties.insert(akey: "ofo",avalue: 3521);
658 QHash<QString, int>::const_iterator i = properties.constBegin();
659 for(; i != properties.constEnd(); ++i) {
660 objet.setProperty(name: i.key(), value: i.value());
661 }
662
663 // start iterating
664 QScriptValueIterator it(objet);
665 it.next();
666 QVERIFY(properties.contains(it.name()));
667
668 delete engine;
669
670 QVERIFY(!objet.isValid());
671 QVERIFY(it.name().isEmpty());
672 QVERIFY(!it.value().isValid());
673
674 QVERIFY(!it.hasNext());
675 it.next();
676
677 QVERIFY(it.name().isEmpty());
678 QVERIFY(!it.scriptName().isValid());
679 QVERIFY(!it.value().isValid());
680 it.setValue("1234567");
681 it.remove();
682
683 QVERIFY(!it.hasPrevious());
684 it.previous();
685
686 QVERIFY(it.name().isEmpty());
687 QVERIFY(!it.scriptName().isValid());
688 QVERIFY(!it.value().isValid());
689 it.setValue("1234567");
690 it.remove();
691}
692
693QTEST_MAIN(tst_QScriptValueIterator)
694#include "tst_qscriptvalueiterator.moc"
695

source code of qtscript/tests/auto/qscriptvalueiterator/tst_qscriptvalueiterator.cpp