Browse Source

Implement varint deserialization tests

- Move deserialization functions to ProtobufObjectPrivate
- Add zigzag varint tests
TODO: tests failing, seems issue in deserialization algorythm
Alexey Edelev 6 years ago
parent
commit
7defb3b64f
3 changed files with 126 additions and 72 deletions
  1. 0 1
      src/generator/generator.cpp
  2. 75 71
      src/lib/protobufobject.h
  3. 51 0
      tests/deserializationtest.cpp

+ 0 - 1
src/generator/generator.cpp

@@ -185,7 +185,6 @@ bool QtGenerator::Generate(const FileDescriptor *file,
         QtSourcesGenerator classSourceGen(file->package(), message,
                                   std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(sourceFileName))));
         classSourceGen.run();
-
     }
 
     std::string globalEnumsFilename = "globalenums.h";

+ 75 - 71
src/lib/protobufobject.h

@@ -273,10 +273,84 @@ protected:
         result.data()[result.size() - 1] &= ~0x80;
         return result;
     }
+
+//####################################################
+//               Deserialization
+//####################################################
+    void deserializeProperty(WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it)
+    {
+        QVariant newPropertyValue;
+        switch(metaProperty.userType()) {
+        case QMetaType::UInt:
+            if (wireType == Fixed32) {
+                newPropertyValue = deserializeFixed<FixedInt32>(it);
+            } else {
+                newPropertyValue = deserializeVarint<unsigned int>(it);
+            }
+            break;
+        case QMetaType::ULongLong:
+            if (wireType == Fixed64) {
+                newPropertyValue = deserializeFixed<FixedInt64>(it);
+            } else {
+                //TODO: deserialize varint
+            }
+            break;
+        case QMetaType::Float:
+            newPropertyValue = deserializeFixed<float>(it);
+            break;
+        case QMetaType::Double:
+            newPropertyValue = deserializeFixed<double>(it);
+            break;
+        case QMetaType::Int:
+            newPropertyValue = deserializeVarint<int>(it);
+            break;
+        default:
+            break;
+        }
+        setProperty(metaProperty.name(), newPropertyValue);
+    }
+
+    template <typename V,
+              typename std::enable_if_t<std::is_floating_point<V>::value
+                                        || std::is_same<V, unsigned int>::value
+                                        || std::is_same<V, qulonglong>::value, int> = 0>
+    QVariant deserializeFixed(QByteArray::const_iterator &it) {
+        QVariant newPropertyValue(QVariant::fromValue(*(V*)it));
+        it += sizeof(V);
+        return newPropertyValue;
+    }
+
+    template <typename V,
+              typename std::enable_if_t<std::is_unsigned<V>::value, int> = 0>
+    QVariant deserializeVarint(QByteArray::const_iterator &it) {
+        return QVariant::fromValue(deserializeVarintCommon<V>(it));
+    }
+
+    template <typename V,
+              typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
+    QVariant deserializeVarint(QByteArray::const_iterator &it) {
+        using UV = typename std::make_unsigned<V>::type;
+        UV unsignedValue = deserializeVarintCommon<UV>(it);
+        V value = (unsignedValue >> 1) ^ (-(unsignedValue & 1));
+
+        return QVariant::fromValue(value);
+    }
+
+    template <typename V>
+    V deserializeVarintCommon(QByteArray::const_iterator &it) {
+        V value = 0;
+        while((*it) & 0x80) {
+            value += (*it) & 0x7f;
+            ++it;
+        }
+        value += (*it) & 0x7f;
+        it++;
+        return value;
+    }
+
 public:
     virtual QByteArray serializePrivate() = 0;
     virtual void deserializePrivate(QByteArray::iterator &it) = 0;
-
 };
 
 template <typename T>
@@ -341,76 +415,6 @@ public:
             deserializeProperty(wireType, metaProperty, it);
         }
     }
-
-    void deserializeProperty(WireTypes wireType, const QMetaProperty &metaProperty, QByteArray::const_iterator &it)
-    {
-        QVariant newPropertyValue;
-        switch(metaProperty.userType()) {
-        case QMetaType::UInt:
-            if (wireType == Fixed32) {
-                newPropertyValue = deserializeFixed<FixedInt32>(it);
-            } else {
-                newPropertyValue = deserializeVarint<unsigned int>(it);
-            }
-            break;
-        case QMetaType::ULongLong:
-            if (wireType == Fixed64) {
-                newPropertyValue = deserializeFixed<FixedInt64>(it);
-            } else {
-                //TODO: deserialize varint
-            }
-            break;
-        case QMetaType::Float:
-            newPropertyValue = deserializeFixed<float>(it);
-            break;
-        case QMetaType::Double:
-            newPropertyValue = deserializeFixed<double>(it);
-            break;
-        case QMetaType::Int:
-            newPropertyValue = deserializeVarint<int>(it);
-            break;
-        default:
-            break;
-        }
-        setProperty(metaProperty.name(), newPropertyValue);
-    }
-
-    template <typename V,
-              typename std::enable_if_t<std::is_floating_point<V>::value
-                                        || std::is_same<V, unsigned int>::value
-                                        || std::is_same<V, qulonglong>::value, int> = 0>
-    QVariant deserializeFixed(QByteArray::const_iterator &it) {
-        QVariant newPropertyValue(QVariant::fromValue(*(V*)it));
-        it += sizeof(V);
-        return newPropertyValue;
-    }
-
-    template <typename V,
-              typename std::enable_if_t<std::is_unsigned<V>::value, int> = 0>
-    QVariant deserializeVarint(QByteArray::const_iterator &it) {
-        V value = 0;
-        while((*it) & 0x80) {
-            value += (*it) & 0x7f;
-            ++it;
-        }
-        value += (*it) & 0x7f;
-        it++;
-        return QVariant::fromValue(value);
-    }
-
-    template <typename V,
-              typename std::enable_if_t<std::is_signed<V>::value, int> = 0>
-    QVariant deserializeVarint(QByteArray::const_iterator &it) {
-        V value = 0;
-        while((*it) & 0x80) {
-            value += (*it) & 0x7f;
-            ++it;
-        }
-        value += (*it) & 0x7f;
-        it++;
-
-        return QVariant::fromValue(value);
-    }
 };
 
 }

+ 51 - 0
tests/deserializationtest.cpp

@@ -156,5 +156,56 @@ TEST_F(DeserializationTest, IntMessageDeserializeTest)
     SimpleIntMessage test;
     test.deserialize(QByteArray::fromHex("081e"));
     ASSERT_EQ(15, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08d804"));
+    ASSERT_EQ(300, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08928008"));
+    ASSERT_EQ(65545, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("0800"));
+    ASSERT_EQ(0, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("088002"));
+    ASSERT_EQ(INT8_MAX + 1, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08808004"));
+    ASSERT_EQ(INT16_MAX + 1, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08fe01"));
+    ASSERT_EQ(INT8_MAX, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08feff03"));
+    ASSERT_EQ(INT16_MAX, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08feffffff0f"));
+    ASSERT_EQ(INT32_MAX, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("0801"));
+    ASSERT_EQ(-1, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("0801"));
+    ASSERT_EQ(-1, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("089b07"));
+    ASSERT_EQ(-462, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08c1e107"));
+    ASSERT_EQ(-63585, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08ff01"));
+    ASSERT_EQ(INT8_MIN, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08ffff03"));
+    ASSERT_EQ(INT16_MIN, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08ffffffff0f"));
+    ASSERT_EQ(INT32_MIN, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("088102"));
+    ASSERT_EQ(INT8_MIN - 1, test.testFieldInt());
+
+    test.deserialize(QByteArray::fromHex("08818004"));
+    ASSERT_EQ(INT16_MIN - 1, test.testFieldInt());
 }