1 /****************************************************************************
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
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
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.
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>
54 Q_DECLARE_METATYPE(QList
<int>)
55 Q_DECLARE_METATYPE(QObjectList
)
56 Q_DECLARE_METATYPE(QScriptProgram
)
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)
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()
73 memset(buf
, 0, sizeof(buf
));
76 static void collectGarbage_helper(QScriptEngine
&eng
)
82 class tst_QScriptEngine
: public QObject
88 virtual ~tst_QScriptEngine();
91 void constructWithParent();
92 void currentContext();
93 void pushPopContext();
94 void getSetDefaultPrototype();
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();
111 void canEvaluate_data();
113 void evaluate_data();
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();
128 void numberParsing_data();
129 void numberParsing();
130 void automaticSemicolonInsertion();
131 void abortEvaluation();
133 void printFunctionWithCustomHandler();
134 void printThrowsException();
135 void errorConstructors();
136 void argumentsProperty();
138 void forInStatement();
139 void functionExpression();
140 void stringObjects();
141 void getterSetterThisObject();
142 void continueInSwitch();
143 void readOnlyPrototypeProperty();
145 void reservedWords_data();
146 void reservedWords();
147 void futureReservedWords_data();
148 void futureReservedWords();
149 void throwInsideWithStatement();
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
;
175 QScriptEngine
*engine
= new QScriptEngine(&obj
);
181 void tst_QScriptEngine::currentContext()
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()
201 QScriptContext
*globalCtx
= eng
.currentContext();
202 QScriptContext
*ctx
= eng
.pushContext();
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();
217 QCOMPARE(ctx2
->parentContext(), ctx
);
218 QVERIFY(!ctx2
->activationObject().strictlyEquals(ctx
->activationObject()));
219 QVERIFY(!ctx2
->argumentsObject().strictlyEquals(ctx
->argumentsObject()));
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()
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()
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()
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);
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);
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()
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()
481 for (int x
= 0; x
< 2; ++x
) {
484 rexp
= eng
.newRegExp("foo", "bar");
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()
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);
603 void tst_QScriptEngine::newQObject()
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);
629 QPointer
<QObject
> ptr
= new QObject();
632 QScriptValue v
= eng
.newQObject(ptr
, QScriptEngine::ScriptOwnership
);
634 eng
.evaluate("gc()");
636 QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue
);
640 QPointer
<QObject
> ptr
= new QObject();
643 QScriptValue v
= eng
.newQObject(ptr
, QScriptEngine::QtOwnership
);
645 QObject
*before
= ptr
;
646 eng
.evaluate("gc()");
647 QVERIFY(ptr
== before
);
651 QObject
*parent
= new QObject();
652 QObject
*child
= new QObject(parent
);
653 QScriptValue v
= eng
.newQObject(child
, QScriptEngine::QtOwnership
);
654 QCOMPARE(v
.toQObject(), child
);
656 QCOMPARE(v
.toQObject(), (QObject
*)0);
659 QPointer
<QObject
> ptr
= new QObject();
662 QScriptValue v
= eng
.newQObject(ptr
, QScriptEngine::AutoOwnership
);
664 eng
.evaluate("gc()");
665 // no parent, so it should be like ScriptOwnership
667 QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue
);
671 QObject
*parent
= new QObject();
672 QPointer
<QObject
> child
= new QObject(parent
);
675 QScriptValue v
= eng
.newQObject(child
, QScriptEngine::AutoOwnership
);
677 eng
.evaluate("gc()");
678 // has parent, so it should be like QtOwnership
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
) {
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);
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());
777 Q_SCRIPT_DECLARE_QMETAOBJECT(QObject
, QObject
*)
778 Q_SCRIPT_DECLARE_QMETAOBJECT(QWidget
, QWidget
*)
781 static QScriptValue
myConstructor(QScriptContext
*ctx
, QScriptEngine
*eng
)
784 if (ctx
->isCalledAsConstructor()) {
785 obj
= ctx
->thisObject();
787 obj
= eng
->newObject();
788 obj
.setPrototype(ctx
->callee().property("prototype"));
790 obj
.setProperty("isCalledAsConstructor", QScriptValue(eng
, ctx
->isCalledAsConstructor()));
794 void tst_QScriptEngine::newQMetaObject()
798 QScriptValue qclass
= eng
.newQMetaObject
<QObject
>();
799 QScriptValue qclass2
= eng
.newQMetaObject
<QWidget
>();
801 QScriptValue qclass
= qScriptValueFromQMetaObject
<QObject
>(&eng
);
802 QScriptValue qclass2
= qScriptValueFromQMetaObject
<QWidget
>(&eng
);
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
;
832 QScriptValue instance3
= qclass
.construct(args
);
833 QCOMPARE(instance3
.isQObject(), true);
834 QCOMPARE(instance3
.toQObject()->parent(), instance
.toQObject());
835 QVERIFY(instance3
.instanceOf(qclass
));
838 QPointer
<QObject
> qpointer1
= instance
.toQObject();
839 QPointer
<QObject
> qpointer2
= instance2
.toQObject();
840 QPointer
<QObject
> qpointer3
= instance3
.toQObject();
846 // verify that AutoOwnership is in effect
847 instance
= QScriptValue();
848 collectGarbage_helper(eng
);
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
));
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
);
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()
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()
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
);
1073 QSet
<QString
> expectedNames
;
1081 << "encodeURIComponent"
1098 << "decodeURIComponent"
1112 QSet
<QString
> actualNames
;
1114 QScriptValueIterator
it(global
);
1115 while (it
.hasNext()) {
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
) {
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
);
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");
1357 << QString("0") << int(QScriptSyntaxCheckResult::Valid
)
1359 QTest::newRow("if (")
1360 << QString("if (\n") << int(QScriptSyntaxCheckResult::Intermediate
)
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
)
1368 QTest::newRow("foo['bar']")
1369 << QString("foo['bar']") << int(QScriptSyntaxCheckResult::Valid
)
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
)
1381 QTest::newRow("foo = 10 /*")
1382 << QString("foo = 10 /*") << int(QScriptSyntaxCheckResult::Intermediate
)
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
)
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
);
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
);
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"
1494 " var b=\";\n" // here's the error
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"
1508 " var b=\";\n" // here's the error
1511 << 10 << true << 15;
1512 QTest::newRow("functionThatDoesntExist()")
1513 << QString(";\n;\n;\nfunctionThatDoesntExist()")
1515 QTest::newRow("for (var p in this) { continue labelThatDoesntExist; }")
1516 << QString("for (var p in this) {\ncontinue labelThatDoesntExist; }")
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
);
1539 if (lineNumber
!= -1)
1540 ret
= eng
.evaluate(code
, /*fileName =*/QString(), lineNumber
);
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
)));
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"));
1564 void tst_QScriptEngine::nestedEvaluate()
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()
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."));
1661 Foo() : x(-1), y(-1) { }
1664 Q_DECLARE_METATYPE(Foo
)
1665 Q_DECLARE_METATYPE(Foo
*)
1667 void tst_QScriptEngine::getSetDefaultPrototype()
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
));
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()
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"));
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
);
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
);
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
);
1885 QScriptValue v
= qScriptValueFromValue(&eng
, &foo
);
1886 Foo
*pfoo
= qscriptvalue_cast
<Foo
*>(v
);
1887 QCOMPARE(pfoo
, &foo
);
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
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
);
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
);
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
;
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
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"));
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
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
);
2145 eng
.globalObject().setProperty("__import__", eng
.newFunction(__import__
));
2146 for (int x
= 0; x
< 2; ++x
) {
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
)
2169 return ctx
->callee().call();
2172 static QScriptValue
recurse2(QScriptContext
*ctx
, QScriptEngine
*eng
)
2175 return ctx
->callee().construct();
2178 void tst_QScriptEngine::infiniteRecursion()
2180 const QString stackOverflowError
= QString::fromLatin1("RangeError: Maximum call stack size exceeded.");
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
);
2207 struct Baz
: public Bar
{
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
2224 Baz
*toBaz(Bar
*b
) { return reinterpret_cast<Baz
*>(b
); }
2227 void tst_QScriptEngine::castWithPrototypeChain()
2232 QScriptValue barProto
= qScriptValueFromValue(&eng
, &bar
);
2233 QScriptValue bazProto
= qScriptValueFromValue(&eng
, &baz
);
2234 eng
.setDefaultPrototype(qMetaTypeId
<Bar
*>(), barProto
);
2235 eng
.setDefaultPrototype(qMetaTypeId
<Baz
*>(), bazProto
);
2240 QScriptValue baz2Value
= qScriptValueFromValue(&eng
, &baz2
);
2242 Baz
*pbaz
= qscriptvalue_cast
<Baz
*>(baz2Value
);
2244 QCOMPARE(pbaz
->b
, baz2
.b
);
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
);
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
);
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
);
2283 // should not work anymore
2284 Bar
*pbar
= qscriptvalue_cast
<Bar
*>(baz2Value
);
2288 bazProto
.setPrototype(eng
.newQObject(this));
2290 Baz
*pbaz
= qscriptvalue_cast
<Baz
*>(baz2Value
);
2292 // should not work now either
2293 Bar
*pbar
= qscriptvalue_cast
<Bar
*>(baz2Value
);
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
);
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
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()
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()
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();
2364 (void)eng
.newQObject(ptr
, QScriptEngine::ScriptOwnership
);
2365 collectGarbage_helper(eng
);
2369 void tst_QScriptEngine::gcWithNestedDataStructure()
2373 "function makeList(size)"
2377 " for (var i = 0; i < size; ++i) {"
2378 " l.data = i + \"\";"
2379 " l.next = { }; l = l.next;"
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
) {
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
2406 bool event(QEvent
*e
) {
2407 received
|= (e
->type() == QEvent::User
+ 1);
2408 return QObject::event(e
);
2414 void tst_QScriptEngine::processEventsWhileRunning()
2416 for (int x
= 0; x
< 2; ++x
) {
2421 QString script
= QString::fromLatin1(
2422 "var end = Number(new Date()) + 2000;"
2424 "while (Number(new Date()) < end) {"
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
);
2446 class EventReceiver2
: public QObject
2449 EventReceiver2(QScriptEngine
*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()
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"
2487 " throw new Error('blah');\n"
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";
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
);
2523 while (it
.hasNext()) {
2525 QScriptValue obj
= it
.value();
2526 QScriptValue frame
= obj
.property("frame");
2528 QCOMPARE(obj
.property("fileName").toString(), fileName
);
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();
2537 QCOMPARE(line
, 3 + counter
);
2539 QVERIFY(frame
.strictlyEquals(eng
.globalObject()));
2540 QVERIFY(obj
.property("functionName").toString().isEmpty());
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"
2563 " throw 'just a string';\n"
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
);
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()
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
2817 enum AbortionResult
{
2823 EventReceiver3(QScriptEngine
*eng
) {
2828 bool event(QEvent
*e
) {
2829 if (e
->type() == QEvent::User
+ 1) {
2830 switch (resultType
) {
2832 engine
->abortEvaluation();
2835 engine
->abortEvaluation(QScriptValue(engine
, QString::fromLatin1("Aborted")));
2838 engine
->abortEvaluation(engine
->currentContext()->throwError("AbortedWithError"));
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()
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());
2881 case EventReceiver3::String
:
2882 QVERIFY(!eng
.hasUncaughtException());
2883 QVERIFY(ret
.isString());
2884 QCOMPARE(ret
.toString(), QString::fromLatin1("Aborted"));
2886 case EventReceiver3::Error
:
2887 QVERIFY(eng
.hasUncaughtException());
2888 QVERIFY(ret
.isError());
2889 QCOMPARE(ret
.toString(), QString::fromLatin1("Error: AbortedWithError"));
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(
2901 " (function() { while (1) { } })();\n"
2906 switch (receiver
.resultType
) {
2907 case EventReceiver3::None
:
2908 QVERIFY(!eng
.hasUncaughtException());
2909 QVERIFY(!ret
.isValid());
2911 case EventReceiver3::String
:
2912 QVERIFY(!eng
.hasUncaughtException());
2913 QVERIFY(ret
.isString());
2914 QCOMPARE(ret
.toString(), QString::fromLatin1("Aborted"));
2916 case EventReceiver3::Error
:
2917 QVERIFY(eng
.hasUncaughtException());
2918 QVERIFY(ret
.isError());
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
2939 EventReceiver4(QScriptEngine
*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
;
2955 void tst_QScriptEngine::isEvaluating()
2959 QVERIFY(!eng
.isEvaluating());
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;"
2983 "while (Number(new Date()) < end) {"
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()
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
;
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()
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()
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'));
3038 code
+= QLatin1String("throw ");
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
));
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()
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());
3077 eng
.evaluate("o = { arguments: 123 }");
3078 QScriptValue ret
= eng
.evaluate("with (o) { arguments; }");
3079 QVERIFY(ret
.isNumber());
3080 QCOMPARE(ret
.toInt32(), 123);
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());
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()
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()
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"));
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()
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"
3342 " function baz() { return 'baz'; }\n"
3343 " return (arg == 'bar') ? bar : baz;\n"
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()
3369 QString
str("ciao");
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
));
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());
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();
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"));
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()
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()));
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"));
3518 eng
.evaluate("o = {}");
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"));
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
3536 eng
.evaluate("o = {}; p = {}; o.__proto__ = p");
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"));
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
3555 QScriptContext
*ctx
= eng
.pushContext();
3557 QScriptValue act
= ctx
->activationObject();
3558 act
.setProperty("act", act
);
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"));
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"));
3576 void tst_QScriptEngine::continueInSwitch()
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"
3588 " case 1: ++j; continue;\n"
3589 " case 100: ++j; continue;\n"
3590 " case 1000: ++j; continue;\n"
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"
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"
3606 QVERIFY(ret
.isNumber());
3607 QCOMPARE(ret
.toInt32(), 3);
3609 // switch - for - continue
3611 QScriptValue ret
= eng
.evaluate("j = 123; switch (j) {\n"
3613 " for (i = 0; i < 100000; ++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"
3631 " case 1: ++j; continue;\n"
3635 QVERIFY(ret
.isNumber());
3636 QCOMPARE(ret
.toInt32(), 1);
3638 // switch - for - switch - continue
3640 QScriptValue ret
= eng
.evaluate("j = 123; switch (j) {\n"
3642 " for (i = 0; i < 100000; ++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
);
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()
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
);
3772 QScriptValue ret
= eng
.evaluate(word
+ " = 123");
3773 QVERIFY(ret
.isError());
3774 QString str
= ret
.toString();
3775 QVERIFY(str
.startsWith("SyntaxError") || str
.startsWith("ReferenceError"));
3779 QScriptValue ret
= eng
.evaluate("var " + word
+ " = 123");
3780 QVERIFY(ret
.isError());
3781 QVERIFY(ret
.toString().startsWith("SyntaxError"));
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"));
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
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
);
3849 QScriptValue ret
= eng
.evaluate(word
+ " = 123");
3850 QCOMPARE(!ret
.isError(), allowed
);
3854 QScriptValue ret
= eng
.evaluate("var " + word
+ " = 123");
3855 QCOMPARE(!ret
.isError(), allowed
);
3858 // this should probably be allowed (see task 162567)
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)
3867 QScriptValue ret
= eng
.evaluate("o = { " + word
+ ": 123 }");
3868 QCOMPARE(!ret
.isError(), allowed
);
3872 void tst_QScriptEngine::throwInsideWithStatement()
3877 QScriptValue ret
= eng
.evaluate(
3879 " o = { bad : \"bug\" };"
3886 QVERIFY(ret
.isError());
3887 QCOMPARE(ret
.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bad"));
3890 QScriptValue ret
= eng
.evaluate(
3892 " o = { bad : \"bug\" };"
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\" };"
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\" };"
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
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);
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
);
3957 QCOMPARE(eng
->agent(), (QScriptEngineAgent
*)0);
3958 eng
->evaluate("(function(){ return 123; })()");
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()
3976 QScriptString s1
= eng1
.toStringHandle("foo");
3977 QScriptString s2
= eng2
.toStringHandle("foo");
3983 eng1
.setProcessEventsInterval(123);
3984 QCOMPARE(eng2
.processEventsInterval(), -1);
3985 eng2
.setProcessEventsInterval(456);
3986 QCOMPARE(eng1
.processEventsInterval(), 123);
3991 qScriptRegisterMetaType
<Foo
>(&eng1
, fooToScriptValue
, fooFromScriptValue
);
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
));
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
4040 QCOMPARE(eng
.evaluate("Array()").toString(), QString());
4041 eng
.evaluate("Array.prototype.toString");
4042 QCOMPARE(eng
.evaluate("Array()").toString(), QString());
4046 QCOMPARE(eng
.evaluate("Array()").toString(), QString());
4050 void tst_QScriptEngine:: incDecNonObjectProperty()
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()
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()
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());
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);
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
);
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()
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
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());
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());
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()
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
));
4323 QScriptProgram sameProgram
= program
;
4324 QVERIFY(sameProgram
== program
);
4325 QVERIFY(eng
.evaluate(sameProgram
).equals(expected
));
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")));
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
) {
4425 for (int y
= 0; y
< 2; ++y
) {
4426 double ret
= eng2
.evaluate(program
).toNumber();
4427 QCOMPARE(ret
, expected
);
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
);
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
);
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"