bios: Implement an iterator for bios attribute table

Traversing bios attribute table should be platform-independent, so
implement a c-version bios attribute table iterator in libpldm, also
implement a c++ auxiliary function to traverse a bios table.

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: I2afcaac306603410e711aa4772ba35b5e0b131d5
diff --git a/libpldm/bios_table.c b/libpldm/bios_table.c
new file mode 100644
index 0000000..26d30bf
--- /dev/null
+++ b/libpldm/bios_table.c
@@ -0,0 +1,199 @@
+#include <assert.h>
+#include <endian.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bios.h"
+#include "bios_table.h"
+
+#define POINTER_CHECK(pointer)                                                 \
+	do {                                                                   \
+		if (pointer == NULL)                                           \
+			return PLDM_ERROR_INVALID_DATA;                        \
+	} while (0)
+
+#define ATTR_TYPE_EXPECT(type, expected)                                       \
+	do {                                                                   \
+		if (type != expected && type != (expected | 0x80))             \
+			return PLDM_ERROR_INVALID_DATA;                        \
+	} while (0)
+
+uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	return entry->metadata[0];
+}
+
+int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
+    const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(pv_num);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
+	*pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+	return PLDM_SUCCESS;
+}
+
+uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+	return entry->metadata[sizeof(uint8_t) /* pv_num */ +
+			       sizeof(uint16_t) * pv_num];
+}
+
+int pldm_bios_table_attr_entry_enum_decode_def_num_check(
+    const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(def_num);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_ENUMERATION);
+	*def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+	return PLDM_SUCCESS;
+}
+
+/** @brief Get length of an enum attribute entry
+ */
+static size_t
+attr_table_entry_length_enum(const struct pldm_bios_attr_table_entry *entry)
+{
+	uint8_t pv_num = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+	uint8_t def_num = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+	return sizeof(*entry) - 1 + sizeof(pv_num) + pv_num * sizeof(uint16_t) +
+	       sizeof(def_num) + def_num;
+}
+
+#define ATTR_ENTRY_STRING_LENGTH_MIN                                           \
+	sizeof(uint8_t) /* string type */ +                                    \
+	    sizeof(uint16_t) /* minimum string length */ +                     \
+	    sizeof(uint16_t) /* maximum string length */ +                     \
+	    sizeof(uint16_t) /* default string length */
+
+uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
+    const struct pldm_bios_attr_table_entry *entry)
+{
+	int def_string_pos = ATTR_ENTRY_STRING_LENGTH_MIN - sizeof(uint16_t);
+	uint16_t def_string_length =
+	    *(uint16_t *)(entry->metadata + def_string_pos);
+	return le16toh(def_string_length);
+}
+
+int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+    const struct pldm_bios_attr_table_entry *entry, uint16_t *def_string_length)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(def_string_length);
+	ATTR_TYPE_EXPECT(entry->attr_type, PLDM_BIOS_STRING);
+	*def_string_length =
+	    pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
+	return PLDM_SUCCESS;
+}
+
+/** @brief Get length of a string attribute entry
+ */
+static size_t
+attr_table_entry_length_string(const struct pldm_bios_attr_table_entry *entry)
+{
+	uint16_t def_string_len =
+	    pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
+	return sizeof(*entry) - 1 + ATTR_ENTRY_STRING_LENGTH_MIN +
+	       def_string_len;
+}
+
+struct attr_table_entry {
+	uint8_t attr_type;
+	size_t (*entry_length_handler)(
+	    const struct pldm_bios_attr_table_entry *);
+};
+
+static struct attr_table_entry attr_table_entrys[] = {
+    {.attr_type = PLDM_BIOS_ENUMERATION,
+     .entry_length_handler = attr_table_entry_length_enum},
+    {.attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY,
+     .entry_length_handler = attr_table_entry_length_enum},
+    {.attr_type = PLDM_BIOS_STRING,
+     .entry_length_handler = attr_table_entry_length_string},
+    {.attr_type = PLDM_BIOS_STRING_READ_ONLY,
+     .entry_length_handler = attr_table_entry_length_string},
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static struct attr_table_entry *find_attr_table_entry_by_type(uint8_t attr_type)
+{
+	size_t i;
+	for (i = 0; i < ARRAY_SIZE(attr_table_entrys); i++) {
+		if (attr_type == attr_table_entrys[i].attr_type)
+			return &attr_table_entrys[i];
+	}
+	return NULL;
+}
+
+static size_t attr_table_entry_length(const void *table_entry)
+{
+	const struct pldm_bios_attr_table_entry *entry = table_entry;
+	struct attr_table_entry *attr_table_entry =
+	    find_attr_table_entry_by_type(entry->attr_type);
+	assert(attr_table_entry != NULL);
+	assert(attr_table_entry->entry_length_handler != NULL);
+
+	return attr_table_entry->entry_length_handler(entry);
+}
+
+struct pldm_bios_table_iter {
+	const uint8_t *table_data;
+	size_t table_len;
+	size_t current_pos;
+	size_t (*entry_length_handler)(const void *table_entry);
+};
+
+struct pldm_bios_table_iter *
+pldm_bios_table_iter_create(const void *table, size_t length,
+			    enum pldm_bios_table_types type)
+{
+	struct pldm_bios_table_iter *iter = malloc(sizeof(*iter));
+	assert(iter != NULL);
+	iter->table_data = table;
+	iter->table_len = length;
+	iter->current_pos = 0;
+	iter->entry_length_handler = NULL;
+	switch (type) {
+	case PLDM_BIOS_STRING_TABLE:
+		break;
+	case PLDM_BIOS_ATTR_TABLE:
+		iter->entry_length_handler = attr_table_entry_length;
+		break;
+	case PLDM_BIOS_ATTR_VAL_TABLE:
+		break;
+	}
+
+	return iter;
+}
+
+void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter)
+{
+	free(iter);
+}
+
+#define pad_and_check_max 7
+bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter)
+{
+	if (iter->table_len - iter->current_pos <= pad_and_check_max)
+		return true;
+	return false;
+}
+
+void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter)
+{
+	if (pldm_bios_table_iter_is_end(iter))
+		return;
+	const void *entry = iter->table_data + iter->current_pos;
+	iter->current_pos += iter->entry_length_handler(entry);
+}
+
+const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter)
+{
+	return iter->table_data + iter->current_pos;
+}
\ No newline at end of file
diff --git a/libpldm/bios_table.h b/libpldm/bios_table.h
new file mode 100644
index 0000000..3d17f3c
--- /dev/null
+++ b/libpldm/bios_table.h
@@ -0,0 +1,115 @@
+#ifndef BIOS_TABLE_H__
+#define BIOS_TABLE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "bios.h"
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+/** @struct pldm_bios_table_iter
+ *  structure representing bios table iterator
+ */
+struct pldm_bios_table_iter;
+
+/** @brief Create a bios table iterator
+ *  @param[in] table - Pointer to table data
+ *  @param[in] length - Length of table data
+ *  @param[in] type - Type of pldm bios table
+ *  @return Iterator to the beginning
+ */
+struct pldm_bios_table_iter *
+pldm_bios_table_iter_create(const void *table, size_t length,
+			    enum pldm_bios_table_types type);
+
+/** @brief Release a bios table iterator
+ *  @param[in] iter - Pointer to bios table iterator
+ */
+void pldm_bios_table_iter_free(struct pldm_bios_table_iter *iter);
+
+/** @brief Check if the iterator reaches the end of the bios table
+ *  @param[in] iter - Pointer to the bios table iterator
+ *  @return true if iterator reaches the end
+ *  @note *end* is a position after the last entry.
+ */
+bool pldm_bios_table_iter_is_end(const struct pldm_bios_table_iter *iter);
+
+/** @brief Get iterator to next entry
+ *  @param[in] iter - Pointer the bios table iterator
+ */
+void pldm_bios_table_iter_next(struct pldm_bios_table_iter *iter);
+
+/** @brief Get the bios table entry that the iterator points to
+ *  @param[in] iter - Pointer to the bios table iterator
+ *  @return Pointer to an entry in bios table
+ */
+const void *pldm_bios_table_iter_value(struct pldm_bios_table_iter *iter);
+
+/** @brief Get the bios attribute table entry that the iterator points to
+ *  @param[in] iter - Pointer the bios attribute table iterator
+ *  @return Pointer to an entry in bios attribute table
+ */
+static inline const struct pldm_bios_attr_table_entry *
+pldm_bios_table_iter_attr_entry_value(struct pldm_bios_table_iter *iter)
+{
+	return (const struct pldm_bios_attr_table_entry *)
+	    pldm_bios_table_iter_value(iter);
+}
+
+/** @brief Get the total number of possible values for the entry
+ *  @param[in] entry - Pointer to bios attribute table entry
+ *  @return total number of possible values
+ */
+uint8_t pldm_bios_table_attr_entry_enum_decode_pv_num(
+    const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get the total number of possible values for the entry and check the
+ * validity of the parameters
+ *  @param[in] entry - Pointer to bios attribute table entry
+ *  @param[out] pv_num - Pointer to total number of possible values
+ *  @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_enum_decode_pv_num_check(
+    const struct pldm_bios_attr_table_entry *entry, uint8_t *pv_num);
+
+/** @brief Get the total number of default values for the entry
+ *  @param[in] entry - Pointer to bios attribute table entry
+ *  @return total number of default values
+ */
+uint8_t pldm_bios_table_attr_entry_enum_decode_def_num(
+    const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get the total number of default values for the entry and check the
+ * validity of the parameters
+ *  @param[in] entry - Pointer to bios attribute table entry
+ *  @param[out] def_num - Pointer to total number of default values
+ *  @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_enum_decode_def_num_check(
+    const struct pldm_bios_attr_table_entry *entry, uint8_t *def_num);
+
+/** @brief Get the length of default string in bytes for the entry
+ *  @param[in] entry - Pointer to bios attribute table entry
+ *  @return length of default string in bytes
+ */
+uint16_t pldm_bios_table_attr_entry_string_decode_def_string_length(
+    const struct pldm_bios_attr_table_entry *entry);
+
+/** @brief Get the length of default string in bytes for the entry and check the
+ * validity of the parameters
+ *  @param[in] entry - Pointer to bios attribute table entry
+ *  @param[out] def_string_length Pointer to length of default string in bytes
+ *  @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+    const struct pldm_bios_attr_table_entry *entry,
+    uint16_t *def_string_length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libpldm/meson.build b/libpldm/meson.build
index 5473c82..4cd9ba3 100644
--- a/libpldm/meson.build
+++ b/libpldm/meson.build
@@ -3,6 +3,7 @@
   'pldm_types.h',
   'platform.h',
   'bios.h',
+  'bios_table.h',
   'states.h',
   'fru.h',
   'utils.h'
@@ -12,6 +13,7 @@
   'base.c',
   'platform.c',
   'bios.c',
+  'bios_table.c',
   'fru.c',
   'utils.c'
 ]
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index a1288b4..a133b2d 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -9,6 +9,7 @@
 #include <chrono>
 #include <ctime>
 #include <iostream>
+#include <memory>
 #include <numeric>
 #include <phosphor-logging/elog-errors.hpp>
 #include <phosphor-logging/log.hpp>
@@ -764,6 +765,30 @@
 
 } // end namespace bios_type_string
 
+void traverseBIOSAttrTable(const Table& biosAttrTable,
+                           AttrTableEntryHandler handler)
+{
+    std::unique_ptr<pldm_bios_table_iter, decltype(&pldm_bios_table_iter_free)>
+        iter(pldm_bios_table_iter_create(biosAttrTable.data(),
+                                         biosAttrTable.size(),
+                                         PLDM_BIOS_ATTR_TABLE),
+             pldm_bios_table_iter_free);
+    while (!pldm_bios_table_iter_is_end(iter.get()))
+    {
+        auto table_entry = pldm_bios_table_iter_attr_entry_value(iter.get());
+        try
+        {
+            handler(table_entry);
+        }
+        catch (const std::exception& e)
+        {
+            log<level::ERR>("handler fails when traversing BIOSAttrTable",
+                            entry("ERROR=%s", e.what()));
+        }
+        pldm_bios_table_iter_next(iter.get());
+    }
+}
+
 using typeHandler =
     std::function<void(const BIOSTable& BIOSStringTable,
                        const char* biosJsonDir, Table& attributeTable)>;
diff --git a/libpldmresponder/bios.hpp b/libpldmresponder/bios.hpp
index 9bb7d23..412e07a 100644
--- a/libpldmresponder/bios.hpp
+++ b/libpldmresponder/bios.hpp
@@ -7,10 +7,12 @@
 
 #include <stdint.h>
 
+#include <functional>
 #include <map>
 #include <vector>
 
 #include "libpldm/bios.h"
+#include "libpldm/bios_table.h"
 
 namespace pldm
 {
@@ -23,6 +25,12 @@
 namespace responder
 {
 
+using AttrTableEntryHandler =
+    std::function<void(const struct pldm_bios_attr_table_entry*)>;
+
+void traverseBIOSAttrTable(const bios::Table& BIOSAttrTable,
+                           AttrTableEntryHandler handler);
+
 namespace bios
 {
 /** @brief Register handlers for command from the platform spec
diff --git a/test/libpldm_bios_table_test.cpp b/test/libpldm_bios_table_test.cpp
new file mode 100644
index 0000000..ea94bfe
--- /dev/null
+++ b/test/libpldm_bios_table_test.cpp
@@ -0,0 +1,175 @@
+#include <string.h>
+
+#include <cstring>
+#include <vector>
+
+#include "libpldm/base.h"
+#include "libpldm/bios.h"
+#include "libpldm/bios_table.h"
+
+#include <gtest/gtest.h>
+
+using Table = std::vector<uint8_t>;
+
+void buildTable(Table& table)
+{
+    auto padSize = ((table.size() % 4) ? (4 - table.size() % 4) : 0);
+    table.insert(table.end(), padSize, 0);
+    table.insert(table.end(), sizeof(uint32_t) /*checksum*/, 0);
+}
+
+template <typename First, typename... Rest>
+void buildTable(Table& table, First& first, Rest&... rest)
+{
+    table.insert(table.end(), first.begin(), first.end());
+    buildTable(table, rest...);
+}
+
+TEST(AttrTable, EnumEntryDecodeTest)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        1, 0, /* attr name handle */
+        2,    /* number of possible value */
+        2, 0, /* possible value handle */
+        3, 0, /* possible value handle */
+        1,    /* number of default value */
+        0     /* defaut value string handle index */
+    };
+
+    auto entry =
+        reinterpret_cast<struct pldm_bios_attr_table_entry*>(enumEntry.data());
+    uint8_t pvNumber = pldm_bios_table_attr_entry_enum_decode_pv_num(entry);
+    EXPECT_EQ(pvNumber, 2);
+    uint8_t defNumber = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+    EXPECT_EQ(defNumber, 1);
+
+    pvNumber = 0;
+    auto rc =
+        pldm_bios_table_attr_entry_enum_decode_pv_num_check(entry, &pvNumber);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(pvNumber, 2);
+    defNumber = 0;
+    rc =
+        pldm_bios_table_attr_entry_enum_decode_def_num_check(entry, &defNumber);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(defNumber, 1);
+
+    rc =
+        pldm_bios_table_attr_entry_enum_decode_pv_num_check(nullptr, &pvNumber);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = pldm_bios_table_attr_entry_enum_decode_def_num_check(entry, nullptr);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    entry->attr_type = PLDM_BIOS_STRING;
+    rc = pldm_bios_table_attr_entry_enum_decode_pv_num_check(entry, &pvNumber);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc =
+        pldm_bios_table_attr_entry_enum_decode_def_num_check(entry, &defNumber);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(AttrTable, StringEntryDecodeTest)
+{
+    std::vector<uint8_t> stringEntry{
+        1,   0,       /* attr handle */
+        1,            /* attr type */
+        12,  0,       /* attr name handle */
+        1,            /* string type */
+        1,   0,       /* minimum length of the string in bytes */
+        100, 0,       /* maximum length of the string in bytes */
+        3,   0,       /* length of default string in length */
+        'a', 'b', 'c' /* default string  */
+    };
+
+    auto entry = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
+        stringEntry.data());
+    uint16_t def_string_length =
+        pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
+    EXPECT_EQ(def_string_length, 3);
+
+    def_string_length = 0;
+    auto rc = pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+        entry, &def_string_length);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(def_string_length, 3);
+
+    rc = pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+        entry, nullptr);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+        nullptr, &def_string_length);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    entry->attr_type = PLDM_BIOS_INTEGER;
+    rc = pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+        entry, &def_string_length);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+        nullptr, &def_string_length);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(AttrTable, ItearatorTest)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        1, 0, /* attr name handle */
+        2,    /* number of possible value */
+        2, 0, /* possible value handle */
+        3, 0, /* possible value handle */
+        1,    /* number of default value */
+        0     /* defaut value string handle index */
+    };
+    std::vector<uint8_t> stringEntry{
+        1,   0,       /* attr handle */
+        1,            /* attr type */
+        12,  0,       /* attr name handle */
+        1,            /* string type */
+        1,   0,       /* minimum length of the string in bytes */
+        100, 0,       /* maximum length of the string in bytes */
+        3,   0,       /* length of default string in length */
+        'a', 'b', 'c' /* default string  */
+    };
+
+    Table table;
+    buildTable(table, enumEntry, stringEntry, enumEntry);
+    auto iter = pldm_bios_table_iter_create(table.data(), table.size(),
+                                            PLDM_BIOS_ATTR_TABLE);
+    auto entry = pldm_bios_table_iter_attr_entry_value(iter);
+    auto rc = std::memcmp(entry, enumEntry.data(), enumEntry.size());
+    EXPECT_EQ(rc, 0);
+
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_attr_entry_value(iter);
+    rc = std::memcmp(entry, stringEntry.data(), stringEntry.size());
+    EXPECT_EQ(rc, 0);
+
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_attr_entry_value(iter);
+    rc = std::memcmp(entry, enumEntry.data(), enumEntry.size());
+    EXPECT_EQ(rc, 0);
+
+    pldm_bios_table_iter_next(iter);
+    EXPECT_TRUE(pldm_bios_table_iter_is_end(iter));
+    pldm_bios_table_iter_free(iter);
+}
+
+TEST(Itearator, DeathTest)
+{
+
+    Table table(256, 0);
+
+    /* first entry */
+    auto attr_entry =
+        reinterpret_cast<struct pldm_bios_attr_table_entry*>(table.data());
+    auto iter = pldm_bios_table_iter_create(table.data(), table.size(),
+                                            PLDM_BIOS_ATTR_TABLE);
+    attr_entry->attr_type = PLDM_BIOS_PASSWORD;
+    EXPECT_DEATH(pldm_bios_table_iter_next(iter), "attr_table_entry != NULL");
+    attr_entry->attr_type = PLDM_BIOS_INTEGER;
+    EXPECT_DEATH(pldm_bios_table_iter_next(iter), "attr_table_entry != NULL");
+    pldm_bios_table_iter_free(iter);
+}
diff --git a/test/libpldmresponder_bios_test.cpp b/test/libpldmresponder_bios_test.cpp
index 417c0ae..1df46cc 100644
--- a/test/libpldmresponder_bios_test.cpp
+++ b/test/libpldmresponder_bios_test.cpp
@@ -5,6 +5,7 @@
 #include <string.h>
 
 #include <array>
+#include <cstring>
 #include <ctime>
 #include <filesystem>
 
@@ -122,6 +123,56 @@
                  std::out_of_range);
 }
 
+TEST(traverseBIOSTable, attrTableScenarios)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        1, 0, /* attr name handle */
+        2,    /* number of possible value */
+        2, 0, /* possible value handle */
+        3, 0, /* possible value handle */
+        1,    /* number of default value */
+        0     /* defaut value string handle index */
+    };
+    std::vector<uint8_t> stringEntry{
+        4,   0,       /* attr handle */
+        1,            /* attr type */
+        12,  0,       /* attr name handle */
+        1,            /* string type */
+        1,   0,       /* minimum length of the string in bytes */
+        100, 0,       /* maximum length of the string in bytes */
+        3,   0,       /* length of default string in length */
+        'a', 'b', 'c' /* default string  */
+    };
+    std::vector<uint8_t> table;
+    table.insert(table.end(), enumEntry.begin(), enumEntry.end());
+    table.insert(table.end(), stringEntry.begin(), stringEntry.end());
+    auto padSize = ((table.size() % 4) ? (4 - table.size() % 4) : 0);
+
+    table.insert(table.end(), padSize, 0);
+    table.insert(table.end(), sizeof(uint32_t) /*checksum*/, 0);
+
+    pldm::responder::traverseBIOSAttrTable(
+        table, [&](const struct pldm_bios_attr_table_entry* entry) {
+            int rc;
+            switch (entry->attr_type)
+            {
+                case 0:
+                    rc = std::memcmp(entry, enumEntry.data(), enumEntry.size());
+                    EXPECT_EQ(rc, 0);
+                    break;
+                case 1:
+                    rc = std::memcmp(entry, stringEntry.data(),
+                                     stringEntry.size());
+                    EXPECT_EQ(rc, 0);
+                    break;
+                default:
+                    break;
+            }
+        });
+}
+
 namespace fs = std::filesystem;
 class TestAllBIOSTables : public ::testing::Test
 {
diff --git a/test/meson.build b/test/meson.build
index e219db5..db250a7 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -20,6 +20,7 @@
   'libpldm_platform_test',
   'libpldmresponder_base_test',
   'libpldm_bios_test',
+  'libpldm_bios_table_test',
   'libpldmresponder_bios_test',
   'libpldmresponder_pdr_state_effecter_test',
   'libpldmresponder_bios_table_test',