Move libpldm test cases into libpldm directory

The test cases for different libraries in this repo are put in the same
test directory.
As a follow up of building libpldm only, move the test cases of libpldm
into libpldm/tests, so that the test cases could be built and run by
libpldm-only option.

Tested: Verify the libpldm tests are built and run by libpldm-only
        option.
        Verify all the tests are built and run without libpldm-only
        option.

Signed-off-by: Lei YU <mine260309@gmail.com>
Change-Id: I097000bef316f787ef1894f1a3feec5089ea081a
diff --git a/libpldm/meson.build b/libpldm/meson.build
index 9d24b2c..bd10096 100644
--- a/libpldm/meson.build
+++ b/libpldm/meson.build
@@ -62,3 +62,7 @@
   description: 'PLDM protocol encode/decode C lib',
   version: meson.project_version(),
   libraries: libpldm)
+
+if get_option('tests').enabled()
+  subdir('tests')
+endif
diff --git a/libpldm/tests/.clang-format b/libpldm/tests/.clang-format
new file mode 100644
index 0000000..ae9ad39
--- /dev/null
+++ b/libpldm/tests/.clang-format
@@ -0,0 +1,98 @@
+---
+Language:        Cpp
+# BasedOnStyle:  LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlinesLeft: false
+AlignOperands:   true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+  AfterClass:      true
+  AfterControlStatement: true
+  AfterEnum:       true
+  AfterFunction:   true
+  AfterNamespace:  true
+  AfterObjCDeclaration: true
+  AfterStruct:     true
+  AfterUnion:      true
+  BeforeCatch:     true
+  BeforeElse:      true
+  IndentBraces:    false
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Custom
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializers: AfterColon
+ColumnLimit:     80
+CommentPragmas:  '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+PointerAlignment: Left
+DisableFormat:   false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
+IncludeCategories:
+  - Regex:           '^[<"](gtest|gmock)'
+    Priority:        5
+  - Regex:           '^"config.h"'
+    Priority:        -1
+  - Regex:           '^".*\.hpp"'
+    Priority:        1
+  - Regex:           '^<.*\.h>'
+    Priority:        2
+  - Regex:           '^<.*'
+    Priority:        3
+  - Regex:           '.*'
+    Priority:        4
+IndentCaseLabels: true
+IndentWidth:     4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+ReflowComments:  true
+SortIncludes:    true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: ControlStatements
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles:  false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard:        Cpp11
+TabWidth:        4
+UseTab:          Never
+...
diff --git a/libpldm/tests/libpldm_base_test.cpp b/libpldm/tests/libpldm_base_test.cpp
new file mode 100644
index 0000000..b8b25d3
--- /dev/null
+++ b/libpldm/tests/libpldm_base_test.cpp
@@ -0,0 +1,545 @@
+#include <string.h>
+
+#include <array>
+#include <cstring>
+#include <vector>
+
+#include "libpldm/base.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::ElementsAreArray;
+
+constexpr auto hdrSize = sizeof(pldm_msg_hdr);
+
+TEST(PackPLDMMessage, BadPathTest)
+{
+    struct pldm_header_info hdr;
+    struct pldm_header_info* hdr_ptr = NULL;
+    pldm_msg_hdr msg{};
+
+    // PLDM header information pointer is NULL
+    auto rc = pack_pldm_header(hdr_ptr, &msg);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // PLDM message pointer is NULL
+    rc = pack_pldm_header(&hdr, nullptr);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // PLDM header information pointer and PLDM message pointer is NULL
+    rc = pack_pldm_header(hdr_ptr, nullptr);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // RESERVED message type
+    hdr.msg_type = PLDM_RESERVED;
+    rc = pack_pldm_header(&hdr, &msg);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // Instance ID out of range
+    hdr.msg_type = PLDM_REQUEST;
+    hdr.instance = 32;
+    rc = pack_pldm_header(&hdr, &msg);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // PLDM type out of range
+    hdr.msg_type = PLDM_REQUEST;
+    hdr.instance = 31;
+    hdr.pldm_type = 64;
+    rc = pack_pldm_header(&hdr, &msg);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_PLDM_TYPE);
+}
+
+TEST(PackPLDMMessage, RequestMessageGoodPath)
+{
+    struct pldm_header_info hdr;
+    pldm_msg_hdr msg{};
+
+    // Message type is REQUEST and lower range of the field values
+    hdr.msg_type = PLDM_REQUEST;
+    hdr.instance = 0;
+    hdr.pldm_type = 0;
+    hdr.command = 0;
+
+    auto rc = pack_pldm_header(&hdr, &msg);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(msg.request, 1);
+    EXPECT_EQ(msg.datagram, 0);
+    EXPECT_EQ(msg.instance_id, 0);
+    EXPECT_EQ(msg.type, 0);
+    EXPECT_EQ(msg.command, 0);
+
+    // Message type is REQUEST and upper range of the field values
+    hdr.instance = 31;
+    hdr.pldm_type = 63;
+    hdr.command = 255;
+
+    rc = pack_pldm_header(&hdr, &msg);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(msg.request, 1);
+    EXPECT_EQ(msg.datagram, 0);
+    EXPECT_EQ(msg.instance_id, 31);
+    EXPECT_EQ(msg.type, 63);
+    EXPECT_EQ(msg.command, 255);
+
+    // Message type is PLDM_ASYNC_REQUEST_NOTIFY
+    hdr.msg_type = PLDM_ASYNC_REQUEST_NOTIFY;
+
+    rc = pack_pldm_header(&hdr, &msg);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(msg.request, 1);
+    EXPECT_EQ(msg.datagram, 1);
+    EXPECT_EQ(msg.instance_id, 31);
+    EXPECT_EQ(msg.type, 63);
+    EXPECT_EQ(msg.command, 255);
+}
+
+TEST(PackPLDMMessage, ResponseMessageGoodPath)
+{
+    struct pldm_header_info hdr;
+    pldm_msg_hdr msg{};
+
+    // Message type is PLDM_RESPONSE and lower range of the field values
+    hdr.msg_type = PLDM_RESPONSE;
+    hdr.instance = 0;
+    hdr.pldm_type = 0;
+    hdr.command = 0;
+
+    auto rc = pack_pldm_header(&hdr, &msg);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(msg.request, 0);
+    EXPECT_EQ(msg.datagram, 0);
+    EXPECT_EQ(msg.instance_id, 0);
+    EXPECT_EQ(msg.type, 0);
+    EXPECT_EQ(msg.command, 0);
+
+    // Message type is PLDM_RESPONSE and upper range of the field values
+    hdr.instance = 31;
+    hdr.pldm_type = 63;
+    hdr.command = 255;
+
+    rc = pack_pldm_header(&hdr, &msg);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(msg.request, 0);
+    EXPECT_EQ(msg.datagram, 0);
+    EXPECT_EQ(msg.instance_id, 31);
+    EXPECT_EQ(msg.type, 63);
+    EXPECT_EQ(msg.command, 255);
+}
+
+TEST(UnpackPLDMMessage, BadPathTest)
+{
+    struct pldm_header_info hdr;
+
+    // PLDM message pointer is NULL
+    auto rc = unpack_pldm_header(nullptr, &hdr);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(UnpackPLDMMessage, RequestMessageGoodPath)
+{
+    struct pldm_header_info hdr;
+    pldm_msg_hdr msg{};
+
+    // Unpack PLDM request message and lower range of field values
+    msg.request = 1;
+    auto rc = unpack_pldm_header(&msg, &hdr);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(hdr.msg_type, PLDM_REQUEST);
+    EXPECT_EQ(hdr.instance, 0);
+    EXPECT_EQ(hdr.pldm_type, 0);
+    EXPECT_EQ(hdr.command, 0);
+
+    // Unpack PLDM async request message and lower range of field values
+    msg.datagram = 1;
+    rc = unpack_pldm_header(&msg, &hdr);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(hdr.msg_type, PLDM_ASYNC_REQUEST_NOTIFY);
+
+    // Unpack PLDM request message and upper range of field values
+    msg.datagram = 0;
+    msg.instance_id = 31;
+    msg.type = 63;
+    msg.command = 255;
+    rc = unpack_pldm_header(&msg, &hdr);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(hdr.msg_type, PLDM_REQUEST);
+    EXPECT_EQ(hdr.instance, 31);
+    EXPECT_EQ(hdr.pldm_type, 63);
+    EXPECT_EQ(hdr.command, 255);
+}
+
+TEST(UnpackPLDMMessage, ResponseMessageGoodPath)
+{
+    struct pldm_header_info hdr;
+    pldm_msg_hdr msg{};
+
+    // Unpack PLDM response message and lower range of field values
+    auto rc = unpack_pldm_header(&msg, &hdr);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(hdr.msg_type, PLDM_RESPONSE);
+    EXPECT_EQ(hdr.instance, 0);
+    EXPECT_EQ(hdr.pldm_type, 0);
+    EXPECT_EQ(hdr.command, 0);
+
+    // Unpack PLDM response message and upper range of field values
+    msg.instance_id = 31;
+    msg.type = 63;
+    msg.command = 255;
+    rc = unpack_pldm_header(&msg, &hdr);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(hdr.msg_type, PLDM_RESPONSE);
+    EXPECT_EQ(hdr.instance, 31);
+    EXPECT_EQ(hdr.pldm_type, 63);
+    EXPECT_EQ(hdr.command, 255);
+}
+
+TEST(GetPLDMCommands, testEncodeRequest)
+{
+    uint8_t pldmType = 0x05;
+    ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_REQ_BYTES>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = encode_get_commands_req(0, pldmType, version, request);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(0, memcmp(request->payload, &pldmType, sizeof(pldmType)));
+    EXPECT_EQ(0, memcmp(request->payload + sizeof(pldmType), &version,
+                        sizeof(version)));
+}
+
+TEST(GetPLDMCommands, testDecodeRequest)
+{
+    uint8_t pldmType = 0x05;
+    ver32_t version{0xFF, 0xFF, 0xFF, 0xFF};
+    uint8_t pldmTypeOut{};
+    ver32_t versionOut{0xFF, 0xFF, 0xFF, 0xFF};
+    std::array<uint8_t, hdrSize + PLDM_GET_COMMANDS_REQ_BYTES> requestMsg{};
+
+    memcpy(requestMsg.data() + hdrSize, &pldmType, sizeof(pldmType));
+    memcpy(requestMsg.data() + sizeof(pldmType) + hdrSize, &version,
+           sizeof(version));
+
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto rc = decode_get_commands_req(request, requestMsg.size() - hdrSize,
+                                      &pldmTypeOut, &versionOut);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(pldmTypeOut, pldmType);
+    EXPECT_EQ(0, memcmp(&versionOut, &version, sizeof(version)));
+}
+
+TEST(GetPLDMCommands, testEncodeResponse)
+{
+    uint8_t completionCode = 0;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_COMMANDS_RESP_BYTES>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    std::array<bitfield8_t, PLDM_MAX_CMDS_PER_TYPE / 8> commands{};
+    commands[0].byte = 1;
+    commands[1].byte = 2;
+    commands[2].byte = 3;
+
+    auto rc =
+        encode_get_commands_resp(0, PLDM_SUCCESS, commands.data(), response);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    uint8_t* payload_ptr = response->payload;
+    EXPECT_EQ(completionCode, payload_ptr[0]);
+    EXPECT_EQ(1, payload_ptr[sizeof(completionCode)]);
+    EXPECT_EQ(2,
+              payload_ptr[sizeof(completionCode) + sizeof(commands[0].byte)]);
+    EXPECT_EQ(3, payload_ptr[sizeof(completionCode) + sizeof(commands[0].byte) +
+                             sizeof(commands[1].byte)]);
+}
+
+TEST(GetPLDMTypes, testEncodeResponse)
+{
+    uint8_t completionCode = 0;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_TYPES_RESP_BYTES>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    std::array<bitfield8_t, PLDM_MAX_TYPES / 8> types{};
+    types[0].byte = 1;
+    types[1].byte = 2;
+    types[2].byte = 3;
+
+    auto rc = encode_get_types_resp(0, PLDM_SUCCESS, types.data(), response);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    uint8_t* payload_ptr = response->payload;
+    EXPECT_EQ(completionCode, payload_ptr[0]);
+    EXPECT_EQ(1, payload_ptr[sizeof(completionCode)]);
+    EXPECT_EQ(2, payload_ptr[sizeof(completionCode) + sizeof(types[0].byte)]);
+    EXPECT_EQ(3, payload_ptr[sizeof(completionCode) + sizeof(types[0].byte) +
+                             sizeof(types[1].byte)]);
+}
+
+TEST(GetPLDMTypes, testGoodDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_TYPES_RESP_BYTES> responseMsg{};
+    responseMsg[1 + hdrSize] = 1;
+    responseMsg[2 + hdrSize] = 2;
+    responseMsg[3 + hdrSize] = 3;
+    std::array<bitfield8_t, PLDM_MAX_TYPES / 8> outTypes{};
+
+    uint8_t completion_code;
+    responseMsg[hdrSize] = PLDM_SUCCESS;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_get_types_resp(response, responseMsg.size() - hdrSize,
+                                    &completion_code, outTypes.data());
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completion_code, PLDM_SUCCESS);
+    EXPECT_EQ(responseMsg[1 + hdrSize], outTypes[0].byte);
+    EXPECT_EQ(responseMsg[2 + hdrSize], outTypes[1].byte);
+    EXPECT_EQ(responseMsg[3 + hdrSize], outTypes[2].byte);
+}
+
+TEST(GetPLDMTypes, testBadDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_TYPES_RESP_BYTES> responseMsg{};
+    responseMsg[1 + hdrSize] = 1;
+    responseMsg[2 + hdrSize] = 2;
+    responseMsg[3 + hdrSize] = 3;
+    std::array<bitfield8_t, PLDM_MAX_TYPES / 8> outTypes{};
+
+    uint8_t retcompletion_code = 0;
+    responseMsg[hdrSize] = PLDM_SUCCESS;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_get_types_resp(response, responseMsg.size() - hdrSize - 1,
+                                    &retcompletion_code, outTypes.data());
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetPLDMCommands, testGoodDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_COMMANDS_RESP_BYTES> responseMsg{};
+    responseMsg[1 + hdrSize] = 1;
+    responseMsg[2 + hdrSize] = 2;
+    responseMsg[3 + hdrSize] = 3;
+    std::array<bitfield8_t, PLDM_MAX_CMDS_PER_TYPE / 8> outTypes{};
+
+    uint8_t completion_code;
+    responseMsg[hdrSize] = PLDM_SUCCESS;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_get_commands_resp(response, responseMsg.size() - hdrSize,
+                                       &completion_code, outTypes.data());
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completion_code, PLDM_SUCCESS);
+    EXPECT_EQ(responseMsg[1 + hdrSize], outTypes[0].byte);
+    EXPECT_EQ(responseMsg[2 + hdrSize], outTypes[1].byte);
+    EXPECT_EQ(responseMsg[3 + hdrSize], outTypes[2].byte);
+}
+
+TEST(GetPLDMCommands, testBadDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_COMMANDS_RESP_BYTES> responseMsg{};
+    responseMsg[1 + hdrSize] = 1;
+    responseMsg[2 + hdrSize] = 2;
+    responseMsg[3 + hdrSize] = 3;
+    std::array<bitfield8_t, PLDM_MAX_CMDS_PER_TYPE / 8> outTypes{};
+
+    uint8_t retcompletion_code = 0;
+    responseMsg[hdrSize] = PLDM_SUCCESS;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc =
+        decode_get_commands_resp(response, responseMsg.size() - hdrSize - 1,
+                                 &retcompletion_code, outTypes.data());
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetPLDMVersion, testGoodEncodeRequest)
+{
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_REQ_BYTES>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    uint8_t pldmType = 0x03;
+    uint32_t transferHandle = 0x0;
+    uint8_t opFlag = 0x01;
+
+    auto rc =
+        encode_get_version_req(0, transferHandle, opFlag, pldmType, request);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(
+        0, memcmp(request->payload, &transferHandle, sizeof(transferHandle)));
+    EXPECT_EQ(0, memcmp(request->payload + sizeof(transferHandle), &opFlag,
+                        sizeof(opFlag)));
+    EXPECT_EQ(0,
+              memcmp(request->payload + sizeof(transferHandle) + sizeof(opFlag),
+                     &pldmType, sizeof(pldmType)));
+}
+
+TEST(GetPLDMVersion, testBadEncodeRequest)
+{
+    uint8_t pldmType = 0x03;
+    uint32_t transferHandle = 0x0;
+    uint8_t opFlag = 0x01;
+
+    auto rc =
+        encode_get_version_req(0, transferHandle, opFlag, pldmType, nullptr);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetPLDMVersion, testEncodeResponse)
+{
+    uint8_t completionCode = 0;
+    uint32_t transferHandle = 0;
+    uint8_t flag = PLDM_START_AND_END;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    ver32_t version = {0xFF, 0xFF, 0xFF, 0xFF};
+
+    auto rc = encode_get_version_resp(0, PLDM_SUCCESS, 0, PLDM_START_AND_END,
+                                      &version, sizeof(ver32_t), response);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completionCode, response->payload[0]);
+    EXPECT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]),
+                        &transferHandle, sizeof(transferHandle)));
+    EXPECT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+                            sizeof(transferHandle),
+                        &flag, sizeof(flag)));
+    EXPECT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+                            sizeof(transferHandle) + sizeof(flag),
+                        &version, sizeof(version)));
+}
+
+TEST(GetPLDMVersion, testDecodeRequest)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_VERSION_REQ_BYTES> requestMsg{};
+    uint32_t transferHandle = 0x0;
+    uint32_t retTransferHandle = 0x0;
+    uint8_t flag = PLDM_GET_FIRSTPART;
+    uint8_t retFlag = PLDM_GET_FIRSTPART;
+    uint8_t pldmType = PLDM_BASE;
+    uint8_t retType = PLDM_BASE;
+
+    memcpy(requestMsg.data() + hdrSize, &transferHandle,
+           sizeof(transferHandle));
+    memcpy(requestMsg.data() + sizeof(transferHandle) + hdrSize, &flag,
+           sizeof(flag));
+    memcpy(requestMsg.data() + sizeof(transferHandle) + sizeof(flag) + hdrSize,
+           &pldmType, sizeof(pldmType));
+
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = decode_get_version_req(request, requestMsg.size() - hdrSize,
+                                     &retTransferHandle, &retFlag, &retType);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(transferHandle, retTransferHandle);
+    EXPECT_EQ(flag, retFlag);
+    EXPECT_EQ(pldmType, retType);
+}
+
+TEST(GetPLDMVersion, testDecodeResponse)
+{
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_VERSION_RESP_BYTES>
+        responseMsg{};
+    uint32_t transferHandle = 0x0;
+    uint32_t retTransferHandle = 0x0;
+    uint8_t flag = PLDM_START_AND_END;
+    uint8_t retFlag = PLDM_START_AND_END;
+    uint8_t completionCode = 0;
+    ver32_t version = {0xFF, 0xFF, 0xFF, 0xFF};
+    ver32_t versionOut;
+    uint8_t completion_code;
+
+    memcpy(responseMsg.data() + sizeof(completionCode) + hdrSize,
+           &transferHandle, sizeof(transferHandle));
+    memcpy(responseMsg.data() + sizeof(completionCode) +
+               sizeof(transferHandle) + hdrSize,
+           &flag, sizeof(flag));
+    memcpy(responseMsg.data() + sizeof(completionCode) +
+               sizeof(transferHandle) + sizeof(flag) + hdrSize,
+           &version, sizeof(version));
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_get_version_resp(response, responseMsg.size() - hdrSize,
+                                      &completion_code, &retTransferHandle,
+                                      &retFlag, &versionOut);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(transferHandle, retTransferHandle);
+    EXPECT_EQ(flag, retFlag);
+
+    EXPECT_EQ(versionOut.major, version.major);
+    EXPECT_EQ(versionOut.minor, version.minor);
+    EXPECT_EQ(versionOut.update, version.update);
+    EXPECT_EQ(versionOut.alpha, version.alpha);
+}
+
+TEST(GetTID, testEncodeRequest)
+{
+    pldm_msg request{};
+
+    auto rc = encode_get_tid_req(0, &request);
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+}
+
+TEST(GetTID, testEncodeResponse)
+{
+    uint8_t completionCode = 0;
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_TID_RESP_BYTES>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    uint8_t tid = 1;
+
+    auto rc = encode_get_tid_resp(0, PLDM_SUCCESS, tid, response);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    uint8_t* payload = response->payload;
+    EXPECT_EQ(completionCode, payload[0]);
+    EXPECT_EQ(1, payload[sizeof(completionCode)]);
+}
+
+TEST(GetTID, testDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_TID_RESP_BYTES> responseMsg{};
+    responseMsg[1 + hdrSize] = 1;
+
+    uint8_t tid;
+    uint8_t completion_code;
+    responseMsg[hdrSize] = PLDM_SUCCESS;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_get_tid_resp(response, responseMsg.size() - hdrSize,
+                                  &completion_code, &tid);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completion_code, PLDM_SUCCESS);
+    EXPECT_EQ(tid, 1);
+}
+
+TEST(CcOnlyResponse, testEncode)
+{
+    struct pldm_msg responseMsg;
+
+    auto rc =
+        encode_cc_only_resp(0 /*instance id*/, 1 /*pldm type*/, 2 /*command*/,
+                            3 /*complection code*/, &responseMsg);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    auto p = reinterpret_cast<uint8_t*>(&responseMsg);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + sizeof(responseMsg)),
+                ElementsAreArray({0, 1, 2, 3}));
+
+    rc = encode_cc_only_resp(PLDM_INSTANCE_MAX + 1, 1, 2, 3, &responseMsg);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = encode_cc_only_resp(0, 1, 2, 3, nullptr);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
diff --git a/libpldm/tests/libpldm_bios_table_test.cpp b/libpldm/tests/libpldm_bios_table_test.cpp
new file mode 100644
index 0000000..b4a6022
--- /dev/null
+++ b/libpldm/tests/libpldm_bios_table_test.cpp
@@ -0,0 +1,1111 @@
+#include <endian.h>
+#include <string.h>
+
+#include <cstring>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "libpldm/base.h"
+#include "libpldm/bios.h"
+#include "libpldm/bios_table.h"
+#include "libpldm/utils.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using testing::ElementsAreArray;
+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);
+    uint32_t checksum = crc32(table.data(), table.size());
+    checksum = htole32(checksum);
+    uint8_t a[4];
+    std::memcpy(a, &checksum, sizeof(checksum));
+    table.insert(table.end(), std::begin(a), std::end(a));
+}
+
+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, HeaderDecodeTest)
+{
+    std::vector<uint8_t> enumEntry{
+        2, 0, /* attr handle */
+        0,    /* attr type */
+        1, 0, /* attr name handle (string 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());
+    auto attrHandle = pldm_bios_table_attr_entry_decode_attribute_handle(entry);
+    EXPECT_EQ(attrHandle, 2);
+    auto attrType = pldm_bios_table_attr_entry_decode_attribute_type(entry);
+    EXPECT_EQ(attrType, 0);
+    auto stringHandle = pldm_bios_table_attr_entry_decode_string_handle(entry);
+    EXPECT_EQ(stringHandle, 1);
+}
+
+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 */
+        1     /* 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);
+    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);
+
+    std::vector<uint16_t> pvHandles(pvNumber, 0);
+    pvNumber = pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+        entry, pvHandles.data(), pvHandles.size());
+    EXPECT_EQ(pvNumber, 2);
+    EXPECT_EQ(pvHandles[0], 2);
+    EXPECT_EQ(pvHandles[1], 3);
+    pvHandles.resize(1);
+    pvNumber = pldm_bios_table_attr_entry_enum_decode_pv_hdls(
+        entry, pvHandles.data(), pvHandles.size());
+    EXPECT_EQ(pvNumber, 1);
+    EXPECT_EQ(pvHandles[0], 2);
+
+    pvHandles.resize(2);
+    rc = pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
+        entry, pvHandles.data(), pvHandles.size());
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(pvHandles[0], 2);
+    EXPECT_EQ(pvHandles[1], 3);
+    rc = pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(
+        entry, pvHandles.data(), 1);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    uint8_t defNumber = pldm_bios_table_attr_entry_enum_decode_def_num(entry);
+    EXPECT_EQ(defNumber, 1);
+    std::vector<uint8_t> defIndices(defNumber);
+    rc = pldm_bios_table_attr_entry_enum_decode_def_indices(
+        entry, defIndices.data(), defIndices.size());
+    EXPECT_EQ(rc, defNumber);
+    EXPECT_THAT(defIndices, ElementsAreArray({1}));
+
+    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);
+    rc =
+        pldm_bios_table_attr_entry_enum_decode_pv_hdls_check(entry, nullptr, 0);
+    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{
+        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());
+    auto stringType =
+        pldm_bios_table_attr_entry_string_decode_string_type(entry);
+    EXPECT_EQ(stringType, 1);
+    auto minLength = pldm_bios_table_attr_entry_string_decode_min_length(entry);
+    EXPECT_EQ(minLength, 1);
+    auto maxLength = pldm_bios_table_attr_entry_string_decode_max_length(entry);
+    EXPECT_EQ(maxLength, 100);
+
+    uint16_t defStringLength =
+        pldm_bios_table_attr_entry_string_decode_def_string_length(entry);
+    EXPECT_EQ(defStringLength, 3);
+    std::vector<char> defString(defStringLength + 1);
+    auto rc = pldm_bios_table_attr_entry_string_decode_def_string(
+        entry, defString.data(), defString.size());
+    EXPECT_EQ(rc, 3);
+    EXPECT_STREQ(defString.data(), "abc");
+    rc = pldm_bios_table_attr_entry_string_decode_def_string(
+        entry, defString.data(), defString.size() - 1);
+    EXPECT_EQ(rc, 2);
+    EXPECT_STREQ(defString.data(), "ab");
+
+    defStringLength = 0;
+    rc = pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+        entry, &defStringLength);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(defStringLength, 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, &defStringLength);
+    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, &defStringLength);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = pldm_bios_table_attr_entry_string_decode_def_string_length_check(
+        nullptr, &defStringLength);
+    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);
+    const char* errmsg;
+    rc = pldm_bios_table_attr_entry_string_info_check(&info, &errmsg);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    EXPECT_STREQ(
+        "MinimumStingLength should not be greater than MaximumStringLength",
+        errmsg);
+    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, integerEntryEncodeTest)
+{
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        1,  0,                   /* attr name handle */
+        1,  0, 0, 0, 0, 0, 0, 0, /* lower bound */
+        10, 0, 0, 0, 0, 0, 0, 0, /* upper bound */
+        2,  0, 0, 0,             /* scalar increment */
+        3,  0, 0, 0, 0, 0, 0, 0, /* defaut value */
+    };
+
+    std::vector<uint16_t> pv_hdls{2, 3};
+    std::vector<uint8_t> defs{0};
+
+    struct pldm_bios_table_attr_entry_integer_info info = {
+        1,     /* name handle */
+        false, /* read only */
+        1,     /* lower bound */
+        10,    /* upper bound */
+        2,     /* sacalar increment */
+        3      /* default value */
+    };
+    auto encodeLength = pldm_bios_table_attr_entry_integer_encode_length();
+    EXPECT_EQ(encodeLength, integerEntry.size());
+
+    std::vector<uint8_t> encodeEntry(encodeLength, 0);
+    pldm_bios_table_attr_entry_integer_encode(encodeEntry.data(),
+                                              encodeEntry.size(), &info);
+    // set attr handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(integerEntry, encodeEntry);
+
+    EXPECT_DEATH(pldm_bios_table_attr_entry_integer_encode(
+                     encodeEntry.data(), encodeEntry.size() - 1, &info),
+                 "length <= entry_length");
+
+    auto rc = pldm_bios_table_attr_entry_integer_encode_check(
+        encodeEntry.data(), encodeEntry.size(), &info);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    // set attr handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(integerEntry, encodeEntry);
+
+    rc = pldm_bios_table_attr_entry_integer_encode_check(
+        encodeEntry.data(), encodeEntry.size() - 1, &info);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+    info.lower_bound = 100;
+    info.upper_bound = 50;
+    const char* errmsg;
+    rc = pldm_bios_table_attr_entry_integer_info_check(&info, &errmsg);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    EXPECT_STREQ("LowerBound should not be greater than UpperBound", errmsg);
+    rc = pldm_bios_table_attr_entry_integer_encode_check(
+        encodeEntry.data(), encodeEntry.size(), &info);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(AttrTable, integerEntryDecodeTest)
+{
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        1,  0,                   /* attr name handle */
+        1,  0, 0, 0, 0, 0, 0, 0, /* lower bound */
+        10, 0, 0, 0, 0, 0, 0, 0, /* upper bound */
+        2,  0, 0, 0,             /* scalar increment */
+        3,  0, 0, 0, 0, 0, 0, 0, /* defaut value */
+    };
+
+    uint64_t lower, upper, def;
+    uint32_t scalar;
+    auto entry = reinterpret_cast<struct pldm_bios_attr_table_entry*>(
+        integerEntry.data());
+    pldm_bios_table_attr_entry_integer_decode(entry, &lower, &upper, &scalar,
+                                              &def);
+    EXPECT_EQ(lower, 1);
+    EXPECT_EQ(upper, 10);
+    EXPECT_EQ(scalar, 2);
+    EXPECT_EQ(def, 3);
+}
+
+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  */
+    };
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        1,  0,                   /* attr name handle */
+        1,  0, 0, 0, 0, 0, 0, 0, /* lower bound */
+        10, 0, 0, 0, 0, 0, 0, 0, /* upper bound */
+        2,  0, 0, 0,             /* scalar increment */
+        3,  0, 0, 0, 0, 0, 0, 0, /* defaut value */
+    };
+
+    Table table;
+    buildTable(table, enumEntry, stringEntry, integerEntry, 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, integerEntry.data(), integerEntry.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(AttrTable, FindTest)
+{
+    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  */
+    };
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        1,  0,                   /* attr name handle */
+        1,  0, 0, 0, 0, 0, 0, 0, /* lower bound */
+        10, 0, 0, 0, 0, 0, 0, 0, /* upper bound */
+        2,  0, 0, 0,             /* scalar increment */
+        3,  0, 0, 0, 0, 0, 0, 0, /* defaut value */
+    };
+
+    Table table;
+    buildTable(table, enumEntry, stringEntry, integerEntry, enumEntry);
+
+    auto entry =
+        pldm_bios_table_attr_find_by_handle(table.data(), table.size(), 1);
+    EXPECT_NE(entry, nullptr);
+    auto p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + stringEntry.size()),
+                ElementsAreArray(stringEntry));
+
+    entry = pldm_bios_table_attr_find_by_handle(table.data(), table.size(), 3);
+    EXPECT_EQ(entry, nullptr);
+}
+
+TEST(AttrValTable, HeaderDecodeTest)
+{
+    std::vector<uint8_t> enumEntry{
+        1, 0, /* attr handle */
+        0,    /* attr type */
+        2,    /* number of current value */
+        0,    /* current value string handle index */
+        1,    /* current value string handle index */
+    };
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        enumEntry.data());
+    auto attrHandle =
+        pldm_bios_table_attr_value_entry_decode_attribute_handle(entry);
+    EXPECT_EQ(attrHandle, 1);
+    auto attrType =
+        pldm_bios_table_attr_value_entry_decode_attribute_type(entry);
+    EXPECT_EQ(attrType, 0);
+}
+
+TEST(AttrValTable, EnumEntryEncodeTest)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        2,    /* number of current value */
+        0,    /* current value string handle index */
+        1,    /* current value string handle index */
+    };
+
+    auto length = pldm_bios_table_attr_value_entry_encode_enum_length(2);
+    EXPECT_EQ(length, enumEntry.size());
+    std::vector<uint8_t> encodeEntry(length, 0);
+    uint8_t handles[] = {0, 1};
+    pldm_bios_table_attr_value_entry_encode_enum(
+        encodeEntry.data(), encodeEntry.size(), 0, 0, 2, handles);
+    EXPECT_EQ(encodeEntry, enumEntry);
+
+    EXPECT_DEATH(
+        pldm_bios_table_attr_value_entry_encode_enum(
+            encodeEntry.data(), encodeEntry.size() - 1, 0, 0, 2, handles),
+        "length <= entry_length");
+
+    auto rc = pldm_bios_table_attr_value_entry_encode_enum_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_ENUMERATION, 2,
+        handles);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(encodeEntry, enumEntry);
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        enumEntry.data());
+    entry->attr_type = PLDM_BIOS_ENUMERATION_READ_ONLY;
+    rc = pldm_bios_table_attr_value_entry_encode_enum_check(
+        encodeEntry.data(), encodeEntry.size(), 0,
+        PLDM_BIOS_ENUMERATION_READ_ONLY, 2, handles);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(encodeEntry, enumEntry);
+    rc = pldm_bios_table_attr_value_entry_encode_enum_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_PASSWORD, 2,
+        handles);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = pldm_bios_table_attr_value_entry_encode_enum_check(
+        encodeEntry.data(), encodeEntry.size() - 1, 0, PLDM_BIOS_ENUMERATION, 2,
+        handles);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(AttrValTable, EnumEntryDecodeTest)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        2,    /* number of current value */
+        0,    /* current value string handle index */
+        1,    /* current value string handle index */
+    };
+
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        enumEntry.data());
+    auto number = pldm_bios_table_attr_value_entry_enum_decode_number(entry);
+    EXPECT_EQ(2, number);
+
+    std::vector<uint8_t> handles(2, 0);
+    auto rc = pldm_bios_table_attr_value_entry_enum_decode_handles(
+        entry, handles.data(), handles.size());
+    EXPECT_EQ(rc, 2);
+    EXPECT_EQ(handles[0], 0);
+    EXPECT_EQ(handles[1], 1);
+}
+
+TEST(AttrValTable, stringEntryEncodeTest)
+{
+    std::vector<uint8_t> stringEntry{
+        0,   0,        /* attr handle */
+        1,             /* attr type */
+        3,   0,        /* current string length */
+        'a', 'b', 'c', /* defaut value string handle index */
+    };
+
+    auto length = pldm_bios_table_attr_value_entry_encode_string_length(3);
+    EXPECT_EQ(length, stringEntry.size());
+    std::vector<uint8_t> encodeEntry(length, 0);
+    pldm_bios_table_attr_value_entry_encode_string(
+        encodeEntry.data(), encodeEntry.size(), 0, 1, 3, "abc");
+    EXPECT_EQ(encodeEntry, stringEntry);
+
+    EXPECT_DEATH(
+        pldm_bios_table_attr_value_entry_encode_string(
+            encodeEntry.data(), encodeEntry.size() - 1, 0, 1, 3, "abc"),
+        "length <= entry_length");
+
+    auto rc = pldm_bios_table_attr_value_entry_encode_string_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_STRING, 3, "abc");
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(encodeEntry, stringEntry);
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        stringEntry.data());
+    entry->attr_type = PLDM_BIOS_STRING_READ_ONLY;
+    rc = pldm_bios_table_attr_value_entry_encode_string_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_STRING_READ_ONLY,
+        3, "abc");
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(encodeEntry, stringEntry);
+    rc = pldm_bios_table_attr_value_entry_encode_string_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_PASSWORD, 3,
+        "abc");
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = pldm_bios_table_attr_value_entry_encode_string_check(
+        encodeEntry.data(), encodeEntry.size() - 1, 0, PLDM_BIOS_STRING, 3,
+        "abc");
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(AttrValTable, StringEntryDecodeTest)
+{
+    std::vector<uint8_t> stringEntry{
+        0,   0,        /* attr handle */
+        1,             /* attr type */
+        3,   0,        /* current string length */
+        'a', 'b', 'c', /* defaut value string handle index */
+    };
+
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        stringEntry.data());
+    auto length = pldm_bios_table_attr_value_entry_string_decode_length(entry);
+    EXPECT_EQ(3, length);
+
+    auto handle = pldm_bios_table_attr_value_entry_decode_handle(entry);
+    EXPECT_EQ(0, handle);
+
+    auto entryLength = pldm_bios_table_attr_value_entry_length(entry);
+    EXPECT_EQ(stringEntry.size(), entryLength);
+
+    variable_field currentString{};
+    pldm_bios_table_attr_value_entry_string_decode_string(entry,
+                                                          &currentString);
+    EXPECT_THAT(std::vector<uint8_t>(currentString.ptr,
+                                     currentString.ptr + currentString.length),
+                ElementsAreArray(std::vector<uint8_t>{'a', 'b', 'c'}));
+}
+
+TEST(AttrValTable, integerEntryEncodeTest)
+{
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        10, 0, 0, 0, 0, 0, 0, 0, /* current value */
+    };
+
+    auto length = pldm_bios_table_attr_value_entry_encode_integer_length();
+    EXPECT_EQ(length, integerEntry.size());
+    std::vector<uint8_t> encodeEntry(length, 0);
+    pldm_bios_table_attr_value_entry_encode_integer(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_INTEGER, 10);
+    EXPECT_EQ(encodeEntry, integerEntry);
+
+    EXPECT_DEATH(pldm_bios_table_attr_value_entry_encode_integer(
+                     encodeEntry.data(), encodeEntry.size() - 1, 0,
+                     PLDM_BIOS_INTEGER, 10),
+                 "length <= entry_length");
+
+    auto rc = pldm_bios_table_attr_value_entry_encode_integer_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_INTEGER, 10);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(encodeEntry, integerEntry);
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        integerEntry.data());
+    entry->attr_type = PLDM_BIOS_INTEGER_READ_ONLY;
+    rc = pldm_bios_table_attr_value_entry_encode_integer_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_INTEGER_READ_ONLY,
+        10);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(encodeEntry, integerEntry);
+
+    rc = pldm_bios_table_attr_value_entry_encode_integer_check(
+        encodeEntry.data(), encodeEntry.size(), 0, PLDM_BIOS_PASSWORD, 10);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = pldm_bios_table_attr_value_entry_encode_integer_check(
+        encodeEntry.data(), encodeEntry.size() - 1, 0,
+        PLDM_BIOS_INTEGER_READ_ONLY, 10);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(AttrValTable, integerEntryDecodeTest)
+{
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        10, 0, 0, 0, 0, 0, 0, 0, /* current value */
+    };
+
+    auto entry = reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(
+        integerEntry.data());
+    auto cv = pldm_bios_table_attr_value_entry_integer_decode_cv(entry);
+    EXPECT_EQ(cv, 10);
+}
+
+TEST(AttrValTable, IteratorTest)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        2,    /* number of current value */
+        0,    /* current value string handle index */
+        1,    /* current value string handle index */
+    };
+    std::vector<uint8_t> stringEntry{
+        0,   0,        /* attr handle */
+        1,             /* attr type */
+        3,   0,        /* current string length */
+        'a', 'b', 'c', /* defaut value string handle index */
+    };
+    std::vector<uint8_t> integerEntry{
+        0,  0,                   /* attr handle */
+        3,                       /* attr type */
+        10, 0, 0, 0, 0, 0, 0, 0, /* current value */
+    };
+
+    Table table;
+    buildTable(table, enumEntry, stringEntry, integerEntry, enumEntry);
+
+    auto iter = pldm_bios_table_iter_create(table.data(), table.size(),
+                                            PLDM_BIOS_ATTR_VAL_TABLE);
+    auto entry = pldm_bios_table_iter_attr_value_entry_value(iter);
+
+    auto p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + enumEntry.size()),
+                ElementsAreArray(enumEntry));
+
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_attr_value_entry_value(iter);
+    p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + stringEntry.size()),
+                ElementsAreArray(stringEntry));
+
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_attr_value_entry_value(iter);
+    p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + integerEntry.size()),
+                ElementsAreArray(integerEntry));
+
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_attr_value_entry_value(iter);
+    p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + enumEntry.size()),
+                ElementsAreArray(enumEntry));
+
+    pldm_bios_table_iter_next(iter);
+    EXPECT_TRUE(pldm_bios_table_iter_is_end(iter));
+
+    pldm_bios_table_iter_free(iter);
+}
+
+TEST(AttrValTable, FindTest)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        2,    /* number of current value */
+        0,    /* current value string handle index */
+        1,    /* current value string handle index */
+    };
+    std::vector<uint8_t> stringEntry{
+        1,   0,        /* attr handle */
+        1,             /* attr type */
+        3,   0,        /* current string length */
+        'a', 'b', 'c', /* defaut value string handle index */
+    };
+    std::vector<uint8_t> integerEntry{
+        2,  0,                   /* attr handle */
+        3,                       /* attr type */
+        10, 0, 0, 0, 0, 0, 0, 0, /* current value */
+    };
+
+    Table table;
+    buildTable(table, enumEntry, stringEntry, integerEntry);
+
+    auto entry = pldm_bios_table_attr_value_find_by_handle(table.data(),
+                                                           table.size(), 1);
+    EXPECT_NE(entry, nullptr);
+    auto p = reinterpret_cast<const uint8_t*>(entry);
+    EXPECT_THAT(std::vector<uint8_t>(p, p + stringEntry.size()),
+                ElementsAreArray(stringEntry));
+
+    entry = pldm_bios_table_attr_value_find_by_handle(table.data(),
+                                                      table.size(), 3);
+    EXPECT_EQ(entry, nullptr);
+
+    auto firstEntry =
+        reinterpret_cast<struct pldm_bios_attr_val_table_entry*>(table.data());
+    firstEntry->attr_type = PLDM_BIOS_PASSWORD;
+    EXPECT_DEATH(pldm_bios_table_attr_value_find_by_handle(table.data(),
+                                                           table.size(), 1),
+                 "entry_length != NULL");
+}
+
+TEST(AttrValTable, CopyAndUpdateTest)
+{
+    std::vector<uint8_t> enumEntry{
+        0, 0, /* attr handle */
+        0,    /* attr type */
+        2,    /* number of current value */
+        0,    /* current value string handle index */
+        1,    /* current value string handle index */
+    };
+    std::vector<uint8_t> stringEntry{
+        1,   0,        /* attr handle */
+        1,             /* attr type */
+        3,   0,        /* current string length */
+        'a', 'b', 'c', /* defaut value string handle index */
+    };
+    std::vector<uint8_t> integerEntry{
+        2,  0,                   /* attr handle */
+        3,                       /* attr type */
+        10, 0, 0, 0, 0, 0, 0, 0, /* current value */
+    };
+
+    Table srcTable;
+    buildTable(srcTable, enumEntry, stringEntry, integerEntry);
+
+    std::vector<uint8_t> stringEntry1{
+        1,   0,        /* attr handle */
+        1,             /* attr type */
+        3,   0,        /* current string length */
+        'd', 'e', 'f', /* defaut value string handle index */
+    };
+
+    Table expectTable;
+    buildTable(expectTable, enumEntry, stringEntry1, integerEntry);
+    Table destTable(expectTable.size() + 10);
+    auto destLength = destTable.size();
+    auto rc = pldm_bios_table_attr_value_copy_and_update(
+        srcTable.data(), srcTable.size(), destTable.data(), &destLength,
+        stringEntry1.data(), stringEntry1.size());
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(destLength, expectTable.size());
+    destTable.resize(destLength);
+    EXPECT_THAT(destTable, ElementsAreArray(expectTable));
+
+    std::vector<uint8_t> stringEntry2{
+        1,   0,                  /* attr handle */
+        1,                       /* attr type */
+        5,   0,                  /* current string length */
+        'd', 'e', 'f', 'a', 'b', /* defaut value string handle index */
+    };
+    expectTable.resize(0);
+    buildTable(expectTable, enumEntry, stringEntry2, integerEntry);
+    destTable.resize(expectTable.size() + 10);
+    destLength = destTable.size();
+    rc = pldm_bios_table_attr_value_copy_and_update(
+        srcTable.data(), srcTable.size(), destTable.data(), &destLength,
+        stringEntry2.data(), stringEntry2.size());
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(destLength, expectTable.size());
+    destTable.resize(destLength);
+    EXPECT_THAT(destTable, ElementsAreArray(expectTable));
+
+    std::vector<uint8_t> stringEntry3{
+        1,   0, /* attr handle */
+        1,      /* attr type */
+        1,   0, /* current string length */
+        'd',    /* defaut value string handle index */
+    };
+    expectTable.resize(0);
+    buildTable(expectTable, enumEntry, stringEntry3, integerEntry);
+    destTable.resize(expectTable.size() + 10);
+    destLength = destTable.size();
+    rc = pldm_bios_table_attr_value_copy_and_update(
+        srcTable.data(), srcTable.size(), destTable.data(), &destLength,
+        stringEntry3.data(), stringEntry3.size());
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(destLength, expectTable.size());
+    destTable.resize(destLength);
+    EXPECT_THAT(destTable, ElementsAreArray(expectTable));
+
+    stringEntry3[2] = PLDM_BIOS_INTEGER; // set attribute type to integer
+    rc = pldm_bios_table_attr_value_copy_and_update(
+        srcTable.data(), srcTable.size(), destTable.data(), &destLength,
+        stringEntry3.data(), stringEntry3.size());
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    stringEntry3[2] = PLDM_BIOS_STRING; // set attribute type to string
+
+    destTable.resize(expectTable.size() - 1);
+    destLength = destTable.size();
+    rc = pldm_bios_table_attr_value_copy_and_update(
+        srcTable.data(), srcTable.size(), destTable.data(), &destLength,
+        stringEntry3.data(), stringEntry3.size());
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(StringTable, EntryEncodeTest)
+{
+    std::vector<uint8_t> stringEntry{
+        0,   0,                            /* string handle*/
+        7,   0,                            /* string length */
+        'A', 'l', 'l', 'o', 'w', 'e', 'd', /* string */
+    };
+
+    const char* str = "Allowed";
+    auto str_length = std::strlen(str);
+    auto encodeLength = pldm_bios_table_string_entry_encode_length(str_length);
+    EXPECT_EQ(encodeLength, stringEntry.size());
+
+    std::vector<uint8_t> encodeEntry(encodeLength, 0);
+    pldm_bios_table_string_entry_encode(encodeEntry.data(), encodeEntry.size(),
+                                        str, str_length);
+    // set string handle = 0
+    encodeEntry[0] = 0;
+    encodeEntry[1] = 0;
+
+    EXPECT_EQ(stringEntry, encodeEntry);
+
+    EXPECT_DEATH(pldm_bios_table_string_entry_encode(encodeEntry.data(),
+                                                     encodeEntry.size() - 1,
+                                                     str, str_length),
+                 "length <= entry_length");
+    auto rc = pldm_bios_table_string_entry_encode_check(
+        encodeEntry.data(), encodeEntry.size() - 1, str, str_length);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(StringTable, EntryDecodeTest)
+{
+    std::vector<uint8_t> stringEntry{
+        4,   0,                            /* string handle*/
+        7,   0,                            /* string length */
+        'A', 'l', 'l', 'o', 'w', 'e', 'd', /* string */
+    };
+    auto entry = reinterpret_cast<struct pldm_bios_string_table_entry*>(
+        stringEntry.data());
+    auto handle = pldm_bios_table_string_entry_decode_handle(entry);
+    EXPECT_EQ(handle, 4);
+    auto strLength = pldm_bios_table_string_entry_decode_string_length(entry);
+    EXPECT_EQ(strLength, 7);
+
+    std::vector<char> buffer(strLength + 1, 0);
+    auto decodedLength = pldm_bios_table_string_entry_decode_string(
+        entry, buffer.data(), buffer.size());
+    EXPECT_EQ(decodedLength, strLength);
+    EXPECT_EQ(std::strcmp("Allowed", buffer.data()), 0);
+    decodedLength = pldm_bios_table_string_entry_decode_string(
+        entry, buffer.data(), 2 + 1 /* sizeof '\0'*/);
+    EXPECT_EQ(decodedLength, 2);
+    EXPECT_EQ(std::strcmp("Al", buffer.data()), 0);
+
+    auto rc = pldm_bios_table_string_entry_decode_string_check(
+        entry, buffer.data(), buffer.size());
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(std::strcmp("Allowed", buffer.data()), 0);
+
+    rc = pldm_bios_table_string_entry_decode_string_check(entry, buffer.data(),
+                                                          buffer.size() - 1);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(StringTable, IteratorTest)
+{
+    std::vector<uint8_t> stringHello{
+        0,   0,                  /* string handle*/
+        5,   0,                  /* string length */
+        'H', 'e', 'l', 'l', 'o', /* string */
+    };
+    std::vector<uint8_t> stringWorld{
+        1,   0,                       /* string handle*/
+        6,   0,                       /* string length */
+        'W', 'o', 'r', 'l', 'd', '!', /* string */
+    };
+
+    Table table;
+    buildTable(table, stringHello, stringWorld);
+
+    auto iter = pldm_bios_table_iter_create(table.data(), table.size(),
+                                            PLDM_BIOS_STRING_TABLE);
+    auto entry = pldm_bios_table_iter_string_entry_value(iter);
+    auto rc = std::memcmp(entry, stringHello.data(), stringHello.size());
+    EXPECT_EQ(rc, 0);
+    pldm_bios_table_iter_next(iter);
+    entry = pldm_bios_table_iter_string_entry_value(iter);
+    rc = std::memcmp(entry, stringWorld.data(), stringWorld.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(StringTable, FindTest)
+{
+    std::vector<uint8_t> stringHello{
+        1,   0,                  /* string handle*/
+        5,   0,                  /* string length */
+        'H', 'e', 'l', 'l', 'o', /* string */
+    };
+    std::vector<uint8_t> stringWorld{
+        2,   0,                       /* string handle*/
+        6,   0,                       /* string length */
+        'W', 'o', 'r', 'l', 'd', '!', /* string */
+    };
+    std::vector<uint8_t> stringHi{
+        3,   0,   /* string handle*/
+        2,   0,   /* string length */
+        'H', 'i', /* string */
+    };
+
+    Table table;
+    buildTable(table, stringHello, stringWorld, stringHi);
+
+    auto entry = pldm_bios_table_string_find_by_string(table.data(),
+                                                       table.size(), "World!");
+    EXPECT_NE(entry, nullptr);
+    auto handle = pldm_bios_table_string_entry_decode_handle(entry);
+    EXPECT_EQ(handle, 2);
+
+    entry = pldm_bios_table_string_find_by_string(table.data(), table.size(),
+                                                  "Worl");
+    EXPECT_EQ(entry, nullptr);
+
+    entry =
+        pldm_bios_table_string_find_by_handle(table.data(), table.size(), 3);
+    EXPECT_NE(entry, nullptr);
+    auto str_length = pldm_bios_table_string_entry_decode_string_length(entry);
+    EXPECT_EQ(str_length, 2);
+    std::vector<char> strBuf(str_length + 1, 0);
+    auto rc = pldm_bios_table_string_entry_decode_string_check(
+        entry, strBuf.data(), strBuf.size());
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(std::strcmp("Hi", strBuf.data()), 0);
+
+    entry =
+        pldm_bios_table_string_find_by_handle(table.data(), table.size(), 4);
+    EXPECT_EQ(entry, nullptr);
+}
+
+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");
+    pldm_bios_table_iter_free(iter);
+}
+
+TEST(PadAndChecksum, PadAndChecksum)
+{
+    EXPECT_EQ(4, pldm_bios_table_pad_checksum_size(0));
+    EXPECT_EQ(7, pldm_bios_table_pad_checksum_size(1));
+    EXPECT_EQ(6, pldm_bios_table_pad_checksum_size(2));
+    EXPECT_EQ(5, pldm_bios_table_pad_checksum_size(3));
+    EXPECT_EQ(4, pldm_bios_table_pad_checksum_size(4));
+
+    // The table is borrowed from
+    // https://github.com/openbmc/pldm/commit/69d3e7fb2d9935773f4fbf44326c33f3fc0a3c38
+    // refer to the commit message
+    Table attrValTable = {0x09, 0x00, 0x01, 0x02, 0x00, 0x65, 0x66};
+    auto sizeWithoutPad = attrValTable.size();
+    attrValTable.resize(sizeWithoutPad +
+                        pldm_bios_table_pad_checksum_size(sizeWithoutPad));
+    pldm_bios_table_append_pad_checksum(attrValTable.data(),
+                                        attrValTable.size(), sizeWithoutPad);
+    Table expectedTable = {0x09, 0x00, 0x01, 0x02, 0x00, 0x65,
+                           0x66, 0x00, 0x6d, 0x81, 0x4a, 0xb6};
+    EXPECT_EQ(attrValTable, expectedTable);
+}
diff --git a/libpldm/tests/libpldm_bios_test.cpp b/libpldm/tests/libpldm_bios_test.cpp
new file mode 100644
index 0000000..ad07877
--- /dev/null
+++ b/libpldm/tests/libpldm_bios_test.cpp
@@ -0,0 +1,821 @@
+#include <string.h>
+
+#include <array>
+
+#include "libpldm/base.h"
+#include "libpldm/bios.h"
+#include "libpldm/utils.h"
+
+#include <gtest/gtest.h>
+
+constexpr auto hdrSize = sizeof(pldm_msg_hdr);
+
+TEST(GetDateTime, testEncodeRequest)
+{
+    pldm_msg request{};
+
+    auto rc = encode_get_date_time_req(0, &request);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+}
+
+TEST(GetDateTime, testEncodeResponse)
+{
+    uint8_t completionCode = 0;
+    uint8_t seconds = 50;
+    uint8_t minutes = 20;
+    uint8_t hours = 5;
+    uint8_t day = 23;
+    uint8_t month = 11;
+    uint16_t year = 2019;
+
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_DATE_TIME_RESP_BYTES>
+        responseMsg{};
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = encode_get_date_time_resp(0, PLDM_SUCCESS, seconds, minutes,
+                                        hours, day, month, year, response);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completionCode, response->payload[0]);
+
+    EXPECT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]),
+                        &seconds, sizeof(seconds)));
+    EXPECT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+                            sizeof(seconds),
+                        &minutes, sizeof(minutes)));
+    EXPECT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+                            sizeof(seconds) + sizeof(minutes),
+                        &hours, sizeof(hours)));
+    EXPECT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+                            sizeof(seconds) + sizeof(minutes) + sizeof(hours),
+                        &day, sizeof(day)));
+    EXPECT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+                            sizeof(seconds) + sizeof(minutes) + sizeof(hours) +
+                            sizeof(day),
+                        &month, sizeof(month)));
+    EXPECT_EQ(0, memcmp(response->payload + sizeof(response->payload[0]) +
+                            sizeof(seconds) + sizeof(minutes) + sizeof(hours) +
+                            sizeof(day) + sizeof(month),
+                        &year, sizeof(year)));
+}
+
+TEST(GetDateTime, testDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_DATE_TIME_RESP_BYTES> responseMsg{};
+
+    uint8_t completionCode = 0;
+
+    uint8_t seconds = 55;
+    uint8_t minutes = 2;
+    uint8_t hours = 8;
+    uint8_t day = 9;
+    uint8_t month = 7;
+    uint16_t year = 2020;
+
+    uint8_t retSeconds = 0;
+    uint8_t retMinutes = 0;
+    uint8_t retHours = 0;
+    uint8_t retDay = 0;
+    uint8_t retMonth = 0;
+    uint16_t retYear = 0;
+
+    memcpy(responseMsg.data() + sizeof(completionCode) + hdrSize, &seconds,
+           sizeof(seconds));
+    memcpy(responseMsg.data() + sizeof(completionCode) + sizeof(seconds) +
+               hdrSize,
+           &minutes, sizeof(minutes));
+    memcpy(responseMsg.data() + sizeof(completionCode) + sizeof(seconds) +
+               sizeof(minutes) + hdrSize,
+           &hours, sizeof(hours));
+    memcpy(responseMsg.data() + sizeof(completionCode) + sizeof(seconds) +
+               sizeof(minutes) + sizeof(hours) + hdrSize,
+           &day, sizeof(day));
+    memcpy(responseMsg.data() + sizeof(completionCode) + sizeof(seconds) +
+               sizeof(minutes) + sizeof(hours) + sizeof(day) + hdrSize,
+           &month, sizeof(month));
+    memcpy(responseMsg.data() + sizeof(completionCode) + sizeof(seconds) +
+               sizeof(minutes) + sizeof(hours) + sizeof(day) + sizeof(month) +
+               hdrSize,
+           &year, sizeof(year));
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_get_date_time_resp(
+        response, responseMsg.size() - hdrSize, &completionCode, &retSeconds,
+        &retMinutes, &retHours, &retDay, &retMonth, &retYear);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(seconds, retSeconds);
+    EXPECT_EQ(minutes, retMinutes);
+    EXPECT_EQ(hours, retHours);
+    EXPECT_EQ(day, retDay);
+    EXPECT_EQ(month, retMonth);
+    EXPECT_EQ(year, retYear);
+}
+
+TEST(SetDateTime, testGoodEncodeResponse)
+{
+    uint8_t instanceId = 0;
+    uint8_t completionCode = PLDM_SUCCESS;
+
+    std::array<uint8_t, hdrSize + sizeof(struct pldm_only_cc_resp)>
+        responseMsg{};
+    struct pldm_msg* response =
+        reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+
+    auto rc = encode_set_date_time_resp(instanceId, completionCode, response,
+                                        responseMsg.size() - hdrSize);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_only_cc_resp* resp =
+        reinterpret_cast<struct pldm_only_cc_resp*>(response->payload);
+    EXPECT_EQ(completionCode, resp->completion_code);
+}
+
+TEST(SetDateTime, testBadEncodeResponse)
+{
+
+    uint8_t instanceId = 10;
+    uint8_t completionCode = PLDM_SUCCESS;
+    std::array<uint8_t, hdrSize + sizeof(struct pldm_only_cc_resp)>
+        responseMsg{};
+    struct pldm_msg* response =
+        reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+    auto rc = encode_set_date_time_resp(instanceId, completionCode, nullptr,
+                                        responseMsg.size() - hdrSize);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = encode_set_date_time_resp(instanceId, completionCode, response,
+                                   responseMsg.size() - hdrSize - 1);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(SetDateTime, testGoodDecodeResponse)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    std::array<uint8_t, hdrSize + sizeof(struct pldm_only_cc_resp)>
+        responseMsg{};
+    struct pldm_msg* response =
+        reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+    struct pldm_only_cc_resp* resp =
+        reinterpret_cast<struct pldm_only_cc_resp*>(response->payload);
+
+    resp->completion_code = completionCode;
+
+    uint8_t retCompletionCode;
+    auto rc = decode_set_date_time_resp(response, responseMsg.size() - hdrSize,
+                                        &retCompletionCode);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completionCode, retCompletionCode);
+}
+
+TEST(SetDateTime, testBadDecodeResponse)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+
+    std::array<uint8_t, hdrSize + sizeof(struct pldm_only_cc_resp)>
+        responseMsg{};
+    struct pldm_msg* response =
+        reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+    auto rc = decode_set_date_time_resp(nullptr, responseMsg.size() - hdrSize,
+                                        &completionCode);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_set_date_time_resp(response, responseMsg.size() - hdrSize - 1,
+                                   &completionCode);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(SetDateTime, testGoodEncodeRequset)
+{
+    uint8_t instanceId = 0;
+    uint8_t seconds = 50;
+    uint8_t minutes = 20;
+    uint8_t hours = 10;
+    uint8_t day = 11;
+    uint8_t month = 11;
+    uint16_t year = 2019;
+
+    std::array<uint8_t, hdrSize + sizeof(struct pldm_set_date_time_req)>
+        requestMsg{};
+
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto rc = encode_set_date_time_req(instanceId, seconds, minutes, hours, day,
+                                       month, year, request,
+                                       requestMsg.size() - hdrSize);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_set_date_time_req* req =
+        reinterpret_cast<struct pldm_set_date_time_req*>(request->payload);
+    EXPECT_EQ(seconds, bcd2dec8(req->seconds));
+    EXPECT_EQ(minutes, bcd2dec8(req->minutes));
+    EXPECT_EQ(hours, bcd2dec8(req->hours));
+    EXPECT_EQ(day, bcd2dec8(req->day));
+    EXPECT_EQ(month, bcd2dec8(req->month));
+    EXPECT_EQ(year, le16toh(bcd2dec16(req->year)));
+}
+
+TEST(SetDateTime, testBadEncodeRequset)
+{
+    uint8_t instanceId = 0;
+
+    uint8_t seconds = 50;
+    uint8_t minutes = 20;
+    uint8_t hours = 10;
+    uint8_t day = 13;
+    uint8_t month = 11;
+    uint16_t year = 2019;
+
+    uint8_t erday = 43;
+
+    std::array<uint8_t, hdrSize + sizeof(struct pldm_set_date_time_req)>
+        requestMsg{};
+
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = encode_set_date_time_req(instanceId, seconds, minutes, hours, day,
+                                       month, year, nullptr,
+                                       requestMsg.size() - hdrSize);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = encode_set_date_time_req(instanceId, seconds, minutes, hours, erday,
+                                  month, year, request,
+                                  requestMsg.size() - hdrSize);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = encode_set_date_time_req(instanceId, seconds, minutes, hours, day,
+                                  month, year, request,
+                                  requestMsg.size() - hdrSize - 4);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(SetDateTime, testGoodDecodeRequest)
+{
+    std::array<uint8_t, hdrSize + sizeof(struct pldm_set_date_time_req)>
+        requestMsg{};
+    uint8_t seconds = 0x50;
+    uint8_t minutes = 0x20;
+    uint8_t hours = 0x10;
+    uint8_t day = 0x11;
+    uint8_t month = 0x11;
+    uint16_t year = 0x2019;
+
+    auto request = reinterpret_cast<struct pldm_msg*>(requestMsg.data());
+    struct pldm_set_date_time_req* req =
+        reinterpret_cast<struct pldm_set_date_time_req*>(request->payload);
+    req->seconds = seconds;
+    req->minutes = minutes;
+    req->hours = hours;
+    req->day = day;
+    req->month = month;
+    req->year = htole16(year);
+
+    uint8_t retseconds;
+    uint8_t retminutes;
+    uint8_t rethours;
+    uint8_t retday;
+    uint8_t retmonth;
+    uint16_t retyear;
+
+    auto rc = decode_set_date_time_req(request, requestMsg.size() - hdrSize,
+                                       &retseconds, &retminutes, &rethours,
+                                       &retday, &retmonth, &retyear);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retseconds, 50);
+    EXPECT_EQ(retminutes, 20);
+    EXPECT_EQ(rethours, 10);
+    EXPECT_EQ(retday, 11);
+    EXPECT_EQ(retmonth, 11);
+    EXPECT_EQ(retyear, 2019);
+}
+
+TEST(SetDateTime, testBadDecodeRequest)
+{
+    uint8_t seconds = 0x50;
+    uint8_t minutes = 0x20;
+    uint8_t hours = 0x10;
+    uint8_t day = 0x11;
+    uint8_t month = 0x11;
+    uint16_t year = 0x2019;
+
+    std::array<uint8_t, hdrSize + sizeof(struct pldm_set_date_time_req)>
+        requestMsg{};
+
+    auto request = reinterpret_cast<struct pldm_msg*>(requestMsg.data());
+
+    decode_set_date_time_req(request, requestMsg.size() - hdrSize, &seconds,
+                             &minutes, &hours, &day, &month, &year);
+
+    auto rc =
+        decode_set_date_time_req(nullptr, requestMsg.size() - hdrSize, &seconds,
+                                 &minutes, &hours, &day, &month, &year);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_set_date_time_req(request, requestMsg.size() - hdrSize, nullptr,
+                                  nullptr, nullptr, nullptr, nullptr, nullptr);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_set_date_time_req(request, requestMsg.size() - hdrSize - 4,
+                                  &seconds, &minutes, &hours, &day, &month,
+                                  &year);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetBIOSTable, testGoodEncodeResponse)
+{
+    std::array<uint8_t,
+               sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 4>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint32_t nextTransferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    std::array<uint8_t, 4> tableData{1, 2, 3, 4};
+
+    auto rc = encode_get_bios_table_resp(
+        0, PLDM_SUCCESS, nextTransferHandle, transferFlag, tableData.data(),
+        sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 4,
+        response);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_get_bios_table_resp* resp =
+        reinterpret_cast<struct pldm_get_bios_table_resp*>(response->payload);
+
+    EXPECT_EQ(completionCode, resp->completion_code);
+    EXPECT_EQ(nextTransferHandle, resp->next_transfer_handle);
+    EXPECT_EQ(transferFlag, resp->transfer_flag);
+    EXPECT_EQ(0, memcmp(tableData.data(), resp->table_data, tableData.size()));
+}
+
+TEST(GetBIOSTable, testBadEncodeResponse)
+{
+    uint32_t nextTransferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    std::array<uint8_t, 4> tableData{1, 2, 3, 4};
+
+    auto rc = encode_get_bios_table_resp(
+        0, PLDM_SUCCESS, nextTransferHandle, transferFlag, tableData.data(),
+        sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES + 4, nullptr);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetBIOSTable, testGoodEncodeRequest)
+{
+    std::array<uint8_t, sizeof(pldm_msg_hdr) + PLDM_GET_BIOS_TABLE_REQ_BYTES>
+        requestMsg{};
+    uint32_t transferHandle = 0x0;
+    uint8_t transferOpFlag = 0x01;
+    uint8_t tableType = PLDM_BIOS_ATTR_TABLE;
+
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto rc = encode_get_bios_table_req(0, transferHandle, transferOpFlag,
+                                        tableType, request);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_get_bios_table_req* req =
+        reinterpret_cast<struct pldm_get_bios_table_req*>(request->payload);
+    EXPECT_EQ(transferHandle, le32toh(req->transfer_handle));
+    EXPECT_EQ(transferOpFlag, req->transfer_op_flag);
+    EXPECT_EQ(tableType, req->table_type);
+}
+
+TEST(GetBIOSTable, testBadEncodeRequest)
+{
+    uint32_t transferHandle = 0x0;
+    uint8_t transferOpFlag = 0x01;
+    uint8_t tableType = PLDM_BIOS_ATTR_TABLE;
+
+    auto rc = encode_get_bios_table_req(0, transferHandle, transferOpFlag,
+                                        tableType, nullptr);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetBIOSTable, testGoodDecodeRequest)
+{
+    const auto hdr_size = sizeof(pldm_msg_hdr);
+    std::array<uint8_t, hdr_size + PLDM_GET_BIOS_TABLE_REQ_BYTES> requestMsg{};
+    uint32_t transferHandle = 31;
+    uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+    uint8_t tableType = PLDM_BIOS_ATTR_TABLE;
+    uint32_t retTransferHandle = 0;
+    uint8_t retTransferOpFlag = 0;
+    uint8_t retTableType = 0;
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_get_bios_table_req* request =
+        reinterpret_cast<struct pldm_get_bios_table_req*>(req->payload);
+
+    request->transfer_handle = transferHandle;
+    request->transfer_op_flag = transferOpFlag;
+    request->table_type = tableType;
+
+    auto rc = decode_get_bios_table_req(req, requestMsg.size() - hdr_size,
+                                        &retTransferHandle, &retTransferOpFlag,
+                                        &retTableType);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(transferHandle, retTransferHandle);
+    EXPECT_EQ(transferOpFlag, retTransferOpFlag);
+    EXPECT_EQ(tableType, retTableType);
+}
+TEST(GetBIOSTable, testBadDecodeRequest)
+{
+    const auto hdr_size = sizeof(pldm_msg_hdr);
+    std::array<uint8_t, hdr_size + PLDM_GET_BIOS_TABLE_REQ_BYTES> requestMsg{};
+    uint32_t transferHandle = 31;
+    uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+    uint8_t tableType = PLDM_BIOS_ATTR_TABLE;
+    uint32_t retTransferHandle = 0;
+    uint8_t retTransferOpFlag = 0;
+    uint8_t retTableType = 0;
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_get_bios_table_req* request =
+        reinterpret_cast<struct pldm_get_bios_table_req*>(req->payload);
+
+    request->transfer_handle = transferHandle;
+    request->transfer_op_flag = transferOpFlag;
+    request->table_type = tableType;
+
+    auto rc = decode_get_bios_table_req(req, requestMsg.size() - hdr_size,
+                                        &retTransferHandle, &retTransferOpFlag,
+                                        &retTableType);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(transferHandle, retTransferHandle);
+    EXPECT_EQ(transferOpFlag, retTransferOpFlag);
+    EXPECT_EQ(tableType, retTableType);
+}
+/*
+TEST(GetBIOSTable, testBadDecodeRequest)
+{
+    const auto hdr_size = sizeof(pldm_msg_hdr);
+    std::array<uint8_t, hdr_size + PLDM_GET_BIOS_TABLE_REQ_BYTES> requestMsg{};
+    uint32_t transferHandle = 31;
+    uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+    uint8_t tableType = PLDM_BIOS_ATTR_TABLE;
+    uint32_t retTransferHandle = 0;
+    uint8_t retTransferOpFlag = 0;
+    uint8_t retTableType = 0;
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_get_bios_table_req* request =
+        reinterpret_cast<struct pldm_get_bios_table_req*>(req->payload);
+
+    request->transfer_handle = transferHandle;
+    request->transfer_op_flag = transferOpFlag;
+    request->table_type = tableType;
+
+    auto rc = decode_get_bios_table_req(req, requestMsg.size() - hdr_size - 3,
+                                        &retTransferHandle, &retTransferOpFlag,
+                                        &retTableType);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}*/
+
+TEST(GetBIOSAttributeCurrentValueByHandle, testGoodDecodeRequest)
+{
+    uint32_t transferHandle = 45;
+    uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+    uint16_t attributehandle = 10;
+    uint32_t retTransferHandle = 0;
+    uint8_t retTransferOpFlag = 0;
+    uint16_t retattributehandle = 0;
+    std::array<uint8_t, hdrSize + sizeof(transferHandle) +
+                            sizeof(transferOpFlag) + sizeof(attributehandle)>
+        requestMsg{};
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_get_bios_attribute_current_value_by_handle_req* request =
+        reinterpret_cast<
+            struct pldm_get_bios_attribute_current_value_by_handle_req*>(
+            req->payload);
+
+    request->transfer_handle = transferHandle;
+    request->transfer_op_flag = transferOpFlag;
+    request->attribute_handle = attributehandle;
+
+    auto rc = decode_get_bios_attribute_current_value_by_handle_req(
+        req, requestMsg.size() - hdrSize, &retTransferHandle,
+        &retTransferOpFlag, &retattributehandle);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(transferHandle, retTransferHandle);
+    EXPECT_EQ(transferOpFlag, retTransferOpFlag);
+    EXPECT_EQ(attributehandle, retattributehandle);
+}
+
+TEST(GetBIOSAttributeCurrentValueByHandle, testBadDecodeRequest)
+{
+
+    uint32_t transferHandle = 0;
+    uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+    uint16_t attribute_handle = 0;
+    uint32_t retTransferHandle = 0;
+    uint8_t retTransferOpFlag = 0;
+    uint16_t retattribute_handle = 0;
+    std::array<uint8_t, hdrSize + sizeof(transferHandle) +
+                            sizeof(transferOpFlag) + sizeof(attribute_handle)>
+        requestMsg{};
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_get_bios_attribute_current_value_by_handle_req* request =
+        reinterpret_cast<
+            struct pldm_get_bios_attribute_current_value_by_handle_req*>(
+            req->payload);
+
+    request->transfer_handle = transferHandle;
+    request->transfer_op_flag = transferOpFlag;
+    request->attribute_handle = attribute_handle;
+
+    auto rc = decode_get_bios_attribute_current_value_by_handle_req(
+        NULL, requestMsg.size() - hdrSize, &retTransferHandle,
+        &retTransferOpFlag, &retattribute_handle);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    transferHandle = 31;
+    request->transfer_handle = transferHandle;
+
+    rc = decode_get_bios_attribute_current_value_by_handle_req(
+        req, 0, &retTransferHandle, &retTransferOpFlag, &retattribute_handle);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetBIOSAttributeCurrentValueByHandle, testGoodEncodeResponse)
+{
+
+    uint8_t instanceId = 10;
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint32_t nextTransferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    uint8_t attributeData = 44;
+    std::array<uint8_t,
+               hdrSize +
+                   sizeof(pldm_get_bios_attribute_current_value_by_handle_resp)>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = encode_get_bios_current_value_by_handle_resp(
+        instanceId, completionCode, nextTransferHandle, transferFlag,
+        &attributeData, sizeof(attributeData), response);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_get_bios_attribute_current_value_by_handle_resp* resp =
+        reinterpret_cast<
+            struct pldm_get_bios_attribute_current_value_by_handle_resp*>(
+            response->payload);
+
+    EXPECT_EQ(completionCode, resp->completion_code);
+    EXPECT_EQ(nextTransferHandle, resp->next_transfer_handle);
+    EXPECT_EQ(transferFlag, resp->transfer_flag);
+    EXPECT_EQ(
+        0, memcmp(&attributeData, resp->attribute_data, sizeof(attributeData)));
+}
+
+TEST(GetBIOSAttributeCurrentValueByHandle, testBadEncodeResponse)
+{
+    uint32_t nextTransferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    uint8_t attributeData = 44;
+
+    auto rc = encode_get_bios_current_value_by_handle_resp(
+        0, PLDM_SUCCESS, nextTransferHandle, transferFlag, &attributeData,
+        sizeof(attributeData), nullptr);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    std::array<uint8_t,
+               hdrSize +
+                   sizeof(pldm_get_bios_attribute_current_value_by_handle_resp)>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    rc = encode_get_bios_current_value_by_handle_resp(
+        0, PLDM_SUCCESS, nextTransferHandle, transferFlag, nullptr,
+        sizeof(attributeData), response);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(SetBiosAttributeCurrentValue, testGoodEncodeRequest)
+{
+    uint8_t instanceId = 10;
+    uint32_t transferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    uint32_t attributeData = 44;
+    std::array<uint8_t, hdrSize + PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES +
+                            sizeof(attributeData)>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto rc = encode_set_bios_attribute_current_value_req(
+        instanceId, transferHandle, transferFlag,
+        reinterpret_cast<uint8_t*>(&attributeData), sizeof(attributeData),
+        request, requestMsg.size() - hdrSize);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_set_bios_attribute_current_value_req* req =
+        reinterpret_cast<struct pldm_set_bios_attribute_current_value_req*>(
+            request->payload);
+    EXPECT_EQ(htole32(transferHandle), req->transfer_handle);
+    EXPECT_EQ(transferFlag, req->transfer_flag);
+    EXPECT_EQ(
+        0, memcmp(&attributeData, req->attribute_data, sizeof(attributeData)));
+}
+
+TEST(SetBiosAttributeCurrentValue, testBadEncodeRequest)
+{
+    uint8_t instanceId = 10;
+    uint32_t transferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    uint32_t attributeData = 44;
+    std::array<uint8_t, hdrSize + PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = encode_set_bios_attribute_current_value_req(
+        instanceId, transferHandle, transferFlag, nullptr, 0, nullptr, 0);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = encode_set_bios_attribute_current_value_req(
+        instanceId, transferHandle, transferFlag,
+        reinterpret_cast<uint8_t*>(&attributeData), sizeof(attributeData),
+        request, requestMsg.size() - hdrSize);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(SetBiosAttributeCurrentValue, testGoodDecodeRequest)
+{
+    uint32_t transferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    uint32_t attributeData = 44;
+
+    std::array<uint8_t, hdrSize + PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES +
+                            sizeof(attributeData)>
+        requestMsg{};
+    auto request = reinterpret_cast<struct pldm_msg*>(requestMsg.data());
+    struct pldm_set_bios_attribute_current_value_req* req =
+        reinterpret_cast<struct pldm_set_bios_attribute_current_value_req*>(
+            request->payload);
+    req->transfer_handle = htole32(transferHandle);
+    req->transfer_flag = transferFlag;
+    memcpy(req->attribute_data, &attributeData, sizeof(attributeData));
+
+    uint32_t retTransferHandle;
+    uint8_t retTransferFlag;
+    struct variable_field attribute;
+    auto rc = decode_set_bios_attribute_current_value_req(
+        request, requestMsg.size() - hdrSize, &retTransferHandle,
+        &retTransferFlag, &attribute);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retTransferHandle, transferHandle);
+    EXPECT_EQ(retTransferFlag, transferFlag);
+    EXPECT_EQ(attribute.length, sizeof(attributeData));
+    EXPECT_EQ(0, memcmp(attribute.ptr, &attributeData, sizeof(attributeData)));
+}
+
+TEST(SetBiosAttributeCurrentValue, testBadDecodeRequest)
+{
+    uint32_t transferHandle = 32;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    struct variable_field attribute;
+    std::array<uint8_t, hdrSize + PLDM_SET_BIOS_ATTR_CURR_VAL_MIN_REQ_BYTES - 1>
+        requestMsg{};
+    auto request = reinterpret_cast<struct pldm_msg*>(requestMsg.data());
+
+    auto rc = decode_set_bios_attribute_current_value_req(
+        nullptr, 0, &transferHandle, &transferFlag, &attribute);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    rc = decode_set_bios_attribute_current_value_req(
+        request, requestMsg.size() - hdrSize, &transferHandle, &transferFlag,
+        &attribute);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(SetBiosAttributeCurrentValue, testGoodEncodeResponse)
+{
+    uint8_t instanceId = 10;
+    uint32_t nextTransferHandle = 32;
+    uint8_t completionCode = PLDM_SUCCESS;
+
+    std::array<uint8_t, hdrSize + PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES>
+        responseMsg{};
+    struct pldm_msg* response =
+        reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+    auto rc = encode_set_bios_attribute_current_value_resp(
+        instanceId, completionCode, nextTransferHandle, response);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_set_bios_attribute_current_value_resp* resp =
+        reinterpret_cast<struct pldm_set_bios_attribute_current_value_resp*>(
+            response->payload);
+    EXPECT_EQ(completionCode, resp->completion_code);
+    EXPECT_EQ(htole32(nextTransferHandle), resp->next_transfer_handle);
+}
+
+TEST(SetBiosAttributeCurrentValue, testBadEncodeResponse)
+{
+    uint8_t instanceId = 10;
+    uint32_t nextTransferHandle = 32;
+    uint8_t completionCode = PLDM_SUCCESS;
+    auto rc = encode_set_bios_attribute_current_value_resp(
+        instanceId, completionCode, nextTransferHandle, nullptr);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+TEST(SetBiosAttributeCurrentValue, testGoodDecodeResponse)
+{
+    uint32_t nextTransferHandle = 32;
+    uint8_t completionCode = PLDM_SUCCESS;
+    std::array<uint8_t, hdrSize + PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES>
+        responseMsg{};
+    struct pldm_msg* response =
+        reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+    struct pldm_set_bios_attribute_current_value_resp* resp =
+        reinterpret_cast<struct pldm_set_bios_attribute_current_value_resp*>(
+            response->payload);
+
+    resp->completion_code = completionCode;
+    resp->next_transfer_handle = htole32(nextTransferHandle);
+
+    uint8_t retCompletionCode;
+    uint32_t retNextTransferHandle;
+    auto rc = decode_set_bios_attribute_current_value_resp(
+        response, responseMsg.size() - hdrSize, &retCompletionCode,
+        &retNextTransferHandle);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completionCode, retCompletionCode);
+    EXPECT_EQ(nextTransferHandle, retNextTransferHandle);
+}
+
+TEST(SetBiosAttributeCurrentValue, testBadDecodeResponse)
+{
+    uint32_t nextTransferHandle = 32;
+    uint8_t completionCode = PLDM_SUCCESS;
+
+    std::array<uint8_t, hdrSize + PLDM_SET_BIOS_ATTR_CURR_VAL_RESP_BYTES>
+        responseMsg{};
+    struct pldm_msg* response =
+        reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+    struct pldm_set_bios_attribute_current_value_resp* resp =
+        reinterpret_cast<struct pldm_set_bios_attribute_current_value_resp*>(
+            response->payload);
+
+    resp->completion_code = completionCode;
+    resp->next_transfer_handle = htole32(nextTransferHandle);
+
+    auto rc = decode_set_bios_attribute_current_value_resp(
+        nullptr, 0, &completionCode, &nextTransferHandle);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_set_bios_attribute_current_value_resp(
+        response, responseMsg.size() - hdrSize - 1, &completionCode,
+        &nextTransferHandle);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetBIOSTable, testDecodeResponse)
+{
+    uint32_t nextTransferHandle = 32;
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint8_t transfer_flag = PLDM_START_AND_END;
+
+    std::array<uint8_t, hdrSize + PLDM_GET_BIOS_TABLE_MIN_RESP_BYTES>
+        responseMsg{};
+    struct pldm_msg* response =
+        reinterpret_cast<struct pldm_msg*>(responseMsg.data());
+
+    struct pldm_get_bios_table_resp* resp =
+        reinterpret_cast<struct pldm_get_bios_table_resp*>(response->payload);
+
+    resp->completion_code = completionCode;
+    resp->next_transfer_handle = htole32(nextTransferHandle);
+    resp->transfer_flag = transfer_flag;
+    size_t biosTableOffset = sizeof(completionCode) +
+                             sizeof(nextTransferHandle) + sizeof(transfer_flag);
+
+    uint8_t retCompletionCode;
+    uint32_t retNextTransferHandle;
+    uint8_t retransfer_flag;
+    size_t rebiosTableOffset = 0;
+    auto rc = decode_get_bios_table_resp(
+        response, responseMsg.size(), &retCompletionCode,
+        &retNextTransferHandle, &retransfer_flag, &rebiosTableOffset);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(completionCode, retCompletionCode);
+    ASSERT_EQ(nextTransferHandle, retNextTransferHandle);
+    ASSERT_EQ(transfer_flag, retransfer_flag);
+    ASSERT_EQ(biosTableOffset, rebiosTableOffset);
+}
diff --git a/libpldm/tests/libpldm_fru_test.cpp b/libpldm/tests/libpldm_fru_test.cpp
new file mode 100644
index 0000000..7331771
--- /dev/null
+++ b/libpldm/tests/libpldm_fru_test.cpp
@@ -0,0 +1,393 @@
+#include <string.h>
+
+#include <array>
+
+#include "libpldm/base.h"
+#include "libpldm/fru.h"
+
+#include <gtest/gtest.h>
+
+TEST(GetFruRecordTableMetadata, testGoodEncodeRequest)
+{
+    std::array<uint8_t, sizeof(pldm_msg_hdr)> requestMsg{};
+    auto requestPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    auto rc = encode_get_fru_record_table_metadata_req(0, requestPtr);
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(requestPtr->hdr.request, PLDM_REQUEST);
+    ASSERT_EQ(requestPtr->hdr.instance_id, 0);
+    ASSERT_EQ(requestPtr->hdr.type, PLDM_FRU);
+    ASSERT_EQ(requestPtr->hdr.command, PLDM_GET_FRU_RECORD_TABLE_METADATA);
+}
+
+TEST(GetFruRecordTableMetadata, testBadEncodeRequest)
+{
+    auto rc = encode_get_fru_record_table_metadata_req(0, NULL);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetFruRecordTableMetadata, testGoodDecodeResponse)
+{
+
+    std::vector<uint8_t> responseMsg(
+        sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    size_t payload_length = responseMsg.size() - sizeof(pldm_msg_hdr);
+    auto response = reinterpret_cast<pldm_get_fru_record_table_metadata_resp*>(
+        responsePtr->payload);
+
+    responsePtr->hdr.request = PLDM_RESPONSE;
+    responsePtr->hdr.instance_id = 0;
+    responsePtr->hdr.type = PLDM_FRU;
+    responsePtr->hdr.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
+    response->completion_code = PLDM_SUCCESS;
+    response->fru_data_major_version = 0x12;
+    response->fru_data_minor_version = 0x21;
+    response->fru_table_maximum_size = 0x1234ABCD;
+    response->fru_table_length = 0x56781234;
+    response->total_record_set_identifiers = 0x34EF;
+    response->total_table_records = 0xEEEF;
+    response->checksum = 0x6543FA71;
+
+    uint8_t completion_code = 0xFF;
+    uint8_t fru_data_major_version = 0x00;
+    uint8_t fru_data_minor_version = 0x00;
+    uint32_t fru_table_maximum_size = 0x00000000;
+    uint32_t fru_table_length = 0x00000000;
+    uint16_t total_record_set_identifiers = 0x0000;
+    uint16_t total_table_records = 0x0000;
+    uint32_t checksum = 0x00000000;
+
+    auto rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, payload_length, &completion_code, &fru_data_major_version,
+        &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
+        &total_record_set_identifiers, &total_table_records, &checksum);
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(completion_code, PLDM_SUCCESS);
+    ASSERT_EQ(fru_data_major_version, 0x12);
+    ASSERT_EQ(fru_data_minor_version, 0x21);
+    ASSERT_EQ(fru_table_maximum_size, 0x1234ABCD);
+    ASSERT_EQ(fru_table_length, 0x56781234);
+    ASSERT_EQ(total_record_set_identifiers, 0x34EF);
+    ASSERT_EQ(total_table_records, 0xEEEF);
+    ASSERT_EQ(checksum, 0x6543FA71);
+
+    response->fru_data_major_version = 0x00;
+    response->fru_data_minor_version = 0x00;
+    response->fru_table_maximum_size = 0x00000000;
+    response->fru_table_length = 0x00000000;
+    response->total_record_set_identifiers = 0x0000;
+    response->total_table_records = 0x0000;
+    response->checksum = 0x00000000;
+    fru_data_major_version = 0x00;
+    fru_data_minor_version = 0x00;
+    fru_table_maximum_size = 0x00000000;
+    fru_table_length = 0x00000000;
+    total_record_set_identifiers = 0x0000;
+    total_table_records = 0x0000;
+    checksum = 0x00000000;
+    response->completion_code = PLDM_ERROR_INVALID_LENGTH;
+    rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, payload_length, &completion_code, &fru_data_major_version,
+        &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
+        &total_record_set_identifiers, &total_table_records, &checksum);
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(responsePtr->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(responsePtr->hdr.instance_id, 0);
+    ASSERT_EQ(responsePtr->hdr.type, PLDM_FRU);
+    ASSERT_EQ(responsePtr->hdr.command, PLDM_GET_FRU_RECORD_TABLE_METADATA);
+    ASSERT_EQ(completion_code, PLDM_ERROR_INVALID_LENGTH);
+    ASSERT_EQ(fru_data_major_version, 0x00);
+    ASSERT_EQ(fru_data_minor_version, 0x00);
+    ASSERT_EQ(fru_table_maximum_size, 0x00000000);
+    ASSERT_EQ(fru_table_length, 0x00000000);
+    ASSERT_EQ(total_record_set_identifiers, 0x0000);
+    ASSERT_EQ(total_table_records, 0x0000);
+    ASSERT_EQ(checksum, 0x00000000);
+}
+
+TEST(GetFruRecordTableMetadata, testBadDecodeResponse)
+{
+    std::vector<uint8_t> responseMsg(
+        sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES);
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    size_t payload_length = responseMsg.size() - sizeof(pldm_msg_hdr);
+    auto response = reinterpret_cast<pldm_get_fru_record_table_metadata_resp*>(
+        responsePtr->payload);
+
+    response->completion_code = PLDM_SUCCESS;
+    response->fru_data_major_version = 0x12;
+    response->fru_data_minor_version = 0x21;
+    response->fru_table_maximum_size = 0x1234ABCD;
+    response->fru_table_length = 0x56781234;
+    response->total_record_set_identifiers = 0x34EF;
+    response->total_table_records = 0xEEEF;
+    response->checksum = 0x6543FA71;
+
+    uint8_t completion_code = 0xFF;
+    uint8_t fru_data_major_version = 0x00;
+    uint8_t fru_data_minor_version = 0x00;
+    uint32_t fru_table_maximum_size = 0x00000000;
+    uint32_t fru_table_length = 0x00000000;
+    uint16_t total_record_set_identifiers = 0x0000;
+    uint16_t total_table_records = 0x0000;
+    uint32_t checksum = 0x00000000;
+
+    auto rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES + 2,
+        &completion_code, &fru_data_major_version, &fru_data_minor_version,
+        &fru_table_maximum_size, &fru_table_length,
+        &total_record_set_identifiers, &total_table_records, &checksum);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+
+    rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, payload_length, &completion_code, NULL,
+        &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
+        &total_record_set_identifiers, &total_table_records, &checksum);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, payload_length, &completion_code, &fru_data_major_version,
+        NULL, &fru_table_maximum_size, &fru_table_length,
+        &total_record_set_identifiers, &total_table_records, &checksum);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, payload_length, &completion_code, &fru_data_major_version,
+        &fru_data_minor_version, NULL, &fru_table_length,
+        &total_record_set_identifiers, &total_table_records, &checksum);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, payload_length, &completion_code, &fru_data_major_version,
+        &fru_data_minor_version, &fru_table_maximum_size, NULL,
+        &total_record_set_identifiers, &total_table_records, &checksum);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, payload_length, &completion_code, &fru_data_major_version,
+        &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
+        NULL, &total_table_records, &checksum);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, payload_length, &completion_code, &fru_data_major_version,
+        &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
+        &total_record_set_identifiers, NULL, &checksum);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_get_fru_record_table_metadata_resp(
+        responsePtr, payload_length, &completion_code, &fru_data_major_version,
+        &fru_data_minor_version, &fru_table_maximum_size, &fru_table_length,
+        &total_record_set_identifiers, &total_table_records, NULL);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetFruRecordTableMetadata, testGoodEncodeResponse)
+{
+
+    std::array<uint8_t, sizeof(pldm_msg_hdr) +
+                            PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES>
+        responseMsg{};
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    responsePtr->hdr.request = PLDM_RESPONSE;
+    responsePtr->hdr.instance_id = 0;
+    responsePtr->hdr.type = PLDM_FRU;
+    responsePtr->hdr.command = PLDM_GET_FRU_RECORD_TABLE_METADATA;
+
+    uint8_t completion_code = PLDM_SUCCESS;
+    uint8_t fru_data_major_version = 0x12;
+    uint8_t fru_data_minor_version = 0x21;
+    uint32_t fru_table_maximum_size = 0x1234ABCD;
+    uint32_t fru_table_length = 0x56781234;
+    uint16_t total_record_set_identifiers = 0x34EF;
+    uint16_t total_table_records = 0xEEEF;
+    uint32_t checksum = 0x6543FA71;
+
+    auto rc = encode_get_fru_record_table_metadata_resp(
+        0, completion_code, fru_data_major_version, fru_data_minor_version,
+        fru_table_maximum_size, fru_table_length, total_record_set_identifiers,
+        total_table_records, checksum, responsePtr);
+
+    auto response = reinterpret_cast<pldm_get_fru_record_table_metadata_resp*>(
+        responsePtr->payload);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(responsePtr->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(responsePtr->hdr.instance_id, 0);
+    ASSERT_EQ(responsePtr->hdr.type, PLDM_FRU);
+    ASSERT_EQ(responsePtr->hdr.command, PLDM_GET_FRU_RECORD_TABLE_METADATA);
+    ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
+    ASSERT_EQ(response->fru_data_major_version, 0x12);
+    ASSERT_EQ(response->fru_data_minor_version, 0x21);
+    ASSERT_EQ(response->fru_table_maximum_size, 0x1234ABCD);
+    ASSERT_EQ(response->fru_table_length, 0x56781234);
+    ASSERT_EQ(response->total_record_set_identifiers, 0x34EF);
+    ASSERT_EQ(response->total_table_records, 0xEEEF);
+    ASSERT_EQ(response->checksum, 0x6543FA71);
+
+    response->fru_data_major_version = 0;
+    response->fru_data_major_version = 0x00;
+    response->fru_data_minor_version = 0x00;
+    response->fru_table_maximum_size = 0x00000000;
+    response->fru_table_length = 0x00000000;
+    response->total_record_set_identifiers = 0x0000;
+    response->total_table_records = 0x0000;
+    response->checksum = 0x00000000;
+    completion_code = PLDM_ERROR_INVALID_DATA;
+    rc = encode_get_fru_record_table_metadata_resp(
+        0, completion_code, fru_data_major_version, fru_data_minor_version,
+        fru_table_maximum_size, fru_table_length, total_record_set_identifiers,
+        total_table_records, checksum, responsePtr);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(responsePtr->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(responsePtr->hdr.instance_id, 0);
+    ASSERT_EQ(responsePtr->hdr.type, PLDM_FRU);
+    ASSERT_EQ(responsePtr->hdr.command, PLDM_GET_FRU_RECORD_TABLE_METADATA);
+    ASSERT_EQ(completion_code, PLDM_ERROR_INVALID_DATA);
+    ASSERT_EQ(response->fru_data_major_version, 0x00);
+    ASSERT_EQ(response->fru_data_minor_version, 0x00);
+    ASSERT_EQ(response->fru_table_maximum_size, 0x00000000);
+    ASSERT_EQ(response->fru_table_length, 0x00000000);
+    ASSERT_EQ(response->total_record_set_identifiers, 0x0000);
+    ASSERT_EQ(response->total_table_records, 0x0000);
+    ASSERT_EQ(response->checksum, 0x00000000);
+}
+
+TEST(GetFruRecordTableMetadata, testBadEncodeResponse)
+{
+    std::array<uint8_t, sizeof(pldm_msg_hdr) +
+                            PLDM_GET_FRU_RECORD_TABLE_METADATA_RESP_BYTES>
+        responseMsg{};
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    uint8_t completion_code = PLDM_SUCCESS;
+    uint8_t fru_data_major_version = 0x12;
+    uint8_t fru_data_minor_version = 0x21;
+    uint32_t fru_table_maximum_size = 0x1234ABCD;
+    uint32_t fru_table_length = 0x56781234;
+    uint16_t total_record_set_identifiers = 0x34EF;
+    uint16_t total_table_records = 0xEEEF;
+    uint32_t checksum = 0x6543FA71;
+
+    auto rc = encode_get_fru_record_table_metadata_resp(
+        0, completion_code, fru_data_major_version, fru_data_minor_version,
+        fru_table_maximum_size, fru_table_length, total_record_set_identifiers,
+        total_table_records, checksum, NULL);
+
+    auto response = reinterpret_cast<pldm_get_fru_record_table_metadata_resp*>(
+        responsePtr->payload);
+
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+    ASSERT_EQ(completion_code, PLDM_SUCCESS);
+    ASSERT_EQ(response->fru_data_major_version, 0x00);
+    ASSERT_EQ(response->fru_data_minor_version, 0x00);
+    ASSERT_EQ(response->fru_table_maximum_size, 0x00000000);
+    ASSERT_EQ(response->fru_table_length, 0x00000000);
+    ASSERT_EQ(response->total_record_set_identifiers, 0x0000);
+    ASSERT_EQ(response->total_table_records, 0x0000);
+    ASSERT_EQ(response->checksum, 0x00000000);
+}
+
+TEST(GetFruRecordTable, testGoodDecodeRequest)
+{
+    uint32_t data_transfer_handle = 31;
+    uint8_t transfer_operation_flag = PLDM_GET_FIRSTPART;
+    std::array<uint8_t,
+               PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES + sizeof(pldm_msg_hdr)>
+        requestMsg{};
+    auto requestPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    size_t payload_length = requestMsg.size() - sizeof(pldm_msg_hdr);
+    auto request =
+        reinterpret_cast<pldm_get_fru_record_table_req*>(requestPtr->payload);
+
+    request->data_transfer_handle = data_transfer_handle;
+    request->transfer_operation_flag = transfer_operation_flag;
+
+    uint32_t ret_data_transfer_handle = 0;
+    uint8_t ret_transfer_operation_flag = 0;
+
+    // Invoke decode get FRU record table request api
+    auto rc = decode_get_fru_record_table_req(requestPtr, payload_length,
+                                              &ret_data_transfer_handle,
+                                              &ret_transfer_operation_flag);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(data_transfer_handle, ret_data_transfer_handle);
+    ASSERT_EQ(transfer_operation_flag, ret_transfer_operation_flag);
+}
+
+TEST(GetFruRecordTable, testBadDecodeRequest)
+{
+    uint32_t data_transfer_handle = 0x0;
+    uint8_t transfer_operation_flag = PLDM_GET_FIRSTPART;
+
+    std::array<uint8_t,
+               sizeof(pldm_msg_hdr) + PLDM_GET_FRU_RECORD_TABLE_REQ_BYTES>
+        requestMsg{};
+    auto requestPtr = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    // Payload message is missing
+    auto rc = decode_get_fru_record_table_req(NULL, 0, &data_transfer_handle,
+                                              &transfer_operation_flag);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    // Payload length is invalid
+    rc = decode_get_fru_record_table_req(requestPtr, 0, &data_transfer_handle,
+                                         &transfer_operation_flag);
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetFruRecordTable, testGoodEncodeResponse)
+{
+    uint8_t completion_code = 0;
+    uint32_t next_data_transfer_handle = 32;
+    uint8_t transfer_flag = PLDM_START_AND_END;
+
+    std::vector<uint8_t> responseMsg(sizeof(pldm_msg_hdr) +
+                                     PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES);
+
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    auto response =
+        reinterpret_cast<pldm_get_fru_record_table_resp*>(responsePtr->payload);
+
+    // Invoke encode get FRU record table response api
+    auto rc = encode_get_fru_record_table_resp(0, completion_code,
+                                               next_data_transfer_handle,
+                                               transfer_flag, responsePtr);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(responsePtr->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(responsePtr->hdr.instance_id, 0);
+    ASSERT_EQ(responsePtr->hdr.type, PLDM_FRU);
+    ASSERT_EQ(responsePtr->hdr.command, PLDM_GET_FRU_RECORD_TABLE);
+    ASSERT_EQ(response->completion_code, PLDM_SUCCESS);
+    ASSERT_EQ(response->next_data_transfer_handle, next_data_transfer_handle);
+    ASSERT_EQ(response->transfer_flag, transfer_flag);
+}
+
+TEST(GetFruRecordTable, testBadEncodeResponse)
+{
+    uint32_t next_data_transfer_handle = 32;
+    uint8_t transfer_flag = PLDM_START_AND_END;
+
+    std::vector<uint8_t> responseMsg(sizeof(pldm_msg_hdr) +
+                                     PLDM_GET_FRU_RECORD_TABLE_MIN_RESP_BYTES);
+
+    auto responsePtr = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    auto rc = encode_get_fru_record_table_resp(
+        0, PLDM_ERROR, next_data_transfer_handle, transfer_flag, responsePtr);
+
+    ASSERT_EQ(rc, PLDM_SUCCESS);
+    ASSERT_EQ(responsePtr->hdr.request, PLDM_RESPONSE);
+    ASSERT_EQ(responsePtr->hdr.instance_id, 0);
+    ASSERT_EQ(responsePtr->hdr.type, PLDM_FRU);
+    ASSERT_EQ(responsePtr->hdr.command, PLDM_GET_FRU_RECORD_TABLE);
+    ASSERT_EQ(responsePtr->payload[0], PLDM_ERROR);
+
+    rc = encode_get_fru_record_table_resp(
+        0, PLDM_SUCCESS, next_data_transfer_handle, transfer_flag, nullptr);
+
+    ASSERT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
diff --git a/libpldm/tests/libpldm_pdr_test.cpp b/libpldm/tests/libpldm_pdr_test.cpp
new file mode 100644
index 0000000..c1caf20
--- /dev/null
+++ b/libpldm/tests/libpldm_pdr_test.cpp
@@ -0,0 +1,319 @@
+#include <array>
+
+#include "libpldm/pdr.h"
+#include "libpldm/platform.h"
+
+#include <gtest/gtest.h>
+
+TEST(PDRAccess, testInit)
+{
+    auto repo = pldm_pdr_init();
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 0);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), 0);
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRUpdate, testAdd)
+{
+    auto repo = pldm_pdr_init();
+
+    std::array<uint8_t, 10> data{};
+    auto handle = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    EXPECT_EQ(handle, 1);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 1);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), data.size());
+
+    handle = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    EXPECT_EQ(handle, 2);
+    handle = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    EXPECT_EQ(handle, 3);
+    handle = pldm_pdr_add(repo, data.data(), data.size(), 0xdeeddeed);
+    EXPECT_EQ(handle, 0xdeeddeed);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 4);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), data.size() * 4);
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRAccess, testGet)
+{
+    auto repo = pldm_pdr_init();
+
+    std::array<uint32_t, 10> in{100, 345, 3, 6, 89, 0, 11, 45, 23434, 123123};
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in.data()), sizeof(in), 1);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 1);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), sizeof(in));
+    uint32_t size{};
+    uint32_t nextRecHdl{};
+    uint8_t* outData = nullptr;
+    auto hdl = pldm_pdr_find_record(repo, 0, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+
+    auto hdl2 = pldm_pdr_find_record(repo, 1, &outData, &size, &nextRecHdl);
+    EXPECT_EQ(hdl, hdl2);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+
+    hdl = pldm_pdr_find_record(repo, 0xdeaddead, &outData, &size, &nextRecHdl);
+    EXPECT_EQ(hdl, nullptr);
+    EXPECT_EQ(size, 0);
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(outData, nullptr);
+    outData = nullptr;
+
+    std::array<uint32_t, 10> in2{1000, 3450, 30,  60,     890,
+                                 0,    110,  450, 234034, 123123};
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 2);
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 3);
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 4);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 4);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), sizeof(in2) * 4);
+    hdl = pldm_pdr_find_record(repo, 0, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 2);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+    hdl2 = pldm_pdr_find_record(repo, 1, &outData, &size, &nextRecHdl);
+    EXPECT_EQ(hdl, hdl2);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 2);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_find_record(repo, 2, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 3);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_find_record(repo, 3, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 4);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_find_record(repo, 4, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRAccess, testGetNext)
+{
+    auto repo = pldm_pdr_init();
+
+    std::array<uint32_t, 10> in{100, 345, 3, 6, 89, 0, 11, 45, 23434, 123123};
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in.data()), sizeof(in), 1);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 1);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), sizeof(in));
+    uint32_t size{};
+    uint32_t nextRecHdl{};
+    uint8_t* outData = nullptr;
+    auto hdl = pldm_pdr_find_record(repo, 0, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in.data(), sizeof(in)), 0);
+    outData = nullptr;
+
+    std::array<uint32_t, 10> in2{1000, 3450, 30,  60,     890,
+                                 0,    110,  450, 234034, 123123};
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 2);
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 3);
+    pldm_pdr_add(repo, reinterpret_cast<uint8_t*>(in2.data()), sizeof(in2), 4);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 4);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo), sizeof(in2) * 4);
+    hdl = pldm_pdr_get_next_record(repo, hdl, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 3);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_get_next_record(repo, hdl, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 4);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+    hdl = pldm_pdr_get_next_record(repo, hdl, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(in2));
+    EXPECT_EQ(nextRecHdl, 0);
+    EXPECT_EQ(memcmp(outData, in2.data(), sizeof(in2)), 0);
+    outData = nullptr;
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRAccess, testFindByType)
+{
+    auto repo = pldm_pdr_init();
+
+    std::array<uint8_t, sizeof(pldm_pdr_hdr)> data{};
+    pldm_pdr_hdr* hdr = reinterpret_cast<pldm_pdr_hdr*>(data.data());
+    hdr->type = 1;
+    auto first = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    hdr->type = 2;
+    auto second = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    hdr->type = 3;
+    auto third = pldm_pdr_add(repo, data.data(), data.size(), 0);
+    hdr->type = 4;
+    auto fourth = pldm_pdr_add(repo, data.data(), data.size(), 0);
+
+    uint8_t* outData = nullptr;
+    uint32_t size{};
+    auto firstRec =
+        pldm_pdr_find_record_by_type(repo, 1, nullptr, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, firstRec), first);
+    outData = nullptr;
+    auto secondRec =
+        pldm_pdr_find_record_by_type(repo, 2, nullptr, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, secondRec), second);
+    outData = nullptr;
+    auto thirdRec =
+        pldm_pdr_find_record_by_type(repo, 3, nullptr, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, thirdRec), third);
+    outData = nullptr;
+    auto fourthRec =
+        pldm_pdr_find_record_by_type(repo, 4, nullptr, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, fourthRec), fourth);
+    outData = nullptr;
+    auto fifthRec =
+        pldm_pdr_find_record_by_type(repo, 5, nullptr, &outData, &size);
+    EXPECT_EQ(fifthRec, nullptr);
+    EXPECT_EQ(outData, nullptr);
+    EXPECT_EQ(size, 0);
+
+    auto rec =
+        pldm_pdr_find_record_by_type(repo, 3, secondRec, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, rec), third);
+    outData = nullptr;
+    rec = pldm_pdr_find_record_by_type(repo, 4, secondRec, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, rec), fourth);
+    outData = nullptr;
+    rec = pldm_pdr_find_record_by_type(repo, 2, firstRec, &outData, &size);
+    EXPECT_EQ(pldm_pdr_get_record_handle(repo, rec), second);
+    outData = nullptr;
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRUpdate, testAddFruRecordSet)
+{
+    auto repo = pldm_pdr_init();
+
+    auto handle = pldm_pdr_add_fru_record_set(repo, 1, 10, 1, 0, 100);
+    EXPECT_EQ(handle, 1);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 1);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo),
+              sizeof(pldm_pdr_hdr) + sizeof(pldm_pdr_fru_record_set));
+    uint32_t size{};
+    uint32_t nextRecHdl{};
+    uint8_t* outData = nullptr;
+    auto hdl = pldm_pdr_find_record(repo, 0, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(pldm_pdr_hdr) + sizeof(pldm_pdr_fru_record_set));
+    EXPECT_EQ(nextRecHdl, 0);
+    pldm_pdr_hdr* hdr = reinterpret_cast<pldm_pdr_hdr*>(outData);
+    EXPECT_EQ(hdr->version, 1);
+    EXPECT_EQ(hdr->type, PLDM_PDR_FRU_RECORD_SET);
+    EXPECT_EQ(hdr->length, sizeof(pldm_pdr_fru_record_set));
+    EXPECT_EQ(hdr->record_handle, 1);
+    pldm_pdr_fru_record_set* fru = reinterpret_cast<pldm_pdr_fru_record_set*>(
+        outData + sizeof(pldm_pdr_hdr));
+    EXPECT_EQ(fru->terminus_handle, 1);
+    EXPECT_EQ(fru->fru_rsi, 10);
+    EXPECT_EQ(fru->entity_type, 1);
+    EXPECT_EQ(fru->entity_instance_num, 0);
+    EXPECT_EQ(fru->container_id, 100);
+    outData = nullptr;
+
+    handle = pldm_pdr_add_fru_record_set(repo, 2, 11, 2, 1, 101);
+    EXPECT_EQ(handle, 2);
+    EXPECT_EQ(pldm_pdr_get_record_count(repo), 2);
+    EXPECT_EQ(pldm_pdr_get_repo_size(repo),
+              2 * (sizeof(pldm_pdr_hdr) + sizeof(pldm_pdr_fru_record_set)));
+    hdl = pldm_pdr_find_record(repo, 2, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(pldm_pdr_hdr) + sizeof(pldm_pdr_fru_record_set));
+    EXPECT_EQ(nextRecHdl, 0);
+    hdr = reinterpret_cast<pldm_pdr_hdr*>(outData);
+    EXPECT_EQ(hdr->version, 1);
+    EXPECT_EQ(hdr->type, PLDM_PDR_FRU_RECORD_SET);
+    EXPECT_EQ(hdr->length, sizeof(pldm_pdr_fru_record_set));
+    EXPECT_EQ(hdr->record_handle, 2);
+    fru = reinterpret_cast<pldm_pdr_fru_record_set*>(outData +
+                                                     sizeof(pldm_pdr_hdr));
+    EXPECT_EQ(fru->terminus_handle, 2);
+    EXPECT_EQ(fru->fru_rsi, 11);
+    EXPECT_EQ(fru->entity_type, 2);
+    EXPECT_EQ(fru->entity_instance_num, 1);
+    EXPECT_EQ(fru->container_id, 101);
+    outData = nullptr;
+
+    hdl = pldm_pdr_find_record(repo, 1, &outData, &size, &nextRecHdl);
+    EXPECT_NE(hdl, nullptr);
+    EXPECT_EQ(size, sizeof(pldm_pdr_hdr) + sizeof(pldm_pdr_fru_record_set));
+    EXPECT_EQ(nextRecHdl, 2);
+    hdr = reinterpret_cast<pldm_pdr_hdr*>(outData);
+    EXPECT_EQ(hdr->version, 1);
+    EXPECT_EQ(hdr->type, PLDM_PDR_FRU_RECORD_SET);
+    EXPECT_EQ(hdr->length, sizeof(pldm_pdr_fru_record_set));
+    EXPECT_EQ(hdr->record_handle, 1);
+    fru = reinterpret_cast<pldm_pdr_fru_record_set*>(outData +
+                                                     sizeof(pldm_pdr_hdr));
+    EXPECT_EQ(fru->terminus_handle, 1);
+    EXPECT_EQ(fru->fru_rsi, 10);
+    EXPECT_EQ(fru->entity_type, 1);
+    EXPECT_EQ(fru->entity_instance_num, 0);
+    EXPECT_EQ(fru->container_id, 100);
+    outData = nullptr;
+
+    pldm_pdr_destroy(repo);
+}
+
+TEST(PDRUpdate, tesFindtFruRecordSet)
+{
+    auto repo = pldm_pdr_init();
+
+    uint16_t terminusHdl{};
+    uint16_t entityType{};
+    uint16_t entityInstanceNum{};
+    uint16_t containerId{};
+    auto first = pldm_pdr_add_fru_record_set(repo, 1, 1, 1, 0, 100);
+    auto second = pldm_pdr_add_fru_record_set(repo, 1, 2, 1, 1, 100);
+    auto third = pldm_pdr_add_fru_record_set(repo, 1, 3, 1, 2, 100);
+    EXPECT_EQ(first, pldm_pdr_get_record_handle(
+                         repo, pldm_pdr_fru_record_set_find_by_rsi(
+                                   repo, 1, &terminusHdl, &entityType,
+                                   &entityInstanceNum, &containerId)));
+    EXPECT_EQ(second, pldm_pdr_get_record_handle(
+                          repo, pldm_pdr_fru_record_set_find_by_rsi(
+                                    repo, 2, &terminusHdl, &entityType,
+                                    &entityInstanceNum, &containerId)));
+    EXPECT_EQ(third, pldm_pdr_get_record_handle(
+                         repo, pldm_pdr_fru_record_set_find_by_rsi(
+                                   repo, 3, &terminusHdl, &entityType,
+                                   &entityInstanceNum, &containerId)));
+    EXPECT_EQ(terminusHdl, 1);
+    EXPECT_EQ(entityType, 1);
+    EXPECT_EQ(entityInstanceNum, 2);
+    EXPECT_EQ(containerId, 100);
+    EXPECT_EQ(nullptr, pldm_pdr_fru_record_set_find_by_rsi(
+                           repo, 4, &terminusHdl, &entityType,
+                           &entityInstanceNum, &containerId));
+
+    pldm_pdr_destroy(repo);
+}
diff --git a/libpldm/tests/libpldm_platform_test.cpp b/libpldm/tests/libpldm_platform_test.cpp
new file mode 100644
index 0000000..11252d6
--- /dev/null
+++ b/libpldm/tests/libpldm_platform_test.cpp
@@ -0,0 +1,545 @@
+#include <string.h>
+
+#include <array>
+
+#include "libpldm/base.h"
+#include "libpldm/platform.h"
+
+#include <gtest/gtest.h>
+
+constexpr auto hdrSize = sizeof(pldm_msg_hdr);
+
+TEST(SetStateEffecterStates, testEncodeResponse)
+{
+    std::array<uint8_t,
+               sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    uint8_t completionCode = 0;
+
+    auto rc = encode_set_state_effecter_states_resp(0, PLDM_SUCCESS, response);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completionCode, response->payload[0]);
+}
+
+TEST(SetStateEffecterStates, testEncodeRequest)
+{
+    std::array<uint8_t,
+               sizeof(pldm_msg_hdr) + PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES>
+        requestMsg{};
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    uint16_t effecterId = 0x0A;
+    uint8_t compEffecterCnt = 0x2;
+    std::array<set_effecter_state_field, 8> stateField{};
+    stateField[0] = {PLDM_REQUEST_SET, 2};
+    stateField[1] = {PLDM_REQUEST_SET, 3};
+
+    auto rc = encode_set_state_effecter_states_req(
+        0, effecterId, compEffecterCnt, stateField.data(), request);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(effecterId, request->payload[0]);
+    EXPECT_EQ(compEffecterCnt, request->payload[sizeof(effecterId)]);
+    EXPECT_EQ(stateField[0].set_request,
+              request->payload[sizeof(effecterId) + sizeof(compEffecterCnt)]);
+    EXPECT_EQ(stateField[0].effecter_state,
+              request->payload[sizeof(effecterId) + sizeof(compEffecterCnt) +
+                               sizeof(stateField[0].set_request)]);
+    EXPECT_EQ(stateField[1].set_request,
+              request->payload[sizeof(effecterId) + sizeof(compEffecterCnt) +
+                               sizeof(stateField[0])]);
+    EXPECT_EQ(stateField[1].effecter_state,
+              request->payload[sizeof(effecterId) + sizeof(compEffecterCnt) +
+                               sizeof(stateField[0]) +
+                               sizeof(stateField[1].set_request)]);
+}
+
+TEST(SetStateEffecterStates, testGoodDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES>
+        responseMsg{};
+
+    uint8_t retcompletion_code = 0;
+
+    responseMsg[hdrSize] = PLDM_SUCCESS;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_set_state_effecter_states_resp(
+        response, responseMsg.size() - hdrSize, &retcompletion_code);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(PLDM_SUCCESS, retcompletion_code);
+}
+
+TEST(SetStateEffecterStates, testGoodDecodeRequest)
+{
+    std::array<uint8_t, hdrSize + PLDM_SET_STATE_EFFECTER_STATES_REQ_BYTES>
+        requestMsg{};
+
+    uint16_t effecterId = 0x32;
+    uint8_t compEffecterCnt = 0x2;
+
+    std::array<set_effecter_state_field, 8> stateField{};
+    stateField[0] = {PLDM_REQUEST_SET, 3};
+    stateField[1] = {PLDM_REQUEST_SET, 4};
+
+    uint16_t retEffecterId = 0;
+    uint8_t retCompEffecterCnt = 0;
+
+    std::array<set_effecter_state_field, 8> retStateField{};
+
+    memcpy(requestMsg.data() + hdrSize, &effecterId, sizeof(effecterId));
+    memcpy(requestMsg.data() + sizeof(effecterId) + hdrSize, &compEffecterCnt,
+           sizeof(compEffecterCnt));
+    memcpy(requestMsg.data() + sizeof(effecterId) + sizeof(compEffecterCnt) +
+               hdrSize,
+           &stateField, sizeof(stateField));
+
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = decode_set_state_effecter_states_req(
+        request, requestMsg.size() - hdrSize, &retEffecterId,
+        &retCompEffecterCnt, retStateField.data());
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(effecterId, retEffecterId);
+    EXPECT_EQ(retCompEffecterCnt, compEffecterCnt);
+    EXPECT_EQ(retStateField[0].set_request, stateField[0].set_request);
+    EXPECT_EQ(retStateField[0].effecter_state, stateField[0].effecter_state);
+    EXPECT_EQ(retStateField[1].set_request, stateField[1].set_request);
+    EXPECT_EQ(retStateField[1].effecter_state, stateField[1].effecter_state);
+}
+
+TEST(SetStateEffecterStates, testBadDecodeRequest)
+{
+    const struct pldm_msg* msg = NULL;
+
+    auto rc = decode_set_state_effecter_states_req(msg, sizeof(*msg), NULL,
+                                                   NULL, NULL);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(SetStateEffecterStates, testBadDecodeResponse)
+{
+    std::array<uint8_t, PLDM_SET_STATE_EFFECTER_STATES_RESP_BYTES>
+        responseMsg{};
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_set_state_effecter_states_resp(response,
+                                                    responseMsg.size(), NULL);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetPDR, testGoodEncodeResponse)
+{
+    uint8_t completionCode = 0;
+    uint32_t nextRecordHndl = 0x12;
+    uint32_t nextDataTransferHndl = 0x13;
+    uint8_t transferFlag = PLDM_END;
+    uint16_t respCnt = 0x5;
+    std::vector<uint8_t> recordData{1, 2, 3, 4, 5};
+    uint8_t transferCRC = 6;
+
+    // + size of record data and transfer CRC
+    std::vector<uint8_t> responseMsg(hdrSize + PLDM_GET_PDR_MIN_RESP_BYTES +
+                                     recordData.size() + 1);
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = encode_get_pdr_resp(0, PLDM_SUCCESS, nextRecordHndl,
+                                  nextDataTransferHndl, transferFlag, respCnt,
+                                  recordData.data(), transferCRC, response);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    struct pldm_get_pdr_resp* resp =
+        reinterpret_cast<struct pldm_get_pdr_resp*>(response->payload);
+
+    EXPECT_EQ(completionCode, resp->completion_code);
+    EXPECT_EQ(nextRecordHndl, resp->next_record_handle);
+    EXPECT_EQ(nextDataTransferHndl, resp->next_data_transfer_handle);
+    EXPECT_EQ(transferFlag, resp->transfer_flag);
+    EXPECT_EQ(respCnt, resp->response_count);
+    EXPECT_EQ(0,
+              memcmp(recordData.data(), resp->record_data, recordData.size()));
+    EXPECT_EQ(*(response->payload + sizeof(pldm_get_pdr_resp) - 1 +
+                recordData.size()),
+              transferCRC);
+
+    transferFlag = PLDM_START_AND_END; // No CRC in this case
+    responseMsg.resize(responseMsg.size() - sizeof(transferCRC));
+    rc = encode_get_pdr_resp(0, PLDM_SUCCESS, nextRecordHndl,
+                             nextDataTransferHndl, transferFlag, respCnt,
+                             recordData.data(), transferCRC, response);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+}
+
+TEST(GetPDR, testBadEncodeResponse)
+{
+    uint32_t nextRecordHndl = 0x12;
+    uint32_t nextDataTransferHndl = 0x13;
+    uint8_t transferFlag = PLDM_START_AND_END;
+    uint16_t respCnt = 0x5;
+    std::vector<uint8_t> recordData{1, 2, 3, 4, 5};
+    uint8_t transferCRC = 0;
+
+    auto rc = encode_get_pdr_resp(0, PLDM_SUCCESS, nextRecordHndl,
+                                  nextDataTransferHndl, transferFlag, respCnt,
+                                  recordData.data(), transferCRC, nullptr);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetPDR, testGoodDecodeRequest)
+{
+    std::array<uint8_t, hdrSize + PLDM_GET_PDR_REQ_BYTES> requestMsg{};
+
+    uint32_t recordHndl = 0x32;
+    uint32_t dataTransferHndl = 0x11;
+    uint8_t transferOpFlag = PLDM_GET_FIRSTPART;
+    uint16_t requestCnt = 0x5;
+    uint16_t recordChangeNum = 0;
+
+    uint32_t retRecordHndl = 0;
+    uint32_t retDataTransferHndl = 0;
+    uint8_t retTransferOpFlag = 0;
+    uint16_t retRequestCnt = 0;
+    uint16_t retRecordChangeNum = 0;
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_get_pdr_req* request =
+        reinterpret_cast<struct pldm_get_pdr_req*>(req->payload);
+
+    request->record_handle = recordHndl;
+    request->data_transfer_handle = dataTransferHndl;
+    request->transfer_op_flag = transferOpFlag;
+    request->request_count = requestCnt;
+    request->record_change_number = recordChangeNum;
+
+    auto rc = decode_get_pdr_req(
+        req, requestMsg.size() - hdrSize, &retRecordHndl, &retDataTransferHndl,
+        &retTransferOpFlag, &retRequestCnt, &retRecordChangeNum);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retRecordHndl, recordHndl);
+    EXPECT_EQ(retDataTransferHndl, dataTransferHndl);
+    EXPECT_EQ(retTransferOpFlag, transferOpFlag);
+    EXPECT_EQ(retRequestCnt, requestCnt);
+    EXPECT_EQ(retRecordChangeNum, recordChangeNum);
+}
+
+TEST(GetPDR, testBadDecodeRequest)
+{
+    std::array<uint8_t, PLDM_GET_PDR_REQ_BYTES> requestMsg{};
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = decode_get_pdr_req(req, requestMsg.size(), NULL, NULL, NULL, NULL,
+                                 NULL);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(GetPDR, testGoodEncodeRequest)
+{
+    uint32_t record_hndl = 0;
+    uint32_t data_transfer_hndl = 0;
+    uint8_t transfer_op_flag = PLDM_GET_FIRSTPART;
+    uint16_t request_cnt = 20;
+    uint16_t record_chg_num = 0;
+
+    std::vector<uint8_t> requestMsg(hdrSize + PLDM_GET_PDR_REQ_BYTES);
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = encode_get_pdr_req(0, record_hndl, data_transfer_hndl,
+                                 transfer_op_flag, request_cnt, record_chg_num,
+                                 request, PLDM_GET_PDR_REQ_BYTES);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    struct pldm_get_pdr_req* req =
+        reinterpret_cast<struct pldm_get_pdr_req*>(request->payload);
+    EXPECT_EQ(record_hndl, req->record_handle);
+    EXPECT_EQ(data_transfer_hndl, req->data_transfer_handle);
+    EXPECT_EQ(transfer_op_flag, req->transfer_op_flag);
+    EXPECT_EQ(request_cnt, req->request_count);
+    EXPECT_EQ(record_chg_num, req->record_change_number);
+}
+
+TEST(GetPDR, testBadEncodeRequest)
+{
+    uint32_t record_hndl = 0;
+    uint32_t data_transfer_hndl = 0;
+    uint8_t transfer_op_flag = PLDM_GET_FIRSTPART;
+    uint16_t request_cnt = 32;
+    uint16_t record_chg_num = 0;
+
+    std::vector<uint8_t> requestMsg(hdrSize + PLDM_GET_PDR_REQ_BYTES);
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = encode_get_pdr_req(0, record_hndl, data_transfer_hndl,
+                                 transfer_op_flag, request_cnt, record_chg_num,
+                                 nullptr, PLDM_GET_PDR_REQ_BYTES);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = encode_get_pdr_req(0, record_hndl, data_transfer_hndl,
+                            transfer_op_flag, request_cnt, record_chg_num,
+                            request, PLDM_GET_PDR_REQ_BYTES + 1);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(GetPDR, testGoodDecodeResponse)
+{
+    const char* recordData = "123456789";
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint32_t nextRecordHndl = 0;
+    uint32_t nextDataTransferHndl = 0;
+    uint8_t transferFlag = PLDM_END;
+    constexpr uint16_t respCnt = 9;
+    uint8_t transferCRC = 96;
+    size_t recordDataLength = 32;
+    std::array<uint8_t, hdrSize + PLDM_GET_PDR_MIN_RESP_BYTES + respCnt +
+                            sizeof(transferCRC)>
+        responseMsg{};
+
+    uint8_t retCompletionCode = 0;
+    uint8_t retRecordData[32] = {0};
+    uint32_t retNextRecordHndl = 0;
+    uint32_t retNextDataTransferHndl = 0;
+    uint8_t retTransferFlag = 0;
+    uint16_t retRespCnt = 0;
+    uint8_t retTransferCRC = 0;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    struct pldm_get_pdr_resp* resp =
+        reinterpret_cast<struct pldm_get_pdr_resp*>(response->payload);
+    resp->completion_code = completionCode;
+    resp->next_record_handle = htole32(nextRecordHndl);
+    resp->next_data_transfer_handle = htole32(nextDataTransferHndl);
+    resp->transfer_flag = transferFlag;
+    resp->response_count = htole16(respCnt);
+    memcpy(resp->record_data, recordData, respCnt);
+    response->payload[PLDM_GET_PDR_MIN_RESP_BYTES + respCnt] = transferCRC;
+
+    auto rc = decode_get_pdr_resp(
+        response, responseMsg.size() - hdrSize, &retCompletionCode,
+        &retNextRecordHndl, &retNextDataTransferHndl, &retTransferFlag,
+        &retRespCnt, retRecordData, recordDataLength, &retTransferCRC);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(retCompletionCode, completionCode);
+    EXPECT_EQ(retNextRecordHndl, nextRecordHndl);
+    EXPECT_EQ(retNextDataTransferHndl, nextDataTransferHndl);
+    EXPECT_EQ(retTransferFlag, transferFlag);
+    EXPECT_EQ(retRespCnt, respCnt);
+    EXPECT_EQ(retTransferCRC, transferCRC);
+    EXPECT_EQ(0, memcmp(recordData, resp->record_data, respCnt));
+}
+
+TEST(GetPDR, testBadDecodeResponse)
+{
+    const char* recordData = "123456789";
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint32_t nextRecordHndl = 0;
+    uint32_t nextDataTransferHndl = 0;
+    uint8_t transferFlag = PLDM_END;
+    constexpr uint16_t respCnt = 9;
+    uint8_t transferCRC = 96;
+    size_t recordDataLength = 32;
+    std::array<uint8_t, hdrSize + PLDM_GET_PDR_MIN_RESP_BYTES + respCnt +
+                            sizeof(transferCRC)>
+        responseMsg{};
+
+    uint8_t retCompletionCode = 0;
+    uint8_t retRecordData[32] = {0};
+    uint32_t retNextRecordHndl = 0;
+    uint32_t retNextDataTransferHndl = 0;
+    uint8_t retTransferFlag = 0;
+    uint16_t retRespCnt = 0;
+    uint8_t retTransferCRC = 0;
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    struct pldm_get_pdr_resp* resp =
+        reinterpret_cast<struct pldm_get_pdr_resp*>(response->payload);
+    resp->completion_code = completionCode;
+    resp->next_record_handle = htole32(nextRecordHndl);
+    resp->next_data_transfer_handle = htole32(nextDataTransferHndl);
+    resp->transfer_flag = transferFlag;
+    resp->response_count = htole16(respCnt);
+    memcpy(resp->record_data, recordData, respCnt);
+    response->payload[PLDM_GET_PDR_MIN_RESP_BYTES + respCnt] = transferCRC;
+
+    auto rc = decode_get_pdr_resp(response, responseMsg.size() - hdrSize, NULL,
+                                  NULL, NULL, NULL, NULL, NULL, 0, NULL);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    rc = decode_get_pdr_resp(
+        response, responseMsg.size() - hdrSize - 1, &retCompletionCode,
+        &retNextRecordHndl, &retNextDataTransferHndl, &retTransferFlag,
+        &retRespCnt, retRecordData, recordDataLength, &retTransferCRC);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(SetNumericEffecterValue, testGoodDecodeRequest)
+{
+    std::array<uint8_t,
+               hdrSize + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES + 3>
+        requestMsg{};
+
+    uint16_t effecter_id = 32768;
+    uint8_t effecter_data_size = PLDM_EFFECTER_DATA_SIZE_UINT32;
+    uint32_t effecter_value = 123456789;
+
+    uint16_t reteffecter_id;
+    uint8_t reteffecter_data_size;
+    uint8_t reteffecter_value[4];
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_set_numeric_effecter_value_req* request =
+        reinterpret_cast<struct pldm_set_numeric_effecter_value_req*>(
+            req->payload);
+
+    request->effecter_id = effecter_id;
+    request->effecter_data_size = effecter_data_size;
+    memcpy(request->effecter_value, &effecter_value, sizeof(effecter_value));
+
+    auto rc = decode_set_numeric_effecter_value_req(
+        req, requestMsg.size() - hdrSize, &reteffecter_id,
+        &reteffecter_data_size, reinterpret_cast<uint8_t*>(&reteffecter_value));
+
+    uint32_t value = *(reinterpret_cast<uint32_t*>(&reteffecter_value[0]));
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(reteffecter_id, effecter_id);
+    EXPECT_EQ(reteffecter_data_size, effecter_data_size);
+    EXPECT_EQ(value, effecter_value);
+}
+
+TEST(SetNumericEffecterValue, testBadDecodeRequest)
+{
+    std::array<uint8_t, hdrSize + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES>
+        requestMsg{};
+
+    auto rc = decode_set_numeric_effecter_value_req(
+        NULL, requestMsg.size() - hdrSize, NULL, NULL, NULL);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    uint16_t effecter_id = 0x10;
+    uint8_t effecter_data_size = PLDM_EFFECTER_DATA_SIZE_UINT8;
+    uint8_t effecter_value = 1;
+
+    uint16_t reteffecter_id;
+    uint8_t reteffecter_data_size;
+    uint8_t reteffecter_value[4];
+
+    auto req = reinterpret_cast<pldm_msg*>(requestMsg.data());
+    struct pldm_set_numeric_effecter_value_req* request =
+        reinterpret_cast<struct pldm_set_numeric_effecter_value_req*>(
+            req->payload);
+
+    request->effecter_id = effecter_id;
+    request->effecter_data_size = effecter_data_size;
+    memcpy(request->effecter_value, &effecter_value, sizeof(effecter_value));
+
+    rc = decode_set_numeric_effecter_value_req(
+        req, requestMsg.size() - hdrSize - 1, &reteffecter_id,
+        &reteffecter_data_size, reinterpret_cast<uint8_t*>(&reteffecter_value));
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_LENGTH);
+}
+
+TEST(SetNumericEffecterValue, testGoodEncodeRequest)
+{
+    uint16_t effecter_id = 0;
+    uint8_t effecter_data_size = PLDM_EFFECTER_DATA_SIZE_UINT8;
+    uint8_t effecter_value = 1;
+
+    std::vector<uint8_t> requestMsg(
+        hdrSize + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES);
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = encode_set_numeric_effecter_value_req(
+        0, effecter_id, effecter_data_size,
+        reinterpret_cast<uint8_t*>(&effecter_value), request,
+        PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES);
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+
+    struct pldm_set_numeric_effecter_value_req* req =
+        reinterpret_cast<struct pldm_set_numeric_effecter_value_req*>(
+            request->payload);
+    EXPECT_EQ(effecter_id, req->effecter_id);
+    EXPECT_EQ(effecter_data_size, req->effecter_data_size);
+    EXPECT_EQ(effecter_value,
+              *(reinterpret_cast<uint8_t*>(&req->effecter_value[0])));
+}
+
+TEST(SetNumericEffecterValue, testBadEncodeRequest)
+{
+    std::vector<uint8_t> requestMsg(
+        hdrSize + PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES);
+    auto request = reinterpret_cast<pldm_msg*>(requestMsg.data());
+
+    auto rc = encode_set_numeric_effecter_value_req(
+        0, 0, 0, NULL, NULL, PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+
+    uint16_t effecter_value;
+    rc = encode_set_numeric_effecter_value_req(
+        0, 0, 6, reinterpret_cast<uint8_t*>(&effecter_value), request,
+        PLDM_SET_NUMERIC_EFFECTER_VALUE_MIN_REQ_BYTES);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(SetNumericEffecterValue, testGoodDecodeResponse)
+{
+    std::array<uint8_t, hdrSize + PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES>
+        responseMsg{};
+
+    uint8_t completion_code = 0xA0;
+
+    uint8_t retcompletion_code;
+
+    memcpy(responseMsg.data() + hdrSize, &completion_code,
+           sizeof(completion_code));
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_set_numeric_effecter_value_resp(
+        response, responseMsg.size() - hdrSize, &retcompletion_code);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completion_code, retcompletion_code);
+}
+
+TEST(SetNumericEffecterValue, testBadDecodeResponse)
+{
+    std::array<uint8_t, PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES>
+        responseMsg{};
+
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+
+    auto rc = decode_set_numeric_effecter_value_resp(response,
+                                                     responseMsg.size(), NULL);
+
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
+
+TEST(SetNumericEffecterValue, testGoodEncodeResponse)
+{
+    std::array<uint8_t, sizeof(pldm_msg_hdr) +
+                            PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES>
+        responseMsg{};
+    auto response = reinterpret_cast<pldm_msg*>(responseMsg.data());
+    uint8_t completionCode = 0;
+
+    auto rc = encode_set_numeric_effecter_value_resp(
+        0, PLDM_SUCCESS, response, PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES);
+
+    EXPECT_EQ(rc, PLDM_SUCCESS);
+    EXPECT_EQ(completionCode, response->payload[0]);
+}
+
+TEST(SetNumericEffecterValue, testBadEncodeResponse)
+{
+    auto rc = encode_set_numeric_effecter_value_resp(
+        0, PLDM_SUCCESS, NULL, PLDM_SET_NUMERIC_EFFECTER_VALUE_RESP_BYTES);
+    EXPECT_EQ(rc, PLDM_ERROR_INVALID_DATA);
+}
diff --git a/libpldm/tests/libpldm_utils_test.cpp b/libpldm/tests/libpldm_utils_test.cpp
new file mode 100644
index 0000000..990a62b
--- /dev/null
+++ b/libpldm/tests/libpldm_utils_test.cpp
@@ -0,0 +1,90 @@
+#include <cstring>
+#include <vector>
+
+#include "libpldm/utils.h"
+
+#include <gtest/gtest.h>
+
+TEST(Crc32, CheckSumTest)
+{
+    const char* password = "123456789";
+    auto checksum = crc32(password, 9);
+    EXPECT_EQ(checksum, 0xcbf43926);
+}
+
+TEST(Crc8, CheckSumTest)
+{
+    const char* data = "123456789";
+    auto checksum = crc8(data, 9);
+    EXPECT_EQ(checksum, 0xf4);
+}
+
+TEST(Ver2string, Ver2string)
+{
+    ver32_t version{0xf3, 0xf7, 0x10, 0x61};
+    const char* vstr = "3.7.10a";
+    char buffer[1024];
+    auto rc = ver2str(&version, buffer, sizeof(buffer));
+    EXPECT_EQ(rc, std::strlen(vstr));
+    EXPECT_STREQ(vstr, buffer);
+
+    version = {0x10, 0x01, 0xf7, 0x00};
+    vstr = "10.01.7";
+    rc = ver2str(&version, buffer, sizeof(buffer));
+    EXPECT_EQ(rc, std::strlen(vstr));
+    EXPECT_STREQ(vstr, buffer);
+
+    version = {0xf3, 0xf1, 0xff, 0x00};
+    vstr = "3.1";
+    rc = ver2str(&version, buffer, sizeof(buffer));
+    EXPECT_EQ(rc, std::strlen(vstr));
+    EXPECT_STREQ(vstr, buffer);
+
+    version = {0xf1, 0xf0, 0xff, 0x61};
+    vstr = "1.0a";
+    rc = ver2str(&version, buffer, sizeof(buffer));
+    EXPECT_EQ(rc, std::strlen(vstr));
+    EXPECT_STREQ(vstr, buffer);
+
+    rc = ver2str(&version, buffer, 3);
+    EXPECT_EQ(rc, 2);
+    EXPECT_STREQ("1.", buffer);
+
+    rc = ver2str(&version, buffer, 1);
+    EXPECT_EQ(rc, 0);
+
+    rc = ver2str(&version, buffer, 0);
+    EXPECT_EQ(rc, -1);
+}
+
+TEST(BcdConversion, BcdCoversion)
+{
+    EXPECT_EQ(12, bcd2dec8(0x12));
+    EXPECT_EQ(99, bcd2dec8(0x99));
+    EXPECT_EQ(1234, bcd2dec16(0x1234));
+    EXPECT_EQ(9999, bcd2dec16(0x9999));
+    EXPECT_EQ(12345678, bcd2dec32(0x12345678));
+    EXPECT_EQ(99999999, bcd2dec32(0x99999999));
+
+    EXPECT_EQ(0x12, dec2bcd8(12));
+    EXPECT_EQ(0x99, dec2bcd8(99));
+    EXPECT_EQ(0x1234, dec2bcd16(1234));
+    EXPECT_EQ(0x9999, dec2bcd16(9999));
+    EXPECT_EQ(0x12345678, dec2bcd32(12345678));
+    EXPECT_EQ(0x99999999, dec2bcd32(99999999));
+}
+
+TEST(TimeLegal, TimeLegal)
+{
+    EXPECT_EQ(true, is_time_legal(30, 25, 16, 18, 8, 2019));
+    EXPECT_EQ(true, is_time_legal(30, 25, 16, 29, 2, 2020)); // leap year
+
+    EXPECT_EQ(false, is_time_legal(30, 25, 16, 18, 8, 1960));  // year illegal
+    EXPECT_EQ(false, is_time_legal(30, 25, 16, 18, 15, 2019)); // month illegal
+    EXPECT_EQ(false, is_time_legal(30, 25, 16, 18, 0, 2019));  // month illegal
+    EXPECT_EQ(false, is_time_legal(30, 25, 16, 0, 8, 2019));   // day illegal
+    EXPECT_EQ(false, is_time_legal(30, 25, 16, 29, 2, 2019));  // day illegal
+    EXPECT_EQ(false, is_time_legal(30, 25, 25, 18, 8, 2019));  // hours illegal
+    EXPECT_EQ(false, is_time_legal(30, 70, 16, 18, 8, 2019)); // minutes illegal
+    EXPECT_EQ(false, is_time_legal(80, 25, 16, 18, 8, 2019)); // seconds illegal
+}
\ No newline at end of file
diff --git a/libpldm/tests/meson.build b/libpldm/tests/meson.build
new file mode 100644
index 0000000..08d2d19
--- /dev/null
+++ b/libpldm/tests/meson.build
@@ -0,0 +1,45 @@
+if get_option('oe-sdk').enabled()
+  # Setup OE SYSROOT
+  OECORE_TARGET_SYSROOT = run_command('sh', '-c', 'echo $OECORE_TARGET_SYSROOT').stdout().strip()
+  if OECORE_TARGET_SYSROOT == ''
+      error('Unable to get $OECORE_TARGET_SYSROOT, check your environment.')
+  endif
+  message('OE_SYSROOT: ' + OECORE_TARGET_SYSROOT)
+  rpath = ':'.join([OECORE_TARGET_SYSROOT + '/lib', OECORE_TARGET_SYSROOT + '/usr/lib'])
+  ld_so = run_command('sh', '-c', 'find ' + OECORE_TARGET_SYSROOT + '/lib/ld-*.so | sort -r -n | head -n1').stdout().strip()
+  dynamic_linker = ['-Wl,-dynamic-linker,' + ld_so]
+else
+  dynamic_linker = []
+endif
+
+gtest = dependency('gtest', main: true, disabler: true, required: true)
+gmock = dependency('gmock', disabler: true, required: true)
+
+tests = [
+  'libpldm_base_test',
+  'libpldm_platform_test',
+  'libpldm_bios_test',
+  'libpldm_bios_table_test',
+  'libpldm_fru_test',
+  'libpldm_utils_test',
+  'libpldm_pdr_test'
+]
+
+if get_option('oem-ibm').enabled()
+  tests += [
+    '../../oem/ibm/test/libpldm_fileio_test',
+  ]
+endif
+
+foreach t : tests
+  test(t, executable(t.underscorify(), t + '.cpp',
+                     implicit_include_directories: false,
+                     link_args: dynamic_linker,
+                     build_rpath: get_option('oe-sdk').enabled() ? rpath : '',
+                     dependencies: [
+                         libpldm,
+                         gtest,
+                         gmock]),
+       workdir: meson.current_source_dir())
+endforeach
+