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 module 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 <QtTest/QtTest> |
30 | |
31 | #include <QAbstractMessageHandler> |
32 | #include <QAbstractUriResolver> |
33 | #include <QtNetwork/QNetworkAccessManager> |
34 | #include <QXmlName> |
35 | #include <QXmlSchema> |
36 | #include <QXmlSchemaValidator> |
37 | |
38 | #include "../qabstracturiresolver/TestURIResolver.h" |
39 | #include "../qxmlquery/MessageSilencer.h" |
40 | |
41 | /*! |
42 | \class tst_QXmlSchemaValidatorValidator |
43 | \internal |
44 | \brief Tests class QXmlSchemaValidator. |
45 | |
46 | This test is not intended for testing the engine, but the functionality specific |
47 | to the QXmlSchemaValidator class. |
48 | */ |
49 | class tst_QXmlSchemaValidator : public QObject |
50 | { |
51 | Q_OBJECT |
52 | |
53 | private Q_SLOTS: |
54 | void defaultConstructor() const; |
55 | void constructorQXmlNamePool() const; |
56 | void propertyInitialization() const; |
57 | void resetSchemaNamePool() const; |
58 | |
59 | void loadInstanceUrlSuccess() const; |
60 | void loadInstanceUrlFail() const; |
61 | void loadInstanceDeviceSuccess() const; |
62 | void loadInstanceDeviceFail() const; |
63 | void loadInstanceDataSuccess() const; |
64 | void loadInstanceDataFail() const; |
65 | |
66 | void networkAccessManagerSignature() const; |
67 | void networkAccessManagerDefaultValue() const; |
68 | void networkAccessManager() const; |
69 | |
70 | void messageHandlerSignature() const; |
71 | void messageHandlerDefaultValue() const; |
72 | void messageHandler() const; |
73 | |
74 | void uriResolverSignature() const; |
75 | void uriResolverDefaultValue() const; |
76 | void uriResolver() const; |
77 | |
78 | void unionCrash() const; |
79 | }; |
80 | |
81 | static QXmlSchema createValidSchema() |
82 | { |
83 | const QByteArray data( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" |
84 | "<xsd:schema" |
85 | " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"" |
86 | " xmlns=\"http://www.qt-project.org/xmlschematest\"" |
87 | " targetNamespace=\"http://www.qt-project.org/xmlschematest\"" |
88 | " version=\"1.0\"" |
89 | " elementFormDefault=\"qualified\">" |
90 | " <xsd:element name=\"myRoot\" type=\"xsd:string\"/>" |
91 | "</xsd:schema>" ); |
92 | |
93 | const QUrl documentUri("http://www.qt-project.org/xmlschematest" ); |
94 | |
95 | QXmlSchema schema; |
96 | schema.load(data, documentUri); |
97 | |
98 | return schema; |
99 | } |
100 | |
101 | void tst_QXmlSchemaValidator::defaultConstructor() const |
102 | { |
103 | /* Allocate instance in different orders. */ |
104 | { |
105 | QXmlSchema schema; |
106 | QXmlSchemaValidator validator(schema); |
107 | } |
108 | |
109 | { |
110 | QXmlSchema schema1; |
111 | QXmlSchema schema2; |
112 | |
113 | QXmlSchemaValidator validator1(schema1); |
114 | QXmlSchemaValidator validator2(schema2); |
115 | } |
116 | |
117 | { |
118 | QXmlSchema schema; |
119 | |
120 | QXmlSchemaValidator validator1(schema); |
121 | QXmlSchemaValidator validator2(schema); |
122 | } |
123 | } |
124 | |
125 | void tst_QXmlSchemaValidator::propertyInitialization() const |
126 | { |
127 | /* Verify that properties set in the schema are used as default values for the validator */ |
128 | { |
129 | MessageSilencer handler; |
130 | TestURIResolver resolver; |
131 | QNetworkAccessManager manager; |
132 | |
133 | QXmlSchema schema; |
134 | schema.setMessageHandler(&handler); |
135 | schema.setUriResolver(&resolver); |
136 | schema.setNetworkAccessManager(&manager); |
137 | |
138 | QXmlSchemaValidator validator(schema); |
139 | QCOMPARE(validator.messageHandler(), static_cast<QAbstractMessageHandler *>(&handler)); |
140 | QCOMPARE(validator.uriResolver(), static_cast<const QAbstractUriResolver *>(&resolver)); |
141 | QCOMPARE(validator.networkAccessManager(), &manager); |
142 | } |
143 | } |
144 | |
145 | void tst_QXmlSchemaValidator::constructorQXmlNamePool() const |
146 | { |
147 | // test that the name pool from the schema is used by |
148 | // the schema validator as well |
149 | QXmlSchema schema; |
150 | |
151 | QXmlNamePool np = schema.namePool(); |
152 | |
153 | const QXmlName name(np, QLatin1String("localName" ), |
154 | QLatin1String("http://example.com/" ), |
155 | QLatin1String("prefix" )); |
156 | |
157 | QXmlSchemaValidator validator(schema); |
158 | |
159 | QXmlNamePool np2(validator.namePool()); |
160 | QCOMPARE(name.namespaceUri(np2), QString::fromLatin1("http://example.com/" )); |
161 | QCOMPARE(name.localName(np2), QString::fromLatin1("localName" )); |
162 | QCOMPARE(name.prefix(np2), QString::fromLatin1("prefix" )); |
163 | |
164 | // make sure namePool() is const |
165 | const QXmlSchemaValidator constValidator(schema); |
166 | np = constValidator.namePool(); |
167 | } |
168 | |
169 | void tst_QXmlSchemaValidator::resetSchemaNamePool() const |
170 | { |
171 | QXmlSchema schema1; |
172 | QXmlNamePool np1 = schema1.namePool(); |
173 | |
174 | const QXmlName name1(np1, QLatin1String("localName" ), |
175 | QLatin1String("http://example.com/" ), |
176 | QLatin1String("prefix" )); |
177 | |
178 | QXmlSchemaValidator validator(schema1); |
179 | |
180 | { |
181 | QXmlNamePool compNamePool(validator.namePool()); |
182 | QCOMPARE(name1.namespaceUri(compNamePool), QString::fromLatin1("http://example.com/" )); |
183 | QCOMPARE(name1.localName(compNamePool), QString::fromLatin1("localName" )); |
184 | QCOMPARE(name1.prefix(compNamePool), QString::fromLatin1("prefix" )); |
185 | } |
186 | |
187 | QXmlSchema schema2; |
188 | QXmlNamePool np2 = schema2.namePool(); |
189 | |
190 | const QXmlName name2(np2, QLatin1String("remoteName" ), |
191 | QLatin1String("http://example.com/" ), |
192 | QLatin1String("suffix" )); |
193 | |
194 | // make sure that after re-setting the schema, the new namepool is used |
195 | validator.setSchema(schema2); |
196 | |
197 | { |
198 | QXmlNamePool compNamePool(validator.namePool()); |
199 | QCOMPARE(name2.namespaceUri(compNamePool), QString::fromLatin1("http://example.com/" )); |
200 | QCOMPARE(name2.localName(compNamePool), QString::fromLatin1("remoteName" )); |
201 | QCOMPARE(name2.prefix(compNamePool), QString::fromLatin1("suffix" )); |
202 | } |
203 | } |
204 | |
205 | void tst_QXmlSchemaValidator::loadInstanceUrlSuccess() const |
206 | { |
207 | /* |
208 | TODO: put valid schema file on given url and enable test |
209 | const QXmlSchema schema(createValidSchema()); |
210 | const QUrl url("http://notavailable/"); |
211 | |
212 | QXmlSchemaValidator validator(schema); |
213 | QVERIFY(!validator.validate(url)); |
214 | */ |
215 | } |
216 | |
217 | void tst_QXmlSchemaValidator::loadInstanceUrlFail() const |
218 | { |
219 | const QXmlSchema schema(createValidSchema()); |
220 | const QUrl url("http://notavailable/" ); |
221 | |
222 | QXmlSchemaValidator validator(schema); |
223 | QVERIFY(!validator.validate(url)); |
224 | } |
225 | |
226 | void tst_QXmlSchemaValidator::loadInstanceDeviceSuccess() const |
227 | { |
228 | const QXmlSchema schema(createValidSchema()); |
229 | |
230 | QByteArray data( "<myRoot xmlns=\"http://www.qt-project.org/xmlschematest\">Testme</myRoot>" ); |
231 | QBuffer buffer(&data); |
232 | buffer.open(openMode: QIODevice::ReadOnly); |
233 | |
234 | QXmlSchemaValidator validator(schema); |
235 | QVERIFY(validator.validate(&buffer)); |
236 | } |
237 | |
238 | void tst_QXmlSchemaValidator::loadInstanceDeviceFail() const |
239 | { |
240 | const QXmlSchema schema(createValidSchema()); |
241 | |
242 | QByteArray data( "<myRoot xmlns=\"http://www.qt-project.org/xmlschematest\">Testme</myRoot>" ); |
243 | QBuffer buffer(&data); |
244 | // a closed device can not be loaded |
245 | |
246 | QXmlSchemaValidator validator(schema); |
247 | QVERIFY(!validator.validate(&buffer)); |
248 | } |
249 | |
250 | void tst_QXmlSchemaValidator::loadInstanceDataSuccess() const |
251 | { |
252 | const QXmlSchema schema(createValidSchema()); |
253 | |
254 | const QByteArray data( "<myRoot xmlns=\"http://www.qt-project.org/xmlschematest\">Testme</myRoot>" ); |
255 | |
256 | QXmlSchemaValidator validator(schema); |
257 | QVERIFY(validator.validate(data)); |
258 | } |
259 | |
260 | void tst_QXmlSchemaValidator::loadInstanceDataFail() const |
261 | { |
262 | const QXmlSchema schema(createValidSchema()); |
263 | |
264 | // empty instance can not be loaded |
265 | const QByteArray data; |
266 | |
267 | QXmlSchemaValidator validator(schema); |
268 | QVERIFY(!validator.validate(data)); |
269 | } |
270 | |
271 | void tst_QXmlSchemaValidator::networkAccessManagerSignature() const |
272 | { |
273 | const QXmlSchema schema; |
274 | |
275 | /* Const object. */ |
276 | const QXmlSchemaValidator validator(schema); |
277 | |
278 | /* The function should be const. */ |
279 | validator.networkAccessManager(); |
280 | } |
281 | |
282 | void tst_QXmlSchemaValidator::networkAccessManagerDefaultValue() const |
283 | { |
284 | /* Test that the default value of network access manager is equal to the one from the schema. */ |
285 | { |
286 | const QXmlSchema schema; |
287 | const QXmlSchemaValidator validator(schema); |
288 | QVERIFY(validator.networkAccessManager() == schema.networkAccessManager()); |
289 | } |
290 | |
291 | /* Test that the default value of network access manager is equal to the one from the schema. */ |
292 | { |
293 | QXmlSchema schema; |
294 | |
295 | QNetworkAccessManager manager; |
296 | schema.setNetworkAccessManager(&manager); |
297 | |
298 | const QXmlSchemaValidator validator(schema); |
299 | QVERIFY(validator.networkAccessManager() == schema.networkAccessManager()); |
300 | } |
301 | } |
302 | |
303 | void tst_QXmlSchemaValidator::networkAccessManager() const |
304 | { |
305 | /* Test that we return the network access manager that was set. */ |
306 | { |
307 | QNetworkAccessManager manager; |
308 | |
309 | const QXmlSchema schema; |
310 | QXmlSchemaValidator validator(schema); |
311 | |
312 | validator.setNetworkAccessManager(&manager); |
313 | QCOMPARE(validator.networkAccessManager(), &manager); |
314 | } |
315 | |
316 | /* Test that we return the network access manager that was set, even if the schema changed in between. */ |
317 | { |
318 | QNetworkAccessManager manager; |
319 | |
320 | const QXmlSchema schema; |
321 | QXmlSchemaValidator validator(schema); |
322 | |
323 | validator.setNetworkAccessManager(&manager); |
324 | |
325 | const QXmlSchema schema2; |
326 | validator.setSchema(schema2); |
327 | |
328 | QCOMPARE(validator.networkAccessManager(), &manager); |
329 | } |
330 | } |
331 | |
332 | void tst_QXmlSchemaValidator::messageHandlerSignature() const |
333 | { |
334 | const QXmlSchema schema; |
335 | |
336 | /* Const object. */ |
337 | const QXmlSchemaValidator validator(schema); |
338 | |
339 | /* The function should be const. */ |
340 | validator.messageHandler(); |
341 | } |
342 | |
343 | void tst_QXmlSchemaValidator::messageHandlerDefaultValue() const |
344 | { |
345 | /* Test that the default value of message handler is equal to the one from the schema. */ |
346 | { |
347 | const QXmlSchema schema; |
348 | const QXmlSchemaValidator validator(schema); |
349 | QVERIFY(validator.messageHandler() == schema.messageHandler()); |
350 | } |
351 | |
352 | /* Test that the default value of network access manager is equal to the one from the schema. */ |
353 | { |
354 | QXmlSchema schema; |
355 | |
356 | MessageSilencer handler; |
357 | schema.setMessageHandler(&handler); |
358 | |
359 | const QXmlSchemaValidator validator(schema); |
360 | QVERIFY(validator.messageHandler() == schema.messageHandler()); |
361 | } |
362 | } |
363 | |
364 | void tst_QXmlSchemaValidator::messageHandler() const |
365 | { |
366 | /* Test that we return the message handler that was set. */ |
367 | { |
368 | MessageSilencer handler; |
369 | |
370 | const QXmlSchema schema; |
371 | QXmlSchemaValidator validator(schema); |
372 | |
373 | validator.setMessageHandler(&handler); |
374 | QCOMPARE(validator.messageHandler(), static_cast<QAbstractMessageHandler *>(&handler)); |
375 | } |
376 | |
377 | /* Test that we return the message handler that was set, even if the schema changed in between. */ |
378 | { |
379 | MessageSilencer handler; |
380 | |
381 | const QXmlSchema schema; |
382 | QXmlSchemaValidator validator(schema); |
383 | |
384 | validator.setMessageHandler(&handler); |
385 | |
386 | const QXmlSchema schema2; |
387 | validator.setSchema(schema2); |
388 | |
389 | QCOMPARE(validator.messageHandler(), static_cast<QAbstractMessageHandler *>(&handler)); |
390 | } |
391 | } |
392 | |
393 | void tst_QXmlSchemaValidator::uriResolverSignature() const |
394 | { |
395 | const QXmlSchema schema; |
396 | |
397 | /* Const object. */ |
398 | const QXmlSchemaValidator validator(schema); |
399 | |
400 | /* The function should be const. */ |
401 | validator.uriResolver(); |
402 | |
403 | /* Const object. */ |
404 | const TestURIResolver resolver; |
405 | |
406 | /* This should compile */ |
407 | QXmlSchema schema2; |
408 | schema2.setUriResolver(&resolver); |
409 | } |
410 | |
411 | void tst_QXmlSchemaValidator::uriResolverDefaultValue() const |
412 | { |
413 | /* Test that the default value of uri resolver is equal to the one from the schema. */ |
414 | { |
415 | const QXmlSchema schema; |
416 | const QXmlSchemaValidator validator(schema); |
417 | QVERIFY(validator.uriResolver() == schema.uriResolver()); |
418 | } |
419 | |
420 | /* Test that the default value of uri resolver is equal to the one from the schema. */ |
421 | { |
422 | QXmlSchema schema; |
423 | |
424 | TestURIResolver resolver; |
425 | schema.setUriResolver(&resolver); |
426 | |
427 | const QXmlSchemaValidator validator(schema); |
428 | QVERIFY(validator.uriResolver() == schema.uriResolver()); |
429 | } |
430 | } |
431 | |
432 | void tst_QXmlSchemaValidator::uriResolver() const |
433 | { |
434 | /* Test that we return the uri resolver that was set. */ |
435 | { |
436 | TestURIResolver resolver; |
437 | |
438 | const QXmlSchema schema; |
439 | QXmlSchemaValidator validator(schema); |
440 | |
441 | validator.setUriResolver(&resolver); |
442 | QCOMPARE(validator.uriResolver(), static_cast<const QAbstractUriResolver *>(&resolver)); |
443 | } |
444 | |
445 | /* Test that we return the uri resolver that was set, even if the schema changed in between. */ |
446 | { |
447 | TestURIResolver resolver; |
448 | |
449 | const QXmlSchema schema; |
450 | QXmlSchemaValidator validator(schema); |
451 | |
452 | validator.setUriResolver(&resolver); |
453 | |
454 | const QXmlSchema schema2; |
455 | validator.setSchema(schema2); |
456 | |
457 | QCOMPARE(validator.uriResolver(), static_cast<const QAbstractUriResolver *>(&resolver)); |
458 | } |
459 | } |
460 | |
461 | void tst_QXmlSchemaValidator::unionCrash() const |
462 | { |
463 | // Regression test for QTBUG-77620 (segfault on nullptr dereference). |
464 | const QString path = QFINDTESTDATA("testdata/" ); |
465 | QXmlSchema schema; |
466 | |
467 | const QString filePath = path + QLatin1String("QTBUG-77620.xsd" ); |
468 | |
469 | QFile file(filePath); |
470 | QVERIFY(file.open(QIODevice::ReadOnly)); |
471 | |
472 | schema.load(data: file.readAll(), documentUri: QUrl(filePath)); |
473 | QVERIFY2(schema.isValid(), "Schema should be found valid." ); |
474 | // Validate instance |
475 | QXmlSchemaValidator validator(schema); |
476 | QEXPECT_FAIL("" , "QTBUG-77620: " // Fixed crash, but not underlying problem: |
477 | "the code fails to record the CUSTOM_KEY's primitive type as pattern_type" , Continue); |
478 | QVERIFY2(validator.validate(QUrl(path + QLatin1String("QTBUG-77620.xml" ))), |
479 | "Document should be found valid" ); |
480 | } |
481 | |
482 | QTEST_MAIN(tst_QXmlSchemaValidator) |
483 | |
484 | #include "tst_qxmlschemavalidator.moc" |
485 | |