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 | |
35 | Q_DECLARE_METATYPE(QScriptValue); |
36 | |
37 | class tst_QScriptValueIterator : public QObject |
38 | { |
39 | Q_OBJECT |
40 | |
41 | public: |
42 | tst_QScriptValueIterator(); |
43 | virtual ~tst_QScriptValueIterator(); |
44 | |
45 | private 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 | |
62 | tst_QScriptValueIterator::tst_QScriptValueIterator() |
63 | { |
64 | } |
65 | |
66 | tst_QScriptValueIterator::~tst_QScriptValueIterator() |
67 | { |
68 | } |
69 | |
70 | void 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 | |
88 | void 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 | |
142 | void tst_QScriptValueIterator::iterateBackward_data() |
143 | { |
144 | iterateForward_data(); |
145 | } |
146 | |
147 | void 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 | |
197 | void 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 | |
214 | void 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 | |
334 | void 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 | |
392 | void 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 | |
408 | void 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 | |
432 | void 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 | |
493 | static 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 | |
500 | static QScriptValue myGetter(QScriptContext *ctx, QScriptEngine *) |
501 | { |
502 | return ctx->thisObject().property(name: "bar" ); |
503 | } |
504 | |
505 | static 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 | |
511 | void 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 | |
596 | void 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 | |
628 | void 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 | |
648 | void 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 | |
693 | QTEST_MAIN(tst_QScriptValueIterator) |
694 | #include "tst_qscriptvalueiterator.moc" |
695 | |