Browse Source

Merge branch 'feature/PROTO-12-design-backend-for-repeated-fie' into feature/PROTO-15-run-sonar

Bart Hertog 6 years ago
parent
commit
bfa7dc20c6

+ 4 - 1
.gitignore

@@ -31,4 +31,7 @@ CMakeFiles/**
 build/
 
 # Ignore sonar scanner binaries
-sonar-scanner**
+sonar-scanner**
+
+# Ignore code coverage reports
+code_coverage_report/**

+ 1 - 1
CMakeLists.txt

@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
 
 project(test_EmbeddedProto)
 
-set(CMAKE_CXX_FLAGS "-std=c++14 -Wall")
+set(CMAKE_CXX_FLAGS "-std=c++14 -Wall -fprofile-arcs -ftest-coverage")
 
 
 add_subdirectory(external/googletest)

+ 10 - 0
code_coverage.sh

@@ -0,0 +1,10 @@
+#! /bin/sh
+
+rm -rf ./code_coverage_report/*
+
+./build/test/test_EmbeddedProto
+
+lcov --directory ./build/test --capture --output-file ./code_coverage_report/total_code_coverage.info -rc lcov_branch_coverage=1
+lcov --remove ./code_coverage_report/total_code_coverage.info $PWD'/external/googletest/*' '/usr/include/*' -o ./code_coverage_report/filtered_code_coverage.info
+
+genhtml ./code_coverage_report/filtered_code_coverage.info --branch-coverage --output-directory ./code_coverage_report

+ 14 - 21
generator/Header_Template.h

@@ -36,7 +36,15 @@ class {{ msg.name }} final: public ::EmbeddedProto::MessageInterface
     {% endfor %}
     {% for field in msg.fields() %}
     static const uint32_t {{field.variable_id_name}} = {{field.variable_id}};
-    {% if field.of_type_message %}
+    {% if field.is_repeated_field %}
+    inline const {{field.type}}& {{field.name}}(uint32_t index) const { return {{field.variable_name}}[index]; }
+    inline void clear_{{field.name}}() { {{field.variable_name}}.clear(); }
+    inline void set_{{field.name}}(uint32_t index, const {{field.type}}& value) { {{field.variable_name}}.set(index, value); }
+    inline void set_{{field.name}}(uint32_t index, const {{field.type}}&& value) { {{field.variable_name}}.set(index, value); }
+    inline void add_{{field.name}}(const {{field.type}}& value) { {{field.variable_name}}.add(value); }
+    inline const {{field.repeated_type}}& get_{{field.name}}() const { return {{field.variable_name}}; }
+    inline {{field.repeated_type}}& mutable_{{field.name}}() { return {{field.variable_name}}; }
+    {% elif field.of_type_message %}
     inline const {{field.type}}& {{field.name}}() const { return {{field.variable_name}}; }
     inline void clear_{{field.name}}() { {{field.variable_name}}.clear(); }
     inline void set_{{field.name}}(const {{field.type}}& value) { {{field.variable_name}} = value; }
@@ -49,14 +57,6 @@ class {{ msg.name }} final: public ::EmbeddedProto::MessageInterface
     inline void set_{{field.name}}(const {{field.type}}& value) { {{field.variable_name}} = value; }
     inline void set_{{field.name}}(const {{field.type}}&& value) { {{field.variable_name}} = value; }
     inline {{field.type}} get_{{field.name}}() const { return {{field.variable_name}}; }
-    {% elif field.is_repeated_field %}
-    inline const {{field.type}}& {{field.name}}(uint32_t index) const { return {{field.variable_name}}[index]; }
-    inline void clear_{{field.name}}() { {{field.variable_name}}.clear(); }
-    inline void set_{{field.name}}(uint32_t index, const {{field.type}}& value) { {{field.variable_name}}.set(index, value); }
-    inline void set_{{field.name}}(uint32_t index, const {{field.type}}&& value) { {{field.variable_name}}.set(index, value); }
-    inline void add_{{field.name}}(const {{field.type}}& value) { {{field.variable_name}}.add(value); }
-    inline const {{field.repeated_type}}& get_{{field.name}}() const { return {{field.variable_name}}; }
-    inline {{field.repeated_type}}& mutable_{{field.name}}() { return {{field.variable_name}}; }
     {% else %}
     inline {{field.type}}::FIELD_TYPE {{field.name}}() const { return {{field.variable_name}}.get(); }
     inline void clear_{{field.name}}() { {{field.variable_name}}.set({{field.default_value}}); }
@@ -116,10 +116,7 @@ class {{ msg.name }} final: public ::EmbeddedProto::MessageInterface
             {% if field.is_repeated_field %}
             if(::EmbeddedProto::WireFormatter::WireType::LENGTH_DELIMITED == wire_type)
             {
-              uint32_t size;
-              result = ::EmbeddedProto::WireFormatter::DeserializeVarint(buffer, size);
-              ::EmbeddedProto::ReadBufferSection bufferSection(buffer, size);
-              result = result && {{field.variable_name}}.deserialize(bufferSection);
+              result = {{field.variable_name}}.deserialize(buffer);
             }
             {% else %}
             if(::EmbeddedProto::WireFormatter::WireType::{{field.wire_type}} == wire_type)
@@ -164,13 +161,6 @@ class {{ msg.name }} final: public ::EmbeddedProto::MessageInterface
       {% endfor %}
     }
 
-    uint32_t serialized_size() const final
-    {
-      ::EmbeddedProto::MessageSizeCalculator calcBuffer;
-      this->serialize(calcBuffer);
-      return calcBuffer.get_size();
-    }
-
   private:
 
     {% for field in msg.fields() %}
@@ -183,7 +173,8 @@ class {{ msg.name }} final: public ::EmbeddedProto::MessageInterface
 };
 {% endmacro %}
 // This file is generated. Please do not edit!
-#pragma once
+#ifndef _{{filename.upper()}}_H_
+#define _{{filename.upper()}}_H_
 
 #include <cstdint>
 {% if messages %}
@@ -208,3 +199,5 @@ namespace {{ namespace }}
 {% if namespace %}
 } // End of namespace {{ namespace }}
 {% endif %}
+#endif // _{{filename.upper()}}_H_
+

+ 5 - 2
generator/protoc-gen-eams.py

@@ -150,8 +150,11 @@ def generate_code(request, respones):
         messages_generator = generate_messages(proto_file.message_type)
         enums_generator = generate_enums(proto_file.enum_type)
 
+        filename_str = os.path.splitext(proto_file.name)[0]
+
         try:
-            file_str = template.render(namespace=proto_file.package, messages=messages_generator, enums=enums_generator)
+            file_str = template.render(filename=filename_str, namespace=proto_file.package, messages=messages_generator,
+                                       enums=enums_generator)
         except jinja2.TemplateError as e:
             print("TemplateError exception: " + str(e))
         except jinja2.UndefinedError as e:
@@ -166,7 +169,7 @@ def generate_code(request, respones):
             print("Template renderer exception: " + str(e))
         else:
             f = respones.file.add()
-            f.name = os.path.splitext(proto_file.name)[0] + ".h"
+            f.name = filename_str + ".h"
             f.content = file_str
 
 

+ 8 - 3
src/Fields.cpp

@@ -1,10 +1,15 @@
 
-#include <Fields.h>
-
+#include "Fields.h"
+#include "MessageSizeCalculator.h"
 
 namespace EmbeddedProto 
 {
-
+  uint32_t Field::serialized_size() const
+  {
+    ::EmbeddedProto::MessageSizeCalculator calcBuffer;
+    this->serialize(calcBuffer);
+    return calcBuffer.get_size();
+  }
 
   bool int32::serialize(uint32_t field_number, WriteBufferInterface& buffer) const
   { 

+ 10 - 4
src/Fields.h

@@ -1,14 +1,13 @@
 #ifndef _FIELDS_H_
 #define _FIELDS_H_
 
-#include <WireFormatter.h>
-#include <WriteBufferInterface.h>
-#include <ReadBufferInterface.h>
+#include "WireFormatter.h"
+#include "WriteBufferInterface.h"
+#include "ReadBufferInterface.h"
 
 namespace EmbeddedProto 
 {
 
-
   class Field 
   {
     public:
@@ -16,9 +15,16 @@ namespace EmbeddedProto
       virtual ~Field() = default;
 
       virtual bool serialize(uint32_t field_number, WriteBufferInterface& buffer) const = 0;
+
       virtual bool serialize(WriteBufferInterface& buffer) const = 0;
 
       virtual bool deserialize(ReadBufferInterface& buffer) = 0;
+
+      //! Calculate the size of this message when serialized.
+      /*!
+          \return The number of bytes this message will require once serialized.
+      */
+      uint32_t serialized_size() const;
   };
 
   template<class TYPE>

+ 6 - 4
src/MessageInterface.cpp

@@ -1,19 +1,21 @@
 #include "MessageInterface.h"
-#include <WireFormatter.h>
+#include "WireFormatter.h"
 
 namespace EmbeddedProto
 {
 
-  bool MessageInterface::serialize(uint32_t field_number, ::EmbeddedProto::WriteBufferInterface& buffer) const
+  bool MessageInterface::MessageInterface::serialize(uint32_t field_number, ::EmbeddedProto::WriteBufferInterface& buffer) const
   {
     const uint32_t size_x = this->serialized_size();
     bool result = (size_x < buffer.get_available_size());
     if(result && (0 < size_x))
     {
-      uint32_t tag = ::EmbeddedProto::WireFormatter::MakeTag(field_number, ::EmbeddedProto::WireFormatter::WireType::LENGTH_DELIMITED);
+      uint32_t tag = ::EmbeddedProto::WireFormatter::MakeTag(field_number, 
+                              ::EmbeddedProto::WireFormatter::WireType::LENGTH_DELIMITED);
       result = ::EmbeddedProto::WireFormatter::SerializeVarint(tag, buffer);
       result = result && ::EmbeddedProto::WireFormatter::SerializeVarint(size_x, buffer);
-      result = result && this->serialize(buffer);
+      const ::EmbeddedProto::Field* base = static_cast<const ::EmbeddedProto::Field*>(this);
+      result = result && base->serialize(buffer);
     }
     return result;
   }

+ 6 - 40
src/MessageInterface.h

@@ -4,45 +4,23 @@
 #define _MESSAGE_INTERFACE_H_
 
 #include <cstdint>
-#include <WireFormatter.h>
+
+#include "WireFormatter.h"
+#include "Fields.h"
 
 namespace EmbeddedProto 
 {
 
-class MessageInterface 
+class MessageInterface : public ::EmbeddedProto::Field
 {
   public:
-    enum class Result 
-    {
-        OK,
-        ERROR_BUFFER_TO_SMALL,
-    };
 
     MessageInterface() = default;
 
     virtual ~MessageInterface() = default;
 
-    bool serialize(uint32_t field_number, ::EmbeddedProto::WriteBufferInterface& buffer) const;
-
-    //! Function to serialize this message.
-    /*!
-        The data this message holds will be serialized into an byte array.
-
-        \param buffer [in]  The memory in which the serialized message is stored.
-
-        \return True when every was successfull. 
-    */
-    virtual bool serialize(::EmbeddedProto::WriteBufferInterface& buffer) const = 0;
-
-    //! Function to deserialize this message.
-    /*!
-        From an array of data fill this message object with data.
-
-        \param buffer [in]  The memory from which the message is obtained.
-
-        \return True when every was successfull. 
-    */
-    virtual bool deserialize(::EmbeddedProto::ReadBufferInterface& buffer) = 0;
+    // TODO doc
+    bool serialize(uint32_t field_number, ::EmbeddedProto::WriteBufferInterface& buffer) const final;
 
     //! Clear the content of this message and set it to it's default state.
     /*!
@@ -50,18 +28,6 @@ class MessageInterface
     */
     virtual void clear() = 0;
 
-    //! Calculate the size of this message when serialized.
-    /*!
-        \return The number of bytes this message will require once serialized.
-    */
-    virtual uint32_t serialized_size() const = 0;
-
-  protected:
-
-
-  private:
-
-
 };
 
 } // End of namespace EmbeddedProto

+ 2 - 2
src/MessageSizeCalculator.h

@@ -2,10 +2,10 @@
 #ifndef _MESSAGE_SIZE_CALCULATOR_H_
 #define _MESSAGE_SIZE_CALCULATOR_H_
 
-#include "WriteBufferInterface.h"
-
 #include <limits> 
 
+#include "WriteBufferInterface.h"
+
 namespace EmbeddedProto 
 {
   //! This class is used in a message to calculate the current serialized size.

+ 1 - 1
src/ReadBufferSection.cpp

@@ -1,5 +1,5 @@
 
-#include <ReadBufferSection.h>
+#include "ReadBufferSection.h"
 
 namespace EmbeddedProto 
 {

+ 4 - 4
src/ReadBufferSection.h

@@ -1,10 +1,10 @@
 
-#ifndef _MESSAGE_BUFFER_SECTIOn_H_
-#define _MESSAGE_BUFFER_SECTION_H_
+#ifndef _READ_BUFFER_SECTION_H_
+#define _READ_BUFFER_SECTION_H_
 
 #include <cstdint>
 
-#include <ReadBufferInterface.h>
+#include "ReadBufferInterface.h"
 
 namespace EmbeddedProto 
 {
@@ -80,4 +80,4 @@ namespace EmbeddedProto
 
 } // End of namespace EmbeddedProto
 
-#endif 
+#endif // _READ_BUFFER_SECTION_H_

+ 101 - 32
src/RepeatedField.h

@@ -4,17 +4,25 @@
 
 #include <cstring>
 #include <algorithm>    // std::min
+#include <type_traits>
 
-#include <Fields.h>
-#include <MessageSizeCalculator.h>
+#include "Fields.h"
+#include "MessageInterface.h"
+#include "MessageSizeCalculator.h"
+#include "ReadBufferSection.h" 
 
 namespace EmbeddedProto
 {
 
   //! Class template that specifies the interface of an arry with the data type.
   template<class DATA_TYPE>
-  class RepeatedField
+  class RepeatedField : public Field
   {
+    static_assert(std::is_base_of<::EmbeddedProto::Field, DATA_TYPE>::value, "A Field can only be used as template paramter.");
+
+    //! Check how this field shoeld be serialized, packed or not.
+    static constexpr bool PACKED = !std::is_base_of<MessageInterface, DATA_TYPE>::value;
+
     public:
 
       RepeatedField() = default;
@@ -88,34 +96,37 @@ namespace EmbeddedProto
       //! Remove all data in the array and set it to the default value.
       virtual void clear() = 0;
 
-
-      bool serialize(uint32_t field_number, WriteBufferInterface& buffer) const
+      bool serialize(WriteBufferInterface& buffer) const final
       {
-        const uint32_t size_x = this->serialized_size();
-        bool result = (size_x < buffer.get_available_size());
-        if(result && (0 < size_x))
-        {
-          uint32_t tag = ::EmbeddedProto::WireFormatter::MakeTag(field_number, ::EmbeddedProto::WireFormatter::WireType::LENGTH_DELIMITED);
-          result = ::EmbeddedProto::WireFormatter::SerializeVarint(tag, buffer);
-          result = result && ::EmbeddedProto::WireFormatter::SerializeVarint(size_x, buffer);
-          result = result && this->serialize(buffer);
-        }
-        return result;
+        return false;
       }
 
-      //! Function to serialize this array.
-      /*!
-          The data this array holds will be serialized into the buffer.
-          \param buffer [in]  The memory in which the serialized array is stored.
-          \return True when every was successfull. 
-      */
-      bool serialize(::EmbeddedProto::WriteBufferInterface& buffer) const
+      bool serialize(uint32_t field_number, WriteBufferInterface& buffer) const final
       {
         bool result = true;
-        for(uint32_t i = 0; (i < this->get_length()) && result; ++i)
+
+        if(PACKED)
         {
-          result = this->get(i).serialize(buffer);
+          const uint32_t size_x = this->serialized_size_packed(field_number);
+          result = (size_x <= buffer.get_available_size());
+
+          // Use the packed way of serialization for base fields.
+          if(result && (0 < size_x))
+          {          
+            uint32_t tag = ::EmbeddedProto::WireFormatter::MakeTag(field_number, 
+                                        ::EmbeddedProto::WireFormatter::WireType::LENGTH_DELIMITED);
+            result = ::EmbeddedProto::WireFormatter::SerializeVarint(tag, buffer);
+            result = result && ::EmbeddedProto::WireFormatter::SerializeVarint(size_x, buffer);
+            result = result && serialize_packed(buffer);
+          }
+        }
+        else 
+        {
+          const uint32_t size_x = this->serialized_size_unpacked(field_number);
+          result = (size_x <= buffer.get_available_size());
+          result = result && serialize_unpacked(field_number, buffer);
         }
+
         return result;
       }
 
@@ -125,14 +136,30 @@ namespace EmbeddedProto
           \param buffer [in]  The memory from which the message is obtained.
           \return True when every was successfull. 
       */
-      bool deserialize(::EmbeddedProto::ReadBufferInterface& buffer)
+      bool deserialize(::EmbeddedProto::ReadBufferInterface& buffer) final
       {
-        this->clear();
-        DATA_TYPE x;
         bool result = true;
-        while(result && x.deserialize(buffer)) 
+        if(PACKED)
+        {              
+          uint32_t size;
+          result = ::EmbeddedProto::WireFormatter::DeserializeVarint(buffer, size);
+          ::EmbeddedProto::ReadBufferSection bufferSection(buffer, size);
+          DATA_TYPE x;
+          while(result && x.deserialize(bufferSection)) 
+          {
+            result = this->add(x);
+          }
+        }
+        else 
         {
-          result = this->add(x);
+          uint32_t size;
+          result = ::EmbeddedProto::WireFormatter::DeserializeVarint(buffer, size);
+          ::EmbeddedProto::ReadBufferSection bufferSection(buffer, size);
+          DATA_TYPE x;
+          if(result && x.deserialize(bufferSection))
+          {
+            result = this->add(x);
+          }
         }
         return result;
       }
@@ -141,13 +168,54 @@ namespace EmbeddedProto
       /*!
           \return The number of bytes this message will require once serialized.
       */
-      uint32_t serialized_size() const 
+      uint32_t serialized_size_packed(int32_t field_number) const 
       {
         ::EmbeddedProto::MessageSizeCalculator calcBuffer;
-        this->serialize(calcBuffer);
+        serialize_packed(calcBuffer);
         return calcBuffer.get_size();
       }
 
+      //! Calculate the size of this message when serialized.
+      /*!
+          \return The number of bytes this message will require once serialized.
+      */
+      uint32_t serialized_size_unpacked(int32_t field_number) const 
+      {
+        ::EmbeddedProto::MessageSizeCalculator calcBuffer;
+        serialize_unpacked(field_number, calcBuffer);
+        return calcBuffer.get_size();
+      }
+
+    private:
+
+      bool serialize_packed(WriteBufferInterface& buffer) const
+      {
+        bool result = true;
+        for(uint32_t i = 0; (i < this->get_length()) && result; ++i)
+        {
+          result = this->get(i).serialize(buffer);
+        }
+        return result;
+      }
+
+      bool serialize_unpacked(uint32_t field_number, WriteBufferInterface& buffer) const
+      {
+        bool result = true;
+        for(uint32_t i = 0; (i < this->get_length()) && result; ++i)
+        {
+          const uint32_t size_x = this->get(i).serialized_size();
+          uint32_t tag = ::EmbeddedProto::WireFormatter::MakeTag(field_number, 
+                                    ::EmbeddedProto::WireFormatter::WireType::LENGTH_DELIMITED);
+          result = ::EmbeddedProto::WireFormatter::SerializeVarint(tag, buffer);
+          result = result && ::EmbeddedProto::WireFormatter::SerializeVarint(size_x, buffer);
+          if(result && (0 < size_x)) 
+          {
+            result = this->get(i).serialize(buffer);
+          }
+        }
+        return result;
+      }
+
   };
 
   //! A template class that actually holds some data.
@@ -227,6 +295,7 @@ namespace EmbeddedProto
       DATA_TYPE data_[MAX_SIZE];
   };
 
+/*
   template<class DATA_TYPE>
   bool serialize(uint32_t field_number, const RepeatedField<DATA_TYPE>& x, WriteBufferInterface& buffer)
   {
@@ -260,7 +329,7 @@ namespace EmbeddedProto
   {
       return x.deserialize(buffer);
   }
-
+*/
 } // End of namespace EmbeddedProto
 
 #endif // End of _DYNAMIC_BUFFER_H_

+ 10 - 32
test/test_RepeatedField.cpp

@@ -1,5 +1,6 @@
 #include <gtest/gtest.h>
 
+#include <Fields.h>
 #include <RepeatedField.h>
 
 namespace test_EmbeddedAMS_RepeatedField
@@ -8,51 +9,30 @@ namespace test_EmbeddedAMS_RepeatedField
 TEST(RepeatedField, construction) 
 {
   static constexpr uint32_t SIZE = 3;
-  EmbeddedProto::RepeatedFieldSize<uint8_t, SIZE> x;
-}
-
-TEST(RepeatedField, size_uint8_t) 
-{
-  static constexpr uint32_t SIZE = 3;
-  EmbeddedProto::RepeatedFieldSize<uint8_t, SIZE> x;
-
-  EXPECT_EQ(0, x.get_size());
-  EXPECT_EQ(SIZE, x.get_max_size());
-  EXPECT_EQ(0, x.get_length());
-  EXPECT_EQ(SIZE, x.get_max_length());
-
-  x.add(1);
-  x.add(2);
-  EXPECT_EQ(2, x.get_size());
-  EXPECT_EQ(2, x.get_length());
-
-  x.add(3);
-
-  EXPECT_EQ(SIZE, x.get_size());
-  EXPECT_EQ(SIZE, x.get_max_size());
-  EXPECT_EQ(SIZE, x.get_length());
-  EXPECT_EQ(SIZE, x.get_max_length());
+  EmbeddedProto::RepeatedFieldSize<::EmbeddedProto::uint32, SIZE> x;
 }
 
 TEST(RepeatedField, size_uint32_t) 
 {  
   static constexpr uint32_t SIZE = 3;
-  EmbeddedProto::RepeatedFieldSize<uint32_t, SIZE> x;
+  EmbeddedProto::RepeatedFieldSize<::EmbeddedProto::uint32, SIZE> x;
+
+  static constexpr int32_t UINT32_SIZE = sizeof(::EmbeddedProto::uint32);
 
   EXPECT_EQ(0, x.get_size());
-  EXPECT_EQ(SIZE*4, x.get_max_size());
+  EXPECT_EQ(SIZE*UINT32_SIZE, x.get_max_size());
   EXPECT_EQ(0, x.get_length());
   EXPECT_EQ(SIZE, x.get_max_length());
 
   x.add(1);
   x.add(2);
-  EXPECT_EQ(2*4, x.get_size());
+  EXPECT_EQ(2*UINT32_SIZE, x.get_size());
   EXPECT_EQ(2, x.get_length());
 
   x.add(3);
 
-  EXPECT_EQ(SIZE*4, x.get_size());
-  EXPECT_EQ(SIZE*4, x.get_max_size());
+  EXPECT_EQ(SIZE*UINT32_SIZE, x.get_size());
+  EXPECT_EQ(SIZE*UINT32_SIZE, x.get_max_size());
   EXPECT_EQ(SIZE, x.get_length());
   EXPECT_EQ(SIZE, x.get_max_length());
 }
@@ -60,7 +40,7 @@ TEST(RepeatedField, size_uint32_t)
 TEST(RepeatedField, set) 
 {
   static constexpr uint32_t SIZE = 3;
-  EmbeddedProto::RepeatedFieldSize<uint8_t, SIZE> x;
+  EmbeddedProto::RepeatedFieldSize<::EmbeddedProto::uint32, SIZE> x;
 
   // First add a value in the middle and see if we have a size of two.
   x.set(1, 2);
@@ -72,8 +52,6 @@ TEST(RepeatedField, set)
 
   x.set(2, 3);
   EXPECT_EQ(3, x.get(2));
-
-
 }
 
 } // End namespace test_EmbeddedAMS_RepeatedField

+ 184 - 4
test/test_RepeatedFieldMessage.cpp

@@ -27,21 +27,35 @@ TEST(RepeatedFieldMessage, construction)
   repeated_message<Y_SIZE> msg2;
 }
 
-TEST(RepeatedFieldMessage, serialize_empty) 
+TEST(RepeatedFieldMessage, serialize_empty_fields) 
 {
   repeated_fields<Y_SIZE> msg;
 
   Mocks::WriteBufferMock buffer;
   EXPECT_CALL(buffer, push(_)).Times(0);
   EXPECT_CALL(buffer, push(_,_)).Times(0);
-  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(99));
+  EXPECT_CALL(buffer, get_available_size()).WillRepeatedly(Return(99));
 
   EXPECT_TRUE(msg.serialize(buffer));
 
   EXPECT_EQ(0, msg.serialized_size());
 }
 
-TEST(RepeatedFieldMessage, serialize_array_zero)
+TEST(RepeatedFieldMessage, serialize_empty_message) 
+{
+  repeated_message<Y_SIZE> msg;
+
+  Mocks::WriteBufferMock buffer;
+  EXPECT_CALL(buffer, push(_)).Times(0);
+  EXPECT_CALL(buffer, push(_,_)).Times(0);
+  EXPECT_CALL(buffer, get_available_size()).WillRepeatedly(Return(99));
+
+  EXPECT_TRUE(msg.serialize(buffer));
+
+  EXPECT_EQ(0, msg.serialized_size());
+}
+
+TEST(RepeatedFieldMessage, serialize_array_zero_fields)
 { 
   InSequence s;
   
@@ -54,6 +68,57 @@ TEST(RepeatedFieldMessage, serialize_array_zero)
 
   uint8_t expected[] = {0x12, 0x03, 0x00, 0x00, 0x00}; // y
 
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(6));
+
+  for(auto e : expected) 
+  {
+    EXPECT_CALL(buffer, push(e)).Times(1).WillOnce(Return(true));
+  }
+
+  EXPECT_TRUE(msg.serialize(buffer));
+}
+
+TEST(RepeatedFieldMessage, serialize_array_zero_messages)
+{ 
+  InSequence s;
+  
+  Mocks::WriteBufferMock buffer;
+  repeated_message<Y_SIZE> msg;
+
+  repeated_nested_message rnm;
+  rnm.set_u(0);
+  rnm.set_v(0);
+
+  msg.add_y(rnm);
+  msg.add_y(rnm);
+  msg.add_y(rnm);
+
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(6));
+
+  EXPECT_CALL(buffer, push(0x12)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x00)).Times(1).WillOnce(Return(true));
+
+  EXPECT_CALL(buffer, push(0x12)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x00)).Times(1).WillOnce(Return(true));
+
+  EXPECT_CALL(buffer, push(0x12)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x00)).Times(1).WillOnce(Return(true));
+
+  EXPECT_TRUE(msg.serialize(buffer));
+}
+
+TEST(RepeatedFieldMessage, serialize_array_zero_one_zero)
+{
+  InSequence s;
+  Mocks::WriteBufferMock buffer;
+
+  repeated_fields<Y_SIZE> msg;
+  msg.add_y(0);
+  msg.add_y(1);
+  msg.add_y(0);
+
+  uint8_t expected[] = {0x12, 0x03, 0x00, 0x01, 0x00}; // y
+
   EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(5));
 
   for(auto e : expected) 
@@ -64,6 +129,45 @@ TEST(RepeatedFieldMessage, serialize_array_zero)
   EXPECT_TRUE(msg.serialize(buffer));
 }
 
+TEST(RepeatedFieldMessage, serialize_array_zero_one_zero_messages)
+{ 
+  InSequence s;
+  
+  Mocks::WriteBufferMock buffer;
+  repeated_message<Y_SIZE> msg;
+
+  repeated_nested_message rnm;
+  
+  rnm.set_u(0);
+  rnm.set_v(0);
+  msg.add_y(rnm);
+
+  rnm.set_u(1);
+  rnm.set_v(1);
+  msg.add_y(rnm);
+  
+  rnm.set_u(0);
+  rnm.set_v(0);
+  msg.add_y(rnm);
+
+  EXPECT_CALL(buffer, get_available_size()).Times(1).WillOnce(Return(10));
+
+  EXPECT_CALL(buffer, push(0x12)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x00)).Times(1).WillOnce(Return(true));
+
+  EXPECT_CALL(buffer, push(0x12)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x04)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x08)).Times(1).WillOnce(Return(true)); 
+  EXPECT_CALL(buffer, push(0x01)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x10)).Times(1).WillOnce(Return(true)); 
+  EXPECT_CALL(buffer, push(0x01)).Times(1).WillOnce(Return(true));
+
+  EXPECT_CALL(buffer, push(0x12)).Times(1).WillOnce(Return(true));
+  EXPECT_CALL(buffer, push(0x00)).Times(1).WillOnce(Return(true));
+
+  EXPECT_TRUE(msg.serialize(buffer));
+}
+
 TEST(RepeatedFieldMessage, serialize_array_one)
 {
   InSequence s;
@@ -175,7 +279,7 @@ TEST(RepeatedFieldMessage, serialize_max)
   EXPECT_TRUE(msg.serialize(buffer));
 }
 
-TEST(RepeatedFieldMessage, deserialize_empty) 
+TEST(RepeatedFieldMessage, deserialize_empty_array) 
 {
   repeated_fields<Y_SIZE> msg;
 
@@ -187,6 +291,17 @@ TEST(RepeatedFieldMessage, deserialize_empty)
 
 }
 
+TEST(RepeatedFieldMessage, deserialize_empty_message_array) 
+{
+  repeated_message<Y_SIZE> msg;
+
+  Mocks::ReadBufferMock buffer;
+  EXPECT_CALL(buffer, pop(_)).WillRepeatedly(Return(false));
+  EXPECT_CALL(buffer, get_size()).WillRepeatedly(Return(0));
+
+  EXPECT_TRUE(msg.deserialize(buffer));
+}
+
 TEST(RepeatedFieldMessage, deserialize_one) 
 {
   InSequence s;
@@ -215,6 +330,71 @@ TEST(RepeatedFieldMessage, deserialize_one)
 
 }
 
+TEST(RepeatedFieldMessage, deserialize_one_message_array) 
+{
+  InSequence s;
+
+  repeated_message<Y_SIZE> msg;
+  Mocks::ReadBufferMock buffer;
+
+  uint8_t referee[] = {0x08, 0x01, // x
+                       0x12, 0x00, 0x12, 0x04, 0x08, 0x01, 0x10, 0x01, 0x12, 0x00, // y
+                       0x18, 0x01}; // z 
+
+  for(auto r: referee) 
+  {
+    EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(r), Return(true)));
+  }
+  EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(Return(false));
+
+  EXPECT_TRUE(msg.deserialize(buffer));
+
+  EXPECT_EQ(1, msg.get_x());
+  EXPECT_EQ(3, msg.get_y().get_length());
+  EXPECT_EQ(0, msg.y(0).u());
+  EXPECT_EQ(0, msg.y(0).v());
+  EXPECT_EQ(1, msg.y(1).u());
+  EXPECT_EQ(1, msg.y(1).v());
+  EXPECT_EQ(0, msg.y(2).u());
+  EXPECT_EQ(0, msg.y(2).v());
+  EXPECT_EQ(1, msg.get_z());
+}
+
+TEST(RepeatedFieldMessage, deserialize_mixed_message_array) 
+{
+  // I should be possible to read in the non packed data mixed with other fields. All elements 
+  // should be added to the array.
+
+  InSequence s;
+
+  repeated_message<Y_SIZE> msg;
+  Mocks::ReadBufferMock buffer;
+
+  uint8_t referee[] = {0x12, 0x00, // y[0]
+                       0x08, 0x01, // x
+                       0x12, 0x04, 0x08, 0x01, 0x10, 0x01, // y[1]
+                       0x18, 0x01, // z
+                       0x12, 0x00, }; // y[2] 
+
+  for(auto r: referee) 
+  {
+    EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(DoAll(SetArgReferee<0>(r), Return(true)));
+  }
+  EXPECT_CALL(buffer, pop(_)).Times(1).WillOnce(Return(false));
+
+  EXPECT_TRUE(msg.deserialize(buffer));
+
+  EXPECT_EQ(1, msg.get_x());
+  EXPECT_EQ(3, msg.get_y().get_length());
+  EXPECT_EQ(0, msg.y(0).u());
+  EXPECT_EQ(0, msg.y(0).v());
+  EXPECT_EQ(1, msg.y(1).u());
+  EXPECT_EQ(1, msg.y(1).v());
+  EXPECT_EQ(0, msg.y(2).u());
+  EXPECT_EQ(0, msg.y(2).v());
+  EXPECT_EQ(1, msg.get_z());
+}
+
 TEST(RepeatedFieldMessage, deserialize_max) 
 {
   InSequence s;

+ 11 - 10
test_data.py

@@ -72,9 +72,9 @@ def test_nested_message():
 
     msg.u = 0 #pow(2, 1023)
     msg.v = 0 #pow(2, 1023)
-    msg.nested_a.x = pow(2, 31) - 1
-    msg.nested_a.y = 0 #1.0
-    msg.nested_a.z = 0 #1
+    #msg.nested_a.x = 0#pow(2, 31) - 1
+    #msg.nested_a.y = 0 #1.0
+    #msg.nested_a.z = 0 #1
 
     str = ""
     msg_str = msg.SerializeToString()
@@ -100,7 +100,7 @@ def test_repeated_fields():
 
     #msg.x = 0
     msg.y.append(0)
-    msg.y.append(0)
+    msg.y.append(1)
     msg.y.append(0)
     #msg.z = 0
 
@@ -133,19 +133,18 @@ def test_repeated_fields():
 
 
 def test_repeated_message():
-    nmsg = rf.nested_message()
-    nmsg.u = 1
-    nmsg.v = 1
-
     msg = rf.repeated_message()
 
     msg.x = 0
     for i in range(3):
         nmsg = msg.y.add()
-        nmsg.u = 1
-        nmsg.v = 1
+        nmsg.u = 0
+        nmsg.v = 0
     msg.z = 0
 
+    msg.y[1].u = 1
+    msg.y[1].v = 1
+
     str = ""
     msg_str = msg.SerializeToString()
     print(len(msg_str))
@@ -156,4 +155,6 @@ def test_repeated_message():
     print(str)
     print()
 
+#test_repeated_fields()
 test_repeated_message()
+#test_nested_message()