diff options
Diffstat (limited to 'tests/auto/corelib/io')
13 files changed, 485 insertions, 201 deletions
diff --git a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp index 3607467ff9..a6d76ea7b6 100644 --- a/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/corelib/io/qdatastream/tst_qdatastream.cpp @@ -269,7 +269,8 @@ static int NColorRoles[] = { QPalette::ToolTipText + 1, // Qt_4_6 QPalette::ToolTipText + 1, // Qt_5_0 QPalette::ToolTipText + 1, // Qt_5_1 - 0 // add the correct value for Qt_5_2 here later + QPalette::ToolTipText + 1, // Qt_5_2 + 0 // add the correct value for Qt_5_3 here later }; // Testing get/set functions diff --git a/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp b/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp index 1f57e38b44..4fcc46efab 100644 --- a/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp +++ b/tests/auto/corelib/io/qipaddress/tst_qipaddress.cpp @@ -361,7 +361,7 @@ void tst_QIpAddress::parseIp6() #endif Ip6 result; - bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()); + bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()) == 0; QVERIFY(ok); QCOMPARE(result, expected); } @@ -441,7 +441,7 @@ void tst_QIpAddress::invalidParseIp6() #endif Ip6 result; - bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()); + bool ok = QIPAddressUtils::parseIp6(result.u8, address.constBegin(), address.constEnd()) == 0; QVERIFY(!ok); } diff --git a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp index c0bf77cfb2..fdb29b60d8 100644 --- a/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp +++ b/tests/auto/corelib/io/qlockfile/tst_qlockfile.cpp @@ -77,7 +77,7 @@ void tst_QLockFile::initTestCase() QString testdata_dir = QFileInfo(QFINDTESTDATA("qlockfiletesthelper")).absolutePath(); QVERIFY2(QDir::setCurrent(testdata_dir), qPrintable("Could not chdir to " + testdata_dir)); m_helperApp = "qlockfiletesthelper/qlockfile_test_helper"; -#endif +#endif // !QT_NO_PROCESS } void tst_QLockFile::lockUnlock() @@ -111,6 +111,9 @@ void tst_QLockFile::lockUnlock() void tst_QLockFile::lockOutOtherProcess() { +#ifdef QT_NO_PROCESS + QSKIP("This test requires QProcess support"); +#else // Lock const QString fileName = dir.path() + "/lockOtherProcess"; QLockFile lockFile(fileName); @@ -132,6 +135,7 @@ void tst_QLockFile::lockOutOtherProcess() QCOMPARE(ret, int(QLockFile::NoError)); // Lock doesn't survive process though (on clean exit) QVERIFY(!QFile::exists(fileName)); +#endif // !QT_NO_PROCESS } static QLockFile::LockError tryLockFromThread(const QString &fileName) @@ -228,6 +232,9 @@ void tst_QLockFile::staleLockFromCrashedProcess_data() void tst_QLockFile::staleLockFromCrashedProcess() { +#ifdef QT_NO_PROCESS + QSKIP("This test requires QProcess support"); +#else QFETCH(int, staleLockTime); const QString fileName = dir.path() + "/staleLockFromCrashedProcess"; @@ -245,10 +252,14 @@ void tst_QLockFile::staleLockFromCrashedProcess() QVERIFY(secondLock.tryLock()); #endif QCOMPARE(int(secondLock.error()), int(QLockFile::NoError)); +#endif // !QT_NO_PROCESS } void tst_QLockFile::staleShortLockFromBusyProcess() { +#ifdef QT_NO_PROCESS + QSKIP("This test requires QProcess support"); +#else const QString fileName = dir.path() + "/staleLockFromBusyProcess"; QProcess proc; @@ -274,10 +285,14 @@ void tst_QLockFile::staleShortLockFromBusyProcess() proc.waitForFinished(); QVERIFY(secondLock.tryLock()); +#endif // !QT_NO_PROCESS } void tst_QLockFile::staleLongLockFromBusyProcess() { +#ifdef QT_NO_PROCESS + QSKIP("This test requires QProcess support"); +#else const QString fileName = dir.path() + "/staleLockFromBusyProcess"; QProcess proc; @@ -297,6 +312,7 @@ void tst_QLockFile::staleLongLockFromBusyProcess() QVERIFY(!secondLock.removeStaleLockFile()); proc.waitForFinished(); +#endif // !QT_NO_PROCESS } static QString tryStaleLockFromThread(const QString &fileName) @@ -326,6 +342,9 @@ static QString tryStaleLockFromThread(const QString &fileName) void tst_QLockFile::staleLockRace() { +#ifdef QT_NO_PROCESS + QSKIP("This test requires QProcess support"); +#else // Multiple threads notice a stale lock at the same time // Only one thread should delete it, otherwise a race will ensue const QString fileName = dir.path() + "/sharedFile"; @@ -341,6 +360,7 @@ void tst_QLockFile::staleLockRace() synchronizer.waitForFinished(); foreach (const QFuture<QString> &future, synchronizer.futures()) QVERIFY2(future.result().isEmpty(), qPrintable(future.result())); +#endif // !QT_NO_PROCESS } void tst_QLockFile::noPermissions() diff --git a/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp b/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp index f1df6187d0..becff75836 100644 --- a/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp +++ b/tests/auto/corelib/io/qnodebug/tst_qnodebug.cpp @@ -72,7 +72,9 @@ void tst_QNoDebug::noDebugOutput() const void tst_QNoDebug::streaming() const { QDateTime dt(QDate(1,2,3),QTime(4,5,6)); - QTest::ignoreMessage(QtWarningMsg, qPrintable(QString::fromLatin1("QDateTime(\"%1\") ").arg(dt.toString()))); + QString debugString = dt.toString(QStringLiteral("yyyy-MM-dd HH:mm:ss.zzz t")) + + QStringLiteral(" Qt::LocalTime"); + QTest::ignoreMessage(QtWarningMsg, qPrintable(QString::fromLatin1("QDateTime(\"%1\") ").arg(debugString))); qWarning() << dt; } diff --git a/tests/auto/corelib/io/qprocess/testForwarding/main.cpp b/tests/auto/corelib/io/qprocess/testForwarding/main.cpp index e69ae173f4..42394f6414 100644 --- a/tests/auto/corelib/io/qprocess/testForwarding/main.cpp +++ b/tests/auto/corelib/io/qprocess/testForwarding/main.cpp @@ -39,30 +39,49 @@ ** ****************************************************************************/ +#include <QtCore/QCoreApplication> #include <QtCore/QProcess> -int main() +#include <stdlib.h> + +int main(int argc, char **argv) { + QCoreApplication app(argc, argv); + + if (argc < 3) + return 13; + #ifndef QT_NO_PROCESS QProcess process; - process.setProcessChannelMode(QProcess::ForwardedChannels); - if (process.processChannelMode() != QProcess::ForwardedChannels) - return -1; - process.start("testProcessEcho/testProcessEcho"); + QProcess::ProcessChannelMode mode = (QProcess::ProcessChannelMode)atoi(argv[1]); + process.setProcessChannelMode(mode); + if (process.processChannelMode() != mode) + return 1; - if (!process.waitForStarted(5000)) - return -1; + QProcess::InputChannelMode inmode = (QProcess::InputChannelMode)atoi(argv[2]); + process.setInputChannelMode(inmode); + if (process.inputChannelMode() != inmode) + return 11; - if (process.write("forwarded\n") != 10) - return -1; + process.start("testProcessEcho2/testProcessEcho2"); - process.waitForReadyRead(250); - if (process.bytesAvailable() != 0) - return -1; + if (!process.waitForStarted(5000)) + return 2; + + if (inmode == QProcess::ManagedInputChannel && process.write("forwarded") != 9) + return 3; process.closeWriteChannel(); - process.waitForFinished(5000); + if (!process.waitForFinished(5000)) + return 4; + + if ((mode == QProcess::ForwardedOutputChannel || mode == QProcess::ForwardedChannels) + && !process.readAllStandardOutput().isEmpty()) + return 5; + if ((mode == QProcess::ForwardedErrorChannel || mode == QProcess::ForwardedChannels) + && !process.readAllStandardError().isEmpty()) + return 6; #endif return 0; } diff --git a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp index 7a3f6837f8..d248f022ed 100644 --- a/tests/auto/corelib/io/qprocess/tst_qprocess.cpp +++ b/tests/auto/corelib/io/qprocess/tst_qprocess.cpp @@ -107,8 +107,8 @@ private slots: void softExitInSlots_data(); void softExitInSlots(); void mergedChannels(); + void forwardedChannels_data(); void forwardedChannels(); - void forwardedChannelsOutput(); void atEnd(); void atEnd2(); void waitForFinishedWithTimeout(); @@ -122,6 +122,7 @@ private slots: void setStandardInputFile(); void setStandardOutputFile_data(); void setStandardOutputFile(); + void setStandardOutputFile2(); void setStandardOutputProcess_data(); void setStandardOutputProcess(); void removeFileWhileProcessIsRunning(); @@ -1089,36 +1090,55 @@ void tst_QProcess::mergedChannels() //----------------------------------------------------------------------------- #ifndef Q_OS_WINCE // Reading and writing to a process is not supported on Qt/CE -void tst_QProcess::forwardedChannels() -{ - QProcess process; - process.setReadChannelMode(QProcess::ForwardedChannels); - QCOMPARE(process.readChannelMode(), QProcess::ForwardedChannels); - - process.start("testProcessEcho2/testProcessEcho2"); - QVERIFY(process.waitForStarted(5000)); - QCOMPARE(process.write("forwarded\n"), qlonglong(10)); - QVERIFY(!process.waitForReadyRead(250)); - QCOMPARE(process.bytesAvailable(), qlonglong(0)); +void tst_QProcess::forwardedChannels_data() +{ + QTest::addColumn<int>("mode"); + QTest::addColumn<int>("inmode"); + QTest::addColumn<QByteArray>("outdata"); + QTest::addColumn<QByteArray>("errdata"); - process.closeWriteChannel(); - QVERIFY(process.waitForFinished(5000)); + QTest::newRow("separate") << int(QProcess::SeparateChannels) << int(QProcess::ManagedInputChannel) + << QByteArray() << QByteArray(); + QTest::newRow("forwarded") << int(QProcess::ForwardedChannels) << int(QProcess::ManagedInputChannel) + << QByteArray("forwarded") << QByteArray("forwarded"); + QTest::newRow("stdout") << int(QProcess::ForwardedOutputChannel) << int(QProcess::ManagedInputChannel) + << QByteArray("forwarded") << QByteArray(); + QTest::newRow("stderr") << int(QProcess::ForwardedErrorChannel) << int(QProcess::ManagedInputChannel) + << QByteArray() << QByteArray("forwarded"); + QTest::newRow("fwdinput") << int(QProcess::ForwardedErrorChannel) << int(QProcess::ForwardedInputChannel) + << QByteArray() << QByteArray("input"); } -#endif -#ifndef Q_OS_WINCE -// Reading and writing to a process is not supported on Qt/CE -void tst_QProcess::forwardedChannelsOutput() +void tst_QProcess::forwardedChannels() { + QFETCH(int, mode); + QFETCH(int, inmode); + QFETCH(QByteArray, outdata); + QFETCH(QByteArray, errdata); + QProcess process; - process.start("testForwarding/testForwarding"); + process.start("testForwarding/testForwarding", QStringList() << QString::number(mode) << QString::number(inmode)); QVERIFY(process.waitForStarted(5000)); + QCOMPARE(process.write("input"), 5); + process.closeWriteChannel(); QVERIFY(process.waitForFinished(5000)); - QVERIFY(!process.exitCode()); - QByteArray data = process.readAll(); - QVERIFY(!data.isEmpty()); - QVERIFY(data.contains("forwarded")); + const char *err; + switch (process.exitCode()) { + case 0: err = "ok"; break; + case 1: err = "processChannelMode is wrong"; break; + case 11: err = "inputChannelMode is wrong"; break; + case 2: err = "failed to start"; break; + case 3: err = "failed to write"; break; + case 4: err = "did not finish"; break; + case 5: err = "unexpected stdout"; break; + case 6: err = "unexpected stderr"; break; + case 13: err = "parameter error"; break; + default: err = "unknown exit code"; break; + } + QVERIFY2(!process.exitCode(), err); + QCOMPARE(process.readAllStandardOutput(), outdata); + QCOMPARE(process.readAllStandardError(), errdata); } #endif @@ -1868,6 +1888,13 @@ void tst_QProcess::setStandardInputFile() QByteArray all = process.readAll(); QCOMPARE(all.size(), int(sizeof data) - 1); // testProcessEcho drops the ending \0 QVERIFY(all == data); + + QProcess process2; + process2.setStandardInputFile(QProcess::nullDevice()); + process2.start("testProcessEcho/testProcessEcho"); + QPROCESS_VERIFY(process2, waitForFinished()); + all = process2.readAll(); + QCOMPARE(all.size(), 0); } #endif @@ -1902,6 +1929,23 @@ void tst_QProcess::setStandardOutputFile_data() << true; } +//----------------------------------------------------------------------------- +#ifndef Q_OS_WINCE +void tst_QProcess::setStandardOutputFile2() +{ + static const char testdata[] = "Test data."; + + QProcess process; + process.setStandardOutputFile(QProcess::nullDevice()); + process.start("testProcessEcho2/testProcessEcho2"); + process.write(testdata, sizeof testdata); + QPROCESS_VERIFY(process,waitForFinished()); + QVERIFY(!process.bytesAvailable()); + + QVERIFY(!QFileInfo(QProcess::nullDevice()).isFile()); +} +#endif + void tst_QProcess::setStandardOutputFile() { static const char data[] = "Original data. "; diff --git a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp index 45f143b9fb..9d3519680c 100644 --- a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp +++ b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp @@ -43,10 +43,6 @@ #include <QObject> #include <QProcessEnvironment> -#ifdef QT_NO_PROCESS -QTEST_NOOP_MAIN -#else - class tst_QProcessEnvironment: public QObject { Q_OBJECT @@ -322,4 +318,3 @@ void tst_QProcessEnvironment::putenv() QTEST_MAIN(tst_QProcessEnvironment) #include "tst_qprocessenvironment.moc" -#endif diff --git a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp index f94c8eac4f..501dde1ba5 100644 --- a/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp +++ b/tests/auto/corelib/io/qstandardpaths/tst_qstandardpaths.cpp @@ -166,7 +166,7 @@ void tst_qstandardpaths::testCustomLocations() void tst_qstandardpaths::enableTestMode() { QVERIFY(!QStandardPaths::isTestModeEnabled()); - QStandardPaths::enableTestMode(true); + QStandardPaths::setTestModeEnabled(true); QVERIFY(QStandardPaths::isTestModeEnabled()); #ifdef Q_XDG_PLATFORM @@ -204,7 +204,7 @@ void tst_qstandardpaths::enableTestMode() // On Windows, what should "Program Files" become, in test mode? //testLocations.insert(QStandardPaths::ApplicationsLocation, QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation)); - QStandardPaths::enableTestMode(false); + QStandardPaths::setTestModeEnabled(false); for (LocationHash::const_iterator it = testLocations.constBegin(); it != testLocations.constEnd(); ++it) QVERIFY2(QStandardPaths::writableLocation(it.key()) != it.value(), qPrintable(it.value())); diff --git a/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp index 40621957ce..db2a5b53fd 100644 --- a/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp +++ b/tests/auto/corelib/io/qtextstream/readAllStdinProcess/main.cpp @@ -40,13 +40,11 @@ ****************************************************************************/ -#include <QtCore/QCoreApplication> #include <QtCore/QTextStream> -#include <QtCore/QDebug> +#include <stdio.h> -int main(int argc, char **argv) +int main(int, char**) { - QCoreApplication a(argc, argv); - qDebug() << QTextStream(stdin).readAll(); + fprintf(stderr, "%s\n", QTextStream(stdin).readAll().toLatin1().constData()); return 0; } diff --git a/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp b/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp index e36a2aeda8..cb4e75c6a2 100644 --- a/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp +++ b/tests/auto/corelib/io/qtextstream/stdinProcess/main.cpp @@ -40,17 +40,16 @@ ****************************************************************************/ -#include <QtCore/QCoreApplication> #include <QtCore/QTextStream> +#include <stdio.h> -int main(int argc, char **argv) +int main(int, char**) { - QCoreApplication a(argc, argv); QTextStream qin(stdin); if (!qin.atEnd()) { - int a, b, c; - qin >> a >> b >> c; - qDebug("%d %d %d", a, b, c); + int a, b, c; + qin >> a >> b >> c; + fprintf(stderr, "%d %d %d\n", a, b, c); } return 0; } diff --git a/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp index 56c07f1590..c19e80bff3 100644 --- a/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp +++ b/tests/auto/corelib/io/qtextstream/tst_qtextstream.cpp @@ -1425,8 +1425,7 @@ void tst_QTextStream::readAllFromStdin() stdinProcess.closeWriteChannel(); QVERIFY(stdinProcess.waitForFinished(5000)); - QChar quoteChar('"'); - QCOMPARE(stream.readAll(), QString::fromLatin1("%1hello world%2 \n").arg(quoteChar).arg(quoteChar)); + QCOMPARE(stream.readAll(), QString::fromLatin1("hello world\n")); } // ------------------------------------------------------------------------------ diff --git a/tests/auto/corelib/io/qurl/tst_qurl.cpp b/tests/auto/corelib/io/qurl/tst_qurl.cpp index 2a506ef8e2..e2fa0d3b47 100644 --- a/tests/auto/corelib/io/qurl/tst_qurl.cpp +++ b/tests/auto/corelib/io/qurl/tst_qurl.cpp @@ -111,6 +111,8 @@ private slots: void percentEncoding(); void swap(); void symmetry(); + void ipvfuture_data(); + void ipvfuture(); void ipv6_data(); void ipv6(); void ipv6_2_data(); @@ -146,6 +148,8 @@ private slots: void stripTrailingSlash(); void hosts_data(); void hosts(); + void hostFlags_data(); + void hostFlags(); void setPort(); void toEncoded_data(); void toEncoded(); @@ -160,6 +164,8 @@ private slots: void binaryData(); void fromUserInput_data(); void fromUserInput(); + void fileName_data(); + void fileName(); void isEmptyForEncodedUrl(); void toEncodedNotUsingUninitializedPath(); void emptyAuthorityRemovesExistingAuthority(); @@ -291,6 +297,8 @@ void tst_QUrl::comparison() QVERIFY(url1 == url2); QVERIFY(!(url1 < url2)); QVERIFY(!(url2 < url1)); + QVERIFY(url1.matches(url2, QUrl::None)); + QVERIFY(url1.matches(url2, QUrl::StripTrailingSlash)); // 6.2.2 Syntax-based Normalization QUrl url3 = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D"); @@ -298,6 +306,22 @@ void tst_QUrl::comparison() QEXPECT_FAIL("", "Normalization not implemented, will probably not be implemented like this", Continue); QCOMPARE(url3, url4); + QUrl url3bis = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D/"); + QUrl url3bisNoSlash = QUrl::fromEncoded("example://a/b/c/%7Bfoo%7D"); + QUrl url4bis = QUrl::fromEncoded("example://a/.//b/../b/c//%7Bfoo%7D/"); + QCOMPARE(url4bis.adjusted(QUrl::NormalizePathSegments), url3bis); + QCOMPARE(url4bis.adjusted(QUrl::NormalizePathSegments | QUrl::StripTrailingSlash), url3bisNoSlash); + QVERIFY(url3bis.matches(url4bis, QUrl::NormalizePathSegments)); + QVERIFY(!url3bisNoSlash.matches(url4bis, QUrl::NormalizePathSegments)); + QVERIFY(url3bisNoSlash.matches(url4bis, QUrl::NormalizePathSegments | QUrl::StripTrailingSlash)); + + QUrl url4EncodedDots = QUrl("example://a/.//b/%2E%2E%2F/b/c/"); + QCOMPARE(url4EncodedDots.path(QUrl::PrettyDecoded), QString("/.//b/..%2F/b/c/")); + QCOMPARE(url4EncodedDots.path(QUrl::FullyDecoded), QString("/.//b/..//b/c/")); + QCOMPARE(QString::fromLatin1(url4EncodedDots.toEncoded()), QString::fromLatin1("example://a/.//b/..%2F/b/c/")); + QCOMPARE(url4EncodedDots.toString(), QString("example://a/.//b/..%2F/b/c/")); + QCOMPARE(url4EncodedDots.adjusted(QUrl::NormalizePathSegments).toString(), QString("example://a/b/..%2F/b/c/")); + // 6.2.2.1 Make sure hexdecimal characters in percent encoding are // treated case-insensitively QUrl url5; @@ -312,6 +336,59 @@ void tst_QUrl::comparison() url8.setEncodedQuery("a=c"); QVERIFY(url7 != url8); QVERIFY(url7 < url8); + + // Trailing slash difference + QUrl url9("http://qt-project.org/path/"); + QUrl url9NoSlash("http://qt-project.org/path"); + QVERIFY(!(url9 == url9NoSlash)); + QVERIFY(!url9.matches(url9NoSlash, QUrl::None)); + QVERIFY(url9.matches(url9NoSlash, QUrl::StripTrailingSlash)); + + // RemoveFilename + QUrl url10("http://qt-project.org/file"); + QUrl url10bis("http://qt-project.org/otherfile"); + QVERIFY(!(url10 == url10bis)); + QVERIFY(!url10.matches(url10bis, QUrl::None)); + QVERIFY(!url10.matches(url10bis, QUrl::StripTrailingSlash)); + QVERIFY(url10.matches(url10bis, QUrl::RemoveFilename)); + + // RemoveAuthority + QUrl authUrl1("x://host/a/b"); + QUrl authUrl2("x://host/a/"); + QUrl authUrl3("x:/a/b"); + QVERIFY(authUrl1.matches(authUrl2, QUrl::RemoveFilename)); + QCOMPARE(authUrl1.adjusted(QUrl::RemoveAuthority), authUrl3.adjusted(QUrl::RemoveAuthority)); + QVERIFY(authUrl1.matches(authUrl3, QUrl::RemoveAuthority)); + QCOMPARE(authUrl2.adjusted(QUrl::RemoveAuthority | QUrl::RemoveFilename), authUrl3.adjusted(QUrl::RemoveAuthority | QUrl::RemoveFilename)); + QVERIFY(authUrl2.matches(authUrl3, QUrl::RemoveAuthority | QUrl::RemoveFilename)); + QVERIFY(authUrl3.matches(authUrl2, QUrl::RemoveAuthority | QUrl::RemoveFilename)); + + QUrl hostUrl1("file:/foo"); + QUrl hostUrl2("file:///foo"); + QVERIFY(hostUrl1 == hostUrl2); + QVERIFY(hostUrl1.matches(hostUrl2, QUrl::None)); + QVERIFY(hostUrl1.matches(hostUrl2, QUrl::RemoveAuthority)); + + // RemovePassword + QUrl passUrl1("http://user:pass@host/"); + QUrl passUrl2("http://user:PASS@host/"); + QVERIFY(!(passUrl1 == passUrl2)); + QVERIFY(passUrl1 != passUrl2); + QVERIFY(!passUrl1.matches(passUrl2, QUrl::None)); + QVERIFY(passUrl1.matches(passUrl2, QUrl::RemovePassword)); + + // RemoveQuery, RemoveFragment + QUrl queryFragUrl1("http://host/file?query#fragment"); + QUrl queryFragUrl2("http://host/file?q2#f2"); + QUrl queryFragUrl3("http://host/file"); + QVERIFY(!(queryFragUrl1 == queryFragUrl2)); + QVERIFY(queryFragUrl1 != queryFragUrl2); + QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::None)); + QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveQuery)); + QVERIFY(!queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveFragment)); + QVERIFY(queryFragUrl1.matches(queryFragUrl2, QUrl::RemoveQuery | QUrl::RemoveFragment)); + QVERIFY(queryFragUrl1.matches(queryFragUrl3, QUrl::RemoveQuery | QUrl::RemoveFragment)); + QVERIFY(queryFragUrl3.matches(queryFragUrl1, QUrl::RemoveQuery | QUrl::RemoveFragment)); } void tst_QUrl::comparison2_data() @@ -422,18 +499,20 @@ void tst_QUrl::setUrl() } { - QUrl url("http://user:pass@[56::56:56:56:127.0.0.1]:99"); + QUrl url("http://user%3A:pass%40@[56::56:56:56:127.0.0.1]:99"); QVERIFY(url.isValid()); QCOMPARE(url.scheme(), QString::fromLatin1("http")); QCOMPARE(url.path(), QString()); QVERIFY(url.encodedQuery().isEmpty()); - QCOMPARE(url.userInfo(), QString::fromLatin1("user:pass")); + QCOMPARE(url.userName(), QString::fromLatin1("user:")); + QCOMPARE(url.password(), QString::fromLatin1("pass@")); + QCOMPARE(url.userInfo(), QString::fromLatin1("user%3A:pass@")); QVERIFY(url.fragment().isEmpty()); QCOMPARE(url.host(), QString::fromLatin1("56::56:56:56:7f00:1")); - QCOMPARE(url.authority(), QString::fromLatin1("user:pass@[56::56:56:56:7f00:1]:99")); + QCOMPARE(url.authority(), QString::fromLatin1("user%3A:pass%40@[56::56:56:56:7f00:1]:99")); QCOMPARE(url.port(), 99); - QCOMPARE(url.url(), QString::fromLatin1("http://user:pass@[56::56:56:56:7f00:1]:99")); - QCOMPARE(url.toDisplayString(), QString::fromLatin1("http://user@[56::56:56:56:7f00:1]:99")); + QCOMPARE(url.url(), QString::fromLatin1("http://user%3A:pass%40@[56::56:56:56:7f00:1]:99")); + QCOMPARE(url.toDisplayString(), QString::fromLatin1("http://user%3A@[56::56:56:56:7f00:1]:99")); } { @@ -611,8 +690,8 @@ void tst_QUrl::setUrl() QUrl charles; charles.setPath("/home/charles/foo%20moo"); - QCOMPARE(charles.path(), QString::fromLatin1("/home/charles/foo moo")); - QCOMPARE(charles.path(QUrl::FullyEncoded), QString::fromLatin1("/home/charles/foo%20moo")); + QCOMPARE(charles.path(), QString::fromLatin1("/home/charles/foo%20moo")); + QCOMPARE(charles.path(QUrl::FullyEncoded), QString::fromLatin1("/home/charles/foo%2520moo")); QUrl charles2("file:/home/charles/foo%20moo"); QCOMPARE(charles2.path(), QString::fromLatin1("/home/charles/foo moo")); @@ -686,7 +765,7 @@ void tst_QUrl::setUrl() QCOMPARE(url.scheme(), QString("data")); QCOMPARE(url.host(), QString()); QCOMPARE(url.path(), QString("text/javascript,d5 = 'five\\u0027s';")); - QCOMPARE(url.encodedPath().constData(), "text/javascript,d5%20=%20'five%5Cu0027s';"); + QCOMPARE(url.encodedPath().constData(), "text/javascript,d5%20%3D%20'five%5Cu0027s'%3B"); } { @@ -946,8 +1025,12 @@ void tst_QUrl::toString() QFETCH(uint, options); QFETCH(QString, string); + QUrl::FormattingOptions opt(options); + QUrl url(urlString); - QCOMPARE(url.toString(QUrl::FormattingOptions(options)), string); + QCOMPARE(url.toString(opt), string); + + QCOMPARE(url.adjusted(opt).toString(), string); } void tst_QUrl::toAndFromStringList_data() @@ -1135,11 +1218,11 @@ void tst_QUrl::fromLocalFile_data() QTest::newRow("data7") << QString::fromLatin1("/Mambo <#5>.mp3") << QString::fromLatin1("file:///Mambo <%235>.mp3") << QString::fromLatin1("/Mambo <#5>.mp3"); QTest::newRow("data8") << QString::fromLatin1("/a%.txt") << QString::fromLatin1("file:///a%25.txt") - << QString::fromLatin1("/a%25.txt"); + << QString::fromLatin1("/a%.txt"); QTest::newRow("data9") << QString::fromLatin1("/a%25.txt") << QString::fromLatin1("file:///a%2525.txt") - << QString::fromLatin1("/a%2525.txt"); + << QString::fromLatin1("/a%25.txt"); QTest::newRow("data10") << QString::fromLatin1("/%80.txt") << QString::fromLatin1("file:///%2580.txt") - << QString::fromLatin1("/%2580.txt"); + << QString::fromLatin1("/%80.txt"); } void tst_QUrl::fromLocalFile() @@ -1498,17 +1581,17 @@ void tst_QUrl::relative() void tst_QUrl::percentEncoding_data() { + // This test is limited. It's superseded by componentEncodings below QTest::addColumn<QString>("original"); QTest::addColumn<QByteArray>("encoded"); QTest::newRow("test_01") << QString::fromLatin1("sdfsdf") << QByteArray("sdfsdf"); QTest::newRow("test_02") << QString::fromUtf8("æss") << QByteArray("%C3%A6ss"); - // not unreserved or reserved - QTest::newRow("test_03") << QString::fromLatin1("{}") << QByteArray("%7B%7D"); } void tst_QUrl::percentEncoding() { + // This test is limited. It's superseded by componentEncodings below QFETCH(QString, original); QFETCH(QByteArray, encoded); @@ -1583,21 +1666,83 @@ void tst_QUrl::symmetry() { QString urlString = QString::fromLatin1("http://desktop:33326/upnp/{32f525a6-6f31-426e-91ca-01c2e6c2c57e}"); + QString encodedUrlString = QString("http://desktop:33326/upnp/%7B32f525a6-6f31-426e-91ca-01c2e6c2c57e%7D"); QUrl urlPreviewList(urlString); - QCOMPARE(urlPreviewList.toString(), urlString); + QCOMPARE(urlPreviewList.toString(), encodedUrlString); QByteArray b = urlPreviewList.toEncoded(); - QCOMPARE(b.constData(), "http://desktop:33326/upnp/%7B32f525a6-6f31-426e-91ca-01c2e6c2c57e%7D"); - QCOMPARE(QUrl::fromEncoded(b).toString(), urlString); - QCOMPARE(QUrl(b).toString(), urlString); + QCOMPARE(b.constData(), encodedUrlString.toLatin1().constData()); + QCOMPARE(QUrl::fromEncoded(b).toString(), encodedUrlString); + QCOMPARE(QUrl(b).toString(), encodedUrlString); } { QString urlString = QString::fromLatin1("http://desktop:53423/deviceDescription?uuid={7977c17b-00bf-4af9-894e-fed28573c3a9}"); + QString encodedUrlString = QString("http://desktop:53423/deviceDescription?uuid=%7B7977c17b-00bf-4af9-894e-fed28573c3a9%7D"); QUrl urlPreviewList(urlString); - QCOMPARE(urlPreviewList.toString(), urlString); + QCOMPARE(urlPreviewList.toString(), encodedUrlString); QByteArray b = urlPreviewList.toEncoded(); - QCOMPARE(b.constData(), "http://desktop:53423/deviceDescription?uuid=%7B7977c17b-00bf-4af9-894e-fed28573c3a9%7D"); - QCOMPARE(QUrl::fromEncoded(b).toString(), urlString); - QCOMPARE(QUrl(b).toString(), urlString); + QCOMPARE(b.constData(), encodedUrlString.toLatin1().constData()); + QCOMPARE(QUrl::fromEncoded(b).toString(), encodedUrlString); + QCOMPARE(QUrl(b).toString(), encodedUrlString); + } +} + +void tst_QUrl::ipvfuture_data() +{ + QTest::addColumn<QString>("input"); + QTest::addColumn<bool>("isValid"); + QTest::addColumn<QString>("output"); + + // No one uses IPvFuture yet, so we have no clue what it might contain + // We're just testing that it can hold what the RFC says it should hold: + // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + QTest::newRow("missing-version-dot") << "x://[v]" << false; + QTest::newRow("missing-version") << "x://[v.]" << false; + QTest::newRow("missing-version-2") << "x://[v.1234]" << false; + QTest::newRow("missing-dot") << "x://[v7]" << false; + QTest::newRow("missing-dot-2") << "x://[v71234]" << false; + QTest::newRow("missing-data") << "x://[v7.]" << false; + QTest::newRow("non-hex-version") << "x://[vz.1234]" << false; + + QTest::newRow("digit-ver") << "x://[v7.1]" << true << "x://[v7.1]"; + QTest::newRow("lowercase-hex-ver") << "x://[va.1]" << true << "x://[vA.1]"; + QTest::newRow("lowercase-hex-ver") << "x://[vA.1]" << true << "x://[vA.1]"; + + QTest::newRow("data-digits") << "x://[v7.1234]" << true << "x://[v7.1234]"; + QTest::newRow("data-unreserved") << "x://[v7.hello~-WORLD_.com]" << true << "x://[v7.hello~-WORLD_.com]"; + QTest::newRow("data-sub-delims-colon") << "x://[v7.!$&'()*+,;=:]" << true << "x://[v7.!$&'()*+,;=:]"; + + // we're using the tolerant parser + QTest::newRow("data-encoded-digits") << "x://[v7.%31%32%33%34]" << true << "x://[v7.1234]"; + QTest::newRow("data-encoded-unreserved") << "x://[v7.%7E%2D%54%5f%2E]" << true << "x://[v7.~-T_.]"; + QTest::newRow("data-encoded-sub-delims-colon") << "x://[v7.%21%24%26%27%28%29%2A%2B%2C%3B%3D%3A]" << true << "x://[v7.!$&'()*+,;=:]"; + + // should we test "[%76%37%2ex]" -> "[v7.x]" ? + + QTest::newRow("data-invalid-space") << "x://[v7.%20]" << false; + QTest::newRow("data-invalid-control") << "x://[v7.\x7f]" << false; + QTest::newRow("data-invalid-other-1") << "x://[v7.{1234}]" << false; + QTest::newRow("data-invalid-other-2") << "x://[v7.<hello>]" << false; + QTest::newRow("data-invalid-unicode") << "x://[v7.æøå]" << false; + QTest::newRow("data-invalid-percent") << "x://[v7.%]" << false; + QTest::newRow("data-invalid-percent-percent") << "x://[v7.%25]" << false; +} + +void tst_QUrl::ipvfuture() +{ + QFETCH(QString, input); + QFETCH(bool, isValid); + + QUrl url(input); + if (isValid) { + QVERIFY2(url.isValid(), qPrintable(url.errorString())); + + QFETCH(QString, output); + QCOMPARE(url.toString(), output); + + QUrl url2(output); + QCOMPARE(url2, url); + } else { + QVERIFY(!url.isValid()); } } @@ -1641,6 +1786,9 @@ void tst_QUrl::ipv6_data() QTest::newRow("case :,") << QString::fromLatin1("//[:,]") << false << ""; QTest::newRow("case ::bla") << QString::fromLatin1("//[::bla]") << false << ""; QTest::newRow("case v4-mapped") << "//[0:0:0:0:0:ffff:7f00:1]" << true << "//[::ffff:127.0.0.1]"; + + QTest::newRow("encoded-digit") << "//[::%31]" << true << "//[::1]"; + QTest::newRow("encoded-colon") << "//[%3A%3A]" << true << "//[::]"; } void tst_QUrl::ipv6() @@ -1932,9 +2080,14 @@ void tst_QUrl::strictParser_data() QTest::newRow("invalid-regname") << "http://bad<hostname>" << "Invalid hostname (contains invalid characters)"; QTest::newRow("invalid-regname-2") << "http://b%61d" << "Invalid hostname (contains invalid characters)"; QTest::newRow("invalid-ipv6") << "http://[:::]" << "Invalid IPv6 address"; + QTest::newRow("invalid-ipv6-char1") << "http://[::g]" << "Invalid IPv6 address (character 'g' not permitted)"; + QTest::newRow("invalid-ipv6-char2") << "http://[z::]" << "Invalid IPv6 address (character 'z' not permitted)"; QTest::newRow("invalid-ipvfuture-1") << "http://[v7]" << "Invalid IPvFuture address"; QTest::newRow("invalid-ipvfuture-2") << "http://[v7.]" << "Invalid IPvFuture address"; QTest::newRow("invalid-ipvfuture-3") << "http://[v789]" << "Invalid IPvFuture address"; + QTest::newRow("invalid-ipvfuture-char1") << "http://[v7.^]" << "Invalid IPvFuture address"; + QTest::newRow("invalid-encoded-ipv6") << "x://[%3a%3a%31]" << "Invalid IPv6 address"; + QTest::newRow("invalid-encoded-ipvfuture") << "x://[v7.%7E%2D%54%5f%2E]" << "Invalid IPvFuture address"; QTest::newRow("unbalanced-brackets") << "http://[ff02::1" << "Expected ']' to match '[' in hostname"; // invalid hostnames happen in TolerantMode too @@ -2035,35 +2188,22 @@ void tst_QUrl::tolerantParser() url.setUrl("http://foo.bar/[image][1].jpg"); QVERIFY(url.isValid()); QVERIFY(!url.toString().isEmpty()); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); - QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/[image][1].jpg")); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/[image][1].jpg")); QCOMPARE(url.toString(), QString("http://foo.bar/[image][1].jpg")); - url.setUrl("[].jpg"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%5B%5D.jpg")); - QCOMPARE(url.toEncoded(), QByteArray("%5B%5D.jpg")); - QCOMPARE(url.toString(), QString("[].jpg")); - - url.setUrl("/some/[path]/[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("/some/%5Bpath%5D/%5B%5D")); - QCOMPARE(url.toEncoded(), QByteArray("/some/%5Bpath%5D/%5B%5D")); - QCOMPARE(url.toString(), QString("/some/[path]/[]")); + url.setUrl("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"); + QVERIFY(url.isValid()); + QVERIFY(!url.toString().isEmpty()); + QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toString(), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); url.setUrl("//[::56:56:56:56:56:56:56]"); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]")); QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]")); QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]")); - url.setUrl("//[::56:56:56:56:56:56:56]#[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]#%5B%5D")); - QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]#%5B%5D")); - QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]#[]")); - - url.setUrl("//[::56:56:56:56:56:56:56]?[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]?[]")); - QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]?[]")); - QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]?[]")); - // invoke the tolerant parser's error correction url.setUrl("%hello.com/f%"); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%25hello.com/f%25")); @@ -2076,38 +2216,24 @@ void tst_QUrl::tolerantParser() url.setEncodedUrl("http://foo.bar/[image][1].jpg"); QVERIFY(url.isValid()); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); - QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/[image][1].jpg")); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/[image][1].jpg")); QCOMPARE(url.toString(), QString("http://foo.bar/[image][1].jpg")); - url.setEncodedUrl("[].jpg"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("%5B%5D.jpg")); - QCOMPARE(url.toEncoded(), QByteArray("%5B%5D.jpg")); - QCOMPARE(url.toString(), QString("[].jpg")); - - url.setEncodedUrl("/some/[path]/[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("/some/%5Bpath%5D/%5B%5D")); - QCOMPARE(url.toEncoded(), QByteArray("/some/%5Bpath%5D/%5B%5D")); - QCOMPARE(url.toString(), QString("/some/[path]/[]")); + url.setEncodedUrl("http://foo.bar/%5Bimage%5D%5B1%5D.jpg"); + QVERIFY(url.isValid()); + QCOMPARE(url.toString(QUrl::FullyEncoded), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toEncoded(), QByteArray("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); + QCOMPARE(url.toString(), QString("http://foo.bar/%5Bimage%5D%5B1%5D.jpg")); url.setEncodedUrl("//[::56:56:56:56:56:56:56]"); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]")); QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]")); - url.setEncodedUrl("//[::56:56:56:56:56:56:56]#[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]#%5B%5D")); - QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]#%5B%5D")); - QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]#[]")); - - url.setEncodedUrl("//[::56:56:56:56:56:56:56]?[]"); - QCOMPARE(url.toString(QUrl::FullyEncoded), QString("//[0:56:56:56:56:56:56:56]?[]")); - QCOMPARE(url.toEncoded(), QByteArray("//[0:56:56:56:56:56:56:56]?[]")); - QCOMPARE(url.toString(), QString("//[0:56:56:56:56:56:56:56]?[]")); - url.setEncodedUrl("data:text/css,div%20{%20border-right:%20solid;%20}"); QCOMPARE(url.toString(QUrl::FullyEncoded), QString("data:text/css,div%20%7B%20border-right:%20solid;%20%7D")); QCOMPARE(url.toEncoded(), QByteArray("data:text/css,div%20%7B%20border-right:%20solid;%20%7D")); - QCOMPARE(url.toString(), QString("data:text/css,div { border-right: solid; }")); + QCOMPARE(url.toString(), QString("data:text/css,div %7B border-right: solid; %7D")); } { @@ -2386,7 +2512,7 @@ void tst_QUrl::setEncodedFragment_data() QTest::newRow("basic test") << BA("http://www.kde.org") << BA("abc") << BA("http://www.kde.org#abc"); QTest::newRow("initial url has fragment") << BA("http://www.kde.org#old") << BA("new") << BA("http://www.kde.org#new"); QTest::newRow("encoded fragment") << BA("http://www.kde.org") << BA("a%20c") << BA("http://www.kde.org#a%20c"); - QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a#b"); + QTest::newRow("with #") << BA("http://www.kde.org") << BA("a#b") << BA("http://www.kde.org#a%23b"); // toString uses "a#b" QTest::newRow("unicode") << BA("http://www.kde.org") << BA("\xc3\xa9") << BA("http://www.kde.org#%C3%A9"); QTest::newRow("binary") << BA("http://www.kde.org") << BA("\x00\xc0\x80", 3) << BA("http://www.kde.org#%00%C0%80"); } @@ -2408,8 +2534,9 @@ void tst_QUrl::setEncodedFragment() void tst_QUrl::fromEncoded() { QUrl qurl2 = QUrl::fromEncoded("print:/specials/Print%20To%20File%20(PDF%252FAcrobat)", QUrl::TolerantMode); - QCOMPARE(qurl2.path(), QString::fromLatin1("/specials/Print To File (PDF%252FAcrobat)")); - QCOMPARE(QFileInfo(qurl2.path()).fileName(), QString::fromLatin1("Print To File (PDF%252FAcrobat)")); + QCOMPARE(qurl2.path(), QString::fromLatin1("/specials/Print To File (PDF%2FAcrobat)")); + QCOMPARE(QFileInfo(qurl2.path()).fileName(), QString::fromLatin1("Print To File (PDF%2FAcrobat)")); + QCOMPARE(qurl2.fileName(), QString::fromLatin1("Print To File (PDF%2FAcrobat)")); QCOMPARE(qurl2.toEncoded().constData(), "print:/specials/Print%20To%20File%20(PDF%252FAcrobat)"); QUrl qurl = QUrl::fromEncoded("http://\303\244.de"); @@ -2427,23 +2554,37 @@ void tst_QUrl::fromEncoded() void tst_QUrl::stripTrailingSlash_data() { QTest::addColumn<QString>("url"); - QTest::addColumn<QString>("expected"); + QTest::addColumn<QString>("expectedStrip"); // toString(Strip) + QTest::addColumn<QString>("expectedDir"); // toString(RemoveFilename) + QTest::addColumn<QString>("expectedDirStrip"); // toString(RemoveFilename|Strip) - QTest::newRow("ftp no slash") << "ftp://ftp.de.kde.org/dir" << "ftp://ftp.de.kde.org/dir"; - QTest::newRow("ftp slash") << "ftp://ftp.de.kde.org/dir/" << "ftp://ftp.de.kde.org/dir"; - QTest::newRow("file slash") << "file:///dir/" << "file:///dir"; - QTest::newRow("file no slash") << "file:///dir/" << "file:///dir"; - QTest::newRow("file root") << "file:///" << "file:///"; - QTest::newRow("no path") << "remote://" << "remote://"; + QTest::newRow("subdir no slash") << "ftp://kde.org/dir/subdir" << "ftp://kde.org/dir/subdir" << "ftp://kde.org/dir/" << "ftp://kde.org/dir"; + QTest::newRow("ftp no slash") << "ftp://kde.org/dir" << "ftp://kde.org/dir" << "ftp://kde.org/" << "ftp://kde.org/"; + QTest::newRow("ftp slash") << "ftp://kde.org/dir/" << "ftp://kde.org/dir" << "ftp://kde.org/dir/" << "ftp://kde.org/dir"; + QTest::newRow("ftp_two_slashes") << "ftp://kde.org/dir//" << "ftp://kde.org/dir" << "ftp://kde.org/dir//" << "ftp://kde.org/dir"; + QTest::newRow("file slash") << "file:///dir/" << "file:///dir" << "file:///dir/" << "file:///dir"; + QTest::newRow("file no slash") << "file:///dir" << "file:///dir" << "file:///" << "file:///"; + QTest::newRow("file root") << "file:///" << "file:///" << "file:///" << "file:///"; + QTest::newRow("file_root_manyslashes") << "file://///" << "file:///" << "file://///" << "file:///"; + QTest::newRow("no path") << "remote://" << "remote://" << "remote://" << "remote://"; } void tst_QUrl::stripTrailingSlash() { QFETCH(QString, url); - QFETCH(QString, expected); + QFETCH(QString, expectedStrip); + QFETCH(QString, expectedDir); + QFETCH(QString, expectedDirStrip); QUrl u(url); - QCOMPARE(u.toString(QUrl::StripTrailingSlash), expected); + QCOMPARE(u.toString(QUrl::StripTrailingSlash), expectedStrip); + QCOMPARE(u.toString(QUrl::RemoveFilename), expectedDir); + QCOMPARE(u.toString(QUrl::RemoveFilename | QUrl::StripTrailingSlash), expectedDirStrip); + + // Same thing, using QUrl::adjusted() + QCOMPARE(u.adjusted(QUrl::StripTrailingSlash).toString(), expectedStrip); + QCOMPARE(u.adjusted(QUrl::RemoveFilename).toString(), expectedDir); + QCOMPARE(u.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toString(), expectedDirStrip); } void tst_QUrl::hosts_data() @@ -2503,6 +2644,29 @@ void tst_QUrl::hosts() QTEST(QUrl(url).host(), "host"); } +void tst_QUrl::hostFlags_data() +{ + QTest::addColumn<QString>("urlStr"); + QTest::addColumn<QUrl::FormattingOptions>("options"); + QTest::addColumn<QString>("expectedHost"); + + QString swedish = QString::fromUtf8("http://www.räksmörgås.se/pub?a=b&a=dø&a=f#vræl"); + QTest::newRow("se_fullydecoded") << swedish << QUrl::FormattingOptions(QUrl::FullyDecoded) << QString::fromUtf8("www.räksmörgås.se"); + QTest::newRow("se_fullyencoded") << swedish << QUrl::FormattingOptions(QUrl::FullyEncoded) << QString::fromUtf8("www.xn--rksmrgs-5wao1o.se"); + QTest::newRow("se_prettydecoded") << swedish << QUrl::FormattingOptions(QUrl::PrettyDecoded) << QString::fromUtf8("www.räksmörgås.se"); + QTest::newRow("se_encodespaces") << swedish << QUrl::FormattingOptions(QUrl::EncodeSpaces) << QString::fromUtf8("www.räksmörgås.se"); +} + +void tst_QUrl::hostFlags() +{ + QFETCH(QString, urlStr); + QFETCH(QUrl::FormattingOptions, options); + QFETCH(QString, expectedHost); + + QUrl url(urlStr); + QCOMPARE(url.host(options), expectedHost); +} + void tst_QUrl::setPort() { { @@ -2729,6 +2893,43 @@ void tst_QUrl::fromUserInput() QCOMPARE(url, guessUrlFromString); } +void tst_QUrl::fileName_data() +{ + QTest::addColumn<QString>("urlStr"); + QTest::addColumn<QString>("expectedDirPath"); + QTest::addColumn<QString>("expectedPrettyDecodedFileName"); + QTest::addColumn<QString>("expectedFullyDecodedFileName"); + + QTest::newRow("fromDocu") << "http://qt-project.org/support/file.html" + << "/support/" << "file.html" << "file.html"; + QTest::newRow("absoluteFile") << "file:///temp/tmp.txt" + << "/temp/" << "tmp.txt" << "tmp.txt"; + QTest::newRow("absoluteDir") << "file:///temp/" + << "/temp/" << QString() << QString(); + QTest::newRow("absoluteInRoot") << "file:///temp" + << "/" << "temp" << "temp"; + QTest::newRow("relative") << "temp/tmp.txt" + << "temp/" << "tmp.txt" << "tmp.txt"; + QTest::newRow("relativeNoSlash") << "tmp.txt" + << QString() << "tmp.txt" << "tmp.txt"; + QTest::newRow("encoded") << "print:/specials/Print%20To%20File%20(PDF%252FAcrobat)" + << "/specials/" << "Print To File (PDF%252FAcrobat)" << "Print To File (PDF%2FAcrobat)"; +} + +void tst_QUrl::fileName() +{ + QFETCH(QString, urlStr); + QFETCH(QString, expectedDirPath); + QFETCH(QString, expectedPrettyDecodedFileName); + QFETCH(QString, expectedFullyDecodedFileName); + + QUrl url(urlStr); + QVERIFY(url.isValid()); + QCOMPARE(url.adjusted(QUrl::RemoveFilename).path(), expectedDirPath); + QCOMPARE(url.fileName(QUrl::PrettyDecoded), expectedPrettyDecodedFileName); + QCOMPARE(url.fileName(QUrl::FullyDecoded), expectedFullyDecodedFileName); +} + // This is a regression test for a previously fixed bug where isEmpty didn't // work for an encoded URL that was yet to be decoded. The test checks that // isEmpty works for an encoded URL both after and before decoding. @@ -2866,7 +3067,8 @@ void tst_QUrl::effectiveTLDs() { QFETCH(QUrl, domain); QFETCH(QString, TLD); - QCOMPARE(domain.topLevelDomain(), TLD); + QCOMPARE(domain.topLevelDomain(QUrl::PrettyDecoded), TLD); + QCOMPARE(domain.topLevelDomain(QUrl::FullyDecoded), TLD); } void tst_QUrl::lowercasesScheme() @@ -2950,19 +3152,25 @@ void tst_QUrl::componentEncodings_data() // sub-delims = "!" / "$" / "&" / "'" / "(" / ")" // / "*" / "+" / "," / ";" / "=" - // like the unreserved, these are decoded everywhere - // don't test in query because they might remain encoded - QTest::newRow("decoded-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c#%3b%3d") + // these are always left alone + QTest::newRow("decoded-subdelims") << QUrl("x://!$&:'()@host/*+,?$=(+)#;=") << int(QUrl::FullyEncoded) << "!$&" << "'()" << "!$&:'()" << "host" << "!$&:'()@host" - << "/*+," << "" << ";=" - << "x://!$&:'()@host/*+,#;="; + << "/*+," << "$=(+)" << ";=" + << "x://!$&:'()@host/*+,?$=(+)#;="; + QTest::newRow("encoded-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c?%26=%26&%3d=%3d#%3b%3d") + << MostDecoded + << "%21%24%26" << "%27%28%29" << "%21%24%26:%27%28%29" + << "host" << "%21%24%26:%27%28%29@host" + << "/%2A%2B%2C" << "%26=%26&%3D=%3D" << "%3B%3D" + << "x://%21%24%26:%27%28%29@host/%2A%2B%2C?%26=%26&%3D=%3D#%3B%3D"; // gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" // these are the separators between fields - // they must appear encoded in certain positions, no exceptions - // in other positions, they can appear decoded, so they always do + // they must appear encoded in certain positions in the full URL, no exceptions + // when in those positions, they appear decoded in the isolated parts + // in other positions and the other delimiters are always left untransformed // 1) test the delimiters that must appear encoded // (if they were decoded, they'd would change the URL parsing) QTest::newRow("encoded-gendelims-changing") << QUrl("x://%5b%3a%2f%3f%23%40%5d:%5b%2f%3f%23%40%5d@host/%2f%3f%23?%23") @@ -2972,32 +3180,21 @@ void tst_QUrl::componentEncodings_data() << "/%2F?#" << "#" << "" << "x://%5B%3A%2F%3F%23%40%5D:%5B%2F%3F%23%40%5D@host/%2F%3F%23?%23"; - // 2) test the delimiters that may appear decoded and would not change the meaning - // and test that %2f is *not* decoded to a slash in the path - // don't test the query because in this mode it doesn't transform anything - QTest::newRow("decoded-gendelims-unchanging") << QUrl("x://:%3a@host/%2f%3a%40#%23%3a%2f%3f%40") + // 2) test that the other delimiters remain decoded + QTest::newRow("decoded-gendelims-unchanging") << QUrl("x://::@host/:@/[]?:/?@[]?#:/?@[]") << int(QUrl::FullyEncoded) << "" << ":" << "::" << "host" << "::@host" - << "/%2F:@" << "" << "#:/?@" - << "x://::@host/%2F:@##:/?@"; - - // 3) test "[" and "]". Even though they are not ambiguous in the path, query or fragment - // the RFC does not allow them to appear there decoded. QUrl adheres strictly in FullyEncoded mode - QTest::newRow("encoded-square-brackets") << QUrl("x:/[]#[]") - << int(QUrl::FullyEncoded) - << "" << "" << "" - << "" << "" - << "/%5B%5D" << "" << "%5B%5D" - << "x:/%5B%5D#%5B%5D"; - - // 4) like above, but now decode them, which is allowed - QTest::newRow("decoded-square-brackets") << QUrl("x:/%5B%5D#%5B%5D") - << MostDecoded - << "" << "" << "" - << "" << "" - << "/[]" << "" << "[]" - << "x:/[]#[]"; + << "/:@/[]" << ":/?@[]?" << ":/?@[]" + << "x://::@host/:@/[]?:/?@[]?#:/?@[]"; + + // 3) and test that the same encoded sequences remain encoded + QTest::newRow("encoded-gendelims-unchanging") << QUrl("x://:%3A@host/%3A%40%5B%5D?%3A%2F%3F%40%5B%5D#%23%3A%2F%3F%40%5B%5D") + << MostDecoded + << "" << "%3A" << ":%3A" + << "host" << ":%3A@host" + << "/%3A%40%5B%5D" << "%3A%2F%3F%40%5B%5D" << "%23%3A%2F%3F%40%5B%5D" + << "x://:%3A@host/%3A%40%5B%5D?%3A%2F%3F%40%5B%5D#%23%3A%2F%3F%40%5B%5D"; // test the query // since QUrl doesn't know what chars the user wants to use for the pair and value delimiters, @@ -3051,23 +3248,13 @@ void tst_QUrl::componentEncodings_data() << QString::fromUtf8("é ") << QString::fromUtf8("x:// é:é @smørbrød.example.no/é ? é#é "); - // the pretty form re-encodes the subdelims (except in the query, where they are left alone) - QTest::newRow("pretty-subdelims") << QUrl("x://%21%24%26:%27%28%29@host/%2a%2b%2c?%26=%26&%3d=%3d#%3b%3d") - << int(QUrl::PrettyDecoded) - << "!$&" << "'()" << "!$&:'()" - << "host" << "!$&:'()@host" - << "/*+," << "%26=%26&%3D=%3D" << ";=" - << "x://!$&:'()@host/*+,?%26=%26&%3D=%3D#;="; - - // the pretty form decodes all unambiguous gen-delims - // (except in query, where they are left alone) - QTest::newRow("pretty-gendelims") << QUrl("x://%5b%3a%40%2f%5d:%5b%3a%40%2f%5d@host" - "/%3a%40%5b%3f%23%5d?[?%3f%23]%5b:%3a@%40%5d#%23") + // the pretty form decodes all unambiguous gen-delims in the individual parts + QTest::newRow("pretty-gendelims") << QUrl("x://%5b%3a%40%2f%3f%23%5d:%5b%40%2f%3f%23%5d@host/%3f%23?%23") << int(QUrl::PrettyDecoded) - << "[:@/]" << "[:@/]" << "[%3A@/]:[:@/]" - << "host" << "%5B%3A%40/%5D:%5B:%40/%5D@host" - << "/:@[?#]" << "[?%3F#]%5B:%3A@%40%5D" << "#" - << "x://%5B%3A%40%2F%5D:%5B:%40%2F%5D@host/:@[%3F%23]?[?%3F%23]%5B:%3A@%40%5D##"; + << "[:@/?#]" << "[@/?#]" << "[%3A@/?#]:[@/?#]" + << "host" << "%5B%3A%40/?#%5D:%5B%40/?#%5D@host" + << "/?#" << "#" << "" + << "x://%5B%3A%40%2F%3F%23%5D:%5B%40%2F%3F%23%5D@host/%3F%23?%23"; // the pretty form keeps the other characters decoded everywhere // except when rebuilding the full URL, when we only allow "{}" to remain decoded @@ -3076,8 +3263,8 @@ void tst_QUrl::componentEncodings_data() << "\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}:\"<>^\\{|}" << "host" << "\"<>^\\{|}:\"<>^\\{|}@host" << "/\"<>^\\{|}" << "\"<>^\\{|}" << "\"<>^\\{|}" - << "x://%22%3C%3E%5E%5C%7B%7C%7D:%22%3C%3E%5E%5C%7B%7C%7D@host/%22%3C%3E%5E%5C{%7C}" - "?%22%3C%3E%5E%5C{%7C}#%22%3C%3E%5E%5C%7B%7C%7D"; + << "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" + "?%22%3C%3E%5E%5C%7B%7C%7D#%22%3C%3E%5E%5C%7B%7C%7D"; } void tst_QUrl::componentEncodings() @@ -3181,6 +3368,17 @@ void tst_QUrl::setComponents_data() QTest::newRow("path-empty") << QUrl("http://example.com/path") << int(Path) << "" << Tolerant << true << PrettyDecoded << "" << "http://example.com"; + // If the %3A gets decoded to ":", the URL becomes invalid; + // see test path-invalid-1 below + QTest::newRow("path-%3A-before-slash") << QUrl() + << int(Path) << "c%3A/" << Tolerant << true + << PrettyDecoded << "c%3A/" << "c%3A/"; + QTest::newRow("path-doubleslash") << QUrl("trash:/") + << int(Path) << "//path" << Tolerant << true + << PrettyDecoded << "/path" << "trash:/path"; + QTest::newRow("path-withdotdot") << QUrl("file:///tmp") + << int(Path) << "//tmp/..///root/." << Tolerant << true + << PrettyDecoded << "/root" << "file:///root"; // the other fields can be present and be empty // that is, their delimiters would be present, but there would be nothing to one side @@ -3346,9 +3544,6 @@ void tst_QUrl::setComponents_data() QTest::newRow("invalid-scheme-encode") << QUrl("http://example.com") << int(Scheme) << "http%61" << Decoded << false << PrettyDecoded << "" << ""; - QTest::newRow("userinfo-encode") << QUrl("http://example.com") - << int(UserInfo) << "h%61llo:world@" << Decoded << true - << PrettyDecoded << "h%2561llo:world@" << "http://h%2561llo:world%40@example.com"; QTest::newRow("username-encode") << QUrl("http://example.com") << int(UserName) << "h%61llo:world" << Decoded << true << PrettyDecoded << "h%2561llo:world" << "http://h%2561llo%3Aworld@example.com"; @@ -3359,9 +3554,6 @@ void tst_QUrl::setComponents_data() QTest::newRow("invalid-host-encode") << QUrl("http://example.com") << int(Host) << "ex%61mple.com" << Decoded << false << PrettyDecoded << "" << ""; - QTest::newRow("invalid-authority-encode") << QUrl("http://example.com") - << int(Authority) << "ex%61mple.com" << Decoded << false - << PrettyDecoded << "" << ""; QTest::newRow("path-encode") << QUrl("http://example.com/foo") << int(Path) << "/bar%23" << Decoded << true << PrettyDecoded << "/bar%2523" << "http://example.com/bar%2523"; @@ -3371,11 +3563,7 @@ void tst_QUrl::setComponents_data() QTest::newRow("fragment-encode") << QUrl("http://example.com/foo#z") << int(Fragment) << "bar%23" << Decoded << true << PrettyDecoded << "bar%2523" << "http://example.com/foo#bar%2523"; - // force decoding; note how the userinfo becomes ambiguous - QTest::newRow("userinfo-decode") << QUrl("http://example.com") - << int(UserInfo) << "hello%3Aworld:}}>b9o%25kR(" << Tolerant << true - << FullyDecoded << "hello:world:}}>b9o%kR(" - << "http://hello%3Aworld:%7D%7D%3Eb9o%25kR(@example.com"; + // force decoding QTest::newRow("username-decode") << QUrl("http://example.com") << int(UserName) << "hello%3Aworld%25" << Tolerant << true << FullyDecoded << "hello:world%" << "http://hello%3Aworld%25@example.com"; @@ -3460,6 +3648,8 @@ void tst_QUrl::setComponents() if (isValid) { QFETCH(QString, toString); QCOMPARE(copy.toString(), toString); + // Check round-tripping + QCOMPARE(QUrl(copy.toString()).toString(), toString); } else { QVERIFY(copy.toString().isEmpty()); } diff --git a/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp b/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp index 2014045171..05d5f94e3d 100644 --- a/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp +++ b/tests/auto/corelib/io/qurlinternal/tst_qurlinternal.cpp @@ -824,12 +824,20 @@ void tst_QUrlInternal::correctEncodedMistakes() QFETCH(QString, expected); // prepend some data to be sure that it remains there - QString output = QTest::currentDataTag(); - expected.prepend(output); + QString dataTag = QTest::currentDataTag(); + QString output = dataTag; if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), 0)) output += input; - QCOMPARE(output, expected); + QCOMPARE(output, dataTag + expected); + + // now try the full decode mode + output = dataTag; + QString expected2 = QUrl::fromPercentEncoding(expected.toLatin1()); + + if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::FullyDecoded)) + output += input; + QCOMPARE(output, dataTag + expected2); } static void addUtf8Data(const char *name, const char *data) @@ -1027,6 +1035,15 @@ void tst_QUrlInternal::encodingRecodeInvalidUtf8() if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::FullyEncoded)) output += input; QCOMPARE(output, QTest::currentDataTag() + input); + + // verify for security reasons that all bad UTF-8 data got replaced by QChar::ReplacementCharacter + output = QTest::currentDataTag(); + if (!qt_urlRecode(output, input.constData(), input.constData() + input.length(), QUrl::FullyEncoded)) + output += input; + for (int i = strlen(QTest::currentDataTag()); i < output.length(); ++i) { + QVERIFY2(output.at(i).unicode() < 0x80 || output.at(i) == QChar::ReplacementCharacter, + qPrintable(QString("Character at i == %1 was U+%2").arg(i).arg(output.at(i).unicode(), 4, 16, QLatin1Char('0')))); + } } void tst_QUrlInternal::recodeByteArray_data() |