1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2018 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QtTest/QtTest> |
31 | |
32 | #include <QtScript/qscriptcontextinfo.h> |
33 | #include <QtScript/qscriptcontext.h> |
34 | #include <QtScript/qscriptengine.h> |
35 | #include <QtScript/qscriptable.h> |
36 | #include <QtScript/qscriptengineagent.h> |
37 | |
38 | Q_DECLARE_METATYPE(QScriptValue) |
39 | Q_DECLARE_METATYPE(QScriptContextInfo) |
40 | Q_DECLARE_METATYPE(QList<QScriptContextInfo>) |
41 | |
42 | class tst_QScriptContextInfo : public QObject, public QScriptable |
43 | { |
44 | Q_OBJECT |
45 | Q_PROPERTY(QScriptValue testProperty READ testProperty WRITE setTestProperty) |
46 | public: |
47 | tst_QScriptContextInfo(); |
48 | virtual ~tst_QScriptContextInfo(); |
49 | |
50 | QScriptValue testProperty() const |
51 | { |
52 | return engine()->globalObject().property(name: "getContextInfoList" ).call(); |
53 | } |
54 | |
55 | QScriptValue setTestProperty(const QScriptValue &) const |
56 | { |
57 | return engine()->globalObject().property(name: "getContextInfoList" ).call(); |
58 | } |
59 | |
60 | public slots: |
61 | QScriptValue testSlot(double a, double b) |
62 | { |
63 | Q_UNUSED(a); Q_UNUSED(b); |
64 | return engine()->globalObject().property(name: "getContextInfoList" ).call(); |
65 | } |
66 | |
67 | QScriptValue testSlot(const QString &s) |
68 | { |
69 | Q_UNUSED(s); |
70 | return engine()->globalObject().property(name: "getContextInfoList" ).call(); |
71 | } |
72 | |
73 | private slots: |
74 | void nativeFunction(); |
75 | void scriptFunction(); |
76 | void qtFunction(); |
77 | void qtPropertyFunction(); |
78 | void nullContext(); |
79 | void streaming(); |
80 | void comparison_null(); |
81 | void assignmentAndComparison(); |
82 | }; |
83 | |
84 | tst_QScriptContextInfo::tst_QScriptContextInfo() |
85 | { |
86 | } |
87 | |
88 | tst_QScriptContextInfo::~tst_QScriptContextInfo() |
89 | { |
90 | } |
91 | |
92 | static QScriptValue getContextInfoList(QScriptContext *ctx, QScriptEngine *eng) |
93 | { |
94 | QList<QScriptContextInfo> lst; |
95 | while (ctx) { |
96 | QScriptContextInfo info(ctx); |
97 | lst.append(t: info); |
98 | ctx = ctx->parentContext(); |
99 | } |
100 | return qScriptValueFromValue(engine: eng, t: lst); |
101 | } |
102 | |
103 | void tst_QScriptContextInfo::nativeFunction() |
104 | { |
105 | QScriptEngine eng; |
106 | eng.globalObject().setProperty(name: "getContextInfoList" , value: eng.newFunction(signature: getContextInfoList)); |
107 | |
108 | QString fileName = "foo.qs" ; |
109 | int lineNumber = 123; |
110 | QScriptValue ret = eng.evaluate(program: "getContextInfoList()" , fileName, lineNumber); |
111 | QList<QScriptContextInfo> lst = qscriptvalue_cast<QList<QScriptContextInfo> >(value: ret); |
112 | QCOMPARE(lst.size(), 2); |
113 | |
114 | { |
115 | // getContextInfoList() |
116 | QScriptContextInfo info = lst.at(i: 0); |
117 | QVERIFY(!info.isNull()); |
118 | QCOMPARE(info.functionType(), QScriptContextInfo::NativeFunction); |
119 | QCOMPARE(info.scriptId(), (qint64)-1); |
120 | QCOMPARE(info.fileName(), QString()); |
121 | QCOMPARE(info.lineNumber(), -1); |
122 | QCOMPARE(info.columnNumber(), -1); |
123 | QCOMPARE(info.functionName(), QString()); |
124 | QCOMPARE(info.functionEndLineNumber(), -1); |
125 | QCOMPARE(info.functionStartLineNumber(), -1); |
126 | QCOMPARE(info.functionParameterNames().size(), 0); |
127 | QCOMPARE(info.functionMetaIndex(), -1); |
128 | } |
129 | |
130 | { |
131 | // evaluate() |
132 | QScriptContextInfo info = lst.at(i: 1); |
133 | QVERIFY(!info.isNull()); |
134 | QCOMPARE(info.functionType(), QScriptContextInfo::NativeFunction); |
135 | QVERIFY(info.scriptId() != -1); |
136 | QCOMPARE(info.fileName(), fileName); |
137 | QCOMPARE(info.lineNumber(), lineNumber); |
138 | QEXPECT_FAIL("" , "QTBUG-17602: columnNumber doesn't work" , Continue); |
139 | QCOMPARE(info.columnNumber(), 1); |
140 | QCOMPARE(info.functionName(), QString()); |
141 | QCOMPARE(info.functionEndLineNumber(), -1); |
142 | QCOMPARE(info.functionStartLineNumber(), -1); |
143 | QCOMPARE(info.functionParameterNames().size(), 0); |
144 | QCOMPARE(info.functionMetaIndex(), -1); |
145 | } |
146 | } |
147 | |
148 | void tst_QScriptContextInfo::scriptFunction() |
149 | { |
150 | QScriptEngine eng; |
151 | eng.globalObject().setProperty(name: "getContextInfoList" , value: eng.newFunction(signature: getContextInfoList)); |
152 | |
153 | QString fileName = "ciao.qs" ; |
154 | int lineNumber = 456; |
155 | QScriptValue ret = eng.evaluate(program: "function bar(a, b, c) {\n return getContextInfoList();\n}\nbar()" , |
156 | fileName, lineNumber); |
157 | QList<QScriptContextInfo> lst = qscriptvalue_cast<QList<QScriptContextInfo> >(value: ret); |
158 | QCOMPARE(lst.size(), 3); |
159 | |
160 | // getContextInfoList() |
161 | QCOMPARE(lst.at(0).functionType(), QScriptContextInfo::NativeFunction); |
162 | |
163 | { |
164 | // bar() |
165 | QScriptContextInfo info = lst.at(i: 1); |
166 | QCOMPARE(info.functionType(), QScriptContextInfo::ScriptFunction); |
167 | QVERIFY(info.scriptId() != -1); |
168 | QCOMPARE(info.fileName(), fileName); |
169 | QCOMPARE(info.lineNumber(), lineNumber + 1); |
170 | QEXPECT_FAIL("" , "QTBUG-17602: columnNumber doesn't work" , Continue); |
171 | QCOMPARE(info.columnNumber(), 2); |
172 | QCOMPARE(info.functionName(), QString::fromLatin1("bar" )); |
173 | QCOMPARE(info.functionStartLineNumber(), lineNumber); |
174 | QCOMPARE(info.functionEndLineNumber(), lineNumber + 2); |
175 | QCOMPARE(info.functionParameterNames().size(), 3); |
176 | QCOMPARE(info.functionParameterNames().at(0), QString::fromLatin1("a" )); |
177 | QCOMPARE(info.functionParameterNames().at(1), QString::fromLatin1("b" )); |
178 | QCOMPARE(info.functionParameterNames().at(2), QString::fromLatin1("c" )); |
179 | QCOMPARE(info.functionMetaIndex(), -1); |
180 | } |
181 | |
182 | { |
183 | // evaluate() |
184 | QScriptContextInfo info = lst.at(i: 2); |
185 | QCOMPARE(info.functionType(), QScriptContextInfo::NativeFunction); |
186 | QVERIFY(info.scriptId() != -1); |
187 | QCOMPARE(info.fileName(), fileName); |
188 | QCOMPARE(info.lineNumber(), lineNumber + 3); |
189 | QEXPECT_FAIL("" , "QTBUG-17602: columnNumber doesn't work" , Continue); |
190 | QCOMPARE(info.columnNumber(), 1); |
191 | QCOMPARE(info.functionName(), QString()); |
192 | QCOMPARE(info.functionEndLineNumber(), -1); |
193 | QCOMPARE(info.functionStartLineNumber(), -1); |
194 | QCOMPARE(info.functionParameterNames().size(), 0); |
195 | QCOMPARE(info.functionMetaIndex(), -1); |
196 | } |
197 | } |
198 | |
199 | void tst_QScriptContextInfo::qtFunction() |
200 | { |
201 | QScriptEngine eng; |
202 | eng.globalObject().setProperty(name: "getContextInfoList" , value: eng.newFunction(signature: getContextInfoList)); |
203 | eng.globalObject().setProperty(name: "qobj" , value: eng.newQObject(object: this)); |
204 | |
205 | for (int x = 0; x < 2; ++x) { // twice to test overloaded slot as well |
206 | QString code; |
207 | const char *sig; |
208 | QStringList pnames; |
209 | if (x == 0) { |
210 | code = "qobj.testSlot(1, 2)" ; |
211 | sig = "testSlot(double,double)" ; |
212 | pnames << "a" << "b" ; |
213 | } else { |
214 | code = "qobj.testSlot('ciao')" ; |
215 | sig = "testSlot(QString)" ; |
216 | pnames << "s" ; |
217 | } |
218 | QScriptValue ret = eng.evaluate(program: code); |
219 | QList<QScriptContextInfo> lst = qscriptvalue_cast<QList<QScriptContextInfo> >(value: ret); |
220 | QCOMPARE(lst.size(), 3); |
221 | |
222 | // getContextInfoList() |
223 | QCOMPARE(lst.at(0).functionType(), QScriptContextInfo::NativeFunction); |
224 | |
225 | { |
226 | // testSlot(double a, double b) |
227 | QScriptContextInfo info = lst.at(i: 1); |
228 | QCOMPARE(info.functionType(), QScriptContextInfo::QtFunction); |
229 | QCOMPARE(info.scriptId(), (qint64)-1); |
230 | QCOMPARE(info.fileName(), QString()); |
231 | QCOMPARE(info.lineNumber(), -1); |
232 | QCOMPARE(info.columnNumber(), -1); |
233 | QCOMPARE(info.functionName(), QString::fromLatin1("testSlot" )); |
234 | QCOMPARE(info.functionEndLineNumber(), -1); |
235 | QCOMPARE(info.functionStartLineNumber(), -1); |
236 | QCOMPARE(info.functionParameterNames().size(), pnames.size()); |
237 | QCOMPARE(info.functionParameterNames(), pnames); |
238 | QCOMPARE(info.functionMetaIndex(), metaObject()->indexOfMethod(sig)); |
239 | } |
240 | |
241 | // evaluate() |
242 | QCOMPARE(lst.at(0).functionType(), QScriptContextInfo::NativeFunction); |
243 | } |
244 | } |
245 | |
246 | void tst_QScriptContextInfo::qtPropertyFunction() |
247 | { |
248 | QScriptEngine eng; |
249 | eng.globalObject().setProperty(name: "getContextInfoList" , value: eng.newFunction(signature: getContextInfoList)); |
250 | eng.globalObject().setProperty(name: "qobj" , value: eng.newQObject(object: this)); |
251 | |
252 | QScriptValue ret = eng.evaluate(program: "qobj.testProperty" ); |
253 | QList<QScriptContextInfo> lst = qscriptvalue_cast<QList<QScriptContextInfo> >(value: ret); |
254 | QCOMPARE(lst.size(), 3); |
255 | |
256 | // getContextInfoList() |
257 | QCOMPARE(lst.at(0).functionType(), QScriptContextInfo::NativeFunction); |
258 | |
259 | { |
260 | // testProperty() |
261 | QScriptContextInfo info = lst.at(i: 1); |
262 | QCOMPARE(info.functionType(), QScriptContextInfo::QtPropertyFunction); |
263 | QCOMPARE(info.scriptId(), (qint64)-1); |
264 | QCOMPARE(info.fileName(), QString()); |
265 | QCOMPARE(info.lineNumber(), -1); |
266 | QCOMPARE(info.columnNumber(), -1); |
267 | QCOMPARE(info.functionName(), QString::fromLatin1("testProperty" )); |
268 | QCOMPARE(info.functionEndLineNumber(), -1); |
269 | QCOMPARE(info.functionStartLineNumber(), -1); |
270 | QCOMPARE(info.functionParameterNames().size(), 0); |
271 | QCOMPARE(info.functionMetaIndex(), metaObject()->indexOfProperty("testProperty" )); |
272 | } |
273 | |
274 | // evaluate() |
275 | QCOMPARE(lst.at(0).functionType(), QScriptContextInfo::NativeFunction); |
276 | } |
277 | |
278 | void tst_QScriptContextInfo::nullContext() |
279 | { |
280 | QScriptContextInfo info((QScriptContext*)0); |
281 | QVERIFY(info.isNull()); |
282 | QCOMPARE(info.columnNumber(), -1); |
283 | QCOMPARE(info.scriptId(), (qint64)-1); |
284 | QCOMPARE(info.fileName(), QString()); |
285 | QCOMPARE(info.functionEndLineNumber(), -1); |
286 | QCOMPARE(info.functionMetaIndex(), -1); |
287 | QCOMPARE(info.functionName(), QString()); |
288 | QCOMPARE(info.functionParameterNames().size(), 0); |
289 | QCOMPARE(info.functionStartLineNumber(), -1); |
290 | QCOMPARE(info.functionType(), QScriptContextInfo::NativeFunction); |
291 | } |
292 | |
293 | void tst_QScriptContextInfo::streaming() |
294 | { |
295 | { |
296 | QScriptContextInfo info((QScriptContext*)0); |
297 | QByteArray ba; |
298 | QDataStream stream(&ba, QIODevice::ReadWrite); |
299 | stream << info; |
300 | stream.device()->seek(pos: 0); |
301 | QScriptContextInfo info2; |
302 | stream >> info2; |
303 | QVERIFY(stream.device()->atEnd()); |
304 | QCOMPARE(info.functionType(), info2.functionType()); |
305 | QCOMPARE(info.scriptId(), info2.scriptId()); |
306 | QCOMPARE(info.fileName(), info2.fileName()); |
307 | QCOMPARE(info.lineNumber(), info2.lineNumber()); |
308 | QCOMPARE(info.columnNumber(), info2.columnNumber()); |
309 | QCOMPARE(info.functionName(), info2.functionName()); |
310 | QCOMPARE(info.functionEndLineNumber(), info2.functionEndLineNumber()); |
311 | QCOMPARE(info.functionStartLineNumber(), info2.functionStartLineNumber()); |
312 | QCOMPARE(info.functionParameterNames(), info2.functionParameterNames()); |
313 | QCOMPARE(info.functionMetaIndex(), info2.functionMetaIndex()); |
314 | } |
315 | { |
316 | QScriptEngine eng; |
317 | eng.globalObject().setProperty(name: "getContextInfoList" , value: eng.newFunction(signature: getContextInfoList)); |
318 | |
319 | QString fileName = "ciao.qs" ; |
320 | int lineNumber = 456; |
321 | QScriptValue ret = eng.evaluate(program: "function bar(a, b, c) {\n return getContextInfoList();\n}\nbar()" , |
322 | fileName, lineNumber); |
323 | QList<QScriptContextInfo> lst = qscriptvalue_cast<QList<QScriptContextInfo> >(value: ret); |
324 | QCOMPARE(lst.size(), 3); |
325 | for (int i = 0; i < lst.size(); ++i) { |
326 | const QScriptContextInfo &info = lst.at(i); |
327 | QByteArray ba; |
328 | QDataStream stream(&ba, QIODevice::ReadWrite); |
329 | stream << info; |
330 | stream.device()->seek(pos: 0); |
331 | QScriptContextInfo info2; |
332 | stream >> info2; |
333 | QVERIFY(stream.device()->atEnd()); |
334 | QCOMPARE(info.functionType(), info2.functionType()); |
335 | QCOMPARE(info.scriptId(), info2.scriptId()); |
336 | QCOMPARE(info.fileName(), info2.fileName()); |
337 | QCOMPARE(info.lineNumber(), info2.lineNumber()); |
338 | QCOMPARE(info.columnNumber(), info2.columnNumber()); |
339 | QCOMPARE(info.functionName(), info2.functionName()); |
340 | QCOMPARE(info.functionEndLineNumber(), info2.functionEndLineNumber()); |
341 | QCOMPARE(info.functionStartLineNumber(), info2.functionStartLineNumber()); |
342 | QCOMPARE(info.functionParameterNames(), info2.functionParameterNames()); |
343 | QCOMPARE(info.functionMetaIndex(), info2.functionMetaIndex()); |
344 | } |
345 | } |
346 | } |
347 | |
348 | void tst_QScriptContextInfo::comparison_null() |
349 | { |
350 | QScriptContextInfo info1, info2, info3(0); |
351 | QCOMPARE(info1, info2); |
352 | QCOMPARE(info1, info3); |
353 | } |
354 | |
355 | void tst_QScriptContextInfo::assignmentAndComparison() |
356 | { |
357 | QScriptEngine eng; |
358 | eng.globalObject().setProperty(name: "getContextInfoList" , value: eng.newFunction(signature: getContextInfoList)); |
359 | QString fileName = "ciao.qs" ; |
360 | int lineNumber = 456; |
361 | QScriptValue ret = eng.evaluate(program: "function bar(a, b, c) {\n return getContextInfoList();\n}\nbar()" , |
362 | fileName, lineNumber); |
363 | QList<QScriptContextInfo> lst = qscriptvalue_cast<QList<QScriptContextInfo> >(value: ret); |
364 | QCOMPARE(lst.size(), 3); |
365 | QScriptContextInfo ci = lst.at(i: 0); |
366 | QScriptContextInfo same = ci; |
367 | QVERIFY(ci == same); |
368 | QVERIFY(!(ci != same)); |
369 | QScriptContextInfo other = lst.at(i: 1); |
370 | QVERIFY(!(ci == other)); |
371 | QVERIFY(ci != other); |
372 | } |
373 | |
374 | QTEST_MAIN(tst_QScriptContextInfo) |
375 | #include "tst_qscriptcontextinfo.moc" |
376 | |