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
38Q_DECLARE_METATYPE(QScriptValue)
39Q_DECLARE_METATYPE(QScriptContextInfo)
40Q_DECLARE_METATYPE(QList<QScriptContextInfo>)
41
42class tst_QScriptContextInfo : public QObject, public QScriptable
43{
44 Q_OBJECT
45 Q_PROPERTY(QScriptValue testProperty READ testProperty WRITE setTestProperty)
46public:
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
60public 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
73private 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
84tst_QScriptContextInfo::tst_QScriptContextInfo()
85{
86}
87
88tst_QScriptContextInfo::~tst_QScriptContextInfo()
89{
90}
91
92static 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
103void 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
148void 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
199void 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
246void 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
278void 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
293void 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
348void tst_QScriptContextInfo::comparison_null()
349{
350 QScriptContextInfo info1, info2, info3(0);
351 QCOMPARE(info1, info2);
352 QCOMPARE(info1, info3);
353}
354
355void 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
374QTEST_MAIN(tst_QScriptContextInfo)
375#include "tst_qscriptcontextinfo.moc"
376

source code of qtscript/tests/auto/qscriptcontextinfo/tst_qscriptcontextinfo.cpp