QUrl: restore empty-but-not-null for components that are present

This got lost during the QStringView port that happend in Qt 6.0
(commit 548dcef089) because
QString::operator+=(QStringView) does not copy the nullness of the right
side, whereas QString::operator+=(const QString &) does.

Pick-to: 6.2 6.4 6.5
Fixes: QTBUG-84315
Change-Id: Ide4dbd0777a44ed0870efffd17399b772d34fd55
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Mårten Nordheim <marten.nordheim@qt.io>
This commit is contained in:
Thiago Macieira 2023-01-12 08:07:52 -08:00
parent a26d25be7b
commit a14a3a5487
2 changed files with 51 additions and 45 deletions

View File

@ -818,14 +818,16 @@ recodeFromUser(const QString &input, const ushort *actions, qsizetype from, qsiz
static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options, static inline void appendToUser(QString &appendTo, QStringView value, QUrl::FormattingOptions options,
const ushort *actions) const ushort *actions)
{ {
// Test ComponentFormattingOptions, ignore FormattingOptions. // The stored value is already QUrl::PrettyDecoded, so there's nothing to
if ((options & 0xFFFF0000) == QUrl::PrettyDecoded) { // do if that's what the user asked for (test only
// ComponentFormattingOptions, ignore FormattingOptions).
if ((options & 0xFFFF0000) == QUrl::PrettyDecoded ||
!qt_urlRecode(appendTo, value, options, actions))
appendTo += value; appendTo += value;
return;
}
if (!qt_urlRecode(appendTo, value, options, actions)) // copy nullness, if necessary, because QString::operator+=(QStringView) doesn't
appendTo += value; if (appendTo.isNull() && !value.isNull())
appendTo.detach();
} }
inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const inline void QUrlPrivate::appendAuthority(QString &appendTo, QUrl::FormattingOptions options, Section appendingTo) const

View File

@ -3801,106 +3801,106 @@ void tst_QUrl::setComponents_data()
QTest::newRow("invalid-username-1") << QUrl("http://example.com") QTest::newRow("invalid-username-1") << QUrl("http://example.com")
<< int(UserName) << "{}" << Strict << false << int(UserName) << "{}" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-username-2") << QUrl("http://example.com") QTest::newRow("invalid-username-2") << QUrl("http://example.com")
<< int(UserName) << "foo/bar" << Strict << false << int(UserName) << "foo/bar" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-username-3") << QUrl("http://example.com") QTest::newRow("invalid-username-3") << QUrl("http://example.com")
<< int(UserName) << "foo:bar" << Strict << false << int(UserName) << "foo:bar" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-password-1") << QUrl("http://example.com") QTest::newRow("invalid-password-1") << QUrl("http://example.com")
<< int(Password) << "{}" << Strict << false << int(Password) << "{}" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-password-2") << QUrl("http://example.com") QTest::newRow("invalid-password-2") << QUrl("http://example.com")
<< int(Password) << "foo/bar" << Strict << false << int(Password) << "foo/bar" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-password-3") << QUrl("http://example.com") QTest::newRow("invalid-password-3") << QUrl("http://example.com")
<< int(Password) << "foo:bar" << Strict << false << int(Password) << "foo:bar" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-userinfo-1") << QUrl("http://example.com") QTest::newRow("invalid-userinfo-1") << QUrl("http://example.com")
<< int(UserInfo) << "{}" << Strict << false << int(UserInfo) << "{}" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-userinfo-2") << QUrl("http://example.com") QTest::newRow("invalid-userinfo-2") << QUrl("http://example.com")
<< int(UserInfo) << "foo/bar" << Strict << false << int(UserInfo) << "foo/bar" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-host-1") << QUrl("http://example.com") QTest::newRow("invalid-host-1") << QUrl("http://example.com")
<< int(Host) << "-not-valid-" << Tolerant << false << int(Host) << "-not-valid-" << Tolerant << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-host-2") << QUrl("http://example.com") QTest::newRow("invalid-host-2") << QUrl("http://example.com")
<< int(Host) << "%31%30.%30.%30.%31" << Strict << false << int(Host) << "%31%30.%30.%30.%31" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-authority-1") << QUrl("http://example.com") QTest::newRow("invalid-authority-1") << QUrl("http://example.com")
<< int(Authority) << "-not-valid-" << Tolerant << false << int(Authority) << "-not-valid-" << Tolerant << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-authority-2") << QUrl("http://example.com") QTest::newRow("invalid-authority-2") << QUrl("http://example.com")
<< int(Authority) << "%31%30.%30.%30.%31" << Strict << false << int(Authority) << "%31%30.%30.%30.%31" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-path-0") << QUrl("http://example.com") QTest::newRow("invalid-path-0") << QUrl("http://example.com")
<< int(Path) << "{}" << Strict << false << int(Path) << "{}" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-query-1") << QUrl("http://example.com") QTest::newRow("invalid-query-1") << QUrl("http://example.com")
<< int(Query) << "{}" << Strict << false << int(Query) << "{}" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("invalid-fragment-1") << QUrl("http://example.com") QTest::newRow("invalid-fragment-1") << QUrl("http://example.com")
<< int(Fragment) << "{}" << Strict << false << int(Fragment) << "{}" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
// these test cases are "compound invalid": // these test cases are "compound invalid":
// they produces isValid == false, but the original is still available // they produces isValid == false, but the original is still available
QTest::newRow("invalid-path-1") << QUrl("/relative") QTest::newRow("invalid-path-1") << QUrl("/relative")
<< int(Path) << "c:/" << Strict << false << int(Path) << "c:/" << Strict << false
<< PrettyDecoded << "c:/" << ""; << PrettyDecoded << "c:/" << QString();
QTest::newRow("invalid-path-2") << QUrl("http://example.com") QTest::newRow("invalid-path-2") << QUrl("http://example.com")
<< int(Path) << "relative" << Strict << false << int(Path) << "relative" << Strict << false
<< PrettyDecoded << "relative" << ""; << PrettyDecoded << "relative" << QString();
QTest::newRow("invalid-path-3") << QUrl("trash:/") QTest::newRow("invalid-path-3") << QUrl("trash:/")
<< int(Path) << "//path" << Tolerant << false << int(Path) << "//path" << Tolerant << false
<< PrettyDecoded << "//path" << ""; << PrettyDecoded << "//path" << QString();
// -- test bad percent encoding -- // -- test bad percent encoding --
// unnecessary to test the scheme, since percent-decoding is not performed in it; // unnecessary to test the scheme, since percent-decoding is not performed in it;
// see tests above // see tests above
QTest::newRow("bad-percent-username") << QUrl("http://example.com") QTest::newRow("bad-percent-username") << QUrl("http://example.com")
<< int(UserName) << "bar%foo" << Strict << false << int(UserName) << "bar%foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-password") << QUrl("http://user@example.com") QTest::newRow("bad-percent-password") << QUrl("http://user@example.com")
<< int(Password) << "bar%foo" << Strict << false << int(Password) << "bar%foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-userinfo-1") << QUrl("http://example.com") QTest::newRow("bad-percent-userinfo-1") << QUrl("http://example.com")
<< int(UserInfo) << "bar%foo" << Strict << false << int(UserInfo) << "bar%foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-userinfo-2") << QUrl("http://example.com") QTest::newRow("bad-percent-userinfo-2") << QUrl("http://example.com")
<< int(UserInfo) << "bar%:foo" << Strict << false << int(UserInfo) << "bar%:foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-userinfo-3") << QUrl("http://example.com") QTest::newRow("bad-percent-userinfo-3") << QUrl("http://example.com")
<< int(UserInfo) << "bar:%foo" << Strict << false << int(UserInfo) << "bar:%foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-authority-1") << QUrl("http://example.com") QTest::newRow("bad-percent-authority-1") << QUrl("http://example.com")
<< int(Authority) << "bar%foo@example.org" << Strict << false << int(Authority) << "bar%foo@example.org" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-authority-2") << QUrl("http://example.com") QTest::newRow("bad-percent-authority-2") << QUrl("http://example.com")
<< int(Authority) << "bar%:foo@example.org" << Strict << false << int(Authority) << "bar%:foo@example.org" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-authority-3") << QUrl("http://example.com") QTest::newRow("bad-percent-authority-3") << QUrl("http://example.com")
<< int(Authority) << "bar:%foo@example.org" << Strict << false << int(Authority) << "bar:%foo@example.org" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-authority-4") << QUrl("http://example.com") QTest::newRow("bad-percent-authority-4") << QUrl("http://example.com")
<< int(Authority) << "bar:foo@bar%foo" << Strict << false << int(Authority) << "bar:foo@bar%foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-host") << QUrl("http://example.com") QTest::newRow("bad-percent-host") << QUrl("http://example.com")
<< int(Host) << "bar%foo" << Strict << false << int(Host) << "bar%foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-path") << QUrl("http://example.com") QTest::newRow("bad-percent-path") << QUrl("http://example.com")
<< int(Path) << "/bar%foo" << Strict << false << int(Path) << "/bar%foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-query") << QUrl("http://example.com") QTest::newRow("bad-percent-query") << QUrl("http://example.com")
<< int(Query) << "bar%foo" << Strict << false << int(Query) << "bar%foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("bad-percent-fragment") << QUrl("http://example.com") QTest::newRow("bad-percent-fragment") << QUrl("http://example.com")
<< int(Fragment) << "bar%foo" << Strict << false << int(Fragment) << "bar%foo" << Strict << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
// -- test decoded behaviour -- // -- test decoded behaviour --
// '%' characters are not permitted in the scheme, this tests that it fails to set anything // '%' characters are not permitted in the scheme, this tests that it fails to set anything
@ -3916,7 +3916,7 @@ void tst_QUrl::setComponents_data()
// '%' characters are not permitted in the hostname, these test that it fails to set anything // '%' characters are not permitted in the hostname, these test that it fails to set anything
QTest::newRow("invalid-host-encode") << QUrl("http://example.com") QTest::newRow("invalid-host-encode") << QUrl("http://example.com")
<< int(Host) << "ex%61mple.com" << Decoded << false << int(Host) << "ex%61mple.com" << Decoded << false
<< PrettyDecoded << "" << ""; << PrettyDecoded << QString() << QString();
QTest::newRow("path-encode") << QUrl("http://example.com/foo") QTest::newRow("path-encode") << QUrl("http://example.com/foo")
<< int(Path) << "/bar%23" << Decoded << true << int(Path) << "/bar%23" << Decoded << true
<< PrettyDecoded << "/bar%2523" << "http://example.com/bar%2523"; << PrettyDecoded << "/bar%2523" << "http://example.com/bar%2523";
@ -3955,41 +3955,44 @@ void tst_QUrl::setComponents()
QFETCH(int, encoding); QFETCH(int, encoding);
QFETCH(QString, output); QFETCH(QString, output);
#define QNULLCOMPARE(a, b) \
do { QCOMPARE(a, b); QCOMPARE(a.isNull(), b.isNull()); } while (false)
switch (component) { switch (component) {
case Scheme: case Scheme:
// scheme is only parsed in strict mode // scheme is only parsed in strict mode
copy.setScheme(newValue); copy.setScheme(newValue);
QCOMPARE(copy.scheme(), output); QCOMPARE(copy.scheme(), output); // schemes don't become null
break; break;
case Path: case Path:
copy.setPath(newValue, QUrl::ParsingMode(parsingMode)); copy.setPath(newValue, QUrl::ParsingMode(parsingMode));
QCOMPARE(copy.path(QUrl::ComponentFormattingOptions(encoding)), output); QNULLCOMPARE(copy.path(QUrl::ComponentFormattingOptions(encoding)), output);
break; break;
case UserInfo: case UserInfo:
copy.setUserInfo(newValue, QUrl::ParsingMode(parsingMode)); copy.setUserInfo(newValue, QUrl::ParsingMode(parsingMode));
QCOMPARE(copy.userInfo(QUrl::ComponentFormattingOptions(encoding)), output); QNULLCOMPARE(copy.userInfo(QUrl::ComponentFormattingOptions(encoding)), output);
break; break;
case UserName: case UserName:
copy.setUserName(newValue, QUrl::ParsingMode(parsingMode)); copy.setUserName(newValue, QUrl::ParsingMode(parsingMode));
QCOMPARE(copy.userName(QUrl::ComponentFormattingOptions(encoding)), output); QNULLCOMPARE(copy.userName(QUrl::ComponentFormattingOptions(encoding)), output);
break; break;
case Password: case Password:
copy.setPassword(newValue, QUrl::ParsingMode(parsingMode)); copy.setPassword(newValue, QUrl::ParsingMode(parsingMode));
QCOMPARE(copy.password(QUrl::ComponentFormattingOptions(encoding)), output); QNULLCOMPARE(copy.password(QUrl::ComponentFormattingOptions(encoding)), output);
break; break;
case Host: case Host:
copy.setHost(newValue, QUrl::ParsingMode(parsingMode)); copy.setHost(newValue, QUrl::ParsingMode(parsingMode));
QCOMPARE(copy.host(QUrl::ComponentFormattingOptions(encoding)), output); QNULLCOMPARE(copy.host(QUrl::ComponentFormattingOptions(encoding)), output);
break; break;
case Authority: case Authority:
copy.setAuthority(newValue, QUrl::ParsingMode(parsingMode)); copy.setAuthority(newValue, QUrl::ParsingMode(parsingMode));
QCOMPARE(copy.authority(QUrl::ComponentFormattingOptions(encoding)), output); QNULLCOMPARE(copy.authority(QUrl::ComponentFormattingOptions(encoding)), output);
break; break;
case Query: case Query:
@ -4004,6 +4007,7 @@ void tst_QUrl::setComponents()
QCOMPARE(copy.fragment(QUrl::ComponentFormattingOptions(encoding)), output); QCOMPARE(copy.fragment(QUrl::ComponentFormattingOptions(encoding)), output);
break; break;
} }
#undef QNULLCOMPARE
QFETCH(bool, isValid); QFETCH(bool, isValid);
QCOMPARE(copy.isValid(), isValid); QCOMPARE(copy.isValid(), isValid);