]> git.saurik.com Git - apple/javascriptcore.git/blob - qt/tests/qscriptvalueiterator/tst_qscriptvalueiterator.cpp
43d0042a74ce694ff26d39a271908fead846f180
[apple/javascriptcore.git] / qt / tests / qscriptvalueiterator / tst_qscriptvalueiterator.cpp
1 /*
2 Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18 */
19
20 #ifndef tst_qscriptvalueiterator_h
21 #define tst_qscriptvalueiterator_h
22
23 #include "qscriptengine.h"
24 #include "qscriptvalue.h"
25 #include "qscriptvalueiterator.h"
26 #include <QtCore/qhash.h>
27 #include <QtTest/QtTest>
28
29 class tst_QScriptValueIterator : public QObject {
30 Q_OBJECT
31
32 public:
33 tst_QScriptValueIterator();
34 virtual ~tst_QScriptValueIterator();
35
36 private slots:
37 void iterateForward_data();
38 void iterateForward();
39 void iterateBackward_data();
40 void iterateBackward();
41 void iterateArray_data();
42 void iterateArray();
43 void iterateBackAndForth();
44 void setValue();
45 void remove();
46 void removeMixed();
47 void removeUndeletable();
48 void iterateString();
49 void assignObjectToIterator();
50 };
51
52 tst_QScriptValueIterator::tst_QScriptValueIterator()
53 {
54 }
55
56 tst_QScriptValueIterator::~tst_QScriptValueIterator()
57 {
58 }
59
60 void tst_QScriptValueIterator::iterateForward_data()
61 {
62 QTest::addColumn<QStringList>("propertyNames");
63 QTest::addColumn<QStringList>("propertyValues");
64
65 QTest::newRow("no properties")
66 << QStringList() << QStringList();
67 QTest::newRow("foo=bar")
68 << (QStringList() << "foo")
69 << (QStringList() << "bar");
70 QTest::newRow("foo=bar, baz=123")
71 << (QStringList() << "foo" << "baz")
72 << (QStringList() << "bar" << "123");
73 QTest::newRow("foo=bar, baz=123, rab=oof")
74 << (QStringList() << "foo" << "baz" << "rab")
75 << (QStringList() << "bar" << "123" << "oof");
76 }
77
78 void tst_QScriptValueIterator::iterateForward()
79 {
80 QFETCH(QStringList, propertyNames);
81 QFETCH(QStringList, propertyValues);
82 QMap<QString, QString> pmap;
83 Q_ASSERT(propertyNames.size() == propertyValues.size());
84
85 QScriptEngine engine;
86 QScriptValue object = engine.newObject();
87 for (int i = 0; i < propertyNames.size(); ++i) {
88 QString name = propertyNames.at(i);
89 QString value = propertyValues.at(i);
90 pmap.insert(name, value);
91 object.setProperty(name, QScriptValue(&engine, value));
92 }
93 QScriptValue otherObject = engine.newObject();
94 otherObject.setProperty("foo", QScriptValue(&engine, 123456));
95 otherObject.setProperty("protoProperty", QScriptValue(&engine, 654321));
96 object.setPrototype(otherObject); // should not affect iterator
97
98 QStringList lst;
99 QScriptValueIterator it(object);
100 while (!pmap.isEmpty()) {
101 QCOMPARE(it.hasNext(), true);
102 QCOMPARE(it.hasNext(), true);
103 it.next();
104 QString name = it.name();
105 QCOMPARE(pmap.contains(name), true);
106 QCOMPARE(it.name(), name);
107 QCOMPARE(it.flags(), object.propertyFlags(name));
108 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
109 QCOMPARE(it.scriptName(), engine.toStringHandle(name));
110 pmap.remove(name);
111 lst.append(name);
112 }
113
114 QCOMPARE(it.hasNext(), false);
115 QCOMPARE(it.hasNext(), false);
116
117 it.toFront();
118 for (int i = 0; i < lst.count(); ++i) {
119 QCOMPARE(it.hasNext(), true);
120 it.next();
121 QCOMPARE(it.name(), lst.at(i));
122 }
123
124 for (int i = 0; i < lst.count(); ++i) {
125 QCOMPARE(it.hasPrevious(), true);
126 it.previous();
127 QCOMPARE(it.name(), lst.at(lst.count()-1-i));
128 }
129 QCOMPARE(it.hasPrevious(), false);
130 }
131
132 void tst_QScriptValueIterator::iterateBackward_data()
133 {
134 iterateForward_data();
135 }
136
137 void tst_QScriptValueIterator::iterateBackward()
138 {
139 QFETCH(QStringList, propertyNames);
140 QFETCH(QStringList, propertyValues);
141 QMap<QString, QString> pmap;
142 Q_ASSERT(propertyNames.size() == propertyValues.size());
143
144 QScriptEngine engine;
145 QScriptValue object = engine.newObject();
146 for (int i = 0; i < propertyNames.size(); ++i) {
147 QString name = propertyNames.at(i);
148 QString value = propertyValues.at(i);
149 pmap.insert(name, value);
150 object.setProperty(name, QScriptValue(&engine, value));
151 }
152
153 QStringList lst;
154 QScriptValueIterator it(object);
155 it.toBack();
156 while (!pmap.isEmpty()) {
157 QCOMPARE(it.hasPrevious(), true);
158 QCOMPARE(it.hasPrevious(), true);
159 it.previous();
160 QString name = it.name();
161 QCOMPARE(pmap.contains(name), true);
162 QCOMPARE(it.name(), name);
163 QCOMPARE(it.flags(), object.propertyFlags(name));
164 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, pmap.value(name))), true);
165 pmap.remove(name);
166 lst.append(name);
167 }
168
169 QCOMPARE(it.hasPrevious(), false);
170 QCOMPARE(it.hasPrevious(), false);
171
172 it.toBack();
173 for (int i = 0; i < lst.count(); ++i) {
174 QCOMPARE(it.hasPrevious(), true);
175 it.previous();
176 QCOMPARE(it.name(), lst.at(i));
177 }
178
179 for (int i = 0; i < lst.count(); ++i) {
180 QCOMPARE(it.hasNext(), true);
181 it.next();
182 QCOMPARE(it.name(), lst.at(lst.count()-1-i));
183 }
184 QCOMPARE(it.hasNext(), false);
185 }
186
187 void tst_QScriptValueIterator::iterateArray_data()
188 {
189 QTest::addColumn<QStringList>("inputPropertyNames");
190 QTest::addColumn<QStringList>("inputPropertyValues");
191 QTest::addColumn<QStringList>("propertyNames");
192 QTest::addColumn<QStringList>("propertyValues");
193 QTest::newRow("no elements") << QStringList() << QStringList() << QStringList() << QStringList();
194
195 QTest::newRow("0=foo, 1=barr")
196 << (QStringList() << "0" << "1")
197 << (QStringList() << "foo" << "bar")
198 << (QStringList() << "0" << "1")
199 << (QStringList() << "foo" << "bar");
200
201 QTest::newRow("0=foo, 3=barr")
202 << (QStringList() << "0" << "1" << "2" << "3")
203 << (QStringList() << "foo" << "" << "" << "bar")
204 << (QStringList() << "0" << "1" << "2" << "3")
205 << (QStringList() << "foo" << "" << "" << "bar");
206 }
207
208 void tst_QScriptValueIterator::iterateArray()
209 {
210 QFETCH(QStringList, inputPropertyNames);
211 QFETCH(QStringList, inputPropertyValues);
212 QFETCH(QStringList, propertyNames);
213 QFETCH(QStringList, propertyValues);
214
215 QScriptEngine engine;
216 QScriptValue array = engine.newArray();
217 for (int i = 0; i < inputPropertyNames.size(); ++i)
218 array.setProperty(inputPropertyNames.at(i), inputPropertyValues.at(i));
219
220 int length = array.property("length").toInt32();
221 QCOMPARE(length, propertyNames.size());
222 QScriptValueIterator it(array);
223 for (int i = 0; i < length; ++i) {
224 QCOMPARE(it.hasNext(), true);
225 it.next();
226 QCOMPARE(it.name(), propertyNames.at(i));
227 QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
228 QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
229 QCOMPARE(it.value().toString(), propertyValues.at(i));
230 }
231 QVERIFY(it.hasNext());
232 it.next();
233 QCOMPARE(it.name(), QString::fromLatin1("length"));
234 QVERIFY(it.value().isNumber());
235 QCOMPARE(it.value().toInt32(), length);
236 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::SkipInEnumeration | QScriptValue::Undeletable));
237
238 it.previous();
239 QCOMPARE(it.hasPrevious(), length > 0);
240 for (int i = length - 1; i >= 0; --i) {
241 it.previous();
242 QCOMPARE(it.name(), propertyNames.at(i));
243 QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
244 QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
245 QCOMPARE(it.value().toString(), propertyValues.at(i));
246 QCOMPARE(it.hasPrevious(), i > 0);
247 }
248 QCOMPARE(it.hasPrevious(), false);
249
250 // hasNext() and hasPrevious() cache their result; verify that the result is in sync
251 if (length > 1) {
252 QVERIFY(it.hasNext());
253 it.next();
254 QCOMPARE(it.name(), QString::fromLatin1("0"));
255 QVERIFY(it.hasNext());
256 it.previous();
257 QCOMPARE(it.name(), QString::fromLatin1("0"));
258 QVERIFY(!it.hasPrevious());
259 it.next();
260 QCOMPARE(it.name(), QString::fromLatin1("0"));
261 QVERIFY(it.hasPrevious());
262 it.next();
263 QCOMPARE(it.name(), QString::fromLatin1("1"));
264 }
265 {
266 // same test as object:
267 QScriptValue originalArray = engine.newArray();
268 for (int i = 0; i < inputPropertyNames.size(); ++i)
269 originalArray.setProperty(inputPropertyNames.at(i), inputPropertyValues.at(i));
270
271 QScriptValue array = originalArray.toObject();
272 int length = array.property("length").toInt32();
273 QCOMPARE(length, propertyNames.size());
274 QScriptValueIterator it(array);
275 for (int i = 0; i < length; ++i) {
276 QCOMPARE(it.hasNext(), true);
277 it.next();
278 QCOMPARE(it.name(), propertyNames.at(i));
279 QCOMPARE(it.flags(), array.propertyFlags(propertyNames.at(i)));
280 QVERIFY(it.value().strictlyEquals(array.property(propertyNames.at(i))));
281 QCOMPARE(it.value().toString(), propertyValues.at(i));
282 }
283 QCOMPARE(it.hasNext(), true);
284 it.next();
285 QCOMPARE(it.name(), QString::fromLatin1("length"));
286 }
287 }
288
289 void tst_QScriptValueIterator::iterateBackAndForth()
290 {
291 QScriptEngine engine;
292 {
293 QScriptValue object = engine.newObject();
294 object.setProperty("foo", QScriptValue(&engine, "bar"));
295 object.setProperty("rab", QScriptValue(&engine, "oof"),
296 QScriptValue::SkipInEnumeration); // should not affect iterator
297 QScriptValueIterator it(object);
298 QVERIFY(it.hasNext());
299 it.next();
300 QCOMPARE(it.name(), QLatin1String("foo"));
301 QVERIFY(it.hasPrevious());
302 it.previous();
303 QCOMPARE(it.name(), QLatin1String("foo"));
304 QVERIFY(it.hasNext());
305 it.next();
306 QCOMPARE(it.name(), QLatin1String("foo"));
307 QVERIFY(it.hasPrevious());
308 it.previous();
309 QCOMPARE(it.name(), QLatin1String("foo"));
310 QVERIFY(it.hasNext());
311 it.next();
312 QCOMPARE(it.name(), QLatin1String("foo"));
313 QVERIFY(it.hasNext());
314 it.next();
315 QCOMPARE(it.name(), QLatin1String("rab"));
316 QVERIFY(it.hasPrevious());
317 it.previous();
318 QCOMPARE(it.name(), QLatin1String("rab"));
319 QVERIFY(it.hasNext());
320 it.next();
321 QCOMPARE(it.name(), QLatin1String("rab"));
322 QVERIFY(it.hasPrevious());
323 it.previous();
324 QCOMPARE(it.name(), QLatin1String("rab"));
325 }
326 {
327 // hasNext() and hasPrevious() cache their result; verify that the result is in sync
328 QScriptValue object = engine.newObject();
329 object.setProperty("foo", QScriptValue(&engine, "bar"));
330 object.setProperty("rab", QScriptValue(&engine, "oof"));
331 QScriptValueIterator it(object);
332 QVERIFY(it.hasNext());
333 it.next();
334 QCOMPARE(it.name(), QString::fromLatin1("foo"));
335 QVERIFY(it.hasNext());
336 it.previous();
337 QCOMPARE(it.name(), QString::fromLatin1("foo"));
338 QVERIFY(!it.hasPrevious());
339 it.next();
340 QCOMPARE(it.name(), QString::fromLatin1("foo"));
341 QVERIFY(it.hasPrevious());
342 it.next();
343 QCOMPARE(it.name(), QString::fromLatin1("rab"));
344 }
345 }
346
347 void tst_QScriptValueIterator::setValue()
348 {
349 QScriptEngine engine;
350 QScriptValue object = engine.newObject();
351 object.setProperty("foo", QScriptValue(&engine, "bar"));
352 QScriptValueIterator it(object);
353 it.next();
354 QCOMPARE(it.name(), QLatin1String("foo"));
355 it.setValue(QScriptValue(&engine, "baz"));
356 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("baz"))), true);
357 QCOMPARE(object.property("foo").toString(), QLatin1String("baz"));
358 it.setValue(QScriptValue(&engine, "zab"));
359 QCOMPARE(it.value().strictlyEquals(QScriptValue(&engine, QLatin1String("zab"))), true);
360 QCOMPARE(object.property("foo").toString(), QLatin1String("zab"));
361 }
362
363 void tst_QScriptValueIterator::remove()
364 {
365 QScriptEngine engine;
366 QScriptValue object = engine.newObject();
367 object.setProperty("foo", QScriptValue(&engine, "bar"),
368 QScriptValue::SkipInEnumeration); // should not affect iterator
369 object.setProperty("rab", QScriptValue(&engine, "oof"));
370 QScriptValueIterator it(object);
371 it.next();
372 QCOMPARE(it.name(), QLatin1String("foo"));
373 it.remove();
374 QCOMPARE(it.hasPrevious(), false);
375 QCOMPARE(object.property("foo").isValid(), false);
376 QCOMPARE(object.property("rab").toString(), QLatin1String("oof"));
377 it.next();
378 QCOMPARE(it.name(), QLatin1String("rab"));
379 QCOMPARE(it.value().toString(), QLatin1String("oof"));
380 QCOMPARE(it.hasNext(), false);
381 it.remove();
382 QCOMPARE(object.property("rab").isValid(), false);
383 QCOMPARE(it.hasPrevious(), false);
384 QCOMPARE(it.hasNext(), false);
385 }
386
387 void tst_QScriptValueIterator::removeMixed()
388 {
389 // This test checks if QScriptValueIterator behaives correctly if an object's property got deleted
390 // in different way.
391 QScriptEngine engine;
392 QScriptValue object = engine.evaluate("o = new Object; o");
393 object.setProperty("a", QScriptValue(124), QScriptValue::SkipInEnumeration);
394 object.setProperty("b", QScriptValue(816));
395 object.setProperty("c", QScriptValue(3264));
396 QScriptValueIterator it(object);
397 it.next();
398 it.next();
399 QCOMPARE(it.name(), QLatin1String("b"));
400 QCOMPARE(it.hasPrevious(), true);
401 QCOMPARE(it.hasNext(), true);
402 // Remove 'a'
403 object.setProperty("a", QScriptValue());
404 QEXPECT_FAIL("", "That would be a significant behavioral and performance change, new QtScript API should be developed (QTBUG-12087)", Abort);
405 QCOMPARE(it.hasPrevious(), false);
406 QCOMPARE(it.hasNext(), true);
407 // Remove 'c'
408 engine.evaluate("delete o.c");
409 QCOMPARE(it.hasPrevious(), false);
410 QCOMPARE(it.hasNext(), false);
411 // Remove 'b'
412 object.setProperty("b", QScriptValue());
413 QCOMPARE(it.hasPrevious(), false);
414 QCOMPARE(it.hasNext(), false);
415 QCOMPARE(it.name(), QString());
416 QCOMPARE(it.value().toString(), QString());
417
418 // Try to remove a removed property.
419 it.remove();
420 QCOMPARE(it.hasPrevious(), false);
421 QCOMPARE(it.hasNext(), false);
422 QCOMPARE(it.name(), QString());
423 QCOMPARE(it.value().toString(), QString());
424
425 for (int i = 0; i < 2; ++i) {
426 it.next();
427 QCOMPARE(it.hasPrevious(), false);
428 QCOMPARE(it.hasNext(), false);
429 QCOMPARE(it.name(), QString());
430 QCOMPARE(it.value().toString(), QString());
431 }
432
433 for (int i = 0; i < 2; ++i) {
434 it.previous();
435 QCOMPARE(it.hasPrevious(), false);
436 QCOMPARE(it.hasNext(), false);
437 QCOMPARE(it.name(), QString());
438 QCOMPARE(it.value().toString(), QString());
439 }
440 }
441
442 void tst_QScriptValueIterator::removeUndeletable()
443 {
444 // Undeletable property can't be deleted via iterator.
445 QScriptEngine engine;
446 QScriptValue object = engine.evaluate("o = new Object; o");
447 object.setProperty("a", QScriptValue(&engine, 124));
448 object.setProperty("b", QScriptValue(&engine, 816), QScriptValue::Undeletable);
449 QVERIFY(object.property("b").isValid());
450 QScriptValueIterator it(object);
451 it.next();
452 it.next();
453 it.remove();
454 it.toFront();
455 QVERIFY(it.hasNext());
456 QVERIFY(object.property("b").isValid());
457 }
458
459 void tst_QScriptValueIterator::iterateString()
460 {
461 QScriptEngine engine;
462 QScriptValue str = QScriptValue(&engine, QString::fromLatin1("ciao"));
463 QVERIFY(str.isString());
464 QScriptValue obj = str.toObject();
465 int length = obj.property("length").toInt32();
466 QCOMPARE(length, 4);
467 QScriptValueIterator it(obj);
468 for (int i = 0; i < length; ++i) {
469 QCOMPARE(it.hasNext(), true);
470 QString indexStr = QScriptValue(&engine, i).toString();
471 it.next();
472 QCOMPARE(it.name(), indexStr);
473 QCOMPARE(it.flags(), obj.propertyFlags(indexStr));
474 QCOMPARE(it.value().strictlyEquals(obj.property(indexStr)), true);
475 }
476 QVERIFY(it.hasNext());
477 it.next();
478 QCOMPARE(it.name(), QString::fromLatin1("length"));
479 QVERIFY(it.value().isNumber());
480 QCOMPARE(it.value().toInt32(), length);
481 QCOMPARE(it.flags(), QScriptValue::PropertyFlags(QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration | QScriptValue::Undeletable));
482
483 it.previous();
484 QCOMPARE(it.hasPrevious(), length > 0);
485 for (int i = length - 1; i >= 0; --i) {
486 it.previous();
487 QString indexStr = QScriptValue(&engine, i).toString();
488 QCOMPARE(it.name(), indexStr);
489 QCOMPARE(it.flags(), obj.propertyFlags(indexStr));
490 QCOMPARE(it.value().strictlyEquals(obj.property(indexStr)), true);
491 QCOMPARE(it.hasPrevious(), i > 0);
492 }
493 QCOMPARE(it.hasPrevious(), false);
494 }
495
496 void tst_QScriptValueIterator::assignObjectToIterator()
497 {
498 QScriptEngine eng;
499 QScriptValue obj1 = eng.newObject();
500 obj1.setProperty("foo", 123);
501 QScriptValue obj2 = eng.newObject();
502 obj2.setProperty("bar", 456);
503
504 QScriptValueIterator it(obj1);
505 QVERIFY(it.hasNext());
506 it.next();
507 it = obj2;
508 QVERIFY(it.hasNext());
509 it.next();
510 QCOMPARE(it.name(), QString::fromLatin1("bar"));
511
512 it = obj1;
513 QVERIFY(it.hasNext());
514 it.next();
515 QCOMPARE(it.name(), QString::fromLatin1("foo"));
516
517 it = obj2;
518 QVERIFY(it.hasNext());
519 it.next();
520 QCOMPARE(it.name(), QString::fromLatin1("bar"));
521
522 it = obj2;
523 QVERIFY(it.hasNext());
524 it.next();
525 QCOMPARE(it.name(), QString::fromLatin1("bar"));
526 }
527
528 QTEST_MAIN(tst_QScriptValueIterator)
529 #include "tst_qscriptvalueiterator.moc"
530
531 #endif // tst_qscriptvalueiterator_h