1/****************************************************************************
2**
3** Copyright (C) 2016 Intel Corporation.
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 <QtCore/QUrlQuery>
30#include <QtTest/QtTest>
31
32typedef QList<QPair<QString, QString> > QueryItems;
33Q_DECLARE_METATYPE(QueryItems)
34Q_DECLARE_METATYPE(QUrl::ComponentFormattingOptions)
35
36class tst_QUrlQuery : public QObject
37{
38 Q_OBJECT
39
40public:
41 tst_QUrlQuery()
42 {
43 qRegisterMetaType<QueryItems>();
44 }
45
46private Q_SLOTS:
47 void constructing();
48 void addRemove();
49 void multiAddRemove();
50 void multiplyAddSamePair();
51 void setQueryItems_data();
52 void setQueryItems();
53 void basicParsing_data();
54 void basicParsing();
55 void reconstructQuery_data();
56 void reconstructQuery();
57 void encodedSetQueryItems_data();
58 void encodedSetQueryItems();
59 void encodedParsing_data();
60 void encodedParsing();
61 void differentDelimiters();
62
63 // old tests from tst_qurl.cpp
64 // add new tests above
65 void old_queryItems();
66 void old_hasQueryItem_data();
67 void old_hasQueryItem();
68};
69
70static QString prettyElement(const QString &key, const QString &value)
71{
72 QString result;
73 if (key.isNull())
74 result += "null -> ";
75 else
76 result += '"' % key % "\" -> ";
77 if (value.isNull())
78 result += "null";
79 else
80 result += '"' % value % '"';
81 return result;
82}
83
84static QString prettyPair(QList<QPair<QString, QString> >::const_iterator it)
85{
86 return prettyElement(key: it->first, value: it->second);
87}
88
89template <typename T>
90static QByteArray prettyList(const T &items)
91{
92 QString result = "(";
93 bool first = true;
94 typename T::const_iterator it = items.constBegin();
95 for ( ; it != items.constEnd(); ++it) {
96 if (!first)
97 result += ", ";
98 first = false;
99 result += prettyPair(it);
100 }
101 result += QLatin1Char(')');
102 return result.toLocal8Bit();
103}
104
105static bool compare(const QList<QPair<QString, QString> > &actual, const QueryItems &expected,
106 const char *actualStr, const char *expectedStr, const char *file, int line)
107{
108 return QTest::compare_helper(success: actual == expected, failureMsg: "Compared values are not the same",
109 val1: qstrdup(prettyList(items: actual)), val2: qstrdup(prettyList(items: expected).data()),
110 actual: actualStr, expected: expectedStr, file, line);
111}
112
113#define COMPARE_ITEMS(actual, expected) \
114 do { \
115 if (!compare(actual, expected, #actual, #expected, __FILE__, __LINE__)) \
116 return; \
117 } while (0)
118
119inline QueryItems operator+(QueryItems items, const QPair<QString, QString> &pair)
120{
121 // items is already a copy
122 items.append(t: pair);
123 return items;
124}
125
126inline QueryItems operator+(const QPair<QString, QString> &pair, QueryItems items)
127{
128 // items is already a copy
129 items.prepend(t: pair);
130 return items;
131}
132
133inline QPair<QString, QString> qItem(const QString &first, const QString &second)
134{
135 return qMakePair(x: first, y: second);
136}
137
138inline QPair<QString, QString> qItem(const char *first, const QString &second)
139{
140 return qMakePair(x: QString::fromUtf8(str: first), y: second);
141}
142
143inline QPair<QString, QString> qItem(const char *first, const char *second)
144{
145 return qMakePair(x: QString::fromUtf8(str: first), y: QString::fromUtf8(str: second));
146}
147
148inline QPair<QString, QString> qItem(const QString &first, const char *second)
149{
150 return qMakePair(x: first, y: QString::fromUtf8(str: second));
151}
152
153static QUrlQuery emptyQuery()
154{
155 return QUrlQuery();
156}
157
158void tst_QUrlQuery::constructing()
159{
160 QUrlQuery empty;
161 QVERIFY(empty.isEmpty());
162 QCOMPARE(empty.queryPairDelimiter(), QUrlQuery::defaultQueryPairDelimiter());
163 QCOMPARE(empty.queryValueDelimiter(), QUrlQuery::defaultQueryValueDelimiter());
164 // undefined whether it is detached, but don't crash
165 QVERIFY(empty.isDetached() || !empty.isDetached());
166
167 empty.clear();
168 QVERIFY(empty.isEmpty());
169
170 {
171 QUrlQuery copy(empty);
172 QVERIFY(copy.isEmpty());
173 QVERIFY(!copy.isDetached());
174 QCOMPARE(copy, empty);
175 QCOMPARE(qHash(copy), qHash(empty));
176 QVERIFY(!(copy != empty));
177
178 copy = empty;
179 QCOMPARE(copy, empty);
180
181 copy = QUrlQuery();
182 QCOMPARE(copy, empty);
183 QCOMPARE(qHash(copy), qHash(empty));
184 }
185 {
186 QUrlQuery copy(emptyQuery());
187 QCOMPARE(copy, empty);
188 }
189
190 QVERIFY(!empty.hasQueryItem("a"));
191 QVERIFY(empty.queryItemValue("a").isEmpty());
192 QVERIFY(empty.allQueryItemValues("a").isEmpty());
193
194 QVERIFY(!empty.hasQueryItem(""));
195 QVERIFY(empty.queryItemValue("").isEmpty());
196 QVERIFY(empty.allQueryItemValues("").isEmpty());
197
198 QVERIFY(!empty.hasQueryItem(QString()));
199 QVERIFY(empty.queryItemValue(QString()).isEmpty());
200 QVERIFY(empty.allQueryItemValues(QString()).isEmpty());
201
202 QVERIFY(empty.queryItems().isEmpty());
203
204 QUrlQuery other;
205 other.addQueryItem(key: "a", value: "b");
206 QVERIFY(!other.isEmpty());
207 QVERIFY(other.isDetached());
208 QVERIFY(other != empty);
209 QVERIFY(!(other == empty));
210
211 QUrlQuery copy(other);
212 QCOMPARE(copy, other);
213
214 copy.clear();
215 QVERIFY(copy.isEmpty());
216 QVERIFY(copy != other);
217
218 copy = other;
219 QVERIFY(!copy.isEmpty());
220 QCOMPARE(copy, other);
221
222 copy = QUrlQuery();
223 QVERIFY(copy.isEmpty());
224
225 empty.setQueryDelimiters(valueDelimiter: '(', pairDelimiter: ')');
226 QCOMPARE(empty.queryValueDelimiter(), QChar(QLatin1Char('(')));
227 QCOMPARE(empty.queryPairDelimiter(), QChar(QLatin1Char(')')));
228
229 QList<QPair<QString, QString> > query;
230 query += qMakePair(x: QString("type"), y: QString("login"));
231 query += qMakePair(x: QString("name"), y: QString::fromUtf8(str: "Ã¥ge nissemannsen"));
232 query += qMakePair(x: QString("ole&du"), y: QString::fromUtf8(str: "anne+jørgen=sant"));
233 query += qMakePair(x: QString("prosent"), y: QString("%"));
234 copy.setQueryItems(query);
235 QVERIFY(!copy.isEmpty());
236
237 QUrlQuery fromList = {
238 {QString("type"), QString("login")},
239 {QString("name"), QString::fromUtf8(str: "Ã¥ge nissemannsen")},
240 {QString("ole&du"), QString::fromUtf8(str: "anne+jørgen=sant")},
241 {QString("prosent"), QString("%")}
242 };
243 QCOMPARE(fromList, copy);
244}
245
246void tst_QUrlQuery::addRemove()
247{
248 QUrlQuery query;
249
250 {
251 // one item
252 query.addQueryItem(key: "a", value: "b");
253 QVERIFY(!query.isEmpty());
254 QVERIFY(query.hasQueryItem("a"));
255 QCOMPARE(query.queryItemValue("a"), QString("b"));
256 QCOMPARE(query.allQueryItemValues("a"), QStringList() << "b");
257
258 QList<QPair<QString, QString> > allItems = query.queryItems();
259 QCOMPARE(allItems.count(), 1);
260 QCOMPARE(allItems.at(0).first, QString("a"));
261 QCOMPARE(allItems.at(0).second, QString("b"));
262 }
263
264 QUrlQuery original = query;
265
266 {
267 // two items
268 query.addQueryItem(key: "c", value: "d");
269 QVERIFY(query.hasQueryItem("a"));
270 QCOMPARE(query.queryItemValue("a"), QString("b"));
271 QCOMPARE(query.allQueryItemValues("a"), QStringList() << "b");
272 QVERIFY(query.hasQueryItem("c"));
273 QCOMPARE(query.queryItemValue("c"), QString("d"));
274 QCOMPARE(query.allQueryItemValues("c"), QStringList() << "d");
275
276 QList<QPair<QString, QString> > allItems = query.queryItems();
277 QCOMPARE(allItems.count(), 2);
278 QVERIFY(allItems.contains(qItem("a", "b")));
279 QVERIFY(allItems.contains(qItem("c", "d")));
280
281 QVERIFY(query != original);
282 QVERIFY(!(query == original));
283 }
284
285 {
286 // remove an item that isn't there
287 QUrlQuery copy = query;
288 query.removeQueryItem(key: "e");
289 QCOMPARE(query, copy);
290 }
291
292 {
293 // remove an item
294 query.removeQueryItem(key: "c");
295 QVERIFY(query.hasQueryItem("a"));
296 QCOMPARE(query.queryItemValue("a"), QString("b"));
297 QCOMPARE(query.allQueryItemValues("a"), QStringList() << "b");
298
299 QList<QPair<QString, QString> > allItems = query.queryItems();
300 QCOMPARE(allItems.count(), 1);
301 QCOMPARE(allItems.at(0).first, QString("a"));
302 QCOMPARE(allItems.at(0).second, QString("b"));
303
304 QCOMPARE(query, original);
305 QVERIFY(!(query != original));
306 QCOMPARE(qHash(query), qHash(original));
307 }
308
309 {
310 // add an item with en empty value
311 QString emptyButNotNull(0, Qt::Uninitialized);
312 QVERIFY(emptyButNotNull.isEmpty());
313 QVERIFY(!emptyButNotNull.isNull());
314
315 query.addQueryItem(key: "e", value: "");
316 QVERIFY(query.hasQueryItem("a"));
317 QCOMPARE(query.queryItemValue("a"), QString("b"));
318 QCOMPARE(query.allQueryItemValues("a"), QStringList() << "b");
319 QVERIFY(query.hasQueryItem("e"));
320 QCOMPARE(query.queryItemValue("e"), emptyButNotNull);
321 QCOMPARE(query.allQueryItemValues("e"), QStringList() << emptyButNotNull);
322
323 QList<QPair<QString, QString> > allItems = query.queryItems();
324 QCOMPARE(allItems.count(), 2);
325 QVERIFY(allItems.contains(qItem("a", "b")));
326 QVERIFY(allItems.contains(qItem("e", emptyButNotNull)));
327
328 QVERIFY(query != original);
329 QVERIFY(!(query == original));
330 }
331
332 {
333 // remove the items
334 query.removeQueryItem(key: "a");
335 query.removeQueryItem(key: "e");
336 QVERIFY(query.isEmpty());
337 }
338}
339
340void tst_QUrlQuery::multiAddRemove()
341{
342 QUrlQuery query;
343
344 {
345 // one item, two values
346 query.addQueryItem(key: "a", value: "b");
347 query.addQueryItem(key: "a", value: "c");
348 QVERIFY(!query.isEmpty());
349 QVERIFY(query.hasQueryItem("a"));
350
351 // returns the first one
352 QCOMPARE(query.queryItemValue("a"), QLatin1String("b"));
353
354 // order is the order we set them in
355 QVERIFY(query.allQueryItemValues("a") == QStringList() << "b" << "c");
356 }
357
358 {
359 // add another item, two values
360 query.addQueryItem(key: "A", value: "B");
361 query.addQueryItem(key: "A", value: "C");
362 QVERIFY(query.hasQueryItem("A"));
363 QVERIFY(query.hasQueryItem("a"));
364
365 QCOMPARE(query.queryItemValue("a"), QLatin1String("b"));
366 QVERIFY(query.allQueryItemValues("a") == QStringList() << "b" << "c");
367 QCOMPARE(query.queryItemValue("A"), QLatin1String("B"));
368 QVERIFY(query.allQueryItemValues("A") == QStringList() << "B" << "C");
369 }
370
371 {
372 // remove one of the original items
373 query.removeQueryItem(key: "a");
374 QVERIFY(query.hasQueryItem("a"));
375
376 // it must have removed the first one
377 QCOMPARE(query.queryItemValue("a"), QLatin1String("c"));
378 }
379
380 {
381 // remove the items we added later
382 query.removeAllQueryItems(key: "A");
383 QVERIFY(!query.isEmpty());
384 QVERIFY(!query.hasQueryItem("A"));
385 }
386
387 {
388 // add one element to the current, then remove them
389 query.addQueryItem(key: "a", value: "d");
390 query.removeAllQueryItems(key: "a");
391 QVERIFY(!query.hasQueryItem("a"));
392 QVERIFY(query.isEmpty());
393 }
394}
395
396void tst_QUrlQuery::multiplyAddSamePair()
397{
398 QUrlQuery query;
399 query.addQueryItem(key: "a", value: "a");
400 query.addQueryItem(key: "a", value: "a");
401 QCOMPARE(query.allQueryItemValues("a"), QStringList() << "a" << "a");
402
403 query.addQueryItem(key: "a", value: "a");
404 QCOMPARE(query.allQueryItemValues("a"), QStringList() << "a" << "a" << "a");
405
406 query.removeQueryItem(key: "a");
407 QCOMPARE(query.allQueryItemValues("a"), QStringList() << "a" << "a");
408}
409
410void tst_QUrlQuery::setQueryItems_data()
411{
412 QTest::addColumn<QueryItems>(name: "items");
413 QString emptyButNotNull(0, Qt::Uninitialized);
414
415 QTest::newRow(dataTag: "empty") << QueryItems();
416 QTest::newRow(dataTag: "1-novalue") << (QueryItems() << qItem(first: "a", second: QString()));
417 QTest::newRow(dataTag: "1-emptyvalue") << (QueryItems() << qItem(first: "a", second: emptyButNotNull));
418
419 QueryItems list;
420 list << qItem(first: "a", second: "b");
421 QTest::newRow(dataTag: "1-value") << list;
422 QTest::newRow(dataTag: "1-multi") << (list + qItem(first: "a", second: "c"));
423 QTest::newRow(dataTag: "1-duplicated") << (list + qItem(first: "a", second: "b"));
424
425 list << qItem(first: "c", second: "d");
426 QTest::newRow(dataTag: "2") << list;
427
428 list << qItem(first: "c", second: "e");
429 QTest::newRow(dataTag: "2-multi") << list;
430}
431
432void tst_QUrlQuery::setQueryItems()
433{
434 QFETCH(QueryItems, items);
435 QUrlQuery query;
436
437 QueryItems::const_iterator it = items.constBegin();
438 for ( ; it != items.constEnd(); ++it)
439 query.addQueryItem(key: it->first, value: it->second);
440 COMPARE_ITEMS(query.queryItems(), items);
441
442 query.clear();
443
444 query.setQueryItems(items);
445 COMPARE_ITEMS(query.queryItems(), items);
446}
447
448void tst_QUrlQuery::basicParsing_data()
449{
450 QTest::addColumn<QString>(name: "queryString");
451 QTest::addColumn<QueryItems>(name: "items");
452 QString emptyButNotNull(0, Qt::Uninitialized);
453
454 QTest::newRow(dataTag: "null") << QString() << QueryItems();
455 QTest::newRow(dataTag: "empty") << "" << QueryItems();
456
457 QTest::newRow(dataTag: "1-novalue") << "a" << (QueryItems() << qItem(first: "a", second: QString()));
458 QTest::newRow(dataTag: "1-emptyvalue") << "a=" << (QueryItems() << qItem(first: "a", second: emptyButNotNull));
459 QTest::newRow(dataTag: "1-value") << "a=b" << (QueryItems() << qItem(first: "a", second: "b"));
460
461 // some longer keys
462 QTest::newRow(dataTag: "1-longkey-novalue") << "thisisalongkey" << (QueryItems() << qItem(first: "thisisalongkey", second: QString()));
463 QTest::newRow(dataTag: "1-longkey-emptyvalue") << "thisisalongkey=" << (QueryItems() << qItem(first: "thisisalongkey", second: emptyButNotNull));
464 QTest::newRow(dataTag: "1-longkey-value") << "thisisalongkey=b" << (QueryItems() << qItem(first: "thisisalongkey", second: "b"));
465
466 // longer values
467 QTest::newRow(dataTag: "1-longvalue-value") << "a=thisisalongreasonablyvalue"
468 << (QueryItems() << qItem(first: "a", second: "thisisalongreasonablyvalue"));
469 QTest::newRow(dataTag: "1-longboth-value") << "thisisalongkey=thisisalongreasonablyvalue"
470 << (QueryItems() << qItem(first: "thisisalongkey", second: "thisisalongreasonablyvalue"));
471
472 // two or more entries
473 QueryItems baselist;
474 baselist << qItem(first: "a", second: "b") << qItem(first: "c", second: "d");
475 QTest::newRow(dataTag: "2-ab-cd") << "a=b&c=d" << baselist;
476 QTest::newRow(dataTag: "2-cd-ab") << "c=d&a=b" << (QueryItems() << qItem(first: "c", second: "d") << qItem(first: "a", second: "b"));
477
478 // the same entry multiply defined
479 QTest::newRow(dataTag: "2-a-a") << "a&a" << (QueryItems() << qItem(first: "a", second: QString()) << qItem(first: "a", second: QString()));
480 QTest::newRow(dataTag: "2-ab-a") << "a=b&a" << (QueryItems() << qItem(first: "a", second: "b") << qItem(first: "a", second: QString()));
481 QTest::newRow(dataTag: "2-ab-ab") << "a=b&a=b" << (QueryItems() << qItem(first: "a", second: "b") << qItem(first: "a", second: "b"));
482 QTest::newRow(dataTag: "2-ab-ac") << "a=b&a=c" << (QueryItems() << qItem(first: "a", second: "b") << qItem(first: "a", second: "c"));
483
484 QPair<QString, QString> novalue = qItem(first: "somekey", second: QString());
485 QueryItems list2 = baselist + novalue;
486 QTest::newRow(dataTag: "3-novalue-ab-cd") << "somekey&a=b&c=d" << (novalue + baselist);
487 QTest::newRow(dataTag: "3-ab-novalue-cd") << "a=b&somekey&c=d" << (QueryItems() << qItem(first: "a", second: "b") << novalue << qItem(first: "c", second: "d"));
488 QTest::newRow(dataTag: "3-ab-cd-novalue") << "a=b&c=d&somekey" << list2;
489
490 list2 << qItem(first: "otherkeynovalue", second: QString());
491 QTest::newRow(dataTag: "4-ab-cd-novalue-novalue") << "a=b&c=d&somekey&otherkeynovalue" << list2;
492
493 QPair<QString, QString> emptyvalue = qItem(first: "somekey", second: emptyButNotNull);
494 list2 = baselist + emptyvalue;
495 QTest::newRow(dataTag: "3-emptyvalue-ab-cd") << "somekey=&a=b&c=d" << (emptyvalue + baselist);
496 QTest::newRow(dataTag: "3-ab-emptyvalue-cd") << "a=b&somekey=&c=d" << (QueryItems() << qItem(first: "a", second: "b") << emptyvalue << qItem(first: "c", second: "d"));
497 QTest::newRow(dataTag: "3-ab-cd-emptyvalue") << "a=b&c=d&somekey=" << list2;
498}
499
500void tst_QUrlQuery::basicParsing()
501{
502 QFETCH(QString, queryString);
503 QFETCH(QueryItems, items);
504
505 QUrlQuery query(queryString);
506 QCOMPARE(query.isEmpty(), items.isEmpty());
507 COMPARE_ITEMS(query.queryItems(), items);
508}
509
510void tst_QUrlQuery::reconstructQuery_data()
511{
512 QTest::addColumn<QString>(name: "queryString");
513 QTest::addColumn<QueryItems>(name: "items");
514 QString emptyButNotNull(0, Qt::Uninitialized);
515
516 QTest::newRow(dataTag: "null") << QString() << QueryItems();
517 QTest::newRow(dataTag: "empty") << "" << QueryItems();
518
519 QTest::newRow(dataTag: "1-novalue") << "a" << (QueryItems() << qItem(first: "a", second: QString()));
520 QTest::newRow(dataTag: "1-emptyvalue") << "a=" << (QueryItems() << qItem(first: "a", second: emptyButNotNull));
521 QTest::newRow(dataTag: "1-value") << "a=b" << (QueryItems() << qItem(first: "a", second: "b"));
522
523 // some longer keys
524 QTest::newRow(dataTag: "1-longkey-novalue") << "thisisalongkey" << (QueryItems() << qItem(first: "thisisalongkey", second: QString()));
525 QTest::newRow(dataTag: "1-longkey-emptyvalue") << "thisisalongkey=" << (QueryItems() << qItem(first: "thisisalongkey", second: emptyButNotNull));
526 QTest::newRow(dataTag: "1-longkey-value") << "thisisalongkey=b" << (QueryItems() << qItem(first: "thisisalongkey", second: "b"));
527
528 // longer values
529 QTest::newRow(dataTag: "1-longvalue-value") << "a=thisisalongreasonablyvalue"
530 << (QueryItems() << qItem(first: "a", second: "thisisalongreasonablyvalue"));
531 QTest::newRow(dataTag: "1-longboth-value") << "thisisalongkey=thisisalongreasonablyvalue"
532 << (QueryItems() << qItem(first: "thisisalongkey", second: "thisisalongreasonablyvalue"));
533
534 // two or more entries
535 QueryItems baselist;
536 baselist << qItem(first: "a", second: "b") << qItem(first: "c", second: "d");
537 QTest::newRow(dataTag: "2-ab-cd") << "a=b&c=d" << baselist;
538
539 // the same entry multiply defined
540 QTest::newRow(dataTag: "2-a-a") << "a&a" << (QueryItems() << qItem(first: "a", second: QString()) << qItem(first: "a", second: QString()));
541 QTest::newRow(dataTag: "2-ab-ab") << "a=b&a=b" << (QueryItems() << qItem(first: "a", second: "b") << qItem(first: "a", second: "b"));
542 QTest::newRow(dataTag: "2-ab-ac") << "a=b&a=c" << (QueryItems() << qItem(first: "a", second: "b") << qItem(first: "a", second: "c"));
543 QTest::newRow(dataTag: "2-ac-ab") << "a=c&a=b" << (QueryItems() << qItem(first: "a", second: "c") << qItem(first: "a", second: "b"));
544 QTest::newRow(dataTag: "2-ab-cd") << "a=b&c=d" << (QueryItems() << qItem(first: "a", second: "b") << qItem(first: "c", second: "d"));
545 QTest::newRow(dataTag: "2-cd-ab") << "c=d&a=b" << (QueryItems() << qItem(first: "c", second: "d") << qItem(first: "a", second: "b"));
546
547 QueryItems list2 = baselist + qItem(first: "somekey", second: QString());
548 QTest::newRow(dataTag: "3-ab-cd-novalue") << "a=b&c=d&somekey" << list2;
549
550 list2 << qItem(first: "otherkeynovalue", second: QString());
551 QTest::newRow(dataTag: "4-ab-cd-novalue-novalue") << "a=b&c=d&somekey&otherkeynovalue" << list2;
552
553 list2 = baselist + qItem(first: "somekey", second: emptyButNotNull);
554 QTest::newRow(dataTag: "3-ab-cd-emptyvalue") << "a=b&c=d&somekey=" << list2;
555}
556
557void tst_QUrlQuery::reconstructQuery()
558{
559 QFETCH(QString, queryString);
560 QFETCH(QueryItems, items);
561
562 QUrlQuery query;
563
564 // add the items
565 for (QueryItems::ConstIterator it = items.constBegin(); it != items.constEnd(); ++it) {
566 query.addQueryItem(key: it->first, value: it->second);
567 }
568 QCOMPARE(query.query(), queryString);
569}
570
571void tst_QUrlQuery::encodedSetQueryItems_data()
572{
573 QTest::addColumn<QString>(name: "queryString");
574 QTest::addColumn<QString>(name: "key");
575 QTest::addColumn<QString>(name: "value");
576 QTest::addColumn<QUrl::ComponentFormattingOptions>(name: "encoding");
577 QTest::addColumn<QString>(name: "expectedQuery");
578 QTest::addColumn<QString>(name: "expectedKey");
579 QTest::addColumn<QString>(name: "expectedValue");
580 typedef QUrl::ComponentFormattingOptions F;
581
582 QTest::newRow(dataTag: "nul") << "f%00=bar%00" << "f%00" << "bar%00" << F(QUrl::PrettyDecoded)
583 << "f%00=bar%00" << "f%00" << "bar%00";
584 QTest::newRow(dataTag: "non-decodable-1") << "foo%01%7f=b%1ar" << "foo%01%7f" << "b%1ar" << F(QUrl::PrettyDecoded)
585 << "foo%01%7F=b%1Ar" << "foo%01%7F" << "b%1Ar";
586 QTest::newRow(dataTag: "non-decodable-2") << "foo\x01\x7f=b\x1ar" << "foo\x01\x7f" << "b\x1Ar" << F(QUrl::PrettyDecoded)
587 << "foo%01%7F=b%1Ar" << "foo%01%7F" << "b%1Ar";
588
589 QTest::newRow(dataTag: "space") << "%20=%20" << "%20" << "%20" << F(QUrl::PrettyDecoded)
590 << " = " << " " << " ";
591 QTest::newRow(dataTag: "encode-space") << " = " << " " << " " << F(QUrl::FullyEncoded)
592 << "%20=%20" << "%20" << "%20";
593
594 // tri-state
595 QTest::newRow(dataTag: "decode-non-delimiters") << "%3C%5C%3E=%7B%7C%7D%5E%60" << "%3C%5C%3E" << "%7B%7C%7D%5E%60" << F(QUrl::DecodeReserved)
596 << "<\\>={|}^`" << "<\\>" << "{|}^`";
597 QTest::newRow(dataTag: "encode-non-delimiters") << "<\\>={|}^`" << "<\\>" << "{|}^`" << F(QUrl::EncodeReserved)
598 << "%3C%5C%3E=%7B%7C%7D%5E%60" << "%3C%5C%3E" << "%7B%7C%7D%5E%60";
599 QTest::newRow(dataTag: "pretty-non-delimiters") << "<\\>={|}^`" << "<\\>" << "{|}^`" << F(QUrl::PrettyDecoded)
600 << "%3C%5C%3E=%7B%7C%7D%5E%60" << "<\\>" << "{|}^`";
601
602 QTest::newRow(dataTag: "equals") << "%3D=%3D" << "%3D" << "%3D" << F(QUrl::PrettyDecoded)
603 << "%3D=%3D" << "=" << "=";
604 QTest::newRow(dataTag: "equals-2") << "%3D==" << "=" << "=" << F(QUrl::PrettyDecoded)
605 << "%3D=%3D" << "=" << "=";
606 QTest::newRow(dataTag: "ampersand") << "%26=%26" << "%26" << "%26" << F(QUrl::PrettyDecoded)
607 << "%26=%26" << "&" << "&";
608 QTest::newRow(dataTag: "hash") << "#=#" << "%23" << "%23" << F(QUrl::PrettyDecoded)
609 << "#=#" << "#" << "#";
610 QTest::newRow(dataTag: "decode-hash") << "%23=%23" << "%23" << "%23" << F(QUrl::PrettyDecoded)
611 << "#=#" << "#" << "#";
612
613 QTest::newRow(dataTag: "percent") << "%25=%25" << "%25" << "%25" << F(QUrl::PrettyDecoded)
614 << "%25=%25" << "%25" << "%25";
615 QTest::newRow(dataTag: "bad-percent-1") << "%=%" << "%" << "%" << F(QUrl::PrettyDecoded)
616 << "%25=%25" << "%25" << "%25";
617 QTest::newRow(dataTag: "bad-percent-2") << "%2=%2" << "%2" << "%2" << F(QUrl::PrettyDecoded)
618 << "%252=%252" << "%252" << "%252";
619
620 QTest::newRow(dataTag: "plus") << "+=+" << "+" << "+" << F(QUrl::PrettyDecoded)
621 << "+=+" << "+" << "+";
622 QTest::newRow(dataTag: "2b") << "%2b=%2b" << "%2b" << "%2b" << F(QUrl::PrettyDecoded)
623 << "%2B=%2B" << "%2B" << "%2B";
624 // plus signs must not be touched
625 QTest::newRow(dataTag: "encode-plus") << "+=+" << "+" << "+" << F(QUrl::FullyEncoded)
626 << "+=+" << "+" << "+";
627 QTest::newRow(dataTag: "decode-2b") << "%2b=%2b" << "%2b" << "%2b" << F(QUrl::PrettyDecoded)
628 << "%2B=%2B" << "%2B" << "%2B";
629
630
631 QTest::newRow(dataTag: "unicode") << "q=R%C3%a9sum%c3%A9" << "q" << "R%C3%a9sum%c3%A9" << F(QUrl::PrettyDecoded)
632 << QString::fromUtf8(str: "q=R\xc3\xa9sum\xc3\xa9") << "q" << QString::fromUtf8(str: "R\xc3\xa9sum\xc3\xa9");
633 QTest::newRow(dataTag: "encode-unicode") << QString::fromUtf8(str: "q=R\xc3\xa9sum\xc3\xa9") << "q" << QString::fromUtf8(str: "R\xc3\xa9sum\xc3\xa9")
634 << F(QUrl::FullyEncoded)
635 << "q=R%C3%A9sum%C3%A9" << "q" << "R%C3%A9sum%C3%A9";
636}
637
638void tst_QUrlQuery::encodedSetQueryItems()
639{
640 QFETCH(QString, key);
641 QFETCH(QString, value);
642 QFETCH(QString, expectedQuery);
643 QFETCH(QString, expectedKey);
644 QFETCH(QString, expectedValue);
645 QFETCH(QUrl::ComponentFormattingOptions, encoding);
646 QUrlQuery query;
647
648 query.addQueryItem(key, value);
649 COMPARE_ITEMS(query.queryItems(encoding), QueryItems() << qItem(expectedKey, expectedValue));
650 QCOMPARE(query.query(encoding), expectedQuery);
651}
652
653void tst_QUrlQuery::encodedParsing_data()
654{
655 encodedSetQueryItems_data();
656}
657
658void tst_QUrlQuery::encodedParsing()
659{
660 QFETCH(QString, queryString);
661 QFETCH(QString, expectedQuery);
662 QFETCH(QString, expectedKey);
663 QFETCH(QString, expectedValue);
664 QFETCH(QUrl::ComponentFormattingOptions, encoding);
665
666 QUrlQuery query(queryString);
667 COMPARE_ITEMS(query.queryItems(encoding), QueryItems() << qItem(expectedKey, expectedValue));
668 QCOMPARE(query.query(encoding), expectedQuery);
669}
670
671void tst_QUrlQuery::differentDelimiters()
672{
673 QUrlQuery query;
674 query.setQueryDelimiters(valueDelimiter: '(', pairDelimiter: ')');
675
676 {
677 // parse:
678 query.setQuery("foo(bar)hello(world)");
679
680 QueryItems expected;
681 expected << qItem(first: "foo", second: "bar") << qItem(first: "hello", second: "world");
682 COMPARE_ITEMS(query.queryItems(), expected);
683 COMPARE_ITEMS(query.queryItems(QUrl::FullyEncoded), expected);
684 COMPARE_ITEMS(query.queryItems(QUrl::PrettyDecoded), expected);
685 }
686
687 {
688 // reconstruct:
689 // note the final ')' is missing because there are no further items
690 QCOMPARE(query.query(), QString("foo(bar)hello(world"));
691 }
692
693 {
694 // set items containing the new delimiters and the old ones
695 query.clear();
696 query.addQueryItem(key: "z(=)", value: "y(&)");
697 QCOMPARE(query.query(), QString("z%28=%29(y%28&%29"));
698
699 QUrlQuery copy = query;
700 QCOMPARE(query.query(), QString("z%28=%29(y%28&%29"));
701
702 copy.setQueryDelimiters(valueDelimiter: QUrlQuery::defaultQueryValueDelimiter(),
703 pairDelimiter: QUrlQuery::defaultQueryPairDelimiter());
704 QCOMPARE(copy.query(), QString("z(%3D)=y(%26)"));
705 }
706}
707
708void tst_QUrlQuery::old_queryItems()
709{
710 // test imported from old tst_qurl.cpp
711 QUrlQuery url;
712
713 QList<QPair<QString, QString> > newItems;
714 newItems += qMakePair(x: QString("1"), y: QString("a"));
715 newItems += qMakePair(x: QString("2"), y: QString("b"));
716 newItems += qMakePair(x: QString("3"), y: QString("c"));
717 newItems += qMakePair(x: QString("4"), y: QString("a b"));
718 newItems += qMakePair(x: QString("5"), y: QString("&"));
719 newItems += qMakePair(x: QString("foo bar"), y: QString("hello world"));
720 newItems += qMakePair(x: QString("foo+bar"), y: QString("hello+world"));
721 newItems += qMakePair(x: QString("tex"), y: QString("a + b = c"));
722 url.setQueryItems(newItems);
723 QVERIFY(!url.isEmpty());
724
725 QList<QPair<QString, QString> > setItems = url.queryItems();
726 QCOMPARE(newItems, setItems);
727
728 url.addQueryItem(key: "1", value: "z");
729
730#if 0
731 // undefined behaviour in the new QUrlQuery
732
733 QVERIFY(url.hasQueryItem("1"));
734 QCOMPARE(url.queryItemValue("1").toLatin1().constData(), "a");
735
736 url.addQueryItem("1", "zz");
737
738 QStringList expected;
739 expected += "a";
740 expected += "z";
741 expected += "zz";
742 QCOMPARE(url.allQueryItemValues("1"), expected);
743
744 url.removeQueryItem("1");
745 QCOMPARE(url.allQueryItemValues("1").size(), 2);
746 QCOMPARE(url.queryItemValue("1").toLatin1().constData(), "z");
747#endif
748
749 url.removeAllQueryItems(key: "1");
750 QVERIFY(!url.hasQueryItem("1"));
751
752 QCOMPARE(url.queryItemValue("4"), QLatin1String("a b"));
753 QCOMPARE(url.queryItemValue("5"), QLatin1String("&"));
754 QCOMPARE(url.queryItemValue("tex"), QLatin1String("a + b = c"));
755 QCOMPARE(url.queryItemValue("foo bar"), QLatin1String("hello world"));
756
757 //url.setUrl("http://www.google.com/search?q=a+b");
758 url.setQuery("q=a+b");
759 QCOMPARE(url.queryItemValue("q"), QLatin1String("a+b"));
760
761 //url.setUrl("http://www.google.com/search?q=a=b"); // invalid, but should be tolerated
762 url.setQuery("q=a=b");
763 QCOMPARE(url.queryItemValue("q"), QLatin1String("a=b"));
764}
765
766void tst_QUrlQuery::old_hasQueryItem_data()
767{
768 QTest::addColumn<QString>(name: "url");
769 QTest::addColumn<QString>(name: "item");
770 QTest::addColumn<bool>(name: "trueFalse");
771
772 // the old tests started with "http://www.foo.bar"
773 QTest::newRow(dataTag: "no query items") << "" << "baz" << false;
774 QTest::newRow(dataTag: "query item: hello") << "hello=world" << "hello" << true;
775 QTest::newRow(dataTag: "no query item: world") << "hello=world" << "world" << false;
776 QTest::newRow(dataTag: "query item: qt") << "hello=world&qt=rocks" << "qt" << true;
777}
778
779void tst_QUrlQuery::old_hasQueryItem()
780{
781 QFETCH(QString, url);
782 QFETCH(QString, item);
783 QFETCH(bool, trueFalse);
784
785 QCOMPARE(QUrlQuery(url).hasQueryItem(item), trueFalse);
786}
787
788#if 0
789// this test doesn't make sense anymore
790void tst_QUrl::removeAllEncodedQueryItems_data()
791{
792 QTest::addColumn<QUrl>("url");
793 QTest::addColumn<QByteArray>("key");
794 QTest::addColumn<QUrl>("result");
795
796 QTest::newRow("test1") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&bbb=b&ccc=c") << QByteArray("bbb") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&ccc=c");
797 QTest::newRow("test2") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&bbb=b&ccc=c") << QByteArray("aaa") << QUrl::fromEncoded("http://qt-project.org/foo?bbb=b&ccc=c");
798// QTest::newRow("test3") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&bbb=b&ccc=c") << QByteArray("ccc") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&bbb=b");
799 QTest::newRow("test4") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&bbb=b&ccc=c") << QByteArray("b%62b") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&bbb=b&ccc=c");
800 QTest::newRow("test5") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&b%62b=b&ccc=c") << QByteArray("b%62b") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&ccc=c");
801 QTest::newRow("test6") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&b%62b=b&ccc=c") << QByteArray("bbb") << QUrl::fromEncoded("http://qt-project.org/foo?aaa=a&b%62b=b&ccc=c");
802}
803
804void tst_QUrl::removeAllEncodedQueryItems()
805{
806 QFETCH(QUrl, url);
807 QFETCH(QByteArray, key);
808 QFETCH(QUrl, result);
809 url.removeAllEncodedQueryItems(key);
810 QCOMPARE(url, result);
811}
812#endif
813
814QTEST_APPLESS_MAIN(tst_QUrlQuery)
815
816#include "tst_qurlquery.moc"
817

source code of qtbase/tests/auto/corelib/io/qurlquery/tst_qurlquery.cpp