|
1 /**************************************************************************** |
|
2 ** |
|
3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
4 ** All rights reserved. |
|
5 ** Contact: Nokia Corporation (qt-info@nokia.com) |
|
6 ** |
|
7 ** This file is part of the test suite of the Qt Toolkit. |
|
8 ** |
|
9 ** $QT_BEGIN_LICENSE:LGPL$ |
|
10 ** No Commercial Usage |
|
11 ** This file contains pre-release code and may not be distributed. |
|
12 ** You may use this file in accordance with the terms and conditions |
|
13 ** contained in the Technology Preview License Agreement accompanying |
|
14 ** this package. |
|
15 ** |
|
16 ** GNU Lesser General Public License Usage |
|
17 ** Alternatively, this file may be used under the terms of the GNU Lesser |
|
18 ** General Public License version 2.1 as published by the Free Software |
|
19 ** Foundation and appearing in the file LICENSE.LGPL included in the |
|
20 ** packaging of this file. Please review the following information to |
|
21 ** ensure the GNU Lesser General Public License version 2.1 requirements |
|
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. |
|
23 ** |
|
24 ** In addition, as a special exception, Nokia gives you certain additional |
|
25 ** rights. These rights are described in the Nokia Qt LGPL Exception |
|
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. |
|
27 ** |
|
28 ** If you have questions regarding the use of this file, please contact |
|
29 ** Nokia at qt-info@nokia.com. |
|
30 ** |
|
31 ** |
|
32 ** |
|
33 ** |
|
34 ** |
|
35 ** |
|
36 ** |
|
37 ** |
|
38 ** $QT_END_LICENSE$ |
|
39 ** |
|
40 ****************************************************************************/ |
|
41 |
|
42 |
|
43 #include <QtTest/QtTest> |
|
44 #include <qdebug.h> |
|
45 |
|
46 #include <QtScript/qscriptengine.h> |
|
47 #include <QtScript/qscriptable.h> |
|
48 |
|
49 //TESTED_CLASS= |
|
50 //TESTED_FILES= |
|
51 |
|
52 class MyScriptable : public QObject, public QScriptable |
|
53 { |
|
54 Q_OBJECT |
|
55 Q_PROPERTY(int baz READ baz WRITE setBaz) |
|
56 Q_PROPERTY(QObject* zab READ zab WRITE setZab) |
|
57 Q_PROPERTY(int 0 READ baz) |
|
58 Q_PROPERTY(QObject* 1 READ zab) |
|
59 Q_PROPERTY(int oof WRITE setOof) |
|
60 public: |
|
61 MyScriptable(QObject *parent = 0) |
|
62 : QObject(parent), m_lastEngine(0) |
|
63 { } |
|
64 ~MyScriptable() { } |
|
65 |
|
66 QScriptEngine *lastEngine() const; |
|
67 |
|
68 void setOof(int) |
|
69 { m_oofThisObject = context()->thisObject(); } |
|
70 QScriptValue oofThisObject() const |
|
71 { return m_oofThisObject; } |
|
72 |
|
73 void emitSig(int value) |
|
74 { emit sig(value); } |
|
75 |
|
76 public slots: |
|
77 void foo(); |
|
78 void setX(int x); |
|
79 void setX(const QString &x); |
|
80 void setX2(int x); |
|
81 bool isBar(); |
|
82 int baz(); |
|
83 void setBaz(int x); |
|
84 void evalIsBar(); |
|
85 bool useInAnotherEngine(); |
|
86 void setOtherEngine(); |
|
87 QObject *zab(); |
|
88 QObject *setZab(QObject *); |
|
89 QScriptValue getArguments(); |
|
90 int getArgumentCount(); |
|
91 |
|
92 signals: |
|
93 void sig(int); |
|
94 |
|
95 private: |
|
96 QScriptEngine *m_lastEngine; |
|
97 QScriptEngine *m_otherEngine; |
|
98 QScriptValue m_oofThisObject; |
|
99 }; |
|
100 |
|
101 QScriptEngine *MyScriptable::lastEngine() const |
|
102 { |
|
103 return m_lastEngine; |
|
104 } |
|
105 |
|
106 int MyScriptable::baz() |
|
107 { |
|
108 m_lastEngine = engine(); |
|
109 return 123; |
|
110 } |
|
111 |
|
112 void MyScriptable::setBaz(int) |
|
113 { |
|
114 m_lastEngine = engine(); |
|
115 } |
|
116 |
|
117 QObject *MyScriptable::zab() |
|
118 { |
|
119 return thisObject().toQObject(); |
|
120 } |
|
121 |
|
122 QObject *MyScriptable::setZab(QObject *) |
|
123 { |
|
124 return thisObject().toQObject(); |
|
125 } |
|
126 |
|
127 QScriptValue MyScriptable::getArguments() |
|
128 { |
|
129 return context()->argumentsObject(); |
|
130 } |
|
131 |
|
132 int MyScriptable::getArgumentCount() |
|
133 { |
|
134 return context()->argumentCount(); |
|
135 } |
|
136 |
|
137 void MyScriptable::foo() |
|
138 { |
|
139 m_lastEngine = engine(); |
|
140 QVERIFY(engine() != 0); |
|
141 context()->throwError("MyScriptable.foo"); |
|
142 } |
|
143 |
|
144 void MyScriptable::evalIsBar() |
|
145 { |
|
146 engine()->evaluate("this.isBar()"); |
|
147 m_lastEngine = engine(); |
|
148 } |
|
149 |
|
150 bool MyScriptable::useInAnotherEngine() |
|
151 { |
|
152 QScriptEngine eng; |
|
153 eng.globalObject().setProperty("foo", eng.newQObject(this)); |
|
154 eng.evaluate("foo.baz()"); |
|
155 m_lastEngine = engine(); |
|
156 return (m_otherEngine == &eng); |
|
157 } |
|
158 |
|
159 void MyScriptable::setOtherEngine() |
|
160 { |
|
161 m_otherEngine = engine(); |
|
162 } |
|
163 |
|
164 void MyScriptable::setX(int x) |
|
165 { |
|
166 m_lastEngine = engine(); |
|
167 Q_ASSERT(engine()); |
|
168 thisObject().setProperty("x", QScriptValue(engine(), x)); |
|
169 } |
|
170 |
|
171 void MyScriptable::setX(const QString &x) |
|
172 { |
|
173 m_lastEngine = engine(); |
|
174 Q_ASSERT(engine()); |
|
175 thisObject().setProperty("x", QScriptValue(engine(), x)); |
|
176 } |
|
177 |
|
178 void MyScriptable::setX2(int) |
|
179 { |
|
180 m_lastEngine = engine(); |
|
181 thisObject().setProperty("x", argument(0)); |
|
182 } |
|
183 |
|
184 bool MyScriptable::isBar() |
|
185 { |
|
186 m_lastEngine = engine(); |
|
187 QString str = thisObject().toString(); |
|
188 return str.contains(QLatin1Char('@')); |
|
189 } |
|
190 |
|
191 class tst_QScriptable : public QObject |
|
192 { |
|
193 Q_OBJECT |
|
194 |
|
195 public: |
|
196 tst_QScriptable(); |
|
197 virtual ~tst_QScriptable(); |
|
198 |
|
199 private slots: |
|
200 void initTestCase(); |
|
201 void cleanupTestCase(); |
|
202 |
|
203 void engine(); |
|
204 void thisObject(); |
|
205 void arguments(); |
|
206 void throwError(); |
|
207 |
|
208 private: |
|
209 QScriptEngine m_engine; |
|
210 MyScriptable m_scriptable; |
|
211 }; |
|
212 |
|
213 tst_QScriptable::tst_QScriptable() |
|
214 { |
|
215 } |
|
216 |
|
217 tst_QScriptable::~tst_QScriptable() |
|
218 { |
|
219 } |
|
220 |
|
221 void tst_QScriptable::initTestCase() |
|
222 { |
|
223 QScriptValue obj = m_engine.newQObject(&m_scriptable); |
|
224 m_engine.globalObject().setProperty("scriptable", obj); |
|
225 } |
|
226 |
|
227 void tst_QScriptable::cleanupTestCase() |
|
228 { |
|
229 } |
|
230 |
|
231 void tst_QScriptable::engine() |
|
232 { |
|
233 QCOMPARE(m_scriptable.engine(), (QScriptEngine*)0); |
|
234 QCOMPARE(m_scriptable.context(), (QScriptContext*)0); |
|
235 QCOMPARE(m_scriptable.lastEngine(), (QScriptEngine *)0); |
|
236 |
|
237 // reading property |
|
238 { |
|
239 QScriptValue ret = m_engine.evaluate("scriptable.baz"); |
|
240 QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, 123)), true); |
|
241 } |
|
242 QCOMPARE(m_scriptable.lastEngine(), &m_engine); |
|
243 { |
|
244 QScriptValue ret = m_engine.evaluate("scriptable[0]"); |
|
245 QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, 123)), true); |
|
246 } |
|
247 QCOMPARE(m_scriptable.lastEngine(), &m_engine); |
|
248 // when reading from C++, engine() should be 0 |
|
249 (void)m_scriptable.property("baz"); |
|
250 QCOMPARE(m_scriptable.lastEngine(), (QScriptEngine *)0); |
|
251 |
|
252 // writing property |
|
253 m_engine.evaluate("scriptable.baz = 123"); |
|
254 QCOMPARE(m_scriptable.lastEngine(), &m_engine); |
|
255 (void)m_scriptable.setProperty("baz", 123); |
|
256 QCOMPARE(m_scriptable.lastEngine(), (QScriptEngine *)0); |
|
257 |
|
258 // calling slot |
|
259 m_engine.evaluate("scriptable.setX(123)"); |
|
260 QCOMPARE(m_scriptable.lastEngine(), &m_engine); |
|
261 QCOMPARE(m_engine.evaluate("scriptable.x") |
|
262 .strictlyEquals(QScriptValue(&m_engine, 123)), true); |
|
263 (void)m_scriptable.setProperty("baz", 123); |
|
264 QCOMPARE(m_scriptable.lastEngine(), (QScriptEngine *)0); |
|
265 |
|
266 // calling overloaded slot |
|
267 m_engine.evaluate("scriptable.setX('123')"); |
|
268 QCOMPARE(m_scriptable.lastEngine(), &m_engine); |
|
269 QCOMPARE(m_engine.evaluate("scriptable.x") |
|
270 .strictlyEquals(QScriptValue(&m_engine, QLatin1String("123"))), true); |
|
271 |
|
272 // calling a slot from another slot |
|
273 m_engine.evaluate("scriptable.evalIsBar()"); |
|
274 QCOMPARE(m_scriptable.lastEngine(), &m_engine); |
|
275 |
|
276 // calling a slot that registers m_scriptable in a different engine |
|
277 // and calls evaluate() |
|
278 { |
|
279 QScriptValue ret = m_engine.evaluate("scriptable.useInAnotherEngine()"); |
|
280 QCOMPARE(m_scriptable.lastEngine(), &m_engine); |
|
281 } |
|
282 } |
|
283 |
|
284 void tst_QScriptable::thisObject() |
|
285 { |
|
286 m_engine.evaluate("o = { }"); |
|
287 { |
|
288 QScriptValue ret = m_engine.evaluate("o.__proto__ = scriptable;" |
|
289 "o.setX(123);" |
|
290 "o.__proto__ = Object.prototype;" |
|
291 "o.x"); |
|
292 QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, 123)), true); |
|
293 } |
|
294 { |
|
295 QScriptValue ret = m_engine.evaluate("o.__proto__ = scriptable;" |
|
296 "o.setX2(456);" |
|
297 "o.__proto__ = Object.prototype;" |
|
298 "o.x"); |
|
299 QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, 456)), true); |
|
300 } |
|
301 m_engine.evaluate("o.__proto__ = scriptable"); |
|
302 { |
|
303 QScriptValue ret = m_engine.evaluate("o.isBar()"); |
|
304 QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, false)), true); |
|
305 } |
|
306 { |
|
307 QScriptValue ret = m_engine.evaluate("o.toString = function() { return 'foo@bar'; }; o.isBar()"); |
|
308 QCOMPARE(ret.strictlyEquals(QScriptValue(&m_engine, true)), true); |
|
309 } |
|
310 |
|
311 // property getter |
|
312 { |
|
313 QScriptValue ret = m_engine.evaluate("scriptable.zab"); |
|
314 QCOMPARE(ret.isQObject(), true); |
|
315 QCOMPARE(ret.toQObject(), (QObject *)&m_scriptable); |
|
316 } |
|
317 { |
|
318 QScriptValue ret = m_engine.evaluate("scriptable[1]"); |
|
319 QCOMPARE(ret.isQObject(), true); |
|
320 QCOMPARE(ret.toQObject(), (QObject *)&m_scriptable); |
|
321 } |
|
322 { |
|
323 QScriptValue ret = m_engine.evaluate("o.zab"); |
|
324 QCOMPARE(ret.toQObject(), (QObject *)0); |
|
325 } |
|
326 // property setter |
|
327 { |
|
328 QScriptValue ret = m_engine.evaluate("scriptable.setZab(null)"); |
|
329 QCOMPARE(ret.isQObject(), true); |
|
330 QCOMPARE(ret.toQObject(), (QObject *)&m_scriptable); |
|
331 } |
|
332 { |
|
333 QVERIFY(!m_scriptable.oofThisObject().isValid()); |
|
334 m_engine.evaluate("o.oof = 123"); |
|
335 QEXPECT_FAIL("", "Setter doesn't get called when it's in the prototype", Continue); |
|
336 QVERIFY(m_scriptable.oofThisObject().strictlyEquals(m_engine.evaluate("o"))); |
|
337 } |
|
338 { |
|
339 m_engine.evaluate("scriptable.oof = 123"); |
|
340 QVERIFY(m_scriptable.oofThisObject().strictlyEquals(m_engine.evaluate("scriptable"))); |
|
341 } |
|
342 |
|
343 // target of signal |
|
344 { |
|
345 { |
|
346 QScriptValue ret = m_engine.evaluate("scriptable.sig.connect(o, scriptable.setX)"); |
|
347 QVERIFY(ret.isUndefined()); |
|
348 } |
|
349 QVERIFY(m_engine.evaluate("o.x").strictlyEquals(QScriptValue(&m_engine, 456))); |
|
350 m_scriptable.emitSig(654321); |
|
351 QVERIFY(m_engine.evaluate("o.x").strictlyEquals(QScriptValue(&m_engine, 654321))); |
|
352 { |
|
353 QScriptValue ret = m_engine.evaluate("scriptable.sig.disconnect(o, scriptable.setX)"); |
|
354 QVERIFY(ret.isUndefined()); |
|
355 } |
|
356 } |
|
357 |
|
358 m_engine.evaluate("delete o"); |
|
359 } |
|
360 |
|
361 void tst_QScriptable::arguments() |
|
362 { |
|
363 // even though the C++ slot accepts zero arguments, it should |
|
364 // still be invoked; the arguments should be accessible through |
|
365 // the QScriptable API |
|
366 QScriptValue args = m_engine.evaluate("scriptable.getArguments(10, 20, 30, 'hi')"); |
|
367 QVERIFY(args.property("length").strictlyEquals(QScriptValue(&m_engine, 4))); |
|
368 QVERIFY(args.property("0").strictlyEquals(QScriptValue(&m_engine, 10))); |
|
369 QVERIFY(args.property("1").strictlyEquals(QScriptValue(&m_engine, 20))); |
|
370 QVERIFY(args.property("2").strictlyEquals(QScriptValue(&m_engine, 30))); |
|
371 QVERIFY(args.property("3").strictlyEquals(QScriptValue(&m_engine, "hi"))); |
|
372 |
|
373 QScriptValue argc = m_engine.evaluate("scriptable.getArgumentCount(1, 2, 3)"); |
|
374 QVERIFY(argc.isNumber()); |
|
375 QCOMPARE(argc.toInt32(), 3); |
|
376 |
|
377 QCOMPARE(m_scriptable.argumentCount(), -1); |
|
378 QVERIFY(!m_scriptable.argument(-1).isValid()); |
|
379 QVERIFY(!m_scriptable.argument(0).isValid()); |
|
380 } |
|
381 |
|
382 void tst_QScriptable::throwError() |
|
383 { |
|
384 QScriptValue ret = m_engine.evaluate("scriptable.foo()"); |
|
385 QCOMPARE(ret.isError(), true); |
|
386 QCOMPARE(ret.toString(), QString("Error: MyScriptable.foo")); |
|
387 } |
|
388 |
|
389 QTEST_MAIN(tst_QScriptable) |
|
390 #include "tst_qscriptable.moc" |