tst_QNetworkReply: don't leak on failure in emitErrorForAllReplies()

The old code allocated QSignalSpies on the heap and stored them in a
non-owning container, so if one of the many check macros trigger,
those objects would be leaked. Ditto QNetworkReplies. The code also
used dynamically-sized containers for statically-sized data; a common
anti-pattern.

Hold the sample QUrls in a C array instead, QSignalSpies in C arrays
of std::optional (to delay initialization) and QNetworkReplies in a C
array of std::unique_ptr with the existing QScopedPointerDeleteLater
deleter.

Change-Id: I7305115af15c079abba6d45c5de8db2198ea7a6d
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
(cherry picked from commit 20eba275d836e071c1ad8a5e4d1ef88fc5b23fca)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Marc Mutz 2024-03-19 18:31:28 +01:00 committed by Qt Cherry-pick Bot
parent 0c343c4c85
commit d272374203

View File

@ -8700,31 +8700,33 @@ void tst_QNetworkReply::ftpAuthentication()
void tst_QNetworkReply::emitErrorForAllReplies() // QTBUG-36890 void tst_QNetworkReply::emitErrorForAllReplies() // QTBUG-36890
{ {
// port 100 is not well-known and should be closed // port 100 is not well-known and should be closed
QList<QUrl> urls = QList<QUrl>() << QUrl("http://localhost:100/request1") const QUrl urls[] = {
<< QUrl("http://localhost:100/request2") QUrl("http://localhost:100/request1"),
<< QUrl("http://localhost:100/request3"); QUrl("http://localhost:100/request2"),
QList<QNetworkReply *> replies; QUrl("http://localhost:100/request3"),
QList<QSignalSpy *> errorSpies; };
QList<QSignalSpy *> finishedSpies; constexpr auto NUrls = std::size(urls);
for (int a = 0; a < urls.size(); ++a) {
QNetworkRequest request(urls.at(a)); std::unique_ptr<QNetworkReply, QScopedPointerDeleteLater> replies[NUrls];
std::optional<QSignalSpy> errorSpies[NUrls];
std::optional<QSignalSpy> finishedSpies[NUrls];
for (size_t i = 0; i < NUrls; ++i) {
QNetworkRequest request(urls[i]);
QNetworkReply *reply = manager.get(request); QNetworkReply *reply = manager.get(request);
replies.append(reply); replies[i].reset(reply);
QSignalSpy *errorSpy = new QSignalSpy(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError))); errorSpies[i].emplace(reply, SIGNAL(errorOccurred(QNetworkReply::NetworkError)));
errorSpies.append(errorSpy); finishedSpies[i].emplace(reply, SIGNAL(finished()));
QSignalSpy *finishedSpy = new QSignalSpy(reply, SIGNAL(finished()));
finishedSpies.append(finishedSpy);
QObject::connect(reply, SIGNAL(finished()), SLOT(emitErrorForAllRepliesSlot())); QObject::connect(reply, SIGNAL(finished()), SLOT(emitErrorForAllRepliesSlot()));
} }
QTestEventLoop::instance().enterLoop(10); QTestEventLoop::instance().enterLoop(10);
QVERIFY(!QTestEventLoop::instance().timeout()); QVERIFY(!QTestEventLoop::instance().timeout());
for (int a = 0; a < urls.size(); ++a) {
QVERIFY(replies.at(a)->isFinished()); for (size_t i = 0; i < NUrls; ++i) {
QCOMPARE(errorSpies.at(a)->size(), 1); QVERIFY(replies[i]->isFinished());
delete errorSpies.at(a); QCOMPARE(errorSpies[i]->size(), 1);
QCOMPARE(finishedSpies.at(a)->size(), 1); QCOMPARE(finishedSpies[i]->size(), 1);
delete finishedSpies.at(a);
replies.at(a)->deleteLater();
} }
} }