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