2 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
20 #include "qscriptengine.h"
21 #include "qscriptprogram.h"
22 #include "qscriptsyntaxcheckresult.h"
23 #include "qscriptvalue.h"
24 #include <QtCore/qnumeric.h>
25 #include <QtTest/qtest.h>
27 class tst_QScriptEngine
: public QObject
{
31 tst_QScriptEngine() {}
32 virtual ~tst_QScriptEngine() {}
43 void collectGarbage();
44 void reportAdditionalMemoryCost();
46 void undefinedValue();
47 void evaluateProgram();
48 void checkSyntax_data();
51 void toObjectTwoEngines();
53 void uncaughtException();
57 /* Evaluating a script that throw an unhandled exception should return an invalid value. */
58 void tst_QScriptEngine::evaluate()
61 QVERIFY2(engine
.evaluate("1+1").isValid(), "the expression should be evaluated and an valid result should be returned");
62 QVERIFY2(engine
.evaluate("ping").isValid(), "Script throwing an unhandled exception should return an exception value");
65 static QScriptValue
myFunction(QScriptContext
*, QScriptEngine
* eng
)
67 return eng
->nullValue();
70 static QScriptValue
myFunctionWithArg(QScriptContext
*, QScriptEngine
* eng
, void* arg
)
72 int* result
= reinterpret_cast<int*>(arg
);
73 return QScriptValue(eng
, *result
);
76 static QScriptValue
myFunctionThatReturns(QScriptContext
*, QScriptEngine
* eng
)
78 return QScriptValue(eng
, 42);
81 static QScriptValue
myFunctionThatReturnsWithoutEngine(QScriptContext
*, QScriptEngine
*)
83 return QScriptValue(1024);
86 static QScriptValue
myFunctionThatReturnsWrongEngine(QScriptContext
*, QScriptEngine
*, void* arg
)
88 QScriptEngine
* wrongEngine
= reinterpret_cast<QScriptEngine
*>(arg
);
89 return QScriptValue(wrongEngine
, 42);
92 void tst_QScriptEngine::newFunction()
96 QScriptValue fun
= eng
.newFunction(myFunction
);
97 QCOMPARE(fun
.isValid(), true);
98 QCOMPARE(fun
.isFunction(), true);
99 QCOMPARE(fun
.isObject(), true);
100 // QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
101 // a prototype property is automatically constructed
103 QScriptValue prot
= fun
.property("prototype", QScriptValue::ResolveLocal
);
104 QVERIFY(prot
.isObject());
105 QVERIFY(prot
.property("constructor").strictlyEquals(fun
));
106 QEXPECT_FAIL("", "JSCallbackObject::getOwnPropertyDescriptor() doesn't return correct information yet", Continue
);
107 QCOMPARE(fun
.propertyFlags("prototype"), QScriptValue::Undeletable
);
108 QEXPECT_FAIL("", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue
);
109 QCOMPARE(prot
.propertyFlags("constructor"), QScriptValue::PropertyFlags(QScriptValue::Undeletable
| QScriptValue::SkipInEnumeration
));
111 // prototype should be Function.prototype
112 QCOMPARE(fun
.prototype().isValid(), true);
113 QCOMPARE(fun
.prototype().isFunction(), true);
114 QCOMPARE(fun
.prototype().strictlyEquals(eng
.evaluate("Function.prototype")), true);
116 QCOMPARE(fun
.call().isNull(), true);
117 // QCOMPARE(fun.construct().isObject(), true);
119 // the overload that takes an extra argument
121 int expectedResult
= 42;
122 QScriptValue fun
= eng
.newFunction(myFunctionWithArg
, reinterpret_cast<void*>(&expectedResult
));
123 QVERIFY(fun
.isFunction());
124 // QCOMPARE(fun.scriptClass(), (QScriptClass*)0);
125 // a prototype property is automatically constructed
127 QScriptValue prot
= fun
.property("prototype", QScriptValue::ResolveLocal
);
128 QVERIFY(prot
.isObject());
129 QVERIFY(prot
.property("constructor").strictlyEquals(fun
));
130 QEXPECT_FAIL("", "JSCallbackObject::getOwnPropertyDescriptor() doesn't return correct information yet", Continue
);
131 QCOMPARE(fun
.propertyFlags("prototype"), QScriptValue::Undeletable
);
132 QEXPECT_FAIL("", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue
);
133 QCOMPARE(prot
.propertyFlags("constructor"), QScriptValue::PropertyFlags(QScriptValue::Undeletable
| QScriptValue::SkipInEnumeration
));
135 // prototype should be Function.prototype
136 QCOMPARE(fun
.prototype().isValid(), true);
137 QCOMPARE(fun
.prototype().isFunction(), true);
138 QCOMPARE(fun
.prototype().strictlyEquals(eng
.evaluate("Function.prototype")), true);
140 QScriptValue result
= fun
.call();
141 QCOMPARE(result
.isNumber(), true);
142 QCOMPARE(result
.toInt32(), expectedResult
);
144 // the overload that takes a prototype
146 QScriptValue proto
= eng
.newObject();
147 QScriptValue fun
= eng
.newFunction(myFunction
, proto
);
148 QCOMPARE(fun
.isValid(), true);
149 QCOMPARE(fun
.isFunction(), true);
150 QCOMPARE(fun
.isObject(), true);
151 // internal prototype should be Function.prototype
152 QCOMPARE(fun
.prototype().isValid(), true);
153 QCOMPARE(fun
.prototype().isFunction(), true);
154 QCOMPARE(fun
.prototype().strictlyEquals(eng
.evaluate("Function.prototype")), true);
155 // public prototype should be the one we passed
156 QCOMPARE(fun
.property("prototype").strictlyEquals(proto
), true);
157 QEXPECT_FAIL("", "JSCallbackObject::getOwnPropertyDescriptor() doesn't return correct information yet", Continue
);
158 QCOMPARE(fun
.propertyFlags("prototype"), QScriptValue::Undeletable
);
159 QCOMPARE(proto
.property("constructor").strictlyEquals(fun
), true);
160 QEXPECT_FAIL("", "WebKit bug: 40613 (The JSObjectSetProperty doesn't overwrite property flags)", Continue
);
161 QCOMPARE(proto
.propertyFlags("constructor"), QScriptValue::PropertyFlags(QScriptValue::Undeletable
| QScriptValue::SkipInEnumeration
));
163 QCOMPARE(fun
.call().isNull(), true);
164 // QCOMPARE(fun.construct().isObject(), true);
166 // whether the return value is correct
168 QScriptValue fun
= eng
.newFunction(myFunctionThatReturns
);
169 QCOMPARE(fun
.isValid(), true);
170 QCOMPARE(fun
.isFunction(), true);
171 QCOMPARE(fun
.isObject(), true);
173 QScriptValue result
= fun
.call();
174 QCOMPARE(result
.isNumber(), true);
175 QCOMPARE(result
.toInt32(), 42);
177 // whether the return value is assigned to the correct engine
179 QScriptValue fun
= eng
.newFunction(myFunctionThatReturnsWithoutEngine
);
180 QCOMPARE(fun
.isValid(), true);
181 QCOMPARE(fun
.isFunction(), true);
182 QCOMPARE(fun
.isObject(), true);
184 QScriptValue result
= fun
.call();
185 QCOMPARE(result
.engine(), &eng
);
186 QCOMPARE(result
.isNumber(), true);
187 QCOMPARE(result
.toInt32(), 1024);
189 // whether the return value is undefined when returning a value with wrong engine
191 QScriptEngine wrongEngine
;
193 QScriptValue fun
= eng
.newFunction(myFunctionThatReturnsWrongEngine
, reinterpret_cast<void*>(&wrongEngine
));
194 QCOMPARE(fun
.isValid(), true);
195 QCOMPARE(fun
.isFunction(), true);
196 QCOMPARE(fun
.isObject(), true);
198 QTest::ignoreMessage(QtWarningMsg
, "Value from different engine returned from native function, returning undefined value instead.");
199 QScriptValue result
= fun
.call();
200 QCOMPARE(result
.isValid(), true);
201 QCOMPARE(result
.isUndefined(), true);
205 void tst_QScriptEngine::newObject()
207 QScriptEngine engine
;
208 QScriptValue object
= engine
.newObject();
209 QVERIFY(object
.isObject());
210 QVERIFY(object
.engine() == &engine
);
211 QVERIFY(!object
.isError());
212 QVERIFY(!object
.equals(engine
.newObject()));
213 QVERIFY(!object
.strictlyEquals(engine
.newObject()));
214 QCOMPARE(object
.toString(), QString::fromAscii("[object Object]"));
217 void tst_QScriptEngine::globalObject()
219 QScriptEngine engine
;
220 QScriptValue global
= engine
.globalObject();
221 QScriptValue self
= engine
.evaluate("this");
222 QVERIFY(global
.isObject());
223 QVERIFY(engine
.globalObject().equals(engine
.evaluate("this")));
224 QVERIFY(engine
.globalObject().strictlyEquals(self
));
227 /* Test garbage collection, at least try to not crash. */
228 void tst_QScriptEngine::collectGarbage()
230 QScriptEngine engine
;
231 QScriptValue foo
= engine
.evaluate("( function foo() {return 'pong';} )");
232 QVERIFY(foo
.isFunction());
233 engine
.collectGarbage();
234 QCOMPARE(foo
.call().toString(), QString::fromAscii("pong"));
237 void tst_QScriptEngine::reportAdditionalMemoryCost()
239 // There isn't any easy way to test the responsiveness of the GC;
240 // just try to call the function a few times with various sizes.
242 for (int i
= 0; i
< 100; ++i
) {
243 eng
.reportAdditionalMemoryCost(0);
244 eng
.reportAdditionalMemoryCost(10);
245 eng
.reportAdditionalMemoryCost(1000);
246 eng
.reportAdditionalMemoryCost(10000);
247 eng
.reportAdditionalMemoryCost(100000);
248 eng
.reportAdditionalMemoryCost(1000000);
249 eng
.reportAdditionalMemoryCost(10000000);
250 eng
.reportAdditionalMemoryCost(-1);
251 eng
.reportAdditionalMemoryCost(-1000);
252 QScriptValue obj
= eng
.evaluate("new Object");
253 eng
.collectGarbage();
257 void tst_QScriptEngine::nullValue()
259 QScriptEngine engine
;
260 QScriptValue value
= engine
.nullValue();
261 QVERIFY(value
.isValid());
262 QVERIFY(value
.isNull());
265 void tst_QScriptEngine::undefinedValue()
267 QScriptEngine engine
;
268 QScriptValue value
= engine
.undefinedValue();
269 QVERIFY(value
.isValid());
270 QVERIFY(value
.isUndefined());
273 void tst_QScriptEngine::evaluateProgram()
277 QString
code("1 + 2");
278 QString
fileName("hello.js");
279 int lineNumber
= 123;
280 QScriptProgram
program(code
, fileName
, lineNumber
);
281 QVERIFY(!program
.isNull());
282 QCOMPARE(program
.sourceCode(), code
);
283 QCOMPARE(program
.fileName(), fileName
);
284 QCOMPARE(program
.firstLineNumber(), lineNumber
);
286 QScriptValue expected
= eng
.evaluate(code
);
287 for (int x
= 0; x
< 10; ++x
) {
288 QScriptValue ret
= eng
.evaluate(program
);
289 QVERIFY(ret
.equals(expected
));
293 QScriptProgram sameProgram
= program
;
294 QVERIFY(sameProgram
== program
);
295 QVERIFY(eng
.evaluate(sameProgram
).equals(expected
));
298 QScriptProgram
sameProgram2(program
);
299 QVERIFY(sameProgram2
== program
);
300 QVERIFY(eng
.evaluate(sameProgram2
).equals(expected
));
302 QScriptProgram
differentProgram("2 + 3");
303 QVERIFY(differentProgram
!= program
);
304 QVERIFY(!eng
.evaluate(differentProgram
).equals(expected
));
307 // Program that accesses variable in the scope
309 QScriptProgram
program("a");
310 QVERIFY(!program
.isNull());
312 QScriptValue ret
= eng
.evaluate(program
);
313 QVERIFY(ret
.isError());
314 QCOMPARE(ret
.toString(), QString::fromLatin1("ReferenceError: Can't find variable: a"));
317 QScriptValue ret
= eng
.evaluate(program
);
318 QVERIFY(ret
.isError());
320 eng
.evaluate("a = 456");
322 QScriptValue ret
= eng
.evaluate(program
);
323 QVERIFY(!ret
.isError());
324 QCOMPARE(ret
.toNumber(), 456.0);
328 // Program that creates closure
330 QScriptProgram
program("(function() { var count = 0; return function() { return count++; }; })");
331 QVERIFY(!program
.isNull());
332 QScriptValue createCounter
= eng
.evaluate(program
);
333 QVERIFY(createCounter
.isFunction());
334 QScriptValue counter
= createCounter
.call();
335 QVERIFY(counter
.isFunction());
337 QScriptValue ret
= counter
.call();
338 QVERIFY(ret
.isNumber());
340 QScriptValue counter2
= createCounter
.call();
341 QVERIFY(counter2
.isFunction());
342 QVERIFY(!counter2
.equals(counter
));
344 QScriptValue ret
= counter2
.call();
345 QVERIFY(ret
.isNumber());
349 // Same program run in different engines
351 QString
code("1 + 2");
352 QScriptProgram
program(code
);
353 QVERIFY(!program
.isNull());
354 double expected
= eng
.evaluate(program
).toNumber();
355 for (int x
= 0; x
< 2; ++x
) {
357 for (int y
= 0; y
< 2; ++y
) {
358 double ret
= eng2
.evaluate(program
).toNumber();
359 QCOMPARE(ret
, expected
);
366 QScriptProgram program
;
367 QVERIFY(program
.isNull());
368 QScriptValue ret
= eng
.evaluate(program
);
369 QVERIFY(!ret
.isValid());
373 void tst_QScriptEngine::checkSyntax_data()
375 QTest::addColumn
<QString
>("code");
376 QTest::addColumn
<int>("expectedState");
377 QTest::addColumn
<int>("errorLineNumber");
378 QTest::addColumn
<int>("errorColumnNumber");
379 QTest::addColumn
<QString
>("errorMessage");
382 << QString("0") << int(QScriptSyntaxCheckResult::Valid
)
384 QTest::newRow("if (")
385 << QString("if (\n") << int(QScriptSyntaxCheckResult::Intermediate
)
387 QTest::newRow("if else")
388 << QString("\nif else") << int(QScriptSyntaxCheckResult::Error
)
389 << 2 << 4 << "SyntaxError: Parse error";
390 QTest::newRow("{if}")
391 << QString("{\n{\nif\n}\n") << int(QScriptSyntaxCheckResult::Error
)
392 << 4 << 1 << "SyntaxError: Parse error";
393 QTest::newRow("foo[")
394 << QString("foo[") << int(QScriptSyntaxCheckResult::Error
)
395 << 1 << 4 << "SyntaxError: Parse error";
396 QTest::newRow("foo['bar']")
397 << QString("foo['bar']") << int(QScriptSyntaxCheckResult::Valid
)
401 << QString("/*") << int(QScriptSyntaxCheckResult::Intermediate
)
402 << 1 << 1 << "Unclosed comment at end of file";
403 QTest::newRow("/*\nMy comment")
404 << QString("/*\nMy comment") << int(QScriptSyntaxCheckResult::Intermediate
)
405 << 1 << 1 << "Unclosed comment at end of file";
406 QTest::newRow("/*\nMy comment */\nfoo = 10")
407 << QString("/*\nMy comment */\nfoo = 10") << int(QScriptSyntaxCheckResult::Valid
)
409 QTest::newRow("foo = 10 /*")
410 << QString("foo = 10 /*") << int(QScriptSyntaxCheckResult::Intermediate
)
412 QTest::newRow("foo = 10; /*")
413 << QString("foo = 10; /*") << int(QScriptSyntaxCheckResult::Intermediate
)
414 << 1 << 11 << "Expected `end of file'";
415 QTest::newRow("foo = 10 /* My comment */")
416 << QString("foo = 10 /* My comment */") << int(QScriptSyntaxCheckResult::Valid
)
420 << QString("/=/") << int(QScriptSyntaxCheckResult::Valid
) << -1 << -1 << "";
421 QTest::newRow("/=/g")
422 << QString("/=/g") << int(QScriptSyntaxCheckResult::Valid
) << -1 << -1 << "";
424 << QString("/a/") << int(QScriptSyntaxCheckResult::Valid
) << -1 << -1 << "";
425 QTest::newRow("/a/g")
426 << QString("/a/g") << int(QScriptSyntaxCheckResult::Valid
) << -1 << -1 << "";
429 void tst_QScriptEngine::checkSyntax()
431 QFETCH(QString
, code
);
432 QFETCH(int, expectedState
);
433 QFETCH(int, errorLineNumber
);
434 QFETCH(int, errorColumnNumber
);
435 QFETCH(QString
, errorMessage
);
437 QScriptSyntaxCheckResult result
= QScriptEngine::checkSyntax(code
);
441 QScriptSyntaxCheckResult copy
= result
;
442 QCOMPARE(copy
.state(), result
.state());
443 QCOMPARE(copy
.errorLineNumber(), result
.errorLineNumber());
444 QCOMPARE(copy
.errorColumnNumber(), result
.errorColumnNumber());
445 QCOMPARE(copy
.errorMessage(), result
.errorMessage());
448 QScriptSyntaxCheckResult
copy(result
);
449 QCOMPARE(copy
.state(), result
.state());
450 QCOMPARE(copy
.errorLineNumber(), result
.errorLineNumber());
451 QCOMPARE(copy
.errorColumnNumber(), result
.errorColumnNumber());
452 QCOMPARE(copy
.errorMessage(), result
.errorMessage());
455 if (expectedState
== QScriptSyntaxCheckResult::Intermediate
)
456 QEXPECT_FAIL("", "QScriptSyntaxCheckResult::state() doesn't return the Intermediate state", Abort
);
457 QCOMPARE(result
.state(), QScriptSyntaxCheckResult::State(expectedState
));
458 QCOMPARE(result
.errorLineNumber(), errorLineNumber
);
459 if (expectedState
!= QScriptSyntaxCheckResult::Valid
&& errorColumnNumber
!= 1)
460 QEXPECT_FAIL("", "QScriptSyntaxCheckResult::errorColumnNumber() doesn't return correct value", Continue
);
461 QCOMPARE(result
.errorColumnNumber(), errorColumnNumber
);
462 QCOMPARE(result
.errorMessage(), errorMessage
);
465 void tst_QScriptEngine::toObject()
468 QVERIFY(!eng
.toObject(eng
.undefinedValue()).isValid());
469 QVERIFY(!eng
.toObject(eng
.nullValue()).isValid());
470 QVERIFY(!eng
.toObject(QScriptValue()).isValid());
472 QScriptValue
falskt(false);
474 QScriptValue tmp
= eng
.toObject(falskt
);
475 QVERIFY(tmp
.isObject());
476 QVERIFY(!falskt
.isObject());
477 QVERIFY(!falskt
.engine());
478 QCOMPARE(tmp
.toNumber(), falskt
.toNumber());
481 QScriptValue
sant(true);
483 QScriptValue tmp
= eng
.toObject(sant
);
484 QVERIFY(tmp
.isObject());
485 QVERIFY(!sant
.isObject());
486 QVERIFY(!sant
.engine());
487 QCOMPARE(tmp
.toNumber(), sant
.toNumber());
490 QScriptValue
number(123.0);
492 QScriptValue tmp
= eng
.toObject(number
);
493 QVERIFY(tmp
.isObject());
494 QVERIFY(!number
.isObject());
495 QVERIFY(!number
.engine());
496 QCOMPARE(tmp
.toNumber(), number
.toNumber());
499 QScriptValue str
= QScriptValue(&eng
, QString("ciao"));
501 QScriptValue tmp
= eng
.toObject(str
);
502 QVERIFY(tmp
.isObject());
503 QVERIFY(!str
.isObject());
504 QCOMPARE(tmp
.toString(), str
.toString());
507 QScriptValue object
= eng
.evaluate("new Object");
509 QScriptValue tmp
= eng
.toObject(object
);
510 QVERIFY(tmp
.isObject());
511 QVERIFY(object
.isObject());
512 QVERIFY(tmp
.strictlyEquals(object
));
516 void tst_QScriptEngine::toObjectTwoEngines()
518 QScriptEngine engine1
;
519 QScriptEngine engine2
;
522 QScriptValue null
= engine1
.nullValue();
523 QTest::ignoreMessage(QtWarningMsg
, "QScriptEngine::toObject: cannot convert value created in a different engine");
524 QVERIFY(!engine2
.toObject(null
).isValid());
525 QVERIFY(null
.isValid());
526 QTest::ignoreMessage(QtWarningMsg
, "QScriptEngine::toObject: cannot convert value created in a different engine");
527 QVERIFY(engine2
.toObject(null
).engine() != &engine2
);
530 QScriptValue undefined
= engine1
.undefinedValue();
531 QTest::ignoreMessage(QtWarningMsg
, "QScriptEngine::toObject: cannot convert value created in a different engine");
532 QVERIFY(!engine2
.toObject(undefined
).isValid());
533 QVERIFY(undefined
.isValid());
534 QTest::ignoreMessage(QtWarningMsg
, "QScriptEngine::toObject: cannot convert value created in a different engine");
535 QVERIFY(engine2
.toObject(undefined
).engine() != &engine2
);
538 QScriptValue value
= engine1
.evaluate("1");
539 QTest::ignoreMessage(QtWarningMsg
, "QScriptEngine::toObject: cannot convert value created in a different engine");
540 QVERIFY(engine2
.toObject(value
).engine() != &engine2
);
541 QVERIFY(!value
.isObject());
544 QScriptValue string
= engine1
.evaluate("'Qt'");
545 QTest::ignoreMessage(QtWarningMsg
, "QScriptEngine::toObject: cannot convert value created in a different engine");
546 QVERIFY(engine2
.toObject(string
).engine() != &engine2
);
547 QVERIFY(!string
.isObject());
550 QScriptValue object
= engine1
.evaluate("new Object");
551 QTest::ignoreMessage(QtWarningMsg
, "QScriptEngine::toObject: cannot convert value created in a different engine");
552 QVERIFY(engine2
.toObject(object
).engine() != &engine2
);
553 QVERIFY(object
.isObject());
557 void tst_QScriptEngine::newArray()
560 QScriptValue array
= eng
.newArray();
561 QCOMPARE(array
.isValid(), true);
562 QCOMPARE(array
.isArray(), true);
563 QCOMPARE(array
.isObject(), true);
564 QVERIFY(!array
.isFunction());
565 // QCOMPARE(array.scriptClass(), (QScriptClass*)0);
567 // Prototype should be Array.prototype.
568 QCOMPARE(array
.prototype().isValid(), true);
569 QCOMPARE(array
.prototype().isArray(), true);
570 QCOMPARE(array
.prototype().strictlyEquals(eng
.evaluate("Array.prototype")), true);
572 QScriptValue arrayWithSize
= eng
.newArray(42);
573 QCOMPARE(arrayWithSize
.isValid(), true);
574 QCOMPARE(arrayWithSize
.isArray(), true);
575 QCOMPARE(arrayWithSize
.isObject(), true);
576 QCOMPARE(arrayWithSize
.property("length").toInt32(), 42);
580 QScriptValue ret
= eng
.evaluate("[].splice(0, 0, 'a')");
581 QVERIFY(ret
.isArray());
582 QCOMPARE(ret
.property("length").toInt32(), 0);
585 QScriptValue ret
= eng
.evaluate("['a'].splice(0, 1, 'b')");
586 QVERIFY(ret
.isArray());
587 QCOMPARE(ret
.property("length").toInt32(), 1);
590 QScriptValue ret
= eng
.evaluate("['a', 'b'].splice(0, 1, 'c')");
591 QVERIFY(ret
.isArray());
592 QCOMPARE(ret
.property("length").toInt32(), 1);
595 QScriptValue ret
= eng
.evaluate("['a', 'b', 'c'].splice(0, 2, 'd')");
596 QVERIFY(ret
.isArray());
597 QCOMPARE(ret
.property("length").toInt32(), 2);
600 QScriptValue ret
= eng
.evaluate("['a', 'b', 'c'].splice(1, 2, 'd', 'e', 'f')");
601 QVERIFY(ret
.isArray());
602 QCOMPARE(ret
.property("length").toInt32(), 2);
606 void tst_QScriptEngine::uncaughtException()
609 QScriptValue fun
= eng
.evaluate("(function foo () { return null; });");
610 QVERIFY(!eng
.uncaughtException().isValid());
611 QVERIFY(fun
.isFunction());
612 QScriptValue throwFun
= eng
.evaluate("( function() { throw new Error('Pong'); });");
613 QVERIFY(throwFun
.isFunction());
615 eng
.evaluate("a = 10");
616 QVERIFY(!eng
.hasUncaughtException());
617 QVERIFY(!eng
.uncaughtException().isValid());
620 eng
.evaluate("1 = 2");
621 QVERIFY(eng
.hasUncaughtException());
622 eng
.clearExceptions();
623 QVERIFY(!eng
.hasUncaughtException());
626 // Check if the call or toString functions can remove the last exception.
627 QVERIFY(throwFun
.call().isError());
628 QVERIFY(eng
.hasUncaughtException());
629 QScriptValue exception
= eng
.uncaughtException();
631 exception
.toString();
632 QVERIFY(eng
.hasUncaughtException());
633 QVERIFY(eng
.uncaughtException().strictlyEquals(exception
));
635 eng
.clearExceptions();
637 // Check if in the call function a new exception can override an existing one.
639 QVERIFY(eng
.hasUncaughtException());
640 QScriptValue exception
= eng
.uncaughtException();
642 QVERIFY(eng
.hasUncaughtException());
643 QVERIFY(!exception
.strictlyEquals(eng
.uncaughtException()));
646 eng
.evaluate("throwFun = (function foo () { throw new Error('bla') });");
647 eng
.evaluate("1;\nthrowFun();");
648 QVERIFY(eng
.hasUncaughtException());
649 QCOMPARE(eng
.uncaughtExceptionLineNumber(), 1);
650 eng
.clearExceptions();
651 QVERIFY(!eng
.hasUncaughtException());
653 for (int x
= 1; x
< 4; ++x
) {
654 QScriptValue ret
= eng
.evaluate("a = 10;\nb = 20;\n0 = 0;\n",
655 QString::fromLatin1("FooScript") + QString::number(x
),
657 QVERIFY(eng
.hasUncaughtException());
658 QCOMPARE(eng
.uncaughtExceptionLineNumber(), x
+ 2);
659 QVERIFY(eng
.uncaughtException().strictlyEquals(ret
));
660 QVERIFY(eng
.hasUncaughtException());
661 QVERIFY(eng
.uncaughtException().strictlyEquals(ret
));
662 QString backtrace
= QString::fromLatin1("<anonymous>()@FooScript") + QString::number(x
) + ":" + QString::number(x
+ 2);
663 QCOMPARE(eng
.uncaughtExceptionBacktrace().join(""), backtrace
);
664 QVERIFY(fun
.call().isNull());
665 QVERIFY(eng
.hasUncaughtException());
666 QCOMPARE(eng
.uncaughtExceptionLineNumber(), x
+ 2);
667 QVERIFY(eng
.uncaughtException().strictlyEquals(ret
));
668 eng
.clearExceptions();
669 QVERIFY(!eng
.hasUncaughtException());
670 QCOMPARE(eng
.uncaughtExceptionLineNumber(), -1);
671 QVERIFY(!eng
.uncaughtException().isValid());
672 eng
.evaluate("2 = 3");
673 QVERIFY(eng
.hasUncaughtException());
674 QScriptValue ret2
= throwFun
.call();
675 QVERIFY(ret2
.isError());
676 QVERIFY(eng
.hasUncaughtException());
677 QVERIFY(eng
.uncaughtException().strictlyEquals(ret2
));
678 QCOMPARE(eng
.uncaughtExceptionLineNumber(), 1);
679 eng
.clearExceptions();
680 QVERIFY(!eng
.hasUncaughtException());
681 eng
.evaluate("1 + 2");
682 QVERIFY(!eng
.hasUncaughtException());
686 void tst_QScriptEngine::newDate()
690 QScriptValue date
= eng
.newDate(0);
691 QCOMPARE(date
.isValid(), true);
692 QCOMPARE(date
.isDate(), true);
693 QCOMPARE(date
.isObject(), true);
694 QVERIFY(!date
.isFunction());
695 // prototype should be Date.prototype
696 QCOMPARE(date
.prototype().isValid(), true);
697 QCOMPARE(date
.prototype().isDate(), true);
698 QCOMPARE(date
.prototype().strictlyEquals(eng
.evaluate("Date.prototype")), true);
701 QDateTime dt
= QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::LocalTime
);
702 QScriptValue date
= eng
.newDate(dt
);
703 QCOMPARE(date
.isValid(), true);
704 QCOMPARE(date
.isDate(), true);
705 QCOMPARE(date
.isObject(), true);
706 // prototype should be Date.prototype
707 QCOMPARE(date
.prototype().isValid(), true);
708 QCOMPARE(date
.prototype().isDate(), true);
709 QCOMPARE(date
.prototype().strictlyEquals(eng
.evaluate("Date.prototype")), true);
711 QCOMPARE(date
.toDateTime(), dt
);
714 QDateTime dt
= QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::UTC
);
715 QScriptValue date
= eng
.newDate(dt
);
716 // toDateTime() result should be in local time
717 QCOMPARE(date
.toDateTime(), dt
.toLocalTime());
719 // Date.parse() should return NaN when it fails
721 QScriptValue ret
= eng
.evaluate("Date.parse()");
722 QVERIFY(ret
.isNumber());
723 QVERIFY(qIsNaN(ret
.toNumber()));
725 // Date.parse() should be able to parse the output of Date().toString()
727 QScriptValue ret
= eng
.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()");
728 QVERIFY(ret
.isBoolean());
729 QCOMPARE(ret
.toBoolean(), true);
733 QTEST_MAIN(tst_QScriptEngine
)
734 #include "tst_qscriptengine.moc"