diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2021-09-27 18:27:15 -0700 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2021-12-17 17:54:05 +0100 |
commit | 46dc8e453ae1d0c1eb749cfebe686995f3a6cfd0 (patch) | |
tree | d7893f8e2ce0a0b1d1d8cb5dffd2aebe1c8de48c /tests/auto/corelib/serialization/qdatastream | |
parent | af36675afd4300387390ceaba35a81994751cb75 (diff) |
QVariant: use a typedef name when saving user types to QDataStream
Due to the way Qt 5 and 6 registered type names, they end up producing
different type names for the same content for a typedef. For example,
because Q_DECLARE_METATYPE can't manage a comma (it's a macro), users
are forced to write something like:
using MyTypeMap = QMap<QString, MyType>
Q_DECLARE_METATYPE(MyTypeMap)
Qt 5's Q_DECLARE_METATYPE's argument "MyTypeMap" was the only name we
knew about the type, so that's what got saved in the stream. However, Qt
6 QtPrivate::typenameHelper is much more clever and obtains the name
from the compiler itself, so it "sees through" the typedef and registers
"QMap<QString,MyType>" as the official type name.
If another library/plugin has a different typedef name for the same type
(e.g., StringTypeMap), it's indeterminate which type gets saved and will
even change from run to run (depends on the QHash order).
[ChangeLog][QtCore][QDataStream] If QDataStream is used with a
QDataStream::Version < Qt_6_0 to serialize a user type that was
registered via a typedef with the metatype system, the typedef's name is
used in the stream instead of the non-typedef name. This restores
compatibility with Qt 5, allowing existing content to read the same
QDataStreams; reading from older Qt 6 versions should not be affected.
(Note: if more than one typedef name is registered, it's indetermine
which name gets used)
Fixes: QTBUG-96916
Pick-to: 6.3 6.2
Change-Id: I2bbf422288924c198645fffd16a8d811aa58201e
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'tests/auto/corelib/serialization/qdatastream')
-rw-r--r-- | tests/auto/corelib/serialization/qdatastream/CMakeLists.txt | 2 | ||||
-rw-r--r-- | tests/auto/corelib/serialization/qdatastream/gen_typedefq5.cpp | 53 | ||||
-rw-r--r-- | tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp | 44 | ||||
-rw-r--r-- | tests/auto/corelib/serialization/qdatastream/typedef.q5 | bin | 0 -> 28 bytes |
4 files changed, 99 insertions, 0 deletions
diff --git a/tests/auto/corelib/serialization/qdatastream/CMakeLists.txt b/tests/auto/corelib/serialization/qdatastream/CMakeLists.txt index 136ff4ee19..b29088c712 100644 --- a/tests/auto/corelib/serialization/qdatastream/CMakeLists.txt +++ b/tests/auto/corelib/serialization/qdatastream/CMakeLists.txt @@ -6,6 +6,7 @@ # Collect test data list(APPEND test_data "datastream.q42") +list(APPEND test_data "typedef.q5") qt_internal_add_test(tst_qdatastream SOURCES @@ -22,6 +23,7 @@ if(ANDROID OR INTEGRITY) # Resources: set(testdata_resource_files "datastream.q42" + "typedef.q5" ) qt_internal_add_resource(tst_qdatastream "testdata" diff --git a/tests/auto/corelib/serialization/qdatastream/gen_typedefq5.cpp b/tests/auto/corelib/serialization/qdatastream/gen_typedefq5.cpp new file mode 100644 index 0000000000..3a10e40576 --- /dev/null +++ b/tests/auto/corelib/serialization/qdatastream/gen_typedefq5.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <QDataStream> +#include <QPair> +#include <QFile> +#include <QVariant> +#include <QDebug> + +using CustomPair = QPair<int, int>; +QDataStream &operator<<(QDataStream &ds, CustomPair pd) +{ return ds << pd.first << pd.second; } +QDataStream &operator>>(QDataStream &ds, CustomPair &pd) +{ return ds >> pd.first >> pd.second; } +Q_DECLARE_METATYPE(CustomPair) + + +int main() { + qRegisterMetaTypeStreamOperators<CustomPair>(); + QFile out("typedef.q5"); + out.open(QIODevice::ReadWrite); + QDataStream stream(&out); + stream.setVersion(QDataStream::Qt_5_15); + CustomPair p {42, 100}; + qDebug() << p.first << p.second; + stream << QVariant::fromValue(p); +} diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp index 8fbe8d745e..511d8f957f 100644 --- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp +++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp @@ -221,6 +221,8 @@ private slots: void nestedTransactionsResult_data(); void nestedTransactionsResult(); + void typedefQt5Compat(); + private: void writebool(QDataStream *s); void writeQBitArray(QDataStream *s); @@ -3872,6 +3874,48 @@ void tst_QDataStream::nestedTransactionsResult() QCOMPARE(int(stream.status()), expectedStatus); } +using CustomPair = QPair<int, int>; +QDataStream &operator<<(QDataStream &ds, CustomPair pd) +{ return ds << pd.first << pd.second; } +QDataStream &operator>>(QDataStream &ds, CustomPair &pd) +{ return ds >> pd.first >> pd.second; } + + +void tst_QDataStream::typedefQt5Compat() +{ + qRegisterMetaType<CustomPair>("CustomPair"); + QByteArray qt5Data; + { + // we can read the qt5 version + QFile in(QFINDTESTDATA("typedef.q5")); + QVERIFY(in.open(QIODevice::ReadOnly)); + qt5Data = in.readAll(); + QVERIFY(in.seek(0)); + QDataStream stream(&in); + stream.setVersion(QDataStream::Qt_5_15); + QVariant var; + stream >> var; + QCOMPARE(stream.status(), QDataStream::Ok); + CustomPair p = var.value<CustomPair>(); + QCOMPARE(p.first, 42); + QCOMPARE(p.second, 100); + } + { + // writing in Qt 6 results in the same file + QTemporaryDir dir; + QVERIFY(dir.isValid()); + QFile file(dir.filePath(u"typedef.q6"_qs)); + file.open(QIODevice::WriteOnly); + QDataStream stream(&file); + stream.setVersion(QDataStream::Qt_5_15); + CustomPair p {42, 100}; + stream << QVariant::fromValue(p); + file.close(); + file.open(QIODevice::ReadOnly); + QCOMPARE(file.readAll(), qt5Data); + } +} + QTEST_MAIN(tst_QDataStream) #include "tst_qdatastream.moc" diff --git a/tests/auto/corelib/serialization/qdatastream/typedef.q5 b/tests/auto/corelib/serialization/qdatastream/typedef.q5 Binary files differnew file mode 100644 index 0000000000..c6b5e8a4df --- /dev/null +++ b/tests/auto/corelib/serialization/qdatastream/typedef.q5 |