Update obsolete contact address.
[profile/ivi/qtxmlpatterns.git] / tests / auto / qabstractxmlnodemodel / tst_qabstractxmlnodemodel.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QFile>
44 #include <QtTest/QtTest>
45
46 #include <QSourceLocation>
47 #include <QXmlFormatter>
48 #include <QXmlNamePool>
49 #include <QXmlQuery>
50 #include <QXmlResultItems>
51 #include <QXmlSerializer>
52 #include <QFileInfo>
53 #include <QDir>
54
55 #include "TestNodeModel.h"
56 #include "LoadingModel.h"
57 #include "../qxmlquery/TestFundament.h"
58
59 /*!
60  \class tst_QAbstractXmlNodeModel
61  \internal
62  \since 4.4
63  \brief Tests the QAbstractXmlNodeModel class.
64  */
65 class tst_QAbstractXmlNodeModel : public QObject
66                                 , private TestFundament
67 {
68     Q_OBJECT
69
70 private Q_SLOTS:
71     // TODO lots of tests missing
72     void initTestCase();
73     void constructor() const;
74     void objectSize() const;
75     void nextFromSimpleAxis();
76     void nextFromSimpleAxis_data() const;
77     void constCorrectness() const;
78     void createData() const;
79     void createPointerAdditionalData() const;
80     void createDataAdditionalData() const;
81     void id() const;
82     void idref() const;
83     void typedValue() const;
84     void sourceLocation() const;
85
86 private:
87     QAbstractXmlNodeModel::Ptr  m_nodeModel;
88     QXmlNamePool                m_namePool;
89     QXmlNodeModelIndex          m_rootNode;
90 };
91
92 const char testFileName[] = "tree.xml";
93
94 void tst_QAbstractXmlNodeModel::initTestCase()
95 {
96     const QString testFilePath = QFINDTESTDATA(testFileName);
97     QVERIFY2(!testFilePath.isEmpty(), "tree.xml not found");
98     const QString testDirectory = QFileInfo(testFilePath).absolutePath();
99     QVERIFY2(QDir::setCurrent(testDirectory), qPrintable(QStringLiteral("Could not chdir to ") + testDirectory));
100
101     m_nodeModel = LoadingModel::create(m_namePool);
102     QVERIFY(m_nodeModel);
103     m_rootNode = m_nodeModel->root(QXmlNodeModelIndex());
104     QVERIFY(!m_rootNode.isNull());
105 }
106
107 void tst_QAbstractXmlNodeModel::constructor() const
108 {
109     /* Allocate instance. */
110     {
111         TestNodeModel instance;
112     }
113
114     {
115         TestNodeModel instance1;
116         TestNodeModel instance2;
117     }
118
119     {
120         TestNodeModel instance1;
121         TestNodeModel instance2;
122         TestNodeModel instance3;
123     }
124 }
125
126 void tst_QAbstractXmlNodeModel::objectSize() const
127 {
128     /* We can't currently test this in portable way,
129      * so disable it. */
130     return;
131
132     const int pointerSize = sizeof(void *);
133     // adjust for pointer alignment
134     const int sharedDataSize = ((sizeof(QSharedData) + pointerSize) / pointerSize) * pointerSize;
135     const int modelSize = sizeof(QAbstractXmlNodeModel);
136
137     /* A d pointer plus a vtable pointer. */
138     QCOMPARE(modelSize, sharedDataSize + pointerSize * 2);
139 }
140
141 /*!
142  Tests nextFromSimpleAxis(). More exactly that all the logic in
143  QAbstractXmlNodeModel::iterate() is as we expect to. Subsequently, a lot
144  of testing code is in LoadingModel(.cpp).
145
146  Approach:
147
148   1. In initTestCase() we loaded tree.xml into LoadingModel and
149      stored the root node in m_rootNode.
150   2. We execute a query that navigates from m_rootNode and write out
151      the result using QXmlFormatter.
152   3. We execute the exact same query, but this time use the built in node backend,
153      and write out the result in the same way. This is our baseline.
154   4. Compare the two.
155
156   Hence we check QAbstractXmlNodeModel::iterate() and friends against our XQuery
157   code, which in turn is (mainly) checked by the XQTS. This means safer testing
158   since we don't create baselines manually, and it also means that we can modify
159   the input file, tree.xml, without having to update static baselines.
160  */
161 void tst_QAbstractXmlNodeModel::nextFromSimpleAxis()
162 {
163     QFETCH(QString, queryString);
164
165     QBuffer out;
166
167     /* Fill out, using LoadingModel. */
168     {
169         QXmlQuery query(m_namePool);
170         query.bindVariable(QLatin1String("node"), m_rootNode);
171         query.setQuery(queryString);
172         QVERIFY(query.isValid());
173
174         QVERIFY(out.open(QIODevice::WriteOnly));
175         QXmlFormatter formatter(query, &out);
176
177         QVERIFY(query.evaluateTo(&formatter));
178     }
179
180     QBuffer baseline;
181
182     /* Create the baseline. */
183     {
184         QXmlQuery openDoc(m_namePool);
185         const QString testFilePath = QDir::currentPath() + QLatin1Char('/') + QLatin1String(testFileName);
186         openDoc.bindVariable(QLatin1String("docURI"), QVariant(testFilePath));
187         openDoc.setQuery(QLatin1String("doc($docURI)"));
188         QXmlResultItems doc;
189         QVERIFY(openDoc.isValid());
190         openDoc.evaluateTo(&doc);
191
192         QXmlQuery produceBaseline(m_namePool);
193         produceBaseline.bindVariable(QLatin1String("node"), doc.next());
194         produceBaseline.setQuery(queryString);
195         QVERIFY(produceBaseline.isValid());
196         QVERIFY(baseline.open(QIODevice::WriteOnly));
197
198         QXmlFormatter baselineFormatter(produceBaseline, &baseline);
199         QVERIFY(produceBaseline.evaluateTo(&baselineFormatter));
200     }
201
202     if(out.data() != baseline.data())
203     {
204         QTextStream(stderr) << "ACTUAL:" << QString::fromUtf8(out.data().constData())
205                             << "EXPECTED:" << QString::fromUtf8(baseline.data().constData());
206     }
207
208     QCOMPARE(out.data(), baseline.data());
209 }
210
211 void tst_QAbstractXmlNodeModel::nextFromSimpleAxis_data() const
212 {
213      QTest::addColumn<QString>("queryString");
214
215      QTest::newRow("The whole tree")
216          << "$node";
217
218      QTest::newRow("::descendant-or-self from $node, all nodes.")
219          << "$node/descendant-or-self::node()";
220
221      QTest::newRow("::descendant from $node, all nodes.")
222          << "$node/descendant::node()";
223
224      QTest::newRow("::descendant from node with no descendants.")
225          << "$node/descendant::node()";
226
227      QTest::newRow("following-sibling on $root.")
228          << "$node/text()[1]/following-sibling::node()";
229
230      QTest::newRow("following-sibling from section1.")
231          << "$node//section1/following-sibling::node()";
232
233      QTest::newRow("preceding-sibling-sibling from section1.")
234          << "$node//section1/preceding-sibling::node()";
235
236      QTest::newRow("following-sibling from oneTextChild.")
237          << "$node//oneTextChild/following-sibling::node()";
238
239      QTest::newRow("preceding-sibling-sibling from oneTextChild.")
240          << "$node//oneTextChild/preceding-sibling::node()";
241
242      QTest::newRow("preceding-sibling on $root.")
243          << "$node/preceding-sibling::node()";
244
245      QTest::newRow("::ancestor from node at the end")
246          << "$node//node()/ancestor::node()";
247
248      QTest::newRow("::ancestor-or-self from node at the end")
249          << "$node//node()/ancestor-or-self::node()";
250
251      QTest::newRow("Copy attributes from all nodes.")
252          << "<e>{for $i in $node//node()/@* order by $i return $i}</e>";
253
254      QTest::newRow("::preceding from node at the end")
255          << "($node//node())[last()]/preceding::node()";
256
257      QTest::newRow("::preceding from $node")
258          << "$node/preceding::node()";
259
260      QTest::newRow("::following from node at the end")
261          << "($node//node())[last()]/following::node()";
262
263      QTest::newRow("::following from $node")
264          << "$node//following::node()";
265
266      QTest::newRow("::following from $node")
267          << "$node/following::node()";
268
269      QTest::newRow("::descendant from text() nodes.")
270          << "$node/descendant-or-self::text()/descendant::node()";
271
272      QTest::newRow("::descendant-or-self from text() nodes.")
273          << "$node/descendant-or-self::text()/descendant-or-self::node()";
274
275      QTest::newRow("descendant-or-self::node() from section1.")
276          << "$node//section1/descendant-or-self::node()";
277
278      QTest::newRow("descendant::node() from section1.")
279          << "$node//section1/descendant::node()";
280
281      /* Checks for axis order. */
282
283      QTest::newRow("::descendant from text() nodes with last(), checking axis order.")
284          << "$node/descendant-or-self::text()/(descendant::node()[last()])";
285
286      QTest::newRow("::descendant-or-self from text() nodes with last(), checking axis order.")
287          << "$node/descendant-or-self::text()/(descendant-or-self::node()[last()])";
288
289      QTest::newRow("::descendant from text() nodes with predicate, checking axis order.")
290          << "$node/descendant-or-self::text()/(descendant::node()[2])";
291
292      QTest::newRow("::descendant-or-self from text() nodes with predicate, checking axis order.")
293          << "$node/descendant-or-self::text()/(descendant-or-self::node()[2])";
294
295      QTest::newRow("::following from node at the end with predicate, checking axis order.")
296          << "($node//node())[last()]/(following::node()[2])";
297
298      QTest::newRow("::following from node at the end with last(), checking axis order.")
299          << "($node//node())[last()]/(following::node()[last()])";
300
301      QTest::newRow("ancestor:: from node at the end with predicate, checking axis order.")
302          << "($node//node())[last()]/(ancestor::node()[2])";
303
304      QTest::newRow("ancestor:: from node at the end with last(), checking axis order.")
305          << "($node//node())[last()]/(ancestor::node()[last()])";
306
307      QTest::newRow("ancestor-or-self:: from node at the end with predicate, checking axis order.")
308          << "($node//node())[last()]/(ancestor::node()[2])";
309
310      QTest::newRow("ancestor-or-self:: from node at the end with last(), checking axis order.")
311          << "($node//node())[last()]/(ancestor::node()[last()])";
312
313      QTest::newRow("::preceding from node at the end with predicate, checking axis order.")
314          << "($node//node())[last()]/(preceding::node()[2])";
315
316      QTest::newRow("descendant-or-self in two levels, with last()")
317          << "$node/descendant-or-self::text()/(descendant-or-self::node()[last()])";
318
319      QTest::newRow("descendant-or-self with last()")
320          << "$node/descendant-or-self::node()[last()]";
321
322      QTest::newRow("::preceding from node at the end with last(), checking axis order.")
323          << "$node/preceding::node()[last()]";
324
325      QTest::newRow("::preceding combined with descendant-or-self, from node at the end with last(), checking axis order.")
326          << "$node//preceding::node()[last()]";
327
328      QTest::newRow("::preceding combined with descendant-or-self, from node at the end with last(), checking axis order.")
329          << "($node//node())[last()]/(preceding::node()[last()])";
330 }
331
332 void tst_QAbstractXmlNodeModel::constCorrectness() const
333 {
334     // TODO
335 }
336
337 void tst_QAbstractXmlNodeModel::createData() const
338 {
339     // TODO
340     // Verify that the argument is qint64
341 }
342
343 void tst_QAbstractXmlNodeModel::createPointerAdditionalData() const
344 {
345     // TODO
346     // Verify that the second argument is qint64
347 }
348
349 void tst_QAbstractXmlNodeModel::createDataAdditionalData() const
350 {
351     // TODO
352 }
353
354 void tst_QAbstractXmlNodeModel::id() const
355 {
356     // TODO verify that invalid NCNames are not sent to the model.
357 }
358
359 void tst_QAbstractXmlNodeModel::idref() const
360 {
361     // TODO verify that invalid NCNames are not sent to the model.
362 }
363
364 /*!
365  Verify that if QAbstractXmlNodeModel::typedValue() return a null
366  QVariant, it is treated as that the node has no typed value.
367  */
368 void tst_QAbstractXmlNodeModel::typedValue() const
369 {
370     class TypedModel : public TestNodeModel
371     {
372     public:
373         virtual QVariant typedValue(const QXmlNodeModelIndex &) const
374         {
375             return QVariant();
376         }
377
378         QXmlNodeModelIndex root() const
379         {
380             return createIndex(qint64(1));
381         }
382     };
383
384     TypedModel model;
385
386     QXmlQuery query;
387     query.bindVariable(QLatin1String("node"), model.root());
388     query.setQuery(QLatin1String("declare variable $node external;"
389                                  "string($node), data($node)"));
390
391     QByteArray output;
392     QBuffer buffer(&output);
393     QVERIFY(buffer.open(QIODevice::WriteOnly));
394     QVERIFY(query.isValid());
395
396     QXmlSerializer serializer(query, &buffer);
397     QVERIFY(query.evaluateTo(&serializer));
398
399     QVERIFY(output.isEmpty());
400 }
401
402 void tst_QAbstractXmlNodeModel::sourceLocation() const
403 {
404     const QAbstractXmlNodeModel* const constModel = m_nodeModel.data();
405     const QSourceLocation location = constModel->sourceLocation(m_rootNode);
406 }
407
408 QTEST_MAIN(tst_QAbstractXmlNodeModel)
409
410 #include "tst_qabstractxmlnodemodel.moc"
411
412 // vim: et:ts=4:sw=4:sts=4