qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -0,0 +1,23 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
if(NOT INTEGRITY)
add_subdirectory(qdnslookup)
add_subdirectory(qdnslookup_appless)
endif()
if(QT_FEATURE_networkinterface)
add_subdirectory(qnetworkproxyfactory)
add_subdirectory(qnetworkinterface)
endif()
add_subdirectory(qnetworkproxy)
add_subdirectory(qnetworkdatagram)
add_subdirectory(qnetworkaddressentry)
add_subdirectory(qhostaddress)
if(QT_FEATURE_private_tests AND NOT MACOS AND NOT INTEGRITY)
add_subdirectory(qhostinfo)
endif()
if(QT_FEATURE_private_tests)
add_subdirectory(qauthenticator)
add_subdirectory(qnetworkinformation)
add_subdirectory(qnetworkinformation_appless)
endif()

View File

@ -0,0 +1,17 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
if(NOT QT_FEATURE_private_tests)
return()
endif()
#####################################################################
## tst_qauthenticator Test:
#####################################################################
qt_internal_add_test(tst_qauthenticator
SOURCES
tst_qauthenticator.cpp
LIBRARIES
Qt::NetworkPrivate
)

View File

@ -0,0 +1,192 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/QString>
#include <QTest>
#include <QtCore/QCoreApplication>
#include <QtNetwork/QAuthenticator>
#include <private/qauthenticator_p.h>
class tst_QAuthenticator : public QObject
{
Q_OBJECT
public:
tst_QAuthenticator();
private Q_SLOTS:
void basicAuth();
void basicAuth_data();
void ntlmAuth_data();
void ntlmAuth();
void sha256AndMd5Digest();
void equalityOperators();
void isMethodSupported();
};
tst_QAuthenticator::tst_QAuthenticator()
{
}
void tst_QAuthenticator::basicAuth_data()
{
QTest::addColumn<QString>("data");
QTest::addColumn<QString>("realm");
QTest::addColumn<QString>("user");
QTest::addColumn<QString>("password");
QTest::addColumn<QByteArray>("expectedReply");
QTest::newRow("just-user") << "" << "" << "foo" << "" << QByteArray("foo:").toBase64();
QTest::newRow("user-password") << "" << "" << "foo" << "bar" << QByteArray("foo:bar").toBase64();
QTest::newRow("user-password-realm") << "realm=\"secure area\"" << "secure area" << "foo" << "bar" << QByteArray("foo:bar").toBase64();
}
void tst_QAuthenticator::basicAuth()
{
QFETCH(QString, data);
QFETCH(QString, realm);
QFETCH(QString, user);
QFETCH(QString, password);
QFETCH(QByteArray, expectedReply);
QAuthenticator auth;
auth.detach();
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth);
QCOMPARE(priv->phase, QAuthenticatorPrivate::Start);
QList<QPair<QByteArray, QByteArray> > headers;
headers << qMakePair(QByteArray("WWW-Authenticate"), "Basic " + data.toUtf8());
priv->parseHttpResponse(headers, /*isProxy = */ false, {});
QCOMPARE(auth.realm(), realm);
QCOMPARE(auth.option("realm").toString(), realm);
auth.setUser(user);
auth.setPassword(password);
QCOMPARE(priv->phase, QAuthenticatorPrivate::Start);
QCOMPARE(priv->calculateResponse("GET", "/", u"").constData(), QByteArray("Basic " + expectedReply).constData());
}
void tst_QAuthenticator::ntlmAuth_data()
{
QTest::addColumn<QString>("data");
QTest::addColumn<QString>("realm");
QTest::addColumn<bool>("sso");
QTest::newRow("no-realm") << "TlRMTVNTUAACAAAAHAAcADAAAAAFAoEATFZ3OLRQADIAAAAAAAAAAJYAlgBMAAAAUQBUAC0AVABFAFMAVAAtAEQATwBNAEEASQBOAAIAHABRAFQALQBUAEUAUwBUAC0ARABPAE0AQQBJAE4AAQAcAFEAVAAtAFQARQBTAFQALQBTAEUAUgBWAEUAUgAEABYAcQB0AC0AdABlAHMAdAAtAG4AZQB0AAMANABxAHQALQB0AGUAcwB0AC0AcwBlAHIAdgBlAHIALgBxAHQALQB0AGUAcwB0AC0AbgBlAHQAAAAAAA==" << "" << false;
QTest::newRow("with-realm") << "TlRMTVNTUAACAAAADAAMADgAAAAFAoECWCZkccFFAzwAAAAAAAAAAL4AvgBEAAAABQLODgAAAA9NAEcARABOAE8ASwACAAwATQBHAEQATgBPAEsAAQAcAE4ATwBLAC0AQQBNAFMAUwBTAEYARQAtADAAMQAEACAAbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQADAD4AbgBvAGsALQBhAG0AcwBzAHMAZgBlAC0AMAAxAC4AbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQAFACAAbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQAAAAAA" << "NOE" << false;
QTest::newRow("no-realm-sso") << "TlRMTVNTUAACAAAAHAAcADAAAAAFAoEATFZ3OLRQADIAAAAAAAAAAJYAlgBMAAAAUQBUAC0AVABFAFMAVAAtAEQATwBNAEEASQBOAAIAHABRAFQALQBUAEUAUwBUAC0ARABPAE0AQQBJAE4AAQAcAFEAVAAtAFQARQBTAFQALQBTAEUAUgBWAEUAUgAEABYAcQB0AC0AdABlAHMAdAAtAG4AZQB0AAMANABxAHQALQB0AGUAcwB0AC0AcwBlAHIAdgBlAHIALgBxAHQALQB0AGUAcwB0AC0AbgBlAHQAAAAAAA==" << "" << true;
QTest::newRow("with-realm-sso") << "TlRMTVNTUAACAAAADAAMADgAAAAFAoECWCZkccFFAzwAAAAAAAAAAL4AvgBEAAAABQLODgAAAA9NAEcARABOAE8ASwACAAwATQBHAEQATgBPAEsAAQAcAE4ATwBLAC0AQQBNAFMAUwBTAEYARQAtADAAMQAEACAAbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQADAD4AbgBvAGsALQBhAG0AcwBzAHMAZgBlAC0AMAAxAC4AbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQAFACAAbQBnAGQAbgBvAGsALgBuAG8AawBpAGEALgBjAG8AbQAAAAAA" << "NOE" << true;
}
void tst_QAuthenticator::ntlmAuth()
{
QFETCH(QString, data);
QFETCH(QString, realm);
QFETCH(bool, sso);
QAuthenticator auth;
if (!sso) {
auth.setUser("unimportant");
auth.setPassword("unimportant");
}
auth.detach();
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth);
QCOMPARE(priv->phase, QAuthenticatorPrivate::Start);
QList<QPair<QByteArray, QByteArray> > headers;
// NTLM phase 1: negotiate
// This phase of NTLM contains no information, other than what we're willing to negotiate
// Current implementation uses flags:
// NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_REQUEST_TARGET
headers << qMakePair(QByteArrayLiteral("WWW-Authenticate"), QByteArrayLiteral("NTLM"));
priv->parseHttpResponse(headers, /*isProxy = */ false, {});
if (sso)
QVERIFY(priv->calculateResponse("GET", "/", u"").startsWith("NTLM "));
else
QCOMPARE(priv->calculateResponse("GET", "/", u"").constData(), "NTLM TlRMTVNTUAABAAAABYIIAAAAAAAAAAAAAAAAAAAAAAA=");
// NTLM phase 2: challenge
headers.clear();
headers << qMakePair(QByteArray("WWW-Authenticate"), "NTLM " + data.toUtf8());
priv->parseHttpResponse(headers, /*isProxy = */ false, {});
QEXPECT_FAIL("with-realm", "NTLM authentication code doesn't extract the realm", Continue);
QEXPECT_FAIL("with-realm-sso", "NTLM authentication code doesn't extract the realm", Continue);
QCOMPARE(auth.realm(), realm);
QVERIFY(priv->calculateResponse("GET", "/", u"").startsWith("NTLM "));
}
// We don't (currently) support SHA256. So, when presented with the option of MD5 or SHA256,
// we should always pick MD5.
void tst_QAuthenticator::sha256AndMd5Digest()
{
QByteArray md5 = "Digest realm=\"\", nonce=\"\", algorithm=MD5, qop=\"auth\"";
QByteArray sha256 = "Digest realm=\"\", nonce=\"\", algorithm=SHA-256, qop=\"auth\"";
QAuthenticator auth;
auth.setUser("unimportant");
auth.setPassword("unimportant");
QAuthenticatorPrivate *priv = QAuthenticatorPrivate::getPrivate(auth);
QVERIFY(priv->isMethodSupported("digest")); // sanity check
QCOMPARE(priv->phase, QAuthenticatorPrivate::Start);
QList<QPair<QByteArray, QByteArray>> headers;
// Put sha256 first, so that its parsed first...
headers.emplace_back("WWW-Authenticate", sha256);
headers.emplace_back("WWW-Authenticate", md5);
priv->parseHttpResponse(headers, false, QString());
QByteArray response = priv->calculateResponse("GET", "/index", {});
QCOMPARE(priv->phase, QAuthenticatorPrivate::Done);
QVERIFY(!response.isEmpty());
QVERIFY(!response.contains("algorithm=SHA-256"));
QVERIFY(response.contains("algorithm=MD5"));
}
void tst_QAuthenticator::equalityOperators()
{
QAuthenticator s1, s2;
QVERIFY(s2 == s1);
QVERIFY(s1 == s2);
QVERIFY(!(s1 != s2));
QVERIFY(!(s2 != s1));
s1.setUser("User");
QVERIFY(!(s2 == s1));
QVERIFY(!(s1 == s2));
QVERIFY(s1 != s2);
QVERIFY(s2 != s1);
}
void tst_QAuthenticator::isMethodSupported()
{
QVERIFY(QAuthenticatorPrivate::isMethodSupported("basic"));
QVERIFY(QAuthenticatorPrivate::isMethodSupported("Basic realm=\"Shadow\""));
QVERIFY(QAuthenticatorPrivate::isMethodSupported("DIgesT"));
QVERIFY(QAuthenticatorPrivate::isMethodSupported("NTLM"));
QVERIFY(QAuthenticatorPrivate::isMethodSupported("ntlm"));
#if QT_CONFIG(sspi) || QT_CONFIG(gssapi)
QVERIFY(QAuthenticatorPrivate::isMethodSupported("negotiate"));
#else
QVERIFY(!QAuthenticatorPrivate::isMethodSupported("negotiate"));
#endif
QVERIFY(!QAuthenticatorPrivate::isMethodSupported("Bearer"));
}
QTEST_MAIN(tst_QAuthenticator);
#include "tst_qauthenticator.moc"

View File

@ -0,0 +1,2 @@
[lookup]
*

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdnslookup Test:
#####################################################################
qt_internal_add_test(tst_qdnslookup
SOURCES
tst_qdnslookup.cpp
LIBRARIES
Qt::Network
)

View File

@ -0,0 +1,403 @@
// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QSignalSpy>
#include <QtNetwork/QDnsLookup>
#include <QtNetwork/QHostAddress>
static const int Timeout = 15000; // 15s
class tst_QDnsLookup: public QObject
{
Q_OBJECT
QString domainName(const QString &input);
QString domainNameList(const QString &input);
QStringList domainNameListAlternatives(const QString &input);
public slots:
void initTestCase();
private slots:
void lookup_data();
void lookup();
void lookupReuse();
void lookupAbortRetry();
void bindingsAndProperties();
};
void tst_QDnsLookup::initTestCase()
{
QTest::addColumn<QString>("tld");
QTest::newRow("normal") << ".test.qt-project.org";
QTest::newRow("idn") << ".alqualond\xc3\xab.test.qt-project.org";
}
QString tst_QDnsLookup::domainName(const QString &input)
{
if (input.isEmpty())
return input;
if (input.endsWith(QLatin1Char('.'))) {
QString nodot = input;
nodot.chop(1);
return nodot;
}
QFETCH_GLOBAL(QString, tld);
return input + tld;
}
QString tst_QDnsLookup::domainNameList(const QString &input)
{
QStringList list = input.split(QLatin1Char(';'));
QString result;
foreach (const QString &s, list) {
if (!result.isEmpty())
result += ';';
result += domainName(s);
}
return result;
}
QStringList tst_QDnsLookup::domainNameListAlternatives(const QString &input)
{
QStringList alternatives = input.split('|');
for (int i = 0; i < alternatives.size(); ++i)
alternatives[i] = domainNameList(alternatives[i]);
return alternatives;
}
void tst_QDnsLookup::lookup_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<QString>("domain");
QTest::addColumn<int>("error");
QTest::addColumn<QString>("cname");
QTest::addColumn<QString>("host");
QTest::addColumn<QString>("mx");
QTest::addColumn<QString>("ns");
QTest::addColumn<QString>("ptr");
QTest::addColumn<QString>("srv");
QTest::addColumn<QString>("txt");
QTest::newRow("a-empty") << int(QDnsLookup::A) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << ""<< "" << "";
QTest::newRow("a-notfound") << int(QDnsLookup::A) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("a-single") << int(QDnsLookup::A) << "a-single" << int(QDnsLookup::NoError) << "" << "192.0.2.1" << "" << "" << "" << "" << "";
QTest::newRow("a-multi") << int(QDnsLookup::A) << "a-multi" << int(QDnsLookup::NoError) << "" << "192.0.2.1;192.0.2.2;192.0.2.3" << "" << "" << "" << "" << "";
QTest::newRow("aaaa-empty") << int(QDnsLookup::AAAA) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("aaaa-notfound") << int(QDnsLookup::AAAA) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("aaaa-single") << int(QDnsLookup::AAAA) << "aaaa-single" << int(QDnsLookup::NoError) << "" << "2001:db8::1" << "" << "" << "" << "" << "";
QTest::newRow("aaaa-multi") << int(QDnsLookup::AAAA) << "aaaa-multi" << int(QDnsLookup::NoError) << "" << "2001:db8::1;2001:db8::2;2001:db8::3" << "" << "" << "" << "" << "";
QTest::newRow("any-empty") << int(QDnsLookup::ANY) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("any-notfound") << int(QDnsLookup::ANY) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("any-a-single") << int(QDnsLookup::ANY) << "a-single" << int(QDnsLookup::NoError) << "" << "192.0.2.1" << "" << "" << "" << "" << "";
QTest::newRow("any-a-plus-aaaa") << int(QDnsLookup::ANY) << "a-plus-aaaa" << int(QDnsLookup::NoError) << "" << "198.51.100.1;2001:db8::1:1" << "" << "" << "" << "" << "";
QTest::newRow("any-multi") << int(QDnsLookup::ANY) << "multi" << int(QDnsLookup::NoError) << "" << "198.51.100.1;198.51.100.2;198.51.100.3;2001:db8::1:1;2001:db8::1:2" << "" << "" << "" << "" << "";
QTest::newRow("mx-empty") << int(QDnsLookup::MX) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("mx-notfound") << int(QDnsLookup::MX) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("mx-single") << int(QDnsLookup::MX) << "mx-single" << int(QDnsLookup::NoError) << "" << "" << "10 multi" << "" << "" << "" << "";
QTest::newRow("mx-single-cname") << int(QDnsLookup::MX) << "mx-single-cname" << int(QDnsLookup::NoError) << "" << "" << "10 cname" << "" << "" << "" << "";
QTest::newRow("mx-multi") << int(QDnsLookup::MX) << "mx-multi" << int(QDnsLookup::NoError) << "" << "" << "10 multi;20 a-single" << "" << "" << "" << "";
QTest::newRow("mx-multi-sameprio") << int(QDnsLookup::MX) << "mx-multi-sameprio" << int(QDnsLookup::NoError) << "" << ""
<< "10 multi;10 a-single|"
"10 a-single;10 multi" << "" << "" << "" << "";
QTest::newRow("ns-empty") << int(QDnsLookup::NS) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("ns-notfound") << int(QDnsLookup::NS) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("ns-single") << int(QDnsLookup::NS) << "ns-single" << int(QDnsLookup::NoError) << "" << "" << "" << "ns11.cloudns.net." << "" << "" << "";
QTest::newRow("ns-multi") << int(QDnsLookup::NS) << "ns-multi" << int(QDnsLookup::NoError) << "" << "" << "" << "ns11.cloudns.net.;ns12.cloudns.net." << "" << "" << "";
QTest::newRow("ptr-empty") << int(QDnsLookup::PTR) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("ptr-notfound") << int(QDnsLookup::PTR) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
#if 0
// temporarily disabled since the new hosting provider can't insert
// PTR records outside of the in-addr.arpa zone
QTest::newRow("ptr-single") << int(QDnsLookup::PTR) << "ptr-single" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "a-single" << "" << "";
#endif
QTest::newRow("srv-empty") << int(QDnsLookup::SRV) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("srv-notfound") << int(QDnsLookup::SRV) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("srv-single") << int(QDnsLookup::SRV) << "_echo._tcp.srv-single" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "5 0 7 multi" << "";
QTest::newRow("srv-prio") << int(QDnsLookup::SRV) << "_echo._tcp.srv-prio" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "1 0 7 multi;2 0 7 a-plus-aaaa" << "";
QTest::newRow("srv-weighted") << int(QDnsLookup::SRV) << "_echo._tcp.srv-weighted" << int(QDnsLookup::NoError) << "" << "" << "" << "" << ""
<< "5 75 7 multi;5 25 7 a-plus-aaaa|"
"5 25 7 a-plus-aaaa;5 75 7 multi" << "";
QTest::newRow("srv-multi") << int(QDnsLookup::SRV) << "_echo._tcp.srv-multi" << int(QDnsLookup::NoError) << "" << "" << "" << "" << ""
<< "1 50 7 multi;2 50 7 a-single;2 50 7 aaaa-single;3 50 7 a-multi|"
"1 50 7 multi;2 50 7 aaaa-single;2 50 7 a-single;3 50 7 a-multi" << "";
QTest::newRow("txt-empty") << int(QDnsLookup::TXT) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("txt-notfound") << int(QDnsLookup::TXT) << "invalid.invalid" << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << "";
QTest::newRow("txt-single") << int(QDnsLookup::TXT) << "txt-single" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "" << "Hello";
QTest::newRow("txt-multi-onerr") << int(QDnsLookup::TXT) << "txt-multi-onerr" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << ""
<< QString::fromLatin1("Hello\0World", sizeof("Hello\0World") - 1);
QTest::newRow("txt-multi-multirr") << int(QDnsLookup::TXT) << "txt-multi-multirr" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "" << "Hello;World";
}
static QByteArray msgDnsLookup(QDnsLookup::Error actualError,
int expectedError,
const QString &domain,
const QString &cname,
const QString &host,
const QString &srv,
const QString &mx,
const QString &ns,
const QString &ptr,
const QString &errorString)
{
QString result;
QTextStream str(&result);
str << "Actual error: " << actualError;
if (!errorString.isEmpty())
str << " (" << errorString << ')';
str << ", expected: " << expectedError;
str << ", domain: " << domain;
if (!cname.isEmpty())
str << ", cname: " << cname;
str << ", host: " << host;
if (!srv.isEmpty())
str << " server: " << srv;
if (!mx.isEmpty())
str << " mx: " << mx;
if (!ns.isEmpty())
str << " ns: " << ns;
if (!ptr.isEmpty())
str << " ptr: " << ptr;
return result.toLocal8Bit();
}
void tst_QDnsLookup::lookup()
{
QFETCH(int, type);
QFETCH(QString, domain);
QFETCH(int, error);
QFETCH(QString, cname);
QFETCH(QString, host);
QFETCH(QString, mx);
QFETCH(QString, ns);
QFETCH(QString, ptr);
QFETCH(QString, srv);
QFETCH(QString, txt);
// transform the inputs
domain = domainName(domain);
cname = domainName(cname);
ns = domainNameList(ns);
ptr = domainNameList(ptr);
// SRV and MX have reply entries that can change order
// and we can't sort
QStringList mx_alternatives = domainNameListAlternatives(mx);
QStringList srv_alternatives = domainNameListAlternatives(srv);
QDnsLookup lookup;
lookup.setType(static_cast<QDnsLookup::Type>(type));
lookup.setName(domain);
lookup.lookup();
QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout);
#if defined(Q_OS_ANDROID)
if (lookup.errorString() == QStringLiteral("Not yet supported on Android"))
QEXPECT_FAIL("", "Not yet supported on Android", Abort);
#endif
QVERIFY2(int(lookup.error()) == error,
msgDnsLookup(lookup.error(), error, domain, cname, host, srv, mx, ns, ptr, lookup.errorString()));
if (error == QDnsLookup::NoError)
QVERIFY(lookup.errorString().isEmpty());
QCOMPARE(int(lookup.type()), type);
QCOMPARE(lookup.name(), domain);
// canonical names
if (!cname.isEmpty()) {
QVERIFY(!lookup.canonicalNameRecords().isEmpty());
const QDnsDomainNameRecord cnameRecord = lookup.canonicalNameRecords().first();
QCOMPARE(cnameRecord.name(), domain);
QCOMPARE(cnameRecord.value(), cname);
} else {
QVERIFY(lookup.canonicalNameRecords().isEmpty());
}
// host addresses
const QString hostName = cname.isEmpty() ? domain : cname;
QStringList addresses;
foreach (const QDnsHostAddressRecord &record, lookup.hostAddressRecords()) {
//reply may include A & AAAA records for nameservers, ignore them and only look at records matching the query
if (record.name() == hostName)
addresses << record.value().toString().toLower();
}
addresses.sort();
QCOMPARE(addresses.join(';'), host);
// mail exchanges
QStringList mailExchanges;
foreach (const QDnsMailExchangeRecord &record, lookup.mailExchangeRecords()) {
QCOMPARE(record.name(), domain);
mailExchanges << QString::number(record.preference()) + QLatin1Char(' ') + record.exchange();
}
QVERIFY2(mx_alternatives.contains(mailExchanges.join(';')),
qPrintable("Actual: " + mailExchanges.join(';') + "\nExpected one of:\n" + mx_alternatives.join('\n')));
// name servers
QStringList nameServers;
foreach (const QDnsDomainNameRecord &record, lookup.nameServerRecords()) {
//reply may include NS records for authoritative nameservers, ignore them and only look at records matching the query
if (record.name() == domain)
nameServers << record.value();
}
nameServers.sort();
QCOMPARE(nameServers.join(';'), ns);
// pointers
if (!ptr.isEmpty()) {
QVERIFY(!lookup.pointerRecords().isEmpty());
const QDnsDomainNameRecord ptrRecord = lookup.pointerRecords().first();
QCOMPARE(ptrRecord.name(), domain);
QCOMPARE(ptrRecord.value(), ptr);
} else {
QVERIFY(lookup.pointerRecords().isEmpty());
}
// services
QStringList services;
foreach (const QDnsServiceRecord &record, lookup.serviceRecords()) {
QCOMPARE(record.name(), domain);
services << (QString::number(record.priority()) + QLatin1Char(' ')
+ QString::number(record.weight()) + QLatin1Char(' ')
+ QString::number(record.port()) + QLatin1Char(' ') + record.target());
}
QVERIFY2(srv_alternatives.contains(services.join(';')),
qPrintable("Actual: " + services.join(';') + "\nExpected one of:\n" + srv_alternatives.join('\n')));
// text
QStringList texts;
foreach (const QDnsTextRecord &record, lookup.textRecords()) {
QCOMPARE(record.name(), domain);
QString text;
foreach (const QByteArray &ba, record.values()) {
if (!text.isEmpty())
text += '\0';
text += QString::fromLatin1(ba);
}
texts << text;
}
texts.sort();
QCOMPARE(texts.join(';'), txt);
}
void tst_QDnsLookup::lookupReuse()
{
QDnsLookup lookup;
// first lookup
lookup.setType(QDnsLookup::A);
lookup.setName(domainName("a-single"));
lookup.lookup();
QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout);
#if defined(Q_OS_ANDROID)
if (lookup.errorString() == QStringLiteral("Not yet supported on Android"))
QEXPECT_FAIL("", "Not yet supported on Android", Abort);
#endif
QCOMPARE(int(lookup.error()), int(QDnsLookup::NoError));
QVERIFY(!lookup.hostAddressRecords().isEmpty());
QCOMPARE(lookup.hostAddressRecords().first().name(), domainName("a-single"));
QCOMPARE(lookup.hostAddressRecords().first().value(), QHostAddress("192.0.2.1"));
// second lookup
lookup.setType(QDnsLookup::AAAA);
lookup.setName(domainName("aaaa-single"));
lookup.lookup();
QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout);
QCOMPARE(int(lookup.error()), int(QDnsLookup::NoError));
QVERIFY(!lookup.hostAddressRecords().isEmpty());
QCOMPARE(lookup.hostAddressRecords().first().name(), domainName("aaaa-single"));
QCOMPARE(lookup.hostAddressRecords().first().value(), QHostAddress("2001:db8::1"));
}
void tst_QDnsLookup::lookupAbortRetry()
{
QDnsLookup lookup;
// try and abort the lookup
lookup.setType(QDnsLookup::A);
lookup.setName(domainName("a-single"));
lookup.lookup();
lookup.abort();
QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout);
QCOMPARE(int(lookup.error()), int(QDnsLookup::OperationCancelledError));
QVERIFY(lookup.hostAddressRecords().isEmpty());
// retry a different lookup
lookup.setType(QDnsLookup::AAAA);
lookup.setName(domainName("aaaa-single"));
lookup.lookup();
QTRY_VERIFY_WITH_TIMEOUT(lookup.isFinished(), Timeout);
#if defined(Q_OS_ANDROID)
if (lookup.errorString() == QStringLiteral("Not yet supported on Android"))
QEXPECT_FAIL("", "Not yet supported on Android", Abort);
#endif
QCOMPARE(int(lookup.error()), int(QDnsLookup::NoError));
QVERIFY(!lookup.hostAddressRecords().isEmpty());
QCOMPARE(lookup.hostAddressRecords().first().name(), domainName("aaaa-single"));
QCOMPARE(lookup.hostAddressRecords().first().value(), QHostAddress("2001:db8::1"));
}
void tst_QDnsLookup::bindingsAndProperties()
{
QFETCH_GLOBAL(const QString, tld);
if (tld == QStringLiteral("idn"))
return;
QDnsLookup lookup;
lookup.setType(QDnsLookup::A);
QProperty<QDnsLookup::Type> dnsTypeProp;
lookup.bindableType().setBinding(Qt::makePropertyBinding(dnsTypeProp));
const QSignalSpy typeChangeSpy(&lookup, &QDnsLookup::typeChanged);
dnsTypeProp = QDnsLookup::AAAA;
QCOMPARE(typeChangeSpy.size(), 1);
QCOMPARE(lookup.type(), QDnsLookup::AAAA);
dnsTypeProp.setBinding(lookup.bindableType().makeBinding());
lookup.setType(QDnsLookup::A);
QCOMPARE(dnsTypeProp.value(), QDnsLookup::A);
QProperty<QString> nameProp;
lookup.bindableName().setBinding(Qt::makePropertyBinding(nameProp));
const QSignalSpy nameChangeSpy(&lookup, &QDnsLookup::nameChanged);
nameProp = QStringLiteral("a-plus-aaaa");
QCOMPARE(nameChangeSpy.size(), 1);
QCOMPARE(lookup.name(), QStringLiteral("a-plus-aaaa"));
nameProp.setBinding(lookup.bindableName().makeBinding());
lookup.setName(QStringLiteral("a-single"));
QCOMPARE(nameProp.value(), QStringLiteral("a-single"));
QProperty<QHostAddress> nameserverProp;
lookup.bindableNameserver().setBinding(Qt::makePropertyBinding(nameserverProp));
const QSignalSpy nameserverChangeSpy(&lookup, &QDnsLookup::nameserverChanged);
nameserverProp = QHostAddress::LocalHost;
QCOMPARE(nameserverChangeSpy.size(), 1);
QCOMPARE(lookup.nameserver(), QHostAddress::LocalHost);
nameserverProp.setBinding(lookup.bindableNameserver().makeBinding());
lookup.setNameserver(QHostAddress::Any);
QCOMPARE(nameserverProp.value(), QHostAddress::Any);
}
QTEST_MAIN(tst_QDnsLookup)
#include "tst_qdnslookup.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qdnslookup_appless Test:
#####################################################################
qt_internal_add_test(tst_qdnslookup_appless
SOURCES
tst_qdnslookup_appless.cpp
LIBRARIES
Qt::Network
)

View File

@ -0,0 +1,55 @@
// Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/QCoreApplication>
#include <QtNetwork/QDnsLookup>
#include <QTest>
#include <QTestEventLoop>
class tst_QDnsLookup_Appless : public QObject
{
Q_OBJECT
private slots:
void noApplication();
void recreateApplication();
void destroyApplicationDuringLookup();
};
void tst_QDnsLookup_Appless::noApplication()
{
QTest::ignoreMessage(QtWarningMsg, "QDnsLookup requires a QCoreApplication");
QDnsLookup dns(QDnsLookup::A, "a-single.test.qt-project.org");
dns.lookup();
}
void tst_QDnsLookup_Appless::recreateApplication()
{
int argc = 0;
char **argv = 0;
for (int i = 0; i < 10; ++i) {
QCoreApplication app(argc, argv);
QDnsLookup dns(QDnsLookup::A, "a-single.test.qt-project.org");
dns.lookup();
if (!dns.isFinished()) {
QObject::connect(&dns, SIGNAL(finished()),
&QTestEventLoop::instance(), SLOT(exitLoop()));
QTestEventLoop::instance().enterLoop(10);
}
QVERIFY(dns.isFinished());
}
}
void tst_QDnsLookup_Appless::destroyApplicationDuringLookup()
{
int argc = 0;
char **argv = 0;
for (int i = 0; i < 10; ++i) {
QCoreApplication app(argc, argv);
QDnsLookup dns(QDnsLookup::A, "a-single.test.macieira.info");
dns.lookup();
}
}
QTEST_APPLESS_MAIN(tst_QDnsLookup_Appless)
#include "tst_qdnslookup_appless.moc"

View File

@ -0,0 +1,21 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qhostaddress Test:
#####################################################################
qt_internal_add_test(tst_qhostaddress
SOURCES
tst_qhostaddress.cpp
LIBRARIES
Qt::NetworkPrivate
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qhostaddress CONDITION WIN32
LIBRARIES
ws2_32
)

View File

@ -0,0 +1,763 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qhostaddress.h>
#include <private/qhostaddress_p.h>
#include <qcoreapplication.h>
#include <QTest>
#include <qplatformdefs.h>
#include <qdebug.h>
#include <qhash.h>
#include <qbytearray.h>
#include <qdatastream.h>
#ifdef Q_OS_WIN
# include <qt_windows.h>
#endif
#if defined(Q_OS_ANDROID) || defined(Q_OS_WASM)
# include <netinet/in.h>
#endif
Q_DECLARE_METATYPE(AddressClassification)
Q_DECLARE_METATYPE(QHostAddress::SpecialAddress)
class tst_QHostAddress : public QObject
{
Q_OBJECT
public:
tst_QHostAddress();
private slots:
void constructor_QString_data();
void constructor_QString();
void setAddress_QString_data();
void setAddress_QString();
void specialAddresses_data();
void specialAddresses();
void compare_data();
void compare();
void isEqual_data();
void isEqual();
void assignment();
void scopeId();
void hashKey();
void streaming_data();
void streaming();
void parseSubnet_data();
void parseSubnet();
void isInSubnet_data();
void isInSubnet();
void classification_data();
void classification();
void convertv4v6_data();
void convertv4v6();
};
Q_DECLARE_METATYPE(QHostAddress)
tst_QHostAddress::tst_QHostAddress()
{
qRegisterMetaType<QHostAddress>("QHostAddress");
}
void tst_QHostAddress::constructor_QString_data()
{
setAddress_QString_data();
}
void tst_QHostAddress::constructor_QString()
{
QFETCH(QString, address);
QFETCH(bool, ok);
QFETCH(int, protocol);
QHostAddress hostAddr(address);
if (address == "0.0.0.0" || address == "::") {
QVERIFY(ok);
} else {
QVERIFY(hostAddr.isNull() != ok);
}
if (ok)
QTEST(hostAddr.toString(), "resAddr");
if ( protocol == 4 ) {
QVERIFY( hostAddr.protocol() == QHostAddress::IPv4Protocol || hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol );
QVERIFY( hostAddr.protocol() != QHostAddress::IPv6Protocol );
} else if ( protocol == 6 ) {
QVERIFY( hostAddr.protocol() != QHostAddress::IPv4Protocol && hostAddr.protocol() != QHostAddress::UnknownNetworkLayerProtocol );
QVERIFY( hostAddr.protocol() == QHostAddress::IPv6Protocol );
} else {
QVERIFY( hostAddr.isNull() );
QVERIFY( hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol );
}
}
void tst_QHostAddress::setAddress_QString_data()
{
QTest::addColumn<QString>("address");
QTest::addColumn<bool>("ok");
QTest::addColumn<QString>("resAddr");
QTest::addColumn<int>("protocol"); // 4: IPv4, 6: IPv6, other: undefined
//next we fill it with data
QTest::newRow("ip4_00") << QString("127.0.0.1") << true << QString("127.0.0.1") << 4;
QTest::newRow("ip4_01") << QString("255.3.2.1") << true << QString("255.3.2.1") << 4;
QTest::newRow("ip4_03") << QString(" 255.3.2.1") << true << QString("255.3.2.1") << 4;
QTest::newRow("ip4_04") << QString("255.3.2.1\r ") << true << QString("255.3.2.1") << 4;
QTest::newRow("ip4_05") << QString("0.0.0.0") << true << QString("0.0.0.0") << 4;
QTest::newRow("ip4_06") << QString("123.0.0") << true << QString("123.0.0.0") << 4;
// for the format of IPv6 addresses see also RFC 5952
// rule 4.1: Leading zeros MUST be suppressed
// rule 4.2.1: Shorten as Much as Possible
// rule 4.2.2: The symbol "::" MUST NOT be used to shorten just one 16-bit 0 field.
// rule 4.2.3: the longest run of consecutive 16-bit 0 fields MUST be shortened
// When the length of the consecutive 16-bit 0 fields, the first sequence
// of zero bits MUST be shortened
// rule 4.3: The characters "a", "b", "c", "d", "e", and "f" in an IPv6 address
// MUST be represented in lowercase
QTest::newRow("ip6_00") << QString("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210") << true << QString("fedc:ba98:7654:3210:fedc:ba98:7654:3210") << 6; // 4.3
QTest::newRow("ip6_01") << QString("1080:0000:0000:0000:0008:0800:200C:417A") << true << QString("1080::8:800:200c:417a") << 6; // 4.1, 4.2.1
QTest::newRow("ip6_02") << QString("1080:0:0:0:8:800:200C:417A") << true << QString("1080::8:800:200c:417a") << 6;
QTest::newRow("ip6_03") << QString("1080::8:800:200C:417A") << true << QString("1080::8:800:200c:417a") << 6;
QTest::newRow("ip6_04") << QString("FF01::43") << true << QString("ff01::43") << 6;
QTest::newRow("ip6_05") << QString("::1") << true << QString("::1") << 6;
QTest::newRow("ip6_06") << QString("1::") << true << QString("1::") << 6;
QTest::newRow("ip6_07") << QString("::") << true << QString("::") << 6;
QTest::newRow("ip6_08") << QString("0:0:0:0:0:0:13.1.68.3") << true << QString("::13.1.68.3") << 6;
QTest::newRow("ip6_09") << QString("::13.1.68.3") << true << QString("::13.1.68.3") << 6;
QTest::newRow("ip6_10") << QString("0:0:0:0:0:FFFF:129.144.52.38") << true << QString("::ffff:129.144.52.38") << 6;
QTest::newRow("ip6_11") << QString("::FFFF:129.144.52.38") << true << QString("::ffff:129.144.52.38") << 6;
QTest::newRow("ip6_12") << QString("1::FFFF:129.144.52.38") << true << QString("1::ffff:8190:3426") << 6;
QTest::newRow("ip6_13") << QString("A:B::D:E") << true << QString("a:b::d:e") << 6;
QTest::newRow("ip6_14") << QString("1080:0:1:0:8:800:200C:417A") << true << QString("1080:0:1:0:8:800:200c:417a") << 6; // 4.2.2
QTest::newRow("ip6_15") << QString("1080:0:1:0:8:800:200C:0") << true << QString("1080:0:1:0:8:800:200c:0") << 6;
QTest::newRow("ip6_16") << QString("1080:0:1:0:8:800:0:0") << true << QString("1080:0:1:0:8:800::") << 6;
QTest::newRow("ip6_17a") << QString("1080:0:0:8:800:0:0:0") << true << QString("1080:0:0:8:800::") << 6; // 4.2.3a
QTest::newRow("ip6_17b") << QString("1080:0:0:0:8:0:0:0") << true << QString("1080::8:0:0:0") << 6; // 4.2.3b
QTest::newRow("ip6_18") << QString("0:1:1:1:8:800:0:0") << true << QString("0:1:1:1:8:800::") << 6;
QTest::newRow("ip6_19") << QString("0:1:1:1:8:800:0:1") << true << QString("0:1:1:1:8:800:0:1") << 6;
QTest::newRow("error_00") << QString("foobarcom") << false << QString() << 0;
QTest::newRow("error_01") << QString("foo.bar.com") << false << QString() << 0;
QTest::newRow("error_02") << QString("") << false << QString() << 0;
QTest::newRow("error_03") << QString() << false << QString() << 0;
QTest::newRow("error_04") << QString(" \t\r") << false << QString() << 0;
QTest::newRow("error_ip4_00") << QString("256.9.9.9") << false << QString() << 0;
QTest::newRow("error_ip4_01") << QString("-1.9.9.9") << false << QString() << 0;
//QTest::newRow("error_ip4_02") << QString("123.0.0") << false << QString() << 0; // no longer invalid in Qt5
QTest::newRow("error_ip4_02") << QString("123.0.0.") << false << QString() << 0;
QTest::newRow("error_ip4_03") << QString("123.0.0.0.0") << false << QString() << 0;
QTest::newRow("error_ip4_04") << QString("255.2 3.2.1") << false << QString() << 0;
QTest::newRow("error_ip6_00") << QString(":") << false << QString() << 0;
QTest::newRow("error_ip6_01") << QString(":::") << false << QString() << 0;
QTest::newRow("error_ip6_02") << QString("::AAAA:") << false << QString() << 0;
QTest::newRow("error_ip6_03") << QString(":AAAA::") << false << QString() << 0;
QTest::newRow("error_ip6_04") << QString("FFFF:::129.144.52.38") << false << QString() << 0;
QTest::newRow("error_ip6_05") << QString("FEDC:BA98:7654:3210:FEDC:BA98:7654:3210:1234") << false << QString() << 0;
QTest::newRow("error_ip6_06") << QString("129.144.52.38::") << false << QString() << 0;
QTest::newRow("error_ip6_07") << QString("::129.144.52.38:129.144.52.38") << false << QString() << 0;
QTest::newRow("error_ip6_08") << QString(":::129.144.52.38") << false << QString() << 0;
QTest::newRow("error_ip6_09") << QString("1FEDC:BA98:7654:3210:FEDC:BA98:7654:3210") << false << QString() << 0;
QTest::newRow("error_ip6_10") << QString("::FFFFFFFF") << false << QString() << 0;
QTest::newRow("error_ip6_11") << QString("::EFGH") << false << QString() << 0;
QTest::newRow("error_ip6_12") << QString("ABCD:ABCD:ABCD") << false << QString() << 0;
QTest::newRow("error_ip6_13") << QString("::ABCD:ABCD::") << false << QString() << 0;
QTest::newRow("error_ip6_14") << QString("1::2::3") << false << QString() << 0;
QTest::newRow("error_ip6_15") << QString("1:2:::") << false << QString() << 0;
QTest::newRow("error_ip6_16") << QString(":::1:2") << false << QString() << 0;
QTest::newRow("error_ip6_17") << QString("1:::2") << false << QString() << 0;
QTest::newRow("error_ip6_18") << QString("FEDC::7654:3210:FEDC:BA98::3210") << false << QString() << 0;
QTest::newRow("error_ip6_19") << QString("ABCD:ABCD:ABCD:1.2.3.4") << false << QString() << 0;
QTest::newRow("error_ip6_20") << QString("ABCD::ABCD::ABCD:1.2.3.4") << false << QString() << 0;
}
void tst_QHostAddress::setAddress_QString()
{
QFETCH(QString, address);
QFETCH(bool, ok);
QFETCH(int, protocol);
QHostAddress hostAddr;
QCOMPARE(hostAddr.setAddress(address), ok);
if (ok)
QTEST(hostAddr.toString(), "resAddr");
if ( protocol == 4 ) {
QVERIFY( hostAddr.protocol() == QHostAddress::IPv4Protocol || hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol );
QVERIFY( hostAddr.protocol() != QHostAddress::IPv6Protocol );
} else if ( protocol == 6 ) {
QVERIFY( hostAddr.protocol() != QHostAddress::IPv4Protocol && hostAddr.protocol() != QHostAddress::UnknownNetworkLayerProtocol );
QVERIFY( hostAddr.protocol() == QHostAddress::IPv6Protocol );
} else {
QVERIFY( hostAddr.isNull() );
QVERIFY( hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol );
}
}
void tst_QHostAddress::specialAddresses_data()
{
QTest::addColumn<QString>("text");
QTest::addColumn<QHostAddress::SpecialAddress>("address");
QTest::addColumn<bool>("result");
QTest::newRow("localhost_1") << QString("127.0.0.1") << QHostAddress::LocalHost << true;
QTest::newRow("localhost_2") << QString("127.0.0.2") << QHostAddress::LocalHost << false;
QTest::newRow("localhost_3") << QString("127.0.0.2") << QHostAddress::LocalHostIPv6 << false;
QTest::newRow("localhost_ipv6_4") << QString("::1") << QHostAddress::LocalHostIPv6 << true;
QTest::newRow("localhost_ipv6_5") << QString("::2") << QHostAddress::LocalHostIPv6 << false;
QTest::newRow("localhost_ipv6_6") << QString("::1") << QHostAddress::LocalHost << false;
QTest::newRow("null_1") << QString("") << QHostAddress::Null << true;
QTest::newRow("null_2") << QString("bjarne") << QHostAddress::Null << true;
QTest::newRow("compare_from_null") << QString("") << QHostAddress::Broadcast << false;
QTest::newRow("broadcast_1") << QString("255.255.255.255") << QHostAddress::Any << false;
QTest::newRow("broadcast_2") << QString("255.255.255.255") << QHostAddress::Broadcast << true;
QTest::newRow("any_ipv6") << QString("::") << QHostAddress::AnyIPv6 << true;
QTest::newRow("any_ipv4") << QString("0.0.0.0") << QHostAddress::AnyIPv4 << true;
QTest::newRow("dual_not_ipv6") << QString("::") << QHostAddress::Any << false;
QTest::newRow("dual_not_ipv4") << QString("0.0.0.0") << QHostAddress::Any << false;
}
void tst_QHostAddress::specialAddresses()
{
QFETCH(QString, text);
QFETCH(QHostAddress::SpecialAddress, address);
QFETCH(bool, result);
QCOMPARE(QHostAddress(text) == address, result);
//check special address equal to itself (QTBUG-22898), note two overloads of operator==
QVERIFY(QHostAddress(address) == QHostAddress(address));
QVERIFY(QHostAddress(address) == address);
QVERIFY(address == QHostAddress(address));
QVERIFY(!(QHostAddress(address) != QHostAddress(address)));
QVERIFY(!(QHostAddress(address) != address));
QVERIFY(!(address != QHostAddress(address)));
{
QHostAddress ha;
ha.setAddress(address);
QVERIFY(ha == address);
}
QHostAddress setter;
setter.setAddress(text);
QCOMPARE(setter == address, result);
}
void tst_QHostAddress::compare_data()
{
QTest::addColumn<QHostAddress>("first");
QTest::addColumn<QHostAddress>("second");
QTest::addColumn<bool>("result");
QTest::newRow("1") << QHostAddress() << QHostAddress() << true;
QTest::newRow("2") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::Any) << true;
QTest::newRow("3") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv6) << true;
QTest::newRow("4") << QHostAddress(QHostAddress::Broadcast) << QHostAddress(QHostAddress::Broadcast) << true;
QTest::newRow("5") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::Broadcast) << false;
QTest::newRow("6") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << false;
QTest::newRow("7") << QHostAddress() << QHostAddress(QHostAddress::LocalHostIPv6) << false;
QTest::newRow("any4-any6") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress(QHostAddress::AnyIPv6) << false;
Q_IPV6ADDR localhostv4mapped = { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1 } };
QTest::newRow("v4-v4mapped") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("::ffff:127.0.0.1") << false;
QTest::newRow("v4-v4mapped-2") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(localhostv4mapped) << false;
}
void tst_QHostAddress::compare()
{
QFETCH(QHostAddress, first);
QFETCH(QHostAddress, second);
QFETCH(bool, result);
QCOMPARE(first == second, result);
QCOMPARE(second == first, result);
if (result == true)
QCOMPARE(qHash(first), qHash(second));
}
void tst_QHostAddress::isEqual_data()
{
QTest::addColumn<QHostAddress>("first");
QTest::addColumn<QHostAddress>("second");
QTest::addColumn<int>("flags");
QTest::addColumn<bool>("result");
// QHostAddress::StrictConversion is already tested in compare()
QTest::newRow("localhost4to6-local") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertLocalHost << true;
QTest::newRow("localhost4to6-compat") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertV4CompatToIPv4 << false;
QTest::newRow("localhost4to6-mapped") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertV4MappedToIPv4 << false;
QTest::newRow("localhost4to6-unspec") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertUnspecifiedAddress << false;
QTest::newRow("0.0.0.1-::1-local") << QHostAddress("0.0.0.1") << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertLocalHost << false;
QTest::newRow("v4-v4compat-local") << QHostAddress("192.168.1.1") << QHostAddress("::192.168.1.1") << (int)QHostAddress::ConvertLocalHost << false;
QTest::newRow("v4-v4mapped-local") << QHostAddress("192.168.1.1") << QHostAddress("::ffff:192.168.1.1") << (int)QHostAddress::ConvertLocalHost << false;
QTest::newRow("0.0.0.1-::1-unspec") << QHostAddress("0.0.0.1") << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertUnspecifiedAddress << false;
QTest::newRow("v4-v4compat-unspec") << QHostAddress("192.168.1.1") << QHostAddress("::192.168.1.1") << (int)QHostAddress::ConvertUnspecifiedAddress << false;
QTest::newRow("v4-v4mapped-unspec") << QHostAddress("192.168.1.1") << QHostAddress("::ffff:192.168.1.1") << (int)QHostAddress::ConvertUnspecifiedAddress << false;
QTest::newRow("0.0.0.1-::1-compat") << QHostAddress("0.0.0.1") << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertV4CompatToIPv4 << false;
QTest::newRow("v4-v4compat-compat") << QHostAddress("192.168.1.1") << QHostAddress("::192.168.1.1") << (int)QHostAddress::ConvertV4CompatToIPv4 << true;
QTest::newRow("v4-v4mapped-compat") << QHostAddress("192.168.1.1") << QHostAddress("::ffff:192.168.1.1") << (int)QHostAddress::ConvertV4CompatToIPv4 << false;
QTest::newRow("0.0.0.1-::1-mapped") << QHostAddress("0.0.0.1") << QHostAddress(QHostAddress::LocalHostIPv6) << (int)QHostAddress::ConvertV4MappedToIPv4 << false;
QTest::newRow("v4-v4compat-mapped") << QHostAddress("192.168.1.1") << QHostAddress("::192.168.1.1") << (int)QHostAddress::ConvertV4MappedToIPv4 << false;
QTest::newRow("v4-v4mapped-mapped") << QHostAddress("192.168.1.1") << QHostAddress("::FFFF:192.168.1.1") << (int)QHostAddress::ConvertV4MappedToIPv4 << true;
QTest::newRow("undef-any-local") << QHostAddress() << QHostAddress(QHostAddress::Any) << (int)QHostAddress::ConvertLocalHost << false;
QTest::newRow("undef-any-unspec") << QHostAddress() << QHostAddress(QHostAddress::Any) << (int)QHostAddress::ConvertUnspecifiedAddress << false;
QTest::newRow("anyv6-anyv4-compat") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertV4CompatToIPv4 << true;
QTest::newRow("anyv6-anyv4-mapped") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertV4MappedToIPv4 << false;
QTest::newRow("anyv6-anyv4-unspec") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertUnspecifiedAddress << true;
QTest::newRow("any-anyv4-unspec") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertUnspecifiedAddress << true;
QTest::newRow("any-anyv6-unspec") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv6) << (int)QHostAddress::ConvertUnspecifiedAddress << true;
QTest::newRow("anyv6-anyv4-local") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertLocalHost << false;
QTest::newRow("any-anyv4-local") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::ConvertLocalHost << false;
QTest::newRow("any-anyv6-local") << QHostAddress(QHostAddress::Any) << QHostAddress(QHostAddress::AnyIPv6) << (int)QHostAddress::ConvertLocalHost << false;
QTest::newRow("localhostv6-any-tolerant") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::Any) << (int)QHostAddress::TolerantConversion << false;
QTest::newRow("localhostv4-any-tolerant") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::Any) << (int)QHostAddress::TolerantConversion << false;
QTest::newRow("localhostv6-anyv6-tolerant") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::AnyIPv6) << (int)QHostAddress::TolerantConversion << false;
QTest::newRow("localhostv4-anyv6-tolerant") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::AnyIPv6) << (int)QHostAddress::TolerantConversion << false;
QTest::newRow("localhostv6-anyv4-tolerant") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::TolerantConversion << false;
QTest::newRow("localhostv4-anyv4-tolerant") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::AnyIPv4) << (int)QHostAddress::TolerantConversion << false;
}
void tst_QHostAddress::isEqual()
{
QFETCH(QHostAddress, first);
QFETCH(QHostAddress, second);
QFETCH(int, flags);
QFETCH(bool, result);
QCOMPARE(first.isEqual(second, QHostAddress::ConversionModeFlag(flags)), result);
QCOMPARE(second.isEqual(first, QHostAddress::ConversionModeFlag(flags)), result);
}
void tst_QHostAddress::assignment()
{
QHostAddress address;
QHostAddress addr("4.2.2.1");
sockaddr_in sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = htonl(addr.toIPv4Address());
address.setAddress((sockaddr *)&sockAddr);
QCOMPARE(address, addr);
}
void tst_QHostAddress::scopeId()
{
QHostAddress address("fe80::2e0:4cff:fefb:662a%eth0");
QCOMPARE(address.scopeId(), QString("eth0"));
QCOMPARE(address.toString().toLower(), QString("fe80::2e0:4cff:fefb:662a%eth0"));
QHostAddress address2("fe80::2e0:4cff:fefb:662a");
QCOMPARE(address2.scopeId(), QString());
address2.setScopeId(QString("en0"));
QCOMPARE(address2.toString().toLower(), QString("fe80::2e0:4cff:fefb:662a%en0"));
address2 = address;
QCOMPARE(address2.scopeId(), QString("eth0"));
QCOMPARE(address2.toString().toLower(), QString("fe80::2e0:4cff:fefb:662a%eth0"));
}
void tst_QHostAddress::hashKey()
{
QHash<QHostAddress, QString> hostHash;
hostHash.insert(QHostAddress(), "ole");
}
void tst_QHostAddress::streaming_data()
{
QTest::addColumn<QHostAddress>("address");
QTest::newRow("1") << QHostAddress();
QTest::newRow("2") << QHostAddress(0xDEADBEEF);
QTest::newRow("3") << QHostAddress("127.128.129.130");
QTest::newRow("4") << QHostAddress("1080:0000:0000:0000:0008:0800:200C:417A");
QTest::newRow("5") << QHostAddress("fe80::2e0:4cff:fefb:662a%eth0");
QTest::newRow("6") << QHostAddress(QHostAddress::Null);
QTest::newRow("7") << QHostAddress(QHostAddress::LocalHost);
QTest::newRow("8") << QHostAddress(QHostAddress::LocalHostIPv6);
QTest::newRow("9") << QHostAddress(QHostAddress::Broadcast);
QTest::newRow("10") << QHostAddress(QHostAddress::Any);
QTest::newRow("11") << QHostAddress(QHostAddress::AnyIPv4);
QTest::newRow("12") << QHostAddress(QHostAddress::AnyIPv6);
QTest::newRow("13") << QHostAddress("foo.bar.com");
}
void tst_QHostAddress::streaming()
{
QFETCH(QHostAddress, address);
QByteArray ba;
QDataStream ds1(&ba, QIODevice::WriteOnly);
ds1 << address;
QCOMPARE(ds1.status(), QDataStream::Ok);
QDataStream ds2(&ba, QIODevice::ReadOnly);
QHostAddress address2;
ds2 >> address2;
QCOMPARE(ds2.status(), QDataStream::Ok);
QCOMPARE(address, address2);
}
void tst_QHostAddress::parseSubnet_data()
{
QTest::addColumn<QString>("subnet");
QTest::addColumn<QHostAddress>("prefix");
QTest::addColumn<int>("prefixLength");
// invalid/error values
QTest::newRow("empty") << QString() << QHostAddress() << -1;
QTest::newRow("invalid_01") << "foobar" << QHostAddress() << -1;
QTest::newRow("invalid_02") << " " << QHostAddress() << -1;
QTest::newRow("invalid_03") << "1.2.3.a" << QHostAddress() << -1;
QTest::newRow("invalid_04") << "1.2.3.4.5" << QHostAddress() << -1;
QTest::newRow("invalid_05") << "1.2.3.4:80" << QHostAddress() << -1;
QTest::newRow("invalid_06") << "1.2.3.4/33" << QHostAddress() << -1;
QTest::newRow("invalid_07") << "1.2.3.4/-1" << QHostAddress() << -1;
QTest::newRow("invalid_08") << "1.2.3.4/256.0.0.0" << QHostAddress() << -1;
QTest::newRow("invalid_09") << "1.2.3.4/255.253.0.0" << QHostAddress() << -1;
QTest::newRow("invalid_10") << "1.2.3.4/255.0.0.255" << QHostAddress() << -1;
QTest::newRow("invalid_11") << "1.2.3.4." << QHostAddress() << -1;
QTest::newRow("invalid_20") << "ffff::/-1" << QHostAddress() << -1;
QTest::newRow("invalid_21") << "ffff::/129" << QHostAddress() << -1;
QTest::newRow("invalid_22") << "ffff::/255.255.0.0" << QHostAddress() << -1;
QTest::newRow("invalid_23") << "ffff::/ff00::" << QHostAddress() << -1;
// correct IPv4 with netmask
QTest::newRow("netmask_0") << "0.0.0.0/0.0.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 0;
QTest::newRow("netmask_1") << "0.0.0.0/255.128.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 9;
QTest::newRow("netmask_2") << "0.0.0.0/255.192.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 10;
QTest::newRow("netmask_3") << "0.0.0.0/255.224.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 11;
QTest::newRow("netmask_4") << "0.0.0.0/255.240.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 12;
QTest::newRow("netmask_5") << "0.0.0.0/255.248.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 13;
QTest::newRow("netmask_6") << "0.0.0.0/255.252.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 14;
QTest::newRow("netmask_7") << "0.0.0.0/255.254.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 15;
QTest::newRow("netmask_8") << "0.0.0.0/255.255.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 16;
QTest::newRow("netmask_16") << "0.0.0.0/255.255.0.0" << QHostAddress(QHostAddress::AnyIPv4) << 16;
QTest::newRow("netmask_24") << "0.0.0.0/255.255.255.0" << QHostAddress(QHostAddress::AnyIPv4) << 24;
QTest::newRow("netmask_31") << "0.0.0.0/255.255.255.254" << QHostAddress(QHostAddress::AnyIPv4) << 31;
QTest::newRow("netmask_32") << "0.0.0.0/255.255.255.255" << QHostAddress(QHostAddress::AnyIPv4) << 32;
// correct IPv4 with prefix
QTest::newRow("prefix_0") << "0.0.0.0/0" << QHostAddress(QHostAddress::AnyIPv4) << 0;
QTest::newRow("prefix_1") << "0.0.0.0/1" << QHostAddress(QHostAddress::AnyIPv4) << 1;
QTest::newRow("prefix_9") << "0.0.0.0/9" << QHostAddress(QHostAddress::AnyIPv4) << 9;
QTest::newRow("prefix_31") << "0.0.0.0/31" << QHostAddress(QHostAddress::AnyIPv4) << 31;
QTest::newRow("prefix_32") << "0.0.0.0/32" << QHostAddress(QHostAddress::AnyIPv4) << 32;
// correct IPv4 without prefix or netmask
QTest::newRow("classA") << "10" << QHostAddress("10.0.0.0") << 8;
QTest::newRow("classA+dot") << "10." << QHostAddress("10.0.0.0") << 8;
QTest::newRow("classB") << "172.16" << QHostAddress("172.16.0.0") << 16;
QTest::newRow("classB+dot") << "172.16." << QHostAddress("172.16.0.0") << 16;
QTest::newRow("classC") << "192.168.0" << QHostAddress("192.168.0.0") << 24;
QTest::newRow("classC+dot") << "192.168.0" << QHostAddress("192.168.0.0") << 24;
QTest::newRow("full-ipv4") << "192.168.0.1" << QHostAddress("192.168.0.1") << 32;
// correct IPv6 with prefix
QTest::newRow("ipv6_01") << "::/0" << QHostAddress(QHostAddress::AnyIPv6) << 0;
QTest::newRow("ipv6_03") << "::/3" << QHostAddress(QHostAddress::AnyIPv6) << 3;
QTest::newRow("ipv6_16") << "::/16" << QHostAddress(QHostAddress::AnyIPv6) << 16;
QTest::newRow("ipv6_48") << "::/48" << QHostAddress(QHostAddress::AnyIPv6) << 48;
QTest::newRow("ipv6_127") << "::/127" << QHostAddress(QHostAddress::AnyIPv6) << 127;
QTest::newRow("ipv6_128") << "::/128" << QHostAddress(QHostAddress::AnyIPv6) << 128;
// tail bit clearing:
QTest::newRow("clear_01") << "255.255.255.255/31" << QHostAddress("255.255.255.254") << 31;
QTest::newRow("clear_08") << "255.255.255.255/24" << QHostAddress("255.255.255.0") << 24;
QTest::newRow("clear_09") << "255.255.255.255/23" << QHostAddress("255.255.254.0") << 23;
QTest::newRow("clear_10") << "255.255.255.255/22" << QHostAddress("255.255.252.0") << 22;
QTest::newRow("clear_11") << "255.255.255.255/21" << QHostAddress("255.255.248.0") << 21;
QTest::newRow("clear_12") << "255.255.255.255/20" << QHostAddress("255.255.240.0") << 20;
QTest::newRow("clear_13") << "255.255.255.255/19" << QHostAddress("255.255.224.0") << 19;
QTest::newRow("clear_14") << "255.255.255.255/18" << QHostAddress("255.255.192.0") << 18;
QTest::newRow("clear_15") << "255.255.255.255/17" << QHostAddress("255.255.128.0") << 17;
QTest::newRow("clear_16") << "255.255.255.255/16" << QHostAddress("255.255.0.0") << 16;
QTest::newRow("clear_24") << "255.255.255.255/8" << QHostAddress("255.0.0.0") << 8;
QTest::newRow("clear_31") << "255.255.255.255/1" << QHostAddress("128.0.0.0") << 1;
QTest::newRow("clear_32") << "255.255.255.255/0" << QHostAddress("0.0.0.0") << 0;
// same for IPv6:
QTest::newRow("ipv6_clear_01") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/127"
<< QHostAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffe")
<< 127;
QTest::newRow("ipv6_clear_07") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/121"
<< QHostAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff80")
<< 121;
QTest::newRow("ipv6_clear_08") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/120"
<< QHostAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ff00")
<< 120;
QTest::newRow("ipv6_clear_16") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/112"
<< QHostAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0")
<< 112;
QTest::newRow("ipv6_clear_80") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/48"
<< QHostAddress("ffff:ffff:ffff::")
<< 48;
QTest::newRow("ipv6_clear_81") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/47"
<< QHostAddress("ffff:ffff:fffe::")
<< 47;
QTest::newRow("ipv6_clear_82") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/46"
<< QHostAddress("ffff:ffff:fffc::")
<< 46;
QTest::newRow("ipv6_clear_83") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/45"
<< QHostAddress("ffff:ffff:fff8::")
<< 45;
QTest::newRow("ipv6_clear_84") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/44"
<< QHostAddress("ffff:ffff:fff0::")
<< 44;
QTest::newRow("ipv6_clear_85") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/43"
<< QHostAddress("ffff:ffff:ffe0::")
<< 43;
QTest::newRow("ipv6_clear_86") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/42"
<< QHostAddress("ffff:ffff:ffc0::")
<< 42;
QTest::newRow("ipv6_clear_87") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/41"
<< QHostAddress("ffff:ffff:ff80::")
<< 41;
QTest::newRow("ipv6_clear_88") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/40"
<< QHostAddress("ffff:ffff:ff00::")
<< 40;
QTest::newRow("ipv6_clear_125") << "3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/3"
<< QHostAddress("2000::")
<< 3;
QTest::newRow("ipv6_clear_127") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/1"
<< QHostAddress("8000::")
<< 1;
QTest::newRow("ipv6_clear_128") << "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/0"
<< QHostAddress(QHostAddress::AnyIPv6)
<< 0;
}
void tst_QHostAddress::parseSubnet()
{
QFETCH(QString, subnet);
QFETCH(QHostAddress, prefix);
QFETCH(int, prefixLength);
QPair<QHostAddress, int> result = QHostAddress::parseSubnet(subnet);
QCOMPARE(result.first, prefix);
QCOMPARE(result.second, prefixLength);
}
void tst_QHostAddress::isInSubnet_data()
{
QTest::addColumn<QHostAddress>("address");
QTest::addColumn<QHostAddress>("prefix");
QTest::addColumn<int>("prefixLength");
QTest::addColumn<bool>("result");
// invalid QHostAddresses are never in any subnets
QTest::newRow("invalid_01") << QHostAddress() << QHostAddress() << 32 << false;
QTest::newRow("invalid_02") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv4) << 32 << false;
QTest::newRow("invalid_03") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv4) << 8 << false;
QTest::newRow("invalid_04") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv4) << 0 << false;
QTest::newRow("invalid_05") << QHostAddress() << QHostAddress("255.255.255.0") << 24 << false;
QTest::newRow("invalid_06") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv6) << 0 << false;
QTest::newRow("invalid_07") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv6) << 32 << false;
QTest::newRow("invalid_08") << QHostAddress() << QHostAddress(QHostAddress::AnyIPv6) << 128<< false;
// and no host address can be in a subnet whose prefix is invalid
QTest::newRow("invalid_20") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress() << 16 << false;
QTest::newRow("invalid_21") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress() << 16 << false;
QTest::newRow("invalid_22") << QHostAddress(QHostAddress::LocalHost) << QHostAddress() << 16 << false;
QTest::newRow("invalid_23") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress() << 16 << false;
// negative netmasks don't make sense:
QTest::newRow("invalid_30") << QHostAddress(QHostAddress::AnyIPv4) << QHostAddress(QHostAddress::Any) << -1 << false;
QTest::newRow("invalid_31") << QHostAddress(QHostAddress::AnyIPv6) << QHostAddress(QHostAddress::AnyIPv6) << -1 << false;
// we don't support IPv4 belonging in an IPv6 netmask and vice-versa
QTest::newRow("v4-in-v6") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::AnyIPv6) << 0 << false;
QTest::newRow("v6-in-v4") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::Any) << 0 << false;
QTest::newRow("v4-in-v6mapped") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("ffff:ffff:ffff:ffff:ffff:ffff:255.0.0.0") << 113 << false;
QTest::newRow("v4-in-v6mapped2") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("::ffff:255.0.0.0") << 113 << false;
// IPv4 correct ones
QTest::newRow("netmask_0") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::AnyIPv4) << 0 << true;
QTest::newRow("netmask_0bis") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("255.255.0.0") << 0 << true;
QTest::newRow("netmask_0ter") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("1.2.3.4") << 0 << true;
QTest::newRow("netmask_1") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::AnyIPv4) << 1 << true;
QTest::newRow("~netmask_1") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("128.0.0.0") << 1 << false;
QTest::newRow("netmask_1bis") << QHostAddress("224.0.0.1") << QHostAddress("128.0.0.0") << 1 << true;
QTest::newRow("~netmask_1bis") << QHostAddress("224.0.0.1") << QHostAddress("0.0.0.0") << 1 << false;
QTest::newRow("netmask_8") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("127.0.0.0") << 8 << true;
QTest::newRow("~netmask_8") << QHostAddress(QHostAddress::LocalHost) << QHostAddress("126.0.0.0") << 8 << false;
QTest::newRow("netmask_15") << QHostAddress("10.0.1.255") << QHostAddress("10.0.0.0") << 15 << true;
QTest::newRow("netmask_16") << QHostAddress("172.16.0.1") << QHostAddress("172.16.0.0") << 16 << true;
// the address is always in the subnet containing its address, regardless of length:
QTest::newRow("same_01") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHost) << 1 << true;
QTest::newRow("same_07") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHost) << 7 << true;
QTest::newRow("same_8") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHost) << 8 << true;
QTest::newRow("same_24") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHost) << 23 << true;
QTest::newRow("same_31") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHost) << 31 << true;
QTest::newRow("same_32") << QHostAddress(QHostAddress::LocalHost) << QHostAddress(QHostAddress::LocalHost) << 32 << true;
// IPv6 correct ones:
QTest::newRow("ipv6_netmask_0") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::AnyIPv6) << 0 << true;
QTest::newRow("ipv6_netmask_0bis") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::LocalHostIPv6) << 0 << true;
QTest::newRow("ipv6_netmask_0ter") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress("ffff::") << 0 << true;
QTest::newRow("ipv6_netmask_1") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress(QHostAddress::AnyIPv6) << 1 << true;
QTest::newRow("ipv6_netmask_1bis") << QHostAddress("fec0::1") << QHostAddress("8000::") << 1 << true;
QTest::newRow("~ipv6_netmask_1") << QHostAddress(QHostAddress::LocalHostIPv6) << QHostAddress("8000::") << 1 << false;
QTest::newRow("~ipv6_netmask_1bis") << QHostAddress("fec0::1") << QHostAddress("::") << 1 << false;
QTest::newRow("ipv6_netmask_47") << QHostAddress("2:3:5::1") << QHostAddress("2:3:4::") << 47 << true;
QTest::newRow("ipv6_netmask_48") << QHostAddress("2:3:4::1") << QHostAddress("2:3:4::") << 48 << true;
QTest::newRow("~ipv6_netmask_48") << QHostAddress("2:3:5::1") << QHostAddress("2:3:4::") << 48 << false;
QTest::newRow("ipv6_netmask_127") << QHostAddress("2:3:4:5::1") << QHostAddress("2:3:4:5::") << 127 << true;
QTest::newRow("ipv6_netmask_128") << QHostAddress("2:3:4:5::1") << QHostAddress("2:3:4:5::1") << 128 << true;
QTest::newRow("~ipv6_netmask_128") << QHostAddress("2:3:4:5::1") << QHostAddress("2:3:4:5::0") << 128 << false;
}
void tst_QHostAddress::isInSubnet()
{
QFETCH(QHostAddress, address);
QFETCH(QHostAddress, prefix);
QFETCH(int, prefixLength);
QTEST(address.isInSubnet(prefix, prefixLength), "result");
}
void tst_QHostAddress::classification_data()
{
QTest::addColumn<QHostAddress>("address");
QTest::addColumn<AddressClassification>("result");
QTest::newRow("default") << QHostAddress() << UnknownAddress;
QTest::newRow("invalid") << QHostAddress("&&&") << UnknownAddress;
QTest::newRow("Any") << QHostAddress(QHostAddress::Any) << LocalNetAddress;
QTest::newRow("Null") << QHostAddress(QHostAddress::Null) << UnknownAddress;
// IPv6 address space
auto addV6 = [](const char *str, AddressClassification cl) {
QTest::newRow(str) << QHostAddress(str) << cl;
};
QTest::newRow("AnyIPv6") << QHostAddress(QHostAddress::AnyIPv6) << LocalNetAddress;
QTest::newRow("ipv6_loop") << QHostAddress(QHostAddress::LocalHostIPv6) << LoopbackAddress;
addV6("::", LocalNetAddress);
addV6("::1", LoopbackAddress);
addV6("::2", GlobalAddress);
addV6("2000::", GlobalAddress);
addV6("3fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", GlobalAddress);
addV6("fbff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", GlobalAddress);
addV6("fc00::", UniqueLocalAddress);
addV6("fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", UniqueLocalAddress);
addV6("fe00::", UnknownAddress);
addV6("fe7f:ffff:ffff:ffff:ffff:ffff:ffff:ffff", UnknownAddress);
addV6("fe80::", LinkLocalAddress);
addV6("febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", LinkLocalAddress);
addV6("fec0::", SiteLocalAddress);
addV6("feff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", SiteLocalAddress);
addV6("ff00::", MulticastAddress);
addV6("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", MulticastAddress);
// IPv4 address space
auto addV4 = [](const char *str, AddressClassification cl) {
QTest::newRow(str) << QHostAddress(str) << cl;
QByteArray v6 = "::ffff:";
v6 += str;
QTest::newRow(v6.constData()) << QHostAddress(QString::fromLatin1(v6)) << cl;
};
QTest::newRow("AnyIPv4") << QHostAddress(QHostAddress::AnyIPv4) << LocalNetAddress;
QTest::newRow("ipv4_loop") << QHostAddress(QHostAddress::LocalHost) << LoopbackAddress;
QTest::newRow("Broadcast") << QHostAddress(QHostAddress::Broadcast) << BroadcastAddress;
addV4("0.0.0.0", LocalNetAddress);
addV4("0.0.0.1", LocalNetAddress);
addV4("0.255.255.255", LocalNetAddress);
addV4("1.0.0.0", GlobalAddress);
addV4("1.2.3.4", GlobalAddress);
addV4("10.0.0.4", PrivateNetworkAddress);
addV4("127.0.0.1", LoopbackAddress);
addV4("127.0.0.2", LoopbackAddress);
addV4("127.255.255.255", LoopbackAddress);
addV4("192.168.3.4", PrivateNetworkAddress);
addV4("223.255.255.255", GlobalAddress);
addV4("224.0.0.0", MulticastAddress);
addV4("239.255.255.255", MulticastAddress);
addV4("240.0.0.0", UnknownAddress);
addV4("255.255.255.254", UnknownAddress);
addV4("255.255.255.255", BroadcastAddress);
}
void tst_QHostAddress::classification()
{
QFETCH(QHostAddress, address);
QFETCH(AddressClassification, result);
bool isLoopback = (result == LoopbackAddress);
bool isGlobal = (result & GlobalAddress); // GlobalAddress is a bit
bool isLinkLocal = (result == LinkLocalAddress);
bool isSiteLocal = (result == SiteLocalAddress);
bool isUniqueLocalAddress = (result == UniqueLocalAddress);
bool isMulticast = (result == MulticastAddress);
bool isBroadcast = (result == BroadcastAddress);
QCOMPARE(address.isLoopback(), isLoopback);
QCOMPARE(address.isGlobal(), isGlobal);
QCOMPARE(address.isLinkLocal(), isLinkLocal);
QCOMPARE(address.isSiteLocal(), isSiteLocal);
QCOMPARE(address.isUniqueLocalUnicast(), isUniqueLocalAddress);
QCOMPARE(address.isMulticast(), isMulticast);
QCOMPARE(address.isBroadcast(), isBroadcast);
}
void tst_QHostAddress::convertv4v6_data()
{
QTest::addColumn<QHostAddress>("source");
QTest::addColumn<int>("protocol");
QTest::addColumn<QHostAddress>("result");
QTest::newRow("any-to-v4") << QHostAddress(QHostAddress::Any) << 4 << QHostAddress(QHostAddress::AnyIPv4);
QTest::newRow("any-to-v6") << QHostAddress(QHostAddress::Any) << 6 << QHostAddress(QHostAddress::AnyIPv6);
QTest::newRow("anyv4-to-v6") << QHostAddress(QHostAddress::AnyIPv4) << 6 << QHostAddress(QHostAddress::AnyIPv6);
QTest::newRow("anyv6-to-v4") << QHostAddress(QHostAddress::AnyIPv6) << 4 << QHostAddress(QHostAddress::AnyIPv4);
QTest::newRow("v4mapped-to-v4") << QHostAddress("::ffff:192.0.2.1") << 4 << QHostAddress("192.0.2.1");
QTest::newRow("v4-to-v4mapped") << QHostAddress("192.0.2.1") << 6 << QHostAddress("::ffff:192.0.2.1");
// we won't convert 127.0.0.1 to ::1 or vice-versa:
// you can connect to a v4 server socket with ::ffff:127.0.0.1, but not with ::1
QTest::newRow("localhost-to-v4mapped") << QHostAddress(QHostAddress::LocalHost) << 6 << QHostAddress("::ffff:127.0.0.1");
QTest::newRow("v4mapped-to-localhost") << QHostAddress("::ffff:127.0.0.1") << 4 << QHostAddress(QHostAddress::LocalHost);
// in turn, that means localhost6 doesn't convert to v4
QTest::newRow("localhost6-to-v4") << QHostAddress(QHostAddress::LocalHostIPv6) << 4 << QHostAddress();
// some other v6 addresses that won't convert to v4
QTest::newRow("v4compat-to-v4") << QHostAddress("::192.0.2.1") << 4 << QHostAddress();
QTest::newRow("localhostv4compat-to-v4") << QHostAddress("::127.0.0.1") << 4 << QHostAddress();
QTest::newRow("v6global-to-v4") << QHostAddress("2001:db8::1") << 4 << QHostAddress();
QTest::newRow("v6multicast-to-v4") << QHostAddress("ff02::1") << 4 << QHostAddress();
}
void tst_QHostAddress::convertv4v6()
{
QFETCH(QHostAddress, source);
QFETCH(int, protocol);
QFETCH(QHostAddress, result);
if (protocol == 4) {
bool ok;
quint32 v4 = source.toIPv4Address(&ok);
QCOMPARE(ok, result.protocol() == QHostAddress::IPv4Protocol);
if (ok)
QCOMPARE(QHostAddress(v4), result);
} else if (protocol == 6) {
QCOMPARE(QHostAddress(source.toIPv6Address()), result);
}
}
QTEST_MAIN(tst_QHostAddress)
#include "tst_qhostaddress.moc"

View File

@ -0,0 +1,6 @@
# These tests fail due to a DNS server issue
# (this is not a Qt bug)
[lookupIPv6:a-plus-aaaa]
windows ci
[blockingLookup:a-plus-aaaa]
windows ci

View File

@ -0,0 +1,26 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
if(NOT QT_FEATURE_private_tests)
return()
endif()
#####################################################################
## tst_qhostinfo Test:
#####################################################################
qt_internal_add_test(tst_qhostinfo
SOURCES
tst_qhostinfo.cpp
LIBRARIES
Qt::CorePrivate
Qt::NetworkPrivate
)
## Scopes:
#####################################################################
qt_internal_extend_target(tst_qhostinfo CONDITION WIN32
LIBRARIES
ws2_32
)

View File

@ -0,0 +1,713 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
// When using WinSock2 on Windows, it's the first thing that can be included
// (except qglobal.h), or else you'll get tons of compile errors
#include <qglobal.h>
// To prevent windows system header files from re-defining min/max
#define NOMINMAX 1
#if defined(Q_OS_WIN)
# include <winsock2.h>
# include <ws2tcpip.h>
#endif
#include <QTest>
#include <QTestEventLoop>
#include <QProcess>
#include <QCoreApplication>
#include <QDebug>
#include <QTcpSocket>
#include <QTcpServer>
#include <private/qthread_p.h>
#include <time.h>
#if defined(Q_OS_WIN)
#include <qt_windows.h>
#else
#include <unistd.h>
#include <signal.h>
#endif
#include <qhostinfo.h>
#include "private/qhostinfo_p.h"
#include <sys/types.h>
#if defined(Q_OS_UNIX)
# include <sys/socket.h>
# include <netdb.h>
#endif
#include "../../../network-settings.h"
#define TEST_DOMAIN ".test.qt-project.org"
class tst_QHostInfo : public QObject
{
Q_OBJECT
private slots:
void init();
void initTestCase();
void swapFunction();
void moveOperator();
void getSetCheck();
void staticInformation();
void lookupIPv4_data();
void lookupIPv4();
void lookupIPv6_data();
void lookupIPv6();
void lookupConnectToFunctionPointer_data();
void lookupConnectToFunctionPointer();
void lookupConnectToFunctionPointerDeleted();
void lookupConnectToLambda_data();
void lookupConnectToLambda();
void reverseLookup_data();
void reverseLookup();
void blockingLookup_data();
void blockingLookup();
void raceCondition();
void threadSafety();
void threadSafetyAsynchronousAPI();
void multipleSameLookups();
void multipleDifferentLookups_data();
void multipleDifferentLookups();
void cache();
void abortHostLookup();
protected slots:
void resultsReady(const QHostInfo &);
private:
bool ipv6LookupsAvailable;
bool ipv6Available;
bool lookupDone;
int lookupsDoneCounter;
QHostInfo lookupResults;
};
void tst_QHostInfo::swapFunction()
{
QHostInfo obj1, obj2;
obj1.setError(QHostInfo::HostInfoError(0));
obj2.setError(QHostInfo::HostInfoError(1));
obj1.swap(obj2);
QCOMPARE(QHostInfo::HostInfoError(0), obj2.error());
QCOMPARE(QHostInfo::HostInfoError(1), obj1.error());
}
void tst_QHostInfo::moveOperator()
{
QHostInfo obj1, obj2, obj3(1);
obj1.setError(QHostInfo::HostInfoError(0));
obj2.setError(QHostInfo::HostInfoError(1));
obj1 = std::move(obj2);
obj2 = obj3;
QCOMPARE(QHostInfo::HostInfoError(1), obj1.error());
QCOMPARE(obj3.lookupId(), obj2.lookupId());
}
// Testing get/set functions
void tst_QHostInfo::getSetCheck()
{
QHostInfo obj1;
// HostInfoError QHostInfo::error()
// void QHostInfo::setError(HostInfoError)
obj1.setError(QHostInfo::HostInfoError(0));
QCOMPARE(QHostInfo::HostInfoError(0), obj1.error());
obj1.setError(QHostInfo::HostInfoError(1));
QCOMPARE(QHostInfo::HostInfoError(1), obj1.error());
// int QHostInfo::lookupId()
// void QHostInfo::setLookupId(int)
obj1.setLookupId(0);
QCOMPARE(0, obj1.lookupId());
obj1.setLookupId(INT_MIN);
QCOMPARE(INT_MIN, obj1.lookupId());
obj1.setLookupId(INT_MAX);
QCOMPARE(INT_MAX, obj1.lookupId());
}
void tst_QHostInfo::staticInformation()
{
qDebug() << "Hostname:" << QHostInfo::localHostName();
qDebug() << "Domain name:" << QHostInfo::localDomainName();
}
void tst_QHostInfo::initTestCase()
{
ipv6Available = false;
ipv6LookupsAvailable = false;
QTcpServer server;
if (server.listen(QHostAddress("::1"))) {
// We have IPv6 support
ipv6Available = true;
}
// check if the system getaddrinfo can do IPv6 lookups
struct addrinfo hint, *result = 0;
memset(&hint, 0, sizeof hint);
hint.ai_family = AF_UNSPEC;
#ifdef AI_ADDRCONFIG
hint.ai_flags = AI_ADDRCONFIG;
#endif
int res = getaddrinfo("::1", "80", &hint, &result);
if (res == 0) {
// this test worked
freeaddrinfo(result);
res = getaddrinfo("aaaa-single" TEST_DOMAIN, "80", &hint, &result);
if (res == 0 && result != 0 && result->ai_family != AF_INET) {
freeaddrinfo(result);
ipv6LookupsAvailable = true;
}
}
// run each testcase with and without test enabled
QTest::addColumn<bool>("cache");
QTest::newRow("WithCache") << true;
QTest::newRow("WithoutCache") << false;
}
void tst_QHostInfo::init()
{
// delete the cache so inidividual testcase results are independent from each other
qt_qhostinfo_clear_cache();
QFETCH_GLOBAL(bool, cache);
qt_qhostinfo_enable_cache(cache);
}
void tst_QHostInfo::lookupIPv4_data()
{
QTest::addColumn<QString>("hostname");
QTest::addColumn<QString>("addresses");
QTest::addColumn<int>("err");
QTest::newRow("empty") << "" << "" << int(QHostInfo::HostNotFound);
QTest::newRow("single_ip4") << "a-single" TEST_DOMAIN << "192.0.2.1" << int(QHostInfo::NoError);
QTest::newRow("multiple_ip4") << "a-multi" TEST_DOMAIN << "192.0.2.1 192.0.2.2 192.0.2.3" << int(QHostInfo::NoError);
QTest::newRow("literal_ip4") << "192.0.2.1" << "192.0.2.1" << int(QHostInfo::NoError);
QTest::newRow("notfound") << "invalid" TEST_DOMAIN << "" << int(QHostInfo::HostNotFound);
QTest::newRow("idn-ace") << "a-single.xn--alqualond-34a" TEST_DOMAIN << "192.0.2.1" << int(QHostInfo::NoError);
QTest::newRow("idn-unicode") << QString::fromLatin1("a-single.alqualond\353" TEST_DOMAIN) << "192.0.2.1" << int(QHostInfo::NoError);
}
void tst_QHostInfo::lookupIPv4()
{
QFETCH(QString, hostname);
QFETCH(int, err);
QFETCH(QString, addresses);
lookupDone = false;
QHostInfo::lookupHost(hostname, this, SLOT(resultsReady(QHostInfo)));
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(lookupDone);
if ((int)lookupResults.error() != (int)err) {
qWarning() << hostname << "=>" << lookupResults.errorString();
}
QCOMPARE((int)lookupResults.error(), (int)err);
QStringList tmp;
for (int i = 0; i < lookupResults.addresses().size(); ++i)
tmp.append(lookupResults.addresses().at(i).toString());
tmp.sort();
QStringList expected = addresses.split(' ');
expected.sort();
QCOMPARE(tmp.join(' '), expected.join(' '));
}
void tst_QHostInfo::lookupIPv6_data()
{
QTest::addColumn<QString>("hostname");
QTest::addColumn<QString>("addresses");
QTest::addColumn<int>("err");
QTest::newRow("aaaa-single") << "aaaa-single" TEST_DOMAIN << "2001:db8::1" << int(QHostInfo::NoError);
QTest::newRow("aaaa-multi") << "aaaa-multi" TEST_DOMAIN << "2001:db8::1 2001:db8::2 2001:db8::3" << int(QHostInfo::NoError);
QTest::newRow("a-plus-aaaa") << "a-plus-aaaa" TEST_DOMAIN << "198.51.100.1 2001:db8::1:1" << int(QHostInfo::NoError);
// avoid using real IPv6 addresses here because this will do a DNS query
// real addresses are between 2000:: and 3fff:ffff:ffff:ffff:ffff:ffff:ffff
QTest::newRow("literal_ip6") << "f001:6b0:1:ea:202:a5ff:fecd:13a6" << "f001:6b0:1:ea:202:a5ff:fecd:13a6" << int(QHostInfo::NoError);
QTest::newRow("literal_shortip6") << "f001:618:1401::4" << "f001:618:1401::4" << int(QHostInfo::NoError);
}
void tst_QHostInfo::lookupIPv6()
{
QFETCH(QString, hostname);
QFETCH(int, err);
QFETCH(QString, addresses);
if (!ipv6LookupsAvailable)
QSKIP("This platform does not support IPv6 lookups");
lookupDone = false;
QHostInfo::lookupHost(hostname, this, SLOT(resultsReady(QHostInfo)));
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(lookupDone);
QCOMPARE((int)lookupResults.error(), (int)err);
QStringList tmp;
for (int i = 0; i < lookupResults.addresses().size(); ++i)
tmp.append(lookupResults.addresses().at(i).toString());
tmp.sort();
QStringList expected = addresses.split(' ');
expected.sort();
QCOMPARE(tmp.join(' ').toLower(), expected.join(' ').toLower());
}
void tst_QHostInfo::lookupConnectToFunctionPointer_data()
{
lookupIPv4_data();
}
void tst_QHostInfo::lookupConnectToFunctionPointer()
{
QFETCH(QString, hostname);
QFETCH(int, err);
QFETCH(QString, addresses);
lookupDone = false;
QHostInfo::lookupHost(hostname, this, &tst_QHostInfo::resultsReady);
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(lookupDone);
if (int(lookupResults.error()) != int(err))
qWarning() << hostname << "=>" << lookupResults.errorString();
QCOMPARE(int(lookupResults.error()), int(err));
QStringList tmp;
for (const auto &result : lookupResults.addresses())
tmp.append(result.toString());
tmp.sort();
QStringList expected = addresses.split(' ');
expected.sort();
QCOMPARE(tmp.join(' '), expected.join(' '));
}
void tst_QHostInfo::lookupConnectToFunctionPointerDeleted()
{
{
QObject contextObject;
QHostInfo::lookupHost("localhost", &contextObject, [](const QHostInfo){
QFAIL("This should never be called!");
});
}
QTestEventLoop::instance().enterLoop(3);
}
void tst_QHostInfo::lookupConnectToLambda_data()
{
lookupIPv4_data();
}
void tst_QHostInfo::lookupConnectToLambda()
{
QFETCH(QString, hostname);
QFETCH(int, err);
QFETCH(QString, addresses);
lookupDone = false;
QHostInfo::lookupHost(hostname, [this](const QHostInfo &hostInfo) {
resultsReady(hostInfo);
});
QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(lookupDone);
if (int(lookupResults.error()) != int(err))
qWarning() << hostname << "=>" << lookupResults.errorString();
QCOMPARE(int(lookupResults.error()), int(err));
QStringList tmp;
for (int i = 0; i < lookupResults.addresses().size(); ++i)
tmp.append(lookupResults.addresses().at(i).toString());
tmp.sort();
QStringList expected = addresses.split(' ');
expected.sort();
QCOMPARE(tmp.join(' '), expected.join(' '));
}
static QStringList reverseLookupHelper(const QString &ip)
{
QStringList results;
const QString pythonCode =
"import socket;"
"import sys;"
"print (socket.getnameinfo((sys.argv[1], 0), 0)[0]);";
QList<QByteArray> lines;
QProcess python;
python.setProcessChannelMode(QProcess::ForwardedErrorChannel);
python.start("python", QStringList() << QString("-c") << pythonCode << ip);
if (python.waitForFinished()) {
if (python.exitStatus() == QProcess::NormalExit && python.exitCode() == 0)
lines = python.readAllStandardOutput().split('\n');
for (QByteArray line : lines) {
if (!line.isEmpty())
results << line.trimmed();
}
if (!results.isEmpty())
return results;
}
qDebug() << "Python failed, falling back to nslookup";
QProcess lookup;
lookup.setProcessChannelMode(QProcess::ForwardedErrorChannel);
lookup.start("nslookup", QStringList(ip));
if (!lookup.waitForFinished()) {
results << "nslookup failure";
qDebug() << "nslookup failure";
return results;
}
lines = lookup.readAllStandardOutput().split('\n');
QByteArray name;
const QByteArray nameMarkerNix("name =");
const QByteArray nameMarkerWin("Name:");
const QByteArray addressMarkerWin("Address:");
for (QByteArray line : lines) {
int index = -1;
if ((index = line.indexOf(nameMarkerNix)) != -1) { // Linux and macOS
name = line.mid(index + nameMarkerNix.size()).chopped(1).trimmed();
results << name;
} else if (line.startsWith(nameMarkerWin)) { // Windows formatting
name = line.mid(line.lastIndexOf(" ")).trimmed();
} else if (line.startsWith(addressMarkerWin)) {
QByteArray address = line.mid(addressMarkerWin.size()).trimmed();
if (address == ip.toUtf8()) {
results << name;
}
}
}
if (results.isEmpty()) {
qDebug() << "Failure to parse nslookup output: " << lines;
}
return results;
}
void tst_QHostInfo::reverseLookup_data()
{
QTest::addColumn<QString>("address");
QTest::addColumn<QStringList>("hostNames");
QTest::addColumn<int>("err");
QTest::addColumn<bool>("ipv6");
QTest::newRow("dns.google") << QString("8.8.8.8") << reverseLookupHelper("8.8.8.8") << 0 << false;
QTest::newRow("one.one.one.one") << QString("1.1.1.1") << reverseLookupHelper("1.1.1.1") << 0 << false;
QTest::newRow("dns.google IPv6") << QString("2001:4860:4860::8888") << reverseLookupHelper("2001:4860:4860::8888") << 0 << true;
QTest::newRow("cloudflare IPv6") << QString("2606:4700:4700::1111") << reverseLookupHelper("2606:4700:4700::1111") << 0 << true;
QTest::newRow("bogus-name IPv6") << QString("1::2::3::4") << QStringList() << 1 << true;
}
void tst_QHostInfo::reverseLookup()
{
QFETCH(QString, address);
QFETCH(QStringList, hostNames);
QFETCH(int, err);
QFETCH(bool, ipv6);
if (ipv6 && !ipv6LookupsAvailable) {
QSKIP("IPv6 reverse lookups are not supported on this platform");
}
QHostInfo info = QHostInfo::fromName(address);
if (err == 0) {
if (!hostNames.contains(info.hostName()))
qDebug() << "Failure: expecting" << hostNames << ",got " << info.hostName();
QVERIFY(hostNames.contains(info.hostName()));
QCOMPARE(info.addresses().first(), QHostAddress(address));
} else {
QCOMPARE(info.hostName(), address);
QCOMPARE(info.error(), QHostInfo::HostNotFound);
}
}
void tst_QHostInfo::blockingLookup_data()
{
lookupIPv4_data();
if (ipv6LookupsAvailable)
lookupIPv6_data();
}
void tst_QHostInfo::blockingLookup()
{
QFETCH(QString, hostname);
QFETCH(int, err);
QFETCH(QString, addresses);
QHostInfo hostInfo = QHostInfo::fromName(hostname);
QStringList tmp;
for (int i = 0; i < hostInfo.addresses().size(); ++i)
tmp.append(hostInfo.addresses().at(i).toString());
tmp.sort();
if ((int)hostInfo.error() != (int)err) {
qWarning() << hostname << "=>" << lookupResults.errorString();
}
QCOMPARE((int)hostInfo.error(), (int)err);
QStringList expected = addresses.split(' ');
expected.sort();
QCOMPARE(tmp.join(' ').toUpper(), expected.join(' ').toUpper());
}
void tst_QHostInfo::raceCondition()
{
for (int i = 0; i < 1000; ++i) {
QTcpSocket socket;
socket.connectToHost("invalid" TEST_DOMAIN, 80);
}
}
class LookupThread : public QThread
{
protected:
inline void run() override
{
QHostInfo info = QHostInfo::fromName("a-single" TEST_DOMAIN);
QCOMPARE(info.error(), QHostInfo::NoError);
QVERIFY(info.addresses().size() > 0);
QCOMPARE(info.addresses().at(0).toString(), QString("192.0.2.1"));
}
};
void tst_QHostInfo::threadSafety()
{
const int nattempts = 5;
const int runs = 100;
LookupThread thr[nattempts];
for (int j = 0; j < runs; ++j) {
for (int i = 0; i < nattempts; ++i)
thr[i].start();
for (int k = nattempts - 1; k >= 0; --k)
thr[k].wait();
}
}
class LookupReceiver : public QObject
{
Q_OBJECT
public slots:
void start();
void resultsReady(const QHostInfo&);
public:
QHostInfo result;
int numrequests;
};
void LookupReceiver::start()
{
for (int i=0;i<numrequests;i++)
QHostInfo::lookupHost(QString("a-single" TEST_DOMAIN), this, SLOT(resultsReady(QHostInfo)));
}
void LookupReceiver::resultsReady(const QHostInfo &info)
{
result = info;
numrequests--;
if (numrequests == 0 || info.error() != QHostInfo::NoError)
QThread::currentThread()->quit();
}
void tst_QHostInfo::threadSafetyAsynchronousAPI()
{
const int nattempts = 10;
const int lookupsperthread = 10;
QList<QThread*> threads;
QList<LookupReceiver*> receivers;
for (int i = 0; i < nattempts; ++i) {
QThread* thread = new QThread;
LookupReceiver* receiver = new LookupReceiver;
receiver->numrequests = lookupsperthread;
receivers.append(receiver);
receiver->moveToThread(thread);
connect(thread, SIGNAL(started()), receiver, SLOT(start()));
thread->start();
threads.append(thread);
}
for (int k = threads.size() - 1; k >= 0; --k)
QVERIFY(threads.at(k)->wait(60000));
foreach (LookupReceiver* receiver, receivers) {
QCOMPARE(receiver->result.error(), QHostInfo::NoError);
QCOMPARE(receiver->result.addresses().at(0).toString(), QString("192.0.2.1"));
QCOMPARE(receiver->numrequests, 0);
}
}
// this test is for the multi-threaded QHostInfo rewrite. It is about getting results at all,
// not about getting correct IPs
void tst_QHostInfo::multipleSameLookups()
{
const int COUNT = 10;
lookupsDoneCounter = 0;
for (int i = 0; i < COUNT; i++)
QHostInfo::lookupHost("localhost", this, SLOT(resultsReady(QHostInfo)));
QElapsedTimer timer;
timer.start();
while (timer.elapsed() < 10000 && lookupsDoneCounter < COUNT) {
QTestEventLoop::instance().enterLoop(2);
}
QCOMPARE(lookupsDoneCounter, COUNT);
}
// this test is for the multi-threaded QHostInfo rewrite. It is about getting results at all,
// not about getting correct IPs
void tst_QHostInfo::multipleDifferentLookups_data()
{
QTest::addColumn<int>("repeats");
QTest::newRow("1") << 1;
QTest::newRow("2") << 2;
QTest::newRow("5") << 5;
QTest::newRow("10") << 10;
}
void tst_QHostInfo::multipleDifferentLookups()
{
QStringList hostnameList;
hostnameList << "a-single" TEST_DOMAIN
<< "a-multi" TEST_DOMAIN
<< "aaaa-single" TEST_DOMAIN
<< "aaaa-multi" TEST_DOMAIN
<< "a-plus-aaaa" TEST_DOMAIN
<< "multi" TEST_DOMAIN
<< "localhost" TEST_DOMAIN
<< "cname" TEST_DOMAIN
<< "127.0.0.1" << "----";
QFETCH(int, repeats);
const int COUNT = hostnameList.size();
lookupsDoneCounter = 0;
for (int i = 0; i < hostnameList.size(); i++)
for (int j = 0; j < repeats; ++j)
QHostInfo::lookupHost(hostnameList.at(i), this, SLOT(resultsReady(QHostInfo)));
QElapsedTimer timer;
timer.start();
while (timer.elapsed() < 60000 && lookupsDoneCounter < repeats*COUNT) {
QTestEventLoop::instance().enterLoop(2);
//qDebug() << "t:" << timer.elapsed();
}
QCOMPARE(lookupsDoneCounter, repeats*COUNT);
}
void tst_QHostInfo::cache()
{
QFETCH_GLOBAL(bool, cache);
if (!cache)
return; // test makes only sense when cache enabled
// reset slot counter
lookupsDoneCounter = 0;
// lookup once, wait in event loop, result should not come directly.
bool valid = true;
int id = -1;
QHostInfo result = qt_qhostinfo_lookup("localhost", this, SLOT(resultsReady(QHostInfo)), &valid, &id);
QTestEventLoop::instance().enterLoop(5);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(!valid);
QVERIFY(result.addresses().isEmpty());
// loopkup second time, result should come directly
valid = false;
result = qt_qhostinfo_lookup("localhost", this, SLOT(resultsReady(QHostInfo)), &valid, &id);
QVERIFY(valid);
QVERIFY(!result.addresses().isEmpty());
// clear the cache
qt_qhostinfo_clear_cache();
// lookup third time, result should not come directly.
valid = true;
result = qt_qhostinfo_lookup("localhost", this, SLOT(resultsReady(QHostInfo)), &valid, &id);
QTestEventLoop::instance().enterLoop(5);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(!valid);
QVERIFY(result.addresses().isEmpty());
// the slot should have been called 2 times.
QCOMPARE(lookupsDoneCounter, 2);
}
void tst_QHostInfo::resultsReady(const QHostInfo &hi)
{
QVERIFY(QThread::currentThread() == thread());
lookupDone = true;
lookupResults = hi;
lookupsDoneCounter++;
QTestEventLoop::instance().exitLoop();
}
void tst_QHostInfo::abortHostLookup()
{
//reset counter
lookupsDoneCounter = 0;
bool valid = false;
int id = -1;
QHostInfo result = qt_qhostinfo_lookup("a-single" TEST_DOMAIN, this, SLOT(resultsReady(QHostInfo)), &valid, &id);
QVERIFY(!valid);
//it is assumed that the DNS request/response in the backend is slower than it takes to call abort
QHostInfo::abortHostLookup(id);
QTestEventLoop::instance().enterLoop(5);
QCOMPARE(lookupsDoneCounter, 0);
}
class LookupAborter : public QObject
{
Q_OBJECT
public slots:
void abort()
{
QHostInfo::abortHostLookup(id);
QThread::currentThread()->quit();
}
public:
int id;
};
QTEST_MAIN(tst_QHostInfo)
#include "tst_qhostinfo.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qnetworkaddressentry Test:
#####################################################################
qt_internal_add_test(tst_qnetworkaddressentry
SOURCES
tst_qnetworkaddressentry.cpp
LIBRARIES
Qt::Network
)

View File

@ -0,0 +1,146 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qcoreapplication.h>
#include <qnetworkinterface.h>
Q_DECLARE_METATYPE(QHostAddress)
class tst_QNetworkAddressEntry: public QObject
{
Q_OBJECT
private slots:
void getSetCheck();
void prefixAndNetmask_data();
void prefixAndNetmask();
};
void tst_QNetworkAddressEntry::getSetCheck()
{
QNetworkAddressEntry entry;
QVERIFY(entry.ip().isNull());
QVERIFY(entry.netmask().isNull());
QVERIFY(entry.broadcast().isNull());
QCOMPARE(entry.prefixLength(), -1);
entry.setIp(QHostAddress::LocalHost);
QCOMPARE(entry.ip(), QHostAddress(QHostAddress::LocalHost));
entry.setIp(QHostAddress());
QVERIFY(entry.ip().isNull());
entry.setBroadcast(QHostAddress::LocalHost);
QCOMPARE(entry.broadcast(), QHostAddress(QHostAddress::LocalHost));
entry.setBroadcast(QHostAddress());
QVERIFY(entry.broadcast().isNull());
// netmask and prefix length tested in the next test
entry.setIp(QHostAddress::LocalHost);
entry.setBroadcast(QHostAddress::LocalHost);
QNetworkAddressEntry entry2;
QVERIFY(entry != entry2);
QVERIFY(!(entry == entry2));
entry = entry2;
QCOMPARE(entry, entry2);
QCOMPARE(entry, entry);
QVERIFY(!(entry != entry2));
}
void tst_QNetworkAddressEntry::prefixAndNetmask_data()
{
QTest::addColumn<QHostAddress>("ip");
QTest::addColumn<QHostAddress>("netmask");
QTest::addColumn<int>("prefix");
// IPv4 set:
QHostAddress ipv4(QHostAddress::LocalHost);
QTest::newRow("v4/0") << ipv4 << QHostAddress(QHostAddress::AnyIPv4) << 0;
QTest::newRow("v4/32") << ipv4 << QHostAddress("255.255.255.255") << 32;
QTest::newRow("v4/24") << ipv4 << QHostAddress("255.255.255.0") << 24;
QTest::newRow("v4/23") << ipv4 << QHostAddress("255.255.254.0") << 23;
QTest::newRow("v4/20") << ipv4 << QHostAddress("255.255.240.0") << 20;
QTest::newRow("v4/invalid1") << ipv4 << QHostAddress(QHostAddress::LocalHost) << -1;
QTest::newRow("v4/invalid2") << ipv4 << QHostAddress(QHostAddress::AnyIPv6) << -1;
QTest::newRow("v4/invalid3") << ipv4 << QHostAddress("255.255.253.0") << -1;
QTest::newRow("v4/invalid4") << ipv4 << QHostAddress() << -2;
QTest::newRow("v4/invalid5") << ipv4 << QHostAddress() << 33;
// IPv6 set:
QHostAddress ipv6(QHostAddress::LocalHostIPv6);
QTest::newRow("v6/0") << ipv6 << QHostAddress(QHostAddress::AnyIPv6) << 0;
QTest::newRow("v6/128") << ipv6 << QHostAddress("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") << 128;
QTest::newRow("v6/64") << ipv6 << QHostAddress("ffff:ffff:ffff:ffff::") << 64;
QTest::newRow("v6/63") << ipv6 << QHostAddress("ffff:ffff:ffff:fffe::") << 63;
QTest::newRow("v6/60") << ipv6 << QHostAddress("ffff:ffff:ffff:fff0::") << 60;
QTest::newRow("v6/48") << ipv6 << QHostAddress("ffff:ffff:ffff::") << 48;
QTest::newRow("v6/3") << ipv6 << QHostAddress("e000::") << 3;
QTest::newRow("v6/invalid1") << ipv6 << QHostAddress(QHostAddress::LocalHostIPv6) << -1;
QTest::newRow("v6/invalid2") << ipv6 << QHostAddress(QHostAddress::Any) << -1;
QTest::newRow("v6/invalid3") << ipv6 << QHostAddress("fffd::") << -1;
QTest::newRow("v6/invalid4") << ipv6 << QHostAddress() << -2;
QTest::newRow("v6/invalid5") << ipv6 << QHostAddress() << 129;
}
void tst_QNetworkAddressEntry::prefixAndNetmask()
{
QFETCH(QHostAddress, ip);
QFETCH(QHostAddress, netmask);
QFETCH(int, prefix);
QNetworkAddressEntry entry;
// first, without setting the IP, all must be invalid:
entry.setNetmask(netmask);
QVERIFY(entry.netmask().isNull());
entry.setPrefixLength(prefix);
QCOMPARE(entry.prefixLength(), -1);
// set the IP:
entry.setIp(ip);
// set the netmask:
if (!netmask.isNull()) {
entry.setNetmask(netmask);
// was it a valid one?
if (prefix != -1) {
QVERIFY(!entry.netmask().isNull());
QCOMPARE(entry.netmask(), netmask);
QCOMPARE(entry.prefixLength(), prefix);
} else {
// not valid
QVERIFY(entry.netmask().isNull());
QCOMPARE(entry.prefixLength(), -1);
}
}
entry.setNetmask(QHostAddress());
QVERIFY(entry.netmask().isNull());
QCOMPARE(entry.prefixLength(), -1);
// set the prefix
if (prefix != -1) {
entry.setPrefixLength(prefix);
// was it a valid one?
if (!netmask.isNull()) {
QVERIFY(!entry.netmask().isNull());
QCOMPARE(entry.netmask(), netmask);
QCOMPARE(entry.prefixLength(), prefix);
} else {
// not valid
QVERIFY(entry.netmask().isNull());
QCOMPARE(entry.prefixLength(), -1);
}
}
entry.setPrefixLength(-1);
QVERIFY(entry.netmask().isNull());
QCOMPARE(entry.prefixLength(), -1);
}
QTEST_MAIN(tst_QNetworkAddressEntry)
#include "tst_qnetworkaddressentry.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qnetworkdatagram Test:
#####################################################################
qt_internal_add_test(tst_qnetworkdatagram
SOURCES
tst_qnetworkdatagram.cpp
LIBRARIES
Qt::Network
)

View File

@ -0,0 +1,132 @@
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QNetworkDatagram>
#include <QTest>
#include <QCoreApplication>
class tst_QNetworkDatagram : public QObject
{
Q_OBJECT
public:
tst_QNetworkDatagram();
private Q_SLOTS:
void getSetCheck();
void makeReply_data();
void makeReply();
};
tst_QNetworkDatagram::tst_QNetworkDatagram()
{
}
void tst_QNetworkDatagram::getSetCheck()
{
QNetworkDatagram dg;
QVERIFY(dg.isNull());
QVERIFY(!dg.isValid());
QCOMPARE(dg.senderAddress(), QHostAddress());
QCOMPARE(dg.destinationAddress(), QHostAddress());
QCOMPARE(dg.senderPort(), -1);
QCOMPARE(dg.destinationPort(), -1);
QCOMPARE(dg.hopLimit(), -1);
QCOMPARE(dg.interfaceIndex(), 0U);
dg.setHopLimit(1);
QCOMPARE(dg.hopLimit(), 1);
dg.setHopLimit(255);
QCOMPARE(dg.hopLimit(), 255);
dg.setInterfaceIndex(1);
QCOMPARE(dg.interfaceIndex(), 1U);
dg.setInterfaceIndex(1234567U);
QCOMPARE(dg.interfaceIndex(), 1234567U);
dg.setSender(QHostAddress::Any, 12345);
QCOMPARE(dg.senderAddress(), QHostAddress(QHostAddress::Any));
QCOMPARE(dg.senderPort(), 12345);
dg.setSender(QHostAddress::LocalHost);
QCOMPARE(dg.senderAddress(), QHostAddress(QHostAddress::LocalHost));
QCOMPARE(dg.senderPort(), 0);
dg.setDestination(QHostAddress::LocalHostIPv6, 12345);
QCOMPARE(dg.destinationAddress(), QHostAddress(QHostAddress::LocalHostIPv6));
QCOMPARE(dg.destinationPort(), 12345);
dg.setDestination(QHostAddress::Broadcast, 137);
QCOMPARE(dg.destinationAddress(), QHostAddress(QHostAddress::Broadcast));
QCOMPARE(dg.destinationPort(), 137);
auto dg2 = dg;
QCOMPARE(dg2.hopLimit(), dg.hopLimit());
QCOMPARE(dg2.interfaceIndex(), dg.interfaceIndex());
QCOMPARE(dg2.senderAddress(), dg.senderAddress());
QCOMPARE(dg2.senderPort(), dg.senderPort());
QCOMPARE(dg2.destinationAddress(), dg.destinationAddress());
QCOMPARE(dg2.destinationPort(), dg.destinationPort());
dg.clear();
QVERIFY(dg.isNull());
}
void tst_QNetworkDatagram::makeReply_data()
{
qRegisterMetaType<QNetworkDatagram>();
QTest::addColumn<QNetworkDatagram>("dgram");
QTest::addColumn<QString>("localAddress");
QNetworkDatagram dgram("some data", QHostAddress("192.0.2.1"), 10001);
dgram.setHopLimit(64);
dgram.setSender(QHostAddress::LocalHost, 12345);
QTest::newRow("ipv4") << dgram << "192.0.2.1";
dgram.setDestination(QHostAddress("224.0.0.1"), 10002);
QTest::newRow("ipv4-multicast") << dgram << QString();
dgram.setSender(QHostAddress::LocalHostIPv6, 12346);
dgram.setDestination(QHostAddress("2001:db8::1"), 12347);
QTest::newRow("ipv6") << dgram << "2001:db8::1";
dgram.setSender(QHostAddress("fe80::1%1"), 10003);
dgram.setDestination(QHostAddress("fe80::2%1"), 10004);
dgram.setInterfaceIndex(1);
QTest::newRow("ipv6-linklocal") << dgram << "fe80::2%1";
dgram.setDestination(QHostAddress("ff02::1%1"), 10005);
QTest::newRow("ipv6-multicast") << dgram << QString();
}
void tst_QNetworkDatagram::makeReply()
{
QFETCH(QNetworkDatagram, dgram);
QFETCH(QString, localAddress);
{
QNetworkDatagram reply = dgram.makeReply("World");
QCOMPARE(reply.data(), QByteArray("World"));
QCOMPARE(reply.senderAddress(), QHostAddress(localAddress));
QCOMPARE(reply.senderPort(), localAddress.isEmpty() ? -1 : dgram.destinationPort());
QCOMPARE(reply.destinationAddress(), dgram.senderAddress());
QCOMPARE(reply.destinationPort(), dgram.senderPort());
QCOMPARE(reply.interfaceIndex(), dgram.interfaceIndex());
QCOMPARE(reply.hopLimit(), -1);
}
QNetworkDatagram copy = dgram;
copy.setData(copy.data());
{
QNetworkDatagram reply = std::move(copy).makeReply("World");
QCOMPARE(reply.data(), QByteArray("World"));
QCOMPARE(reply.senderAddress(), QHostAddress(localAddress));
QCOMPARE(reply.senderPort(), localAddress.isEmpty() ? -1 : dgram.destinationPort());
QCOMPARE(reply.destinationAddress(), dgram.senderAddress());
QCOMPARE(reply.destinationPort(), dgram.senderPort());
QCOMPARE(reply.interfaceIndex(), dgram.interfaceIndex());
QCOMPARE(reply.hopLimit(), -1);
}
}
QTEST_MAIN(tst_QNetworkDatagram)
#include "tst_qnetworkdatagram.moc"

View File

@ -0,0 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_test(tst_qnetworkinformation
SOURCES
tst_qnetworkinformation.cpp
LIBRARIES
Qt::NetworkPrivate
)

View File

@ -0,0 +1,255 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtNetwork/private/qnetworkinformation_p.h>
#include <QtNetwork/qnetworkinformation.h>
#include <QtTest/qtest.h>
#include <QtTest/qsignalspy.h>
#include <limits>
#include <memory>
class MockFactory;
class tst_QNetworkInformation : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void supportedFeatures();
void reachability();
void behindCaptivePortal();
void transportMedium();
void isMetered();
void cleanupTestCase();
private:
std::unique_ptr<MockFactory> mockFactory;
};
static const QString mockName = QStringLiteral("mock");
class MockBackend : public QNetworkInformationBackend
{
Q_OBJECT
public:
MockBackend()
{
Q_ASSERT(!instance);
instance = this;
setReachability(QNetworkInformation::Reachability::Online);
setNewBehindCaptivePortal(false);
}
~MockBackend() { instance = nullptr; }
QString name() const override { return mockName; }
QNetworkInformation::Features featuresSupported() const override
{
return featuresSupportedStatic();
}
static void setNewReachability(QNetworkInformation::Reachability value)
{
Q_ASSERT(instance);
instance->setReachability(value);
}
static void setNewBehindCaptivePortal(bool value)
{
Q_ASSERT(instance);
instance->setBehindCaptivePortal(value);
}
static void setNewTransportMedium(QNetworkInformation::TransportMedium medium)
{
Q_ASSERT(instance);
instance->setTransportMedium(medium);
}
static void setNewMetered(bool metered)
{
Q_ASSERT(instance);
instance->setMetered(metered);
}
static QNetworkInformation::Features featuresSupportedStatic()
{
return { QNetworkInformation::Feature::Reachability
| QNetworkInformation::Feature::CaptivePortal
| QNetworkInformation::Feature::TransportMedium
| QNetworkInformation::Feature::Metered };
}
private:
static inline MockBackend *instance = nullptr;
};
class MockFactory : public QNetworkInformationBackendFactory
{
Q_OBJECT
public:
QString name() const override { return mockName; }
QNetworkInformationBackend *
create(QNetworkInformation::Features requiredFeatures) const override
{
if ((requiredFeatures & featuresSupported()) != requiredFeatures)
return nullptr;
return new MockBackend();
}
QNetworkInformation::Features featuresSupported() const override
{
return MockBackend::featuresSupportedStatic();
}
};
void tst_QNetworkInformation::initTestCase()
{
auto prevBackends = QNetworkInformation::availableBackends();
qDebug() << "available backends:" << prevBackends;
// Creating the factory registers it as a backend
mockFactory = std::make_unique<MockFactory>();
auto backends = QNetworkInformation::availableBackends();
QVERIFY(backends.size() > prevBackends.size());
QVERIFY(backends.contains(u"mock"));
QVERIFY(QNetworkInformation::loadBackendByName(u"mock"));
QVERIFY(QNetworkInformation::loadBackendByName(u"mock"));
QVERIFY(QNetworkInformation::loadBackendByName(u"mOcK"));
QVERIFY(!QNetworkInformation::loadBackendByName(u"mocks"));
}
void tst_QNetworkInformation::cleanupTestCase()
{
// Make sure the factory gets unregistered on destruction:
mockFactory.reset();
auto backends = QNetworkInformation::availableBackends();
QVERIFY(!backends.contains(u"mock"));
}
void tst_QNetworkInformation::supportedFeatures()
{
auto info = QNetworkInformation::instance();
auto allFeatures = QNetworkInformation::Features(QNetworkInformation::Feature::CaptivePortal
| QNetworkInformation::Feature::Reachability
| QNetworkInformation::Feature::TransportMedium
| QNetworkInformation::Feature::Metered);
QCOMPARE(info->supportedFeatures(), allFeatures);
QVERIFY(info->supports(allFeatures));
QVERIFY(info->supports(QNetworkInformation::Feature::CaptivePortal));
QVERIFY(info->supports(QNetworkInformation::Feature::Reachability));
QVERIFY(info->supports(QNetworkInformation::Feature::TransportMedium));
QVERIFY(info->supports(QNetworkInformation::Feature::Metered));
}
void tst_QNetworkInformation::reachability()
{
auto info = QNetworkInformation::instance();
QNetworkInformation::Reachability boundIsOnline = QNetworkInformation::Reachability::Unknown;
bool signalEmitted = false;
connect(info, &QNetworkInformation::reachabilityChanged, this, [&, info]() {
signalEmitted = true;
boundIsOnline = info->reachability();
});
QCOMPARE(info->reachability(), QNetworkInformation::Reachability::Online);
MockBackend::setNewReachability(QNetworkInformation::Reachability::Disconnected);
QCoreApplication::processEvents();
QVERIFY(signalEmitted);
QCOMPARE(info->reachability(), QNetworkInformation::Reachability::Disconnected);
QCOMPARE(boundIsOnline, QNetworkInformation::Reachability::Disconnected);
// Set the same value again, signal should not be emitted again
signalEmitted = false;
MockBackend::setNewReachability(QNetworkInformation::Reachability::Disconnected);
QCoreApplication::processEvents();
QVERIFY(!signalEmitted);
MockBackend::setNewReachability(QNetworkInformation::Reachability::Local);
QCOMPARE(info->reachability(), QNetworkInformation::Reachability::Local);
QCOMPARE(boundIsOnline, QNetworkInformation::Reachability::Local);
MockBackend::setNewReachability(QNetworkInformation::Reachability::Site);
QCOMPARE(info->reachability(), QNetworkInformation::Reachability::Site);
QCOMPARE(boundIsOnline, QNetworkInformation::Reachability::Site);
}
void tst_QNetworkInformation::behindCaptivePortal()
{
auto info = QNetworkInformation::instance();
bool behindPortal = false;
bool signalEmitted = false;
connect(info, &QNetworkInformation::isBehindCaptivePortalChanged, this,
[&, info](bool state) {
signalEmitted = true;
QCOMPARE(state, info->isBehindCaptivePortal());
behindPortal = info->isBehindCaptivePortal();
});
QVERIFY(!info->isBehindCaptivePortal());
MockBackend::setNewBehindCaptivePortal(true);
QCoreApplication::processEvents();
QVERIFY(signalEmitted);
QVERIFY(info->isBehindCaptivePortal());
QVERIFY(behindPortal);
// Set the same value again, signal should not be emitted again
signalEmitted = false;
MockBackend::setNewBehindCaptivePortal(true);
QCoreApplication::processEvents();
QVERIFY(!signalEmitted);
}
void tst_QNetworkInformation::transportMedium()
{
auto info = QNetworkInformation::instance();
using TransportMedium = QNetworkInformation::TransportMedium;
TransportMedium medium = TransportMedium::Unknown;
bool signalEmitted = false;
connect(info, &QNetworkInformation::transportMediumChanged, this, [&, info](TransportMedium tm) {
signalEmitted = true;
QCOMPARE(tm, info->transportMedium());
medium = info->transportMedium();
});
QCOMPARE(info->transportMedium(), TransportMedium::Unknown); // Default is unknown
auto transportMediumEnum = QMetaEnum::fromType<TransportMedium>();
auto mediumCount = transportMediumEnum.keyCount();
// Verify index 0 is Unknown and skip it in the loop, it's the default.
QCOMPARE(TransportMedium(transportMediumEnum.value(0)), TransportMedium::Unknown);
for (int i = 1; i < mediumCount; ++i) {
signalEmitted = false;
TransportMedium m = TransportMedium(transportMediumEnum.value(i));
MockBackend::setNewTransportMedium(m);
QCoreApplication::processEvents();
QVERIFY(signalEmitted);
QCOMPARE(info->transportMedium(), m);
QCOMPARE(medium, m);
}
// Set the current value again, signal should not be emitted again
signalEmitted = false;
MockBackend::setNewTransportMedium(medium);
QCoreApplication::processEvents();
QVERIFY(!signalEmitted);
}
void tst_QNetworkInformation::isMetered()
{
auto info = QNetworkInformation::instance();
QSignalSpy spy(info, &QNetworkInformation::isMeteredChanged);
QVERIFY(!info->isMetered());
MockBackend::setNewMetered(true);
QCOMPARE(spy.size(), 1);
QVERIFY(info->isMetered());
QVERIFY(spy[0][0].toBool());
spy.clear();
// Set the same value again, signal should not be emitted again
MockBackend::setNewMetered(true);
QCOMPARE(spy.size(), 0);
}
QTEST_MAIN(tst_QNetworkInformation);
#include "tst_qnetworkinformation.moc"

View File

@ -0,0 +1,9 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
qt_internal_add_test(tst_qnetworkinformation_appless
SOURCES
tst_qnetworkinformation_appless.cpp
LIBRARIES
Qt::Network
)

View File

@ -0,0 +1,42 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/qcoreapplication.h>
#include <QtNetwork/qnetworkinformation.h>
#include <QtTest/qtest.h>
class tst_QNetworkInformation_appless : public QObject
{
Q_OBJECT
private slots:
void reinit();
};
void tst_QNetworkInformation_appless::reinit()
{
int argc = 1;
char name[] = "./test";
char *argv[] = { name, nullptr };
{
QCoreApplication app(argc, argv);
if (QNetworkInformation::availableBackends().isEmpty())
QSKIP("No backends available!");
QVERIFY(QNetworkInformation::loadDefaultBackend());
auto info = QNetworkInformation::instance();
QVERIFY(info);
}
QVERIFY(!QNetworkInformation::instance());
{
QCoreApplication app(argc, argv);
QVERIFY(QNetworkInformation::loadDefaultBackend());
auto info = QNetworkInformation::instance();
QVERIFY(info);
}
}
QTEST_APPLESS_MAIN(tst_QNetworkInformation_appless);
#include "tst_qnetworkinformation_appless.moc"

View File

@ -0,0 +1,14 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qnetworkinterface Test:
#####################################################################
qt_internal_add_test(tst_qnetworkinterface
SOURCES
tst_qnetworkinterface.cpp
LIBRARIES
Qt::Network
QT_TEST_SERVER_LIST "apache2"
)

View File

@ -0,0 +1,303 @@
// Copyright (C) 2016 The Qt Company Ltd.
// Copyright (C) 2016 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QtEndian>
#include <QSet>
#include <qcoreapplication.h>
#include <qnetworkinterface.h>
#include <qudpsocket.h>
#include "../../../network-settings.h"
Q_DECLARE_METATYPE(QHostAddress)
class tst_QNetworkInterface : public QObject
{
Q_OBJECT
public:
tst_QNetworkInterface();
virtual ~tst_QNetworkInterface();
bool isIPv6Working();
private slots:
void initTestCase();
void dump();
void consistencyCheck();
void loopbackIPv4();
void loopbackIPv6();
void localAddress_data();
void localAddress();
void interfaceFromXXX_data();
void interfaceFromXXX();
void copyInvalidInterface();
private:
bool hasNetworkServer = false;
};
tst_QNetworkInterface::tst_QNetworkInterface()
{
}
tst_QNetworkInterface::~tst_QNetworkInterface()
{
}
bool tst_QNetworkInterface::isIPv6Working()
{
// Version without following cannot get IPV6 information
#if !defined(QT_NO_GETIFADDRS) && !defined(QT_NO_IPV6IFNAME)
QUdpSocket socket;
socket.connectToHost(QHostAddress::LocalHostIPv6, 1234);
return socket.state() == QAbstractSocket::ConnectedState || socket.waitForConnected(100);
#else
return false;
#endif
}
void tst_QNetworkInterface::initTestCase()
{
#ifdef QT_TEST_SERVER
hasNetworkServer = QtNetworkSettings::verifyConnection(QtNetworkSettings::httpServerName(), 80);
#else
hasNetworkServer = QtNetworkSettings::verifyTestNetworkSettings();
#endif
}
void tst_QNetworkInterface::dump()
{
// This is for manual testing:
QList<QNetworkInterface> allInterfaces = QNetworkInterface::allInterfaces();
foreach (const QNetworkInterface &i, allInterfaces) {
QString flags;
if (i.flags() & QNetworkInterface::IsUp) flags += "Up,";
if (i.flags() & QNetworkInterface::IsRunning) flags += "Running,";
if (i.flags() & QNetworkInterface::CanBroadcast) flags += "Broadcast,";
if (i.flags() & QNetworkInterface::IsLoopBack) flags += "Loopback,";
if (i.flags() & QNetworkInterface::IsPointToPoint) flags += "PointToPoint,";
if (i.flags() & QNetworkInterface::CanMulticast) flags += "Multicast,";
flags.chop(1); // drop last comma
QString friendlyName = i.humanReadableName();
if (friendlyName != i.name()) {
friendlyName.prepend('(');
friendlyName.append(')');
} else {
friendlyName.clear();
}
qDebug() << "Interface: " << i.name() << qPrintable(friendlyName);
QVERIFY(i.isValid());
qDebug() << " index: " << i.index();
qDebug() << " flags: " << qPrintable(flags);
qDebug() << " type: " << i.type();
qDebug() << " hw address:" << qPrintable(i.hardwareAddress());
qDebug() << " MTU: " << i.maximumTransmissionUnit();
int count = 0;
foreach (const QNetworkAddressEntry &e, i.addressEntries()) {
QDebug s = qDebug();
s.nospace() << " address "
<< qSetFieldWidth(2) << count++ << qSetFieldWidth(0);
s.nospace() << ": " << qPrintable(e.ip().toString());
if (!e.netmask().isNull())
s.nospace() << '/' << e.prefixLength()
<< " (" << qPrintable(e.netmask().toString()) << ')';
if (!e.broadcast().isNull())
s.nospace() << " broadcast " << qPrintable(e.broadcast().toString());
if (e.dnsEligibility() == QNetworkAddressEntry::DnsEligible)
s.nospace() << " dns-eligible";
else if (e.dnsEligibility() == QNetworkAddressEntry::DnsIneligible)
s.nospace() << " dns-ineligible";
if (e.isLifetimeKnown()) {
#define printable(l) qPrintable(l.isForever() ? "forever" : QString::fromLatin1("%1ms").arg(l.remainingTime()))
s.nospace() << " preferred:" << printable(e.preferredLifetime())
<< " valid:" << printable(e.validityLifetime());
#undef printable
}
}
}
}
void tst_QNetworkInterface::consistencyCheck()
{
QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
QSet<QString> interfaceNames;
QList<int> interfaceIndexes;
foreach (const QNetworkInterface &iface, ifaces) {
QVERIFY(iface.isValid());
QVERIFY2(!interfaceNames.contains(iface.name()),
"duplicate name = " + iface.name().toLocal8Bit());
interfaceNames << iface.name();
QVERIFY2(!interfaceIndexes.contains(iface.index()),
"duplicate index = " + QByteArray::number(iface.index()));
if (iface.index())
interfaceIndexes << iface.index();
QVERIFY(iface.maximumTransmissionUnit() >= 0);
const QList<QNetworkAddressEntry> addresses = iface.addressEntries();
for (auto entry : addresses) {
QVERIFY(entry.ip().protocol() != QAbstractSocket::UnknownNetworkLayerProtocol);
if (!entry.preferredLifetime().isForever() || !entry.validityLifetime().isForever())
QVERIFY(entry.isLifetimeKnown());
if (!entry.validityLifetime().isForever())
QVERIFY(entry.isTemporary());
}
}
}
void tst_QNetworkInterface::loopbackIPv4()
{
QList<QHostAddress> all = QNetworkInterface::allAddresses();
QVERIFY(all.contains(QHostAddress(QHostAddress::LocalHost)));
}
void tst_QNetworkInterface::loopbackIPv6()
{
if (!isIPv6Working())
QSKIP("IPv6 not active on this machine");
QList<QHostAddress> all = QNetworkInterface::allAddresses();
QVERIFY(all.contains(QHostAddress(QHostAddress::LocalHostIPv6)));
}
void tst_QNetworkInterface::localAddress_data()
{
bool ipv6 = isIPv6Working();
QTest::addColumn<QHostAddress>("target");
QTest::newRow("localhost-ipv4") << QHostAddress(QHostAddress::LocalHost);
if (ipv6)
QTest::newRow("localhost-ipv6") << QHostAddress(QHostAddress::LocalHostIPv6);
if (hasNetworkServer)
QTest::newRow("test-server") << QtNetworkSettings::httpServerIp();
QSet<QHostAddress> added;
const QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
for (const QNetworkInterface &iface : ifaces) {
if ((iface.flags() & QNetworkInterface::IsUp) == 0)
continue;
const QList<QNetworkAddressEntry> addrs = iface.addressEntries();
for (const QNetworkAddressEntry &entry : addrs) {
QHostAddress addr = entry.ip();
if (addr.isLoopback())
continue; // added above
if (addr.protocol() == QAbstractSocket::IPv4Protocol) {
// add an IPv4 address with bits in the host portion of the address flipped
quint32 ip4 = entry.ip().toIPv4Address();
addr.setAddress(ip4 ^ ~entry.netmask().toIPv4Address());
} else if (!ipv6 || entry.prefixLength() != 64) {
continue;
} else {
// add a random node in this IPv6 network
quint64 randomid = qFromBigEndian(Q_UINT64_C(0x8f41f072e5733caa));
QIPv6Address ip6 = addr.toIPv6Address();
memcpy(&ip6[8], &randomid, sizeof(randomid));
addr.setAddress(ip6);
}
if (added.contains(addr))
continue;
added.insert(addr);
QTest::addRow("%s-%s", qPrintable(iface.name()), qPrintable(addr.toString())) << addr;
}
}
}
void tst_QNetworkInterface::localAddress()
{
QFETCH(QHostAddress, target);
QUdpSocket socket;
socket.connectToHost(target, 80);
QVERIFY(socket.waitForConnected(5000));
QHostAddress local = socket.localAddress();
// find the interface that contains the address QUdpSocket reported
QList<QNetworkInterface> ifaces = QNetworkInterface::allInterfaces();
const QNetworkInterface *outgoingIface = nullptr;
for (const QNetworkInterface &iface : ifaces) {
QList<QNetworkAddressEntry> addrs = iface.addressEntries();
for (const QNetworkAddressEntry &entry : addrs) {
if (entry.ip() == local) {
outgoingIface = &iface;
break;
}
}
if (outgoingIface)
break;
}
QVERIFY(outgoingIface);
// we get QVariant() if the QNativeSocketEngine doesn't know how to get the PMTU
int pmtu = socket.socketOption(QAbstractSocket::PathMtuSocketOption).toInt();
qDebug() << "Connected to" << target.toString() << "via interface" << outgoingIface->name()
<< "pmtu" << pmtu;
// check that the Path MTU is less than or equal the interface's MTU
QVERIFY(pmtu <= outgoingIface->maximumTransmissionUnit());
}
void tst_QNetworkInterface::interfaceFromXXX_data()
{
QTest::addColumn<QNetworkInterface>("iface");
QList<QNetworkInterface> allInterfaces = QNetworkInterface::allInterfaces();
if (allInterfaces.size() == 0)
QSKIP("No interfaces to test!");
foreach (QNetworkInterface iface, allInterfaces)
QTest::newRow(iface.name().toLocal8Bit()) << iface;
}
void tst_QNetworkInterface::interfaceFromXXX()
{
QFETCH(QNetworkInterface, iface);
QVERIFY(QNetworkInterface::interfaceFromName(iface.name()).isValid());
if (int idx = iface.index()) {
QVERIFY(QNetworkInterface::interfaceFromIndex(idx).isValid());
QCOMPARE(QNetworkInterface::interfaceNameFromIndex(idx), iface.name());
QCOMPARE(QNetworkInterface::interfaceIndexFromName(iface.name()), idx);
}
foreach (QNetworkAddressEntry entry, iface.addressEntries()) {
QVERIFY(!entry.ip().isNull());
if (!entry.netmask().isNull()) {
QCOMPARE(entry.netmask().protocol(), entry.ip().protocol());
// if the netmask is known, the broadcast is known
// but only for IPv4 (there is no such thing as broadcast in IPv6)
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) {
QVERIFY(!entry.broadcast().isNull());
}
}
if (!entry.broadcast().isNull())
QCOMPARE(entry.broadcast().protocol(), entry.ip().protocol());
}
}
void tst_QNetworkInterface::copyInvalidInterface()
{
// Force a copy of an interfaces that isn't likely to exist
QNetworkInterface i = QNetworkInterface::interfaceFromName("plopp");
QVERIFY(!i.isValid());
QCOMPARE(i.index(), 0);
QVERIFY(i.name().isEmpty());
QVERIFY(i.humanReadableName().isEmpty());
QVERIFY(i.hardwareAddress().isEmpty());
QCOMPARE(int(i.flags()), 0);
QVERIFY(i.addressEntries().isEmpty());
}
QTEST_MAIN(tst_QNetworkInterface)
#include "tst_qnetworkinterface.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qnetworkproxy Test:
#####################################################################
qt_internal_add_test(tst_qnetworkproxy
SOURCES
tst_qnetworkproxy.cpp
LIBRARIES
Qt::Network
)

View File

@ -0,0 +1,77 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qcoreapplication.h>
#include <qdebug.h>
#include <qnetworkproxy.h>
class tst_QNetworkProxy : public QObject
{
Q_OBJECT
public:
tst_QNetworkProxy();
virtual ~tst_QNetworkProxy();
private slots:
void getSetCheck();
void capabilitiesPerType();
};
tst_QNetworkProxy::tst_QNetworkProxy()
{
}
tst_QNetworkProxy::~tst_QNetworkProxy()
{
}
// Testing get/set functions
void tst_QNetworkProxy::getSetCheck()
{
QNetworkProxy obj1;
// quint16 QNetworkProxy::port()
// void QNetworkProxy::setPort(quint16)
obj1.setPort(quint16(0));
QCOMPARE(quint16(0), obj1.port());
obj1.setPort(quint16(0xffff));
QCOMPARE(quint16(0xffff), obj1.port());
obj1.setType(QNetworkProxy::DefaultProxy);
QCOMPARE(obj1.type(), QNetworkProxy::DefaultProxy);
obj1.setType(QNetworkProxy::HttpProxy);
QCOMPARE(obj1.type(), QNetworkProxy::HttpProxy);
obj1.setType(QNetworkProxy::Socks5Proxy);
QCOMPARE(obj1.type(), QNetworkProxy::Socks5Proxy);
}
void tst_QNetworkProxy::capabilitiesPerType()
{
QNetworkProxy proxy(QNetworkProxy::Socks5Proxy);
QVERIFY(proxy.capabilities() & QNetworkProxy::TunnelingCapability);
QVERIFY(proxy.capabilities() & QNetworkProxy::HostNameLookupCapability);
QVERIFY(proxy.capabilities() & QNetworkProxy::UdpTunnelingCapability);
proxy.setType(QNetworkProxy::NoProxy);
// verify that the capabilities changed
QVERIFY(!(proxy.capabilities() & QNetworkProxy::HostNameLookupCapability));
QVERIFY(proxy.capabilities() & QNetworkProxy::UdpTunnelingCapability);
proxy.setType(QNetworkProxy::HttpProxy);
QVERIFY(proxy.capabilities() & QNetworkProxy::HostNameLookupCapability);
QVERIFY(!(proxy.capabilities() & QNetworkProxy::UdpTunnelingCapability));
// now set the capabilities on stone:
proxy.setCapabilities(QNetworkProxy::TunnelingCapability | QNetworkProxy::UdpTunnelingCapability);
QCOMPARE(proxy.capabilities(), QNetworkProxy::TunnelingCapability | QNetworkProxy::UdpTunnelingCapability);
// changing the type shouldn't change the capabilities any more
proxy.setType(QNetworkProxy::Socks5Proxy);
QCOMPARE(proxy.capabilities(), QNetworkProxy::TunnelingCapability | QNetworkProxy::UdpTunnelingCapability);
}
QTEST_MAIN(tst_QNetworkProxy)
#include "tst_qnetworkproxy.moc"

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
#####################################################################
## tst_qnetworkproxyfactory Test:
#####################################################################
qt_internal_add_test(tst_qnetworkproxyfactory
SOURCES
tst_qnetworkproxyfactory.cpp
LIBRARIES
Qt::NetworkPrivate
)

View File

@ -0,0 +1,294 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtTest/QTest>
#include <QtTest/QTestEventLoop>
#include <qcoreapplication.h>
#include <qdebug.h>
#include <qnetworkproxy.h>
#include <QNetworkAccessManager>
#include <QNetworkInterface>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QList>
#include <QSysInfo>
#include <QThread>
#include <private/qtnetworkglobal_p.h>
class tst_QNetworkProxyFactory : public QObject {
Q_OBJECT
public:
tst_QNetworkProxyFactory();
class QDebugProxyFactory : public QNetworkProxyFactory
{
public:
QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery &query = QNetworkProxyQuery()) override
{
returnedList = QNetworkProxyFactory::systemProxyForQuery(query);
requestCounter++;
return returnedList;
}
QList<QNetworkProxy> returnedList;
static int requestCounter;
};
private slots:
void systemProxyForQueryCalledFromThread();
void systemProxyForQuery_data();
void systemProxyForQuery() const;
void systemProxyForQuery_local();
void genericSystemProxy();
void genericSystemProxy_data();
private:
QString formatProxyName(const QNetworkProxy & proxy) const;
QDebugProxyFactory *factory;
};
int tst_QNetworkProxyFactory::QDebugProxyFactory::requestCounter = 0;
tst_QNetworkProxyFactory::tst_QNetworkProxyFactory()
{
factory = new QDebugProxyFactory;
QNetworkProxyFactory::setApplicationProxyFactory(factory);
}
QString tst_QNetworkProxyFactory::formatProxyName(const QNetworkProxy & proxy) const
{
QString proxyName;
if (!proxy.user().isNull())
proxyName.append(QString("%1:%2@").arg(proxy.user(), proxy.password()));
proxyName.append(QString("%1:%2").arg(proxy.hostName()).arg(proxy.port()));
proxyName.append(QString(" (type=%1, capabilities=%2)").arg(proxy.type()).arg(proxy.capabilities()));
return proxyName;
}
void tst_QNetworkProxyFactory::systemProxyForQuery_data()
{
QTest::addColumn<int>("type");
QTest::addColumn<QUrl>("url");
QTest::addColumn<QString>("tag");
QTest::addColumn<QString>("hostName");
QTest::addColumn<int>("port");
QTest::addColumn<int>("requiredCapabilities");
//URLs
QTest::newRow("http") << (int)QNetworkProxyQuery::UrlRequest << QUrl("http://qt-project.org") << QString() << QString() << 0 << 0;
//windows: "intranet" should be bypassed if "bypass proxy server for local addresses" is ticked
QTest::newRow("intranet") << (int)QNetworkProxyQuery::UrlRequest << QUrl("http://qt-test-server") << QString() << QString() << 0 << 0;
//windows: "intranet2" should be bypassed if "*.local" is in the exceptions list (advanced settings)
QTest::newRow("intranet2") << (int)QNetworkProxyQuery::UrlRequest << QUrl("http://qt-test-server.local") << QString() << QString() << 0 << 0;
QTest::newRow("https") << (int)QNetworkProxyQuery::UrlRequest << QUrl("https://qt-project.org") << QString() << QString() << 0 << (int)QNetworkProxy::TunnelingCapability;
QTest::newRow("ftp") << (int)QNetworkProxyQuery::UrlRequest << QUrl("ftp://qt-project.org") << QString() << QString() << 0 << 0;
//TCP
QTest::newRow("imap") << (int)QNetworkProxyQuery::TcpSocket << QUrl() << QString() << QString("qt-project.org") << 0 << (int)QNetworkProxy::TunnelingCapability;
QTest::newRow("autobind-server") << (int)QNetworkProxyQuery::TcpServer << QUrl() << QString() << QString() << 0 << (int)QNetworkProxy::ListeningCapability;
QTest::newRow("web-server") << (int)QNetworkProxyQuery::TcpServer << QUrl() << QString() << QString() << 80 << (int)QNetworkProxy::ListeningCapability;
//windows: these should be bypassed if "bypass proxy server for local addresses" is ticked
foreach (QHostAddress address, QNetworkInterface::allAddresses()) {
QTest::newRow(qPrintable(address.toString())) << (int)QNetworkProxyQuery::TcpSocket << QUrl() << QString() << address.toString() << 0 << 0;
}
//UDP
QTest::newRow("udp") << (int)QNetworkProxyQuery::UdpSocket << QUrl() << QString() << QString() << 0 << (int)QNetworkProxy::UdpTunnelingCapability;
//Protocol tags
QTest::newRow("http-tag") << (int)QNetworkProxyQuery::TcpSocket << QUrl() << QString("http") << QString("qt-project.org") << 80 << (int)QNetworkProxy::TunnelingCapability;
QTest::newRow("ftp-tag") << (int)QNetworkProxyQuery::TcpSocket << QUrl() << QString("ftp") << QString("qt-project.org") << 21 << (int)QNetworkProxy::TunnelingCapability;
QTest::newRow("https-tag") << (int)QNetworkProxyQuery::TcpSocket << QUrl() << QString("https") << QString("qt-project.org") << 443 << (int)QNetworkProxy::TunnelingCapability;
#ifdef Q_OS_WIN
//in Qt 4.8, "socks" would get the socks proxy, but we don't want to enforce that for all platforms
QTest::newRow("socks-tag") << (int)QNetworkProxyQuery::TcpSocket << QUrl() << QString("socks") << QString("qt-project.org") << 21 << (int)(QNetworkProxy::TunnelingCapability | QNetworkProxy::ListeningCapability);
#endif
//windows: ssh is not a tag provided by the os, but any tunneling proxy is acceptable
QTest::newRow("ssh-tag") << (int)QNetworkProxyQuery::TcpSocket << QUrl() << QString("ssh") << QString("qt-project.org") << 22 << (int)QNetworkProxy::TunnelingCapability;
//Server protocol tags (ftp/http proxies are no good, we need socks or nothing)
QTest::newRow("http-server-tag") << (int)QNetworkProxyQuery::TcpServer << QUrl() << QString("http") << QString() << 80 << (int)QNetworkProxy::ListeningCapability;
QTest::newRow("ftp-server-tag") << (int)QNetworkProxyQuery::TcpServer << QUrl() << QString("ftp") << QString() << 21 << (int)QNetworkProxy::ListeningCapability;
QTest::newRow("imap-server-tag") << (int)QNetworkProxyQuery::TcpServer << QUrl() << QString("imap") << QString() << 143 << (int)QNetworkProxy::ListeningCapability;
//UDP protocol tag
QTest::newRow("sip-udp-tag") << (int)QNetworkProxyQuery::UdpSocket << QUrl() << QString("sip") << QString("qt-project.org") << 5061 << (int)QNetworkProxy::UdpTunnelingCapability;
}
void tst_QNetworkProxyFactory::systemProxyForQuery() const
{
QFETCH(int, type);
QFETCH(QUrl, url);
QFETCH(QString, tag);
QFETCH(QString, hostName);
QFETCH(int, port);
QFETCH(int, requiredCapabilities);
QNetworkProxyQuery query;
switch (type) {
case QNetworkProxyQuery::UrlRequest:
query = QNetworkProxyQuery(url);
break;
case QNetworkProxyQuery::TcpSocket:
case QNetworkProxyQuery::UdpSocket:
query = QNetworkProxyQuery(hostName, port, tag, QNetworkProxyQuery::QueryType(type));
break;
case QNetworkProxyQuery::TcpServer:
query = QNetworkProxyQuery(quint16(port), tag);
break;
}
QElapsedTimer sw;
sw.start();
QList<QNetworkProxy> systemProxyList = QNetworkProxyFactory::systemProxyForQuery(query);
qDebug() << sw.elapsed() << "ms";
QVERIFY(!systemProxyList.isEmpty());
// for manual comparison with system
qDebug() << systemProxyList;
foreach (const QNetworkProxy &proxy, systemProxyList) {
QVERIFY((requiredCapabilities == 0) || (proxy.capabilities() & requiredCapabilities));
}
}
void tst_QNetworkProxyFactory::systemProxyForQuery_local()
{
QList<QNetworkProxy> list;
const QString proxyHost("myproxy.test.com");
// set an arbitrary proxy
QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::HttpProxy, proxyHost, 80));
factory = 0;
// localhost
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QUrl("http://localhost/")));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QString("localhost"), 80));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
// 127.0.0.1
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QUrl("http://127.0.0.1/")));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QString("127.0.0.1"), 80));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
// [::1]
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QUrl("http://[::1]/")));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QString("[::1]"), 80));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
// an arbitrary host
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QUrl("http://another.host.com/")));
QVERIFY((!list.isEmpty()) && (list[0].hostName() == proxyHost));
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QString("another.host.com"), 80));
QVERIFY((!list.isEmpty()) && (list[0].hostName() == proxyHost));
// disable proxy
QNetworkProxy::setApplicationProxy(QNetworkProxy(QNetworkProxy::NoProxy));
factory = 0;
// localhost
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QUrl("http://localhost/")));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QString("localhost"), 80));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
// 127.0.0.1
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QUrl("http://127.0.0.1/")));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QString("127.0.0.1"), 80));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
// [::1]
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QUrl("http://[::1]/")));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QString("[::1]"), 80));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
// an arbitrary host
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QUrl("http://another.host.com/")));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
list = QNetworkProxyFactory::proxyForQuery(QNetworkProxyQuery(QString("another.host.com"), 80));
QVERIFY(list.isEmpty() || (list[0].type() == QNetworkProxy::NoProxy));
}
Q_DECLARE_METATYPE(QNetworkProxy::ProxyType)
void tst_QNetworkProxyFactory::genericSystemProxy()
{
QFETCH(QByteArray, envVar);
QFETCH(QByteArray, url);
QFETCH(QNetworkProxy::ProxyType, proxyType);
QFETCH(QString, hostName);
QFETCH(int, port);
qputenv(envVar, url);
const QList<QNetworkProxy> systemProxy = QNetworkProxyFactory::systemProxyForQuery();
QCOMPARE(systemProxy.size(), 1);
QCOMPARE(systemProxy.first().type(), proxyType);
QCOMPARE(systemProxy.first().hostName(), hostName);
QCOMPARE(systemProxy.first().port(), static_cast<quint16>(port));
qunsetenv(envVar);
}
void tst_QNetworkProxyFactory::genericSystemProxy_data()
{
// We can only use the generic system proxy where available:
#if defined(Q_OS_WIN) || defined(Q_OS_MACOS) || defined(Q_OS_ANDROID) || QT_CONFIG(libproxy)
QSKIP("Generic system proxy not available on this platform.");
#else
QTest::addColumn<QByteArray>("envVar");
QTest::addColumn<QByteArray>("url");
QTest::addColumn<QNetworkProxy::ProxyType>("proxyType");
QTest::addColumn<QString>("hostName");
QTest::addColumn<int>("port");
QTest::newRow("no proxy") << QByteArray("http_proxy") << QByteArray() << QNetworkProxy::NoProxy
<< QString() << 0;
QTest::newRow("socks5") << QByteArray("http_proxy") << QByteArray("socks5://127.0.0.1:4242")
<< QNetworkProxy::Socks5Proxy << QString("127.0.0.1") << 4242;
QTest::newRow("http") << QByteArray("http_proxy") << QByteArray("http://example.com:666")
<< QNetworkProxy::HttpProxy << QString("example.com") << 666;
#endif
}
class QSPFQThread : public QThread
{
protected:
void run() override
{
proxies = QNetworkProxyFactory::systemProxyForQuery(query);
}
public:
QNetworkProxyQuery query;
QList<QNetworkProxy> proxies;
};
//regression test for QTBUG-18799
void tst_QNetworkProxyFactory::systemProxyForQueryCalledFromThread()
{
if (QSysInfo::productType() == QLatin1String("windows") && QSysInfo::productVersion() == QLatin1String("7sp1")) {
QSKIP("This test fails by the systemProxyForQuery() call hanging - QTQAINFRA-1200");
}
QUrl url(QLatin1String("http://qt-project.org"));
QNetworkProxyQuery query(url);
QSPFQThread thread;
thread.query = query;
connect(&thread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
thread.start();
QTestEventLoop::instance().enterLoop(5);
QVERIFY(thread.isFinished());
QCOMPARE(thread.proxies, QNetworkProxyFactory::systemProxyForQuery(query));
}
QTEST_MAIN(tst_QNetworkProxyFactory)
#include "tst_qnetworkproxyfactory.moc"