1/****************************************************************************
2**
3** Copyright (C) 2016 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#include <qtest.h>
30#include <private/qv4instr_moth_p.h>
31#include <private/qv4script_p.h>
32
33class tst_v4misc: public QObject
34{
35 Q_OBJECT
36
37private slots:
38 void tdzOptimizations_data();
39 void tdzOptimizations();
40
41 void parserMisc_data();
42 void parserMisc();
43
44 void subClassing_data();
45 void subClassing();
46
47 void nestingDepth();
48};
49
50void tst_v4misc::tdzOptimizations_data()
51{
52 QTest::addColumn<QString>(name: "scriptToCompile");
53
54 QTest::newRow(dataTag: "access-after-let") << QString("let x; x = 10;");
55 QTest::newRow(dataTag: "access-after-const") << QString("const x = 10; print(x);");
56 QTest::newRow(dataTag: "access-after-let") << QString("for (let x of y) print(x);");
57}
58
59void tst_v4misc::tdzOptimizations()
60{
61 QFETCH(QString, scriptToCompile);
62
63 QV4::ExecutionEngine v4;
64 QV4::Script script(&v4, nullptr, /*parse as binding*/false, scriptToCompile);
65 script.parse();
66 QVERIFY(!v4.hasException);
67
68 const auto function = script.compilationUnit->unitData()->functionAt(idx: 0);
69 const auto *code = function->code();
70 const auto len = function->codeSize;
71 const char *end = code + len;
72
73 const auto decodeInstruction = [&code]() {
74 QV4::Moth::Instr::Type type = QV4::Moth::Instr::Type(static_cast<uchar>(*code));
75 dispatch:
76 switch (type) {
77 case QV4::Moth::Instr::Type::Nop:
78 ++code;
79 type = QV4::Moth::Instr::Type(static_cast<uchar>(*code));
80 goto dispatch;
81 case QV4::Moth::Instr::Type::Nop_Wide: /* wide prefix */
82 ++code;
83 type = QV4::Moth::Instr::Type(0x100 | static_cast<uchar>(*code));
84 goto dispatch;
85
86#define CASE_AND_GOTO_INSTRUCTION(name, nargs, ...) \
87 case QV4::Moth::Instr::Type::name: \
88 MOTH_ADJUST_CODE(qint8, nargs); \
89 break;
90
91#define CASE_AND_GOTO_WIDE_INSTRUCTION(name, nargs, ...) \
92 case QV4::Moth::Instr::Type::name##_Wide: \
93 MOTH_ADJUST_CODE(int, nargs); \
94 type = QV4::Moth::Instr::Type::name; \
95 break;
96
97#define MOTH_DECODE_WITHOUT_ARGS(instr) \
98 INSTR_##instr(CASE_AND_GOTO) \
99 INSTR_##instr(CASE_AND_GOTO_WIDE)
100
101 FOR_EACH_MOTH_INSTR(MOTH_DECODE_WITHOUT_ARGS)
102 }
103 return type;
104 };
105
106 while (code < end) {
107 QV4::Moth::Instr::Type type = decodeInstruction();
108 QVERIFY(type != QV4::Moth::Instr::Type::DeadTemporalZoneCheck);
109 }
110
111}
112
113void tst_v4misc::parserMisc_data()
114{
115 QTest::addColumn<QString>(name: "error");
116
117 QTest::newRow(dataTag: "8[++i][+++i]") << QString("ReferenceError: Prefix ++ operator applied to value that is not a reference.");
118 QTest::newRow(dataTag: "`a${1++}`") << QString("ReferenceError: Invalid left-hand side expression in postfix operation");
119 QTest::newRow(dataTag: "for (var f in ++!binaryMathg) ;") << QString("ReferenceError: Prefix ++ operator applied to value that is not a reference.");
120 QTest::newRow(dataTag: "for (va() in obj) {}") << QString("ReferenceError: Invalid left-hand side expression for 'in' expression");
121 QTest::newRow(dataTag: "[1]=7[A=8=9]") << QString("ReferenceError: left-hand side of assignment operator is not an lvalue");
122 QTest::newRow(dataTag: "var asmvalsLen = asmvals{{{{{ngth}}}}};") << QString("SyntaxError: Expected token `;'");
123 QTest::newRow(dataTag: "T||9[---L6i]") << QString("ReferenceError: Prefix ++ operator applied to value that is not a reference.");
124 QTest::newRow(dataTag: "a?b:[---Hi]") << QString("ReferenceError: Prefix ++ operator applied to value that is not a reference.");
125 QTest::newRow(dataTag: "[``]=1") << QString("ReferenceError: Binding target is not a reference.");
126}
127
128void tst_v4misc::parserMisc()
129{
130 QFETCH(QString, error);
131
132 QJSEngine engine;
133 QJSValue result = engine.evaluate(program: QString::fromUtf8(str: QTest::currentDataTag()));
134 QVERIFY(result.isError());
135 QCOMPARE(result.toString(), error);
136}
137
138void tst_v4misc::subClassing_data()
139{
140 QTest::addColumn<QString>(name: "script");
141
142 QString code(
143 "class Foo extends %1 {"
144 " constructor() { super(); this.reset(); }"
145 " reset() { }"
146 "}"
147 "new Foo();");
148
149
150 QTest::newRow(dataTag: "Array") << code.arg(a: "Array");
151 QTest::newRow(dataTag: "Boolean") << code.arg(a: "Boolean");
152 QTest::newRow(dataTag: "Date") << code.arg(a: "Date");
153 QTest::newRow(dataTag: "Function") << code.arg(a: "Function");
154 QTest::newRow(dataTag: "Number") << code.arg(a: "Number");
155 QTest::newRow(dataTag: "Map") << code.arg(a: "Map");
156 QTest::newRow(dataTag: "Promise") << QString(
157 "class Foo extends Promise {"
158 " constructor() { super(Function()); this.reset(); }"
159 " reset() { }"
160 "}"
161 "new Foo();");
162 QTest::newRow(dataTag: "RegExp") << code.arg(a: "RegExp");
163 QTest::newRow(dataTag: "Set") << code.arg(a: "Set");
164 QTest::newRow(dataTag: "String") << code.arg(a: "String");
165 QTest::newRow(dataTag: "WeakMap") << code.arg(a: "WeakMap");
166 QTest::newRow(dataTag: "WeakSet") << code.arg(a: "WeakSet");
167}
168
169void tst_v4misc::subClassing()
170{
171 QFETCH(QString, script);
172
173 QJSEngine engine;
174 QJSValue result = engine.evaluate(program: script);
175 QVERIFY(!result.isError());
176}
177
178void tst_v4misc::nestingDepth()
179{
180 { // left recursive
181 QString s(40000, '`');
182
183 QJSEngine engine;
184 QJSValue result = engine.evaluate(program: s);
185 QVERIFY(result.isError());
186 QCOMPARE(result.toString(), "SyntaxError: Maximum statement or expression depth exceeded");
187 }
188
189 { // right recursive
190 QString s(200000, '-');
191 s += "\nd";
192
193 QJSEngine engine;
194 QJSValue result = engine.evaluate(program: s);
195 QVERIFY(result.isError());
196 QCOMPARE(result.toString(), "SyntaxError: Maximum statement or expression depth exceeded");
197 }
198}
199
200QTEST_MAIN(tst_v4misc);
201
202#include "tst_v4misc.moc"
203

source code of qtdeclarative/tests/auto/qml/v4misc/tst_v4misc.cpp