bios: Implement BIOSConfig

Load the parsed json configs into memory.
And provid APIs to get/set on bios tables.

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: Ida1fedc923d31afc61dd2d4aec70d81bb6a90ae9
diff --git a/test/libpldmresponder_bios_config_test.cpp b/test/libpldmresponder_bios_config_test.cpp
new file mode 100644
index 0000000..2a2b72f
--- /dev/null
+++ b/test/libpldmresponder_bios_config_test.cpp
@@ -0,0 +1,255 @@
+#include "bios_utils.hpp"
+#include "libpldmresponder/bios_config.hpp"
+#include "libpldmresponder/bios_string_attribute.hpp"
+#include "mocked_bios.hpp"
+#include "mocked_utils.hpp"
+
+#include <fstream>
+#include <memory>
+#include <nlohmann/json.hpp>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using namespace pldm::bios::utils;
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Throw;
+
+class TestBIOSConfig : public ::testing::Test
+{
+  public:
+    static void SetUpTestCase() // will execute once at the begining of all
+                                // TestBIOSConfig objects
+    {
+        char tmpdir[] = "/tmp/BIOSTables.XXXXXX";
+        tableDir = fs::path(mkdtemp(tmpdir));
+
+        std::vector<fs::path> paths = {
+            "./bios_jsons/string_attrs.json",
+        };
+
+        for (auto& path : paths)
+        {
+            std::ifstream file;
+            file.open(path);
+            auto j = Json::parse(file);
+            jsons.emplace_back(j);
+        }
+    }
+
+    std::optional<Json> findJsonEntry(const std::string& name)
+    {
+        for (auto& json : jsons)
+        {
+            auto entries = json.at("entries");
+            for (auto& entry : entries)
+            {
+                auto n = entry.at("attribute_name").get<std::string>();
+                if (n == name)
+                {
+                    return entry;
+                }
+            }
+        }
+        return std::nullopt;
+    }
+
+    static void TearDownTestCase() // will be executed once at th end of all
+                                   // TestBIOSConfig objects
+    {
+        fs::remove_all(tableDir);
+    }
+
+    static fs::path tableDir;
+    static std::vector<Json> jsons;
+};
+
+fs::path TestBIOSConfig::tableDir;
+std::vector<Json> TestBIOSConfig::jsons;
+
+TEST_F(TestBIOSConfig, buildTablesTest)
+{
+    MockdBusHandler dbusHandler;
+
+    ON_CALL(dbusHandler, getDbusPropertyVariant(_, _, _))
+        .WillByDefault(Throw(std::exception()));
+
+    BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler);
+    biosConfig.buildTables();
+
+    auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE);
+    auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+    auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+
+    EXPECT_TRUE(stringTable);
+    EXPECT_TRUE(attrTable);
+    EXPECT_TRUE(attrValueTable);
+
+    std::set<std::string> expectedStrings = {"HMCManagedState",
+                                             "On",
+                                             "Off",
+                                             "FWBootSide",
+                                             "Perm",
+                                             "Temp",
+                                             "InbandCodeUpdate",
+                                             "Allowed",
+                                             "NotAllowed",
+                                             "CodeUpdatePolicy",
+                                             "Concurrent",
+                                             "Disruptive",
+                                             "VDD_AVSBUS_RAIL",
+                                             "SBE_IMAGE_MINIMUM_VALID_ECS",
+                                             "INTEGER_INVALID_CASE",
+                                             "str_example1",
+                                             "str_example2",
+                                             "str_example3"};
+    std::set<std::string> strings;
+    for (auto entry : BIOSTableIter<PLDM_BIOS_STRING_TABLE>(
+             stringTable->data(), stringTable->size()))
+    {
+        auto str = table::string::decodeString(entry);
+        strings.emplace(str);
+    }
+
+    EXPECT_EQ(strings, expectedStrings);
+
+    BIOSStringTable biosStringTable(*stringTable);
+
+    for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(),
+                                                          attrTable->size()))
+    {
+        auto header = table::attribute::decodeHeader(entry);
+        auto attrName = biosStringTable.findString(header.stringHandle);
+        auto jsonEntry = findJsonEntry(attrName);
+        EXPECT_TRUE(jsonEntry);
+        switch (header.attrType)
+        {
+            case PLDM_BIOS_STRING:
+            case PLDM_BIOS_STRING_READ_ONLY:
+            {
+                auto stringField = table::attribute::decodeStringEntry(entry);
+                auto stringType = BIOSStringAttribute::strTypeMap.at(
+                    jsonEntry->at("string_type").get<std::string>());
+                EXPECT_EQ(stringField.stringType,
+                          static_cast<uint8_t>(stringType));
+
+                EXPECT_EQ(
+                    stringField.minLength,
+                    jsonEntry->at("minimum_string_length").get<uint16_t>());
+                EXPECT_EQ(
+                    stringField.maxLength,
+                    jsonEntry->at("maximum_string_length").get<uint16_t>());
+                EXPECT_EQ(
+                    stringField.defLength,
+                    jsonEntry->at("default_string_length").get<uint16_t>());
+                EXPECT_EQ(stringField.defString,
+                          jsonEntry->at("default_string").get<std::string>());
+                break;
+            }
+            default:
+                EXPECT_TRUE(false);
+                break;
+        }
+    }
+
+    for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
+             attrValueTable->data(), attrValueTable->size()))
+    {
+        auto header = table::attribute_value::decodeHeader(entry);
+        auto attrEntry =
+            table::attribute::findByHandle(*attrTable, header.attrHandle);
+        auto attrHeader = table::attribute::decodeHeader(attrEntry);
+        auto attrName = biosStringTable.findString(attrHeader.stringHandle);
+        auto jsonEntry = findJsonEntry(attrName);
+        EXPECT_TRUE(jsonEntry);
+        switch (header.attrType)
+        {
+            case PLDM_BIOS_STRING:
+            case PLDM_BIOS_STRING_READ_ONLY:
+            {
+                auto value = table::attribute_value::decodeStringEntry(entry);
+                auto defValue =
+                    jsonEntry->at("default_string").get<std::string>();
+                EXPECT_EQ(value, defValue);
+                break;
+            }
+            default:
+                EXPECT_TRUE(false);
+                break;
+        }
+    }
+}
+
+TEST_F(TestBIOSConfig, setAttrValue)
+{
+    MockdBusHandler dbusHandler;
+
+    BIOSConfig biosConfig("./bios_jsons", tableDir.c_str(), &dbusHandler);
+    biosConfig.removeTables();
+    biosConfig.buildTables();
+
+    auto stringTable = biosConfig.getBIOSTable(PLDM_BIOS_STRING_TABLE);
+    auto attrTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_TABLE);
+
+    BIOSStringTable biosStringTable(*stringTable);
+    BIOSTableIter<PLDM_BIOS_ATTR_TABLE> attrTableIter(attrTable->data(),
+                                                      attrTable->size());
+    auto stringHandle = biosStringTable.findHandle("str_example1");
+    uint16_t attrHandle{};
+
+    for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_TABLE>(attrTable->data(),
+                                                          attrTable->size()))
+    {
+        auto header = table::attribute::decodeHeader(entry);
+        if (header.stringHandle == stringHandle)
+        {
+            attrHandle = header.attrHandle;
+            break;
+        }
+    }
+
+    EXPECT_NE(attrHandle, 0);
+
+    std::vector<uint8_t> attrValueEntry{
+        0,   0,             /* attr handle */
+        1,                  /* attr type string read-write */
+        4,   0,             /* current string length */
+        'a', 'b', 'c', 'd', /* defaut value string handle index */
+    };
+
+    attrValueEntry[0] = attrHandle & 0xff;
+    attrValueEntry[1] = (attrHandle >> 8) & 0xff;
+
+    DBusMapping dbusMapping{"/xyz/abc/def",
+                            "xyz.openbmc_project.str_example1.value",
+                            "Str_example1", "string"};
+    PropertyValue value = std::string("abcd");
+    EXPECT_CALL(dbusHandler, setDbusProperty(dbusMapping, value)).Times(1);
+
+    auto rc =
+        biosConfig.setAttrValue(attrValueEntry.data(), attrValueEntry.size());
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    auto attrValueTable = biosConfig.getBIOSTable(PLDM_BIOS_ATTR_VAL_TABLE);
+    auto findEntry =
+        [&attrValueTable](
+            uint16_t handle) -> const pldm_bios_attr_val_table_entry* {
+        for (auto entry : BIOSTableIter<PLDM_BIOS_ATTR_VAL_TABLE>(
+                 attrValueTable->data(), attrValueTable->size()))
+        {
+            auto [attrHandle, _] = table::attribute_value::decodeHeader(entry);
+            if (attrHandle == handle)
+                return entry;
+        }
+        return nullptr;
+    };
+
+    auto entry = findEntry(attrHandle);
+    EXPECT_NE(entry, nullptr);
+
+    auto p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + attrValueEntry.size()),
+                ElementsAreArray(attrValueEntry));
+}
diff --git a/test/meson.build b/test/meson.build
index 827f9fc..5c03866 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -21,6 +21,7 @@
   'libpldmresponder_bios_test',
   'libpldmresponder_bios_attribute_test',
   'libpldmresponder_bios_string_attribute_test',
+  'libpldmresponder_bios_config_test',
   'libpldmresponder_pdr_state_effecter_test',
   'libpldmresponder_bios_table_test',
   'libpldmresponder_platform_test',