msgbuf: Add pldm_msgbuf_copy_string_utf16()

Safely copy a NUL-terminated UTF16-{BE,LE} string between msgbuf
instances.

Change-Id: If96df9598f17ac771d75f0831be270c5e0139578
Signed-off-by: Andrew Jeffery <andrew@codeconstruct.com.au>
diff --git a/tests/msgbuf.cpp b/tests/msgbuf.cpp
index f2c9aca..c84acce 100644
--- a/tests/msgbuf.cpp
+++ b/tests/msgbuf.cpp
@@ -1434,3 +1434,77 @@
     ASSERT_EQ(pldm_msgbuf_destroy(dst), 0);
     ASSERT_EQ(pldm_msgbuf_destroy(src), -EOVERFLOW);
 }
+
+TEST(msgbuf, pldm_msgbuf_copy_utf16_exact)
+{
+    const char16_t msg[] = u"this is a message";
+
+    struct pldm_msgbuf _src;
+    struct pldm_msgbuf* src = &_src;
+    struct pldm_msgbuf _dst;
+    struct pldm_msgbuf* dst = &_dst;
+
+    char buf[sizeof(msg)] = {};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(src, 0, msg, sizeof(msg)), 0);
+    ASSERT_EQ(pldm_msgbuf_init_errno(dst, 0, buf, sizeof(buf)), 0);
+    EXPECT_EQ(pldm_msgbuf_copy_string_utf16(dst, src), 0);
+    ASSERT_EQ(pldm_msgbuf_destroy(dst), 0);
+    ASSERT_EQ(pldm_msgbuf_destroy(src), 0);
+    EXPECT_EQ(0, memcmp(buf, msg, sizeof(msg)));
+}
+
+TEST(msgbuf, pldm_msgbuf_copy_utf16_dst_exceeds_src)
+{
+    const char16_t msg[] = u"this is a message";
+
+    struct pldm_msgbuf _src;
+    struct pldm_msgbuf* src = &_src;
+    struct pldm_msgbuf _dst;
+    struct pldm_msgbuf* dst = &_dst;
+
+    char buf[sizeof(msg) + 1] = {};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(src, 0, msg, sizeof(msg)), 0);
+    ASSERT_EQ(pldm_msgbuf_init_errno(dst, 0, buf, sizeof(buf)), 0);
+    EXPECT_EQ(pldm_msgbuf_copy_string_utf16(dst, src), 0);
+    ASSERT_EQ(pldm_msgbuf_destroy(dst), 0);
+    ASSERT_EQ(pldm_msgbuf_destroy(src), 0);
+    EXPECT_EQ(0, memcmp(buf, msg, sizeof(msg)));
+}
+
+TEST(msgbuf, pldm_msgbuf_copy_utf16_src_exceeds_dst)
+{
+    const char16_t msg[] = u"this is a message";
+
+    struct pldm_msgbuf _src;
+    struct pldm_msgbuf* src = &_src;
+    struct pldm_msgbuf _dst;
+    struct pldm_msgbuf* dst = &_dst;
+
+    char buf[sizeof(msg) - 1] = {};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(src, 0, msg, sizeof(msg)), 0);
+    ASSERT_EQ(pldm_msgbuf_init_errno(dst, 0, buf, sizeof(buf)), 0);
+    EXPECT_EQ(pldm_msgbuf_copy_string_utf16(dst, src), -EOVERFLOW);
+    ASSERT_EQ(pldm_msgbuf_destroy(dst), -EOVERFLOW);
+    ASSERT_EQ(pldm_msgbuf_destroy(src), 0);
+}
+
+TEST(msgbuf, pldm_msgbuf_copy_utf16_unterminated_src)
+{
+    const char16_t msg[] = {u'a'};
+
+    struct pldm_msgbuf _src;
+    struct pldm_msgbuf* src = &_src;
+    struct pldm_msgbuf _dst;
+    struct pldm_msgbuf* dst = &_dst;
+
+    char buf[sizeof(msg)] = {};
+
+    ASSERT_EQ(pldm_msgbuf_init_errno(src, 0, msg, sizeof(msg)), 0);
+    ASSERT_EQ(pldm_msgbuf_init_errno(dst, 0, buf, sizeof(buf)), 0);
+    EXPECT_EQ(pldm_msgbuf_copy_string_utf16(dst, src), -EOVERFLOW);
+    ASSERT_EQ(pldm_msgbuf_destroy(dst), 0);
+    ASSERT_EQ(pldm_msgbuf_destroy(src), -EOVERFLOW);
+}