diff --git a/src/protobuf/CMakeLists.txt b/src/protobuf/CMakeLists.txt index 9caf93fb..cf094c22 100644 --- a/src/protobuf/CMakeLists.txt +++ b/src/protobuf/CMakeLists.txt @@ -5,11 +5,13 @@ qt_internal_add_module(Protobuf SOURCES qtprotobufglobal.h qabstractprotobufserializer.cpp qabstractprotobufserializer.h + qprotobufbaseserializer.cpp qprotobufbaseserializer.h qprotobufmessage.cpp qprotobufmessage.h qprotobufmessage_p.h qprotobuflazymessagepointer.h qprotobufobject.h qprotobufselfcheckiterator.h qprotobufserializer.cpp qprotobufserializer.h qprotobufserializer_p.h + qprotobufjsonserializer.cpp qprotobufjsonserializer.h qtprotobuflogging.cpp qtprotobuflogging_p.h qtprotobuftypes.cpp qtprotobuftypes.h qprotobufoneof.cpp qprotobufoneof.h diff --git a/src/protobuf/qprotobufbaseserializer.cpp b/src/protobuf/qprotobufbaseserializer.cpp new file mode 100644 index 00000000..8cea8c20 --- /dev/null +++ b/src/protobuf/qprotobufbaseserializer.cpp @@ -0,0 +1,85 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qprotobufbaseserializer.h" + +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QProtobufBaseSerializer + \inmodule QtProtobuf + \since 6.7 + \brief The QProtobufBaseSerializer class is an interface that represents + basic functions for serializing/deserializing objects, lists, and enums. + + The QProtobufBaseSerializer class registers serializers/deserializers for + classes implementing a protobuf message, inheriting QProtobufMessage. These + classes are generated automatically, based on a .proto file, using the cmake + build macro qt6_add_protobuf or by running qtprotobufgen directly. + + This class should be used as a base for specific serializers. The handlers + property contains all message-specific serializers and should be used while + serialization/deserialization. Inherited classes should reimplement scope of + virtual methods that used by registered message + serialization/deserialization functions. +*/ + +/*! + Destroys this QProtobufBaseSerializer. +*/ +QProtobufBaseSerializer::~QProtobufBaseSerializer() = default; + +/*! + \fn QByteArray QProtobufBaseSerializer::serializeObject(const QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const + + This function serializes a registered Protobuf message \a message + with defined \a ordering and \a fieldInfo, that is recognized + like an object, into a QByteArray. \a message must not be \nullptr. + + \sa deserializeObject() +*/ + +/*! + \fn bool QProtobufBaseSerializer::deserializeObject(QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const + + This function deserializes a registered Protobuf message \a message + with defined \a ordering from the \a it iterator. \a message must not be \nullptr. + Returns \c true if deserialization was successful, otherwise \c false. + + \sa serializeObject() +*/ + +/*! + \relates QProtobufBaseSerializer + \fn template inline void qRegisterProtobufType() + + Registers a Protobuf type \e T. + This function is normally called by generated code. +*/ + +/*! + \relates QProtobufBaseSerializer + \fn template inline void qRegisterProtobufMapType(); + + Registers a Protobuf map type \c K and \c V. + \c V must be a QProtobufMessage. + This function is normally called by generated code. +*/ + +/*! + \relates QProtobufBaseSerializer + \fn template inline void qRegisterProtobufEnumType(); + + Registers serializers for enumeration type \c T in QtProtobuf global + serializers registry. + + This function is normally called by generated code. +*/ + +QT_END_NAMESPACE diff --git a/src/protobuf/qprotobufbaseserializer.h b/src/protobuf/qprotobufbaseserializer.h new file mode 100644 index 00000000..aee26da8 --- /dev/null +++ b/src/protobuf/qprotobufbaseserializer.h @@ -0,0 +1,347 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QPROTOBUFSBASEERIALIZER_H +#define QPROTOBUFSBASEERIALIZER_H + +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_PROTOBUF_EXPORT QProtobufBaseSerializer: public QAbstractProtobufSerializer +{ + +public: + enum Status { + Serialized = 0, + SerializationInProgress, + SerializationError + }; + + virtual ~QProtobufBaseSerializer(); + + virtual QByteArray + serializeObject(const QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const = 0; + virtual bool deserializeObject(QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const = 0; + + virtual QByteArray + serializeListObject(const QList &messageList, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const = 0; + virtual Status + deserializeListObject(QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const = 0; + + virtual QByteArray + serializeMapPair(const QList> &list, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const = 0; + virtual Status deserializeMapPair(QVariant &key, QVariant &value, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const = 0; + + virtual QByteArray + serializeEnum(QtProtobuf::int64 value, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const = 0; + virtual QByteArray + serializeEnumList(const QList &value, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const = 0; + virtual bool deserializeEnum(QtProtobuf::int64 &value, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const = 0; + virtual bool + deserializeEnumList(QList &value, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const = 0; +}; + +namespace QtProtobufPrivate { + +using Serializer = void (*)(const QProtobufBaseSerializer *, const QVariant &, + const QProtobufPropertyOrderingInfo &, QByteArray &); +using Deserializer = void (*)(const QProtobufBaseSerializer *, QProtobufSelfcheckIterator &, + QVariant &); + +/*! + \private + \brief SerializationHandlers contains set of objects that required for class + serialization/deserialization + */ +struct SerializationHandler +{ + Serializer serializer = nullptr; /*!< serializer assigned to class */ + Deserializer deserializer = nullptr; /*!< deserializer assigned to class */ +}; + +extern Q_PROTOBUF_EXPORT SerializationHandler findHandler(QMetaType type); +extern Q_PROTOBUF_EXPORT void registerHandler(QMetaType type, const SerializationHandler &handlers); + +/*! + \private + \brief default serializer template for type T that inherits from QProtobufMessage + */ +template::value, int> = 0> +void serializeObject(const QProtobufBaseSerializer *serializer, const QVariant &value, + const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + buffer.append(serializer->serializeObject(value.value(), T::propertyOrdering, fieldInfo)); +} + +/*! + \private + \brief default serializer template for list of type T objects that inherits from QProtobufMessage + */ +template::value, int> = 0> +void serializeList(const QProtobufBaseSerializer *serializer, const QVariant &listValue, + const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + QList objList = listValue.value>(); + QList messageList; + for (const auto &value : objList) + messageList.append(&value); + buffer.append(serializer->serializeListObject(messageList, V::propertyOrdering, fieldInfo)); +} + +/*! + \private + \brief default serializer template for map of key K, value V + */ +template::value, int> = 0> +void serializeMap(const QProtobufBaseSerializer *serializer, const QVariant &value, + const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + QHash original = value.value>(); + QList> variantContainer; + for (const auto &[k, v] : original.asKeyValueRange()) { + variantContainer.append(qMakePair(QVariant::fromValue(k), + QVariant::fromValue(v))); + } + buffer.append(serializer->serializeMapPair(variantContainer, fieldInfo)); + +} + +/*! + \private + \brief default serializer template for map of type key K, value V. Specialization for V that + inherits from QProtobufMessage + */ +template::value, int> = 0> +void serializeMap(const QProtobufBaseSerializer *serializer, const QVariant &value, + const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + QHash original = value.value>(); + QList> variantContainer; + for (const auto &[k, v] : original.asKeyValueRange()) { + variantContainer.append(qMakePair(QVariant::fromValue(k), + QVariant::fromValue(&v))); + + } + buffer.append(serializer->serializeMapPair(variantContainer, fieldInfo)); +} + +/*! + \private + \brief default serializer template for enum types + */ +template::value, int> = 0> +void serializeEnum(const QProtobufBaseSerializer *serializer, const QVariant &value, + const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + buffer.append(serializer->serializeEnum(QtProtobuf::int64(value.value()), fieldInfo)); +} + +/*! + \private + \brief default serializer template for enum list types + */ +template::value, int> = 0> +void serializeEnumList(const QProtobufBaseSerializer *serializer, const QVariant &value, + const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + QList intList; + for (auto enumValue : value.value>()) { + intList.append(QtProtobuf::int64(enumValue)); + } + buffer.append(serializer->serializeEnumList(intList, fieldInfo)); +} + +/*! + \private + \brief default deserializer template for type T that inherits from QProtobufMessage + */ +template::value, int> = 0> +void deserializeObject(const QProtobufBaseSerializer *serializer, QProtobufSelfcheckIterator &it, + QVariant &to) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + Q_ASSERT_X(to.isNull() || to.metaType() == QMetaType::fromType(), + "QProtobufBaseSerializer", + "Property should be either uninitialized or contain a valid pointer"); + + T *value = to.value(); + if (value == nullptr) { + value = new T; + to = QVariant::fromValue(value); + } + serializer->deserializeObject(value, T::propertyOrdering, it); +} + +/*! + \private + \brief default deserializer template for list of type T objects that inherits from QProtobufMessage + */ +template::value, int> = 0> +void deserializeList(const QProtobufBaseSerializer *serializer, QProtobufSelfcheckIterator &it, + QVariant &previous) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + + V newValue; + QProtobufBaseSerializer::Status result = QProtobufBaseSerializer::SerializationError; + do { + result = serializer->deserializeListObject(&newValue, V::propertyOrdering, it); + QList list = previous.value>(); + list.append(newValue); + previous.setValue(list); + } while (result == QProtobufBaseSerializer::SerializationInProgress); +} + +/*! + \private + * + \brief default deserializer template for map of key K, value V + */ +template::value, int> = 0> +void deserializeMap(const QProtobufBaseSerializer *serializer, QProtobufSelfcheckIterator &it, + QVariant &previous) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + + QHash out = previous.value>(); + QVariant key = QVariant::fromValue(K()); + QVariant value = QVariant::fromValue(V()); + + if (serializer->deserializeMapPair(key, value, it) == QProtobufBaseSerializer::Serialized) { + out[key.value()] = value.value(); + previous = QVariant::fromValue>(out); + } +} + +/*! + \private + * + \brief default deserializer template for map of type key K, value V. Specialization for V + that inherits from QProtobufMessage + */ +template::value, int> = 0> +void deserializeMap(const QProtobufBaseSerializer *serializer, QProtobufSelfcheckIterator &it, + QVariant &previous) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + + auto out = previous.value>(); + QVariant key = QVariant::fromValue(K()); + QVariant value = QVariant::fromValue(nullptr); + + if (serializer->deserializeMapPair(key, value, it) == QProtobufBaseSerializer::Serialized) { + const auto valuePtr = value.value(); + out[key.value()] = valuePtr ? *valuePtr : V(); + previous = QVariant::fromValue>(out); + } +} + +/*! + \private + * + \brief default deserializer template for enum type T + */ +template::value, int> = 0> +void deserializeEnum(const QProtobufBaseSerializer *serializer, QProtobufSelfcheckIterator &it, + QVariant &to) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + QtProtobuf::int64 intValue; + if (serializer->deserializeEnum(intValue, it)) + to = QVariant::fromValue(static_cast(intValue._t)); +} + +/*! + \private + * + \brief default deserializer template for enumList type T + */ +template::value, int> = 0> +void deserializeEnumList(const QProtobufBaseSerializer *serializer, QProtobufSelfcheckIterator &it, + QVariant &previous) +{ + Q_ASSERT_X(serializer != nullptr, "QProtobufBaseSerializer", "Serializer is null"); + QList intList; + if (!serializer->deserializeEnumList(intList, it)) + return; + QList enumList = previous.value>(); + for (auto intValue : intList) + enumList.append(static_cast(intValue._t)); + previous = QVariant::fromValue>(enumList); +} +} // namespace QtProtobufPrivate + +template +inline void qRegisterProtobufType() +{ + T::registerTypes(); + QtProtobufPrivate::registerOrdering(QMetaType::fromType(), T::propertyOrdering); + QtProtobufPrivate::registerHandler( + QMetaType::fromType(), + { QtProtobufPrivate::serializeObject, QtProtobufPrivate::deserializeObject }); + QtProtobufPrivate::registerHandler( + QMetaType::fromType>(), + { QtProtobufPrivate::serializeList, QtProtobufPrivate::deserializeList }); +} + +template +inline void qRegisterProtobufMapType() +{ + QtProtobufPrivate::registerHandler( + QMetaType::fromType>(), + { QtProtobufPrivate::serializeMap, QtProtobufPrivate::deserializeMap }); +} + +#ifdef Q_QDOC +template +inline void qRegisterProtobufEnumType(); +#else // !Q_QDOC +template::value, int> = 0> +inline void qRegisterProtobufEnumType() +{ + QtProtobufPrivate::registerHandler( + QMetaType::fromType(), + { QtProtobufPrivate::serializeEnum, QtProtobufPrivate::deserializeEnum }); + QtProtobufPrivate::registerHandler( + QMetaType::fromType>(), + { QtProtobufPrivate::serializeEnumList, QtProtobufPrivate::deserializeEnumList }); +} +#endif // Q_QDOC + +QT_END_NAMESPACE +#endif // QPROTOBUFSBASEERIALIZER_H diff --git a/src/protobuf/qprotobufjsonserializer.cpp b/src/protobuf/qprotobufjsonserializer.cpp new file mode 100644 index 00000000..0488faf4 --- /dev/null +++ b/src/protobuf/qprotobufjsonserializer.cpp @@ -0,0 +1,679 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qprotobufjsonserializer.h" +#include "qprotobufserializer_p.h" +#include "qprotobufmessage_p.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +QT_BEGIN_NAMESPACE + +/*! + \class QProtobufJsonSerializer + \inmodule QtProtobuf + \since 6.7 + \brief The QProtobufJsonSerializer class is interface that represents + basic functions for serialization/deserialization of QProtobufMessage + objects to Json. + \reentrant + + The QProtobufJsonSerializer class registers serializers/deserializers for + classes implementing a protobuf message, inheriting QProtobufMessage. These + classes are generated automatically, based on a .proto file, using the cmake + build macro qt6_add_protobuf or by running qtprotobufgen directly. +*/ + + +/*! + \fn QAbstractProtobufSerializer::DeserializationError QProtobufJsonSerializer::deserializationError() const + + Returns the last deserialization error. +*/ + +/*! + \fn QString QProtobufJsonSerializer::deserializationErrorString() const + + Returns a human-readable string describing the last deserialization error. + If there was no error, an empty string is returned. +*/ + +using namespace Qt::StringLiterals; +using namespace QtProtobufPrivate; + +class QProtobufJsonSerializerPrivate final +{ + Q_DISABLE_COPY_MOVE(QProtobufJsonSerializerPrivate) + +public: + using Serializer = std::function; + using Deserializer = std::function; + + struct SerializationHandlers { + // serializer assigned to class + Serializer serializer; + // deserializer assigned to class + Deserializer deserializer; + }; + + // TBD Replace std::unordered_map to QHash + using SerializerRegistry = std::unordered_map; + + static QByteArray serializeFloat(const QVariant &propertyValue) + { + bool ok = false; + float value = propertyValue.toFloat(&ok); + if (!ok || qIsNaN(value)) { + return QByteArray("NaN"); + } + return QByteArray::number(value, 'g', 7); + } + + static QByteArray serializeDouble(const QVariant &propertyValue) + { + bool ok = false; + double value = propertyValue.toDouble(&ok); + if (!ok || qIsNaN(value)) { + return QByteArray("NaN"); + } + return QByteArray::number(value, 'g', 14); + } + + static QByteArray serializeString(const QVariant &propertyValue) + { + return '"' + propertyValue.toString().toUtf8() + '"'; + } + + static QByteArray serializeBytes(const QVariant &propertyValue) { + return QByteArray("\"") + propertyValue.toByteArray().toBase64() + "\""; + } + + template + static QByteArray serializeList(const QVariant &propertyValue) + { + L listValue = propertyValue.value(); + QByteArray result("["); + for (auto value : listValue) { + result += QByteArray::number(value) + ","; + } + //Remove trailing `,` + if (listValue.size() > 0) { + result.chop(1); + } + result += "]"; + return result; + } + + static QByteArray serializeBoolList(const QVariant &propertyValue) + { + QtProtobuf::boolList listValue = propertyValue.value(); + QByteArray result("["); + for (auto value : listValue) { + if (value) + result += QByteArray("true,"); + else + result += QByteArray("false,"); + } + if (listValue.size() > 0) { + result.chop(1); + } + result += "]"; + return result; + } + + static QByteArray serializeFloatList(const QVariant &propertyValue) + { + QtProtobuf::floatList listValue = propertyValue.value(); + QByteArray result("["); + for (auto value : listValue) { + if (qIsNaN(value)) + return QByteArray("NaN"); + result += QByteArray::number(value, 'g', 7) + ","; + } + if (listValue.size() > 0) { + result.chop(1); + } + result += "]"; + return result; + } + + static QByteArray serializeStringList(const QVariant &propertyValue) + { + QStringList listValue = propertyValue.value(); + QByteArray result("["); + for (auto value : listValue) { + result += QByteArray("\"") + value.toUtf8() + "\","; + } + if (listValue.size() > 0) { + result.chop(1); + } + result += "]"; + return result; + } + + static QByteArray serializeBytesList(const QVariant &propertyValue) + { + QByteArrayList listValue = propertyValue.value(); + QByteArray result("["); + for (auto value : listValue) { + result += QByteArray("\"") + value.toBase64() + "\","; + } + if (listValue.size() > 0) { + result.chop(1); + } + result += "]"; + return result; + } + + static QByteArray serializeDoubleList(const QVariant &propertyValue) + { + QtProtobuf::doubleList listValue = propertyValue.value(); + QByteArray result("["); + for (auto value : listValue) { + if (qIsNaN(value)) + return QByteArray("NaN"); + result += QByteArray::number(value, 'g', 14) + ","; + } + if (listValue.size() > 0) { + result.chop(1); + } + result += "]"; + return result; + } + + QProtobufJsonSerializerPrivate(QProtobufJsonSerializer *q) + : qPtr(q) + { + // TBD Change to assigning the result of a lambda to a static variable + if (handlers.empty()) { + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeInt32}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeInt32}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeInt32}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeInt64}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeInt64}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeInt64}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeUInt32}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeUInt32}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeUInt64}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeUInt64}; + handlers[qMetaTypeId()] + = {{}, QProtobufJsonSerializerPrivate::deserializeBool}; + handlers[QMetaType::Float] = {QProtobufJsonSerializerPrivate::serializeFloat, + QProtobufJsonSerializerPrivate::deserializeFloat}; + handlers[QMetaType::Double] = {QProtobufJsonSerializerPrivate::serializeDouble, + QProtobufJsonSerializerPrivate::deserializeDouble}; + handlers[QMetaType::QString] + = {QProtobufJsonSerializerPrivate::serializeString, + QProtobufJsonSerializerPrivate::deserializeString}; + handlers[QMetaType::QByteArray] + = {QProtobufJsonSerializerPrivate::serializeBytes, + QProtobufJsonSerializerPrivate::deserializeByteArray}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeBoolList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeFloatList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeDoubleList, + QProtobufJsonSerializerPrivate::deserializeList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeStringList, + QProtobufJsonSerializerPrivate::deserializeStringList}; + handlers[qMetaTypeId()] + = {QProtobufJsonSerializerPrivate::serializeBytesList, + QProtobufJsonSerializerPrivate::deserializeList}; + } + } + ~QProtobufJsonSerializerPrivate() = default; + + QByteArray serializeValue(const QVariant &propertyValue, + const QProtobufPropertyOrderingInfo &fieldInfo) + { + QByteArray buffer; + QMetaType metaType = propertyValue.metaType(); + auto userType = propertyValue.userType(); + + if (metaType.id() == QMetaType::UnknownType) { + return {}; + } + auto handler = QtProtobufPrivate::findHandler(metaType); + if (handler.serializer) { + handler.serializer(qPtr, propertyValue, fieldInfo, buffer); + } else { + auto handler = handlers.find(userType); + if (handler != handlers.end() && handler->second.serializer) { + buffer += handler->second.serializer(propertyValue); + } else { + buffer += propertyValue.toString().toUtf8(); + } + } + return buffer; + } + + QByteArray serializeProperty(const QVariant &propertyValue, + const QProtobufPropertyOrderingInfo &fieldInfo) + { + return QByteArray("\"") + + QByteArrayView(fieldInfo.getJsonName()) + + QByteArray("\":") + serializeValue(propertyValue, fieldInfo); + } + + QByteArray serializeObject(const QProtobufMessage *message, + const QProtobufPropertyOrdering &ordering) + { + QByteArray result = "{"; + // if a message is not initialized, just return empty { } + if (message) { + for (int index = 0; index < ordering.fieldCount(); ++index) { + int fieldIndex = ordering.getFieldNumber(index); + Q_ASSERT_X(fieldIndex < 536870912 && fieldIndex > 0, + "", + "fieldIndex is out of range"); + QProtobufPropertyOrderingInfo fieldInfo(ordering, index); + QVariant propertyValue = message->property(fieldInfo); + result.append(serializeProperty(propertyValue, fieldInfo)); + result.append(","); + } + result.chop(1); + } + result.append("}"); + return result; + } + + static QVariant deserializeInt32(const QJsonValue &value, bool &ok) + { + auto val = value.toInt(); + ok = value.isDouble(); + return QVariant::fromValue(val); + } + + static QVariant deserializeUInt32(const QJsonValue &value, bool &ok) + { + auto val = value.toVariant().toUInt(&ok); + return QVariant::fromValue(val); + } + + static QVariant deserializeInt64(const QJsonValue &value, bool &ok) + { + auto val = value.toVariant().toLongLong(&ok); + return QVariant::fromValue(val); + } + + static QVariant deserializeUInt64(const QJsonValue &value, bool &ok) + { + auto val = value.toVariant().toULongLong(&ok); + return QVariant::fromValue(val); + } + + static QVariant deserializeFloat(const QJsonValue &value, bool &ok) + { + QByteArray data = value.toVariant().toByteArray(); + if (data == "NaN" || data == "Infinity" || data == "-Infinity") { + ok = true; + return QVariant(data); + } + auto val = data.toFloat(&ok); + return QVariant::fromValue(val); + } + + static QVariant deserializeDouble(const QJsonValue &value, bool &ok) + { + QByteArray data = value.toVariant().toByteArray(); + if (data == "NaN" || data == "Infinity" || data == "-Infinity") { + ok = true; + return QVariant(data); + } + auto val = data.toDouble(&ok); + return QVariant::fromValue(val); + } + + static QVariant deserializeBool(const QJsonValue &value, bool &ok) + { + ok = value.isBool(); + return (value.isBool()) ? QVariant(value.toBool()) : QVariant(); + } + + static QVariant deserializeString(const QJsonValue &value, bool &ok) + { + ok = value.isString(); + return value.toString(); + } + + static QVariant deserializeByteArray(const QJsonValue &value, bool &ok) + { + QByteArray data = value.toVariant().toByteArray(); + if (value.isString()) { + ok = true; + return QVariant::fromValue(QByteArray::fromBase64(data)); + } + ok = false; + return QVariant(); + } + + template + static QVariant deserializeList(const QJsonValue &value, bool &ok) + { + if (!value.isArray()) { + ok = false; + return QVariant(); + } + ok = true; + QList list; + QJsonArray array = value.toArray(); + auto handler = handlers.find(qMetaTypeId()); + if (handler == handlers.end() || !handler->second.deserializer) { + qProtoWarning() << "Unable to deserialize simple type list." + "Could not find deserializer for type" + << QMetaType::fromType().name(); + return QVariant::fromValue(list); + } + + for (auto arrayValue : array) { + bool valueOk = false; + QVariant newValue = handler->second.deserializer(arrayValue, valueOk); + list.append(newValue.value()); + } + return QVariant::fromValue(list); + } + + static QVariant deserializeStringList(const QJsonValue &value, bool &ok) + { + if (!value.isArray()) { + ok = false; + return QVariant(); + } + QStringList list; + if (value.isArray()) { + QJsonArray array = value.toArray(); + for (auto arrayValue : array) { + QVariant newValue = deserializeString(arrayValue, ok); + list.append(newValue.value()); + } + } + return QVariant::fromValue(list); + } + + QVariant deserializeValue(const QMetaType &metaType, + QProtobufSelfcheckIterator &it, + const QJsonValue &value, + bool &ok) + { + QVariant result; + auto handler = QtProtobufPrivate::findHandler(metaType); + if (handler.deserializer) { + handler.deserializer(qPtr, it, result); + ok = result.isValid(); + } else { + auto handler = handlers.find(metaType.id()); + if (handler != handlers.end() && handler->second.deserializer) { + result = handler->second.deserializer(value, ok); + } else { + QString error = QString::fromUtf8("No deserializer is registered for value %1") + .arg(QString::fromUtf8(metaType.name())); + setDeserializationError( + QAbstractProtobufSerializer::NoDeserializerError, + QCoreApplication::translate("QtProtobuf", + error.toUtf8().data())); + } + } + return result; + } + + bool deserializeObject(QProtobufMessage *message, + const QProtobufPropertyOrdering &ordering, + QByteArrayView data) + { + auto it = QProtobufSelfcheckIterator::fromView(data); + Q_ASSERT(it.isValid() && it.bytesLeft() > 0); + + bool ok = false; + // TBD Try fromJson(QBAView) instead of current variant + QJsonDocument document + = QJsonDocument::fromJson(QByteArray(data.data(), static_cast(data.size()))); + + if (!document.isObject()) + return false; + + std::map msgContainer; // map + for (int index = 0; index < ordering.fieldCount(); ++index) { + int fieldIndex = ordering.getFieldNumber(index); + Q_ASSERT_X(fieldIndex < 536870912 && fieldIndex > 0, "", "fieldIndex is out of range"); + QProtobufPropertyOrderingInfo fieldInfo(ordering, index); + QString key = fieldInfo.getJsonName().toString(); + msgContainer.insert(std::pair(key, fieldInfo)); + } + + QByteArray object; + // Go through QJSON doc and find keys that are presented in msgContainer + QJsonObject obj = document.object(); + for (auto &key : obj.keys()) { + QJsonValue jsonValue = obj.value(key); + auto iter = msgContainer.find(key); + if (iter != msgContainer.end()) { + QVariant newPropertyValue = message->property(iter->second); + // Complex message case; move iterator to the deserializing array + if (jsonValue.isArray()) { + QJsonArray array = jsonValue.toArray(); + object = QJsonDocument(array).toJson(); + it = QProtobufSelfcheckIterator::fromView(object); + } + // Complex message case; move iterator to the deserializing object + if (jsonValue.isObject()) { + object = QJsonDocument(jsonValue.toObject()).toJson(); + it = QProtobufSelfcheckIterator::fromView(object); + } + newPropertyValue = deserializeValue(newPropertyValue.metaType(), + it, + jsonValue, + ok); + if (ok) { + message->setProperty(iter->second, std::move(newPropertyValue)); + } + } + } + + return ok; + } + + void setDeserializationError(QAbstractProtobufSerializer::DeserializationError error, + const QString &errorString) + { + deserializationError = error; + deserializationErrorString = errorString; + } + + void setUnexpectedEndOfStreamError() + { + setDeserializationError(QAbstractProtobufSerializer::UnexpectedEndOfStreamError, + QCoreApplication::translate("QtProtobuf", + "Unexpected end of stream")); + } + + void clearError(); + + QAbstractProtobufSerializer::DeserializationError deserializationError = + QAbstractProtobufSerializer::NoDeserializerError; + QString deserializationErrorString; + QJsonArray activeArray; + +private: + static SerializerRegistry handlers; + QProtobufJsonSerializer *qPtr; +}; + +QProtobufJsonSerializerPrivate::SerializerRegistry QProtobufJsonSerializerPrivate::handlers = {}; + +void QProtobufJsonSerializerPrivate::clearError() +{ + deserializationError = QAbstractProtobufSerializer::NoError; + deserializationErrorString.clear(); +} + +QProtobufJsonSerializer::QProtobufJsonSerializer() : + d_ptr(new QProtobufJsonSerializerPrivate(this)) +{ +} + +QProtobufJsonSerializer::~QProtobufJsonSerializer() = default; + +QAbstractProtobufSerializer::DeserializationError +QProtobufJsonSerializer::deserializationError() const +{ + return d_ptr->deserializationError; +} + +QString QProtobufJsonSerializer::deserializationErrorString() const +{ + return d_ptr->deserializationErrorString; +} + +QByteArray +QProtobufJsonSerializer::serializeMessage(const QProtobufMessage *message, + const QProtobufPropertyOrdering &ordering) const +{ + return d_ptr->serializeObject(message, ordering); +} + +bool QProtobufJsonSerializer::deserializeMessage(QProtobufMessage *message, + const QProtobufPropertyOrdering &ordering, + QByteArrayView data) const +{ + d_ptr->clearError(); + auto it = QProtobufSelfcheckIterator::fromView(data); + if (!d_ptr->deserializeObject(message, ordering, data)) + return false; + + if (!it.isValid()) + d_ptr->setUnexpectedEndOfStreamError(); + return it.isValid(); +} + +QByteArray +QProtobufJsonSerializer::serializeObject(const QProtobufMessage *message, + const QProtobufPropertyOrdering &ordering, + const QProtobufPropertyOrderingInfo &fieldInfo) const +{ + Q_UNUSED(fieldInfo); + return serializeMessage(message, ordering); +} + +QByteArray +QProtobufJsonSerializer::serializeListObject(const QList &messageList, + const QProtobufPropertyOrdering &ordering, + const QProtobufPropertyOrderingInfo &fieldInfo) const +{ + QByteArray result("["); + for (auto message : messageList) { + result.append(serializeObject(message, ordering, fieldInfo) + ","); + } + if (messageList.size() > 0) { + result.chop(1); + } + result.append("]"); + return result; +} + +bool QProtobufJsonSerializer::deserializeObject(QProtobufMessage *message, + const QProtobufPropertyOrdering &ordering, + QProtobufSelfcheckIterator &it) const +{ + return deserializeMessage(message, ordering, it.data()); +} + +QProtobufBaseSerializer::Status +QProtobufJsonSerializer::deserializeListObject(QProtobufMessage *message, + const QProtobufPropertyOrdering &ordering, + QProtobufSelfcheckIterator &it) const +{ + if (d_ptr->activeArray.empty()) { + QJsonDocument doc = QJsonDocument::fromJson(QByteArray(it.data(), it.bytesLeft())); + if (doc.isArray()) + d_ptr->activeArray = doc.array(); + else + return QProtobufBaseSerializer::SerializationError; + } + + // doc.array() is empty + if (d_ptr->activeArray.empty()) + return QProtobufBaseSerializer::SerializationError; + + const QJsonValue &element = d_ptr->activeArray.takeAt(0); + if (element.isObject()) { + auto newIt + = QProtobufSelfcheckIterator::fromView(QJsonDocument(element.toObject()).toJson()); + bool result = deserializeObject(message, ordering, newIt); + + if (!d_ptr->activeArray.empty()) { + return QProtobufBaseSerializer::SerializationInProgress; + } else { + return result ? QProtobufBaseSerializer::Serialized + : QProtobufBaseSerializer::SerializationError; + } + } + + return QProtobufBaseSerializer::SerializationError; +} + +QByteArray QProtobufJsonSerializer::serializeMapPair(const QList> &list, + const QProtobufPropertyOrderingInfo &fieldInfo + ) const +{ + Q_UNUSED(fieldInfo); + QByteArray result; + for (auto element: list) { + const QVariant &key = element.first; + qProtoWarning() << "Map pair serialization will be done soon:" << key << element.second; + } + return result; +} + +QT_END_NAMESPACE diff --git a/src/protobuf/qprotobufjsonserializer.h b/src/protobuf/qprotobufjsonserializer.h new file mode 100644 index 00000000..20e576ad --- /dev/null +++ b/src/protobuf/qprotobufjsonserializer.h @@ -0,0 +1,113 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QPROTOBUFJSONSERIALIZER_H +#define QPROTOBUFJSONSERIALIZER_H + +#include +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +class QProtobufJsonSerializerPrivate; +class Q_PROTOBUF_EXPORT QProtobufJsonSerializer : public QProtobufBaseSerializer +{ + Q_DISABLE_COPY_MOVE(QProtobufJsonSerializer) + +public: + QProtobufJsonSerializer(); + ~QProtobufJsonSerializer() override; + + QAbstractProtobufSerializer::DeserializationError deserializationError() const override; + QString deserializationErrorString() const override; + + QByteArray serializeMessage(const QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering + ) const override; + + bool deserializeMessage(QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + QByteArrayView data) const override; + + QByteArray serializeObject(const QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo + ) const override; + bool deserializeObject(QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const override; + + QByteArray + serializeListObject(const QList &messageList, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo + ) const override; + + QProtobufBaseSerializer::Status + deserializeListObject(QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const override; + + QByteArray + serializeMapPair(const QList> &list, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo + ) const override; + + QProtobufBaseSerializer::Status + deserializeMapPair(QVariant &key, QVariant &value, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const override + { + Q_UNUSED(key); + Q_UNUSED(value); + Q_UNUSED(it); + return QProtobufBaseSerializer::SerializationError; + } + + QByteArray + serializeEnum(QtProtobuf::int64 value, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const override + { + Q_UNUSED(value); + Q_UNUSED(fieldInfo); + return QByteArray(); + } + + QByteArray + serializeEnumList(const QList &value, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo + ) const override + { + Q_UNUSED(value); + Q_UNUSED(fieldInfo); + return QByteArray(); + } + + Q_REQUIRED_RESULT + bool deserializeEnum(QtProtobuf::int64 &value, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const override + { + Q_UNUSED(value); + Q_UNUSED(it); + return false; + } + + Q_REQUIRED_RESULT bool + deserializeEnumList(QList &value, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const override + { + Q_UNUSED(value); + Q_UNUSED(it); + return false; + } + +private: + std::unique_ptr d_ptr; +}; + +QT_END_NAMESPACE + +#endif // QPROTOBUFJSONSERIALIZER_H + diff --git a/src/protobuf/qprotobufmessage.h b/src/protobuf/qprotobufmessage.h index 7f9e0697..a5a7dcd7 100644 --- a/src/protobuf/qprotobufmessage.h +++ b/src/protobuf/qprotobufmessage.h @@ -62,8 +62,9 @@ private: friend class QProtobufSerializer; friend class QAbstractProtobufSerializer; + friend class QProtobufBaseSerializer; friend class QProtobufSerializerPrivate; - friend class QAbstractProtobufSerializer; + friend class QProtobufJsonSerializerPrivate; friend struct QProtobufMessageDeleter; QProtobufMessagePrivate *d_ptr; diff --git a/src/protobuf/qprotobufserializer.cpp b/src/protobuf/qprotobufserializer.cpp index 4f0ce2e0..f1e2e9d4 100644 --- a/src/protobuf/qprotobufserializer.cpp +++ b/src/protobuf/qprotobufserializer.cpp @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -99,33 +100,6 @@ QtProtobufPrivate::SerializationHandler QtProtobufPrivate::findHandler(QMetaType If there was no error, an empty string is returned. */ -/*! - \relates QProtobufSerializer - \fn template inline void qRegisterProtobufType() - - Registers a Protobuf type \e T. - This function is normally called by generated code. -*/ - -/*! - \relates QProtobufSerializer - \fn template inline void qRegisterProtobufMapType(); - - Registers a Protobuf map type \c K and \c V. - \c V must be a QProtobufMessage. - This function is normally called by generated code. -*/ - -/*! - \relates QProtobufSerializer - \fn template inline void qRegisterProtobufEnumType(); - - Registers serializers for enumeration type \c T in QtProtobuf global - serializers registry. - - This function is normally called by generated code. -*/ - using namespace Qt::StringLiterals; using namespace QtProtobufPrivate; @@ -386,66 +360,81 @@ bool QProtobufSerializer::deserializeObject(QProtobufMessage *message, } /*! - This function is called to serialize \a message as a part of list property + This function is called to serialize \a messageList as a list of messages one by one with \a ordering and \a fieldInfo. You should not call this function directly. */ QByteArray QProtobufSerializer::serializeListObject( - const QProtobufMessage *message, - const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, - const QProtobufPropertyOrderingInfo &fieldInfo) const + const QList &messageList, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + const QProtobufPropertyOrderingInfo &fieldInfo) const { - return serializeObject(message, ordering, fieldInfo); + QByteArray result; + for (const auto &message : messageList) + result.append(serializeObject(message, ordering, fieldInfo)); + return result; } /*! This function deserializes an \a message from byte stream as part of list property, with \a ordering from a QProtobufSelfcheckIterator \a it. - Returns \c true if deserialization was successful, otherwise \c false. + Returns \c Serialized if deserialization was successful, + otherwise \c SerializationError. You should not call this function directly. */ -bool QProtobufSerializer::deserializeListObject(QProtobufMessage *message, +QProtobufBaseSerializer::Status QProtobufSerializer::deserializeListObject(QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, QProtobufSelfcheckIterator &it) const { - return deserializeObject(message, ordering, it); + if (deserializeObject(message, ordering, it)) + return QProtobufBaseSerializer::Serialized; + else + return QProtobufBaseSerializer::SerializationError; } /*! - This function serializes QMap pair of \a key and \a value with + This function serializes \a list of pairs, each pair has a key and a value with \a fieldInfo to a QByteArray You should not call this function directly. */ QByteArray -QProtobufSerializer::serializeMapPair(const QVariant &key, const QVariant &value, +QProtobufSerializer::serializeMapPair(const QList> &list, const QProtobufPropertyOrderingInfo &fieldInfo) const { - auto keyHandler = findIntegratedTypeHandler(key.metaType(), false); - Q_ASSERT_X(keyHandler, "QProtobufSerializer", "Map key is not an integrated type."); + QByteArray result; + for (const auto &element : list) { + const QVariant &key = element.first; + auto keyHandler = findIntegratedTypeHandler(key.metaType(), false); + Q_ASSERT_X(keyHandler, "QProtobufSerializer", "Map key is not an integrated type."); - QByteArray result = QProtobufSerializerPrivate::encodeHeader( - fieldInfo.getFieldNumber(), QtProtobuf::WireTypes::LengthDelimited); + result.append(QProtobufSerializerPrivate::encodeHeader( + fieldInfo.getFieldNumber(), QtProtobuf::WireTypes::LengthDelimited)); - result.append(QProtobufSerializerPrivate::prependLengthDelimitedSize( + result.append(QProtobufSerializerPrivate::prependLengthDelimitedSize( keyHandler->serializer( - key, QProtobufSerializerPrivate::encodeHeader(1, keyHandler->wireType)) - + d_ptr->serializeProperty(value, fieldInfo.infoForMapValue()))); + key, QProtobufSerializerPrivate::encodeHeader(1, keyHandler->wireType)) + + d_ptr->serializeProperty(element.second, fieldInfo.infoForMapValue()))); + } return result; } /*! This function deserializes QMap pair of \a key and \a value from a QProtobufSelfcheckIterator \a it. - Returns \c true if deserialization was successful, otherwise \c false. + Returns \c Serialized if deserialization was successful, + otherwise \c SerializationError. You should not call this function directly. */ -bool QProtobufSerializer::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const +QProtobufBaseSerializer::Status QProtobufSerializer::deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const { - return d_ptr->deserializeMapPair(key, value, it); + if (d_ptr->deserializeMapPair(key, value, it)) + return QProtobufBaseSerializer::Serialized; + else + return QProtobufBaseSerializer::SerializationError; } /*! @@ -742,10 +731,12 @@ bool QProtobufSerializerPrivate::deserializeProperty( auto handler = QtProtobufPrivate::findHandler(metaType); if (!handler.deserializer) { qProtoWarning() << "No deserializer for type" << metaType.name(); + QString error + = QString::fromUtf8("No deserializer is registered for type %1") + .arg(QString::fromUtf8(metaType.name())); setDeserializationError( QAbstractProtobufSerializer::NoDeserializerError, - QCoreApplication::translate("QtProtobuf", - "No deserializer is registered for type %1")); + QCoreApplication::translate("QtProtobuf", error.toUtf8().data())); return false; } handler.deserializer(q_ptr, it, newPropertyValue); diff --git a/src/protobuf/qprotobufserializer.h b/src/protobuf/qprotobufserializer.h index 887327ae..703255e3 100644 --- a/src/protobuf/qprotobufserializer.h +++ b/src/protobuf/qprotobufserializer.h @@ -6,15 +6,9 @@ #define QPROTOBUFSERIALIZER_H #include - -#include - +#include #include -#include -#include -#include - #include #include @@ -24,8 +18,9 @@ namespace QtProtobufPrivate { class QProtobufSelfcheckIterator; } // namespace QtProtobufPrivate +class QProtobufMessage; class QProtobufSerializerPrivate; -class Q_PROTOBUF_EXPORT QProtobufSerializer : public QAbstractProtobufSerializer +class Q_PROTOBUF_EXPORT QProtobufSerializer : public QProtobufBaseSerializer { Q_DISABLE_COPY_MOVE(QProtobufSerializer) public: @@ -37,7 +32,8 @@ public: QByteArray serializeMessage(const QProtobufMessage *message, - const QtProtobufPrivate::QProtobufPropertyOrdering &ordering) const override; + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering + ) const override; bool deserializeMessage(QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, QByteArrayView data) const override; @@ -45,311 +41,50 @@ public: QByteArray serializeObject(const QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, - const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo + ) const override; bool deserializeObject(QProtobufMessage *message, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, - QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const override; QByteArray - serializeListObject(const QProtobufMessage *message, + serializeListObject(const QList &messageList, const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, - const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; - bool deserializeListObject(QProtobufMessage *message, - const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, - QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo + ) const override; + QProtobufBaseSerializer::Status deserializeListObject(QProtobufMessage *message, + const QtProtobufPrivate::QProtobufPropertyOrdering &ordering, + QtProtobufPrivate::QProtobufSelfcheckIterator &it + ) const override; QByteArray - serializeMapPair(const QVariant &key, const QVariant &value, - const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; - bool deserializeMapPair(QVariant &key, QVariant &value, - QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; + serializeMapPair(const QList > &list, + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo + ) const override; + QProtobufBaseSerializer::Status deserializeMapPair(QVariant &key, QVariant &value, + QtProtobufPrivate::QProtobufSelfcheckIterator &it + ) const override; QByteArray serializeEnum(QtProtobuf::int64 value, - const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo + ) const override; QByteArray serializeEnumList(const QList &value, - const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo) const; + const QtProtobufPrivate::QProtobufPropertyOrderingInfo &fieldInfo + ) const override; Q_REQUIRED_RESULT bool deserializeEnum(QtProtobuf::int64 &value, - QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; - Q_REQUIRED_RESULT - bool deserializeEnumList(QList &value, - QtProtobufPrivate::QProtobufSelfcheckIterator &it) const; + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const override; + Q_REQUIRED_RESULT bool + deserializeEnumList(QList &value, + QtProtobufPrivate::QProtobufSelfcheckIterator &it) const override; void shouldPreserveUnknownFields(bool preserveUnknownFields); private: std::unique_ptr d_ptr; }; -namespace QtProtobufPrivate { - -using Serializer = void (*)(const QProtobufSerializer *, const QVariant &, - const QProtobufPropertyOrderingInfo &, QByteArray &); -using Deserializer = void (*)(const QProtobufSerializer *, QProtobufSelfcheckIterator &, - QVariant &); - -/*! - \private - \brief SerializationHandlers contains set of objects that required for class - serialization/deserialization - */ -struct SerializationHandler -{ - Serializer serializer = nullptr; /*!< serializer assigned to class */ - Deserializer deserializer = nullptr; /*!< deserializer assigned to class */ -}; - -extern Q_PROTOBUF_EXPORT SerializationHandler findHandler(QMetaType type); -extern Q_PROTOBUF_EXPORT void registerHandler(QMetaType type, const SerializationHandler &handlers); - -/*! - \private - \brief default serializer template for type T that inherits from QProtobufMessage - */ -template::value, int> = 0> -void serializeObject(const QProtobufSerializer *serializer, const QVariant &value, - const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - buffer.append(serializer->serializeObject(value.value(), T::propertyOrdering, fieldInfo)); -} - -/*! - \private - \brief default serializer template for list of type T objects that inherits from QProtobufMessage - */ -template::value, int> = 0> -void serializeList(const QProtobufSerializer *serializer, const QVariant &listValue, - const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - for (const auto &value : listValue.value>()) { - buffer.append(serializer->serializeListObject(&value, V::propertyOrdering, fieldInfo)); - } -} - -/*! - \private - \brief default serializer template for map of key K, value V - */ -template::value, int> = 0> -void serializeMap(const QProtobufSerializer *serializer, const QVariant &value, - const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - for (const auto &[k, v] : value.value>().asKeyValueRange()) { - buffer.append(serializer->serializeMapPair(QVariant::fromValue(k), - QVariant::fromValue(v), fieldInfo)); - } -} - -/*! - \private - \brief default serializer template for map of type key K, value V. Specialization for V that - inherits from QProtobufMessage - */ -template::value, int> = 0> -void serializeMap(const QProtobufSerializer *serializer, const QVariant &value, - const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - for (const auto &[k, v] : value.value>().asKeyValueRange()) { - buffer.append(serializer->serializeMapPair(QVariant::fromValue(k), - QVariant::fromValue(&v), fieldInfo)); - } -} - -/*! - \private - \brief default serializer template for enum types - */ -template::value, int> = 0> -void serializeEnum(const QProtobufSerializer *serializer, const QVariant &value, - const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - buffer.append(serializer->serializeEnum(QtProtobuf::int64(value.value()), fieldInfo)); -} - -/*! - \private - \brief default serializer template for enum list types - */ -template::value, int> = 0> -void serializeEnumList(const QProtobufSerializer *serializer, const QVariant &value, - const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &buffer) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - QList intList; - for (auto enumValue : value.value>()) { - intList.append(QtProtobuf::int64(enumValue)); - } - buffer.append(serializer->serializeEnumList(intList, fieldInfo)); -} - -/*! - \private - \brief default deserializer template for type T that inherits from QProtobufMessage - */ -template::value, int> = 0> -void deserializeObject(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, - QVariant &to) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - Q_ASSERT_X(to.isNull() || to.metaType() == QMetaType::fromType(), "QProtobufSerializer", - "Property should be either uninitialized or contain a valid pointer"); - - T *value = to.value(); - if (value == nullptr) { - value = new T; - to = QVariant::fromValue(value); - } - serializer->deserializeObject(value, T::propertyOrdering, it); -} - -/*! - \private - \brief default deserializer template for list of type T objects that inherits from QProtobufMessage - */ -template::value, int> = 0> -void deserializeList(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, - QVariant &previous) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - - V newValue; - if (serializer->deserializeListObject(&newValue, V::propertyOrdering, it)) { - QList list = previous.value>(); - list.append(newValue); - previous.setValue(list); - } -} - -/*! - \private - * - \brief default deserializer template for map of key K, value V - */ -template::value, int> = 0> -void deserializeMap(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, - QVariant &previous) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - - QHash out = previous.value>(); - QVariant key = QVariant::fromValue(K()); - QVariant value = QVariant::fromValue(V()); - - if (serializer->deserializeMapPair(key, value, it)) { - out[key.value()] = value.value(); - previous = QVariant::fromValue>(out); - } -} - -/*! - \private - * - \brief default deserializer template for map of type key K, value V. Specialization for V - that inherits from QProtobufMessage - */ -template::value, int> = 0> -void deserializeMap(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, - QVariant &previous) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - - auto out = previous.value>(); - QVariant key = QVariant::fromValue(K()); - QVariant value = QVariant::fromValue(nullptr); - - if (serializer->deserializeMapPair(key, value, it)) { - const auto valuePtr = value.value(); - out[key.value()] = valuePtr ? *valuePtr : V(); - previous = QVariant::fromValue>(out); - } -} - -/*! - \private - * - \brief default deserializer template for enum type T - */ -template::value, int> = 0> -void deserializeEnum(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, - QVariant &to) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - QtProtobuf::int64 intValue; - if (serializer->deserializeEnum(intValue, it)) - to = QVariant::fromValue(static_cast(intValue._t)); -} - -/*! - \private - * - \brief default deserializer template for enumList type T - */ -template::value, int> = 0> -void deserializeEnumList(const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, - QVariant &previous) -{ - Q_ASSERT_X(serializer != nullptr, "QProtobufSerializer", "Serializer is null"); - QList intList; - if (!serializer->deserializeEnumList(intList, it)) - return; - QList enumList = previous.value>(); - for (auto intValue : intList) - enumList.append(static_cast(intValue._t)); - previous = QVariant::fromValue>(enumList); -} -} // namespace QtProtobufPrivate - -template -inline void qRegisterProtobufType() -{ - T::registerTypes(); - QtProtobufPrivate::registerOrdering(QMetaType::fromType(), T::propertyOrdering); - QtProtobufPrivate::registerHandler( - QMetaType::fromType(), - { QtProtobufPrivate::serializeObject, QtProtobufPrivate::deserializeObject }); - QtProtobufPrivate::registerHandler( - QMetaType::fromType>(), - { QtProtobufPrivate::serializeList, QtProtobufPrivate::deserializeList }); -} - -template -inline void qRegisterProtobufMapType() -{ - QtProtobufPrivate::registerHandler( - QMetaType::fromType>(), - { QtProtobufPrivate::serializeMap, QtProtobufPrivate::deserializeMap }); -} - -#ifdef Q_QDOC -template -inline void qRegisterProtobufEnumType(); -#else // !Q_QDOC -template::value, int> = 0> -inline void qRegisterProtobufEnumType() -{ - QtProtobufPrivate::registerHandler( - QMetaType::fromType(), - { QtProtobufPrivate::serializeEnum, QtProtobufPrivate::deserializeEnum }); - QtProtobufPrivate::registerHandler( - QMetaType::fromType>(), - { QtProtobufPrivate::serializeEnumList, QtProtobufPrivate::deserializeEnumList }); -} -#endif // Q_QDOC - QT_END_NAMESPACE #endif // QPROTOBUFSERIALIZER_H diff --git a/src/protobufqttypes/protobufqtcoretypes/qtprotobufqttypescommon_p.h b/src/protobufqttypes/protobufqtcoretypes/qtprotobufqttypescommon_p.h index 28b51eac..3dabbd34 100644 --- a/src/protobufqttypes/protobufqtcoretypes/qtprotobufqttypescommon_p.h +++ b/src/protobufqttypes/protobufqtcoretypes/qtprotobufqttypescommon_p.h @@ -41,7 +41,7 @@ void registerQtTypeHandler() { registerHandler( QMetaType::fromType(), - { [](const QProtobufSerializer *serializer, const QVariant &value, + { [](const QProtobufBaseSerializer *serializer, const QVariant &value, const QProtobufPropertyOrderingInfo &info, QByteArray &buffer) { auto do_convert = [](const QType &qtype) { auto res = convert(qtype); @@ -60,7 +60,7 @@ void registerQtTypeHandler() warnTypeConversionError(); } }, - [](const QProtobufSerializer *serializer, QProtobufSelfcheckIterator &it, + [](const QProtobufBaseSerializer *serializer, QProtobufSelfcheckIterator &it, QVariant &value) { PType object; serializer->deserializeObject(&object, PType::propertyOrdering, it); diff --git a/src/wellknown/qprotobufanysupport.cpp b/src/wellknown/qprotobufanysupport.cpp index 835840d5..deb499bb 100644 --- a/src/wellknown/qprotobufanysupport.cpp +++ b/src/wellknown/qprotobufanysupport.cpp @@ -24,7 +24,7 @@ public: static AnyPrivate *get(const Any *any) { return any->d_ptr; } }; -static void serializerProxy(const QProtobufSerializer *serializer, const QVariant &object, +static void serializerProxy(const QProtobufBaseSerializer *serializer, const QVariant &object, const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &output) { if (object.isNull()) @@ -41,20 +41,31 @@ static void serializerProxy(const QProtobufSerializer *serializer, const QVarian fieldInfo)); } -static void listSerializerProxy(const QProtobufSerializer *serializer, const QVariant &object, - const QProtobufPropertyOrderingInfo &fieldInfo, QByteArray &output) +static void listSerializerProxy(const QProtobufBaseSerializer *serializer, + const QVariant &object, + const QProtobufPropertyOrderingInfo &fieldInfo, + QByteArray &output) { - const auto anyList = object.value>(); + const QList anyList = object.value>(); + QList msgList; + msgList.reserve(anyList.size()); + QList msgAny; + msgAny.reserve(anyList.size()); for (const Any &any : anyList) { google::protobuf::Any realAny; realAny.setValue(any.value()); realAny.setTypeUrl(any.typeUrl()); - output.append(serializer->serializeListObject(&realAny, - google::protobuf::Any::propertyOrdering, fieldInfo)); + msgAny.append(realAny); } + for (const google::protobuf::Any &any : msgAny) { + msgList.append(&any); + } + output.append(serializer->serializeListObject(msgList, + google::protobuf::Any::propertyOrdering, + fieldInfo)); } -static void listDeserializerProxy(const QProtobufSerializer *deserializer, +static void listDeserializerProxy(const QProtobufBaseSerializer *deserializer, QProtobufSelfcheckIterator &it, QVariant &object) { auto anyList = object.value>(); @@ -71,7 +82,7 @@ static void listDeserializerProxy(const QProtobufSerializer *deserializer, object.setValue(std::move(anyList)); } -static void deserializerProxy(const QProtobufSerializer *deserializer, +static void deserializerProxy(const QProtobufBaseSerializer *deserializer, QProtobufSelfcheckIterator &it, QVariant &object) { google::protobuf::Any realAny; diff --git a/tests/auto/protobuf/CMakeLists.txt b/tests/auto/protobuf/CMakeLists.txt index 57dc4637..87b417a2 100644 --- a/tests/auto/protobuf/CMakeLists.txt +++ b/tests/auto/protobuf/CMakeLists.txt @@ -6,6 +6,7 @@ if(TARGET Qt6::qtprotobufgen) get_target_property(protoc_version WrapProtoc::WrapProtoc _qt_internal_protobuf_version) add_subdirectory(basic) + add_subdirectory(jsontypes) add_subdirectory(syntax) add_subdirectory(nopackage) add_subdirectory(enums) diff --git a/tests/auto/protobuf/jsontypes/BLACKLIST b/tests/auto/protobuf/jsontypes/BLACKLIST new file mode 100644 index 00000000..c12ede4e --- /dev/null +++ b/tests/auto/protobuf/jsontypes/BLACKLIST @@ -0,0 +1,2 @@ +[RepeatedComplexMessageTest] +macos diff --git a/tests/auto/protobuf/jsontypes/CMakeLists.txt b/tests/auto/protobuf/jsontypes/CMakeLists.txt new file mode 100644 index 00000000..6c91034e --- /dev/null +++ b/tests/auto/protobuf/jsontypes/CMakeLists.txt @@ -0,0 +1,92 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_protobuf_json_basic LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +qt6_add_protobuf(tst_protobuf_json_basic_types_gen + PROTO_FILES + ../basic/proto/basicmessages.proto + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_protobuf_generated" +) +qt_autogen_tools_initial_setup(tst_protobuf_json_basic_types_gen) + +qt_internal_add_test(tst_protobuf_json_basic_types + SOURCES + tst_protobuf_serialization_json_basictypes.cpp + LIBRARIES + Qt::Test + Qt::Protobuf + tst_protobuf_json_basic_types_gen +) + +qt_internal_add_test(tst_protobuf_deserialization_json_basictypes + SOURCES + tst_protobuf_deserialization_json_basictypes.cpp + LIBRARIES + Qt::Test + Qt::Protobuf + tst_protobuf_json_basic_types_gen +) + +qt6_add_protobuf(tst_protobuf_json_repeatedtypes_gen + PROTO_FILES + ../basic/proto/repeatedmessages.proto + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_protobuf_generated" +) +target_link_libraries(tst_protobuf_json_repeatedtypes_gen + PUBLIC + tst_protobuf_json_basic_types_gen +) +qt_autogen_tools_initial_setup(tst_protobuf_json_repeatedtypes_gen) + +qt_internal_add_test(tst_protobuf_serialization_json_repeatedtypes + SOURCES + tst_protobuf_serialization_json_repeatedtypes.cpp + LIBRARIES + Qt::Test + Qt::Protobuf + tst_protobuf_json_basic_types_gen + tst_protobuf_json_repeatedtypes_gen +) + +qt_internal_add_test(tst_protobuf_deserialization_json_repeatedtypes + SOURCES + tst_protobuf_deserialization_json_repeatedtypes.cpp + LIBRARIES + Qt::Test + Qt::Protobuf + tst_protobuf_json_basic_types_gen + tst_protobuf_json_repeatedtypes_gen +) + +qt6_add_protobuf(tst_protobuf_json_maptypes_gen + PROTO_FILES + ../basic/proto/mapmessages.proto + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/qt_protobuf_generated" +) +if(MINGW) + target_compile_options(tst_protobuf_json_maptypes_gen PRIVATE "-Wa,-mbig-obj") +endif() + +qt_autogen_tools_initial_setup(tst_protobuf_json_maptypes_gen) + +target_link_libraries(tst_protobuf_json_maptypes_gen + PUBLIC + tst_protobuf_json_basic_types_gen +) + +qt_internal_add_test(tst_protobuf_serialization_json_maptypes + SOURCES + tst_protobuf_serialization_json_maptypes.cpp + INCLUDE_DIRECTORIES + ../shared + LIBRARIES + Qt::Test + Qt::Protobuf + tst_protobuf_json_basic_types_gen + tst_protobuf_json_maptypes_gen +) diff --git a/tests/auto/protobuf/jsontypes/tst_protobuf_deserialization_json_basictypes.cpp b/tests/auto/protobuf/jsontypes/tst_protobuf_deserialization_json_basictypes.cpp new file mode 100644 index 00000000..63039f8f --- /dev/null +++ b/tests/auto/protobuf/jsontypes/tst_protobuf_deserialization_json_basictypes.cpp @@ -0,0 +1,494 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "basicmessages.qpb.h" + +#include +#include +#include + +using namespace Qt::Literals::StringLiterals; + +class QtProtobufTypesJsonDeserializationTest : public QObject +{ + Q_OBJECT +private slots: + void init() { qRegisterProtobufTypes(); serializer.reset(new QProtobufJsonSerializer); } + + void BoolMessageDeserializeTest_data(); + void BoolMessageDeserializeTest(); + void IntMessageDeserializeTest_data(); + void IntMessageDeserializeTest(); + void UIntMessageDeserializeTest_data(); + void UIntMessageDeserializeTest(); + void SIntMessageDeserializeTest_data(); + void SIntMessageDeserializeTest(); + void Int64MessageDeserializeTest_data(); + void Int64MessageDeserializeTest(); + void UInt64MessageDeserializeTest_data(); + void UInt64MessageDeserializeTest(); + void SInt64MessageDeserializeTest_data(); + void SInt64MessageDeserializeTest(); + void FixedInt32MessageDeserializeTest_data(); + void FixedInt32MessageDeserializeTest(); + void FixedInt64MessageDeserializeTest_data(); + void FixedInt64MessageDeserializeTest(); + void SFixedInt32MessageDeserializeTest_data(); + void SFixedInt32MessageDeserializeTest(); + void SFixedInt64MessageDeserializeTest_data(); + void SFixedInt64MessageDeserializeTest(); + void FloatMessageDeserializeTest_data(); + void FloatMessageDeserializeTest(); + void DoubleMessageDeserializeTest_data(); + void DoubleMessageDeserializeTest(); + void StringMessageDeserializeTest(); + void ComplexTypeDeserializeTest_data(); + void ComplexTypeDeserializeTest(); + void ResetComplexTypeDeserializeTest_data(); + void ResetComplexTypeDeserializeTest(); + void DefaultConstructedComplexTypeDeserializeTest(); + void EmptyBytesMessageTest(); + void EmptyStringMessageTest(); + +private: + std::unique_ptr serializer; +}; + +using namespace qtprotobufnamespace::tests; + +void QtProtobufTypesJsonDeserializationTest::BoolMessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("True") << true << "{\"testFieldBool\":true}"_ba; + QTest::newRow("False") << false << "{\"testFieldBool\":false}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::BoolMessageDeserializeTest() +{ + QFETCH(const bool, value); + QFETCH(const QByteArray, serializeData); + + SimpleBoolMessage test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldBool(), value); +} + +void QtProtobufTypesJsonDeserializationTest::IntMessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("555") << 555 << "{\"testFieldInt\":555}"_ba; + QTest::newRow("0") << 0 << "{\"testFieldInt\":0}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::IntMessageDeserializeTest() +{ + QFETCH(const int32_t, value); + QFETCH(const QByteArray, serializeData); + + SimpleIntMessage test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldInt(), value); +} + +void QtProtobufTypesJsonDeserializationTest::UIntMessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("15") << (uint32_t)15 << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (uint32_t)300 << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (uint32_t)65545 << "{\"testFieldInt\":65545}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::UIntMessageDeserializeTest() +{ + QFETCH(const uint32_t, value); + QFETCH(const QByteArray, serializeData); + + SimpleUIntMessage test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldInt(), value); +} + +void QtProtobufTypesJsonDeserializationTest::SIntMessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("15") << (int32_t)15 << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (int32_t)300 << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (int32_t)65545 << "{\"testFieldInt\":65545}"_ba; + + QTest::newRow("-1") << (int32_t)-1 << "{\"testFieldInt\":-1}"_ba; + QTest::newRow("-462") << (int32_t)-462 << "{\"testFieldInt\":-462}"_ba; + QTest::newRow("-63585") << (int32_t)-63585 << "{\"testFieldInt\":-63585}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::SIntMessageDeserializeTest() +{ + QFETCH(const int32_t, value); + QFETCH(const QByteArray, serializeData); + + SimpleSIntMessage test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldInt(), value); +} + +void QtProtobufTypesJsonDeserializationTest::Int64MessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("15") << (int64_t)15 << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (int64_t)300 << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (int64_t)65545 << "{\"testFieldInt\":65545}"_ba; + + QTest::newRow("-1") << (int64_t)-1 << "{\"testFieldInt\":-1}"_ba; + QTest::newRow("-462") << (int64_t)-462 << "{\"testFieldInt\":-462}"_ba; + QTest::newRow("-63585") << (int64_t)-63585 << "{\"testFieldInt\":-63585}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::Int64MessageDeserializeTest() +{ + QFETCH(const int64_t, value); + QFETCH(const QByteArray, serializeData); + + SimpleInt64Message test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldInt(), value); +} + +void QtProtobufTypesJsonDeserializationTest::UInt64MessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("15") << (uint64_t)15 << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (uint64_t)300 << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (uint64_t)65545 << "{\"testFieldInt\":65545}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::UInt64MessageDeserializeTest() +{ + QFETCH(const QtProtobuf::uint64, value); + QFETCH(const QByteArray, serializeData); + + SimpleUInt64Message test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldInt(), value); +} + +void QtProtobufTypesJsonDeserializationTest::SInt64MessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("15") << (int64_t)15 << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (int64_t)300 << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (int64_t)65545 << "{\"testFieldInt\":65545}"_ba; + + QTest::newRow("-1") << (int64_t)-1 << "{\"testFieldInt\":-1}"_ba; + QTest::newRow("-462") << (int64_t)-462 << "{\"testFieldInt\":-462}"_ba; + QTest::newRow("-63585") << (int64_t)-63585 << "{\"testFieldInt\":-63585}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::SInt64MessageDeserializeTest() +{ + QFETCH(const int64_t, value); + QFETCH(const QByteArray, serializeData); + + SimpleSInt64Message test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldInt(), value); +} + +void QtProtobufTypesJsonDeserializationTest::FixedInt32MessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("15") << (uint32_t)15 << "{\"testFieldFixedInt32\":15}"_ba; + QTest::newRow("300") << (uint32_t)300 << "{\"testFieldFixedInt32\":300}"_ba; + QTest::newRow("65545") << (uint32_t)65545 << "{\"testFieldFixedInt32\":65545}"_ba; + + QTest::newRow("5") << (uint32_t)5 << "{\"testFieldFixedInt32\": 5}"_ba; + QTest::newRow("0") << (uint32_t)0 << "{\"testFieldFixedInt32\": 0}"_ba; + QTest::newRow("555") << (uint32_t)555 << "{\"testFieldFixedInt32\":555}"_ba; + QTest::newRow("nullptr") << (uint32_t)0 << "{\"testFieldFixedInt32\":null}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::FixedInt32MessageDeserializeTest() +{ + QFETCH(const uint32_t, value); + QFETCH(const QByteArray, serializeData); + + SimpleFixedInt32Message test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldFixedInt32(), value); +} + +void QtProtobufTypesJsonDeserializationTest::FixedInt64MessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("15") << (uint64_t)15 << "{\"testFieldFixedInt64\":15}"_ba; + QTest::newRow("300") << (uint64_t)300 << "{\"testFieldFixedInt64\":300}"_ba; + QTest::newRow("65545") << (uint64_t)65545 << "{\"testFieldFixedInt64\":65545}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::FixedInt64MessageDeserializeTest() +{ + QFETCH(const uint64_t, value); + QFETCH(const QByteArray, serializeData); + + SimpleFixedInt64Message test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldFixedInt64(), value); +} + +void QtProtobufTypesJsonDeserializationTest::SFixedInt32MessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("15") << (int32_t)15 << "{\"testFieldFixedInt32\":15}"_ba; + QTest::newRow("300") << (int32_t)300 << "{\"testFieldFixedInt32\":300}"_ba; + QTest::newRow("65545") << (int32_t)65545 << "{\"testFieldFixedInt32\":65545}"_ba; + + QTest::newRow("-1") << (int32_t)-1 << "{\"testFieldFixedInt32\":-1}"_ba; + QTest::newRow("-462") << (int32_t)-462 << "{\"testFieldFixedInt32\":-462}"_ba; + QTest::newRow("-63585") << (int32_t)-63585 << "{\"testFieldFixedInt32\":-63585}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::SFixedInt32MessageDeserializeTest() +{ + QFETCH(const int32_t, value); + QFETCH(const QByteArray, serializeData); + + SimpleSFixedInt32Message test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldFixedInt32(), value); +} + +void QtProtobufTypesJsonDeserializationTest::SFixedInt64MessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("15") << (int64_t)15 << "{\"testFieldFixedInt64\":15}"_ba; + QTest::newRow("300") << (int64_t)300 << "{\"testFieldFixedInt64\":300}"_ba; + QTest::newRow("65545") << (int64_t)65545 << "{\"testFieldFixedInt64\":65545}"_ba; + + QTest::newRow("-1") << (int64_t)-1 << "{\"testFieldFixedInt64\":-1}"_ba; + QTest::newRow("-462") << (int64_t)-462 << "{\"testFieldFixedInt64\":-462}"_ba; + QTest::newRow("-63585") << (int64_t)-63585 << "{\"testFieldFixedInt64\":-63585}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::SFixedInt64MessageDeserializeTest() +{ + QFETCH(const int64_t, value); + QFETCH(const QByteArray, serializeData); + + SimpleSFixedInt64Message test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldFixedInt64(), value); +} + +void QtProtobufTypesJsonDeserializationTest::FloatMessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("float_value_0_1") << 0.1f << "{\"testFieldFloat\":0.1}"_ba; + QTest::newRow("float_value_min") << std::numeric_limits::min() + << "{\"testFieldFloat\":1.17549e-38}"_ba; + QTest::newRow("float_value_max") << std::numeric_limits::max() + << "{\"testFieldFloat\":3.40282e+38}"_ba; + QTest::newRow("float_neg_value_4_2") << -4.2f << "{\"testFieldFloat\":-4.2}"_ba; + QTest::newRow("float_neg_value_0_0") << (float)-0.0f << "{\"testFieldFloat\":0}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::FloatMessageDeserializeTest() +{ + QFETCH(const float, value); + QFETCH(const QByteArray, serializeData); + + SimpleFloatMessage test; + test.setTestFieldFloat(value); + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldFloat(), value); +} + +void QtProtobufTypesJsonDeserializationTest::DoubleMessageDeserializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("serializeData"); + + QTest::newRow("double_value_0_1") << 0.1 << "{\"testFieldDouble\":0.1}"_ba; + QTest::newRow("double_value_min") + << std::numeric_limits::min() + << "{\"testFieldDouble\":2.2250738585072014e-308}"_ba; + QTest::newRow("double_value_max") + << std::numeric_limits::max() + << "{\"testFieldDouble\":1.7976931348623157e+308}"_ba; + QTest::newRow("double_neg_value_4_2") << -4.2 + << "{\"testFieldDouble\":-4.2}"_ba; + QTest::newRow("double_value_0_0") << 0.0 << "{\"testFieldDouble\":0}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::DoubleMessageDeserializeTest() +{ + QFETCH(const double, value); + QFETCH(const QByteArray, serializeData); + + SimpleDoubleMessage test; + test.setTestFieldDouble(value); + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldDouble(), value); +} + +void QtProtobufTypesJsonDeserializationTest::StringMessageDeserializeTest() +{ + SimpleStringMessage test; + test.deserialize(serializer.get(), "{\"testFieldString\":\"qwerty\"}"_ba); + QCOMPARE(test.testFieldString(), "qwerty"); + + test.deserialize(serializer.get(), "{\"testFieldString\":\"\"}"_ba); + QCOMPARE(test.testFieldString(), ""); + + test.deserialize(serializer.get(), "{\"testFieldString\":\"null\"}"_ba); + QCOMPARE(test.testFieldString(), "null"); + + test.deserialize(serializer.get(), "{\"testFieldString\":\"NaN\"}"_ba); + QCOMPARE(test.testFieldString(), "NaN"); + + test.deserialize(serializer.get(), "{\"testFieldString\":\"Infinity\"}"_ba); + QCOMPARE(test.testFieldString(), "Infinity"); + + test.deserialize(serializer.get(), "{\"testFieldString\":\"-Infinity\"}"_ba); + QCOMPARE(test.testFieldString(), "-Infinity"); +} + +void QtProtobufTypesJsonDeserializationTest::ComplexTypeDeserializeTest_data() +{ + QTest::addColumn("intField"); + QTest::addColumn("stringField"); + QTest::addColumn("serializeData"); + + QTest::newRow("empty_value") + << 0 << "" + << "{\"testFieldInt\":0,\"testComplexField\":{\"testFieldString\":\"\"}}"_ba; + QTest::newRow("null_complex_field") + << 0 << "" + << "{\"testFieldInt\":0,\"testComplexField\":null}"_ba; + QTest::newRow("value_only_int") + << 42 << "" + << "{\"testFieldInt\":42,\"testComplexField\":{\"testFieldString\":\"\"}}"_ba; + QTest::newRow("value_only_string") + << 0 << "qwerty" + << "{\"testFieldInt\":0,\"testComplexField\":{\"testFieldString\":\"qwerty\"}}"_ba; + QTest::newRow("int_and_string") + << 42 << "qwerty" + << "{\"testFieldInt\":42,\"testComplexField\":{\"testFieldString\":\"qwerty\"}}"_ba; + QTest::newRow("int_and_big_string") + << 42 + << "YVRfJvjxqbgvFwS1YvOZXgtj5ffGLS7AiNHz9oZIoKbm7z8H79xBuyPkpQXvGoO09OY9xRawx3eOAs9xjo" + "TA1xJhrw28TAcq1CebYlC9WUfQC6hIantaNdyHiKToffi0Zt7la42SRxXZSP4GuxbcZIp53pJnyCwfCy1q" + "dFczT0dmn7h8fpyAdemEavwFeda4d0PApGfSU2jLt39X8kYUBxNM2WgALRBgHdVde87q6Pi5U69TjhMd28" + "W1SFD1DxyogCCrqOct2ZPICoLnrqdF3OdNzjRVLfeyvQ8LgLvRNFR9WfWAyAz79nKgBamd8Ntlvt4Mg35E" + "5gVS2g7AQ7rkm72cBdnW9sCEyGabeXAuH5j4GRbuLT7qBZWDcFLF4SsCdS3WfFGdNHfwaijzykByo71PvF" + "VlTXH2WJWoFvR5FALjBTn7bCdP0pAiSbLCY8Xz2Msc3dBb5Ff9GISPbUpNmUvBdMZMHQvqOmTNXEPpN0b7" + "4MDOMQfWJShOo3NkAvMjs" + << "{\"testFieldInt\":42,\"testComplexField\":{\"testFieldString\":\"YVRfJvjxqbgvFwS1Y" + "vOZXgtj5ffGLS7AiNHz9oZIoKbm7z8H79xBuyPkpQXvGoO09OY9xRawx3eOAs9xjoTA1xJhrw28TAcq1Ce" + "bYlC9WUfQC6hIantaNdyHiKToffi0Zt7la42SRxXZSP4GuxbcZIp53pJnyCwfCy1qdFczT0dmn7h8fpyAd" + "emEavwFeda4d0PApGfSU2jLt39X8kYUBxNM2WgALRBgHdVde87q6Pi5U69TjhMd28W1SFD1DxyogCCrqOc" + "t2ZPICoLnrqdF3OdNzjRVLfeyvQ8LgLvRNFR9WfWAyAz79nKgBamd8Ntlvt4Mg35E5gVS2g7AQ7rkm72cB" + "dnW9sCEyGabeXAuH5j4GRbuLT7qBZWDcFLF4SsCdS3WfFGdNHfwaijzykByo71PvFVlTXH2WJWoFvR5FAL" + "jBTn7bCdP0pAiSbLCY8Xz2Msc3dBb5Ff9GISPbUpNmUvBdMZMHQvqOmTNXEPpN0b74MDOMQfWJShOo3NkA" + "vMjs\"}}"_ba; + QTest::newRow("neg_int_and_string") + << -45 << "qwerty" + << "{\"testFieldInt\":-45,\"testComplexField\":{\"testFieldString\":\"qwerty\"}}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::ComplexTypeDeserializeTest() +{ + QFETCH(const int, intField); + QFETCH(const QString, stringField); + QFETCH(const QByteArray, serializeData); + + SimpleStringMessage stringMessage; + stringMessage.setTestFieldString(stringField); + + ComplexMessage test; + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldInt(), intField); + QCOMPARE(test.testComplexField(), stringMessage); +} + +void QtProtobufTypesJsonDeserializationTest::ResetComplexTypeDeserializeTest_data() +{ + QTest::addColumn("intField"); + QTest::addColumn("stringField"); + QTest::addColumn("serializeData"); + + QTest::newRow("empty_value") + << 0 << u""_s << "{\"testFieldInt\":0,\"testComplexField\":{}}"_ba; + QTest::newRow("value_only_int") + << 42 << u""_s << "{\"testFieldInt\":42,\"testComplexField\":{}}"_ba; + QTest::newRow("value_only_string") + << 0 << u""_s << "{\"testFieldInt\":0,\"testComplexField\":{}}"_ba; + QTest::newRow("int_and_string") + << 42 << u"qwerty"_s + << "{\"testFieldInt\":42,\"testComplexField\":{\"testFieldString\":\"qwerty\"}}"_ba; +} + +void QtProtobufTypesJsonDeserializationTest::ResetComplexTypeDeserializeTest() +{ + QFETCH(const int, intField); + QFETCH(const QString, stringField); + QFETCH(const QByteArray, serializeData); + + SimpleStringMessage stringMessage; + stringMessage.setTestFieldString(stringField); + ComplexMessage test; + test.setTestFieldInt(intField); + test.setTestComplexField(stringMessage); + + // Reset Complex field + test.clearTestComplexField(); + test.deserialize(serializer.get(), serializeData); + QCOMPARE(test.testFieldInt(), intField); + QCOMPARE(test.testComplexField(), stringMessage); +} + +void QtProtobufTypesJsonDeserializationTest::DefaultConstructedComplexTypeDeserializeTest() +{ + ComplexMessage test; + test.deserialize(serializer.get(), "{\"testFieldInt\":0,\"testComplexField\":{}}"_ba); + QCOMPARE(test.testFieldInt(), 0); + QCOMPARE(test.testComplexField().testFieldString(), ""); +} + +void QtProtobufTypesJsonDeserializationTest::EmptyBytesMessageTest() +{ + SimpleBytesMessage test; + test.deserialize(serializer.get(), "{\"testFieldBytes\":\"\"}"_ba); + QCOMPARE(test.testFieldBytes(), ""); +} + +void QtProtobufTypesJsonDeserializationTest::EmptyStringMessageTest() +{ + SimpleStringMessage test; + test.deserialize(serializer.get(), "{\"testFieldString\":\"\"}"_ba); + QCOMPARE(test.testFieldString(), ""); +} + +QTEST_MAIN(QtProtobufTypesJsonDeserializationTest) +#include "tst_protobuf_deserialization_json_basictypes.moc" diff --git a/tests/auto/protobuf/jsontypes/tst_protobuf_deserialization_json_repeatedtypes.cpp b/tests/auto/protobuf/jsontypes/tst_protobuf_deserialization_json_repeatedtypes.cpp new file mode 100644 index 00000000..97cbc9a8 --- /dev/null +++ b/tests/auto/protobuf/jsontypes/tst_protobuf_deserialization_json_repeatedtypes.cpp @@ -0,0 +1,245 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +//#include "basicmessages.qpb.h" +#include "repeatedmessages.qpb.h" + +#include +#include +#include + +using namespace Qt::Literals::StringLiterals; + +class QtProtobufRepeatedTypesJsonDeserializationTest : public QObject +{ + Q_OBJECT +private slots: + void init() + { + serializer.reset(new QProtobufJsonSerializer); + } + + void RepeatedStringMessageTest(); + void RepeatedFloatMessageTest(); + void RepeatedBytesMessageTest(); + void RepeatedDoubleMessageTest(); + void RepeatedIntMessageTest(); + void RepeatedSIntMessageTest(); + void RepeatedUIntMessageTest(); + void RepeatedInt64MessageTest(); + void RepeatedSInt64MessageTest(); + void RepeatedUInt64MessageTest(); + void RepeatedFixedIntMessageTest(); + void RepeatedSFixedIntMessageTest(); + void RepeatedFixedInt64MessageTest(); + void RepeatedSFixedInt64MessageTest(); + void RepeatedComplexMessageTest(); + void RepeatedBoolMessageTest(); +private: + std::unique_ptr serializer; +}; + +using namespace qtprotobufnamespace::tests; + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedStringMessageTest() +{ + RepeatedStringMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedString\":[\"aaaa\",\"bbbbb\",\"ccc\",\"dddddd\",\"eeeee\",\"\"]}"_ba); + QCOMPARE(test.testRepeatedString().count(), 6); + QCOMPARE(test.testRepeatedString(), QStringList({"aaaa","bbbbb","ccc","dddddd","eeeee",""})); + + test.deserialize(serializer.get(), "{\"testRepeatedString\":[]"_ba); + QVERIFY(test.testRepeatedString().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedBytesMessageTest() +{ + RepeatedBytesMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedBytes\":[\"AQIDBAUG\",\"/////w==\",\"6urq6uo=\",\"AQIDBAUG\"]}"_ba); + QCOMPARE(test.testRepeatedBytes().count(), 4); + QCOMPARE(test.testRepeatedBytes(), QByteArrayList({QByteArray::fromHex("010203040506"), + QByteArray::fromHex("ffffffff"), + QByteArray::fromHex("eaeaeaeaea"), + QByteArray::fromHex("010203040506")})); + //TODO: Serialization for list types works partially incorrect because of appending of values to existing + //Need to make decision if deserialize should reset all protobuf properties or not + RepeatedBytesMessage test2; + test2.deserialize(serializer.get(), "{\"testRepeatedBytes\":[\"AQIDBAUG\",\"\",\"6urq6uo=\",\"AQIDBAUG\"]}"_ba); + QCOMPARE(test2.testRepeatedBytes().count(), 4); + QCOMPARE(test2.testRepeatedBytes(), QByteArrayList({QByteArray::fromHex("010203040506"), + QByteArray::fromHex(""), + QByteArray::fromHex("eaeaeaeaea"), + QByteArray::fromHex("010203040506")})); + test.deserialize(serializer.get(), "{\"testRepeatedBytes\":[]"_ba); + QVERIFY(test.testRepeatedBytes().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedFloatMessageTest() +{ + RepeatedFloatMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedFloat\":[0.4,1.2,0.5,3.912348,0.6]}"_ba); + QCOMPARE(test.testRepeatedFloat().count(), 5); + QCOMPARE(test.testRepeatedFloat(), QtProtobuf::floatList({0.4f, 1.2f, 0.5f, 3.912348f, 0.6f})); + + test.deserialize(serializer.get(), "{\"testRepeatedFloat\":[]"_ba); + QVERIFY(test.testRepeatedFloat().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedDoubleMessageTest() +{ + RepeatedDoubleMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedDouble\":[0.1,0.2,0.3,3.912348239293,0.5]}"_ba); + QCOMPARE(test.testRepeatedDouble().count(), 5); + QCOMPARE(test.testRepeatedDouble(), QtProtobuf::doubleList({0.1,0.2,0.3,3.912348239293,0.5})); + + test.deserialize(serializer.get(), "{\"testRepeatedDouble\":[]"_ba); + QVERIFY(test.testRepeatedDouble().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedIntMessageTest() +{ + RepeatedIntMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[0,1,321,-65999,123245,-3,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 7); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::int32List({0, 1, 321, -65999, 123245, -3, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedSIntMessageTest() +{ + RepeatedSIntMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,321,-65999,123245,-3,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 6); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::sint32List({1, 321, -65999, 123245, -3, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedUIntMessageTest() +{ + RepeatedUIntMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,0,321,65999,123245,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 6); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::uint32List({1, 0, 321, 65999, 123245, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedInt64MessageTest() +{ + RepeatedInt64Message test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,321,-65999,12324523123123,-3,0,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 7); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::int64List({1, 321, -65999, 12324523123123, -3, 0, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedSInt64MessageTest() +{ + RepeatedSInt64Message test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,321,-65999,12324523123123,-3,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 6); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::sint64List({1, 321, -65999, 12324523123123, -3, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedUInt64MessageTest() +{ + RepeatedUInt64Message test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,321,65999,123245,123245324235425234,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 6); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::uint64List({1, 321, 65999, 123245, 123245324235425234, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedFixedIntMessageTest() +{ + RepeatedFixedIntMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,321,65999,12324523,3,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 6); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::fixed32List({1, 321, 65999, 12324523, 3, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedSFixedIntMessageTest() +{ + RepeatedSFixedIntMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[0,1,321,-65999,12324523,-3,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 7); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::sfixed32List({0, 1, 321, -65999, 12324523, -3, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedFixedInt64MessageTest() +{ + RepeatedFixedInt64Message test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,321,65999,123245324235425234,3,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 6); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::fixed64List({1, 321, 65999, 123245324235425234, 3, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedSFixedInt64MessageTest() +{ + RepeatedSFixedInt64Message test; + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[1,321,-65999,123245324235425234,-3,3]}"_ba); + QCOMPARE(test.testRepeatedInt().count(), 6); + QCOMPARE(test.testRepeatedInt(), QtProtobuf::sfixed64List({1, 321, -65999, 123245324235425234, -3, 3})); + + test.deserialize(serializer.get(), "{\"testRepeatedInt\":[]"_ba); + QVERIFY(test.testRepeatedInt().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedComplexMessageTest() +{ + RepeatedComplexMessage test; + test.deserialize(serializer.get(), "{\"testRepeatedComplex\":[{\"testFieldInt\":21,\"testComplexField\":" + "{\"testFieldString\":\"12345\"}},{\"testFieldInt\":22,\"testComplexField\":" + "{\"testFieldString\":\"qwerty\"}},{\"testFieldInt\":23,\"testComplexField\":" + "{\"testFieldString\":\"\"}}]}"_ba); + + QCOMPARE(test.testRepeatedComplex().count(), 3); + for (auto element: test.testRepeatedComplex()) { + qWarning() << "testFieldInt = " << element.testFieldInt() + << "testFieldString = " << element.testComplexField().testFieldString(); + } + QCOMPARE(test.testRepeatedComplex().at(0).testFieldInt(), 21); + QCOMPARE(test.testRepeatedComplex().at(0).testComplexField().testFieldString(), QString("12345")); + QCOMPARE(test.testRepeatedComplex().at(1).testFieldInt(), 22); + QCOMPARE(test.testRepeatedComplex().at(1).testComplexField().testFieldString(), QString("qwerty")); + QCOMPARE(test.testRepeatedComplex().at(2).testFieldInt(), 23); + QCOMPARE(test.testRepeatedComplex().at(2).testComplexField().testFieldString(), QString("")); + + test.deserialize(serializer.get(), "{\"testRepeatedComplex\":[]}"_ba); + QVERIFY(!test.testRepeatedComplex().isEmpty()); +} + +void QtProtobufRepeatedTypesJsonDeserializationTest::RepeatedBoolMessageTest() +{ + RepeatedBoolMessage boolMsg; + boolMsg.deserialize(serializer.get(), "{\"testRepeatedBool\":[true,true,true,false,false,false,false,false,false,false,false,false,true]}"_ba); + QCOMPARE(serializer->deserializationError(), QAbstractProtobufSerializer::NoError); + QtProtobuf::boolList expected({ true, true, true, false, false, false, false, + false, false, false, false, false, true }); + QCOMPARE(boolMsg.testRepeatedBool().count(), 13); + QCOMPARE(boolMsg.testRepeatedBool(), expected); +} + +QTEST_MAIN(QtProtobufRepeatedTypesJsonDeserializationTest) +#include "tst_protobuf_deserialization_json_repeatedtypes.moc" diff --git a/tests/auto/protobuf/jsontypes/tst_protobuf_serialization_json_basictypes.cpp b/tests/auto/protobuf/jsontypes/tst_protobuf_serialization_json_basictypes.cpp new file mode 100644 index 00000000..68dcb2b9 --- /dev/null +++ b/tests/auto/protobuf/jsontypes/tst_protobuf_serialization_json_basictypes.cpp @@ -0,0 +1,603 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "basicmessages.qpb.h" + +#include +#include +#include + +using namespace Qt::Literals::StringLiterals; + +class QtProtobufTypesJsonSerializationTest : public QObject +{ + Q_OBJECT +private slots: + void init() { qRegisterProtobufTypes(); m_serializer.reset(new QProtobufJsonSerializer); } + + void BoolMessageSerializeTest_data(); + void BoolMessageSerializeTest(); + void IntMessageSerializeTest_data(); + void IntMessageSerializeTest(); + void UIntMessageSerializeTest_data(); + void UIntMessageSerializeTest(); + void SIntMessageSerializeTest_data(); + void SIntMessageSerializeTest(); + void Int64MessageSerializeTest_data(); + void Int64MessageSerializeTest(); + void UInt64MessageSerializeTest_data(); + void UInt64MessageSerializeTest(); + void SInt64MessageSerializeTest_data(); + void SInt64MessageSerializeTest(); + void FixedInt32MessageSerializeTest_data(); + void FixedInt32MessageSerializeTest(); + void FixedInt64MessageSerializeTest_data(); + void FixedInt64MessageSerializeTest(); + void SFixedInt32MessageSerializeTest_data(); + void SFixedInt32MessageSerializeTest(); + void SFixedInt64MessageSerializeTest_data(); + void SFixedInt64MessageSerializeTest(); + void FloatMessageSerializeTest_data(); + void FloatMessageSerializeTest(); + void DoubleMessageSerializeTest_data(); + void DoubleMessageSerializeTest(); + void StringMessageSerializeTest(); + void ComplexTypeSerializeTest_data(); + void ComplexTypeSerializeTest(); + void ResetComplexTypeSerializeTest_data(); + void ResetComplexTypeSerializeTest(); + void DefaultConstructedComplexTypeSerializeTest(); + void EmptyBytesMessageTest(); + void EmptyStringMessageTest(); + + /* TBD: Add ANY type support for Json Serializer + void OneofMessageEmptyTest(); + void OneofMessageClearTest(); + void OneofMessageIntTest(); + void OneofMessageComplexTest(); + */ + +private: + std::unique_ptr m_serializer; +}; + +using namespace qtprotobufnamespace::tests; + +void QtProtobufTypesJsonSerializationTest::BoolMessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("True") << true << qsizetype(22) << "{\"testFieldBool\":true}"_ba; + QTest::newRow("False") << false << qsizetype(23) << "{\"testFieldBool\":false}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::BoolMessageSerializeTest() +{ + QFETCH(const bool, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleBoolMessage test; + test.setTestFieldBool(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::IntMessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("555") << 555 << qsizetype(20) << "{\"testFieldInt\":555}"_ba; + QTest::newRow("0") << 0 << qsizetype(18) << "{\"testFieldInt\":0}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::IntMessageSerializeTest() +{ + QFETCH(const int32_t, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleIntMessage test; + test.setTestFieldInt(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::UIntMessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("15") << (uint32_t)15 << qsizetype(19) << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (uint32_t)300 << qsizetype(20) << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (uint32_t)65545 << qsizetype(22) << "{\"testFieldInt\":65545}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::UIntMessageSerializeTest() +{ + QFETCH(const uint32_t, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleUIntMessage test; + test.setTestFieldInt(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::SIntMessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("15") << (int32_t)15 << qsizetype(19) << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (int32_t)300 << qsizetype(20) << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (int32_t)65545 << qsizetype(22) << "{\"testFieldInt\":65545}"_ba; + + QTest::newRow("-1") << (int32_t)-1 << qsizetype(19) << "{\"testFieldInt\":-1}"_ba; + QTest::newRow("-462") << (int32_t)-462 << qsizetype(21) << "{\"testFieldInt\":-462}"_ba; + QTest::newRow("-63585") << (int32_t)-63585 << qsizetype(23) << "{\"testFieldInt\":-63585}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::SIntMessageSerializeTest() +{ + QFETCH(const int32_t, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleSIntMessage test; + test.setTestFieldInt(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::Int64MessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("15") << (int64_t)15 << qsizetype(19) << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (int64_t)300 << qsizetype(20) << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (int64_t)65545 << qsizetype(22) << "{\"testFieldInt\":65545}"_ba; + + QTest::newRow("-1") << (int64_t)-1 << qsizetype(19) << "{\"testFieldInt\":-1}"_ba; + QTest::newRow("-462") << (int64_t)-462 << qsizetype(21) << "{\"testFieldInt\":-462}"_ba; + QTest::newRow("-63585") << (int64_t)-63585 << qsizetype(23) << "{\"testFieldInt\":-63585}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::Int64MessageSerializeTest() +{ + QFETCH(const int64_t, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleInt64Message test; + test.setTestFieldInt(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::UInt64MessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("15") << (uint64_t)15 << qsizetype(19) << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (uint64_t)300 << qsizetype(20) << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (uint64_t)65545 << qsizetype(22) << "{\"testFieldInt\":65545}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::UInt64MessageSerializeTest() +{ + QFETCH(const QtProtobuf::uint64, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleUInt64Message test; + test.setTestFieldInt(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::SInt64MessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("15") << (int64_t)15 << qsizetype(19) << "{\"testFieldInt\":15}"_ba; + QTest::newRow("300") << (int64_t)300 << qsizetype(20) << "{\"testFieldInt\":300}"_ba; + QTest::newRow("65545") << (int64_t)65545 << qsizetype(22) << "{\"testFieldInt\":65545}"_ba; + + QTest::newRow("-1") << (int64_t)-1 << qsizetype(19) << "{\"testFieldInt\":-1}"_ba; + QTest::newRow("-462") << (int64_t)-462 << qsizetype(21) << "{\"testFieldInt\":-462}"_ba; + QTest::newRow("-63585") << (int64_t)-63585 << qsizetype(23) << "{\"testFieldInt\":-63585}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::SInt64MessageSerializeTest() +{ + QFETCH(const int64_t, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleSInt64Message test; + test.setTestFieldInt(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::FixedInt32MessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("15") << (uint32_t)15 << qsizetype(26) << "{\"testFieldFixedInt32\":15}"_ba; + QTest::newRow("300") << (uint32_t)300 << qsizetype(27) << "{\"testFieldFixedInt32\":300}"_ba; + QTest::newRow("65545") + << (uint32_t)65545 << qsizetype(29) << "{\"testFieldFixedInt32\":65545}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::FixedInt32MessageSerializeTest() +{ + QFETCH(const uint32_t, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleFixedInt32Message test; + test.setTestFieldFixedInt32(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::FixedInt64MessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("15") << (uint64_t)15 << qsizetype(26) << "{\"testFieldFixedInt64\":15}"_ba; + QTest::newRow("300") << (uint64_t)300 << qsizetype(27) << "{\"testFieldFixedInt64\":300}"_ba; + QTest::newRow("65545") + << (uint64_t)65545 << qsizetype(29) << "{\"testFieldFixedInt64\":65545}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::FixedInt64MessageSerializeTest() +{ + QFETCH(const uint64_t, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleFixedInt64Message test; + test.setTestFieldFixedInt64(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::SFixedInt32MessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("15") << (int32_t)15 << qsizetype(26) << "{\"testFieldFixedInt32\":15}"_ba; + QTest::newRow("300") << (int32_t)300 << qsizetype(27) << "{\"testFieldFixedInt32\":300}"_ba; + QTest::newRow("65545") + << (int32_t)65545 << qsizetype(29) << "{\"testFieldFixedInt32\":65545}"_ba; + + QTest::newRow("-1") << (int32_t)-1 << qsizetype(26) << "{\"testFieldFixedInt32\":-1}"_ba; + QTest::newRow("-462") << (int32_t)-462 << qsizetype(28) << "{\"testFieldFixedInt32\":-462}"_ba; + QTest::newRow("-63585") + << (int32_t)-63585 << qsizetype(30) << "{\"testFieldFixedInt32\":-63585}"_ba; +} +void QtProtobufTypesJsonSerializationTest::SFixedInt32MessageSerializeTest() +{ + QFETCH(const int32_t, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleSFixedInt32Message test; + test.setTestFieldFixedInt32(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::SFixedInt64MessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("15") << (int64_t)15 << qsizetype(26) << "{\"testFieldFixedInt64\":15}"_ba; + QTest::newRow("300") << (int64_t)300 << qsizetype(27) << "{\"testFieldFixedInt64\":300}"_ba; + QTest::newRow("65545") + << (int64_t)65545 << qsizetype(29) << "{\"testFieldFixedInt64\":65545}"_ba; + + QTest::newRow("-1") << (int64_t)-1 << qsizetype(26) << "{\"testFieldFixedInt64\":-1}"_ba; + QTest::newRow("-462") << (int64_t)-462 << qsizetype(28) << "{\"testFieldFixedInt64\":-462}"_ba; + QTest::newRow("-63585") << (int64_t)-63585 << qsizetype(30) + << "{\"testFieldFixedInt64\":-63585}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::SFixedInt64MessageSerializeTest() +{ + QFETCH(const int64_t, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleSFixedInt64Message test; + test.setTestFieldFixedInt64(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::FloatMessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("float_value_0_1") << 0.1f << qsizetype(22) << "{\"testFieldFloat\":0.1}"_ba; + QTest::newRow("float_value_min") << std::numeric_limits::min() << qsizetype(31) + << "{\"testFieldFloat\":1.175494e-38}"_ba; + QTest::newRow("float_value_max") << std::numeric_limits::max() << qsizetype(31) + << "{\"testFieldFloat\":3.402823e+38}"_ba; + QTest::newRow("float_neg_value_4_2") + << -4.2f << qsizetype(23) << "{\"testFieldFloat\":-4.2}"_ba; + QTest::newRow("float_neg_value_0_0") + << (float)-0.0f << qsizetype(20) << "{\"testFieldFloat\":0}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::FloatMessageSerializeTest() +{ + QFETCH(const float, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleFloatMessage test; + test.setTestFieldFloat(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::DoubleMessageSerializeTest_data() +{ + QTest::addColumn("value"); + QTest::addColumn("expectedSize"); + QTest::addColumn("expectedData"); + + QTest::newRow("double_value_0_1") << 0.1 << qsizetype(23) + << "{\"testFieldDouble\":0.1}"_ba; + QTest::newRow("double_value_min") + << std::numeric_limits::min() << qsizetype(40) + << "{\"testFieldDouble\":2.2250738585072e-308}"_ba; + QTest::newRow("double_value_max") + << std::numeric_limits::max() << qsizetype(40) + << "{\"testFieldDouble\":1.7976931348623e+308}"_ba; + QTest::newRow("double_neg_value_4_2") << -4.2 << qsizetype(24) + << "{\"testFieldDouble\":-4.2}"_ba; + QTest::newRow("double_value_0_0") << 0.0 << qsizetype(21) + << "{\"testFieldDouble\":0}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::DoubleMessageSerializeTest() +{ + QFETCH(const double, value); + QFETCH(const qsizetype, expectedSize); + QFETCH(const QByteArray, expectedData); + + SimpleDoubleMessage test; + test.setTestFieldDouble(value); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result.size(), expectedSize); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::StringMessageSerializeTest() +{ + SimpleStringMessage test; + test.setTestFieldString("qwerty"); + QByteArray result = test.serialize(m_serializer.get()); + + QCOMPARE(result, "{\"testFieldString\":\"qwerty\"}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestFieldString(""); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testFieldString\":\"\"}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestFieldString("null"); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testFieldString\":\"null\"}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestFieldString("NaN"); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testFieldString\":\"NaN\"}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestFieldString("Infinity"); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testFieldString\":\"Infinity\"}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestFieldString("-Infinity"); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testFieldString\":\"-Infinity\"}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::ComplexTypeSerializeTest_data() +{ + QTest::addColumn("intField"); + QTest::addColumn("stringField"); + QTest::addColumn("expectedData"); + + QTest::newRow("empty_value") + << 0 << "" + << "{\"testFieldInt\":0,\"testComplexField\":{\"testFieldString\":\"\"}}"_ba; + QTest::newRow("value_only_int") + << 42 << "" + << "{\"testFieldInt\":42,\"testComplexField\":{\"testFieldString\":\"\"}}"_ba; + QTest::newRow("value_only_string") + << 0 << "qwerty" + << "{\"testFieldInt\":0,\"testComplexField\":{\"testFieldString\":\"qwerty\"}}"_ba; + QTest::newRow("int_and_string") + << 42 << "qwerty" + << "{\"testFieldInt\":42,\"testComplexField\":{\"testFieldString\":\"qwerty\"}}"_ba; + QTest::newRow("int_and_big_string") + << 42 + << "YVRfJvjxqbgvFwS1YvOZXgtj5ffGLS7AiNHz9oZIoKbm7z8H79xBuyPkpQXvGoO09OY9xRawx3eOAs9xjo" + "TA1xJhrw28TAcq1CebYlC9WUfQC6hIantaNdyHiKToffi0Zt7la42SRxXZSP4GuxbcZIp53pJnyCwfCy1q" + "dFczT0dmn7h8fpyAdemEavwFeda4d0PApGfSU2jLt39X8kYUBxNM2WgALRBgHdVde87q6Pi5U69TjhMd28" + "W1SFD1DxyogCCrqOct2ZPICoLnrqdF3OdNzjRVLfeyvQ8LgLvRNFR9WfWAyAz79nKgBamd8Ntlvt4Mg35E" + "5gVS2g7AQ7rkm72cBdnW9sCEyGabeXAuH5j4GRbuLT7qBZWDcFLF4SsCdS3WfFGdNHfwaijzykByo71PvF" + "VlTXH2WJWoFvR5FALjBTn7bCdP0pAiSbLCY8Xz2Msc3dBb5Ff9GISPbUpNmUvBdMZMHQvqOmTNXEPpN0b7" + "4MDOMQfWJShOo3NkAvMjs" + << "{\"testFieldInt\":42,\"testComplexField\":{\"testFieldString\":\"YVRfJvjxqbgvFwS1Y" + "vOZXgtj5ffGLS7AiNHz9oZIoKbm7z8H79xBuyPkpQXvGoO09OY9xRawx3eOAs9xjoTA1xJhrw28TAcq1Ce" + "bYlC9WUfQC6hIantaNdyHiKToffi0Zt7la42SRxXZSP4GuxbcZIp53pJnyCwfCy1qdFczT0dmn7h8fpyAd" + "emEavwFeda4d0PApGfSU2jLt39X8kYUBxNM2WgALRBgHdVde87q6Pi5U69TjhMd28W1SFD1DxyogCCrqOc" + "t2ZPICoLnrqdF3OdNzjRVLfeyvQ8LgLvRNFR9WfWAyAz79nKgBamd8Ntlvt4Mg35E5gVS2g7AQ7rkm72cB" + "dnW9sCEyGabeXAuH5j4GRbuLT7qBZWDcFLF4SsCdS3WfFGdNHfwaijzykByo71PvFVlTXH2WJWoFvR5FAL" + "jBTn7bCdP0pAiSbLCY8Xz2Msc3dBb5Ff9GISPbUpNmUvBdMZMHQvqOmTNXEPpN0b74MDOMQfWJShOo3NkA" + "vMjs\"}}"_ba; + QTest::newRow("neg_int_and_string") + << -45 << "qwerty" + << "{\"testFieldInt\":-45,\"testComplexField\":{\"testFieldString\":\"qwerty\"}}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::ComplexTypeSerializeTest() +{ + QFETCH(const int, intField); + QFETCH(const QString, stringField); + QFETCH(const QByteArray, expectedData); + + SimpleStringMessage stringMessage; + stringMessage.setTestFieldString(stringField); + ComplexMessage test, testStd; + + test.setTestFieldInt(intField); + test.setTestComplexField(stringMessage); + + testStd.setTestFieldInt(intField); + testStd.setTestComplexField(stringMessage); + + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::ResetComplexTypeSerializeTest_data() +{ + QTest::addColumn("intField"); + QTest::addColumn("stringField"); + QTest::addColumn("expectedData"); + + QTest::newRow("empty_value") + << 0 << u""_s << "{\"testFieldInt\":0,\"testComplexField\":{}}"_ba; + QTest::newRow("value_only_int") + << 42 << u""_s << "{\"testFieldInt\":42,\"testComplexField\":{}}"_ba; + QTest::newRow("value_only_string") + << 0 << u"qwerty"_s << "{\"testFieldInt\":0,\"testComplexField\":{}}"_ba; + QTest::newRow("int_and_string") + << 42 << u"qwerty"_s << "{\"testFieldInt\":42,\"testComplexField\":{}}"_ba; +} + +void QtProtobufTypesJsonSerializationTest::ResetComplexTypeSerializeTest() +{ + QFETCH(const int, intField); + QFETCH(const QString, stringField); + QFETCH(const QByteArray, expectedData); + + SimpleStringMessage stringMessage; + stringMessage.setTestFieldString(stringField); + ComplexMessage test; + test.setTestFieldInt(intField); + test.setTestComplexField(stringMessage); + + // Reset Complex field + test.clearTestComplexField(); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, expectedData); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::DefaultConstructedComplexTypeSerializeTest() +{ + ComplexMessage test; + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testFieldInt\":0,\"testComplexField\":{}}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::EmptyBytesMessageTest() +{ + SimpleBytesMessage msg; + QByteArray result = msg.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testFieldBytes\":\"\"}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufTypesJsonSerializationTest::EmptyStringMessageTest() +{ + SimpleStringMessage msg; + QByteArray result = msg.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testFieldString\":\"\"}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +/* TBD: Add ANY type support for Json Serializer +void QtProtobufTypesJsonSerializationTest::OneofMessageEmptyTest() +{ +} + +void QtProtobufTypesJsonSerializationTest::OneofMessageIntTest() +{ +} + +void QtProtobufTypesJsonSerializationTest::OneofMessageClearTest() +{ +} + +void QtProtobufTypesJsonSerializationTest::OneofMessageComplexTest() +{ +} +*/ + +QTEST_MAIN(QtProtobufTypesJsonSerializationTest) +#include "tst_protobuf_serialization_json_basictypes.moc" diff --git a/tests/auto/protobuf/jsontypes/tst_protobuf_serialization_json_maptypes.cpp b/tests/auto/protobuf/jsontypes/tst_protobuf_serialization_json_maptypes.cpp new file mode 100644 index 00000000..6a480e15 --- /dev/null +++ b/tests/auto/protobuf/jsontypes/tst_protobuf_serialization_json_maptypes.cpp @@ -0,0 +1,123 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "mapmessages.qpb.h" + +#include +#include +#include + +using namespace qtprotobufnamespace::tests; +using namespace Qt::Literals::StringLiterals; + +class QtProtobufJsonMapTypesSerializationTest : public QObject +{ + Q_OBJECT +private slots: + void init() { m_serializer.reset(new QProtobufJsonSerializer); } + void SimpleFixed32StringMapSerializeTest(); + void SimpleSFixed32StringMapSerializeTest(); + void SimpleInt32StringMapSerializeTest(); + void SimpleSInt32StringMapSerializeTest(); + void SimpleUInt32StringMapSerializeTest(); + void SimpleFixed64StringMapSerializeTest(); + void SimpleSFixed64StringMapSerializeTest(); + void SimpleInt64StringMapSerializeTest(); + void SimpleSInt64StringMapSerializeTest(); + void SimpleUInt64StringMapSerializeTest(); + void SimpleStringStringMapSerializeTest(); + +private: + std::unique_ptr m_serializer; +}; + +void QtProtobufJsonMapTypesSerializationTest::SimpleFixed32StringMapSerializeTest() +{ + SimpleFixed32StringMapMessage test; + test.setMapField({ { 10, { "ten" } }, { 42, { "fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleSFixed32StringMapSerializeTest() +{ + SimpleSFixed32StringMapMessage test; + test.setMapField({ { 10, { "ten" } }, { -42, { "minus fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleInt32StringMapSerializeTest() +{ + SimpleInt32StringMapMessage test; + test.setMapField({ { -10, { "minus ten" } }, { 42, { "fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); + +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleSInt32StringMapSerializeTest() +{ + SimpleSInt32StringMapMessage test; + test.setMapField({ { 10, { "ten" } }, { -42, { "minus fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); + +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleUInt32StringMapSerializeTest() +{ + SimpleUInt32StringMapMessage test; + test.setMapField({ { 10, { "ten" } }, { 42, { "fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); + +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleFixed64StringMapSerializeTest() +{ + SimpleFixed64StringMapMessage test; + test.setMapField({ { 10, { "ten" } }, { 42, { "fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); + +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleSFixed64StringMapSerializeTest() +{ + SimpleSFixed64StringMapMessage test; + test.setMapField({ { 10, { "ten" } }, { -42, { "minus fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); + +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleInt64StringMapSerializeTest() +{ + SimpleInt64StringMapMessage test; + test.setMapField({ { -10, { "minus ten" } }, { 42, { "fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); + +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleSInt64StringMapSerializeTest() +{ + SimpleSInt64StringMapMessage test; + test.setMapField({ { 10, { "ten" } }, { -42, { "minus fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); + +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleUInt64StringMapSerializeTest() +{ + SimpleUInt64StringMapMessage test; + test.setMapField({ { 10, { "ten" } }, { 42, { "fourty two" } }, { 15, { "fifteen" } } }); + QByteArray result = test.serialize(m_serializer.get()); + +} + +void QtProtobufJsonMapTypesSerializationTest::SimpleStringStringMapSerializeTest() +{ + SimpleStringStringMapMessage test; + test.setMapField({ { "ben", "ten" }, + { "what is the answer?", "fourty two" }, + { "sweet", "fifteen" } }); + QByteArray result = test.serialize(m_serializer.get()); + +} + +QTEST_MAIN(QtProtobufJsonMapTypesSerializationTest) +#include "tst_protobuf_serialization_json_maptypes.moc" diff --git a/tests/auto/protobuf/jsontypes/tst_protobuf_serialization_json_repeatedtypes.cpp b/tests/auto/protobuf/jsontypes/tst_protobuf_serialization_json_repeatedtypes.cpp new file mode 100644 index 00000000..ead3e282 --- /dev/null +++ b/tests/auto/protobuf/jsontypes/tst_protobuf_serialization_json_repeatedtypes.cpp @@ -0,0 +1,293 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +//#include "basicmessages.qpb.h" +#include "repeatedmessages.qpb.h" + +#include +#include +#include + +using namespace Qt::Literals::StringLiterals; + +class QtProtobufRepeatedTypesJsonSerializationTest : public QObject +{ + Q_OBJECT +private slots: + void init() { + m_serializer.reset(new QProtobufJsonSerializer); + } + void RepeatedIntMessageTest(); + void RepeatedSIntMessageTest(); + void RepeatedUIntMessageTest(); + void RepeatedInt64MessageTest(); + void RepeatedSInt64MessageTest(); + void RepeatedUInt64MessageTest(); + void RepeatedFixedIntMessageTest(); + void RepeatedSFixedIntMessageTest(); + void RepeatedFixedInt64MessageTest(); + void RepeatedSFixedInt64MessageTest(); + void RepeatedStringMessageTest(); + void RepeatedFloatMessageTest(); + void RepeatedDoubleMessageTest(); + void RepeatedBytesMessageTest(); + void RepeatedComplexMessageTest(); + void RepeatedBoolMessageTest(); +private: + std::unique_ptr m_serializer; +}; + +using namespace qtprotobufnamespace::tests; + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedIntMessageTest() +{ + RepeatedIntMessage test; + test.setTestRepeatedInt({0, 1, 321, -65999, 123245, -3, 3}); + QByteArray result = test.serialize(m_serializer.get()); + + QCOMPARE(result, "{\"testRepeatedInt\":[0,1,321,-65999,123245,-3,3]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::int32List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedSIntMessageTest() +{ + RepeatedSIntMessage test; + test.setTestRepeatedInt({1, 321, -65999, 123245, -3, 3, 0}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[1,321,-65999,123245,-3,3,0]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::sint32List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedUIntMessageTest() +{ + RepeatedUIntMessage test; + test.setTestRepeatedInt({1, 0, 321, 65999, 123245, 3}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[1,0,321,65999,123245,3]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::uint32List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedInt64MessageTest() +{ + RepeatedInt64Message test; + test.setTestRepeatedInt({1, 321, -65999, 12324523123123, -3, 0, 3}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[1,321,-65999,12324523123123,-3,0,3]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::int64List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedSInt64MessageTest() +{ + RepeatedSInt64Message test; + test.setTestRepeatedInt({1, 321, -65999, 12324523123123, 0, -3, 3}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[1,321,-65999,12324523123123,0,-3,3]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::sint64List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedUInt64MessageTest() +{ + RepeatedUInt64Message test; + test.setTestRepeatedInt({1, 321, 0, 65999, 123245, 123245324235425234, 3}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[1,321,0,65999,123245,123245324235425234,3]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::uint64List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedFixedIntMessageTest() +{ + RepeatedFixedIntMessage test; + test.setTestRepeatedInt({1, 321, 65999, 12324523, 3, 3, 0}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[1,321,65999,12324523,3,3,0]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::fixed32List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedSFixedIntMessageTest() +{ + RepeatedSFixedIntMessage test; + test.setTestRepeatedInt({0, 1, 321, -65999, 12324523, -3, 3}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[0,1,321,-65999,12324523,-3,3]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::sfixed32List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedFixedInt64MessageTest() +{ + RepeatedFixedInt64Message test; + test.setTestRepeatedInt({1, 321, 65999, 123245324235425234, 3, 3, 0}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[1,321,65999,123245324235425234,3,3,0]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::fixed64List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedSFixedInt64MessageTest() +{ + RepeatedSFixedInt64Message test; + test.setTestRepeatedInt({1, 321, -65999, 123245324235425234, -3, 3, 0}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[1,321,-65999,123245324235425234,-3,3,0]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedInt(QtProtobuf::sfixed64List()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedInt\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedStringMessageTest() +{ + RepeatedStringMessage test; + test.setTestRepeatedString({"aaaa","bbbbb","ccc","dddddd","eeeee", ""}); + QByteArray result = test.serialize(m_serializer.get()); + QCOMPARE(result, + "{\"testRepeatedString\":[\"aaaa\",\"bbbbb\",\"ccc\",\"dddddd\",\"eeeee\",\"\"]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + + test.setTestRepeatedString(QStringList()); + result = test.serialize(m_serializer.get()); + QCOMPARE(result, "{\"testRepeatedString\":[]}"_ba); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedFloatMessageTest() +{ + RepeatedFloatMessage test; + test.setTestRepeatedFloat({0.4f, 1.2f, 0.5f, 3.912348f, 0.6f}); + QByteArray result = test.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, "{\"testRepeatedFloat\":[0.4,1.2,0.5,3.912348,0.6]}"_ba); + + test.setTestRepeatedFloat(QtProtobuf::floatList()); + result = test.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, "{\"testRepeatedFloat\":[]}"_ba); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedDoubleMessageTest() +{ + RepeatedDoubleMessage test; + test.setTestRepeatedDouble({0.1, 0.2, 0.3, 3.912348239293, 0.5}); + QByteArray result = test.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, "{\"testRepeatedDouble\":[0.1,0.2,0.3,3.912348239293,0.5]}"_ba); + + test.setTestRepeatedDouble(QtProtobuf::doubleList()); + result = test.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, "{\"testRepeatedDouble\":[]}"_ba); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedBytesMessageTest() +{ + RepeatedBytesMessage test; + test.setTestRepeatedBytes({QByteArray::fromHex("010203040506"), + QByteArray::fromHex("ffffffff"), + QByteArray::fromHex("eaeaeaeaea"), + QByteArray::fromHex("010203040506")}); + QByteArray result = test.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, + "{\"testRepeatedBytes\":[\"AQIDBAUG\",\"/////w==\",\"6urq6uo=\",\"AQIDBAUG\"]}"_ba); + + test.setTestRepeatedBytes(QByteArrayList()); + result = test.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, "{\"testRepeatedBytes\":[]}"_ba); + + test.setTestRepeatedBytes({QByteArray::fromHex("010203040506"), + QByteArray::fromHex(""), + QByteArray::fromHex("eaeaeaeaea"), + QByteArray::fromHex("010203040506")}); + result = test.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, + "{\"testRepeatedBytes\":[\"AQIDBAUG\",\"\",\"6urq6uo=\",\"AQIDBAUG\"]}"_ba); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedComplexMessageTest() +{ + SimpleStringMessage stringMsg; + stringMsg.setTestFieldString("qwerty"); + ComplexMessage msg; + msg.setTestFieldInt(25); + msg.setTestComplexField(stringMsg); + RepeatedComplexMessage test; + test.setTestRepeatedComplex({msg, msg, msg}); + QByteArray result = test.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, + "{\"testRepeatedComplex\":[{\"testFieldInt\":25,\"testComplexField\":" + "{\"testFieldString\":\"qwerty\"}},{\"testFieldInt\":25,\"testComplexField\":" + "{\"testFieldString\":\"qwerty\"}},{\"testFieldInt\":25,\"testComplexField\":" + "{\"testFieldString\":\"qwerty\"}}]}"_ba); + + test.setTestRepeatedComplex({}); + result = test.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, "{\"testRepeatedComplex\":[]}"_ba); +} + +void QtProtobufRepeatedTypesJsonSerializationTest::RepeatedBoolMessageTest() +{ + RepeatedBoolMessage boolMsg; + boolMsg.setTestRepeatedBool({ true, true, true, false, false, false, false, false, + false, false, false, false, true }); + QByteArray result = boolMsg.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, "{\"testRepeatedBool\":[true,true,true,false,false,false,false," + "false,false,false,false,false,true]}"_ba); + + boolMsg.setTestRepeatedBool(QtProtobuf::boolList()); + result = boolMsg.serialize(m_serializer.get()); + QVERIFY(!QJsonDocument::fromJson(result).isNull()); + QCOMPARE(result, "{\"testRepeatedBool\":[]}"_ba); +} + +QTEST_MAIN(QtProtobufRepeatedTypesJsonSerializationTest) +#include "tst_protobuf_serialization_json_repeatedtypes.moc"