[PATCH BlueZ v2 06/10] unit/test-util: Add str2utf8 tests

Luiz Augusto von Dentz <[email protected]>
Newsgroups org.kernel.vger.linux-bluetooth
Message-ID <[email protected]>
From: Luiz Augusto von Dentz <[email protected]>

Cover the cases str2utf8() is meant to handle: well-formed input that
has to be left alone, whitespace stripping, input that is not NUL
terminated, and the ill-formed sequences that have to be replaced,
including the overlong encodings, the UTF-16 surrogates and the code
points past U+10FFFF.

Also check that a maximal subpart is replaced by a single U+FFFD rather
than one per byte, and that the result is always well-formed UTF-8.

Assisted-by: Claude:claude-opus-5
---
 unit/test-util.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/unit/test-util.c b/unit/test-util.c
index 1672b32eb39c..f0b1bb7994fb 100644
--- a/unit/test-util.c
+++ b/unit/test-util.c
@@ -83,6 +83,85 @@ static void test_min_max(const void *data)
 	tester_test_passed();
 }
 
+struct str2utf8_data {
+	const char *input;	/* Not NUL terminated, len bytes are used */
+	size_t len;
+	const char *expected;
+};
+
+#define FFFD "\xef\xbf\xbd"		/* U+FFFD REPLACEMENT CHARACTER */
+
+static const struct str2utf8_data str2utf8_tests[] = {
+	/* Nothing to do */
+	{ "", 0, "" },
+	{ "Pixel 7", 7, "Pixel 7" },
+	/* Well-formed multi-byte sequences are kept as they are */
+	{ "\xe2\x82\xac 5", 5, "\xe2\x82\xac 5" },		/* U+20AC */
+	{ "\xf0\x9f\x94\x8a", 4, "\xf0\x9f\x94\x8a" },		/* U+1F50A */
+	/* Leading and trailing whitespace is removed */
+	{ "  spaced  ", 10, "spaced" },
+	{ "\t\r\nname\n\r\t", 10, "name" },
+	{ "   ", 3, "" },
+	/* The name is not NUL terminated, only len bytes are used */
+	{ "truncated", 4, "trun" },
+	/* A byte that can never appear in UTF-8 */
+	{ "ab\xff""cd", 5, "ab" FFFD "cd" },
+	/* A continuation byte cannot start a sequence */
+	{ "ab\x80""cd", 5, "ab" FFFD "cd" },
+	/* One U+FFFD per maximal subpart, not per byte */
+	{ "ab\xe2\x82""cd", 6, "ab" FFFD "cd" },
+	/* A sequence cut short by len is still one maximal subpart */
+	{ "ab\xe2\x82\xac", 4, "ab" FFFD },
+	/* Latin-1 text is not valid UTF-8 */
+	{ "caf\xe9", 4, "caf" FFFD },
+	/* Overlong encodings are rejected, C0 and C1 are never valid */
+	{ "\xc0\x80", 2, FFFD FFFD },
+	{ "\xc0\xaf", 2, FFFD FFFD },
+	/* UTF-16 surrogates have no UTF-8 encoding */
+	{ "\xed\xa0\x80", 3, FFFD FFFD FFFD },
+	/* U+10FFFF is the last code point, F5 to FF are out of range */
+	{ "\xf4\x90\x80\x80", 4, FFFD FFFD FFFD FFFD },
+	{ "\xf5\x80\x80\x80", 4, FFFD FFFD FFFD FFFD },
+	/* The last code point itself is fine */
+	{ "\xf4\x8f\xbf\xbf", 4, "\xf4\x8f\xbf\xbf" },
+	/* Replacement and stripping combined */
+	{ " \xff ", 3, FFFD },
+};
+
+static void test_str2utf8(const void *data)
+{
+	size_t i;
+
+	for (i = 0; i < sizeof(str2utf8_tests) /
+				sizeof(str2utf8_tests[0]); i++) {
+		const struct str2utf8_data *test = &str2utf8_tests[i];
+		char *str = str2utf8((const uint8_t *) test->input,
+								test->len);
+
+		assert(str);
+		if (strcmp(str, test->expected)) {
+			printf("test %zu: expected \"%s\", got \"%s\"\n", i,
+							test->expected, str);
+			free(str);
+			tester_test_failed();
+			return;
+		}
+
+		/* The result is always well-formed UTF-8 */
+		assert(strisutf8(str, strlen(str)));
+
+		free(str);
+	}
+
+	tester_test_passed();
+}
+
+static void test_str2utf8_null(const void *data)
+{
+	assert(!str2utf8(NULL, 0));
+	tester_test_passed();
+}
+
 int main(int argc, char *argv[])
 {
 	tester_init(&argc, &argv);
@@ -95,6 +174,10 @@ int main(int argc, char *argv[])
 			test_cleanup_type, NULL);
 	tester_add("/util/cleanup_fd", NULL, NULL,
 			test_cleanup_fd, NULL);
+	tester_add("/util/str2utf8", NULL, NULL,
+			test_str2utf8, NULL);
+	tester_add("/util/str2utf8_null", NULL, NULL,
+			test_str2utf8_null, NULL);
 
 	return tester_run();
 }
-- 
2.54.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.