PEL: Add Stream class to manipulate PEL data

This stream inserts data into and extracts data from the vector<uint8_t>
that it is given in its contructor.  That vector is how PEL data is
stored.  This object takes care of the endian conversion for fields that
require it, as PEL data is big endian.

On writes, it will expand the vector if necessary.

An exception will be thrown an invalid access is attempted, such as
trying to extract a value when at the end of the data.

It provides >> and << operators for common data types, as well as
read()/write() functions when using other types.

Example:

std::vector<uint8_t> data;
Stream stream{data};

uin32_t value = 0x12345678;
stream << value;

stream.offset(0);

uint32_t newValue;
stream >> newValue;

assert(value == newValue);

uint8_t buf[3000] = {0};
stream.write(buf, 3000);

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I8dc5566371749b45a260389a564836433323eef8
diff --git a/test/openpower-pels/stream_test.cpp b/test/openpower-pels/stream_test.cpp
new file mode 100644
index 0000000..dd5ca93
--- /dev/null
+++ b/test/openpower-pels/stream_test.cpp
@@ -0,0 +1,160 @@
+#include "extensions/openpower-pels/stream.hpp"
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+using namespace openpower::pels;
+
+TEST(StreamTest, TestExtract)
+{
+    std::vector<uint8_t> data{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                              0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+                              0x08, 'h',  'e',  'l',  'l',  'o'};
+    Stream stream{data};
+
+    {
+        uint8_t v;
+        stream >> v;
+        EXPECT_EQ(v, 0x11);
+    }
+    {
+        uint16_t v;
+        stream >> v;
+        EXPECT_EQ(v, 0x2233);
+    }
+    {
+        uint32_t v;
+        stream >> v;
+        EXPECT_EQ(v, 0x44556677);
+    }
+    {
+        uint64_t v;
+        stream >> v;
+        EXPECT_EQ(v, 0x0102030405060708);
+    }
+    {
+        char v[6] = {0};
+        stream.read(v, 5);
+        EXPECT_EQ(memcmp(v, "hello", 5), 0);
+    }
+
+    EXPECT_EQ(stream.remaining(), 0);
+
+    // At the end, so should throw.
+    uint8_t v;
+    EXPECT_THROW(stream >> v, std::out_of_range);
+}
+
+TEST(StreamTest, InputTestNoExpansion)
+{
+    std::vector<uint8_t> data(256, 0);
+    Stream stream(data);
+    uint8_t v1 = 0x11;
+    uint16_t v2 = 0x2233;
+    uint64_t v3 = 0x445566778899AABB;
+    uint32_t v4 = 0xCCDDEEFF;
+
+    stream << v3 << v2 << v4 << v1;
+
+    uint8_t e1;
+    uint16_t e2;
+    uint64_t e3;
+    uint32_t e4;
+
+    stream.offset(0);
+    stream >> e3 >> e2 >> e4 >> e1;
+
+    EXPECT_EQ(v1, e1);
+    EXPECT_EQ(v2, e2);
+    EXPECT_EQ(v3, e3);
+    EXPECT_EQ(v4, e4);
+}
+
+TEST(StreamTest, InputTestExpansion)
+{
+    // The stream will expand the underlying vector
+    std::vector<uint8_t> data;
+    Stream stream(data);
+
+    uint32_t v1 = 0xAABBCCDD;
+    stream << v1;
+
+    stream.offset(0);
+    uint32_t e1;
+    stream >> e1;
+    EXPECT_EQ(data.size(), 4);
+    EXPECT_EQ(v1, e1);
+
+    stream.offset(2);
+
+    uint64_t v2 = 0x0102030405060708;
+    stream << v2;
+
+    EXPECT_EQ(data.size(), 10);
+    uint64_t e2;
+    stream.offset(2);
+    stream >> e2;
+
+    EXPECT_EQ(v2, e2);
+
+    auto origSize = data.size();
+    uint8_t v3 = 0xCC;
+    stream << v3;
+
+    EXPECT_EQ(origSize + 1, data.size());
+    stream.offset(stream.offset() - 1);
+    uint8_t e3;
+    stream >> e3;
+    EXPECT_EQ(v3, e3);
+}
+
+TEST(StreamTest, ReadWriteTest)
+{
+    std::vector<uint8_t> data{0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
+                              0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc};
+    Stream stream{data};
+    uint8_t buf[data.size()];
+
+    stream.read(buf, data.size());
+
+    for (size_t i = 0; i < data.size(); i++)
+    {
+        EXPECT_EQ(buf[i], data[i]);
+
+        // for the next test
+        buf[i] = 0x20 + i;
+    }
+
+    stream.offset(6);
+    stream.write(buf, 6);
+    for (size_t i = 0; i < 6; i++)
+    {
+        EXPECT_EQ(buf[i], data[i + 6]);
+    }
+}
+
+TEST(StreamTest, TestOffsets)
+{
+    std::vector<uint8_t> data{0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77};
+    Stream stream{data, 3};
+
+    {
+        uint8_t v;
+        stream >> v;
+        EXPECT_EQ(v, 0x44);
+        EXPECT_EQ(stream.offset(), 4);
+    }
+
+    stream.offset(6);
+
+    {
+        uint8_t v;
+        stream >> v;
+        EXPECT_EQ(v, 0x77);
+        EXPECT_EQ(stream.offset(), 7);
+        EXPECT_EQ(stream.remaining(), 0);
+    }
+
+    EXPECT_THROW(stream.offset(100), std::out_of_range);
+}