API review: QRegExp::numCaptures() -> QRegExp::captureCount()
[qt-netbsd.git] / tests / auto / qscriptengine / tst_qscriptengine.cpp
blob8eaad78470f12cbc3a825918a5229d2a4b5341c3
1 /****************************************************************************
2 **
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
38 ** $QT_END_LICENSE$
40 ****************************************************************************/
43 #include <QtTest/QtTest>
45 #include <qscriptengine.h>
46 #include <qscriptengineagent.h>
47 #include <qscriptprogram.h>
48 #include <qscriptvalueiterator.h>
49 #include <qgraphicsitem.h>
50 #include <qstandarditemmodel.h>
51 #include <QtCore/qnumeric.h>
52 #include <stdlib.h>
54 Q_DECLARE_METATYPE(QList<int>)
55 Q_DECLARE_METATYPE(QObjectList)
56 Q_DECLARE_METATYPE(QScriptProgram)
58 //TESTED_CLASS=
59 //TESTED_FILES=
61 #if defined(Q_OS_SYMBIAN)
62 # define STRINGIFY(x) #x
63 # define TOSTRING(x) STRINGIFY(x)
64 # define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID)
65 #endif
67 // The JavaScriptCore GC marks the C stack. To try to ensure that there is
68 // no JSObject* left in stack memory by the compiler, we call this function
69 // to zap some bytes of memory before calling collectGarbage().
70 static void zapSomeStack()
72 char buf[4096];
73 memset(buf, 0, sizeof(buf));
76 static void collectGarbage_helper(QScriptEngine &eng)
78 zapSomeStack();
79 eng.collectGarbage();
82 class tst_QScriptEngine : public QObject
84 Q_OBJECT
86 public:
87 tst_QScriptEngine();
88 virtual ~tst_QScriptEngine();
90 private slots:
91 void constructWithParent();
92 void currentContext();
93 void pushPopContext();
94 void getSetDefaultPrototype();
95 void newFunction();
96 void newObject();
97 void newArray();
98 void newVariant();
99 void newRegExp();
100 void newDate();
101 void newQObject();
102 void newQMetaObject();
103 void newActivationObject();
104 void getSetGlobalObject();
105 void globalObjectProperties();
106 void globalObjectGetterSetterProperty();
107 void builtinFunctionNames_data();
108 void builtinFunctionNames();
109 void checkSyntax_data();
110 void checkSyntax();
111 void canEvaluate_data();
112 void canEvaluate();
113 void evaluate_data();
114 void evaluate();
115 void nestedEvaluate();
116 void uncaughtException();
117 void errorMessage_QT679();
118 void valueConversion();
119 void importExtension();
120 void infiniteRecursion();
121 void castWithPrototypeChain();
122 void castWithMultipleInheritance();
123 void collectGarbage();
124 void gcWithNestedDataStructure();
125 void processEventsWhileRunning();
126 void throwErrorFromProcessEvents();
127 void stacktrace();
128 void numberParsing_data();
129 void numberParsing();
130 void automaticSemicolonInsertion();
131 void abortEvaluation();
132 void isEvaluating();
133 void printFunctionWithCustomHandler();
134 void printThrowsException();
135 void errorConstructors();
136 void argumentsProperty();
137 void numberClass();
138 void forInStatement();
139 void functionExpression();
140 void stringObjects();
141 void getterSetterThisObject();
142 void continueInSwitch();
143 void readOnlyPrototypeProperty();
144 void toObject();
145 void reservedWords_data();
146 void reservedWords();
147 void futureReservedWords_data();
148 void futureReservedWords();
149 void throwInsideWithStatement();
150 void getSetAgent();
151 void reentrancy();
152 void incDecNonObjectProperty();
153 void installTranslatorFunctions();
154 void functionScopes();
155 void nativeFunctionScopes();
156 void evaluateProgram();
158 void qRegExpInport_data();
159 void qRegExpInport();
162 tst_QScriptEngine::tst_QScriptEngine()
166 tst_QScriptEngine::~tst_QScriptEngine()
170 void tst_QScriptEngine::constructWithParent()
172 QPointer<QScriptEngine> ptr;
174 QObject obj;
175 QScriptEngine *engine = new QScriptEngine(&obj);
176 ptr = engine;
178 QVERIFY(ptr == 0);
181 void tst_QScriptEngine::currentContext()
183 QScriptEngine eng;
184 QScriptContext *globalCtx = eng.currentContext();
185 QVERIFY(globalCtx != 0);
186 QVERIFY(globalCtx->parentContext() == 0);
187 QCOMPARE(globalCtx->engine(), &eng);
188 QCOMPARE(globalCtx->argumentCount(), 0);
189 QCOMPARE(globalCtx->backtrace().size(), 1);
190 QVERIFY(!globalCtx->isCalledAsConstructor());
191 QVERIFY(!globalCtx->callee().isValid());
192 QCOMPARE(globalCtx->state(), QScriptContext::NormalState);
193 QVERIFY(globalCtx->thisObject().strictlyEquals(eng.globalObject()));
194 QVERIFY(globalCtx->activationObject().strictlyEquals(eng.globalObject()));
195 QVERIFY(globalCtx->argumentsObject().isObject());
198 void tst_QScriptEngine::pushPopContext()
200 QScriptEngine eng;
201 QScriptContext *globalCtx = eng.currentContext();
202 QScriptContext *ctx = eng.pushContext();
203 QVERIFY(ctx != 0);
204 QCOMPARE(ctx->parentContext(), globalCtx);
205 QVERIFY(!ctx->isCalledAsConstructor());
206 QVERIFY(!ctx->callee().isValid());
207 QVERIFY(ctx->thisObject().strictlyEquals(eng.globalObject()));
208 QCOMPARE(ctx->argumentCount(), 0);
209 QCOMPARE(ctx->backtrace().size(), 2);
210 QCOMPARE(ctx->engine(), &eng);
211 QCOMPARE(ctx->state(), QScriptContext::NormalState);
212 QVERIFY(ctx->activationObject().isObject());
213 QVERIFY(ctx->argumentsObject().isObject());
215 QScriptContext *ctx2 = eng.pushContext();
216 QVERIFY(ctx2 != 0);
217 QCOMPARE(ctx2->parentContext(), ctx);
218 QVERIFY(!ctx2->activationObject().strictlyEquals(ctx->activationObject()));
219 QVERIFY(!ctx2->argumentsObject().strictlyEquals(ctx->argumentsObject()));
221 eng.popContext();
222 eng.popContext();
223 QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
224 eng.popContext(); // ignored
225 QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()");
226 eng.popContext(); // ignored
229 static QScriptValue myFunction(QScriptContext *, QScriptEngine *eng)
231 return eng->nullValue();
234 static QScriptValue myFunctionWithVoidArg(QScriptContext *, QScriptEngine *eng, void *)
236 return eng->nullValue();
239 static QScriptValue myThrowingFunction(QScriptContext *ctx, QScriptEngine *)
241 return ctx->throwError("foo");
244 void tst_QScriptEngine::newFunction()
246 QScriptEngine eng;
248 QScriptValue fun = eng.newFunction(myFunction);
249 QCOMPARE(fun.isValid(), true);
250 QCOMPARE(fun.isFunction(), true);
251 QCOMPARE(fun.isObject(), true);
252 QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
253 // a prototype property is automatically constructed
255 QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
256 QVERIFY(prot.isObject());
257 QVERIFY(prot.property("constructor").strictlyEquals(fun));
258 QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
259 QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
261 // prototype should be Function.prototype
262 QCOMPARE(fun.prototype().isValid(), true);
263 QCOMPARE(fun.prototype().isFunction(), true);
264 QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
266 QCOMPARE(fun.call().isNull(), true);
267 QCOMPARE(fun.construct().isObject(), true);
270 // the overload that takes a void*
272 QScriptValue fun = eng.newFunction(myFunctionWithVoidArg, (void*)this);
273 QVERIFY(fun.isFunction());
274 QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
275 // a prototype property is automatically constructed
277 QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal);
278 QVERIFY(prot.isObject());
279 QVERIFY(prot.property("constructor").strictlyEquals(fun));
280 QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
281 QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
283 // prototype should be Function.prototype
284 QCOMPARE(fun.prototype().isValid(), true);
285 QCOMPARE(fun.prototype().isFunction(), true);
286 QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
288 QCOMPARE(fun.call().isNull(), true);
289 QCOMPARE(fun.construct().isObject(), true);
292 // the overload that takes a prototype
294 QScriptValue proto = eng.newObject();
295 QScriptValue fun = eng.newFunction(myFunction, proto);
296 QCOMPARE(fun.isValid(), true);
297 QCOMPARE(fun.isFunction(), true);
298 QCOMPARE(fun.isObject(), true);
299 // internal prototype should be Function.prototype
300 QCOMPARE(fun.prototype().isValid(), true);
301 QCOMPARE(fun.prototype().isFunction(), true);
302 QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true);
303 // public prototype should be the one we passed
304 QCOMPARE(fun.property("prototype").strictlyEquals(proto), true);
305 QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable);
306 QCOMPARE(proto.property("constructor").strictlyEquals(fun), true);
307 QCOMPARE(proto.propertyFlags("constructor"),
308 QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
310 QCOMPARE(fun.call().isNull(), true);
311 QCOMPARE(fun.construct().isObject(), true);
315 void tst_QScriptEngine::newObject()
317 QScriptEngine eng;
318 QScriptValue object = eng.newObject();
319 QCOMPARE(object.isValid(), true);
320 QCOMPARE(object.isObject(), true);
321 QCOMPARE(object.isFunction(), false);
322 QCOMPARE(object.scriptClass(), (QScriptClass*)0);
323 // prototype should be Object.prototype
324 QCOMPARE(object.prototype().isValid(), true);
325 QCOMPARE(object.prototype().isObject(), true);
326 QCOMPARE(object.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true);
329 void tst_QScriptEngine::newArray()
331 QScriptEngine eng;
332 QScriptValue array = eng.newArray();
333 QCOMPARE(array.isValid(), true);
334 QCOMPARE(array.isArray(), true);
335 QCOMPARE(array.isObject(), true);
336 QVERIFY(!array.isFunction());
337 QCOMPARE(array.scriptClass(), (QScriptClass*)0);
338 // prototype should be Array.prototype
339 QCOMPARE(array.prototype().isValid(), true);
340 QCOMPARE(array.prototype().isArray(), true);
341 QCOMPARE(array.prototype().strictlyEquals(eng.evaluate("Array.prototype")), true);
343 // task 218092
345 QScriptValue ret = eng.evaluate("[].splice(0, 0, 'a')");
346 QVERIFY(ret.isArray());
347 QCOMPARE(ret.property("length").toInt32(), 0);
350 QScriptValue ret = eng.evaluate("['a'].splice(0, 1, 'b')");
351 QVERIFY(ret.isArray());
352 QCOMPARE(ret.property("length").toInt32(), 1);
355 QScriptValue ret = eng.evaluate("['a', 'b'].splice(0, 1, 'c')");
356 QVERIFY(ret.isArray());
357 QCOMPARE(ret.property("length").toInt32(), 1);
360 QScriptValue ret = eng.evaluate("['a', 'b', 'c'].splice(0, 2, 'd')");
361 QVERIFY(ret.isArray());
362 QCOMPARE(ret.property("length").toInt32(), 2);
365 QScriptValue ret = eng.evaluate("['a', 'b', 'c'].splice(1, 2, 'd', 'e', 'f')");
366 QVERIFY(ret.isArray());
367 QCOMPARE(ret.property("length").toInt32(), 2);
370 // task 233836
372 QScriptValue ret = eng.evaluate("a = new Array(4294967295); a.push('foo')");
373 QVERIFY(ret.isNumber());
374 QCOMPARE(ret.toInt32(), 0);
375 QCOMPARE(eng.evaluate("a[4294967295]").toString(), QString::fromLatin1("foo"));
378 QScriptValue ret = eng.newArray(0xFFFFFFFF);
379 QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
380 ret.setProperty(0xFFFFFFFF, 123);
381 QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
382 QVERIFY(ret.property(0xFFFFFFFF).isNumber());
383 QCOMPARE(ret.property(0xFFFFFFFF).toInt32(), 123);
384 ret.setProperty(123, 456);
385 QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF));
386 QVERIFY(ret.property(123).isNumber());
387 QCOMPARE(ret.property(123).toInt32(), 456);
391 void tst_QScriptEngine::newVariant()
393 QScriptEngine eng;
395 QScriptValue opaque = eng.newVariant(QVariant());
396 QCOMPARE(opaque.isValid(), true);
397 QCOMPARE(opaque.isVariant(), true);
398 QVERIFY(!opaque.isFunction());
399 QCOMPARE(opaque.isObject(), true);
400 QCOMPARE(opaque.prototype().isValid(), true);
401 QCOMPARE(opaque.prototype().isVariant(), true);
402 QVERIFY(opaque.property("valueOf").call(opaque).isUndefined());
404 // default prototype should be set automatically
406 QScriptValue proto = eng.newObject();
407 eng.setDefaultPrototype(qMetaTypeId<QString>(), proto);
408 QScriptValue ret = eng.newVariant(QVariant(QString::fromLatin1("hello")));
409 QVERIFY(ret.isVariant());
410 QCOMPARE(ret.scriptClass(), (QScriptClass*)0);
411 QVERIFY(ret.prototype().strictlyEquals(proto));
412 eng.setDefaultPrototype(qMetaTypeId<QString>(), QScriptValue());
413 QScriptValue ret2 = eng.newVariant(QVariant(QString::fromLatin1("hello")));
414 QVERIFY(ret2.isVariant());
415 QVERIFY(!ret2.prototype().strictlyEquals(proto));
417 // "promote" plain object to variant
419 QScriptValue object = eng.newObject();
420 object.setProperty("foo", eng.newObject());
421 object.setProperty("bar", object.property("foo"));
422 QVERIFY(object.property("foo").isObject());
423 QVERIFY(!object.property("foo").isVariant());
424 QScriptValue originalProto = object.property("foo").prototype();
425 QScriptValue ret = eng.newVariant(object.property("foo"), QVariant(123));
426 QVERIFY(ret.isValid());
427 QVERIFY(ret.strictlyEquals(object.property("foo")));
428 QVERIFY(ret.isVariant());
429 QVERIFY(object.property("foo").isVariant());
430 QVERIFY(object.property("bar").isVariant());
431 QCOMPARE(ret.toVariant(), QVariant(123));
432 QVERIFY(ret.prototype().strictlyEquals(originalProto));
434 // replace value of existing object
436 QScriptValue object = eng.newVariant(QVariant(123));
437 QScriptValue ret = eng.newVariant(object, QVariant(456));
438 QVERIFY(ret.isValid());
439 QVERIFY(ret.strictlyEquals(object));
440 QVERIFY(ret.isVariant());
441 QCOMPARE(ret.toVariant(), QVariant(456));
444 // valueOf() and toString()
446 QScriptValue object = eng.newVariant(QVariant(123));
447 QScriptValue value = object.property("valueOf").call(object);
448 QVERIFY(value.isNumber());
449 QCOMPARE(value.toInt32(), 123);
450 QCOMPARE(object.toString(), QString::fromLatin1("123"));
451 QCOMPARE(object.toVariant().toString(), object.toString());
454 QScriptValue object = eng.newVariant(QVariant(QString::fromLatin1("hello")));
455 QScriptValue value = object.property("valueOf").call(object);
456 QVERIFY(value.isString());
457 QCOMPARE(value.toString(), QString::fromLatin1("hello"));
458 QCOMPARE(object.toString(), QString::fromLatin1("hello"));
459 QCOMPARE(object.toVariant().toString(), object.toString());
462 QScriptValue object = eng.newVariant(QVariant(false));
463 QScriptValue value = object.property("valueOf").call(object);
464 QVERIFY(value.isBoolean());
465 QCOMPARE(value.toBoolean(), false);
466 QCOMPARE(object.toString(), QString::fromLatin1("false"));
467 QCOMPARE(object.toVariant().toString(), object.toString());
470 QScriptValue object = eng.newVariant(QVariant(QPoint(10, 20)));
471 QScriptValue value = object.property("valueOf").call(object);
472 QVERIFY(value.isObject());
473 QVERIFY(value.strictlyEquals(object));
474 QCOMPARE(object.toString(), QString::fromLatin1("QVariant(QPoint)"));
478 void tst_QScriptEngine::newRegExp()
480 QScriptEngine eng;
481 for (int x = 0; x < 2; ++x) {
482 QScriptValue rexp;
483 if (x == 0)
484 rexp = eng.newRegExp("foo", "bar");
485 else
486 rexp = eng.newRegExp(QRegExp("foo"));
487 QCOMPARE(rexp.isValid(), true);
488 QCOMPARE(rexp.isRegExp(), true);
489 QCOMPARE(rexp.isObject(), true);
490 QVERIFY(rexp.isFunction()); // in JSC, RegExp objects are callable
491 // prototype should be RegExp.prototype
492 QCOMPARE(rexp.prototype().isValid(), true);
493 QCOMPARE(rexp.prototype().isObject(), true);
494 QCOMPARE(rexp.prototype().isRegExp(), false);
495 QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true);
497 QCOMPARE(rexp.toRegExp().pattern(), QRegExp("foo").pattern());
500 QScriptValue r = eng.evaluate("/foo/gim");
501 QVERIFY(r.isRegExp());
502 QCOMPARE(r.toString(), QString::fromLatin1("/foo/gim"));
504 QScriptValue rxCtor = eng.globalObject().property("RegExp");
505 QScriptValue r2 = rxCtor.call(QScriptValue(), QScriptValueList() << r);
506 QVERIFY(r2.isRegExp());
507 QVERIFY(r2.strictlyEquals(r));
509 QScriptValue r3 = rxCtor.call(QScriptValue(), QScriptValueList() << r << "gim");
510 QVERIFY(r3.isError());
511 QCOMPARE(r3.toString(), QString::fromLatin1("TypeError: Cannot supply flags when constructing one RegExp from another."));
513 QScriptValue r4 = rxCtor.call(QScriptValue(), QScriptValueList() << "foo" << "gim");
514 QVERIFY(r4.isRegExp());
516 QScriptValue r5 = rxCtor.construct(QScriptValueList() << r);
517 QVERIFY(r5.isRegExp());
518 QCOMPARE(r5.toString(), QString::fromLatin1("/foo/gim"));
519 // In JSC, constructing a RegExp from another produces the same identical object.
520 // This is different from SpiderMonkey and old back-end.
521 QVERIFY(r5.strictlyEquals(r));
523 QScriptValue r6 = rxCtor.construct(QScriptValueList() << "foo" << "bar");
524 QVERIFY(r6.isError());
525 QCOMPARE(r6.toString(), QString::fromLatin1("SyntaxError: Invalid regular expression: invalid regular expression flag"));
527 QScriptValue r7 = eng.evaluate("/foo/gimp");
528 QVERIFY(r7.isError());
529 QCOMPARE(r7.toString(), QString::fromLatin1("SyntaxError: Invalid regular expression: invalid regular expression flag"));
531 QScriptValue r8 = eng.evaluate("/foo/migmigmig");
532 QVERIFY(r8.isRegExp());
533 QCOMPARE(r8.toString(), QString::fromLatin1("/foo/gim"));
535 QScriptValue r9 = rxCtor.construct();
536 QVERIFY(r9.isRegExp());
537 QCOMPARE(r9.toString(), QString::fromLatin1("/(?:)/"));
539 QScriptValue r10 = rxCtor.construct(QScriptValueList() << "" << "gim");
540 QVERIFY(r10.isRegExp());
541 QCOMPARE(r10.toString(), QString::fromLatin1("/(?:)/gim"));
543 QScriptValue r11 = rxCtor.construct(QScriptValueList() << "{1.*}" << "g");
544 QVERIFY(r11.isRegExp());
545 QCOMPARE(r11.toString(), QString::fromLatin1("/{1.*}/g"));
549 void tst_QScriptEngine::newDate()
551 QScriptEngine eng;
554 QScriptValue date = eng.newDate(0);
555 QCOMPARE(date.isValid(), true);
556 QCOMPARE(date.isDate(), true);
557 QCOMPARE(date.isObject(), true);
558 QVERIFY(!date.isFunction());
559 // prototype should be Date.prototype
560 QCOMPARE(date.prototype().isValid(), true);
561 QCOMPARE(date.prototype().isDate(), true);
562 QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
566 QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::LocalTime);
567 QScriptValue date = eng.newDate(dt);
568 QCOMPARE(date.isValid(), true);
569 QCOMPARE(date.isDate(), true);
570 QCOMPARE(date.isObject(), true);
571 // prototype should be Date.prototype
572 QCOMPARE(date.prototype().isValid(), true);
573 QCOMPARE(date.prototype().isDate(), true);
574 QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true);
576 QCOMPARE(date.toDateTime(), dt);
580 QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::UTC);
581 QScriptValue date = eng.newDate(dt);
582 // toDateTime() result should be in local time
583 QCOMPARE(date.toDateTime(), dt.toLocalTime());
586 // Date.parse() should return NaN when it fails
588 QScriptValue ret = eng.evaluate("Date.parse()");
589 QVERIFY(ret.isNumber());
590 QVERIFY(qIsNaN(ret.toNumber()));
593 // Date.parse() should be able to parse the output of Date().toString()
594 #ifndef Q_WS_WIN // TODO: Test and remove this since 169701 has been fixed
596 QScriptValue ret = eng.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()");
597 QVERIFY(ret.isBoolean());
598 QCOMPARE(ret.toBoolean(), true);
600 #endif
603 void tst_QScriptEngine::newQObject()
605 QScriptEngine eng;
608 QScriptValue qobject = eng.newQObject(0);
609 QCOMPARE(qobject.isValid(), true);
610 QCOMPARE(qobject.isNull(), true);
611 QCOMPARE(qobject.isObject(), false);
612 QCOMPARE(qobject.toQObject(), (QObject *)0);
615 QScriptValue qobject = eng.newQObject(this);
616 QCOMPARE(qobject.isValid(), true);
617 QCOMPARE(qobject.isQObject(), true);
618 QCOMPARE(qobject.isObject(), true);
619 QCOMPARE(qobject.toQObject(), (QObject *)this);
620 QVERIFY(!qobject.isFunction());
621 // prototype should be QObject.prototype
622 QCOMPARE(qobject.prototype().isValid(), true);
623 QCOMPARE(qobject.prototype().isQObject(), true);
624 QCOMPARE(qobject.scriptClass(), (QScriptClass*)0);
627 // test ownership
629 QPointer<QObject> ptr = new QObject();
630 QVERIFY(ptr != 0);
632 QScriptValue v = eng.newQObject(ptr, QScriptEngine::ScriptOwnership);
634 eng.evaluate("gc()");
635 if (ptr)
636 QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue);
637 QVERIFY(ptr == 0);
640 QPointer<QObject> ptr = new QObject();
641 QVERIFY(ptr != 0);
643 QScriptValue v = eng.newQObject(ptr, QScriptEngine::QtOwnership);
645 QObject *before = ptr;
646 eng.evaluate("gc()");
647 QVERIFY(ptr == before);
648 delete ptr;
651 QObject *parent = new QObject();
652 QObject *child = new QObject(parent);
653 QScriptValue v = eng.newQObject(child, QScriptEngine::QtOwnership);
654 QCOMPARE(v.toQObject(), child);
655 delete parent;
656 QCOMPARE(v.toQObject(), (QObject *)0);
659 QPointer<QObject> ptr = new QObject();
660 QVERIFY(ptr != 0);
662 QScriptValue v = eng.newQObject(ptr, QScriptEngine::AutoOwnership);
664 eng.evaluate("gc()");
665 // no parent, so it should be like ScriptOwnership
666 if (ptr)
667 QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue);
668 QVERIFY(ptr == 0);
671 QObject *parent = new QObject();
672 QPointer<QObject> child = new QObject(parent);
673 QVERIFY(child != 0);
675 QScriptValue v = eng.newQObject(child, QScriptEngine::AutoOwnership);
677 eng.evaluate("gc()");
678 // has parent, so it should be like QtOwnership
679 QVERIFY(child != 0);
680 delete parent;
683 // "promote" plain object to QObject
685 QScriptValue obj = eng.newObject();
686 QScriptValue originalProto = obj.prototype();
687 QScriptValue ret = eng.newQObject(obj, this);
688 QVERIFY(ret.isValid());
689 QVERIFY(ret.isQObject());
690 QVERIFY(ret.strictlyEquals(obj));
691 QVERIFY(obj.isQObject());
692 QCOMPARE(ret.toQObject(), (QObject *)this);
693 QVERIFY(ret.prototype().strictlyEquals(originalProto));
694 QScriptValue val = ret.property("objectName");
695 QVERIFY(val.isString());
697 // "promote" variant object to QObject
699 QScriptValue obj = eng.newVariant(123);
700 QVERIFY(obj.isVariant());
701 QScriptValue originalProto = obj.prototype();
702 QScriptValue ret = eng.newQObject(obj, this);
703 QVERIFY(ret.isQObject());
704 QVERIFY(ret.strictlyEquals(obj));
705 QVERIFY(obj.isQObject());
706 QCOMPARE(ret.toQObject(), (QObject *)this);
707 QVERIFY(ret.prototype().strictlyEquals(originalProto));
709 // replace QObject* of existing object
711 QScriptValue object = eng.newVariant(123);
712 QScriptValue originalProto = object.prototype();
713 QObject otherQObject;
714 QScriptValue ret = eng.newQObject(object, &otherQObject);
715 QVERIFY(ret.isValid());
716 QVERIFY(ret.isQObject());
717 QVERIFY(ret.strictlyEquals(object));
718 QCOMPARE(ret.toQObject(), (QObject *)&otherQObject);
719 QVERIFY(ret.prototype().strictlyEquals(originalProto));
722 // calling newQObject() several times with same object
723 for (int x = 0; x < 2; ++x) {
724 QObject qobj;
725 // the default is to create a new wrapper object
726 QScriptValue obj1 = eng.newQObject(&qobj);
727 QScriptValue obj2 = eng.newQObject(&qobj);
728 QVERIFY(!obj2.strictlyEquals(obj1));
730 QScriptEngine::QObjectWrapOptions opt = 0;
731 bool preferExisting = (x != 0);
732 if (preferExisting)
733 opt |= QScriptEngine::PreferExistingWrapperObject;
735 QScriptValue obj3 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt);
736 QVERIFY(!obj3.strictlyEquals(obj2));
737 QScriptValue obj4 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt);
738 QCOMPARE(obj4.strictlyEquals(obj3), preferExisting);
740 QScriptValue obj5 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt);
741 QVERIFY(!obj5.strictlyEquals(obj4));
742 QScriptValue obj6 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt);
743 QCOMPARE(obj6.strictlyEquals(obj5), preferExisting);
745 QScriptValue obj7 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership,
746 QScriptEngine::ExcludeSuperClassMethods | opt);
747 QVERIFY(!obj7.strictlyEquals(obj6));
748 QScriptValue obj8 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership,
749 QScriptEngine::ExcludeSuperClassMethods | opt);
750 QCOMPARE(obj8.strictlyEquals(obj7), preferExisting);
753 // newQObject() should set the default prototype, if one has been registered
755 QScriptValue oldQObjectProto = eng.defaultPrototype(qMetaTypeId<QObject*>());
757 QScriptValue qobjectProto = eng.newObject();
758 eng.setDefaultPrototype(qMetaTypeId<QObject*>(), qobjectProto);
760 QScriptValue ret = eng.newQObject(this);
761 QVERIFY(ret.prototype().equals(qobjectProto));
763 QScriptValue tstProto = eng.newObject();
764 int typeId = qRegisterMetaType<tst_QScriptEngine*>("tst_QScriptEngine*");
765 eng.setDefaultPrototype(typeId, tstProto);
767 QScriptValue ret = eng.newQObject(this);
768 QVERIFY(ret.prototype().equals(tstProto));
771 eng.setDefaultPrototype(qMetaTypeId<QObject*>(), oldQObjectProto);
772 eng.setDefaultPrototype(typeId, QScriptValue());
776 QT_BEGIN_NAMESPACE
777 Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*)
778 Q_SCRIPT_DECLARE_QMETAOBJECT(QWidget, QWidget*)
779 QT_END_NAMESPACE
781 static QScriptValue myConstructor(QScriptContext *ctx, QScriptEngine *eng)
783 QScriptValue obj;
784 if (ctx->isCalledAsConstructor()) {
785 obj = ctx->thisObject();
786 } else {
787 obj = eng->newObject();
788 obj.setPrototype(ctx->callee().property("prototype"));
790 obj.setProperty("isCalledAsConstructor", QScriptValue(eng, ctx->isCalledAsConstructor()));
791 return obj;
794 void tst_QScriptEngine::newQMetaObject()
796 QScriptEngine eng;
797 #if 0
798 QScriptValue qclass = eng.newQMetaObject<QObject>();
799 QScriptValue qclass2 = eng.newQMetaObject<QWidget>();
800 #else
801 QScriptValue qclass = qScriptValueFromQMetaObject<QObject>(&eng);
802 QScriptValue qclass2 = qScriptValueFromQMetaObject<QWidget>(&eng);
803 #endif
804 QCOMPARE(qclass.isValid(), true);
805 QCOMPARE(qclass.isQMetaObject(), true);
806 QCOMPARE(qclass.toQMetaObject(), &QObject::staticMetaObject);
807 QCOMPARE(qclass.isFunction(), true);
808 QVERIFY(qclass.property("prototype").isObject());
810 QCOMPARE(qclass2.isValid(), true);
811 QCOMPARE(qclass2.isQMetaObject(), true);
812 QCOMPARE(qclass2.toQMetaObject(), &QWidget::staticMetaObject);
813 QCOMPARE(qclass2.isFunction(), true);
814 QVERIFY(qclass2.property("prototype").isObject());
816 // prototype should be QMetaObject.prototype
817 QCOMPARE(qclass.prototype().isObject(), true);
818 QCOMPARE(qclass2.prototype().isObject(), true);
820 QScriptValue instance = qclass.construct();
821 QCOMPARE(instance.isQObject(), true);
822 QCOMPARE(instance.toQObject()->metaObject(), qclass.toQMetaObject());
823 QVERIFY(instance.instanceOf(qclass));
825 QScriptValue instance2 = qclass2.construct();
826 QCOMPARE(instance2.isQObject(), true);
827 QCOMPARE(instance2.toQObject()->metaObject(), qclass2.toQMetaObject());
828 QVERIFY(instance2.instanceOf(qclass2));
830 QScriptValueList args;
831 args << instance;
832 QScriptValue instance3 = qclass.construct(args);
833 QCOMPARE(instance3.isQObject(), true);
834 QCOMPARE(instance3.toQObject()->parent(), instance.toQObject());
835 QVERIFY(instance3.instanceOf(qclass));
836 args.clear();
838 QPointer<QObject> qpointer1 = instance.toQObject();
839 QPointer<QObject> qpointer2 = instance2.toQObject();
840 QPointer<QObject> qpointer3 = instance3.toQObject();
842 QVERIFY(qpointer1);
843 QVERIFY(qpointer2);
844 QVERIFY(qpointer3);
846 // verify that AutoOwnership is in effect
847 instance = QScriptValue();
848 collectGarbage_helper(eng);
850 QVERIFY(!qpointer1);
851 QVERIFY(qpointer2);
852 QVERIFY(!qpointer3); // was child of instance
854 QVERIFY(instance.toQObject() == 0);
855 QVERIFY(instance3.toQObject() == 0); // was child of instance
856 QVERIFY(instance2.toQObject() != 0);
857 instance2 = QScriptValue();
858 collectGarbage_helper(eng);
859 QVERIFY(instance2.toQObject() == 0);
861 // with custom constructor
862 QScriptValue ctor = eng.newFunction(myConstructor);
863 QScriptValue qclass3 = eng.newQMetaObject(&QObject::staticMetaObject, ctor);
864 QVERIFY(qclass3.property("prototype").equals(ctor.property("prototype")));
866 QScriptValue ret = qclass3.call();
867 QVERIFY(ret.isObject());
868 QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
869 QVERIFY(!ret.property("isCalledAsConstructor").toBoolean());
870 QVERIFY(ret.instanceOf(qclass3));
873 QScriptValue ret = qclass3.construct();
874 QVERIFY(ret.isObject());
875 QVERIFY(ret.property("isCalledAsConstructor").isBoolean());
876 QVERIFY(ret.property("isCalledAsConstructor").toBoolean());
877 QVERIFY(ret.instanceOf(qclass3));
880 // subclassing
881 qclass2.setProperty("prototype", qclass.construct());
882 QVERIFY(qclass2.construct().instanceOf(qclass));
884 // with meta-constructor
885 QScriptValue qclass4 = eng.newQMetaObject(&QObject::staticMetaObject);
887 QScriptValue inst = qclass4.construct();
888 QVERIFY(inst.isQObject());
889 QVERIFY(inst.toQObject() != 0);
890 QCOMPARE(inst.toQObject()->parent(), (QObject*)0);
891 QVERIFY(inst.instanceOf(qclass4));
894 QScriptValue inst = qclass4.construct(QScriptValueList() << eng.newQObject(this));
895 QVERIFY(inst.isQObject());
896 QVERIFY(inst.toQObject() != 0);
897 QCOMPARE(inst.toQObject()->parent(), (QObject*)this);
898 QVERIFY(inst.instanceOf(qclass4));
902 void tst_QScriptEngine::newActivationObject()
904 QSKIP("internal function not implemented in JSC-based back-end", SkipAll);
905 QScriptEngine eng;
906 QScriptValue act = eng.newActivationObject();
907 QEXPECT_FAIL("", "", Continue);
908 QCOMPARE(act.isValid(), true);
909 QEXPECT_FAIL("", "", Continue);
910 QCOMPARE(act.isObject(), true);
911 QVERIFY(!act.isFunction());
912 QScriptValue v(&eng, 123);
913 act.setProperty("prop", v);
914 QEXPECT_FAIL("", "", Continue);
915 QCOMPARE(act.property("prop").strictlyEquals(v), true);
916 QCOMPARE(act.scope().isValid(), false);
917 QEXPECT_FAIL("", "", Continue);
918 QVERIFY(act.prototype().isNull());
921 void tst_QScriptEngine::getSetGlobalObject()
923 QScriptEngine eng;
924 QScriptValue glob = eng.globalObject();
925 QCOMPARE(glob.isValid(), true);
926 QCOMPARE(glob.isObject(), true);
927 QVERIFY(!glob.isFunction());
928 QVERIFY(eng.currentContext()->thisObject().strictlyEquals(glob));
929 QVERIFY(eng.currentContext()->activationObject().strictlyEquals(glob));
930 QCOMPARE(glob.toString(), QString::fromLatin1("[object global]"));
931 // prototype should be Object.prototype
932 QCOMPARE(glob.prototype().isValid(), true);
933 QCOMPARE(glob.prototype().isObject(), true);
934 QCOMPARE(glob.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true);
936 QScriptValue obj = eng.newObject();
937 eng.setGlobalObject(obj);
938 QVERIFY(eng.globalObject().strictlyEquals(obj));
939 QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
940 QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
941 QVERIFY(eng.evaluate("this").strictlyEquals(obj));
942 QCOMPARE(eng.globalObject().toString(), QString::fromLatin1("[object Object]"));
944 glob = QScriptValue(); // kill reference to old global object
945 collectGarbage_helper(eng);
946 obj = eng.newObject();
947 eng.setGlobalObject(obj);
948 QVERIFY(eng.globalObject().strictlyEquals(obj));
949 QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
950 QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
952 collectGarbage_helper(eng);
953 QVERIFY(eng.globalObject().strictlyEquals(obj));
954 QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj));
955 QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj));
957 QVERIFY(!obj.property("foo").isValid());
958 eng.evaluate("var foo = 123");
960 QScriptValue ret = obj.property("foo");
961 QVERIFY(ret.isNumber());
962 QCOMPARE(ret.toInt32(), 123);
965 QVERIFY(!obj.property("bar").isValid());
966 eng.evaluate("bar = 456");
968 QScriptValue ret = obj.property("bar");
969 QVERIFY(ret.isNumber());
970 QCOMPARE(ret.toInt32(), 456);
973 QVERIFY(!obj.property("baz").isValid());
974 eng.evaluate("this['baz'] = 789");
976 QScriptValue ret = obj.property("baz");
977 QVERIFY(ret.isNumber());
978 QCOMPARE(ret.toInt32(), 789);
982 QScriptValue ret = eng.evaluate("(function() { return this; })()");
983 QVERIFY(ret.strictlyEquals(obj));
987 static QScriptValue getSetFoo(QScriptContext *ctx, QScriptEngine *)
989 if (ctx->argumentCount() > 0)
990 ctx->thisObject().setProperty("foo", ctx->argument(0));
991 return ctx->thisObject().property("foo");
994 void tst_QScriptEngine::globalObjectProperties()
996 QScriptEngine eng;
997 QScriptValue global = eng.globalObject();
999 QVERIFY(global.property("NaN").isNumber());
1000 QVERIFY(qIsNaN(global.property("NaN").toNumber()));
1001 QCOMPARE(global.propertyFlags("NaN"), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
1003 QVERIFY(global.property("Infinity").isNumber());
1004 QVERIFY(qIsInf(global.property("Infinity").toNumber()));
1005 QCOMPARE(global.propertyFlags("NaN"), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
1007 QVERIFY(global.property("undefined").isUndefined());
1008 QCOMPARE(global.propertyFlags("undefined"), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable);
1010 QVERIFY(global.property("eval").isFunction());
1011 QCOMPARE(global.propertyFlags("eval"), QScriptValue::SkipInEnumeration);
1013 QVERIFY(global.property("parseInt").isFunction());
1014 QCOMPARE(global.propertyFlags("parseInt"), QScriptValue::SkipInEnumeration);
1016 QVERIFY(global.property("parseFloat").isFunction());
1017 QCOMPARE(global.propertyFlags("parseFloat"), QScriptValue::SkipInEnumeration);
1019 QVERIFY(global.property("isNaN").isFunction());
1020 QCOMPARE(global.propertyFlags("isNaN"), QScriptValue::SkipInEnumeration);
1022 QVERIFY(global.property("isFinite").isFunction());
1023 QCOMPARE(global.propertyFlags("isFinite"), QScriptValue::SkipInEnumeration);
1025 QVERIFY(global.property("decodeURI").isFunction());
1026 QCOMPARE(global.propertyFlags("decodeURI"), QScriptValue::SkipInEnumeration);
1028 QVERIFY(global.property("decodeURIComponent").isFunction());
1029 QCOMPARE(global.propertyFlags("decodeURIComponent"), QScriptValue::SkipInEnumeration);
1031 QVERIFY(global.property("encodeURI").isFunction());
1032 QCOMPARE(global.propertyFlags("encodeURI"), QScriptValue::SkipInEnumeration);
1034 QVERIFY(global.property("encodeURIComponent").isFunction());
1035 QCOMPARE(global.propertyFlags("encodeURIComponent"), QScriptValue::SkipInEnumeration);
1037 QVERIFY(global.property("Object").isFunction());
1038 QCOMPARE(global.propertyFlags("Object"), QScriptValue::SkipInEnumeration);
1039 QVERIFY(global.property("Function").isFunction());
1040 QCOMPARE(global.propertyFlags("Function"), QScriptValue::SkipInEnumeration);
1041 QVERIFY(global.property("Array").isFunction());
1042 QCOMPARE(global.propertyFlags("Array"), QScriptValue::SkipInEnumeration);
1043 QVERIFY(global.property("String").isFunction());
1044 QCOMPARE(global.propertyFlags("String"), QScriptValue::SkipInEnumeration);
1045 QVERIFY(global.property("Boolean").isFunction());
1046 QCOMPARE(global.propertyFlags("Boolean"), QScriptValue::SkipInEnumeration);
1047 QVERIFY(global.property("Number").isFunction());
1048 QCOMPARE(global.propertyFlags("Number"), QScriptValue::SkipInEnumeration);
1049 QVERIFY(global.property("Date").isFunction());
1050 QCOMPARE(global.propertyFlags("Date"), QScriptValue::SkipInEnumeration);
1051 QVERIFY(global.property("RegExp").isFunction());
1052 QCOMPARE(global.propertyFlags("RegExp"), QScriptValue::SkipInEnumeration);
1053 QVERIFY(global.property("Error").isFunction());
1054 QCOMPARE(global.propertyFlags("Error"), QScriptValue::SkipInEnumeration);
1055 QVERIFY(global.property("EvalError").isFunction());
1056 QCOMPARE(global.propertyFlags("EvalError"), QScriptValue::SkipInEnumeration);
1057 QVERIFY(global.property("RangeError").isFunction());
1058 QCOMPARE(global.propertyFlags("RangeError"), QScriptValue::SkipInEnumeration);
1059 QVERIFY(global.property("ReferenceError").isFunction());
1060 QCOMPARE(global.propertyFlags("ReferenceError"), QScriptValue::SkipInEnumeration);
1061 QVERIFY(global.property("SyntaxError").isFunction());
1062 QCOMPARE(global.propertyFlags("SyntaxError"), QScriptValue::SkipInEnumeration);
1063 QVERIFY(global.property("TypeError").isFunction());
1064 QCOMPARE(global.propertyFlags("TypeError"), QScriptValue::SkipInEnumeration);
1065 QVERIFY(global.property("URIError").isFunction());
1066 QCOMPARE(global.propertyFlags("URIError"), QScriptValue::SkipInEnumeration);
1067 QVERIFY(global.property("Math").isObject());
1068 QVERIFY(!global.property("Math").isFunction());
1069 QEXPECT_FAIL("", "[ECMA compliance] JSC sets DontDelete flag for Math object", Continue);
1070 QCOMPARE(global.propertyFlags("Math"), QScriptValue::SkipInEnumeration);
1072 // enumeration
1073 QSet<QString> expectedNames;
1074 expectedNames
1075 << "isNaN"
1076 << "parseFloat"
1077 << "String"
1078 << "EvalError"
1079 << "URIError"
1080 << "Math"
1081 << "encodeURIComponent"
1082 << "RangeError"
1083 << "eval"
1084 << "isFinite"
1085 << "ReferenceError"
1086 << "Infinity"
1087 << "Function"
1088 << "RegExp"
1089 << "Number"
1090 << "parseInt"
1091 << "Object"
1092 << "decodeURI"
1093 << "TypeError"
1094 << "Boolean"
1095 << "encodeURI"
1096 << "NaN"
1097 << "Error"
1098 << "decodeURIComponent"
1099 << "Date"
1100 << "Array"
1101 << "escape"
1102 << "unescape"
1103 << "SyntaxError"
1104 << "undefined"
1105 // non-standard
1106 << "gc"
1107 << "version"
1108 << "print"
1109 // JavaScriptCore
1110 << "JSON"
1112 QSet<QString> actualNames;
1114 QScriptValueIterator it(global);
1115 while (it.hasNext()) {
1116 it.next();
1117 actualNames.insert(it.name());
1121 QSet<QString> remainingNames = actualNames;
1123 QSet<QString>::const_iterator it;
1124 for (it = expectedNames.constBegin(); it != expectedNames.constEnd(); ++it) {
1125 QString name = *it;
1126 QVERIFY(actualNames.contains(name));
1127 remainingNames.remove(name);
1130 QVERIFY(remainingNames.isEmpty());
1132 // create property with no attributes
1134 QString name = QString::fromLatin1("foo");
1135 QVERIFY(!global.property(name).isValid());
1136 QScriptValue val(123);
1137 global.setProperty(name, val);
1138 QVERIFY(global.property(name).equals(val));
1139 QVERIFY(global.propertyFlags(name) == 0);
1140 global.setProperty(name, QScriptValue());
1141 QVERIFY(!global.property(name).isValid());
1143 // create property with attributes
1145 QString name = QString::fromLatin1("bar");
1146 QVERIFY(!global.property(name).isValid());
1147 QScriptValue val(QString::fromLatin1("ciao"));
1148 QScriptValue::PropertyFlags flags = QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration;
1149 global.setProperty(name, val, flags);
1150 QVERIFY(global.property(name).equals(val));
1151 QEXPECT_FAIL("", "custom Global Object properties don't retain attributes", Continue);
1152 QCOMPARE(global.propertyFlags(name), flags);
1153 global.setProperty(name, QScriptValue());
1154 QVERIFY(!global.property(name).isValid());
1158 void tst_QScriptEngine::globalObjectGetterSetterProperty()
1160 QScriptEngine engine;
1161 QScriptValue global = engine.globalObject();
1162 global.setProperty("bar", engine.newFunction(getSetFoo),
1163 QScriptValue::PropertySetter | QScriptValue::PropertyGetter);
1164 global.setProperty("foo", 123);
1165 QVERIFY(global.property("bar").equals(global.property("foo")));
1166 QVERIFY(engine.evaluate("bar").equals(global.property("foo")));
1167 global.setProperty("bar", 456);
1168 QVERIFY(global.property("bar").equals(global.property("foo")));
1170 engine.evaluate("__defineGetter__('baz', function() { return 789; })");
1171 QVERIFY(engine.evaluate("baz").equals(789));
1172 QVERIFY(global.property("baz").equals(789));
1175 void tst_QScriptEngine::builtinFunctionNames_data()
1177 QTest::addColumn<QString>("expression");
1178 QTest::addColumn<QString>("expectedName");
1180 QTest::newRow("print") << QString("print") << QString("print");
1181 QTest::newRow("parseInt") << QString("parseInt") << QString("parseInt");
1182 QTest::newRow("parseFloat") << QString("parseFloat") << QString("parseFloat");
1183 QTest::newRow("isNaN") << QString("isNaN") << QString("isNaN");
1184 QTest::newRow("isFinite") << QString("isFinite") << QString("isFinite");
1185 QTest::newRow("decodeURI") << QString("decodeURI") << QString("decodeURI");
1186 QTest::newRow("decodeURIComponent") << QString("decodeURIComponent") << QString("decodeURIComponent");
1187 QTest::newRow("encodeURI") << QString("encodeURI") << QString("encodeURI");
1188 QTest::newRow("encodeURIComponent") << QString("encodeURIComponent") << QString("encodeURIComponent");
1189 QTest::newRow("escape") << QString("escape") << QString("escape");
1190 QTest::newRow("unescape") << QString("unescape") << QString("unescape");
1191 QTest::newRow("version") << QString("version") << QString("version");
1192 QTest::newRow("gc") << QString("gc") << QString("gc");
1194 QTest::newRow("Array") << QString("Array") << QString("Array");
1195 QTest::newRow("Array.prototype.toString") << QString("Array.prototype.toString") << QString("toString");
1196 QTest::newRow("Array.prototype.toLocaleString") << QString("Array.prototype.toLocaleString") << QString("toLocaleString");
1197 QTest::newRow("Array.prototype.concat") << QString("Array.prototype.concat") << QString("concat");
1198 QTest::newRow("Array.prototype.join") << QString("Array.prototype.join") << QString("join");
1199 QTest::newRow("Array.prototype.pop") << QString("Array.prototype.pop") << QString("pop");
1200 QTest::newRow("Array.prototype.push") << QString("Array.prototype.push") << QString("push");
1201 QTest::newRow("Array.prototype.reverse") << QString("Array.prototype.reverse") << QString("reverse");
1202 QTest::newRow("Array.prototype.shift") << QString("Array.prototype.shift") << QString("shift");
1203 QTest::newRow("Array.prototype.slice") << QString("Array.prototype.slice") << QString("slice");
1204 QTest::newRow("Array.prototype.sort") << QString("Array.prototype.sort") << QString("sort");
1205 QTest::newRow("Array.prototype.splice") << QString("Array.prototype.splice") << QString("splice");
1206 QTest::newRow("Array.prototype.unshift") << QString("Array.prototype.unshift") << QString("unshift");
1208 QTest::newRow("Boolean") << QString("Boolean") << QString("Boolean");
1209 QTest::newRow("Boolean.prototype.toString") << QString("Boolean.prototype.toString") << QString("toString");
1211 QTest::newRow("Date") << QString("Date") << QString("Date");
1212 QTest::newRow("Date.prototype.toString") << QString("Date.prototype.toString") << QString("toString");
1213 QTest::newRow("Date.prototype.toDateString") << QString("Date.prototype.toDateString") << QString("toDateString");
1214 QTest::newRow("Date.prototype.toTimeString") << QString("Date.prototype.toTimeString") << QString("toTimeString");
1215 QTest::newRow("Date.prototype.toLocaleString") << QString("Date.prototype.toLocaleString") << QString("toLocaleString");
1216 QTest::newRow("Date.prototype.toLocaleDateString") << QString("Date.prototype.toLocaleDateString") << QString("toLocaleDateString");
1217 QTest::newRow("Date.prototype.toLocaleTimeString") << QString("Date.prototype.toLocaleTimeString") << QString("toLocaleTimeString");
1218 QTest::newRow("Date.prototype.valueOf") << QString("Date.prototype.valueOf") << QString("valueOf");
1219 QTest::newRow("Date.prototype.getTime") << QString("Date.prototype.getTime") << QString("getTime");
1220 QTest::newRow("Date.prototype.getYear") << QString("Date.prototype.getYear") << QString("getYear");
1221 QTest::newRow("Date.prototype.getFullYear") << QString("Date.prototype.getFullYear") << QString("getFullYear");
1222 QTest::newRow("Date.prototype.getUTCFullYear") << QString("Date.prototype.getUTCFullYear") << QString("getUTCFullYear");
1223 QTest::newRow("Date.prototype.getMonth") << QString("Date.prototype.getMonth") << QString("getMonth");
1224 QTest::newRow("Date.prototype.getUTCMonth") << QString("Date.prototype.getUTCMonth") << QString("getUTCMonth");
1225 QTest::newRow("Date.prototype.getDate") << QString("Date.prototype.getDate") << QString("getDate");
1226 QTest::newRow("Date.prototype.getUTCDate") << QString("Date.prototype.getUTCDate") << QString("getUTCDate");
1227 QTest::newRow("Date.prototype.getDay") << QString("Date.prototype.getDay") << QString("getDay");
1228 QTest::newRow("Date.prototype.getUTCDay") << QString("Date.prototype.getUTCDay") << QString("getUTCDay");
1229 QTest::newRow("Date.prototype.getHours") << QString("Date.prototype.getHours") << QString("getHours");
1230 QTest::newRow("Date.prototype.getUTCHours") << QString("Date.prototype.getUTCHours") << QString("getUTCHours");
1231 QTest::newRow("Date.prototype.getMinutes") << QString("Date.prototype.getMinutes") << QString("getMinutes");
1232 QTest::newRow("Date.prototype.getUTCMinutes") << QString("Date.prototype.getUTCMinutes") << QString("getUTCMinutes");
1233 QTest::newRow("Date.prototype.getSeconds") << QString("Date.prototype.getSeconds") << QString("getSeconds");
1234 QTest::newRow("Date.prototype.getUTCSeconds") << QString("Date.prototype.getUTCSeconds") << QString("getUTCSeconds");
1235 QTest::newRow("Date.prototype.getMilliseconds") << QString("Date.prototype.getMilliseconds") << QString("getMilliseconds");
1236 QTest::newRow("Date.prototype.getUTCMilliseconds") << QString("Date.prototype.getUTCMilliseconds") << QString("getUTCMilliseconds");
1237 QTest::newRow("Date.prototype.getTimezoneOffset") << QString("Date.prototype.getTimezoneOffset") << QString("getTimezoneOffset");
1238 QTest::newRow("Date.prototype.setTime") << QString("Date.prototype.setTime") << QString("setTime");
1239 QTest::newRow("Date.prototype.setMilliseconds") << QString("Date.prototype.setMilliseconds") << QString("setMilliseconds");
1240 QTest::newRow("Date.prototype.setUTCMilliseconds") << QString("Date.prototype.setUTCMilliseconds") << QString("setUTCMilliseconds");
1241 QTest::newRow("Date.prototype.setSeconds") << QString("Date.prototype.setSeconds") << QString("setSeconds");
1242 QTest::newRow("Date.prototype.setUTCSeconds") << QString("Date.prototype.setUTCSeconds") << QString("setUTCSeconds");
1243 QTest::newRow("Date.prototype.setMinutes") << QString("Date.prototype.setMinutes") << QString("setMinutes");
1244 QTest::newRow("Date.prototype.setUTCMinutes") << QString("Date.prototype.setUTCMinutes") << QString("setUTCMinutes");
1245 QTest::newRow("Date.prototype.setHours") << QString("Date.prototype.setHours") << QString("setHours");
1246 QTest::newRow("Date.prototype.setUTCHours") << QString("Date.prototype.setUTCHours") << QString("setUTCHours");
1247 QTest::newRow("Date.prototype.setDate") << QString("Date.prototype.setDate") << QString("setDate");
1248 QTest::newRow("Date.prototype.setUTCDate") << QString("Date.prototype.setUTCDate") << QString("setUTCDate");
1249 QTest::newRow("Date.prototype.setMonth") << QString("Date.prototype.setMonth") << QString("setMonth");
1250 QTest::newRow("Date.prototype.setUTCMonth") << QString("Date.prototype.setUTCMonth") << QString("setUTCMonth");
1251 QTest::newRow("Date.prototype.setYear") << QString("Date.prototype.setYear") << QString("setYear");
1252 QTest::newRow("Date.prototype.setFullYear") << QString("Date.prototype.setFullYear") << QString("setFullYear");
1253 QTest::newRow("Date.prototype.setUTCFullYear") << QString("Date.prototype.setUTCFullYear") << QString("setUTCFullYear");
1254 QTest::newRow("Date.prototype.toUTCString") << QString("Date.prototype.toUTCString") << QString("toUTCString");
1255 QTest::newRow("Date.prototype.toGMTString") << QString("Date.prototype.toGMTString") << QString("toGMTString");
1257 QTest::newRow("Error") << QString("Error") << QString("Error");
1258 // QTest::newRow("Error.prototype.backtrace") << QString("Error.prototype.backtrace") << QString("backtrace");
1259 QTest::newRow("Error.prototype.toString") << QString("Error.prototype.toString") << QString("toString");
1261 QTest::newRow("EvalError") << QString("EvalError") << QString("EvalError");
1262 QTest::newRow("RangeError") << QString("RangeError") << QString("RangeError");
1263 QTest::newRow("ReferenceError") << QString("ReferenceError") << QString("ReferenceError");
1264 QTest::newRow("SyntaxError") << QString("SyntaxError") << QString("SyntaxError");
1265 QTest::newRow("TypeError") << QString("TypeError") << QString("TypeError");
1266 QTest::newRow("URIError") << QString("URIError") << QString("URIError");
1268 QTest::newRow("Function") << QString("Function") << QString("Function");
1269 QTest::newRow("Function.prototype.toString") << QString("Function.prototype.toString") << QString("toString");
1270 QTest::newRow("Function.prototype.apply") << QString("Function.prototype.apply") << QString("apply");
1271 QTest::newRow("Function.prototype.call") << QString("Function.prototype.call") << QString("call");
1272 QTest::newRow("Function.prototype.connect") << QString("Function.prototype.connect") << QString("connect");
1273 QTest::newRow("Function.prototype.disconnect") << QString("Function.prototype.disconnect") << QString("disconnect");
1275 QTest::newRow("Math.abs") << QString("Math.abs") << QString("abs");
1276 QTest::newRow("Math.acos") << QString("Math.acos") << QString("acos");
1277 QTest::newRow("Math.asin") << QString("Math.asin") << QString("asin");
1278 QTest::newRow("Math.atan") << QString("Math.atan") << QString("atan");
1279 QTest::newRow("Math.atan2") << QString("Math.atan2") << QString("atan2");
1280 QTest::newRow("Math.ceil") << QString("Math.ceil") << QString("ceil");
1281 QTest::newRow("Math.cos") << QString("Math.cos") << QString("cos");
1282 QTest::newRow("Math.exp") << QString("Math.exp") << QString("exp");
1283 QTest::newRow("Math.floor") << QString("Math.floor") << QString("floor");
1284 QTest::newRow("Math.log") << QString("Math.log") << QString("log");
1285 QTest::newRow("Math.max") << QString("Math.max") << QString("max");
1286 QTest::newRow("Math.min") << QString("Math.min") << QString("min");
1287 QTest::newRow("Math.pow") << QString("Math.pow") << QString("pow");
1288 QTest::newRow("Math.random") << QString("Math.random") << QString("random");
1289 QTest::newRow("Math.round") << QString("Math.round") << QString("round");
1290 QTest::newRow("Math.sin") << QString("Math.sin") << QString("sin");
1291 QTest::newRow("Math.sqrt") << QString("Math.sqrt") << QString("sqrt");
1292 QTest::newRow("Math.tan") << QString("Math.tan") << QString("tan");
1294 QTest::newRow("Number") << QString("Number") << QString("Number");
1295 QTest::newRow("Number.prototype.toString") << QString("Number.prototype.toString") << QString("toString");
1296 QTest::newRow("Number.prototype.toLocaleString") << QString("Number.prototype.toLocaleString") << QString("toLocaleString");
1297 QTest::newRow("Number.prototype.valueOf") << QString("Number.prototype.valueOf") << QString("valueOf");
1298 QTest::newRow("Number.prototype.toFixed") << QString("Number.prototype.toFixed") << QString("toFixed");
1299 QTest::newRow("Number.prototype.toExponential") << QString("Number.prototype.toExponential") << QString("toExponential");
1300 QTest::newRow("Number.prototype.toPrecision") << QString("Number.prototype.toPrecision") << QString("toPrecision");
1302 QTest::newRow("Object") << QString("Object") << QString("Object");
1303 QTest::newRow("Object.prototype.toString") << QString("Object.prototype.toString") << QString("toString");
1304 QTest::newRow("Object.prototype.toLocaleString") << QString("Object.prototype.toLocaleString") << QString("toLocaleString");
1305 QTest::newRow("Object.prototype.valueOf") << QString("Object.prototype.valueOf") << QString("valueOf");
1306 QTest::newRow("Object.prototype.hasOwnProperty") << QString("Object.prototype.hasOwnProperty") << QString("hasOwnProperty");
1307 QTest::newRow("Object.prototype.isPrototypeOf") << QString("Object.prototype.isPrototypeOf") << QString("isPrototypeOf");
1308 QTest::newRow("Object.prototype.propertyIsEnumerable") << QString("Object.prototype.propertyIsEnumerable") << QString("propertyIsEnumerable");
1309 QTest::newRow("Object.prototype.__defineGetter__") << QString("Object.prototype.__defineGetter__") << QString("__defineGetter__");
1310 QTest::newRow("Object.prototype.__defineSetter__") << QString("Object.prototype.__defineSetter__") << QString("__defineSetter__");
1312 QTest::newRow("RegExp") << QString("RegExp") << QString("RegExp");
1313 QTest::newRow("RegExp.prototype.exec") << QString("RegExp.prototype.exec") << QString("exec");
1314 QTest::newRow("RegExp.prototype.test") << QString("RegExp.prototype.test") << QString("test");
1315 QTest::newRow("RegExp.prototype.toString") << QString("RegExp.prototype.toString") << QString("toString");
1317 QTest::newRow("String") << QString("String") << QString("String");
1318 QTest::newRow("String.prototype.toString") << QString("String.prototype.toString") << QString("toString");
1319 QTest::newRow("String.prototype.valueOf") << QString("String.prototype.valueOf") << QString("valueOf");
1320 QTest::newRow("String.prototype.charAt") << QString("String.prototype.charAt") << QString("charAt");
1321 QTest::newRow("String.prototype.charCodeAt") << QString("String.prototype.charCodeAt") << QString("charCodeAt");
1322 QTest::newRow("String.prototype.concat") << QString("String.prototype.concat") << QString("concat");
1323 QTest::newRow("String.prototype.indexOf") << QString("String.prototype.indexOf") << QString("indexOf");
1324 QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf");
1325 QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare");
1326 QTest::newRow("String.prototype.match") << QString("String.prototype.match") << QString("match");
1327 QTest::newRow("String.prototype.replace") << QString("String.prototype.replace") << QString("replace");
1328 QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search");
1329 QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice");
1330 QTest::newRow("String.prototype.split") << QString("String.prototype.split") << QString("split");
1331 QTest::newRow("String.prototype.substring") << QString("String.prototype.substring") << QString("substring");
1332 QTest::newRow("String.prototype.toLowerCase") << QString("String.prototype.toLowerCase") << QString("toLowerCase");
1333 QTest::newRow("String.prototype.toLocaleLowerCase") << QString("String.prototype.toLocaleLowerCase") << QString("toLocaleLowerCase");
1334 QTest::newRow("String.prototype.toUpperCase") << QString("String.prototype.toUpperCase") << QString("toUpperCase");
1335 QTest::newRow("String.prototype.toLocaleUpperCase") << QString("String.prototype.toLocaleUpperCase") << QString("toLocaleUpperCase");
1338 void tst_QScriptEngine::builtinFunctionNames()
1340 QFETCH(QString, expression);
1341 QFETCH(QString, expectedName);
1342 QScriptEngine eng;
1343 QScriptValue ret = eng.evaluate(QString::fromLatin1("%0.name").arg(expression));
1344 QVERIFY(ret.isString());
1345 QCOMPARE(ret.toString(), expectedName);
1348 void tst_QScriptEngine::checkSyntax_data()
1350 QTest::addColumn<QString>("code");
1351 QTest::addColumn<int>("expectedState");
1352 QTest::addColumn<int>("errorLineNumber");
1353 QTest::addColumn<int>("errorColumnNumber");
1354 QTest::addColumn<QString>("errorMessage");
1356 QTest::newRow("0")
1357 << QString("0") << int(QScriptSyntaxCheckResult::Valid)
1358 << -1 << -1 << "";
1359 QTest::newRow("if (")
1360 << QString("if (\n") << int(QScriptSyntaxCheckResult::Intermediate)
1361 << 1 << 4 << "";
1362 QTest::newRow("if else")
1363 << QString("\nif else") << int(QScriptSyntaxCheckResult::Error)
1364 << 2 << 4 << "Expected `('";
1365 QTest::newRow("foo[")
1366 << QString("foo[") << int(QScriptSyntaxCheckResult::Error)
1367 << 1 << 4 << "";
1368 QTest::newRow("foo['bar']")
1369 << QString("foo['bar']") << int(QScriptSyntaxCheckResult::Valid)
1370 << -1 << -1 << "";
1372 QTest::newRow("/*")
1373 << QString("/*") << int(QScriptSyntaxCheckResult::Intermediate)
1374 << 1 << 1 << "Unclosed comment at end of file";
1375 QTest::newRow("/*\nMy comment")
1376 << QString("/*\nMy comment") << int(QScriptSyntaxCheckResult::Intermediate)
1377 << 1 << 1 << "Unclosed comment at end of file";
1378 QTest::newRow("/*\nMy comment */\nfoo = 10")
1379 << QString("/*\nMy comment */\nfoo = 10") << int(QScriptSyntaxCheckResult::Valid)
1380 << -1 << -1 << "";
1381 QTest::newRow("foo = 10 /*")
1382 << QString("foo = 10 /*") << int(QScriptSyntaxCheckResult::Intermediate)
1383 << -1 << -1 << "";
1384 QTest::newRow("foo = 10; /*")
1385 << QString("foo = 10; /*") << int(QScriptSyntaxCheckResult::Intermediate)
1386 << 1 << 11 << "Expected `end of file'";
1387 QTest::newRow("foo = 10 /* My comment */")
1388 << QString("foo = 10 /* My comment */") << int(QScriptSyntaxCheckResult::Valid)
1389 << -1 << -1 << "";
1391 QTest::newRow("/=/")
1392 << QString("/=/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
1393 QTest::newRow("/=/g")
1394 << QString("/=/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
1395 QTest::newRow("/a/")
1396 << QString("/a/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
1397 QTest::newRow("/a/g")
1398 << QString("/a/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
1401 void tst_QScriptEngine::checkSyntax()
1403 QFETCH(QString, code);
1404 QFETCH(int, expectedState);
1405 QFETCH(int, errorLineNumber);
1406 QFETCH(int, errorColumnNumber);
1407 QFETCH(QString, errorMessage);
1409 QScriptSyntaxCheckResult result = QScriptEngine::checkSyntax(code);
1410 QCOMPARE(result.state(), QScriptSyntaxCheckResult::State(expectedState));
1411 QCOMPARE(result.errorLineNumber(), errorLineNumber);
1412 QCOMPARE(result.errorColumnNumber(), errorColumnNumber);
1413 QCOMPARE(result.errorMessage(), errorMessage);
1415 // assignment
1417 QScriptSyntaxCheckResult copy = result;
1418 QCOMPARE(copy.state(), result.state());
1419 QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
1420 QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
1421 QCOMPARE(copy.errorMessage(), result.errorMessage());
1424 QScriptSyntaxCheckResult copy(result);
1425 QCOMPARE(copy.state(), result.state());
1426 QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
1427 QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
1428 QCOMPARE(copy.errorMessage(), result.errorMessage());
1432 void tst_QScriptEngine::canEvaluate_data()
1434 QTest::addColumn<QString>("code");
1435 QTest::addColumn<bool>("expectSuccess");
1437 QTest::newRow("") << QString("") << true;
1438 QTest::newRow("0") << QString("0") << true;
1439 QTest::newRow("!") << QString("!\n") << false;
1440 QTest::newRow("if (") << QString("if (\n") << false;
1441 QTest::newRow("if (10) //") << QString("if (10) //\n") << false;
1442 QTest::newRow("a = 1; if (") << QString("a = 1;\nif (\n") << false;
1443 QTest::newRow("./test.js") << QString("./test.js\n") << true;
1444 QTest::newRow("if (0) print(1)") << QString("if (0)\nprint(1)\n") << true;
1445 QTest::newRow("0 = ") << QString("0 = \n") << false;
1446 QTest::newRow("0 = 0") << QString("0 = 0\n") << true;
1447 QTest::newRow("foo[") << QString("foo[") << true; // automatic semicolon will be inserted
1448 QTest::newRow("foo[") << QString("foo[\n") << false;
1449 QTest::newRow("foo['bar']") << QString("foo['bar']") << true;
1451 QTest::newRow("/*") << QString("/*") << false;
1452 QTest::newRow("/*\nMy comment") << QString("/*\nMy comment") << false;
1453 QTest::newRow("/*\nMy comment */\nfoo = 10") << QString("/*\nMy comment */\nfoo = 10") << true;
1454 QTest::newRow("foo = 10 /*") << QString("foo = 10 /*") << false;
1455 QTest::newRow("foo = 10; /*") << QString("foo = 10; /*") << false;
1456 QTest::newRow("foo = 10 /* My comment */") << QString("foo = 10 /* My comment */") << true;
1458 QTest::newRow("/=/") << QString("/=/") << true;
1459 QTest::newRow("/=/g") << QString("/=/g") << true;
1460 QTest::newRow("/a/") << QString("/a/") << true;
1461 QTest::newRow("/a/g") << QString("/a/g") << true;
1464 void tst_QScriptEngine::canEvaluate()
1466 QFETCH(QString, code);
1467 QFETCH(bool, expectSuccess);
1469 QScriptEngine eng;
1470 QCOMPARE(eng.canEvaluate(code), expectSuccess);
1473 void tst_QScriptEngine::evaluate_data()
1475 QTest::addColumn<QString>("code");
1476 QTest::addColumn<int>("lineNumber");
1477 QTest::addColumn<bool>("expectHadError");
1478 QTest::addColumn<int>("expectErrorLineNumber");
1480 QTest::newRow("(newline)") << QString("\n") << -1 << false << -1;
1481 QTest::newRow("0 //") << QString("0 //") << -1 << false << -1;
1482 QTest::newRow("/* */") << QString("/* */") << -1 << false << -1;
1483 QTest::newRow("//") << QString("//") << -1 << false << -1;
1484 QTest::newRow("(spaces)") << QString(" ") << -1 << false << -1;
1485 QTest::newRow("(empty)") << QString("") << -1 << false << -1;
1486 QTest::newRow("0") << QString("0") << -1 << false << -1;
1487 QTest::newRow("0=1") << QString("\n0=1;\n") << -1 << true << 2;
1488 QTest::newRow("a=1") << QString("a=1\n") << -1 << false << -1;
1489 QTest::newRow("a=1;K") << QString("a=1;\nK") << -1 << true << 2;
1491 QTest::newRow("f()") << QString("function f()\n"
1492 "{\n"
1493 " var a;\n"
1494 " var b=\";\n" // here's the error
1495 "}\n"
1496 "f();\n")
1497 << -1 << true << 4;
1499 QTest::newRow("0") << QString("0") << 10 << false << -1;
1500 QTest::newRow("0=1") << QString("\n\n0=1\n") << 10 << true << 13;
1501 QTest::newRow("a=1") << QString("a=1\n") << 10 << false << -1;
1502 QTest::newRow("a=1;K") << QString("a=1;\n\nK") << 10 << true << 12;
1504 QTest::newRow("f()") << QString("function f()\n"
1505 "{\n"
1506 " var a;\n"
1507 "\n\n"
1508 " var b=\";\n" // here's the error
1509 "}\n"
1510 "f();\n")
1511 << 10 << true << 15;
1512 QTest::newRow("functionThatDoesntExist()")
1513 << QString(";\n;\n;\nfunctionThatDoesntExist()")
1514 << -1 << true << 4;
1515 QTest::newRow("for (var p in this) { continue labelThatDoesntExist; }")
1516 << QString("for (var p in this) {\ncontinue labelThatDoesntExist; }")
1517 << 4 << true << 5;
1518 QTest::newRow("duplicateLabel: { duplicateLabel: ; }")
1519 << QString("duplicateLabel: { duplicateLabel: ; }")
1520 << 12 << true << 12;
1522 QTest::newRow("/=/") << QString("/=/") << -1 << false << -1;
1523 QTest::newRow("/=/g") << QString("/=/g") << -1 << false << -1;
1524 QTest::newRow("/a/") << QString("/a/") << -1 << false << -1;
1525 QTest::newRow("/a/g") << QString("/a/g") << -1 << false << -1;
1526 QTest::newRow("/a/gim") << QString("/a/gim") << -1 << false << -1;
1527 QTest::newRow("/a/gimp") << QString("/a/gimp") << 1 << true << 1;
1530 void tst_QScriptEngine::evaluate()
1532 QFETCH(QString, code);
1533 QFETCH(int, lineNumber);
1534 QFETCH(bool, expectHadError);
1535 QFETCH(int, expectErrorLineNumber);
1537 QScriptEngine eng;
1538 QScriptValue ret;
1539 if (lineNumber != -1)
1540 ret = eng.evaluate(code, /*fileName =*/QString(), lineNumber);
1541 else
1542 ret = eng.evaluate(code);
1543 QCOMPARE(eng.hasUncaughtException(), expectHadError);
1544 QCOMPARE(eng.uncaughtExceptionLineNumber(), expectErrorLineNumber);
1545 if (eng.hasUncaughtException() && ret.isError())
1546 QVERIFY(ret.property("lineNumber").strictlyEquals(QScriptValue(&eng, expectErrorLineNumber)));
1547 else
1548 QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
1551 static QScriptValue eval_nested(QScriptContext *ctx, QScriptEngine *eng)
1553 QScriptValue result = eng->newObject();
1554 eng->evaluate("var bar = 'local';");
1555 result.setProperty("thisObjectIdBefore", ctx->thisObject().property("id"));
1556 QScriptValue evaluatedThisObject = eng->evaluate("this");
1557 result.setProperty("thisObjectIdAfter", ctx->thisObject().property("id"));
1558 result.setProperty("evaluatedThisObjectId", evaluatedThisObject.property("id"));
1559 result.setProperty("local_bar", eng->evaluate("bar"));
1561 return result;
1564 void tst_QScriptEngine::nestedEvaluate()
1566 QScriptEngine eng;
1567 QScriptValue fun = eng.newFunction(eval_nested);
1568 eng.globalObject().setProperty("fun", fun);
1570 QScriptValue result = eng.evaluate("o = { id:'foo'}; o.fun = fun; o.fun()");
1571 QCOMPARE(result.property("local_bar").toString(), QString("local"));
1572 QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo"));
1573 QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo"));
1574 QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
1575 QScriptValue bar = eng.evaluate("bar");
1576 QVERIFY(bar.isError());
1577 QCOMPARE(bar.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bar"));
1581 QScriptValue result = fun.call(eng.evaluate("p = { id:'foo' }") , QScriptValueList() );
1582 QCOMPARE(result.property("local_bar").toString(), QString("local"));
1583 QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo"));
1584 QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo"));
1585 QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo"));
1586 QScriptValue bar = eng.evaluate("bar");
1587 QVERIFY(bar.isError());
1588 QCOMPARE(bar.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bar"));
1592 void tst_QScriptEngine::uncaughtException()
1594 QScriptEngine eng;
1595 QScriptValue fun = eng.newFunction(myFunction);
1596 QScriptValue throwFun = eng.newFunction(myThrowingFunction);
1597 for (int x = -1; x < 2; ++x) {
1599 QScriptValue ret = eng.evaluate("a = 10;\nb = 20;\n0 = 0;\n", /*fileName=*/QString(), /*lineNumber=*/x);
1600 QVERIFY(eng.hasUncaughtException());
1601 QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2);
1602 QVERIFY(eng.uncaughtException().strictlyEquals(ret));
1603 (void)ret.toString();
1604 QVERIFY(eng.hasUncaughtException());
1605 QVERIFY(eng.uncaughtException().strictlyEquals(ret));
1606 QVERIFY(fun.call().isNull());
1607 QVERIFY(eng.hasUncaughtException());
1608 QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2);
1609 QVERIFY(eng.uncaughtException().strictlyEquals(ret));
1610 eng.clearExceptions();
1611 QVERIFY(!eng.hasUncaughtException());
1612 QCOMPARE(eng.uncaughtExceptionLineNumber(), -1);
1613 QVERIFY(!eng.uncaughtException().isValid());
1615 eng.evaluate("2 = 3");
1616 QVERIFY(eng.hasUncaughtException());
1617 QScriptValue ret2 = throwFun.call();
1618 QVERIFY(ret2.isError());
1619 QVERIFY(eng.hasUncaughtException());
1620 QVERIFY(eng.uncaughtException().strictlyEquals(ret2));
1621 QCOMPARE(eng.uncaughtExceptionLineNumber(), 0);
1622 eng.clearExceptions();
1623 QVERIFY(!eng.hasUncaughtException());
1624 eng.evaluate("1 + 2");
1625 QVERIFY(!eng.hasUncaughtException());
1628 QScriptValue ret = eng.evaluate("a = 10");
1629 QVERIFY(!eng.hasUncaughtException());
1630 QVERIFY(!eng.uncaughtException().isValid());
1633 QScriptValue ret = eng.evaluate("1 = 2");
1634 QVERIFY(eng.hasUncaughtException());
1635 eng.clearExceptions();
1636 QVERIFY(!eng.hasUncaughtException());
1639 eng.globalObject().setProperty("throwFun", throwFun);
1640 eng.evaluate("1;\nthrowFun();");
1641 QVERIFY(eng.hasUncaughtException());
1642 QCOMPARE(eng.uncaughtExceptionLineNumber(), 2);
1643 eng.clearExceptions();
1644 QVERIFY(!eng.hasUncaughtException());
1649 void tst_QScriptEngine::errorMessage_QT679()
1651 QScriptEngine engine;
1652 engine.globalObject().setProperty("foo", 15);
1653 QScriptValue error = engine.evaluate("'hello world';\nfoo.bar.blah");
1654 QVERIFY(error.isError());
1655 QCOMPARE(error.toString(), QString::fromLatin1("TypeError: Result of expression 'foo.bar' [undefined] is not an object."));
1658 struct Foo {
1659 public:
1660 int x, y;
1661 Foo() : x(-1), y(-1) { }
1664 Q_DECLARE_METATYPE(Foo)
1665 Q_DECLARE_METATYPE(Foo*)
1667 void tst_QScriptEngine::getSetDefaultPrototype()
1669 QScriptEngine eng;
1671 QScriptValue object = eng.newObject();
1672 QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
1673 eng.setDefaultPrototype(qMetaTypeId<int>(), object);
1674 QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).strictlyEquals(object), true);
1675 QScriptValue value = eng.newVariant(int(123));
1676 QCOMPARE(value.prototype().isObject(), true);
1677 QCOMPARE(value.prototype().strictlyEquals(object), true);
1679 eng.setDefaultPrototype(qMetaTypeId<int>(), QScriptValue());
1680 QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false);
1681 QScriptValue value2 = eng.newVariant(int(123));
1682 QCOMPARE(value2.prototype().strictlyEquals(object), false);
1685 QScriptValue object = eng.newObject();
1686 QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
1687 eng.setDefaultPrototype(qMetaTypeId<Foo>(), object);
1688 QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(object), true);
1689 QScriptValue value = eng.newVariant(qVariantFromValue(Foo()));
1690 QCOMPARE(value.prototype().isObject(), true);
1691 QCOMPARE(value.prototype().strictlyEquals(object), true);
1693 eng.setDefaultPrototype(qMetaTypeId<Foo>(), QScriptValue());
1694 QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false);
1695 QScriptValue value2 = eng.newVariant(qVariantFromValue(Foo()));
1696 QCOMPARE(value2.prototype().strictlyEquals(object), false);
1700 static QScriptValue fooToScriptValue(QScriptEngine *eng, const Foo &foo)
1702 QScriptValue obj = eng->newObject();
1703 obj.setProperty("x", QScriptValue(eng, foo.x));
1704 obj.setProperty("y", QScriptValue(eng, foo.y));
1705 return obj;
1708 static void fooFromScriptValue(const QScriptValue &value, Foo &foo)
1710 foo.x = value.property("x").toInt32();
1711 foo.y = value.property("y").toInt32();
1714 static QScriptValue fooToScriptValueV2(QScriptEngine *eng, const Foo &foo)
1716 return QScriptValue(eng, foo.x);
1719 static void fooFromScriptValueV2(const QScriptValue &value, Foo &foo)
1721 foo.x = value.toInt32();
1724 Q_DECLARE_METATYPE(QLinkedList<QString>)
1725 Q_DECLARE_METATYPE(QList<Foo>)
1726 Q_DECLARE_METATYPE(QVector<QChar>)
1727 Q_DECLARE_METATYPE(QStack<int>)
1728 Q_DECLARE_METATYPE(QQueue<char>)
1729 Q_DECLARE_METATYPE(QLinkedList<QStack<int> >)
1731 void tst_QScriptEngine::valueConversion()
1733 QScriptEngine eng;
1735 QScriptValue num = qScriptValueFromValue(&eng, 123);
1736 QCOMPARE(num.isNumber(), true);
1737 QCOMPARE(num.strictlyEquals(QScriptValue(&eng, 123)), true);
1739 int inum = qScriptValueToValue<int>(num);
1740 QCOMPARE(inum, 123);
1742 QString snum = qScriptValueToValue<QString>(num);
1743 QCOMPARE(snum, QLatin1String("123"));
1745 #ifndef QT_NO_MEMBER_TEMPLATES
1747 QScriptValue num = eng.toScriptValue(123);
1748 QCOMPARE(num.isNumber(), true);
1749 QCOMPARE(num.strictlyEquals(QScriptValue(&eng, 123)), true);
1751 int inum = eng.fromScriptValue<int>(num);
1752 QCOMPARE(inum, 123);
1754 QString snum = eng.fromScriptValue<QString>(num);
1755 QCOMPARE(snum, QLatin1String("123"));
1757 #endif
1759 QScriptValue num(&eng, 123);
1760 QCOMPARE(qScriptValueToValue<char>(num), char(123));
1761 QCOMPARE(qScriptValueToValue<unsigned char>(num), (unsigned char)(123));
1762 QCOMPARE(qScriptValueToValue<short>(num), short(123));
1763 QCOMPARE(qScriptValueToValue<unsigned short>(num), (unsigned short)(123));
1764 QCOMPARE(qScriptValueToValue<float>(num), float(123));
1765 QCOMPARE(qScriptValueToValue<double>(num), double(123));
1766 QCOMPARE(qScriptValueToValue<qlonglong>(num), qlonglong(123));
1767 QCOMPARE(qScriptValueToValue<qulonglong>(num), qulonglong(123));
1770 QScriptValue num(123);
1771 QCOMPARE(qScriptValueToValue<char>(num), char(123));
1772 QCOMPARE(qScriptValueToValue<unsigned char>(num), (unsigned char)(123));
1773 QCOMPARE(qScriptValueToValue<short>(num), short(123));
1774 QCOMPARE(qScriptValueToValue<unsigned short>(num), (unsigned short)(123));
1775 QCOMPARE(qScriptValueToValue<float>(num), float(123));
1776 QCOMPARE(qScriptValueToValue<double>(num), double(123));
1777 QCOMPARE(qScriptValueToValue<qlonglong>(num), qlonglong(123));
1778 QCOMPARE(qScriptValueToValue<qulonglong>(num), qulonglong(123));
1782 QScriptValue num = qScriptValueFromValue(&eng, Q_INT64_C(0x100000000));
1783 QCOMPARE(qScriptValueToValue<qlonglong>(num), Q_INT64_C(0x100000000));
1784 QCOMPARE(qScriptValueToValue<qulonglong>(num), Q_UINT64_C(0x100000000));
1788 QChar c = QLatin1Char('c');
1789 QScriptValue str = QScriptValue(&eng, "ciao");
1790 QCOMPARE(qScriptValueToValue<QChar>(str), c);
1791 QScriptValue code = QScriptValue(&eng, c.unicode());
1792 QCOMPARE(qScriptValueToValue<QChar>(code), c);
1793 QCOMPARE(qScriptValueToValue<QChar>(qScriptValueFromValue(&eng, c)), c);
1797 // a type that we don't have built-in conversion of
1798 // (it's stored as a variant)
1799 QTime tm(1, 2, 3, 4);
1800 QScriptValue val = qScriptValueFromValue(&eng, tm);
1801 QCOMPARE(qScriptValueToValue<QTime>(val), tm);
1805 Foo foo;
1806 foo.x = 12;
1807 foo.y = 34;
1808 QScriptValue fooVal = qScriptValueFromValue(&eng, foo);
1809 QCOMPARE(fooVal.isVariant(), true);
1811 Foo foo2 = qScriptValueToValue<Foo>(fooVal);
1812 QCOMPARE(foo2.x, foo.x);
1813 QCOMPARE(foo2.y, foo.y);
1816 qScriptRegisterMetaType<Foo>(&eng, fooToScriptValue, fooFromScriptValue);
1819 Foo foo;
1820 foo.x = 12;
1821 foo.y = 34;
1822 QScriptValue fooVal = qScriptValueFromValue(&eng, foo);
1823 QCOMPARE(fooVal.isObject(), true);
1824 QVERIFY(fooVal.prototype().strictlyEquals(eng.evaluate("Object.prototype")));
1825 QCOMPARE(fooVal.property("x").strictlyEquals(QScriptValue(&eng, 12)), true);
1826 QCOMPARE(fooVal.property("y").strictlyEquals(QScriptValue(&eng, 34)), true);
1827 fooVal.setProperty("x", QScriptValue(&eng, 56));
1828 fooVal.setProperty("y", QScriptValue(&eng, 78));
1830 Foo foo2 = qScriptValueToValue<Foo>(fooVal);
1831 QCOMPARE(foo2.x, 56);
1832 QCOMPARE(foo2.y, 78);
1834 QScriptValue fooProto = eng.newObject();
1835 eng.setDefaultPrototype(qMetaTypeId<Foo>(), fooProto);
1836 QScriptValue fooVal2 = qScriptValueFromValue(&eng, foo2);
1837 QVERIFY(fooVal2.prototype().strictlyEquals(fooProto));
1838 QVERIFY(fooVal2.property("x").strictlyEquals(QScriptValue(&eng, 56)));
1839 QVERIFY(fooVal2.property("y").strictlyEquals(QScriptValue(&eng, 78)));
1842 qScriptRegisterSequenceMetaType<QLinkedList<QString> >(&eng);
1845 QLinkedList<QString> lst;
1846 lst << QLatin1String("foo") << QLatin1String("bar");
1847 QScriptValue lstVal = qScriptValueFromValue(&eng, lst);
1848 QCOMPARE(lstVal.isArray(), true);
1849 QCOMPARE(lstVal.property("length").toInt32(), 2);
1850 QCOMPARE(lstVal.property("0").isString(), true);
1851 QCOMPARE(lstVal.property("0").toString(), QLatin1String("foo"));
1852 QCOMPARE(lstVal.property("1").isString(), true);
1853 QCOMPARE(lstVal.property("1").toString(), QLatin1String("bar"));
1856 qScriptRegisterSequenceMetaType<QList<Foo> >(&eng);
1857 qScriptRegisterSequenceMetaType<QStack<int> >(&eng);
1858 qScriptRegisterSequenceMetaType<QVector<QChar> >(&eng);
1859 qScriptRegisterSequenceMetaType<QQueue<char> >(&eng);
1860 qScriptRegisterSequenceMetaType<QLinkedList<QStack<int> > >(&eng);
1863 QLinkedList<QStack<int> > lst;
1864 QStack<int> first; first << 13 << 49; lst << first;
1865 QStack<int> second; second << 99999;lst << second;
1866 QScriptValue lstVal = qScriptValueFromValue(&eng, lst);
1867 QCOMPARE(lstVal.isArray(), true);
1868 QCOMPARE(lstVal.property("length").toInt32(), 2);
1869 QCOMPARE(lstVal.property("0").isArray(), true);
1870 QCOMPARE(lstVal.property("0").property("length").toInt32(), 2);
1871 QCOMPARE(lstVal.property("0").property("0").toInt32(), first.at(0));
1872 QCOMPARE(lstVal.property("0").property("1").toInt32(), first.at(1));
1873 QCOMPARE(lstVal.property("1").isArray(), true);
1874 QCOMPARE(lstVal.property("1").property("length").toInt32(), 1);
1875 QCOMPARE(lstVal.property("1").property("0").toInt32(), second.at(0));
1876 QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("0")), first);
1877 QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("1")), second);
1878 QCOMPARE(qscriptvalue_cast<QLinkedList<QStack<int> > >(lstVal), lst);
1881 // pointers
1883 Foo foo;
1885 QScriptValue v = qScriptValueFromValue(&eng, &foo);
1886 Foo *pfoo = qscriptvalue_cast<Foo*>(v);
1887 QCOMPARE(pfoo, &foo);
1890 Foo *pfoo = 0;
1891 QScriptValue v = qScriptValueFromValue(&eng, pfoo);
1892 QCOMPARE(v.isNull(), true);
1893 QVERIFY(qscriptvalue_cast<Foo*>(v) == 0);
1897 // QList<int> and QObjectList should be converted from/to arrays by default
1899 QList<int> lst;
1900 lst << 1 << 2 << 3;
1901 QScriptValue val = qScriptValueFromValue(&eng, lst);
1902 QVERIFY(val.isArray());
1903 QCOMPARE(val.property("length").toInt32(), lst.size());
1904 QCOMPARE(val.property(0).toInt32(), lst.at(0));
1905 QCOMPARE(val.property(1).toInt32(), lst.at(1));
1906 QCOMPARE(val.property(2).toInt32(), lst.at(2));
1908 QCOMPARE(qscriptvalue_cast<QList<int> >(val), lst);
1911 QObjectList lst;
1912 lst << this;
1913 QScriptValue val = qScriptValueFromValue(&eng, lst);
1914 QVERIFY(val.isArray());
1915 QCOMPARE(val.property("length").toInt32(), lst.size());
1916 QCOMPARE(val.property(0).toQObject(), (QObject *)this);
1918 QCOMPARE(qscriptvalue_cast<QObjectList>(val), lst);
1921 // qScriptValueFromValue() should be "smart" when the argument is a QVariant
1923 QScriptValue val = qScriptValueFromValue(&eng, QVariant());
1924 QVERIFY(!val.isVariant());
1925 QVERIFY(val.isUndefined());
1928 QScriptValue val = qScriptValueFromValue(&eng, QVariant(true));
1929 QVERIFY(!val.isVariant());
1930 QVERIFY(val.isBoolean());
1931 QCOMPARE(val.toBoolean(), true);
1934 QScriptValue val = qScriptValueFromValue(&eng, QVariant(int(123)));
1935 QVERIFY(!val.isVariant());
1936 QVERIFY(val.isNumber());
1937 QCOMPARE(val.toNumber(), qsreal(123));
1940 QScriptValue val = qScriptValueFromValue(&eng, QVariant(qsreal(1.25)));
1941 QVERIFY(!val.isVariant());
1942 QVERIFY(val.isNumber());
1943 QCOMPARE(val.toNumber(), qsreal(1.25));
1946 QString str = QString::fromLatin1("ciao");
1947 QScriptValue val = qScriptValueFromValue(&eng, QVariant(str));
1948 QVERIFY(!val.isVariant());
1949 QVERIFY(val.isString());
1950 QCOMPARE(val.toString(), str);
1953 QScriptValue val = qScriptValueFromValue(&eng, qVariantFromValue((QObject*)this));
1954 QVERIFY(!val.isVariant());
1955 QVERIFY(val.isQObject());
1956 QCOMPARE(val.toQObject(), (QObject*)this);
1959 QVariant var = qVariantFromValue(QPoint(123, 456));
1960 QScriptValue val = qScriptValueFromValue(&eng, var);
1961 QVERIFY(val.isVariant());
1962 QCOMPARE(val.toVariant(), var);
1965 // task 248802
1966 qScriptRegisterMetaType<Foo>(&eng, fooToScriptValueV2, fooFromScriptValueV2);
1968 QScriptValue num(&eng, 123);
1969 Foo foo = qScriptValueToValue<Foo>(num);
1970 QCOMPARE(foo.x, 123);
1973 QScriptValue num(123);
1974 Foo foo = qScriptValueToValue<Foo>(num);
1975 QCOMPARE(foo.x, -1);
1978 QScriptValue str(&eng, "123");
1979 Foo foo = qScriptValueToValue<Foo>(str);
1980 QCOMPARE(foo.x, 123);
1983 // more built-in types
1985 QScriptValue val = qScriptValueFromValue(&eng, uint(123));
1986 QVERIFY(val.isNumber());
1987 QCOMPARE(val.toInt32(), 123);
1990 QScriptValue val = qScriptValueFromValue(&eng, qulonglong(123));
1991 QVERIFY(val.isNumber());
1992 QCOMPARE(val.toInt32(), 123);
1995 QScriptValue val = qScriptValueFromValue(&eng, float(123));
1996 QVERIFY(val.isNumber());
1997 QCOMPARE(val.toInt32(), 123);
2000 QScriptValue val = qScriptValueFromValue(&eng, short(123));
2001 QVERIFY(val.isNumber());
2002 QCOMPARE(val.toInt32(), 123);
2005 QScriptValue val = qScriptValueFromValue(&eng, ushort(123));
2006 QVERIFY(val.isNumber());
2007 QCOMPARE(val.toInt32(), 123);
2010 QScriptValue val = qScriptValueFromValue(&eng, char(123));
2011 QVERIFY(val.isNumber());
2012 QCOMPARE(val.toInt32(), 123);
2015 QScriptValue val = qScriptValueFromValue(&eng, uchar(123));
2016 QVERIFY(val.isNumber());
2017 QCOMPARE(val.toInt32(), 123);
2020 QDateTime in = QDateTime::currentDateTime();
2021 QScriptValue val = qScriptValueFromValue(&eng, in);
2022 QVERIFY(val.isDate());
2023 QCOMPARE(val.toDateTime(), in);
2026 QDate in = QDate::currentDate();
2027 QScriptValue val = qScriptValueFromValue(&eng, in);
2028 QVERIFY(val.isDate());
2029 QCOMPARE(val.toDateTime().date(), in);
2032 QRegExp in = QRegExp("foo");
2033 QScriptValue val = qScriptValueFromValue(&eng, in);
2034 QVERIFY(val.isRegExp());
2035 QRegExp out = val.toRegExp();
2036 QEXPECT_FAIL("", "JSC-based back-end doesn't preserve QRegExp::patternSyntax (always uses RegExp2)", Continue);
2037 QCOMPARE(out.patternSyntax(), in.patternSyntax());
2038 QCOMPARE(out.pattern(), in.pattern());
2039 QCOMPARE(out.caseSensitivity(), in.caseSensitivity());
2040 QCOMPARE(out.isMinimal(), in.isMinimal());
2043 QRegExp in = QRegExp("foo", Qt::CaseSensitive, QRegExp::RegExp2);
2044 QScriptValue val = qScriptValueFromValue(&eng, in);
2045 QVERIFY(val.isRegExp());
2046 QCOMPARE(val.toRegExp(), in);
2049 QRegExp in = QRegExp("foo");
2050 in.setMinimal(true);
2051 QScriptValue val = qScriptValueFromValue(&eng, in);
2052 QVERIFY(val.isRegExp());
2053 QEXPECT_FAIL("", "JSC-based back-end doesn't preserve QRegExp::minimal (always false)", Continue);
2054 QCOMPARE(val.toRegExp().isMinimal(), in.isMinimal());
2058 static QScriptValue __import__(QScriptContext *ctx, QScriptEngine *eng)
2060 return eng->importExtension(ctx->argument(0).toString());
2063 void tst_QScriptEngine::importExtension()
2065 QStringList libPaths = QCoreApplication::instance()->libraryPaths();
2066 QCoreApplication::instance()->setLibraryPaths(QStringList() << SRCDIR);
2068 QStringList availableExtensions;
2070 QScriptEngine eng;
2071 QVERIFY(eng.importedExtensions().isEmpty());
2072 QStringList ret = eng.availableExtensions();
2073 QCOMPARE(ret.size(), 4);
2074 QCOMPARE(ret.at(0), QString::fromLatin1("com"));
2075 QCOMPARE(ret.at(1), QString::fromLatin1("com.trolltech"));
2076 QCOMPARE(ret.at(2), QString::fromLatin1("com.trolltech.recursive"));
2077 QCOMPARE(ret.at(3), QString::fromLatin1("com.trolltech.syntaxerror"));
2078 availableExtensions = ret;
2081 // try to import something that doesn't exist
2083 QScriptEngine eng;
2084 QScriptValue ret = eng.importExtension("this.extension.does.not.exist");
2085 QCOMPARE(eng.hasUncaughtException(), true);
2086 QCOMPARE(ret.isError(), true);
2087 QCOMPARE(ret.toString(), QString::fromLatin1("Error: Unable to import this.extension.does.not.exist: no such extension"));
2091 QScriptEngine eng;
2092 for (int x = 0; x < 2; ++x) {
2093 QCOMPARE(eng.globalObject().property("com").isValid(), x == 1);
2094 QScriptValue ret = eng.importExtension("com.trolltech");
2095 QCOMPARE(eng.hasUncaughtException(), false);
2096 QCOMPARE(ret.isUndefined(), true);
2098 QScriptValue com = eng.globalObject().property("com");
2099 QCOMPARE(com.isObject(), true);
2100 QCOMPARE(com.property("wasDefinedAlready")
2101 .strictlyEquals(QScriptValue(&eng, false)), true);
2102 QCOMPARE(com.property("name")
2103 .strictlyEquals(QScriptValue(&eng, "com")), true);
2104 QCOMPARE(com.property("level")
2105 .strictlyEquals(QScriptValue(&eng, 1)), true);
2106 QVERIFY(com.property("originalPostInit").isUndefined());
2107 QVERIFY(com.property("postInitCallCount").strictlyEquals(1));
2109 QScriptValue trolltech = com.property("trolltech");
2110 QCOMPARE(trolltech.isObject(), true);
2111 QCOMPARE(trolltech.property("wasDefinedAlready")
2112 .strictlyEquals(QScriptValue(&eng, false)), true);
2113 QCOMPARE(trolltech.property("name")
2114 .strictlyEquals(QScriptValue(&eng, "com.trolltech")), true);
2115 QCOMPARE(trolltech.property("level")
2116 .strictlyEquals(QScriptValue(&eng, 2)), true);
2117 QVERIFY(trolltech.property("originalPostInit").isUndefined());
2118 QVERIFY(trolltech.property("postInitCallCount").strictlyEquals(1));
2120 QStringList imp = eng.importedExtensions();
2121 QCOMPARE(imp.size(), 2);
2122 QCOMPARE(imp.at(0), QString::fromLatin1("com"));
2123 QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
2124 QCOMPARE(eng.availableExtensions(), availableExtensions);
2127 // recursive import should throw an error
2129 QScriptEngine eng;
2130 QVERIFY(eng.importedExtensions().isEmpty());
2131 eng.globalObject().setProperty("__import__", eng.newFunction(__import__));
2132 QScriptValue ret = eng.importExtension("com.trolltech.recursive");
2133 QCOMPARE(eng.hasUncaughtException(), true);
2134 QVERIFY(ret.isError());
2135 QCOMPARE(ret.toString(), QString::fromLatin1("Error: recursive import of com.trolltech.recursive"));
2136 QStringList imp = eng.importedExtensions();
2137 QCOMPARE(imp.size(), 2);
2138 QCOMPARE(imp.at(0), QString::fromLatin1("com"));
2139 QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
2140 QCOMPARE(eng.availableExtensions(), availableExtensions);
2144 QScriptEngine eng;
2145 eng.globalObject().setProperty("__import__", eng.newFunction(__import__));
2146 for (int x = 0; x < 2; ++x) {
2147 if (x == 0)
2148 QVERIFY(eng.importedExtensions().isEmpty());
2149 QScriptValue ret = eng.importExtension("com.trolltech.syntaxerror");
2150 QVERIFY(eng.hasUncaughtException());
2151 QEXPECT_FAIL("", "JSC throws syntax error eagerly", Continue);
2152 QCOMPARE(eng.uncaughtExceptionLineNumber(), 4);
2153 QVERIFY(ret.isError());
2154 QCOMPARE(ret.property("message").toString(), QLatin1String("Parse error"));
2156 QStringList imp = eng.importedExtensions();
2157 QCOMPARE(imp.size(), 2);
2158 QCOMPARE(imp.at(0), QString::fromLatin1("com"));
2159 QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech"));
2160 QCOMPARE(eng.availableExtensions(), availableExtensions);
2163 QCoreApplication::instance()->setLibraryPaths(libPaths);
2166 static QScriptValue recurse(QScriptContext *ctx, QScriptEngine *eng)
2168 Q_UNUSED(eng);
2169 return ctx->callee().call();
2172 static QScriptValue recurse2(QScriptContext *ctx, QScriptEngine *eng)
2174 Q_UNUSED(eng);
2175 return ctx->callee().construct();
2178 void tst_QScriptEngine::infiniteRecursion()
2180 const QString stackOverflowError = QString::fromLatin1("RangeError: Maximum call stack size exceeded.");
2181 QScriptEngine eng;
2183 QScriptValue ret = eng.evaluate("function foo() { foo(); }; foo();");
2184 QCOMPARE(ret.isError(), true);
2185 QCOMPARE(ret.toString(), stackOverflowError);
2187 #if 0 //The native C++ stack overflow before the JS stack
2189 QScriptValue fun = eng.newFunction(recurse);
2190 QScriptValue ret = fun.call();
2191 QCOMPARE(ret.isError(), true);
2192 QCOMPARE(ret.toString(), stackOverflowError);
2195 QScriptValue fun = eng.newFunction(recurse2);
2196 QScriptValue ret = fun.construct();
2197 QCOMPARE(ret.isError(), true);
2198 QCOMPARE(ret.toString(), stackOverflowError);
2200 #endif
2203 struct Bar {
2204 int a;
2207 struct Baz : public Bar {
2208 int b;
2211 Q_DECLARE_METATYPE(Bar*)
2212 Q_DECLARE_METATYPE(Baz*)
2214 Q_DECLARE_METATYPE(QGradient)
2215 Q_DECLARE_METATYPE(QGradient*)
2216 Q_DECLARE_METATYPE(QLinearGradient)
2218 class Zoo : public QObject
2220 Q_OBJECT
2221 public:
2222 Zoo() { }
2223 public slots:
2224 Baz *toBaz(Bar *b) { return reinterpret_cast<Baz*>(b); }
2227 void tst_QScriptEngine::castWithPrototypeChain()
2229 QScriptEngine eng;
2230 Bar bar;
2231 Baz baz;
2232 QScriptValue barProto = qScriptValueFromValue(&eng, &bar);
2233 QScriptValue bazProto = qScriptValueFromValue(&eng, &baz);
2234 eng.setDefaultPrototype(qMetaTypeId<Bar*>(), barProto);
2235 eng.setDefaultPrototype(qMetaTypeId<Baz*>(), bazProto);
2237 Baz baz2;
2238 baz2.a = 123;
2239 baz2.b = 456;
2240 QScriptValue baz2Value = qScriptValueFromValue(&eng, &baz2);
2242 Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
2243 QVERIFY(pbaz != 0);
2244 QCOMPARE(pbaz->b, baz2.b);
2246 Zoo zoo;
2247 QScriptValue scriptZoo = eng.newQObject(&zoo);
2248 QScriptValue toBaz = scriptZoo.property("toBaz");
2249 QVERIFY(toBaz.isFunction());
2251 // no relation between Bar and Baz's proto --> casting fails
2253 Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
2254 QVERIFY(pbar == 0);
2258 QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value);
2259 QVERIFY(ret.isError());
2260 QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to toBaz(); candidates were\n toBaz(Bar*)"));
2263 // establish chain -- now casting should work
2264 bazProto.setPrototype(barProto);
2267 Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
2268 QVERIFY(pbar != 0);
2269 QCOMPARE(pbar->a, baz2.a);
2273 QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value);
2274 QVERIFY(!ret.isError());
2275 QCOMPARE(qscriptvalue_cast<Baz*>(ret), pbaz);
2279 bazProto.setPrototype(barProto.prototype()); // kill chain
2281 Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
2282 QVERIFY(pbaz != 0);
2283 // should not work anymore
2284 Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
2285 QVERIFY(pbar == 0);
2288 bazProto.setPrototype(eng.newQObject(this));
2290 Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value);
2291 QVERIFY(pbaz != 0);
2292 // should not work now either
2293 Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value);
2294 QVERIFY(pbar == 0);
2298 QScriptValue b = qScriptValueFromValue(&eng, QBrush());
2299 b.setPrototype(barProto);
2300 // this shows that a "wrong" cast is possible, if you
2301 // don't play by the rules (the pointer is actually a QBrush*)...
2302 Bar *pbar = qscriptvalue_cast<Bar*>(b);
2303 QVERIFY(pbar != 0);
2307 QScriptValue gradientProto = qScriptValueFromValue(&eng, QGradient());
2308 QScriptValue linearGradientProto = qScriptValueFromValue(&eng, QLinearGradient());
2309 linearGradientProto.setPrototype(gradientProto);
2310 QLinearGradient lg(10, 20, 30, 40);
2311 QScriptValue linearGradient = qScriptValueFromValue(&eng, lg);
2313 QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient);
2314 QVERIFY(pgrad == 0);
2316 linearGradient.setPrototype(linearGradientProto);
2318 QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient);
2319 QVERIFY(pgrad != 0);
2320 QCOMPARE(pgrad->type(), QGradient::LinearGradient);
2321 QLinearGradient *plingrad = static_cast<QLinearGradient*>(pgrad);
2322 QCOMPARE(plingrad->start(), lg.start());
2323 QCOMPARE(plingrad->finalStop(), lg.finalStop());
2328 class Klazz : public QWidget,
2329 public QStandardItem,
2330 public QGraphicsItem
2332 Q_OBJECT
2333 public:
2334 Klazz(QWidget *parent = 0) : QWidget(parent) { }
2335 virtual QRectF boundingRect() const { return QRectF(); }
2336 virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { }
2339 Q_DECLARE_METATYPE(Klazz*)
2340 Q_DECLARE_METATYPE(QStandardItem*)
2342 void tst_QScriptEngine::castWithMultipleInheritance()
2344 QScriptEngine eng;
2345 Klazz klz;
2346 QScriptValue v = eng.newQObject(&klz);
2348 QCOMPARE(qscriptvalue_cast<Klazz*>(v), &klz);
2349 QCOMPARE(qscriptvalue_cast<QWidget*>(v), (QWidget *)&klz);
2350 QCOMPARE(qscriptvalue_cast<QObject*>(v), (QObject *)&klz);
2351 QCOMPARE(qscriptvalue_cast<QStandardItem*>(v), (QStandardItem *)&klz);
2352 QCOMPARE(qscriptvalue_cast<QGraphicsItem*>(v), (QGraphicsItem *)&klz);
2355 void tst_QScriptEngine::collectGarbage()
2357 QScriptEngine eng;
2358 eng.evaluate("a = new Object(); a = new Object(); a = new Object()");
2359 QScriptValue a = eng.newObject();
2360 a = eng.newObject();
2361 a = eng.newObject();
2362 QPointer<QObject> ptr = new QObject();
2363 QVERIFY(ptr != 0);
2364 (void)eng.newQObject(ptr, QScriptEngine::ScriptOwnership);
2365 collectGarbage_helper(eng);
2366 QVERIFY(ptr == 0);
2369 void tst_QScriptEngine::gcWithNestedDataStructure()
2371 QScriptEngine eng;
2372 eng.evaluate(
2373 "function makeList(size)"
2375 " var head = { };"
2376 " var l = head;"
2377 " for (var i = 0; i < size; ++i) {"
2378 " l.data = i + \"\";"
2379 " l.next = { }; l = l.next;"
2380 " }"
2381 " l.next = null;"
2382 " return head;"
2383 "}");
2384 QCOMPARE(eng.hasUncaughtException(), false);
2385 const int size = 200;
2386 QScriptValue head = eng.evaluate(QString::fromLatin1("makeList(%0)").arg(size));
2387 QCOMPARE(eng.hasUncaughtException(), false);
2388 for (int x = 0; x < 2; ++x) {
2389 if (x == 1)
2390 eng.evaluate("gc()");
2391 QScriptValue l = head;
2392 for (int i = 0; i < 200; ++i) {
2393 QCOMPARE(l.property("data").toString(), QString::number(i));
2394 l = l.property("next");
2399 class EventReceiver : public QObject
2401 public:
2402 EventReceiver() {
2403 received = false;
2406 bool event(QEvent *e) {
2407 received |= (e->type() == QEvent::User + 1);
2408 return QObject::event(e);
2411 bool received;
2414 void tst_QScriptEngine::processEventsWhileRunning()
2416 for (int x = 0; x < 2; ++x) {
2417 QScriptEngine eng;
2418 if (x == 0)
2419 eng.pushContext();
2421 QString script = QString::fromLatin1(
2422 "var end = Number(new Date()) + 2000;"
2423 "var x = 0;"
2424 "while (Number(new Date()) < end) {"
2425 " ++x;"
2426 "}");
2428 EventReceiver receiver;
2429 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
2431 eng.evaluate(script);
2432 QVERIFY(!eng.hasUncaughtException());
2433 QVERIFY(!receiver.received);
2435 QCOMPARE(eng.processEventsInterval(), -1);
2436 eng.setProcessEventsInterval(100);
2437 eng.evaluate(script);
2438 QVERIFY(!eng.hasUncaughtException());
2439 QVERIFY(receiver.received);
2441 if (x == 0)
2442 eng.popContext();
2446 class EventReceiver2 : public QObject
2448 public:
2449 EventReceiver2(QScriptEngine *eng) {
2450 engine = eng;
2453 bool event(QEvent *e) {
2454 if (e->type() == QEvent::User + 1) {
2455 engine->currentContext()->throwError("Killed");
2457 return QObject::event(e);
2460 QScriptEngine *engine;
2463 void tst_QScriptEngine::throwErrorFromProcessEvents()
2465 QScriptEngine eng;
2467 EventReceiver2 receiver(&eng);
2468 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
2470 eng.setProcessEventsInterval(100);
2471 QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }"));
2472 QVERIFY(ret.isError());
2473 QCOMPARE(ret.toString(), QString::fromLatin1("Error: Killed"));
2476 void tst_QScriptEngine::stacktrace()
2478 QString script = QString::fromLatin1(
2479 "function foo(counter) {\n"
2480 " switch (counter) {\n"
2481 " case 0: foo(counter+1); break;\n"
2482 " case 1: foo(counter+1); break;\n"
2483 " case 2: foo(counter+1); break;\n"
2484 " case 3: foo(counter+1); break;\n"
2485 " case 4: foo(counter+1); break;\n"
2486 " default:\n"
2487 " throw new Error('blah');\n"
2488 " }\n"
2489 "}\n"
2490 "foo(0);");
2492 const QString fileName("testfile");
2494 QStringList backtrace;
2495 backtrace << "foo(5)@testfile:9"
2496 << "foo(4)@testfile:7"
2497 << "foo(3)@testfile:6"
2498 << "foo(2)@testfile:5"
2499 << "foo(1)@testfile:4"
2500 << "foo(0)@testfile:3"
2501 << "<global>()@testfile:12";
2503 QScriptEngine eng;
2504 QScriptValue result = eng.evaluate(script, fileName);
2505 QVERIFY(eng.hasUncaughtException());
2506 QVERIFY(result.isError());
2508 QEXPECT_FAIL("", "", Abort);
2509 QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
2510 QVERIFY(eng.hasUncaughtException());
2511 QVERIFY(result.strictlyEquals(eng.uncaughtException()));
2513 QCOMPARE(result.property("fileName").toString(), fileName);
2514 QCOMPARE(result.property("lineNumber").toInt32(), 9);
2516 QScriptValue stack = result.property("stack");
2517 QVERIFY(stack.isArray());
2519 QCOMPARE(stack.property("length").toInt32(), 7);
2521 QScriptValueIterator it(stack);
2522 int counter = 5;
2523 while (it.hasNext()) {
2524 it.next();
2525 QScriptValue obj = it.value();
2526 QScriptValue frame = obj.property("frame");
2528 QCOMPARE(obj.property("fileName").toString(), fileName);
2529 if (counter >= 0) {
2530 QScriptValue callee = frame.property("arguments").property("callee");
2531 QVERIFY(callee.strictlyEquals(eng.globalObject().property("foo")));
2532 QCOMPARE(obj.property("functionName").toString(), QString("foo"));
2533 int line = obj.property("lineNumber").toInt32();
2534 if (counter == 5)
2535 QCOMPARE(line, 9);
2536 else
2537 QCOMPARE(line, 3 + counter);
2538 } else {
2539 QVERIFY(frame.strictlyEquals(eng.globalObject()));
2540 QVERIFY(obj.property("functionName").toString().isEmpty());
2543 --counter;
2547 QScriptValue bt = result.property("backtrace").call(result);
2548 QCOMPARE(qscriptvalue_cast<QStringList>(bt), backtrace);
2551 // throw something that isn't an Error object
2552 eng.clearExceptions();
2553 QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
2554 QString script2 = QString::fromLatin1(
2555 "function foo(counter) {\n"
2556 " switch (counter) {\n"
2557 " case 0: foo(counter+1); break;\n"
2558 " case 1: foo(counter+1); break;\n"
2559 " case 2: foo(counter+1); break;\n"
2560 " case 3: foo(counter+1); break;\n"
2561 " case 4: foo(counter+1); break;\n"
2562 " default:\n"
2563 " throw 'just a string';\n"
2564 " }\n"
2565 "}\n"
2566 "foo(0);");
2568 QScriptValue result2 = eng.evaluate(script2, fileName);
2569 QVERIFY(eng.hasUncaughtException());
2570 QVERIFY(!result2.isError());
2571 QVERIFY(result2.isString());
2573 QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace);
2574 QVERIFY(eng.hasUncaughtException());
2576 eng.clearExceptions();
2577 QVERIFY(!eng.hasUncaughtException());
2578 QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty());
2581 void tst_QScriptEngine::numberParsing_data()
2583 QTest::addColumn<QString>("string");
2584 QTest::addColumn<qsreal>("expect");
2586 QTest::newRow("decimal 0") << QString("0") << qsreal(0);
2587 QTest::newRow("octal 0") << QString("00") << qsreal(00);
2588 QTest::newRow("hex 0") << QString("0x0") << qsreal(0x0);
2589 QTest::newRow("decimal 100") << QString("100") << qsreal(100);
2590 QTest::newRow("hex 100") << QString("0x100") << qsreal(0x100);
2591 QTest::newRow("octal 100") << QString("0100") << qsreal(0100);
2592 QTest::newRow("decimal 4G") << QString("4294967296") << qsreal(Q_UINT64_C(4294967296));
2593 QTest::newRow("hex 4G") << QString("0x100000000") << qsreal(Q_UINT64_C(0x100000000));
2594 QTest::newRow("octal 4G") << QString("040000000000") << qsreal(Q_UINT64_C(040000000000));
2595 QTest::newRow("0.5") << QString("0.5") << qsreal(0.5);
2596 QTest::newRow("1.5") << QString("1.5") << qsreal(1.5);
2597 QTest::newRow("1e2") << QString("1e2") << qsreal(100);
2600 void tst_QScriptEngine::numberParsing()
2602 QFETCH(QString, string);
2603 QFETCH(qsreal, expect);
2605 QScriptEngine eng;
2606 QScriptValue ret = eng.evaluate(string);
2607 QVERIFY(ret.isNumber());
2608 qsreal actual = ret.toNumber();
2609 QCOMPARE(actual, expect);
2612 // see ECMA-262, section 7.9
2613 void tst_QScriptEngine::automaticSemicolonInsertion()
2615 QScriptEngine eng;
2617 QScriptValue ret = eng.evaluate("{ 1 2 } 3");
2618 QVERIFY(ret.isError());
2619 QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
2622 QScriptValue ret = eng.evaluate("{ 1\n2 } 3");
2623 QVERIFY(ret.isNumber());
2624 QCOMPARE(ret.toInt32(), 3);
2627 QScriptValue ret = eng.evaluate("for (a; b\n)");
2628 QVERIFY(ret.isError());
2629 QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
2632 QScriptValue ret = eng.evaluate("(function() { return\n1 + 2 })()");
2633 QVERIFY(ret.isUndefined());
2636 eng.evaluate("c = 2; b = 1");
2637 QScriptValue ret = eng.evaluate("a = b\n++c");
2638 QVERIFY(ret.isNumber());
2639 QCOMPARE(ret.toInt32(), 3);
2642 QScriptValue ret = eng.evaluate("if (a > b)\nelse c = d");
2643 QVERIFY(ret.isError());
2644 QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
2647 eng.evaluate("function c() { return { foo: function() { return 5; } } }");
2648 eng.evaluate("b = 1; d = 2; e = 3");
2649 QScriptValue ret = eng.evaluate("a = b + c\n(d + e).foo()");
2650 QVERIFY(ret.isNumber());
2651 QCOMPARE(ret.toInt32(), 6);
2654 QScriptValue ret = eng.evaluate("throw\n1");
2655 QVERIFY(ret.isError());
2656 QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error"));
2659 QScriptValue ret = eng.evaluate("a = Number(1)\n++a");
2660 QVERIFY(ret.isNumber());
2661 QCOMPARE(ret.toInt32(), 2);
2664 // "a semicolon is never inserted automatically if the semicolon
2665 // would then be parsed as an empty statement"
2667 eng.evaluate("a = 123");
2668 QScriptValue ret = eng.evaluate("if (0)\n ++a; a");
2669 QVERIFY(ret.isNumber());
2670 QCOMPARE(ret.toInt32(), 123);
2673 eng.evaluate("a = 123");
2674 QScriptValue ret = eng.evaluate("if (0)\n --a; a");
2675 QVERIFY(ret.isNumber());
2676 QCOMPARE(ret.toInt32(), 123);
2679 eng.evaluate("a = 123");
2680 QScriptValue ret = eng.evaluate("if ((0))\n ++a; a");
2681 QVERIFY(ret.isNumber());
2682 QCOMPARE(ret.toInt32(), 123);
2685 eng.evaluate("a = 123");
2686 QScriptValue ret = eng.evaluate("if ((0))\n --a; a");
2687 QVERIFY(ret.isNumber());
2688 QCOMPARE(ret.toInt32(), 123);
2691 eng.evaluate("a = 123");
2692 QScriptValue ret = eng.evaluate("if (0\n)\n ++a; a");
2693 QVERIFY(ret.isNumber());
2694 QCOMPARE(ret.toInt32(), 123);
2697 eng.evaluate("a = 123");
2698 QScriptValue ret = eng.evaluate("if (0\n ++a; a");
2699 QVERIFY(ret.isError());
2702 eng.evaluate("a = 123");
2703 QScriptValue ret = eng.evaluate("if (0))\n ++a; a");
2704 QVERIFY(ret.isError());
2707 QScriptValue ret = eng.evaluate("n = 0; for (i = 0; i < 10; ++i)\n ++n; n");
2708 QVERIFY(ret.isNumber());
2709 QCOMPARE(ret.toInt32(), 10);
2712 QScriptValue ret = eng.evaluate("n = 30; for (i = 0; i < 10; ++i)\n --n; n");
2713 QVERIFY(ret.isNumber());
2714 QCOMPARE(ret.toInt32(), 20);
2717 QScriptValue ret = eng.evaluate("n = 0; for (var i = 0; i < 10; ++i)\n ++n; n");
2718 QVERIFY(ret.isNumber());
2719 QCOMPARE(ret.toInt32(), 10);
2722 QScriptValue ret = eng.evaluate("n = 30; for (var i = 0; i < 10; ++i)\n --n; n");
2723 QVERIFY(ret.isNumber());
2724 QCOMPARE(ret.toInt32(), 20);
2727 QScriptValue ret = eng.evaluate("n = 0; i = 0; while (i++ < 10)\n ++n; n");
2728 QVERIFY(ret.isNumber());
2729 QCOMPARE(ret.toInt32(), 10);
2732 QScriptValue ret = eng.evaluate("n = 30; i = 0; while (i++ < 10)\n --n; n");
2733 QVERIFY(ret.isNumber());
2734 QCOMPARE(ret.toInt32(), 20);
2737 QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (i in o)\n ++n; n");
2738 QVERIFY(ret.isNumber());
2739 QCOMPARE(ret.toInt32(), 3);
2742 QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (i in o)\n --n; n");
2743 QVERIFY(ret.isNumber());
2744 QCOMPARE(ret.toInt32(), 6);
2747 QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (var i in o)\n ++n; n");
2748 QVERIFY(ret.isNumber());
2749 QCOMPARE(ret.toInt32(), 3);
2752 QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (var i in o)\n --n; n");
2753 QVERIFY(ret.isNumber());
2754 QCOMPARE(ret.toInt32(), 6);
2757 QScriptValue ret = eng.evaluate("o = { n: 3 }; n = 5; with (o)\n ++n; n");
2758 QVERIFY(ret.isNumber());
2759 QCOMPARE(ret.toInt32(), 5);
2762 QScriptValue ret = eng.evaluate("o = { n: 3 }; n = 10; with (o)\n --n; n");
2763 QVERIFY(ret.isNumber());
2764 QCOMPARE(ret.toInt32(), 10);
2767 QScriptValue ret = eng.evaluate("n = 5; i = 0; do\n ++n; while (++i < 10); n");
2768 QVERIFY(ret.isNumber());
2769 QCOMPARE(ret.toInt32(), 15);
2772 QScriptValue ret = eng.evaluate("n = 20; i = 0; do\n --n; while (++i < 10); n");
2773 QVERIFY(ret.isNumber());
2774 QCOMPARE(ret.toInt32(), 10);
2778 QScriptValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n++n; n");
2779 QVERIFY(ret.isNumber());
2780 QCOMPARE(ret.toInt32(), 2);
2783 QScriptValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n--n; n");
2784 QVERIFY(ret.isNumber());
2785 QCOMPARE(ret.toInt32(), 0);
2789 QScriptValue ret = eng.evaluate("if (0)");
2790 QVERIFY(ret.isError());
2793 QScriptValue ret = eng.evaluate("while (0)");
2794 QVERIFY(ret.isError());
2797 QScriptValue ret = eng.evaluate("for (;;)");
2798 QVERIFY(ret.isError());
2801 QScriptValue ret = eng.evaluate("for (p in this)");
2802 QVERIFY(ret.isError());
2805 QScriptValue ret = eng.evaluate("with (this)");
2806 QVERIFY(ret.isError());
2809 QScriptValue ret = eng.evaluate("do");
2810 QVERIFY(ret.isError());
2814 class EventReceiver3 : public QObject
2816 public:
2817 enum AbortionResult {
2818 None = 0,
2819 String = 1,
2820 Error = 2
2823 EventReceiver3(QScriptEngine *eng) {
2824 engine = eng;
2825 resultType = None;
2828 bool event(QEvent *e) {
2829 if (e->type() == QEvent::User + 1) {
2830 switch (resultType) {
2831 case None:
2832 engine->abortEvaluation();
2833 break;
2834 case String:
2835 engine->abortEvaluation(QScriptValue(engine, QString::fromLatin1("Aborted")));
2836 break;
2837 case Error:
2838 engine->abortEvaluation(engine->currentContext()->throwError("AbortedWithError"));
2839 break;
2842 return QObject::event(e);
2845 AbortionResult resultType;
2846 QScriptEngine *engine;
2849 static QScriptValue myFunctionAbortingEvaluation(QScriptContext *, QScriptEngine *eng)
2851 eng->abortEvaluation();
2852 return eng->nullValue(); // should be ignored
2855 void tst_QScriptEngine::abortEvaluation()
2857 QScriptEngine eng;
2859 eng.abortEvaluation();
2860 QVERIFY(!eng.hasUncaughtException());
2862 eng.abortEvaluation(123);
2864 QScriptValue ret = eng.evaluate("'ciao'");
2865 QVERIFY(ret.isString());
2866 QCOMPARE(ret.toString(), QString::fromLatin1("ciao"));
2869 EventReceiver3 receiver(&eng);
2871 eng.setProcessEventsInterval(100);
2872 for (int x = 0; x < 3; ++x) {
2873 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
2874 receiver.resultType = EventReceiver3::AbortionResult(x);
2875 QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }"));
2876 switch (receiver.resultType) {
2877 case EventReceiver3::None:
2878 QVERIFY(!eng.hasUncaughtException());
2879 QVERIFY(!ret.isValid());
2880 break;
2881 case EventReceiver3::String:
2882 QVERIFY(!eng.hasUncaughtException());
2883 QVERIFY(ret.isString());
2884 QCOMPARE(ret.toString(), QString::fromLatin1("Aborted"));
2885 break;
2886 case EventReceiver3::Error:
2887 QVERIFY(eng.hasUncaughtException());
2888 QVERIFY(ret.isError());
2889 QCOMPARE(ret.toString(), QString::fromLatin1("Error: AbortedWithError"));
2890 break;
2894 // scripts cannot intercept the abortion with try/catch
2895 for (int y = 0; y < 3; ++y) {
2896 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
2897 receiver.resultType = EventReceiver3::AbortionResult(y);
2898 QScriptValue ret = eng.evaluate(QString::fromLatin1(
2899 "while (1) {\n"
2900 " try {\n"
2901 " (function() { while (1) { } })();\n"
2902 " } catch (e) {\n"
2903 " ;\n"
2904 " }\n"
2905 "}"));
2906 switch (receiver.resultType) {
2907 case EventReceiver3::None:
2908 QVERIFY(!eng.hasUncaughtException());
2909 QVERIFY(!ret.isValid());
2910 break;
2911 case EventReceiver3::String:
2912 QVERIFY(!eng.hasUncaughtException());
2913 QVERIFY(ret.isString());
2914 QCOMPARE(ret.toString(), QString::fromLatin1("Aborted"));
2915 break;
2916 case EventReceiver3::Error:
2917 QVERIFY(eng.hasUncaughtException());
2918 QVERIFY(ret.isError());
2919 break;
2924 QScriptValue fun = eng.newFunction(myFunctionAbortingEvaluation);
2925 eng.globalObject().setProperty("myFunctionAbortingEvaluation", fun);
2926 QScriptValue ret = eng.evaluate("myFunctionAbortingEvaluation()");
2927 QVERIFY(!ret.isValid());
2931 static QScriptValue myFunctionReturningIsEvaluating(QScriptContext *, QScriptEngine *eng)
2933 return QScriptValue(eng, eng->isEvaluating());
2936 class EventReceiver4 : public QObject
2938 public:
2939 EventReceiver4(QScriptEngine *eng) {
2940 engine = eng;
2941 wasEvaluating = false;
2944 bool event(QEvent *e) {
2945 if (e->type() == QEvent::User + 1) {
2946 wasEvaluating = engine->isEvaluating();
2948 return QObject::event(e);
2951 QScriptEngine *engine;
2952 bool wasEvaluating;
2955 void tst_QScriptEngine::isEvaluating()
2957 QScriptEngine eng;
2959 QVERIFY(!eng.isEvaluating());
2961 eng.evaluate("");
2962 QVERIFY(!eng.isEvaluating());
2963 eng.evaluate("123");
2964 QVERIFY(!eng.isEvaluating());
2965 eng.evaluate("0 = 0");
2966 QVERIFY(!eng.isEvaluating());
2969 QScriptValue fun = eng.newFunction(myFunctionReturningIsEvaluating);
2970 eng.globalObject().setProperty("myFunctionReturningIsEvaluating", fun);
2971 QScriptValue ret = eng.evaluate("myFunctionReturningIsEvaluating()");
2972 QVERIFY(ret.isBoolean());
2973 QVERIFY(ret.toBoolean());
2977 EventReceiver4 receiver(&eng);
2978 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1)));
2980 QString script = QString::fromLatin1(
2981 "var end = Number(new Date()) + 1000;"
2982 "var x = 0;"
2983 "while (Number(new Date()) < end) {"
2984 " ++x;"
2985 "}");
2987 eng.setProcessEventsInterval(100);
2988 eng.evaluate(script);
2989 QVERIFY(receiver.wasEvaluating);
2993 static QtMsgType theMessageType;
2994 static QString theMessage;
2996 static void myMsgHandler(QtMsgType type, const char *msg)
2998 theMessageType = type;
2999 theMessage = QString::fromLatin1(msg);
3002 void tst_QScriptEngine::printFunctionWithCustomHandler()
3004 QScriptEngine eng;
3005 QtMsgHandler oldHandler = qInstallMsgHandler(myMsgHandler);
3006 QVERIFY(eng.globalObject().property("print").isFunction());
3007 theMessageType = QtSystemMsg;
3008 QVERIFY(theMessage.isEmpty());
3009 QVERIFY(eng.evaluate("print('test')").isUndefined());
3010 QCOMPARE(theMessageType, QtDebugMsg);
3011 QCOMPARE(theMessage, QString::fromLatin1("test"));
3012 theMessageType = QtSystemMsg;
3013 theMessage.clear();
3014 QVERIFY(eng.evaluate("print(3, true, 'little pigs')").isUndefined());
3015 QCOMPARE(theMessageType, QtDebugMsg);
3016 QCOMPARE(theMessage, QString::fromLatin1("3 true little pigs"));
3017 qInstallMsgHandler(oldHandler);
3020 void tst_QScriptEngine::printThrowsException()
3022 QScriptEngine eng;
3023 QScriptValue ret = eng.evaluate("print({ toString: function() { throw 'foo'; } });");
3024 QVERIFY(eng.hasUncaughtException());
3025 QVERIFY(ret.strictlyEquals(QScriptValue(&eng, QLatin1String("foo"))));
3028 void tst_QScriptEngine::errorConstructors()
3030 QScriptEngine eng;
3031 QStringList prefixes;
3032 prefixes << "" << "Eval" << "Range" << "Reference" << "Syntax" << "Type" << "URI";
3033 for (int x = 0; x < 3; ++x) {
3034 for (int i = 0; i < prefixes.size(); ++i) {
3035 QString name = prefixes.at(i) + QLatin1String("Error");
3036 QString code = QString(i+1, QLatin1Char('\n'));
3037 if (x == 0)
3038 code += QLatin1String("throw ");
3039 else if (x == 1)
3040 code += QLatin1String("new ");
3041 code += name + QLatin1String("()");
3042 QScriptValue ret = eng.evaluate(code);
3043 QVERIFY(ret.isError());
3044 QCOMPARE(eng.hasUncaughtException(), x == 0);
3045 eng.clearExceptions();
3046 QVERIFY(ret.toString().startsWith(name));
3047 if (x != 0)
3048 QEXPECT_FAIL("", "JSC doesn't assign lineNumber when errors are not thrown", Continue);
3049 QCOMPARE(ret.property("lineNumber").toInt32(), i+2);
3054 static QScriptValue argumentsProperty_fun(QScriptContext *, QScriptEngine *eng)
3056 eng->evaluate("var a = arguments[0];");
3057 eng->evaluate("arguments[0] = 200;");
3058 return eng->evaluate("a + arguments[0]");
3062 void tst_QScriptEngine::argumentsProperty()
3065 QScriptEngine eng;
3066 QEXPECT_FAIL("", "", Continue);
3067 QVERIFY(eng.evaluate("arguments").isUndefined());
3068 eng.evaluate("arguments = 10");
3069 QScriptValue ret = eng.evaluate("arguments");
3070 QVERIFY(ret.isNumber());
3071 QCOMPARE(ret.toInt32(), 10);
3072 QEXPECT_FAIL("", "", Continue);
3073 QVERIFY(!eng.evaluate("delete arguments").toBoolean());
3076 QScriptEngine eng;
3077 eng.evaluate("o = { arguments: 123 }");
3078 QScriptValue ret = eng.evaluate("with (o) { arguments; }");
3079 QVERIFY(ret.isNumber());
3080 QCOMPARE(ret.toInt32(), 123);
3083 QScriptEngine eng;
3084 QScriptValue ret = eng.evaluate("(function() { arguments = 456; return arguments; })()");
3085 QVERIFY(ret.isNumber());
3086 QCOMPARE(ret.toInt32(), 456);
3087 QEXPECT_FAIL("", "", Continue);
3088 QVERIFY(eng.evaluate("arguments").isUndefined());
3092 QScriptEngine eng;
3093 QScriptValue fun = eng.newFunction(argumentsProperty_fun);
3094 eng.globalObject().setProperty("fun", eng.newFunction(argumentsProperty_fun));
3095 QScriptValue result = eng.evaluate("fun(18)");
3096 QVERIFY(result.isNumber());
3097 QCOMPARE(result.toInt32(), 218);
3101 void tst_QScriptEngine::numberClass()
3103 QScriptEngine eng;
3105 QScriptValue ctor = eng.globalObject().property("Number");
3106 QVERIFY(ctor.property("length").isNumber());
3107 QCOMPARE(ctor.property("length").toNumber(), qsreal(1));
3108 QScriptValue proto = ctor.property("prototype");
3109 QVERIFY(proto.isObject());
3111 QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration
3112 | QScriptValue::Undeletable
3113 | QScriptValue::ReadOnly;
3114 QCOMPARE(ctor.propertyFlags("prototype"), flags);
3115 QVERIFY(ctor.property("MAX_VALUE").isNumber());
3116 QCOMPARE(ctor.propertyFlags("MAX_VALUE"), flags);
3117 QVERIFY(ctor.property("MIN_VALUE").isNumber());
3118 QCOMPARE(ctor.propertyFlags("MIN_VALUE"), flags);
3119 QVERIFY(ctor.property("NaN").isNumber());
3120 QCOMPARE(ctor.propertyFlags("NaN"), flags);
3121 QVERIFY(ctor.property("NEGATIVE_INFINITY").isNumber());
3122 QCOMPARE(ctor.propertyFlags("NEGATIVE_INFINITY"), flags);
3123 QVERIFY(ctor.property("POSITIVE_INFINITY").isNumber());
3124 QCOMPARE(ctor.propertyFlags("POSITIVE_INFINITY"), flags);
3126 QVERIFY(proto.instanceOf(eng.globalObject().property("Object")));
3127 QCOMPARE(proto.toNumber(), qsreal(0));
3128 QVERIFY(proto.property("constructor").strictlyEquals(ctor));
3131 QScriptValue ret = eng.evaluate("Number()");
3132 QVERIFY(ret.isNumber());
3133 QCOMPARE(ret.toNumber(), qsreal(0));
3136 QScriptValue ret = eng.evaluate("Number(123)");
3137 QVERIFY(ret.isNumber());
3138 QCOMPARE(ret.toNumber(), qsreal(123));
3141 QScriptValue ret = eng.evaluate("Number('456')");
3142 QVERIFY(ret.isNumber());
3143 QCOMPARE(ret.toNumber(), qsreal(456));
3146 QScriptValue ret = eng.evaluate("new Number()");
3147 QVERIFY(!ret.isNumber());
3148 QVERIFY(ret.isObject());
3149 QCOMPARE(ret.toNumber(), qsreal(0));
3152 QScriptValue ret = eng.evaluate("new Number(123)");
3153 QVERIFY(!ret.isNumber());
3154 QVERIFY(ret.isObject());
3155 QCOMPARE(ret.toNumber(), qsreal(123));
3158 QScriptValue ret = eng.evaluate("new Number('456')");
3159 QVERIFY(!ret.isNumber());
3160 QVERIFY(ret.isObject());
3161 QCOMPARE(ret.toNumber(), qsreal(456));
3164 QVERIFY(proto.property("toString").isFunction());
3166 QScriptValue ret = eng.evaluate("new Number(123).toString()");
3167 QVERIFY(ret.isString());
3168 QCOMPARE(ret.toString(), QString::fromLatin1("123"));
3171 QScriptValue ret = eng.evaluate("new Number(123).toString(8)");
3172 QVERIFY(ret.isString());
3173 QCOMPARE(ret.toString(), QString::fromLatin1("173"));
3176 QScriptValue ret = eng.evaluate("new Number(123).toString(16)");
3177 QVERIFY(ret.isString());
3178 QCOMPARE(ret.toString(), QString::fromLatin1("7b"));
3180 QVERIFY(proto.property("toLocaleString").isFunction());
3182 QScriptValue ret = eng.evaluate("new Number(123).toLocaleString()");
3183 QVERIFY(ret.isString());
3184 QCOMPARE(ret.toString(), QString::fromLatin1("123"));
3186 QVERIFY(proto.property("valueOf").isFunction());
3188 QScriptValue ret = eng.evaluate("new Number(123).valueOf()");
3189 QVERIFY(ret.isNumber());
3190 QCOMPARE(ret.toNumber(), qsreal(123));
3192 QVERIFY(proto.property("toExponential").isFunction());
3194 QScriptValue ret = eng.evaluate("new Number(123).toExponential()");
3195 QVERIFY(ret.isString());
3196 QCOMPARE(ret.toString(), QString::fromLatin1("1.23e+2"));
3198 QVERIFY(proto.property("toFixed").isFunction());
3200 QScriptValue ret = eng.evaluate("new Number(123).toFixed()");
3201 QVERIFY(ret.isString());
3202 QCOMPARE(ret.toString(), QString::fromLatin1("123"));
3204 QVERIFY(proto.property("toPrecision").isFunction());
3206 QScriptValue ret = eng.evaluate("new Number(123).toPrecision()");
3207 QVERIFY(ret.isString());
3208 QCOMPARE(ret.toString(), QString::fromLatin1("123"));
3212 void tst_QScriptEngine::forInStatement()
3214 QScriptEngine eng;
3216 QScriptValue ret = eng.evaluate("o = { }; r = []; for (var p in o) r[r.length] = p; r");
3217 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3218 QVERIFY(lst.isEmpty());
3221 QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];"
3222 "for (var p in o) r[r.length] = p; r");
3223 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3224 QCOMPARE(lst.size(), 1);
3225 QCOMPARE(lst.at(0), QString::fromLatin1("p"));
3228 QScriptValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];"
3229 "for (var p in o) r[r.length] = p; r");
3230 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3231 QCOMPARE(lst.size(), 2);
3232 QCOMPARE(lst.at(0), QString::fromLatin1("p"));
3233 QCOMPARE(lst.at(1), QString::fromLatin1("q"));
3236 // properties in prototype
3238 QScriptValue ret = eng.evaluate("o = { }; o.__proto__ = { p: 123 }; r = [];"
3239 "for (var p in o) r[r.length] = p; r");
3240 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3241 QCOMPARE(lst.size(), 1);
3242 QCOMPARE(lst.at(0), QString::fromLatin1("p"));
3245 QScriptValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { q: 456 }; r = [];"
3246 "for (var p in o) r[r.length] = p; r");
3247 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3248 QCOMPARE(lst.size(), 2);
3249 QCOMPARE(lst.at(0), QString::fromLatin1("p"));
3250 QCOMPARE(lst.at(1), QString::fromLatin1("q"));
3253 // shadowed property
3254 QScriptValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { p: 456 }; r = [];"
3255 "for (var p in o) r[r.length] = p; r");
3256 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3257 QCOMPARE(lst.size(), 1);
3258 QCOMPARE(lst.at(0), QString::fromLatin1("p"));
3261 // deleting property during enumeration
3263 QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];"
3264 "for (var p in o) { r[r.length] = p; delete r[p]; } r");
3265 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3266 QCOMPARE(lst.size(), 1);
3267 QCOMPARE(lst.at(0), QString::fromLatin1("p"));
3270 QScriptValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];"
3271 "for (var p in o) { r[r.length] = p; delete o.q; } r");
3272 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3273 QCOMPARE(lst.size(), 1);
3274 QCOMPARE(lst.at(0), QString::fromLatin1("p"));
3277 // adding property during enumeration
3279 QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];"
3280 "for (var p in o) { r[r.length] = p; o.q = 456; } r");
3281 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3282 QCOMPARE(lst.size(), 1);
3283 QCOMPARE(lst.at(0), QString::fromLatin1("p"));
3286 // arrays
3288 QScriptValue ret = eng.evaluate("a = [123, 456]; r = [];"
3289 "for (var p in a) r[r.length] = p; r");
3290 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3291 QCOMPARE(lst.size(), 2);
3292 QCOMPARE(lst.at(0), QString::fromLatin1("0"));
3293 QCOMPARE(lst.at(1), QString::fromLatin1("1"));
3296 QScriptValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar'; r = [];"
3297 "for (var p in a) r[r.length] = p; r");
3298 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3299 QCOMPARE(lst.size(), 3);
3300 QCOMPARE(lst.at(0), QString::fromLatin1("0"));
3301 QCOMPARE(lst.at(1), QString::fromLatin1("1"));
3302 QCOMPARE(lst.at(2), QString::fromLatin1("foo"));
3305 QScriptValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar';"
3306 "b = [111, 222, 333]; b.bar = 'baz';"
3307 "a.__proto__ = b; r = [];"
3308 "for (var p in a) r[r.length] = p; r");
3309 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3310 QCOMPARE(lst.size(), 5);
3311 QCOMPARE(lst.at(0), QString::fromLatin1("0"));
3312 QCOMPARE(lst.at(1), QString::fromLatin1("1"));
3313 QCOMPARE(lst.at(2), QString::fromLatin1("foo"));
3314 QCOMPARE(lst.at(3), QString::fromLatin1("2"));
3315 QCOMPARE(lst.at(4), QString::fromLatin1("bar"));
3318 // null and undefined
3319 // according to the spec, we should throw an exception; however, for
3320 // compability with the real world, we don't
3322 QScriptValue ret = eng.evaluate("r = true; for (var p in undefined) r = false; r");
3323 QVERIFY(ret.isBool());
3324 QVERIFY(ret.toBool());
3327 QScriptValue ret = eng.evaluate("r = true; for (var p in null) r = false; r");
3328 QVERIFY(ret.isBool());
3329 QVERIFY(ret.toBool());
3333 void tst_QScriptEngine::functionExpression()
3335 // task 175679
3336 QScriptEngine eng;
3337 QVERIFY(!eng.globalObject().property("bar").isValid());
3338 eng.evaluate("function foo(arg) {\n"
3339 " if (arg == 'bar')\n"
3340 " function bar() { return 'bar'; }\n"
3341 " else\n"
3342 " function baz() { return 'baz'; }\n"
3343 " return (arg == 'bar') ? bar : baz;\n"
3344 "}");
3345 QVERIFY(!eng.globalObject().property("bar").isValid());
3346 QVERIFY(!eng.globalObject().property("baz").isValid());
3347 QVERIFY(eng.evaluate("foo").isFunction());
3349 QScriptValue ret = eng.evaluate("foo('bar')");
3350 QVERIFY(ret.isFunction());
3351 QScriptValue ret2 = ret.call(QScriptValue());
3352 QCOMPARE(ret2.toString(), QString::fromLatin1("bar"));
3353 QVERIFY(!eng.globalObject().property("bar").isValid());
3354 QVERIFY(!eng.globalObject().property("baz").isValid());
3357 QScriptValue ret = eng.evaluate("foo('baz')");
3358 QVERIFY(ret.isFunction());
3359 QScriptValue ret2 = ret.call(QScriptValue());
3360 QCOMPARE(ret2.toString(), QString::fromLatin1("baz"));
3361 QVERIFY(!eng.globalObject().property("bar").isValid());
3362 QVERIFY(!eng.globalObject().property("baz").isValid());
3366 void tst_QScriptEngine::stringObjects()
3368 QScriptEngine eng;
3369 QString str("ciao");
3370 // in C++
3372 QScriptValue obj = QScriptValue(&eng, str).toObject();
3373 QCOMPARE(obj.property("length").toInt32(), str.length());
3374 QCOMPARE(obj.propertyFlags("length"), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly));
3375 for (int i = 0; i < str.length(); ++i) {
3376 QString pname = QString::number(i);
3377 QVERIFY(obj.property(pname).isString());
3378 QCOMPARE(obj.property(pname).toString(), QString(str.at(i)));
3379 QCOMPARE(obj.propertyFlags(pname), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::ReadOnly));
3380 obj.setProperty(pname, QScriptValue());
3381 obj.setProperty(pname, QScriptValue(&eng, 123));
3382 QVERIFY(obj.property(pname).isString());
3383 QCOMPARE(obj.property(pname).toString(), QString(str.at(i)));
3385 QVERIFY(!obj.property("-1").isValid());
3386 QVERIFY(!obj.property(QString::number(str.length())).isValid());
3388 QScriptValue val(&eng, 123);
3389 obj.setProperty("-1", val);
3390 QVERIFY(obj.property("-1").strictlyEquals(val));
3391 obj.setProperty("100", val);
3392 QVERIFY(obj.property("100").strictlyEquals(val));
3395 // in script
3397 QScriptValue ret = eng.evaluate("s = new String('ciao'); r = []; for (var p in s) r.push(p); r");
3398 QVERIFY(ret.isArray());
3399 QStringList lst = qscriptvalue_cast<QStringList>(ret);
3400 QCOMPARE(lst.size(), str.length());
3401 for (int i = 0; i < str.length(); ++i)
3402 QCOMPARE(lst.at(i), QString::number(i));
3404 QScriptValue ret2 = eng.evaluate("s[0] = 123; s[0]");
3405 QVERIFY(ret2.isString());
3406 QCOMPARE(ret2.toString().length(), 1);
3407 QCOMPARE(ret2.toString().at(0), str.at(0));
3409 QScriptValue ret3 = eng.evaluate("s[-1] = 123; s[-1]");
3410 QVERIFY(ret3.isNumber());
3411 QCOMPARE(ret3.toInt32(), 123);
3413 QScriptValue ret4 = eng.evaluate("s[s.length] = 456; s[s.length]");
3414 QVERIFY(ret4.isNumber());
3415 QCOMPARE(ret4.toInt32(), 456);
3417 QScriptValue ret5 = eng.evaluate("delete s[0]");
3418 QVERIFY(ret5.isBoolean());
3419 QVERIFY(!ret5.toBoolean());
3421 QScriptValue ret6 = eng.evaluate("delete s[-1]");
3422 QVERIFY(ret6.isBoolean());
3423 QVERIFY(ret6.toBoolean());
3425 QScriptValue ret7 = eng.evaluate("delete s[s.length]");
3426 QVERIFY(ret7.isBoolean());
3427 QVERIFY(ret7.toBoolean());
3430 // task 212440
3432 QScriptValue ret = eng.evaluate("replace_args = []; \"a a a\".replace(/(a)/g, function() { replace_args.push(arguments); }); replace_args");
3433 QVERIFY(ret.isArray());
3434 int len = ret.property("length").toInt32();
3435 QCOMPARE(len, 3);
3436 for (int i = 0; i < len; ++i) {
3437 QScriptValue args = ret.property(i);
3438 QCOMPARE(args.property("length").toInt32(), 4);
3439 QCOMPARE(args.property(0).toString(), QString::fromLatin1("a")); // matched string
3440 QCOMPARE(args.property(1).toString(), QString::fromLatin1("a")); // capture
3441 QVERIFY(args.property(2).isNumber());
3442 QCOMPARE(args.property(2).toInt32(), i*2); // index of match
3443 QCOMPARE(args.property(3).toString(), QString::fromLatin1("a a a"));
3446 // task 212501
3448 QScriptValue ret = eng.evaluate("\"foo\".replace(/a/g, function() {})");
3449 QVERIFY(ret.isString());
3450 QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
3454 void tst_QScriptEngine::getterSetterThisObject()
3456 // Global Object
3458 QScriptEngine eng;
3459 // read
3460 eng.evaluate("__defineGetter__('x', function() { return this; });");
3462 QScriptValue ret = eng.evaluate("x");
3463 QVERIFY(ret.equals(eng.globalObject()));
3466 QScriptValue ret = eng.evaluate("(function() { return x; })()");
3467 QVERIFY(ret.equals(eng.globalObject()));
3470 QScriptValue ret = eng.evaluate("with (this) x");
3471 QVERIFY(ret.equals(eng.globalObject()));
3474 QScriptValue ret = eng.evaluate("with ({}) x");
3475 QVERIFY(ret.equals(eng.globalObject()));
3478 QScriptValue ret = eng.evaluate("(function() { with ({}) return x; })()");
3479 QVERIFY(ret.equals(eng.globalObject()));
3481 // write
3482 eng.evaluate("__defineSetter__('x', function() { return this; });");
3484 QScriptValue ret = eng.evaluate("x = 'foo'");
3485 // SpiderMonkey says setter return value, JSC says RHS.
3486 QVERIFY(ret.isString());
3487 QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
3490 QScriptValue ret = eng.evaluate("(function() { return x = 'foo'; })()");
3491 // SpiderMonkey says setter return value, JSC says RHS.
3492 QVERIFY(ret.isString());
3493 QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
3496 QScriptValue ret = eng.evaluate("with (this) x = 'foo'");
3497 // SpiderMonkey says setter return value, JSC says RHS.
3498 QVERIFY(ret.isString());
3499 QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
3502 QScriptValue ret = eng.evaluate("with ({}) x = 'foo'");
3503 // SpiderMonkey says setter return value, JSC says RHS.
3504 QVERIFY(ret.isString());
3505 QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
3508 QScriptValue ret = eng.evaluate("(function() { with ({}) return x = 'foo'; })()");
3509 // SpiderMonkey says setter return value, JSC says RHS.
3510 QVERIFY(ret.isString());
3511 QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
3515 // other object
3517 QScriptEngine eng;
3518 eng.evaluate("o = {}");
3519 // read
3520 eng.evaluate("o.__defineGetter__('x', function() { return this; })");
3521 QVERIFY(eng.evaluate("o.x === o").toBoolean());
3522 QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o")));
3523 QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean());
3524 eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o"));
3525 // write
3526 eng.evaluate("o.__defineSetter__('x', function() { return this; });");
3527 // SpiderMonkey says setter return value, JSC says RHS.
3528 QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean());
3529 QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo"));
3530 QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo"));
3533 // getter+setter in prototype chain
3535 QScriptEngine eng;
3536 eng.evaluate("o = {}; p = {}; o.__proto__ = p");
3537 // read
3538 eng.evaluate("p.__defineGetter__('x', function() { return this; })");
3539 QVERIFY(eng.evaluate("o.x === o").toBoolean());
3540 QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o")));
3541 QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean());
3542 eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o"));
3543 eng.evaluate("with (q) with (o) x").equals(eng.evaluate("o"));
3544 // write
3545 eng.evaluate("o.__defineSetter__('x', function() { return this; });");
3546 // SpiderMonkey says setter return value, JSC says RHS.
3547 QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean());
3548 QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo"));
3549 QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo"));
3552 // getter+setter in activation
3554 QScriptEngine eng;
3555 QScriptContext *ctx = eng.pushContext();
3556 QVERIFY(ctx != 0);
3557 QScriptValue act = ctx->activationObject();
3558 act.setProperty("act", act);
3559 // read
3560 eng.evaluate("act.__defineGetter__('x', function() { return this; })");
3561 QVERIFY(eng.evaluate("x === act").toBoolean());
3562 QEXPECT_FAIL("", "Exotic overload (don't care for now)", Continue);
3563 QVERIFY(eng.evaluate("with (act) x").equals("foo"));
3564 QVERIFY(eng.evaluate("(function() { with (act) return x; })() === act").toBoolean());
3565 eng.evaluate("q = {}; with (act) with (q) x").equals(eng.evaluate("act"));
3566 eng.evaluate("with (q) with (act) x").equals(eng.evaluate("act"));
3567 // write
3568 eng.evaluate("act.__defineSetter__('x', function() { return this; });");
3569 QVERIFY(eng.evaluate("(x = 'foo') === 'foo'").toBoolean());
3570 QVERIFY(eng.evaluate("with (act) x = 'foo'").equals("foo"));
3571 QVERIFY(eng.evaluate("with (act) with (q) x = 'foo'").equals("foo"));
3572 eng.popContext();
3576 void tst_QScriptEngine::continueInSwitch()
3578 QScriptEngine eng;
3579 // switch - continue
3581 QScriptValue ret = eng.evaluate("switch (1) { default: continue; }");
3582 QVERIFY(ret.isError());
3584 // for - switch - case - continue
3586 QScriptValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
3587 " switch (i) {\n"
3588 " case 1: ++j; continue;\n"
3589 " case 100: ++j; continue;\n"
3590 " case 1000: ++j; continue;\n"
3591 " }\n"
3592 "}; j");
3593 QVERIFY(ret.isNumber());
3594 QCOMPARE(ret.toInt32(), 3);
3596 // for - switch - case - default - continue
3598 QScriptValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
3599 " switch (i) {\n"
3600 " case 1: ++j; continue;\n"
3601 " case 100: ++j; continue;\n"
3602 " case 1000: ++j; continue;\n"
3603 " default: if (i < 50000) break; else continue;\n"
3604 " }\n"
3605 "}; j");
3606 QVERIFY(ret.isNumber());
3607 QCOMPARE(ret.toInt32(), 3);
3609 // switch - for - continue
3611 QScriptValue ret = eng.evaluate("j = 123; switch (j) {\n"
3612 " case 123:\n"
3613 " for (i = 0; i < 100000; ++i) {\n"
3614 " continue;\n"
3615 " }\n"
3616 "}; i\n");
3617 QVERIFY(ret.isNumber());
3618 QCOMPARE(ret.toInt32(), 100000);
3620 // switch - switch - continue
3622 QScriptValue ret = eng.evaluate("i = 1; switch (i) { default: switch (i) { case 1: continue; } }");
3623 QVERIFY(ret.isError());
3625 // for - switch - switch - continue
3627 QScriptValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n"
3628 " switch (i) {\n"
3629 " case 1:\n"
3630 " switch (i) {\n"
3631 " case 1: ++j; continue;\n"
3632 " }\n"
3633 " }\n"
3634 "}; j");
3635 QVERIFY(ret.isNumber());
3636 QCOMPARE(ret.toInt32(), 1);
3638 // switch - for - switch - continue
3640 QScriptValue ret = eng.evaluate("j = 123; switch (j) {\n"
3641 " case 123:\n"
3642 " for (i = 0; i < 100000; ++i) {\n"
3643 " switch (i) {\n"
3644 " case 1:\n"
3645 " ++j; continue;\n"
3646 " }\n"
3647 " }\n"
3648 "}; i\n");
3649 QVERIFY(ret.isNumber());
3650 QCOMPARE(ret.toInt32(), 100000);
3654 void tst_QScriptEngine::readOnlyPrototypeProperty()
3656 QSKIP("JSC semantics differ from old back-end and SpiderMonkey", SkipAll);
3657 QScriptEngine eng;
3658 QCOMPARE(eng.evaluate("o = {}; o.__proto__ = parseInt; o.length").toInt32(), 2);
3659 QCOMPARE(eng.evaluate("o.length = 4; o.length").toInt32(), 2);
3660 QVERIFY(!eng.evaluate("o.hasOwnProperty('length')").toBoolean());
3661 QCOMPARE(eng.evaluate("o.length *= 2; o.length").toInt32(), 2);
3662 QCOMPARE(eng.evaluate("o.length /= 2; o.length").toInt32(), 2);
3663 QCOMPARE(eng.evaluate("o.length %= 2; o.length").toInt32(), 2);
3664 QCOMPARE(eng.evaluate("o.length += 2; o.length").toInt32(), 2);
3665 QCOMPARE(eng.evaluate("o.length -= 2; o.length").toInt32(), 2);
3666 QCOMPARE(eng.evaluate("o.length <<= 2; o.length").toInt32(), 2);
3667 QCOMPARE(eng.evaluate("o.length >>= 2; o.length").toInt32(), 2);
3668 QCOMPARE(eng.evaluate("o.length >>>= 2; o.length").toInt32(), 2);
3669 QCOMPARE(eng.evaluate("o.length &= 0; o.length").toInt32(), 2);
3670 QCOMPARE(eng.evaluate("o.length ^= 255; o.length").toInt32(), 2);
3671 QCOMPARE(eng.evaluate("o.length |= 255; o.length").toInt32(), 2);
3674 QScriptValue ret = eng.evaluate("o.__defineGetter__('length', function() {})");
3675 QVERIFY(ret.isError());
3676 QCOMPARE(ret.toString(), QString::fromLatin1("Error: cannot redefine read-only property"));
3679 QScriptValue ret = eng.evaluate("o.__defineSetter__('length', function() {})");
3680 QVERIFY(ret.isError());
3681 QCOMPARE(ret.toString(), QString::fromLatin1("Error: cannot redefine read-only property"));
3685 void tst_QScriptEngine::toObject()
3687 QScriptEngine eng;
3689 QVERIFY(!eng.toObject(eng.undefinedValue()).isValid());
3691 QVERIFY(!eng.toObject(eng.nullValue()).isValid());
3693 QScriptValue falskt(false);
3695 QScriptValue tmp = eng.toObject(falskt);
3696 QVERIFY(tmp.isObject());
3697 QCOMPARE(tmp.toNumber(), falskt.toNumber());
3700 QScriptValue sant(true);
3702 QScriptValue tmp = eng.toObject(sant);
3703 QVERIFY(tmp.isObject());
3704 QCOMPARE(tmp.toNumber(), sant.toNumber());
3707 QScriptValue number(123.0);
3709 QScriptValue tmp = eng.toObject(number);
3710 QVERIFY(tmp.isObject());
3711 QCOMPARE(tmp.toNumber(), number.toNumber());
3714 QScriptValue str = QScriptValue(&eng, QString("ciao"));
3716 QScriptValue tmp = eng.toObject(str);
3717 QVERIFY(tmp.isObject());
3718 QCOMPARE(tmp.toString(), str.toString());
3721 QScriptValue object = eng.newObject();
3723 QScriptValue tmp = eng.toObject(object);
3724 QVERIFY(tmp.isObject());
3725 QVERIFY(tmp.strictlyEquals(object));
3728 QScriptValue qobject = eng.newQObject(this);
3729 QVERIFY(eng.toObject(qobject).strictlyEquals(qobject));
3731 QVERIFY(!eng.toObject(QScriptValue()).isValid());
3734 void tst_QScriptEngine::reservedWords_data()
3736 QTest::addColumn<QString>("word");
3737 QTest::newRow("break") << QString("break");
3738 QTest::newRow("case") << QString("case");
3739 QTest::newRow("catch") << QString("catch");
3740 QTest::newRow("continue") << QString("continue");
3741 QTest::newRow("default") << QString("default");
3742 QTest::newRow("delete") << QString("delete");
3743 QTest::newRow("do") << QString("do");
3744 QTest::newRow("else") << QString("else");
3745 QTest::newRow("false") << QString("false");
3746 QTest::newRow("finally") << QString("finally");
3747 QTest::newRow("for") << QString("for");
3748 QTest::newRow("function") << QString("function");
3749 QTest::newRow("if") << QString("if");
3750 QTest::newRow("in") << QString("in");
3751 QTest::newRow("instanceof") << QString("instanceof");
3752 QTest::newRow("new") << QString("new");
3753 QTest::newRow("null") << QString("null");
3754 QTest::newRow("return") << QString("return");
3755 QTest::newRow("switch") << QString("switch");
3756 QTest::newRow("this") << QString("this");
3757 QTest::newRow("throw") << QString("throw");
3758 QTest::newRow("true") << QString("true");
3759 QTest::newRow("try") << QString("try");
3760 QTest::newRow("typeof") << QString("typeof");
3761 QTest::newRow("var") << QString("var");
3762 QTest::newRow("void") << QString("void");
3763 QTest::newRow("while") << QString("while");
3764 QTest::newRow("with") << QString("with");
3767 void tst_QScriptEngine::reservedWords()
3769 QFETCH(QString, word);
3771 QScriptEngine eng;
3772 QScriptValue ret = eng.evaluate(word + " = 123");
3773 QVERIFY(ret.isError());
3774 QString str = ret.toString();
3775 QVERIFY(str.startsWith("SyntaxError") || str.startsWith("ReferenceError"));
3778 QScriptEngine eng;
3779 QScriptValue ret = eng.evaluate("var " + word + " = 123");
3780 QVERIFY(ret.isError());
3781 QVERIFY(ret.toString().startsWith("SyntaxError"));
3784 QScriptEngine eng;
3785 QScriptValue ret = eng.evaluate("o = {}; o." + word + " = 123");
3786 // in the old back-end and in SpiderMonkey this is allowed, but not in JSC
3787 QVERIFY(ret.isError());
3788 QVERIFY(ret.toString().startsWith("SyntaxError"));
3791 QScriptEngine eng;
3792 QScriptValue ret = eng.evaluate("o = { " + word + ": 123 }");
3793 // in the old back-end and in SpiderMonkey this is allowed, but not in JSC
3794 QVERIFY(ret.isError());
3795 QVERIFY(ret.toString().startsWith("SyntaxError"));
3798 // SpiderMonkey allows this, but we don't
3799 QScriptEngine eng;
3800 QScriptValue ret = eng.evaluate("function " + word + "() {}");
3801 QVERIFY(ret.isError());
3802 QVERIFY(ret.toString().startsWith("SyntaxError"));
3806 void tst_QScriptEngine::futureReservedWords_data()
3808 QTest::addColumn<QString>("word");
3809 QTest::addColumn<bool>("allowed");
3810 QTest::newRow("abstract") << QString("abstract") << true;
3811 QTest::newRow("boolean") << QString("boolean") << true;
3812 QTest::newRow("byte") << QString("byte") << true;
3813 QTest::newRow("char") << QString("char") << true;
3814 QTest::newRow("class") << QString("class") << false;
3815 QTest::newRow("const") << QString("const") << false;
3816 QTest::newRow("debugger") << QString("debugger") << false;
3817 QTest::newRow("double") << QString("double") << true;
3818 QTest::newRow("enum") << QString("enum") << false;
3819 QTest::newRow("export") << QString("export") << false;
3820 QTest::newRow("extends") << QString("extends") << false;
3821 QTest::newRow("final") << QString("final") << true;
3822 QTest::newRow("float") << QString("float") << true;
3823 QTest::newRow("goto") << QString("goto") << true;
3824 QTest::newRow("implements") << QString("implements") << true;
3825 QTest::newRow("import") << QString("import") << false;
3826 QTest::newRow("int") << QString("int") << true;
3827 QTest::newRow("interface") << QString("interface") << true;
3828 QTest::newRow("long") << QString("long") << true;
3829 QTest::newRow("native") << QString("native") << true;
3830 QTest::newRow("package") << QString("package") << true;
3831 QTest::newRow("private") << QString("private") << true;
3832 QTest::newRow("protected") << QString("protected") << true;
3833 QTest::newRow("public") << QString("public") << true;
3834 QTest::newRow("short") << QString("short") << true;
3835 QTest::newRow("static") << QString("static") << true;
3836 QTest::newRow("super") << QString("super") << false;
3837 QTest::newRow("synchronized") << QString("synchronized") << true;
3838 QTest::newRow("throws") << QString("throws") << true;
3839 QTest::newRow("transient") << QString("transient") << true;
3840 QTest::newRow("volatile") << QString("volatile") << true;
3843 void tst_QScriptEngine::futureReservedWords()
3845 QFETCH(QString, word);
3846 QFETCH(bool, allowed);
3848 QScriptEngine eng;
3849 QScriptValue ret = eng.evaluate(word + " = 123");
3850 QCOMPARE(!ret.isError(), allowed);
3853 QScriptEngine eng;
3854 QScriptValue ret = eng.evaluate("var " + word + " = 123");
3855 QCOMPARE(!ret.isError(), allowed);
3858 // this should probably be allowed (see task 162567)
3859 QScriptEngine eng;
3860 QScriptValue ret = eng.evaluate("o = {}; o." + word + " = 123");
3861 QCOMPARE(ret.isNumber(), allowed);
3862 QCOMPARE(!ret.isError(), allowed);
3865 // this should probably be allowed (see task 162567)
3866 QScriptEngine eng;
3867 QScriptValue ret = eng.evaluate("o = { " + word + ": 123 }");
3868 QCOMPARE(!ret.isError(), allowed);
3872 void tst_QScriptEngine::throwInsideWithStatement()
3874 // task 209988
3875 QScriptEngine eng;
3877 QScriptValue ret = eng.evaluate(
3878 "try {"
3879 " o = { bad : \"bug\" };"
3880 " with (o) {"
3881 " throw 123;"
3882 " }"
3883 "} catch (e) {"
3884 " bad;"
3885 "}");
3886 QVERIFY(ret.isError());
3887 QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bad"));
3890 QScriptValue ret = eng.evaluate(
3891 "try {"
3892 " o = { bad : \"bug\" };"
3893 " with (o) {"
3894 " throw 123;"
3895 " }"
3896 "} finally {"
3897 " bad;"
3898 "}");
3899 QVERIFY(ret.isError());
3900 QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bad"));
3903 eng.clearExceptions();
3904 QScriptValue ret = eng.evaluate(
3905 "o = { bug : \"no bug\" };"
3906 "with (o) {"
3907 " try {"
3908 " throw 123;"
3909 " } finally {"
3910 " bug;"
3911 " }"
3912 "}");
3913 QVERIFY(ret.isNumber());
3914 QCOMPARE(ret.toInt32(), 123);
3915 QVERIFY(eng.hasUncaughtException());
3918 eng.clearExceptions();
3919 QScriptValue ret = eng.evaluate(
3920 "o = { bug : \"no bug\" };"
3921 "with (o) {"
3922 " throw 123;"
3923 "}");
3924 QVERIFY(ret.isNumber());
3925 QScriptValue ret2 = eng.evaluate("bug");
3926 QVERIFY(ret2.isError());
3927 QCOMPARE(ret2.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bug"));
3931 class TestAgent : public QScriptEngineAgent
3933 public:
3934 TestAgent(QScriptEngine *engine) : QScriptEngineAgent(engine) {}
3937 void tst_QScriptEngine::getSetAgent()
3939 // case 1: engine deleted before agent --> agent deleted too
3941 QScriptEngine *eng = new QScriptEngine;
3942 QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
3943 TestAgent *agent = new TestAgent(eng);
3944 eng->setAgent(agent);
3945 QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
3946 eng->setAgent(0); // the engine maintains ownership of the old agent
3947 QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
3948 delete eng;
3950 // case 2: agent deleted before engine --> engine's agent should become 0
3952 QScriptEngine *eng = new QScriptEngine;
3953 TestAgent *agent = new TestAgent(eng);
3954 eng->setAgent(agent);
3955 QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent);
3956 delete agent;
3957 QCOMPARE(eng->agent(), (QScriptEngineAgent*)0);
3958 eng->evaluate("(function(){ return 123; })()");
3959 delete eng;
3962 QScriptEngine eng;
3963 QScriptEngine eng2;
3964 TestAgent *agent = new TestAgent(&eng);
3965 QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::setAgent(): cannot set agent belonging to different engine");
3966 eng2.setAgent(agent);
3967 QCOMPARE(eng2.agent(), (QScriptEngineAgent*)0);
3971 void tst_QScriptEngine::reentrancy()
3974 QScriptEngine eng1;
3975 QScriptEngine eng2;
3976 QScriptString s1 = eng1.toStringHandle("foo");
3977 QScriptString s2 = eng2.toStringHandle("foo");
3978 QVERIFY(s1 != s2);
3981 QScriptEngine eng1;
3982 QScriptEngine eng2;
3983 eng1.setProcessEventsInterval(123);
3984 QCOMPARE(eng2.processEventsInterval(), -1);
3985 eng2.setProcessEventsInterval(456);
3986 QCOMPARE(eng1.processEventsInterval(), 123);
3989 QScriptEngine eng1;
3990 QScriptEngine eng2;
3991 qScriptRegisterMetaType<Foo>(&eng1, fooToScriptValue, fooFromScriptValue);
3992 Foo foo;
3993 foo.x = 12;
3994 foo.y = 34;
3996 QScriptValue fooVal = qScriptValueFromValue(&eng1, foo);
3997 QVERIFY(fooVal.isObject());
3998 QVERIFY(!fooVal.isVariant());
3999 QCOMPARE(fooVal.property("x").toInt32(), 12);
4000 QCOMPARE(fooVal.property("y").toInt32(), 34);
4001 fooVal.setProperty("x", 56);
4002 fooVal.setProperty("y", 78);
4004 Foo foo2 = qScriptValueToValue<Foo>(fooVal);
4005 QCOMPARE(foo2.x, 56);
4006 QCOMPARE(foo2.y, 78);
4009 QScriptValue fooVal = qScriptValueFromValue(&eng2, foo);
4010 QVERIFY(fooVal.isVariant());
4012 Foo foo2 = qScriptValueToValue<Foo>(fooVal);
4013 QCOMPARE(foo2.x, 12);
4014 QCOMPARE(foo2.y, 34);
4016 QVERIFY(!eng1.defaultPrototype(qMetaTypeId<Foo>()).isValid());
4017 QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
4018 QScriptValue proto1 = eng1.newObject();
4019 eng1.setDefaultPrototype(qMetaTypeId<Foo>(), proto1);
4020 QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
4021 QScriptValue proto2 = eng2.newObject();
4022 eng2.setDefaultPrototype(qMetaTypeId<Foo>(), proto2);
4023 QVERIFY(eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid());
4024 QVERIFY(eng1.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(proto1));
4027 QScriptEngine eng1;
4028 QScriptEngine eng2;
4029 QVERIFY(!eng2.globalObject().property("a").isValid());
4030 eng1.evaluate("a = 10");
4031 QVERIFY(eng1.globalObject().property("a").isNumber());
4032 QVERIFY(!eng2.globalObject().property("a").isValid());
4033 eng2.evaluate("a = 20");
4034 QVERIFY(eng2.globalObject().property("a").isNumber());
4035 QCOMPARE(eng1.globalObject().property("a").toInt32(), 10);
4037 // weird bug with JSC backend
4039 QScriptEngine eng;
4040 QCOMPARE(eng.evaluate("Array()").toString(), QString());
4041 eng.evaluate("Array.prototype.toString");
4042 QCOMPARE(eng.evaluate("Array()").toString(), QString());
4045 QScriptEngine eng;
4046 QCOMPARE(eng.evaluate("Array()").toString(), QString());
4050 void tst_QScriptEngine:: incDecNonObjectProperty()
4052 QScriptEngine eng;
4054 QScriptValue ret = eng.evaluate("var a; a.n++");
4055 QVERIFY(ret.isError());
4056 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [undefined] is not an object."));
4059 QScriptValue ret = eng.evaluate("var a; a.n--");
4060 QVERIFY(ret.isError());
4061 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [undefined] is not an object."));
4064 QScriptValue ret = eng.evaluate("var a = null; a.n++");
4065 QVERIFY(ret.isError());
4066 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
4069 QScriptValue ret = eng.evaluate("var a = null; a.n--");
4070 QVERIFY(ret.isError());
4071 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
4074 QScriptValue ret = eng.evaluate("var a; ++a.n");
4075 QVERIFY(ret.isError());
4076 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
4079 QScriptValue ret = eng.evaluate("var a; --a.n");
4080 QVERIFY(ret.isError());
4081 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
4084 QScriptValue ret = eng.evaluate("var a; a.n += 1");
4085 QVERIFY(ret.isError());
4086 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
4089 QScriptValue ret = eng.evaluate("var a; a.n -= 1");
4090 QVERIFY(ret.isError());
4091 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object."));
4094 QScriptValue ret = eng.evaluate("var a = 'ciao'; a.length++");
4095 QVERIFY(ret.isNumber());
4096 QCOMPARE(ret.toInt32(), 4);
4099 QScriptValue ret = eng.evaluate("var a = 'ciao'; a.length--");
4100 QVERIFY(ret.isNumber());
4101 QCOMPARE(ret.toInt32(), 4);
4104 QScriptValue ret = eng.evaluate("var a = 'ciao'; ++a.length");
4105 QVERIFY(ret.isNumber());
4106 QCOMPARE(ret.toInt32(), 5);
4109 QScriptValue ret = eng.evaluate("var a = 'ciao'; --a.length");
4110 QVERIFY(ret.isNumber());
4111 QCOMPARE(ret.toInt32(), 3);
4115 void tst_QScriptEngine::installTranslatorFunctions()
4117 QScriptEngine eng;
4118 QScriptValue global = eng.globalObject();
4119 QVERIFY(!global.property("qsTranslate").isValid());
4120 QVERIFY(!global.property("QT_TRANSLATE_NOOP").isValid());
4121 QVERIFY(!global.property("qsTr").isValid());
4122 QVERIFY(!global.property("QT_TR_NOOP").isValid());
4123 QVERIFY(!global.property("String").property("prototype").property("arg").isValid());
4125 eng.installTranslatorFunctions();
4126 QVERIFY(global.property("qsTranslate").isFunction());
4127 QVERIFY(global.property("QT_TRANSLATE_NOOP").isFunction());
4128 QVERIFY(global.property("qsTr").isFunction());
4129 QVERIFY(global.property("QT_TR_NOOP").isFunction());
4130 QVERIFY(global.property("String").property("prototype").property("arg").isFunction());
4133 QScriptValue ret = eng.evaluate("qsTr('foo')");
4134 QVERIFY(ret.isString());
4135 QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
4138 QScriptValue ret = eng.evaluate("qsTranslate('foo', 'bar')");
4139 QVERIFY(ret.isString());
4140 QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
4143 QScriptValue ret = eng.evaluate("QT_TR_NOOP('foo')");
4144 QVERIFY(ret.isString());
4145 QCOMPARE(ret.toString(), QString::fromLatin1("foo"));
4148 QScriptValue ret = eng.evaluate("QT_TRANSLATE_NOOP('foo', 'bar')");
4149 QVERIFY(ret.isString());
4150 QCOMPARE(ret.toString(), QString::fromLatin1("bar"));
4153 QScriptValue ret = eng.evaluate("'foo%0'.arg('bar')");
4154 QVERIFY(ret.isString());
4155 QCOMPARE(ret.toString(), QString::fromLatin1("foobar"));
4159 void tst_QScriptEngine::functionScopes()
4161 QScriptEngine eng;
4163 // top-level functions have only the global object in their scope
4164 QScriptValue fun = eng.evaluate("(function() {})");
4165 QVERIFY(fun.isFunction());
4166 QEXPECT_FAIL("", "Function scope proxying is not implemented", Abort);
4167 QVERIFY(fun.scope().isObject());
4168 QVERIFY(fun.scope().strictlyEquals(eng.globalObject()));
4169 QVERIFY(!eng.globalObject().scope().isValid());
4172 QScriptValue fun = eng.globalObject().property("Object");
4173 QVERIFY(fun.isFunction());
4174 // native built-in functions don't have scope
4175 QVERIFY(!fun.scope().isValid());
4178 // closure
4179 QScriptValue fun = eng.evaluate("(function(arg) { var foo = arg; return function() { return foo; }; })(123)");
4180 QVERIFY(fun.isFunction());
4182 QScriptValue ret = fun.call();
4183 QVERIFY(ret.isNumber());
4184 QCOMPARE(ret.toInt32(), 123);
4186 QScriptValue scope = fun.scope();
4187 QVERIFY(scope.isObject());
4189 QScriptValue ret = scope.property("foo");
4190 QVERIFY(ret.isNumber());
4191 QCOMPARE(ret.toInt32(), 123);
4192 QCOMPARE(scope.propertyFlags("foo"), QScriptValue::Undeletable);
4195 QScriptValue ret = scope.property("arg");
4196 QVERIFY(ret.isNumber());
4197 QCOMPARE(ret.toInt32(), 123);
4198 QCOMPARE(scope.propertyFlags("arg"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration);
4201 scope.setProperty("foo", 456);
4203 QScriptValue ret = fun.call();
4204 QVERIFY(ret.isNumber());
4205 QCOMPARE(ret.toInt32(), 456);
4208 scope = scope.scope();
4209 QVERIFY(scope.isObject());
4210 QVERIFY(scope.strictlyEquals(eng.globalObject()));
4214 static QScriptValue counter_inner(QScriptContext *ctx, QScriptEngine *)
4216 QScriptValue outerAct = ctx->callee().scope();
4217 double count = outerAct.property("count").toNumber();
4218 outerAct.setProperty("count", count+1);
4219 return count;
4222 static QScriptValue counter(QScriptContext *ctx, QScriptEngine *eng)
4224 QScriptValue act = ctx->activationObject();
4225 act.setProperty("count", ctx->argument(0).toInt32());
4226 QScriptValue result = eng->newFunction(counter_inner);
4227 result.setScope(act);
4228 return result;
4231 static QScriptValue counter_hybrid(QScriptContext *ctx, QScriptEngine *eng)
4233 QScriptValue act = ctx->activationObject();
4234 act.setProperty("count", ctx->argument(0).toInt32());
4235 return eng->evaluate("(function() { return count++; })");
4238 void tst_QScriptEngine::nativeFunctionScopes()
4240 QScriptEngine eng;
4242 QScriptValue fun = eng.newFunction(counter);
4243 QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123);
4244 QVERIFY(cnt.isFunction());
4246 QScriptValue ret = cnt.call();
4247 QVERIFY(ret.isNumber());
4248 QCOMPARE(ret.toInt32(), 123);
4252 QScriptValue fun = eng.newFunction(counter_hybrid);
4253 QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123);
4254 QVERIFY(cnt.isFunction());
4256 QScriptValue ret = cnt.call();
4257 QVERIFY(ret.isNumber());
4258 QCOMPARE(ret.toInt32(), 123);
4262 //from http://doc.trolltech.com/latest/qtscript.html#nested-functions-and-the-scope-chain
4264 QScriptEngine eng;
4265 eng.evaluate("function counter() { var count = 0; return function() { return count++; } }\n"
4266 "var c1 = counter(); var c2 = counter(); ");
4267 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
4268 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
4269 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
4270 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
4271 QVERIFY(!eng.hasUncaughtException());
4274 QScriptEngine eng;
4275 eng.globalObject().setProperty("counter", eng.newFunction(counter));
4276 eng.evaluate("var c1 = counter(); var c2 = counter(); ");
4277 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
4278 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
4279 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
4280 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
4281 QVERIFY(!eng.hasUncaughtException());
4284 QScriptEngine eng;
4285 eng.globalObject().setProperty("counter", eng.newFunction(counter_hybrid));
4286 eng.evaluate("var c1 = counter(); var c2 = counter(); ");
4287 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0"));
4288 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1"));
4289 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0"));
4290 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1"));
4291 QVERIFY(!eng.hasUncaughtException());
4295 static QScriptValue createProgram(QScriptContext *ctx, QScriptEngine *eng)
4297 QString code = ctx->argument(0).toString();
4298 QScriptProgram result(code);
4299 return qScriptValueFromValue(eng, result);
4302 void tst_QScriptEngine::evaluateProgram()
4304 QScriptEngine eng;
4307 QString code("1 + 2");
4308 QString fileName("hello.js");
4309 int lineNumber(123);
4310 QScriptProgram program(code, fileName, lineNumber);
4311 QVERIFY(!program.isNull());
4312 QCOMPARE(program.sourceCode(), code);
4313 QCOMPARE(program.fileName(), fileName);
4314 QCOMPARE(program.firstLineNumber(), lineNumber);
4316 QScriptValue expected = eng.evaluate(code);
4317 for (int x = 0; x < 10; ++x) {
4318 QScriptValue ret = eng.evaluate(program);
4319 QVERIFY(ret.equals(expected));
4322 // operator=
4323 QScriptProgram sameProgram = program;
4324 QVERIFY(sameProgram == program);
4325 QVERIFY(eng.evaluate(sameProgram).equals(expected));
4327 // copy constructor
4328 QScriptProgram sameProgram2(program);
4329 QVERIFY(sameProgram2 == program);
4330 QVERIFY(eng.evaluate(sameProgram2).equals(expected));
4332 QScriptProgram differentProgram("2 + 3");
4333 QVERIFY(differentProgram != program);
4334 QVERIFY(!eng.evaluate(differentProgram).equals(expected));
4337 // Program that accesses variable in the scope
4339 QScriptProgram program("a");
4340 QVERIFY(!program.isNull());
4342 QScriptValue ret = eng.evaluate(program);
4343 QVERIFY(ret.isError());
4344 QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: a"));
4347 QScriptValue obj = eng.newObject();
4348 obj.setProperty("a", 123);
4349 QScriptContext *ctx = eng.currentContext();
4350 ctx->pushScope(obj);
4352 QScriptValue ret = eng.evaluate(program);
4353 QVERIFY(!ret.isError());
4354 QVERIFY(ret.equals(obj.property("a")));
4357 obj.setProperty("a", QScriptValue());
4359 QScriptValue ret = eng.evaluate(program);
4360 QVERIFY(ret.isError());
4363 QScriptValue obj2 = eng.newObject();
4364 obj2.setProperty("a", 456);
4365 ctx->pushScope(obj2);
4367 QScriptValue ret = eng.evaluate(program);
4368 QVERIFY(!ret.isError());
4369 QVERIFY(ret.equals(obj2.property("a")));
4372 ctx->popScope();
4375 // Program that creates closure
4377 QScriptProgram program("(function() { var count = 0; return function() { return count++; }; })");
4378 QVERIFY(!program.isNull());
4379 QScriptValue createCounter = eng.evaluate(program);
4380 QVERIFY(createCounter.isFunction());
4381 QScriptValue counter = createCounter.call();
4382 QVERIFY(counter.isFunction());
4384 QScriptValue ret = counter.call();
4385 QVERIFY(ret.isNumber());
4387 QScriptValue counter2 = createCounter.call();
4388 QVERIFY(counter2.isFunction());
4389 QVERIFY(!counter2.equals(counter));
4391 QScriptValue ret = counter2.call();
4392 QVERIFY(ret.isNumber());
4396 // Program created in a function call, then executed later
4398 QScriptValue fun = eng.newFunction(createProgram);
4399 QScriptProgram program = qscriptvalue_cast<QScriptProgram>(
4400 fun.call(QScriptValue(), QScriptValueList() << "a + 1"));
4401 QVERIFY(!program.isNull());
4402 eng.globalObject().setProperty("a", QScriptValue());
4404 QScriptValue ret = eng.evaluate(program);
4405 QVERIFY(ret.isError());
4406 QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: a"));
4408 eng.globalObject().setProperty("a", 122);
4410 QScriptValue ret = eng.evaluate(program);
4411 QVERIFY(!ret.isError());
4412 QVERIFY(ret.isNumber());
4413 QCOMPARE(ret.toInt32(), 123);
4417 // Same program run in different engines
4419 QString code("1 + 2");
4420 QScriptProgram program(code);
4421 QVERIFY(!program.isNull());
4422 double expected = eng.evaluate(program).toNumber();
4423 for (int x = 0; x < 2; ++x) {
4424 QScriptEngine eng2;
4425 for (int y = 0; y < 2; ++y) {
4426 double ret = eng2.evaluate(program).toNumber();
4427 QCOMPARE(ret, expected);
4432 // No program
4434 QScriptProgram program;
4435 QVERIFY(program.isNull());
4436 QScriptValue ret = eng.evaluate(program);
4437 QVERIFY(!ret.isValid());
4441 static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; }
4443 void tst_QScriptEngine::qRegExpInport_data()
4445 QTest::addColumn<QRegExp>("rx");
4446 QTest::addColumn<QString>("string");
4447 QTest::addColumn<QString>("matched");
4449 QTest::newRow("normal") << QRegExp("(test|foo)") << "test _ foo _ test _ Foo";
4450 QTest::newRow("normal2") << QRegExp("(Test|Foo)") << "test _ foo _ test _ Foo";
4451 QTest::newRow("case insensitive)") << QRegExp("(test|foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo";
4452 QTest::newRow("case insensitive2)") << QRegExp("(Test|Foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo";
4453 QTest::newRow("b(a*)(b*)") << QRegExp("b(a*)(b*)", Qt::CaseInsensitive) << "aaabbBbaAabaAaababaaabbaaab";
4454 QTest::newRow("greedy") << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp2) << "aaaabaaba";
4455 // this one will fail because we do not support the QRegExp::RegExp in JSC
4456 //QTest::newRow("not_greedy") << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp) << "aaaabaaba";
4457 QTest::newRow("willcard") << QRegExp("*.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "file.txt";
4458 QTest::newRow("willcard 2") << QRegExp("a?b.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "ab.txt abb.rtc acb.txt";
4459 QTest::newRow("slash") << QRegExp("g/.*/s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string/string/string";
4460 QTest::newRow("slash2") << QRegExp("g / .* / s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string / string / string";
4461 QTest::newRow("fixed") << QRegExp("a*aa.a(ba)*a\\ba", Qt::CaseInsensitive, QRegExp::FixedString) << "aa*aa.a(ba)*a\\ba";
4462 QTest::newRow("fixed insensitive") << QRegExp("A*A", Qt::CaseInsensitive, QRegExp::FixedString) << "a*A A*a A*A a*a";
4463 QTest::newRow("fixed sensitive") << QRegExp("A*A", Qt::CaseSensitive, QRegExp::FixedString) << "a*A A*a A*A a*a";
4464 QTest::newRow("html") << QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2) << "<b>bold</b><i>italic</i><b>bold</b>";
4465 QTest::newRow("html minimal") << minimal(QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2)) << "<b>bold</b><i>italic</i><b>bold</b>";
4466 QTest::newRow("aaa") << QRegExp("a{2,5}") << "aAaAaaaaaAa";
4467 QTest::newRow("aaa minimal") << minimal(QRegExp("a{2,5}")) << "aAaAaaaaaAa";
4468 QTest::newRow("minimal") << minimal(QRegExp(".*\\} [*8]")) << "}?} ?} *";
4471 void tst_QScriptEngine::qRegExpInport()
4473 QFETCH(QRegExp, rx);
4474 QFETCH(QString, string);
4476 QScriptEngine eng;
4477 QScriptValue rexp;
4478 rexp = eng.newRegExp(rx);
4480 QCOMPARE(rexp.isValid(), true);
4481 QCOMPARE(rexp.isRegExp(), true);
4482 QVERIFY(rexp.isFunction());
4484 QScriptValue func = eng.evaluate("(function(string, regexp) { return string.match(regexp); })");
4485 QScriptValue result = func.call(QScriptValue(), QScriptValueList() << string << rexp);
4487 rx.indexIn(string);
4488 for (int i = 0; i <= rx.captureCount(); i++) {
4489 QCOMPARE(result.property(i).toString(), rx.cap(i));
4493 QTEST_MAIN(tst_QScriptEngine)
4494 #include "tst_qscriptengine.moc"