]> git.saurik.com Git - apple/javascriptcore.git/blob - qt/tests/qscriptengine/tst_qscriptengine.cpp
1ec9ad3f0c0979c6c756ff1ea183a375cb0e3f06
[apple/javascriptcore.git] / qt / tests / qscriptengine / tst_qscriptengine.cpp
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"
21 #include "qscriptprogram.h"
22 #include "qscriptsyntaxcheckresult.h"
23 #include "qscriptvalue.h"
24 #include <QtTest/qtest.h>
25
26 class tst_QScriptEngine : public QObject {
27 Q_OBJECT
28
29 public:
30 tst_QScriptEngine() {}
31 virtual ~tst_QScriptEngine() {}
32
33 public slots:
34 void init() {}
35 void cleanup() {}
36
37 private slots:
38 void globalObject();
39 void evaluate();
40 void collectGarbage();
41 void reportAdditionalMemoryCost();
42 void nullValue();
43 void undefinedValue();
44 void evaluateProgram();
45 void checkSyntax_data();
46 void checkSyntax();
47 };
48
49 /* Evaluating a script that throw an unhandled exception should return an invalid value. */
50 void tst_QScriptEngine::evaluate()
51 {
52 QScriptEngine engine;
53 QVERIFY2(engine.evaluate("1+1").isValid(), "the expression should be evaluated and an valid result should be returned");
54 QVERIFY2(engine.evaluate("ping").isValid(), "Script throwing an unhandled exception should return an exception value");
55 }
56
57 void tst_QScriptEngine::globalObject()
58 {
59 QScriptEngine engine;
60 QScriptValue global = engine.globalObject();
61 QScriptValue self = engine.evaluate("this");
62 QVERIFY(global.isObject());
63 QVERIFY(engine.globalObject().equals(engine.evaluate("this")));
64 QEXPECT_FAIL("", "strictlyEquals is broken - bug 36600 in bugs.webkit.org", Continue);
65 QVERIFY(engine.globalObject().strictlyEquals(self));
66 }
67
68 /* Test garbage collection, at least try to not crash. */
69 void tst_QScriptEngine::collectGarbage()
70 {
71 QScriptEngine engine;
72 QScriptValue foo = engine.evaluate("( function foo() {return 'pong';} )");
73 QVERIFY(foo.isFunction());
74 engine.collectGarbage();
75 QCOMPARE(foo.call().toString(), QString::fromAscii("pong"));
76 }
77
78 void tst_QScriptEngine::reportAdditionalMemoryCost()
79 {
80 // There isn't any easy way to test the responsiveness of the GC;
81 // just try to call the function a few times with various sizes.
82 QScriptEngine eng;
83 for (int i = 0; i < 100; ++i) {
84 eng.reportAdditionalMemoryCost(0);
85 eng.reportAdditionalMemoryCost(10);
86 eng.reportAdditionalMemoryCost(1000);
87 eng.reportAdditionalMemoryCost(10000);
88 eng.reportAdditionalMemoryCost(100000);
89 eng.reportAdditionalMemoryCost(1000000);
90 eng.reportAdditionalMemoryCost(10000000);
91 eng.reportAdditionalMemoryCost(-1);
92 eng.reportAdditionalMemoryCost(-1000);
93 QScriptValue obj = eng.evaluate("new Object");
94 eng.collectGarbage();
95 }
96 }
97
98 void tst_QScriptEngine::nullValue()
99 {
100 QScriptEngine engine;
101 QScriptValue value = engine.nullValue();
102 QVERIFY(value.isValid());
103 QVERIFY(value.isNull());
104 }
105
106 void tst_QScriptEngine::undefinedValue()
107 {
108 QScriptEngine engine;
109 QScriptValue value = engine.undefinedValue();
110 QVERIFY(value.isValid());
111 QVERIFY(value.isUndefined());
112 }
113
114 void tst_QScriptEngine::evaluateProgram()
115 {
116 QScriptEngine eng;
117 {
118 QString code("1 + 2");
119 QString fileName("hello.js");
120 int lineNumber = 123;
121 QScriptProgram program(code, fileName, lineNumber);
122 QVERIFY(!program.isNull());
123 QCOMPARE(program.sourceCode(), code);
124 QCOMPARE(program.fileName(), fileName);
125 QCOMPARE(program.firstLineNumber(), lineNumber);
126
127 QScriptValue expected = eng.evaluate(code);
128 for (int x = 0; x < 10; ++x) {
129 QScriptValue ret = eng.evaluate(program);
130 QVERIFY(ret.equals(expected));
131 }
132
133 // operator=
134 QScriptProgram sameProgram = program;
135 QVERIFY(sameProgram == program);
136 QVERIFY(eng.evaluate(sameProgram).equals(expected));
137
138 // copy constructor
139 QScriptProgram sameProgram2(program);
140 QVERIFY(sameProgram2 == program);
141 QVERIFY(eng.evaluate(sameProgram2).equals(expected));
142
143 QScriptProgram differentProgram("2 + 3");
144 QVERIFY(differentProgram != program);
145 QVERIFY(!eng.evaluate(differentProgram).equals(expected));
146 }
147
148 // Program that accesses variable in the scope
149 {
150 QScriptProgram program("a");
151 QVERIFY(!program.isNull());
152 {
153 QScriptValue ret = eng.evaluate(program);
154 QVERIFY(ret.isError());
155 QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: a"));
156 }
157 {
158 QScriptValue ret = eng.evaluate(program);
159 QVERIFY(ret.isError());
160 }
161 eng.evaluate("a = 456");
162 {
163 QScriptValue ret = eng.evaluate(program);
164 QVERIFY(!ret.isError());
165 QCOMPARE(ret.toNumber(), 456.0);
166 }
167 }
168
169 // Program that creates closure
170 {
171 QScriptProgram program("(function() { var count = 0; return function() { return count++; }; })");
172 QVERIFY(!program.isNull());
173 QScriptValue createCounter = eng.evaluate(program);
174 QVERIFY(createCounter.isFunction());
175 QScriptValue counter = createCounter.call();
176 QVERIFY(counter.isFunction());
177 {
178 QScriptValue ret = counter.call();
179 QVERIFY(ret.isNumber());
180 }
181 QScriptValue counter2 = createCounter.call();
182 QVERIFY(counter2.isFunction());
183 QVERIFY(!counter2.equals(counter));
184 {
185 QScriptValue ret = counter2.call();
186 QVERIFY(ret.isNumber());
187 }
188 }
189
190 // Same program run in different engines
191 {
192 QString code("1 + 2");
193 QScriptProgram program(code);
194 QVERIFY(!program.isNull());
195 double expected = eng.evaluate(program).toNumber();
196 for (int x = 0; x < 2; ++x) {
197 QScriptEngine eng2;
198 for (int y = 0; y < 2; ++y) {
199 double ret = eng2.evaluate(program).toNumber();
200 QCOMPARE(ret, expected);
201 }
202 }
203 }
204
205 // No program
206 {
207 QScriptProgram program;
208 QVERIFY(program.isNull());
209 QScriptValue ret = eng.evaluate(program);
210 QVERIFY(!ret.isValid());
211 }
212 }
213
214 void tst_QScriptEngine::checkSyntax_data()
215 {
216 QTest::addColumn<QString>("code");
217 QTest::addColumn<int>("expectedState");
218 QTest::addColumn<int>("errorLineNumber");
219 QTest::addColumn<int>("errorColumnNumber");
220 QTest::addColumn<QString>("errorMessage");
221
222 QTest::newRow("0")
223 << QString("0") << int(QScriptSyntaxCheckResult::Valid)
224 << -1 << -1 << "";
225 QTest::newRow("if (")
226 << QString("if (\n") << int(QScriptSyntaxCheckResult::Intermediate)
227 << 1 << 4 << "";
228 QTest::newRow("if else")
229 << QString("\nif else") << int(QScriptSyntaxCheckResult::Error)
230 << 2 << 4 << "SyntaxError: Parse error";
231 QTest::newRow("{if}")
232 << QString("{\n{\nif\n}\n") << int(QScriptSyntaxCheckResult::Error)
233 << 4 << 1 << "SyntaxError: Parse error";
234 QTest::newRow("foo[")
235 << QString("foo[") << int(QScriptSyntaxCheckResult::Error)
236 << 1 << 4 << "SyntaxError: Parse error";
237 QTest::newRow("foo['bar']")
238 << QString("foo['bar']") << int(QScriptSyntaxCheckResult::Valid)
239 << -1 << -1 << "";
240
241 QTest::newRow("/*")
242 << QString("/*") << int(QScriptSyntaxCheckResult::Intermediate)
243 << 1 << 1 << "Unclosed comment at end of file";
244 QTest::newRow("/*\nMy comment")
245 << QString("/*\nMy comment") << int(QScriptSyntaxCheckResult::Intermediate)
246 << 1 << 1 << "Unclosed comment at end of file";
247 QTest::newRow("/*\nMy comment */\nfoo = 10")
248 << QString("/*\nMy comment */\nfoo = 10") << int(QScriptSyntaxCheckResult::Valid)
249 << -1 << -1 << "";
250 QTest::newRow("foo = 10 /*")
251 << QString("foo = 10 /*") << int(QScriptSyntaxCheckResult::Intermediate)
252 << -1 << -1 << "";
253 QTest::newRow("foo = 10; /*")
254 << QString("foo = 10; /*") << int(QScriptSyntaxCheckResult::Intermediate)
255 << 1 << 11 << "Expected `end of file'";
256 QTest::newRow("foo = 10 /* My comment */")
257 << QString("foo = 10 /* My comment */") << int(QScriptSyntaxCheckResult::Valid)
258 << -1 << -1 << "";
259
260 QTest::newRow("/=/")
261 << QString("/=/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
262 QTest::newRow("/=/g")
263 << QString("/=/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
264 QTest::newRow("/a/")
265 << QString("/a/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
266 QTest::newRow("/a/g")
267 << QString("/a/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << "";
268 }
269
270 void tst_QScriptEngine::checkSyntax()
271 {
272 QFETCH(QString, code);
273 QFETCH(int, expectedState);
274 QFETCH(int, errorLineNumber);
275 QFETCH(int, errorColumnNumber);
276 QFETCH(QString, errorMessage);
277
278 QScriptSyntaxCheckResult result = QScriptEngine::checkSyntax(code);
279
280 // assignment
281 {
282 QScriptSyntaxCheckResult copy = result;
283 QCOMPARE(copy.state(), result.state());
284 QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
285 QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
286 QCOMPARE(copy.errorMessage(), result.errorMessage());
287 }
288 {
289 QScriptSyntaxCheckResult copy(result);
290 QCOMPARE(copy.state(), result.state());
291 QCOMPARE(copy.errorLineNumber(), result.errorLineNumber());
292 QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber());
293 QCOMPARE(copy.errorMessage(), result.errorMessage());
294 }
295
296 if (expectedState == QScriptSyntaxCheckResult::Intermediate)
297 QEXPECT_FAIL("", "QScriptSyntaxCheckResult::state() doesn't return the Intermediate state", Abort);
298 QCOMPARE(result.state(), QScriptSyntaxCheckResult::State(expectedState));
299 QCOMPARE(result.errorLineNumber(), errorLineNumber);
300 if (expectedState != QScriptSyntaxCheckResult::Valid && errorColumnNumber != 1)
301 QEXPECT_FAIL("", "QScriptSyntaxCheckResult::errorColumnNumber() doesn't return correct value", Continue);
302 QCOMPARE(result.errorColumnNumber(), errorColumnNumber);
303 QCOMPARE(result.errorMessage(), errorMessage);
304 }
305
306
307 QTEST_MAIN(tst_QScriptEngine)
308 #include "tst_qscriptengine.moc"