OSDN Git Service

test_vendor: Add PacketBuilder classes
authorMyles Watson <mylesgw@google.com>
Wed, 14 Nov 2018 00:56:38 +0000 (16:56 -0800)
committerMyles Watson <mylesgw@google.com>
Mon, 10 Dec 2018 23:47:53 +0000 (23:47 +0000)
Templated PacketBuilder class for inserting fixed width
types with the correct endianness.

Test: rootcanal-packets_test_host --gtest_filter=*PacketBuilderEndian*
Change-Id: I7f8b5cfd225ebae35f310b44fc0782b940a23007

vendor_libs/test_vendor_lib/packets/base_packet_builder.h [new file with mode: 0644]
vendor_libs/test_vendor_lib/packets/packet_builder.h [new file with mode: 0644]
vendor_libs/test_vendor_lib/test/packet_builder_test.cc [new file with mode: 0644]

diff --git a/vendor_libs/test_vendor_lib/packets/base_packet_builder.h b/vendor_libs/test_vendor_lib/packets/base_packet_builder.h
new file mode 100644 (file)
index 0000000..8e51af5
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+namespace test_vendor_lib {
+namespace packets {
+
+// A little-endian PacketBuilder might contain a big-endian PacketBuilder,
+// so BasePacketBuilder provides a common base class.
+class BasePacketBuilder {
+ public:
+  virtual ~BasePacketBuilder() = default;
+
+  virtual size_t size() const = 0;
+
+  // Write to the vector with the given iterator.
+  virtual void Serialize(
+      std::back_insert_iterator<std::vector<uint8_t>> it) const = 0;
+
+ protected:
+  BasePacketBuilder() = default;
+};
+
+}  // namespace packets
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/packet_builder.h b/vendor_libs/test_vendor_lib/packets/packet_builder.h
new file mode 100644 (file)
index 0000000..8cf94ea
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "base_packet_builder.h"
+#include "types/raw_address.h"
+
+namespace test_vendor_lib {
+namespace packets {
+
+// Abstract base class that is subclassed to build specifc packets.
+// The template parameter little_endian controls the generation of insert().
+template <bool little_endian>
+class PacketBuilder : public BasePacketBuilder {
+ public:
+  PacketBuilder() = default;
+  virtual ~PacketBuilder() = default;
+
+  // Classes which need fragmentation should define a function like this:
+  // std::forward_list<DerivedBuilder>& Fragment(size_t max_size);
+
+ protected:
+  // Write sizeof(FixedWidthIntegerType) bytes using the iterator
+  template <typename FixedWidthIntegerType>
+  void insert(FixedWidthIntegerType value,
+              std::back_insert_iterator<std::vector<uint8_t>> it) const {
+    static_assert(std::is_integral<FixedWidthIntegerType>::value,
+                  "PacketBuilder::insert requires an integral type.");
+    for (size_t i = 0; i < sizeof(FixedWidthIntegerType); i++) {
+      if (little_endian == true) {
+        *it = static_cast<uint8_t>(value >> (i * 8));
+      } else {
+        *it = static_cast<uint8_t>(
+            value >> ((sizeof(FixedWidthIntegerType) - i - 1) * 8));
+      }
+      it++;
+    }
+  }
+
+  // Write a vector of FixedWidthIntegerType using the iterator
+  template <typename FixedWidthIntegerType>
+  void insert_vector(const std::vector<FixedWidthIntegerType>& vec,
+                     std::back_insert_iterator<std::vector<uint8_t>> it) const {
+    static_assert(std::is_integral<FixedWidthIntegerType>::value,
+                  "PacketBuilder::insert requires an integral type vector.");
+    for (const auto& element : vec) {
+      insert(element, it);
+    }
+  }
+
+  void insert_address(
+      const RawAddress& addr,
+      std::back_insert_iterator<std::vector<uint8_t>> it) const {
+    for (const auto& element : addr.address) {
+      insert(element, it);
+    }
+  }
+};
+
+}  // namespace packets
+}  // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/packet_builder_test.cc b/vendor_libs/test_vendor_lib/test/packet_builder_test.cc
new file mode 100644 (file)
index 0000000..8563a7a
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "packets/packet_builder.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+using std::vector;
+
+namespace {
+vector<uint8_t> count_all = {
+    0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
+    0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
+    0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+
+vector<uint8_t> count_1 = {
+    0x00,
+    0x01,
+    0x02,
+};
+
+vector<uint8_t> count_2 = {
+    0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+};
+
+vector<uint8_t> count_3 = {
+    0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+    0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+};
+}  // namespace
+
+namespace test_vendor_lib {
+namespace packets {
+
+template <bool little_endian>
+class EndianBuilder : public PacketBuilder<little_endian> {
+ public:
+  EndianBuilder(uint8_t byte, uint16_t two_bytes, uint32_t four_bytes,
+                uint64_t eight_bytes)
+      : byte_(byte),
+        two_bytes_(two_bytes),
+        four_bytes_(four_bytes),
+        eight_bytes_(eight_bytes) {}
+  ~EndianBuilder() = default;
+
+  virtual size_t size() const override {
+    return sizeof(signature_) + sizeof(byte_) + sizeof(two_bytes_) +
+           sizeof(four_bytes_) + sizeof(eight_bytes_);
+  }
+
+  virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+    std::unique_ptr<std::vector<uint8_t>> packet =
+        std::make_unique<std::vector<uint8_t>>();
+    packet->reserve(size());
+    std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+    Serialize(it);
+    return packet;
+  }
+
+  virtual void Serialize(
+      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+    PacketBuilder<little_endian>::insert(signature_, it);
+    PacketBuilder<little_endian>::insert(byte_, it);
+    PacketBuilder<little_endian>::insert(two_bytes_, it);
+    PacketBuilder<little_endian>::insert(four_bytes_, it);
+    PacketBuilder<little_endian>::insert(eight_bytes_, it);
+  }
+
+ private:
+  uint32_t signature_{(little_endian ? 0x03020100 : 0x00010203)};
+  uint8_t byte_;
+  uint16_t two_bytes_;
+  uint32_t four_bytes_;
+  uint64_t eight_bytes_;
+};
+
+class PacketBuilderEndianTest : public ::testing::Test {
+ public:
+  PacketBuilderEndianTest() = default;
+  ~PacketBuilderEndianTest() = default;
+};
+
+TEST(PacketBuilderEndianTest, insertTest) {
+  EndianBuilder<true> little(0x04, 0x0605, 0x0a090807, 0x1211100f0e0d0c0b);
+  EndianBuilder<false> big(0x04, 0x0506, 0x0708090a, 0x0b0c0d0e0f101112);
+  ASSERT_EQ(*big.FinalPacket(), *little.FinalPacket());
+}
+
+template <typename T>
+class VectorBuilder : public PacketBuilder<true> {
+ public:
+  VectorBuilder(std::vector<uint64_t> vect) {
+    for (uint64_t element : vect) {
+      vect.push_back(static_cast<T>(element));
+    }
+  }
+  ~VectorBuilder() = default;
+
+  virtual size_t size() const override { return vect_.size() * sizeof(T); }
+
+  virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+    std::unique_ptr<std::vector<uint8_t>> packet =
+        std::make_unique<std::vector<uint8_t>>();
+    packet->reserve(size());
+    std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+    Serialize(it);
+    return packet;
+  }
+
+  virtual void Serialize(
+      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+    PacketBuilder<true>::insert_vector(vect_, it);
+  }
+
+ private:
+  std::vector<T> vect_;
+};
+
+template <typename T>
+class InsertElementsBuilder : public PacketBuilder<true> {
+ public:
+  InsertElementsBuilder(std::vector<uint64_t> vect) {
+    for (uint64_t element : vect) {
+      vect.push_back(static_cast<T>(element));
+    }
+  }
+  virtual ~InsertElementsBuilder() = default;
+
+  virtual size_t size() const override { return vect_.size() * sizeof(T); }
+
+  virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+    std::unique_ptr<std::vector<uint8_t>> packet =
+        std::make_unique<std::vector<uint8_t>>();
+    packet->reserve(size());
+    std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+    Serialize(it);
+    return packet;
+  }
+
+  virtual void Serialize(
+      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+    for (T elem : vect_) {
+      PacketBuilder<true>::insert(elem, it);
+    }
+  }
+
+ private:
+  std::vector<T> vect_;
+};
+
+std::vector<uint64_t> vector_data{
+    0x7060504030201000, 0x7161514131211101, 0x7262524232221202,
+    0x7363534333231303, 0x7464544434241404, 0x7565554535251505,
+    0x7666564636261606, 0x7767574737271707, 0x7868584838281808,
+};
+
+template <typename T>
+class VectorBuilderTest : public ::testing::Test {
+ public:
+  VectorBuilderTest() = default;
+  ~VectorBuilderTest() = default;
+
+  void SetUp() {
+    packet_1_ =
+        std::shared_ptr<VectorBuilder<T>>(new VectorBuilder<T>(vector_data));
+    packet_2_ = std::shared_ptr<InsertElementsBuilder<T>>(
+        new InsertElementsBuilder<T>(vector_data));
+  }
+
+  void TearDown() {
+    packet_1_.reset();
+    packet_2_.reset();
+  }
+
+  std::shared_ptr<VectorBuilder<T>> packet_1_;
+  std::shared_ptr<InsertElementsBuilder<T>> packet_2_;
+};
+
+using VectorBaseTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t,
+                                         int8_t, int16_t, int32_t, int64_t>;
+TYPED_TEST_CASE(VectorBuilderTest, VectorBaseTypes);
+
+TYPED_TEST(VectorBuilderTest, insertVectorTest) {
+  ASSERT_EQ(*(this->packet_1_->FinalPacket()),
+            *(this->packet_2_->FinalPacket()));
+}
+
+class NestedBuilder : public PacketBuilder<true> {
+ public:
+  ~NestedBuilder() = default;
+
+  virtual size_t size() const override {
+    size_t payload_size = (payload_ ? payload_->size() : 0);
+    return 1 + payload_size;
+  }
+
+  static std::unique_ptr<NestedBuilder> Create(uint8_t level) {
+    return std::unique_ptr<NestedBuilder>(new NestedBuilder(level));
+  }
+
+  static std::unique_ptr<NestedBuilder> CreateNested(
+      std::unique_ptr<BasePacketBuilder> payload, uint8_t level) {
+    return std::unique_ptr<NestedBuilder>(
+        new NestedBuilder(std::move(payload), level));
+  }
+
+  virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
+    std::unique_ptr<std::vector<uint8_t>> packet =
+        std::make_unique<std::vector<uint8_t>>();
+    packet->reserve(size());
+    std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
+    Serialize(it);
+    return packet;
+  }
+
+  virtual void Serialize(
+      std::back_insert_iterator<std::vector<uint8_t>> it) const override {
+    PacketBuilder<true>::insert(level_, it);
+    if (payload_) {
+      payload_->Serialize(it);
+    }
+  }
+
+ private:
+  std::unique_ptr<BasePacketBuilder> payload_;
+  uint8_t level_;
+
+  NestedBuilder(std::unique_ptr<BasePacketBuilder> inner, uint8_t level)
+      : payload_(std::move(inner)), level_(level) {}
+  NestedBuilder(uint8_t level) : level_(level) {}
+};
+
+class BuilderBuilderTest : public ::testing::Test {};
+
+TEST(BuilderBuilderTest, nestingTest) {
+  std::unique_ptr<BasePacketBuilder> innermost = NestedBuilder::Create(0);
+  std::unique_ptr<BasePacketBuilder> number_1 =
+      NestedBuilder::CreateNested(std::move(innermost), 1);
+  std::unique_ptr<BasePacketBuilder> number_2 =
+      NestedBuilder::CreateNested(std::move(number_1), 2);
+  std::unique_ptr<BasePacketBuilder> number_3 =
+      NestedBuilder::CreateNested(std::move(number_2), 3);
+  std::unique_ptr<BasePacketBuilder> number_4 =
+      NestedBuilder::CreateNested(std::move(number_3), 4);
+  std::unique_ptr<NestedBuilder> number_5 =
+      NestedBuilder::CreateNested(std::move(number_4), 5);
+
+  std::vector<uint8_t> count_down{5, 4, 3, 2, 1, 0};
+  ASSERT_EQ(*number_5->FinalPacket(), count_down);
+}
+}  // namespace packets
+}  // namespace test_vendor_lib