|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 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 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 |
|
43 #include <QtTest/QtTest> |
|
44 |
|
45 #include <qscriptengine.h> |
|
46 #include <qscriptengineagent.h> |
|
47 #include <qscriptvalueiterator.h> |
|
48 #include <qgraphicsitem.h> |
|
49 #include <qstandarditemmodel.h> |
|
50 #include <QtCore/qnumeric.h> |
|
51 #include <stdlib.h> |
|
52 |
|
53 Q_DECLARE_METATYPE(QList<int>) |
|
54 Q_DECLARE_METATYPE(QObjectList) |
|
55 |
|
56 //TESTED_CLASS= |
|
57 //TESTED_FILES= |
|
58 |
|
59 #if defined(Q_OS_SYMBIAN) |
|
60 # define STRINGIFY(x) #x |
|
61 # define TOSTRING(x) STRINGIFY(x) |
|
62 # define SRCDIR "C:/Private/" TOSTRING(SYMBIAN_SRCDIR_UID) |
|
63 #endif |
|
64 |
|
65 // The JavaScriptCore GC marks the C stack. To try to ensure that there is |
|
66 // no JSObject* left in stack memory by the compiler, we call this function |
|
67 // to zap some bytes of memory before calling collectGarbage(). |
|
68 static void zapSomeStack() |
|
69 { |
|
70 char buf[4096]; |
|
71 memset(buf, 0, sizeof(buf)); |
|
72 } |
|
73 |
|
74 static void collectGarbage_helper(QScriptEngine &eng) |
|
75 { |
|
76 zapSomeStack(); |
|
77 eng.collectGarbage(); |
|
78 } |
|
79 |
|
80 class tst_QScriptEngine : public QObject |
|
81 { |
|
82 Q_OBJECT |
|
83 |
|
84 public: |
|
85 tst_QScriptEngine(); |
|
86 virtual ~tst_QScriptEngine(); |
|
87 |
|
88 private slots: |
|
89 void constructWithParent(); |
|
90 void currentContext(); |
|
91 void pushPopContext(); |
|
92 void getSetDefaultPrototype(); |
|
93 void newFunction(); |
|
94 void newObject(); |
|
95 void newArray(); |
|
96 void newVariant(); |
|
97 void newRegExp(); |
|
98 void newDate(); |
|
99 void newQObject(); |
|
100 void newQMetaObject(); |
|
101 void newActivationObject(); |
|
102 void getSetGlobalObject(); |
|
103 void globalObjectProperties(); |
|
104 void globalObjectGetterSetterProperty(); |
|
105 void builtinFunctionNames_data(); |
|
106 void builtinFunctionNames(); |
|
107 void checkSyntax_data(); |
|
108 void checkSyntax(); |
|
109 void canEvaluate_data(); |
|
110 void canEvaluate(); |
|
111 void evaluate_data(); |
|
112 void evaluate(); |
|
113 void nestedEvaluate(); |
|
114 void uncaughtException(); |
|
115 void errorMessage_QT679(); |
|
116 void valueConversion(); |
|
117 void importExtension(); |
|
118 void infiniteRecursion(); |
|
119 void castWithPrototypeChain(); |
|
120 void castWithMultipleInheritance(); |
|
121 void collectGarbage(); |
|
122 void gcWithNestedDataStructure(); |
|
123 void processEventsWhileRunning(); |
|
124 void throwErrorFromProcessEvents(); |
|
125 void stacktrace(); |
|
126 void numberParsing_data(); |
|
127 void numberParsing(); |
|
128 void automaticSemicolonInsertion(); |
|
129 void abortEvaluation(); |
|
130 void isEvaluating(); |
|
131 void printFunctionWithCustomHandler(); |
|
132 void printThrowsException(); |
|
133 void errorConstructors(); |
|
134 void argumentsProperty(); |
|
135 void numberClass(); |
|
136 void forInStatement(); |
|
137 void functionExpression(); |
|
138 void stringObjects(); |
|
139 void getterSetterThisObject(); |
|
140 void continueInSwitch(); |
|
141 void readOnlyPrototypeProperty(); |
|
142 void toObject(); |
|
143 void reservedWords_data(); |
|
144 void reservedWords(); |
|
145 void futureReservedWords_data(); |
|
146 void futureReservedWords(); |
|
147 void throwInsideWithStatement(); |
|
148 void getSetAgent(); |
|
149 void reentrancy(); |
|
150 void incDecNonObjectProperty(); |
|
151 void installTranslatorFunctions(); |
|
152 void functionScopes(); |
|
153 void nativeFunctionScopes(); |
|
154 |
|
155 void qRegExpInport_data(); |
|
156 void qRegExpInport(); |
|
157 }; |
|
158 |
|
159 tst_QScriptEngine::tst_QScriptEngine() |
|
160 { |
|
161 } |
|
162 |
|
163 tst_QScriptEngine::~tst_QScriptEngine() |
|
164 { |
|
165 } |
|
166 |
|
167 void tst_QScriptEngine::constructWithParent() |
|
168 { |
|
169 QPointer<QScriptEngine> ptr; |
|
170 { |
|
171 QObject obj; |
|
172 QScriptEngine *engine = new QScriptEngine(&obj); |
|
173 ptr = engine; |
|
174 } |
|
175 QVERIFY(ptr == 0); |
|
176 } |
|
177 |
|
178 void tst_QScriptEngine::currentContext() |
|
179 { |
|
180 QScriptEngine eng; |
|
181 QScriptContext *globalCtx = eng.currentContext(); |
|
182 QVERIFY(globalCtx != 0); |
|
183 QVERIFY(globalCtx->parentContext() == 0); |
|
184 QCOMPARE(globalCtx->engine(), &eng); |
|
185 QCOMPARE(globalCtx->argumentCount(), 0); |
|
186 QCOMPARE(globalCtx->backtrace().size(), 1); |
|
187 QVERIFY(!globalCtx->isCalledAsConstructor()); |
|
188 QVERIFY(!globalCtx->callee().isValid()); |
|
189 QCOMPARE(globalCtx->state(), QScriptContext::NormalState); |
|
190 QVERIFY(globalCtx->thisObject().strictlyEquals(eng.globalObject())); |
|
191 QVERIFY(globalCtx->activationObject().strictlyEquals(eng.globalObject())); |
|
192 QVERIFY(globalCtx->argumentsObject().isObject()); |
|
193 } |
|
194 |
|
195 void tst_QScriptEngine::pushPopContext() |
|
196 { |
|
197 QScriptEngine eng; |
|
198 QScriptContext *globalCtx = eng.currentContext(); |
|
199 QScriptContext *ctx = eng.pushContext(); |
|
200 QVERIFY(ctx != 0); |
|
201 QCOMPARE(ctx->parentContext(), globalCtx); |
|
202 QVERIFY(!ctx->isCalledAsConstructor()); |
|
203 QVERIFY(!ctx->callee().isValid()); |
|
204 QVERIFY(ctx->thisObject().strictlyEquals(eng.globalObject())); |
|
205 QCOMPARE(ctx->argumentCount(), 0); |
|
206 QCOMPARE(ctx->backtrace().size(), 2); |
|
207 QCOMPARE(ctx->engine(), &eng); |
|
208 QCOMPARE(ctx->state(), QScriptContext::NormalState); |
|
209 QVERIFY(ctx->activationObject().isObject()); |
|
210 QVERIFY(ctx->argumentsObject().isObject()); |
|
211 |
|
212 QScriptContext *ctx2 = eng.pushContext(); |
|
213 QVERIFY(ctx2 != 0); |
|
214 QCOMPARE(ctx2->parentContext(), ctx); |
|
215 QVERIFY(!ctx2->activationObject().strictlyEquals(ctx->activationObject())); |
|
216 QVERIFY(!ctx2->argumentsObject().strictlyEquals(ctx->argumentsObject())); |
|
217 |
|
218 eng.popContext(); |
|
219 eng.popContext(); |
|
220 QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()"); |
|
221 eng.popContext(); // ignored |
|
222 QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::popContext() doesn't match with pushContext()"); |
|
223 eng.popContext(); // ignored |
|
224 } |
|
225 |
|
226 static QScriptValue myFunction(QScriptContext *, QScriptEngine *eng) |
|
227 { |
|
228 return eng->nullValue(); |
|
229 } |
|
230 |
|
231 static QScriptValue myFunctionWithVoidArg(QScriptContext *, QScriptEngine *eng, void *) |
|
232 { |
|
233 return eng->nullValue(); |
|
234 } |
|
235 |
|
236 static QScriptValue myThrowingFunction(QScriptContext *ctx, QScriptEngine *) |
|
237 { |
|
238 return ctx->throwError("foo"); |
|
239 } |
|
240 |
|
241 void tst_QScriptEngine::newFunction() |
|
242 { |
|
243 QScriptEngine eng; |
|
244 { |
|
245 QScriptValue fun = eng.newFunction(myFunction); |
|
246 QCOMPARE(fun.isValid(), true); |
|
247 QCOMPARE(fun.isFunction(), true); |
|
248 QCOMPARE(fun.isObject(), true); |
|
249 QCOMPARE(fun.scriptClass(), (QScriptClass*)0); |
|
250 // a prototype property is automatically constructed |
|
251 { |
|
252 QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal); |
|
253 QVERIFY(prot.isObject()); |
|
254 QVERIFY(prot.property("constructor").strictlyEquals(fun)); |
|
255 QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable); |
|
256 QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); |
|
257 } |
|
258 // prototype should be Function.prototype |
|
259 QCOMPARE(fun.prototype().isValid(), true); |
|
260 QCOMPARE(fun.prototype().isFunction(), true); |
|
261 QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true); |
|
262 |
|
263 QCOMPARE(fun.call().isNull(), true); |
|
264 QCOMPARE(fun.construct().isObject(), true); |
|
265 } |
|
266 |
|
267 // the overload that takes a void* |
|
268 { |
|
269 QScriptValue fun = eng.newFunction(myFunctionWithVoidArg, (void*)this); |
|
270 QVERIFY(fun.isFunction()); |
|
271 QCOMPARE(fun.scriptClass(), (QScriptClass*)0); |
|
272 // a prototype property is automatically constructed |
|
273 { |
|
274 QScriptValue prot = fun.property("prototype", QScriptValue::ResolveLocal); |
|
275 QVERIFY(prot.isObject()); |
|
276 QVERIFY(prot.property("constructor").strictlyEquals(fun)); |
|
277 QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable); |
|
278 QCOMPARE(prot.propertyFlags("constructor"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); |
|
279 } |
|
280 // prototype should be Function.prototype |
|
281 QCOMPARE(fun.prototype().isValid(), true); |
|
282 QCOMPARE(fun.prototype().isFunction(), true); |
|
283 QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true); |
|
284 |
|
285 QCOMPARE(fun.call().isNull(), true); |
|
286 QCOMPARE(fun.construct().isObject(), true); |
|
287 } |
|
288 |
|
289 // the overload that takes a prototype |
|
290 { |
|
291 QScriptValue proto = eng.newObject(); |
|
292 QScriptValue fun = eng.newFunction(myFunction, proto); |
|
293 QCOMPARE(fun.isValid(), true); |
|
294 QCOMPARE(fun.isFunction(), true); |
|
295 QCOMPARE(fun.isObject(), true); |
|
296 // internal prototype should be Function.prototype |
|
297 QCOMPARE(fun.prototype().isValid(), true); |
|
298 QCOMPARE(fun.prototype().isFunction(), true); |
|
299 QCOMPARE(fun.prototype().strictlyEquals(eng.evaluate("Function.prototype")), true); |
|
300 // public prototype should be the one we passed |
|
301 QCOMPARE(fun.property("prototype").strictlyEquals(proto), true); |
|
302 QCOMPARE(fun.propertyFlags("prototype"), QScriptValue::Undeletable); |
|
303 QCOMPARE(proto.property("constructor").strictlyEquals(fun), true); |
|
304 QCOMPARE(proto.propertyFlags("constructor"), |
|
305 QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); |
|
306 |
|
307 QCOMPARE(fun.call().isNull(), true); |
|
308 QCOMPARE(fun.construct().isObject(), true); |
|
309 } |
|
310 } |
|
311 |
|
312 void tst_QScriptEngine::newObject() |
|
313 { |
|
314 QScriptEngine eng; |
|
315 QScriptValue object = eng.newObject(); |
|
316 QCOMPARE(object.isValid(), true); |
|
317 QCOMPARE(object.isObject(), true); |
|
318 QCOMPARE(object.isFunction(), false); |
|
319 QCOMPARE(object.scriptClass(), (QScriptClass*)0); |
|
320 // prototype should be Object.prototype |
|
321 QCOMPARE(object.prototype().isValid(), true); |
|
322 QCOMPARE(object.prototype().isObject(), true); |
|
323 QCOMPARE(object.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true); |
|
324 } |
|
325 |
|
326 void tst_QScriptEngine::newArray() |
|
327 { |
|
328 QScriptEngine eng; |
|
329 QScriptValue array = eng.newArray(); |
|
330 QCOMPARE(array.isValid(), true); |
|
331 QCOMPARE(array.isArray(), true); |
|
332 QCOMPARE(array.isObject(), true); |
|
333 QVERIFY(!array.isFunction()); |
|
334 QCOMPARE(array.scriptClass(), (QScriptClass*)0); |
|
335 // prototype should be Array.prototype |
|
336 QCOMPARE(array.prototype().isValid(), true); |
|
337 QCOMPARE(array.prototype().isArray(), true); |
|
338 QCOMPARE(array.prototype().strictlyEquals(eng.evaluate("Array.prototype")), true); |
|
339 |
|
340 // task 218092 |
|
341 { |
|
342 QScriptValue ret = eng.evaluate("[].splice(0, 0, 'a')"); |
|
343 QVERIFY(ret.isArray()); |
|
344 QCOMPARE(ret.property("length").toInt32(), 0); |
|
345 } |
|
346 { |
|
347 QScriptValue ret = eng.evaluate("['a'].splice(0, 1, 'b')"); |
|
348 QVERIFY(ret.isArray()); |
|
349 QCOMPARE(ret.property("length").toInt32(), 1); |
|
350 } |
|
351 { |
|
352 QScriptValue ret = eng.evaluate("['a', 'b'].splice(0, 1, 'c')"); |
|
353 QVERIFY(ret.isArray()); |
|
354 QCOMPARE(ret.property("length").toInt32(), 1); |
|
355 } |
|
356 { |
|
357 QScriptValue ret = eng.evaluate("['a', 'b', 'c'].splice(0, 2, 'd')"); |
|
358 QVERIFY(ret.isArray()); |
|
359 QCOMPARE(ret.property("length").toInt32(), 2); |
|
360 } |
|
361 { |
|
362 QScriptValue ret = eng.evaluate("['a', 'b', 'c'].splice(1, 2, 'd', 'e', 'f')"); |
|
363 QVERIFY(ret.isArray()); |
|
364 QCOMPARE(ret.property("length").toInt32(), 2); |
|
365 } |
|
366 |
|
367 // task 233836 |
|
368 { |
|
369 QScriptValue ret = eng.evaluate("a = new Array(4294967295); a.push('foo')"); |
|
370 QVERIFY(ret.isNumber()); |
|
371 QCOMPARE(ret.toInt32(), 0); |
|
372 QCOMPARE(eng.evaluate("a[4294967295]").toString(), QString::fromLatin1("foo")); |
|
373 } |
|
374 { |
|
375 QScriptValue ret = eng.newArray(0xFFFFFFFF); |
|
376 QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF)); |
|
377 ret.setProperty(0xFFFFFFFF, 123); |
|
378 QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF)); |
|
379 QVERIFY(ret.property(0xFFFFFFFF).isNumber()); |
|
380 QCOMPARE(ret.property(0xFFFFFFFF).toInt32(), 123); |
|
381 ret.setProperty(123, 456); |
|
382 QCOMPARE(ret.property("length").toUInt32(), uint(0xFFFFFFFF)); |
|
383 QVERIFY(ret.property(123).isNumber()); |
|
384 QCOMPARE(ret.property(123).toInt32(), 456); |
|
385 } |
|
386 } |
|
387 |
|
388 void tst_QScriptEngine::newVariant() |
|
389 { |
|
390 QScriptEngine eng; |
|
391 { |
|
392 QScriptValue opaque = eng.newVariant(QVariant()); |
|
393 QCOMPARE(opaque.isValid(), true); |
|
394 QCOMPARE(opaque.isVariant(), true); |
|
395 QVERIFY(!opaque.isFunction()); |
|
396 QCOMPARE(opaque.isObject(), true); |
|
397 QCOMPARE(opaque.prototype().isValid(), true); |
|
398 QCOMPARE(opaque.prototype().isVariant(), true); |
|
399 QVERIFY(opaque.property("valueOf").call(opaque).isUndefined()); |
|
400 } |
|
401 // default prototype should be set automatically |
|
402 { |
|
403 QScriptValue proto = eng.newObject(); |
|
404 eng.setDefaultPrototype(qMetaTypeId<QString>(), proto); |
|
405 QScriptValue ret = eng.newVariant(QVariant(QString::fromLatin1("hello"))); |
|
406 QVERIFY(ret.isVariant()); |
|
407 QCOMPARE(ret.scriptClass(), (QScriptClass*)0); |
|
408 QVERIFY(ret.prototype().strictlyEquals(proto)); |
|
409 eng.setDefaultPrototype(qMetaTypeId<QString>(), QScriptValue()); |
|
410 QScriptValue ret2 = eng.newVariant(QVariant(QString::fromLatin1("hello"))); |
|
411 QVERIFY(ret2.isVariant()); |
|
412 QVERIFY(!ret2.prototype().strictlyEquals(proto)); |
|
413 } |
|
414 // "promote" plain object to variant |
|
415 { |
|
416 QScriptValue object = eng.newObject(); |
|
417 object.setProperty("foo", eng.newObject()); |
|
418 object.setProperty("bar", object.property("foo")); |
|
419 QVERIFY(object.property("foo").isObject()); |
|
420 QVERIFY(!object.property("foo").isVariant()); |
|
421 QScriptValue originalProto = object.property("foo").prototype(); |
|
422 QScriptValue ret = eng.newVariant(object.property("foo"), QVariant(123)); |
|
423 QVERIFY(ret.isValid()); |
|
424 QVERIFY(ret.strictlyEquals(object.property("foo"))); |
|
425 QVERIFY(ret.isVariant()); |
|
426 QVERIFY(object.property("foo").isVariant()); |
|
427 QVERIFY(object.property("bar").isVariant()); |
|
428 QCOMPARE(ret.toVariant(), QVariant(123)); |
|
429 QVERIFY(ret.prototype().strictlyEquals(originalProto)); |
|
430 } |
|
431 // replace value of existing object |
|
432 { |
|
433 QScriptValue object = eng.newVariant(QVariant(123)); |
|
434 QScriptValue ret = eng.newVariant(object, QVariant(456)); |
|
435 QVERIFY(ret.isValid()); |
|
436 QVERIFY(ret.strictlyEquals(object)); |
|
437 QVERIFY(ret.isVariant()); |
|
438 QCOMPARE(ret.toVariant(), QVariant(456)); |
|
439 } |
|
440 |
|
441 // valueOf() and toString() |
|
442 { |
|
443 QScriptValue object = eng.newVariant(QVariant(123)); |
|
444 QScriptValue value = object.property("valueOf").call(object); |
|
445 QVERIFY(value.isNumber()); |
|
446 QCOMPARE(value.toInt32(), 123); |
|
447 QCOMPARE(object.toString(), QString::fromLatin1("123")); |
|
448 QCOMPARE(object.toVariant().toString(), object.toString()); |
|
449 } |
|
450 { |
|
451 QScriptValue object = eng.newVariant(QVariant(QString::fromLatin1("hello"))); |
|
452 QScriptValue value = object.property("valueOf").call(object); |
|
453 QVERIFY(value.isString()); |
|
454 QCOMPARE(value.toString(), QString::fromLatin1("hello")); |
|
455 QCOMPARE(object.toString(), QString::fromLatin1("hello")); |
|
456 QCOMPARE(object.toVariant().toString(), object.toString()); |
|
457 } |
|
458 { |
|
459 QScriptValue object = eng.newVariant(QVariant(false)); |
|
460 QScriptValue value = object.property("valueOf").call(object); |
|
461 QVERIFY(value.isBoolean()); |
|
462 QCOMPARE(value.toBoolean(), false); |
|
463 QCOMPARE(object.toString(), QString::fromLatin1("false")); |
|
464 QCOMPARE(object.toVariant().toString(), object.toString()); |
|
465 } |
|
466 { |
|
467 QScriptValue object = eng.newVariant(QVariant(QPoint(10, 20))); |
|
468 QScriptValue value = object.property("valueOf").call(object); |
|
469 QVERIFY(value.isObject()); |
|
470 QVERIFY(value.strictlyEquals(object)); |
|
471 QCOMPARE(object.toString(), QString::fromLatin1("QVariant(QPoint)")); |
|
472 } |
|
473 } |
|
474 |
|
475 void tst_QScriptEngine::newRegExp() |
|
476 { |
|
477 QScriptEngine eng; |
|
478 for (int x = 0; x < 2; ++x) { |
|
479 QScriptValue rexp; |
|
480 if (x == 0) |
|
481 rexp = eng.newRegExp("foo", "bar"); |
|
482 else |
|
483 rexp = eng.newRegExp(QRegExp("foo")); |
|
484 QCOMPARE(rexp.isValid(), true); |
|
485 QCOMPARE(rexp.isRegExp(), true); |
|
486 QCOMPARE(rexp.isObject(), true); |
|
487 QVERIFY(rexp.isFunction()); // in JSC, RegExp objects are callable |
|
488 // prototype should be RegExp.prototype |
|
489 QCOMPARE(rexp.prototype().isValid(), true); |
|
490 QCOMPARE(rexp.prototype().isObject(), true); |
|
491 QCOMPARE(rexp.prototype().isRegExp(), false); |
|
492 QCOMPARE(rexp.prototype().strictlyEquals(eng.evaluate("RegExp.prototype")), true); |
|
493 |
|
494 QCOMPARE(rexp.toRegExp().pattern(), QRegExp("foo").pattern()); |
|
495 } |
|
496 { |
|
497 QScriptValue r = eng.evaluate("/foo/gim"); |
|
498 QVERIFY(r.isRegExp()); |
|
499 QCOMPARE(r.toString(), QString::fromLatin1("/foo/gim")); |
|
500 |
|
501 QScriptValue rxCtor = eng.globalObject().property("RegExp"); |
|
502 QScriptValue r2 = rxCtor.call(QScriptValue(), QScriptValueList() << r); |
|
503 QVERIFY(r2.isRegExp()); |
|
504 QVERIFY(r2.strictlyEquals(r)); |
|
505 |
|
506 QScriptValue r3 = rxCtor.call(QScriptValue(), QScriptValueList() << r << "gim"); |
|
507 QVERIFY(r3.isError()); |
|
508 QCOMPARE(r3.toString(), QString::fromLatin1("TypeError: Cannot supply flags when constructing one RegExp from another.")); |
|
509 |
|
510 QScriptValue r4 = rxCtor.call(QScriptValue(), QScriptValueList() << "foo" << "gim"); |
|
511 QVERIFY(r4.isRegExp()); |
|
512 |
|
513 QScriptValue r5 = rxCtor.construct(QScriptValueList() << r); |
|
514 QVERIFY(r5.isRegExp()); |
|
515 QCOMPARE(r5.toString(), QString::fromLatin1("/foo/gim")); |
|
516 // In JSC, constructing a RegExp from another produces the same identical object. |
|
517 // This is different from SpiderMonkey and old back-end. |
|
518 QVERIFY(r5.strictlyEquals(r)); |
|
519 |
|
520 QScriptValue r6 = rxCtor.construct(QScriptValueList() << "foo" << "bar"); |
|
521 QVERIFY(r6.isError()); |
|
522 QCOMPARE(r6.toString(), QString::fromLatin1("SyntaxError: Invalid regular expression: invalid regular expression flag")); |
|
523 |
|
524 QScriptValue r7 = eng.evaluate("/foo/gimp"); |
|
525 QVERIFY(r7.isError()); |
|
526 QCOMPARE(r7.toString(), QString::fromLatin1("SyntaxError: Invalid regular expression: invalid regular expression flag")); |
|
527 |
|
528 QScriptValue r8 = eng.evaluate("/foo/migmigmig"); |
|
529 QVERIFY(r8.isRegExp()); |
|
530 QCOMPARE(r8.toString(), QString::fromLatin1("/foo/gim")); |
|
531 |
|
532 QScriptValue r9 = rxCtor.construct(); |
|
533 QVERIFY(r9.isRegExp()); |
|
534 QCOMPARE(r9.toString(), QString::fromLatin1("/(?:)/")); |
|
535 |
|
536 QScriptValue r10 = rxCtor.construct(QScriptValueList() << "" << "gim"); |
|
537 QVERIFY(r10.isRegExp()); |
|
538 QCOMPARE(r10.toString(), QString::fromLatin1("/(?:)/gim")); |
|
539 |
|
540 QScriptValue r11 = rxCtor.construct(QScriptValueList() << "{1.*}" << "g"); |
|
541 QVERIFY(r11.isRegExp()); |
|
542 QCOMPARE(r11.toString(), QString::fromLatin1("/{1.*}/g")); |
|
543 } |
|
544 } |
|
545 |
|
546 void tst_QScriptEngine::newDate() |
|
547 { |
|
548 QScriptEngine eng; |
|
549 |
|
550 { |
|
551 QScriptValue date = eng.newDate(0); |
|
552 QCOMPARE(date.isValid(), true); |
|
553 QCOMPARE(date.isDate(), true); |
|
554 QCOMPARE(date.isObject(), true); |
|
555 QVERIFY(!date.isFunction()); |
|
556 // prototype should be Date.prototype |
|
557 QCOMPARE(date.prototype().isValid(), true); |
|
558 QCOMPARE(date.prototype().isDate(), true); |
|
559 QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true); |
|
560 } |
|
561 |
|
562 { |
|
563 QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::LocalTime); |
|
564 QScriptValue date = eng.newDate(dt); |
|
565 QCOMPARE(date.isValid(), true); |
|
566 QCOMPARE(date.isDate(), true); |
|
567 QCOMPARE(date.isObject(), true); |
|
568 // prototype should be Date.prototype |
|
569 QCOMPARE(date.prototype().isValid(), true); |
|
570 QCOMPARE(date.prototype().isDate(), true); |
|
571 QCOMPARE(date.prototype().strictlyEquals(eng.evaluate("Date.prototype")), true); |
|
572 |
|
573 QCOMPARE(date.toDateTime(), dt); |
|
574 } |
|
575 |
|
576 { |
|
577 QDateTime dt = QDateTime(QDate(1, 2, 3), QTime(4, 5, 6, 7), Qt::UTC); |
|
578 QScriptValue date = eng.newDate(dt); |
|
579 // toDateTime() result should be in local time |
|
580 QCOMPARE(date.toDateTime(), dt.toLocalTime()); |
|
581 } |
|
582 |
|
583 // Date.parse() should return NaN when it fails |
|
584 { |
|
585 QScriptValue ret = eng.evaluate("Date.parse()"); |
|
586 QVERIFY(ret.isNumber()); |
|
587 QVERIFY(qIsNaN(ret.toNumber())); |
|
588 } |
|
589 |
|
590 // Date.parse() should be able to parse the output of Date().toString() |
|
591 #ifndef Q_WS_WIN // TODO: Test and remove this since 169701 has been fixed |
|
592 { |
|
593 QScriptValue ret = eng.evaluate("var x = new Date(); var s = x.toString(); s == new Date(Date.parse(s)).toString()"); |
|
594 QVERIFY(ret.isBoolean()); |
|
595 QCOMPARE(ret.toBoolean(), true); |
|
596 } |
|
597 #endif |
|
598 } |
|
599 |
|
600 void tst_QScriptEngine::newQObject() |
|
601 { |
|
602 QScriptEngine eng; |
|
603 |
|
604 { |
|
605 QScriptValue qobject = eng.newQObject(0); |
|
606 QCOMPARE(qobject.isValid(), true); |
|
607 QCOMPARE(qobject.isNull(), true); |
|
608 QCOMPARE(qobject.isObject(), false); |
|
609 QCOMPARE(qobject.toQObject(), (QObject *)0); |
|
610 } |
|
611 { |
|
612 QScriptValue qobject = eng.newQObject(this); |
|
613 QCOMPARE(qobject.isValid(), true); |
|
614 QCOMPARE(qobject.isQObject(), true); |
|
615 QCOMPARE(qobject.isObject(), true); |
|
616 QCOMPARE(qobject.toQObject(), (QObject *)this); |
|
617 QVERIFY(!qobject.isFunction()); |
|
618 // prototype should be QObject.prototype |
|
619 QCOMPARE(qobject.prototype().isValid(), true); |
|
620 QCOMPARE(qobject.prototype().isQObject(), true); |
|
621 QCOMPARE(qobject.scriptClass(), (QScriptClass*)0); |
|
622 } |
|
623 |
|
624 // test ownership |
|
625 { |
|
626 QPointer<QObject> ptr = new QObject(); |
|
627 QVERIFY(ptr != 0); |
|
628 { |
|
629 QScriptValue v = eng.newQObject(ptr, QScriptEngine::ScriptOwnership); |
|
630 } |
|
631 eng.evaluate("gc()"); |
|
632 if (ptr) |
|
633 QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue); |
|
634 QVERIFY(ptr == 0); |
|
635 } |
|
636 { |
|
637 QPointer<QObject> ptr = new QObject(); |
|
638 QVERIFY(ptr != 0); |
|
639 { |
|
640 QScriptValue v = eng.newQObject(ptr, QScriptEngine::QtOwnership); |
|
641 } |
|
642 QObject *before = ptr; |
|
643 eng.evaluate("gc()"); |
|
644 QVERIFY(ptr == before); |
|
645 delete ptr; |
|
646 } |
|
647 { |
|
648 QObject *parent = new QObject(); |
|
649 QObject *child = new QObject(parent); |
|
650 QScriptValue v = eng.newQObject(child, QScriptEngine::QtOwnership); |
|
651 QCOMPARE(v.toQObject(), child); |
|
652 delete parent; |
|
653 QCOMPARE(v.toQObject(), (QObject *)0); |
|
654 } |
|
655 { |
|
656 QPointer<QObject> ptr = new QObject(); |
|
657 QVERIFY(ptr != 0); |
|
658 { |
|
659 QScriptValue v = eng.newQObject(ptr, QScriptEngine::AutoOwnership); |
|
660 } |
|
661 eng.evaluate("gc()"); |
|
662 // no parent, so it should be like ScriptOwnership |
|
663 if (ptr) |
|
664 QEXPECT_FAIL("", "In the JSC-based back-end, script-owned QObjects are not always deleted immediately during GC", Continue); |
|
665 QVERIFY(ptr == 0); |
|
666 } |
|
667 { |
|
668 QObject *parent = new QObject(); |
|
669 QPointer<QObject> child = new QObject(parent); |
|
670 QVERIFY(child != 0); |
|
671 { |
|
672 QScriptValue v = eng.newQObject(child, QScriptEngine::AutoOwnership); |
|
673 } |
|
674 eng.evaluate("gc()"); |
|
675 // has parent, so it should be like QtOwnership |
|
676 QVERIFY(child != 0); |
|
677 delete parent; |
|
678 } |
|
679 |
|
680 // "promote" plain object to QObject |
|
681 { |
|
682 QScriptValue obj = eng.newObject(); |
|
683 QScriptValue originalProto = obj.prototype(); |
|
684 QScriptValue ret = eng.newQObject(obj, this); |
|
685 QVERIFY(ret.isValid()); |
|
686 QVERIFY(ret.isQObject()); |
|
687 QVERIFY(ret.strictlyEquals(obj)); |
|
688 QVERIFY(obj.isQObject()); |
|
689 QCOMPARE(ret.toQObject(), (QObject *)this); |
|
690 QVERIFY(ret.prototype().strictlyEquals(originalProto)); |
|
691 QScriptValue val = ret.property("objectName"); |
|
692 QVERIFY(val.isString()); |
|
693 } |
|
694 // "promote" variant object to QObject |
|
695 { |
|
696 QScriptValue obj = eng.newVariant(123); |
|
697 QVERIFY(obj.isVariant()); |
|
698 QScriptValue originalProto = obj.prototype(); |
|
699 QScriptValue ret = eng.newQObject(obj, this); |
|
700 QVERIFY(ret.isQObject()); |
|
701 QVERIFY(ret.strictlyEquals(obj)); |
|
702 QVERIFY(obj.isQObject()); |
|
703 QCOMPARE(ret.toQObject(), (QObject *)this); |
|
704 QVERIFY(ret.prototype().strictlyEquals(originalProto)); |
|
705 } |
|
706 // replace QObject* of existing object |
|
707 { |
|
708 QScriptValue object = eng.newVariant(123); |
|
709 QScriptValue originalProto = object.prototype(); |
|
710 QObject otherQObject; |
|
711 QScriptValue ret = eng.newQObject(object, &otherQObject); |
|
712 QVERIFY(ret.isValid()); |
|
713 QVERIFY(ret.isQObject()); |
|
714 QVERIFY(ret.strictlyEquals(object)); |
|
715 QCOMPARE(ret.toQObject(), (QObject *)&otherQObject); |
|
716 QVERIFY(ret.prototype().strictlyEquals(originalProto)); |
|
717 } |
|
718 |
|
719 // calling newQObject() several times with same object |
|
720 for (int x = 0; x < 2; ++x) { |
|
721 QObject qobj; |
|
722 // the default is to create a new wrapper object |
|
723 QScriptValue obj1 = eng.newQObject(&qobj); |
|
724 QScriptValue obj2 = eng.newQObject(&qobj); |
|
725 QVERIFY(!obj2.strictlyEquals(obj1)); |
|
726 |
|
727 QScriptEngine::QObjectWrapOptions opt = 0; |
|
728 bool preferExisting = (x != 0); |
|
729 if (preferExisting) |
|
730 opt |= QScriptEngine::PreferExistingWrapperObject; |
|
731 |
|
732 QScriptValue obj3 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt); |
|
733 QVERIFY(!obj3.strictlyEquals(obj2)); |
|
734 QScriptValue obj4 = eng.newQObject(&qobj, QScriptEngine::AutoOwnership, opt); |
|
735 QCOMPARE(obj4.strictlyEquals(obj3), preferExisting); |
|
736 |
|
737 QScriptValue obj5 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt); |
|
738 QVERIFY(!obj5.strictlyEquals(obj4)); |
|
739 QScriptValue obj6 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, opt); |
|
740 QCOMPARE(obj6.strictlyEquals(obj5), preferExisting); |
|
741 |
|
742 QScriptValue obj7 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, |
|
743 QScriptEngine::ExcludeSuperClassMethods | opt); |
|
744 QVERIFY(!obj7.strictlyEquals(obj6)); |
|
745 QScriptValue obj8 = eng.newQObject(&qobj, QScriptEngine::ScriptOwnership, |
|
746 QScriptEngine::ExcludeSuperClassMethods | opt); |
|
747 QCOMPARE(obj8.strictlyEquals(obj7), preferExisting); |
|
748 } |
|
749 |
|
750 // newQObject() should set the default prototype, if one has been registered |
|
751 { |
|
752 QScriptValue oldQObjectProto = eng.defaultPrototype(qMetaTypeId<QObject*>()); |
|
753 |
|
754 QScriptValue qobjectProto = eng.newObject(); |
|
755 eng.setDefaultPrototype(qMetaTypeId<QObject*>(), qobjectProto); |
|
756 { |
|
757 QScriptValue ret = eng.newQObject(this); |
|
758 QVERIFY(ret.prototype().equals(qobjectProto)); |
|
759 } |
|
760 QScriptValue tstProto = eng.newObject(); |
|
761 int typeId = qRegisterMetaType<tst_QScriptEngine*>("tst_QScriptEngine*"); |
|
762 eng.setDefaultPrototype(typeId, tstProto); |
|
763 { |
|
764 QScriptValue ret = eng.newQObject(this); |
|
765 QVERIFY(ret.prototype().equals(tstProto)); |
|
766 } |
|
767 |
|
768 eng.setDefaultPrototype(qMetaTypeId<QObject*>(), oldQObjectProto); |
|
769 eng.setDefaultPrototype(typeId, QScriptValue()); |
|
770 } |
|
771 } |
|
772 |
|
773 QT_BEGIN_NAMESPACE |
|
774 Q_SCRIPT_DECLARE_QMETAOBJECT(QObject, QObject*) |
|
775 Q_SCRIPT_DECLARE_QMETAOBJECT(QWidget, QWidget*) |
|
776 QT_END_NAMESPACE |
|
777 |
|
778 static QScriptValue myConstructor(QScriptContext *ctx, QScriptEngine *eng) |
|
779 { |
|
780 QScriptValue obj; |
|
781 if (ctx->isCalledAsConstructor()) { |
|
782 obj = ctx->thisObject(); |
|
783 } else { |
|
784 obj = eng->newObject(); |
|
785 obj.setPrototype(ctx->callee().property("prototype")); |
|
786 } |
|
787 obj.setProperty("isCalledAsConstructor", QScriptValue(eng, ctx->isCalledAsConstructor())); |
|
788 return obj; |
|
789 } |
|
790 |
|
791 void tst_QScriptEngine::newQMetaObject() |
|
792 { |
|
793 QScriptEngine eng; |
|
794 #if 0 |
|
795 QScriptValue qclass = eng.newQMetaObject<QObject>(); |
|
796 QScriptValue qclass2 = eng.newQMetaObject<QWidget>(); |
|
797 #else |
|
798 QScriptValue qclass = qScriptValueFromQMetaObject<QObject>(&eng); |
|
799 QScriptValue qclass2 = qScriptValueFromQMetaObject<QWidget>(&eng); |
|
800 #endif |
|
801 QCOMPARE(qclass.isValid(), true); |
|
802 QCOMPARE(qclass.isQMetaObject(), true); |
|
803 QCOMPARE(qclass.toQMetaObject(), &QObject::staticMetaObject); |
|
804 QCOMPARE(qclass.isFunction(), true); |
|
805 QVERIFY(qclass.property("prototype").isObject()); |
|
806 |
|
807 QCOMPARE(qclass2.isValid(), true); |
|
808 QCOMPARE(qclass2.isQMetaObject(), true); |
|
809 QCOMPARE(qclass2.toQMetaObject(), &QWidget::staticMetaObject); |
|
810 QCOMPARE(qclass2.isFunction(), true); |
|
811 QVERIFY(qclass2.property("prototype").isObject()); |
|
812 |
|
813 // prototype should be QMetaObject.prototype |
|
814 QCOMPARE(qclass.prototype().isObject(), true); |
|
815 QCOMPARE(qclass2.prototype().isObject(), true); |
|
816 |
|
817 QScriptValue instance = qclass.construct(); |
|
818 QCOMPARE(instance.isQObject(), true); |
|
819 QCOMPARE(instance.toQObject()->metaObject(), qclass.toQMetaObject()); |
|
820 QVERIFY(instance.instanceOf(qclass)); |
|
821 |
|
822 QScriptValue instance2 = qclass2.construct(); |
|
823 QCOMPARE(instance2.isQObject(), true); |
|
824 QCOMPARE(instance2.toQObject()->metaObject(), qclass2.toQMetaObject()); |
|
825 QVERIFY(instance2.instanceOf(qclass2)); |
|
826 |
|
827 QScriptValueList args; |
|
828 args << instance; |
|
829 QScriptValue instance3 = qclass.construct(args); |
|
830 QCOMPARE(instance3.isQObject(), true); |
|
831 QCOMPARE(instance3.toQObject()->parent(), instance.toQObject()); |
|
832 QVERIFY(instance3.instanceOf(qclass)); |
|
833 args.clear(); |
|
834 |
|
835 QPointer<QObject> qpointer1 = instance.toQObject(); |
|
836 QPointer<QObject> qpointer2 = instance2.toQObject(); |
|
837 QPointer<QObject> qpointer3 = instance3.toQObject(); |
|
838 |
|
839 QVERIFY(qpointer1); |
|
840 QVERIFY(qpointer2); |
|
841 QVERIFY(qpointer3); |
|
842 |
|
843 // verify that AutoOwnership is in effect |
|
844 instance = QScriptValue(); |
|
845 collectGarbage_helper(eng); |
|
846 |
|
847 QVERIFY(!qpointer1); |
|
848 QVERIFY(qpointer2); |
|
849 QVERIFY(!qpointer3); // was child of instance |
|
850 |
|
851 QVERIFY(instance.toQObject() == 0); |
|
852 QVERIFY(instance3.toQObject() == 0); // was child of instance |
|
853 QVERIFY(instance2.toQObject() != 0); |
|
854 instance2 = QScriptValue(); |
|
855 collectGarbage_helper(eng); |
|
856 QVERIFY(instance2.toQObject() == 0); |
|
857 |
|
858 // with custom constructor |
|
859 QScriptValue ctor = eng.newFunction(myConstructor); |
|
860 QScriptValue qclass3 = eng.newQMetaObject(&QObject::staticMetaObject, ctor); |
|
861 QVERIFY(qclass3.property("prototype").equals(ctor.property("prototype"))); |
|
862 { |
|
863 QScriptValue ret = qclass3.call(); |
|
864 QVERIFY(ret.isObject()); |
|
865 QVERIFY(ret.property("isCalledAsConstructor").isBoolean()); |
|
866 QVERIFY(!ret.property("isCalledAsConstructor").toBoolean()); |
|
867 QVERIFY(ret.instanceOf(qclass3)); |
|
868 } |
|
869 { |
|
870 QScriptValue ret = qclass3.construct(); |
|
871 QVERIFY(ret.isObject()); |
|
872 QVERIFY(ret.property("isCalledAsConstructor").isBoolean()); |
|
873 QVERIFY(ret.property("isCalledAsConstructor").toBoolean()); |
|
874 QVERIFY(ret.instanceOf(qclass3)); |
|
875 } |
|
876 |
|
877 // subclassing |
|
878 qclass2.setProperty("prototype", qclass.construct()); |
|
879 QVERIFY(qclass2.construct().instanceOf(qclass)); |
|
880 |
|
881 // with meta-constructor |
|
882 QScriptValue qclass4 = eng.newQMetaObject(&QObject::staticMetaObject); |
|
883 { |
|
884 QScriptValue inst = qclass4.construct(); |
|
885 QVERIFY(inst.isQObject()); |
|
886 QVERIFY(inst.toQObject() != 0); |
|
887 QCOMPARE(inst.toQObject()->parent(), (QObject*)0); |
|
888 QVERIFY(inst.instanceOf(qclass4)); |
|
889 } |
|
890 { |
|
891 QScriptValue inst = qclass4.construct(QScriptValueList() << eng.newQObject(this)); |
|
892 QVERIFY(inst.isQObject()); |
|
893 QVERIFY(inst.toQObject() != 0); |
|
894 QCOMPARE(inst.toQObject()->parent(), (QObject*)this); |
|
895 QVERIFY(inst.instanceOf(qclass4)); |
|
896 } |
|
897 } |
|
898 |
|
899 void tst_QScriptEngine::newActivationObject() |
|
900 { |
|
901 QSKIP("internal function not implemented in JSC-based back-end", SkipAll); |
|
902 QScriptEngine eng; |
|
903 QScriptValue act = eng.newActivationObject(); |
|
904 QEXPECT_FAIL("", "", Continue); |
|
905 QCOMPARE(act.isValid(), true); |
|
906 QEXPECT_FAIL("", "", Continue); |
|
907 QCOMPARE(act.isObject(), true); |
|
908 QVERIFY(!act.isFunction()); |
|
909 QScriptValue v(&eng, 123); |
|
910 act.setProperty("prop", v); |
|
911 QEXPECT_FAIL("", "", Continue); |
|
912 QCOMPARE(act.property("prop").strictlyEquals(v), true); |
|
913 QCOMPARE(act.scope().isValid(), false); |
|
914 QEXPECT_FAIL("", "", Continue); |
|
915 QVERIFY(act.prototype().isNull()); |
|
916 } |
|
917 |
|
918 void tst_QScriptEngine::getSetGlobalObject() |
|
919 { |
|
920 QScriptEngine eng; |
|
921 QScriptValue glob = eng.globalObject(); |
|
922 QCOMPARE(glob.isValid(), true); |
|
923 QCOMPARE(glob.isObject(), true); |
|
924 QVERIFY(!glob.isFunction()); |
|
925 QVERIFY(eng.currentContext()->thisObject().strictlyEquals(glob)); |
|
926 QVERIFY(eng.currentContext()->activationObject().strictlyEquals(glob)); |
|
927 QCOMPARE(glob.toString(), QString::fromLatin1("[object global]")); |
|
928 // prototype should be Object.prototype |
|
929 QCOMPARE(glob.prototype().isValid(), true); |
|
930 QCOMPARE(glob.prototype().isObject(), true); |
|
931 QCOMPARE(glob.prototype().strictlyEquals(eng.evaluate("Object.prototype")), true); |
|
932 |
|
933 QScriptValue obj = eng.newObject(); |
|
934 eng.setGlobalObject(obj); |
|
935 QVERIFY(eng.globalObject().strictlyEquals(obj)); |
|
936 QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj)); |
|
937 QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj)); |
|
938 QVERIFY(eng.evaluate("this").strictlyEquals(obj)); |
|
939 QCOMPARE(eng.globalObject().toString(), QString::fromLatin1("[object Object]")); |
|
940 |
|
941 glob = QScriptValue(); // kill reference to old global object |
|
942 collectGarbage_helper(eng); |
|
943 obj = eng.newObject(); |
|
944 eng.setGlobalObject(obj); |
|
945 QVERIFY(eng.globalObject().strictlyEquals(obj)); |
|
946 QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj)); |
|
947 QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj)); |
|
948 |
|
949 collectGarbage_helper(eng); |
|
950 QVERIFY(eng.globalObject().strictlyEquals(obj)); |
|
951 QVERIFY(eng.currentContext()->thisObject().strictlyEquals(obj)); |
|
952 QVERIFY(eng.currentContext()->activationObject().strictlyEquals(obj)); |
|
953 |
|
954 QVERIFY(!obj.property("foo").isValid()); |
|
955 eng.evaluate("var foo = 123"); |
|
956 { |
|
957 QScriptValue ret = obj.property("foo"); |
|
958 QVERIFY(ret.isNumber()); |
|
959 QCOMPARE(ret.toInt32(), 123); |
|
960 } |
|
961 |
|
962 QVERIFY(!obj.property("bar").isValid()); |
|
963 eng.evaluate("bar = 456"); |
|
964 { |
|
965 QScriptValue ret = obj.property("bar"); |
|
966 QVERIFY(ret.isNumber()); |
|
967 QCOMPARE(ret.toInt32(), 456); |
|
968 } |
|
969 |
|
970 QVERIFY(!obj.property("baz").isValid()); |
|
971 eng.evaluate("this['baz'] = 789"); |
|
972 { |
|
973 QScriptValue ret = obj.property("baz"); |
|
974 QVERIFY(ret.isNumber()); |
|
975 QCOMPARE(ret.toInt32(), 789); |
|
976 } |
|
977 |
|
978 { |
|
979 QScriptValue ret = eng.evaluate("(function() { return this; })()"); |
|
980 QVERIFY(ret.strictlyEquals(obj)); |
|
981 } |
|
982 } |
|
983 |
|
984 static QScriptValue getSetFoo(QScriptContext *ctx, QScriptEngine *) |
|
985 { |
|
986 if (ctx->argumentCount() > 0) |
|
987 ctx->thisObject().setProperty("foo", ctx->argument(0)); |
|
988 return ctx->thisObject().property("foo"); |
|
989 } |
|
990 |
|
991 void tst_QScriptEngine::globalObjectProperties() |
|
992 { |
|
993 QScriptEngine eng; |
|
994 QScriptValue global = eng.globalObject(); |
|
995 |
|
996 QVERIFY(global.property("NaN").isNumber()); |
|
997 QVERIFY(qIsNaN(global.property("NaN").toNumber())); |
|
998 QCOMPARE(global.propertyFlags("NaN"), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable); |
|
999 |
|
1000 QVERIFY(global.property("Infinity").isNumber()); |
|
1001 QVERIFY(qIsInf(global.property("Infinity").toNumber())); |
|
1002 QCOMPARE(global.propertyFlags("NaN"), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable); |
|
1003 |
|
1004 QVERIFY(global.property("undefined").isUndefined()); |
|
1005 QCOMPARE(global.propertyFlags("undefined"), QScriptValue::SkipInEnumeration | QScriptValue::Undeletable); |
|
1006 |
|
1007 QVERIFY(global.property("eval").isFunction()); |
|
1008 QCOMPARE(global.propertyFlags("eval"), QScriptValue::SkipInEnumeration); |
|
1009 |
|
1010 QVERIFY(global.property("parseInt").isFunction()); |
|
1011 QCOMPARE(global.propertyFlags("parseInt"), QScriptValue::SkipInEnumeration); |
|
1012 |
|
1013 QVERIFY(global.property("parseFloat").isFunction()); |
|
1014 QCOMPARE(global.propertyFlags("parseFloat"), QScriptValue::SkipInEnumeration); |
|
1015 |
|
1016 QVERIFY(global.property("isNaN").isFunction()); |
|
1017 QCOMPARE(global.propertyFlags("isNaN"), QScriptValue::SkipInEnumeration); |
|
1018 |
|
1019 QVERIFY(global.property("isFinite").isFunction()); |
|
1020 QCOMPARE(global.propertyFlags("isFinite"), QScriptValue::SkipInEnumeration); |
|
1021 |
|
1022 QVERIFY(global.property("decodeURI").isFunction()); |
|
1023 QCOMPARE(global.propertyFlags("decodeURI"), QScriptValue::SkipInEnumeration); |
|
1024 |
|
1025 QVERIFY(global.property("decodeURIComponent").isFunction()); |
|
1026 QCOMPARE(global.propertyFlags("decodeURIComponent"), QScriptValue::SkipInEnumeration); |
|
1027 |
|
1028 QVERIFY(global.property("encodeURI").isFunction()); |
|
1029 QCOMPARE(global.propertyFlags("encodeURI"), QScriptValue::SkipInEnumeration); |
|
1030 |
|
1031 QVERIFY(global.property("encodeURIComponent").isFunction()); |
|
1032 QCOMPARE(global.propertyFlags("encodeURIComponent"), QScriptValue::SkipInEnumeration); |
|
1033 |
|
1034 QVERIFY(global.property("Object").isFunction()); |
|
1035 QCOMPARE(global.propertyFlags("Object"), QScriptValue::SkipInEnumeration); |
|
1036 QVERIFY(global.property("Function").isFunction()); |
|
1037 QCOMPARE(global.propertyFlags("Function"), QScriptValue::SkipInEnumeration); |
|
1038 QVERIFY(global.property("Array").isFunction()); |
|
1039 QCOMPARE(global.propertyFlags("Array"), QScriptValue::SkipInEnumeration); |
|
1040 QVERIFY(global.property("String").isFunction()); |
|
1041 QCOMPARE(global.propertyFlags("String"), QScriptValue::SkipInEnumeration); |
|
1042 QVERIFY(global.property("Boolean").isFunction()); |
|
1043 QCOMPARE(global.propertyFlags("Boolean"), QScriptValue::SkipInEnumeration); |
|
1044 QVERIFY(global.property("Number").isFunction()); |
|
1045 QCOMPARE(global.propertyFlags("Number"), QScriptValue::SkipInEnumeration); |
|
1046 QVERIFY(global.property("Date").isFunction()); |
|
1047 QCOMPARE(global.propertyFlags("Date"), QScriptValue::SkipInEnumeration); |
|
1048 QVERIFY(global.property("RegExp").isFunction()); |
|
1049 QCOMPARE(global.propertyFlags("RegExp"), QScriptValue::SkipInEnumeration); |
|
1050 QVERIFY(global.property("Error").isFunction()); |
|
1051 QCOMPARE(global.propertyFlags("Error"), QScriptValue::SkipInEnumeration); |
|
1052 QVERIFY(global.property("EvalError").isFunction()); |
|
1053 QCOMPARE(global.propertyFlags("EvalError"), QScriptValue::SkipInEnumeration); |
|
1054 QVERIFY(global.property("RangeError").isFunction()); |
|
1055 QCOMPARE(global.propertyFlags("RangeError"), QScriptValue::SkipInEnumeration); |
|
1056 QVERIFY(global.property("ReferenceError").isFunction()); |
|
1057 QCOMPARE(global.propertyFlags("ReferenceError"), QScriptValue::SkipInEnumeration); |
|
1058 QVERIFY(global.property("SyntaxError").isFunction()); |
|
1059 QCOMPARE(global.propertyFlags("SyntaxError"), QScriptValue::SkipInEnumeration); |
|
1060 QVERIFY(global.property("TypeError").isFunction()); |
|
1061 QCOMPARE(global.propertyFlags("TypeError"), QScriptValue::SkipInEnumeration); |
|
1062 QVERIFY(global.property("URIError").isFunction()); |
|
1063 QCOMPARE(global.propertyFlags("URIError"), QScriptValue::SkipInEnumeration); |
|
1064 QVERIFY(global.property("Math").isObject()); |
|
1065 QVERIFY(!global.property("Math").isFunction()); |
|
1066 QEXPECT_FAIL("", "[ECMA compliance] JSC sets DontDelete flag for Math object", Continue); |
|
1067 QCOMPARE(global.propertyFlags("Math"), QScriptValue::SkipInEnumeration); |
|
1068 |
|
1069 // enumeration |
|
1070 QSet<QString> expectedNames; |
|
1071 expectedNames |
|
1072 << "isNaN" |
|
1073 << "parseFloat" |
|
1074 << "String" |
|
1075 << "EvalError" |
|
1076 << "URIError" |
|
1077 << "Math" |
|
1078 << "encodeURIComponent" |
|
1079 << "RangeError" |
|
1080 << "eval" |
|
1081 << "isFinite" |
|
1082 << "ReferenceError" |
|
1083 << "Infinity" |
|
1084 << "Function" |
|
1085 << "RegExp" |
|
1086 << "Number" |
|
1087 << "parseInt" |
|
1088 << "Object" |
|
1089 << "decodeURI" |
|
1090 << "TypeError" |
|
1091 << "Boolean" |
|
1092 << "encodeURI" |
|
1093 << "NaN" |
|
1094 << "Error" |
|
1095 << "decodeURIComponent" |
|
1096 << "Date" |
|
1097 << "Array" |
|
1098 << "escape" |
|
1099 << "unescape" |
|
1100 << "SyntaxError" |
|
1101 << "undefined" |
|
1102 // non-standard |
|
1103 << "gc" |
|
1104 << "version" |
|
1105 << "print" |
|
1106 // JavaScriptCore |
|
1107 << "JSON" |
|
1108 ; |
|
1109 QSet<QString> actualNames; |
|
1110 { |
|
1111 QScriptValueIterator it(global); |
|
1112 while (it.hasNext()) { |
|
1113 it.next(); |
|
1114 actualNames.insert(it.name()); |
|
1115 } |
|
1116 } |
|
1117 |
|
1118 QSet<QString> remainingNames = actualNames; |
|
1119 { |
|
1120 QSet<QString>::const_iterator it; |
|
1121 for (it = expectedNames.constBegin(); it != expectedNames.constEnd(); ++it) { |
|
1122 QString name = *it; |
|
1123 QVERIFY(actualNames.contains(name)); |
|
1124 remainingNames.remove(name); |
|
1125 } |
|
1126 } |
|
1127 QVERIFY(remainingNames.isEmpty()); |
|
1128 |
|
1129 // create property with no attributes |
|
1130 { |
|
1131 QString name = QString::fromLatin1("foo"); |
|
1132 QVERIFY(!global.property(name).isValid()); |
|
1133 QScriptValue val(123); |
|
1134 global.setProperty(name, val); |
|
1135 QVERIFY(global.property(name).equals(val)); |
|
1136 QVERIFY(global.propertyFlags(name) == 0); |
|
1137 global.setProperty(name, QScriptValue()); |
|
1138 QVERIFY(!global.property(name).isValid()); |
|
1139 } |
|
1140 // create property with attributes |
|
1141 { |
|
1142 QString name = QString::fromLatin1("bar"); |
|
1143 QVERIFY(!global.property(name).isValid()); |
|
1144 QScriptValue val(QString::fromLatin1("ciao")); |
|
1145 QScriptValue::PropertyFlags flags = QScriptValue::ReadOnly | QScriptValue::SkipInEnumeration; |
|
1146 global.setProperty(name, val, flags); |
|
1147 QVERIFY(global.property(name).equals(val)); |
|
1148 QEXPECT_FAIL("", "custom Global Object properties don't retain attributes", Continue); |
|
1149 QCOMPARE(global.propertyFlags(name), flags); |
|
1150 global.setProperty(name, QScriptValue()); |
|
1151 QVERIFY(!global.property(name).isValid()); |
|
1152 } |
|
1153 } |
|
1154 |
|
1155 void tst_QScriptEngine::globalObjectGetterSetterProperty() |
|
1156 { |
|
1157 QScriptEngine engine; |
|
1158 QScriptValue global = engine.globalObject(); |
|
1159 global.setProperty("bar", engine.newFunction(getSetFoo), |
|
1160 QScriptValue::PropertySetter | QScriptValue::PropertyGetter); |
|
1161 global.setProperty("foo", 123); |
|
1162 QVERIFY(global.property("bar").equals(global.property("foo"))); |
|
1163 QVERIFY(engine.evaluate("bar").equals(global.property("foo"))); |
|
1164 global.setProperty("bar", 456); |
|
1165 QVERIFY(global.property("bar").equals(global.property("foo"))); |
|
1166 |
|
1167 engine.evaluate("__defineGetter__('baz', function() { return 789; })"); |
|
1168 QVERIFY(engine.evaluate("baz").equals(789)); |
|
1169 QVERIFY(global.property("baz").equals(789)); |
|
1170 } |
|
1171 |
|
1172 void tst_QScriptEngine::builtinFunctionNames_data() |
|
1173 { |
|
1174 QTest::addColumn<QString>("expression"); |
|
1175 QTest::addColumn<QString>("expectedName"); |
|
1176 |
|
1177 QTest::newRow("print") << QString("print") << QString("print"); |
|
1178 QTest::newRow("parseInt") << QString("parseInt") << QString("parseInt"); |
|
1179 QTest::newRow("parseFloat") << QString("parseFloat") << QString("parseFloat"); |
|
1180 QTest::newRow("isNaN") << QString("isNaN") << QString("isNaN"); |
|
1181 QTest::newRow("isFinite") << QString("isFinite") << QString("isFinite"); |
|
1182 QTest::newRow("decodeURI") << QString("decodeURI") << QString("decodeURI"); |
|
1183 QTest::newRow("decodeURIComponent") << QString("decodeURIComponent") << QString("decodeURIComponent"); |
|
1184 QTest::newRow("encodeURI") << QString("encodeURI") << QString("encodeURI"); |
|
1185 QTest::newRow("encodeURIComponent") << QString("encodeURIComponent") << QString("encodeURIComponent"); |
|
1186 QTest::newRow("escape") << QString("escape") << QString("escape"); |
|
1187 QTest::newRow("unescape") << QString("unescape") << QString("unescape"); |
|
1188 QTest::newRow("version") << QString("version") << QString("version"); |
|
1189 QTest::newRow("gc") << QString("gc") << QString("gc"); |
|
1190 |
|
1191 QTest::newRow("Array") << QString("Array") << QString("Array"); |
|
1192 QTest::newRow("Array.prototype.toString") << QString("Array.prototype.toString") << QString("toString"); |
|
1193 QTest::newRow("Array.prototype.toLocaleString") << QString("Array.prototype.toLocaleString") << QString("toLocaleString"); |
|
1194 QTest::newRow("Array.prototype.concat") << QString("Array.prototype.concat") << QString("concat"); |
|
1195 QTest::newRow("Array.prototype.join") << QString("Array.prototype.join") << QString("join"); |
|
1196 QTest::newRow("Array.prototype.pop") << QString("Array.prototype.pop") << QString("pop"); |
|
1197 QTest::newRow("Array.prototype.push") << QString("Array.prototype.push") << QString("push"); |
|
1198 QTest::newRow("Array.prototype.reverse") << QString("Array.prototype.reverse") << QString("reverse"); |
|
1199 QTest::newRow("Array.prototype.shift") << QString("Array.prototype.shift") << QString("shift"); |
|
1200 QTest::newRow("Array.prototype.slice") << QString("Array.prototype.slice") << QString("slice"); |
|
1201 QTest::newRow("Array.prototype.sort") << QString("Array.prototype.sort") << QString("sort"); |
|
1202 QTest::newRow("Array.prototype.splice") << QString("Array.prototype.splice") << QString("splice"); |
|
1203 QTest::newRow("Array.prototype.unshift") << QString("Array.prototype.unshift") << QString("unshift"); |
|
1204 |
|
1205 QTest::newRow("Boolean") << QString("Boolean") << QString("Boolean"); |
|
1206 QTest::newRow("Boolean.prototype.toString") << QString("Boolean.prototype.toString") << QString("toString"); |
|
1207 |
|
1208 QTest::newRow("Date") << QString("Date") << QString("Date"); |
|
1209 QTest::newRow("Date.prototype.toString") << QString("Date.prototype.toString") << QString("toString"); |
|
1210 QTest::newRow("Date.prototype.toDateString") << QString("Date.prototype.toDateString") << QString("toDateString"); |
|
1211 QTest::newRow("Date.prototype.toTimeString") << QString("Date.prototype.toTimeString") << QString("toTimeString"); |
|
1212 QTest::newRow("Date.prototype.toLocaleString") << QString("Date.prototype.toLocaleString") << QString("toLocaleString"); |
|
1213 QTest::newRow("Date.prototype.toLocaleDateString") << QString("Date.prototype.toLocaleDateString") << QString("toLocaleDateString"); |
|
1214 QTest::newRow("Date.prototype.toLocaleTimeString") << QString("Date.prototype.toLocaleTimeString") << QString("toLocaleTimeString"); |
|
1215 QTest::newRow("Date.prototype.valueOf") << QString("Date.prototype.valueOf") << QString("valueOf"); |
|
1216 QTest::newRow("Date.prototype.getTime") << QString("Date.prototype.getTime") << QString("getTime"); |
|
1217 QTest::newRow("Date.prototype.getYear") << QString("Date.prototype.getYear") << QString("getYear"); |
|
1218 QTest::newRow("Date.prototype.getFullYear") << QString("Date.prototype.getFullYear") << QString("getFullYear"); |
|
1219 QTest::newRow("Date.prototype.getUTCFullYear") << QString("Date.prototype.getUTCFullYear") << QString("getUTCFullYear"); |
|
1220 QTest::newRow("Date.prototype.getMonth") << QString("Date.prototype.getMonth") << QString("getMonth"); |
|
1221 QTest::newRow("Date.prototype.getUTCMonth") << QString("Date.prototype.getUTCMonth") << QString("getUTCMonth"); |
|
1222 QTest::newRow("Date.prototype.getDate") << QString("Date.prototype.getDate") << QString("getDate"); |
|
1223 QTest::newRow("Date.prototype.getUTCDate") << QString("Date.prototype.getUTCDate") << QString("getUTCDate"); |
|
1224 QTest::newRow("Date.prototype.getDay") << QString("Date.prototype.getDay") << QString("getDay"); |
|
1225 QTest::newRow("Date.prototype.getUTCDay") << QString("Date.prototype.getUTCDay") << QString("getUTCDay"); |
|
1226 QTest::newRow("Date.prototype.getHours") << QString("Date.prototype.getHours") << QString("getHours"); |
|
1227 QTest::newRow("Date.prototype.getUTCHours") << QString("Date.prototype.getUTCHours") << QString("getUTCHours"); |
|
1228 QTest::newRow("Date.prototype.getMinutes") << QString("Date.prototype.getMinutes") << QString("getMinutes"); |
|
1229 QTest::newRow("Date.prototype.getUTCMinutes") << QString("Date.prototype.getUTCMinutes") << QString("getUTCMinutes"); |
|
1230 QTest::newRow("Date.prototype.getSeconds") << QString("Date.prototype.getSeconds") << QString("getSeconds"); |
|
1231 QTest::newRow("Date.prototype.getUTCSeconds") << QString("Date.prototype.getUTCSeconds") << QString("getUTCSeconds"); |
|
1232 QTest::newRow("Date.prototype.getMilliseconds") << QString("Date.prototype.getMilliseconds") << QString("getMilliseconds"); |
|
1233 QTest::newRow("Date.prototype.getUTCMilliseconds") << QString("Date.prototype.getUTCMilliseconds") << QString("getUTCMilliseconds"); |
|
1234 QTest::newRow("Date.prototype.getTimezoneOffset") << QString("Date.prototype.getTimezoneOffset") << QString("getTimezoneOffset"); |
|
1235 QTest::newRow("Date.prototype.setTime") << QString("Date.prototype.setTime") << QString("setTime"); |
|
1236 QTest::newRow("Date.prototype.setMilliseconds") << QString("Date.prototype.setMilliseconds") << QString("setMilliseconds"); |
|
1237 QTest::newRow("Date.prototype.setUTCMilliseconds") << QString("Date.prototype.setUTCMilliseconds") << QString("setUTCMilliseconds"); |
|
1238 QTest::newRow("Date.prototype.setSeconds") << QString("Date.prototype.setSeconds") << QString("setSeconds"); |
|
1239 QTest::newRow("Date.prototype.setUTCSeconds") << QString("Date.prototype.setUTCSeconds") << QString("setUTCSeconds"); |
|
1240 QTest::newRow("Date.prototype.setMinutes") << QString("Date.prototype.setMinutes") << QString("setMinutes"); |
|
1241 QTest::newRow("Date.prototype.setUTCMinutes") << QString("Date.prototype.setUTCMinutes") << QString("setUTCMinutes"); |
|
1242 QTest::newRow("Date.prototype.setHours") << QString("Date.prototype.setHours") << QString("setHours"); |
|
1243 QTest::newRow("Date.prototype.setUTCHours") << QString("Date.prototype.setUTCHours") << QString("setUTCHours"); |
|
1244 QTest::newRow("Date.prototype.setDate") << QString("Date.prototype.setDate") << QString("setDate"); |
|
1245 QTest::newRow("Date.prototype.setUTCDate") << QString("Date.prototype.setUTCDate") << QString("setUTCDate"); |
|
1246 QTest::newRow("Date.prototype.setMonth") << QString("Date.prototype.setMonth") << QString("setMonth"); |
|
1247 QTest::newRow("Date.prototype.setUTCMonth") << QString("Date.prototype.setUTCMonth") << QString("setUTCMonth"); |
|
1248 QTest::newRow("Date.prototype.setYear") << QString("Date.prototype.setYear") << QString("setYear"); |
|
1249 QTest::newRow("Date.prototype.setFullYear") << QString("Date.prototype.setFullYear") << QString("setFullYear"); |
|
1250 QTest::newRow("Date.prototype.setUTCFullYear") << QString("Date.prototype.setUTCFullYear") << QString("setUTCFullYear"); |
|
1251 QTest::newRow("Date.prototype.toUTCString") << QString("Date.prototype.toUTCString") << QString("toUTCString"); |
|
1252 QTest::newRow("Date.prototype.toGMTString") << QString("Date.prototype.toGMTString") << QString("toGMTString"); |
|
1253 |
|
1254 QTest::newRow("Error") << QString("Error") << QString("Error"); |
|
1255 // QTest::newRow("Error.prototype.backtrace") << QString("Error.prototype.backtrace") << QString("backtrace"); |
|
1256 QTest::newRow("Error.prototype.toString") << QString("Error.prototype.toString") << QString("toString"); |
|
1257 |
|
1258 QTest::newRow("EvalError") << QString("EvalError") << QString("EvalError"); |
|
1259 QTest::newRow("RangeError") << QString("RangeError") << QString("RangeError"); |
|
1260 QTest::newRow("ReferenceError") << QString("ReferenceError") << QString("ReferenceError"); |
|
1261 QTest::newRow("SyntaxError") << QString("SyntaxError") << QString("SyntaxError"); |
|
1262 QTest::newRow("TypeError") << QString("TypeError") << QString("TypeError"); |
|
1263 QTest::newRow("URIError") << QString("URIError") << QString("URIError"); |
|
1264 |
|
1265 QTest::newRow("Function") << QString("Function") << QString("Function"); |
|
1266 QTest::newRow("Function.prototype.toString") << QString("Function.prototype.toString") << QString("toString"); |
|
1267 QTest::newRow("Function.prototype.apply") << QString("Function.prototype.apply") << QString("apply"); |
|
1268 QTest::newRow("Function.prototype.call") << QString("Function.prototype.call") << QString("call"); |
|
1269 QTest::newRow("Function.prototype.connect") << QString("Function.prototype.connect") << QString("connect"); |
|
1270 QTest::newRow("Function.prototype.disconnect") << QString("Function.prototype.disconnect") << QString("disconnect"); |
|
1271 |
|
1272 QTest::newRow("Math.abs") << QString("Math.abs") << QString("abs"); |
|
1273 QTest::newRow("Math.acos") << QString("Math.acos") << QString("acos"); |
|
1274 QTest::newRow("Math.asin") << QString("Math.asin") << QString("asin"); |
|
1275 QTest::newRow("Math.atan") << QString("Math.atan") << QString("atan"); |
|
1276 QTest::newRow("Math.atan2") << QString("Math.atan2") << QString("atan2"); |
|
1277 QTest::newRow("Math.ceil") << QString("Math.ceil") << QString("ceil"); |
|
1278 QTest::newRow("Math.cos") << QString("Math.cos") << QString("cos"); |
|
1279 QTest::newRow("Math.exp") << QString("Math.exp") << QString("exp"); |
|
1280 QTest::newRow("Math.floor") << QString("Math.floor") << QString("floor"); |
|
1281 QTest::newRow("Math.log") << QString("Math.log") << QString("log"); |
|
1282 QTest::newRow("Math.max") << QString("Math.max") << QString("max"); |
|
1283 QTest::newRow("Math.min") << QString("Math.min") << QString("min"); |
|
1284 QTest::newRow("Math.pow") << QString("Math.pow") << QString("pow"); |
|
1285 QTest::newRow("Math.random") << QString("Math.random") << QString("random"); |
|
1286 QTest::newRow("Math.round") << QString("Math.round") << QString("round"); |
|
1287 QTest::newRow("Math.sin") << QString("Math.sin") << QString("sin"); |
|
1288 QTest::newRow("Math.sqrt") << QString("Math.sqrt") << QString("sqrt"); |
|
1289 QTest::newRow("Math.tan") << QString("Math.tan") << QString("tan"); |
|
1290 |
|
1291 QTest::newRow("Number") << QString("Number") << QString("Number"); |
|
1292 QTest::newRow("Number.prototype.toString") << QString("Number.prototype.toString") << QString("toString"); |
|
1293 QTest::newRow("Number.prototype.toLocaleString") << QString("Number.prototype.toLocaleString") << QString("toLocaleString"); |
|
1294 QTest::newRow("Number.prototype.valueOf") << QString("Number.prototype.valueOf") << QString("valueOf"); |
|
1295 QTest::newRow("Number.prototype.toFixed") << QString("Number.prototype.toFixed") << QString("toFixed"); |
|
1296 QTest::newRow("Number.prototype.toExponential") << QString("Number.prototype.toExponential") << QString("toExponential"); |
|
1297 QTest::newRow("Number.prototype.toPrecision") << QString("Number.prototype.toPrecision") << QString("toPrecision"); |
|
1298 |
|
1299 QTest::newRow("Object") << QString("Object") << QString("Object"); |
|
1300 QTest::newRow("Object.prototype.toString") << QString("Object.prototype.toString") << QString("toString"); |
|
1301 QTest::newRow("Object.prototype.toLocaleString") << QString("Object.prototype.toLocaleString") << QString("toLocaleString"); |
|
1302 QTest::newRow("Object.prototype.valueOf") << QString("Object.prototype.valueOf") << QString("valueOf"); |
|
1303 QTest::newRow("Object.prototype.hasOwnProperty") << QString("Object.prototype.hasOwnProperty") << QString("hasOwnProperty"); |
|
1304 QTest::newRow("Object.prototype.isPrototypeOf") << QString("Object.prototype.isPrototypeOf") << QString("isPrototypeOf"); |
|
1305 QTest::newRow("Object.prototype.propertyIsEnumerable") << QString("Object.prototype.propertyIsEnumerable") << QString("propertyIsEnumerable"); |
|
1306 QTest::newRow("Object.prototype.__defineGetter__") << QString("Object.prototype.__defineGetter__") << QString("__defineGetter__"); |
|
1307 QTest::newRow("Object.prototype.__defineSetter__") << QString("Object.prototype.__defineSetter__") << QString("__defineSetter__"); |
|
1308 |
|
1309 QTest::newRow("RegExp") << QString("RegExp") << QString("RegExp"); |
|
1310 QTest::newRow("RegExp.prototype.exec") << QString("RegExp.prototype.exec") << QString("exec"); |
|
1311 QTest::newRow("RegExp.prototype.test") << QString("RegExp.prototype.test") << QString("test"); |
|
1312 QTest::newRow("RegExp.prototype.toString") << QString("RegExp.prototype.toString") << QString("toString"); |
|
1313 |
|
1314 QTest::newRow("String") << QString("String") << QString("String"); |
|
1315 QTest::newRow("String.prototype.toString") << QString("String.prototype.toString") << QString("toString"); |
|
1316 QTest::newRow("String.prototype.valueOf") << QString("String.prototype.valueOf") << QString("valueOf"); |
|
1317 QTest::newRow("String.prototype.charAt") << QString("String.prototype.charAt") << QString("charAt"); |
|
1318 QTest::newRow("String.prototype.charCodeAt") << QString("String.prototype.charCodeAt") << QString("charCodeAt"); |
|
1319 QTest::newRow("String.prototype.concat") << QString("String.prototype.concat") << QString("concat"); |
|
1320 QTest::newRow("String.prototype.indexOf") << QString("String.prototype.indexOf") << QString("indexOf"); |
|
1321 QTest::newRow("String.prototype.lastIndexOf") << QString("String.prototype.lastIndexOf") << QString("lastIndexOf"); |
|
1322 QTest::newRow("String.prototype.localeCompare") << QString("String.prototype.localeCompare") << QString("localeCompare"); |
|
1323 QTest::newRow("String.prototype.match") << QString("String.prototype.match") << QString("match"); |
|
1324 QTest::newRow("String.prototype.replace") << QString("String.prototype.replace") << QString("replace"); |
|
1325 QTest::newRow("String.prototype.search") << QString("String.prototype.search") << QString("search"); |
|
1326 QTest::newRow("String.prototype.slice") << QString("String.prototype.slice") << QString("slice"); |
|
1327 QTest::newRow("String.prototype.split") << QString("String.prototype.split") << QString("split"); |
|
1328 QTest::newRow("String.prototype.substring") << QString("String.prototype.substring") << QString("substring"); |
|
1329 QTest::newRow("String.prototype.toLowerCase") << QString("String.prototype.toLowerCase") << QString("toLowerCase"); |
|
1330 QTest::newRow("String.prototype.toLocaleLowerCase") << QString("String.prototype.toLocaleLowerCase") << QString("toLocaleLowerCase"); |
|
1331 QTest::newRow("String.prototype.toUpperCase") << QString("String.prototype.toUpperCase") << QString("toUpperCase"); |
|
1332 QTest::newRow("String.prototype.toLocaleUpperCase") << QString("String.prototype.toLocaleUpperCase") << QString("toLocaleUpperCase"); |
|
1333 } |
|
1334 |
|
1335 void tst_QScriptEngine::builtinFunctionNames() |
|
1336 { |
|
1337 QFETCH(QString, expression); |
|
1338 QFETCH(QString, expectedName); |
|
1339 QScriptEngine eng; |
|
1340 QScriptValue ret = eng.evaluate(QString::fromLatin1("%0.name").arg(expression)); |
|
1341 QVERIFY(ret.isString()); |
|
1342 QCOMPARE(ret.toString(), expectedName); |
|
1343 } |
|
1344 |
|
1345 void tst_QScriptEngine::checkSyntax_data() |
|
1346 { |
|
1347 QTest::addColumn<QString>("code"); |
|
1348 QTest::addColumn<int>("expectedState"); |
|
1349 QTest::addColumn<int>("errorLineNumber"); |
|
1350 QTest::addColumn<int>("errorColumnNumber"); |
|
1351 QTest::addColumn<QString>("errorMessage"); |
|
1352 |
|
1353 QTest::newRow("0") |
|
1354 << QString("0") << int(QScriptSyntaxCheckResult::Valid) |
|
1355 << -1 << -1 << ""; |
|
1356 QTest::newRow("if (") |
|
1357 << QString("if (\n") << int(QScriptSyntaxCheckResult::Intermediate) |
|
1358 << 1 << 4 << ""; |
|
1359 QTest::newRow("if else") |
|
1360 << QString("\nif else") << int(QScriptSyntaxCheckResult::Error) |
|
1361 << 2 << 4 << "Expected `('"; |
|
1362 QTest::newRow("foo[") |
|
1363 << QString("foo[") << int(QScriptSyntaxCheckResult::Error) |
|
1364 << 1 << 4 << ""; |
|
1365 QTest::newRow("foo['bar']") |
|
1366 << QString("foo['bar']") << int(QScriptSyntaxCheckResult::Valid) |
|
1367 << -1 << -1 << ""; |
|
1368 |
|
1369 QTest::newRow("/*") |
|
1370 << QString("/*") << int(QScriptSyntaxCheckResult::Intermediate) |
|
1371 << 1 << 1 << "Unclosed comment at end of file"; |
|
1372 QTest::newRow("/*\nMy comment") |
|
1373 << QString("/*\nMy comment") << int(QScriptSyntaxCheckResult::Intermediate) |
|
1374 << 1 << 1 << "Unclosed comment at end of file"; |
|
1375 QTest::newRow("/*\nMy comment */\nfoo = 10") |
|
1376 << QString("/*\nMy comment */\nfoo = 10") << int(QScriptSyntaxCheckResult::Valid) |
|
1377 << -1 << -1 << ""; |
|
1378 QTest::newRow("foo = 10 /*") |
|
1379 << QString("foo = 10 /*") << int(QScriptSyntaxCheckResult::Intermediate) |
|
1380 << -1 << -1 << ""; |
|
1381 QTest::newRow("foo = 10; /*") |
|
1382 << QString("foo = 10; /*") << int(QScriptSyntaxCheckResult::Intermediate) |
|
1383 << 1 << 11 << "Expected `end of file'"; |
|
1384 QTest::newRow("foo = 10 /* My comment */") |
|
1385 << QString("foo = 10 /* My comment */") << int(QScriptSyntaxCheckResult::Valid) |
|
1386 << -1 << -1 << ""; |
|
1387 |
|
1388 QTest::newRow("/=/") |
|
1389 << QString("/=/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << ""; |
|
1390 QTest::newRow("/=/g") |
|
1391 << QString("/=/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << ""; |
|
1392 QTest::newRow("/a/") |
|
1393 << QString("/a/") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << ""; |
|
1394 QTest::newRow("/a/g") |
|
1395 << QString("/a/g") << int(QScriptSyntaxCheckResult::Valid) << -1 << -1 << ""; |
|
1396 } |
|
1397 |
|
1398 void tst_QScriptEngine::checkSyntax() |
|
1399 { |
|
1400 QFETCH(QString, code); |
|
1401 QFETCH(int, expectedState); |
|
1402 QFETCH(int, errorLineNumber); |
|
1403 QFETCH(int, errorColumnNumber); |
|
1404 QFETCH(QString, errorMessage); |
|
1405 |
|
1406 QScriptSyntaxCheckResult result = QScriptEngine::checkSyntax(code); |
|
1407 QCOMPARE(result.state(), QScriptSyntaxCheckResult::State(expectedState)); |
|
1408 QCOMPARE(result.errorLineNumber(), errorLineNumber); |
|
1409 QCOMPARE(result.errorColumnNumber(), errorColumnNumber); |
|
1410 QCOMPARE(result.errorMessage(), errorMessage); |
|
1411 |
|
1412 // assignment |
|
1413 { |
|
1414 QScriptSyntaxCheckResult copy = result; |
|
1415 QCOMPARE(copy.state(), result.state()); |
|
1416 QCOMPARE(copy.errorLineNumber(), result.errorLineNumber()); |
|
1417 QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber()); |
|
1418 QCOMPARE(copy.errorMessage(), result.errorMessage()); |
|
1419 } |
|
1420 { |
|
1421 QScriptSyntaxCheckResult copy(result); |
|
1422 QCOMPARE(copy.state(), result.state()); |
|
1423 QCOMPARE(copy.errorLineNumber(), result.errorLineNumber()); |
|
1424 QCOMPARE(copy.errorColumnNumber(), result.errorColumnNumber()); |
|
1425 QCOMPARE(copy.errorMessage(), result.errorMessage()); |
|
1426 } |
|
1427 } |
|
1428 |
|
1429 void tst_QScriptEngine::canEvaluate_data() |
|
1430 { |
|
1431 QTest::addColumn<QString>("code"); |
|
1432 QTest::addColumn<bool>("expectSuccess"); |
|
1433 |
|
1434 QTest::newRow("") << QString("") << true; |
|
1435 QTest::newRow("0") << QString("0") << true; |
|
1436 QTest::newRow("!") << QString("!\n") << false; |
|
1437 QTest::newRow("if (") << QString("if (\n") << false; |
|
1438 QTest::newRow("if (10) //") << QString("if (10) //\n") << false; |
|
1439 QTest::newRow("a = 1; if (") << QString("a = 1;\nif (\n") << false; |
|
1440 QTest::newRow("./test.js") << QString("./test.js\n") << true; |
|
1441 QTest::newRow("if (0) print(1)") << QString("if (0)\nprint(1)\n") << true; |
|
1442 QTest::newRow("0 = ") << QString("0 = \n") << false; |
|
1443 QTest::newRow("0 = 0") << QString("0 = 0\n") << true; |
|
1444 QTest::newRow("foo[") << QString("foo[") << true; // automatic semicolon will be inserted |
|
1445 QTest::newRow("foo[") << QString("foo[\n") << false; |
|
1446 QTest::newRow("foo['bar']") << QString("foo['bar']") << true; |
|
1447 |
|
1448 QTest::newRow("/*") << QString("/*") << false; |
|
1449 QTest::newRow("/*\nMy comment") << QString("/*\nMy comment") << false; |
|
1450 QTest::newRow("/*\nMy comment */\nfoo = 10") << QString("/*\nMy comment */\nfoo = 10") << true; |
|
1451 QTest::newRow("foo = 10 /*") << QString("foo = 10 /*") << false; |
|
1452 QTest::newRow("foo = 10; /*") << QString("foo = 10; /*") << false; |
|
1453 QTest::newRow("foo = 10 /* My comment */") << QString("foo = 10 /* My comment */") << true; |
|
1454 |
|
1455 QTest::newRow("/=/") << QString("/=/") << true; |
|
1456 QTest::newRow("/=/g") << QString("/=/g") << true; |
|
1457 QTest::newRow("/a/") << QString("/a/") << true; |
|
1458 QTest::newRow("/a/g") << QString("/a/g") << true; |
|
1459 } |
|
1460 |
|
1461 void tst_QScriptEngine::canEvaluate() |
|
1462 { |
|
1463 QFETCH(QString, code); |
|
1464 QFETCH(bool, expectSuccess); |
|
1465 |
|
1466 QScriptEngine eng; |
|
1467 QCOMPARE(eng.canEvaluate(code), expectSuccess); |
|
1468 } |
|
1469 |
|
1470 void tst_QScriptEngine::evaluate_data() |
|
1471 { |
|
1472 QTest::addColumn<QString>("code"); |
|
1473 QTest::addColumn<int>("lineNumber"); |
|
1474 QTest::addColumn<bool>("expectHadError"); |
|
1475 QTest::addColumn<int>("expectErrorLineNumber"); |
|
1476 |
|
1477 QTest::newRow("(newline)") << QString("\n") << -1 << false << -1; |
|
1478 QTest::newRow("0 //") << QString("0 //") << -1 << false << -1; |
|
1479 QTest::newRow("/* */") << QString("/* */") << -1 << false << -1; |
|
1480 QTest::newRow("//") << QString("//") << -1 << false << -1; |
|
1481 QTest::newRow("(spaces)") << QString(" ") << -1 << false << -1; |
|
1482 QTest::newRow("(empty)") << QString("") << -1 << false << -1; |
|
1483 QTest::newRow("0") << QString("0") << -1 << false << -1; |
|
1484 QTest::newRow("0=1") << QString("\n0=1;\n") << -1 << true << 2; |
|
1485 QTest::newRow("a=1") << QString("a=1\n") << -1 << false << -1; |
|
1486 QTest::newRow("a=1;K") << QString("a=1;\nK") << -1 << true << 2; |
|
1487 |
|
1488 QTest::newRow("f()") << QString("function f()\n" |
|
1489 "{\n" |
|
1490 " var a;\n" |
|
1491 " var b=\";\n" // here's the error |
|
1492 "}\n" |
|
1493 "f();\n") |
|
1494 << -1 << true << 4; |
|
1495 |
|
1496 QTest::newRow("0") << QString("0") << 10 << false << -1; |
|
1497 QTest::newRow("0=1") << QString("\n\n0=1\n") << 10 << true << 13; |
|
1498 QTest::newRow("a=1") << QString("a=1\n") << 10 << false << -1; |
|
1499 QTest::newRow("a=1;K") << QString("a=1;\n\nK") << 10 << true << 12; |
|
1500 |
|
1501 QTest::newRow("f()") << QString("function f()\n" |
|
1502 "{\n" |
|
1503 " var a;\n" |
|
1504 "\n\n" |
|
1505 " var b=\";\n" // here's the error |
|
1506 "}\n" |
|
1507 "f();\n") |
|
1508 << 10 << true << 15; |
|
1509 QTest::newRow("functionThatDoesntExist()") |
|
1510 << QString(";\n;\n;\nfunctionThatDoesntExist()") |
|
1511 << -1 << true << 4; |
|
1512 QTest::newRow("for (var p in this) { continue labelThatDoesntExist; }") |
|
1513 << QString("for (var p in this) {\ncontinue labelThatDoesntExist; }") |
|
1514 << 4 << true << 5; |
|
1515 QTest::newRow("duplicateLabel: { duplicateLabel: ; }") |
|
1516 << QString("duplicateLabel: { duplicateLabel: ; }") |
|
1517 << 12 << true << 12; |
|
1518 |
|
1519 QTest::newRow("/=/") << QString("/=/") << -1 << false << -1; |
|
1520 QTest::newRow("/=/g") << QString("/=/g") << -1 << false << -1; |
|
1521 QTest::newRow("/a/") << QString("/a/") << -1 << false << -1; |
|
1522 QTest::newRow("/a/g") << QString("/a/g") << -1 << false << -1; |
|
1523 QTest::newRow("/a/gim") << QString("/a/gim") << -1 << false << -1; |
|
1524 QTest::newRow("/a/gimp") << QString("/a/gimp") << 1 << true << 1; |
|
1525 } |
|
1526 |
|
1527 void tst_QScriptEngine::evaluate() |
|
1528 { |
|
1529 QFETCH(QString, code); |
|
1530 QFETCH(int, lineNumber); |
|
1531 QFETCH(bool, expectHadError); |
|
1532 QFETCH(int, expectErrorLineNumber); |
|
1533 |
|
1534 QScriptEngine eng; |
|
1535 QScriptValue ret; |
|
1536 if (lineNumber != -1) |
|
1537 ret = eng.evaluate(code, /*fileName =*/QString(), lineNumber); |
|
1538 else |
|
1539 ret = eng.evaluate(code); |
|
1540 QCOMPARE(eng.hasUncaughtException(), expectHadError); |
|
1541 QCOMPARE(eng.uncaughtExceptionLineNumber(), expectErrorLineNumber); |
|
1542 if (eng.hasUncaughtException() && ret.isError()) |
|
1543 QVERIFY(ret.property("lineNumber").strictlyEquals(QScriptValue(&eng, expectErrorLineNumber))); |
|
1544 else |
|
1545 QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty()); |
|
1546 } |
|
1547 |
|
1548 static QScriptValue eval_nested(QScriptContext *ctx, QScriptEngine *eng) |
|
1549 { |
|
1550 QScriptValue result = eng->newObject(); |
|
1551 eng->evaluate("var bar = 'local';"); |
|
1552 result.setProperty("thisObjectIdBefore", ctx->thisObject().property("id")); |
|
1553 QScriptValue evaluatedThisObject = eng->evaluate("this"); |
|
1554 result.setProperty("thisObjectIdAfter", ctx->thisObject().property("id")); |
|
1555 result.setProperty("evaluatedThisObjectId", evaluatedThisObject.property("id")); |
|
1556 result.setProperty("local_bar", eng->evaluate("bar")); |
|
1557 |
|
1558 return result; |
|
1559 } |
|
1560 |
|
1561 void tst_QScriptEngine::nestedEvaluate() |
|
1562 { |
|
1563 QScriptEngine eng; |
|
1564 QScriptValue fun = eng.newFunction(eval_nested); |
|
1565 eng.globalObject().setProperty("fun", fun); |
|
1566 { |
|
1567 QScriptValue result = eng.evaluate("o = { id:'foo'}; o.fun = fun; o.fun()"); |
|
1568 QCOMPARE(result.property("local_bar").toString(), QString("local")); |
|
1569 QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo")); |
|
1570 QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo")); |
|
1571 QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo")); |
|
1572 QScriptValue bar = eng.evaluate("bar"); |
|
1573 QVERIFY(bar.isError()); |
|
1574 QCOMPARE(bar.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bar")); |
|
1575 } |
|
1576 |
|
1577 { |
|
1578 QScriptValue result = fun.call(eng.evaluate("p = { id:'foo' }") , QScriptValueList() ); |
|
1579 QCOMPARE(result.property("local_bar").toString(), QString("local")); |
|
1580 QCOMPARE(result.property("thisObjectIdBefore").toString(), QString("foo")); |
|
1581 QCOMPARE(result.property("thisObjectIdAfter").toString(), QString("foo")); |
|
1582 QCOMPARE(result.property("evaluatedThisObjectId").toString(), QString("foo")); |
|
1583 QScriptValue bar = eng.evaluate("bar"); |
|
1584 QVERIFY(bar.isError()); |
|
1585 QCOMPARE(bar.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bar")); |
|
1586 } |
|
1587 } |
|
1588 |
|
1589 void tst_QScriptEngine::uncaughtException() |
|
1590 { |
|
1591 QScriptEngine eng; |
|
1592 QScriptValue fun = eng.newFunction(myFunction); |
|
1593 QScriptValue throwFun = eng.newFunction(myThrowingFunction); |
|
1594 for (int x = -1; x < 2; ++x) { |
|
1595 { |
|
1596 QScriptValue ret = eng.evaluate("a = 10;\nb = 20;\n0 = 0;\n", /*fileName=*/QString(), /*lineNumber=*/x); |
|
1597 QVERIFY(eng.hasUncaughtException()); |
|
1598 QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2); |
|
1599 QVERIFY(eng.uncaughtException().strictlyEquals(ret)); |
|
1600 (void)ret.toString(); |
|
1601 QVERIFY(eng.hasUncaughtException()); |
|
1602 QVERIFY(eng.uncaughtException().strictlyEquals(ret)); |
|
1603 QVERIFY(fun.call().isNull()); |
|
1604 QVERIFY(eng.hasUncaughtException()); |
|
1605 QCOMPARE(eng.uncaughtExceptionLineNumber(), x+2); |
|
1606 QVERIFY(eng.uncaughtException().strictlyEquals(ret)); |
|
1607 eng.clearExceptions(); |
|
1608 QVERIFY(!eng.hasUncaughtException()); |
|
1609 QCOMPARE(eng.uncaughtExceptionLineNumber(), -1); |
|
1610 QVERIFY(!eng.uncaughtException().isValid()); |
|
1611 |
|
1612 eng.evaluate("2 = 3"); |
|
1613 QVERIFY(eng.hasUncaughtException()); |
|
1614 QScriptValue ret2 = throwFun.call(); |
|
1615 QVERIFY(ret2.isError()); |
|
1616 QVERIFY(eng.hasUncaughtException()); |
|
1617 QVERIFY(eng.uncaughtException().strictlyEquals(ret2)); |
|
1618 QCOMPARE(eng.uncaughtExceptionLineNumber(), 0); |
|
1619 eng.clearExceptions(); |
|
1620 QVERIFY(!eng.hasUncaughtException()); |
|
1621 eng.evaluate("1 + 2"); |
|
1622 QVERIFY(!eng.hasUncaughtException()); |
|
1623 } |
|
1624 { |
|
1625 QScriptValue ret = eng.evaluate("a = 10"); |
|
1626 QVERIFY(!eng.hasUncaughtException()); |
|
1627 QVERIFY(!eng.uncaughtException().isValid()); |
|
1628 } |
|
1629 { |
|
1630 QScriptValue ret = eng.evaluate("1 = 2"); |
|
1631 QVERIFY(eng.hasUncaughtException()); |
|
1632 eng.clearExceptions(); |
|
1633 QVERIFY(!eng.hasUncaughtException()); |
|
1634 } |
|
1635 { |
|
1636 eng.globalObject().setProperty("throwFun", throwFun); |
|
1637 eng.evaluate("1;\nthrowFun();"); |
|
1638 QVERIFY(eng.hasUncaughtException()); |
|
1639 QCOMPARE(eng.uncaughtExceptionLineNumber(), 2); |
|
1640 eng.clearExceptions(); |
|
1641 QVERIFY(!eng.hasUncaughtException()); |
|
1642 } |
|
1643 } |
|
1644 } |
|
1645 |
|
1646 void tst_QScriptEngine::errorMessage_QT679() |
|
1647 { |
|
1648 QScriptEngine engine; |
|
1649 engine.globalObject().setProperty("foo", 15); |
|
1650 QScriptValue error = engine.evaluate("'hello world';\nfoo.bar.blah"); |
|
1651 QVERIFY(error.isError()); |
|
1652 QCOMPARE(error.toString(), QString::fromLatin1("TypeError: Result of expression 'foo.bar' [undefined] is not an object.")); |
|
1653 } |
|
1654 |
|
1655 struct Foo { |
|
1656 public: |
|
1657 int x, y; |
|
1658 Foo() : x(-1), y(-1) { } |
|
1659 }; |
|
1660 |
|
1661 Q_DECLARE_METATYPE(Foo) |
|
1662 Q_DECLARE_METATYPE(Foo*) |
|
1663 |
|
1664 void tst_QScriptEngine::getSetDefaultPrototype() |
|
1665 { |
|
1666 QScriptEngine eng; |
|
1667 { |
|
1668 QScriptValue object = eng.newObject(); |
|
1669 QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false); |
|
1670 eng.setDefaultPrototype(qMetaTypeId<int>(), object); |
|
1671 QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).strictlyEquals(object), true); |
|
1672 QScriptValue value = eng.newVariant(int(123)); |
|
1673 QCOMPARE(value.prototype().isObject(), true); |
|
1674 QCOMPARE(value.prototype().strictlyEquals(object), true); |
|
1675 |
|
1676 eng.setDefaultPrototype(qMetaTypeId<int>(), QScriptValue()); |
|
1677 QCOMPARE(eng.defaultPrototype(qMetaTypeId<int>()).isValid(), false); |
|
1678 QScriptValue value2 = eng.newVariant(int(123)); |
|
1679 QCOMPARE(value2.prototype().strictlyEquals(object), false); |
|
1680 } |
|
1681 { |
|
1682 QScriptValue object = eng.newObject(); |
|
1683 QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false); |
|
1684 eng.setDefaultPrototype(qMetaTypeId<Foo>(), object); |
|
1685 QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(object), true); |
|
1686 QScriptValue value = eng.newVariant(qVariantFromValue(Foo())); |
|
1687 QCOMPARE(value.prototype().isObject(), true); |
|
1688 QCOMPARE(value.prototype().strictlyEquals(object), true); |
|
1689 |
|
1690 eng.setDefaultPrototype(qMetaTypeId<Foo>(), QScriptValue()); |
|
1691 QCOMPARE(eng.defaultPrototype(qMetaTypeId<Foo>()).isValid(), false); |
|
1692 QScriptValue value2 = eng.newVariant(qVariantFromValue(Foo())); |
|
1693 QCOMPARE(value2.prototype().strictlyEquals(object), false); |
|
1694 } |
|
1695 } |
|
1696 |
|
1697 static QScriptValue fooToScriptValue(QScriptEngine *eng, const Foo &foo) |
|
1698 { |
|
1699 QScriptValue obj = eng->newObject(); |
|
1700 obj.setProperty("x", QScriptValue(eng, foo.x)); |
|
1701 obj.setProperty("y", QScriptValue(eng, foo.y)); |
|
1702 return obj; |
|
1703 } |
|
1704 |
|
1705 static void fooFromScriptValue(const QScriptValue &value, Foo &foo) |
|
1706 { |
|
1707 foo.x = value.property("x").toInt32(); |
|
1708 foo.y = value.property("y").toInt32(); |
|
1709 } |
|
1710 |
|
1711 static QScriptValue fooToScriptValueV2(QScriptEngine *eng, const Foo &foo) |
|
1712 { |
|
1713 return QScriptValue(eng, foo.x); |
|
1714 } |
|
1715 |
|
1716 static void fooFromScriptValueV2(const QScriptValue &value, Foo &foo) |
|
1717 { |
|
1718 foo.x = value.toInt32(); |
|
1719 } |
|
1720 |
|
1721 Q_DECLARE_METATYPE(QLinkedList<QString>) |
|
1722 Q_DECLARE_METATYPE(QList<Foo>) |
|
1723 Q_DECLARE_METATYPE(QVector<QChar>) |
|
1724 Q_DECLARE_METATYPE(QStack<int>) |
|
1725 Q_DECLARE_METATYPE(QQueue<char>) |
|
1726 Q_DECLARE_METATYPE(QLinkedList<QStack<int> >) |
|
1727 |
|
1728 void tst_QScriptEngine::valueConversion() |
|
1729 { |
|
1730 QScriptEngine eng; |
|
1731 { |
|
1732 QScriptValue num = qScriptValueFromValue(&eng, 123); |
|
1733 QCOMPARE(num.isNumber(), true); |
|
1734 QCOMPARE(num.strictlyEquals(QScriptValue(&eng, 123)), true); |
|
1735 |
|
1736 int inum = qScriptValueToValue<int>(num); |
|
1737 QCOMPARE(inum, 123); |
|
1738 |
|
1739 QString snum = qScriptValueToValue<QString>(num); |
|
1740 QCOMPARE(snum, QLatin1String("123")); |
|
1741 } |
|
1742 #ifndef QT_NO_MEMBER_TEMPLATES |
|
1743 { |
|
1744 QScriptValue num = eng.toScriptValue(123); |
|
1745 QCOMPARE(num.isNumber(), true); |
|
1746 QCOMPARE(num.strictlyEquals(QScriptValue(&eng, 123)), true); |
|
1747 |
|
1748 int inum = eng.fromScriptValue<int>(num); |
|
1749 QCOMPARE(inum, 123); |
|
1750 |
|
1751 QString snum = eng.fromScriptValue<QString>(num); |
|
1752 QCOMPARE(snum, QLatin1String("123")); |
|
1753 } |
|
1754 #endif |
|
1755 { |
|
1756 QScriptValue num(&eng, 123); |
|
1757 QCOMPARE(qScriptValueToValue<char>(num), char(123)); |
|
1758 QCOMPARE(qScriptValueToValue<unsigned char>(num), (unsigned char)(123)); |
|
1759 QCOMPARE(qScriptValueToValue<short>(num), short(123)); |
|
1760 QCOMPARE(qScriptValueToValue<unsigned short>(num), (unsigned short)(123)); |
|
1761 QCOMPARE(qScriptValueToValue<float>(num), float(123)); |
|
1762 QCOMPARE(qScriptValueToValue<double>(num), double(123)); |
|
1763 QCOMPARE(qScriptValueToValue<qlonglong>(num), qlonglong(123)); |
|
1764 QCOMPARE(qScriptValueToValue<qulonglong>(num), qulonglong(123)); |
|
1765 } |
|
1766 { |
|
1767 QScriptValue num(123); |
|
1768 QCOMPARE(qScriptValueToValue<char>(num), char(123)); |
|
1769 QCOMPARE(qScriptValueToValue<unsigned char>(num), (unsigned char)(123)); |
|
1770 QCOMPARE(qScriptValueToValue<short>(num), short(123)); |
|
1771 QCOMPARE(qScriptValueToValue<unsigned short>(num), (unsigned short)(123)); |
|
1772 QCOMPARE(qScriptValueToValue<float>(num), float(123)); |
|
1773 QCOMPARE(qScriptValueToValue<double>(num), double(123)); |
|
1774 QCOMPARE(qScriptValueToValue<qlonglong>(num), qlonglong(123)); |
|
1775 QCOMPARE(qScriptValueToValue<qulonglong>(num), qulonglong(123)); |
|
1776 } |
|
1777 |
|
1778 { |
|
1779 QScriptValue num = qScriptValueFromValue(&eng, Q_INT64_C(0x100000000)); |
|
1780 QCOMPARE(qScriptValueToValue<qlonglong>(num), Q_INT64_C(0x100000000)); |
|
1781 QCOMPARE(qScriptValueToValue<qulonglong>(num), Q_UINT64_C(0x100000000)); |
|
1782 } |
|
1783 |
|
1784 { |
|
1785 QChar c = QLatin1Char('c'); |
|
1786 QScriptValue str = QScriptValue(&eng, "ciao"); |
|
1787 QCOMPARE(qScriptValueToValue<QChar>(str), c); |
|
1788 QScriptValue code = QScriptValue(&eng, c.unicode()); |
|
1789 QCOMPARE(qScriptValueToValue<QChar>(code), c); |
|
1790 QCOMPARE(qScriptValueToValue<QChar>(qScriptValueFromValue(&eng, c)), c); |
|
1791 } |
|
1792 |
|
1793 { |
|
1794 // a type that we don't have built-in conversion of |
|
1795 // (it's stored as a variant) |
|
1796 QTime tm(1, 2, 3, 4); |
|
1797 QScriptValue val = qScriptValueFromValue(&eng, tm); |
|
1798 QCOMPARE(qScriptValueToValue<QTime>(val), tm); |
|
1799 } |
|
1800 |
|
1801 { |
|
1802 Foo foo; |
|
1803 foo.x = 12; |
|
1804 foo.y = 34; |
|
1805 QScriptValue fooVal = qScriptValueFromValue(&eng, foo); |
|
1806 QCOMPARE(fooVal.isVariant(), true); |
|
1807 |
|
1808 Foo foo2 = qScriptValueToValue<Foo>(fooVal); |
|
1809 QCOMPARE(foo2.x, foo.x); |
|
1810 QCOMPARE(foo2.y, foo.y); |
|
1811 } |
|
1812 |
|
1813 qScriptRegisterMetaType<Foo>(&eng, fooToScriptValue, fooFromScriptValue); |
|
1814 |
|
1815 { |
|
1816 Foo foo; |
|
1817 foo.x = 12; |
|
1818 foo.y = 34; |
|
1819 QScriptValue fooVal = qScriptValueFromValue(&eng, foo); |
|
1820 QCOMPARE(fooVal.isObject(), true); |
|
1821 QVERIFY(fooVal.prototype().strictlyEquals(eng.evaluate("Object.prototype"))); |
|
1822 QCOMPARE(fooVal.property("x").strictlyEquals(QScriptValue(&eng, 12)), true); |
|
1823 QCOMPARE(fooVal.property("y").strictlyEquals(QScriptValue(&eng, 34)), true); |
|
1824 fooVal.setProperty("x", QScriptValue(&eng, 56)); |
|
1825 fooVal.setProperty("y", QScriptValue(&eng, 78)); |
|
1826 |
|
1827 Foo foo2 = qScriptValueToValue<Foo>(fooVal); |
|
1828 QCOMPARE(foo2.x, 56); |
|
1829 QCOMPARE(foo2.y, 78); |
|
1830 |
|
1831 QScriptValue fooProto = eng.newObject(); |
|
1832 eng.setDefaultPrototype(qMetaTypeId<Foo>(), fooProto); |
|
1833 QScriptValue fooVal2 = qScriptValueFromValue(&eng, foo2); |
|
1834 QVERIFY(fooVal2.prototype().strictlyEquals(fooProto)); |
|
1835 QVERIFY(fooVal2.property("x").strictlyEquals(QScriptValue(&eng, 56))); |
|
1836 QVERIFY(fooVal2.property("y").strictlyEquals(QScriptValue(&eng, 78))); |
|
1837 } |
|
1838 |
|
1839 qScriptRegisterSequenceMetaType<QLinkedList<QString> >(&eng); |
|
1840 |
|
1841 { |
|
1842 QLinkedList<QString> lst; |
|
1843 lst << QLatin1String("foo") << QLatin1String("bar"); |
|
1844 QScriptValue lstVal = qScriptValueFromValue(&eng, lst); |
|
1845 QCOMPARE(lstVal.isArray(), true); |
|
1846 QCOMPARE(lstVal.property("length").toInt32(), 2); |
|
1847 QCOMPARE(lstVal.property("0").isString(), true); |
|
1848 QCOMPARE(lstVal.property("0").toString(), QLatin1String("foo")); |
|
1849 QCOMPARE(lstVal.property("1").isString(), true); |
|
1850 QCOMPARE(lstVal.property("1").toString(), QLatin1String("bar")); |
|
1851 } |
|
1852 |
|
1853 qScriptRegisterSequenceMetaType<QList<Foo> >(&eng); |
|
1854 qScriptRegisterSequenceMetaType<QStack<int> >(&eng); |
|
1855 qScriptRegisterSequenceMetaType<QVector<QChar> >(&eng); |
|
1856 qScriptRegisterSequenceMetaType<QQueue<char> >(&eng); |
|
1857 qScriptRegisterSequenceMetaType<QLinkedList<QStack<int> > >(&eng); |
|
1858 |
|
1859 { |
|
1860 QLinkedList<QStack<int> > lst; |
|
1861 QStack<int> first; first << 13 << 49; lst << first; |
|
1862 QStack<int> second; second << 99999;lst << second; |
|
1863 QScriptValue lstVal = qScriptValueFromValue(&eng, lst); |
|
1864 QCOMPARE(lstVal.isArray(), true); |
|
1865 QCOMPARE(lstVal.property("length").toInt32(), 2); |
|
1866 QCOMPARE(lstVal.property("0").isArray(), true); |
|
1867 QCOMPARE(lstVal.property("0").property("length").toInt32(), 2); |
|
1868 QCOMPARE(lstVal.property("0").property("0").toInt32(), first.at(0)); |
|
1869 QCOMPARE(lstVal.property("0").property("1").toInt32(), first.at(1)); |
|
1870 QCOMPARE(lstVal.property("1").isArray(), true); |
|
1871 QCOMPARE(lstVal.property("1").property("length").toInt32(), 1); |
|
1872 QCOMPARE(lstVal.property("1").property("0").toInt32(), second.at(0)); |
|
1873 QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("0")), first); |
|
1874 QCOMPARE(qscriptvalue_cast<QStack<int> >(lstVal.property("1")), second); |
|
1875 QCOMPARE(qscriptvalue_cast<QLinkedList<QStack<int> > >(lstVal), lst); |
|
1876 } |
|
1877 |
|
1878 // pointers |
|
1879 { |
|
1880 Foo foo; |
|
1881 { |
|
1882 QScriptValue v = qScriptValueFromValue(&eng, &foo); |
|
1883 Foo *pfoo = qscriptvalue_cast<Foo*>(v); |
|
1884 QCOMPARE(pfoo, &foo); |
|
1885 } |
|
1886 { |
|
1887 Foo *pfoo = 0; |
|
1888 QScriptValue v = qScriptValueFromValue(&eng, pfoo); |
|
1889 QCOMPARE(v.isNull(), true); |
|
1890 QVERIFY(qscriptvalue_cast<Foo*>(v) == 0); |
|
1891 } |
|
1892 } |
|
1893 |
|
1894 // QList<int> and QObjectList should be converted from/to arrays by default |
|
1895 { |
|
1896 QList<int> lst; |
|
1897 lst << 1 << 2 << 3; |
|
1898 QScriptValue val = qScriptValueFromValue(&eng, lst); |
|
1899 QVERIFY(val.isArray()); |
|
1900 QCOMPARE(val.property("length").toInt32(), lst.size()); |
|
1901 QCOMPARE(val.property(0).toInt32(), lst.at(0)); |
|
1902 QCOMPARE(val.property(1).toInt32(), lst.at(1)); |
|
1903 QCOMPARE(val.property(2).toInt32(), lst.at(2)); |
|
1904 |
|
1905 QCOMPARE(qscriptvalue_cast<QList<int> >(val), lst); |
|
1906 } |
|
1907 { |
|
1908 QObjectList lst; |
|
1909 lst << this; |
|
1910 QScriptValue val = qScriptValueFromValue(&eng, lst); |
|
1911 QVERIFY(val.isArray()); |
|
1912 QCOMPARE(val.property("length").toInt32(), lst.size()); |
|
1913 QCOMPARE(val.property(0).toQObject(), (QObject *)this); |
|
1914 |
|
1915 QCOMPARE(qscriptvalue_cast<QObjectList>(val), lst); |
|
1916 } |
|
1917 |
|
1918 // qScriptValueFromValue() should be "smart" when the argument is a QVariant |
|
1919 { |
|
1920 QScriptValue val = qScriptValueFromValue(&eng, QVariant()); |
|
1921 QVERIFY(!val.isVariant()); |
|
1922 QVERIFY(val.isUndefined()); |
|
1923 } |
|
1924 { |
|
1925 QScriptValue val = qScriptValueFromValue(&eng, QVariant(true)); |
|
1926 QVERIFY(!val.isVariant()); |
|
1927 QVERIFY(val.isBoolean()); |
|
1928 QCOMPARE(val.toBoolean(), true); |
|
1929 } |
|
1930 { |
|
1931 QScriptValue val = qScriptValueFromValue(&eng, QVariant(int(123))); |
|
1932 QVERIFY(!val.isVariant()); |
|
1933 QVERIFY(val.isNumber()); |
|
1934 QCOMPARE(val.toNumber(), qsreal(123)); |
|
1935 } |
|
1936 { |
|
1937 QScriptValue val = qScriptValueFromValue(&eng, QVariant(qsreal(1.25))); |
|
1938 QVERIFY(!val.isVariant()); |
|
1939 QVERIFY(val.isNumber()); |
|
1940 QCOMPARE(val.toNumber(), qsreal(1.25)); |
|
1941 } |
|
1942 { |
|
1943 QString str = QString::fromLatin1("ciao"); |
|
1944 QScriptValue val = qScriptValueFromValue(&eng, QVariant(str)); |
|
1945 QVERIFY(!val.isVariant()); |
|
1946 QVERIFY(val.isString()); |
|
1947 QCOMPARE(val.toString(), str); |
|
1948 } |
|
1949 { |
|
1950 QScriptValue val = qScriptValueFromValue(&eng, qVariantFromValue((QObject*)this)); |
|
1951 QVERIFY(!val.isVariant()); |
|
1952 QVERIFY(val.isQObject()); |
|
1953 QCOMPARE(val.toQObject(), (QObject*)this); |
|
1954 } |
|
1955 { |
|
1956 QVariant var = qVariantFromValue(QPoint(123, 456)); |
|
1957 QScriptValue val = qScriptValueFromValue(&eng, var); |
|
1958 QVERIFY(val.isVariant()); |
|
1959 QCOMPARE(val.toVariant(), var); |
|
1960 } |
|
1961 |
|
1962 // task 248802 |
|
1963 qScriptRegisterMetaType<Foo>(&eng, fooToScriptValueV2, fooFromScriptValueV2); |
|
1964 { |
|
1965 QScriptValue num(&eng, 123); |
|
1966 Foo foo = qScriptValueToValue<Foo>(num); |
|
1967 QCOMPARE(foo.x, 123); |
|
1968 } |
|
1969 { |
|
1970 QScriptValue num(123); |
|
1971 Foo foo = qScriptValueToValue<Foo>(num); |
|
1972 QCOMPARE(foo.x, -1); |
|
1973 } |
|
1974 { |
|
1975 QScriptValue str(&eng, "123"); |
|
1976 Foo foo = qScriptValueToValue<Foo>(str); |
|
1977 QCOMPARE(foo.x, 123); |
|
1978 } |
|
1979 |
|
1980 // more built-in types |
|
1981 { |
|
1982 QScriptValue val = qScriptValueFromValue(&eng, uint(123)); |
|
1983 QVERIFY(val.isNumber()); |
|
1984 QCOMPARE(val.toInt32(), 123); |
|
1985 } |
|
1986 { |
|
1987 QScriptValue val = qScriptValueFromValue(&eng, qulonglong(123)); |
|
1988 QVERIFY(val.isNumber()); |
|
1989 QCOMPARE(val.toInt32(), 123); |
|
1990 } |
|
1991 { |
|
1992 QScriptValue val = qScriptValueFromValue(&eng, float(123)); |
|
1993 QVERIFY(val.isNumber()); |
|
1994 QCOMPARE(val.toInt32(), 123); |
|
1995 } |
|
1996 { |
|
1997 QScriptValue val = qScriptValueFromValue(&eng, short(123)); |
|
1998 QVERIFY(val.isNumber()); |
|
1999 QCOMPARE(val.toInt32(), 123); |
|
2000 } |
|
2001 { |
|
2002 QScriptValue val = qScriptValueFromValue(&eng, ushort(123)); |
|
2003 QVERIFY(val.isNumber()); |
|
2004 QCOMPARE(val.toInt32(), 123); |
|
2005 } |
|
2006 { |
|
2007 QScriptValue val = qScriptValueFromValue(&eng, char(123)); |
|
2008 QVERIFY(val.isNumber()); |
|
2009 QCOMPARE(val.toInt32(), 123); |
|
2010 } |
|
2011 { |
|
2012 QScriptValue val = qScriptValueFromValue(&eng, uchar(123)); |
|
2013 QVERIFY(val.isNumber()); |
|
2014 QCOMPARE(val.toInt32(), 123); |
|
2015 } |
|
2016 { |
|
2017 QDateTime in = QDateTime::currentDateTime(); |
|
2018 QScriptValue val = qScriptValueFromValue(&eng, in); |
|
2019 QVERIFY(val.isDate()); |
|
2020 QCOMPARE(val.toDateTime(), in); |
|
2021 } |
|
2022 { |
|
2023 QDate in = QDate::currentDate(); |
|
2024 QScriptValue val = qScriptValueFromValue(&eng, in); |
|
2025 QVERIFY(val.isDate()); |
|
2026 QCOMPARE(val.toDateTime().date(), in); |
|
2027 } |
|
2028 { |
|
2029 QRegExp in = QRegExp("foo"); |
|
2030 QScriptValue val = qScriptValueFromValue(&eng, in); |
|
2031 QVERIFY(val.isRegExp()); |
|
2032 QRegExp out = val.toRegExp(); |
|
2033 QEXPECT_FAIL("", "JSC-based back-end doesn't preserve QRegExp::patternSyntax (always uses RegExp2)", Continue); |
|
2034 QCOMPARE(out.patternSyntax(), in.patternSyntax()); |
|
2035 QCOMPARE(out.pattern(), in.pattern()); |
|
2036 QCOMPARE(out.caseSensitivity(), in.caseSensitivity()); |
|
2037 QCOMPARE(out.isMinimal(), in.isMinimal()); |
|
2038 } |
|
2039 { |
|
2040 QRegExp in = QRegExp("foo", Qt::CaseSensitive, QRegExp::RegExp2); |
|
2041 QScriptValue val = qScriptValueFromValue(&eng, in); |
|
2042 QVERIFY(val.isRegExp()); |
|
2043 QCOMPARE(val.toRegExp(), in); |
|
2044 } |
|
2045 { |
|
2046 QRegExp in = QRegExp("foo"); |
|
2047 in.setMinimal(true); |
|
2048 QScriptValue val = qScriptValueFromValue(&eng, in); |
|
2049 QVERIFY(val.isRegExp()); |
|
2050 QEXPECT_FAIL("", "JSC-based back-end doesn't preserve QRegExp::minimal (always false)", Continue); |
|
2051 QCOMPARE(val.toRegExp().isMinimal(), in.isMinimal()); |
|
2052 } |
|
2053 } |
|
2054 |
|
2055 static QScriptValue __import__(QScriptContext *ctx, QScriptEngine *eng) |
|
2056 { |
|
2057 return eng->importExtension(ctx->argument(0).toString()); |
|
2058 } |
|
2059 |
|
2060 void tst_QScriptEngine::importExtension() |
|
2061 { |
|
2062 QStringList libPaths = QCoreApplication::instance()->libraryPaths(); |
|
2063 QCoreApplication::instance()->setLibraryPaths(QStringList() << SRCDIR); |
|
2064 |
|
2065 QStringList availableExtensions; |
|
2066 { |
|
2067 QScriptEngine eng; |
|
2068 QVERIFY(eng.importedExtensions().isEmpty()); |
|
2069 QStringList ret = eng.availableExtensions(); |
|
2070 QCOMPARE(ret.size(), 4); |
|
2071 QCOMPARE(ret.at(0), QString::fromLatin1("com")); |
|
2072 QCOMPARE(ret.at(1), QString::fromLatin1("com.trolltech")); |
|
2073 QCOMPARE(ret.at(2), QString::fromLatin1("com.trolltech.recursive")); |
|
2074 QCOMPARE(ret.at(3), QString::fromLatin1("com.trolltech.syntaxerror")); |
|
2075 availableExtensions = ret; |
|
2076 } |
|
2077 |
|
2078 // try to import something that doesn't exist |
|
2079 { |
|
2080 QScriptEngine eng; |
|
2081 QScriptValue ret = eng.importExtension("this.extension.does.not.exist"); |
|
2082 QCOMPARE(eng.hasUncaughtException(), true); |
|
2083 QCOMPARE(ret.isError(), true); |
|
2084 QCOMPARE(ret.toString(), QString::fromLatin1("Error: Unable to import this.extension.does.not.exist: no such extension")); |
|
2085 } |
|
2086 |
|
2087 { |
|
2088 QScriptEngine eng; |
|
2089 for (int x = 0; x < 2; ++x) { |
|
2090 QCOMPARE(eng.globalObject().property("com").isValid(), x == 1); |
|
2091 QScriptValue ret = eng.importExtension("com.trolltech"); |
|
2092 QCOMPARE(eng.hasUncaughtException(), false); |
|
2093 QCOMPARE(ret.isUndefined(), true); |
|
2094 |
|
2095 QScriptValue com = eng.globalObject().property("com"); |
|
2096 QCOMPARE(com.isObject(), true); |
|
2097 QCOMPARE(com.property("wasDefinedAlready") |
|
2098 .strictlyEquals(QScriptValue(&eng, false)), true); |
|
2099 QCOMPARE(com.property("name") |
|
2100 .strictlyEquals(QScriptValue(&eng, "com")), true); |
|
2101 QCOMPARE(com.property("level") |
|
2102 .strictlyEquals(QScriptValue(&eng, 1)), true); |
|
2103 QVERIFY(com.property("originalPostInit").isUndefined()); |
|
2104 QVERIFY(com.property("postInitCallCount").strictlyEquals(1)); |
|
2105 |
|
2106 QScriptValue trolltech = com.property("trolltech"); |
|
2107 QCOMPARE(trolltech.isObject(), true); |
|
2108 QCOMPARE(trolltech.property("wasDefinedAlready") |
|
2109 .strictlyEquals(QScriptValue(&eng, false)), true); |
|
2110 QCOMPARE(trolltech.property("name") |
|
2111 .strictlyEquals(QScriptValue(&eng, "com.trolltech")), true); |
|
2112 QCOMPARE(trolltech.property("level") |
|
2113 .strictlyEquals(QScriptValue(&eng, 2)), true); |
|
2114 QVERIFY(trolltech.property("originalPostInit").isUndefined()); |
|
2115 QVERIFY(trolltech.property("postInitCallCount").strictlyEquals(1)); |
|
2116 } |
|
2117 QStringList imp = eng.importedExtensions(); |
|
2118 QCOMPARE(imp.size(), 2); |
|
2119 QCOMPARE(imp.at(0), QString::fromLatin1("com")); |
|
2120 QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech")); |
|
2121 QCOMPARE(eng.availableExtensions(), availableExtensions); |
|
2122 } |
|
2123 |
|
2124 // recursive import should throw an error |
|
2125 { |
|
2126 QScriptEngine eng; |
|
2127 QVERIFY(eng.importedExtensions().isEmpty()); |
|
2128 eng.globalObject().setProperty("__import__", eng.newFunction(__import__)); |
|
2129 QScriptValue ret = eng.importExtension("com.trolltech.recursive"); |
|
2130 QCOMPARE(eng.hasUncaughtException(), true); |
|
2131 QVERIFY(ret.isError()); |
|
2132 QCOMPARE(ret.toString(), QString::fromLatin1("Error: recursive import of com.trolltech.recursive")); |
|
2133 QStringList imp = eng.importedExtensions(); |
|
2134 QCOMPARE(imp.size(), 2); |
|
2135 QCOMPARE(imp.at(0), QString::fromLatin1("com")); |
|
2136 QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech")); |
|
2137 QCOMPARE(eng.availableExtensions(), availableExtensions); |
|
2138 } |
|
2139 |
|
2140 { |
|
2141 QScriptEngine eng; |
|
2142 eng.globalObject().setProperty("__import__", eng.newFunction(__import__)); |
|
2143 for (int x = 0; x < 2; ++x) { |
|
2144 if (x == 0) |
|
2145 QVERIFY(eng.importedExtensions().isEmpty()); |
|
2146 QScriptValue ret = eng.importExtension("com.trolltech.syntaxerror"); |
|
2147 QVERIFY(eng.hasUncaughtException()); |
|
2148 QEXPECT_FAIL("", "JSC throws syntax error eagerly", Continue); |
|
2149 QCOMPARE(eng.uncaughtExceptionLineNumber(), 4); |
|
2150 QVERIFY(ret.isError()); |
|
2151 QCOMPARE(ret.property("message").toString(), QLatin1String("Parse error")); |
|
2152 } |
|
2153 QStringList imp = eng.importedExtensions(); |
|
2154 QCOMPARE(imp.size(), 2); |
|
2155 QCOMPARE(imp.at(0), QString::fromLatin1("com")); |
|
2156 QCOMPARE(imp.at(1), QString::fromLatin1("com.trolltech")); |
|
2157 QCOMPARE(eng.availableExtensions(), availableExtensions); |
|
2158 } |
|
2159 |
|
2160 QCoreApplication::instance()->setLibraryPaths(libPaths); |
|
2161 } |
|
2162 |
|
2163 static QScriptValue recurse(QScriptContext *ctx, QScriptEngine *eng) |
|
2164 { |
|
2165 Q_UNUSED(eng); |
|
2166 return ctx->callee().call(); |
|
2167 } |
|
2168 |
|
2169 static QScriptValue recurse2(QScriptContext *ctx, QScriptEngine *eng) |
|
2170 { |
|
2171 Q_UNUSED(eng); |
|
2172 return ctx->callee().construct(); |
|
2173 } |
|
2174 |
|
2175 void tst_QScriptEngine::infiniteRecursion() |
|
2176 { |
|
2177 const QString stackOverflowError = QString::fromLatin1("RangeError: Maximum call stack size exceeded."); |
|
2178 QScriptEngine eng; |
|
2179 { |
|
2180 QScriptValue ret = eng.evaluate("function foo() { foo(); }; foo();"); |
|
2181 QCOMPARE(ret.isError(), true); |
|
2182 QCOMPARE(ret.toString(), stackOverflowError); |
|
2183 } |
|
2184 #if 0 //The native C++ stack overflow before the JS stack |
|
2185 { |
|
2186 QScriptValue fun = eng.newFunction(recurse); |
|
2187 QScriptValue ret = fun.call(); |
|
2188 QCOMPARE(ret.isError(), true); |
|
2189 QCOMPARE(ret.toString(), stackOverflowError); |
|
2190 } |
|
2191 { |
|
2192 QScriptValue fun = eng.newFunction(recurse2); |
|
2193 QScriptValue ret = fun.construct(); |
|
2194 QCOMPARE(ret.isError(), true); |
|
2195 QCOMPARE(ret.toString(), stackOverflowError); |
|
2196 } |
|
2197 #endif |
|
2198 } |
|
2199 |
|
2200 struct Bar { |
|
2201 int a; |
|
2202 }; |
|
2203 |
|
2204 struct Baz : public Bar { |
|
2205 int b; |
|
2206 }; |
|
2207 |
|
2208 Q_DECLARE_METATYPE(Bar*) |
|
2209 Q_DECLARE_METATYPE(Baz*) |
|
2210 |
|
2211 Q_DECLARE_METATYPE(QGradient) |
|
2212 Q_DECLARE_METATYPE(QGradient*) |
|
2213 Q_DECLARE_METATYPE(QLinearGradient) |
|
2214 |
|
2215 class Zoo : public QObject |
|
2216 { |
|
2217 Q_OBJECT |
|
2218 public: |
|
2219 Zoo() { } |
|
2220 public slots: |
|
2221 Baz *toBaz(Bar *b) { return reinterpret_cast<Baz*>(b); } |
|
2222 }; |
|
2223 |
|
2224 void tst_QScriptEngine::castWithPrototypeChain() |
|
2225 { |
|
2226 QScriptEngine eng; |
|
2227 Bar bar; |
|
2228 Baz baz; |
|
2229 QScriptValue barProto = qScriptValueFromValue(&eng, &bar); |
|
2230 QScriptValue bazProto = qScriptValueFromValue(&eng, &baz); |
|
2231 eng.setDefaultPrototype(qMetaTypeId<Bar*>(), barProto); |
|
2232 eng.setDefaultPrototype(qMetaTypeId<Baz*>(), bazProto); |
|
2233 |
|
2234 Baz baz2; |
|
2235 baz2.a = 123; |
|
2236 baz2.b = 456; |
|
2237 QScriptValue baz2Value = qScriptValueFromValue(&eng, &baz2); |
|
2238 { |
|
2239 Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value); |
|
2240 QVERIFY(pbaz != 0); |
|
2241 QCOMPARE(pbaz->b, baz2.b); |
|
2242 |
|
2243 Zoo zoo; |
|
2244 QScriptValue scriptZoo = eng.newQObject(&zoo); |
|
2245 QScriptValue toBaz = scriptZoo.property("toBaz"); |
|
2246 QVERIFY(toBaz.isFunction()); |
|
2247 |
|
2248 // no relation between Bar and Baz's proto --> casting fails |
|
2249 { |
|
2250 Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value); |
|
2251 QVERIFY(pbar == 0); |
|
2252 } |
|
2253 |
|
2254 { |
|
2255 QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value); |
|
2256 QVERIFY(ret.isError()); |
|
2257 QCOMPARE(ret.toString(), QLatin1String("TypeError: incompatible type of argument(s) in call to toBaz(); candidates were\n toBaz(Bar*)")); |
|
2258 } |
|
2259 |
|
2260 // establish chain -- now casting should work |
|
2261 bazProto.setPrototype(barProto); |
|
2262 |
|
2263 { |
|
2264 Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value); |
|
2265 QVERIFY(pbar != 0); |
|
2266 QCOMPARE(pbar->a, baz2.a); |
|
2267 } |
|
2268 |
|
2269 { |
|
2270 QScriptValue ret = toBaz.call(scriptZoo, QScriptValueList() << baz2Value); |
|
2271 QVERIFY(!ret.isError()); |
|
2272 QCOMPARE(qscriptvalue_cast<Baz*>(ret), pbaz); |
|
2273 } |
|
2274 } |
|
2275 |
|
2276 bazProto.setPrototype(barProto.prototype()); // kill chain |
|
2277 { |
|
2278 Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value); |
|
2279 QVERIFY(pbaz != 0); |
|
2280 // should not work anymore |
|
2281 Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value); |
|
2282 QVERIFY(pbar == 0); |
|
2283 } |
|
2284 |
|
2285 bazProto.setPrototype(eng.newQObject(this)); |
|
2286 { |
|
2287 Baz *pbaz = qscriptvalue_cast<Baz*>(baz2Value); |
|
2288 QVERIFY(pbaz != 0); |
|
2289 // should not work now either |
|
2290 Bar *pbar = qscriptvalue_cast<Bar*>(baz2Value); |
|
2291 QVERIFY(pbar == 0); |
|
2292 } |
|
2293 |
|
2294 { |
|
2295 QScriptValue b = qScriptValueFromValue(&eng, QBrush()); |
|
2296 b.setPrototype(barProto); |
|
2297 // this shows that a "wrong" cast is possible, if you |
|
2298 // don't play by the rules (the pointer is actually a QBrush*)... |
|
2299 Bar *pbar = qscriptvalue_cast<Bar*>(b); |
|
2300 QVERIFY(pbar != 0); |
|
2301 } |
|
2302 |
|
2303 { |
|
2304 QScriptValue gradientProto = qScriptValueFromValue(&eng, QGradient()); |
|
2305 QScriptValue linearGradientProto = qScriptValueFromValue(&eng, QLinearGradient()); |
|
2306 linearGradientProto.setPrototype(gradientProto); |
|
2307 QLinearGradient lg(10, 20, 30, 40); |
|
2308 QScriptValue linearGradient = qScriptValueFromValue(&eng, lg); |
|
2309 { |
|
2310 QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient); |
|
2311 QVERIFY(pgrad == 0); |
|
2312 } |
|
2313 linearGradient.setPrototype(linearGradientProto); |
|
2314 { |
|
2315 QGradient *pgrad = qscriptvalue_cast<QGradient*>(linearGradient); |
|
2316 QVERIFY(pgrad != 0); |
|
2317 QCOMPARE(pgrad->type(), QGradient::LinearGradient); |
|
2318 QLinearGradient *plingrad = static_cast<QLinearGradient*>(pgrad); |
|
2319 QCOMPARE(plingrad->start(), lg.start()); |
|
2320 QCOMPARE(plingrad->finalStop(), lg.finalStop()); |
|
2321 } |
|
2322 } |
|
2323 } |
|
2324 |
|
2325 class Klazz : public QWidget, |
|
2326 public QStandardItem, |
|
2327 public QGraphicsItem |
|
2328 { |
|
2329 Q_OBJECT |
|
2330 public: |
|
2331 Klazz(QWidget *parent = 0) : QWidget(parent) { } |
|
2332 virtual QRectF boundingRect() const { return QRectF(); } |
|
2333 virtual void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*) { } |
|
2334 }; |
|
2335 |
|
2336 Q_DECLARE_METATYPE(Klazz*) |
|
2337 Q_DECLARE_METATYPE(QStandardItem*) |
|
2338 |
|
2339 void tst_QScriptEngine::castWithMultipleInheritance() |
|
2340 { |
|
2341 QScriptEngine eng; |
|
2342 Klazz klz; |
|
2343 QScriptValue v = eng.newQObject(&klz); |
|
2344 |
|
2345 QCOMPARE(qscriptvalue_cast<Klazz*>(v), &klz); |
|
2346 QCOMPARE(qscriptvalue_cast<QWidget*>(v), (QWidget *)&klz); |
|
2347 QCOMPARE(qscriptvalue_cast<QObject*>(v), (QObject *)&klz); |
|
2348 QCOMPARE(qscriptvalue_cast<QStandardItem*>(v), (QStandardItem *)&klz); |
|
2349 QCOMPARE(qscriptvalue_cast<QGraphicsItem*>(v), (QGraphicsItem *)&klz); |
|
2350 } |
|
2351 |
|
2352 void tst_QScriptEngine::collectGarbage() |
|
2353 { |
|
2354 QScriptEngine eng; |
|
2355 eng.evaluate("a = new Object(); a = new Object(); a = new Object()"); |
|
2356 QScriptValue a = eng.newObject(); |
|
2357 a = eng.newObject(); |
|
2358 a = eng.newObject(); |
|
2359 QPointer<QObject> ptr = new QObject(); |
|
2360 QVERIFY(ptr != 0); |
|
2361 (void)eng.newQObject(ptr, QScriptEngine::ScriptOwnership); |
|
2362 collectGarbage_helper(eng); |
|
2363 QVERIFY(ptr == 0); |
|
2364 } |
|
2365 |
|
2366 void tst_QScriptEngine::gcWithNestedDataStructure() |
|
2367 { |
|
2368 QScriptEngine eng; |
|
2369 eng.evaluate( |
|
2370 "function makeList(size)" |
|
2371 "{" |
|
2372 " var head = { };" |
|
2373 " var l = head;" |
|
2374 " for (var i = 0; i < size; ++i) {" |
|
2375 " l.data = i + \"\";" |
|
2376 " l.next = { }; l = l.next;" |
|
2377 " }" |
|
2378 " l.next = null;" |
|
2379 " return head;" |
|
2380 "}"); |
|
2381 QCOMPARE(eng.hasUncaughtException(), false); |
|
2382 const int size = 200; |
|
2383 QScriptValue head = eng.evaluate(QString::fromLatin1("makeList(%0)").arg(size)); |
|
2384 QCOMPARE(eng.hasUncaughtException(), false); |
|
2385 for (int x = 0; x < 2; ++x) { |
|
2386 if (x == 1) |
|
2387 eng.evaluate("gc()"); |
|
2388 QScriptValue l = head; |
|
2389 for (int i = 0; i < 200; ++i) { |
|
2390 QCOMPARE(l.property("data").toString(), QString::number(i)); |
|
2391 l = l.property("next"); |
|
2392 } |
|
2393 } |
|
2394 } |
|
2395 |
|
2396 class EventReceiver : public QObject |
|
2397 { |
|
2398 public: |
|
2399 EventReceiver() { |
|
2400 received = false; |
|
2401 } |
|
2402 |
|
2403 bool event(QEvent *e) { |
|
2404 received |= (e->type() == QEvent::User + 1); |
|
2405 return QObject::event(e); |
|
2406 } |
|
2407 |
|
2408 bool received; |
|
2409 }; |
|
2410 |
|
2411 void tst_QScriptEngine::processEventsWhileRunning() |
|
2412 { |
|
2413 for (int x = 0; x < 2; ++x) { |
|
2414 QScriptEngine eng; |
|
2415 if (x == 0) |
|
2416 eng.pushContext(); |
|
2417 |
|
2418 QString script = QString::fromLatin1( |
|
2419 "var end = Number(new Date()) + 2000;" |
|
2420 "var x = 0;" |
|
2421 "while (Number(new Date()) < end) {" |
|
2422 " ++x;" |
|
2423 "}"); |
|
2424 |
|
2425 EventReceiver receiver; |
|
2426 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); |
|
2427 |
|
2428 eng.evaluate(script); |
|
2429 QVERIFY(!eng.hasUncaughtException()); |
|
2430 QVERIFY(!receiver.received); |
|
2431 |
|
2432 QCOMPARE(eng.processEventsInterval(), -1); |
|
2433 eng.setProcessEventsInterval(100); |
|
2434 eng.evaluate(script); |
|
2435 QVERIFY(!eng.hasUncaughtException()); |
|
2436 QVERIFY(receiver.received); |
|
2437 |
|
2438 if (x == 0) |
|
2439 eng.popContext(); |
|
2440 } |
|
2441 } |
|
2442 |
|
2443 class EventReceiver2 : public QObject |
|
2444 { |
|
2445 public: |
|
2446 EventReceiver2(QScriptEngine *eng) { |
|
2447 engine = eng; |
|
2448 } |
|
2449 |
|
2450 bool event(QEvent *e) { |
|
2451 if (e->type() == QEvent::User + 1) { |
|
2452 engine->currentContext()->throwError("Killed"); |
|
2453 } |
|
2454 return QObject::event(e); |
|
2455 } |
|
2456 |
|
2457 QScriptEngine *engine; |
|
2458 }; |
|
2459 |
|
2460 void tst_QScriptEngine::throwErrorFromProcessEvents() |
|
2461 { |
|
2462 QScriptEngine eng; |
|
2463 |
|
2464 EventReceiver2 receiver(&eng); |
|
2465 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); |
|
2466 |
|
2467 eng.setProcessEventsInterval(100); |
|
2468 QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }")); |
|
2469 QVERIFY(ret.isError()); |
|
2470 QCOMPARE(ret.toString(), QString::fromLatin1("Error: Killed")); |
|
2471 } |
|
2472 |
|
2473 void tst_QScriptEngine::stacktrace() |
|
2474 { |
|
2475 QString script = QString::fromLatin1( |
|
2476 "function foo(counter) {\n" |
|
2477 " switch (counter) {\n" |
|
2478 " case 0: foo(counter+1); break;\n" |
|
2479 " case 1: foo(counter+1); break;\n" |
|
2480 " case 2: foo(counter+1); break;\n" |
|
2481 " case 3: foo(counter+1); break;\n" |
|
2482 " case 4: foo(counter+1); break;\n" |
|
2483 " default:\n" |
|
2484 " throw new Error('blah');\n" |
|
2485 " }\n" |
|
2486 "}\n" |
|
2487 "foo(0);"); |
|
2488 |
|
2489 const QString fileName("testfile"); |
|
2490 |
|
2491 QStringList backtrace; |
|
2492 backtrace << "foo(5)@testfile:9" |
|
2493 << "foo(4)@testfile:7" |
|
2494 << "foo(3)@testfile:6" |
|
2495 << "foo(2)@testfile:5" |
|
2496 << "foo(1)@testfile:4" |
|
2497 << "foo(0)@testfile:3" |
|
2498 << "<global>()@testfile:12"; |
|
2499 |
|
2500 QScriptEngine eng; |
|
2501 QScriptValue result = eng.evaluate(script, fileName); |
|
2502 QVERIFY(eng.hasUncaughtException()); |
|
2503 QVERIFY(result.isError()); |
|
2504 |
|
2505 QEXPECT_FAIL("", "", Abort); |
|
2506 QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace); |
|
2507 QVERIFY(eng.hasUncaughtException()); |
|
2508 QVERIFY(result.strictlyEquals(eng.uncaughtException())); |
|
2509 |
|
2510 QCOMPARE(result.property("fileName").toString(), fileName); |
|
2511 QCOMPARE(result.property("lineNumber").toInt32(), 9); |
|
2512 |
|
2513 QScriptValue stack = result.property("stack"); |
|
2514 QVERIFY(stack.isArray()); |
|
2515 |
|
2516 QCOMPARE(stack.property("length").toInt32(), 7); |
|
2517 |
|
2518 QScriptValueIterator it(stack); |
|
2519 int counter = 5; |
|
2520 while (it.hasNext()) { |
|
2521 it.next(); |
|
2522 QScriptValue obj = it.value(); |
|
2523 QScriptValue frame = obj.property("frame"); |
|
2524 |
|
2525 QCOMPARE(obj.property("fileName").toString(), fileName); |
|
2526 if (counter >= 0) { |
|
2527 QScriptValue callee = frame.property("arguments").property("callee"); |
|
2528 QVERIFY(callee.strictlyEquals(eng.globalObject().property("foo"))); |
|
2529 QCOMPARE(obj.property("functionName").toString(), QString("foo")); |
|
2530 int line = obj.property("lineNumber").toInt32(); |
|
2531 if (counter == 5) |
|
2532 QCOMPARE(line, 9); |
|
2533 else |
|
2534 QCOMPARE(line, 3 + counter); |
|
2535 } else { |
|
2536 QVERIFY(frame.strictlyEquals(eng.globalObject())); |
|
2537 QVERIFY(obj.property("functionName").toString().isEmpty()); |
|
2538 } |
|
2539 |
|
2540 --counter; |
|
2541 } |
|
2542 |
|
2543 { |
|
2544 QScriptValue bt = result.property("backtrace").call(result); |
|
2545 QCOMPARE(qscriptvalue_cast<QStringList>(bt), backtrace); |
|
2546 } |
|
2547 |
|
2548 // throw something that isn't an Error object |
|
2549 eng.clearExceptions(); |
|
2550 QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty()); |
|
2551 QString script2 = QString::fromLatin1( |
|
2552 "function foo(counter) {\n" |
|
2553 " switch (counter) {\n" |
|
2554 " case 0: foo(counter+1); break;\n" |
|
2555 " case 1: foo(counter+1); break;\n" |
|
2556 " case 2: foo(counter+1); break;\n" |
|
2557 " case 3: foo(counter+1); break;\n" |
|
2558 " case 4: foo(counter+1); break;\n" |
|
2559 " default:\n" |
|
2560 " throw 'just a string';\n" |
|
2561 " }\n" |
|
2562 "}\n" |
|
2563 "foo(0);"); |
|
2564 |
|
2565 QScriptValue result2 = eng.evaluate(script2, fileName); |
|
2566 QVERIFY(eng.hasUncaughtException()); |
|
2567 QVERIFY(!result2.isError()); |
|
2568 QVERIFY(result2.isString()); |
|
2569 |
|
2570 QCOMPARE(eng.uncaughtExceptionBacktrace(), backtrace); |
|
2571 QVERIFY(eng.hasUncaughtException()); |
|
2572 |
|
2573 eng.clearExceptions(); |
|
2574 QVERIFY(!eng.hasUncaughtException()); |
|
2575 QVERIFY(eng.uncaughtExceptionBacktrace().isEmpty()); |
|
2576 } |
|
2577 |
|
2578 void tst_QScriptEngine::numberParsing_data() |
|
2579 { |
|
2580 QTest::addColumn<QString>("string"); |
|
2581 QTest::addColumn<qsreal>("expect"); |
|
2582 |
|
2583 QTest::newRow("decimal 0") << QString("0") << qsreal(0); |
|
2584 QTest::newRow("octal 0") << QString("00") << qsreal(00); |
|
2585 QTest::newRow("hex 0") << QString("0x0") << qsreal(0x0); |
|
2586 QTest::newRow("decimal 100") << QString("100") << qsreal(100); |
|
2587 QTest::newRow("hex 100") << QString("0x100") << qsreal(0x100); |
|
2588 QTest::newRow("octal 100") << QString("0100") << qsreal(0100); |
|
2589 QTest::newRow("decimal 4G") << QString("4294967296") << qsreal(Q_UINT64_C(4294967296)); |
|
2590 QTest::newRow("hex 4G") << QString("0x100000000") << qsreal(Q_UINT64_C(0x100000000)); |
|
2591 QTest::newRow("octal 4G") << QString("040000000000") << qsreal(Q_UINT64_C(040000000000)); |
|
2592 QTest::newRow("0.5") << QString("0.5") << qsreal(0.5); |
|
2593 QTest::newRow("1.5") << QString("1.5") << qsreal(1.5); |
|
2594 QTest::newRow("1e2") << QString("1e2") << qsreal(100); |
|
2595 } |
|
2596 |
|
2597 void tst_QScriptEngine::numberParsing() |
|
2598 { |
|
2599 QFETCH(QString, string); |
|
2600 QFETCH(qsreal, expect); |
|
2601 |
|
2602 QScriptEngine eng; |
|
2603 QScriptValue ret = eng.evaluate(string); |
|
2604 QVERIFY(ret.isNumber()); |
|
2605 qsreal actual = ret.toNumber(); |
|
2606 QCOMPARE(actual, expect); |
|
2607 } |
|
2608 |
|
2609 // see ECMA-262, section 7.9 |
|
2610 void tst_QScriptEngine::automaticSemicolonInsertion() |
|
2611 { |
|
2612 QScriptEngine eng; |
|
2613 { |
|
2614 QScriptValue ret = eng.evaluate("{ 1 2 } 3"); |
|
2615 QVERIFY(ret.isError()); |
|
2616 QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error")); |
|
2617 } |
|
2618 { |
|
2619 QScriptValue ret = eng.evaluate("{ 1\n2 } 3"); |
|
2620 QVERIFY(ret.isNumber()); |
|
2621 QCOMPARE(ret.toInt32(), 3); |
|
2622 } |
|
2623 { |
|
2624 QScriptValue ret = eng.evaluate("for (a; b\n)"); |
|
2625 QVERIFY(ret.isError()); |
|
2626 QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error")); |
|
2627 } |
|
2628 { |
|
2629 QScriptValue ret = eng.evaluate("(function() { return\n1 + 2 })()"); |
|
2630 QVERIFY(ret.isUndefined()); |
|
2631 } |
|
2632 { |
|
2633 eng.evaluate("c = 2; b = 1"); |
|
2634 QScriptValue ret = eng.evaluate("a = b\n++c"); |
|
2635 QVERIFY(ret.isNumber()); |
|
2636 QCOMPARE(ret.toInt32(), 3); |
|
2637 } |
|
2638 { |
|
2639 QScriptValue ret = eng.evaluate("if (a > b)\nelse c = d"); |
|
2640 QVERIFY(ret.isError()); |
|
2641 QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error")); |
|
2642 } |
|
2643 { |
|
2644 eng.evaluate("function c() { return { foo: function() { return 5; } } }"); |
|
2645 eng.evaluate("b = 1; d = 2; e = 3"); |
|
2646 QScriptValue ret = eng.evaluate("a = b + c\n(d + e).foo()"); |
|
2647 QVERIFY(ret.isNumber()); |
|
2648 QCOMPARE(ret.toInt32(), 6); |
|
2649 } |
|
2650 { |
|
2651 QScriptValue ret = eng.evaluate("throw\n1"); |
|
2652 QVERIFY(ret.isError()); |
|
2653 QCOMPARE(ret.toString(), QString::fromLatin1("SyntaxError: Parse error")); |
|
2654 } |
|
2655 { |
|
2656 QScriptValue ret = eng.evaluate("a = Number(1)\n++a"); |
|
2657 QVERIFY(ret.isNumber()); |
|
2658 QCOMPARE(ret.toInt32(), 2); |
|
2659 } |
|
2660 |
|
2661 // "a semicolon is never inserted automatically if the semicolon |
|
2662 // would then be parsed as an empty statement" |
|
2663 { |
|
2664 eng.evaluate("a = 123"); |
|
2665 QScriptValue ret = eng.evaluate("if (0)\n ++a; a"); |
|
2666 QVERIFY(ret.isNumber()); |
|
2667 QCOMPARE(ret.toInt32(), 123); |
|
2668 } |
|
2669 { |
|
2670 eng.evaluate("a = 123"); |
|
2671 QScriptValue ret = eng.evaluate("if (0)\n --a; a"); |
|
2672 QVERIFY(ret.isNumber()); |
|
2673 QCOMPARE(ret.toInt32(), 123); |
|
2674 } |
|
2675 { |
|
2676 eng.evaluate("a = 123"); |
|
2677 QScriptValue ret = eng.evaluate("if ((0))\n ++a; a"); |
|
2678 QVERIFY(ret.isNumber()); |
|
2679 QCOMPARE(ret.toInt32(), 123); |
|
2680 } |
|
2681 { |
|
2682 eng.evaluate("a = 123"); |
|
2683 QScriptValue ret = eng.evaluate("if ((0))\n --a; a"); |
|
2684 QVERIFY(ret.isNumber()); |
|
2685 QCOMPARE(ret.toInt32(), 123); |
|
2686 } |
|
2687 { |
|
2688 eng.evaluate("a = 123"); |
|
2689 QScriptValue ret = eng.evaluate("if (0\n)\n ++a; a"); |
|
2690 QVERIFY(ret.isNumber()); |
|
2691 QCOMPARE(ret.toInt32(), 123); |
|
2692 } |
|
2693 { |
|
2694 eng.evaluate("a = 123"); |
|
2695 QScriptValue ret = eng.evaluate("if (0\n ++a; a"); |
|
2696 QVERIFY(ret.isError()); |
|
2697 } |
|
2698 { |
|
2699 eng.evaluate("a = 123"); |
|
2700 QScriptValue ret = eng.evaluate("if (0))\n ++a; a"); |
|
2701 QVERIFY(ret.isError()); |
|
2702 } |
|
2703 { |
|
2704 QScriptValue ret = eng.evaluate("n = 0; for (i = 0; i < 10; ++i)\n ++n; n"); |
|
2705 QVERIFY(ret.isNumber()); |
|
2706 QCOMPARE(ret.toInt32(), 10); |
|
2707 } |
|
2708 { |
|
2709 QScriptValue ret = eng.evaluate("n = 30; for (i = 0; i < 10; ++i)\n --n; n"); |
|
2710 QVERIFY(ret.isNumber()); |
|
2711 QCOMPARE(ret.toInt32(), 20); |
|
2712 } |
|
2713 { |
|
2714 QScriptValue ret = eng.evaluate("n = 0; for (var i = 0; i < 10; ++i)\n ++n; n"); |
|
2715 QVERIFY(ret.isNumber()); |
|
2716 QCOMPARE(ret.toInt32(), 10); |
|
2717 } |
|
2718 { |
|
2719 QScriptValue ret = eng.evaluate("n = 30; for (var i = 0; i < 10; ++i)\n --n; n"); |
|
2720 QVERIFY(ret.isNumber()); |
|
2721 QCOMPARE(ret.toInt32(), 20); |
|
2722 } |
|
2723 { |
|
2724 QScriptValue ret = eng.evaluate("n = 0; i = 0; while (i++ < 10)\n ++n; n"); |
|
2725 QVERIFY(ret.isNumber()); |
|
2726 QCOMPARE(ret.toInt32(), 10); |
|
2727 } |
|
2728 { |
|
2729 QScriptValue ret = eng.evaluate("n = 30; i = 0; while (i++ < 10)\n --n; n"); |
|
2730 QVERIFY(ret.isNumber()); |
|
2731 QCOMPARE(ret.toInt32(), 20); |
|
2732 } |
|
2733 { |
|
2734 QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (i in o)\n ++n; n"); |
|
2735 QVERIFY(ret.isNumber()); |
|
2736 QCOMPARE(ret.toInt32(), 3); |
|
2737 } |
|
2738 { |
|
2739 QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (i in o)\n --n; n"); |
|
2740 QVERIFY(ret.isNumber()); |
|
2741 QCOMPARE(ret.toInt32(), 6); |
|
2742 } |
|
2743 { |
|
2744 QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 0; for (var i in o)\n ++n; n"); |
|
2745 QVERIFY(ret.isNumber()); |
|
2746 QCOMPARE(ret.toInt32(), 3); |
|
2747 } |
|
2748 { |
|
2749 QScriptValue ret = eng.evaluate("o = { a: 0, b: 1, c: 2 }; n = 9; for (var i in o)\n --n; n"); |
|
2750 QVERIFY(ret.isNumber()); |
|
2751 QCOMPARE(ret.toInt32(), 6); |
|
2752 } |
|
2753 { |
|
2754 QScriptValue ret = eng.evaluate("o = { n: 3 }; n = 5; with (o)\n ++n; n"); |
|
2755 QVERIFY(ret.isNumber()); |
|
2756 QCOMPARE(ret.toInt32(), 5); |
|
2757 } |
|
2758 { |
|
2759 QScriptValue ret = eng.evaluate("o = { n: 3 }; n = 10; with (o)\n --n; n"); |
|
2760 QVERIFY(ret.isNumber()); |
|
2761 QCOMPARE(ret.toInt32(), 10); |
|
2762 } |
|
2763 { |
|
2764 QScriptValue ret = eng.evaluate("n = 5; i = 0; do\n ++n; while (++i < 10); n"); |
|
2765 QVERIFY(ret.isNumber()); |
|
2766 QCOMPARE(ret.toInt32(), 15); |
|
2767 } |
|
2768 { |
|
2769 QScriptValue ret = eng.evaluate("n = 20; i = 0; do\n --n; while (++i < 10); n"); |
|
2770 QVERIFY(ret.isNumber()); |
|
2771 QCOMPARE(ret.toInt32(), 10); |
|
2772 } |
|
2773 |
|
2774 { |
|
2775 QScriptValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n++n; n"); |
|
2776 QVERIFY(ret.isNumber()); |
|
2777 QCOMPARE(ret.toInt32(), 2); |
|
2778 } |
|
2779 { |
|
2780 QScriptValue ret = eng.evaluate("n = 1; i = 0; if (n) i\n--n; n"); |
|
2781 QVERIFY(ret.isNumber()); |
|
2782 QCOMPARE(ret.toInt32(), 0); |
|
2783 } |
|
2784 |
|
2785 { |
|
2786 QScriptValue ret = eng.evaluate("if (0)"); |
|
2787 QVERIFY(ret.isError()); |
|
2788 } |
|
2789 { |
|
2790 QScriptValue ret = eng.evaluate("while (0)"); |
|
2791 QVERIFY(ret.isError()); |
|
2792 } |
|
2793 { |
|
2794 QScriptValue ret = eng.evaluate("for (;;)"); |
|
2795 QVERIFY(ret.isError()); |
|
2796 } |
|
2797 { |
|
2798 QScriptValue ret = eng.evaluate("for (p in this)"); |
|
2799 QVERIFY(ret.isError()); |
|
2800 } |
|
2801 { |
|
2802 QScriptValue ret = eng.evaluate("with (this)"); |
|
2803 QVERIFY(ret.isError()); |
|
2804 } |
|
2805 { |
|
2806 QScriptValue ret = eng.evaluate("do"); |
|
2807 QVERIFY(ret.isError()); |
|
2808 } |
|
2809 } |
|
2810 |
|
2811 class EventReceiver3 : public QObject |
|
2812 { |
|
2813 public: |
|
2814 enum AbortionResult { |
|
2815 None = 0, |
|
2816 String = 1, |
|
2817 Error = 2 |
|
2818 }; |
|
2819 |
|
2820 EventReceiver3(QScriptEngine *eng) { |
|
2821 engine = eng; |
|
2822 resultType = None; |
|
2823 } |
|
2824 |
|
2825 bool event(QEvent *e) { |
|
2826 if (e->type() == QEvent::User + 1) { |
|
2827 switch (resultType) { |
|
2828 case None: |
|
2829 engine->abortEvaluation(); |
|
2830 break; |
|
2831 case String: |
|
2832 engine->abortEvaluation(QScriptValue(engine, QString::fromLatin1("Aborted"))); |
|
2833 break; |
|
2834 case Error: |
|
2835 engine->abortEvaluation(engine->currentContext()->throwError("AbortedWithError")); |
|
2836 break; |
|
2837 } |
|
2838 } |
|
2839 return QObject::event(e); |
|
2840 } |
|
2841 |
|
2842 AbortionResult resultType; |
|
2843 QScriptEngine *engine; |
|
2844 }; |
|
2845 |
|
2846 static QScriptValue myFunctionAbortingEvaluation(QScriptContext *, QScriptEngine *eng) |
|
2847 { |
|
2848 eng->abortEvaluation(); |
|
2849 return eng->nullValue(); // should be ignored |
|
2850 } |
|
2851 |
|
2852 void tst_QScriptEngine::abortEvaluation() |
|
2853 { |
|
2854 QScriptEngine eng; |
|
2855 |
|
2856 eng.abortEvaluation(); |
|
2857 QVERIFY(!eng.hasUncaughtException()); |
|
2858 |
|
2859 eng.abortEvaluation(123); |
|
2860 { |
|
2861 QScriptValue ret = eng.evaluate("'ciao'"); |
|
2862 QVERIFY(ret.isString()); |
|
2863 QCOMPARE(ret.toString(), QString::fromLatin1("ciao")); |
|
2864 } |
|
2865 |
|
2866 EventReceiver3 receiver(&eng); |
|
2867 |
|
2868 eng.setProcessEventsInterval(100); |
|
2869 for (int x = 0; x < 3; ++x) { |
|
2870 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); |
|
2871 receiver.resultType = EventReceiver3::AbortionResult(x); |
|
2872 QScriptValue ret = eng.evaluate(QString::fromLatin1("while (1) { }")); |
|
2873 switch (receiver.resultType) { |
|
2874 case EventReceiver3::None: |
|
2875 QVERIFY(!eng.hasUncaughtException()); |
|
2876 QVERIFY(!ret.isValid()); |
|
2877 break; |
|
2878 case EventReceiver3::String: |
|
2879 QVERIFY(!eng.hasUncaughtException()); |
|
2880 QVERIFY(ret.isString()); |
|
2881 QCOMPARE(ret.toString(), QString::fromLatin1("Aborted")); |
|
2882 break; |
|
2883 case EventReceiver3::Error: |
|
2884 QVERIFY(eng.hasUncaughtException()); |
|
2885 QVERIFY(ret.isError()); |
|
2886 QCOMPARE(ret.toString(), QString::fromLatin1("Error: AbortedWithError")); |
|
2887 break; |
|
2888 } |
|
2889 } |
|
2890 |
|
2891 // scripts cannot intercept the abortion with try/catch |
|
2892 for (int y = 0; y < 3; ++y) { |
|
2893 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); |
|
2894 receiver.resultType = EventReceiver3::AbortionResult(y); |
|
2895 QScriptValue ret = eng.evaluate(QString::fromLatin1( |
|
2896 "while (1) {\n" |
|
2897 " try {\n" |
|
2898 " (function() { while (1) { } })();\n" |
|
2899 " } catch (e) {\n" |
|
2900 " ;\n" |
|
2901 " }\n" |
|
2902 "}")); |
|
2903 switch (receiver.resultType) { |
|
2904 case EventReceiver3::None: |
|
2905 QVERIFY(!eng.hasUncaughtException()); |
|
2906 QVERIFY(!ret.isValid()); |
|
2907 break; |
|
2908 case EventReceiver3::String: |
|
2909 QVERIFY(!eng.hasUncaughtException()); |
|
2910 QVERIFY(ret.isString()); |
|
2911 QCOMPARE(ret.toString(), QString::fromLatin1("Aborted")); |
|
2912 break; |
|
2913 case EventReceiver3::Error: |
|
2914 QVERIFY(eng.hasUncaughtException()); |
|
2915 QVERIFY(ret.isError()); |
|
2916 break; |
|
2917 } |
|
2918 } |
|
2919 |
|
2920 { |
|
2921 QScriptValue fun = eng.newFunction(myFunctionAbortingEvaluation); |
|
2922 eng.globalObject().setProperty("myFunctionAbortingEvaluation", fun); |
|
2923 QScriptValue ret = eng.evaluate("myFunctionAbortingEvaluation()"); |
|
2924 QVERIFY(!ret.isValid()); |
|
2925 } |
|
2926 } |
|
2927 |
|
2928 static QScriptValue myFunctionReturningIsEvaluating(QScriptContext *, QScriptEngine *eng) |
|
2929 { |
|
2930 return QScriptValue(eng, eng->isEvaluating()); |
|
2931 } |
|
2932 |
|
2933 class EventReceiver4 : public QObject |
|
2934 { |
|
2935 public: |
|
2936 EventReceiver4(QScriptEngine *eng) { |
|
2937 engine = eng; |
|
2938 wasEvaluating = false; |
|
2939 } |
|
2940 |
|
2941 bool event(QEvent *e) { |
|
2942 if (e->type() == QEvent::User + 1) { |
|
2943 wasEvaluating = engine->isEvaluating(); |
|
2944 } |
|
2945 return QObject::event(e); |
|
2946 } |
|
2947 |
|
2948 QScriptEngine *engine; |
|
2949 bool wasEvaluating; |
|
2950 }; |
|
2951 |
|
2952 void tst_QScriptEngine::isEvaluating() |
|
2953 { |
|
2954 QScriptEngine eng; |
|
2955 |
|
2956 QVERIFY(!eng.isEvaluating()); |
|
2957 |
|
2958 eng.evaluate(""); |
|
2959 QVERIFY(!eng.isEvaluating()); |
|
2960 eng.evaluate("123"); |
|
2961 QVERIFY(!eng.isEvaluating()); |
|
2962 eng.evaluate("0 = 0"); |
|
2963 QVERIFY(!eng.isEvaluating()); |
|
2964 |
|
2965 { |
|
2966 QScriptValue fun = eng.newFunction(myFunctionReturningIsEvaluating); |
|
2967 eng.globalObject().setProperty("myFunctionReturningIsEvaluating", fun); |
|
2968 QScriptValue ret = eng.evaluate("myFunctionReturningIsEvaluating()"); |
|
2969 QVERIFY(ret.isBoolean()); |
|
2970 QVERIFY(ret.toBoolean()); |
|
2971 } |
|
2972 |
|
2973 { |
|
2974 EventReceiver4 receiver(&eng); |
|
2975 QCoreApplication::postEvent(&receiver, new QEvent(QEvent::Type(QEvent::User+1))); |
|
2976 |
|
2977 QString script = QString::fromLatin1( |
|
2978 "var end = Number(new Date()) + 1000;" |
|
2979 "var x = 0;" |
|
2980 "while (Number(new Date()) < end) {" |
|
2981 " ++x;" |
|
2982 "}"); |
|
2983 |
|
2984 eng.setProcessEventsInterval(100); |
|
2985 eng.evaluate(script); |
|
2986 QVERIFY(receiver.wasEvaluating); |
|
2987 } |
|
2988 } |
|
2989 |
|
2990 static QtMsgType theMessageType; |
|
2991 static QString theMessage; |
|
2992 |
|
2993 static void myMsgHandler(QtMsgType type, const char *msg) |
|
2994 { |
|
2995 theMessageType = type; |
|
2996 theMessage = QString::fromLatin1(msg); |
|
2997 } |
|
2998 |
|
2999 void tst_QScriptEngine::printFunctionWithCustomHandler() |
|
3000 { |
|
3001 QScriptEngine eng; |
|
3002 QtMsgHandler oldHandler = qInstallMsgHandler(myMsgHandler); |
|
3003 QVERIFY(eng.globalObject().property("print").isFunction()); |
|
3004 theMessageType = QtSystemMsg; |
|
3005 QVERIFY(theMessage.isEmpty()); |
|
3006 QVERIFY(eng.evaluate("print('test')").isUndefined()); |
|
3007 QCOMPARE(theMessageType, QtDebugMsg); |
|
3008 QCOMPARE(theMessage, QString::fromLatin1("test")); |
|
3009 theMessageType = QtSystemMsg; |
|
3010 theMessage.clear(); |
|
3011 QVERIFY(eng.evaluate("print(3, true, 'little pigs')").isUndefined()); |
|
3012 QCOMPARE(theMessageType, QtDebugMsg); |
|
3013 QCOMPARE(theMessage, QString::fromLatin1("3 true little pigs")); |
|
3014 qInstallMsgHandler(oldHandler); |
|
3015 } |
|
3016 |
|
3017 void tst_QScriptEngine::printThrowsException() |
|
3018 { |
|
3019 QScriptEngine eng; |
|
3020 QScriptValue ret = eng.evaluate("print({ toString: function() { throw 'foo'; } });"); |
|
3021 QVERIFY(eng.hasUncaughtException()); |
|
3022 QVERIFY(ret.strictlyEquals(QScriptValue(&eng, QLatin1String("foo")))); |
|
3023 } |
|
3024 |
|
3025 void tst_QScriptEngine::errorConstructors() |
|
3026 { |
|
3027 QScriptEngine eng; |
|
3028 QStringList prefixes; |
|
3029 prefixes << "" << "Eval" << "Range" << "Reference" << "Syntax" << "Type" << "URI"; |
|
3030 for (int x = 0; x < 3; ++x) { |
|
3031 for (int i = 0; i < prefixes.size(); ++i) { |
|
3032 QString name = prefixes.at(i) + QLatin1String("Error"); |
|
3033 QString code = QString(i+1, QLatin1Char('\n')); |
|
3034 if (x == 0) |
|
3035 code += QLatin1String("throw "); |
|
3036 else if (x == 1) |
|
3037 code += QLatin1String("new "); |
|
3038 code += name + QLatin1String("()"); |
|
3039 QScriptValue ret = eng.evaluate(code); |
|
3040 QVERIFY(ret.isError()); |
|
3041 QCOMPARE(eng.hasUncaughtException(), x == 0); |
|
3042 eng.clearExceptions(); |
|
3043 QVERIFY(ret.toString().startsWith(name)); |
|
3044 if (x != 0) |
|
3045 QEXPECT_FAIL("", "JSC doesn't assign lineNumber when errors are not thrown", Continue); |
|
3046 QCOMPARE(ret.property("lineNumber").toInt32(), i+2); |
|
3047 } |
|
3048 } |
|
3049 } |
|
3050 |
|
3051 static QScriptValue argumentsProperty_fun(QScriptContext *, QScriptEngine *eng) |
|
3052 { |
|
3053 eng->evaluate("var a = arguments[0];"); |
|
3054 eng->evaluate("arguments[0] = 200;"); |
|
3055 return eng->evaluate("a + arguments[0]"); |
|
3056 } |
|
3057 |
|
3058 |
|
3059 void tst_QScriptEngine::argumentsProperty() |
|
3060 { |
|
3061 { |
|
3062 QScriptEngine eng; |
|
3063 QEXPECT_FAIL("", "", Continue); |
|
3064 QVERIFY(eng.evaluate("arguments").isUndefined()); |
|
3065 eng.evaluate("arguments = 10"); |
|
3066 QScriptValue ret = eng.evaluate("arguments"); |
|
3067 QVERIFY(ret.isNumber()); |
|
3068 QCOMPARE(ret.toInt32(), 10); |
|
3069 QEXPECT_FAIL("", "", Continue); |
|
3070 QVERIFY(!eng.evaluate("delete arguments").toBoolean()); |
|
3071 } |
|
3072 { |
|
3073 QScriptEngine eng; |
|
3074 eng.evaluate("o = { arguments: 123 }"); |
|
3075 QScriptValue ret = eng.evaluate("with (o) { arguments; }"); |
|
3076 QVERIFY(ret.isNumber()); |
|
3077 QCOMPARE(ret.toInt32(), 123); |
|
3078 } |
|
3079 { |
|
3080 QScriptEngine eng; |
|
3081 QScriptValue ret = eng.evaluate("(function() { arguments = 456; return arguments; })()"); |
|
3082 QVERIFY(ret.isNumber()); |
|
3083 QCOMPARE(ret.toInt32(), 456); |
|
3084 QEXPECT_FAIL("", "", Continue); |
|
3085 QVERIFY(eng.evaluate("arguments").isUndefined()); |
|
3086 } |
|
3087 |
|
3088 { |
|
3089 QScriptEngine eng; |
|
3090 QScriptValue fun = eng.newFunction(argumentsProperty_fun); |
|
3091 eng.globalObject().setProperty("fun", eng.newFunction(argumentsProperty_fun)); |
|
3092 QScriptValue result = eng.evaluate("fun(18)"); |
|
3093 QVERIFY(result.isNumber()); |
|
3094 QCOMPARE(result.toInt32(), 218); |
|
3095 } |
|
3096 } |
|
3097 |
|
3098 void tst_QScriptEngine::numberClass() |
|
3099 { |
|
3100 QScriptEngine eng; |
|
3101 |
|
3102 QScriptValue ctor = eng.globalObject().property("Number"); |
|
3103 QVERIFY(ctor.property("length").isNumber()); |
|
3104 QCOMPARE(ctor.property("length").toNumber(), qsreal(1)); |
|
3105 QScriptValue proto = ctor.property("prototype"); |
|
3106 QVERIFY(proto.isObject()); |
|
3107 { |
|
3108 QScriptValue::PropertyFlags flags = QScriptValue::SkipInEnumeration |
|
3109 | QScriptValue::Undeletable |
|
3110 | QScriptValue::ReadOnly; |
|
3111 QCOMPARE(ctor.propertyFlags("prototype"), flags); |
|
3112 QVERIFY(ctor.property("MAX_VALUE").isNumber()); |
|
3113 QCOMPARE(ctor.propertyFlags("MAX_VALUE"), flags); |
|
3114 QVERIFY(ctor.property("MIN_VALUE").isNumber()); |
|
3115 QCOMPARE(ctor.propertyFlags("MIN_VALUE"), flags); |
|
3116 QVERIFY(ctor.property("NaN").isNumber()); |
|
3117 QCOMPARE(ctor.propertyFlags("NaN"), flags); |
|
3118 QVERIFY(ctor.property("NEGATIVE_INFINITY").isNumber()); |
|
3119 QCOMPARE(ctor.propertyFlags("NEGATIVE_INFINITY"), flags); |
|
3120 QVERIFY(ctor.property("POSITIVE_INFINITY").isNumber()); |
|
3121 QCOMPARE(ctor.propertyFlags("POSITIVE_INFINITY"), flags); |
|
3122 } |
|
3123 QVERIFY(proto.instanceOf(eng.globalObject().property("Object"))); |
|
3124 QCOMPARE(proto.toNumber(), qsreal(0)); |
|
3125 QVERIFY(proto.property("constructor").strictlyEquals(ctor)); |
|
3126 |
|
3127 { |
|
3128 QScriptValue ret = eng.evaluate("Number()"); |
|
3129 QVERIFY(ret.isNumber()); |
|
3130 QCOMPARE(ret.toNumber(), qsreal(0)); |
|
3131 } |
|
3132 { |
|
3133 QScriptValue ret = eng.evaluate("Number(123)"); |
|
3134 QVERIFY(ret.isNumber()); |
|
3135 QCOMPARE(ret.toNumber(), qsreal(123)); |
|
3136 } |
|
3137 { |
|
3138 QScriptValue ret = eng.evaluate("Number('456')"); |
|
3139 QVERIFY(ret.isNumber()); |
|
3140 QCOMPARE(ret.toNumber(), qsreal(456)); |
|
3141 } |
|
3142 { |
|
3143 QScriptValue ret = eng.evaluate("new Number()"); |
|
3144 QVERIFY(!ret.isNumber()); |
|
3145 QVERIFY(ret.isObject()); |
|
3146 QCOMPARE(ret.toNumber(), qsreal(0)); |
|
3147 } |
|
3148 { |
|
3149 QScriptValue ret = eng.evaluate("new Number(123)"); |
|
3150 QVERIFY(!ret.isNumber()); |
|
3151 QVERIFY(ret.isObject()); |
|
3152 QCOMPARE(ret.toNumber(), qsreal(123)); |
|
3153 } |
|
3154 { |
|
3155 QScriptValue ret = eng.evaluate("new Number('456')"); |
|
3156 QVERIFY(!ret.isNumber()); |
|
3157 QVERIFY(ret.isObject()); |
|
3158 QCOMPARE(ret.toNumber(), qsreal(456)); |
|
3159 } |
|
3160 |
|
3161 QVERIFY(proto.property("toString").isFunction()); |
|
3162 { |
|
3163 QScriptValue ret = eng.evaluate("new Number(123).toString()"); |
|
3164 QVERIFY(ret.isString()); |
|
3165 QCOMPARE(ret.toString(), QString::fromLatin1("123")); |
|
3166 } |
|
3167 { |
|
3168 QScriptValue ret = eng.evaluate("new Number(123).toString(8)"); |
|
3169 QVERIFY(ret.isString()); |
|
3170 QCOMPARE(ret.toString(), QString::fromLatin1("173")); |
|
3171 } |
|
3172 { |
|
3173 QScriptValue ret = eng.evaluate("new Number(123).toString(16)"); |
|
3174 QVERIFY(ret.isString()); |
|
3175 QCOMPARE(ret.toString(), QString::fromLatin1("7b")); |
|
3176 } |
|
3177 QVERIFY(proto.property("toLocaleString").isFunction()); |
|
3178 { |
|
3179 QScriptValue ret = eng.evaluate("new Number(123).toLocaleString()"); |
|
3180 QVERIFY(ret.isString()); |
|
3181 QCOMPARE(ret.toString(), QString::fromLatin1("123")); |
|
3182 } |
|
3183 QVERIFY(proto.property("valueOf").isFunction()); |
|
3184 { |
|
3185 QScriptValue ret = eng.evaluate("new Number(123).valueOf()"); |
|
3186 QVERIFY(ret.isNumber()); |
|
3187 QCOMPARE(ret.toNumber(), qsreal(123)); |
|
3188 } |
|
3189 QVERIFY(proto.property("toExponential").isFunction()); |
|
3190 { |
|
3191 QScriptValue ret = eng.evaluate("new Number(123).toExponential()"); |
|
3192 QVERIFY(ret.isString()); |
|
3193 QCOMPARE(ret.toString(), QString::fromLatin1("1.23e+2")); |
|
3194 } |
|
3195 QVERIFY(proto.property("toFixed").isFunction()); |
|
3196 { |
|
3197 QScriptValue ret = eng.evaluate("new Number(123).toFixed()"); |
|
3198 QVERIFY(ret.isString()); |
|
3199 QCOMPARE(ret.toString(), QString::fromLatin1("123")); |
|
3200 } |
|
3201 QVERIFY(proto.property("toPrecision").isFunction()); |
|
3202 { |
|
3203 QScriptValue ret = eng.evaluate("new Number(123).toPrecision()"); |
|
3204 QVERIFY(ret.isString()); |
|
3205 QCOMPARE(ret.toString(), QString::fromLatin1("123")); |
|
3206 } |
|
3207 } |
|
3208 |
|
3209 void tst_QScriptEngine::forInStatement() |
|
3210 { |
|
3211 QScriptEngine eng; |
|
3212 { |
|
3213 QScriptValue ret = eng.evaluate("o = { }; r = []; for (var p in o) r[r.length] = p; r"); |
|
3214 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3215 QVERIFY(lst.isEmpty()); |
|
3216 } |
|
3217 { |
|
3218 QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];" |
|
3219 "for (var p in o) r[r.length] = p; r"); |
|
3220 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3221 QCOMPARE(lst.size(), 1); |
|
3222 QCOMPARE(lst.at(0), QString::fromLatin1("p")); |
|
3223 } |
|
3224 { |
|
3225 QScriptValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];" |
|
3226 "for (var p in o) r[r.length] = p; r"); |
|
3227 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3228 QCOMPARE(lst.size(), 2); |
|
3229 QCOMPARE(lst.at(0), QString::fromLatin1("p")); |
|
3230 QCOMPARE(lst.at(1), QString::fromLatin1("q")); |
|
3231 } |
|
3232 |
|
3233 // properties in prototype |
|
3234 { |
|
3235 QScriptValue ret = eng.evaluate("o = { }; o.__proto__ = { p: 123 }; r = [];" |
|
3236 "for (var p in o) r[r.length] = p; r"); |
|
3237 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3238 QCOMPARE(lst.size(), 1); |
|
3239 QCOMPARE(lst.at(0), QString::fromLatin1("p")); |
|
3240 } |
|
3241 { |
|
3242 QScriptValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { q: 456 }; r = [];" |
|
3243 "for (var p in o) r[r.length] = p; r"); |
|
3244 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3245 QCOMPARE(lst.size(), 2); |
|
3246 QCOMPARE(lst.at(0), QString::fromLatin1("p")); |
|
3247 QCOMPARE(lst.at(1), QString::fromLatin1("q")); |
|
3248 } |
|
3249 { |
|
3250 // shadowed property |
|
3251 QScriptValue ret = eng.evaluate("o = { p: 123 }; o.__proto__ = { p: 456 }; r = [];" |
|
3252 "for (var p in o) r[r.length] = p; r"); |
|
3253 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3254 QCOMPARE(lst.size(), 1); |
|
3255 QCOMPARE(lst.at(0), QString::fromLatin1("p")); |
|
3256 } |
|
3257 |
|
3258 // deleting property during enumeration |
|
3259 { |
|
3260 QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];" |
|
3261 "for (var p in o) { r[r.length] = p; delete r[p]; } r"); |
|
3262 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3263 QCOMPARE(lst.size(), 1); |
|
3264 QCOMPARE(lst.at(0), QString::fromLatin1("p")); |
|
3265 } |
|
3266 { |
|
3267 QScriptValue ret = eng.evaluate("o = { p: 123, q: 456 }; r = [];" |
|
3268 "for (var p in o) { r[r.length] = p; delete o.q; } r"); |
|
3269 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3270 QCOMPARE(lst.size(), 1); |
|
3271 QCOMPARE(lst.at(0), QString::fromLatin1("p")); |
|
3272 } |
|
3273 |
|
3274 // adding property during enumeration |
|
3275 { |
|
3276 QScriptValue ret = eng.evaluate("o = { p: 123 }; r = [];" |
|
3277 "for (var p in o) { r[r.length] = p; o.q = 456; } r"); |
|
3278 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3279 QCOMPARE(lst.size(), 1); |
|
3280 QCOMPARE(lst.at(0), QString::fromLatin1("p")); |
|
3281 } |
|
3282 |
|
3283 // arrays |
|
3284 { |
|
3285 QScriptValue ret = eng.evaluate("a = [123, 456]; r = [];" |
|
3286 "for (var p in a) r[r.length] = p; r"); |
|
3287 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3288 QCOMPARE(lst.size(), 2); |
|
3289 QCOMPARE(lst.at(0), QString::fromLatin1("0")); |
|
3290 QCOMPARE(lst.at(1), QString::fromLatin1("1")); |
|
3291 } |
|
3292 { |
|
3293 QScriptValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar'; r = [];" |
|
3294 "for (var p in a) r[r.length] = p; r"); |
|
3295 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3296 QCOMPARE(lst.size(), 3); |
|
3297 QCOMPARE(lst.at(0), QString::fromLatin1("0")); |
|
3298 QCOMPARE(lst.at(1), QString::fromLatin1("1")); |
|
3299 QCOMPARE(lst.at(2), QString::fromLatin1("foo")); |
|
3300 } |
|
3301 { |
|
3302 QScriptValue ret = eng.evaluate("a = [123, 456]; a.foo = 'bar';" |
|
3303 "b = [111, 222, 333]; b.bar = 'baz';" |
|
3304 "a.__proto__ = b; r = [];" |
|
3305 "for (var p in a) r[r.length] = p; r"); |
|
3306 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3307 QCOMPARE(lst.size(), 5); |
|
3308 QCOMPARE(lst.at(0), QString::fromLatin1("0")); |
|
3309 QCOMPARE(lst.at(1), QString::fromLatin1("1")); |
|
3310 QCOMPARE(lst.at(2), QString::fromLatin1("foo")); |
|
3311 QCOMPARE(lst.at(3), QString::fromLatin1("2")); |
|
3312 QCOMPARE(lst.at(4), QString::fromLatin1("bar")); |
|
3313 } |
|
3314 |
|
3315 // null and undefined |
|
3316 // according to the spec, we should throw an exception; however, for |
|
3317 // compability with the real world, we don't |
|
3318 { |
|
3319 QScriptValue ret = eng.evaluate("r = true; for (var p in undefined) r = false; r"); |
|
3320 QVERIFY(ret.isBool()); |
|
3321 QVERIFY(ret.toBool()); |
|
3322 } |
|
3323 { |
|
3324 QScriptValue ret = eng.evaluate("r = true; for (var p in null) r = false; r"); |
|
3325 QVERIFY(ret.isBool()); |
|
3326 QVERIFY(ret.toBool()); |
|
3327 } |
|
3328 } |
|
3329 |
|
3330 void tst_QScriptEngine::functionExpression() |
|
3331 { |
|
3332 // task 175679 |
|
3333 QScriptEngine eng; |
|
3334 QVERIFY(!eng.globalObject().property("bar").isValid()); |
|
3335 eng.evaluate("function foo(arg) {\n" |
|
3336 " if (arg == 'bar')\n" |
|
3337 " function bar() { return 'bar'; }\n" |
|
3338 " else\n" |
|
3339 " function baz() { return 'baz'; }\n" |
|
3340 " return (arg == 'bar') ? bar : baz;\n" |
|
3341 "}"); |
|
3342 QVERIFY(!eng.globalObject().property("bar").isValid()); |
|
3343 QVERIFY(!eng.globalObject().property("baz").isValid()); |
|
3344 QVERIFY(eng.evaluate("foo").isFunction()); |
|
3345 { |
|
3346 QScriptValue ret = eng.evaluate("foo('bar')"); |
|
3347 QVERIFY(ret.isFunction()); |
|
3348 QScriptValue ret2 = ret.call(QScriptValue()); |
|
3349 QCOMPARE(ret2.toString(), QString::fromLatin1("bar")); |
|
3350 QVERIFY(!eng.globalObject().property("bar").isValid()); |
|
3351 QVERIFY(!eng.globalObject().property("baz").isValid()); |
|
3352 } |
|
3353 { |
|
3354 QScriptValue ret = eng.evaluate("foo('baz')"); |
|
3355 QVERIFY(ret.isFunction()); |
|
3356 QScriptValue ret2 = ret.call(QScriptValue()); |
|
3357 QCOMPARE(ret2.toString(), QString::fromLatin1("baz")); |
|
3358 QVERIFY(!eng.globalObject().property("bar").isValid()); |
|
3359 QVERIFY(!eng.globalObject().property("baz").isValid()); |
|
3360 } |
|
3361 } |
|
3362 |
|
3363 void tst_QScriptEngine::stringObjects() |
|
3364 { |
|
3365 QScriptEngine eng; |
|
3366 QString str("ciao"); |
|
3367 // in C++ |
|
3368 { |
|
3369 QScriptValue obj = QScriptValue(&eng, str).toObject(); |
|
3370 QCOMPARE(obj.property("length").toInt32(), str.length()); |
|
3371 QCOMPARE(obj.propertyFlags("length"), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::SkipInEnumeration | QScriptValue::ReadOnly)); |
|
3372 for (int i = 0; i < str.length(); ++i) { |
|
3373 QString pname = QString::number(i); |
|
3374 QVERIFY(obj.property(pname).isString()); |
|
3375 QCOMPARE(obj.property(pname).toString(), QString(str.at(i))); |
|
3376 QCOMPARE(obj.propertyFlags(pname), QScriptValue::PropertyFlags(QScriptValue::Undeletable | QScriptValue::ReadOnly)); |
|
3377 obj.setProperty(pname, QScriptValue()); |
|
3378 obj.setProperty(pname, QScriptValue(&eng, 123)); |
|
3379 QVERIFY(obj.property(pname).isString()); |
|
3380 QCOMPARE(obj.property(pname).toString(), QString(str.at(i))); |
|
3381 } |
|
3382 QVERIFY(!obj.property("-1").isValid()); |
|
3383 QVERIFY(!obj.property(QString::number(str.length())).isValid()); |
|
3384 |
|
3385 QScriptValue val(&eng, 123); |
|
3386 obj.setProperty("-1", val); |
|
3387 QVERIFY(obj.property("-1").strictlyEquals(val)); |
|
3388 obj.setProperty("100", val); |
|
3389 QVERIFY(obj.property("100").strictlyEquals(val)); |
|
3390 } |
|
3391 |
|
3392 // in script |
|
3393 { |
|
3394 QScriptValue ret = eng.evaluate("s = new String('ciao'); r = []; for (var p in s) r.push(p); r"); |
|
3395 QVERIFY(ret.isArray()); |
|
3396 QStringList lst = qscriptvalue_cast<QStringList>(ret); |
|
3397 QCOMPARE(lst.size(), str.length()); |
|
3398 for (int i = 0; i < str.length(); ++i) |
|
3399 QCOMPARE(lst.at(i), QString::number(i)); |
|
3400 |
|
3401 QScriptValue ret2 = eng.evaluate("s[0] = 123; s[0]"); |
|
3402 QVERIFY(ret2.isString()); |
|
3403 QCOMPARE(ret2.toString().length(), 1); |
|
3404 QCOMPARE(ret2.toString().at(0), str.at(0)); |
|
3405 |
|
3406 QScriptValue ret3 = eng.evaluate("s[-1] = 123; s[-1]"); |
|
3407 QVERIFY(ret3.isNumber()); |
|
3408 QCOMPARE(ret3.toInt32(), 123); |
|
3409 |
|
3410 QScriptValue ret4 = eng.evaluate("s[s.length] = 456; s[s.length]"); |
|
3411 QVERIFY(ret4.isNumber()); |
|
3412 QCOMPARE(ret4.toInt32(), 456); |
|
3413 |
|
3414 QScriptValue ret5 = eng.evaluate("delete s[0]"); |
|
3415 QVERIFY(ret5.isBoolean()); |
|
3416 QVERIFY(!ret5.toBoolean()); |
|
3417 |
|
3418 QScriptValue ret6 = eng.evaluate("delete s[-1]"); |
|
3419 QVERIFY(ret6.isBoolean()); |
|
3420 QVERIFY(ret6.toBoolean()); |
|
3421 |
|
3422 QScriptValue ret7 = eng.evaluate("delete s[s.length]"); |
|
3423 QVERIFY(ret7.isBoolean()); |
|
3424 QVERIFY(ret7.toBoolean()); |
|
3425 } |
|
3426 |
|
3427 // task 212440 |
|
3428 { |
|
3429 QScriptValue ret = eng.evaluate("replace_args = []; \"a a a\".replace(/(a)/g, function() { replace_args.push(arguments); }); replace_args"); |
|
3430 QVERIFY(ret.isArray()); |
|
3431 int len = ret.property("length").toInt32(); |
|
3432 QCOMPARE(len, 3); |
|
3433 for (int i = 0; i < len; ++i) { |
|
3434 QScriptValue args = ret.property(i); |
|
3435 QCOMPARE(args.property("length").toInt32(), 4); |
|
3436 QCOMPARE(args.property(0).toString(), QString::fromLatin1("a")); // matched string |
|
3437 QCOMPARE(args.property(1).toString(), QString::fromLatin1("a")); // capture |
|
3438 QVERIFY(args.property(2).isNumber()); |
|
3439 QCOMPARE(args.property(2).toInt32(), i*2); // index of match |
|
3440 QCOMPARE(args.property(3).toString(), QString::fromLatin1("a a a")); |
|
3441 } |
|
3442 } |
|
3443 // task 212501 |
|
3444 { |
|
3445 QScriptValue ret = eng.evaluate("\"foo\".replace(/a/g, function() {})"); |
|
3446 QVERIFY(ret.isString()); |
|
3447 QCOMPARE(ret.toString(), QString::fromLatin1("foo")); |
|
3448 } |
|
3449 } |
|
3450 |
|
3451 void tst_QScriptEngine::getterSetterThisObject() |
|
3452 { |
|
3453 // Global Object |
|
3454 { |
|
3455 QScriptEngine eng; |
|
3456 // read |
|
3457 eng.evaluate("__defineGetter__('x', function() { return this; });"); |
|
3458 { |
|
3459 QScriptValue ret = eng.evaluate("x"); |
|
3460 QVERIFY(ret.equals(eng.globalObject())); |
|
3461 } |
|
3462 { |
|
3463 QScriptValue ret = eng.evaluate("(function() { return x; })()"); |
|
3464 QVERIFY(ret.equals(eng.globalObject())); |
|
3465 } |
|
3466 { |
|
3467 QScriptValue ret = eng.evaluate("with (this) x"); |
|
3468 QVERIFY(ret.equals(eng.globalObject())); |
|
3469 } |
|
3470 { |
|
3471 QScriptValue ret = eng.evaluate("with ({}) x"); |
|
3472 QVERIFY(ret.equals(eng.globalObject())); |
|
3473 } |
|
3474 { |
|
3475 QScriptValue ret = eng.evaluate("(function() { with ({}) return x; })()"); |
|
3476 QVERIFY(ret.equals(eng.globalObject())); |
|
3477 } |
|
3478 // write |
|
3479 eng.evaluate("__defineSetter__('x', function() { return this; });"); |
|
3480 { |
|
3481 QScriptValue ret = eng.evaluate("x = 'foo'"); |
|
3482 // SpiderMonkey says setter return value, JSC says RHS. |
|
3483 QVERIFY(ret.isString()); |
|
3484 QCOMPARE(ret.toString(), QString::fromLatin1("foo")); |
|
3485 } |
|
3486 { |
|
3487 QScriptValue ret = eng.evaluate("(function() { return x = 'foo'; })()"); |
|
3488 // SpiderMonkey says setter return value, JSC says RHS. |
|
3489 QVERIFY(ret.isString()); |
|
3490 QCOMPARE(ret.toString(), QString::fromLatin1("foo")); |
|
3491 } |
|
3492 { |
|
3493 QScriptValue ret = eng.evaluate("with (this) x = 'foo'"); |
|
3494 // SpiderMonkey says setter return value, JSC says RHS. |
|
3495 QVERIFY(ret.isString()); |
|
3496 QCOMPARE(ret.toString(), QString::fromLatin1("foo")); |
|
3497 } |
|
3498 { |
|
3499 QScriptValue ret = eng.evaluate("with ({}) x = 'foo'"); |
|
3500 // SpiderMonkey says setter return value, JSC says RHS. |
|
3501 QVERIFY(ret.isString()); |
|
3502 QCOMPARE(ret.toString(), QString::fromLatin1("foo")); |
|
3503 } |
|
3504 { |
|
3505 QScriptValue ret = eng.evaluate("(function() { with ({}) return x = 'foo'; })()"); |
|
3506 // SpiderMonkey says setter return value, JSC says RHS. |
|
3507 QVERIFY(ret.isString()); |
|
3508 QCOMPARE(ret.toString(), QString::fromLatin1("foo")); |
|
3509 } |
|
3510 } |
|
3511 |
|
3512 // other object |
|
3513 { |
|
3514 QScriptEngine eng; |
|
3515 eng.evaluate("o = {}"); |
|
3516 // read |
|
3517 eng.evaluate("o.__defineGetter__('x', function() { return this; })"); |
|
3518 QVERIFY(eng.evaluate("o.x === o").toBoolean()); |
|
3519 QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o"))); |
|
3520 QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean()); |
|
3521 eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o")); |
|
3522 // write |
|
3523 eng.evaluate("o.__defineSetter__('x', function() { return this; });"); |
|
3524 // SpiderMonkey says setter return value, JSC says RHS. |
|
3525 QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean()); |
|
3526 QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo")); |
|
3527 QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo")); |
|
3528 } |
|
3529 |
|
3530 // getter+setter in prototype chain |
|
3531 { |
|
3532 QScriptEngine eng; |
|
3533 eng.evaluate("o = {}; p = {}; o.__proto__ = p"); |
|
3534 // read |
|
3535 eng.evaluate("p.__defineGetter__('x', function() { return this; })"); |
|
3536 QVERIFY(eng.evaluate("o.x === o").toBoolean()); |
|
3537 QVERIFY(eng.evaluate("with (o) x").equals(eng.evaluate("o"))); |
|
3538 QVERIFY(eng.evaluate("(function() { with (o) return x; })() === o").toBoolean()); |
|
3539 eng.evaluate("q = {}; with (o) with (q) x").equals(eng.evaluate("o")); |
|
3540 eng.evaluate("with (q) with (o) x").equals(eng.evaluate("o")); |
|
3541 // write |
|
3542 eng.evaluate("o.__defineSetter__('x', function() { return this; });"); |
|
3543 // SpiderMonkey says setter return value, JSC says RHS. |
|
3544 QVERIFY(eng.evaluate("(o.x = 'foo') === 'foo'").toBoolean()); |
|
3545 QVERIFY(eng.evaluate("with (o) x = 'foo'").equals("foo")); |
|
3546 QVERIFY(eng.evaluate("with (o) with (q) x = 'foo'").equals("foo")); |
|
3547 } |
|
3548 |
|
3549 // getter+setter in activation |
|
3550 { |
|
3551 QScriptEngine eng; |
|
3552 QScriptContext *ctx = eng.pushContext(); |
|
3553 QVERIFY(ctx != 0); |
|
3554 QScriptValue act = ctx->activationObject(); |
|
3555 act.setProperty("act", act); |
|
3556 // read |
|
3557 eng.evaluate("act.__defineGetter__('x', function() { return this; })"); |
|
3558 QVERIFY(eng.evaluate("x === act").toBoolean()); |
|
3559 QEXPECT_FAIL("", "Exotic overload (don't care for now)", Continue); |
|
3560 QVERIFY(eng.evaluate("with (act) x").equals("foo")); |
|
3561 QVERIFY(eng.evaluate("(function() { with (act) return x; })() === act").toBoolean()); |
|
3562 eng.evaluate("q = {}; with (act) with (q) x").equals(eng.evaluate("act")); |
|
3563 eng.evaluate("with (q) with (act) x").equals(eng.evaluate("act")); |
|
3564 // write |
|
3565 eng.evaluate("act.__defineSetter__('x', function() { return this; });"); |
|
3566 QVERIFY(eng.evaluate("(x = 'foo') === 'foo'").toBoolean()); |
|
3567 QVERIFY(eng.evaluate("with (act) x = 'foo'").equals("foo")); |
|
3568 QVERIFY(eng.evaluate("with (act) with (q) x = 'foo'").equals("foo")); |
|
3569 eng.popContext(); |
|
3570 } |
|
3571 } |
|
3572 |
|
3573 void tst_QScriptEngine::continueInSwitch() |
|
3574 { |
|
3575 QScriptEngine eng; |
|
3576 // switch - continue |
|
3577 { |
|
3578 QScriptValue ret = eng.evaluate("switch (1) { default: continue; }"); |
|
3579 QVERIFY(ret.isError()); |
|
3580 } |
|
3581 // for - switch - case - continue |
|
3582 { |
|
3583 QScriptValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n" |
|
3584 " switch (i) {\n" |
|
3585 " case 1: ++j; continue;\n" |
|
3586 " case 100: ++j; continue;\n" |
|
3587 " case 1000: ++j; continue;\n" |
|
3588 " }\n" |
|
3589 "}; j"); |
|
3590 QVERIFY(ret.isNumber()); |
|
3591 QCOMPARE(ret.toInt32(), 3); |
|
3592 } |
|
3593 // for - switch - case - default - continue |
|
3594 { |
|
3595 QScriptValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n" |
|
3596 " switch (i) {\n" |
|
3597 " case 1: ++j; continue;\n" |
|
3598 " case 100: ++j; continue;\n" |
|
3599 " case 1000: ++j; continue;\n" |
|
3600 " default: if (i < 50000) break; else continue;\n" |
|
3601 " }\n" |
|
3602 "}; j"); |
|
3603 QVERIFY(ret.isNumber()); |
|
3604 QCOMPARE(ret.toInt32(), 3); |
|
3605 } |
|
3606 // switch - for - continue |
|
3607 { |
|
3608 QScriptValue ret = eng.evaluate("j = 123; switch (j) {\n" |
|
3609 " case 123:\n" |
|
3610 " for (i = 0; i < 100000; ++i) {\n" |
|
3611 " continue;\n" |
|
3612 " }\n" |
|
3613 "}; i\n"); |
|
3614 QVERIFY(ret.isNumber()); |
|
3615 QCOMPARE(ret.toInt32(), 100000); |
|
3616 } |
|
3617 // switch - switch - continue |
|
3618 { |
|
3619 QScriptValue ret = eng.evaluate("i = 1; switch (i) { default: switch (i) { case 1: continue; } }"); |
|
3620 QVERIFY(ret.isError()); |
|
3621 } |
|
3622 // for - switch - switch - continue |
|
3623 { |
|
3624 QScriptValue ret = eng.evaluate("j = 0; for (i = 0; i < 100000; ++i) {\n" |
|
3625 " switch (i) {\n" |
|
3626 " case 1:\n" |
|
3627 " switch (i) {\n" |
|
3628 " case 1: ++j; continue;\n" |
|
3629 " }\n" |
|
3630 " }\n" |
|
3631 "}; j"); |
|
3632 QVERIFY(ret.isNumber()); |
|
3633 QCOMPARE(ret.toInt32(), 1); |
|
3634 } |
|
3635 // switch - for - switch - continue |
|
3636 { |
|
3637 QScriptValue ret = eng.evaluate("j = 123; switch (j) {\n" |
|
3638 " case 123:\n" |
|
3639 " for (i = 0; i < 100000; ++i) {\n" |
|
3640 " switch (i) {\n" |
|
3641 " case 1:\n" |
|
3642 " ++j; continue;\n" |
|
3643 " }\n" |
|
3644 " }\n" |
|
3645 "}; i\n"); |
|
3646 QVERIFY(ret.isNumber()); |
|
3647 QCOMPARE(ret.toInt32(), 100000); |
|
3648 } |
|
3649 } |
|
3650 |
|
3651 void tst_QScriptEngine::readOnlyPrototypeProperty() |
|
3652 { |
|
3653 QSKIP("JSC semantics differ from old back-end and SpiderMonkey", SkipAll); |
|
3654 QScriptEngine eng; |
|
3655 QCOMPARE(eng.evaluate("o = {}; o.__proto__ = parseInt; o.length").toInt32(), 2); |
|
3656 QCOMPARE(eng.evaluate("o.length = 4; o.length").toInt32(), 2); |
|
3657 QVERIFY(!eng.evaluate("o.hasOwnProperty('length')").toBoolean()); |
|
3658 QCOMPARE(eng.evaluate("o.length *= 2; o.length").toInt32(), 2); |
|
3659 QCOMPARE(eng.evaluate("o.length /= 2; o.length").toInt32(), 2); |
|
3660 QCOMPARE(eng.evaluate("o.length %= 2; o.length").toInt32(), 2); |
|
3661 QCOMPARE(eng.evaluate("o.length += 2; o.length").toInt32(), 2); |
|
3662 QCOMPARE(eng.evaluate("o.length -= 2; o.length").toInt32(), 2); |
|
3663 QCOMPARE(eng.evaluate("o.length <<= 2; o.length").toInt32(), 2); |
|
3664 QCOMPARE(eng.evaluate("o.length >>= 2; o.length").toInt32(), 2); |
|
3665 QCOMPARE(eng.evaluate("o.length >>>= 2; o.length").toInt32(), 2); |
|
3666 QCOMPARE(eng.evaluate("o.length &= 0; o.length").toInt32(), 2); |
|
3667 QCOMPARE(eng.evaluate("o.length ^= 255; o.length").toInt32(), 2); |
|
3668 QCOMPARE(eng.evaluate("o.length |= 255; o.length").toInt32(), 2); |
|
3669 |
|
3670 { |
|
3671 QScriptValue ret = eng.evaluate("o.__defineGetter__('length', function() {})"); |
|
3672 QVERIFY(ret.isError()); |
|
3673 QCOMPARE(ret.toString(), QString::fromLatin1("Error: cannot redefine read-only property")); |
|
3674 } |
|
3675 { |
|
3676 QScriptValue ret = eng.evaluate("o.__defineSetter__('length', function() {})"); |
|
3677 QVERIFY(ret.isError()); |
|
3678 QCOMPARE(ret.toString(), QString::fromLatin1("Error: cannot redefine read-only property")); |
|
3679 } |
|
3680 } |
|
3681 |
|
3682 void tst_QScriptEngine::toObject() |
|
3683 { |
|
3684 QScriptEngine eng; |
|
3685 |
|
3686 QVERIFY(!eng.toObject(eng.undefinedValue()).isValid()); |
|
3687 |
|
3688 QVERIFY(!eng.toObject(eng.nullValue()).isValid()); |
|
3689 |
|
3690 QScriptValue falskt(false); |
|
3691 { |
|
3692 QScriptValue tmp = eng.toObject(falskt); |
|
3693 QVERIFY(tmp.isObject()); |
|
3694 QCOMPARE(tmp.toNumber(), falskt.toNumber()); |
|
3695 } |
|
3696 |
|
3697 QScriptValue sant(true); |
|
3698 { |
|
3699 QScriptValue tmp = eng.toObject(sant); |
|
3700 QVERIFY(tmp.isObject()); |
|
3701 QCOMPARE(tmp.toNumber(), sant.toNumber()); |
|
3702 } |
|
3703 |
|
3704 QScriptValue number(123.0); |
|
3705 { |
|
3706 QScriptValue tmp = eng.toObject(number); |
|
3707 QVERIFY(tmp.isObject()); |
|
3708 QCOMPARE(tmp.toNumber(), number.toNumber()); |
|
3709 } |
|
3710 |
|
3711 QScriptValue str = QScriptValue(&eng, QString("ciao")); |
|
3712 { |
|
3713 QScriptValue tmp = eng.toObject(str); |
|
3714 QVERIFY(tmp.isObject()); |
|
3715 QCOMPARE(tmp.toString(), str.toString()); |
|
3716 } |
|
3717 |
|
3718 QScriptValue object = eng.newObject(); |
|
3719 { |
|
3720 QScriptValue tmp = eng.toObject(object); |
|
3721 QVERIFY(tmp.isObject()); |
|
3722 QVERIFY(tmp.strictlyEquals(object)); |
|
3723 } |
|
3724 |
|
3725 QScriptValue qobject = eng.newQObject(this); |
|
3726 QVERIFY(eng.toObject(qobject).strictlyEquals(qobject)); |
|
3727 |
|
3728 QVERIFY(!eng.toObject(QScriptValue()).isValid()); |
|
3729 } |
|
3730 |
|
3731 void tst_QScriptEngine::reservedWords_data() |
|
3732 { |
|
3733 QTest::addColumn<QString>("word"); |
|
3734 QTest::newRow("break") << QString("break"); |
|
3735 QTest::newRow("case") << QString("case"); |
|
3736 QTest::newRow("catch") << QString("catch"); |
|
3737 QTest::newRow("continue") << QString("continue"); |
|
3738 QTest::newRow("default") << QString("default"); |
|
3739 QTest::newRow("delete") << QString("delete"); |
|
3740 QTest::newRow("do") << QString("do"); |
|
3741 QTest::newRow("else") << QString("else"); |
|
3742 QTest::newRow("false") << QString("false"); |
|
3743 QTest::newRow("finally") << QString("finally"); |
|
3744 QTest::newRow("for") << QString("for"); |
|
3745 QTest::newRow("function") << QString("function"); |
|
3746 QTest::newRow("if") << QString("if"); |
|
3747 QTest::newRow("in") << QString("in"); |
|
3748 QTest::newRow("instanceof") << QString("instanceof"); |
|
3749 QTest::newRow("new") << QString("new"); |
|
3750 QTest::newRow("null") << QString("null"); |
|
3751 QTest::newRow("return") << QString("return"); |
|
3752 QTest::newRow("switch") << QString("switch"); |
|
3753 QTest::newRow("this") << QString("this"); |
|
3754 QTest::newRow("throw") << QString("throw"); |
|
3755 QTest::newRow("true") << QString("true"); |
|
3756 QTest::newRow("try") << QString("try"); |
|
3757 QTest::newRow("typeof") << QString("typeof"); |
|
3758 QTest::newRow("var") << QString("var"); |
|
3759 QTest::newRow("void") << QString("void"); |
|
3760 QTest::newRow("while") << QString("while"); |
|
3761 QTest::newRow("with") << QString("with"); |
|
3762 } |
|
3763 |
|
3764 void tst_QScriptEngine::reservedWords() |
|
3765 { |
|
3766 QFETCH(QString, word); |
|
3767 { |
|
3768 QScriptEngine eng; |
|
3769 QScriptValue ret = eng.evaluate(word + " = 123"); |
|
3770 QVERIFY(ret.isError()); |
|
3771 QString str = ret.toString(); |
|
3772 QVERIFY(str.startsWith("SyntaxError") || str.startsWith("ReferenceError")); |
|
3773 } |
|
3774 { |
|
3775 QScriptEngine eng; |
|
3776 QScriptValue ret = eng.evaluate("var " + word + " = 123"); |
|
3777 QVERIFY(ret.isError()); |
|
3778 QVERIFY(ret.toString().startsWith("SyntaxError")); |
|
3779 } |
|
3780 { |
|
3781 QScriptEngine eng; |
|
3782 QScriptValue ret = eng.evaluate("o = {}; o." + word + " = 123"); |
|
3783 // in the old back-end and in SpiderMonkey this is allowed, but not in JSC |
|
3784 QVERIFY(ret.isError()); |
|
3785 QVERIFY(ret.toString().startsWith("SyntaxError")); |
|
3786 } |
|
3787 { |
|
3788 QScriptEngine eng; |
|
3789 QScriptValue ret = eng.evaluate("o = { " + word + ": 123 }"); |
|
3790 // in the old back-end and in SpiderMonkey this is allowed, but not in JSC |
|
3791 QVERIFY(ret.isError()); |
|
3792 QVERIFY(ret.toString().startsWith("SyntaxError")); |
|
3793 } |
|
3794 { |
|
3795 // SpiderMonkey allows this, but we don't |
|
3796 QScriptEngine eng; |
|
3797 QScriptValue ret = eng.evaluate("function " + word + "() {}"); |
|
3798 QVERIFY(ret.isError()); |
|
3799 QVERIFY(ret.toString().startsWith("SyntaxError")); |
|
3800 } |
|
3801 } |
|
3802 |
|
3803 void tst_QScriptEngine::futureReservedWords_data() |
|
3804 { |
|
3805 QTest::addColumn<QString>("word"); |
|
3806 QTest::addColumn<bool>("allowed"); |
|
3807 QTest::newRow("abstract") << QString("abstract") << true; |
|
3808 QTest::newRow("boolean") << QString("boolean") << true; |
|
3809 QTest::newRow("byte") << QString("byte") << true; |
|
3810 QTest::newRow("char") << QString("char") << true; |
|
3811 QTest::newRow("class") << QString("class") << false; |
|
3812 QTest::newRow("const") << QString("const") << false; |
|
3813 QTest::newRow("debugger") << QString("debugger") << false; |
|
3814 QTest::newRow("double") << QString("double") << true; |
|
3815 QTest::newRow("enum") << QString("enum") << false; |
|
3816 QTest::newRow("export") << QString("export") << false; |
|
3817 QTest::newRow("extends") << QString("extends") << false; |
|
3818 QTest::newRow("final") << QString("final") << true; |
|
3819 QTest::newRow("float") << QString("float") << true; |
|
3820 QTest::newRow("goto") << QString("goto") << true; |
|
3821 QTest::newRow("implements") << QString("implements") << true; |
|
3822 QTest::newRow("import") << QString("import") << false; |
|
3823 QTest::newRow("int") << QString("int") << true; |
|
3824 QTest::newRow("interface") << QString("interface") << true; |
|
3825 QTest::newRow("long") << QString("long") << true; |
|
3826 QTest::newRow("native") << QString("native") << true; |
|
3827 QTest::newRow("package") << QString("package") << true; |
|
3828 QTest::newRow("private") << QString("private") << true; |
|
3829 QTest::newRow("protected") << QString("protected") << true; |
|
3830 QTest::newRow("public") << QString("public") << true; |
|
3831 QTest::newRow("short") << QString("short") << true; |
|
3832 QTest::newRow("static") << QString("static") << true; |
|
3833 QTest::newRow("super") << QString("super") << false; |
|
3834 QTest::newRow("synchronized") << QString("synchronized") << true; |
|
3835 QTest::newRow("throws") << QString("throws") << true; |
|
3836 QTest::newRow("transient") << QString("transient") << true; |
|
3837 QTest::newRow("volatile") << QString("volatile") << true; |
|
3838 } |
|
3839 |
|
3840 void tst_QScriptEngine::futureReservedWords() |
|
3841 { |
|
3842 QFETCH(QString, word); |
|
3843 QFETCH(bool, allowed); |
|
3844 { |
|
3845 QScriptEngine eng; |
|
3846 QScriptValue ret = eng.evaluate(word + " = 123"); |
|
3847 QCOMPARE(!ret.isError(), allowed); |
|
3848 } |
|
3849 { |
|
3850 QScriptEngine eng; |
|
3851 QScriptValue ret = eng.evaluate("var " + word + " = 123"); |
|
3852 QCOMPARE(!ret.isError(), allowed); |
|
3853 } |
|
3854 { |
|
3855 // this should probably be allowed (see task 162567) |
|
3856 QScriptEngine eng; |
|
3857 QScriptValue ret = eng.evaluate("o = {}; o." + word + " = 123"); |
|
3858 QCOMPARE(ret.isNumber(), allowed); |
|
3859 QCOMPARE(!ret.isError(), allowed); |
|
3860 } |
|
3861 { |
|
3862 // this should probably be allowed (see task 162567) |
|
3863 QScriptEngine eng; |
|
3864 QScriptValue ret = eng.evaluate("o = { " + word + ": 123 }"); |
|
3865 QCOMPARE(!ret.isError(), allowed); |
|
3866 } |
|
3867 } |
|
3868 |
|
3869 void tst_QScriptEngine::throwInsideWithStatement() |
|
3870 { |
|
3871 // task 209988 |
|
3872 QScriptEngine eng; |
|
3873 { |
|
3874 QScriptValue ret = eng.evaluate( |
|
3875 "try {" |
|
3876 " o = { bad : \"bug\" };" |
|
3877 " with (o) {" |
|
3878 " throw 123;" |
|
3879 " }" |
|
3880 "} catch (e) {" |
|
3881 " bad;" |
|
3882 "}"); |
|
3883 QVERIFY(ret.isError()); |
|
3884 QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bad")); |
|
3885 } |
|
3886 { |
|
3887 QScriptValue ret = eng.evaluate( |
|
3888 "try {" |
|
3889 " o = { bad : \"bug\" };" |
|
3890 " with (o) {" |
|
3891 " throw 123;" |
|
3892 " }" |
|
3893 "} finally {" |
|
3894 " bad;" |
|
3895 "}"); |
|
3896 QVERIFY(ret.isError()); |
|
3897 QCOMPARE(ret.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bad")); |
|
3898 } |
|
3899 { |
|
3900 eng.clearExceptions(); |
|
3901 QScriptValue ret = eng.evaluate( |
|
3902 "o = { bug : \"no bug\" };" |
|
3903 "with (o) {" |
|
3904 " try {" |
|
3905 " throw 123;" |
|
3906 " } finally {" |
|
3907 " bug;" |
|
3908 " }" |
|
3909 "}"); |
|
3910 QVERIFY(ret.isNumber()); |
|
3911 QCOMPARE(ret.toInt32(), 123); |
|
3912 QVERIFY(eng.hasUncaughtException()); |
|
3913 } |
|
3914 { |
|
3915 eng.clearExceptions(); |
|
3916 QScriptValue ret = eng.evaluate( |
|
3917 "o = { bug : \"no bug\" };" |
|
3918 "with (o) {" |
|
3919 " throw 123;" |
|
3920 "}"); |
|
3921 QVERIFY(ret.isNumber()); |
|
3922 QScriptValue ret2 = eng.evaluate("bug"); |
|
3923 QVERIFY(ret2.isError()); |
|
3924 QCOMPARE(ret2.toString(), QString::fromLatin1("ReferenceError: Can't find variable: bug")); |
|
3925 } |
|
3926 } |
|
3927 |
|
3928 class TestAgent : public QScriptEngineAgent |
|
3929 { |
|
3930 public: |
|
3931 TestAgent(QScriptEngine *engine) : QScriptEngineAgent(engine) {} |
|
3932 }; |
|
3933 |
|
3934 void tst_QScriptEngine::getSetAgent() |
|
3935 { |
|
3936 // case 1: engine deleted before agent --> agent deleted too |
|
3937 { |
|
3938 QScriptEngine *eng = new QScriptEngine; |
|
3939 QCOMPARE(eng->agent(), (QScriptEngineAgent*)0); |
|
3940 TestAgent *agent = new TestAgent(eng); |
|
3941 eng->setAgent(agent); |
|
3942 QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent); |
|
3943 eng->setAgent(0); // the engine maintains ownership of the old agent |
|
3944 QCOMPARE(eng->agent(), (QScriptEngineAgent*)0); |
|
3945 delete eng; |
|
3946 } |
|
3947 // case 2: agent deleted before engine --> engine's agent should become 0 |
|
3948 { |
|
3949 QScriptEngine *eng = new QScriptEngine; |
|
3950 TestAgent *agent = new TestAgent(eng); |
|
3951 eng->setAgent(agent); |
|
3952 QCOMPARE(eng->agent(), (QScriptEngineAgent*)agent); |
|
3953 delete agent; |
|
3954 QCOMPARE(eng->agent(), (QScriptEngineAgent*)0); |
|
3955 eng->evaluate("(function(){ return 123; })()"); |
|
3956 delete eng; |
|
3957 } |
|
3958 { |
|
3959 QScriptEngine eng; |
|
3960 QScriptEngine eng2; |
|
3961 TestAgent *agent = new TestAgent(&eng); |
|
3962 QTest::ignoreMessage(QtWarningMsg, "QScriptEngine::setAgent(): cannot set agent belonging to different engine"); |
|
3963 eng2.setAgent(agent); |
|
3964 QCOMPARE(eng2.agent(), (QScriptEngineAgent*)0); |
|
3965 } |
|
3966 } |
|
3967 |
|
3968 void tst_QScriptEngine::reentrancy() |
|
3969 { |
|
3970 { |
|
3971 QScriptEngine eng1; |
|
3972 QScriptEngine eng2; |
|
3973 QScriptString s1 = eng1.toStringHandle("foo"); |
|
3974 QScriptString s2 = eng2.toStringHandle("foo"); |
|
3975 QVERIFY(s1 != s2); |
|
3976 } |
|
3977 { |
|
3978 QScriptEngine eng1; |
|
3979 QScriptEngine eng2; |
|
3980 eng1.setProcessEventsInterval(123); |
|
3981 QCOMPARE(eng2.processEventsInterval(), -1); |
|
3982 eng2.setProcessEventsInterval(456); |
|
3983 QCOMPARE(eng1.processEventsInterval(), 123); |
|
3984 } |
|
3985 { |
|
3986 QScriptEngine eng1; |
|
3987 QScriptEngine eng2; |
|
3988 qScriptRegisterMetaType<Foo>(&eng1, fooToScriptValue, fooFromScriptValue); |
|
3989 Foo foo; |
|
3990 foo.x = 12; |
|
3991 foo.y = 34; |
|
3992 { |
|
3993 QScriptValue fooVal = qScriptValueFromValue(&eng1, foo); |
|
3994 QVERIFY(fooVal.isObject()); |
|
3995 QVERIFY(!fooVal.isVariant()); |
|
3996 QCOMPARE(fooVal.property("x").toInt32(), 12); |
|
3997 QCOMPARE(fooVal.property("y").toInt32(), 34); |
|
3998 fooVal.setProperty("x", 56); |
|
3999 fooVal.setProperty("y", 78); |
|
4000 |
|
4001 Foo foo2 = qScriptValueToValue<Foo>(fooVal); |
|
4002 QCOMPARE(foo2.x, 56); |
|
4003 QCOMPARE(foo2.y, 78); |
|
4004 } |
|
4005 { |
|
4006 QScriptValue fooVal = qScriptValueFromValue(&eng2, foo); |
|
4007 QVERIFY(fooVal.isVariant()); |
|
4008 |
|
4009 Foo foo2 = qScriptValueToValue<Foo>(fooVal); |
|
4010 QCOMPARE(foo2.x, 12); |
|
4011 QCOMPARE(foo2.y, 34); |
|
4012 } |
|
4013 QVERIFY(!eng1.defaultPrototype(qMetaTypeId<Foo>()).isValid()); |
|
4014 QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid()); |
|
4015 QScriptValue proto1 = eng1.newObject(); |
|
4016 eng1.setDefaultPrototype(qMetaTypeId<Foo>(), proto1); |
|
4017 QVERIFY(!eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid()); |
|
4018 QScriptValue proto2 = eng2.newObject(); |
|
4019 eng2.setDefaultPrototype(qMetaTypeId<Foo>(), proto2); |
|
4020 QVERIFY(eng2.defaultPrototype(qMetaTypeId<Foo>()).isValid()); |
|
4021 QVERIFY(eng1.defaultPrototype(qMetaTypeId<Foo>()).strictlyEquals(proto1)); |
|
4022 } |
|
4023 { |
|
4024 QScriptEngine eng1; |
|
4025 QScriptEngine eng2; |
|
4026 QVERIFY(!eng2.globalObject().property("a").isValid()); |
|
4027 eng1.evaluate("a = 10"); |
|
4028 QVERIFY(eng1.globalObject().property("a").isNumber()); |
|
4029 QVERIFY(!eng2.globalObject().property("a").isValid()); |
|
4030 eng2.evaluate("a = 20"); |
|
4031 QVERIFY(eng2.globalObject().property("a").isNumber()); |
|
4032 QCOMPARE(eng1.globalObject().property("a").toInt32(), 10); |
|
4033 } |
|
4034 // weird bug with JSC backend |
|
4035 { |
|
4036 QScriptEngine eng; |
|
4037 QCOMPARE(eng.evaluate("Array()").toString(), QString()); |
|
4038 eng.evaluate("Array.prototype.toString"); |
|
4039 QCOMPARE(eng.evaluate("Array()").toString(), QString()); |
|
4040 } |
|
4041 { |
|
4042 QScriptEngine eng; |
|
4043 QCOMPARE(eng.evaluate("Array()").toString(), QString()); |
|
4044 } |
|
4045 } |
|
4046 |
|
4047 void tst_QScriptEngine:: incDecNonObjectProperty() |
|
4048 { |
|
4049 QScriptEngine eng; |
|
4050 { |
|
4051 QScriptValue ret = eng.evaluate("var a; a.n++"); |
|
4052 QVERIFY(ret.isError()); |
|
4053 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [undefined] is not an object.")); |
|
4054 } |
|
4055 { |
|
4056 QScriptValue ret = eng.evaluate("var a; a.n--"); |
|
4057 QVERIFY(ret.isError()); |
|
4058 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [undefined] is not an object.")); |
|
4059 } |
|
4060 { |
|
4061 QScriptValue ret = eng.evaluate("var a = null; a.n++"); |
|
4062 QVERIFY(ret.isError()); |
|
4063 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object.")); |
|
4064 } |
|
4065 { |
|
4066 QScriptValue ret = eng.evaluate("var a = null; a.n--"); |
|
4067 QVERIFY(ret.isError()); |
|
4068 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object.")); |
|
4069 } |
|
4070 { |
|
4071 QScriptValue ret = eng.evaluate("var a; ++a.n"); |
|
4072 QVERIFY(ret.isError()); |
|
4073 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object.")); |
|
4074 } |
|
4075 { |
|
4076 QScriptValue ret = eng.evaluate("var a; --a.n"); |
|
4077 QVERIFY(ret.isError()); |
|
4078 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object.")); |
|
4079 } |
|
4080 { |
|
4081 QScriptValue ret = eng.evaluate("var a; a.n += 1"); |
|
4082 QVERIFY(ret.isError()); |
|
4083 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object.")); |
|
4084 } |
|
4085 { |
|
4086 QScriptValue ret = eng.evaluate("var a; a.n -= 1"); |
|
4087 QVERIFY(ret.isError()); |
|
4088 QCOMPARE(ret.toString(), QString::fromLatin1("TypeError: Result of expression 'a' [null] is not an object.")); |
|
4089 } |
|
4090 { |
|
4091 QScriptValue ret = eng.evaluate("var a = 'ciao'; a.length++"); |
|
4092 QVERIFY(ret.isNumber()); |
|
4093 QCOMPARE(ret.toInt32(), 4); |
|
4094 } |
|
4095 { |
|
4096 QScriptValue ret = eng.evaluate("var a = 'ciao'; a.length--"); |
|
4097 QVERIFY(ret.isNumber()); |
|
4098 QCOMPARE(ret.toInt32(), 4); |
|
4099 } |
|
4100 { |
|
4101 QScriptValue ret = eng.evaluate("var a = 'ciao'; ++a.length"); |
|
4102 QVERIFY(ret.isNumber()); |
|
4103 QCOMPARE(ret.toInt32(), 5); |
|
4104 } |
|
4105 { |
|
4106 QScriptValue ret = eng.evaluate("var a = 'ciao'; --a.length"); |
|
4107 QVERIFY(ret.isNumber()); |
|
4108 QCOMPARE(ret.toInt32(), 3); |
|
4109 } |
|
4110 } |
|
4111 |
|
4112 void tst_QScriptEngine::installTranslatorFunctions() |
|
4113 { |
|
4114 QScriptEngine eng; |
|
4115 QScriptValue global = eng.globalObject(); |
|
4116 QVERIFY(!global.property("qsTranslate").isValid()); |
|
4117 QVERIFY(!global.property("QT_TRANSLATE_NOOP").isValid()); |
|
4118 QVERIFY(!global.property("qsTr").isValid()); |
|
4119 QVERIFY(!global.property("QT_TR_NOOP").isValid()); |
|
4120 QVERIFY(!global.property("String").property("prototype").property("arg").isValid()); |
|
4121 |
|
4122 eng.installTranslatorFunctions(); |
|
4123 QVERIFY(global.property("qsTranslate").isFunction()); |
|
4124 QVERIFY(global.property("QT_TRANSLATE_NOOP").isFunction()); |
|
4125 QVERIFY(global.property("qsTr").isFunction()); |
|
4126 QVERIFY(global.property("QT_TR_NOOP").isFunction()); |
|
4127 QVERIFY(global.property("String").property("prototype").property("arg").isFunction()); |
|
4128 |
|
4129 { |
|
4130 QScriptValue ret = eng.evaluate("qsTr('foo')"); |
|
4131 QVERIFY(ret.isString()); |
|
4132 QCOMPARE(ret.toString(), QString::fromLatin1("foo")); |
|
4133 } |
|
4134 { |
|
4135 QScriptValue ret = eng.evaluate("qsTranslate('foo', 'bar')"); |
|
4136 QVERIFY(ret.isString()); |
|
4137 QCOMPARE(ret.toString(), QString::fromLatin1("bar")); |
|
4138 } |
|
4139 { |
|
4140 QScriptValue ret = eng.evaluate("QT_TR_NOOP('foo')"); |
|
4141 QVERIFY(ret.isString()); |
|
4142 QCOMPARE(ret.toString(), QString::fromLatin1("foo")); |
|
4143 } |
|
4144 { |
|
4145 QScriptValue ret = eng.evaluate("QT_TRANSLATE_NOOP('foo', 'bar')"); |
|
4146 QVERIFY(ret.isString()); |
|
4147 QCOMPARE(ret.toString(), QString::fromLatin1("bar")); |
|
4148 } |
|
4149 { |
|
4150 QScriptValue ret = eng.evaluate("'foo%0'.arg('bar')"); |
|
4151 QVERIFY(ret.isString()); |
|
4152 QCOMPARE(ret.toString(), QString::fromLatin1("foobar")); |
|
4153 } |
|
4154 } |
|
4155 |
|
4156 void tst_QScriptEngine::functionScopes() |
|
4157 { |
|
4158 QScriptEngine eng; |
|
4159 { |
|
4160 // top-level functions have only the global object in their scope |
|
4161 QScriptValue fun = eng.evaluate("(function() {})"); |
|
4162 QVERIFY(fun.isFunction()); |
|
4163 QEXPECT_FAIL("", "Function scope proxying is not implemented", Abort); |
|
4164 QVERIFY(fun.scope().isObject()); |
|
4165 QVERIFY(fun.scope().strictlyEquals(eng.globalObject())); |
|
4166 QVERIFY(!eng.globalObject().scope().isValid()); |
|
4167 } |
|
4168 { |
|
4169 QScriptValue fun = eng.globalObject().property("Object"); |
|
4170 QVERIFY(fun.isFunction()); |
|
4171 // native built-in functions don't have scope |
|
4172 QVERIFY(!fun.scope().isValid()); |
|
4173 } |
|
4174 { |
|
4175 // closure |
|
4176 QScriptValue fun = eng.evaluate("(function(arg) { var foo = arg; return function() { return foo; }; })(123)"); |
|
4177 QVERIFY(fun.isFunction()); |
|
4178 { |
|
4179 QScriptValue ret = fun.call(); |
|
4180 QVERIFY(ret.isNumber()); |
|
4181 QCOMPARE(ret.toInt32(), 123); |
|
4182 } |
|
4183 QScriptValue scope = fun.scope(); |
|
4184 QVERIFY(scope.isObject()); |
|
4185 { |
|
4186 QScriptValue ret = scope.property("foo"); |
|
4187 QVERIFY(ret.isNumber()); |
|
4188 QCOMPARE(ret.toInt32(), 123); |
|
4189 QCOMPARE(scope.propertyFlags("foo"), QScriptValue::Undeletable); |
|
4190 } |
|
4191 { |
|
4192 QScriptValue ret = scope.property("arg"); |
|
4193 QVERIFY(ret.isNumber()); |
|
4194 QCOMPARE(ret.toInt32(), 123); |
|
4195 QCOMPARE(scope.propertyFlags("arg"), QScriptValue::Undeletable | QScriptValue::SkipInEnumeration); |
|
4196 } |
|
4197 |
|
4198 scope.setProperty("foo", 456); |
|
4199 { |
|
4200 QScriptValue ret = fun.call(); |
|
4201 QVERIFY(ret.isNumber()); |
|
4202 QCOMPARE(ret.toInt32(), 456); |
|
4203 } |
|
4204 |
|
4205 scope = scope.scope(); |
|
4206 QVERIFY(scope.isObject()); |
|
4207 QVERIFY(scope.strictlyEquals(eng.globalObject())); |
|
4208 } |
|
4209 } |
|
4210 |
|
4211 static QScriptValue counter_inner(QScriptContext *ctx, QScriptEngine *) |
|
4212 { |
|
4213 QScriptValue outerAct = ctx->callee().scope(); |
|
4214 double count = outerAct.property("count").toNumber(); |
|
4215 outerAct.setProperty("count", count+1); |
|
4216 return count; |
|
4217 } |
|
4218 |
|
4219 static QScriptValue counter(QScriptContext *ctx, QScriptEngine *eng) |
|
4220 { |
|
4221 QScriptValue act = ctx->activationObject(); |
|
4222 act.setProperty("count", ctx->argument(0).toInt32()); |
|
4223 QScriptValue result = eng->newFunction(counter_inner); |
|
4224 result.setScope(act); |
|
4225 return result; |
|
4226 } |
|
4227 |
|
4228 static QScriptValue counter_hybrid(QScriptContext *ctx, QScriptEngine *eng) |
|
4229 { |
|
4230 QScriptValue act = ctx->activationObject(); |
|
4231 act.setProperty("count", ctx->argument(0).toInt32()); |
|
4232 return eng->evaluate("(function() { return count++; })"); |
|
4233 } |
|
4234 |
|
4235 void tst_QScriptEngine::nativeFunctionScopes() |
|
4236 { |
|
4237 QScriptEngine eng; |
|
4238 { |
|
4239 QScriptValue fun = eng.newFunction(counter); |
|
4240 QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123); |
|
4241 QVERIFY(cnt.isFunction()); |
|
4242 { |
|
4243 QScriptValue ret = cnt.call(); |
|
4244 QVERIFY(ret.isNumber()); |
|
4245 QCOMPARE(ret.toInt32(), 123); |
|
4246 } |
|
4247 } |
|
4248 { |
|
4249 QScriptValue fun = eng.newFunction(counter_hybrid); |
|
4250 QScriptValue cnt = fun.call(QScriptValue(), QScriptValueList() << 123); |
|
4251 QVERIFY(cnt.isFunction()); |
|
4252 { |
|
4253 QScriptValue ret = cnt.call(); |
|
4254 QVERIFY(ret.isNumber()); |
|
4255 QCOMPARE(ret.toInt32(), 123); |
|
4256 } |
|
4257 } |
|
4258 |
|
4259 //from http://doc.trolltech.com/latest/qtscript.html#nested-functions-and-the-scope-chain |
|
4260 { |
|
4261 QScriptEngine eng; |
|
4262 eng.evaluate("function counter() { var count = 0; return function() { return count++; } }\n" |
|
4263 "var c1 = counter(); var c2 = counter(); "); |
|
4264 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0")); |
|
4265 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1")); |
|
4266 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0")); |
|
4267 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1")); |
|
4268 QVERIFY(!eng.hasUncaughtException()); |
|
4269 } |
|
4270 { |
|
4271 QScriptEngine eng; |
|
4272 eng.globalObject().setProperty("counter", eng.newFunction(counter)); |
|
4273 eng.evaluate("var c1 = counter(); var c2 = counter(); "); |
|
4274 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0")); |
|
4275 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1")); |
|
4276 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0")); |
|
4277 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1")); |
|
4278 QVERIFY(!eng.hasUncaughtException()); |
|
4279 } |
|
4280 { |
|
4281 QScriptEngine eng; |
|
4282 eng.globalObject().setProperty("counter", eng.newFunction(counter_hybrid)); |
|
4283 eng.evaluate("var c1 = counter(); var c2 = counter(); "); |
|
4284 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("0")); |
|
4285 QCOMPARE(eng.evaluate("c1()").toString(), QString::fromLatin1("1")); |
|
4286 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("0")); |
|
4287 QCOMPARE(eng.evaluate("c2()").toString(), QString::fromLatin1("1")); |
|
4288 QVERIFY(!eng.hasUncaughtException()); |
|
4289 } |
|
4290 } |
|
4291 |
|
4292 static QRegExp minimal(QRegExp r) { r.setMinimal(true); return r; } |
|
4293 |
|
4294 void tst_QScriptEngine::qRegExpInport_data() |
|
4295 { |
|
4296 QTest::addColumn<QRegExp>("rx"); |
|
4297 QTest::addColumn<QString>("string"); |
|
4298 QTest::addColumn<QString>("matched"); |
|
4299 |
|
4300 QTest::newRow("normal") << QRegExp("(test|foo)") << "test _ foo _ test _ Foo"; |
|
4301 QTest::newRow("normal2") << QRegExp("(Test|Foo)") << "test _ foo _ test _ Foo"; |
|
4302 QTest::newRow("case insensitive)") << QRegExp("(test|foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo"; |
|
4303 QTest::newRow("case insensitive2)") << QRegExp("(Test|Foo)", Qt::CaseInsensitive) << "test _ foo _ test _ Foo"; |
|
4304 QTest::newRow("b(a*)(b*)") << QRegExp("b(a*)(b*)", Qt::CaseInsensitive) << "aaabbBbaAabaAaababaaabbaaab"; |
|
4305 QTest::newRow("greedy") << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp2) << "aaaabaaba"; |
|
4306 // this one will fail because we do not support the QRegExp::RegExp in JSC |
|
4307 //QTest::newRow("not_greedy") << QRegExp("a*(a*)", Qt::CaseInsensitive, QRegExp::RegExp) << "aaaabaaba"; |
|
4308 QTest::newRow("willcard") << QRegExp("*.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "file.txt"; |
|
4309 QTest::newRow("willcard 2") << QRegExp("a?b.txt", Qt::CaseSensitive, QRegExp::Wildcard) << "ab.txt abb.rtc acb.txt"; |
|
4310 QTest::newRow("slash") << QRegExp("g/.*/s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string/string/string"; |
|
4311 QTest::newRow("slash2") << QRegExp("g / .* / s", Qt::CaseInsensitive, QRegExp::RegExp2) << "string / string / string"; |
|
4312 QTest::newRow("fixed") << QRegExp("a*aa.a(ba)*a\\ba", Qt::CaseInsensitive, QRegExp::FixedString) << "aa*aa.a(ba)*a\\ba"; |
|
4313 QTest::newRow("fixed insensitive") << QRegExp("A*A", Qt::CaseInsensitive, QRegExp::FixedString) << "a*A A*a A*A a*a"; |
|
4314 QTest::newRow("fixed sensitive") << QRegExp("A*A", Qt::CaseSensitive, QRegExp::FixedString) << "a*A A*a A*A a*a"; |
|
4315 QTest::newRow("html") << QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2) << "<b>bold</b><i>italic</i><b>bold</b>"; |
|
4316 QTest::newRow("html minimal") << minimal(QRegExp("<b>(.*)</b>", Qt::CaseSensitive, QRegExp::RegExp2)) << "<b>bold</b><i>italic</i><b>bold</b>"; |
|
4317 QTest::newRow("aaa") << QRegExp("a{2,5}") << "aAaAaaaaaAa"; |
|
4318 QTest::newRow("aaa minimal") << minimal(QRegExp("a{2,5}")) << "aAaAaaaaaAa"; |
|
4319 QTest::newRow("minimal") << minimal(QRegExp(".*\\} [*8]")) << "}?} ?} *"; |
|
4320 } |
|
4321 |
|
4322 void tst_QScriptEngine::qRegExpInport() |
|
4323 { |
|
4324 QFETCH(QRegExp, rx); |
|
4325 QFETCH(QString, string); |
|
4326 |
|
4327 QScriptEngine eng; |
|
4328 QScriptValue rexp; |
|
4329 rexp = eng.newRegExp(rx); |
|
4330 |
|
4331 QCOMPARE(rexp.isValid(), true); |
|
4332 QCOMPARE(rexp.isRegExp(), true); |
|
4333 QVERIFY(rexp.isFunction()); |
|
4334 |
|
4335 QScriptValue func = eng.evaluate("(function(string, regexp) { return string.match(regexp); })"); |
|
4336 QScriptValue result = func.call(QScriptValue(), QScriptValueList() << string << rexp); |
|
4337 |
|
4338 rx.indexIn(string); |
|
4339 for (int i = 0; i <= rx.numCaptures(); i++) { |
|
4340 QCOMPARE(result.property(i).toString(), rx.cap(i)); |
|
4341 } |
|
4342 } |
|
4343 |
|
4344 QTEST_MAIN(tst_QScriptEngine) |
|
4345 #include "tst_qscriptengine.moc" |