1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Copyright (C) 2016 Intel Corporation.
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
10** Commercial License Usage
11** Licensees holding valid commercial Qt licenses may use this file in
12** accordance with the commercial license agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and The Qt Company. For licensing terms
15** and conditions see https://www.qt.io/terms-conditions. For further
16** information use the contact form at https://www.qt.io/contact-us.
17**
18** GNU General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#define QT_DEPRECATED
31#define QT_DISABLE_DEPRECATED_BEFORE 0
32#include <qurl.h>
33#include <QtTest/QtTest>
34#include <QtCore/QDebug>
35
36#include <qcoreapplication.h>
37
38#include <qfileinfo.h>
39#include <qtextcodec.h>
40#include <qmap.h>
41
42Q_DECLARE_METATYPE(QUrl::FormattingOptions)
43
44class tst_QUrl : public QObject
45{
46 Q_OBJECT
47
48private slots:
49 void initTestCase();
50 void cleanupTestCase();
51 void effectiveTLDs_data();
52 void effectiveTLDs();
53 void getSetCheck();
54 void constructing();
55 void hashInPath();
56 void unc();
57 void assignment();
58 void comparison();
59 void comparison2_data();
60 void comparison2();
61 void copying();
62 void setUrl();
63 void i18n_data();
64 void i18n();
65 void resolving_data();
66 void resolving();
67 void toString_data();
68 void toString();
69 void toString_PreferLocalFile_data();
70 void toString_PreferLocalFile();
71 void toString_constructed_data();
72 void toString_constructed();
73 void toDisplayString_PreferLocalFile_data();
74 void toDisplayString_PreferLocalFile();
75 void toAndFromStringList_data();
76 void toAndFromStringList();
77 void isParentOf_data();
78 void isParentOf();
79 void toLocalFile_data();
80 void toLocalFile();
81 void fromLocalFile_data();
82 void fromLocalFile();
83 void fromLocalFileNormalize_data();
84 void fromLocalFileNormalize();
85 void macTypes();
86 void relative();
87 void compat_legacy();
88 void compat_constructor_01_data();
89 void compat_constructor_01();
90 void compat_constructor_02_data();
91 void compat_constructor_02();
92 void compat_constructor_03_data();
93 void compat_constructor_03();
94 void compat_isValid_01_data();
95 void compat_isValid_01();
96 void compat_isValid_02_data();
97 void compat_isValid_02();
98 void compat_path_data();
99 void compat_path();
100 void compat_fileName_data();
101 void compat_fileName();
102 void compat_decode_data();
103 void compat_decode();
104 void compat_encode_data();
105 void compat_encode();
106 void percentEncoding_data();
107 void percentEncoding();
108 void swap();
109 void symmetry();
110 void ipvfuture_data();
111 void ipvfuture();
112 void ipv6_data();
113 void ipv6();
114 void ipv6_2_data();
115 void ipv6_2();
116 void moreIpv6();
117 void toPercentEncoding_data();
118 void toPercentEncoding();
119 void isRelative_data();
120 void isRelative();
121 void hasQuery_data();
122 void hasQuery();
123 void nameprep();
124 void isValid();
125 void schemeValidator_data();
126 void schemeValidator();
127 void setScheme_data();
128 void setScheme();
129 void strictParser_data();
130 void strictParser();
131 void tolerantParser();
132 void correctEncodedMistakes_data();
133 void correctEncodedMistakes();
134 void correctDecodedMistakes_data();
135 void correctDecodedMistakes();
136 void tldRestrictions_data();
137 void tldRestrictions();
138 void emptyQueryOrFragment();
139 void hasFragment_data();
140 void hasFragment();
141 void setFragment_data();
142 void setFragment();
143 void fromEncoded();
144 void stripTrailingSlash_data();
145 void stripTrailingSlash();
146 void hosts_data();
147 void hosts();
148 void hostFlags_data();
149 void hostFlags();
150 void setPort();
151 void port_data();
152 void port();
153 void toEncoded_data();
154 void toEncoded();
155 void setAuthority_data();
156 void setAuthority();
157 void setEmptyAuthority_data();
158 void setEmptyAuthority();
159 void clear();
160 void resolvedWithAbsoluteSchemes() const;
161 void resolvedWithAbsoluteSchemes_data() const;
162 void binaryData_data();
163 void binaryData();
164 void fromUserInput_data();
165 void fromUserInput();
166 void fromUserInputWithCwd_data();
167 void fromUserInputWithCwd();
168 void fileName_data();
169 void fileName();
170 void isEmptyForEncodedUrl();
171 void toEncodedNotUsingUninitializedPath();
172 void emptyAuthorityRemovesExistingAuthority_data();
173 void emptyAuthorityRemovesExistingAuthority();
174 void acceptEmptyAuthoritySegments();
175 void lowercasesScheme();
176 void componentEncodings_data();
177 void componentEncodings();
178 void setComponents_data();
179 void setComponents();
180 void streaming_data();
181 void streaming();
182 void detach();
183 void testThreading();
184 void matches_data();
185 void matches();
186 void ipv6_zoneId_data();
187 void ipv6_zoneId();
188 void normalizeRemotePaths_data();
189 void normalizeRemotePaths();
190
191private:
192 void testThreadingHelper();
193
194 const QString m_currentPath = QDir::currentPath();
195 QTemporaryDir m_tempDir;
196};
197
198void tst_QUrl::initTestCase()
199{
200 QVERIFY2(m_tempDir.isValid(), qPrintable(m_tempDir.errorString()));
201}
202
203void tst_QUrl::cleanupTestCase()
204{
205 // Restore working directory changed in fromUserInputWithCwd()
206 QDir::setCurrent(m_currentPath);
207}
208
209// Testing get/set functions
210void tst_QUrl::getSetCheck()
211{
212 QUrl obj1;
213 // int QUrl::port()
214 // void QUrl::setPort(int)
215 obj1.setPort(0);
216 QCOMPARE(0, obj1.port());
217
218 obj1.setPort(INT_MIN);
219 QCOMPARE(-1, obj1.port()); // Out of range, -1
220
221 obj1.setPort(INT_MAX);
222 QCOMPARE(-1, obj1.port()); // Out of range, -1
223
224 obj1.setPort(1234);
225 QCOMPARE(1234, obj1.port());
226
227 // static QStringList QUrl::idnWhitelist()
228 // static void QUrl::setIdnWhitelist(QStringList)
229 QStringList original = QUrl::idnWhitelist(); // save for later
230
231 QUrl::setIdnWhitelist(QStringList());
232 QCOMPARE(QUrl::idnWhitelist(), QStringList());
233
234 QStringList norway; norway << "no";
235 QUrl::setIdnWhitelist(norway);
236 QCOMPARE(QUrl::idnWhitelist(), norway);
237
238 QStringList modified = original;
239 modified << "foo";
240 QUrl::setIdnWhitelist(modified);
241 QCOMPARE(QUrl::idnWhitelist(), modified);
242
243 // reset to the original
244 QUrl::setIdnWhitelist(original);
245 QCOMPARE(QUrl::idnWhitelist(), original);
246}
247
248void tst_QUrl::constructing()
249{
250 QUrl url;
251 QVERIFY(!url.isValid());
252 QVERIFY(url.isEmpty());
253 QCOMPARE(url.port(), -1);
254 QCOMPARE(url.toString(), QString());
255 QCOMPARE(url, url);
256 QVERIFY(!(url < url));
257
258 QUrl fromLocal = QUrl::fromLocalFile(localfile: QString());
259 QVERIFY(!fromLocal.isValid());
260 QVERIFY(fromLocal.isEmpty());
261 QCOMPARE(fromLocal.toString(), QString());
262
263 QUrl justHost("qt-project.org");
264 QVERIFY(!justHost.isEmpty());
265 QVERIFY(justHost.host().isEmpty());
266 QCOMPARE(justHost.path(), QString::fromLatin1("qt-project.org"));
267
268 QUrl hostWithSlashes("//qt-project.org");
269 QVERIFY(hostWithSlashes.path().isEmpty());
270 QCOMPARE(hostWithSlashes.host(), QString::fromLatin1("qt-project.org"));
271}
272
273void tst_QUrl::hashInPath()
274{
275 QUrl withHashInPath;
276 withHashInPath.setPath(path: QString::fromLatin1(str: "hi#mum.txt"));
277 QCOMPARE(withHashInPath.path(), QString::fromLatin1("hi#mum.txt"));
278 QCOMPARE(withHashInPath.toEncoded(), QByteArray("hi%23mum.txt"));
279 QCOMPARE(withHashInPath.toString(), QString("hi%23mum.txt"));
280 QCOMPARE(withHashInPath.toDisplayString(QUrl::PreferLocalFile), QString("hi%23mum.txt"));
281
282 QUrl fromHashInPath = QUrl::fromEncoded(url: withHashInPath.toEncoded());
283 QCOMPARE(withHashInPath, fromHashInPath);
284
285 const QUrl localWithHash = QUrl::fromLocalFile(localfile: "/hi#mum.txt");
286 QCOMPARE(localWithHash.path(), QString::fromLatin1("/hi#mum.txt"));
287 QCOMPARE(localWithHash.toEncoded(), QByteArray("file:///hi%23mum.txt"));
288 QCOMPARE(localWithHash.toString(), QString("file:///hi%23mum.txt"));
289 QCOMPARE(localWithHash.path(), QString::fromLatin1("/hi#mum.txt"));
290 QCOMPARE(localWithHash.toString(QUrl::PreferLocalFile), QString("/hi#mum.txt"));
291 QCOMPARE(localWithHash.toDisplayString(QUrl::PreferLocalFile), QString("/hi#mum.txt"));
292}
293
294void tst_QUrl::unc()
295{
296 QUrl buildUNC;
297 buildUNC.setScheme(QString::fromLatin1(str: "file"));
298 buildUNC.setHost(host: QString::fromLatin1(str: "somehost"));
299 buildUNC.setPath(path: QString::fromLatin1(str: "somepath"));
300 QCOMPARE(buildUNC.toLocalFile(), QString::fromLatin1("//somehost/somepath"));
301 buildUNC.toEncoded();
302 QVERIFY(!buildUNC.isEmpty());
303}
304
305void tst_QUrl::assignment()
306{
307 QUrl url("http://qt-project.org/");
308 QVERIFY(url.isValid());
309
310 QUrl copy;
311 copy = url;
312
313 QCOMPARE(url, copy);
314}
315
316void tst_QUrl::comparison()
317{
318 QUrl url1("http://qt-project.org/");
319 QVERIFY(url1.isValid());
320
321 QUrl url2("http://qt-project.org/");
322 QVERIFY(url2.isValid());
323
324 QCOMPARE(url1, url2);
325 QVERIFY(!(url1 < url2));
326 QVERIFY(!(url2 < url1));
327 QVERIFY(url1.matches(url2, QUrl::None));
328 QVERIFY(url1.matches(url2, QUrl::StripTrailingSlash));
329
330 // 6.2.2 Syntax-based Normalization
331 QUrl url3 = QUrl::fromEncoded(url: "example://a/b/c/%7Bfoo%7D");
332 QUrl url4 = QUrl::fromEncoded(url: "eXAMPLE://a/./b/../b/%63/%7bfoo%7d");
333 QEXPECT_FAIL("", "Normalization not implemented, will probably not be implemented like this", Continue);
334 QCOMPARE(url3, url4);
335
336 QUrl url3bis = QUrl::fromEncoded(url: "example://a/b/c/%7Bfoo%7D/");
337 QUrl url3bisNoSlash = QUrl::fromEncoded(url: "example://a/b/c/%7Bfoo%7D");
338 QUrl url4bis = QUrl::fromEncoded(url: "example://a/./b/../b/c/%7Bfoo%7D/");
339 QCOMPARE(url4bis.adjusted(QUrl::NormalizePathSegments), url3bis);
340 QCOMPARE(url4bis.adjusted(QUrl::NormalizePathSegments | QUrl::StripTrailingSlash), url3bisNoSlash);
341 QVERIFY(url3bis.matches(url4bis, QUrl::NormalizePathSegments));
342 QVERIFY(!url3bisNoSlash.matches(url4bis, QUrl::NormalizePathSegments));
343 QVERIFY(url3bisNoSlash.matches(url4bis, QUrl::NormalizePathSegments | QUrl::StripTrailingSlash));
344
345 QUrl url4EncodedDots = QUrl("example://a/.//b/%2E%2E%2F/b/c/");
346 QCOMPARE(url4EncodedDots.path(QUrl::PrettyDecoded), QString("/.//b/..%2F/b/c/"));
347 QCOMPARE(url4EncodedDots.path(QUrl::FullyDecoded), QString("/.//b/..//b/c/"));
348 QCOMPARE(QString::fromLatin1(url4EncodedDots.toEncoded()), QString::fromLatin1("example://a/.//b/..%2F/b/c/"));
349 QCOMPARE(url4EncodedDots.toString(), QString("example://a/.//b/..%2F/b/c/"));
350 QCOMPARE(url4EncodedDots.adjusted(QUrl::NormalizePathSegments).toString(), QString("example://a//b/..%2F/b/c/"));
351
352 // 6.2.2.1 Make sure hexdecimal characters in percent encoding are
353 // treated case-insensitively
354 QUrl url5;
355 url5.setQuery(query: QLatin1String("a=%2a"));
356 QUrl url6;
357 url6.setQuery(query: QLatin1String("a=%2A"));
358 QCOMPARE(url5, url6);
359
360 QUrl url7;
361 url7.setQuery(query: QLatin1String("a=C"));
362 QUrl url8;
363 url8.setQuery(query: QLatin1String("a=c"));
364 QVERIFY(url7 != url8);
365 QVERIFY(url7 < url8);
366
367 // Trailing slash difference
368 QUrl url9("http://qt-project.org/path/");
369 QUrl url9NoSlash("http://qt-project.org/path");
370 QVERIFY(!(url9 == url9NoSlash));
371 QVERIFY(!url9.matches(url9NoSlash, QUrl::None));
372 QVERIFY(url9.matches(url9NoSlash, QUrl::StripTrailingSlash));
373
374 // RemoveFilename
375 QUrl url10("http://qt-project.org/file");
376 QUrl url10bis("http://qt-project.org/otherfile");
377 QVERIFY(!(url10 == url10bis));
378 QVERIFY(!url10.matches(url10bis, QUrl::None));
379 QVERIFY(!url10.matches(url10bis, QUrl::StripTrailingSlash));
380 QVERIFY(url10.matches(url10bis, QUrl::RemoveFilename));
381
382 // RemoveAuthority
383 QUrl authUrl1("x://host/a/b");
384 QUrl authUrl2("x://host/a/");
385 QUrl authUrl3("x:/a/b");
386 QVERIFY(authUrl1.matches(authUrl2, QUrl::RemoveFilename));
387 QCOMPARE(authUrl1.adjusted(QUrl::RemoveAuthority), authUrl3.adjusted(QUrl::RemoveAuthority));
388 QVERIFY(authUrl1.matches(authUrl3, QUrl::RemoveAuthority));
389 QCOMPARE(authUrl2.adjusted(QUrl::RemoveAuthority | QUrl::RemoveFilename), authUrl3.adjusted(QUrl::RemoveAuthority | QUrl::RemoveFilename));
390 QVERIFY(authUrl2.matches(authUrl3, QUrl::RemoveAuthority | QUrl::RemoveFilename));
391 QVERIFY(authUrl3.matches(authUrl2, QUrl::RemoveAuthority | QUrl::RemoveFilename));
392
393 QUrl hostUrl1("file:/foo");
394 QUrl hostUrl2("file:///foo");
395 QCOMPARE(hostUrl1, hostUrl2);
396 QVERIFY(hostUrl1.matches(hostUrl2, QUrl::None));
397 QVERIFY(hostUrl1.matches(hostUrl2, QUrl::RemoveAuthority));
398
399 // RemovePassword
400 QUrl passUrl1("http://user:pass@host/");
401 QUrl passUrl2("http://user:PASS@host/");
402 QVERIFY(!(passUrl1 == passUrl2));
403 QVERIFY(passUrl1 != passUrl2);
404 QVERIFY(!passUrl1.matches(passUrl2, QUrl::None));
405 QVERIFY(passUrl1.matches(passUrl2, QUrl::RemovePassword));
406
407 // RemovePassword, null vs empty
408 QUrl emptyPassUrl1("http://user:@host/");
409 QUrl emptyPassUrl2("http://user@host/");
410 QVERIFY(!(emptyPassUrl1 == emptyPassUrl2));
411 QVERIFY(emptyPassUrl1 != emptyPassUrl2);
412 QVERIFY(!emptyPassUrl1.matches(emptyPassUrl2, QUrl::None));
413 QVERIFY(emptyPassUrl1.matches(emptyPassUrl2, QUrl::RemovePassword));
414
415 // RemoveQuery, RemoveFragment
416 QUrl queryFragUrl1("http://host/file?query#fragment");
417 QUrl queryFragUrl2("http://host/file?q2#f2");
418 QUrl queryFragUrl3("http://host/file");
419 QVERIFY(!(queryFragUrl1 == queryFragUrl2));
420 QVERIFY(queryFragUrl1 != queryFragUrl2);
421 QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::None));
422 QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveQuery));
423 QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveFragment));
424 QVERIFY(queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveQuery | QUrl::RemoveFragment));
425 QVERIFY(queryFragUrl1.matches(queryFragUrl3, QUrl::RemoveQuery | QUrl::RemoveFragment));
426 QVERIFY(queryFragUrl3.matches(queryFragUrl1, QUrl::RemoveQuery | QUrl::RemoveFragment));
427}
428
429void tst_QUrl::comparison2_data()
430{
431 QTest::addColumn<QUrl>(name: "url1");
432 QTest::addColumn<QUrl>(name: "url2");
433 QTest::addColumn<int>(name: "ordering"); // like strcmp
434
435 QTest::newRow(dataTag: "null-null") << QUrl() << QUrl() << 0;
436
437 QUrl empty;
438 empty.setPath(path: "/hello"); // ensure it has detached
439 empty.setPath(path: QString());
440 QTest::newRow(dataTag: "null-empty") << QUrl() << empty << 0;
441
442 QTest::newRow(dataTag: "scheme-null") << QUrl("x:") << QUrl() << 1;
443 QTest::newRow(dataTag: "samescheme") << QUrl("x:") << QUrl("x:") << 0;
444 QTest::newRow(dataTag: "no-fragment-empty-fragment") << QUrl("http://kde.org/dir/") << QUrl("http://kde.org/dir/#") << -1;
445 QTest::newRow(dataTag: "no-query-empty-query") << QUrl("http://kde.org/dir/") << QUrl("http://kde.org/dir/?") << -1;
446 QTest::newRow(dataTag: "simple-file-url") << QUrl("file:///home/dfaure/file") << QUrl("file:///home/dfaure/file") << 0;
447 QTest::newRow(dataTag: "fromLocalFile-vs-ctor") << QUrl::fromLocalFile(localfile: "/home/dfaure/file") << QUrl("file:///home/dfaure/file") << 0;
448
449 // the following three are by choice
450 // the order could be the opposite and it would still be correct
451 QTest::newRow(dataTag: "scheme-path") << QUrl("x:") << QUrl("/tmp") << +1;
452 QTest::newRow(dataTag: "fragment-path") << QUrl("#foo") << QUrl("/tmp") << -1;
453 QTest::newRow(dataTag: "fragment-scheme") << QUrl("#foo") << QUrl("x:") << -1;
454
455 QTest::newRow(dataTag: "noport-zeroport") << QUrl("http://example.com") << QUrl("http://example.com:0") << -1;
456}
457
458void tst_QUrl::comparison2()
459{
460 QFETCH(QUrl, url1);
461 QFETCH(QUrl, url2);
462 QFETCH(int, ordering);
463
464 QCOMPARE(url1.toString() == url2.toString(), ordering == 0);
465 QCOMPARE(url1 == url2, ordering == 0);
466 QCOMPARE(url1 != url2, ordering != 0);
467 if (ordering == 0)
468 QCOMPARE(qHash(url1), qHash(url2));
469
470 QCOMPARE(url1 < url2, ordering < 0);
471 QCOMPARE(!(url1 < url2), ordering >= 0);
472
473 QCOMPARE(url2 < url1, ordering > 0);
474 QCOMPARE(!(url2 < url1), ordering <= 0);
475
476 // redundant checks (the above should catch these)
477 QCOMPARE(url1 < url2 || url2 < url1, ordering != 0);
478 QVERIFY(!(url1 < url2 && url2 < url1));
479 QVERIFY(url1 < url2 || url1 == url2 || url2 < url1);
480}
481
482void tst_QUrl::copying()
483{
484 QUrl url("http://qt-project.org/");
485 QVERIFY(url.isValid());
486
487 QUrl copy(url);
488
489 QCOMPARE(url, copy);
490}
491
492void tst_QUrl::setUrl()
493{
494 {
495 QUrl url("http://0.foo.com");
496 QVERIFY(url.isValid());
497 QCOMPARE(url.scheme(), QString::fromLatin1("http"));
498 QCOMPARE(url.path(), QString());
499 QCOMPARE(url.host(), QString::fromLatin1("0.foo.com"));
500 }
501
502 {
503 QUrl url("file:/");
504 QVERIFY(url.isValid());
505 QCOMPARE(url.scheme(), QString::fromLatin1("file"));
506 QCOMPARE(url.path(), QString::fromLatin1("/"));
507 QVERIFY(url.query().isEmpty());
508 QVERIFY(url.userInfo().isEmpty());
509 QVERIFY(url.authority().isEmpty());
510 QVERIFY(url.fragment().isEmpty());
511 QCOMPARE(url.port(), -1);
512 QCOMPARE(url.toString(), QString::fromLatin1("file:///"));
513 QCOMPARE(url.toDisplayString(), QString::fromLatin1("file:///"));
514 QCOMPARE(url.toDisplayString(QUrl::PreferLocalFile), QString::fromLatin1("/"));
515 }
516
517 {
518 QUrl url("hTTp://www.foo.bar:80");
519 QVERIFY(url.isValid());
520 QCOMPARE(url.scheme(), QString::fromLatin1("http"));
521 QCOMPARE(url.path(), QString());
522 QVERIFY(url.query().isEmpty());
523 QVERIFY(url.userInfo().isEmpty());
524 QVERIFY(url.fragment().isEmpty());
525 QCOMPARE(url.host(), QString::fromLatin1("www.foo.bar"));
526 QCOMPARE(url.authority(), QString::fromLatin1("www.foo.bar:80"));
527 QCOMPARE(url.port(), 80);
528 QCOMPARE(url.toString(), QString::fromLatin1("http://www.foo.bar:80"));
529 QCOMPARE(url.toDisplayString(), QString::fromLatin1("http://www.foo.bar:80"));
530 QCOMPARE(url.toDisplayString(QUrl::PreferLocalFile), QString::fromLatin1("http://www.foo.bar:80"));
531
532 QUrl url2("//www1.foo.bar");
533 QCOMPARE(url.resolved(url2).toString(), QString::fromLatin1("http://www1.foo.bar"));
534 }
535
536 {
537 QUrl url("http://user%3A:pass%40@[56::56:56:56:127.0.0.1]:99");
538 QVERIFY(url.isValid());
539 QCOMPARE(url.scheme(), QString::fromLatin1("http"));
540 QCOMPARE(url.path(), QString());
541 QVERIFY(url.query().isEmpty());
542 QCOMPARE(url.userName(), QString::fromLatin1("user:"));
543 QCOMPARE(url.password(), QString::fromLatin1("pass@"));
544 QCOMPARE(url.userInfo(), QString::fromLatin1("user%3A:pass@"));
545 QVERIFY(url.fragment().isEmpty());
546 QCOMPARE(url.host(), QString::fromLatin1("56::56:56:56:7f00:1"));
547 QCOMPARE(url.authority(), QString::fromLatin1("user%3A:pass%40@[56::56:56:56:7f00:1]:99"));
548 QCOMPARE(url.port(), 99);
549 QCOMPARE(url.url(), QString::fromLatin1("http://user%3A:pass%40@[56::56:56:56:7f00:1]:99"));
550 QCOMPARE(url.toDisplayString(), QString::fromLatin1("http://user%3A@[56::56:56:56:7f00:1]:99"));
551 }
552
553 {
554 QUrl url("http://user@localhost:8000/xmlhttprequest/resources/basic-auth-nouserpass/basic-auth-nouserpass.php");
555 QVERIFY(url.isValid());
556 QCOMPARE(url.scheme(), QString::fromLatin1("http"));
557 QCOMPARE(url.userName(), QString::fromLatin1("user"));
558 QCOMPARE(url.password(), QString());
559 QCOMPARE(url.userInfo(), QString::fromLatin1("user"));
560 QCOMPARE(url.port(), 8000);
561 }
562
563 {
564 QUrl url("http://www.foo.bar");
565 QVERIFY(url.isValid());
566
567 QUrl url2("/top//test/../test1/file.html");
568 QCOMPARE(url.resolved(url2).toString(), QString::fromLatin1("http://www.foo.bar/top//test1/file.html"));
569 }
570
571 {
572 QUrl url("http://www.foo.bar");
573 QVERIFY(url.isValid());
574
575 QUrl url2("/top//test/../test1/file.html");
576 QCOMPARE(url.resolved(url2).toString(), QString::fromLatin1("http://www.foo.bar/top//test1/file.html"));
577 }
578
579 {
580 QUrl url("http://www.foo.bar/top//test2/file2.html");
581 QVERIFY(url.isValid());
582
583 QCOMPARE(url.toString(), QString::fromLatin1("http://www.foo.bar/top//test2/file2.html"));
584 }
585
586 {
587 QUrl url("http://www.foo.bar/top//test2/file2.html");
588 QVERIFY(url.isValid());
589
590 QCOMPARE(url.toString(), QString::fromLatin1("http://www.foo.bar/top//test2/file2.html"));
591 }
592
593 {
594 QUrl url("file:/usr/local/src/kde2/////kdelibs/kio");
595 QVERIFY(url.isValid());
596 QCOMPARE(url.toString(), QString::fromLatin1("file:///usr/local/src/kde2/////kdelibs/kio"));
597 }
598
599 {
600 QUrl url("http://www.foo.bar");
601 QVERIFY(url.isValid());
602
603 QUrl url2("mailto:bastian@kde.org");
604 QVERIFY(url2.isValid());
605 QCOMPARE(url.resolved(url2).toString(), QString::fromLatin1("mailto:bastian@kde.org"));
606 }
607
608 {
609 QUrl url("mailto:bastian@kde.org?subject=hello");
610 QCOMPARE(url.toString(), QString::fromLatin1("mailto:bastian@kde.org?subject=hello"));
611 }
612
613 {
614 QUrl url("file:/usr/local/src/kde2/kdelibs/kio/");
615 QVERIFY(url.isValid());
616
617 QUrl url2("../../////kdebase/konqueror");
618 QCOMPARE(url.resolved(url2).toString(),
619 QString::fromLatin1("file:///usr/local/src/kde2/////kdebase/konqueror"));
620 }
621
622 {
623 QString u1 = "file:/home/dfaure/my#myref";
624 QUrl url = u1;
625 QVERIFY(url.isValid());
626 QCOMPARE(url.toString(), QString::fromLatin1("file:///home/dfaure/my#myref"));
627 QCOMPARE(url.toString(QUrl::PreferLocalFile), QString::fromLatin1("file:///home/dfaure/my#myref"));
628 QCOMPARE(url.fragment(), QString::fromLatin1("myref"));
629 }
630
631 {
632 QUrl url("gg:www.kde.org");
633 QVERIFY(url.isValid());
634 QCOMPARE(url.scheme(), QString::fromLatin1("gg"));
635 QVERIFY(url.host().isEmpty());
636 QCOMPARE(url.path(), QString::fromLatin1("www.kde.org"));
637 }
638
639 {
640 QUrl url("KDE");
641 QVERIFY(url.isValid());
642 QCOMPARE(url.path(), QString::fromLatin1("KDE"));
643 QVERIFY(url.scheme().isEmpty());
644 }
645
646 {
647 QUrl url("$HOME/.kde/share/config");
648 QVERIFY(url.isValid());
649 QCOMPARE(url.path(), QString::fromLatin1("$HOME/.kde/share/config"));
650 QVERIFY(url.scheme().isEmpty());
651 }
652
653 {
654 QUrl url("file:/opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject::connect");
655 QVERIFY(url.isValid());
656 QCOMPARE(url.fragment(), QString::fromLatin1("QObject::connect"));
657 }
658
659 {
660 QUrl url("file:/opt/kde2/qt2/doc/html/showimg-main-cpp.html#QObject:connect");
661 QVERIFY(url.isValid());
662 QCOMPARE(url.fragment(), QString::fromLatin1("QObject:connect"));
663 }
664
665 {
666 // suburls
667 QUrl url("file:/home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/#myref");
668 QVERIFY(url.isValid());
669
670 // or simply 'myref?'
671 QCOMPARE(url.fragment(), QString::fromLatin1("gzip:/#tar:/#myref"));
672 }
673
674 {
675 QUrl url("error:/?error=14&errText=Unknown%20host%20asdfu.adgi.sdfgoi#http://asdfu.adgi.sdfgoi");
676 QVERIFY(url.isValid());
677 QCOMPARE(url.fragment(), QString::fromLatin1("http://asdfu.adgi.sdfgoi"));
678 }
679
680 {
681 // suburls
682 QUrl url("file:/home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/");
683 QVERIFY(url.isValid());
684 }
685
686 {
687 QUrl url("file:/home/dfaure/cdrdao-1.1.5/dao/#CdrDriver.cc#");
688 QVERIFY(url.isValid());
689 }
690
691 {
692 QUrl url("file:/home/dfaure/my%20tar%20file.tgz#gzip:/#tar:/README");
693 QVERIFY(url.isValid());
694 QCOMPARE(url.toString(), QString::fromLatin1("file:///home/dfaure/my tar file.tgz#gzip:/#tar:/README"));
695 }
696
697 {
698 QUrl notPretty("http://ferret.lmh.ox.ac.uk/%7Ekdecvs/");
699 QVERIFY(notPretty.isValid());
700 QCOMPARE(notPretty.toString(), QString::fromLatin1("http://ferret.lmh.ox.ac.uk/~kdecvs/"));
701
702 QUrl notPretty2("file:/home/test/directory%20with%20spaces");
703 QVERIFY(notPretty2.isValid());
704 QCOMPARE(notPretty2.toString(), QString::fromLatin1("file:///home/test/directory with spaces"));
705
706 QUrl notPretty3("fish://foo/%23README%23");
707 QVERIFY(notPretty3.isValid());
708 QCOMPARE(notPretty3.toString(), QString::fromLatin1("fish://foo/%23README%23"));
709
710 QUrl url15581;
711 url15581.setUrl(url: "http://alain.knaff.linux.lu/bug-reports/kde/spaces in url.html");
712 QCOMPARE(url15581.toString(), QString::fromLatin1("http://alain.knaff.linux.lu/bug-reports/kde/spaces in url.html"));
713 QCOMPARE(url15581.toEncoded().constData(), QByteArray("http://alain.knaff.linux.lu/bug-reports/kde/spaces%20in%20url.html").constData());
714
715 QUrl url15582("http://alain.knaff.linux.lu/bug-reports/kde/percentage%in%url.html");
716 QCOMPARE(url15582.toString(), QString::fromLatin1("http://alain.knaff.linux.lu/bug-reports/kde/percentage%25in%25url.html"));
717 QCOMPARE(url15582.toEncoded(), QByteArray("http://alain.knaff.linux.lu/bug-reports/kde/percentage%25in%25url.html"));
718 QCOMPARE(url15582.toString(QUrl::FullyEncoded), QString("http://alain.knaff.linux.lu/bug-reports/kde/percentage%25in%25url.html"));
719 }
720
721 {
722 QUrl carsten;
723 carsten.setPath(path: "/home/gis/src/kde/kdelibs/kfile/.#kfiledetailview.cpp.1.18");
724 QCOMPARE(carsten.path(), QString::fromLatin1("/home/gis/src/kde/kdelibs/kfile/.#kfiledetailview.cpp.1.18"));
725
726 QUrl charles;
727 charles.setPath(path: "/home/charles/foo%20moo");
728 QCOMPARE(charles.path(), QString::fromLatin1("/home/charles/foo%20moo"));
729 QCOMPARE(charles.path(QUrl::FullyEncoded), QString::fromLatin1("/home/charles/foo%2520moo"));
730
731 QUrl charles2("file:/home/charles/foo%20moo");
732 QCOMPARE(charles2.path(), QString::fromLatin1("/home/charles/foo moo"));
733 QCOMPARE(charles2.path(QUrl::FullyEncoded), QString::fromLatin1("/home/charles/foo%20moo"));
734 }
735
736 {
737 QUrl udir;
738 QCOMPARE(udir.toEncoded(), QByteArray());
739 QCOMPARE(udir.toString(QUrl::FullyEncoded), QString());
740 QVERIFY(!udir.isValid());
741
742 udir = QUrl::fromLocalFile(localfile: "/home/dfaure/file.txt");
743 QCOMPARE(udir.path(), QString::fromLatin1("/home/dfaure/file.txt"));
744 QCOMPARE(udir.toEncoded(), QByteArray("file:///home/dfaure/file.txt"));
745 QCOMPARE(udir.toString(QUrl::FullyEncoded), QString("file:///home/dfaure/file.txt"));
746 }
747
748 {
749 QUrl url;
750 url.setUrl(url: "hello.com#?");
751 QVERIFY(url.isValid());
752 url.setUrl(url: "hello.com");
753 QVERIFY(!url.toString().contains(QLatin1Char('#')));
754 QVERIFY(!url.toString().contains(QLatin1Char('?')));
755 }
756
757 {
758 QUrl url;
759 url.setUrl(url: "http://1.2.3.4.example.com");
760 QVERIFY(url.isValid());
761 QCOMPARE(url.scheme(), QString("http"));
762 QCOMPARE(url.host(), QString("1.2.3.4.example.com"));
763 }
764
765 {
766 QUrl url;
767 url.setUrl(url: "http://1.2.3.4");
768 QVERIFY(url.isValid());
769 QCOMPARE(url.scheme(), QString("http"));
770 QCOMPARE(url.host(), QString("1.2.3.4"));
771 }
772 {
773 QUrl url;
774 url.setUrl(url: "http://1.2.3.4/");
775 QVERIFY(url.isValid());
776 QCOMPARE(url.scheme(), QString("http"));
777 QCOMPARE(url.host(), QString("1.2.3.4"));
778 QCOMPARE(url.path(), QString("/"));
779 }
780 {
781 QUrl url;
782 url.setUrl(url: "http://1.2.3.4?foo");
783 QVERIFY(url.isValid());
784 QCOMPARE(url.scheme(), QString("http"));
785 QCOMPARE(url.host(), QString("1.2.3.4"));
786 QCOMPARE(url.query(QUrl::FullyEncoded), QLatin1String("foo"));
787 }
788 {
789 QUrl url;
790 url.setUrl(url: "http://1.2.3.4#bar");
791 QVERIFY(url.isValid());
792 QCOMPARE(url.scheme(), QString("http"));
793 QCOMPARE(url.host(), QString("1.2.3.4"));
794 QCOMPARE(url.fragment(), QString("bar"));
795 }
796
797 {
798 QUrl url("data:text/javascript,d5%20%3D%20'five\\u0027s'%3B");
799 QVERIFY(url.isValid());
800 QCOMPARE(url.scheme(), QString("data"));
801 QCOMPARE(url.host(), QString());
802 QCOMPARE(url.path(), QString("text/javascript,d5 = 'five\\u0027s';"));
803 QCOMPARE(url.path(QUrl::FullyEncoded), QLatin1String("text/javascript,d5%20%3D%20'five%5Cu0027s'%3B"));
804 }
805
806 {
807 // invalid port number
808 QUrl url;
809 url.setUrl(url: QLatin1String("foo://tel:2147483648"), mode: QUrl::StrictMode);
810 QVERIFY(!url.isValid());
811 }
812
813 { //check it calls detach
814 QUrl u1("http://aaa.com");
815 QUrl u2 = u1;
816 u2.setUrl(url: "http://bbb.com");
817 QCOMPARE(u1.host(), QString::fromLatin1("aaa.com"));
818 QCOMPARE(u2.host(), QString::fromLatin1("bbb.com"));
819 }
820}
821
822void tst_QUrl::i18n_data()
823{
824 QTest::addColumn<QString>(name: "input");
825 QTest::addColumn<QByteArray>(name: "punyOutput");
826
827 QTest::newRow(dataTag: "øl") << QString::fromUtf8(str: "http://ole:passord@www.øl.no/index.html?ole=æsemann&ilder gud=hei#top")
828 << QByteArray("http://ole:passord@www.xn--l-4ga.no/index.html?ole=%C3%A6semann&ilder%20gud=hei#top");
829 QTest::newRow(dataTag: "räksmörgås") << QString::fromUtf8(str: "http://www.räksmörgås.no/")
830 << QByteArray("http://www.xn--rksmrgs-5wao1o.no/");
831 QTest::newRow(dataTag: "bühler") << QString::fromUtf8(str: "http://www.bühler.no/")
832 << QByteArray("http://www.xn--bhler-kva.no/");
833 QTest::newRow(dataTag: "non-latin1")
834 << QString::fromUtf8(str: "http://www.\316\261\316\270\316\256\316\275\316\261.info")
835 << QByteArray("http://www.xn--jxafb0a0a.info");
836}
837
838void tst_QUrl::i18n()
839{
840 QFETCH(QString, input);
841 QFETCH(QByteArray, punyOutput);
842
843 QUrl url(input);
844 QVERIFY(url.isValid());
845
846 QCOMPARE(url.toEncoded().constData(), punyOutput.constData());
847 QCOMPARE(QUrl::fromEncoded(punyOutput), url);
848 QCOMPARE(QUrl::fromEncoded(punyOutput).toString(), input);
849}
850
851
852void tst_QUrl::resolving_data()
853{
854 QTest::addColumn<QString>(name: "baseUrl");
855 QTest::addColumn<QString>(name: "relativeUrl");
856 QTest::addColumn<QString>(name: "resolvedUrl");
857
858 // 5.4.1 Normal Examples (http://www.ietf.org/rfc/rfc3986.txt)
859 QTest::newRow(dataTag: "g:h") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g:h") << QString::fromLatin1(str: "g:h");
860 QTest::newRow(dataTag: "g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g") << QString::fromLatin1(str: "http://a/b/c/g");
861 QTest::newRow(dataTag: "./g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "./g") << QString::fromLatin1(str: "http://a/b/c/g");
862 QTest::newRow(dataTag: "g/") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g/") << QString::fromLatin1(str: "http://a/b/c/g/");
863 QTest::newRow(dataTag: "/g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "/g") << QString::fromLatin1(str: "http://a/g");
864 QTest::newRow(dataTag: "//g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "//g") << QString::fromLatin1(str: "http://g");
865 QTest::newRow(dataTag: "?y") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "?y") << QString::fromLatin1(str: "http://a/b/c/d;p?y");
866 QTest::newRow(dataTag: "g?y") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g?y") << QString::fromLatin1(str: "http://a/b/c/g?y");
867 QTest::newRow(dataTag: "#s") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "#s") << QString::fromLatin1(str: "http://a/b/c/d;p?q#s");
868 QTest::newRow(dataTag: "g#s") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g#s") << QString::fromLatin1(str: "http://a/b/c/g#s");
869 QTest::newRow(dataTag: "g?y#s") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g?y#s") << QString::fromLatin1(str: "http://a/b/c/g?y#s");
870 QTest::newRow(dataTag: ";x") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: ";x") << QString::fromLatin1(str: "http://a/b/c/;x");
871 QTest::newRow(dataTag: "g;x") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g;x") << QString::fromLatin1(str: "http://a/b/c/g;x");
872 QTest::newRow(dataTag: "g;x?y#s") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g;x?y#s") << QString::fromLatin1(str: "http://a/b/c/g;x?y#s");
873 QTest::newRow(dataTag: "[empty]") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "") << QString::fromLatin1(str: "http://a/b/c/d;p?q");
874 QTest::newRow(dataTag: ".") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: ".") << QString::fromLatin1(str: "http://a/b/c/");
875 QTest::newRow(dataTag: "./") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "./") << QString::fromLatin1(str: "http://a/b/c/");
876 QTest::newRow(dataTag: "..") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "..") << QString::fromLatin1(str: "http://a/b/");
877 QTest::newRow(dataTag: "../") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "../") << QString::fromLatin1(str: "http://a/b/");
878 QTest::newRow(dataTag: "../g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "../g") << QString::fromLatin1(str: "http://a/b/g");
879 QTest::newRow(dataTag: "../..") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "../..") << QString::fromLatin1(str: "http://a/");
880 QTest::newRow(dataTag: "../../") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "../../") << QString::fromLatin1(str: "http://a/");
881 QTest::newRow(dataTag: "../../g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "../../g") << QString::fromLatin1(str: "http://a/g");
882
883 // 5.4.2 Abnormal Examples (http://www.ietf.org/rfc/rfc3986.txt)
884
885 // Parsers must be careful in handling cases where there are more
886 // relative path ".." segments than there are hierarchical levels in the
887 // base URI's path. Note that the ".." syntax cannot be used to change
888 // the authority component of a URI.
889 QTest::newRow(dataTag: "../../../g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "../../../g") << QString::fromLatin1(str: "http://a/g");
890 QTest::newRow(dataTag: "../../../../g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "../../../../g") << QString::fromLatin1(str: "http://a/g");
891
892 // Similarly, parsers must remove the dot-segments "." and ".." when
893 // they are complete components of a path, but not when they are only
894 // part of a segment.
895 QTest::newRow(dataTag: "/./g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "/./g") << QString::fromLatin1(str: "http://a/g");
896 QTest::newRow(dataTag: "/../g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "/../g") << QString::fromLatin1(str: "http://a/g");
897 QTest::newRow(dataTag: "g.") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g.") << QString::fromLatin1(str: "http://a/b/c/g.");
898 QTest::newRow(dataTag: ".g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: ".g") << QString::fromLatin1(str: "http://a/b/c/.g");
899 QTest::newRow(dataTag: "g..") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g..") << QString::fromLatin1(str: "http://a/b/c/g..");
900 QTest::newRow(dataTag: "..g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "..g") << QString::fromLatin1(str: "http://a/b/c/..g");
901
902 // Less likely are cases where the relative URI reference uses
903 // unnecessary or nonsensical forms of the "." and ".." complete path
904 // segments.
905 QTest::newRow(dataTag: "./../g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "./../g") << QString::fromLatin1(str: "http://a/b/g");
906 QTest::newRow(dataTag: "./g/.") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "./g/.") << QString::fromLatin1(str: "http://a/b/c/g/");
907 QTest::newRow(dataTag: "g/./h") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g/./h") << QString::fromLatin1(str: "http://a/b/c/g/h");
908 QTest::newRow(dataTag: "g/../h") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g/../h") << QString::fromLatin1(str: "http://a/b/c/h");
909 QTest::newRow(dataTag: "g;x=1/./y") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g;x=1/./y") << QString::fromLatin1(str: "http://a/b/c/g;x=1/y");
910 QTest::newRow(dataTag: "g;x=1/../y") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g;x=1/../y") << QString::fromLatin1(str: "http://a/b/c/y");
911
912 // Some applications fail to separate the reference's query and/or
913 // fragment components from a relative path before merging it with the
914 // base path and removing dot-segments. This error is rarely noticed,
915 // since typical usage of a fragment never includes the hierarchy ("/")
916 // character, and the query component is not normally used within
917 // relative references.
918 QTest::newRow(dataTag: "g?y/./x") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g?y/./x") << QString::fromLatin1(str: "http://a/b/c/g?y/./x");
919 QTest::newRow(dataTag: "g?y/../x") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g?y/../x") << QString::fromLatin1(str: "http://a/b/c/g?y/../x");
920 QTest::newRow(dataTag: "g#s/./x") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g#s/./x") << QString::fromLatin1(str: "http://a/b/c/g#s/./x");
921 QTest::newRow(dataTag: "g#s/../x") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "g#s/../x") << QString::fromLatin1(str: "http://a/b/c/g#s/../x");
922
923 // Some parsers allow the scheme name to be present in a relative URI
924 // reference if it is the same as the base URI scheme. This is
925 // considered to be a loophole in prior specifications of partial URI [RFC1630],
926 //QTest::newRow("http:g [for backward compatibility]") << QString::fromLatin1("http://a/b/c/d;p?q") << QString::fromLatin1("http:g") << QString::fromLatin1("http://a/b/c/g");
927 // However we don't do that anymore, as per RFC3986, in order for the data:subpage testcase below to work.
928 QTest::newRow(dataTag: "http:g") << QString::fromLatin1(str: "http://a/b/c/d;p?q") << QString::fromLatin1(str: "http:g") << QString::fromLatin1(str: "http:g");
929 QTest::newRow(dataTag: "data:subpage") << QString::fromLatin1(str: "data:text/plain, main page") << QString::fromLatin1(str: "data:text/plain, subpage") << QString::fromLatin1(str: "data:text/plain, subpage");
930
931 // Resolve relative with relative
932 QTest::newRow(dataTag: "../a (1)") << QString::fromLatin1(str: "b") << QString::fromLatin1(str: "../a") << QString::fromLatin1(str: "a");
933 QTest::newRow(dataTag: "../a (2)") << QString::fromLatin1(str: "b/a") << QString::fromLatin1(str: "../a") << QString::fromLatin1(str: "a");
934 QTest::newRow(dataTag: "../a (3)") << QString::fromLatin1(str: "b/c/a") << QString::fromLatin1(str: "../a") << QString::fromLatin1(str: "b/a");
935 QTest::newRow(dataTag: "../a (4)") << QString::fromLatin1(str: "b") << QString::fromLatin1(str: "/a") << QString::fromLatin1(str: "/a");
936
937 QTest::newRow(dataTag: "../a (5)") << QString::fromLatin1(str: "/b") << QString::fromLatin1(str: "../a") << QString::fromLatin1(str: "/a");
938 QTest::newRow(dataTag: "../a (6)") << QString::fromLatin1(str: "/b/a") << QString::fromLatin1(str: "../a") << QString::fromLatin1(str: "/a");
939 QTest::newRow(dataTag: "../a (7)") << QString::fromLatin1(str: "/b/c/a") << QString::fromLatin1(str: "../a") << QString::fromLatin1(str: "/b/a");
940 QTest::newRow(dataTag: "../a (8)") << QString::fromLatin1(str: "/b") << QString::fromLatin1(str: "/a") << QString::fromLatin1(str: "/a");
941
942 // More tests from KDE
943 QTest::newRow(dataTag: "brackets") << QString::fromLatin1(str: "http://www.calorieking.com/personal/diary/") << QString::fromLatin1(str: "/personal/diary/rpc.php?C=jsrs1&F=getDiaryDay&P0=[2006-3-8]&U=1141858921458") << QString::fromLatin1(str: "http://www.calorieking.com/personal/diary/rpc.php?C=jsrs1&F=getDiaryDay&P0=[2006-3-8]&U=1141858921458");
944 QTest::newRow(dataTag: "javascript")<< QString::fromLatin1(str: "http://www.youtube.com/?v=JvOSnRD5aNk") << QString::fromLatin1(str: "javascript:window.location+\"__flashplugin_unique__\"") << QString::fromLatin1(str: "javascript:window.location+%22__flashplugin_unique__%22");
945}
946
947void tst_QUrl::resolving()
948{
949 QFETCH(QString, baseUrl);
950 QFETCH(QString, relativeUrl);
951 QFETCH(QString, resolvedUrl);
952
953 QUrl url(baseUrl);
954 QCOMPARE(url.resolved(relativeUrl).toString(), resolvedUrl);
955}
956
957void tst_QUrl::toString_data()
958{
959 QTest::addColumn<QString>(name: "urlString");
960 QTest::addColumn<uint>(name: "options");
961 QTest::addColumn<QString>(name: "string");
962
963 QTest::newRow(dataTag: "data0") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
964 << uint(QUrl::RemoveScheme)
965 << QString::fromLatin1(str: "//ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top");
966
967 QTest::newRow(dataTag: "data2") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
968 << uint(QUrl::RemovePassword)
969 << QString::fromLatin1(str: "http://ole@www.troll.no:9090/index.html?ole=semann&gud=hei#top");
970
971 // show that QUrl keeps the empty-but-present username if you remove the password
972 // see data3-bis for another case
973 QTest::newRow(dataTag: "data2-bis") << QString::fromLatin1(str: "http://:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
974 << uint(QUrl::RemovePassword)
975 << QString::fromLatin1(str: "http://@www.troll.no:9090/index.html?ole=semann&gud=hei#top");
976
977 QTest::newRow(dataTag: "data3") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
978 << uint(QUrl::RemoveUserInfo)
979 << QString::fromLatin1(str: "http://www.troll.no:9090/index.html?ole=semann&gud=hei#top");
980
981 // show that QUrl keeps the empty-but-preset hostname if you remove the userinfo
982 QTest::newRow(dataTag: "data3-bis") << QString::fromLatin1(str: "http://ole:password@/index.html?ole=semann&gud=hei#top")
983 << uint(QUrl::RemoveUserInfo)
984 << QString::fromLatin1(str: "http:///index.html?ole=semann&gud=hei#top");
985
986 QTest::newRow(dataTag: "data4") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
987 << uint(QUrl::RemovePort)
988 << QString::fromLatin1(str: "http://ole:password@www.troll.no/index.html?ole=semann&gud=hei#top");
989
990 QTest::newRow(dataTag: "data5") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
991 << uint(QUrl::RemoveAuthority)
992 << QString::fromLatin1(str: "http:/index.html?ole=semann&gud=hei#top");
993
994 QTest::newRow(dataTag: "data6") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
995 << uint(QUrl::RemovePath)
996 << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090?ole=semann&gud=hei#top");
997
998 QTest::newRow(dataTag: "data7") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
999 << uint(QUrl::RemoveQuery)
1000 << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html#top");
1001
1002 QTest::newRow(dataTag: "data8") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1003 << uint(QUrl::RemoveFragment)
1004 << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei");
1005
1006 QTest::newRow(dataTag: "data9") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1007 << uint(QUrl::RemoveScheme | QUrl::RemovePassword)
1008 << QString::fromLatin1(str: "//ole@www.troll.no:9090/index.html?ole=semann&gud=hei#top");
1009
1010 QTest::newRow(dataTag: "data10") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1011 << uint(QUrl::RemoveScheme | QUrl::RemoveUserInfo)
1012 << QString::fromLatin1(str: "//www.troll.no:9090/index.html?ole=semann&gud=hei#top");
1013
1014 QTest::newRow(dataTag: "data11") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1015 << uint(QUrl::RemoveScheme | QUrl::RemovePort)
1016 << QString::fromLatin1(str: "//ole:password@www.troll.no/index.html?ole=semann&gud=hei#top");
1017
1018 QTest::newRow(dataTag: "data12") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1019 << uint(QUrl::RemoveScheme | QUrl::RemoveAuthority)
1020 << QString::fromLatin1(str: "/index.html?ole=semann&gud=hei#top");
1021
1022 QTest::newRow(dataTag: "data13") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1023 << uint(QUrl::RemoveScheme | QUrl::RemovePath)
1024 << QString::fromLatin1(str: "//ole:password@www.troll.no:9090?ole=semann&gud=hei#top");
1025
1026 QTest::newRow(dataTag: "data14") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1027 << uint(QUrl::RemoveScheme | QUrl::RemoveAuthority | QUrl::RemoveFragment)
1028 << QString::fromLatin1(str: "/index.html?ole=semann&gud=hei");
1029
1030 QTest::newRow(dataTag: "data15") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1031 << uint(QUrl::RemoveAuthority | QUrl::RemoveQuery)
1032 << QString::fromLatin1(str: "http:/index.html#top");
1033
1034 QTest::newRow(dataTag: "data16") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1035 << uint(QUrl::RemovePassword | QUrl::RemovePort
1036 | QUrl::RemovePath | QUrl::RemoveQuery
1037 | QUrl::RemoveFragment)
1038 << QString::fromLatin1(str: "http://ole@www.troll.no");
1039
1040 QTest::newRow(dataTag: "data17") << QString::fromLatin1(str: "http://ole:password@www.troll.no:9090/index.html?ole=semann&gud=hei#top")
1041 << uint(QUrl::RemoveScheme | QUrl::RemovePassword
1042 | QUrl::RemovePort | QUrl::RemovePath
1043 | QUrl::RemoveQuery | QUrl::RemoveFragment)
1044 << QString::fromLatin1(str: "//ole@www.troll.no");
1045
1046 QTest::newRow(dataTag: "data18") << QString::fromLatin1(str: "http://andreas:hemmelig@www.vg.no/?my=query&your=query#yougotfragged")
1047 << uint(QUrl::None)
1048 << QString::fromLatin1(str: "http://andreas:hemmelig@www.vg.no/?my=query&your=query#yougotfragged");
1049
1050 QTest::newRow(dataTag: "nopath") << QString::fromLatin1(str: "host://protocol")
1051 << uint(QUrl::None)
1052 << QString::fromLatin1(str: "host://protocol");
1053
1054 QTest::newRow(dataTag: "underscore") << QString::fromLatin1(str: "http://foo_bar.host.com/rss.php")
1055 << uint(QUrl::None)
1056 << QString::fromLatin1(str: "http://foo_bar.host.com/rss.php");
1057
1058 QTest::newRow(dataTag: "mailto-brackets") << QString::fromLatin1(str: "mailto:test[at]gmail[dot]com")
1059 << uint(QUrl::PrettyDecoded)
1060 << QString::fromLatin1(str: "mailto:test[at]gmail[dot]com");
1061 QTest::newRow(dataTag: "mailto-query") << QString::fromLatin1(str: "mailto:?to=test@example.com")
1062 << uint(QUrl::PrettyDecoded)
1063 << QString::fromLatin1(str: "mailto:?to=test@example.com");
1064}
1065
1066void tst_QUrl::toString()
1067{
1068 QFETCH(QString, urlString);
1069 QFETCH(uint, options);
1070 QFETCH(QString, string);
1071
1072 QUrl::FormattingOptions opt(options);
1073
1074 QUrl url(urlString);
1075 QCOMPARE(url.toString(opt), string);
1076
1077 QCOMPARE(url.adjusted(opt).toString(), string);
1078}
1079void tst_QUrl::toString_PreferLocalFile_data()
1080{
1081 QTest::addColumn<QUrl>(name: "url");
1082 QTest::addColumn<QString>(name: "string");
1083
1084#ifdef Q_OS_WIN
1085 QTest::newRow("win-drive") << QUrl(QString::fromLatin1("file:///c:/windows/regedit.exe"))
1086 << QString::fromLatin1("c:/windows/regedit.exe");
1087 QTest::newRow("win-share") << QUrl(QString::fromLatin1("//Anarki/homes"))
1088 << QString::fromLatin1("//anarki/homes");
1089#else
1090 QTest::newRow(dataTag: "unix-path") << QUrl(QString::fromLatin1(str: "file:///tmp"))
1091 << QString::fromLatin1(str: "/tmp");
1092#endif
1093}
1094
1095void tst_QUrl::toString_PreferLocalFile()
1096{
1097 QFETCH(QUrl, url);
1098 QFETCH(QString, string);
1099
1100 QCOMPARE(url.toString(QUrl::PreferLocalFile), string);
1101}
1102
1103void tst_QUrl::toAndFromStringList_data()
1104{
1105 QTest::addColumn<QStringList>(name: "strings");
1106
1107 QTest::newRow(dataTag: "empty") << QStringList();
1108 QTest::newRow(dataTag: "local") << (QStringList() << "file:///tmp" << "file:///");
1109 QTest::newRow(dataTag: "remote") << (QStringList() << "http://qt-project.org");
1110}
1111
1112void tst_QUrl::toAndFromStringList()
1113{
1114 QFETCH(QStringList, strings);
1115
1116 const QList<QUrl> urls = QUrl::fromStringList(uris: strings);
1117 QCOMPARE(urls.count(), strings.count());
1118 const QStringList converted = QUrl::toStringList(uris: urls);
1119 QCOMPARE(converted, strings);
1120}
1121
1122//### more tests ... what do we expect ...
1123void tst_QUrl::isParentOf_data()
1124{
1125 QTest::addColumn<QString>(name: "parent");
1126 QTest::addColumn<QString>(name: "child");
1127 QTest::addColumn<bool>(name: "trueFalse");
1128
1129 QTest::newRow(dataTag: "data0") << QString::fromLatin1(str: "http://a.b.c/d")
1130 << QString::fromLatin1(str: "http://a.b.c/d/e?f") << true;
1131 QTest::newRow(dataTag: "data1") << QString::fromLatin1(str: "http://a.b.c/d")
1132 << QString::fromLatin1(str: "http://a.b.c/d") << false;
1133 QTest::newRow(dataTag: "data2") << QString::fromLatin1(str: "http://a.b.c/d")
1134 << QString::fromLatin1(str: "http://a.b.c/de") << false;
1135 QTest::newRow(dataTag: "data3") << QString::fromLatin1(str: "http://a.b.c/d/")
1136 << QString::fromLatin1(str: "http://a.b.c/de") << false;
1137 QTest::newRow(dataTag: "data4") << QString::fromLatin1(str: "http://a.b.c/d/")
1138 << QString::fromLatin1(str: "http://a.b.c/d/e") << true;
1139}
1140
1141void tst_QUrl::toString_constructed_data()
1142{
1143 QTest::addColumn<QString>(name: "scheme");
1144 QTest::addColumn<QString>(name: "userName");
1145 QTest::addColumn<QString>(name: "password");
1146 QTest::addColumn<QString>(name: "host");
1147 QTest::addColumn<int>(name: "port");
1148 QTest::addColumn<QString>(name: "path");
1149 QTest::addColumn<QString>(name: "query");
1150 QTest::addColumn<QString>(name: "fragment");
1151 QTest::addColumn<QString>(name: "asString");
1152 QTest::addColumn<QByteArray>(name: "asEncoded");
1153 QTest::addColumn<uint>(name: "options");
1154
1155 QString n("");
1156
1157 QTest::newRow(dataTag: "data1") << n << n << n << QString::fromLatin1(str: "qt-project.org") << -1 << QString::fromLatin1(str: "/index.html")
1158 << QString() << n << QString::fromLatin1(str: "//qt-project.org/index.html")
1159 << QByteArray("//qt-project.org/index.html") << 0u;
1160 QTest::newRow(dataTag: "data2") << QString::fromLatin1(str: "file") << n << n << n << -1 << QString::fromLatin1(str: "/root") << QString()
1161 << n << QString::fromLatin1(str: "file:///root") << QByteArray("file:///root") << 0u;
1162 QTest::newRow(dataTag: "userAndPass") << QString::fromLatin1(str: "http") << QString::fromLatin1(str: "dfaure") << QString::fromLatin1(str: "kde")
1163 << "kde.org" << 443 << QString::fromLatin1(str: "/") << QString() << n
1164 << QString::fromLatin1(str: "http://dfaure:kde@kde.org:443/") << QByteArray("http://dfaure:kde@kde.org:443/")
1165 << 0u;
1166 QTest::newRow(dataTag: "PassWithoutUser") << QString::fromLatin1(str: "http") << n << QString::fromLatin1(str: "kde")
1167 << "kde.org" << 443 << QString::fromLatin1(str: "/") << QString() << n
1168 << QString::fromLatin1(str: "http://:kde@kde.org:443/") << QByteArray("http://:kde@kde.org:443/") << 0u;
1169 QTest::newRow(dataTag: "PassWithoutUser-RemovePassword") << QString::fromLatin1(str: "http") << n << QString::fromLatin1(str: "kde")
1170 << "kde.org" << 443 << QString::fromLatin1(str: "/") << QString() << n
1171 << QString::fromLatin1(str: "http://kde.org:443/") << QByteArray("http://kde.org:443/")
1172 << uint(QUrl::RemovePassword);
1173}
1174
1175void tst_QUrl::toString_constructed()
1176{
1177 QFETCH(QString, scheme);
1178 QFETCH(QString, userName);
1179 QFETCH(QString, password);
1180 QFETCH(QString, host);
1181 QFETCH(int, port);
1182 QFETCH(QString, path);
1183 QFETCH(QString, query);
1184 QFETCH(QString, fragment);
1185 QFETCH(QString, asString);
1186 QFETCH(QByteArray, asEncoded);
1187 QFETCH(uint, options);
1188
1189 QUrl url;
1190 if (!scheme.isEmpty())
1191 url.setScheme(scheme);
1192 if (!userName.isEmpty())
1193 url.setUserName(userName);
1194 if (!password.isEmpty())
1195 url.setPassword(password);
1196 if (!host.isEmpty())
1197 url.setHost(host);
1198 if (port != -1)
1199 url.setPort(port);
1200 if (!path.isEmpty())
1201 url.setPath(path);
1202 if (!query.isEmpty())
1203 url.setQuery(query, mode: QUrl::StrictMode);
1204 if (!fragment.isEmpty())
1205 url.setFragment(fragment);
1206
1207 QVERIFY(url.isValid());
1208
1209 QUrl::FormattingOptions formattingOptions(options);
1210 QCOMPARE(url.toString(formattingOptions), asString);
1211 QCOMPARE(QString::fromLatin1(url.toEncoded(formattingOptions)), QString::fromLatin1(asEncoded)); // readable in case of differences
1212 QCOMPARE(url.toEncoded(formattingOptions), asEncoded);
1213}
1214
1215void tst_QUrl::toDisplayString_PreferLocalFile_data()
1216{
1217 QTest::addColumn<QUrl>(name: "url");
1218 QTest::addColumn<QString>(name: "string");
1219
1220 QTest::newRow(dataTag: "basic") << QUrl::fromLocalFile(localfile: "/home/charles/foomoo")
1221 << QString::fromLatin1(str: "/home/charles/foomoo");
1222 QTest::newRow(dataTag: "with%") << QUrl::fromLocalFile(localfile: "/home/charles/foo%20moo")
1223 << QString::fromLatin1(str: "/home/charles/foo%20moo");
1224 QTest::newRow(dataTag: "non-local") << QUrl("file://host/foo")
1225 << QString::fromLatin1(str: "//host/foo");
1226 QTest::newRow(dataTag: "query-and-fragment") << QUrl("file://user:pass@example.org/a?b=c%20d%23e#frag%23ment")
1227 << QString::fromLatin1(str: "file://user@example.org/a?b=c d%23e#frag%23ment");
1228 QTest::newRow(dataTag: "http") << QUrl("http://user:pass@example.org/a?b=c%20d%23e#frag%23ment")
1229 << QString::fromLatin1(str: "http://user@example.org/a?b=c d%23e#frag%23ment");
1230}
1231
1232void tst_QUrl::toDisplayString_PreferLocalFile()
1233{
1234 QFETCH(QUrl, url);
1235 QFETCH(QString, string);
1236
1237 if (url.isLocalFile() && url.query().isEmpty() && url.fragment().isEmpty())
1238 QCOMPARE(url.toLocalFile(), string);
1239 QCOMPARE(url.toDisplayString(QUrl::PreferLocalFile), string);
1240}
1241
1242void tst_QUrl::isParentOf()
1243{
1244 QFETCH(QString, parent);
1245 QFETCH(QString, child);
1246 QFETCH(bool, trueFalse);
1247
1248 QUrl url(parent);
1249 QCOMPARE(url.isParentOf(QUrl(child)), trueFalse);
1250}
1251
1252void tst_QUrl::toLocalFile_data()
1253{
1254 QTest::addColumn<QString>(name: "theUrl");
1255 QTest::addColumn<QString>(name: "theFile");
1256
1257 QTest::newRow(dataTag: "file:/") << QString::fromLatin1(str: "file:/a.txt") << QString::fromLatin1(str: "/a.txt");
1258 QTest::newRow(dataTag: "file:///") << QString::fromLatin1(str: "file:///a.txt") << QString::fromLatin1(str: "/a.txt");
1259 QTest::newRow(dataTag: "file:////") << QString::fromLatin1(str: "file:////somehost/somedir/somefile") << QString::fromLatin1(str: "//somehost/somedir/somefile");
1260 QTest::newRow(dataTag: "FILE:/") << QString::fromLatin1(str: "FILE:/a.txt") << QString::fromLatin1(str: "/a.txt");
1261
1262 QTest::newRow(dataTag: "path-delimiter") << QString::fromLatin1(str: "file:///Mambo <%235>.mp3") << QString::fromLatin1(str: "/Mambo <#5>.mp3");
1263 QTest::newRow(dataTag: "path-percent") << QString::fromLatin1(str: "file:///a%25.txt") << QString::fromLatin1(str: "/a%.txt");
1264 QTest::newRow(dataTag: "path-percent-percent") << QString::fromLatin1(str: "file:///a%25%25.txt") << QString::fromLatin1(str: "/a%%.txt");
1265 QTest::newRow(dataTag: "path-percent-a-percent") << QString::fromLatin1(str: "file:///a%25a%25.txt") << QString::fromLatin1(str: "/a%a%.txt");
1266 QTest::newRow(dataTag: "path-control-char") << QString::fromLatin1(str: "file:///a%1f.txt") << QString::fromLatin1(str: "/a\x1f.txt");
1267 QTest::newRow(dataTag: "path-percent-hex-hex") << QString::fromLatin1(str: "file:///%2580.txt") << QString::fromLatin1(str: "/%80.txt");
1268
1269 QTest::newRow(dataTag: "webdavs") << QString::fromLatin1(str: "webdavs://somewebdavhost/somedir/somefile")
1270#ifdef Q_OS_WIN // QTBUG-42346, WebDAV is visible as local file on Windows only.
1271 << QString::fromLatin1("//somewebdavhost@SSL/somedir/somefile");
1272#else
1273 << QString();
1274#endif
1275#ifdef Q_OS_WIN
1276 QTest::newRow("windows-drive-absolute") << QString::fromLatin1("file:///c:/a.txt") << QString::fromLatin1("c:/a.txt");
1277#else
1278 QTest::newRow(dataTag: "windows-drive-absolute") << QString::fromLatin1(str: "file:///c:/a.txt") << QString::fromLatin1(str: "/c:/a.txt");
1279#endif
1280 QTest::newRow(dataTag: "windows-unc-path") << QString::fromLatin1(str: "file://somehost/somedir/somefile") << QString::fromLatin1(str: "//somehost/somedir/somefile");
1281 QTest::newRow(dataTag: "windows-unc-root") << QString::fromLatin1(str: "file://somehost/") << QString::fromLatin1(str: "//somehost/");
1282 QTest::newRow(dataTag: "windows-unc-nopath") << QString::fromLatin1(str: "file://somehost") << QString::fromLatin1(str: "//somehost");
1283 QTest::newRow(dataTag: "windows-extlen-path") << QString::fromLatin1(str: "file:////%3F/somedir/somefile") << QString::fromLatin1(str: "//?/somedir/somefile");
1284 QTest::newRow(dataTag: "windows-wsl-path") << QString::fromLatin1(str: "file:////wsl$/somedir/somefile") << QString::fromLatin1(str: "//wsl$/somedir/somefile");
1285 QTest::newRow(dataTag: "windows-device-path") << QString::fromLatin1(str: "file:////./somedir/somefile") << QString::fromLatin1(str: "//./somedir/somefile");
1286
1287 // and some that result in empty (i.e., not local)
1288 QTest::newRow(dataTag: "noscheme-absolute") << QString::fromLatin1(str: "/a.txt") << QString();
1289 QTest::newRow(dataTag: "noscheme-host") << QString::fromLatin1(str: "//a.txt") << QString();
1290 QTest::newRow(dataTag: "noscheme-host-path") << QString::fromLatin1(str: "///a.txt") << QString();
1291 QTest::newRow(dataTag: "fooscheme-absolute") << QString::fromLatin1(str: "foo:/a.txt") << QString();
1292 QTest::newRow(dataTag: "fooscheme-host") << QString::fromLatin1(str: "foo://a.txt") << QString();
1293 QTest::newRow(dataTag: "fooscheme-host-path") << QString::fromLatin1(str: "foo:///a.txt") << QString();
1294}
1295
1296void tst_QUrl::toLocalFile()
1297{
1298 QFETCH(QString, theUrl);
1299 QFETCH(QString, theFile);
1300
1301 QUrl url(theUrl);
1302 QCOMPARE(url.toLocalFile(), theFile);
1303 QCOMPARE(url.isLocalFile(), !theFile.isEmpty());
1304}
1305
1306void tst_QUrl::fromLocalFile_data()
1307{
1308 QTest::addColumn<QString>(name: "theFile");
1309 QTest::addColumn<QString>(name: "theUrl");
1310 QTest::addColumn<QString>(name: "thePath");
1311
1312 QTest::newRow(dataTag: "absolute-path") << QString::fromLatin1(str: "/a.txt") << QString::fromLatin1(str: "file:///a.txt") << QString::fromLatin1(str: "/a.txt");
1313 QTest::newRow(dataTag: "relative-path") << QString::fromLatin1(str: "a.txt") << QString::fromLatin1(str: "file:a.txt") << QString::fromLatin1(str: "a.txt");
1314 QTest::newRow(dataTag: "absolute-two-path") << QString::fromLatin1(str: "/a/b.txt") << QString::fromLatin1(str: "file:///a/b.txt") << QString::fromLatin1(str: "/a/b.txt");
1315 QTest::newRow(dataTag: "path-delimiters") << QString::fromLatin1(str: "/Mambo <#5>.mp3") << QString::fromLatin1(str: "file:///Mambo <%235>.mp3")
1316 << QString::fromLatin1(str: "/Mambo <#5>.mp3");
1317
1318 // Windows absolute details
1319 QTest::newRow(dataTag: "windows-drive") << QString::fromLatin1(str: "c:/a.txt") << QString::fromLatin1(str: "file:///c:/a.txt") << QString::fromLatin1(str: "/c:/a.txt");
1320
1321 // Windows UNC paths
1322 for (const char *suffix : { "", "/", "/somedir/somefile" }) {
1323 const char *pathDescription =
1324 strlen(s: suffix) == 0 ? "nopath" :
1325 strlen(s: suffix) > 1 ? "path" : "root";
1326
1327 QTest::addRow(format: "windows-unc-%s", pathDescription)
1328 << QString("//somehost") + suffix
1329 << QString("file://somehost") + suffix
1330 << QString(suffix);
1331#ifdef Q_OS_WIN32
1332 // debackslashification only happens on Windows
1333 QTest::addRow("windows-backslash-unc-%s", pathDescription)
1334 << QString(QString("//somehost") + suffix).replace('/', '\\')
1335 << QString("file://somehost") + suffix
1336 << QString(suffix);
1337 QTest::addRow("windows-backslash-extlen-%s", pathDescription)
1338 << QString(QString("//?") + suffix).replace('/', '\\')
1339 << QString("file:////%3F") + suffix
1340 << QString("//?") + suffix;
1341#endif
1342 QTest::addRow(format: "windows-extlen-%s", pathDescription)
1343 << QString("//?") + suffix
1344 << QString("file:////%3F") + suffix
1345 << QString("//?") + suffix;
1346 QTest::addRow(format: "windows-wsl-%s", pathDescription)
1347 << QString("//wsl$") + suffix
1348 << QString("file:////wsl$") + suffix
1349 << QString("//wsl$") + suffix;
1350 QTest::addRow(format: "windows-device--%s", pathDescription)
1351 << QString("//.") + suffix
1352 << QString("file:////.") + suffix
1353 << QString("//.") + suffix;
1354 }
1355
1356 QTest::newRow(dataTag: "windows-webdav")
1357 << QString::fromLatin1(str: "//somewebdavhost@SSL/somedir/somefile")
1358 << QString::fromLatin1(str: "webdavs://somewebdavhost/somedir/somefile")
1359 << QString::fromLatin1(str: "/somedir/somefile");
1360}
1361
1362void tst_QUrl::fromLocalFile()
1363{
1364 QFETCH(QString, theFile);
1365 QFETCH(QString, theUrl);
1366 QFETCH(QString, thePath);
1367
1368 QUrl url = QUrl::fromLocalFile(localfile: theFile);
1369
1370 QCOMPARE(url.toString(QUrl::DecodeReserved), theUrl);
1371 QCOMPARE(url.path(), thePath);
1372}
1373
1374void tst_QUrl::fromLocalFileNormalize_data()
1375{
1376 QTest::addColumn<QString>(name: "theFile"); // should support the fromLocalFile/toLocalFile roundtrip (so no //host or windows path)
1377 QTest::addColumn<QString>(name: "theUrl");
1378 QTest::addColumn<QString>(name: "urlWithNormalizedPath");
1379
1380 QTest::newRow(dataTag: "absolute-path") << QString::fromLatin1(str: "/a.txt") << QString::fromLatin1(str: "file:///a.txt") << QString::fromLatin1(str: "file:///a.txt");
1381 QTest::newRow(dataTag: "relative-path") << QString::fromLatin1(str: "a.txt") << QString::fromLatin1(str: "file:a.txt") << QString::fromLatin1(str: "file:a.txt");
1382 QTest::newRow(dataTag: "percent") << QString::fromLatin1(str: "/a%.txt") << QString::fromLatin1(str: "file:///a%25.txt")
1383 << QString::fromLatin1(str: "file:///a%25.txt");
1384 QTest::newRow(dataTag: "percent25") << QString::fromLatin1(str: "/a%25.txt") << QString::fromLatin1(str: "file:///a%2525.txt")
1385 << QString::fromLatin1(str: "file:///a%2525.txt");
1386 QTest::newRow(dataTag: "percent80") << QString::fromLatin1(str: "/%80.txt") << QString::fromLatin1(str: "file:///%2580.txt")
1387 << QString::fromLatin1(str: "file:///%2580.txt");
1388 QTest::newRow(dataTag: "relative-dot") << QString::fromLatin1(str: "./a.txt") << QString::fromLatin1(str: "file:./a.txt") << QString::fromLatin1(str: "file:a.txt");
1389 QTest::newRow(dataTag: "relative-dot-dot") << QString::fromLatin1(str: "././a.txt") << QString::fromLatin1(str: "file:././a.txt") << QString::fromLatin1(str: "file:a.txt");
1390 QTest::newRow(dataTag: "relative-path-dotdot") << QString::fromLatin1(str: "b/../a.txt") << QString::fromLatin1(str: "file:b/../a.txt") << QString::fromLatin1(str: "file:a.txt");
1391 QTest::newRow(dataTag: "absolute-path-dotdot") << QString::fromLatin1(str: "/b/../a.txt") << QString::fromLatin1(str: "file:///b/../a.txt") << QString::fromLatin1(str: "file:///a.txt");
1392 QTest::newRow(dataTag: "absolute-path-dot") << QString::fromLatin1(str: "/b/.") << QString::fromLatin1(str: "file:///b/.") << QString::fromLatin1(str: "file:///b");
1393}
1394
1395void tst_QUrl::fromLocalFileNormalize()
1396{
1397 QFETCH(QString, theFile);
1398 QFETCH(QString, theUrl);
1399 QFETCH(QString, urlWithNormalizedPath);
1400
1401 QUrl url = QUrl::fromLocalFile(localfile: theFile);
1402
1403 QCOMPARE(url.toString(QUrl::DecodeReserved), theUrl);
1404 QCOMPARE(url.toLocalFile(), theFile); // roundtrip
1405 QCOMPARE(url.path(), theFile); // works as well as long as we don't test windows paths
1406 QCOMPARE(url.toString(QUrl::NormalizePathSegments), urlWithNormalizedPath);
1407}
1408
1409void tst_QUrl::macTypes()
1410{
1411#ifndef Q_OS_MAC
1412 QSKIP("This is a Mac-only test");
1413#else
1414 extern void tst_QUrl_mactypes(); // in tst_qurl_mac.mm
1415 void tst_QUrl_mactypes();
1416#endif
1417}
1418
1419void tst_QUrl::compat_legacy()
1420{
1421 {
1422 QUrl u( "file:bar" );
1423 QCOMPARE( u.toString(QUrl::RemoveScheme), QString("bar") );
1424 }
1425
1426 /* others
1427 */
1428 {
1429 QUrl u( "http://qt-project.org/images/ban/pgs_front.jpg" );
1430 QCOMPARE( u.path(), QString("/images/ban/pgs_front.jpg") );
1431 }
1432 {
1433 QUrl tmp( "http://qt-project.org/images/ban/" );
1434 QUrl u = tmp.resolved(relative: QString("pgs_front.jpg"));
1435 QCOMPARE( u.path(), QString("/images/ban/pgs_front.jpg") );
1436 }
1437 {
1438 QUrl tmp;
1439 QUrl u = tmp.resolved(relative: QString("http://qt-project.org/images/ban/pgs_front.jpg"));
1440 QCOMPARE( u.path(), QString("/images/ban/pgs_front.jpg") );
1441 }
1442 {
1443 QUrl tmp;
1444 QUrl u = tmp.resolved(relative: QString("http://qt-project.org/images/ban/pgs_front.jpg"));
1445 QFileInfo fi(u.path());
1446 u.setPath(path: fi.path());
1447 QCOMPARE( u.path(), QString("/images/ban") );
1448 }
1449}
1450
1451void tst_QUrl::compat_constructor_01_data()
1452{
1453 QTest::addColumn<QString>(name: "urlStr");
1454 QTest::addColumn<QString>(name: "res");
1455
1456 //next we fill it with data
1457 QTest::newRow( dataTag: "data0" ) << QString("Makefile") << QString("Makefile"); // nolonger add file by default
1458 QTest::newRow( dataTag: "data1" ) << QString("Makefile") << QString("Makefile");
1459 QTest::newRow( dataTag: "data2" ) << QString("ftp://ftp.qt-project.org/qt/INSTALL") << QString("ftp://ftp.qt-project.org/qt/INSTALL");
1460 QTest::newRow( dataTag: "data3" ) << QString("ftp://ftp.qt-project.org/qt/INSTALL") << QString("ftp://ftp.qt-project.org/qt/INSTALL");
1461}
1462
1463void tst_QUrl::compat_constructor_01()
1464{
1465 QFETCH( QString, urlStr );
1466
1467 {
1468 QUrl empty;
1469 QUrl u = empty.resolved(relative: urlStr);
1470
1471 QTEST( u.toString(), "res" );
1472 }
1473 {
1474 QUrl empty;
1475 QUrl u = empty.resolved(relative: urlStr);
1476
1477 QTEST( u.toString(), "res" );
1478 }
1479}
1480
1481void tst_QUrl::compat_constructor_02_data()
1482{
1483 QTest::addColumn<QString>(name: "urlStr");
1484 QTest::addColumn<QString>(name: "fileName");
1485 QTest::addColumn<QString>(name: "res");
1486
1487 //next we fill it with data
1488 QTest::newRow( dataTag: "data0" ) << QString("ftp://ftp.qt-project.org/qt") << QString("INSTALL") << QString("ftp://ftp.qt-project.org/INSTALL");
1489 QTest::newRow( dataTag: "data1" ) << QString("ftp://ftp.qt-project.org/qt/") << QString("INSTALL") << QString("ftp://ftp.qt-project.org/qt/INSTALL");
1490}
1491
1492void tst_QUrl::compat_constructor_02()
1493{
1494 QFETCH( QString, urlStr );
1495 QFETCH( QString, fileName );
1496
1497 QUrl tmp( urlStr );
1498 QUrl u = tmp.resolved(relative: fileName);
1499
1500 QTEST( u.toString(), "res" );
1501}
1502
1503void tst_QUrl::compat_constructor_03_data()
1504{
1505 QTest::addColumn<QString>(name: "urlStr");
1506 QTest::addColumn<QString>(name: "res");
1507
1508 //next we fill it with data
1509 QTest::newRow( dataTag: "protocol00" ) << QString( "http://qt-project.org/index.html" ) << QString( "http://qt-project.org/index.html" );
1510 QTest::newRow( dataTag: "protocol01" ) << QString( "http://qt-project.org" ) << QString( "http://qt-project.org" );
1511 QTest::newRow( dataTag: "protocol02" ) << QString( "http://qt-project.org/" ) << QString( "http://qt-project.org/" );
1512 QTest::newRow( dataTag: "protocol03" ) << QString( "http://qt-project.org/foo" ) << QString( "http://qt-project.org/foo" );
1513 QTest::newRow( dataTag: "protocol04" ) << QString( "http://qt-project.org/foo/" ) << QString( "http://qt-project.org/foo/" );
1514 QTest::newRow( dataTag: "protocol05" ) << QString( "ftp://ftp.qt-project.org/foo/index.txt" ) << QString( "ftp://ftp.qt-project.org/foo/index.txt" );
1515
1516 QTest::newRow( dataTag: "local00" ) << QString( "/foo" ) << QString( "/foo" );
1517 QTest::newRow( dataTag: "local01" ) << QString( "/foo/" ) << QString( "/foo/" );
1518 QTest::newRow( dataTag: "local02" ) << QString( "/foo/bar" ) << QString( "/foo/bar" );
1519 QTest::newRow( dataTag: "local03" ) << QString( "/foo/bar/" ) << QString( "/foo/bar/" );
1520 QTest::newRow( dataTag: "local04" ) << QString( "foo" ) << QString( "foo" );
1521 QTest::newRow( dataTag: "local05" ) << QString( "foo/" ) << QString( "foo/" );
1522 QTest::newRow( dataTag: "local06" ) << QString( "foo/bar" ) << QString( "foo/bar" );
1523 QTest::newRow( dataTag: "local07" ) << QString( "foo/bar/" ) << QString( "foo/bar/" );
1524 QTest::newRow( dataTag: "local09" ) << QString( "" ) << QString( "" );
1525
1526 QTest::newRow( dataTag: "file00" ) << QString( "file:/foo" ) << QString( "file:///foo" );
1527 QTest::newRow( dataTag: "file01" ) << QString( "file:/foo/" ) << QString( "file:///foo/" );
1528 QTest::newRow( dataTag: "file02" ) << QString( "file:/foo/bar" ) << QString( "file:///foo/bar" );
1529 QTest::newRow( dataTag: "file03" ) << QString( "file:/foo/bar/" ) << QString( "file:///foo/bar/" );
1530 QTest::newRow( dataTag: "relProtocol00" ) << QString( "foo:bar" ) << QString( "foo:bar" );
1531 QTest::newRow( dataTag: "relProtocol01" ) << QString( "foo:/bar" ) << QString( "foo:/bar" );
1532
1533 QTest::newRow( dataTag: "windowsDrive00" ) << QString( "c:/" ) << QString( "c:/" );
1534 QTest::newRow( dataTag: "windowsDrive01" ) << QString( "c:" ) << QString( "c:" );
1535 QTest::newRow( dataTag: "windowsDrive02" ) << QString( "c:/WinNT/" ) << QString( "c:/WinNT/" );
1536 QTest::newRow( dataTag: "windowsDrive03" ) << QString( "c:/autoexec.bat" ) << QString( "c:/autoexec.bat" );
1537 QTest::newRow( dataTag: "windowsDrive04" ) << QString( "c:WinNT/" ) << QString( "c:WinNT/" );
1538 QTest::newRow( dataTag: "windowsDrive05" ) << QString( "c:autoexec.bat" ) << QString( "c:autoexec.bat" );
1539
1540 QTest::newRow(dataTag: "nopath") << QString("protocol://host") << QString("protocol://host");
1541}
1542
1543void tst_QUrl::compat_constructor_03()
1544{
1545 QFETCH( QString, urlStr );
1546
1547 QUrl u( urlStr );
1548 QTEST( u.toString(), "res" );
1549}
1550
1551void tst_QUrl::compat_isValid_01_data()
1552{
1553 QTest::addColumn<QString>(name: "urlStr");
1554 QTest::addColumn<bool>(name: "res");
1555
1556 QTest::newRow( dataTag: "ok_01" ) << QString("ftp://ftp.qt-project.org/qt/INSTALL") << (bool)true;
1557 QTest::newRow( dataTag: "ok_02" ) << QString( "file:/foo") << (bool)true;
1558 QTest::newRow( dataTag: "ok_03" ) << QString( "file:foo") << (bool)true;
1559
1560 QTest::newRow( dataTag: "err_01" ) << QString("#ftp://ftp.qt-project.org/qt/INSTALL") << (bool)true;
1561 QTest::newRow( dataTag: "err_02" ) << QString( "file:/::foo") << (bool)true;
1562}
1563
1564void tst_QUrl::compat_isValid_01()
1565{
1566 QFETCH( QString, urlStr );
1567 QFETCH( bool, res );
1568
1569 QUrl url( urlStr );
1570 QCOMPARE( url.isValid(), res );
1571 if (!res)
1572 QVERIFY(url.toString().isEmpty());
1573}
1574
1575void tst_QUrl::compat_isValid_02_data()
1576{
1577 QTest::addColumn<QString>(name: "protocol");
1578 QTest::addColumn<QString>(name: "user");
1579 QTest::addColumn<QString>(name: "password");
1580 QTest::addColumn<QString>(name: "host");
1581 QTest::addColumn<int>(name: "port");
1582 QTest::addColumn<QString>(name: "path");
1583 QTest::addColumn<bool>(name: "res");
1584
1585 QString n = "";
1586
1587 QTest::newRow( dataTag: "ok_01" ) << n << n << n << n << -1 << QString("path") << (bool)true;
1588 QTest::newRow( dataTag: "ok_02" ) << QString("ftp") << n << n << QString("ftp.qt-project.org") << -1 << n << (bool)true;
1589 QTest::newRow( dataTag: "ok_03" ) << QString("ftp") << QString("foo") << n << QString("ftp.qt-project.org") << -1 << n << (bool)true;
1590 QTest::newRow( dataTag: "ok_04" ) << QString("ftp") << QString("foo") << QString("bar") << QString("ftp.qt-project.org") << -1 << n << (bool)true;
1591 QTest::newRow( dataTag: "ok_05" ) << QString("ftp") << n << n << QString("ftp.qt-project.org") << -1 << QString("/path")<< (bool)true;
1592 QTest::newRow( dataTag: "ok_06" ) << QString("ftp") << QString("foo") << n << QString("ftp.qt-project.org") << -1 << QString("/path") << (bool)true;
1593 QTest::newRow( dataTag: "ok_07" ) << QString("ftp") << QString("foo") << QString("bar") << QString("ftp.qt-project.org") << -1 << QString("/path")<< (bool)true;
1594
1595 QTest::newRow( dataTag: "err_01" ) << n << n << n << n << -1 << n << (bool)false;
1596 QTest::newRow( dataTag: "err_02" ) << QString("ftp") << n << n << n << -1 << n << (bool)true;
1597 QTest::newRow( dataTag: "err_03" ) << n << QString("foo") << n << n << -1 << n << (bool)true;
1598 QTest::newRow( dataTag: "err_04" ) << n << n << QString("bar") << n << -1 << n << (bool)true;
1599 QTest::newRow( dataTag: "err_05" ) << n << n << n << QString("ftp.qt-project.org") << -1 << n << (bool)true;
1600 QTest::newRow( dataTag: "err_06" ) << n << n << n << n << 80 << n << (bool)true;
1601 QTest::newRow( dataTag: "err_07" ) << QString("ftp") << QString("foo") << n << n << -1 << n << (bool)true;
1602 QTest::newRow( dataTag: "err_08" ) << QString("ftp") << n << QString("bar") << n << -1 << n << (bool)true;
1603 QTest::newRow( dataTag: "err_09" ) << QString("ftp") << QString("foo") << QString("bar") << n << -1 << n << (bool)true;
1604}
1605
1606void tst_QUrl::compat_isValid_02()
1607{
1608 QFETCH( QString, protocol );
1609 QFETCH( QString, user );
1610 QFETCH( QString, password );
1611 QFETCH( QString, host );
1612 QFETCH( int, port );
1613 QFETCH( QString, path );
1614 QFETCH( bool, res );
1615
1616 QUrl url;
1617 if ( !protocol.isEmpty() )
1618 url.setScheme( protocol );
1619 if ( !user.isEmpty() )
1620 url.setUserName( userName: user );
1621 if ( !password.isEmpty() )
1622 url.setPassword( password );
1623 if ( !host.isEmpty() )
1624 url.setHost( host );
1625 if ( port != -1 )
1626 url.setPort( port );
1627 if ( !path.isEmpty() )
1628 url.setPath( path );
1629
1630 QCOMPARE( url.isValid(), res );
1631 if (!res)
1632 QVERIFY(url.toString().isEmpty());
1633}
1634
1635void tst_QUrl::compat_path_data()
1636{
1637 QTest::addColumn<QString>(name: "url");
1638 QTest::addColumn<QString>(name: "res");
1639
1640 QTest::newRow( dataTag: "protocol00" ) << "http://qt-project.org/images/ban/pgs_front.jpg" << "/images/ban/pgs_front.jpg";
1641
1642#if defined( Q_OS_WIN32 )
1643 QTest::newRow( "winShare00" ) << "//Anarki/homes" << "/homes";
1644#endif
1645}
1646
1647void tst_QUrl::compat_path()
1648{
1649 QFETCH( QString, url );
1650
1651 QUrl u( url );
1652 QTEST( u.path(), "res" );
1653}
1654
1655void tst_QUrl::compat_fileName_data()
1656{
1657 QTest::addColumn<QString>(name: "url");
1658 QTest::addColumn<QString>(name: "fileName");
1659
1660#ifdef Q_OS_WIN32
1661 QTest::newRow( "Windows - DrivePathFileName - \\" ) << QString("c:\\windows\\tmp\\filename.txt")<< QString("filename.txt");
1662 QTest::newRow( "Windows - DrivePathFileName - /" ) << QString("c:/windows/tmp/filename.txt") << QString("filename.txt");
1663 QTest::newRow( "Windows - DrivePathWithSlash - \\" ) << QString("c:\\windows\\tmp\\") << QString();
1664 QTest::newRow( "Windows - DrivePathWithSlash - /" ) << QString("c:/windows/tmp/") << QString();
1665 QTest::newRow( "Windows - DrivePathWithoutSlash - \\" ) << QString("c:/windows/tmp") << QString("tmp");
1666 QTest::newRow( "Windows - DrivePathWithoutSlash - /" ) << QString("c:/windows/tmp") << QString("tmp");
1667#endif
1668 QTest::newRow( dataTag: "Path00" ) << QString("/") << QString();
1669 QTest::newRow( dataTag: "Path01" ) << QString("/home/dev/test/") << QString();
1670 QTest::newRow( dataTag: "PathFileName00" ) << QString("/home/dev/test") << QString("test");
1671}
1672
1673void tst_QUrl::compat_fileName()
1674{
1675 QFETCH( QString, url );
1676 QFETCH( QString, fileName );
1677 QUrl fileUrl = QUrl::fromLocalFile(localfile: url);
1678 QFileInfo fi(fileUrl.toLocalFile());
1679 QCOMPARE( fi.fileName(), fileName );
1680}
1681
1682void tst_QUrl::compat_decode_data()
1683{
1684 QTest::addColumn<QByteArray>(name: "encodedString");
1685 QTest::addColumn<QString>(name: "decodedString");
1686
1687 QTest::newRow(dataTag: "NormalString") << QByteArray("filename") << QString("filename");
1688 QTest::newRow(dataTag: "NormalStringEncoded") << QByteArray("file%20name") << QString("file name");
1689 QTest::newRow(dataTag: "JustEncoded") << QByteArray("%20") << QString(" ");
1690 QTest::newRow(dataTag: "HTTPUrl") << QByteArray("http://qt-project.org") << QString("http://qt-project.org");
1691 QTest::newRow(dataTag: "HTTPUrlEncoded") << QByteArray("http://qt-project%20org") << QString("http://qt-project org");
1692 QTest::newRow(dataTag: "EmptyString") << QByteArray("") << QString("");
1693 QTest::newRow(dataTag: "NulByte") << QByteArray("C%00%0A") << QString::fromLatin1(str: "C\0\n", size: 3);
1694 QTest::newRow(dataTag: "Task27166") << QByteArray("Fran%C3%A7aise") << QString::fromUtf8(str: "Française");
1695}
1696
1697void tst_QUrl::compat_decode()
1698{
1699 QFETCH(QByteArray, encodedString);
1700 QFETCH(QString, decodedString);
1701
1702 QCOMPARE(QUrl::fromPercentEncoding(encodedString), decodedString);
1703}
1704
1705void tst_QUrl::compat_encode_data()
1706{
1707 QTest::addColumn<QString>(name: "decodedString");
1708 QTest::addColumn<QByteArray>(name: "encodedString");
1709
1710 QTest::newRow(dataTag: "NormalString") << QString("filename") << QByteArray("filename");
1711 QTest::newRow(dataTag: "NormalStringEncoded") << QString("file name") << QByteArray("file%20name");
1712 QTest::newRow(dataTag: "JustEncoded") << QString(" ") << QByteArray("%20");
1713 QTest::newRow(dataTag: "HTTPUrl") << QString("http://qt-project.org") << QByteArray("http%3A//qt-project.org");
1714 QTest::newRow(dataTag: "HTTPUrlEncoded") << QString("http://qt-project org") << QByteArray("http%3A//qt-project%20org");
1715 QTest::newRow(dataTag: "EmptyString") << QString("") << QByteArray("");
1716 QTest::newRow(dataTag: "NulByte") << QString::fromLatin1(str: "C\0\n", size: 3) << QByteArray("C%00%0A");
1717 QTest::newRow(dataTag: "Task27166") << QString::fromUtf8(str: "Française") << QByteArray("Fran%C3%A7aise");
1718}
1719
1720void tst_QUrl::compat_encode()
1721{
1722 QFETCH(QString, decodedString);
1723 QFETCH(QByteArray, encodedString);
1724
1725 QCOMPARE(QUrl::toPercentEncoding(decodedString, "/."), encodedString);
1726}
1727
1728
1729void tst_QUrl::relative()
1730{
1731 QUrl url("../ole");
1732 QCOMPARE(url.path(), QString::fromLatin1("../ole"));
1733
1734 QUrl url2("./");
1735 QCOMPARE(url2.path(), QString::fromLatin1("./"));
1736
1737 QUrl url3("..");
1738 QCOMPARE(url3.path(), QString::fromLatin1(".."));
1739
1740 QUrl url4("../..");
1741 QCOMPARE(url4.path(), QString::fromLatin1("../.."));
1742}
1743
1744void tst_QUrl::percentEncoding_data()
1745{
1746 // This test is limited. It's superseded by componentEncodings below
1747 QTest::addColumn<QString>(name: "original");
1748 QTest::addColumn<QByteArray>(name: "encoded");
1749
1750 QTest::newRow(dataTag: "test_01") << QString::fromLatin1(str: "sdfsdf") << QByteArray("sdfsdf");
1751 QTest::newRow(dataTag: "test_02") << QString::fromUtf8(str: "æss") << QByteArray("%C3%A6ss");
1752}
1753
1754void tst_QUrl::percentEncoding()
1755{
1756 // This test is limited. It's superseded by componentEncodings below
1757 QFETCH(QString, original);
1758 QFETCH(QByteArray, encoded);
1759
1760 QCOMPARE(QUrl(original).toEncoded().constData(), encoded.constData());
1761 QCOMPARE(QUrl::fromEncoded(QUrl(original).toEncoded()), QUrl(original));
1762 QCOMPARE(QUrl::fromEncoded(QUrl(original).toEncoded()).toString(), original);
1763 QCOMPARE(QUrl::fromEncoded(encoded), QUrl(original));
1764 QCOMPARE(QUrl(QUrl(original).toString()).toString(), original);
1765}
1766
1767void tst_QUrl::toPercentEncoding_data()
1768{
1769 QTest::addColumn<QString>(name: "original");
1770 QTest::addColumn<QByteArray>(name: "encoded");
1771 QTest::addColumn<QByteArray>(name: "excludeInEncoding");
1772 QTest::addColumn<QByteArray>(name: "includeInEncoding");
1773
1774 QTest::newRow(dataTag: "test_01") << QString::fromLatin1(str: "abcdevghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678-._~")
1775 << QByteArray("abcdevghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ012345678-._~")
1776 << QByteArray("")
1777 << QByteArray("");
1778 QTest::newRow(dataTag: "test_02") << QString::fromLatin1(str: "{\t\n\r^\"abc}")
1779 << QByteArray("%7B%09%0A%0D%5E%22abc%7D")
1780 << QByteArray("")
1781 << QByteArray("");
1782 QTest::newRow(dataTag: "test_03") << QString::fromLatin1(str: "://?#[]@!$&'()*+,;=")
1783 << QByteArray("%3A%2F%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D")
1784 << QByteArray("")
1785 << QByteArray("");
1786 QTest::newRow(dataTag: "test_04") << QString::fromLatin1(str: "://?#[]@!$&'()*+,;=")
1787 << QByteArray("%3A%2F%2F%3F%23%5B%5D%40!$&'()*+,;=")
1788 << QByteArray("!$&'()*+,;=")
1789 << QByteArray("");
1790 QTest::newRow(dataTag: "test_05") << QString::fromLatin1(str: "abcd")
1791 << QByteArray("a%62%63d")
1792 << QByteArray("")
1793 << QByteArray("bc");
1794}
1795
1796void tst_QUrl::toPercentEncoding()
1797{
1798 QFETCH(QString, original);
1799 QFETCH(QByteArray, encoded);
1800 QFETCH(QByteArray, excludeInEncoding);
1801 QFETCH(QByteArray, includeInEncoding);
1802
1803 QByteArray encodedUrl = QUrl::toPercentEncoding(original, exclude: excludeInEncoding, include: includeInEncoding);
1804 QCOMPARE(encodedUrl.constData(), encoded.constData());
1805 QCOMPARE(original, QUrl::fromPercentEncoding(encodedUrl));
1806}
1807
1808void tst_QUrl::swap()
1809{
1810 QUrl u1(QLatin1String("http://qt-project.org")), u2(QLatin1String("http://www.kdab.com"));
1811 u1.swap(other&: u2);
1812 QCOMPARE(u2.host(),QLatin1String("qt-project.org"));
1813 QCOMPARE(u1.host(),QLatin1String("www.kdab.com"));
1814}
1815
1816void tst_QUrl::symmetry()
1817{
1818 QUrl url(QString::fromUtf8(str: "http://www.räksmörgås.se/pub?a=b&a=dø&a=f#vræl"));
1819 QCOMPARE(url.scheme(), QString::fromLatin1("http"));
1820 QCOMPARE(url.host(), QString::fromUtf8("www.räksmörgås.se"));
1821 QCOMPARE(url.host(QUrl::EncodeSpaces), QString::fromUtf8("www.räksmörgås.se"));
1822 QCOMPARE(url.host(QUrl::EncodeUnicode), QString::fromUtf8("www.xn--rksmrgs-5wao1o.se"));
1823 QCOMPARE(url.host(QUrl::EncodeUnicode | QUrl::EncodeSpaces), QString::fromUtf8("www.xn--rksmrgs-5wao1o.se"));
1824 QCOMPARE(url.path(), QString::fromLatin1("/pub"));
1825 // this will be encoded ...
1826 QCOMPARE(url.query(QUrl::FullyEncoded), QLatin1String("a=b&a=d%C3%B8&a=f"));
1827 QCOMPARE(url.fragment(), QString::fromUtf8("vræl"));
1828
1829 QUrl onlyHost("//qt-project.org");
1830 QCOMPARE(onlyHost.toString(), QString::fromLatin1("//qt-project.org"));
1831
1832 {
1833 QString urlString = QString::fromLatin1(str: "http://desktop:33326/upnp/{32f525a6-6f31-426e-91ca-01c2e6c2c57e}");
1834 QString encodedUrlString = QString("http://desktop:33326/upnp/%7B32f525a6-6f31-426e-91ca-01c2e6c2c57e%7D");
1835 QUrl urlPreviewList(urlString);
1836 QCOMPARE(urlPreviewList.toString(), encodedUrlString);
1837 QByteArray b = urlPreviewList.toEncoded();
1838 QCOMPARE(b.constData(), encodedUrlString.toLatin1().constData());
1839 QCOMPARE(QUrl::fromEncoded(b).toString(), encodedUrlString);
1840 QCOMPARE(QUrl(b).toString(), encodedUrlString);
1841 }
1842 {
1843 QString urlString = QString::fromLatin1(str: "http://desktop:53423/deviceDescription?uuid={7977c17b-00bf-4af9-894e-fed28573c3a9}");
1844 QString encodedUrlString = QString("http://desktop:53423/deviceDescription?uuid=%7B7977c17b-00bf-4af9-894e-fed28573c3a9%7D");
1845 QUrl urlPreviewList(urlString);
1846 QCOMPARE(urlPreviewList.toString(), encodedUrlString);
1847 QByteArray b = urlPreviewList.toEncoded();
1848 QCOMPARE(b.constData(), encodedUrlString.toLatin1().constData());
1849 QCOMPARE(QUrl::fromEncoded(b).toString(), encodedUrlString);
1850 QCOMPARE(QUrl(b).toString(), encodedUrlString);
1851 }
1852}
1853
1854void tst_QUrl::ipvfuture_data()
1855{
1856 QTest::addColumn<QString>(name: "input");
1857 QTest::addColumn<bool>(name: "isValid");
1858 QTest::addColumn<QString>(name: "output");
1859
1860 // No one uses IPvFuture yet, so we have no clue what it might contain
1861 // We're just testing that it can hold what the RFC says it should hold:
1862 // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
1863 QTest::newRow(dataTag: "missing-version-dot") << "x://[v]" << false;
1864 QTest::newRow(dataTag: "missing-version") << "x://[v.]" << false;
1865 QTest::newRow(dataTag: "missing-version-2") << "x://[v.1234]" << false;
1866 QTest::newRow(dataTag: "missing-dot") << "x://[v7]" << false;
1867 QTest::newRow(dataTag: "missing-dot-2") << "x://[v71234]" << false;
1868 QTest::newRow(dataTag: "missing-data") << "x://[v7.]" << false;
1869 QTest::newRow(dataTag: "non-hex-version") << "x://[vz.1234]" << false;
1870
1871 QTest::newRow(dataTag: "digit-ver") << "x://[v7.1]" << true << "x://[v7.1]";
1872 QTest::newRow(dataTag: "lowercase-hex-ver") << "x://[va.1]" << true << "x://[vA.1]";
1873 QTest::newRow(dataTag: "lowercase-hex-ver") << "x://[vA.1]" << true << "x://[vA.1]";
1874
1875 QTest::newRow(dataTag: "data-digits") << "x://[v7.1234]" << true << "x://[v7.1234]";
1876 QTest::newRow(dataTag: "data-unreserved") << "x://[v7.hello~-WORLD_.com]" << true << "x://[v7.hello~-WORLD_.com]";
1877 QTest::newRow(dataTag: "data-sub-delims-colon") << "x://[v7.!$&'()*+,;=:]" << true << "x://[v7.!$&'()*+,;=:]";
1878
1879 // we're using the tolerant parser
1880 QTest::newRow(dataTag: "data-encoded-digits") << "x://[v7.%31%32%33%34]" << true << "x://[v7.1234]";
1881 QTest::newRow(dataTag: "data-encoded-unreserved") << "x://[v7.%7E%2D%54%5f%2E]" << true << "x://[v7.~-T_.]";
1882 QTest::newRow(dataTag: "data-encoded-sub-delims-colon") << "x://[v7.%21%24%26%27%28%29%2A%2B%2C%3B%3D%3A]" << true << "x://[v7.!$&'()*+,;=:]";
1883
1884 // should we test "[%76%37%2ex]" -> "[v7.x]" ?
1885
1886 QTest::newRow(dataTag: "data-invalid-space") << "x://[v7.%20]" << false;
1887 QTest::newRow(dataTag: "data-invalid-control") << "x://[v7.\x7f]" << false;
1888 QTest::newRow(dataTag: "data-invalid-other-1") << "x://[v7.{1234}]" << false;
1889 QTest::newRow(dataTag: "data-invalid-other-2") << "x://[v7.<hello>]" << false;
1890 QTest::newRow(dataTag: "data-invalid-unicode") << "x://[v7.æøå]" << false;
1891 QTest::newRow(dataTag: "data-invalid-percent") << "x://[v7.%]" << false;
1892 QTest::newRow(dataTag: "data-invalid-percent-percent") << "x://[v7.%25]" << false;
1893}
1894
1895void tst_QUrl::ipvfuture()
1896{
1897 QFETCH(QString, input);
1898 QFETCH(bool, isValid);
1899
1900 QUrl url(input);
1901 if (isValid) {
1902 QVERIFY2(url.isValid(), qPrintable(url.errorString()));
1903
1904 QFETCH(QString, output);
1905 QCOMPARE(url.toString(), output);
1906
1907 QUrl url2(output);
1908 QCOMPARE(url2, url);
1909 } else {
1910 QVERIFY(!url.isValid());
1911 }
1912}
1913
1914
1915void tst_QUrl::ipv6_data()
1916{
1917 QTest::addColumn<QString>(name: "ipv6Auth");
1918 QTest::addColumn<bool>(name: "isValid");
1919 QTest::addColumn<QString>(name: "output");
1920
1921 QTest::newRow(dataTag: "empty") << "//[]" << false << "";
1922
1923 QTest::newRow(dataTag: "case 1") << QString::fromLatin1(str: "//[56:56:56:56:56:56:56:56]") << true
1924 << "//[56:56:56:56:56:56:56:56]";
1925 QTest::newRow(dataTag: "case 2") << QString::fromLatin1(str: "//[::56:56:56:56:56:56:56]") << true
1926 << "//[0:56:56:56:56:56:56:56]";
1927 QTest::newRow(dataTag: "case 3") << QString::fromLatin1(str: "//[56::56:56:56:56:56:56]") << true
1928 << "//[56:0:56:56:56:56:56:56]";
1929 QTest::newRow(dataTag: "case 4") << QString::fromLatin1(str: "//[56:56::56:56:56:56:56]") << true
1930 << "//[56:56:0:56:56:56:56:56]";
1931 QTest::newRow(dataTag: "case 5") << QString::fromLatin1(str: "//[56:56:56::56:56:56:56]") << true
1932 << "//[56:56:56:0:56:56:56:56]";
1933 QTest::newRow(dataTag: "case 6") << QString::fromLatin1(str: "//[56:56:56:56::56:56:56]") << true
1934 << "//[56:56:56:56:0:56:56:56]";
1935 QTest::newRow(dataTag: "case 7") << QString::fromLatin1(str: "//[56:56:56:56:56::56:56]") << true
1936 << "//[56:56:56:56:56:0:56:56]";
1937 QTest::newRow(dataTag: "case 8") << QString::fromLatin1(str: "//[56:56:56:56:56:56::56]") << true
1938 << "//[56:56:56:56:56:56:0:56]";
1939 QTest::newRow(dataTag: "case 9") << QString::fromLatin1(str: "//[56:56:56:56:56:56:56::]") << true
1940 << "//[56:56:56:56:56:56:56:0]";
1941 QTest::newRow(dataTag: "case 4 with one less") << QString::fromLatin1(str: "//[56::56:56:56:56:56]") << true
1942 << "//[56::56:56:56:56:56]";
1943 QTest::newRow(dataTag: "case 4 with less and ip4") << QString::fromLatin1(str: "//[56::56:56:56:127.0.0.1]") << true
1944 << "//[56::56:56:56:7f00:1]";
1945 QTest::newRow(dataTag: "case 7 with one and ip4") << QString::fromLatin1(str: "//[56::255.0.0.0]") << true
1946 << "//[56::ff00:0]";
1947 QTest::newRow(dataTag: "case 2 with ip4") << QString::fromLatin1(str: "//[::56:56:56:56:56:0.0.0.255]") << true
1948 << "//[0:56:56:56:56:56:0:ff]";
1949 QTest::newRow(dataTag: "case 2 with half ip4") << QString::fromLatin1(str: "//[::56:56:56:56:56:56:0.255]") << false << "";
1950 QTest::newRow(dataTag: "case 4 with less and ip4 and port and useinfo")
1951 << QString::fromLatin1(str: "//user:pass@[56::56:56:56:127.0.0.1]:99") << true
1952 << "//user:pass@[56::56:56:56:7f00:1]:99";
1953 QTest::newRow(dataTag: "case :,") << QString::fromLatin1(str: "//[:,]") << false << "";
1954 QTest::newRow(dataTag: "case ::bla") << QString::fromLatin1(str: "//[::bla]") << false << "";
1955 QTest::newRow(dataTag: "case v4-mapped") << "//[0:0:0:0:0:ffff:7f00:1]" << true << "//[::ffff:127.0.0.1]";
1956
1957 QTest::newRow(dataTag: "encoded-digit") << "//[::%31]" << true << "//[::1]";
1958 QTest::newRow(dataTag: "encoded-colon") << "//[%3A%3A]" << true << "//[::]";
1959
1960 QTest::newRow(dataTag: "full ipv6 with zone id (decoded %)") << QString::fromLatin1(str: "//[56:56:56:56:56:56:56:56%eth0]") << true
1961 << "//[56:56:56:56:56:56:56:56%25eth0]";
1962
1963 QTest::newRow(dataTag: "full ipv6 with zone id (encoded %)") << QString::fromLatin1(str: "//[56:56:56:56:56:56:56:56%25eth0]") << true
1964 << "//[56:56:56:56:56:56:56:56%25eth0]";
1965
1966 QTest::newRow(dataTag: "full ipv6 with invalid zone id") << QString::fromLatin1(str: "//[56:56:56:56:56:56:56:56%]") << false << "";
1967
1968 QTest::newRow(dataTag: "full ipv6 with invalid zone id (encoded)") << QString::fromLatin1(str: "//[56:56:56:56:56:56:56:56%25]") << false << "";
1969
1970 QTest::newRow(dataTag: "full ipv6 with zone id 25 (encoded)") << QString::fromLatin1(str: "//[56:56:56:56:56:56:56:56%2525]") << true << "//[56:56:56:56:56:56:56:56%2525]";
1971
1972 QTest::newRow(dataTag: "case 4 with less and ip4 and port and useinfo and zone id")
1973 << QString::fromLatin1(str: "//user:pass@[56::56:56:56:127.0.0.1%ethernet_1]:99") << true
1974 << "//user:pass@[56::56:56:56:7f00:1%25ethernet_1]:99";
1975
1976 QTest::newRow(dataTag: "encoded-digit including zone id") << "//[::%31%25eth0]" << true << "//[::1%25eth0]";
1977}
1978
1979void tst_QUrl::ipv6()
1980{
1981 QFETCH(QString, ipv6Auth);
1982 QFETCH(bool, isValid);
1983 QFETCH(QString, output);
1984
1985 QUrl url(ipv6Auth);
1986
1987 QCOMPARE(url.isValid(), isValid);
1988 QCOMPARE(url.toString().isEmpty(), !isValid);
1989 if (url.isValid()) {
1990 QCOMPARE(url.toString(), output);
1991 url.setHost(host: url.host());
1992 QVERIFY(url.isValid());
1993 QCOMPARE(url.toString(), output);
1994 }
1995}
1996
1997void tst_QUrl::ipv6_2_data()
1998{
1999 QTest::addColumn<QString>(name: "input");
2000 QTest::addColumn<QString>(name: "output");
2001
2002 QTest::newRow(dataTag: "[::ffff:129.144.52.38]")
2003 << QString("http://[::ffff:129.144.52.38]/cgi/test.cgi")
2004 << QString("http://[::ffff:129.144.52.38]/cgi/test.cgi");
2005 QTest::newRow(dataTag: "[::FFFF:129.144.52.38]")
2006 << QString("http://[::FFFF:129.144.52.38]/cgi/test.cgi")
2007 << QString("http://[::ffff:129.144.52.38]/cgi/test.cgi");
2008}
2009
2010void tst_QUrl::ipv6_2()
2011{
2012 QFETCH(QString, input);
2013 QFETCH(QString, output);
2014
2015 QUrl url(input);
2016 QCOMPARE(url.toString(), output);
2017 url.setHost(host: url.host());
2018 QCOMPARE(url.toString(), output);
2019}
2020
2021void tst_QUrl::moreIpv6()
2022{
2023 QUrl waba1("http://www.kde.org/cgi/test.cgi");
2024 waba1.setHost(host: "::ffff:129.144.52.38");
2025 QCOMPARE(QString::fromLatin1(waba1.toEncoded()), QString::fromLatin1("http://[::ffff:129.144.52.38]/cgi/test.cgi"));
2026}
2027
2028void tst_QUrl::isRelative_data()
2029{
2030 QTest::addColumn<QString>(name: "url");
2031 QTest::addColumn<bool>(name: "trueFalse");
2032
2033 QTest::newRow(dataTag: "not") << QString::fromLatin1(str: "http://qt-project.org") << false;
2034 QTest::newRow(dataTag: "55288") << QString::fromLatin1(str: "node64.html#fig:form:ana") << true;
2035
2036 // kde
2037 QTest::newRow(dataTag: "mailto: URL, is relative") << "mailto:faure@kde.org" << false;
2038 QTest::newRow(dataTag: "man: URL, is relative") << "man:mmap" << false;
2039 QTest::newRow(dataTag: "javascript: URL, is relative") << "javascript:doSomething()" << false;
2040 QTest::newRow(dataTag: "file: URL, is relative") << "file:/blah" << false;
2041 QTest::newRow(dataTag: "/path, is relative") << "/path" << true;
2042 QTest::newRow(dataTag: "something, is relative") << "something" << true;
2043 // end kde
2044}
2045
2046void tst_QUrl::isRelative()
2047{
2048 QFETCH(QString, url);
2049 QFETCH(bool, trueFalse);
2050
2051 QCOMPARE(QUrl(url).isRelative(), trueFalse);
2052}
2053
2054void tst_QUrl::hasQuery_data()
2055{
2056 QTest::addColumn<QString>(name: "url");
2057 QTest::addColumn<bool>(name: "trueFalse");
2058
2059 QTest::newRow(dataTag: "no query items") << "http://www.foo.bar" << false;
2060
2061 QTest::newRow(dataTag: "empty query") << "http://www.foo.bar?" << true;
2062 QTest::newRow(dataTag: "empty query 2") << "http://www.foo.bar/?" << true;
2063
2064 QTest::newRow(dataTag: "query") << "http://www.foo.bar?query" << true;
2065 QTest::newRow(dataTag: "query=") << "http://www.foo.bar?query=" << true;
2066 QTest::newRow(dataTag: "query=value") << "http://www.foo.bar?query=value" << true;
2067
2068 QTest::newRow(dataTag: "%3f") << "http://www.foo.bar/file%3f" << false;
2069 QTest::newRow(dataTag: "%3f-query") << "http://www.foo.bar/file%3fquery" << false;
2070 QTest::newRow(dataTag: "%3f-query=value") << "http://www.foo.bar/file%3fquery=value" << false;
2071}
2072
2073void tst_QUrl::hasQuery()
2074{
2075 QFETCH(QString, url);
2076 QFETCH(bool, trueFalse);
2077
2078 QUrl qurl(url);
2079 QCOMPARE(qurl.hasQuery(), trueFalse);
2080 QCOMPARE(qurl.query().isNull(), !trueFalse);
2081}
2082
2083void tst_QUrl::nameprep()
2084{
2085 QUrl url(QString::fromUtf8(str: "http://www.fu""\xc3""\x9f""ball.de/"));
2086 QCOMPARE(url.toString(), QString::fromLatin1("http://www.fussball.de/"));
2087}
2088
2089void tst_QUrl::isValid()
2090{
2091 {
2092 QUrl url(QString("A=B"));
2093 QVERIFY(url.isValid());
2094 QVERIFY(!url.toString().isEmpty());
2095 QCOMPARE(url.path(), QString("A=B"));
2096 }
2097 {
2098 QUrl url = QUrl::fromEncoded(url: "http://strange<username>@ok-hostname/", mode: QUrl::StrictMode);
2099 QVERIFY(!url.isValid());
2100 QVERIFY(url.toString().isEmpty());
2101 // < and > are not allowed in userinfo in strict mode
2102 url.setUserName(userName: "normal_username");
2103 QVERIFY(url.isValid());
2104 }
2105 {
2106 QUrl url = QUrl::fromEncoded(url: "http://strange<username>@ok-hostname/");
2107 QVERIFY(url.isValid());
2108 QVERIFY(!url.toString().isEmpty());
2109 // < and > are allowed in tolerant mode
2110 QCOMPARE(url.toEncoded(), QByteArray("http://strange%3Cusername%3E@ok-hostname/"));
2111 }
2112 {
2113 QUrl url = QUrl::fromEncoded(url: "http://strange;hostname/here");
2114 QVERIFY(!url.isValid());
2115 QVERIFY(url.toString().isEmpty());
2116 QCOMPARE(url.path(), QString("/here"));
2117 url.setAuthority(authority: "strange;hostname");
2118 QVERIFY(!url.isValid());
2119 QVERIFY(url.toString().isEmpty());
2120 url.setAuthority(authority: "foobar@bar");
2121 QVERIFY(url.isValid());
2122 QVERIFY(!url.toString().isEmpty());
2123 url.setAuthority(authority: "strange;hostname");
2124 QVERIFY(!url.isValid());
2125 QVERIFY(url.toString().isEmpty());
2126 QVERIFY2(url.errorString().contains("Invalid hostname"),
2127 qPrintable(url.errorString()));
2128 }
2129
2130 {
2131 QUrl url = QUrl::fromEncoded(url: "foo://stuff;1/g");
2132 QVERIFY(!url.isValid());
2133 QVERIFY(url.toString().isEmpty());
2134 QCOMPARE(url.path(), QString("/g"));
2135 url.setHost(host: "stuff;1");
2136 QVERIFY(!url.isValid());
2137 QVERIFY(url.toString().isEmpty());
2138 url.setHost(host: "stuff-1");
2139 QVERIFY(url.isValid());
2140 QVERIFY(!url.toString().isEmpty());
2141 url.setHost(host: "stuff;1");
2142 QVERIFY(!url.isValid());
2143 QVERIFY(url.toString().isEmpty());
2144 QVERIFY2(url.errorString().contains("Invalid hostname"),
2145 qPrintable(url.errorString()));
2146 }
2147
2148 {
2149 QUrl url = QUrl::fromEncoded(url: "foo://%f0%9f%93%99.example.la/g");
2150 QVERIFY(!url.isValid());
2151 QVERIFY(url.toString().isEmpty());
2152 QCOMPARE(url.path(), QString("/g"));
2153 url.setHost(host: "%f0%9f%93%99.example.la/");
2154 QVERIFY(!url.isValid());
2155 QVERIFY(url.toString().isEmpty());
2156 url.setHost(host: "\xf0\x9f\x93\x99.example.la/");
2157 QVERIFY(!url.isValid());
2158 QVERIFY(url.toString().isEmpty());
2159 QVERIFY2(url.errorString().contains("Invalid hostname"),
2160 qPrintable(url.errorString()));
2161 }
2162
2163 {
2164 QUrl url("http://example.com");
2165 QVERIFY(url.isValid());
2166 QVERIFY(!url.toString().isEmpty());
2167 url.setPath(path: "relative");
2168 QVERIFY(!url.isValid());
2169 QVERIFY(url.toString().isEmpty());
2170 QVERIFY(url.errorString().contains("Path component is relative and authority is present"));
2171 }
2172
2173 {
2174 QUrl url("http:");
2175 url.setPath(path: "//example.com");
2176 QVERIFY(!url.isValid());
2177 QVERIFY(url.toString().isEmpty());
2178 QVERIFY(url.errorString().contains("Path component starts with '//' and authority is absent"));
2179
2180 // should disappear if we set a port
2181 url.setPort(80);
2182 QVERIFY(url.isValid());
2183 QCOMPARE(url.toString(), QString("http://:80//example.com"));
2184 }
2185
2186 {
2187 QUrl url;
2188 url.setPath(path: "http://example.com");
2189 QVERIFY(!url.isValid());
2190 QVERIFY(url.toString().isEmpty());
2191 QVERIFY(url.errorString().contains("':' before any '/'"));
2192
2193 // this specific error disappears if we set anything in the authority,
2194 // but then we run into another error
2195 url.setPort(80);
2196 QVERIFY(!url.isValid());
2197 QVERIFY(url.toString().isEmpty());
2198 QVERIFY(url.errorString().contains("Path component is relative and authority is present"));
2199 }
2200
2201 {
2202 QUrl url("file://./localfile.html");
2203 QVERIFY(!url.isValid());
2204 }
2205}
2206
2207void tst_QUrl::schemeValidator_data()
2208{
2209 QTest::addColumn<QString>(name: "input");
2210 QTest::addColumn<bool>(name: "result");
2211 QTest::addColumn<QString>(name: "scheme");
2212
2213 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
2214
2215 QTest::newRow(dataTag: "empty") << QString() << false << QString();
2216
2217 // uncontroversial ones
2218 QTest::newRow(dataTag: "ftp") << "ftp://ftp.example.com/" << true << "ftp";
2219 QTest::newRow(dataTag: "http") << "http://www.example.com/" << true << "http";
2220 QTest::newRow(dataTag: "mailto") << "mailto:smith@example.com" << true << "mailto";
2221 QTest::newRow(dataTag: "file-1slash") << "file:/etc/passwd" << true << "file";
2222 QTest::newRow(dataTag: "file-2slashes") << "file://server/etc/passwd" << true << "file";
2223 QTest::newRow(dataTag: "file-3slashes") << "file:///etc/passwd" << true << "file";
2224
2225 QTest::newRow(dataTag: "mailto+subject") << "mailto:smith@example.com?subject=Hello%20World" << true << "mailto";
2226 QTest::newRow(dataTag: "mailto+host") << "mailto://smtp.example.com/smith@example.com" << true << "mailto";
2227
2228 // valid, but unexpected
2229 QTest::newRow(dataTag: "ftp-nohost") << "ftp:/etc/passwd" << true << "ftp";
2230 QTest::newRow(dataTag: "http-nohost") << "http:/etc/passwd" << true << "http";
2231 QTest::newRow(dataTag: "mailto-nomail") << "mailto://smtp.example.com" << true << "mailto";
2232
2233 // schemes with numbers
2234 QTest::newRow(dataTag: "digits") << "proto2://" << true << "proto2";
2235
2236 // schemes with dots, dashes, and pluses
2237 QTest::newRow(dataTag: "svn+ssh") << "svn+ssh://svn.example.com" << true << "svn+ssh";
2238 QTest::newRow(dataTag: "withdash") << "svn-ssh://svn.example.com" << true << "svn-ssh";
2239 QTest::newRow(dataTag: "withdots") << "org.qt-project://qt-project.org" << true << "org.qt-project";
2240
2241 // lowercasing
2242 QTest::newRow(dataTag: "FTP") << "FTP://ftp.example.com/" << true << "ftp";
2243 QTest::newRow(dataTag: "HTTP") << "HTTP://www.example.com/" << true << "http";
2244 QTest::newRow(dataTag: "MAILTO") << "MAILTO:smith@example.com" << true << "mailto";
2245 QTest::newRow(dataTag: "FILE") << "FILE:/etc/passwd" << true << "file";
2246 QTest::newRow(dataTag: "SVN+SSH") << "SVN+SSH://svn.example.com" << true << "svn+ssh";
2247 QTest::newRow(dataTag: "WITHDASH") << "SVN-SSH://svn.example.com" << true << "svn-ssh";
2248 QTest::newRow(dataTag: "WITHDOTS") << "ORG.QT-PROJECT://qt-project.org" << true << "org.qt-project";
2249
2250 // invalid entries
2251 QTest::newRow(dataTag: "start-digit") << "1http://example.com" << false << "1http";
2252 QTest::newRow(dataTag: "start-plus") << "+ssh://user@example.com" << false << "+ssh";
2253 QTest::newRow(dataTag: "start-dot") << ".org.example:///" << false << ".org.example";
2254 QTest::newRow(dataTag: "with-space") << "a b://" << false << "a b";
2255 QTest::newRow(dataTag: "with-non-ascii") << "\304\245\305\243\305\245\321\200://example.com" << false << "\304\245\305\243\305\245\321\200";
2256 QTest::newRow(dataTag: "with-control1") << "http\1://example.com" << false << "http\1";
2257 QTest::newRow(dataTag: "with-control127") << "http\177://example.com" << false << "http\177";
2258 QTest::newRow(dataTag: "with-null") << QString::fromLatin1(str: "http\0://example.com", size: 19) << false << QString::fromLatin1(str: "http\0", size: 5);
2259
2260 QTest::newRow(dataTag: "percent-encoded") << "%68%74%%74%70://example.com" << false << "%68%74%%74%70";
2261
2262 static const char controls[] = "!\"$&'()*,;<=>[\\]^_`{|}~";
2263 for (char control : controls) {
2264 const QString scheme = QLatin1String("pre") + QLatin1Char(control) + QLatin1String("post");
2265 QTest::newRow(dataTag: (QByteArrayLiteral("with-") + control).constData())
2266 << (scheme + QLatin1String("://example.com/"))
2267 << false << scheme;
2268 }
2269}
2270
2271void tst_QUrl::schemeValidator()
2272{
2273 QFETCH(QString, input);
2274 QFETCH(bool, result);
2275
2276 QUrl url(input);
2277 QCOMPARE(url.isValid(), result);
2278 if (result) {
2279 QFETCH(QString, scheme);
2280 QCOMPARE(url.scheme(), scheme);
2281
2282 // reconstruct with just the scheme:
2283 url.setUrl(url: scheme + ':');
2284 QVERIFY(url.isValid());
2285 QCOMPARE(url.scheme(), scheme);
2286 } else {
2287 QVERIFY(url.toString().isEmpty());
2288 }
2289}
2290
2291void tst_QUrl::setScheme_data()
2292{
2293 schemeValidator_data();
2294
2295 // a couple more which wouldn't work in parsing a full URL
2296 QTest::newRow(dataTag: "with-slash") << QString() << false << "http/";
2297 QTest::newRow(dataTag: "with-question") << QString() << false << "http?";
2298 QTest::newRow(dataTag: "with-hash") << QString() << false << "http#";
2299}
2300
2301void tst_QUrl::setScheme()
2302{
2303 QFETCH(QString, scheme);
2304 QFETCH(bool, result);
2305 QString expectedScheme;
2306 if (result)
2307 expectedScheme = scheme;
2308
2309 QUrl url;
2310 url.setScheme(scheme);
2311 QCOMPARE(url.isValid(), result);
2312 QCOMPARE(url.scheme(), expectedScheme);
2313
2314 url.setScheme(scheme.toUpper());
2315 QCOMPARE(url.isValid(), result);
2316 QCOMPARE(url.scheme(), expectedScheme);
2317}
2318
2319void tst_QUrl::strictParser_data()
2320{
2321 QTest::addColumn<QString>(name: "input");
2322 QTest::addColumn<QString>(name: "needle");
2323
2324 // QUrl doesn't detect an error in the scheme when parsing because
2325 // it falls back to parsing as a path. So, these errors are path errors
2326 QTest::newRow(dataTag: "invalid-scheme") << "ht%://example.com" << "character '%' not permitted";
2327 QTest::newRow(dataTag: "empty-scheme") << ":/" << "':' before any '/'";
2328
2329 QTest::newRow(dataTag: "invalid-user1") << "http://bad<user_name>@ok-hostname" << "Invalid user name (character '<' not permitted)";
2330 QTest::newRow(dataTag: "invalid-user2") << "http://bad%@ok-hostname" << "Invalid user name (character '%' not permitted)";
2331
2332 QTest::newRow(dataTag: "invalid-password") << "http://user:pass\x7F@ok-hostname" << "Invalid password (character '\x7F' not permitted)";
2333
2334 QTest::newRow(dataTag: "invalid-regname") << "http://bad<hostname>" << "Invalid hostname (contains invalid characters)";
2335 QTest::newRow(dataTag: "invalid-regname-2") << "http://b%61d" << "Invalid hostname (contains invalid characters)";
2336 QTest::newRow(dataTag: "invalid-ipv6") << "http://[:::]" << "Invalid IPv6 address";
2337 QTest::newRow(dataTag: "invalid-ipv6-char1") << "http://[::g]" << "Invalid IPv6 address (character 'g' not permitted)";
2338 QTest::newRow(dataTag: "invalid-ipv6-char2") << "http://[z::]" << "Invalid IPv6 address (character 'z' not permitted)";
2339 QTest::newRow(dataTag: "invalid-ipvfuture-1") << "http://[v7]" << "Invalid IPvFuture address";
2340 QTest::newRow(dataTag: "invalid-ipvfuture-2") << "http://[v7.]" << "Invalid IPvFuture address";
2341 QTest::newRow(dataTag: "invalid-ipvfuture-3") << "http://[v789]" << "Invalid IPvFuture address";
2342 QTest::newRow(dataTag: "invalid-ipvfuture-char1") << "http://[v7.^]" << "Invalid IPvFuture address";
2343 QTest::newRow(dataTag: "invalid-encoded-ipv6") << "x://[%3a%3a%31]" << "Invalid IPv6 address";
2344 QTest::newRow(dataTag: "invalid-encoded-ipvfuture") << "x://[v7.%7E%2D%54%5f%2E]" << "Invalid IPvFuture address";
2345 QTest::newRow(dataTag: "unbalanced-brackets") << "http://[ff02::1" << "Expected ']' to match '[' in hostname";
2346
2347 // invalid hostnames happen in TolerantMode too
2348 QTest::newRow(dataTag: "invalid-hostname-leading-dot") << "http://.co.uk" << "Invalid hostname (contains invalid characters)";
2349 QTest::newRow(dataTag: "invalid-hostname-double-dot") << "http://co..uk" << "Invalid hostname (contains invalid characters)";
2350 QTest::newRow(dataTag: "invalid-hostname-non-LDH") << "http://foo,bar.example.com" << "Invalid hostname (contains invalid characters)";
2351 QTest::newRow(dataTag: "idn-prohibited-char-space") << "http:// " << "Invalid hostname (contains invalid characters)";
2352 QTest::newRow(dataTag: "idn-prohibited-char-nbsp") << "http://\xc2\xa0" << "Invalid hostname (contains invalid characters)";
2353 QTest::newRow(dataTag: "idn-prohibited-char-control-1f") << "http://\x1f" << "Invalid hostname (contains invalid characters)";
2354 QTest::newRow(dataTag: "idn-prohibited-char-control-7f") << "http://\x7f" << "Invalid hostname (contains invalid characters)";
2355 QTest::newRow(dataTag: "idn-prohibited-char-control-80") << "http://\xc2\x80" << "Invalid hostname (contains invalid characters)";
2356 QTest::newRow(dataTag: "idn-prohibited-char-private-bmp") << "http://\xee\x80\x80" << "Invalid hostname (contains invalid characters)";
2357 QTest::newRow(dataTag: "idn-prohibited-char-private-plane15") << "http://\xf3\xb0\x80\x80" << "Invalid hostname (contains invalid characters)";
2358 QTest::newRow(dataTag: "idn-prohibited-char-private-plane16") << "http://\xf4\x80\x80\x80" << "Invalid hostname (contains invalid characters)";
2359 QTest::newRow(dataTag: "idn-prohibited-char-ffff") << "http://\xef\xbf\xbf" << "Invalid hostname (contains invalid characters)";
2360 QTest::newRow(dataTag: "idn-prohibited-char-surrogate-1") << "http://" + QString(QChar(0xD800)) << "Invalid hostname (contains invalid characters)";
2361 QTest::newRow(dataTag: "idn-prohibited-char-surrogate-2") << "http://" + QString(QChar(0xDC00)) << "Invalid hostname (contains invalid characters)";
2362 QTest::newRow(dataTag: "idn-prohibited-char-surrogate-3") << "http://" + QString(QChar(0xD800)) + "a" << "Invalid hostname (contains invalid characters)";
2363 // FIXME: add some tests for prohibited BiDi (RFC 3454 section 6)
2364
2365 // port errors happen in TolerantMode too
2366 QTest::newRow(dataTag: "invalid-port-1") << "http://example.com:-1" << "Invalid port";
2367 QTest::newRow(dataTag: "invalid-port-2") << "http://example.com:abc" << "Invalid port";
2368 QTest::newRow(dataTag: "invalid-port-3") << "http://example.com:9a" << "Invalid port";
2369 QTest::newRow(dataTag: "port-range") << "http://example.com:65536" << "out of range";
2370
2371 QTest::newRow(dataTag: "invalid-path") << "foo:/path%\x1F" << "Invalid path (character '%' not permitted)";
2372
2373 QTest::newRow(dataTag: "invalid-query") << "foo:?\\#" << "Invalid query (character '\\' not permitted)";
2374
2375 QTest::newRow(dataTag: "invalid-fragment") << "#{}" << "Invalid fragment (character '{' not permitted)";
2376}
2377
2378void tst_QUrl::strictParser()
2379{
2380 QFETCH(QString, input);
2381 QFETCH(QString, needle);
2382
2383 QUrl url(input, QUrl::StrictMode);
2384 QVERIFY(!url.isValid());
2385 QVERIFY(url.toString().isEmpty());
2386 QVERIFY(!url.errorString().isEmpty());
2387 QVERIFY2(url.errorString().contains(input),
2388 "Error string does not contain the original input (\"" +
2389 input.toLatin1() + "\"): " + url.errorString().toLatin1());
2390
2391 // Note: if the following fails due to changes in the parser, simply update the test data
2392 QVERIFY2(url.errorString().contains(needle),
2393 "Error string changed and does not contain \"" +
2394 needle.toLatin1() + "\" anymore: " + url.errorString().toLatin1());
2395}
2396
2397void tst_QUrl::tolerantParser()
2398{
2399 {
2400 QUrl url("http://www.example.com/path%20with spaces.html");
2401 QVERIFY(url.isValid());
2402 QVERIFY(!url.toString().isEmpty());
2403 QCOMPARE(url.path(), QString("/path with spaces.html"));
2404 QCOMPARE(url.toEncoded(), QByteArray("http://www.example.com/path%20with%20spaces.html"));
2405 QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://www.example.com/path%20with%20spaces.html"));
2406 url.setUrl(url: "http://www.example.com/path%20with spaces.html", mode: QUrl::StrictMode);
2407 QVERIFY(!url.isValid());
2408 QVERIFY(url.toString().isEmpty());
2409 }
2410 {
2411 QUrl url = QUrl::fromEncoded(url: "http://www.example.com/path%20with spaces.html");
2412 QVERIFY(url.isValid());
2413 QVERIFY(!url.toString().isEmpty());
2414 QCOMPARE(url.path(), QString("/path with spaces.html"));
2415 url.setUrl(url: QLatin1String("http://www.example.com/path%20with spaces.html"), mode: QUrl::StrictMode);
2416 QVERIFY(!url.isValid());
2417 QVERIFY(url.toString().isEmpty());
2418 }
2419
2420 {
2421 QUrl url15581("http://alain.knaff.linux.lu/bug-reports/kde/percentage%in%url.htm>");
2422 QVERIFY(url15581.isValid());
2423 QCOMPARE(url15581.toEncoded().constData(), "http://alain.knaff.linux.lu/bug-reports/kde/percentage%25in%25url.htm%3E");
2424 }
2425
2426 {
2427 QUrl webkit22616 =
2428 QUrl::fromEncoded(url: "http://example.com/testya.php?browser-info=s:1400x1050x24:f:9.0%20r152:t:%u0442%u0435%u0441%u0442");
2429 QVERIFY(webkit22616.isValid());
2430
2431 // Qt 5 behaviour change: one broken % means all % are considered broken
2432// QCOMPARE(webkit22616.toEncoded().constData(),
2433// "http://example.com/testya.php?browser-info=s:1400x1050x24:f:9.0%20r152:t:%25u0442%25u0435%25u0441%25u0442");
2434 QCOMPARE(webkit22616.toEncoded().constData(),
2435 "http://example.com/testya.php?browser-info=s:1400x1050x24:f:9.0%2520r152:t:%25u0442%25u0435%25u0441%25u0442");
2436 }
2437
2438 {
2439 QUrl url;
2440 url.setUrl(url: "http://foo.bar/[image][1].jpg");
2441 QVERIFY(url.isValid());
2442 QVERIFY(!url.toString().isEmpty());
2443 QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/[image][1].jpg"));
2444 QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/[image][1].jpg"));
2445 QCOMPARE(url.toString(), QString("http://foo.bar/[image][1].jpg"));
2446
2447 url.setUrl(url: "http://foo.bar/%5Bimage%5D%5B1%5D.jpg");
2448 QVERIFY(url.isValid());
2449 QVERIFY(!url.toString().isEmpty());
2450 QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
2451 QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
2452 QCOMPARE(url.toString(), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
2453
2454 url.setUrl(url: "//[::56:56:56:56:56:56:56]");
2455 QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]"));
2456 QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]"));
2457 QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]"));
2458
2459 // invoke the tolerant parser's error correction
2460 url.setUrl(url: "%hello.com/f%");
2461 QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%25hello.com/f%25"));
2462 QCOMPARE(url.toEncoded(), QByteArray("%25hello.com/f%25"));
2463 QCOMPARE(url.toString(), QString("%25hello.com/f%25"));
2464
2465 url.setUrl(url: QLatin1String("http://www.host.com/foo.php?P0=[2006-3-8]"), mode: QUrl::StrictMode);
2466 QVERIFY(url.isValid());
2467 QVERIFY(!url.toString().isEmpty());
2468
2469 url.setUrl(url: QLatin1String("http://foo.bar/[image][1].jpg"), mode: QUrl::StrictMode);
2470 QVERIFY(url.isValid());
2471 QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/[image][1].jpg"));
2472 QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/[image][1].jpg"));
2473 QCOMPARE(url.toString(), QString("http://foo.bar/[image][1].jpg"));
2474
2475 url.setUrl(url: QLatin1String("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"), mode: QUrl::StrictMode);
2476 QVERIFY(url.isValid());
2477 QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
2478 QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
2479 QCOMPARE(url.toString(), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"));
2480
2481 url.setUrl(url: QLatin1String("//[::56:56:56:56:56:56:56]"), mode: QUrl::StrictMode);
2482 QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]"));
2483 QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]"));
2484
2485 url.setUrl(url: QLatin1String("data:text/css,div%20{%20border-right:%20solid;%20}"), mode: QUrl::TolerantMode);
2486 QCOMPARE(url.toString(QUrl::FullyEncoded), QString("data:text/css,div%20%7B%20border-right:%20solid;%20%7D"));
2487 QCOMPARE(url.toEncoded(), QByteArray("data:text/css,div%20%7B%20border-right:%20solid;%20%7D"));
2488 QCOMPARE(url.toString(), QString("data:text/css,div %7B border-right: solid; %7D"));
2489 }
2490
2491 {
2492 const QString tsdgeos = QLatin1String("http://google.com/c?c=Translation+%C2%BB+trunk|");
2493 QUrl tsdgeosQUrl;
2494 tsdgeosQUrl.setUrl(url: tsdgeos, mode: QUrl::TolerantMode);
2495 QVERIFY(tsdgeosQUrl.isValid()); // failed in Qt-4.4, works in Qt-4.5
2496 QByteArray tsdgeosExpected("http://google.com/c?c=Translation+%C2%BB+trunk%7C");
2497 QCOMPARE(QString(tsdgeosQUrl.toEncoded()), QString(tsdgeosExpected));
2498 }
2499
2500 {
2501 QUrl url;
2502 url.setUrl(url: "http://strange<username>@hostname/", mode: QUrl::TolerantMode);
2503 QVERIFY(url.isValid());
2504 QCOMPARE(QString(url.toEncoded()), QString("http://strange%3Cusername%3E@hostname/"));
2505 }
2506
2507 {
2508 QUrl url;
2509 url.setUrl(url: "http://en%63o%64%65%64.hostname/", mode: QUrl::TolerantMode);
2510 QVERIFY(url.isValid());
2511 QCOMPARE(url.toString(), QString("http://encoded.hostname/"));
2512 }
2513}
2514
2515void tst_QUrl::correctEncodedMistakes_data()
2516{
2517 QTest::addColumn<QByteArray>(name: "encodedUrl");
2518 QTest::addColumn<bool>(name: "result");
2519 QTest::addColumn<QString>(name: "toDecoded");
2520
2521 QTest::newRow(dataTag: "%") << QByteArray("%") << true << QString("%25");
2522 QTest::newRow(dataTag: "3%") << QByteArray("3%") << true << QString("3%25");
2523 QTest::newRow(dataTag: "13%") << QByteArray("13%") << true << QString("13%25");
2524 QTest::newRow(dataTag: "13%!") << QByteArray("13%!") << true << QString("13%25!");
2525 QTest::newRow(dataTag: "13%!!") << QByteArray("13%!!") << true << QString("13%25!!");
2526 QTest::newRow(dataTag: "13%a") << QByteArray("13%a") << true << QString("13%25a");
2527 QTest::newRow(dataTag: "13%az") << QByteArray("13%az") << true << QString("13%25az");
2528 QTest::newRow(dataTag: "13%25") << QByteArray("13%25") << true << QString("13%25");
2529}
2530
2531void tst_QUrl::correctEncodedMistakes()
2532{
2533 QFETCH(QByteArray, encodedUrl);
2534 QFETCH(bool, result);
2535 QFETCH(QString, toDecoded);
2536
2537 QUrl url = QUrl::fromEncoded(url: encodedUrl);
2538 QCOMPARE(url.isValid(), result);
2539 if (url.isValid()) {
2540 QCOMPARE(url.toString(), toDecoded);
2541 } else {
2542 QVERIFY(url.toString().isEmpty());
2543 }
2544}
2545
2546void tst_QUrl::correctDecodedMistakes_data()
2547{
2548 QTest::addColumn<QString>(name: "decodedUrl");
2549 QTest::addColumn<bool>(name: "result");
2550 QTest::addColumn<QString>(name: "toDecoded");
2551
2552 QTest::newRow(dataTag: "%") << QString("%") << true << QString("%25");
2553 QTest::newRow(dataTag: "3%") << QString("3%") << true << QString("3%25");
2554 QTest::newRow(dataTag: "13%") << QString("13%") << true << QString("13%25");
2555 QTest::newRow(dataTag: "13%!") << QString("13%!") << true << QString("13%25!");
2556 QTest::newRow(dataTag: "13%!!") << QString("13%!!") << true << QString("13%25!!");
2557 QTest::newRow(dataTag: "13%a") << QString("13%a") << true << QString("13%25a");
2558 QTest::newRow(dataTag: "13%az") << QString("13%az") << true << QString("13%25az");
2559}
2560
2561void tst_QUrl::correctDecodedMistakes()
2562{
2563 QFETCH(QString, decodedUrl);
2564 QFETCH(bool, result);
2565 QFETCH(QString, toDecoded);
2566
2567 QUrl url(decodedUrl);
2568 QCOMPARE(url.isValid(), result);
2569 if (url.isValid()) {
2570 QCOMPARE(url.toString(), toDecoded);
2571 } else {
2572 QVERIFY(url.toString().isEmpty());
2573 }
2574}
2575
2576void tst_QUrl::tldRestrictions_data()
2577{
2578 QTest::addColumn<QString>(name: "tld");
2579 QTest::addColumn<bool>(name: "encode");
2580
2581 // current whitelist
2582 QTest::newRow(dataTag: "ac") << QString("ac") << true;
2583 QTest::newRow(dataTag: "ar") << QString("ar") << true;
2584 QTest::newRow(dataTag: "asia") << QString("asia") << true;
2585 QTest::newRow(dataTag: "at") << QString("at") << true;
2586 QTest::newRow(dataTag: "biz") << QString("biz") << true;
2587 QTest::newRow(dataTag: "br") << QString("br") << true;
2588 QTest::newRow(dataTag: "cat") << QString("cat") << true;
2589 QTest::newRow(dataTag: "ch") << QString("ch") << true;
2590 QTest::newRow(dataTag: "cl") << QString("cl") << true;
2591 QTest::newRow(dataTag: "cn") << QString("cn") << true;
2592 QTest::newRow(dataTag: "com") << QString("com") << true;
2593 QTest::newRow(dataTag: "de") << QString("de") << true;
2594 QTest::newRow(dataTag: "dk") << QString("dk") << true;
2595 QTest::newRow(dataTag: "es") << QString("es") << true;
2596 QTest::newRow(dataTag: "fi") << QString("fi") << true;
2597 QTest::newRow(dataTag: "gr") << QString("gr") << true;
2598 QTest::newRow(dataTag: "hu") << QString("hu") << true;
2599 QTest::newRow(dataTag: "il") << QString("il") << true;
2600 QTest::newRow(dataTag: "info") << QString("info") << true;
2601 QTest::newRow(dataTag: "io") << QString("io") << true;
2602 QTest::newRow(dataTag: "is") << QString("is") << true;
2603 QTest::newRow(dataTag: "ir") << QString("ir") << true;
2604 QTest::newRow(dataTag: "jp") << QString("jp") << true;
2605 QTest::newRow(dataTag: "kr") << QString("kr") << true;
2606 QTest::newRow(dataTag: "li") << QString("li") << true;
2607 QTest::newRow(dataTag: "lt") << QString("lt") << true;
2608 QTest::newRow(dataTag: "lu") << QString("lu") << true;
2609 QTest::newRow(dataTag: "lv") << QString("lv") << true;
2610 QTest::newRow(dataTag: "museum") << QString("museum") << true;
2611 QTest::newRow(dataTag: "name") << QString("name") << true;
2612 QTest::newRow(dataTag: "net") << QString("name") << true;
2613 QTest::newRow(dataTag: "no") << QString("no") << true;
2614 QTest::newRow(dataTag: "nu") << QString("nu") << true;
2615 QTest::newRow(dataTag: "nz") << QString("nz") << true;
2616 QTest::newRow(dataTag: "org") << QString("org") << true;
2617 QTest::newRow(dataTag: "pl") << QString("pl") << true;
2618 QTest::newRow(dataTag: "pr") << QString("pr") << true;
2619 QTest::newRow(dataTag: "se") << QString("se") << true;
2620 QTest::newRow(dataTag: "sh") << QString("sh") << true;
2621 QTest::newRow(dataTag: "tel") << QString("tel") << true;
2622 QTest::newRow(dataTag: "th") << QString("th") << true;
2623 QTest::newRow(dataTag: "tm") << QString("tm") << true;
2624 QTest::newRow(dataTag: "tw") << QString("tw") << true;
2625 QTest::newRow(dataTag: "ua") << QString("ua") << true;
2626 QTest::newRow(dataTag: "vn") << QString("vn") << true;
2627
2628 // known blacklists:
2629 QTest::newRow(dataTag: "foo") << QString("foo") << false;
2630}
2631
2632void tst_QUrl::tldRestrictions()
2633{
2634 QFETCH(QString, tld);
2635
2636 // www.brød.tld
2637 QByteArray ascii = "www.xn--brd-1na." + tld.toLatin1();
2638 QString unicode = QLatin1String("www.br\370d.") + tld;
2639 QString encoded = QUrl::fromAce(ascii);
2640 QTEST(!encoded.contains(".xn--"), "encode");
2641 QTEST(encoded == unicode, "encode");
2642
2643 QUrl url = QUrl::fromEncoded(url: "http://www.xn--brd-1na." + tld.toLatin1());
2644 QTEST(!url.host().contains(".xn--"), "encode");
2645 QTEST(url.host() == unicode, "encode");
2646
2647 url.setUrl(url: QLatin1String("http://www.xn--brd-1na.") + tld);
2648 QTEST(!url.host().contains(".xn--"), "encode");
2649 QTEST(url.host() == unicode, "encode");
2650
2651 url.setUrl(url: QLatin1String("http://www.br\370d.") + tld);
2652 QTEST(!url.host().contains(".xn--"), "encode");
2653 QTEST(url.host() == unicode, "encode");
2654
2655 url = QUrl::fromEncoded(url: "http://www.br%C3%B8d." + tld.toLatin1());
2656 QTEST(!url.host().contains(".xn--"), "encode");
2657 QTEST(url.host() == unicode, "encode");
2658}
2659
2660void tst_QUrl::emptyQueryOrFragment()
2661{
2662 QUrl qurl = QUrl::fromEncoded(url: "http://www.kde.org/cgi/test.cgi?", mode: QUrl::TolerantMode);
2663 QCOMPARE(qurl.toEncoded().constData(), "http://www.kde.org/cgi/test.cgi?"); // Empty refs should be preserved
2664 QCOMPARE(qurl.toString(), QString("http://www.kde.org/cgi/test.cgi?"));
2665 qurl = QUrl::fromEncoded(url: "http://www.kde.org/cgi/test.cgi#", mode: QUrl::TolerantMode);
2666 QCOMPARE(qurl.toEncoded().constData(), "http://www.kde.org/cgi/test.cgi#");
2667 QCOMPARE(qurl.toString(), QString("http://www.kde.org/cgi/test.cgi#"));
2668
2669 {
2670 // start with an empty one
2671 QUrl url("http://www.foo.bar/baz");
2672 QVERIFY(!url.hasFragment());
2673 QVERIFY(url.fragment().isNull());
2674
2675 // add fragment
2676 url.setFragment(fragment: QLatin1String("abc"));
2677 QVERIFY(url.hasFragment());
2678 QCOMPARE(url.fragment(), QString(QLatin1String("abc")));
2679 QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz#abc")));
2680
2681 // remove fragment
2682 url.setFragment(fragment: QString());
2683 QVERIFY(!url.hasFragment());
2684 QVERIFY(url.fragment().isNull());
2685 QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz")));
2686
2687 // add empty fragment
2688 url.setFragment(fragment: QLatin1String(""));
2689 QVERIFY(url.hasFragment());
2690 QVERIFY(url.fragment().isEmpty());
2691 QVERIFY(!url.fragment().isNull());
2692 QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz#")));
2693 }
2694
2695 {
2696 // start with an empty one
2697 QUrl url("http://www.foo.bar/baz");
2698 QVERIFY(!url.hasQuery());
2699 QVERIFY(url.query().isNull());
2700
2701 // add encodedQuery
2702 url.setQuery(query: "abc=def");
2703 QVERIFY(url.hasQuery());
2704 QCOMPARE(url.query(), QString(QLatin1String("abc=def")));
2705 QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?abc=def")));
2706 url.setQuery(query: QLatin1String("abc=def"));
2707 QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?abc=def")));
2708
2709 // remove encodedQuery
2710 url.setQuery(query: QString());
2711 QVERIFY(!url.hasQuery());
2712 QVERIFY(url.query().isNull());
2713 QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz")));
2714 url.setQuery(query: QString());
2715 QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz")));
2716
2717 // add empty encodedQuery
2718 url.setQuery(query: "");
2719 QVERIFY(url.hasQuery());
2720 QVERIFY(url.query().isEmpty());
2721 QVERIFY(!url.query().isNull());
2722 QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?")));
2723 url.setQuery(query: QLatin1String(""));
2724 QCOMPARE(url.toString(), QString(QLatin1String("http://www.foo.bar/baz?")));
2725 }
2726}
2727
2728void tst_QUrl::hasFragment_data()
2729{
2730 QTest::addColumn<QString>(name: "url");
2731 QTest::addColumn<bool>(name: "trueFalse");
2732
2733 QTest::newRow(dataTag: "no fragment") << "http://www.foo.bar" << false;
2734
2735 QTest::newRow(dataTag: "empty fragment") << "http://www.foo.bar#" << true;
2736 QTest::newRow(dataTag: "empty fragment 2") << "http://www.foo.bar/#" << true;
2737
2738 QTest::newRow(dataTag: "fragment") << "http://www.foo.bar#baz" << true;
2739 QTest::newRow(dataTag: "fragment2") << "http://www.foo.bar/#baz" << true;
2740
2741 QTest::newRow(dataTag: "%23") << "http://www.foo.bar/%23" << false;
2742 QTest::newRow(dataTag: "%23-and-something") << "http://www.foo.bar/%23baz" << false;
2743}
2744
2745void tst_QUrl::hasFragment()
2746{
2747 QFETCH(QString, url);
2748 QFETCH(bool, trueFalse);
2749
2750 QUrl qurl(url);
2751 QCOMPARE(qurl.hasFragment(), trueFalse);
2752 QCOMPARE(qurl.fragment().isNull(), !trueFalse);
2753}
2754
2755void tst_QUrl::setFragment_data()
2756{
2757 QTest::addColumn<QString>(name: "base");
2758 QTest::addColumn<QString>(name: "fragment");
2759 QTest::addColumn<QString>(name: "expected");
2760
2761 QTest::newRow(dataTag: "null") << QString::fromLatin1(str: "http://www.kde.org") << QString() << QString::fromLatin1(str: "http://www.kde.org");
2762 QTest::newRow(dataTag: "empty") << QString::fromLatin1(str: "http://www.kde.org") << QString::fromLatin1(str: "") << QString::fromLatin1(str: "http://www.kde.org#");
2763 QTest::newRow(dataTag: "basic test") << QString::fromLatin1(str: "http://www.kde.org") << QString::fromLatin1(str: "abc") << QString::fromLatin1(str: "http://www.kde.org#abc");
2764 QTest::newRow(dataTag: "initial url has fragment") << QString::fromLatin1(str: "http://www.kde.org#old") << QString::fromLatin1(str: "new") << QString::fromLatin1(str: "http://www.kde.org#new");
2765 QTest::newRow(dataTag: "encoded fragment") << QString::fromLatin1(str: "http://www.kde.org") << QString::fromLatin1(str: "a%20c") << QString::fromLatin1(str: "http://www.kde.org#a%20c");
2766 QTest::newRow(dataTag: "with #") << QString::fromLatin1(str: "http://www.kde.org") << QString::fromLatin1(str: "a#b") << QString::fromLatin1(str: "http://www.kde.org#a%23b"); // toString uses "a#b"
2767 QTest::newRow(dataTag: "unicode") << QString::fromLatin1(str: "http://www.kde.org") << QString::fromUtf8(str: "\xc3\xa9") << QString::fromLatin1(str: "http://www.kde.org#%C3%A9");
2768}
2769
2770void tst_QUrl::setFragment()
2771{
2772 QFETCH(QString, base);
2773 QFETCH(QString, fragment);
2774 QFETCH(QString, expected);
2775 QUrl u;
2776 u.setUrl(url: base, mode: QUrl::TolerantMode);
2777 QVERIFY(u.isValid());
2778 u.setFragment(fragment);
2779 QVERIFY(u.isValid());
2780 QCOMPARE(!fragment.isNull(), u.hasFragment());
2781 QCOMPARE(QString::fromUtf8(u.toEncoded()), expected);
2782}
2783
2784void tst_QUrl::fromEncoded()
2785{
2786 QUrl qurl2 = QUrl::fromEncoded(url: "print:/specials/Print%20To%20File%20(PDF%252FAcrobat)", mode: QUrl::TolerantMode);
2787 QCOMPARE(qurl2.path(), QString::fromLatin1("/specials/Print To File (PDF%2FAcrobat)"));
2788 QCOMPARE(QFileInfo(qurl2.path()).fileName(), QString::fromLatin1("Print To File (PDF%2FAcrobat)"));
2789 QCOMPARE(qurl2.fileName(), QString::fromLatin1("Print To File (PDF%2FAcrobat)"));
2790 QCOMPARE(qurl2.toEncoded().constData(), "print:/specials/Print%20To%20File%20(PDF%252FAcrobat)");
2791
2792 QUrl qurl = QUrl::fromEncoded(url: "http://\303\244.de");
2793 QVERIFY(qurl.isValid());
2794 QCOMPARE(qurl.toEncoded().constData(), "http://xn--4ca.de");
2795
2796 QUrl qurltest(QUrl::fromPercentEncoding("http://\303\244.de"));
2797 QVERIFY(qurltest.isValid());
2798
2799 QUrl qurl_newline_1 = QUrl::fromEncoded(url: "http://www.foo.bar/foo/bar\ngnork", mode: QUrl::TolerantMode);
2800 QVERIFY(qurl_newline_1.isValid());
2801 QCOMPARE(qurl_newline_1.toEncoded().constData(), "http://www.foo.bar/foo/bar%0Agnork");
2802}
2803
2804void tst_QUrl::stripTrailingSlash_data()
2805{
2806 QTest::addColumn<QString>(name: "url");
2807 QTest::addColumn<QString>(name: "expectedStrip"); // toString(Strip)
2808 QTest::addColumn<QString>(name: "expectedDir"); // toString(RemoveFilename)
2809 QTest::addColumn<QString>(name: "expectedDirStrip"); // toString(RemoveFilename|Strip)
2810
2811 QTest::newRow(dataTag: "subdir no slash") << "ftp://kde.org/dir/subdir" << "ftp://kde.org/dir/subdir" << "ftp://kde.org/dir/" << "ftp://kde.org/dir";
2812 QTest::newRow(dataTag: "ftp no slash") << "ftp://kde.org/dir" << "ftp://kde.org/dir" << "ftp://kde.org/" << "ftp://kde.org/";
2813 QTest::newRow(dataTag: "ftp slash") << "ftp://kde.org/dir/" << "ftp://kde.org/dir" << "ftp://kde.org/dir/" << "ftp://kde.org/dir";
2814 QTest::newRow(dataTag: "ftp_two_slashes") << "ftp://kde.org/dir//" << "ftp://kde.org/dir" << "ftp://kde.org/dir//" << "ftp://kde.org/dir";
2815 QTest::newRow(dataTag: "file slash") << "file:///dir/" << "file:///dir" << "file:///dir/" << "file:///dir";
2816 QTest::newRow(dataTag: "file no slash") << "file:///dir" << "file:///dir" << "file:///" << "file:///";
2817 QTest::newRow(dataTag: "file root") << "file:///" << "file:///" << "file:///" << "file:///";
2818 QTest::newRow(dataTag: "file_root_manyslashes") << "file://///" << "file:///" << "file://///" << "file:///";
2819 QTest::newRow(dataTag: "no path") << "remote://" << "remote://" << "remote://" << "remote://";
2820}
2821
2822void tst_QUrl::stripTrailingSlash()
2823{
2824 QFETCH(QString, url);
2825 QFETCH(QString, expectedStrip);
2826 QFETCH(QString, expectedDir);
2827 QFETCH(QString, expectedDirStrip);
2828
2829 QUrl u(url);
2830 QCOMPARE(u.toString(QUrl::StripTrailingSlash), expectedStrip);
2831 QCOMPARE(u.toString(QUrl::RemoveFilename), expectedDir);
2832 QCOMPARE(u.toString(QUrl::RemoveFilename | QUrl::StripTrailingSlash), expectedDirStrip);
2833
2834 // Same thing, using QUrl::adjusted()
2835 QCOMPARE(u.adjusted(QUrl::StripTrailingSlash).toString(), expectedStrip);
2836 QCOMPARE(u.adjusted(QUrl::RemoveFilename).toString(), expectedDir);
2837 QCOMPARE(u.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toString(), expectedDirStrip);
2838}
2839
2840void tst_QUrl::hosts_data()
2841{
2842 QTest::addColumn<QString>(name: "url");
2843 QTest::addColumn<QString>(name: "host");
2844
2845 QTest::newRow(dataTag: "empty") << QString("") << QString("");
2846 QTest::newRow(dataTag: "empty1") << QString("file:///file") << QString("");
2847 QTest::newRow(dataTag: "empty2") << QString("file:/file") << QString("");
2848 QTest::newRow(dataTag: "empty3") << QString("http:///file") << QString("");
2849 QTest::newRow(dataTag: "empty4") << QString("http:/file") << QString("");
2850
2851 // numeric hostnames -> decoded as IPv4 as per inet_aton(3)
2852 QTest::newRow(dataTag: "http://123/") << QString("http://123/") << QString("0.0.0.123");
2853 QTest::newRow(dataTag: "http://456/") << QString("http://456/") << QString("0.0.1.200");
2854 QTest::newRow(dataTag: "http://1000/") << QString("http://1000/") << QString("0.0.3.232");
2855
2856 // IP literals
2857 QTest::newRow(dataTag: "normal-ip-literal") << QString("http://1.2.3.4") << QString("1.2.3.4");
2858 QTest::newRow(dataTag: "normal-ip-literal-with-port") << QString("http://1.2.3.4:80")
2859 << QString("1.2.3.4");
2860 QTest::newRow(dataTag: "ipv6-literal") << QString("http://[::1]") << QString("::1");
2861 QTest::newRow(dataTag: "ipv6-literal-with-port") << QString("http://[::1]:80") << QString("::1");
2862 QTest::newRow(dataTag: "long-ipv6-literal") << QString("http://[2001:200:0:8002:203:47ff:fea5:3085]")
2863 << QString("2001:200:0:8002:203:47ff:fea5:3085");
2864 QTest::newRow(dataTag: "long-ipv6-literal-with-port") << QString("http://[2001:200:0:8002:203:47ff:fea5:3085]:80")
2865 << QString("2001:200:0:8002:203:47ff:fea5:3085");
2866 QTest::newRow(dataTag: "ipv6-literal-v4compat") << QString("http://[::255.254.253.252]")
2867 << QString("::255.254.253.252");
2868 QTest::newRow(dataTag: "ipv6-literal-v4mapped") << QString("http://[::ffff:255.254.253.252]")
2869 << QString("::ffff:255.254.253.252");
2870 QTest::newRow(dataTag: "ipv6-literal-v4mapped-2") << QString("http://[::ffff:fffe:fdfc]")
2871 << QString("::ffff:255.254.253.252");
2872
2873 // no embedded v4 unless the cases above
2874 QTest::newRow(dataTag: "ipv6-literal-v4decoded") << QString("http://[1000::ffff:127.128.129.1]")
2875 << QString("1000::ffff:7f80:8101");
2876 QTest::newRow(dataTag: "long-ipv6-literal-v4decoded") << QString("http://[fec0:8000::8002:1000:ffff:200.100.50.250]")
2877 << QString("fec0:8000:0:8002:1000:ffff:c864:32fa");
2878 QTest::newRow(dataTag: "longer-ipv6-literal-v4decoded") << QString("http://[fec0:8000:4000:8002:1000:ffff:200.100.50.250]")
2879 << QString("fec0:8000:4000:8002:1000:ffff:c864:32fa");
2880
2881 // normal hostnames
2882 QTest::newRow(dataTag: "normal") << QString("http://intern") << QString("intern");
2883 QTest::newRow(dataTag: "normal2") << QString("http://qt-project.org") << QString("qt-project.org");
2884
2885 // IDN hostnames
2886 QTest::newRow(dataTag: "idn") << QString(QLatin1String("http://\345r.no")) << QString(QLatin1String("\345r.no"));
2887 QTest::newRow(dataTag: "idn-ace") << QString("http://xn--r-1fa.no") << QString(QLatin1String("\345r.no"));
2888}
2889
2890void tst_QUrl::hosts()
2891{
2892 QFETCH(QString, url);
2893
2894 QUrl u(url);
2895 QTEST(u.host(), "host");
2896 QVERIFY(u.isEmpty() || u.isValid());
2897}
2898
2899void tst_QUrl::hostFlags_data()
2900{
2901 QTest::addColumn<QString>(name: "urlStr");
2902 QTest::addColumn<QUrl::FormattingOptions>(name: "options");
2903 QTest::addColumn<QString>(name: "expectedHost");
2904
2905 QString swedish = QString::fromUtf8(str: "http://www.räksmörgås.se/pub?a=b&a=dø&a=f#vræl");
2906 QTest::newRow(dataTag: "se_fullydecoded") << swedish << QUrl::FormattingOptions(QUrl::FullyDecoded) << QString::fromUtf8(str: "www.räksmörgås.se");
2907 QTest::newRow(dataTag: "se_fullyencoded") << swedish << QUrl::FormattingOptions(QUrl::FullyEncoded) << QString::fromUtf8(str: "www.xn--rksmrgs-5wao1o.se");
2908 QTest::newRow(dataTag: "se_prettydecoded") << swedish << QUrl::FormattingOptions(QUrl::PrettyDecoded) << QString::fromUtf8(str: "www.räksmörgås.se");
2909 QTest::newRow(dataTag: "se_encodespaces") << swedish << QUrl::FormattingOptions(QUrl::EncodeSpaces) << QString::fromUtf8(str: "www.räksmörgås.se");
2910}
2911
2912void tst_QUrl::hostFlags()
2913{
2914 QFETCH(QString, urlStr);
2915 QFETCH(QUrl::FormattingOptions, options);
2916 QFETCH(QString, expectedHost);
2917
2918 QUrl url(urlStr);
2919 QCOMPARE(url.host(options), expectedHost);
2920}
2921
2922void tst_QUrl::setPort()
2923{
2924 {
2925 QUrl url;
2926 QVERIFY(url.toString().isEmpty());
2927 url.setHost(host: "a");
2928 url.setPort(80);
2929 QCOMPARE(url.port(), 80);
2930 QCOMPARE(url.toString(), QString::fromLatin1("//a:80"));
2931 url.setPort(-1);
2932 url.setHost(host: QString());
2933 QCOMPARE(url.port(), -1);
2934 QCOMPARE(url.toString(), QString());
2935 url.setPort(80);
2936 url.setPort(65536);
2937 QCOMPARE(url.port(), -1);
2938 QVERIFY(url.errorString().contains("out of range"));
2939 }
2940
2941 {
2942 QUrl reference("//:80");
2943 QUrl piecewise;
2944 piecewise.setPort(80);
2945 QCOMPARE(piecewise, reference);
2946 }
2947
2948 {
2949 // setAuthority must clear the port
2950 QUrl url("http://example.com:80");
2951 url.setAuthority(authority: "example.org");
2952 QCOMPARE(url.port(), -1);
2953 QCOMPARE(url.toString(), QString("http://example.org"));
2954 }
2955
2956 {
2957 // setAuthority must clear the port
2958 QUrl url("http://example.com:80");
2959 url.setAuthority(authority: QString());
2960 QCOMPARE(url.port(), -1);
2961 QCOMPARE(url.toString(), QString("http:"));
2962 }
2963}
2964
2965void tst_QUrl::port_data()
2966{
2967 QTest::addColumn<QString>(name: "input");
2968 QTest::addColumn<int>(name: "port");
2969
2970 QTest::newRow(dataTag: "no-port-1") << "http://example.com" << -1;
2971 QTest::newRow(dataTag: "no-port-2") << "http://example.com/" << -1;
2972 QTest::newRow(dataTag: "empty-port-1") << "http://example.com:" << -1;
2973 QTest::newRow(dataTag: "empty-port-2") << "http://example.com:/" << -1;
2974 QTest::newRow(dataTag: "zero-port-1") << "http://example.com:0" << 0;
2975 QTest::newRow(dataTag: "zero-port-2") << "http://example.com:0/" << 0;
2976 QTest::newRow(dataTag: "set-port-1") << "http://example.com:80" << 80;
2977 QTest::newRow(dataTag: "set-port-2") << "http://example.com:80/" << 80;
2978}
2979
2980void tst_QUrl::port()
2981{
2982 QFETCH(QString, input);
2983 QFETCH(int, port);
2984
2985 QUrl url(input);
2986 QVERIFY(url.isValid());
2987 QCOMPARE(url.port(), port);
2988}
2989
2990void tst_QUrl::toEncoded_data()
2991{
2992 QTest::addColumn<QByteArray>(name: "url");
2993 QTest::addColumn<QUrl::FormattingOptions>(name: "options");
2994 QTest::addColumn<QByteArray>(name: "encoded");
2995 QTest::newRow(dataTag: "file:///dir/") << QByteArray("file:///dir/")
2996 << QUrl::FormattingOptions(QUrl::StripTrailingSlash)
2997 << QByteArray("file:///dir");
2998}
2999
3000void tst_QUrl::toEncoded()
3001{
3002 QFETCH(QByteArray, url);
3003 QFETCH(QUrl::FormattingOptions, options);
3004 QFETCH(QByteArray, encoded);
3005
3006 QCOMPARE(QUrl::fromEncoded(url).toEncoded(options), encoded);
3007}
3008
3009void tst_QUrl::setAuthority_data()
3010{
3011 QTest::addColumn<QString>(name: "authority");
3012 QTest::addColumn<QString>(name: "url");
3013 QTest::newRow(dataTag: "Plain auth") << QString("62.70.27.22:21") << QString("//62.70.27.22:21");
3014 QTest::newRow(dataTag: "Yet another plain auth") << QString("192.168.1.1:21") << QString("//192.168.1.1:21");
3015 QTest::newRow(dataTag: "Auth without port") << QString("192.168.1.1") << QString("//192.168.1.1");
3016 QTest::newRow(dataTag: "Auth w/full hostname without port") << QString("shusaku.troll.no") << QString("//shusaku.troll.no");
3017 QTest::newRow(dataTag: "Auth w/hostname without port") << QString("shusaku") << QString("//shusaku");
3018 QTest::newRow(dataTag: "Auth w/full hostname that ends with number, without port") << QString("shusaku.troll.no.2") << QString("//shusaku.troll.no.2");
3019 QTest::newRow(dataTag: "Auth w/hostname that ends with number, without port") << QString("shusaku2") << QString("//shusaku2");
3020 QTest::newRow(dataTag: "Empty auth") << QString() << QString();
3021}
3022
3023void tst_QUrl::setAuthority()
3024{
3025 QUrl u;
3026 QFETCH(QString, authority);
3027 QFETCH(QString, url);
3028 u.setAuthority(authority);
3029 QCOMPARE(u.toString(), url);
3030}
3031
3032void tst_QUrl::setEmptyAuthority_data()
3033{
3034 QTest::addColumn<QString>(name: "host");
3035 QTest::addColumn<QString>(name: "authority");
3036 QTest::addColumn<QString>(name: "expectedUrlString");
3037
3038 QTest::newRow(dataTag: "null host and authority") << QString() << QString() << QString("");
3039 QTest::newRow(dataTag: "empty host and authority") << QString("") << QString("") << QString("//");
3040}
3041
3042void tst_QUrl::setEmptyAuthority()
3043{
3044 QFETCH(QString, host);
3045 QFETCH(QString, authority);
3046 QFETCH(QString, expectedUrlString);
3047 QUrl u;
3048 u.setHost(host);
3049 QCOMPARE(u.toString(), expectedUrlString);
3050 u.setAuthority(authority);
3051 QCOMPARE(u.toString(), expectedUrlString);
3052}
3053
3054void tst_QUrl::clear()
3055{
3056 QUrl url("a");
3057 QUrl url2("a");
3058 QCOMPARE(url, url2);
3059 url.clear();
3060 QVERIFY(url != url2);
3061}
3062
3063void tst_QUrl::binaryData_data()
3064{
3065 QTest::addColumn<QString>(name: "url");
3066 QTest::newRow(dataTag: "username") << "http://%01%0D%0A%7F@foo/";
3067 QTest::newRow(dataTag: "username-at") << "http://abc%40_def@foo/";
3068 QTest::newRow(dataTag: "username-nul") << "http://abc%00_def@foo/";
3069 QTest::newRow(dataTag: "username-colon") << "http://abc%3A_def@foo/";
3070 QTest::newRow(dataTag: "username-nonutf8") << "http://abc%E1_def@foo/";
3071
3072 QTest::newRow(dataTag: "password") << "http://user:%01%0D%0A%7F@foo/";
3073 QTest::newRow(dataTag: "password-at") << "http://user:abc%40_def@foo/";
3074 QTest::newRow(dataTag: "password-nul") << "http://user:abc%00_def@foo/";
3075 QTest::newRow(dataTag: "password-nonutf8") << "http://user:abc%E1_def@foo/";
3076
3077 QTest::newRow(dataTag: "file") << "http://foo/%01%0D%0A%7F";
3078 QTest::newRow(dataTag: "file-nul") << "http://foo/abc%00_def";
3079 QTest::newRow(dataTag: "file-hash") << "http://foo/abc%23_def";
3080 QTest::newRow(dataTag: "file-question") << "http://foo/abc%3F_def";
3081 QTest::newRow(dataTag: "file-nonutf8") << "http://foo/abc%E1_def";
3082 QTest::newRow(dataTag: "file-slash") << "http://foo/abc%2F_def";
3083
3084 QTest::newRow(dataTag: "ref") << "http://foo/file#a%01%0D%0A%7F";
3085 QTest::newRow(dataTag: "ref-nul") << "http://foo/file#abc%00_def";
3086 QTest::newRow(dataTag: "ref-question") << "http://foo/file#abc?_def";
3087 QTest::newRow(dataTag: "ref-nonutf8") << "http://foo/file#abc%E1_def";
3088
3089 QTest::newRow(dataTag: "query-value") << "http://foo/query?foo=%01%0D%0A%7F";
3090 QTest::newRow(dataTag: "query-value-nul") << "http://foo/query?foo=abc%00_def";
3091 QTest::newRow(dataTag: "query-value-nonutf8") << "http://foo/query?foo=abc%E1_def";
3092
3093 QTest::newRow(dataTag: "query-name") << "http://foo/query/a%01%0D%0A%7Fz=foo";
3094 QTest::newRow(dataTag: "query-name-nul") << "http://foo/query/abc%00_def=foo";
3095 QTest::newRow(dataTag: "query-name-nonutf8") << "http://foo/query/abc%E1_def=foo";
3096}
3097
3098void tst_QUrl::binaryData()
3099{
3100 QFETCH(QString, url);
3101 QUrl u = QUrl::fromEncoded(url: url.toUtf8());
3102
3103 QVERIFY(u.isValid());
3104 QVERIFY(!u.isEmpty());
3105
3106 QString url2 = QString::fromUtf8(str: u.toEncoded());
3107 //QCOMPARE(url2.length(), url.length());
3108 QCOMPARE(url2, url);
3109}
3110
3111void tst_QUrl::fromUserInput_data()
3112{
3113 //
3114 // most of this test is:
3115 // Copyright (C) Research In Motion Limited 2009. All rights reserved.
3116 // Distributed under the BSD license.
3117 // See qurl.cpp
3118 //
3119
3120 QTest::addColumn<QString>(name: "string");
3121 QTest::addColumn<QUrl>(name: "guessUrlFromString");
3122
3123 // Null
3124 QTest::newRow(dataTag: "null") << QString() << QUrl();
3125
3126 // File
3127 QDirIterator it(QDir::homePath());
3128 int c = 0;
3129 while (it.hasNext()) {
3130 it.next();
3131 QTest::newRow(dataTag: ("file-" + QByteArray::number(c++)).constData())
3132 << it.filePath() << QUrl::fromLocalFile(localfile: it.filePath());
3133 }
3134
3135 // basic latin1
3136 QTest::newRow(dataTag: "unicode-0") << QString::fromUtf8(str: "\xc3\xa5.com/") << QUrl::fromEncoded(url: QString::fromUtf8(str: "http://\xc3\xa5.com/").toUtf8(), mode: QUrl::TolerantMode);
3137 QTest::newRow(dataTag: "unicode-0b") << QString::fromUtf8(str: "\xc3\xa5.com/") << QUrl::fromEncoded(url: "http://%C3%A5.com/", mode: QUrl::TolerantMode);
3138 QTest::newRow(dataTag: "unicode-0c") << QString::fromUtf8(str: "\xc3\xa5.com/") << QUrl::fromEncoded(url: "http://xn--5ca.com/", mode: QUrl::TolerantMode);
3139 // unicode
3140 QTest::newRow(dataTag: "unicode-1") << QString::fromUtf8(str: "\xce\xbb.com/") << QUrl::fromEncoded(url: QString::fromUtf8(str: "http://\xce\xbb.com/").toUtf8(), mode: QUrl::TolerantMode);
3141 QTest::newRow(dataTag: "unicode-1b") << QString::fromUtf8(str: "\xce\xbb.com/") << QUrl::fromEncoded(url: "http://%CE%BB.com/", mode: QUrl::TolerantMode);
3142 QTest::newRow(dataTag: "unicode-1c") << QString::fromUtf8(str: "\xce\xbb.com/") << QUrl::fromEncoded(url: "http://xn--wxa.com/", mode: QUrl::TolerantMode);
3143
3144 // no scheme
3145 QTest::newRow(dataTag: "add scheme-0") << "example.org" << QUrl("http://example.org");
3146 QTest::newRow(dataTag: "add scheme-1") << "www.example.org" << QUrl("http://www.example.org");
3147 QTest::newRow(dataTag: "add scheme-2") << "ftp.example.org" << QUrl("ftp://ftp.example.org");
3148 QTest::newRow(dataTag: "add scheme-3") << "hostname" << QUrl("http://hostname");
3149 QTest::newRow(dataTag: "ipv4-1") << "127.0.0.1" << QUrl("http://127.0.0.1");
3150 QTest::newRow(dataTag: "ipv6-0") << "::" << QUrl("http://[::]");
3151 QTest::newRow(dataTag: "ipv6-1") << "::1" << QUrl("http://[::1]");
3152 QTest::newRow(dataTag: "ipv6-2") << "1::1" << QUrl("http://[1::1]");
3153 QTest::newRow(dataTag: "ipv6-3") << "1::" << QUrl("http://[1::]");
3154 QTest::newRow(dataTag: "ipv6-4") << "c::" << QUrl("http://[c::]");
3155 QTest::newRow(dataTag: "ipv6-5") << "c:f00:ba4::" << QUrl("http://[c:f00:ba4::]");
3156
3157 // no host
3158 QTest::newRow(dataTag: "nohost-1") << "http://" << QUrl("http://");
3159 QTest::newRow(dataTag: "nohost-2") << "smb:" << QUrl("smb:");
3160
3161 // QUrl's tolerant parser should already handle this
3162 QTest::newRow(dataTag: "not-encoded-0") << "http://example.org/test page.html" << QUrl::fromEncoded(url: "http://example.org/test%20page.html");
3163
3164 // Make sure the :80, i.e. port doesn't screw anything up
3165 QUrl portUrl("http://example.org");
3166 portUrl.setPort(80);
3167 QTest::newRow(dataTag: "port-0") << "example.org:80" << portUrl;
3168 QTest::newRow(dataTag: "port-1") << "http://example.org:80" << portUrl;
3169 portUrl.setPath(path: "/path");
3170 QTest::newRow(dataTag: "port-2") << "example.org:80/path" << portUrl;
3171 QTest::newRow(dataTag: "port-3") << "http://example.org:80/path" << portUrl;
3172
3173 // mailto doesn't have a ://, but is valid
3174 QUrl mailto("ben@example.net");
3175 mailto.setScheme("mailto");
3176 QTest::newRow(dataTag: "mailto") << "mailto:ben@example.net" << mailto;
3177
3178 // misc
3179 QTest::newRow(dataTag: "localhost-1") << "localhost:80" << QUrl("http://localhost:80");
3180 QTest::newRow(dataTag: "spaces-0") << " http://example.org/test page.html " << QUrl("http://example.org/test%20page.html");
3181 QTest::newRow(dataTag: "trash-0") << "example.org/test?someData=42%&someOtherData=abcde#anchor" << QUrl::fromEncoded(url: "http://example.org/test?someData=42%25&someOtherData=abcde#anchor");
3182 QTest::newRow(dataTag: "other-scheme-0") << "spotify:track:0hO542doVbfGDAGQULMORT" << QUrl("spotify:track:0hO542doVbfGDAGQULMORT");
3183 QTest::newRow(dataTag: "other-scheme-1") << "weirdscheme:80:otherstuff" << QUrl("weirdscheme:80:otherstuff");
3184 QTest::newRow(dataTag: "number-path-0") << "tel:2147483648" << QUrl("tel:2147483648");
3185
3186 // FYI: The scheme in the resulting url user
3187 QUrl authUrl("user:pass@domain.com");
3188 QTest::newRow(dataTag: "misc-1") << "user:pass@domain.com" << authUrl;
3189
3190 // FTP with double slashes in path
3191 QTest::newRow(dataTag: "ftp-double-slash-1") << "ftp.example.com//path" << QUrl("ftp://ftp.example.com/%2Fpath");
3192 QTest::newRow(dataTag: "ftp-double-slash-1") << "ftp://ftp.example.com//path" << QUrl("ftp://ftp.example.com/%2Fpath");
3193}
3194
3195void tst_QUrl::fromUserInput()
3196{
3197 QFETCH(QString, string);
3198 QFETCH(QUrl, guessUrlFromString);
3199
3200 QUrl url = QUrl::fromUserInput(userInput: string);
3201 QCOMPARE(url, guessUrlFromString);
3202}
3203
3204void tst_QUrl::fromUserInputWithCwd_data()
3205{
3206 QTest::addColumn<QString>(name: "string");
3207 QTest::addColumn<QString>(name: "directory");
3208 QTest::addColumn<QUrl>(name: "guessedUrlDefault");
3209 QTest::addColumn<QUrl>(name: "guessedUrlAssumeLocalFile");
3210
3211 // Null
3212 QTest::newRow(dataTag: "null") << QString() << QString() << QUrl() << QUrl();
3213
3214 // Use a tempdir with files, for testing specific file names
3215 // We use canonicalPath() on the dir path because ::getcwd() canonicalizes,
3216 // so we get a canonical base path for URLs with "." as working directory.
3217 const QString base = QDir(m_tempDir.path()).canonicalPath();
3218 QDir::setCurrent(base); // for the tests that use "." as working dir
3219
3220 // "."
3221 {
3222 const QUrl url = QUrl::fromLocalFile(localfile: base); // fromUserInput cleans the path
3223 QTest::newRow(dataTag: "dot-in-path") << "." << base << url << url;
3224 QTest::newRow(dataTag: "dot-in-dot") << "." << QStringLiteral(".") << url << url;
3225 }
3226
3227 // Existing files
3228 for (const char *fileName : {"file.txt", "file#a.txt", "file .txt", "file.txt "
3229#ifndef Q_OS_WIN
3230 , "file:colon.txt"
3231#endif
3232 }) {
3233 const QString filePath = base + '/' + fileName;
3234 QFile file(filePath);
3235 QVERIFY2(file.open(QIODevice::WriteOnly), qPrintable(filePath));
3236 file.write(data: "Hello world\n");
3237
3238 const QUrl url = QUrl::fromLocalFile(localfile: filePath);
3239 QTest::newRow(dataTag: fileName) << fileName << base << url << url;
3240 QTest::newRow(dataTag: QByteArray(fileName) + "-in-dot") << fileName << QStringLiteral(".") << url << url;
3241 }
3242
3243#ifndef Q_OS_WINRT // WinRT cannot cd outside current / sandbox
3244 QDir parent(base);
3245 QVERIFY(parent.cdUp());
3246 QUrl parentUrl = QUrl::fromLocalFile(localfile: parent.path());
3247 QTest::newRow(dataTag: "dotdot") << ".." << base << parentUrl << parentUrl;
3248#endif
3249
3250 QTest::newRow(dataTag: "nonexisting") << "nonexisting" << base << QUrl("http://nonexisting") << QUrl::fromLocalFile(localfile: base + "/nonexisting");
3251 QTest::newRow(dataTag: "short-url") << "example.org" << base << QUrl("http://example.org") << QUrl::fromLocalFile(localfile: base + "/example.org");
3252 QTest::newRow(dataTag: "full-url") << "http://example.org" << base << QUrl("http://example.org") << QUrl("http://example.org");
3253 QTest::newRow(dataTag: "absolute") << "/doesnotexist.txt" << base << QUrl("file:///doesnotexist.txt") << QUrl("file:///doesnotexist.txt");
3254#ifdef Q_OS_WIN
3255 QTest::newRow("windows-absolute") << "c:/doesnotexist.txt" << base << QUrl("file:///c:/doesnotexist.txt") << QUrl("file:///c:/doesnotexist.txt");
3256#endif
3257
3258 // IPv4 & IPv6
3259 // same as fromUserInput, but needs retesting
3260 QTest::newRow(dataTag: "ipv4-1") << "127.0.0.1" << base << QUrl("http://127.0.0.1") << QUrl::fromLocalFile(localfile: base + "/127.0.0.1");
3261 QTest::newRow(dataTag: "ipv6-0") << "::" << base << QUrl("http://[::]") << QUrl("http://[::]");
3262 QTest::newRow(dataTag: "ipv6-1") << "::1" << base << QUrl("http://[::1]") << QUrl("http://[::1]");
3263 QTest::newRow(dataTag: "ipv6-2") << "1::1" << base << QUrl("http://[1::1]") << QUrl("http://[1::1]");
3264 QTest::newRow(dataTag: "ipv6-3") << "1::" << base << QUrl("http://[1::]") << QUrl("http://[1::]");
3265 QTest::newRow(dataTag: "ipv6-4") << "c::" << base << QUrl("http://[c::]") << QUrl("http://[c::]");
3266 QTest::newRow(dataTag: "ipv6-5") << "c:f00:ba4::" << base << QUrl("http://[c:f00:ba4::]") << QUrl("http://[c:f00:ba4::]");
3267}
3268
3269void tst_QUrl::fromUserInputWithCwd()
3270{
3271 QFETCH(QString, string);
3272 QFETCH(QString, directory);
3273 QFETCH(QUrl, guessedUrlDefault);
3274 QFETCH(QUrl, guessedUrlAssumeLocalFile);
3275
3276 QUrl url = QUrl::fromUserInput(userInput: string, workingDirectory: directory);
3277 QCOMPARE(url, guessedUrlDefault);
3278
3279 url = QUrl::fromUserInput(userInput: string, workingDirectory: directory, options: QUrl::AssumeLocalFile);
3280 QCOMPARE(url, guessedUrlAssumeLocalFile);
3281}
3282
3283void tst_QUrl::fileName_data()
3284{
3285 QTest::addColumn<QString>(name: "urlStr");
3286 QTest::addColumn<QString>(name: "expectedDirPath");
3287 QTest::addColumn<QString>(name: "expectedPrettyDecodedFileName");
3288 QTest::addColumn<QString>(name: "expectedFullyDecodedFileName");
3289
3290 QTest::newRow(dataTag: "fromDocu") << "http://qt-project.org/support/file.html"
3291 << "/support/" << "file.html" << "file.html";
3292 QTest::newRow(dataTag: "absoluteFile") << "file:///temp/tmp.txt"
3293 << "/temp/" << "tmp.txt" << "tmp.txt";
3294 QTest::newRow(dataTag: "absoluteDir") << "file:///temp/"
3295 << "/temp/" << QString() << QString();
3296 QTest::newRow(dataTag: "absoluteInRoot") << "file:///temp"
3297 << "/" << "temp" << "temp";
3298 QTest::newRow(dataTag: "relative") << "temp/tmp.txt"
3299 << "temp/" << "tmp.txt" << "tmp.txt";
3300 QTest::newRow(dataTag: "relativeNoSlash") << "tmp.txt"
3301 << QString() << "tmp.txt" << "tmp.txt";
3302 QTest::newRow(dataTag: "encoded") << "print:/specials/Print%20To%20File%20(PDF%252FAcrobat)"
3303 << "/specials/" << "Print To File (PDF%252FAcrobat)" << "Print To File (PDF%2FAcrobat)";
3304 QTest::newRow(dataTag: "endsWithDot") << "file:///temp/."
3305 << "/temp/" << "." << ".";
3306}
3307
3308void tst_QUrl::fileName()
3309{
3310 QFETCH(QString, urlStr);
3311 QFETCH(QString, expectedDirPath);
3312 QFETCH(QString, expectedPrettyDecodedFileName);
3313 QFETCH(QString, expectedFullyDecodedFileName);
3314
3315 QUrl url(urlStr);
3316 QVERIFY(url.isValid());
3317 QCOMPARE(url.adjusted(QUrl::RemoveFilename).path(), expectedDirPath);
3318 QCOMPARE(url.fileName(QUrl::PrettyDecoded), expectedPrettyDecodedFileName);
3319 QCOMPARE(url.fileName(QUrl::FullyDecoded), expectedFullyDecodedFileName);
3320}
3321
3322// This is a regression test for a previously fixed bug where isEmpty didn't
3323// work for an encoded URL that was yet to be decoded. The test checks that
3324// isEmpty works for an encoded URL both after and before decoding.
3325void tst_QUrl::isEmptyForEncodedUrl()
3326{
3327 {
3328 QUrl url;
3329 url.setUrl(url: QLatin1String("LABEL=USB_STICK"), mode: QUrl::TolerantMode);
3330 QVERIFY( url.isValid() );
3331 QCOMPARE( url.path(), QString("LABEL=USB_STICK") );
3332 QVERIFY( !url.isEmpty() );
3333 }
3334 {
3335 QUrl url;
3336 url.setUrl(url: QLatin1String("LABEL=USB_STICK"), mode: QUrl::TolerantMode);
3337 QVERIFY( url.isValid() );
3338 QVERIFY( !url.isEmpty() );
3339 QCOMPARE( url.path(), QString("LABEL=USB_STICK") );
3340 }
3341}
3342
3343// This test verifies that the QUrl::toEncoded() does not rely on the
3344// potentially uninitialized unencoded path.
3345void tst_QUrl::toEncodedNotUsingUninitializedPath()
3346{
3347 QUrl url;
3348 url.setPath(path: QLatin1String("/test.txt"));
3349 url.setHost(host: "example.com");
3350
3351 QCOMPARE(url.toEncoded().constData(), "//example.com/test.txt");
3352
3353 url.path();
3354 QCOMPARE(url.toEncoded().constData(), "//example.com/test.txt");
3355}
3356
3357void tst_QUrl::resolvedWithAbsoluteSchemes() const
3358{
3359 QFETCH(QUrl, base);
3360 QFETCH(QUrl, relative);
3361 QFETCH(QUrl, expected);
3362
3363 /* Check our input. */
3364 QVERIFY(relative.isValid());
3365 QVERIFY(base.isValid());
3366 QVERIFY(expected.isValid());
3367
3368 const QUrl result(base.resolved(relative));
3369
3370 QVERIFY(result.isValid());
3371 QCOMPARE(result, expected);
3372}
3373
3374void tst_QUrl::resolvedWithAbsoluteSchemes_data() const
3375{
3376 QTest::addColumn<QUrl>(name: "base");
3377 QTest::addColumn<QUrl>(name: "relative");
3378 QTest::addColumn<QUrl>(name: "expected");
3379
3380 QTest::newRow(dataTag: "Absolute file:/// against absolute FTP.")
3381 << QUrl::fromEncoded(url: "file:///foo/")
3382 << QUrl::fromEncoded(url: "ftp://example.com/")
3383 << QUrl::fromEncoded(url: "ftp://example.com/");
3384
3385 QTest::newRow(dataTag: "Absolute file:/// against absolute HTTP.")
3386 << QUrl::fromEncoded(url: "file:///foo/")
3387 << QUrl::fromEncoded(url: "http://example.com/")
3388 << QUrl::fromEncoded(url: "http://example.com/");
3389
3390 QTest::newRow(dataTag: "Absolute file:/// against data scheme.")
3391 << QUrl::fromEncoded(url: "file:///foo/")
3392 << QUrl::fromEncoded(url: "data:application/xml,%3Ce%2F%3E")
3393 << QUrl::fromEncoded(url: "data:application/xml,%3Ce%2F%3E");
3394
3395 QTest::newRow(dataTag: "Resolve with base url and port.")
3396 << QUrl::fromEncoded(url: "http://www.foo.com:8080/")
3397 << QUrl::fromEncoded(url: "newfile.html")
3398 << QUrl::fromEncoded(url: "http://www.foo.com:8080/newfile.html");
3399
3400 QTest::newRow(dataTag: "Resolve with relative path")
3401 << QUrl::fromEncoded(url: "http://example.com/")
3402 << QUrl::fromEncoded(url: "http://andreas:hemmelig@www.vg.no/a/../?my=query&your=query#yougotfragged")
3403 << QUrl::fromEncoded(url: "http://andreas:hemmelig@www.vg.no/?my=query&your=query#yougotfragged");
3404}
3405
3406void tst_QUrl::emptyAuthorityRemovesExistingAuthority_data()
3407{
3408 QTest::addColumn<QString>(name: "input");
3409 QTest::addColumn<QString>(name: "expected");
3410 QTest::newRow(dataTag: "regular") << "foo://example.com/something" << "foo:/something";
3411 QTest::newRow(dataTag: "empty") << "foo:///something" << "foo:/something";
3412}
3413
3414void tst_QUrl::emptyAuthorityRemovesExistingAuthority()
3415{
3416 QFETCH(QString, input);
3417 QFETCH(QString, expected);
3418 QUrl url(input);
3419 QUrl orig = url;
3420
3421 url.setAuthority(authority: QString());
3422 QCOMPARE(url.authority(), QString());
3423 QVERIFY(url != orig);
3424 QCOMPARE(url.toString(), expected);
3425 QCOMPARE(url, QUrl(expected));
3426}
3427
3428void tst_QUrl::acceptEmptyAuthoritySegments()
3429{
3430 QCOMPARE(QUrl("remote://").toString(), QString::fromLatin1("remote://"));
3431
3432 // Verify that foo:///bar is not mangled to foo:/bar nor vice-versa
3433 QString foo_triple_bar("foo:///bar"), foo_uni_bar("foo:/bar");
3434
3435 QVERIFY(QUrl(foo_triple_bar) != QUrl(foo_uni_bar));
3436
3437 QCOMPARE(QUrl(foo_triple_bar).toString(), foo_triple_bar);
3438 QCOMPARE(QUrl(foo_triple_bar).toEncoded(), foo_triple_bar.toLatin1());
3439
3440 QCOMPARE(QUrl(foo_uni_bar).toString(), foo_uni_bar);
3441 QCOMPARE(QUrl(foo_uni_bar).toEncoded(), foo_uni_bar.toLatin1());
3442
3443 QCOMPARE(QUrl(foo_triple_bar, QUrl::StrictMode).toString(), foo_triple_bar);
3444 QCOMPARE(QUrl(foo_triple_bar, QUrl::StrictMode).toEncoded(), foo_triple_bar.toLatin1());
3445
3446 QCOMPARE(QUrl(foo_uni_bar, QUrl::StrictMode).toString(), foo_uni_bar);
3447 QCOMPARE(QUrl(foo_uni_bar, QUrl::StrictMode).toEncoded(), foo_uni_bar.toLatin1());
3448
3449 // However, file:/bar is the same as file:///bar
3450 QString file_triple_bar("file:///bar"), file_uni_bar("file:/bar");
3451
3452 QCOMPARE(QUrl(file_triple_bar), QUrl(file_uni_bar));
3453
3454 QCOMPARE(QUrl(file_uni_bar).toString(), file_triple_bar);
3455 QCOMPARE(QUrl(file_uni_bar, QUrl::StrictMode).toString(), file_triple_bar);
3456}
3457
3458void tst_QUrl::effectiveTLDs_data()
3459{
3460 // See also: tst_QNetworkCookieJar::setCookiesFromUrl().
3461 // in tests/auto/network/access/qnetworkcookiejar/tst_qnetworkcookiejar.cpp
3462 QTest::addColumn<QUrl>(name: "domain");
3463 QTest::addColumn<QString>(name: "TLD");
3464 // TODO: autogenerate test-cases from:
3465 // https://raw.githubusercontent.com/publicsuffix/list/master/tests/test_psl.txt
3466 // checkPublicSuffix(domain, tail) appears in the list if
3467 // either tail is null and domain is public or
3468 // tail is the "registrable" part of domain; i.e. its minimal non-public tail.
3469
3470 QTest::newRow(dataTag: "yes0") << QUrl::fromEncoded(url: "http://test.co.uk") << ".co.uk";
3471 QTest::newRow(dataTag: "yes1") << QUrl::fromEncoded(url: "http://test.com") << ".com";
3472 QTest::newRow(dataTag: "yes2") << QUrl::fromEncoded(url: "http://www.test.de") << ".de";
3473 QTest::newRow(dataTag: "yes3") << QUrl::fromEncoded(url: "http://test.ulm.museum") << ".ulm.museum";
3474 QTest::newRow(dataTag: "yes4") << QUrl::fromEncoded(url: "http://www.com.krodsherad.no") << ".krodsherad.no";
3475 QTest::newRow(dataTag: "yes5") << QUrl::fromEncoded(url: "http://www.co.uk.1.bg") << ".1.bg";
3476 QTest::newRow(dataTag: "yes6") << QUrl::fromEncoded(url: "http://www.com.com.cn") << ".com.cn";
3477 QTest::newRow(dataTag: "yes7") << QUrl::fromEncoded(url: "http://www.test.org.ws") << ".org.ws";
3478 QTest::newRow(dataTag: "yes9") << QUrl::fromEncoded(url: "http://www.com.co.uk.wallonie.museum") << ".wallonie.museum";
3479 QTest::newRow(dataTag: "yes10") << QUrl::fromEncoded(url: "http://www.com.evje-og-hornnes.no") << ".evje-og-hornnes.no";
3480 QTest::newRow(dataTag: "yes11") << QUrl::fromEncoded(url: "http://www.bla.kamijima.ehime.jp") << ".kamijima.ehime.jp";
3481 QTest::newRow(dataTag: "yes12") << QUrl::fromEncoded(url: "http://www.bla.kakuda.miyagi.jp") << ".kakuda.miyagi.jp";
3482 QTest::newRow(dataTag: "yes13") << QUrl::fromEncoded(url: "http://mypage.betainabox.com") << ".betainabox.com";
3483 QTest::newRow(dataTag: "yes14") << QUrl::fromEncoded(url: "http://mypage.rhcloud.com") << ".rhcloud.com";
3484 QTest::newRow(dataTag: "yes15") << QUrl::fromEncoded(url: "http://mypage.int.az") << ".int.az";
3485 QTest::newRow(dataTag: "yes16") << QUrl::fromEncoded(url: "http://anything.pagespeedmobilizer.com") << ".pagespeedmobilizer.com";
3486 QTest::newRow(dataTag: "yes17") << QUrl::fromEncoded(url: "http://anything.eu-central-1.compute.amazonaws.com") << ".eu-central-1.compute.amazonaws.com";
3487 QTest::newRow(dataTag: "yes18") << QUrl::fromEncoded(url: "http://anything.ltd.hk") << ".ltd.hk";
3488 QTest::newRow(dataTag: "trentino.it")
3489 << QUrl::fromEncoded(url: "http://any.thing.trentino.it") << ".trentino.it";
3490 QTest::newRow(dataTag: "net.ni") << QUrl::fromEncoded(url: "http://test.net.ni") << ".net.ni";
3491 QTest::newRow(dataTag: "dyn.cosidns.de")
3492 << QUrl::fromEncoded(url: "http://test.dyn.cosidns.de") << ".dyn.cosidns.de";
3493 QTest::newRow(dataTag: "freeddns.org")
3494 << QUrl::fromEncoded(url: "http://test.freeddns.org") << ".freeddns.org";
3495 QTest::newRow(dataTag: "app.os.stg.fedoraproject.org")
3496 << QUrl::fromEncoded(url: "http://test.app.os.stg.fedoraproject.org")
3497 << ".app.os.stg.fedoraproject.org";
3498 QTest::newRow(dataTag: "development.run") << QUrl::fromEncoded(url: "http://test.development.run") << ".development.run";
3499 QTest::newRow(dataTag: "crafting.xyz") << QUrl::fromEncoded(url: "http://test.crafting.xyz") << ".crafting.xyz";
3500 QTest::newRow(dataTag: "nym.ie") << QUrl::fromEncoded(url: "http://shamus.nym.ie") << ".ie";
3501 QTest::newRow(dataTag: "vapor.cloud") << QUrl::fromEncoded(url: "http://test.vapor.cloud") << ".vapor.cloud";
3502 QTest::newRow(dataTag: "official.academy") << QUrl::fromEncoded(url: "http://acredited.official.academy") << ".official.academy";
3503}
3504
3505void tst_QUrl::effectiveTLDs()
3506{
3507 QFETCH(QUrl, domain);
3508 QFETCH(QString, TLD);
3509 QCOMPARE(domain.topLevelDomain(QUrl::PrettyDecoded), TLD);
3510 QCOMPARE(domain.topLevelDomain(QUrl::FullyDecoded), TLD);
3511}
3512
3513void tst_QUrl::lowercasesScheme()
3514{
3515 QUrl url;
3516 url.setScheme("HELLO");
3517 QCOMPARE(url.scheme(), QString("hello"));
3518}
3519
3520void tst_QUrl::componentEncodings_data()
3521{
3522 QTest::addColumn<QUrl>(name: "url");
3523 QTest::addColumn<int>(name: "encoding");
3524 QTest::addColumn<QString>(name: "userName");
3525 QTest::addColumn<QString>(name: "password");
3526 QTest::addColumn<QString>(name: "userInfo");
3527 QTest::addColumn<QString>(name: "host");
3528 QTest::addColumn<QString>(name: "authority");
3529 QTest::addColumn<QString>(name: "path");
3530 QTest::addColumn<QString>(name: "query");
3531 QTest::addColumn<QString>(name: "fragment");
3532 QTest::addColumn<QString>(name: "toString");
3533
3534 const int MostDecoded = QUrl::DecodeReserved; // the most decoded mode without being fully decoded
3535
3536 QTest::newRow(dataTag: "empty") << QUrl() << int(QUrl::FullyEncoded)
3537 << QString() << QString() << QString()
3538 << QString() << QString()
3539 << QString() << QString() << QString() << QString();
3540
3541 // hostname cannot contain spaces
3542 QTest::newRow(dataTag: "encoded-space") << QUrl("x://user name:pass word@host/path name?query value#fragment value")
3543 << int(QUrl::EncodeSpaces)
3544 << "user%20name" << "pass%20word" << "user%20name:pass%20word"
3545 << "host" << "user%20name:pass%20word@host"
3546 << "/path%20name" << "query%20value" << "fragment%20value"
3547 << "x://user%20name:pass%20word@host/path%20name?query%20value#fragment%20value";
3548
3549 QTest::newRow(dataTag: "decoded-space") << QUrl("x://user%20name:pass%20word@host/path%20name?query%20value#fragment%20value")
3550 << MostDecoded
3551 << "user name" << "pass word" << "user name:pass word"
3552 << "host" << "user name:pass word@host"
3553 << "/path name" << "query value" << "fragment value"
3554 << "x://user name:pass word@host/path name?query value#fragment value";
3555
3556 // binary data is always encoded
3557 // this is also testing non-UTF8 data
3558 QTest::newRow(dataTag: "binary") << QUrl("x://%c0%00:%c1%01@host/%c2%02?%c3%03#%d4%04")
3559 << MostDecoded
3560 << "%C0%00" << "%C1%01" << "%C0%00:%C1%01"
3561 << "host" << "%C0%00:%C1%01@host"
3562 << "/%C2%02" << "%C3%03" << "%D4%04"
3563 << "x://%C0%00:%C1%01@host/%C2%02?%C3%03#%D4%04";
3564
3565 // unicode tests
3566 // hostnames can participate in this test, but we need a top-level domain that accepts Unicode
3567 QTest::newRow(dataTag: "encoded-unicode") << QUrl(QString::fromUtf8(str: "x://\xc2\x80:\xc3\x90@smørbrød.example.no/\xe0\xa0\x80?\xf0\x90\x80\x80#é"))
3568 << int(QUrl::EncodeUnicode)
3569 << "%C2%80" << "%C3%90" << "%C2%80:%C3%90"
3570 << "xn--smrbrd-cyad.example.no" << "%C2%80:%C3%90@xn--smrbrd-cyad.example.no"
3571 << "/%E0%A0%80" << "%F0%90%80%80" << "%C3%A9"
3572 << "x://%C2%80:%C3%90@xn--smrbrd-cyad.example.no/%E0%A0%80?%F0%90%80%80#%C3%A9";
3573 QTest::newRow(dataTag: "decoded-unicode") << QUrl("x://%C2%80:%C3%90@XN--SMRBRD-cyad.example.NO/%E0%A0%80?%F0%90%80%80#%C3%A9")
3574 << MostDecoded
3575 << QString::fromUtf8(str: "\xc2\x80") << QString::fromUtf8(str: "\xc3\x90")
3576 << QString::fromUtf8(str: "\xc2\x80:\xc3\x90")
3577 << QString::fromUtf8(str: "smørbrød.example.no")
3578 << QString::fromUtf8(str: "\xc2\x80:\xc3\x90@smørbrød.example.no")
3579 << QString::fromUtf8(str: "/\xe0\xa0\x80")
3580 << QString::fromUtf8(str: "\xf0\x90\x80\x80") << QString::fromUtf8(str: "é")
3581 << QString::fromUtf8(str: "x://\xc2\x80:\xc3\x90@smørbrød.example.no/\xe0\xa0\x80?\xf0\x90\x80\x80#é");
3582
3583 // unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
3584 // these are always decoded
3585 QTest::newRow(dataTag: "decoded-unreserved") << QUrl("x://%61:%71@%41%30%2eexample%2ecom/%7e?%5f#%51")
3586 << int(QUrl::FullyEncoded)
3587 << "a" << "q" << "a:q"
3588 << "a0.example.com" << "a:q@a0.example.com"
3589 << "/~" << "_" << "Q"
3590 << "x://a:q@a0.example.com/~?_#Q";
3591
3592 // sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
3593 // / "*" / "+" / "," / ";" / "="
3594 // these are always left alone
3595 QTest::newRow(dataTag: "decoded-subdelims") << QUrl("x://!$&:'()@host/*+,?$=(+)#;=")
3596 << int(QUrl::FullyEncoded)
3597 << "!$&" << "'()" << "!$&:'()"
3598 << "host" << "!$&:'()@host"
3599 << "/*+," << "$=(+)" << ";="
3600 << "x://!$&:'()@host/*+,?$=(+)#;=";
3601 QTest::newRow(dataTag: "encoded-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c?%26=%26&%3d=%3d#%3b%3d")
3602 << MostDecoded
3603 << "%21%24%26" << "%27%28%29" << "%21%24%26:%27%28%29"
3604 << "host" << "%21%24%26:%27%28%29@host"
3605 << "/%2A%2B%2C" << "%26=%26&%3D=%3D" << "%3B%3D"
3606 << "x://%21%24%26:%27%28%29@host/%2A%2B%2C?%26=%26&%3D=%3D#%3B%3D";
3607
3608 // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
3609 // these are the separators between fields
3610 // they must appear encoded in certain positions in the full URL, no exceptions
3611 // when in those positions, they appear decoded in the isolated parts
3612 // in other positions and the other delimiters are always left untransformed
3613 // 1) test the delimiters that must appear encoded
3614 // (if they were decoded, they'd would change the URL parsing)
3615 QTest::newRow(dataTag: "encoded-gendelims-changing") << QUrl("x://%5b%3a%2f%3f%23%40%5d:%5b%2f%3f%23%40%5d@host/%2f%3f%23?%23")
3616 << MostDecoded
3617 << "[:/?#@]" << "[/?#@]" << "[%3A/?#@]:[/?#@]"
3618 << "host" << "%5B%3A/?#%40%5D:%5B/?#%40%5D@host"
3619 << "/%2F?#" << "#" << ""
3620 << "x://%5B%3A%2F%3F%23%40%5D:%5B%2F%3F%23%40%5D@host/%2F%3F%23?%23";
3621
3622 // 2) test that the other delimiters remain decoded
3623 QTest::newRow(dataTag: "decoded-gendelims-unchanging") << QUrl("x://::@host/:@/[]?:/?@[]?#:/?@[]")
3624 << int(QUrl::FullyEncoded)
3625 << "" << ":" << "::"
3626 << "host" << "::@host"
3627 << "/:@/[]" << ":/?@[]?" << ":/?@[]"
3628 << "x://::@host/:@/[]?:/?@[]?#:/?@[]";
3629
3630 // 3) and test that the same encoded sequences remain encoded
3631 QTest::newRow(dataTag: "encoded-gendelims-unchanging") << QUrl("x://:%3A@host/%3A%40%5B%5D?%3A%2F%3F%40%5B%5D#%23%3A%2F%3F%40%5B%5D")
3632 << MostDecoded
3633 << "" << "%3A" << ":%3A"
3634 << "host" << ":%3A@host"
3635 << "/%3A%40%5B%5D" << "%3A%2F%3F%40%5B%5D" << "%23%3A%2F%3F%40%5B%5D"
3636 << "x://:%3A@host/%3A%40%5B%5D?%3A%2F%3F%40%5B%5D#%23%3A%2F%3F%40%5B%5D";
3637
3638 // test the query
3639 // since QUrl doesn't know what chars the user wants to use for the pair and value delimiters,
3640 // it keeps the delimiters alone except for "#", which must always be encoded.
3641 // In the following test, all delimiter characters appear both as encoded and as decoded (except for "#")
3642 QTest::newRow(dataTag: "unencoded-delims-query") << QUrl("?!$()*+,;=:/?[]@%21%24%26%27%28%29%2a%2b%2c%2f%3a%3b%3d%3f%40%5b%5d")
3643 << int(QUrl::FullyEncoded)
3644 << QString() << QString() << QString()
3645 << QString() << QString()
3646 << QString() << "!$()*+,;=:/?[]@%21%24%26%27%28%29%2A%2B%2C%2F%3A%3B%3D%3F%40%5B%5D" << QString()
3647 << "?!$()*+,;=:/?[]@%21%24%26%27%28%29%2A%2B%2C%2F%3A%3B%3D%3F%40%5B%5D";
3648 QTest::newRow(dataTag: "undecoded-delims-query") << QUrl("?!$()*+,;=:/?[]@%21%24%26%27%28%29%2a%2b%2c%2f%3a%3b%3d%3f%40%5b%5d")
3649 << MostDecoded
3650 << QString() << QString() << QString()
3651 << QString() << QString()
3652 << QString() << "!$()*+,;=:/?[]@%21%24%26%27%28%29%2A%2B%2C%2F%3A%3B%3D%3F%40%5B%5D" << QString()
3653 << "?!$()*+,;=:/?[]@%21%24%26%27%28%29%2A%2B%2C%2F%3A%3B%3D%3F%40%5B%5D";
3654
3655 // reserved characters: '"' / "<" / ">" / "^" / "\" / "{" / "|" "}"
3656 // the RFC does not allow them undecoded anywhere, but we do
3657 QTest::newRow(dataTag: "encoded-reserved") << QUrl("x://\"<>^\\{|}:\"<>^\\{|}@host/\"<>^\\{|}?\"<>^\\{|}#\"<>^\\{|}")
3658 << int(QUrl::FullyEncoded)
3659 << "%22%3C%3E%5E%5C%7B%7C%7D" << "%22%3C%3E%5E%5C%7B%7C%7D"
3660 << "%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D"
3661 << "host" << "%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D@host"
3662 << "/%22%3C%3E%5E%5C%7B%7C%7D" << "%22%3C%3E%5E%5C%7B%7C%7D"
3663 << "%22%3C%3E%5E%5C%7B%7C%7D"
3664 << "x://%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D@host/%22%3C%3E%5E%5C%7B%7C%7D"
3665 "?%22%3C%3E%5E%5C%7B%7C%7D#%22%3C%3E%5E%5C%7B%7C%7D";
3666 QTest::newRow(dataTag: "decoded-reserved") << QUrl("x://%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D@host"
3667 "/%22%3C%3E%5E%5C%7B%7C%7D?%22%3C%3E%5E%5C%7B%7C%7D#%22%3C%3E%5E%5C%7B%7C%7D")
3668 << int(QUrl::DecodeReserved)
3669 << "\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}:\"<>^\\{|}"
3670 << "host" << "\"<>^\\{|}:\"<>^\\{|}@host"
3671 << "/\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}"
3672 << "x://\"<>^\\{|}:\"<>^\\{|}@host/\"<>^\\{|}?\"<>^\\{|}#\"<>^\\{|}";
3673
3674
3675 // Beauty is in the eye of the beholder
3676 // Test PrettyDecoder against our expectations
3677
3678 // spaces and unicode are considered pretty and are decoded
3679 // this includes hostnames
3680 QTest::newRow(dataTag: "pretty-spaces-unicode") << QUrl("x://%20%c3%a9:%c3%a9%20@XN--SMRBRD-cyad.example.NO/%c3%a9%20?%20%c3%a9#%c3%a9%20")
3681 << int(QUrl::PrettyDecoded)
3682 << QString::fromUtf8(str: " é") << QString::fromUtf8(str: "é ")
3683 << QString::fromUtf8(str: " é:é ")
3684 << QString::fromUtf8(str: "smørbrød.example.no")
3685 << QString::fromUtf8(str: " é:é @smørbrød.example.no")
3686 << QString::fromUtf8(str: "/é ") << QString::fromUtf8(str: " é")
3687 << QString::fromUtf8(str: "é ")
3688 << QString::fromUtf8(str: "x:// é:é @smørbrød.example.no/é ? é#é ");
3689
3690 // the pretty form decodes all unambiguous gen-delims in the individual parts
3691 QTest::newRow(dataTag: "pretty-gendelims") << QUrl("x://%5b%3a%40%2f%3f%23%5d:%5b%40%2f%3f%23%5d@host/%3f%23?%23")
3692 << int(QUrl::PrettyDecoded)
3693 << "[:@/?#]" << "[@/?#]" << "[%3A@/?#]:[@/?#]"
3694 << "host" << "%5B%3A%40/?#%5D:%5B%40/?#%5D@host"
3695 << "/?#" << "#" << ""
3696 << "x://%5B%3A%40%2F%3F%23%5D:%5B%40%2F%3F%23%5D@host/%3F%23?%23";
3697
3698 // the pretty form keeps the other characters decoded everywhere
3699 // except when rebuilding the full URL, when we only allow "{}" to remain decoded
3700 QTest::newRow(dataTag: "pretty-reserved") << QUrl("x://\"<>^\\{|}:\"<>^\\{|}@host/\"<>^\\{|}?\"<>^\\{|}#\"<>^\\{|}")
3701 << int(QUrl::PrettyDecoded)
3702 << "\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}:\"<>^\\{|}"
3703 << "host" << "\"<>^\\{|}:\"<>^\\{|}@host"
3704 << "/\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}"
3705 << "x://%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D@host/%22%3C%3E%5E%5C%7B%7C%7D"
3706 "?%22%3C%3E%5E%5C%7B%7C%7D#%22%3C%3E%5E%5C%7B%7C%7D";
3707}
3708
3709void tst_QUrl::componentEncodings()
3710{
3711 QFETCH(QUrl, url);
3712 QFETCH(int, encoding);
3713 QFETCH(QString, userName);
3714 QFETCH(QString, password);
3715 QFETCH(QString, userInfo);
3716 QFETCH(QString, host);
3717 QFETCH(QString, authority);
3718 QFETCH(QString, path);
3719 QFETCH(QString, query);
3720 QFETCH(QString, fragment);
3721 QFETCH(QString, toString);
3722
3723 QUrl::ComponentFormattingOptions formatting(encoding);
3724 QCOMPARE(url.userName(formatting), userName);
3725 QCOMPARE(url.password(formatting), password);
3726 QCOMPARE(url.userInfo(formatting), userInfo);
3727 QCOMPARE(url.host(formatting), host);
3728 QCOMPARE(url.authority(formatting), authority);
3729 QCOMPARE(url.path(formatting), path);
3730 QCOMPARE(url.query(formatting), query);
3731 QCOMPARE(url.fragment(formatting), fragment);
3732 QCOMPARE(url.toString(formatting),
3733 (((QString(toString ))))); // the weird () and space is to align the output
3734
3735 // repeat with the URL we got from toString
3736 QUrl url2(toString);
3737 QCOMPARE(url2.userName(formatting), userName);
3738 QCOMPARE(url2.password(formatting), password);
3739 QCOMPARE(url2.userInfo(formatting), userInfo);
3740 QCOMPARE(url2.host(formatting), host);
3741 QCOMPARE(url2.authority(formatting), authority);
3742 QCOMPARE(url2.path(formatting), path);
3743 QCOMPARE(url2.query(formatting), query);
3744 QCOMPARE(url2.fragment(formatting), fragment);
3745 QCOMPARE(url2.toString(formatting), toString);
3746
3747 // and use the comparison operator
3748 QCOMPARE(url2, url);
3749}
3750
3751enum Component {
3752 Scheme = 0x01,
3753 UserName = 0x02,
3754 Password = 0x04,
3755 UserInfo = UserName | Password,
3756 Host = 0x08,
3757 Port = 0x10,
3758 Authority = UserInfo | Host | Port,
3759 Path = 0x20,
3760 Hierarchy = Authority | Path,
3761 Query = 0x40,
3762 Fragment = 0x80,
3763 FullUrl = 0xff
3764};
3765
3766void tst_QUrl::setComponents_data()
3767{
3768 QTest::addColumn<QUrl>(name: "original");
3769 QTest::addColumn<int>(name: "component");
3770 QTest::addColumn<QString>(name: "newValue");
3771 QTest::addColumn<int>(name: "parsingMode");
3772 QTest::addColumn<bool>(name: "isValid");
3773 QTest::addColumn<int>(name: "encoding");
3774 QTest::addColumn<QString>(name: "output");
3775 QTest::addColumn<QString>(name: "toString");
3776
3777 const int Tolerant = QUrl::TolerantMode;
3778 const int Strict = QUrl::StrictMode;
3779 const int Decoded = QUrl::DecodedMode;
3780 const int PrettyDecoded = QUrl::PrettyDecoded;
3781 const int FullyDecoded = QUrl::FullyDecoded;
3782
3783 // -- test empty vs null --
3784 // there's no empty-but-present scheme or path
3785 // a URL with an empty scheme is a "URI reference"
3786 // and the path is always non-empty if it's present
3787 QTest::newRow(dataTag: "scheme-null") << QUrl("http://example.com")
3788 << int(Scheme) << QString() << Tolerant << true
3789 << PrettyDecoded << QString() << "//example.com";
3790 QTest::newRow(dataTag: "scheme-empty") << QUrl("http://example.com")
3791 << int(Scheme) << "" << Tolerant << true
3792 << PrettyDecoded << "" << "//example.com";
3793 QTest::newRow(dataTag: "path-null") << QUrl("http://example.com/path")
3794 << int(Path) << QString() << Tolerant << true
3795 << PrettyDecoded << QString() << "http://example.com";
3796 QTest::newRow(dataTag: "path-empty") << QUrl("http://example.com/path")
3797 << int(Path) << "" << Tolerant << true
3798 << PrettyDecoded << "" << "http://example.com";
3799 // If the %3A gets decoded to ":", the URL becomes invalid;
3800 // see test path-invalid-1 below
3801 QTest::newRow(dataTag: "path-%3A-before-slash") << QUrl()
3802 << int(Path) << "c%3A/" << Tolerant << true
3803 << PrettyDecoded << "c%3A/" << "c%3A/";
3804 QTest::newRow(dataTag: "path-doubleslash") << QUrl("http://example.com")
3805 << int(Path) << "//path" << Tolerant << true
3806 << PrettyDecoded << "//path" << "http://example.com//path";
3807 QTest::newRow(dataTag: "path-withdotdot") << QUrl("file:///tmp")
3808 << int(Path) << "//tmp/..///root/." << Tolerant << true
3809 << PrettyDecoded << "//tmp/..///root/." << "file:////tmp/..///root/.";
3810
3811 // the other fields can be present and be empty
3812 // that is, their delimiters would be present, but there would be nothing to one side
3813 QTest::newRow(dataTag: "userinfo-null") << QUrl("http://user:pass@example.com")
3814 << int(UserInfo) << QString() << Tolerant << true
3815 << PrettyDecoded << QString() << "http://example.com";
3816 QTest::newRow(dataTag: "userinfo-empty") << QUrl("http://user:pass@example.com")
3817 << int(UserInfo) << "" << Tolerant << true
3818 << PrettyDecoded << "" << "http://@example.com";
3819 QTest::newRow(dataTag: "userinfo-colon") << QUrl("http://user@example.com")
3820 << int(UserInfo) << ":" << Tolerant << true
3821 << PrettyDecoded << ":" << "http://:@example.com";
3822 QTest::newRow(dataTag: "username-null") << QUrl("http://user@example.com")
3823 << int(UserName) << QString() << Tolerant << true
3824 << PrettyDecoded << QString() << "http://example.com";
3825 QTest::newRow(dataTag: "username-empty") << QUrl("http://user@example.com")
3826 << int(UserName) << "" << Tolerant << true
3827 << PrettyDecoded << "" << "http://@example.com";
3828 QTest::newRow(dataTag: "username-empty-password-nonempty") << QUrl("http://user:pass@example.com")
3829 << int(UserName) << "" << Tolerant << true
3830 << PrettyDecoded << "" << "http://:pass@example.com";
3831 QTest::newRow(dataTag: "username-empty-password-empty") << QUrl("http://user:@example.com")
3832 << int(UserName) << "" << Tolerant << true
3833 << PrettyDecoded << "" << "http://:@example.com";
3834 QTest::newRow(dataTag: "password-null") << QUrl("http://user:pass@example.com")
3835 << int(Password) << QString() << Tolerant << true
3836 << PrettyDecoded << QString() << "http://user@example.com";
3837 QTest::newRow(dataTag: "password-empty") << QUrl("http://user:pass@example.com")
3838 << int(Password) << "" << Tolerant << true
3839 << PrettyDecoded << "" << "http://user:@example.com";
3840 QTest::newRow(dataTag: "host-null") << QUrl("foo://example.com/path")
3841 << int(Host) << QString() << Tolerant << true
3842 << PrettyDecoded << QString() << "foo:/path";
3843 QTest::newRow(dataTag: "host-empty") << QUrl("foo://example.com/path")
3844 << int(Host) << "" << Tolerant << true
3845 << PrettyDecoded << QString() << "foo:///path";
3846 QTest::newRow(dataTag: "authority-null") << QUrl("foo://example.com/path")
3847 << int(Authority) << QString() << Tolerant << true
3848 << PrettyDecoded << QString() << "foo:/path";
3849 QTest::newRow(dataTag: "authority-empty") << QUrl("foo://example.com/path")
3850 << int(Authority) << "" << Tolerant << true
3851 << PrettyDecoded << QString() << "foo:///path";
3852 QTest::newRow(dataTag: "query-null") << QUrl("http://example.com/?q=foo")
3853 << int(Query) << QString() << Tolerant << true
3854 << PrettyDecoded << QString() << "http://example.com/";
3855 QTest::newRow(dataTag: "query-empty") << QUrl("http://example.com/?q=foo")
3856 << int(Query) << "" << Tolerant << true
3857 << PrettyDecoded << QString() << "http://example.com/?";
3858 QTest::newRow(dataTag: "fragment-null") << QUrl("http://example.com/#bar")
3859 << int(Fragment) << QString() << Tolerant << true
3860 << PrettyDecoded << QString() << "http://example.com/";
3861 QTest::newRow(dataTag: "fragment-empty") << QUrl("http://example.com/#bar")
3862 << int(Fragment) << "" << Tolerant << true
3863 << PrettyDecoded << "" << "http://example.com/#";
3864
3865 // -- test some non-valid components --
3866 QTest::newRow(dataTag: "invalid-scheme-1") << QUrl("http://example.com")
3867 << int(Scheme) << "1http" << Tolerant << false
3868 << PrettyDecoded << "" << "";
3869 QTest::newRow(dataTag: "invalid-scheme-2") << QUrl("http://example.com")
3870 << int(Scheme) << "http%40" << Tolerant << false
3871 << PrettyDecoded << "" << "";
3872 QTest::newRow(dataTag: "invalid-scheme-3") << QUrl("http://example.com")
3873 << int(Scheme) << "http%61" << Strict << false
3874 << PrettyDecoded << "" << "";
3875
3876 QTest::newRow(dataTag: "invalid-username-1") << QUrl("http://example.com")
3877 << int(UserName) << "{}" << Strict << false
3878 << PrettyDecoded << "" << "";
3879 QTest::newRow(dataTag: "invalid-username-2") << QUrl("http://example.com")
3880 << int(UserName) << "foo/bar" << Strict << false
3881 << PrettyDecoded << "" << "";
3882 QTest::newRow(dataTag: "invalid-username-3") << QUrl("http://example.com")
3883 << int(UserName) << "foo:bar" << Strict << false
3884 << PrettyDecoded << "" << "";
3885 QTest::newRow(dataTag: "invalid-password-1") << QUrl("http://example.com")
3886 << int(Password) << "{}" << Strict << false
3887 << PrettyDecoded << "" << "";
3888 QTest::newRow(dataTag: "invalid-password-2") << QUrl("http://example.com")
3889 << int(Password) << "foo/bar" << Strict << false
3890 << PrettyDecoded << "" << "";
3891 QTest::newRow(dataTag: "invalid-password-3") << QUrl("http://example.com")
3892 << int(Password) << "foo:bar" << Strict << false
3893 << PrettyDecoded << "" << "";
3894 QTest::newRow(dataTag: "invalid-userinfo-1") << QUrl("http://example.com")
3895 << int(UserInfo) << "{}" << Strict << false
3896 << PrettyDecoded << "" << "";
3897 QTest::newRow(dataTag: "invalid-userinfo-2") << QUrl("http://example.com")
3898 << int(UserInfo) << "foo/bar" << Strict << false
3899 << PrettyDecoded << "" << "";
3900
3901 QTest::newRow(dataTag: "invalid-host-1") << QUrl("http://example.com")
3902 << int(Host) << "-not-valid-" << Tolerant << false
3903 << PrettyDecoded << "" << "";
3904 QTest::newRow(dataTag: "invalid-host-2") << QUrl("http://example.com")
3905 << int(Host) << "%31%30.%30.%30.%31" << Strict << false
3906 << PrettyDecoded << "" << "";
3907 QTest::newRow(dataTag: "invalid-authority-1") << QUrl("http://example.com")
3908 << int(Authority) << "-not-valid-" << Tolerant << false
3909 << PrettyDecoded << "" << "";
3910 QTest::newRow(dataTag: "invalid-authority-2") << QUrl("http://example.com")
3911 << int(Authority) << "%31%30.%30.%30.%31" << Strict << false
3912 << PrettyDecoded << "" << "";
3913
3914 QTest::newRow(dataTag: "invalid-path-0") << QUrl("http://example.com")
3915 << int(Path) << "{}" << Strict << false
3916 << PrettyDecoded << "" << "";
3917 QTest::newRow(dataTag: "invalid-query-1") << QUrl("http://example.com")
3918 << int(Query) << "{}" << Strict << false
3919 << PrettyDecoded << "" << "";
3920 QTest::newRow(dataTag: "invalid-fragment-1") << QUrl("http://example.com")
3921 << int(Fragment) << "{}" << Strict << false
3922 << PrettyDecoded << "" << "";
3923
3924 // these test cases are "compound invalid":
3925 // they produces isValid == false, but the original is still available
3926 QTest::newRow(dataTag: "invalid-path-1") << QUrl("/relative")
3927 << int(Path) << "c:/" << Strict << false
3928 << PrettyDecoded << "c:/" << "";
3929 QTest::newRow(dataTag: "invalid-path-2") << QUrl("http://example.com")
3930 << int(Path) << "relative" << Strict << false
3931 << PrettyDecoded << "relative" << "";
3932 QTest::newRow(dataTag: "invalid-path-3") << QUrl("trash:/")
3933 << int(Path) << "//path" << Tolerant << false
3934 << PrettyDecoded << "//path" << "";
3935
3936 // -- test bad percent encoding --
3937 // unnecessary to test the scheme, since percent-decoding is not performed in it;
3938 // see tests above
3939 QTest::newRow(dataTag: "bad-percent-username") << QUrl("http://example.com")
3940 << int(UserName) << "bar%foo" << Strict << false
3941 << PrettyDecoded << "" << "";
3942 QTest::newRow(dataTag: "bad-percent-password") << QUrl("http://user@example.com")
3943 << int(Password) << "bar%foo" << Strict << false
3944 << PrettyDecoded << "" << "";
3945 QTest::newRow(dataTag: "bad-percent-userinfo-1") << QUrl("http://example.com")
3946 << int(UserInfo) << "bar%foo" << Strict << false
3947 << PrettyDecoded << "" << "";
3948 QTest::newRow(dataTag: "bad-percent-userinfo-2") << QUrl("http://example.com")
3949 << int(UserInfo) << "bar%:foo" << Strict << false
3950 << PrettyDecoded << "" << "";
3951 QTest::newRow(dataTag: "bad-percent-userinfo-3") << QUrl("http://example.com")
3952 << int(UserInfo) << "bar:%foo" << Strict << false
3953 << PrettyDecoded << "" << "";
3954 QTest::newRow(dataTag: "bad-percent-authority-1") << QUrl("http://example.com")
3955 << int(Authority) << "bar%foo@example.org" << Strict << false
3956 << PrettyDecoded << "" << "";
3957 QTest::newRow(dataTag: "bad-percent-authority-2") << QUrl("http://example.com")
3958 << int(Authority) << "bar%:foo@example.org" << Strict << false
3959 << PrettyDecoded << "" << "";
3960 QTest::newRow(dataTag: "bad-percent-authority-3") << QUrl("http://example.com")
3961 << int(Authority) << "bar:%foo@example.org" << Strict << false
3962 << PrettyDecoded << "" << "";
3963 QTest::newRow(dataTag: "bad-percent-authority-4") << QUrl("http://example.com")
3964 << int(Authority) << "bar:foo@bar%foo" << Strict << false
3965 << PrettyDecoded << "" << "";
3966 QTest::newRow(dataTag: "bad-percent-host") << QUrl("http://example.com")
3967 << int(Host) << "bar%foo" << Strict << false
3968 << PrettyDecoded << "" << "";
3969 QTest::newRow(dataTag: "bad-percent-path") << QUrl("http://example.com")
3970 << int(Path) << "/bar%foo" << Strict << false
3971 << PrettyDecoded << "" << "";
3972 QTest::newRow(dataTag: "bad-percent-query") << QUrl("http://example.com")
3973 << int(Query) << "bar%foo" << Strict << false
3974 << PrettyDecoded << "" << "";
3975 QTest::newRow(dataTag: "bad-percent-fragment") << QUrl("http://example.com")
3976 << int(Fragment) << "bar%foo" << Strict << false
3977 << PrettyDecoded << "" << "";
3978
3979 // -- test decoded behaviour --
3980 // '%' characters are not permitted in the scheme, this tests that it fails to set anything
3981 QTest::newRow(dataTag: "invalid-scheme-encode") << QUrl("http://example.com")
3982 << int(Scheme) << "http%61" << Decoded << false
3983 << PrettyDecoded << "" << "";
3984 QTest::newRow(dataTag: "username-encode") << QUrl("http://example.com")
3985 << int(UserName) << "h%61llo:world" << Decoded << true
3986 << PrettyDecoded << "h%2561llo:world" << "http://h%2561llo%3Aworld@example.com";
3987 QTest::newRow(dataTag: "password-encode") << QUrl("http://example.com")
3988 << int(Password) << "h%61llo:world@" << Decoded << true
3989 << PrettyDecoded << "h%2561llo:world@" << "http://:h%2561llo:world%40@example.com";
3990 // '%' characters are not permitted in the hostname, these test that it fails to set anything
3991 QTest::newRow(dataTag: "invalid-host-encode") << QUrl("http://example.com")
3992 << int(Host) << "ex%61mple.com" << Decoded << false
3993 << PrettyDecoded << "" << "";
3994 QTest::newRow(dataTag: "path-encode") << QUrl("http://example.com/foo")
3995 << int(Path) << "/bar%23" << Decoded << true
3996 << PrettyDecoded << "/bar%2523" << "http://example.com/bar%2523";
3997 QTest::newRow(dataTag: "query-encode") << QUrl("http://example.com/foo?q")
3998 << int(Query) << "bar%23" << Decoded << true
3999 << PrettyDecoded << "bar%2523" << "http://example.com/foo?bar%2523";
4000 QTest::newRow(dataTag: "fragment-encode") << QUrl("http://example.com/foo#z")
4001 << int(Fragment) << "bar%23" << Decoded << true
4002 << PrettyDecoded << "bar%2523" << "http://example.com/foo#bar%2523";
4003 // force decoding
4004 QTest::newRow(dataTag: "username-decode") << QUrl("http://example.com")
4005 << int(UserName) << "hello%3Aworld%25" << Tolerant << true
4006 << FullyDecoded << "hello:world%" << "http://hello%3Aworld%25@example.com";
4007 QTest::newRow(dataTag: "password-decode") << QUrl("http://example.com")
4008 << int(Password) << "}}>b9o%25kR(" << Tolerant << true
4009 << FullyDecoded << "}}>b9o%kR(" << "http://:%7D%7D%3Eb9o%25kR(@example.com";
4010 QTest::newRow(dataTag: "path-decode") << QUrl("http://example.com/")
4011 << int(Path) << "/bar%25foo" << Tolerant << true
4012 << FullyDecoded << "/bar%foo" << "http://example.com/bar%25foo";
4013 QTest::newRow(dataTag: "query-decode") << QUrl("http://example.com/foo?qq")
4014 << int(Query) << "bar%25foo" << Tolerant << true
4015 << FullyDecoded << "bar%foo" << "http://example.com/foo?bar%25foo";
4016 QTest::newRow(dataTag: "fragment-decode") << QUrl("http://example.com/foo#qq")
4017 << int(Fragment) << "bar%25foo" << Tolerant << true
4018 << FullyDecoded << "bar%foo" << "http://example.com/foo#bar%25foo";
4019}
4020
4021void tst_QUrl::setComponents()
4022{
4023 QFETCH(QUrl, original);
4024 QUrl copy(original);
4025
4026 QFETCH(int, component);
4027 QFETCH(int, parsingMode);
4028 QFETCH(QString, newValue);
4029 QFETCH(int, encoding);
4030 QFETCH(QString, output);
4031
4032 switch (component) {
4033 case Scheme:
4034 // scheme is only parsed in strict mode
4035 copy.setScheme(newValue);
4036 QCOMPARE(copy.scheme(), output);
4037 break;
4038
4039 case Path:
4040 copy.setPath(path: newValue, mode: QUrl::ParsingMode(parsingMode));
4041 QCOMPARE(copy.path(QUrl::ComponentFormattingOptions(encoding)), output);
4042 break;
4043
4044 case UserInfo:
4045 copy.setUserInfo(userInfo: newValue, mode: QUrl::ParsingMode(parsingMode));
4046 QCOMPARE(copy.userInfo(QUrl::ComponentFormattingOptions(encoding)), output);
4047 break;
4048
4049 case UserName:
4050 copy.setUserName(userName: newValue, mode: QUrl::ParsingMode(parsingMode));
4051 QCOMPARE(copy.userName(QUrl::ComponentFormattingOptions(encoding)), output);
4052 break;
4053
4054 case Password:
4055 copy.setPassword(password: newValue, mode: QUrl::ParsingMode(parsingMode));
4056 QCOMPARE(copy.password(QUrl::ComponentFormattingOptions(encoding)), output);
4057 break;
4058
4059 case Host:
4060 copy.setHost(host: newValue, mode: QUrl::ParsingMode(parsingMode));
4061 QCOMPARE(copy.host(QUrl::ComponentFormattingOptions(encoding)), output);
4062 break;
4063
4064 case Authority:
4065 copy.setAuthority(authority: newValue, mode: QUrl::ParsingMode(parsingMode));
4066 QCOMPARE(copy.authority(QUrl::ComponentFormattingOptions(encoding)), output);
4067 break;
4068
4069 case Query:
4070 copy.setQuery(query: newValue, mode: QUrl::ParsingMode(parsingMode));
4071 QCOMPARE(copy.hasQuery(), !newValue.isNull());
4072 QCOMPARE(copy.query(QUrl::ComponentFormattingOptions(encoding)), output);
4073 break;
4074
4075 case Fragment:
4076 copy.setFragment(fragment: newValue, mode: QUrl::ParsingMode(parsingMode));
4077 QCOMPARE(copy.hasFragment(), !newValue.isNull());
4078 QCOMPARE(copy.fragment(QUrl::ComponentFormattingOptions(encoding)), output);
4079 break;
4080 }
4081
4082 QFETCH(bool, isValid);
4083 QCOMPARE(copy.isValid(), isValid);
4084
4085 if (isValid) {
4086 QFETCH(QString, toString);
4087 QCOMPARE(copy.toString(), toString);
4088 // Check round-tripping
4089 QCOMPARE(QUrl(copy.toString()).toString(), toString);
4090 } else {
4091 QVERIFY(copy.toString().isEmpty());
4092 }
4093}
4094
4095void tst_QUrl::streaming_data()
4096{
4097 QTest::addColumn<QString>(name: "urlStr");
4098
4099 QTest::newRow(dataTag: "origURL") << "http://www.website.com/directory/?#ref";
4100 QTest::newRow(dataTag: "urlWithPassAndNoUser") << "ftp://:password@ftp.kde.org/path";
4101 QTest::newRow(dataTag: "accentuated") << QString::fromUtf8(str: "trash:/été");
4102 QTest::newRow(dataTag: "withPercents") << "http://host/path%25path?%3Fque%25ry#%23ref%25";
4103 QTest::newRow(dataTag: "empty") << "";
4104 QVERIFY(!QUrl("ptal://mlc:usb").isValid());
4105 QTest::newRow(dataTag: "invalid") << "ptal://mlc:usb";
4106 QTest::newRow(dataTag: "ipv6") << "http://[::ffff:129.144.52.38]:81?query";
4107}
4108
4109void tst_QUrl::streaming()
4110{
4111 QFETCH(QString, urlStr);
4112 QUrl url(urlStr);
4113
4114 QByteArray buffer;
4115 QDataStream writeStream( &buffer, QIODevice::WriteOnly );
4116 writeStream << url;
4117
4118 QDataStream stream( buffer );
4119 QUrl restored;
4120 stream >> restored;
4121 if (url.isValid())
4122 QCOMPARE(restored.url(), url.url());
4123 else
4124 QVERIFY(!restored.isValid());
4125}
4126
4127void tst_QUrl::detach()
4128{
4129 QUrl empty;
4130 empty.detach();
4131
4132 QUrl foo("http://www.kde.org");
4133 QUrl foo2 = foo;
4134 foo2.detach(); // not that it's needed, given that setHost detaches, of course. But this increases coverage :)
4135 foo2.setHost(host: "www.gnome.org");
4136 QCOMPARE(foo2.host(), QString("www.gnome.org"));
4137 QCOMPARE(foo.host(), QString("www.kde.org"));
4138}
4139
4140// Test accessing the same QUrl from multiple threads concurrently
4141// To maximize the chances of a race (and of a report from helgrind), we actually use
4142// 10 urls rather than one.
4143class UrlStorage
4144{
4145public:
4146 UrlStorage() {
4147 m_urls.resize(asize: 10);
4148 for (int i = 0 ; i < m_urls.size(); ++i)
4149 m_urls[i] = QUrl::fromEncoded(url: "http://www.kde.org", mode: QUrl::StrictMode);
4150 }
4151 QVector<QUrl> m_urls;
4152};
4153
4154static const UrlStorage * s_urlStorage = nullptr;
4155
4156void tst_QUrl::testThreadingHelper()
4157{
4158 const UrlStorage* storage = s_urlStorage;
4159 for (const auto &u : storage->m_urls) {
4160 // QVERIFY/QCOMPARE trigger race conditions in helgrind
4161 if (!u.isValid())
4162 qFatal(msg: "invalid url");
4163 if (u.scheme() != QLatin1String("http"))
4164 qFatal(msg: "invalid scheme");
4165 if (!u.toString().startsWith(c: 'h'))
4166 qFatal(msg: "invalid toString");
4167 QUrl copy(u);
4168 copy.setHost(host: "www.new-host.com");
4169 QUrl copy2(u);
4170 copy2.setUserName(userName: "dfaure");
4171 QUrl copy3(u);
4172 copy3.setUrl(url: "http://www.new-host.com");
4173 QUrl copy4(u);
4174 copy4.detach();
4175 QUrl copy5(u);
4176 QUrl resolved1 = u.resolved(relative: QUrl("index.html"));
4177 Q_UNUSED(resolved1);
4178 QUrl resolved2 = QUrl("http://www.kde.org").resolved(relative: u);
4179 Q_UNUSED(resolved2);
4180 QString local = u.toLocalFile();
4181 Q_UNUSED(local);
4182 QTest::qWait(ms: 10); // give time for the other threads to start
4183 }
4184}
4185
4186#include <QThreadPool>
4187#include <QtConcurrent>
4188
4189void tst_QUrl::testThreading()
4190{
4191 s_urlStorage = new UrlStorage;
4192 QThreadPool::globalInstance()->setMaxThreadCount(100);
4193 QFutureSynchronizer<void> sync;
4194 for (int i = 0; i < 100; ++i)
4195 sync.addFuture(future: QtConcurrent::run(object: this, fn: &tst_QUrl::testThreadingHelper));
4196 sync.waitForFinished();
4197 delete s_urlStorage;
4198}
4199
4200void tst_QUrl::matches_data()
4201{
4202 QTest::addColumn<QString>(name: "urlStrOne");
4203 QTest::addColumn<QString>(name: "urlStrTwo");
4204 QTest::addColumn<uint>(name: "options");
4205 QTest::addColumn<bool>(name: "matches");
4206
4207 QTest::newRow(dataTag: "matchingString-none") << "http://www.website.com/directory/?#ref"
4208 << "http://www.website.com/directory/?#ref"
4209 << uint(QUrl::None) << true;
4210 QTest::newRow(dataTag: "nonMatchingString-none") << "http://www.website.com/directory/?#ref"
4211 << "http://www.nomatch.com/directory/?#ref"
4212 << uint(QUrl::None) << false;
4213 QTest::newRow(dataTag: "matchingHost-removePath") << "http://www.website.com/directory"
4214 << "http://www.website.com/differentdir"
4215 << uint(QUrl::RemovePath) << true;
4216 QTest::newRow(dataTag: "nonMatchingHost-removePath") << "http://www.website.com/directory"
4217 << "http://www.different.com/differentdir"
4218 << uint(QUrl::RemovePath) << false;
4219 QTest::newRow(dataTag: "matchingHost-removePathAuthority") << "http://user:pass@www.website.com/directory"
4220 << "http://www.website.com/differentdir"
4221 << uint(QUrl::RemovePath | QUrl::RemoveAuthority)
4222 << true;
4223 QTest::newRow(dataTag: "nonMatchingHost-removePathAuthority") << "http://user:pass@www.website.com/directory"
4224 << "http://user:pass@www.different.com/differentdir"
4225 << uint(QUrl::RemovePath | QUrl::RemoveAuthority)
4226 << true;
4227 QTest::newRow(dataTag: "matchingHostAuthority-removePathAuthority")
4228 << "http://user:pass@www.website.com/directory" << "http://www.website.com/differentdir"
4229 << uint(QUrl::RemovePath | QUrl::RemoveAuthority) << true;
4230 QTest::newRow(dataTag: "nonMatchingAuthority-removePathAuthority")
4231 << "http://user:pass@www.website.com/directory"
4232 << "http://otheruser:otherpass@www.website.com/directory"
4233 << uint(QUrl::RemovePath | QUrl::RemoveAuthority) << true;
4234 QTest::newRow(dataTag: "matchingHost-removePort") << "http://example.com" << "http://example.com"
4235 << uint(QUrl::RemovePort) << true;
4236 QTest::newRow(dataTag: "nonMatchingHost-removePort") << "http://example.com" << "http://example.net"
4237 << uint(QUrl::RemovePort) << false;
4238 QTest::newRow(dataTag: "matchingHost-removePassword") << "http://example.com" << "http://example.com"
4239 << uint(QUrl::RemovePassword) << true;
4240 QTest::newRow(dataTag: "nonMatchingHost-removePassword") << "http://example.com" << "http://example.net"
4241 << uint(QUrl::RemovePassword) << false;
4242 QTest::newRow(dataTag: "matchingUserName-removePassword") << "http://user@example.com" << "http://user@example.com"
4243 << uint(QUrl::RemovePassword) << true;
4244 QTest::newRow(dataTag: "nonMatchingUserName-removePassword") << "http://user@example.com" << "http://user2@example.com"
4245 << uint(QUrl::RemovePassword) << false;
4246}
4247
4248void tst_QUrl::matches()
4249{
4250 QFETCH(QString, urlStrOne);
4251 QFETCH(QString, urlStrTwo);
4252 QFETCH(uint, options);
4253 QFETCH(bool, matches);
4254
4255 QUrl urlOne(urlStrOne);
4256 QUrl urlTwo(urlStrTwo);
4257 QCOMPARE(urlOne.matches(urlTwo, QUrl::FormattingOptions(options)), matches);
4258}
4259
4260void tst_QUrl::ipv6_zoneId_data()
4261{
4262 QTest::addColumn<QUrl>(name: "url");
4263 QTest::addColumn<QString>(name: "decodedHost");
4264 QTest::addColumn<QString>(name: "prettyHost");
4265 QTest::addColumn<QString>(name: "encodedHost");
4266
4267 QTest::newRow(dataTag: "digit") << QUrl("x://[::%251]") << "::%1" << "::%251" << "::%251";
4268 QTest::newRow(dataTag: "eth0") << QUrl("x://[::%25eth0]") << "::%eth0" << "::%25eth0" << "::%25eth0";
4269 QTest::newRow(dataTag: "space") << QUrl("x://[::%25%20]") << "::% " << "::%25 " << "::%25%20";
4270 QTest::newRow(dataTag: "subdelims") << QUrl("x://[::%25eth%2B]") << "::%eth+" << "::%25eth%2B" << "::%25eth%2B";
4271 QTest::newRow(dataTag: "other") << QUrl("x://[::%25^]") << "::%^" << "::%25%5E" << "::%25%5E";
4272 QTest::newRow(dataTag: "control") << QUrl("x://[::%25%7F]") << "::%\x7f" << "::%25%7F" << "::%25%7F";
4273 QTest::newRow(dataTag: "unicode") << QUrl("x://[::%25wlán0]") << "::%wlán0" << "::%25wlán0" << "::%25wl%C3%A1n0";
4274 QTest::newRow(dataTag: "non-utf8") << QUrl("x://[::%25%80]") << QString("::%") + QChar(QChar::ReplacementCharacter) << "::%25%80" << "::%25%80";
4275 }
4276
4277void tst_QUrl::ipv6_zoneId()
4278{
4279 QFETCH(QUrl, url);
4280 QFETCH(QString, decodedHost);
4281 QFETCH(QString, prettyHost);
4282 QFETCH(QString, encodedHost);
4283
4284 QVERIFY2(url.isValid(), qPrintable(url.errorString()));
4285 QCOMPARE(url.host(QUrl::FullyDecoded), decodedHost);
4286 QCOMPARE(url.host(), decodedHost);
4287 QCOMPARE(url.host(QUrl::FullyEncoded), encodedHost);
4288 QCOMPARE(url.toString(), "x://[" + prettyHost + "]");
4289 QCOMPARE(url.toString(QUrl::FullyEncoded), "x://[" + encodedHost + "]");
4290}
4291
4292void tst_QUrl::normalizeRemotePaths_data()
4293{
4294 QTest::addColumn<QUrl>(name: "url");
4295 QTest::addColumn<QString>(name: "expected");
4296
4297 QTest::newRow(dataTag: "dotdot-slashslash") << QUrl("http://qt-project.org/some/long/..//path") << "http://qt-project.org/some//path";
4298 QTest::newRow(dataTag: "slashslash-dotdot") << QUrl("http://qt-project.org/some//../path") << "http://qt-project.org/some/path";
4299 QTest::newRow(dataTag: "slashslash-dotdot2") << QUrl("http://qt-project.org/some//path/../") << "http://qt-project.org/some//";
4300 QTest::newRow(dataTag: "dot-slash") << QUrl("http://qt-project.org/some/./path") << "http://qt-project.org/some/path";
4301 QTest::newRow(dataTag: "slashslash-dot-slashslash") << QUrl("http://qt-project.org/some//.//path") << "http://qt-project.org/some///path";
4302 QTest::newRow(dataTag: "dot-slashslash") << QUrl("http://qt-project.org/some/.//path") << "http://qt-project.org/some//path";
4303 QTest::newRow(dataTag: "multiple-slashes") << QUrl("http://qt-project.org/some//path") << "http://qt-project.org/some//path";
4304 QTest::newRow(dataTag: "multiple-slashes4") << QUrl("http://qt-project.org/some////path") << "http://qt-project.org/some////path";
4305 QTest::newRow(dataTag: "slashes-at-end") << QUrl("http://qt-project.org/some//") << "http://qt-project.org/some//";
4306 QTest::newRow(dataTag: "dot-dotdot") << QUrl("http://qt-project.org/path/./../") << "http://qt-project.org/";
4307 QTest::newRow(dataTag: "slash-dot-slash-dot-slash") << QUrl("http://qt-project.org/path//.//.//") << "http://qt-project.org/path////";
4308 QTest::newRow(dataTag: "dotdot") << QUrl("http://qt-project.org/../") << "http://qt-project.org/";
4309 QTest::newRow(dataTag: "dotdot-dotdot") << QUrl("http://qt-project.org/path/../../") << "http://qt-project.org/";
4310 QTest::newRow(dataTag: "dot-dotdot-tail") << QUrl("http://qt-project.org/stem/path/./../tail") << "http://qt-project.org/stem/tail";
4311 QTest::newRow(dataTag: "slash-dotdot-slash-tail") << QUrl("http://qt-project.org/stem/path//..//tail") << "http://qt-project.org/stem/path//tail";
4312}
4313
4314void tst_QUrl::normalizeRemotePaths()
4315{
4316 QFETCH(QUrl, url);
4317 QFETCH(QString, expected);
4318
4319 QCOMPARE(url.adjusted(QUrl::NormalizePathSegments).toString(), expected);
4320}
4321
4322QTEST_MAIN(tst_QUrl)
4323
4324#include "tst_qurl.moc"
4325

source code of qtbase/tests/auto/corelib/io/qurl/tst_qurl.cpp