Browse Source

Implement enum lists support

- Rework enum types serialization mechanism
- Add enum lists serialization/deserialization support
- Add and update tests
- Fix issue in lists serializers(0 value was not serialized
  for varint lists)
Alexey Edelev 5 years ago
parent
commit
c95642db58

+ 1 - 0
src/generator/globalenumssourcegenerator.cpp

@@ -87,6 +87,7 @@ void GlobalEnumsSourceGenerator::printRegisterBody(const std::list<const FileDes
                                                                    {"namespaces", fullNamespace}};
             mPrinter.Print(properties, Templates::ComplexGlobalEnumFieldRegistrationTemplate);
             mPrinter.Print(properties, Templates::RegisterMetaTypeTemplate);
+            mPrinter.Print(properties, Templates::RegisterEnumSerializersTemplate);
         }
     }
     Outdent();

+ 3 - 1
src/generator/protobufsourcegenerator.cpp

@@ -59,9 +59,11 @@ void ProtobufSourceGenerator::printRegisterBody()
             mPrinter.Print({{"type", mClassName + "::" + field->enum_type()->name() + "List"},
                             {"namespaces", mNamespacesColonDelimited}},
                            Templates::RegisterMetaTypeTemplateNoNamespace);
-            mPrinter.Print({{"type", mClassName+ "::" + field->enum_type()->name() + "List"},
+            mPrinter.Print({{"type", mClassName + "::" + field->enum_type()->name() + "List"},
                             {"namespaces", mNamespacesColonDelimited}},
                            Templates::RegisterMetaTypeTemplate);
+            mPrinter.Print({{"type", mClassName + "::" + field->enum_type()->name()}},
+                           Templates::RegisterEnumSerializersTemplate);
         } else if (field->is_map()) {
             mPrinter.Print({{"type", field->message_type()->name()},
                             {"namespaces", mClassName}},

+ 1 - 0
src/generator/templates.cpp

@@ -209,6 +209,7 @@ const char *Templates::ClientMethodDefinitionAsync2Template = "\nvoid $classname
                                                               "}\n";
 
 const char *Templates::RegisterSerializersTemplate = "qRegisterProtobufType<$classname$>();\n";
+const char *Templates::RegisterEnumSerializersTemplate = "qRegisterProtobufEnumType<$type$>();\n";
 const char *Templates::RegistratorTemplate = "static QtProtobuf::QProtobufRegistrationHelper helper(registerTypes);\n";
 const char *Templates::QmlRegisterTypeTemplate = "qmlRegisterType<$namespaces$::$classname$>(\"$package$\", 1, 0, \"$classname$\");\n";
 const char *Templates::QmlRegisterTypeUncreatableTemplate = "qmlRegisterUncreatableType<$namespaces$::$classname$>(\"$package$\", 1, 0, \"$classname$\", \"$namespaces$::$classname$ Could not be created from qml context\");\n";

+ 1 - 0
src/generator/templates.h

@@ -110,6 +110,7 @@ public:
     static const char *QEnumTemplate;
     static const char *MapSerializationRegisterTemplate;
     static const char *RegisterSerializersTemplate;
+    static const char *RegisterEnumSerializersTemplate;
     static const char *RegistratorTemplate;
     static const char *QmlRegisterTypeTemplate;
     static const char *QmlRegisterTypeUncreatableTemplate;

+ 53 - 0
src/protobuf/qabstractprotobufserializer.h

@@ -183,6 +183,44 @@ public:
      * \see https://developers.google.com/protocol-buffers/docs/proto3#maps for details
      */
     virtual void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const = 0;
+
+    /*!
+     * \brief serializeEnum Serializes enum value represented as int64 type
+     * \param[in] value Enum value to be serialized
+     * \param[in] metaEnum Information about enumeration type
+     * \param[in] metaProperty Information about property to be serialized
+     * \return Raw serialized data represented as byte array
+     *
+     * \see https://developers.google.com/protocol-buffers/docs/proto3#maps for details
+     */
+    virtual QByteArray serializeEnum(int64 value, const QMetaEnum &metaEnum, const QtProtobuf::QProtobufMetaProperty &metaProperty) const = 0;
+
+    /*!
+     * \brief serializeEnumList  Method called to serialize list of enum values
+     * \param[in] value List of enum values to be serialized, represented as int64
+     * \param[in] metaEnum Information about enumeration type
+     * \param[in] metaProperty Information about property to be serialized
+     * \return Raw serialized data represented as byte array
+     *
+     * \see https://developers.google.com/protocol-buffers/docs/proto3#maps for details
+     */
+    virtual QByteArray serializeEnumList(const QList<int64> &value, const QMetaEnum &metaEnum, const QtProtobuf::QProtobufMetaProperty &metaProperty) const = 0;
+
+    /*!
+     * \brief deserializeEnum Deserializes enum value from byte stream
+     * \param[out] value Buffer that will be used to collect new enum value
+     * \param[in] metaEnum Information about enumeration type
+     * \param[in] it Points to serialized raw key/value data
+     */
+    virtual void deserializeEnum(int64 &value, const QMetaEnum &metaEnum, QProtobufSelfcheckIterator &it) const = 0;
+
+    /*!
+     * \brief deserializeEnum Deserializes list of enum values from byte stream
+     * \param[out] value QList that will be used to collect deserialized enum values
+     * \param[in] metaEnum Information about enumeration type
+     * \param[in] it Points to serialized raw key/value data
+     */
+    virtual void deserializeEnumList(QList<int64> &value, const QMetaEnum &metaEnum, QProtobufSelfcheckIterator &it) const = 0;
 };
 /*! \} */
 }
@@ -226,3 +264,18 @@ inline void qRegisterProtobufMapType() {
     QtProtobufPrivate::registerHandler(qMetaTypeId<QMap<K, QSharedPointer<V>>>(), { QtProtobufPrivate::serializeMap<K, V>,
     QtProtobufPrivate::deserializeMap<K, V>, QtProtobufPrivate::MapHandler });
 }
+
+
+/*!
+ * \brief Registers serializers for enumeration type in QtProtobuf global serializers registry
+ *
+ * \details generates default serializers for enumeration and QList of enumerations.
+ */
+template<typename T,
+         typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
+inline void qRegisterProtobufEnumType() {
+    QtProtobufPrivate::registerHandler(qMetaTypeId<T>(), { QtProtobufPrivate::serializeEnum<T>,
+                                                           QtProtobufPrivate::deserializeEnum<T>, QtProtobufPrivate::ObjectHandler });
+    QtProtobufPrivate::registerHandler(qMetaTypeId<QList<T>>(), { QtProtobufPrivate::serializeEnumList<T>,
+                                                           QtProtobufPrivate::deserializeEnumList<T>, QtProtobufPrivate::ListHandler });
+}

+ 47 - 8
src/protobuf/qabstractprotobufserializer_p.h

@@ -28,6 +28,7 @@
 #include <QObject>
 #include <QVariant>
 #include <QMetaObject>
+#include <QMetaEnum>
 
 #include <functional>
 
@@ -71,7 +72,6 @@ extern Q_PROTOBUF_EXPORT void registerHandler(int userType, const SerializationH
 
 /*!
  * \private
- *
  * \brief default serializer template for type T inherited of QObject
  */
 template <typename T,
@@ -83,7 +83,6 @@ void serializeObject(const QtProtobuf::QAbstractProtobufSerializer *serializer,
 
 /*!
  * \private
- *
  * \brief default serializer template for list of type T objects inherited of QObject
  */
 template<typename V,
@@ -109,7 +108,6 @@ void serializeList(const QtProtobuf::QAbstractProtobufSerializer *serializer, co
 
 /*!
  * \private
- *
  * \brief default serializer template for map of key K, value V
  */
 template<typename K, typename V,
@@ -124,9 +122,7 @@ void serializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, con
 
 /*!
  * \private
- *
- * \brief default serializer template for map of type key K, value V. Specialization for V
- *        inherited of QObject
+ * \brief default serializer template for map of type key K, value V. Specialization for V inherited of QObject
  */
 template<typename K, typename V,
          typename std::enable_if_t<std::is_base_of<QObject, V>::value, int> = 0>
@@ -144,7 +140,32 @@ void serializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, con
 
 /*!
  * \private
- *
+ * \brief default serializer template for enum types
+ */
+template<typename T,
+         typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
+void serializeEnum(const QtProtobuf::QAbstractProtobufSerializer *serializer, const QVariant &value, const QtProtobuf::QProtobufMetaProperty &metaProperty, QByteArray &buffer) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer set is not setup");
+    buffer.append(serializer->serializeEnum(QtProtobuf::int64(value.value<T>()), QMetaEnum::fromType<T>(),  metaProperty));
+}
+
+/*!
+ * \private
+ * \brief default serializer template for enum list types
+ */
+template<typename T,
+         typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
+void serializeEnumList(const QtProtobuf::QAbstractProtobufSerializer *serializer, const QVariant &value, const QtProtobuf::QProtobufMetaProperty &metaProperty, QByteArray &buffer) {
+    Q_ASSERT_X(serializer != nullptr, "QAbstractProtobufSerializer", "serializer set is not setup");
+    QList<QtProtobuf::int64> intList;
+    for (auto enumValue : value.value<QList<T>>()) {
+        intList.append(QtProtobuf::int64(enumValue));
+    }
+    buffer.append(serializer->serializeEnumList(intList, QMetaEnum::fromType<T>(), metaProperty));
+}
+
+/*!
+ * \private
  * \brief default deserializer template for type T inherited of QObject
  */
 template <typename T,
@@ -158,7 +179,6 @@ void deserializeObject(const QtProtobuf::QAbstractProtobufSerializer *serializer
 
 /*!
  * \private
- *
  * \brief default deserializer template for list of type T objects inherited of QObject
  */
 template <typename V,
@@ -215,4 +235,23 @@ void deserializeMap(const QtProtobuf::QAbstractProtobufSerializer *serializer, Q
     previous = QVariant::fromValue<QMap<K, QSharedPointer<V>>>(out);
 }
 
+template <typename T,
+          typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
+void deserializeEnum(const QtProtobuf::QAbstractProtobufSerializer *serializer, QtProtobuf::QProtobufSelfcheckIterator &it, QVariant &to) {
+    QtProtobuf::int64 intValue;
+    serializer->deserializeEnum(intValue, QMetaEnum::fromType<T>(), it);
+    to = QVariant::fromValue<T>(static_cast<T>(intValue._t));
+}
+
+template <typename T,
+          typename std::enable_if_t<std::is_enum<T>::value, int> = 0>
+void deserializeEnumList(const QtProtobuf::QAbstractProtobufSerializer *serializer, QtProtobuf::QProtobufSelfcheckIterator &it, QVariant &previous) {
+    QList<QtProtobuf::int64> intList;
+    serializer->deserializeEnumList(intList, QMetaEnum::fromType<T>(), it);
+    QList<T> enumList = previous.value<QList<T>>();
+    for (auto intValue : intList) {
+        enumList.append(static_cast<T>(intValue._t));
+    }
+    previous = QVariant::fromValue<QList<T>>(enumList);
+}
 }

+ 30 - 0
src/protobuf/qprotobufjsonserializer.cpp

@@ -132,3 +132,33 @@ void QProtobufJsonSerializer::deserializeMapPair(QVariant &key, QVariant &value,
     Q_UNUSED(value)
     Q_UNUSED(it)
 }
+
+QByteArray QProtobufJsonSerializer::serializeEnum(int64 value, const QMetaEnum &metaEnum, const QtProtobuf::QProtobufMetaProperty &metaProperty) const
+{
+    Q_UNUSED(value)
+    Q_UNUSED(metaEnum)
+    Q_UNUSED(metaProperty)
+    return QByteArray();
+}
+
+QByteArray QProtobufJsonSerializer::serializeEnumList(const QList<int64> &value, const QMetaEnum &metaEnum, const QtProtobuf::QProtobufMetaProperty &metaProperty) const
+{
+    Q_UNUSED(value)
+    Q_UNUSED(metaEnum)
+    Q_UNUSED(metaProperty)
+    return QByteArray();
+}
+
+void QProtobufJsonSerializer::deserializeEnum(int64 &value, const QMetaEnum &metaEnum, QProtobufSelfcheckIterator &it) const
+{
+    Q_UNUSED(value)
+    Q_UNUSED(metaEnum)
+    Q_UNUSED(it)
+}
+
+void QProtobufJsonSerializer::deserializeEnumList(QList<int64> &value, const QMetaEnum &metaEnum, QProtobufSelfcheckIterator &it) const
+{
+    Q_UNUSED(value)
+    Q_UNUSED(metaEnum)
+    Q_UNUSED(it)
+}

+ 6 - 0
src/protobuf/qprotobufjsonserializer.h

@@ -52,6 +52,12 @@ protected:
 
     QByteArray serializeMapPair(const QVariant &key, const QVariant &value, const QProtobufMetaProperty &metaProperty) const override;
     void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const override;
+
+    QByteArray serializeEnum(int64 value, const QMetaEnum &metaEnum, const QtProtobuf::QProtobufMetaProperty &metaProperty) const override;
+    QByteArray serializeEnumList(const QList<int64> &value, const QMetaEnum &metaEnum, const QtProtobuf::QProtobufMetaProperty &metaProperty) const override;
+
+    void deserializeEnum(int64 &value, const QMetaEnum &metaEnum, QProtobufSelfcheckIterator &it) const override;
+    void deserializeEnumList(QList<int64> &value, const QMetaEnum &metaEnum, QProtobufSelfcheckIterator &it) const override;
 private:
     std::unique_ptr<QProtobufJsonSerializerPrivate> d_ptr;
 };

+ 44 - 16
src/protobuf/qprotobufserializer.cpp

@@ -189,6 +189,41 @@ void QProtobufSerializer::deserializeMapPair(QVariant &key, QVariant &value, QPr
     }
 }
 
+QByteArray QProtobufSerializer::serializeEnum(int64 value, const QMetaEnum &/*metaEnum*/, const QtProtobuf::QProtobufMetaProperty &metaProperty) const
+{
+    WireTypes type = Varint;
+    int fieldIndex = metaProperty.protoFieldIndex();
+    QByteArray result = QProtobufSerializerPrivate::serializeBasic<int64>(value, fieldIndex);
+    if (fieldIndex != QtProtobufPrivate::NotUsedFieldIndex) {
+        result.prepend(QProtobufSerializerPrivate::encodeHeader(metaProperty.protoFieldIndex(), type));
+    }
+    return result;
+}
+
+QByteArray QProtobufSerializer::serializeEnumList(const QList<int64> &value, const QMetaEnum &/*metaEnum*/, const QtProtobuf::QProtobufMetaProperty &metaProperty) const
+{
+    WireTypes type = LengthDelimited;
+    int fieldIndex = metaProperty.protoFieldIndex();
+    QByteArray result = QProtobufSerializerPrivate::serializeListType<int64>(value, fieldIndex);
+    if (fieldIndex != QtProtobufPrivate::NotUsedFieldIndex) {
+        result.prepend(QProtobufSerializerPrivate::encodeHeader(metaProperty.protoFieldIndex(), type));
+    }
+    return result;
+}
+
+void QProtobufSerializer::deserializeEnum(int64 &value, const QMetaEnum &/*metaEnum*/, QProtobufSelfcheckIterator &it) const
+{
+    QVariant variantValue;
+    QProtobufSerializerPrivate::deserializeBasic<int64>(it, variantValue);
+    value = variantValue.value<int64>();
+}
+
+void QProtobufSerializer::deserializeEnumList(QList<int64> &value, const QMetaEnum &/*metaEnum*/, QProtobufSelfcheckIterator &it) const
+{
+    QVariant variantValue;
+    QProtobufSerializerPrivate::deserializeList<int64>(it, variantValue);
+    value = variantValue.value<QList<int64>>();
+}
 
 QProtobufSerializerPrivate::QProtobufSerializerPrivate(QProtobufSerializer *q) : q_ptr(q)
 {
@@ -244,9 +279,6 @@ QByteArray QProtobufSerializerPrivate::serializeProperty(const QVariant &propert
     WireTypes type = UnknownWireType;
 
     int userType = propertyValue.userType();
-    if (metaProperty.isEnumType()) {
-        userType = qMetaTypeId<int64>();
-    }
 
     //TODO: replace with some common function
     int fieldIndex = metaProperty.protoFieldIndex();
@@ -292,20 +324,16 @@ void QProtobufSerializerPrivate::deserializeProperty(QObject *object, const QPro
                   << "currentByte:" << QString::number((*it), 16);
 
     QVariant newPropertyValue;
-    if (metaProperty.isEnumType()) {
-        QProtobufSerializerPrivate::deserializeBasic<int64>(it, newPropertyValue);
-        newPropertyValue.convert(qMetaTypeId<int32_t>());
+    newPropertyValue = metaProperty.read(object);
+    int userType = metaProperty.userType();
+
+    //TODO: replace with some common function
+    auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
+    if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
+        basicIt->second.deserializer(it, newPropertyValue);
     } else {
-        newPropertyValue = metaProperty.read(object);
-        int userType = metaProperty.userType();
-        //TODO: replace with some common function
-        auto basicIt = QProtobufSerializerPrivate::handlers.find(userType);
-        if (basicIt != QProtobufSerializerPrivate::handlers.end()) {
-            basicIt->second.deserializer(it, newPropertyValue);
-        } else {
-            auto &handler = QtProtobufPrivate::findHandler(userType);
-            handler.deserializer(q_ptr, it, newPropertyValue);//throws if not implemented
-        }
+        auto &handler = QtProtobufPrivate::findHandler(userType);
+        handler.deserializer(q_ptr, it, newPropertyValue);
     }
     metaProperty.write(object, newPropertyValue);
 }

+ 6 - 0
src/protobuf/qprotobufserializer.h

@@ -54,6 +54,12 @@ protected:
     QByteArray serializeMapPair(const QVariant &key, const QVariant &value, const QProtobufMetaProperty &metaProperty) const override;
     void deserializeMapPair(QVariant &key, QVariant &value, QProtobufSelfcheckIterator &it) const override;
 
+    QByteArray serializeEnum(int64 value, const QMetaEnum &metaEnum, const QtProtobuf::QProtobufMetaProperty &metaProperty) const override;
+    QByteArray serializeEnumList(const QList<int64> &value, const QMetaEnum &metaEnum, const QtProtobuf::QProtobufMetaProperty &metaProperty) const override;
+
+    void deserializeEnum(int64 &value, const QMetaEnum &metaEnum, QProtobufSelfcheckIterator &it) const override;
+    void deserializeEnumList(QList<int64> &value, const QMetaEnum &metaEnum, QProtobufSelfcheckIterator &it) const override;
+
     std::unique_ptr<QProtobufSerializerPrivate> d_ptr;
 };
 

+ 7 - 1
src/protobuf/qprotobufserializer_p.h

@@ -237,7 +237,11 @@ public:
         int empty = QtProtobufPrivate::NotUsedFieldIndex;
         QByteArray serializedList;
         for (auto &value : listValue) {
-            serializedList.append(serializeBasic<V>(value, empty));
+            QByteArray element = serializeBasic<V>(value, empty);
+            if (element.isEmpty()) {
+                element.append('\0');
+            }
+            serializedList.append(element);
         }
         //If internal field type is not LengthDelimited, exact amount of fields to be specified
         serializedList = prependLengthDelimitedSize(serializedList);
@@ -263,6 +267,7 @@ public:
         outFieldIndex = QtProtobufPrivate::NotUsedFieldIndex;
         return serializedList;
     }
+
     //###########################################################################
     //                               Deserializers
     //###########################################################################
@@ -426,6 +431,7 @@ public:
                 type
         };
     }
+
     // this set of 3 methods is used to skip bytes corresponding to an unexpected property
     // in a serialized message met while the message being deserialized
     static int skipSerializedFieldBytes(QProtobufSelfcheckIterator &it, WireTypes type);

+ 18 - 0
tests/test_protobuf/deserializationtest.cpp

@@ -86,6 +86,8 @@
 #include "fieldindextest3message.h"
 #include "fieldindextest4message.h"
 
+#include "simpleenumlistmessage.h"
+
 using namespace qtprotobufnamespace::tests;
 using namespace QtProtobuf::tests;
 using namespace QtProtobuf;
@@ -903,3 +905,19 @@ TEST_F(DeserializationTest, FieldIndexRangeTest)
     msg4.deserialize(serializer.get(), QByteArray::fromHex("f8ffffff0f02"));
     ASSERT_EQ(msg4.testField(), 1);
 }
+
+TEST_F(DeserializationTest, SimpleEnumListMessageTest)
+{
+    SimpleEnumListMessage msg;
+
+    msg.deserialize(serializer.get(), QByteArray());
+    ASSERT_TRUE(msg.localEnumList().isEmpty());
+
+    msg.deserialize(serializer.get(), QByteArray::fromHex("0a06000102010203"));
+    ASSERT_TRUE((msg.localEnumList() == SimpleEnumListMessage::LocalEnumList {SimpleEnumListMessage::LOCAL_ENUM_VALUE0,
+                SimpleEnumListMessage::LOCAL_ENUM_VALUE1,
+                SimpleEnumListMessage::LOCAL_ENUM_VALUE2,
+                SimpleEnumListMessage::LOCAL_ENUM_VALUE1,
+                SimpleEnumListMessage::LOCAL_ENUM_VALUE2,
+                SimpleEnumListMessage::LOCAL_ENUM_VALUE3}));
+}

+ 42 - 22
tests/test_protobuf/serializationtest.cpp

@@ -75,6 +75,7 @@
 #include "fieldindextest2message.h"
 #include "fieldindextest3message.h"
 #include "fieldindextest4message.h"
+#include "simpleenumlistmessage.h"
 
 using namespace qtprotobufnamespace::tests;
 using namespace QtProtobuf::tests;
@@ -1335,10 +1336,10 @@ TEST_F(SerializationTest, ComplexTypeSerializeTest)
 TEST_F(SerializationTest, RepeatedIntMessageTest)
 {
     RepeatedIntMessage test;
-    test.setTestRepeatedInt({1, 321, -65999, 123245, -3, 3});
+    test.setTestRepeatedInt({0, 1, 321, -65999, 123245, -3, 3});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "RepeatedIntMessage result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a1101c102b1fcfbff0fedc207fdffffff0f03"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a120001c102b1fcfbff0fedc207fdffffff0f03"));
     test.setTestRepeatedInt(int32List());
     result = test.serialize(serializer.get());
     ASSERT_TRUE(result.isEmpty());
@@ -1347,10 +1348,10 @@ TEST_F(SerializationTest, RepeatedIntMessageTest)
 TEST_F(SerializationTest, RepeatedSIntMessageTest)
 {
     RepeatedSIntMessage test;
-    test.setTestRepeatedInt({1, 321, -65999, 123245, -3, 3});
+    test.setTestRepeatedInt({1, 321, -65999, 123245, -3, 3, 0});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "RepeatedSIntMessage result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a0b0282059d8708da850f0506"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a0c0282059d8708da850f050600"));
 
     test.setTestRepeatedInt(sint32List());
     result = test.serialize(serializer.get());
@@ -1360,10 +1361,10 @@ TEST_F(SerializationTest, RepeatedSIntMessageTest)
 TEST_F(SerializationTest, RepeatedUIntMessageTest)
 {
     RepeatedUIntMessage test;
-    test.setTestRepeatedInt({1, 321, 65999, 123245, 3});
+    test.setTestRepeatedInt({1, 0, 321, 65999, 123245, 3});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a0a01c102cf8304edc20703"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a0b0100c102cf8304edc20703"));
 
     test.setTestRepeatedInt(uint32List());
     result = test.serialize(serializer.get());
@@ -1373,10 +1374,10 @@ TEST_F(SerializationTest, RepeatedUIntMessageTest)
 TEST_F(SerializationTest, RepeatedInt64MessageTest)
 {
     RepeatedInt64Message test;
-    test.setTestRepeatedInt({1, 321, -65999, 12324523123123, -3, 3});
+    test.setTestRepeatedInt({1, 321, -65999, 12324523123123, -3, 0, 3});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a1f01c102b1fcfbffffffffffff01b3c3cab6d8e602fdffffffffffffffff0103"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a2001c102b1fcfbffffffffffff01b3c3cab6d8e602fdffffffffffffffff010003"));
 
     test.setTestRepeatedInt(int64List());
     result = test.serialize(serializer.get());
@@ -1386,10 +1387,10 @@ TEST_F(SerializationTest, RepeatedInt64MessageTest)
 TEST_F(SerializationTest, RepeatedSInt64MessageTest)
 {
     RepeatedSInt64Message test;
-    test.setTestRepeatedInt({1, 321, -65999, 12324523123123, -3, 3});
+    test.setTestRepeatedInt({1, 321, -65999, 12324523123123, 0, -3, 3});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a0f0282059d8708e68695edb0cd050506"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a100282059d8708e68695edb0cd05000506"));
 
     test.setTestRepeatedInt(sint64List());
     result = test.serialize(serializer.get());
@@ -1399,10 +1400,10 @@ TEST_F(SerializationTest, RepeatedSInt64MessageTest)
 TEST_F(SerializationTest, RepeatedUInt64MessageTest)
 {
     RepeatedUInt64Message test;
-    test.setTestRepeatedInt({1, 321, 65999, 123245, 123245324235425234, 3});
+    test.setTestRepeatedInt({1, 321, 0, 65999, 123245, 123245324235425234, 3});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a1301c102cf8304edc207d28b9fda82dff6da0103"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a1401c10200cf8304edc207d28b9fda82dff6da0103"));
 
     test.setTestRepeatedInt(uint64List());
     result = test.serialize(serializer.get());
@@ -1412,10 +1413,10 @@ TEST_F(SerializationTest, RepeatedUInt64MessageTest)
 TEST_F(SerializationTest, RepeatedFixedIntMessageTest)
 {
     RepeatedFixedIntMessage test;
-    test.setTestRepeatedInt({1, 321, 65999, 12324523, 3, 3});
+    test.setTestRepeatedInt({1, 321, 65999, 12324523, 3, 3, 0});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a180100000041010000cf010100ab0ebc000300000003000000"));
+    ASSERT_STREQ(result.toHex().toStdString().c_str(), "0a1c0100000041010000cf010100ab0ebc00030000000300000000000000");
     test.setTestRepeatedInt(fixed32List());
     result = test.serialize(serializer.get());
     ASSERT_TRUE(result.isEmpty());
@@ -1424,10 +1425,10 @@ TEST_F(SerializationTest, RepeatedFixedIntMessageTest)
 TEST_F(SerializationTest, RepeatedSFixedIntMessageTest)
 {
     RepeatedSFixedIntMessage test;
-    test.setTestRepeatedInt({1, 321, -65999, 12324523, -3, 3});
+    test.setTestRepeatedInt({0, 1, 321, -65999, 12324523, -3, 3});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a18010000004101000031fefeffab0ebc00fdffffff03000000"));
+    ASSERT_STREQ(result.toHex().toStdString().c_str(), "0a1c00000000010000004101000031fefeffab0ebc00fdffffff03000000");
 
     test.setTestRepeatedInt(sfixed32List());
     result = test.serialize(serializer.get());
@@ -1437,10 +1438,10 @@ TEST_F(SerializationTest, RepeatedSFixedIntMessageTest)
 TEST_F(SerializationTest, RepeatedFixedInt64MessageTest)
 {
     RepeatedFixedInt64Message test;
-    test.setTestRepeatedInt({1, 321, 65999, 123245324235425234, 3, 3});
+    test.setTestRepeatedInt({1, 321, 65999, 123245324235425234, 3, 3, 0});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a3001000000000000004101000000000000cf01010000000000d2c5472bf8dab50103000000000000000300000000000000"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a3801000000000000004101000000000000cf01010000000000d2c5472bf8dab501030000000000000003000000000000000000000000000000"));
 
     test.setTestRepeatedInt(fixed64List());
     result = test.serialize(serializer.get());
@@ -1450,10 +1451,10 @@ TEST_F(SerializationTest, RepeatedFixedInt64MessageTest)
 TEST_F(SerializationTest, RepeatedSFixedInt64MessageTest)
 {
     RepeatedSFixedInt64Message test;
-    test.setTestRepeatedInt({1, 321, -65999, 123245324235425234, -3, 3});
+    test.setTestRepeatedInt({1, 321, -65999, 123245324235425234, -3, 3, 0});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a300100000000000000410100000000000031fefeffffffffffd2c5472bf8dab501fdffffffffffffff0300000000000000"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a380100000000000000410100000000000031fefeffffffffffd2c5472bf8dab501fdffffffffffffff03000000000000000000000000000000"));
 
     test.setTestRepeatedInt(sfixed64List());
     result = test.serialize(serializer.get());
@@ -1463,10 +1464,10 @@ TEST_F(SerializationTest, RepeatedSFixedInt64MessageTest)
 TEST_F(SerializationTest, RepeatedStringMessageTest)
 {
     RepeatedStringMessage test;
-    test.setTestRepeatedString({"aaaa","bbbbb","ccc","dddddd","eeeee"});
+    test.setTestRepeatedString({"aaaa","bbbbb","ccc","dddddd","eeeee", ""});
     QByteArray result = test.serialize(serializer.get());
     //qDebug() << "result " << result.toHex();
-    ASSERT_TRUE(result == QByteArray::fromHex("0a04616161610a0562626262620a036363630a066464646464640a056565656565"));
+    ASSERT_TRUE(result == QByteArray::fromHex("0a04616161610a0562626262620a036363630a066464646464640a0565656565650a00"));
 
     test.setTestRepeatedString(QStringList());
     result = test.serialize(serializer.get());
@@ -1701,6 +1702,25 @@ TEST_F(SerializationTest, FieldIndexRangeTest)
                  "f8ffffff0f02");
 }
 
+TEST_F(SerializationTest, SimpleEnumListMessageTest)
+{
+    SimpleEnumListMessage msg;
+
+    msg.setLocalEnumList({SimpleEnumListMessage::LOCAL_ENUM_VALUE0,
+                          SimpleEnumListMessage::LOCAL_ENUM_VALUE1,
+                          SimpleEnumListMessage::LOCAL_ENUM_VALUE2,
+                          SimpleEnumListMessage::LOCAL_ENUM_VALUE1,
+                          SimpleEnumListMessage::LOCAL_ENUM_VALUE2,
+                          SimpleEnumListMessage::LOCAL_ENUM_VALUE3});
+    QByteArray result = msg.serialize(serializer.get());
+    ASSERT_STREQ(result.toHex().toStdString().c_str(),
+                 "0a06000102010203");
+    msg.setLocalEnumList({});
+    result = msg.serialize(serializer.get());
+    ASSERT_STREQ(result.toHex().toStdString().c_str(),
+                 "");
+}
+
 TEST_F(SerializationTest, DISABLED_BenchmarkTest)
 {
     SimpleIntMessage msg;