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 */
49class tst_QXmlSchemaValidator : public QObject
50{
51 Q_OBJECT
52
53private 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
81static 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
101void 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
125void 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
145void 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
169void 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
205void 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
217void 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
226void 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
238void 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
250void 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
260void 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
271void 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
282void 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
303void 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
332void 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
343void 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
364void 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
393void 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
411void 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
432void 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
461void 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
482QTEST_MAIN(tst_QXmlSchemaValidator)
483
484#include "tst_qxmlschemavalidator.moc"
485

source code of qtxmlpatterns/tests/auto/qxmlschemavalidator/tst_qxmlschemavalidator.cpp