Add mock RPC interface

Add comparators for the RPC parameter types and mock RPC interface.

Signed-off-by: Imre Kis <imre.kis@arm.com>
Change-Id: I9a927cc35a5dcb346d4c2e2a04b34c8a8d2460fb
diff --git a/components/rpc/common/test/call_param_buf_comparator.h b/components/rpc/common/test/call_param_buf_comparator.h
new file mode 100644
index 0000000..6bfa727
--- /dev/null
+++ b/components/rpc/common/test/call_param_buf_comparator.h
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef CALL_PARAM_BUF_COMPARATOR_H_
+#define CALL_PARAM_BUF_COMPARATOR_H_
+
+#include <CppUTestExt/MockSupport.h>
+#include "../endpoint/rpc_interface.h"
+
+class call_param_buf_comparator : public MockNamedValueComparator
+{
+public:
+	enum check_mode {
+		mode_normal = 0,
+		mode_ignore_data_len
+	};
+
+	call_param_buf_comparator(check_mode mode = mode_normal) : mode(mode)
+	{
+	}
+
+	virtual bool isEqual(const void *object1, const void *object2)
+	{
+		struct call_param_buf *buf1 = (struct call_param_buf *)object1;
+		struct call_param_buf *buf2 = (struct call_param_buf *)object2;
+
+		return (buf1->size == buf2->size) &&
+			(mode == mode_ignore_data_len || (buf1->data_len == buf2->data_len)) &&
+			(buf1->data == buf2->data);
+	}
+
+	// LCOV_EXCL_START
+	virtual SimpleString valueToString(const void *object)
+	{
+		struct call_param_buf *buf = (struct call_param_buf *)object;
+
+		return StringFromFormat("<size = %zu, data_len = %zu%s, data = %p>",
+					buf->size, buf->data_len,
+					(mode == mode_ignore_data_len) ? " (ignored)" : "",
+					buf->data);
+	}
+	// LCOV_EXCL_STOP
+
+private:
+	check_mode mode;
+};
+
+#endif /* CALL_PARAM_BUF_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/call_req_comparator.h b/components/rpc/common/test/call_req_comparator.h
new file mode 100644
index 0000000..753bab2
--- /dev/null
+++ b/components/rpc/common/test/call_req_comparator.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef CALL_REQ_COMPARATOR_H_
+#define CALL_REQ_COMPARATOR_H_
+
+#include <CppUTestExt/MockSupport.h>
+#include <inttypes.h>
+#include "call_param_buf_comparator.h"
+
+class call_req_comparator : public MockNamedValueComparator
+{
+public:
+	enum check_mode {
+		mode_normal = 0,
+		mode_ignore_opstatus
+	};
+
+	call_req_comparator(check_mode mode) : mode(mode)
+	{
+	}
+
+	virtual bool isEqual(const void *object1, const void *object2)
+	{
+		struct call_req *req1 = (struct call_req *)object1;
+		struct call_req *req2 = (struct call_req *)object2;
+		call_param_buf_comparator buf_comparator_normal;
+		call_param_buf_comparator buf_comparator_ignore_data_len(
+			call_param_buf_comparator::mode_ignore_data_len);
+
+		return (req1->caller_id == req2->caller_id) &&
+			(req1->interface_id == req2->interface_id) &&
+			(req1->opcode == req2->opcode) &&
+			(req1->encoding == req2->encoding) &&
+			(mode == mode_ignore_opstatus || req1->opstatus == req2->opstatus) &&
+			buf_comparator_normal.isEqual(&req1->req_buf, &req2->req_buf) &&
+			buf_comparator_ignore_data_len.isEqual(&req1->resp_buf, &req2->resp_buf);
+	}
+
+	// LCOV_EXCL_START
+	virtual SimpleString valueToString(const void *object)
+	{
+		struct call_req *req = (struct call_req *)object;
+		call_param_buf_comparator buf_comparator_normal;
+		call_param_buf_comparator buf_comparator_ignore_data_len(
+			call_param_buf_comparator::mode_ignore_data_len);
+		SimpleString req_buf_str = buf_comparator_normal.valueToString(&req->req_buf);
+		SimpleString resp_buf_str =
+			buf_comparator_ignore_data_len.valueToString(&req->resp_buf);
+
+		return StringFromFormat("caller_id = 0x%" PRIx32 ", interface_id = %" PRIu32 ", " \
+					"opcode = %" PRIu32 ", encoding = %" PRIu32 ", " \
+					"opstatus = 0x%" PRIx64 "%s, req_buf = %s, " \
+					"resp_buf = %s",
+					req->caller_id, req->interface_id, req->opcode,
+					req->encoding, req->opstatus,
+					(mode == mode_ignore_opstatus) ? " (ignore)" : "",
+					req_buf_str.asCharString(), resp_buf_str.asCharString());
+	}
+	// LCOV_EXCL_STOP
+
+private:
+	check_mode mode;
+};
+
+#endif /* CALL_REQ_COMPARATOR_H_ */
diff --git a/components/rpc/common/test/mock_rpc_interface.cpp b/components/rpc/common/test/mock_rpc_interface.cpp
new file mode 100644
index 0000000..af3836d
--- /dev/null
+++ b/components/rpc/common/test/mock_rpc_interface.cpp
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <CppUTestExt/MockSupport.h>
+#include "mock_rpc_interface.h"
+#include "call_req_comparator.h"
+
+static call_req_comparator req_comparator(call_req_comparator::mode_ignore_opstatus);
+
+void mock_rpc_interface_init(void)
+{
+	mock().installComparator("call_req", req_comparator);
+}
+
+void expect_mock_rpc_interface_receive(struct rpc_interface *iface,
+				       const struct call_req *req, rpc_status_t result)
+{
+	mock().expectOneCall("rpc_interface_receive").
+		onObject(iface).
+		withOutputParameterReturning("opstatus", &req->opstatus, sizeof(req->opstatus)).
+		withOutputParameterReturning("resp_buf_data_len", &req->resp_buf.data_len,
+					     sizeof(req->resp_buf.data_len)).
+		withParameterOfType("call_req", "req", req).
+		andReturnValue(result);
+}
+
+rpc_status_t mock_rpc_interface_receive(struct rpc_interface *iface,
+					struct call_req *req)
+{
+	return mock().actualCall("rpc_interface_receive").
+		onObject(iface).
+		withOutputParameter("opstatus", &req->opstatus).
+		withOutputParameter("resp_buf_data_len", &req->resp_buf.data_len).
+		withParameterOfType("call_req", "req", req).
+		returnIntValue();
+}
diff --git a/components/rpc/common/test/mock_rpc_interface.h b/components/rpc/common/test/mock_rpc_interface.h
new file mode 100644
index 0000000..7e80c4a
--- /dev/null
+++ b/components/rpc/common/test/mock_rpc_interface.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#ifndef MOCK_RPC_INTERFACE_H_
+#define MOCK_RPC_INTERFACE_H_
+
+#include "../endpoint/rpc_interface.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void mock_rpc_interface_init(void);
+
+void expect_mock_rpc_interface_receive(struct rpc_interface *iface,
+				       const struct call_req *req, rpc_status_t result);
+
+rpc_status_t mock_rpc_interface_receive(struct rpc_interface *iface,
+					struct call_req *req);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MOCK_RPC_INTERFACE_H_ */
diff --git a/components/rpc/common/test/test_mock_rpc_interface.cpp b/components/rpc/common/test/test_mock_rpc_interface.cpp
new file mode 100644
index 0000000..f3390f0
--- /dev/null
+++ b/components/rpc/common/test/test_mock_rpc_interface.cpp
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/*
+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
+ */
+
+#include <CppUTest/TestHarness.h>
+#include <CppUTestExt/MockSupport.h>
+#include <string.h>
+#include "mock_rpc_interface.h"
+
+TEST_GROUP(mock_rpc_interface)
+{
+	TEST_SETUP()
+	{
+		mock_rpc_interface_init();
+		memset(&iface, 0x00, sizeof(iface));
+	}
+
+	TEST_TEARDOWN()
+	{
+		mock().checkExpectations();
+		mock().removeAllComparatorsAndCopiers();
+		mock().clear();
+	}
+
+	struct rpc_interface iface;
+};
+
+TEST(mock_rpc_interface, receive)
+{
+	rpc_status_t res = TS_RPC_ERROR_INTERNAL;
+	struct call_req expected_req = { 0 };
+	struct call_req req = { 0 };
+
+	iface.context = (void *)1;
+	iface.receive = mock_rpc_interface_receive;
+
+	expected_req.caller_id = 0x01234567;
+	expected_req.interface_id = 0x89abcdef;
+	expected_req.opcode = 0xfedcba98;
+	expected_req.encoding = 0x76543210;
+	expected_req.opstatus = (rpc_opstatus_t)-1;
+
+	expected_req.req_buf.size = 1;
+	expected_req.req_buf.data_len = 2;
+	expected_req.req_buf.data = (void *)3;
+
+	expected_req.resp_buf.size = 4;
+	expected_req.resp_buf.data_len = 5;
+	expected_req.resp_buf.data = (void *)6;
+
+	memcpy(&req, &expected_req, sizeof(req));
+	req.opstatus = 0;
+	req.resp_buf.data_len = 0;
+
+	expect_mock_rpc_interface_receive(&iface, &expected_req, res);
+	LONGS_EQUAL(res, mock_rpc_interface_receive(&iface, &req));
+
+	UNSIGNED_LONGLONGS_EQUAL(expected_req.opstatus, req.opstatus);
+	UNSIGNED_LONGLONGS_EQUAL(expected_req.resp_buf.data_len, req.resp_buf.data_len);
+}
diff --git a/components/rpc/common/tests.cmake b/components/rpc/common/tests.cmake
new file mode 100644
index 0000000..edacfca
--- /dev/null
+++ b/components/rpc/common/tests.cmake
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2021, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+include(UnitTest)
+
+unit_test_add_suite(
+	NAME mock_rpc_interface
+	SOURCES
+		${CMAKE_CURRENT_LIST_DIR}/test/mock_rpc_interface.cpp
+		${CMAKE_CURRENT_LIST_DIR}/test/test_mock_rpc_interface.cpp
+	INCLUDE_DIRECTORIES
+		${CMAKE_CURRENT_LIST_DIR}/test
+		${UNIT_TEST_PROJECT_PATH}
+		${UNIT_TEST_PROJECT_PATH}/components/rpc/common/interface
+	COMPILE_DEFINITIONS
+		-DARM64
+)