dsp: base: Add encode req & decode resp for MultipartReceive command

Added encode/decode APIs for MultipartReceive command(0x09) which is
defined in DSP0240 Version 1.2.0 section 9.6.

Change-Id: I577997978728cbaa9132e0685cdd85e277427554
Signed-off-by: Dung Cao <dung@os.amperecomputing.com>
Signed-off-by: Chau Ly <chaul@amperecomputing.com>
diff --git a/tests/dsp/base.cpp b/tests/dsp/base.cpp
index 5e71c80..7b5bfcf 100644
--- a/tests/dsp/base.cpp
+++ b/tests/dsp/base.cpp
@@ -6,6 +6,8 @@
 #include <cstring>
 #include <vector>
 
+#include "msgbuf.h"
+
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
@@ -759,6 +761,213 @@
               PLDM_ERROR_INVALID_DATA);
 }
 
+#ifdef LIBPLDM_API_TESTING
+TEST(EncodeMultipartReceiveRequest, GoodTest)
+{
+    uint8_t instance_id = 0;
+
+    const struct pldm_multipart_receive_req req_data = {
+        PLDM_BASE, PLDM_XFER_FIRST_PART, 0x01, 0x10, 0x00, 0x10};
+
+    std::array<uint8_t, PLDM_MULTIPART_RECEIVE_REQ_BYTES> requestMsg = {
+        PLDM_BASE, PLDM_XFER_FIRST_PART,
+        0x01,      0x00,
+        0x00,      0x00,
+        0x10,      0x00,
+        0x00,      0x00,
+        0x00,      0x00,
+        0x00,      0x00,
+        0x10,      0x00,
+        0x00,      0x00};
+
+    PLDM_MSG_DEFINE_P(requestPtr, PLDM_MULTIPART_RECEIVE_REQ_BYTES);
+    auto rc = encode_base_multipart_receive_req(
+        instance_id, &req_data, requestPtr, PLDM_MULTIPART_RECEIVE_REQ_BYTES);
+
+    ASSERT_EQ(rc, 0);
+    EXPECT_EQ(
+        0, memcmp(requestPtr->payload, requestMsg.data(), sizeof(requestMsg)));
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(EncodeMultipartReceiveRequest, BadTestUnAllocatedPtrParams)
+{
+    uint8_t instance_id = 0;
+    int rc;
+
+    const struct pldm_multipart_receive_req req_data = {
+        PLDM_BASE, PLDM_XFER_FIRST_PART, 0x01, 0x10, 0x00, 0x10};
+
+    PLDM_MSG_DEFINE_P(requestPtr, PLDM_MULTIPART_RECEIVE_REQ_BYTES);
+    rc = encode_base_multipart_receive_req(instance_id, nullptr, requestPtr,
+                                           PLDM_MULTIPART_RECEIVE_REQ_BYTES);
+    EXPECT_EQ(rc, -EINVAL);
+
+    rc = encode_base_multipart_receive_req(instance_id, &req_data, nullptr,
+                                           PLDM_MULTIPART_RECEIVE_REQ_BYTES);
+    EXPECT_EQ(rc, -EINVAL);
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(EncodeMultipartReceiveRequest, BadTestInvalidExpectedOutputMsgLength)
+{
+    uint8_t instance_id = 0;
+    int rc;
+
+    const struct pldm_multipart_receive_req req_data = {
+        PLDM_BASE, PLDM_XFER_FIRST_PART, 0x01, 0x10, 0x00, 0x10};
+
+    PLDM_MSG_DEFINE_P(requestPtr, PLDM_MULTIPART_RECEIVE_REQ_BYTES);
+
+    rc = encode_base_multipart_receive_req(instance_id, &req_data, requestPtr,
+                                           1);
+    EXPECT_EQ(rc, -EOVERFLOW);
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(DecodeMultipartReceiveResponse, GoodTest)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint8_t transferFlag = PLDM_BASE_MULTIPART_RECEIVE_TRANSFER_FLAG_END;
+    uint32_t nextDataTransferHandle = 0x15;
+    static constexpr const uint32_t dataLength = 9;
+    std::vector<uint8_t> data = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+    uint32_t dataIntegrityChecksum = 0x3C;
+
+    struct pldm_multipart_receive_resp resp_data = {};
+
+    PLDM_MSGBUF_DEFINE_P(buf);
+    int rc;
+
+    static constexpr const size_t payload_length =
+        PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES + dataLength +
+        sizeof(dataIntegrityChecksum);
+    PLDM_MSG_DEFINE_P(responseMsg, payload_length);
+
+    rc = pldm_msgbuf_init_errno(buf, 0, responseMsg->payload, payload_length);
+    ASSERT_EQ(rc, 0);
+
+    pldm_msgbuf_insert_uint8(buf, completionCode);
+    pldm_msgbuf_insert_uint8(buf, transferFlag);
+    pldm_msgbuf_insert_uint32(buf, nextDataTransferHandle);
+    pldm_msgbuf_insert_uint32(buf, dataLength);
+    rc = pldm_msgbuf_insert_array_uint8(buf, dataLength, data.data(),
+                                        dataLength);
+    EXPECT_EQ(rc, 0);
+    pldm_msgbuf_insert_uint32(buf, dataIntegrityChecksum);
+
+    ASSERT_EQ(pldm_msgbuf_complete_consumed(buf), 0);
+
+    uint32_t respDataIntegrityChecksum = 0;
+
+    rc = decode_base_multipart_receive_resp(
+        responseMsg, payload_length, &resp_data, &respDataIntegrityChecksum);
+
+    ASSERT_EQ(rc, 0);
+    EXPECT_EQ(resp_data.completion_code, completionCode);
+    EXPECT_EQ(resp_data.transfer_flag, transferFlag);
+    EXPECT_EQ(resp_data.next_transfer_handle, nextDataTransferHandle);
+    EXPECT_EQ(resp_data.data.length, dataLength);
+    EXPECT_EQ(0,
+              memcmp(data.data(), resp_data.data.ptr, resp_data.data.length));
+    EXPECT_EQ(respDataIntegrityChecksum, dataIntegrityChecksum);
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(DecodeMultipartReceiveResponse, BadTestUnAllocatedPtrParams)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint8_t transferFlag = PLDM_BASE_MULTIPART_RECEIVE_TRANSFER_FLAG_END;
+    uint32_t nextDataTransferHandle = 0x15;
+    static constexpr const uint32_t dataLength = 9;
+    std::vector<uint8_t> data = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+    uint32_t dataIntegrityChecksum = 0x3C;
+
+    struct pldm_multipart_receive_resp resp_data = {};
+
+    PLDM_MSGBUF_DEFINE_P(buf);
+    int rc;
+
+    static constexpr const size_t payload_length =
+        PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES + dataLength +
+        sizeof(dataIntegrityChecksum);
+    PLDM_MSG_DEFINE_P(responseMsg, payload_length);
+
+    rc = pldm_msgbuf_init_errno(buf, 0, responseMsg->payload, payload_length);
+    ASSERT_EQ(rc, 0);
+
+    pldm_msgbuf_insert_uint8(buf, completionCode);
+    pldm_msgbuf_insert_uint8(buf, transferFlag);
+    pldm_msgbuf_insert_uint32(buf, nextDataTransferHandle);
+    pldm_msgbuf_insert_uint32(buf, dataLength);
+    rc = pldm_msgbuf_insert_array_uint8(buf, dataLength, data.data(),
+                                        dataLength);
+    EXPECT_EQ(rc, 0);
+    pldm_msgbuf_insert_uint32(buf, dataIntegrityChecksum);
+
+    ASSERT_EQ(pldm_msgbuf_complete_consumed(buf), 0);
+
+    uint32_t respDataIntegrityChecksum = 0;
+
+    rc = decode_base_multipart_receive_resp(nullptr, payload_length, &resp_data,
+                                            &respDataIntegrityChecksum);
+
+    EXPECT_EQ(rc, -EINVAL);
+
+    rc = decode_base_multipart_receive_resp(
+        responseMsg, payload_length, nullptr, &respDataIntegrityChecksum);
+
+    EXPECT_EQ(rc, -EINVAL);
+}
+#endif
+
+#ifdef LIBPLDM_API_TESTING
+TEST(DecodeMultipartReceiveResponse, BadTestInvalidExpectedInputMsgLength)
+{
+    uint8_t completionCode = PLDM_SUCCESS;
+    uint8_t transferFlag = PLDM_BASE_MULTIPART_RECEIVE_TRANSFER_FLAG_END;
+    uint32_t nextDataTransferHandle = 0x15;
+    static constexpr const uint32_t dataLength = 9;
+    std::vector<uint8_t> data = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+    uint32_t dataIntegrityChecksum = 0x3C;
+
+    struct pldm_multipart_receive_resp resp_data = {};
+
+    PLDM_MSGBUF_DEFINE_P(buf);
+    int rc;
+
+    static constexpr const size_t payload_length =
+        PLDM_BASE_MULTIPART_RECEIVE_RESP_MIN_BYTES + dataLength +
+        sizeof(dataIntegrityChecksum);
+    PLDM_MSG_DEFINE_P(responseMsg, payload_length);
+
+    rc = pldm_msgbuf_init_errno(buf, 0, responseMsg->payload, payload_length);
+    ASSERT_EQ(rc, 0);
+
+    pldm_msgbuf_insert_uint8(buf, completionCode);
+    pldm_msgbuf_insert_uint8(buf, transferFlag);
+    pldm_msgbuf_insert_uint32(buf, nextDataTransferHandle);
+    pldm_msgbuf_insert_uint32(buf, dataLength);
+    rc = pldm_msgbuf_insert_array_uint8(buf, dataLength, data.data(),
+                                        dataLength);
+    EXPECT_EQ(rc, 0);
+    pldm_msgbuf_insert_uint32(buf, dataIntegrityChecksum);
+
+    ASSERT_EQ(pldm_msgbuf_complete_consumed(buf), 0);
+
+    uint32_t respDataIntegrityChecksum = 0;
+
+    rc = decode_base_multipart_receive_resp(responseMsg, 0, &resp_data,
+                                            &respDataIntegrityChecksum);
+
+    EXPECT_EQ(rc, -EOVERFLOW);
+}
+#endif
+
 TEST(CcOnlyResponse, testEncode)
 {
     struct pldm_msg responseMsg;