buffer: Implement "initialize" and add unit tests

Add buffer headers and the initialization process

Tested: Unit Tested

Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: Iaf3c26ce01f7109000266cdbc7efa77988eae73b
diff --git a/test/buffer_test.cpp b/test/buffer_test.cpp
new file mode 100644
index 0000000..ee03163
--- /dev/null
+++ b/test/buffer_test.cpp
@@ -0,0 +1,114 @@
+#include "buffer.hpp"
+#include "data_interface_mock.hpp"
+
+#include <array>
+#include <cstdint>
+#include <memory>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bios_bmc_smm_error_logger
+{
+namespace
+{
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::InSequence;
+using ::testing::Return;
+
+class BufferTest : public ::testing::Test
+{
+  protected:
+    BufferTest() :
+        dataInterfaceMock(std::make_unique<DataInterfaceMock>()),
+        dataInterfaceMockPtr(dataInterfaceMock.get())
+    {
+        bufferImpl = std::make_unique<BufferImpl>(std::move(dataInterfaceMock));
+        testInitializationHeader.bmcInterfaceVersion = testBmcInterfaceVersion;
+        testInitializationHeader.queueSize = testQueueSize;
+        testInitializationHeader.ueRegionSize = testUeRegionSize;
+        testInitializationHeader.magicNumber = testMagicNumber;
+    }
+    ~BufferTest() override = default;
+
+    // CircularBufferHeader size is 0x30, ensure the test region is bigger
+    static constexpr size_t testRegionSize = 0x200;
+    static constexpr uint32_t testBmcInterfaceVersion = 123;
+    static constexpr uint16_t testQueueSize = 0x100;
+    static constexpr uint16_t testUeRegionSize = 0x50;
+    static constexpr std::array<uint32_t, 4> testMagicNumber = {
+        0x12345678, 0x22345678, 0x32345678, 0x42345678};
+    struct CircularBufferHeader testInitializationHeader
+    {};
+
+    std::unique_ptr<DataInterfaceMock> dataInterfaceMock;
+    DataInterfaceMock* dataInterfaceMockPtr;
+
+    std::unique_ptr<BufferImpl> bufferImpl;
+};
+
+TEST_F(BufferTest, BufferInitializeEraseFail)
+{
+    InSequence s;
+
+    EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
+        .WillOnce(Return(testRegionSize));
+    const std::vector<uint8_t> emptyArray(testRegionSize, 0);
+    // Return a smaller write than the intended testRegionSize to test the error
+    EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
+        .WillOnce(Return(testRegionSize - 1));
+    EXPECT_THROW(
+        try {
+            bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
+                                   testUeRegionSize, testMagicNumber);
+        } catch (const std::runtime_error& e) {
+            EXPECT_STREQ(e.what(), "Buffer initialization only erased '511'");
+            throw;
+        },
+        std::runtime_error);
+
+    EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
+        .WillOnce(Return(testRegionSize));
+    EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
+        .WillOnce(Return(testRegionSize));
+    // Return a smaller write than the intended initializationHeader to test the
+    // error
+    EXPECT_CALL(*dataInterfaceMockPtr, write(0, _)).WillOnce(Return(0));
+    EXPECT_THROW(
+        try {
+            bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize,
+                                   testUeRegionSize, testMagicNumber);
+        } catch (const std::runtime_error& e) {
+            EXPECT_STREQ(
+                e.what(),
+                "Buffer initialization buffer header write only wrote '0'");
+            throw;
+        },
+        std::runtime_error);
+}
+
+TEST_F(BufferTest, BufferInitializePass)
+{
+    InSequence s;
+    EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize())
+        .WillOnce(Return(testRegionSize));
+    const std::vector<uint8_t> emptyArray(testRegionSize, 0);
+    EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray)))
+        .WillOnce(Return(testRegionSize));
+
+    uint8_t* testInitializationHeaderPtr =
+        reinterpret_cast<uint8_t*>(&testInitializationHeader);
+    size_t initializationHeaderSize = sizeof(testInitializationHeader);
+    EXPECT_CALL(*dataInterfaceMockPtr,
+                write(0, ElementsAreArray(testInitializationHeaderPtr,
+                                          initializationHeaderSize)))
+        .WillOnce(Return(initializationHeaderSize));
+    EXPECT_NO_THROW(bufferImpl->initialize(testBmcInterfaceVersion,
+                                           testQueueSize, testUeRegionSize,
+                                           testMagicNumber));
+}
+
+} // namespace
+} // namespace bios_bmc_smm_error_logger
diff --git a/test/include/data_interface_mock.hpp b/test/include/data_interface_mock.hpp
new file mode 100644
index 0000000..942103e
--- /dev/null
+++ b/test/include/data_interface_mock.hpp
@@ -0,0 +1,24 @@
+#pragma once
+#include "data_interface.hpp"
+
+#include <cstdint>
+#include <span>
+#include <vector>
+
+#include <gmock/gmock.h>
+
+namespace bios_bmc_smm_error_logger
+{
+
+class DataInterfaceMock : public DataInterface
+{
+  public:
+    MOCK_METHOD(std::vector<uint8_t>, read,
+                (const uint32_t offset, const uint32_t length), (override));
+    MOCK_METHOD(uint32_t, write,
+                (const uint32_t offset, const std::span<const uint8_t> bytes),
+                (override));
+    MOCK_METHOD(uint32_t, getMemoryRegionSize, (), (override));
+};
+
+} // namespace bios_bmc_smm_error_logger
diff --git a/test/meson.build b/test/meson.build
index 081fcd7..6f72d9f 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -17,13 +17,19 @@
   endif
 endif
 
+test_dep = declare_dependency(
+  include_directories: include_directories('include'),
+  dependencies: [bios_bmc_smm_error_logger_dep, gtest, gmock, rde_dep]
+)
+
 gtests = [
   'pci_handler',
   'rde_dictionary_manager',
+  'buffer',
 ]
 foreach t : gtests
   test(t, executable(t.underscorify(), t + '_test.cpp',
                      build_by_default: false,
                      implicit_include_directories: false,
-                     dependencies: [bios_bmc_smm_error_logger_dep, gtest, gmock, rde_dep]))
+                     dependencies: test_dep))
 endforeach