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 | |
32 | typedef QList<QPair<QString, QString> > QueryItems; |
33 | Q_DECLARE_METATYPE(QueryItems) |
34 | Q_DECLARE_METATYPE(QUrl::ComponentFormattingOptions) |
35 | |
36 | class tst_QUrlQuery : public QObject |
37 | { |
38 | Q_OBJECT |
39 | |
40 | public: |
41 | tst_QUrlQuery() |
42 | { |
43 | qRegisterMetaType<QueryItems>(); |
44 | } |
45 | |
46 | private 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 | |
70 | static 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 | |
84 | static QString prettyPair(QList<QPair<QString, QString> >::const_iterator it) |
85 | { |
86 | return prettyElement(key: it->first, value: it->second); |
87 | } |
88 | |
89 | template <typename T> |
90 | static 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 | |
105 | static 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 | |
119 | inline 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 | |
126 | inline 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 | |
133 | inline QPair<QString, QString> qItem(const QString &first, const QString &second) |
134 | { |
135 | return qMakePair(x: first, y: second); |
136 | } |
137 | |
138 | inline QPair<QString, QString> qItem(const char *first, const QString &second) |
139 | { |
140 | return qMakePair(x: QString::fromUtf8(str: first), y: second); |
141 | } |
142 | |
143 | inline 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 | |
148 | inline QPair<QString, QString> qItem(const QString &first, const char *second) |
149 | { |
150 | return qMakePair(x: first, y: QString::fromUtf8(str: second)); |
151 | } |
152 | |
153 | static QUrlQuery emptyQuery() |
154 | { |
155 | return QUrlQuery(); |
156 | } |
157 | |
158 | void 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 | |
246 | void 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 | |
340 | void 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 | |
396 | void 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 | |
410 | void 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 | |
432 | void 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 | |
448 | void 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 | |
500 | void 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 | |
510 | void 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 | |
557 | void 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 | |
571 | void 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 | |
638 | void 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 | |
653 | void tst_QUrlQuery::encodedParsing_data() |
654 | { |
655 | encodedSetQueryItems_data(); |
656 | } |
657 | |
658 | void 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 | |
671 | void 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 | |
708 | void 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 | |
766 | void 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 | |
779 | void 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 |
790 | void 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 | |
804 | void 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 | |
814 | QTEST_APPLESS_MAIN(tst_QUrlQuery) |
815 | |
816 | #include "tst_qurlquery.moc" |
817 | |