bios: Move en/decodes for Attribute Table to libpldm

BIOS Attribute Table has various attribute types, the existing
code implements enum/string.

This commit moves the existing encode/decode functions for
BIOS Attribute Table to libplm.

Signed-off-by: John Wang <wangzqbj@inspur.com>
Change-Id: I60757ee346464d3d108d1667e6074a1345e6e150
diff --git a/libpldm/bios_table.c b/libpldm/bios_table.c
index d9c2505..8782a16 100644
--- a/libpldm/bios_table.c
+++ b/libpldm/bios_table.c
@@ -110,6 +110,72 @@
 	       pldm_bios_table_string_entry_decode_string_length(entry);
 }
 
+static uint16_t get_bios_attr_handle()
+{
+	static uint16_t handle = 0;
+	assert(handle != UINT16_MAX);
+
+	return handle++;
+}
+
+static void attr_table_entry_encode_header(void *entry, size_t length,
+					   uint8_t attr_type,
+					   uint16_t string_handle)
+{
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+	assert(sizeof(*attr_entry) <= length);
+	attr_entry->attr_handle = htole16(get_bios_attr_handle());
+	attr_entry->attr_type = attr_type;
+	attr_entry->string_handle = htole16(string_handle);
+}
+
+size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
+						     uint8_t def_num)
+{
+	return sizeof(struct pldm_bios_attr_table_entry) -
+	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
+	       sizeof(pv_num) + pv_num * sizeof(uint16_t) + sizeof(def_num) +
+	       def_num;
+}
+
+void pldm_bios_table_attr_entry_enum_encode(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_enum_info *info)
+{
+	size_t length = pldm_bios_table_attr_entry_enum_encode_length(
+	    info->pv_num, info->def_num);
+	assert(length <= entry_length);
+	uint8_t attr_type = info->read_only ? PLDM_BIOS_ENUMERATION_READ_ONLY
+					    : PLDM_BIOS_ENUMERATION;
+	attr_table_entry_encode_header(entry, entry_length, attr_type,
+				       info->name_handle);
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+	attr_entry->metadata[0] = info->pv_num;
+	uint16_t *pv_hdls =
+	    (uint16_t *)(attr_entry->metadata + 1 /* sizeof(pv num) */);
+	size_t i;
+	for (i = 0; i < info->pv_num; i++)
+		pv_hdls[i] = htole16(info->pv_handle[i]);
+	attr_entry->metadata[1 + info->pv_num * sizeof(uint16_t)] =
+	    info->def_num;
+	memcpy(attr_entry->metadata + 1 /* sizeof(pv num) */ +
+		   info->pv_num * sizeof(uint16_t) + 1 /* sizeof(def num)*/,
+	       info->def_index, info->def_num);
+}
+
+int pldm_bios_table_attr_entry_enum_encode_check(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_enum_info *info)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(info);
+	size_t length = pldm_bios_table_attr_entry_enum_encode_length(
+	    info->pv_num, info->def_num);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	pldm_bios_table_attr_entry_enum_encode(entry, entry_length, info);
+	return PLDM_SUCCESS;
+}
+
 #define ATTR_TYPE_EXPECT(type, expected)                                       \
 	do {                                                                   \
 		if (type != expected && type != (expected | 0x80))             \
@@ -186,23 +252,74 @@
 {
 	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;
+	return pldm_bios_table_attr_entry_enum_encode_length(pv_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 */
+struct attr_table_string_entry_fields {
+	uint8_t string_type;
+	uint16_t min_length;
+	uint16_t max_length;
+	uint16_t def_length;
+	uint8_t def_string[1];
+} __attribute__((packed));
+
+size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len)
+{
+	return sizeof(struct pldm_bios_attr_table_entry) -
+	       MEMBER_SIZE(pldm_bios_attr_table_entry, metadata) +
+	       sizeof(struct attr_table_string_entry_fields) -
+	       MEMBER_SIZE(attr_table_string_entry_fields, def_string) +
+	       def_str_len;
+}
+
+void pldm_bios_table_attr_entry_string_encode(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_string_info *info)
+{
+	size_t length =
+	    pldm_bios_table_attr_entry_string_encode_length(info->def_length);
+	assert(length <= entry_length);
+	uint8_t attr_type =
+	    info->read_only ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
+	attr_table_entry_encode_header(entry, entry_length, attr_type,
+				       info->name_handle);
+	struct pldm_bios_attr_table_entry *attr_entry = entry;
+	struct attr_table_string_entry_fields *attr_fields =
+	    (struct attr_table_string_entry_fields *)attr_entry->metadata;
+	attr_fields->string_type = info->string_type;
+	attr_fields->min_length = htole16(info->min_length);
+	attr_fields->max_length = htole16(info->max_length);
+	attr_fields->def_length = htole16(info->def_length);
+	if (info->def_length != 0 && info->def_string != NULL)
+		memcpy(attr_fields->def_string, info->def_string,
+		       info->def_length);
+}
+
+int pldm_bios_table_attr_entry_string_encode_check(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_string_info *info)
+{
+	POINTER_CHECK(entry);
+	POINTER_CHECK(info);
+	size_t length =
+	    pldm_bios_table_attr_entry_string_encode_length(info->def_length);
+	BUFFER_SIZE_EXPECT(entry_length, length);
+	if (info->def_length > info->max_length ||
+	    info->def_length < info->min_length ||
+	    info->min_length > info->max_length)
+		return PLDM_ERROR_INVALID_DATA;
+	if (info->string_type > 5 && info->string_type != 0xFF)
+		return PLDM_ERROR_INVALID_DATA;
+	pldm_bios_table_attr_entry_string_encode(entry, entry_length, info);
+	return PLDM_SUCCESS;
+}
 
 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);
+	struct attr_table_string_entry_fields *fields =
+	    (struct attr_table_string_entry_fields *)entry->metadata;
+	return le16toh(fields->def_length);
 }
 
 int pldm_bios_table_attr_entry_string_decode_def_string_length_check(
@@ -221,10 +338,9 @@
 static size_t
 attr_table_entry_length_string(const struct pldm_bios_attr_table_entry *entry)
 {
-	uint16_t def_string_len =
+	uint16_t def_str_len =
 	    pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
-	return sizeof(*entry) - 1 + ATTR_ENTRY_STRING_LENGTH_MIN +
-	       def_string_len;
+	return pldm_bios_table_attr_entry_string_encode_length(def_str_len);
 }
 
 struct attr_table_entry {
diff --git a/libpldm/bios_table.h b/libpldm/bios_table.h
index fc9c0eb..97c64ce 100644
--- a/libpldm/bios_table.h
+++ b/libpldm/bios_table.h
@@ -152,6 +152,51 @@
 pldm_bios_table_string_find_by_handle(const void *table, size_t length,
 				      uint16_t handle);
 
+/** @struct pldm_bios_table_attr_entry_enum_info
+ *
+ *  An auxiliary structure for passing parameters to @ref
+ * pldm_bios_table_attr_entry_enum_encode
+ *
+ */
+struct pldm_bios_table_attr_entry_enum_info {
+	uint16_t name_handle; //!< attribute name handle
+	bool read_only;       //!< indicate whether the attribute is read-only
+	uint8_t pv_num;       //!< number of possible values
+	const uint16_t *pv_handle; //!< handles of possible values
+	uint8_t def_num;	   //!< nnumber of default values
+	const uint8_t *def_index;  //!< indices of default values.
+};
+
+/** @brief Get length that an attribute entry(type: enum) will take
+ *  @param[in] pv_num - Number of possible values
+ *  @param[in] def_num - Number of default values
+ *  @return The length that an entry(type: enum) will take
+ */
+size_t pldm_bios_table_attr_entry_enum_encode_length(uint8_t pv_num,
+						     uint8_t def_num);
+
+/** @brief Create an entry of BIOS Attribute Table (type: enum)
+ *  @param[out] entry - Pointer to a buffer to create an entry
+ *  @param[in] entry_length - Length of the buffer to create an entry
+ *  @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_enum_info
+ */
+void pldm_bios_table_attr_entry_enum_encode(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_enum_info *info);
+
+/** @brief Create an entry of BIOS Attribute Table (type: enum) and check the
+ * validity of the parameters
+ *  @param[out] entry - Pointer to a buffer to create an entry
+ *  @param[in] entry_length - Length of the buffer to create an entry
+ *  @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_enum_info
+ *  @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_enum_encode_check(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_enum_info *info);
+
 /** @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
@@ -208,6 +253,50 @@
     const struct pldm_bios_attr_table_entry *entry, uint16_t *pv_hdls,
     uint8_t pv_num);
 
+/** @struct pldm_bios_table_attr_entry_string_info
+ *
+ *  An auxiliary structure for passing parameters to @ref
+ * pldm_bios_table_attr_entry_string_encode
+ *
+ */
+struct pldm_bios_table_attr_entry_string_info {
+	uint16_t name_handle;   //!< attribute name handle
+	bool read_only;		//!< indicate whether the attribute is read-only
+	uint8_t string_type;    //!< The type of the string
+	uint16_t min_length;    //!< The minimum length of the string in bytes
+	uint16_t max_length;    //!< The maximum length of the string in bytes
+	uint16_t def_length;    //!< The length of the defaut string in bytes
+	const char *def_string; //!< The default string itself
+};
+
+/** @brief Get length that an attribute entry(type: string) will take
+ *  @param[in] def_str_len - Length of default string
+ *  @return The length that an entry(type: string) will take
+ */
+size_t pldm_bios_table_attr_entry_string_encode_length(uint16_t def_str_len);
+
+/** @brief Create an entry of BIOS Attribute Table (type: string)
+ *  @param[out] entry - Pointer to a buffer to create an entry
+ *  @param[in] entry_length - Length of the buffer to create an entry
+ *  @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_string_info
+ */
+void pldm_bios_table_attr_entry_string_encode(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_string_info *info);
+
+/** @brief Create an entry of BIOS Attribute Table (type: string) and check the
+ * validity of the parameters
+ *  @param[out] entry - Pointer to a buffer to create an entry
+ *  @param[in] entry_length - Length of the buffer to create an entry
+ *  @param[in] info - Pointer to an auxiliary structure @ref
+ * pldm_bios_table_attr_entry_string_info
+ *  @return pldm_completion_codes
+ */
+int pldm_bios_table_attr_entry_string_encode_check(
+    void *entry, size_t entry_length,
+    const struct pldm_bios_table_attr_entry_string_info *info);
+
 /** @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
diff --git a/libpldmresponder/bios.cpp b/libpldmresponder/bios.cpp
index 5bfe0ae..4372e21 100644
--- a/libpldmresponder/bios.cpp
+++ b/libpldmresponder/bios.cpp
@@ -128,16 +128,6 @@
     return response;
 }
 
-/** @brief Generate the next attribute handle
- *
- *  @return - uint16_t - next attribute handle
- */
-AttributeHandle nextAttributeHandle()
-{
-    static AttributeHandle attrHdl = 0;
-    return attrHdl++;
-}
-
 /** @brief Construct the BIOS string table
  *
  *  @param[in] BIOSStringTable - the string table
@@ -357,9 +347,7 @@
                             entry("ATTRIBUTE=%s", key.c_str()));
             continue;
         }
-        uint8_t typeOfAttr = (std::get<0>(value))
-                                 ? PLDM_BIOS_ENUMERATION_READ_ONLY
-                                 : PLDM_BIOS_ENUMERATION;
+        bool readOnly = (std::get<0>(value));
         PossibleValues possiVals = std::get<1>(value);
         DefaultValues defVals = std::get<2>(value);
         // both the possible and default values are stored in sorted manner to
@@ -383,35 +371,21 @@
             }
         }
         auto defValsByHdl = findDefaultValHandle(possiVals, defVals);
+        auto entryLength = pldm_bios_table_attr_entry_enum_encode_length(
+            possiValsByHdl.size(), defValsByHdl.size());
 
-        BIOSTableRow enumAttrTable(
-            (sizeof(struct pldm_bios_attr_table_entry) - 1) + sizeof(uint8_t) +
-                possiValsByHdl.size() * sizeof(uint16_t) + sizeof(uint8_t) +
-                defValsByHdl.size() * sizeof(uint8_t),
-            0);
-        BIOSTableRow::iterator it = enumAttrTable.begin();
-        auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
-            enumAttrTable.data());
-        attrPtr->attr_handle = nextAttributeHandle();
-        attrPtr->attr_type = typeOfAttr;
-        attrPtr->string_handle = std::move(strHandle);
-        std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
-        uint8_t numPossibleVals = possiValsByHdl.size();
-        std::copy_n(&numPossibleVals, sizeof(numPossibleVals), it);
-        std::advance(it, sizeof(numPossibleVals));
-        std::copy_n(reinterpret_cast<uint8_t*>(possiValsByHdl.data()),
-                    sizeof(uint16_t) * possiValsByHdl.size(), it);
-        std::advance(
-            it, sizeof(uint16_t) *
-                    possiValsByHdl.size()); // possible val handle is uint16_t
-        uint8_t numDefaultVals = defValsByHdl.size();
-        std::copy_n(&numDefaultVals, sizeof(numDefaultVals), it);
-        std::advance(it, sizeof(numDefaultVals));
-        std::copy(defValsByHdl.begin(), defValsByHdl.end(), it);
-        std::advance(it, defValsByHdl.size());
-
-        std::move(enumAttrTable.begin(), enumAttrTable.end(),
-                  std::back_inserter(attributeTable));
+        auto attrTableSize = attributeTable.size();
+        attributeTable.resize(attrTableSize + entryLength, 0);
+        struct pldm_bios_table_attr_entry_enum_info info = {
+            strHandle,
+            readOnly,
+            (uint8_t)possiValsByHdl.size(),
+            possiValsByHdl.data(),
+            (uint8_t)defValsByHdl.size(),
+            defValsByHdl.data(),
+        };
+        pldm_bios_table_attr_entry_enum_encode(
+            attributeTable.data() + attrTableSize, entryLength, &info);
     }
 }
 
@@ -469,7 +443,6 @@
 {
     const auto& attributeMap = getValues();
     StringHandle strHandle;
-
     for (const auto& [key, value] : attributeMap)
     {
         try
@@ -483,37 +456,19 @@
             continue;
         }
 
-        const auto& [type, strType, minStrLen, maxStrLen, defaultStrLen,
+        const auto& [readOnly, strType, minStrLen, maxStrLen, defaultStrLen,
                      defaultStr] = value;
-        uint8_t typeOfAttr =
-            type ? PLDM_BIOS_STRING_READ_ONLY : PLDM_BIOS_STRING;
+        auto entryLength =
+            pldm_bios_table_attr_entry_string_encode_length(defaultStrLen);
 
-        BIOSTableRow stringAttrTable(bios_parser::bios_string::attrTableSize +
-                                     defaultStr.size());
-        BIOSTableRow::iterator it = stringAttrTable.begin();
-        auto attrPtr = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
-            stringAttrTable.data());
-        attrPtr->attr_handle = nextAttributeHandle();
-        attrPtr->attr_type = typeOfAttr;
-        attrPtr->string_handle = strHandle;
-
-        std::advance(it, (sizeof(struct pldm_bios_attr_table_entry) - 1));
-        std::copy_n(&strType, sizeof(uint8_t), it);
-        std::advance(it, sizeof(uint8_t));
-        std::copy_n(reinterpret_cast<const uint8_t*>(&minStrLen),
-                    sizeof(uint16_t), it);
-        std::advance(it, sizeof(uint16_t));
-        std::copy_n(reinterpret_cast<const uint8_t*>(&maxStrLen),
-                    sizeof(uint16_t), it);
-        std::advance(it, sizeof(uint16_t));
-        std::copy_n(reinterpret_cast<const uint8_t*>(&defaultStrLen),
-                    sizeof(uint16_t), it);
-        std::advance(it, sizeof(uint16_t));
-        std::copy_n(defaultStr.data(), defaultStr.size(), it);
-        std::advance(it, defaultStr.size());
-
-        attributeTable.insert(attributeTable.end(), stringAttrTable.begin(),
-                              stringAttrTable.end());
+        struct pldm_bios_table_attr_entry_string_info info = {
+            strHandle, readOnly,      strType,           minStrLen,
+            maxStrLen, defaultStrLen, defaultStr.data(),
+        };
+        auto attrTableSize = attributeTable.size();
+        attributeTable.resize(attrTableSize + entryLength, 0);
+        pldm_bios_table_attr_entry_string_encode(
+            attributeTable.data() + attrTableSize, entryLength, &info);
     }
 }
 
diff --git a/libpldmresponder/bios_parser.hpp b/libpldmresponder/bios_parser.hpp
index bc92e3c..6620ddb 100644
--- a/libpldmresponder/bios_parser.hpp
+++ b/libpldmresponder/bios_parser.hpp
@@ -87,15 +87,6 @@
 using AttrValuesMap =
     std::map<AttrName, std::tuple<IsReadOnly, StrType, MinStrLen, MaxStrLen,
                                   DefaultStrLen, DefaultStr>>;
-/* attrTableSize is the sum of fixed length of members which construct a string
- * attribute table, including attr_handle(uint16_t), attr_type(uint8_t),
- * string_handle(uint16_t), strType(uint8_t), minStrLen(uint16_t),
- * MaxStrLen(uint16_t), DefaultStrLen(uint16_t) */
-constexpr auto attrTableSize = 12;
-static_assert(attrTableSize == sizeof(uint16_t) + sizeof(uint8_t) +
-                                   sizeof(uint16_t) + sizeof(uint8_t) +
-                                   sizeof(uint16_t) + sizeof(uint16_t) +
-                                   sizeof(uint16_t));
 
 /** @brief Get the string related values and the default values for the
  *         BIOSString and BIOSStringReadOnly types
diff --git a/test/libpldm_bios_table_test.cpp b/test/libpldm_bios_table_test.cpp
index 8a808a5..a07036a 100644
--- a/test/libpldm_bios_table_test.cpp
+++ b/test/libpldm_bios_table_test.cpp
@@ -1,6 +1,7 @@
 #include <string.h>
 
 #include <cstring>
+#include <utility>
 #include <vector>
 
 #include "libpldm/base.h"
@@ -96,6 +97,58 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
 
+TEST(AttrTable, EnumEntryEncodeTest)
+{
+    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<uint16_t> pv_hdls{2, 3};
+    std::vector<uint8_t> defs{0};
+
+    struct pldm_bios_table_attr_entry_enum_info info = {
+        1,              /* name handle */
+        false,          /* read only */
+        2,              /* pv number */
+        pv_hdls.data(), /* pv handle */
+        1,              /*def number */
+        defs.data()     /*def index*/
+    };
+    auto encodeLength = pldm_bios_table_attr_entry_enum_encode_length(2, 1);
+    EXPECT_EQ(encodeLength, enumEntry.size());
+
+    std::vector<uint8_t> encodeEntry(encodeLength, 0);
+    pldm_bios_table_attr_entry_enum_encode(encodeEntry.data(),
+                                           encodeEntry.size(), &info);
+    // set attr handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(enumEntry, encodeEntry);
+
+    EXPECT_DEATH(pldm_bios_table_attr_entry_enum_encode(
+                     encodeEntry.data(), encodeEntry.size() - 1, &info),
+                 "length <= entry_length");
+    auto rc = pldm_bios_table_attr_entry_enum_encode_check(
+        encodeEntry.data(), encodeEntry.size(), &info);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    // set attr handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(enumEntry, encodeEntry);
+    rc = pldm_bios_table_attr_entry_enum_encode_check(
+        encodeEntry.data(), encodeEntry.size() - 1, &info);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
 TEST(AttrTable, StringEntryDecodeTest)
 {
     std::vector<uint8_t> stringEntry{
@@ -136,6 +189,86 @@
     EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
 }
 
+TEST(AttrTable, StringEntryEncodeTest)
+{
+    std::vector<uint8_t> stringEntry{
+        0,   0,        /* attr handle */
+        1,             /* attr type */
+        3,   0,        /* attr name handle */
+        1,             /* string type */
+        1,   0,        /* min string length */
+        100, 0,        /* max string length */
+        3,   0,        /* default string length */
+        'a', 'b', 'c', /* defaul string */
+    };
+
+    struct pldm_bios_table_attr_entry_string_info info = {
+        3,     /* name handle */
+        false, /* read only */
+        1,     /* string type ascii */
+        1,     /* min length */
+        100,   /* max length */
+        3,     /* def length */
+        "abc", /* def string */
+    };
+    auto encodeLength = pldm_bios_table_attr_entry_string_encode_length(3);
+    EXPECT_EQ(encodeLength, stringEntry.size());
+
+    std::vector<uint8_t> encodeEntry(encodeLength, 0);
+    pldm_bios_table_attr_entry_string_encode(encodeEntry.data(),
+                                             encodeEntry.size(), &info);
+    // set attr handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(stringEntry, encodeEntry);
+
+    EXPECT_DEATH(pldm_bios_table_attr_entry_string_encode(
+                     encodeEntry.data(), encodeEntry.size() - 1, &info),
+                 "length <= entry_length");
+    auto rc = pldm_bios_table_attr_entry_string_encode_check(
+        encodeEntry.data(), encodeEntry.size(), &info);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    // set attr handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(stringEntry, encodeEntry);
+    rc = pldm_bios_table_attr_entry_string_encode_check(
+        encodeEntry.data(), encodeEntry.size() - 1, &info);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+    std::swap(info.max_length, info.min_length);
+    rc = pldm_bios_table_attr_entry_string_encode_check(
+        encodeEntry.data(), encodeEntry.size(), &info);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    std::swap(info.max_length, info.min_length);
+
+    std::vector<uint8_t> stringEntryLength0{
+        0,   0, /* attr handle */
+        1,      /* attr type */
+        3,   0, /* attr name handle */
+        1,      /* string type */
+        1,   0, /* min string length */
+        100, 0, /* max string length */
+        0,   0, /* default string length */
+    };
+
+    info.def_length = 0;
+    info.def_string = nullptr;
+
+    encodeLength = pldm_bios_table_attr_entry_string_encode_length(0);
+    EXPECT_EQ(encodeLength, stringEntryLength0.size());
+
+    encodeEntry.resize(encodeLength);
+    pldm_bios_table_attr_entry_string_encode(encodeEntry.data(),
+                                             encodeEntry.size(), &info);
+    // set attr handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(stringEntryLength0, encodeEntry);
+}
+
 TEST(AttrTable, ItearatorTest)
 {
     std::vector<uint8_t> enumEntry{