Implement mock RPMB backend

The backend uses CppUMock for enabling the testing of upper RPMB layers.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I1289ffa335610a6558a6d133351b47005cb39b7d
diff --git a/components/service/rpmb/backend/mock/component.cmake b/components/service/rpmb/backend/mock/component.cmake
new file mode 100644
index 0000000..b75d6e3
--- /dev/null
+++ b/components/service/rpmb/backend/mock/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/rpmb_backend_mock.cpp"
+	)
diff --git a/components/service/rpmb/backend/mock/rpmb_backend_mock.cpp b/components/service/rpmb/backend/mock/rpmb_backend_mock.cpp
new file mode 100644
index 0000000..83bde95
--- /dev/null
+++ b/components/service/rpmb/backend/mock/rpmb_backend_mock.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTestExt/MockSupport.h>
+#include "rpmb_backend_mock.h"
+
+void rpmb_backend_mock_expect_get_dev_info(void *context, uint32_t dev_id,
+					   const struct rpmb_dev_info *dev_info,
+					   psa_status_t result)
+{
+	mock().expectOneCall("get_dev_info").
+		onObject(context).
+		withUnsignedIntParameter("dev_id", dev_id).
+		withOutputParameterReturning("dev_info", dev_info, sizeof(*dev_info)).
+		andReturnValue(result);
+}
+
+static psa_status_t rpmb_backend_mock_get_dev_info(void *context, uint32_t dev_id,
+						   struct rpmb_dev_info *dev_info)
+{
+	return mock().actualCall("get_dev_info").
+		onObject(context).
+		withUnsignedIntParameter("dev_id", dev_id).
+		withOutputParameter("dev_info", dev_info).
+		returnIntValue();
+}
+
+void rpmb_backend_mock_expect_data_request(
+	void *context, uint32_t dev_id, const struct rpmb_data_frame *request_frames,
+	size_t request_frame_count, const struct rpmb_data_frame *response_frames,
+	size_t response_frame_count_in, size_t *response_frame_count_out, psa_status_t result)
+{
+	size_t request_size = sizeof(*request_frames) * request_frame_count;
+	size_t response_size = sizeof(*response_frames) * (*response_frame_count_out);
+
+	mock().expectOneCall("data_request").
+		onObject(context).
+		withUnsignedIntParameter("dev_id", dev_id).
+		withMemoryBufferParameter("request_frames", (const unsigned char *)request_frames,
+					  request_size).
+		withUnsignedIntParameter("request_frame_count", request_frame_count).
+		withOutputParameterReturning("response_frames", response_frames, response_size).
+		withUnsignedIntParameter("response_frame_count_in", response_frame_count_in).
+		withOutputParameterReturning("response_frame_count_out", response_frame_count_out,
+					     sizeof(*response_frame_count_out)).
+		andReturnValue(result);
+}
+
+static psa_status_t rpmb_backend_mock_data_request(
+	void *context, uint32_t dev_id, const struct rpmb_data_frame *request_frames,
+	size_t request_frame_count, struct rpmb_data_frame *response_frames,
+	size_t *response_frame_count)
+{
+	size_t request_size = sizeof(*request_frames) * request_frame_count;
+
+	return mock().actualCall("data_request").
+		onObject(context).
+		withUnsignedIntParameter("dev_id", dev_id).
+		withMemoryBufferParameter("request_frames", (const unsigned char *)request_frames,
+					  request_size).
+		withUnsignedIntParameter("request_frame_count", request_frame_count).
+		withOutputParameter("response_frames", response_frames).
+		withUnsignedIntParameter("response_frame_count_in", *response_frame_count).
+		withOutputParameter("response_frame_count_out", response_frame_count).
+		returnIntValue();
+}
+
+struct rpmb_backend *rpmb_backend_mock_init(struct rpmb_backend_mock *context)
+{
+	static const struct rpmb_backend_interface interface = {
+		rpmb_backend_mock_get_dev_info,
+		rpmb_backend_mock_data_request,
+	};
+
+	if (!context)
+		return NULL;
+
+	context->backend.context = context;
+	context->backend.interface = &interface;
+
+	return &context->backend;
+}
+
+void rpmb_backend_mock_deinit(struct rpmb_backend_mock *context)
+{
+	*context = (struct rpmb_backend_mock){ 0 };
+}
diff --git a/components/service/rpmb/backend/mock/rpmb_backend_mock.h b/components/service/rpmb/backend/mock/rpmb_backend_mock.h
new file mode 100644
index 0000000..1268d42
--- /dev/null
+++ b/components/service/rpmb/backend/mock/rpmb_backend_mock.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef RPMB_BACKEND_MOCK_H_
+#define RPMB_BACKEND_MOCK_H_
+
+#include "../rpmb_backend.h"
+#include <stdbool.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Mock RPMB backend
+ *
+ * Backend for testing purposes
+ */
+struct rpmb_backend_mock {
+	struct rpmb_backend backend;
+};
+
+struct rpmb_backend *rpmb_backend_mock_init(struct rpmb_backend_mock *context);
+void rpmb_backend_mock_deinit(struct rpmb_backend_mock *context);
+
+void rpmb_backend_mock_expect_get_dev_info(void *context, uint32_t dev_id,
+					   const struct rpmb_dev_info *dev_info,
+					   psa_status_t result);
+
+void rpmb_backend_mock_expect_data_request(
+	void *context, uint32_t dev_id, const struct rpmb_data_frame *request_frames,
+	size_t request_frame_count, const struct rpmb_data_frame *response_frames,
+	size_t response_frame_count_in, size_t *response_frame_count_out, psa_status_t result);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* RPMB_BACKEND_MOCK_H_ */
diff --git a/components/service/rpmb/backend/mock/test/component.cmake b/components/service/rpmb/backend/mock/test/component.cmake
new file mode 100644
index 0000000..86506bf
--- /dev/null
+++ b/components/service/rpmb/backend/mock/test/component.cmake
@@ -0,0 +1,13 @@
+#-------------------------------------------------------------------------------
+# Copyright (c) 2023, Arm Limited and Contributors. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+#-------------------------------------------------------------------------------
+if (NOT DEFINED TGT)
+	message(FATAL_ERROR "mandatory parameter TGT is not defined.")
+endif()
+
+target_sources(${TGT} PRIVATE
+	"${CMAKE_CURRENT_LIST_DIR}/test_rpmb_backend_mock.cpp"
+	)
diff --git a/components/service/rpmb/backend/mock/test/test_rpmb_backend_mock.cpp b/components/service/rpmb/backend/mock/test/test_rpmb_backend_mock.cpp
new file mode 100644
index 0000000..594ba3c
--- /dev/null
+++ b/components/service/rpmb/backend/mock/test/test_rpmb_backend_mock.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2023, Arm Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <CppUTest/TestHarness.h>
+#include "../rpmb_backend_mock.h"
+#include <string.h>
+
+TEST_GROUP(rpmb_backend_mock) {
+	TEST_SETUP()
+	{
+		backend = rpmb_backend_mock_init(&mock_backend);
+	}
+
+	TEST_TEARDOWN()
+	{
+		rpmb_backend_mock_deinit(&mock_backend);
+	}
+
+	struct rpmb_backend *backend;
+	struct rpmb_backend_mock mock_backend;
+	const uint32_t dev_id = 1;
+};
+
+TEST(rpmb_backend_mock, get_dev_info)
+{
+	const struct rpmb_dev_info expected_dev_info = {
+		.cid = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+			0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+		.rpmb_size_mult = 100
+	};
+	struct rpmb_dev_info dev_info = { 0 };
+	psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+	rpmb_backend_mock_expect_get_dev_info(backend, dev_id, &expected_dev_info, PSA_SUCCESS);
+
+	status = rpmb_backend_get_dev_info(backend, dev_id, &dev_info);
+	LONGS_EQUAL(PSA_SUCCESS, status);
+	MEMCMP_EQUAL(&expected_dev_info, &dev_info, sizeof(expected_dev_info));
+}
+
+TEST(rpmb_backend_mock, data_request)
+{
+	struct rpmb_data_frame request_frames[2];
+	struct rpmb_data_frame expected_response_frames[3];
+	struct rpmb_data_frame response_frames[3] = { 0 };
+	size_t expected_response_frame_count = 3;
+	size_t response_frame_count = 4;
+	psa_status_t status = PSA_ERROR_GENERIC_ERROR;
+
+	memset(request_frames, 0x11, sizeof(request_frames));
+	memset(expected_response_frames, 0x22, sizeof(response_frames));
+
+	rpmb_backend_mock_expect_data_request(backend, dev_id,
+					      request_frames, 2,
+					      expected_response_frames, 4, &expected_response_frame_count,
+					      PSA_SUCCESS);
+
+	status = rpmb_backend_data_request(backend, dev_id, request_frames, 2,
+					   response_frames, &response_frame_count);
+	LONGS_EQUAL(PSA_SUCCESS, status);
+	UNSIGNED_LONGS_EQUAL(expected_response_frame_count, response_frame_count);
+	MEMCMP_EQUAL(&expected_response_frames, &response_frames, sizeof(expected_response_frames));
+}
\ No newline at end of file