From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.remote-ip=100.103.45.18 ARC-Seal: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; cv=none; t=1794269353; b=t2PaBCzu/tDR6fNLzAmdH2XBYIugQhKjhHC3SxiK7SzFCWpGpFkAxjYaj2PL//8mKVrk iIcARDkN48VueFOoLfSkxe3p3lR/jVsfRjjq0/4NA/t0CpWXylyABpedHf5grqZGayDt8 vrhp6Mj+ISomkR8xZoBllvsZg8vt29PsJEyRGFdmD0SO9LQ7YZTaJyZ9Uv5obd7urnzIg QlRZTO4hYm4LOQE3t0ec2vQQXeh0ljeFOtvckuR61wQ9w6/zdSCqbCm/P2UMnkD0Zz9gG YyqC3D+AaKdX4ZRojKDJVM+ngYV7O3r/P/EHm0z/bwrETYtxA6AWhgNa3gcrA3+SZpg== ARC-Message-Signature: i=1; d=subspace.kernel.org; s=arc20261015; a=rsa-sha256; c=relaxed/relaxed; t=1794269353; h=Received:DKIM-Signature:Date:To:From:Subject:Message-Id; bh=2sADtvR8xRruKhbTehK05Ksdl+O9CyvkErm6+5ZybOw=; b=2bOJRP/UvLjNmeuMt0+J6yhRlPaexvRGsmMdmxUVfbVKEbTbQ9SMEwYvWPu24G1QZdq+ 24493jdaOvaCRN8eMoJAQzNUCuj2vdFIgBMWuLiG1gKvJdXeqy1/c24xwzD2srF+iimJO sdxOI088upDdeTsSBGD5KA6SI7Z8TMy/bUR3Hl2WBOsndpNxpptbIZvIl89BR1wMGrxk6 M1iqP+BIFmCPmIkCklDpUBMVXbYjHv9hXsVC9nJ7b4vjGxCdOiopns3afkalmF8niFFRG RTgdEXeOXUZm1INw7cOBal8WrzyqgAZp1SHoKGgM4xbMQO4X5oy/Y5q7r5lGqdMFkew== ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass header.d=linux-foundation.org header.i=@linux-foundation.org header.a=rsa-sha256 header.s=korg header.b=tVJsxRxD; arc=none smtp.remote-ip=100.103.45.18 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (prime256v1)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 0D5E8606A31C for ; Tue, 10 Nov 2026 00:09:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linux-foundation.org header.i=@linux-foundation.org header.a=rsa-sha256 header.s=korg header.b=tVJsxRxD Received: by smtp.kernel.org (Postfix) with ESMTPSA id A86F41F0089F; Tue, 10 Nov 2026 00:09:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux-foundation.org; s=korg; t=1794269352; bh=2sADtvR8xRruKhbTehK05Ksdl+O9CyvkErm6+5ZybOw=; h=Date:To:From:Subject; b=tVJsxRxDdar3hSB484mS79VTscCLSg1um9aa0c3IW8qOk+VMy5ezEDVnL9Wf88/KO 8srWJ91FlQoja3qBGXLfCPs8afVX1XPKFQUempNMVPrR36OjA+qrhfin3CzUe87KI9 SYyjkaoD7HlpQxVHemkW+tyu/hqcl8r8LJFKpjH8= Date: Mon, 09 Nov 2026 16:09:12 -0800 To: mm-commits@vger.kernel.org,raemoar63@gmail.com, ilias.apalodimas@linaro.org,david@davidgow.net,brendan.higgins@linux.dev, ardb@kernel.org,amit.patole@gmail.com,akpm@linux-foundation.org From: Andrew Morton Subject: + lib-tests-add-kunit-tests-for-the-ucs-2-string-helpers.patch added to mm-nonmm-unstable branch Message-Id: <20261110000912.A86F41F0089F@smtp.kernel.org> X-Mailing-List: mm-commits@vger.kernel.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list The patch titled Subject: lib/tests: add KUnit tests for the UCS-2 string helpers has been added to the -mm mm-nonmm-unstable branch. Its filename is lib-tests-add-kunit-tests-for-the-ucs-2-string-helpers.patch This patch will shortly appear at https://git.kernel.org/pub/scm/linux/kernel/git/akpm/25-new.git/tree/patches/lib-tests-add-kunit-tests-for-the-ucs-2-string-helpers.patch This patch will later appear in the mm-nonmm-unstable branch at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/process/submit-checklist.rst when testing your code *** The -mm tree is included into linux-next via various branches at git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm and is updated there most days ------------------------------------------------------ From: Amit Patole Subject: lib/tests: add KUnit tests for the UCS-2 string helpers Date: Fri, 06 Nov 2026 08:12:31 -0500 lib/ucs2_string.c is used for EFI variable names (efivarfs, efi-pstore), Apple device properties, the EFI stub's load options and Hyper-V interface aliases, but has no unit tests. Add a KUnit suite that covers: - ucs2_strnlen(), ucs2_strlen() and ucs2_strsize(), including a byte limit that is not a whole number of characters; - ucs2_strscpy(): exact fit, truncation with -E2BIG and NUL termination, and the zero-sized and oversized buffer checks; - ucs2_strncmp(): ordering, the length limit, prefixes and unsigned comparison of characters above 0x7fff; - ucs2_utf8size() and ucs2_as_utf8() for the one, two and three byte UTF-8 boundaries (U+007F/U+0080, U+07FF/U+0800, U+FFFF); - truncation in ucs2_as_utf8(): a multi-byte character is never split, and the terminator is written only when there is room; - ucs2_as_utf8_l() on a source that is not NUL terminated, which is why it was split out of ucs2_as_utf8(). An AI coding assistant (Claude Opus 5.5) was used to pick the untested helpers and draft the tests. They were run with "tools/testing/kunit/kunit.py run" on UML (19/19 pass), built with W=1 without warnings, and checked against deliberately broken versions of ucs2_strscpy() and ucs2_as_utf8_l(), which the suite catches. Link: https://lore.kernel.org/20261106-kunit-ucs2-string-v1-1-28d8e134ba1f@gmail.com Signed-off-by: Amit Patole Signed-off-by: Andrew Morton Cc: Ard Biesheuvel Cc: Ilias Apalodimas Cc: Brendan Higgins Cc: David Gow Cc: Rae Moar --- lib/Kconfig.debug | 14 + lib/tests/Makefile | 1 lib/tests/ucs2_string_kunit.c | 288 ++++++++++++++++++++++++++++++++ 3 files changed, 303 insertions(+) --- a/lib/Kconfig.debug~lib-tests-add-kunit-tests-for-the-ucs-2-string-helpers +++ a/lib/Kconfig.debug @@ -3507,6 +3507,20 @@ config XXHASH_KUNIT_TEST If unsure, say N. +config UCS2_STRING_KUNIT_TEST + tristate "KUnit test for UCS-2 string helpers" if !KUNIT_ALL_TESTS + depends on KUNIT + select UCS2_STRING + default KUNIT_ALL_TESTS + help + This option enables the KUnit test suite for the UCS-2 string + helpers in lib/ucs2_string.c, which are used for EFI variable + names and other firmware strings. The tests cover length, + copy and compare helpers and the UCS-2 to UTF-8 conversion, + including truncation at the destination buffer size. + + If unsure, say N. + config UUID_KUNIT_TEST tristate "KUnit test for UUID" if !KUNIT_ALL_TESTS depends on KUNIT --- a/lib/tests/Makefile~lib-tests-add-kunit-tests-for-the-ucs-2-string-helpers +++ a/lib/tests/Makefile @@ -57,6 +57,7 @@ CFLAGS_stackinit_kunit.o += $(call cc-di obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o +obj-$(CONFIG_UCS2_STRING_KUNIT_TEST) += ucs2_string_kunit.o obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o obj-$(CONFIG_RATELIMIT_KUNIT_TEST) += test_ratelimit.o diff --git a/lib/tests/ucs2_string_kunit.c a/lib/tests/ucs2_string_kunit.c new file mode 100644 --- /dev/null +++ a/lib/tests/ucs2_string_kunit.c @@ -0,0 +1,288 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit tests for the UCS-2 string helpers in lib/ucs2_string.c + */ + +#include +#include +#include +#include + +/* "abc" */ +static const ucs2_char_t abc[] = { 'a', 'b', 'c', 0 }; +/* "a", U+00E9 (e acute), U+20AC (euro sign) */ +static const ucs2_char_t mixed[] = { 'a', 0x00e9, 0x20ac, 0 }; +static const ucs2_char_t empty[] = { 0 }; + +static void ucs2_strnlen_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, ucs2_strnlen(empty, 10), 0); + KUNIT_EXPECT_EQ(test, ucs2_strnlen(abc, 10), 3); + KUNIT_EXPECT_EQ(test, ucs2_strnlen(abc, 3), 3); + KUNIT_EXPECT_EQ(test, ucs2_strnlen(abc, 2), 2); + KUNIT_EXPECT_EQ(test, ucs2_strnlen(abc, 0), 0); + KUNIT_EXPECT_EQ(test, ucs2_strnlen(mixed, 10), 3); +} + +static void ucs2_strlen_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, ucs2_strlen(empty), 0); + KUNIT_EXPECT_EQ(test, ucs2_strlen(abc), 3); + KUNIT_EXPECT_EQ(test, ucs2_strlen(mixed), 3); +} + +static void ucs2_strsize_test(struct kunit *test) +{ + /* The result is in bytes, and @maxlength is in bytes too. */ + KUNIT_EXPECT_EQ(test, ucs2_strsize(abc, 100), 6); + KUNIT_EXPECT_EQ(test, ucs2_strsize(abc, 4), 4); + /* An odd byte limit is rounded down to whole characters. */ + KUNIT_EXPECT_EQ(test, ucs2_strsize(abc, 5), 4); + KUNIT_EXPECT_EQ(test, ucs2_strsize(abc, 1), 0); + KUNIT_EXPECT_EQ(test, ucs2_strsize(empty, 100), 0); +} + +static void ucs2_strscpy_test(struct kunit *test) +{ + ucs2_char_t dst[8]; + + /* Plenty of room. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_strscpy(dst, abc, ARRAY_SIZE(dst)), 3); + KUNIT_EXPECT_EQ(test, ucs2_strncmp(dst, abc, ARRAY_SIZE(dst)), 0); + /* Nothing is written past the terminator. */ + KUNIT_EXPECT_EQ(test, dst[4], 0xffff); + + /* Exact fit: three characters plus the terminator. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_strscpy(dst, abc, 4), 3); + KUNIT_EXPECT_EQ(test, dst[3], 0); + + /* One short: truncated, still terminated, -E2BIG. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_strscpy(dst, abc, 3), -E2BIG); + KUNIT_EXPECT_EQ(test, dst[0], 'a'); + KUNIT_EXPECT_EQ(test, dst[1], 'b'); + KUNIT_EXPECT_EQ(test, dst[2], 0); + KUNIT_EXPECT_EQ(test, dst[3], 0xffff); + + /* Room for the terminator only. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_strscpy(dst, abc, 1), -E2BIG); + KUNIT_EXPECT_EQ(test, dst[0], 0); + KUNIT_EXPECT_EQ(test, dst[1], 0xffff); + + /* A zero-sized buffer is rejected and left untouched. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_strscpy(dst, abc, 0), -E2BIG); + KUNIT_EXPECT_EQ(test, dst[0], 0xffff); + + /* So is a size that does not fit in the ssize_t return value. */ + KUNIT_EXPECT_EQ(test, ucs2_strscpy(dst, abc, (size_t)SSIZE_MAX + 1), + -E2BIG); + KUNIT_EXPECT_EQ(test, dst[0], 0xffff); + + /* Empty source. */ + KUNIT_EXPECT_EQ(test, ucs2_strscpy(dst, empty, ARRAY_SIZE(dst)), 0); + KUNIT_EXPECT_EQ(test, dst[0], 0); +} + +static void ucs2_strncmp_test(struct kunit *test) +{ + static const ucs2_char_t abd[] = { 'a', 'b', 'd', 0 }; + static const ucs2_char_t ab[] = { 'a', 'b', 0 }; + static const ucs2_char_t lo[] = { 0x0001, 0 }; + static const ucs2_char_t hi[] = { 0xffff, 0 }; + + KUNIT_EXPECT_EQ(test, ucs2_strncmp(abc, abc, 10), 0); + KUNIT_EXPECT_EQ(test, ucs2_strncmp(abc, abd, 10), -1); + KUNIT_EXPECT_EQ(test, ucs2_strncmp(abd, abc, 10), 1); + /* Only the first @len characters are compared. */ + KUNIT_EXPECT_EQ(test, ucs2_strncmp(abc, abd, 2), 0); + KUNIT_EXPECT_EQ(test, ucs2_strncmp(abc, abd, 0), 0); + /* A prefix sorts first, because its terminator is the smaller value. */ + KUNIT_EXPECT_EQ(test, ucs2_strncmp(ab, abc, 10), -1); + KUNIT_EXPECT_EQ(test, ucs2_strncmp(abc, ab, 10), 1); + KUNIT_EXPECT_EQ(test, ucs2_strncmp(empty, empty, 10), 0); + /* Characters compare as unsigned 16-bit values. */ + KUNIT_EXPECT_EQ(test, ucs2_strncmp(lo, hi, 10), -1); + KUNIT_EXPECT_EQ(test, ucs2_strncmp(hi, lo, 10), 1); +} + +/* One UCS-2 character and its expected UTF-8 encoding. */ +struct ucs2_utf8_case { + ucs2_char_t c; + u8 utf8[3]; + unsigned int len; +}; + +static const struct ucs2_utf8_case utf8_cases[] = { + { 0x0001, { 0x01 }, 1 }, + { 0x0041, { 0x41 }, 1 }, + { 0x007f, { 0x7f }, 1 }, + { 0x0080, { 0xc2, 0x80 }, 2 }, + { 0x00e9, { 0xc3, 0xa9 }, 2 }, + { 0x07ff, { 0xdf, 0xbf }, 2 }, + { 0x0800, { 0xe0, 0xa0, 0x80 }, 3 }, + { 0x20ac, { 0xe2, 0x82, 0xac }, 3 }, + { 0xfffd, { 0xef, 0xbf, 0xbd }, 3 }, + { 0xffff, { 0xef, 0xbf, 0xbf }, 3 }, +}; + +static void ucs2_utf8_case_desc(const struct ucs2_utf8_case *t, char *desc) +{ + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "U+%04X", t->c); +} + +KUNIT_ARRAY_PARAM(ucs2_utf8, utf8_cases, ucs2_utf8_case_desc); + +static void ucs2_as_utf8_char_test(struct kunit *test) +{ + const struct ucs2_utf8_case *t = test->param_value; + const ucs2_char_t src[] = { t->c, 0 }; + u8 dst[8]; + + KUNIT_EXPECT_EQ(test, ucs2_utf8size(src), t->len); + + memset(dst, 0xff, sizeof(dst)); + KUNIT_ASSERT_EQ(test, ucs2_as_utf8(dst, src, sizeof(dst)), t->len); + KUNIT_EXPECT_MEMEQ(test, dst, t->utf8, t->len); + KUNIT_EXPECT_EQ(test, dst[t->len], 0); +} + +static void ucs2_utf8size_test(struct kunit *test) +{ + KUNIT_EXPECT_EQ(test, ucs2_utf8size(empty), 0); + KUNIT_EXPECT_EQ(test, ucs2_utf8size(abc), 3); + KUNIT_EXPECT_EQ(test, ucs2_utf8size(mixed), 1 + 2 + 3); +} + +static void ucs2_as_utf8_string_test(struct kunit *test) +{ + static const u8 mixed_utf8[] = { 'a', 0xc3, 0xa9, 0xe2, 0x82, 0xac }; + u8 dst[16]; + + memset(dst, 0xff, sizeof(dst)); + KUNIT_ASSERT_EQ(test, ucs2_as_utf8(dst, mixed, sizeof(dst)), + sizeof(mixed_utf8)); + KUNIT_EXPECT_MEMEQ(test, dst, mixed_utf8, sizeof(mixed_utf8)); + KUNIT_EXPECT_EQ(test, dst[sizeof(mixed_utf8)], 0); + + /* The output length matches what ucs2_utf8size() predicts. */ + KUNIT_EXPECT_EQ(test, ucs2_as_utf8(dst, mixed, sizeof(dst)), + ucs2_utf8size(mixed)); + + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8(dst, empty, sizeof(dst)), 0); + KUNIT_EXPECT_EQ(test, dst[0], 0); +} + +static void ucs2_as_utf8_truncate_test(struct kunit *test) +{ + u8 dst[16]; + + /* + * Output that exactly fills @maxlength is not NUL terminated, and + * nothing is written past it. + */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8(dst, abc, 3), 3); + KUNIT_EXPECT_MEMEQ(test, dst, "abc", 3); + KUNIT_EXPECT_EQ(test, dst[3], 0xff); + + /* A shorter buffer truncates, with no terminator. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8(dst, abc, 2), 2); + KUNIT_EXPECT_MEMEQ(test, dst, "ab", 2); + KUNIT_EXPECT_EQ(test, dst[2], 0xff); + + /* + * A multi-byte character is never split: "a" + U+00E9 + U+20AC needs + * 6 bytes; with 4 the euro sign is dropped whole and the spare byte + * holds the terminator. + */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8(dst, mixed, 4), 3); + KUNIT_EXPECT_MEMEQ(test, dst, "a\xc3\xa9", 3); + KUNIT_EXPECT_EQ(test, dst[3], 0); + KUNIT_EXPECT_EQ(test, dst[4], 0xff); + + /* Likewise when two bytes are left for the three-byte euro sign. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8(dst, mixed, 5), 3); + KUNIT_EXPECT_MEMEQ(test, dst, "a\xc3\xa9", 3); + KUNIT_EXPECT_EQ(test, dst[3], 0); + KUNIT_EXPECT_EQ(test, dst[4], 0xff); + + /* No room for even the first two-byte character. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8(dst, &mixed[1], 1), 0); + KUNIT_EXPECT_EQ(test, dst[0], 0); + KUNIT_EXPECT_EQ(test, dst[1], 0xff); + + /* A zero-sized buffer is not written at all. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8(dst, abc, 0), 0); + KUNIT_EXPECT_EQ(test, dst[0], 0xff); +} + +static void ucs2_as_utf8_l_test(struct kunit *test) +{ + /* Deliberately not NUL terminated. */ + static const ucs2_char_t unterminated[] = { 'x', 0x00e9, 'y' }; + static const u8 expected[] = { 'x', 0xc3, 0xa9, 'y' }; + u8 dst[16]; + + /* @limit bounds the source, so it may lack a terminator. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8_l(dst, unterminated, + ARRAY_SIZE(unterminated), + sizeof(dst)), sizeof(expected)); + KUNIT_EXPECT_MEMEQ(test, dst, expected, sizeof(expected)); + KUNIT_EXPECT_EQ(test, dst[sizeof(expected)], 0); + + /* A smaller @limit stops early, on a character boundary. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8_l(dst, unterminated, 2, + sizeof(dst)), 3); + KUNIT_EXPECT_MEMEQ(test, dst, expected, 3); + KUNIT_EXPECT_EQ(test, dst[3], 0); + + /* @maxlength still applies when @limit allows more. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8_l(dst, unterminated, + ARRAY_SIZE(unterminated), 2), 1); + KUNIT_EXPECT_EQ(test, dst[0], 'x'); + KUNIT_EXPECT_EQ(test, dst[1], 0); + KUNIT_EXPECT_EQ(test, dst[2], 0xff); + + /* A zero @limit converts nothing but still terminates. */ + memset(dst, 0xff, sizeof(dst)); + KUNIT_EXPECT_EQ(test, ucs2_as_utf8_l(dst, unterminated, 0, + sizeof(dst)), 0); + KUNIT_EXPECT_EQ(test, dst[0], 0); +} + +static struct kunit_case ucs2_string_test_cases[] = { + KUNIT_CASE(ucs2_strnlen_test), + KUNIT_CASE(ucs2_strlen_test), + KUNIT_CASE(ucs2_strsize_test), + KUNIT_CASE(ucs2_strscpy_test), + KUNIT_CASE(ucs2_strncmp_test), + KUNIT_CASE(ucs2_utf8size_test), + KUNIT_CASE_PARAM(ucs2_as_utf8_char_test, ucs2_utf8_gen_params), + KUNIT_CASE(ucs2_as_utf8_string_test), + KUNIT_CASE(ucs2_as_utf8_truncate_test), + KUNIT_CASE(ucs2_as_utf8_l_test), + {} +}; + +static struct kunit_suite ucs2_string_test_suite = { + .name = "ucs2_string", + .test_cases = ucs2_string_test_cases, +}; + +kunit_test_suite(ucs2_string_test_suite); + +MODULE_DESCRIPTION("KUnit tests for the UCS-2 string helpers"); +MODULE_LICENSE("GPL"); _ Patches currently in -mm which might be from amit.patole@gmail.com are lib-genalloc-dont-dereference-a-null-pool-in-gen_pool_dma_alloc.patch lib-tests-add-kunit-tests-for-genalloc.patch lib-tests-add-kunit-tests-for-xxhash.patch lib-tests-add-kunit-tests-for-the-ucs-2-string-helpers.patch