From 4ca0c6db5e1b639c42e28e5046e283b2e3faaa4d Mon Sep 17 00:00:00 2001 From: Mate Barany Date: Tue, 18 Jun 2024 18:11:07 +0300 Subject: [PATCH] Add move semantics autotest for QFormDataBuilder Change-Id: If9df38f0afd09218c15587b2864edb957cbbdaac Reviewed-by: Marc Mutz (cherry picked from commit 12d2ba9c913d03d637ffb9d123949a5f45e69e5e) Reviewed-by: Qt Cherry-pick Bot --- src/network/access/qhttpmultipart_p.h | 2 +- tests/auto/network/access/CMakeLists.txt | 2 + .../access/qformdatabuilder/CMakeLists.txt | 12 +++ .../access/qformdatabuilder/rfc3252.txt | 2 +- .../qformdatabuilder/tst_qformdatabuilder.cpp | 94 +++++++++++++++++++ 5 files changed, 110 insertions(+), 2 deletions(-) diff --git a/src/network/access/qhttpmultipart_p.h b/src/network/access/qhttpmultipart_p.h index c2f23bb5951..39c147d2bc7 100644 --- a/src/network/access/qhttpmultipart_p.h +++ b/src/network/access/qhttpmultipart_p.h @@ -131,7 +131,7 @@ public: -class QHttpMultiPartPrivate: public QObjectPrivate +class Q_AUTOTEST_EXPORT QHttpMultiPartPrivate: public QObjectPrivate { public: diff --git a/tests/auto/network/access/CMakeLists.txt b/tests/auto/network/access/CMakeLists.txt index ed99aa87460..13332f02687 100644 --- a/tests/auto/network/access/CMakeLists.txt +++ b/tests/auto/network/access/CMakeLists.txt @@ -14,7 +14,9 @@ add_subdirectory(qnetworkcachemetadata) add_subdirectory(qabstractnetworkcache) if(QT_FEATURE_http) add_subdirectory(qnetworkreply_local) + if(NOT WASM) # QTBUG-121822 add_subdirectory(qformdatabuilder) + endif() add_subdirectory(qnetworkrequestfactory) add_subdirectory(qrestaccessmanager) endif() diff --git a/tests/auto/network/access/qformdatabuilder/CMakeLists.txt b/tests/auto/network/access/qformdatabuilder/CMakeLists.txt index dde2dc10e0c..59d1b54e2af 100644 --- a/tests/auto/network/access/qformdatabuilder/CMakeLists.txt +++ b/tests/auto/network/access/qformdatabuilder/CMakeLists.txt @@ -8,11 +8,17 @@ if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) endif() qt_internal_add_test(tst_qformdatabuilder + NO_BATCH # QTBUG-121815 + DEFINES + QTEST_THROW_ON_FAIL + QTEST_THROW_ON_SKIP SOURCES tst_qformdatabuilder.cpp LIBRARIES Qt::Core + Qt::CorePrivate Qt::Network + Qt::NetworkPrivate TESTDATA rfc3252.txt image1.jpg @@ -20,3 +26,9 @@ qt_internal_add_test(tst_qformdatabuilder sheet.xlsx ) +if(QT_FEATURE_sanitize_undefined) + qt_internal_extend_target(tst_qformdatabuilder + DEFINES + QT_SANITIZE_UNDEFINED # GCC (in)famously doesn't provide a predefined macro for this + ) +endif() diff --git a/tests/auto/network/access/qformdatabuilder/rfc3252.txt b/tests/auto/network/access/qformdatabuilder/rfc3252.txt index 5436ce5b26d..0521a80d121 100644 --- a/tests/auto/network/access/qformdatabuilder/rfc3252.txt +++ b/tests/auto/network/access/qformdatabuilder/rfc3252.txt @@ -1 +1 @@ -some text for reference +some text for reference \ No newline at end of file diff --git a/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp b/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp index 154edc806c1..bc6c4b44f01 100644 --- a/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp +++ b/tests/auto/network/access/qformdatabuilder/tst_qformdatabuilder.cpp @@ -1,6 +1,7 @@ // Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include #include #include @@ -8,12 +9,18 @@ #include +#ifndef QTEST_THROW_ON_FAIL +# error This test requires QTEST_THROW_ON_FAIL being active. +#endif + using namespace Qt::StringLiterals; class tst_QFormDataBuilder : public QObject { Q_OBJECT + void checkBodyPartsAreEquivalent(QByteArrayView expected, QByteArrayView actual); + private Q_SLOTS: void generateQHttpPartWithDevice_data(); void generateQHttpPartWithDevice(); @@ -32,8 +39,26 @@ private Q_SLOTS: void picksUtf8NameEncodingIfAsciiDoesNotSuffice_data(); void picksUtf8NameEncodingIfAsciiDoesNotSuffice(); + + void moveSemantics(); }; +void tst_QFormDataBuilder::checkBodyPartsAreEquivalent(QByteArrayView expected, QByteArrayView actual) +{ + qsizetype expectedCrlfPos = expected.indexOf("\r\n"); + qsizetype expectedBoundaryPos = expected.lastIndexOf("--boundary_.oOo."); + + qsizetype actualCrlfPos = actual.indexOf("\r\n"); + qsizetype actualBoundaryPos = actual.lastIndexOf("--boundary_.oOo."); + + qsizetype start = expectedCrlfPos + 2; + qsizetype end = expectedBoundaryPos - expectedCrlfPos - 2; + + QCOMPARE(actualCrlfPos, expectedCrlfPos); + QCOMPARE(actualBoundaryPos, expectedBoundaryPos); + QCOMPARE(actual.sliced(start, end), expected.sliced(start, end)); +} + void tst_QFormDataBuilder::generateQHttpPartWithDevice_data() { QTest::addColumn("name_data"); @@ -358,5 +383,74 @@ void tst_QFormDataBuilder::picksUtf8NameEncodingIfAsciiDoesNotSuffice() qPrintable(u"content-disposition not found : "_s + expected_content_disposition_data)); } +void tst_QFormDataBuilder::moveSemantics() +{ +#if defined(QT_BUILD_INTERNAL) || !defined(QT_UNDEFINED_SANITIZER) + constexpr QByteArrayView expected = "--boundary_.oOo._4SUrZy7x9lPHMF3fbRSsE15hiWu5Sbmy\r\n" + "content-type: text/plain\r\ncontent-disposition: form-data; name=\"text\"; filename=\"rfc3252.txt\"\r\n\r\n" + "some text for reference\r\n" + "--boundary_.oOo._4SUrZy7x9lPHMF3fbRSsE15hiWu5Sbmy--\r\n"; + + const QString testData = QFileInfo(QFINDTESTDATA("rfc3252.txt")).absoluteFilePath(); + + // We get the expected + { + QFile data_file(testData); + QVERIFY2(data_file.open(QIODeviceBase::ReadOnly), qPrintable(data_file.errorString())); + + QFormDataBuilder qfdb; + qfdb.part("text"_L1).setBodyDevice(&data_file, "rfc3252.txt"); + std::unique_ptr mp = qfdb.buildMultiPart(); + + auto mp_priv = QHttpMultiPartPrivate::get(mp.get()); + mp_priv->device->open(QIODeviceBase::ReadOnly); + const QByteArray actual = mp_priv->device->readAll(); + + checkBodyPartsAreEquivalent(expected, actual); + } + + // We get the expected from a move constructed qfdb + { + QFile data_file(testData); + QVERIFY2(data_file.open(QIODeviceBase::ReadOnly), qPrintable(data_file.errorString())); + + QFormDataBuilder qfdb; + auto &p = qfdb.part("text"_L1); + auto qfdb_moved = std::move(qfdb); + + p.setBodyDevice(&data_file, "rfc3252.txt"); + std::unique_ptr mp = qfdb_moved.buildMultiPart(); + + auto mp_priv = QHttpMultiPartPrivate::get(mp.get()); + mp_priv->device->open(QIODeviceBase::ReadOnly); + const QByteArray actual = mp_priv->device->readAll(); + + checkBodyPartsAreEquivalent(expected, actual); + } + + // We get the expected from a move assigned qfdb + { + QFile data_file(testData); + QVERIFY2(data_file.open(QIODeviceBase::ReadOnly), qPrintable(data_file.errorString())); + + QFormDataBuilder qfdb; + QFormDataBuilder qfdb_moved; + + qfdb.part("text"_L1).setBodyDevice(&data_file, "rfc3252.txt"); + + qfdb_moved = std::move(qfdb); + std::unique_ptr mp = qfdb_moved.buildMultiPart(); + + auto mp_priv = QHttpMultiPartPrivate::get(mp.get()); + mp_priv->device->open(QIODeviceBase::ReadOnly); + const QByteArray actual = mp_priv->device->readAll(); + + checkBodyPartsAreEquivalent(expected, actual); + } +#else + QSKIP("This test requires -developer-build when --sanitize=undefined is active."); +#endif +} + QTEST_MAIN(tst_QFormDataBuilder) #include "tst_qformdatabuilder.moc"