Merge branch 'master' into refactor
[profile/ivi/qtdeclarative.git] / tests / benchmarks / declarative / js / qjsengine / tst_qjsengine.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** 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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qtest.h>
43 #include <QtDeclarative/qjsvalue.h>
44 #include <QtDeclarative/qjsengine.h>
45
46
47 Q_DECLARE_METATYPE(QJSValue)
48
49 //TESTED_FILES=
50
51 class tst_QJSEngine : public QObject
52 {
53     Q_OBJECT
54
55 public:
56     tst_QJSEngine();
57     virtual ~tst_QJSEngine();
58
59 public slots:
60     void init();
61     void cleanup();
62
63 private slots:
64     void constructor();
65 #if 0 // No defaultPrototype for now
66     void defaultPrototype();
67     void setDefaultPrototype();
68 #endif
69     void evaluate_data();
70     void evaluate();
71 #if 0 // No program
72     void evaluateProgram_data();
73     void evaluateProgram();
74 #endif
75 #if 0 // no connections for now
76     void connectAndDisconnect();
77 #endif
78     void globalObject();
79     void hasUncaughtException();
80 #if 0  // no is Evaluating for now
81     void isEvaluating();
82 #endif
83     void newArray_data();
84     void newArray();
85     void newDate();
86     void newDateFromMs();
87     void newObject();
88 #if 0 // No ScriptClass
89     void newObjectWithScriptClass();
90 #endif
91 #if 0 // no qmetaobject
92     void newQMetaObject();
93 #endif
94     void newQObject();
95 #if 0 // no native functions for now
96     void newFunction();
97 #endif
98     void newRegExp();
99     void newRegExpFromString();
100     void newVariant();
101     void nullValue();
102     void undefinedValue();
103     void collectGarbage();
104 #if 0 // No extensions
105     void availableExtensions();
106     void importedExtensions();
107 #endif
108 #if 0 // no context
109     void currentContext();
110     void pushAndPopContext();
111 #endif
112     void toObject_data();
113     void toObject();
114 #if 0 // no stringhandle
115     void toStringHandle();
116 #endif
117     void castValueToQreal();
118 #if 0 // no native functions for now
119     void nativeCall();
120 #endif
121 #if 0 // no translations
122     void installTranslatorFunctions();
123     void translation_data();
124     void translation();
125 #endif
126 #if 0 // no declarative class
127     void readScopeProperty_data();
128     void readScopeProperty();
129 #endif
130 #if 0 // no context
131     void evaluateInNewContext();
132     void evaluateInNewContextWithScope();
133 #endif
134 #if 0 // no pushScope
135     void evaluateBindingExpression();
136 #endif
137
138 private:
139     void defineStandardTestValues();
140     void newEngine()
141     {
142         delete m_engine;
143         m_engine = new QJSEngine;
144     }
145
146     QJSEngine *m_engine;
147 };
148
149 tst_QJSEngine::tst_QJSEngine()
150     : m_engine(0)
151 {
152 }
153
154 tst_QJSEngine::~tst_QJSEngine()
155 {
156     delete m_engine;
157 }
158
159 void tst_QJSEngine::init()
160 {
161 }
162
163 void tst_QJSEngine::cleanup()
164 {
165 }
166
167 void tst_QJSEngine::constructor()
168 {
169     QBENCHMARK {
170         QJSEngine engine;
171         (void)engine.parent();
172     }
173 }
174
175 #if 0 // No defaultPrototype for now
176 void tst_QJSEngine::defaultPrototype()
177 {
178     newEngine();
179     int type = qMetaTypeId<int>();
180     m_engine->setDefaultPrototype(type, m_engine->newObject());
181     QBENCHMARK {
182         m_engine->defaultPrototype(type);
183     }
184 }
185
186 void tst_QJSEngine::setDefaultPrototype()
187 {
188     newEngine();
189     int type = qMetaTypeId<int>();
190     QJSValue proto = m_engine->newObject();
191     QBENCHMARK {
192         m_engine->setDefaultPrototype(type, proto);
193     }
194 }
195
196 #endif
197
198 void tst_QJSEngine::evaluate_data()
199 {
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)");
233 }
234
235 void tst_QJSEngine::evaluate()
236 {
237     QFETCH(QString, code);
238     newEngine();
239
240     QBENCHMARK {
241         (void)m_engine->evaluate(code);
242     }
243 }
244
245 #if 0
246 void tst_QJSEngine::connectAndDisconnect()
247 {
248     newEngine();
249     QJSValue fun = m_engine->evaluate("(function() { })");
250     QBENCHMARK {
251         qScriptConnect(m_engine, SIGNAL(destroyed()), QJSValue(), fun);
252         qScriptDisconnect(m_engine, SIGNAL(destroyed()), QJSValue(), fun);
253     }
254 }
255
256 void tst_QJSEngine::evaluateProgram_data()
257 {
258     evaluate_data();
259 }
260
261 void tst_QJSEngine::evaluateProgram()
262 {
263     QFETCH(QString, code);
264     QScriptProgram program(code);
265     newEngine();
266
267     QBENCHMARK {
268         (void)m_engine->evaluate(program);
269     }
270 }
271 #endif
272
273 void tst_QJSEngine::globalObject()
274 {
275     newEngine();
276     QBENCHMARK {
277         m_engine->globalObject();
278     }
279 }
280
281 void tst_QJSEngine::hasUncaughtException()
282 {
283     newEngine();
284     QBENCHMARK {
285         m_engine->hasUncaughtException();
286     }
287 }
288
289 #if 0
290 void tst_QJSEngine::isEvaluating()
291 {
292     newEngine();
293     QBENCHMARK {
294         m_engine->isEvaluating();
295     }
296 }
297 #endif
298
299 void tst_QJSEngine::newArray_data()
300 {
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;
308 }
309
310 void tst_QJSEngine::newArray()
311 {
312     QFETCH(int, size);
313     newEngine();
314     QBENCHMARK {
315         m_engine->newArray(size);
316     }
317 }
318
319 void tst_QJSEngine::newDate()
320 {
321     newEngine();
322     QDateTime dt = QDateTime::currentDateTime();
323     QBENCHMARK {
324         m_engine->newDate(dt);
325     }
326 }
327
328 void tst_QJSEngine::newDateFromMs()
329 {
330     newEngine();
331     QBENCHMARK {
332         m_engine->newDate(0);
333     }
334 }
335
336 void tst_QJSEngine::newObject()
337 {
338     newEngine();
339     QBENCHMARK {
340         (void)m_engine->newObject();
341     }
342 }
343
344 #if 0
345 void tst_QJSEngine::newObjectWithScriptClass()
346 {
347     newEngine();
348     QScriptClass cls(m_engine);
349     QBENCHMARK {
350         m_engine->newObject(&cls);
351     }
352 }
353
354 void tst_QJSEngine::newQMetaObject()
355 {
356     newEngine();
357     QBENCHMARK {
358         m_engine->newQMetaObject(&QJSEngine::staticMetaObject);
359     }
360 }
361 #endif
362
363 void tst_QJSEngine::newQObject()
364 {
365     newEngine();
366     QBENCHMARK {
367         (void)m_engine->newQObject(QCoreApplication::instance());
368     }
369 }
370
371 #if 0
372 static QJSValue testFunction(QScriptContext *, QJSEngine *)
373 {
374     return 0;
375 }
376
377 void tst_QJSEngine::newFunction()
378 {
379     newEngine();
380     QBENCHMARK {
381         (void)m_engine->newFunction(testFunction);
382     }
383 }
384 #endif
385
386 void tst_QJSEngine::newRegExp()
387 {
388     newEngine();
389     QRegExp re = QRegExp("foo");
390     QBENCHMARK {
391         m_engine->newRegExp(re);
392     }
393 }
394
395 void tst_QJSEngine::newRegExpFromString()
396 {
397     newEngine();
398     QString pattern("foo");
399     QString flags("gim");
400     QBENCHMARK {
401         m_engine->newRegExp(pattern, flags);
402     }
403 }
404
405 void tst_QJSEngine::newVariant()
406 {
407     newEngine();
408     QVariant var(123);
409     QBENCHMARK {
410         (void)m_engine->newVariant(var);
411     }
412 }
413
414 void tst_QJSEngine::nullValue()
415 {
416     newEngine();
417     QBENCHMARK {
418         m_engine->nullValue();
419     }
420 }
421
422 void tst_QJSEngine::undefinedValue()
423 {
424     newEngine();
425     QBENCHMARK {
426         m_engine->undefinedValue();
427     }
428 }
429
430 void tst_QJSEngine::collectGarbage()
431 {
432     newEngine();
433     QBENCHMARK {
434         m_engine->collectGarbage();
435     }
436 }
437
438 #if 0
439 void tst_QJSEngine::availableExtensions()
440 {
441     newEngine();
442     QBENCHMARK {
443         m_engine->availableExtensions();
444     }
445 }
446
447 void tst_QJSEngine::importedExtensions()
448 {
449     newEngine();
450     QBENCHMARK {
451         m_engine->importedExtensions();
452     }
453 }
454
455 void tst_QJSEngine::currentContext()
456 {
457     newEngine();
458     QBENCHMARK {
459         m_engine->currentContext();
460     }
461 }
462
463 void tst_QJSEngine::pushAndPopContext()
464 {
465     newEngine();
466     QBENCHMARK {
467         (void)m_engine->pushContext();
468         m_engine->popContext();
469     }
470 }
471 #endif
472
473 void tst_QJSEngine::toObject_data()
474 {
475     newEngine();
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");
488
489     QTest::newRow("qobject") << m_engine->newQObject(this);
490 #if 0 // no QMetaObject
491     QTest::newRow("qmetaobject") << m_engine->newQMetaObject(&QJSEngine::staticMetaObject);
492 #endif
493     QTest::newRow("variant") << m_engine->newVariant(123);
494 #if 0 //no classes
495     QTest::newRow("qscriptclassobject") << m_engine->newObject(new QScriptClass(m_engine));
496 #endif
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);
503 }
504
505 void tst_QJSEngine::toObject()
506 {
507     QFETCH(QJSValue, val);
508     QBENCHMARK {
509         m_engine->toObject(val);
510     }
511 }
512
513 #if 0
514 void tst_QJSEngine::toStringHandle()
515 {
516     newEngine();
517     QString str = QString::fromLatin1("foobarbaz");
518     QBENCHMARK {
519         (void)m_engine->toStringHandle(str);
520     }
521 }
522 #endif
523
524 void tst_QJSEngine::castValueToQreal()
525 {
526     QJSValue val(123);
527     QBENCHMARK {
528         (void)qjsvalue_cast<qreal>(val);
529     }
530 }
531
532 #if 0
533 static QJSValue native_function(QScriptContext *, QJSEngine *)
534 {
535     return 42;
536 }
537
538 void tst_QJSEngine::nativeCall()
539 {
540     newEngine();
541     m_engine->globalObject().setProperty("fun", m_engine->newFunction(native_function));
542     QBENCHMARK{
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(); }");
546 #else
547         m_engine->evaluate("var w = 0; for (i = 0; i < 25000; ++i) {\n"
548                      "  w += fun() + fun(); w -= fun(); fun(); w -= fun(); }");
549 #endif
550     }
551 }
552
553 void tst_QJSEngine::installTranslatorFunctions()
554 {
555     newEngine();
556     QBENCHMARK {
557         m_engine->installTranslatorFunctions();
558     }
559 }
560
561 void tst_QJSEngine::translation_data()
562 {
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";
569 }
570
571 void tst_QJSEngine::translation()
572 {
573     QFETCH(QString, text);
574     QFETCH(QString, fileName);
575     newEngine();
576     m_engine->installTranslatorFunctions();
577
578     QBENCHMARK {
579         (void)m_engine->evaluate(text, fileName);
580     }
581 }
582 #endif
583
584 #if 0
585 void tst_QJSEngine::readScopeProperty_data()
586 {
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;
593 }
594
595 void tst_QJSEngine::readScopeProperty()
596 {
597     QFETCH(bool, staticScope);
598     QFETCH(bool, nestedScope);
599
600     newEngine();
601     QScriptContext *ctx = m_engine->pushContext();
602
603     QJSValue scope;
604     if (staticScope)
605         scope = QScriptDeclarativeClass::newStaticScopeObject(m_engine);
606     else
607         scope = m_engine->newObject();
608     scope.setProperty("foo", 123);
609     ctx->pushScope(scope);
610
611     if (nestedScope) {
612         QJSValue scope2;
613         if (staticScope)
614             scope2 = QScriptDeclarativeClass::newStaticScopeObject(m_engine);
615         else
616             scope2 = m_engine->newObject();
617         scope2.setProperty("bar", 456); // ensure a miss in inner scope
618         ctx->pushScope(scope2);
619     }
620
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"
624                                        "  }\n"
625                                        "})");
626     m_engine->popContext();
627     QVERIFY(fun.isFunction());
628     QBENCHMARK {
629         fun.call();
630     }
631 }
632
633 void tst_QJSEngine::evaluateInNewContext()
634 {
635     QJSEngine engine;
636     QBENCHMARK {
637         engine.pushContext();
638         engine.evaluate("var a = 10");
639         engine.popContext();
640     }
641 }
642
643 void tst_QJSEngine::evaluateInNewContextWithScope()
644 {
645     QJSEngine engine;
646     QJSValue scope = engine.newObject();
647     scope.setProperty("foo", 123);
648     QBENCHMARK {
649         QScriptContext *ctx = engine.pushContext();
650         ctx->pushScope(scope);
651         engine.evaluate("foo");
652         engine.popContext();
653     }
654 }
655
656 // Binding expressions in QML are implemented as anonymous functions
657 // with custom scopes.
658 void tst_QJSEngine::evaluateBindingExpression()
659 {
660     QJSEngine engine;
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());
667     engine.popContext();
668     QVERIFY(fun.call().equals(scope.property("foo")));
669     QJSValue receiver = engine.globalObject();
670     QBENCHMARK {
671         fun.call(receiver);
672     }
673 }
674 #endif
675
676 QTEST_MAIN(tst_QJSEngine)
677 #include "tst_qjsengine.moc"