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 "../../shared/util.h" |
30 | |
31 | #include <qtest.h> |
32 | #include <QObject> |
33 | #include <QQmlEngine> |
34 | #include <QQmlComponent> |
35 | #include <private/qqmljsdiagnosticmessage_p.h> |
36 | #include <private/qqmldirparser_p.h> |
37 | #include <QDebug> |
38 | |
39 | #include <algorithm> |
40 | |
41 | // Test the parsing of qmldir files |
42 | |
43 | class tst_qqmldirparser : public QQmlDataTest |
44 | { |
45 | Q_OBJECT |
46 | public: |
47 | tst_qqmldirparser(); |
48 | |
49 | private slots: |
50 | void parse_data(); |
51 | void parse(); |
52 | }; |
53 | |
54 | tst_qqmldirparser::tst_qqmldirparser() |
55 | { |
56 | } |
57 | |
58 | namespace { |
59 | |
60 | QStringList toStringList(const QList<QQmlJS::DiagnosticMessage> &errors) |
61 | { |
62 | QStringList rv; |
63 | |
64 | for (const QQmlJS::DiagnosticMessage &e : errors) { |
65 | QString errorString = QLatin1String("qmldir" ); |
66 | if (e.loc.startLine > 0) { |
67 | errorString += QLatin1Char(':') + QString::number(e.loc.startLine); |
68 | if (e.loc.startColumn > 0) |
69 | errorString += QLatin1Char(':') + QString::number(e.loc.startColumn); |
70 | } |
71 | |
72 | errorString += QLatin1String(": " ) + e.message; |
73 | rv.append(t: errorString); |
74 | } |
75 | |
76 | return rv; |
77 | } |
78 | |
79 | QString toString(const QQmlDirParser::Plugin &p) |
80 | { |
81 | return p.name + QLatin1Char('|') + p.path; |
82 | } |
83 | |
84 | QStringList toStringList(const QList<QQmlDirParser::Plugin> &plugins) |
85 | { |
86 | QStringList rv; |
87 | |
88 | foreach (const QQmlDirParser::Plugin &p, plugins) |
89 | rv.append(t: toString(p)); |
90 | |
91 | return rv; |
92 | } |
93 | |
94 | QString toString(const QQmlDirParser::Component &c) |
95 | { |
96 | return c.typeName + QLatin1Char('|') + c.fileName + QLatin1Char('|') |
97 | + QString::number(c.majorVersion) + QLatin1Char('|') + QString::number(c.minorVersion) |
98 | + QLatin1Char('|') + (c.internal ? "true" : "false" ); |
99 | } |
100 | |
101 | QStringList toStringList(const QQmlDirComponents &components) |
102 | { |
103 | QStringList rv; |
104 | |
105 | foreach (const QQmlDirParser::Component &c, components.values()) |
106 | rv.append(t: toString(c)); |
107 | |
108 | std::sort(first: rv.begin(), last: rv.end()); |
109 | return rv; |
110 | } |
111 | |
112 | QString toString(const QQmlDirParser::Script &s) |
113 | { |
114 | return s.nameSpace + QLatin1Char('|') + s.fileName + QLatin1Char('|') |
115 | + QString::number(s.majorVersion) + '|' + QString::number(s.minorVersion); |
116 | } |
117 | |
118 | QStringList toStringList(const QList<QQmlDirParser::Script> &scripts) |
119 | { |
120 | QStringList rv; |
121 | |
122 | foreach (const QQmlDirParser::Script &s, scripts) |
123 | rv.append(t: toString(s)); |
124 | |
125 | return rv; |
126 | } |
127 | } |
128 | |
129 | void tst_qqmldirparser::parse_data() |
130 | { |
131 | QTest::addColumn<QString>(name: "file" ); |
132 | QTest::addColumn<QStringList>(name: "errors" ); |
133 | QTest::addColumn<QStringList>(name: "plugins" ); |
134 | QTest::addColumn<QStringList>(name: "components" ); |
135 | QTest::addColumn<QStringList>(name: "scripts" ); |
136 | QTest::addColumn<QStringList>(name: "dependencies" ); |
137 | QTest::addColumn<bool>(name: "designerSupported" ); |
138 | |
139 | QTest::newRow(dataTag: "empty" ) |
140 | << "empty/qmldir" |
141 | << QStringList() |
142 | << QStringList() |
143 | << QStringList() |
144 | << QStringList() |
145 | << QStringList() |
146 | << false; |
147 | |
148 | QTest::newRow(dataTag: "no-content" ) |
149 | << "no-content/qmldir" |
150 | << QStringList() |
151 | << QStringList() |
152 | << QStringList() |
153 | << QStringList() |
154 | << QStringList() |
155 | << false; |
156 | |
157 | QTest::newRow(dataTag: "one-section" ) |
158 | << "one-section/qmldir" |
159 | << (QStringList() << "qmldir:1: a component declaration requires two or three arguments, but 1 were provided" ) |
160 | << QStringList() |
161 | << QStringList() |
162 | << QStringList() |
163 | << QStringList() |
164 | << false; |
165 | |
166 | QTest::newRow(dataTag: "four-sections" ) |
167 | << "four-sections/qmldir" |
168 | << (QStringList() << "qmldir:1: a component declaration requires two or three arguments, but 4 were provided" ) |
169 | << QStringList() |
170 | << QStringList() |
171 | << QStringList() |
172 | << QStringList() |
173 | << false; |
174 | |
175 | QTest::newRow(dataTag: "incomplete-module" ) |
176 | << "incomplete-module/qmldir" |
177 | << (QStringList() << "qmldir:1: module identifier directive requires one argument, but 0 were provided" ) |
178 | << QStringList() |
179 | << QStringList() |
180 | << QStringList() |
181 | << QStringList() |
182 | << false; |
183 | |
184 | QTest::newRow(dataTag: "excessive-module" ) |
185 | << "excessive-module/qmldir" |
186 | << (QStringList() << "qmldir:1: module identifier directive requires one argument, but 2 were provided" ) |
187 | << QStringList() |
188 | << QStringList() |
189 | << QStringList() |
190 | << QStringList() |
191 | << false; |
192 | |
193 | QTest::newRow(dataTag: "repeated-module" ) |
194 | << "repeated-module/qmldir" |
195 | << (QStringList() << "qmldir:2: only one module identifier directive may be defined in a qmldir file" ) |
196 | << QStringList() |
197 | << QStringList() |
198 | << QStringList() |
199 | << QStringList() |
200 | << false; |
201 | |
202 | QTest::newRow(dataTag: "non-first-module" ) |
203 | << "non-first-module/qmldir" |
204 | << (QStringList() << "qmldir:2: module identifier directive must be the first directive in a qmldir file" ) |
205 | << (QStringList() << "foo|" ) |
206 | << QStringList() |
207 | << QStringList() |
208 | << QStringList() |
209 | << false; |
210 | |
211 | QTest::newRow(dataTag: "incomplete-plugin" ) |
212 | << "incomplete-plugin/qmldir" |
213 | << (QStringList() << "qmldir:1: plugin directive requires one or two arguments, but 0 were provided" ) |
214 | << QStringList() |
215 | << QStringList() |
216 | << QStringList() |
217 | << QStringList() |
218 | << false; |
219 | |
220 | QTest::newRow(dataTag: "excessive-plugin" ) |
221 | << "excessive-plugin/qmldir" |
222 | << (QStringList() << "qmldir:1: plugin directive requires one or two arguments, but 3 were provided" ) |
223 | << QStringList() |
224 | << QStringList() |
225 | << QStringList() |
226 | << QStringList() |
227 | << false; |
228 | |
229 | QTest::newRow(dataTag: "name-plugin" ) |
230 | << "name-plugin/qmldir" |
231 | << QStringList() |
232 | << (QStringList() << "foo|" ) |
233 | << QStringList() |
234 | << QStringList() |
235 | << QStringList() |
236 | << false; |
237 | |
238 | QTest::newRow(dataTag: "name-path-plugin" ) |
239 | << "name-path-plugin/qmldir" |
240 | << QStringList() |
241 | << (QStringList() << "foo|bar" ) |
242 | << QStringList() |
243 | << QStringList() |
244 | << QStringList() |
245 | << false; |
246 | |
247 | QTest::newRow(dataTag: "unversioned-component" ) |
248 | << "unversioned-component/qmldir" |
249 | << QStringList() |
250 | << QStringList() |
251 | << (QStringList() << "foo|bar|-1|-1|false" ) |
252 | << QStringList() |
253 | << QStringList() |
254 | << false; |
255 | |
256 | QTest::newRow(dataTag: "invalid-versioned-component" ) |
257 | << "invalid-versioned-component/qmldir" |
258 | << (QStringList() << "qmldir:1: invalid version 100, expected <major>.<minor>" ) |
259 | << QStringList() |
260 | << QStringList() |
261 | << QStringList() |
262 | << QStringList() |
263 | << false; |
264 | |
265 | QTest::newRow(dataTag: "versioned-component" ) |
266 | << "versioned-component/qmldir" |
267 | << QStringList() |
268 | << QStringList() |
269 | << (QStringList() << "foo|bar|33|66|false" ) |
270 | << QStringList() |
271 | << QStringList() |
272 | << false; |
273 | |
274 | QTest::newRow(dataTag: "invalid-versioned-script" ) |
275 | << "invalid-versioned-script/qmldir" |
276 | << (QStringList() << "qmldir:1: invalid version 100, expected <major>.<minor>" ) |
277 | << QStringList() |
278 | << QStringList() |
279 | << QStringList() |
280 | << QStringList() |
281 | << false; |
282 | |
283 | QTest::newRow(dataTag: "versioned-script" ) |
284 | << "versioned-script/qmldir" |
285 | << QStringList() |
286 | << QStringList() |
287 | << QStringList() |
288 | << (QStringList() << "foo|bar.js|33|66" ) |
289 | << QStringList() |
290 | << false; |
291 | |
292 | QTest::newRow(dataTag: "multiple" ) |
293 | << "multiple/qmldir" |
294 | << QStringList() |
295 | << (QStringList() << "PluginA|plugina.so" ) |
296 | << (QStringList() << "ComponentA|componenta-1_0.qml|1|0|false" |
297 | << "ComponentA|componenta-1_5.qml|1|5|false" |
298 | << "ComponentB|componentb-1_5.qml|1|5|false" ) |
299 | << (QStringList() << "ScriptA|scripta-1_0.js|1|0" ) |
300 | << QStringList() |
301 | << false; |
302 | |
303 | QTest::newRow(dataTag: "designersupported-yes" ) |
304 | << "designersupported-yes/qmldir" |
305 | << QStringList() |
306 | << (QStringList() << "foo|" ) |
307 | << QStringList() |
308 | << QStringList() |
309 | << QStringList() |
310 | << true; |
311 | |
312 | QTest::newRow(dataTag: "designersupported-no" ) |
313 | << "designersupported-no/qmldir" |
314 | << QStringList() |
315 | << (QStringList() << "foo|" ) |
316 | << QStringList() |
317 | << QStringList() |
318 | << QStringList() |
319 | << false; |
320 | |
321 | QTest::newRow(dataTag: "invalid-versioned-dependency" ) |
322 | << "invalid-versioned-dependency/qmldir" |
323 | << (QStringList() << "qmldir:1: invalid version 100, expected <major>.<minor>" ) |
324 | << QStringList() |
325 | << QStringList() |
326 | << QStringList() |
327 | << QStringList() |
328 | << false; |
329 | |
330 | QTest::newRow(dataTag: "dependency" ) |
331 | << "dependency/qmldir" |
332 | << QStringList() |
333 | << (QStringList() << "foo|" ) |
334 | << QStringList() |
335 | << QStringList() |
336 | << (QStringList() << "bar||1|0|true" ) |
337 | << false; |
338 | |
339 | QTest::newRow(dataTag: "classname" ) |
340 | << "classname/qmldir" |
341 | << QStringList() |
342 | << (QStringList() << "qtquick2plugin|" ) |
343 | << QStringList() |
344 | << QStringList() |
345 | << QStringList() |
346 | << true; |
347 | } |
348 | |
349 | void tst_qqmldirparser::parse() |
350 | { |
351 | QFETCH(QString, file); |
352 | QFETCH(QStringList, errors); |
353 | QFETCH(QStringList, plugins); |
354 | QFETCH(QStringList, components); |
355 | QFETCH(QStringList, scripts); |
356 | QFETCH(QStringList, dependencies); |
357 | QFETCH(bool, designerSupported); |
358 | |
359 | QFile f(testFile(fileName: file)); |
360 | f.open(flags: QIODevice::ReadOnly); |
361 | |
362 | QQmlDirParser p; |
363 | p.parse(source: f.readAll()); |
364 | |
365 | if (errors.isEmpty()) { |
366 | QCOMPARE(p.hasError(), false); |
367 | } else { |
368 | QCOMPARE(p.hasError(), true); |
369 | QCOMPARE(toStringList(p.errors("qmldir" )), errors); |
370 | } |
371 | |
372 | QCOMPARE(toStringList(p.plugins()), plugins); |
373 | QCOMPARE(toStringList(p.components()), components); |
374 | QCOMPARE(toStringList(p.scripts()), scripts); |
375 | QCOMPARE(toStringList(p.dependencies()), dependencies); |
376 | |
377 | QCOMPARE(p.designerSupported(), designerSupported); |
378 | |
379 | p.clear(); |
380 | QVERIFY(p.typeNamespace().isEmpty()); |
381 | } |
382 | |
383 | QTEST_MAIN(tst_qqmldirparser) |
384 | |
385 | #include "tst_qqmldirparser.moc" |
386 | |