1 /****************************************************************************
3 ** Copyright (C) 2011 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include <QtDeclarative/qjsvalue.h>
44 #include <QtDeclarative/qjsengine.h>
47 Q_DECLARE_METATYPE(QJSValue)
51 class tst_QJSEngine : public QObject
57 virtual ~tst_QJSEngine();
65 #if 0 // No defaultPrototype for now
66 void defaultPrototype();
67 void setDefaultPrototype();
72 void evaluateProgram_data();
73 void evaluateProgram();
75 #if 0 // no connections for now
76 void connectAndDisconnect();
79 void hasUncaughtException();
80 #if 0 // no is Evaluating for now
88 #if 0 // No ScriptClass
89 void newObjectWithScriptClass();
91 #if 0 // no qmetaobject
92 void newQMetaObject();
95 #if 0 // no native functions for now
99 void newRegExpFromString();
102 void undefinedValue();
103 void collectGarbage();
104 #if 0 // No extensions
105 void availableExtensions();
106 void importedExtensions();
109 void currentContext();
110 void pushAndPopContext();
112 void toObject_data();
114 #if 0 // no stringhandle
115 void toStringHandle();
117 void castValueToQreal();
118 #if 0 // no native functions for now
121 #if 0 // no translations
122 void installTranslatorFunctions();
123 void translation_data();
126 #if 0 // no declarative class
127 void readScopeProperty_data();
128 void readScopeProperty();
131 void evaluateInNewContext();
132 void evaluateInNewContextWithScope();
134 #if 0 // no pushScope
135 void evaluateBindingExpression();
139 void defineStandardTestValues();
143 m_engine = new QJSEngine;
149 tst_QJSEngine::tst_QJSEngine()
154 tst_QJSEngine::~tst_QJSEngine()
159 void tst_QJSEngine::init()
163 void tst_QJSEngine::cleanup()
167 void tst_QJSEngine::constructor()
171 (void)engine.parent();
175 #if 0 // No defaultPrototype for now
176 void tst_QJSEngine::defaultPrototype()
179 int type = qMetaTypeId<int>();
180 m_engine->setDefaultPrototype(type, m_engine->newObject());
182 m_engine->defaultPrototype(type);
186 void tst_QJSEngine::setDefaultPrototype()
189 int type = qMetaTypeId<int>();
190 QJSValue proto = m_engine->newObject();
192 m_engine->setDefaultPrototype(type, proto);
198 void tst_QJSEngine::evaluate_data()
200 QTest::addColumn<QString>("code");
201 QTest::newRow("empty script") << QString::fromLatin1("");
202 QTest::newRow("number literal") << QString::fromLatin1("123");
203 QTest::newRow("string literal") << QString::fromLatin1("'ciao'");
204 QTest::newRow("regexp literal") << QString::fromLatin1("/foo/gim");
205 QTest::newRow("null literal") << QString::fromLatin1("null");
206 QTest::newRow("undefined literal") << QString::fromLatin1("undefined");
207 QTest::newRow("null literal") << QString::fromLatin1("null");
208 QTest::newRow("empty object literal") << QString::fromLatin1("{}");
209 QTest::newRow("this") << QString::fromLatin1("this");
210 QTest::newRow("object literal with one property") << QString::fromLatin1("{ foo: 123 }");
211 QTest::newRow("object literal with two properties") << QString::fromLatin1("{ foo: 123, bar: 456 }");
212 QTest::newRow("object literal with many properties") << QString::fromLatin1("{ a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10 }");
213 QTest::newRow("empty array literal") << QString::fromLatin1("[]");
214 QTest::newRow("array literal with one element") << QString::fromLatin1("[1]");
215 QTest::newRow("array literal with two elements") << QString::fromLatin1("[1,2]");
216 QTest::newRow("array literal with many elements") << QString::fromLatin1("[1,2,3,4,5,6,7,8,9,10,9,8,7,6,5,4,3,2,1]");
217 QTest::newRow("empty function definition") << QString::fromLatin1("function foo() { }");
218 QTest::newRow("function definition") << QString::fromLatin1("function foo() { return 123; }");
219 QTest::newRow("for loop with empty body (1000 iterations)") << QString::fromLatin1("for (i = 0; i < 1000; ++i) {}");
220 QTest::newRow("for loop with empty body (10000 iterations)") << QString::fromLatin1("for (i = 0; i < 10000; ++i) {}");
221 QTest::newRow("for loop with empty body (100000 iterations)") << QString::fromLatin1("for (i = 0; i < 100000; ++i) {}");
222 QTest::newRow("for loop with empty body (1000000 iterations)") << QString::fromLatin1("for (i = 0; i < 1000000; ++i) {}");
223 QTest::newRow("for loop (1000 iterations)") << QString::fromLatin1("j = 0; for (i = 0; i < 1000; ++i) { j += i; }; j");
224 QTest::newRow("for loop (10000 iterations)") << QString::fromLatin1("j = 0; for (i = 0; i < 10000; ++i) { j += i; }; j");
225 QTest::newRow("for loop (100000 iterations)") << QString::fromLatin1("j = 0; for (i = 0; i < 100000; ++i) { j += i; }; j");
226 QTest::newRow("for loop (1000000 iterations)") << QString::fromLatin1("j = 0; for (i = 0; i < 1000000; ++i) { j += i; }; j");
227 QTest::newRow("assignments") << QString::fromLatin1("a = 1; b = 2; c = 3; d = 4");
228 QTest::newRow("while loop (1000 iterations)") << QString::fromLatin1("i = 0; while (i < 1000) { ++i; }; i");
229 QTest::newRow("while loop (10000 iterations)") << QString::fromLatin1("i = 0; while (i < 10000) { ++i; }; i");
230 QTest::newRow("while loop (100000 iterations)") << QString::fromLatin1("i = 0; while (i < 100000) { ++i; }; i");
231 QTest::newRow("while loop (1000000 iterations)") << QString::fromLatin1("i = 0; while (i < 1000000) { ++i; }; i");
232 QTest::newRow("function expression") << QString::fromLatin1("(function(a, b, c){ return a + b + c; })(1, 2, 3)");
235 void tst_QJSEngine::evaluate()
237 QFETCH(QString, code);
241 (void)m_engine->evaluate(code);
246 void tst_QJSEngine::connectAndDisconnect()
249 QJSValue fun = m_engine->evaluate("(function() { })");
251 qScriptConnect(m_engine, SIGNAL(destroyed()), QJSValue(), fun);
252 qScriptDisconnect(m_engine, SIGNAL(destroyed()), QJSValue(), fun);
256 void tst_QJSEngine::evaluateProgram_data()
261 void tst_QJSEngine::evaluateProgram()
263 QFETCH(QString, code);
264 QScriptProgram program(code);
268 (void)m_engine->evaluate(program);
273 void tst_QJSEngine::globalObject()
277 m_engine->globalObject();
281 void tst_QJSEngine::hasUncaughtException()
285 m_engine->hasUncaughtException();
290 void tst_QJSEngine::isEvaluating()
294 m_engine->isEvaluating();
299 void tst_QJSEngine::newArray_data()
301 QTest::addColumn<int>("size");
302 QTest::newRow("size=0") << 0;
303 QTest::newRow("size=10") << 10;
304 QTest::newRow("size=100") << 0;
305 QTest::newRow("size=1000") << 0;
306 QTest::newRow("size=10000") << 0;
307 QTest::newRow("size=50000") << 0;
310 void tst_QJSEngine::newArray()
315 m_engine->newArray(size);
319 void tst_QJSEngine::newDate()
322 QDateTime dt = QDateTime::currentDateTime();
324 m_engine->newDate(dt);
328 void tst_QJSEngine::newDateFromMs()
332 m_engine->newDate(0);
336 void tst_QJSEngine::newObject()
340 (void)m_engine->newObject();
345 void tst_QJSEngine::newObjectWithScriptClass()
348 QScriptClass cls(m_engine);
350 m_engine->newObject(&cls);
354 void tst_QJSEngine::newQMetaObject()
358 m_engine->newQMetaObject(&QJSEngine::staticMetaObject);
363 void tst_QJSEngine::newQObject()
367 (void)m_engine->newQObject(QCoreApplication::instance());
372 static QJSValue testFunction(QScriptContext *, QJSEngine *)
377 void tst_QJSEngine::newFunction()
381 (void)m_engine->newFunction(testFunction);
386 void tst_QJSEngine::newRegExp()
389 QRegExp re = QRegExp("foo");
391 m_engine->newRegExp(re);
395 void tst_QJSEngine::newRegExpFromString()
398 QString pattern("foo");
399 QString flags("gim");
401 m_engine->newRegExp(pattern, flags);
405 void tst_QJSEngine::newVariant()
410 (void)m_engine->newVariant(var);
414 void tst_QJSEngine::nullValue()
418 m_engine->nullValue();
422 void tst_QJSEngine::undefinedValue()
426 m_engine->undefinedValue();
430 void tst_QJSEngine::collectGarbage()
434 m_engine->collectGarbage();
439 void tst_QJSEngine::availableExtensions()
443 m_engine->availableExtensions();
447 void tst_QJSEngine::importedExtensions()
451 m_engine->importedExtensions();
455 void tst_QJSEngine::currentContext()
459 m_engine->currentContext();
463 void tst_QJSEngine::pushAndPopContext()
467 (void)m_engine->pushContext();
468 m_engine->popContext();
473 void tst_QJSEngine::toObject_data()
476 QTest::addColumn<QJSValue>("val");
477 QTest::newRow("bool") << m_engine->evaluate("true");
478 QTest::newRow("number") << m_engine->evaluate("123");
479 QTest::newRow("string") << m_engine->evaluate("'ciao'");
480 QTest::newRow("null") << m_engine->evaluate("null");
481 QTest::newRow("undefined") << m_engine->evaluate("undefined");
482 QTest::newRow("object") << m_engine->evaluate("({foo:123})");
483 QTest::newRow("array") << m_engine->evaluate("[10,20,30]");
484 QTest::newRow("function") << m_engine->evaluate("(function foo(a, b, c) { return a + b + c; })");
485 QTest::newRow("date") << m_engine->evaluate("new Date");
486 QTest::newRow("regexp") << m_engine->evaluate("new RegExp('foo')");
487 QTest::newRow("error") << m_engine->evaluate("new Error");
489 QTest::newRow("qobject") << m_engine->newQObject(this);
490 #if 0 // no QMetaObject
491 QTest::newRow("qmetaobject") << m_engine->newQMetaObject(&QJSEngine::staticMetaObject);
493 QTest::newRow("variant") << m_engine->newVariant(123);
495 QTest::newRow("qscriptclassobject") << m_engine->newObject(new QScriptClass(m_engine));
497 QTest::newRow("invalid") << QJSValue();
498 QTest::newRow("bool-no-engine") << QJSValue(true);
499 QTest::newRow("number-no-engine") << QJSValue(123.0);
500 QTest::newRow("string-no-engine") << QJSValue(QString::fromLatin1("hello"));
501 QTest::newRow("null-no-engine") << QJSValue(QJSValue::NullValue);
502 QTest::newRow("undefined-no-engine") << QJSValue(QJSValue::UndefinedValue);
505 void tst_QJSEngine::toObject()
507 QFETCH(QJSValue, val);
509 m_engine->toObject(val);
514 void tst_QJSEngine::toStringHandle()
517 QString str = QString::fromLatin1("foobarbaz");
519 (void)m_engine->toStringHandle(str);
524 void tst_QJSEngine::castValueToQreal()
528 (void)qjsvalue_cast<qreal>(val);
533 static QJSValue native_function(QScriptContext *, QJSEngine *)
538 void tst_QJSEngine::nativeCall()
541 m_engine->globalObject().setProperty("fun", m_engine->newFunction(native_function));
543 #if !defined(Q_OS_SYMBIAN)
544 m_engine->evaluate("var w = 0; for (i = 0; i < 100000; ++i) {\n"
545 " w += fun() + fun(); w -= fun(); fun(); w -= fun(); }");
547 m_engine->evaluate("var w = 0; for (i = 0; i < 25000; ++i) {\n"
548 " w += fun() + fun(); w -= fun(); fun(); w -= fun(); }");
553 void tst_QJSEngine::installTranslatorFunctions()
557 m_engine->installTranslatorFunctions();
561 void tst_QJSEngine::translation_data()
563 QTest::addColumn<QString>("text");
564 QTest::addColumn<QString>("fileName");
565 QTest::newRow("no translation") << "\"hello world\"" << "";
566 QTest::newRow("qsTr") << "qsTr(\"hello world\")" << "";
567 QTest::newRow("qsTranslate") << "qsTranslate(\"\", \"hello world\")" << "";
568 QTest::newRow("qsTr:script.js") << "qsTr(\"hello world\")" << "script.js";
571 void tst_QJSEngine::translation()
573 QFETCH(QString, text);
574 QFETCH(QString, fileName);
576 m_engine->installTranslatorFunctions();
579 (void)m_engine->evaluate(text, fileName);
585 void tst_QJSEngine::readScopeProperty_data()
587 QTest::addColumn<bool>("staticScope");
588 QTest::addColumn<bool>("nestedScope");
589 QTest::newRow("single dynamic scope") << false << false;
590 QTest::newRow("single static scope") << true << false;
591 QTest::newRow("double dynamic scope") << false << true;
592 QTest::newRow("double static scope") << true << true;
595 void tst_QJSEngine::readScopeProperty()
597 QFETCH(bool, staticScope);
598 QFETCH(bool, nestedScope);
601 QScriptContext *ctx = m_engine->pushContext();
605 scope = QScriptDeclarativeClass::newStaticScopeObject(m_engine);
607 scope = m_engine->newObject();
608 scope.setProperty("foo", 123);
609 ctx->pushScope(scope);
614 scope2 = QScriptDeclarativeClass::newStaticScopeObject(m_engine);
616 scope2 = m_engine->newObject();
617 scope2.setProperty("bar", 456); // ensure a miss in inner scope
618 ctx->pushScope(scope2);
621 QJSValue fun = m_engine->evaluate("(function() {\n"
622 " for (var i = 0; i < 10000; ++i) {\n"
623 " foo; foo; foo; foo; foo; foo; foo; foo;\n"
626 m_engine->popContext();
627 QVERIFY(fun.isFunction());
633 void tst_QJSEngine::evaluateInNewContext()
637 engine.pushContext();
638 engine.evaluate("var a = 10");
643 void tst_QJSEngine::evaluateInNewContextWithScope()
646 QJSValue scope = engine.newObject();
647 scope.setProperty("foo", 123);
649 QScriptContext *ctx = engine.pushContext();
650 ctx->pushScope(scope);
651 engine.evaluate("foo");
656 // Binding expressions in QML are implemented as anonymous functions
657 // with custom scopes.
658 void tst_QJSEngine::evaluateBindingExpression()
661 QScriptContext *ctx = engine.pushContext();
662 QJSValue scope = engine.newObject();
663 scope.setProperty("foo", 123);
664 ctx->pushScope(scope);
665 QJSValue fun = engine.evaluate("(function() { return foo; })");
666 QVERIFY(fun.isFunction());
668 QVERIFY(fun.call().equals(scope.property("foo")));
669 QJSValue receiver = engine.globalObject();
676 QTEST_MAIN(tst_QJSEngine)
677 #include "tst_qjsengine.moc"