]> git.saurik.com Git - apple/javascriptcore.git/blame - qt/tests/qscriptengine/tst_qscriptengine.cpp
JavaScriptCore-903.tar.gz
[apple/javascriptcore.git] / qt / tests / qscriptengine / tst_qscriptengine.cpp
CommitLineData
f9bf01c6
A
1/*
2 Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 Boston, MA 02110-1301, USA.
18*/
19
20#include "qscriptengine.h"
4e4e5a6f
A
21#include "qscriptprogram.h"
22#include "qscriptsyntaxcheckresult.h"
f9bf01c6 23#include "qscriptvalue.h"
14957cd0 24#include <QtCore/qnumeric.h>
f9bf01c6
A
25#include <QtTest/qtest.h>
26
27class tst_QScriptEngine : public QObject {
28 Q_OBJECT
29
30public:
31 tst_QScriptEngine() {}
32 virtual ~tst_QScriptEngine() {}
33
34public slots:
35 void init() {}
36 void cleanup() {}
37
38private slots:
14957cd0
A
39 void newFunction();
40 void newObject();
4e4e5a6f 41 void globalObject();
f9bf01c6
A
42 void evaluate();
43 void collectGarbage();
4e4e5a6f
A
44 void reportAdditionalMemoryCost();
45 void nullValue();
46 void undefinedValue();
47 void evaluateProgram();
48 void checkSyntax_data();
49 void checkSyntax();
14957cd0
A
50 void toObject();
51 void toObjectTwoEngines();
52 void newArray();
53 void uncaughtException();
54 void newDate();
f9bf01c6
A
55};
56
57/* Evaluating a script that throw an unhandled exception should return an invalid value. */
58void tst_QScriptEngine::evaluate()
59{
60 QScriptEngine engine;
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");
63}
64
14957cd0
A
65static QScriptValue myFunction(QScriptContext*, QScriptEngine* eng)
66{
67 return eng->nullValue();
68}
69
70static QScriptValue myFunctionWithArg(QScriptContext*, QScriptEngine* eng, void* arg)
71{
72 int* result = reinterpret_cast<int*>(arg);
73 return QScriptValue(eng, *result);
74}
75
76static QScriptValue myFunctionThatReturns(QScriptContext*, QScriptEngine* eng)
77{
78 return QScriptValue(eng, 42);
79}
80
81static QScriptValue myFunctionThatReturnsWithoutEngine(QScriptContext*, QScriptEngine*)
82{
83 return QScriptValue(1024);
84}
85
86static QScriptValue myFunctionThatReturnsWrongEngine(QScriptContext*, QScriptEngine*, void* arg)
87{
88 QScriptEngine* wrongEngine = reinterpret_cast<QScriptEngine*>(arg);
89 return QScriptValue(wrongEngine, 42);
90}
91
92void tst_QScriptEngine::newFunction()
93{
94 QScriptEngine eng;
95 {
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
102 {
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));
110 }
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);
115
116 QCOMPARE(fun.call().isNull(), true);
117 // QCOMPARE(fun.construct().isObject(), true);
118 }
119 // the overload that takes an extra argument
120 {
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
126 {
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));
134 }
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);
139
140 QScriptValue result = fun.call();
141 QCOMPARE(result.isNumber(), true);
142 QCOMPARE(result.toInt32(), expectedResult);
143 }
144 // the overload that takes a prototype
145 {
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));
162
163 QCOMPARE(fun.call().isNull(), true);
164 // QCOMPARE(fun.construct().isObject(), true);
165 }
166 // whether the return value is correct
167 {
168 QScriptValue fun = eng.newFunction(myFunctionThatReturns);
169 QCOMPARE(fun.isValid(), true);
170 QCOMPARE(fun.isFunction(), true);
171 QCOMPARE(fun.isObject(), true);
172
173 QScriptValue result = fun.call();
174 QCOMPARE(result.isNumber(), true);
175 QCOMPARE(result.toInt32(), 42);
176 }
177 // whether the return value is assigned to the correct engine
178 {
179 QScriptValue fun = eng.newFunction(myFunctionThatReturnsWithoutEngine);
180 QCOMPARE(fun.isValid(), true);
181 QCOMPARE(fun.isFunction(), true);
182 QCOMPARE(fun.isObject(), true);
183
184 QScriptValue result = fun.call();
185 QCOMPARE(result.engine(), &eng);
186 QCOMPARE(result.isNumber(), true);
187 QCOMPARE(result.toInt32(), 1024);
188 }
189 // whether the return value is undefined when returning a value with wrong engine
190 {
191 QScriptEngine wrongEngine;
192
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);
197
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);
202 }
203}
204
205void tst_QScriptEngine::newObject()
206{
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]"));
215}
216
4e4e5a6f
A
217void tst_QScriptEngine::globalObject()
218{
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")));
4e4e5a6f
A
224 QVERIFY(engine.globalObject().strictlyEquals(self));
225}
226
f9bf01c6
A
227/* Test garbage collection, at least try to not crash. */
228void tst_QScriptEngine::collectGarbage()
229{
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"));
235}
4e4e5a6f
A
236
237void tst_QScriptEngine::reportAdditionalMemoryCost()
238{
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.
241 QScriptEngine eng;
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();
254 }
255}
256
257void tst_QScriptEngine::nullValue()
258{
259 QScriptEngine engine;
260 QScriptValue value = engine.nullValue();
261 QVERIFY(value.isValid());
262 QVERIFY(value.isNull());
263}
264
265void tst_QScriptEngine::undefinedValue()
266{
267 QScriptEngine engine;
268 QScriptValue value = engine.undefinedValue();
269 QVERIFY(value.isValid());
270 QVERIFY(value.isUndefined());
271}
272
273void tst_QScriptEngine::evaluateProgram()
274{
275 QScriptEngine eng;
276 {
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);
285
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));
290 }
291
292 // operator=
293 QScriptProgram sameProgram = program;
294 QVERIFY(sameProgram == program);
295 QVERIFY(eng.evaluate(sameProgram).equals(expected));
296
297 // copy constructor
298 QScriptProgram sameProgram2(program);
299 QVERIFY(sameProgram2 == program);
300 QVERIFY(eng.evaluate(sameProgram2).equals(expected));
301
302 QScriptProgram differentProgram("2 + 3");
303 QVERIFY(differentProgram != program);
304 QVERIFY(!eng.evaluate(differentProgram).equals(expected));
305 }
306
307 // Program that accesses variable in the scope
308 {
309 QScriptProgram program("a");
310 QVERIFY(!program.isNull());
311 {
312 QScriptValue ret = eng.evaluate(program);
313 QVERIFY(ret.isError());
314 QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: a"));
315 }
316 {
317 QScriptValue ret = eng.evaluate(program);
318 QVERIFY(ret.isError());
319 }
320 eng.evaluate("a = 456");
321 {
322 QScriptValue ret = eng.evaluate(program);
323 QVERIFY(!ret.isError());
324 QCOMPARE(ret.toNumber(), 456.0);
325 }
326 }
327
328 // Program that creates closure
329 {
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());
336 {
337 QScriptValue ret = counter.call();
338 QVERIFY(ret.isNumber());
339 }
340 QScriptValue counter2 = createCounter.call();
341 QVERIFY(counter2.isFunction());
342 QVERIFY(!counter2.equals(counter));
343 {
344 QScriptValue ret = counter2.call();
345 QVERIFY(ret.isNumber());
346 }
347 }
348
349 // Same program run in different engines
350 {
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) {
356 QScriptEngine eng2;
357 for (int y = 0; y < 2; ++y) {
358 double ret = eng2.evaluate(program).toNumber();
359 QCOMPARE(ret, expected);
360 }
361 }
362 }
363
364 // No program
365 {
366 QScriptProgram program;
367 QVERIFY(program.isNull());
368 QScriptValue ret = eng.evaluate(program);
369 QVERIFY(!ret.isValid());
370 }
371}
372
373void tst_QScriptEngine::checkSyntax_data()
374{
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");
380
381 QTest::newRow("0")
382 << QString("0") << int(QScriptSyntaxCheckResult::Valid)
383 << -1 << -1 << "";
384 QTest::newRow("if (")
385 << QString("if (\n") << int(QScriptSyntaxCheckResult::Intermediate)
386 << 1 << 4 << "";
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)
398 << -1 << -1 << "";
399
400 QTest::newRow("/*")
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)
408 << -1 << -1 << "";
409 QTest::newRow("foo = 10 /*")
410 << QString("foo = 10 /*") << int(QScriptSyntaxCheckResult::Intermediate)
411 << -1 << -1 << "";
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)
417 << -1 << -1 << "";
418
419 QTest::newRow("/=/")
420 << QString("/=/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
421 QTest::newRow("/=/g")
422 << QString("/=/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
423 QTest::newRow("/a/")
424 << QString("/a/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
425 QTest::newRow("/a/g")
426 << QString("/a/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
427}
428
429void tst_QScriptEngine::checkSyntax()
430{
431 QFETCH(QString, code);
432 QFETCH(int, expectedState);
433 QFETCH(int, errorLineNumber);
434 QFETCH(int, errorColumnNumber);
435 QFETCH(QString, errorMessage);
436
437 QScriptSyntaxCheckResult result = QScriptEngine::checkSyntax(code);
438
439 // assignment
440 {
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());
446 }
447 {
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());
453 }
454
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);
463}
464
14957cd0
A
465void tst_QScriptEngine::toObject()
466{
467 QScriptEngine eng;
468 QVERIFY(!eng.toObject(eng.undefinedValue()).isValid());
469 QVERIFY(!eng.toObject(eng.nullValue()).isValid());
470 QVERIFY(!eng.toObject(QScriptValue()).isValid());
471
472 QScriptValue falskt(false);
473 {
474 QScriptValue tmp = eng.toObject(falskt);
475 QVERIFY(tmp.isObject());
476 QVERIFY(!falskt.isObject());
477 QVERIFY(!falskt.engine());
478 QCOMPARE(tmp.toNumber(), falskt.toNumber());
479 }
480
481 QScriptValue sant(true);
482 {
483 QScriptValue tmp = eng.toObject(sant);
484 QVERIFY(tmp.isObject());
485 QVERIFY(!sant.isObject());
486 QVERIFY(!sant.engine());
487 QCOMPARE(tmp.toNumber(), sant.toNumber());
488 }
489
490 QScriptValue number(123.0);
491 {
492 QScriptValue tmp = eng.toObject(number);
493 QVERIFY(tmp.isObject());
494 QVERIFY(!number.isObject());
495 QVERIFY(!number.engine());
496 QCOMPARE(tmp.toNumber(), number.toNumber());
497 }
498
499 QScriptValue str = QScriptValue(&eng, QString("ciao"));
500 {
501 QScriptValue tmp = eng.toObject(str);
502 QVERIFY(tmp.isObject());
503 QVERIFY(!str.isObject());
504 QCOMPARE(tmp.toString(), str.toString());
505 }
506
507 QScriptValue object = eng.evaluate("new Object");
508 {
509 QScriptValue tmp = eng.toObject(object);
510 QVERIFY(tmp.isObject());
511 QVERIFY(object.isObject());
512 QVERIFY(tmp.strictlyEquals(object));
513 }
514}
515
516void tst_QScriptEngine::toObjectTwoEngines()
517{
518 QScriptEngine engine1;
519 QScriptEngine engine2;
520
521 {
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);
528 }
529 {
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);
536 }
537 {
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());
542 }
543 {
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());
548 }
549 {
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());
554 }
555}
556
557void tst_QScriptEngine::newArray()
558{
559 QScriptEngine eng;
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);
566
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);
571
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);
577
578 // task 218092
579 {
580 QScriptValue ret = eng.evaluate("[].splice(0, 0, 'a')");
581 QVERIFY(ret.isArray());
582 QCOMPARE(ret.property("length").toInt32(), 0);
583 }
584 {
585 QScriptValue ret = eng.evaluate("['a'].splice(0, 1, 'b')");
586 QVERIFY(ret.isArray());
587 QCOMPARE(ret.property("length").toInt32(), 1);
588 }
589 {
590 QScriptValue ret = eng.evaluate("['a', 'b'].splice(0, 1, 'c')");
591 QVERIFY(ret.isArray());
592 QCOMPARE(ret.property("length").toInt32(), 1);
593 }
594 {
595 QScriptValue ret = eng.evaluate("['a', 'b', 'c'].splice(0, 2, 'd')");
596 QVERIFY(ret.isArray());
597 QCOMPARE(ret.property("length").toInt32(), 2);
598 }
599 {
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);
603 }
604}
605
606void tst_QScriptEngine::uncaughtException()
607{
608 QScriptEngine eng;
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());
614 {
615 eng.evaluate("a = 10");
616 QVERIFY(!eng.hasUncaughtException());
617 QVERIFY(!eng.uncaughtException().isValid());
618 }
619 {
620 eng.evaluate("1 = 2");
621 QVERIFY(eng.hasUncaughtException());
622 eng.clearExceptions();
623 QVERIFY(!eng.hasUncaughtException());
624 }
625 {
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();
630 fun.call();
631 exception.toString();
632 QVERIFY(eng.hasUncaughtException());
633 QVERIFY(eng.uncaughtException().strictlyEquals(exception));
634 }
635 eng.clearExceptions();
636 {
637 // Check if in the call function a new exception can override an existing one.
638 throwFun.call();
639 QVERIFY(eng.hasUncaughtException());
640 QScriptValue exception = eng.uncaughtException();
641 throwFun.call();
642 QVERIFY(eng.hasUncaughtException());
643 QVERIFY(!exception.strictlyEquals(eng.uncaughtException()));
644 }
645 {
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());
652 }
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),
656 /* lineNumber */ 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());
683 }
684}
685
686void tst_QScriptEngine::newDate()
687{
688 QScriptEngine eng;
689 {
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);
699 }
700 {
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);
710
711 QCOMPARE(date.toDateTime(), dt);
712 }
713 {
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());
718 }
719 // Date.parse() should return NaN when it fails
720 {
721 QScriptValue ret = eng.evaluate("Date.parse()");
722 QVERIFY(ret.isNumber());
723 QVERIFY(qIsNaN(ret.toNumber()));
724 }
725 // Date.parse() should be able to parse the output of Date().toString()
726 {
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);
730 }
731}
4e4e5a6f 732
f9bf01c6
A
733QTEST_MAIN(tst_QScriptEngine)
734#include "tst_qscriptengine.moc"