18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Test cases for lib/string_helpers.c module.
38c2ecf20Sopenharmony_ci */
48c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/init.h>
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/slab.h>
98c2ecf20Sopenharmony_ci#include <linux/module.h>
108c2ecf20Sopenharmony_ci#include <linux/random.h>
118c2ecf20Sopenharmony_ci#include <linux/string.h>
128c2ecf20Sopenharmony_ci#include <linux/string_helpers.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_cistatic __init bool test_string_check_buf(const char *name, unsigned int flags,
158c2ecf20Sopenharmony_ci					 char *in, size_t p,
168c2ecf20Sopenharmony_ci					 char *out_real, size_t q_real,
178c2ecf20Sopenharmony_ci					 char *out_test, size_t q_test)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	if (q_real == q_test && !memcmp(out_test, out_real, q_test))
208c2ecf20Sopenharmony_ci		return true;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	pr_warn("Test '%s' failed: flags = %u\n", name, flags);
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	print_hex_dump(KERN_WARNING, "Input: ", DUMP_PREFIX_NONE, 16, 1,
258c2ecf20Sopenharmony_ci		       in, p, true);
268c2ecf20Sopenharmony_ci	print_hex_dump(KERN_WARNING, "Expected: ", DUMP_PREFIX_NONE, 16, 1,
278c2ecf20Sopenharmony_ci		       out_test, q_test, true);
288c2ecf20Sopenharmony_ci	print_hex_dump(KERN_WARNING, "Got: ", DUMP_PREFIX_NONE, 16, 1,
298c2ecf20Sopenharmony_ci		       out_real, q_real, true);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci	return false;
328c2ecf20Sopenharmony_ci}
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_cistruct test_string {
358c2ecf20Sopenharmony_ci	const char *in;
368c2ecf20Sopenharmony_ci	const char *out;
378c2ecf20Sopenharmony_ci	unsigned int flags;
388c2ecf20Sopenharmony_ci};
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic const struct test_string strings[] __initconst = {
418c2ecf20Sopenharmony_ci	{
428c2ecf20Sopenharmony_ci		.in = "\\f\\ \\n\\r\\t\\v",
438c2ecf20Sopenharmony_ci		.out = "\f\\ \n\r\t\v",
448c2ecf20Sopenharmony_ci		.flags = UNESCAPE_SPACE,
458c2ecf20Sopenharmony_ci	},
468c2ecf20Sopenharmony_ci	{
478c2ecf20Sopenharmony_ci		.in = "\\40\\1\\387\\0064\\05\\040\\8a\\110\\777",
488c2ecf20Sopenharmony_ci		.out = " \001\00387\0064\005 \\8aH?7",
498c2ecf20Sopenharmony_ci		.flags = UNESCAPE_OCTAL,
508c2ecf20Sopenharmony_ci	},
518c2ecf20Sopenharmony_ci	{
528c2ecf20Sopenharmony_ci		.in = "\\xv\\xa\\x2c\\xD\\x6f2",
538c2ecf20Sopenharmony_ci		.out = "\\xv\n,\ro2",
548c2ecf20Sopenharmony_ci		.flags = UNESCAPE_HEX,
558c2ecf20Sopenharmony_ci	},
568c2ecf20Sopenharmony_ci	{
578c2ecf20Sopenharmony_ci		.in = "\\h\\\\\\\"\\a\\e\\",
588c2ecf20Sopenharmony_ci		.out = "\\h\\\"\a\e\\",
598c2ecf20Sopenharmony_ci		.flags = UNESCAPE_SPECIAL,
608c2ecf20Sopenharmony_ci	},
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic void __init test_string_unescape(const char *name, unsigned int flags,
648c2ecf20Sopenharmony_ci					bool inplace)
658c2ecf20Sopenharmony_ci{
668c2ecf20Sopenharmony_ci	int q_real = 256;
678c2ecf20Sopenharmony_ci	char *in = kmalloc(q_real, GFP_KERNEL);
688c2ecf20Sopenharmony_ci	char *out_test = kmalloc(q_real, GFP_KERNEL);
698c2ecf20Sopenharmony_ci	char *out_real = kmalloc(q_real, GFP_KERNEL);
708c2ecf20Sopenharmony_ci	int i, p = 0, q_test = 0;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (!in || !out_test || !out_real)
738c2ecf20Sopenharmony_ci		goto out;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(strings); i++) {
768c2ecf20Sopenharmony_ci		const char *s = strings[i].in;
778c2ecf20Sopenharmony_ci		int len = strlen(strings[i].in);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci		/* Copy string to in buffer */
808c2ecf20Sopenharmony_ci		memcpy(&in[p], s, len);
818c2ecf20Sopenharmony_ci		p += len;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci		/* Copy expected result for given flags */
848c2ecf20Sopenharmony_ci		if (flags & strings[i].flags) {
858c2ecf20Sopenharmony_ci			s = strings[i].out;
868c2ecf20Sopenharmony_ci			len = strlen(strings[i].out);
878c2ecf20Sopenharmony_ci		}
888c2ecf20Sopenharmony_ci		memcpy(&out_test[q_test], s, len);
898c2ecf20Sopenharmony_ci		q_test += len;
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci	in[p++] = '\0';
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	/* Call string_unescape and compare result */
948c2ecf20Sopenharmony_ci	if (inplace) {
958c2ecf20Sopenharmony_ci		memcpy(out_real, in, p);
968c2ecf20Sopenharmony_ci		if (flags == UNESCAPE_ANY)
978c2ecf20Sopenharmony_ci			q_real = string_unescape_any_inplace(out_real);
988c2ecf20Sopenharmony_ci		else
998c2ecf20Sopenharmony_ci			q_real = string_unescape_inplace(out_real, flags);
1008c2ecf20Sopenharmony_ci	} else if (flags == UNESCAPE_ANY) {
1018c2ecf20Sopenharmony_ci		q_real = string_unescape_any(in, out_real, q_real);
1028c2ecf20Sopenharmony_ci	} else {
1038c2ecf20Sopenharmony_ci		q_real = string_unescape(in, out_real, q_real, flags);
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	test_string_check_buf(name, flags, in, p - 1, out_real, q_real,
1078c2ecf20Sopenharmony_ci			      out_test, q_test);
1088c2ecf20Sopenharmony_ciout:
1098c2ecf20Sopenharmony_ci	kfree(out_real);
1108c2ecf20Sopenharmony_ci	kfree(out_test);
1118c2ecf20Sopenharmony_ci	kfree(in);
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_cistruct test_string_1 {
1158c2ecf20Sopenharmony_ci	const char *out;
1168c2ecf20Sopenharmony_ci	unsigned int flags;
1178c2ecf20Sopenharmony_ci};
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci#define	TEST_STRING_2_MAX_S1		32
1208c2ecf20Sopenharmony_cistruct test_string_2 {
1218c2ecf20Sopenharmony_ci	const char *in;
1228c2ecf20Sopenharmony_ci	struct test_string_1 s1[TEST_STRING_2_MAX_S1];
1238c2ecf20Sopenharmony_ci};
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci#define	TEST_STRING_2_DICT_0		NULL
1268c2ecf20Sopenharmony_cistatic const struct test_string_2 escape0[] __initconst = {{
1278c2ecf20Sopenharmony_ci	.in = "\f\\ \n\r\t\v",
1288c2ecf20Sopenharmony_ci	.s1 = {{
1298c2ecf20Sopenharmony_ci		.out = "\\f\\ \\n\\r\\t\\v",
1308c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE,
1318c2ecf20Sopenharmony_ci	},{
1328c2ecf20Sopenharmony_ci		.out = "\\f\\134\\040\\n\\r\\t\\v",
1338c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE | ESCAPE_OCTAL,
1348c2ecf20Sopenharmony_ci	},{
1358c2ecf20Sopenharmony_ci		.out = "\\f\\x5c\\x20\\n\\r\\t\\v",
1368c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE | ESCAPE_HEX,
1378c2ecf20Sopenharmony_ci	},{
1388c2ecf20Sopenharmony_ci		/* terminator */
1398c2ecf20Sopenharmony_ci	}},
1408c2ecf20Sopenharmony_ci},{
1418c2ecf20Sopenharmony_ci	.in = "\\h\\\"\a\e\\",
1428c2ecf20Sopenharmony_ci	.s1 = {{
1438c2ecf20Sopenharmony_ci		.out = "\\\\h\\\\\"\\a\\e\\\\",
1448c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPECIAL,
1458c2ecf20Sopenharmony_ci	},{
1468c2ecf20Sopenharmony_ci		.out = "\\\\\\150\\\\\\042\\a\\e\\\\",
1478c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPECIAL | ESCAPE_OCTAL,
1488c2ecf20Sopenharmony_ci	},{
1498c2ecf20Sopenharmony_ci		.out = "\\\\\\x68\\\\\\x22\\a\\e\\\\",
1508c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPECIAL | ESCAPE_HEX,
1518c2ecf20Sopenharmony_ci	},{
1528c2ecf20Sopenharmony_ci		/* terminator */
1538c2ecf20Sopenharmony_ci	}},
1548c2ecf20Sopenharmony_ci},{
1558c2ecf20Sopenharmony_ci	.in = "\eb \\C\007\"\x90\r]",
1568c2ecf20Sopenharmony_ci	.s1 = {{
1578c2ecf20Sopenharmony_ci		.out = "\eb \\C\007\"\x90\\r]",
1588c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE,
1598c2ecf20Sopenharmony_ci	},{
1608c2ecf20Sopenharmony_ci		.out = "\\eb \\\\C\\a\"\x90\r]",
1618c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPECIAL,
1628c2ecf20Sopenharmony_ci	},{
1638c2ecf20Sopenharmony_ci		.out = "\\eb \\\\C\\a\"\x90\\r]",
1648c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE | ESCAPE_SPECIAL,
1658c2ecf20Sopenharmony_ci	},{
1668c2ecf20Sopenharmony_ci		.out = "\\033\\142\\040\\134\\103\\007\\042\\220\\015\\135",
1678c2ecf20Sopenharmony_ci		.flags = ESCAPE_OCTAL,
1688c2ecf20Sopenharmony_ci	},{
1698c2ecf20Sopenharmony_ci		.out = "\\033\\142\\040\\134\\103\\007\\042\\220\\r\\135",
1708c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE | ESCAPE_OCTAL,
1718c2ecf20Sopenharmony_ci	},{
1728c2ecf20Sopenharmony_ci		.out = "\\e\\142\\040\\\\\\103\\a\\042\\220\\015\\135",
1738c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPECIAL | ESCAPE_OCTAL,
1748c2ecf20Sopenharmony_ci	},{
1758c2ecf20Sopenharmony_ci		.out = "\\e\\142\\040\\\\\\103\\a\\042\\220\\r\\135",
1768c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_OCTAL,
1778c2ecf20Sopenharmony_ci	},{
1788c2ecf20Sopenharmony_ci		.out = "\eb \\C\007\"\x90\r]",
1798c2ecf20Sopenharmony_ci		.flags = ESCAPE_NP,
1808c2ecf20Sopenharmony_ci	},{
1818c2ecf20Sopenharmony_ci		.out = "\eb \\C\007\"\x90\\r]",
1828c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE | ESCAPE_NP,
1838c2ecf20Sopenharmony_ci	},{
1848c2ecf20Sopenharmony_ci		.out = "\\eb \\C\\a\"\x90\r]",
1858c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPECIAL | ESCAPE_NP,
1868c2ecf20Sopenharmony_ci	},{
1878c2ecf20Sopenharmony_ci		.out = "\\eb \\C\\a\"\x90\\r]",
1888c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE | ESCAPE_SPECIAL | ESCAPE_NP,
1898c2ecf20Sopenharmony_ci	},{
1908c2ecf20Sopenharmony_ci		.out = "\\033b \\C\\007\"\\220\\015]",
1918c2ecf20Sopenharmony_ci		.flags = ESCAPE_OCTAL | ESCAPE_NP,
1928c2ecf20Sopenharmony_ci	},{
1938c2ecf20Sopenharmony_ci		.out = "\\033b \\C\\007\"\\220\\r]",
1948c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPACE | ESCAPE_OCTAL | ESCAPE_NP,
1958c2ecf20Sopenharmony_ci	},{
1968c2ecf20Sopenharmony_ci		.out = "\\eb \\C\\a\"\\220\\r]",
1978c2ecf20Sopenharmony_ci		.flags = ESCAPE_SPECIAL | ESCAPE_SPACE | ESCAPE_OCTAL |
1988c2ecf20Sopenharmony_ci			 ESCAPE_NP,
1998c2ecf20Sopenharmony_ci	},{
2008c2ecf20Sopenharmony_ci		.out = "\\x1bb \\C\\x07\"\\x90\\x0d]",
2018c2ecf20Sopenharmony_ci		.flags = ESCAPE_NP | ESCAPE_HEX,
2028c2ecf20Sopenharmony_ci	},{
2038c2ecf20Sopenharmony_ci		/* terminator */
2048c2ecf20Sopenharmony_ci	}},
2058c2ecf20Sopenharmony_ci},{
2068c2ecf20Sopenharmony_ci	/* terminator */
2078c2ecf20Sopenharmony_ci}};
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci#define	TEST_STRING_2_DICT_1		"b\\ \t\r"
2108c2ecf20Sopenharmony_cistatic const struct test_string_2 escape1[] __initconst = {{
2118c2ecf20Sopenharmony_ci	.in = "\f\\ \n\r\t\v",
2128c2ecf20Sopenharmony_ci	.s1 = {{
2138c2ecf20Sopenharmony_ci		.out = "\f\\134\\040\n\\015\\011\v",
2148c2ecf20Sopenharmony_ci		.flags = ESCAPE_OCTAL,
2158c2ecf20Sopenharmony_ci	},{
2168c2ecf20Sopenharmony_ci		.out = "\f\\x5c\\x20\n\\x0d\\x09\v",
2178c2ecf20Sopenharmony_ci		.flags = ESCAPE_HEX,
2188c2ecf20Sopenharmony_ci	},{
2198c2ecf20Sopenharmony_ci		/* terminator */
2208c2ecf20Sopenharmony_ci	}},
2218c2ecf20Sopenharmony_ci},{
2228c2ecf20Sopenharmony_ci	.in = "\\h\\\"\a\e\\",
2238c2ecf20Sopenharmony_ci	.s1 = {{
2248c2ecf20Sopenharmony_ci		.out = "\\134h\\134\"\a\e\\134",
2258c2ecf20Sopenharmony_ci		.flags = ESCAPE_OCTAL,
2268c2ecf20Sopenharmony_ci	},{
2278c2ecf20Sopenharmony_ci		/* terminator */
2288c2ecf20Sopenharmony_ci	}},
2298c2ecf20Sopenharmony_ci},{
2308c2ecf20Sopenharmony_ci	.in = "\eb \\C\007\"\x90\r]",
2318c2ecf20Sopenharmony_ci	.s1 = {{
2328c2ecf20Sopenharmony_ci		.out = "\e\\142\\040\\134C\007\"\x90\\015]",
2338c2ecf20Sopenharmony_ci		.flags = ESCAPE_OCTAL,
2348c2ecf20Sopenharmony_ci	},{
2358c2ecf20Sopenharmony_ci		/* terminator */
2368c2ecf20Sopenharmony_ci	}},
2378c2ecf20Sopenharmony_ci},{
2388c2ecf20Sopenharmony_ci	/* terminator */
2398c2ecf20Sopenharmony_ci}};
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_cistatic const struct test_string strings_upper[] __initconst = {
2428c2ecf20Sopenharmony_ci	{
2438c2ecf20Sopenharmony_ci		.in = "abcdefgh1234567890test",
2448c2ecf20Sopenharmony_ci		.out = "ABCDEFGH1234567890TEST",
2458c2ecf20Sopenharmony_ci	},
2468c2ecf20Sopenharmony_ci	{
2478c2ecf20Sopenharmony_ci		.in = "abCdeFgH1234567890TesT",
2488c2ecf20Sopenharmony_ci		.out = "ABCDEFGH1234567890TEST",
2498c2ecf20Sopenharmony_ci	},
2508c2ecf20Sopenharmony_ci};
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_cistatic const struct test_string strings_lower[] __initconst = {
2538c2ecf20Sopenharmony_ci	{
2548c2ecf20Sopenharmony_ci		.in = "ABCDEFGH1234567890TEST",
2558c2ecf20Sopenharmony_ci		.out = "abcdefgh1234567890test",
2568c2ecf20Sopenharmony_ci	},
2578c2ecf20Sopenharmony_ci	{
2588c2ecf20Sopenharmony_ci		.in = "abCdeFgH1234567890TesT",
2598c2ecf20Sopenharmony_ci		.out = "abcdefgh1234567890test",
2608c2ecf20Sopenharmony_ci	},
2618c2ecf20Sopenharmony_ci};
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_cistatic __init const char *test_string_find_match(const struct test_string_2 *s2,
2648c2ecf20Sopenharmony_ci						 unsigned int flags)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	const struct test_string_1 *s1 = s2->s1;
2678c2ecf20Sopenharmony_ci	unsigned int i;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	if (!flags)
2708c2ecf20Sopenharmony_ci		return s2->in;
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci	/* Test cases are NULL-aware */
2738c2ecf20Sopenharmony_ci	flags &= ~ESCAPE_NULL;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	/* ESCAPE_OCTAL has a higher priority */
2768c2ecf20Sopenharmony_ci	if (flags & ESCAPE_OCTAL)
2778c2ecf20Sopenharmony_ci		flags &= ~ESCAPE_HEX;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	for (i = 0; i < TEST_STRING_2_MAX_S1 && s1->out; i++, s1++)
2808c2ecf20Sopenharmony_ci		if (s1->flags == flags)
2818c2ecf20Sopenharmony_ci			return s1->out;
2828c2ecf20Sopenharmony_ci	return NULL;
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_cistatic __init void
2868c2ecf20Sopenharmony_citest_string_escape_overflow(const char *in, int p, unsigned int flags, const char *esc,
2878c2ecf20Sopenharmony_ci			    int q_test, const char *name)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	int q_real;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	q_real = string_escape_mem(in, p, NULL, 0, flags, esc);
2928c2ecf20Sopenharmony_ci	if (q_real != q_test)
2938c2ecf20Sopenharmony_ci		pr_warn("Test '%s' failed: flags = %u, osz = 0, expected %d, got %d\n",
2948c2ecf20Sopenharmony_ci			name, flags, q_test, q_real);
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic __init void test_string_escape(const char *name,
2988c2ecf20Sopenharmony_ci				      const struct test_string_2 *s2,
2998c2ecf20Sopenharmony_ci				      unsigned int flags, const char *esc)
3008c2ecf20Sopenharmony_ci{
3018c2ecf20Sopenharmony_ci	size_t out_size = 512;
3028c2ecf20Sopenharmony_ci	char *out_test = kmalloc(out_size, GFP_KERNEL);
3038c2ecf20Sopenharmony_ci	char *out_real = kmalloc(out_size, GFP_KERNEL);
3048c2ecf20Sopenharmony_ci	char *in = kmalloc(256, GFP_KERNEL);
3058c2ecf20Sopenharmony_ci	int p = 0, q_test = 0;
3068c2ecf20Sopenharmony_ci	int q_real;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	if (!out_test || !out_real || !in)
3098c2ecf20Sopenharmony_ci		goto out;
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci	for (; s2->in; s2++) {
3128c2ecf20Sopenharmony_ci		const char *out;
3138c2ecf20Sopenharmony_ci		int len;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci		/* NULL injection */
3168c2ecf20Sopenharmony_ci		if (flags & ESCAPE_NULL) {
3178c2ecf20Sopenharmony_ci			in[p++] = '\0';
3188c2ecf20Sopenharmony_ci			out_test[q_test++] = '\\';
3198c2ecf20Sopenharmony_ci			out_test[q_test++] = '0';
3208c2ecf20Sopenharmony_ci		}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		/* Don't try strings that have no output */
3238c2ecf20Sopenharmony_ci		out = test_string_find_match(s2, flags);
3248c2ecf20Sopenharmony_ci		if (!out)
3258c2ecf20Sopenharmony_ci			continue;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci		/* Copy string to in buffer */
3288c2ecf20Sopenharmony_ci		len = strlen(s2->in);
3298c2ecf20Sopenharmony_ci		memcpy(&in[p], s2->in, len);
3308c2ecf20Sopenharmony_ci		p += len;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		/* Copy expected result for given flags */
3338c2ecf20Sopenharmony_ci		len = strlen(out);
3348c2ecf20Sopenharmony_ci		memcpy(&out_test[q_test], out, len);
3358c2ecf20Sopenharmony_ci		q_test += len;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	q_real = string_escape_mem(in, p, out_real, out_size, flags, esc);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	test_string_check_buf(name, flags, in, p, out_real, q_real, out_test,
3418c2ecf20Sopenharmony_ci			      q_test);
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	test_string_escape_overflow(in, p, flags, esc, q_test, name);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ciout:
3468c2ecf20Sopenharmony_ci	kfree(in);
3478c2ecf20Sopenharmony_ci	kfree(out_real);
3488c2ecf20Sopenharmony_ci	kfree(out_test);
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci#define string_get_size_maxbuf 16
3528c2ecf20Sopenharmony_ci#define test_string_get_size_one(size, blk_size, exp_result10, exp_result2)    \
3538c2ecf20Sopenharmony_ci	do {                                                                   \
3548c2ecf20Sopenharmony_ci		BUILD_BUG_ON(sizeof(exp_result10) >= string_get_size_maxbuf);  \
3558c2ecf20Sopenharmony_ci		BUILD_BUG_ON(sizeof(exp_result2) >= string_get_size_maxbuf);   \
3568c2ecf20Sopenharmony_ci		__test_string_get_size((size), (blk_size), (exp_result10),     \
3578c2ecf20Sopenharmony_ci				       (exp_result2));                         \
3588c2ecf20Sopenharmony_ci	} while (0)
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic __init void test_string_get_size_check(const char *units,
3628c2ecf20Sopenharmony_ci					      const char *exp,
3638c2ecf20Sopenharmony_ci					      char *res,
3648c2ecf20Sopenharmony_ci					      const u64 size,
3658c2ecf20Sopenharmony_ci					      const u64 blk_size)
3668c2ecf20Sopenharmony_ci{
3678c2ecf20Sopenharmony_ci	if (!memcmp(res, exp, strlen(exp) + 1))
3688c2ecf20Sopenharmony_ci		return;
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	res[string_get_size_maxbuf - 1] = '\0';
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	pr_warn("Test 'test_string_get_size' failed!\n");
3738c2ecf20Sopenharmony_ci	pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %s)\n",
3748c2ecf20Sopenharmony_ci		size, blk_size, units);
3758c2ecf20Sopenharmony_ci	pr_warn("expected: '%s', got '%s'\n", exp, res);
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic __init void __test_string_get_size(const u64 size, const u64 blk_size,
3798c2ecf20Sopenharmony_ci					  const char *exp_result10,
3808c2ecf20Sopenharmony_ci					  const char *exp_result2)
3818c2ecf20Sopenharmony_ci{
3828c2ecf20Sopenharmony_ci	char buf10[string_get_size_maxbuf];
3838c2ecf20Sopenharmony_ci	char buf2[string_get_size_maxbuf];
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	string_get_size(size, blk_size, STRING_UNITS_10, buf10, sizeof(buf10));
3868c2ecf20Sopenharmony_ci	string_get_size(size, blk_size, STRING_UNITS_2, buf2, sizeof(buf2));
3878c2ecf20Sopenharmony_ci
3888c2ecf20Sopenharmony_ci	test_string_get_size_check("STRING_UNITS_10", exp_result10, buf10,
3898c2ecf20Sopenharmony_ci				   size, blk_size);
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	test_string_get_size_check("STRING_UNITS_2", exp_result2, buf2,
3928c2ecf20Sopenharmony_ci				   size, blk_size);
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic __init void test_string_get_size(void)
3968c2ecf20Sopenharmony_ci{
3978c2ecf20Sopenharmony_ci	/* small values */
3988c2ecf20Sopenharmony_ci	test_string_get_size_one(0, 512, "0 B", "0 B");
3998c2ecf20Sopenharmony_ci	test_string_get_size_one(1, 512, "512 B", "512 B");
4008c2ecf20Sopenharmony_ci	test_string_get_size_one(1100, 1, "1.10 kB", "1.07 KiB");
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	/* normal values */
4038c2ecf20Sopenharmony_ci	test_string_get_size_one(16384, 512, "8.39 MB", "8.00 MiB");
4048c2ecf20Sopenharmony_ci	test_string_get_size_one(500118192, 512, "256 GB", "238 GiB");
4058c2ecf20Sopenharmony_ci	test_string_get_size_one(8192, 4096, "33.6 MB", "32.0 MiB");
4068c2ecf20Sopenharmony_ci
4078c2ecf20Sopenharmony_ci	/* weird block sizes */
4088c2ecf20Sopenharmony_ci	test_string_get_size_one(3000, 1900, "5.70 MB", "5.44 MiB");
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	/* huge values */
4118c2ecf20Sopenharmony_ci	test_string_get_size_one(U64_MAX, 4096, "75.6 ZB", "64.0 ZiB");
4128c2ecf20Sopenharmony_ci	test_string_get_size_one(4096, U64_MAX, "75.6 ZB", "64.0 ZiB");
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic void __init test_string_upper_lower(void)
4168c2ecf20Sopenharmony_ci{
4178c2ecf20Sopenharmony_ci	char *dst;
4188c2ecf20Sopenharmony_ci	int i;
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(strings_upper); i++) {
4218c2ecf20Sopenharmony_ci		const char *s = strings_upper[i].in;
4228c2ecf20Sopenharmony_ci		int len = strlen(strings_upper[i].in) + 1;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci		dst = kmalloc(len, GFP_KERNEL);
4258c2ecf20Sopenharmony_ci		if (!dst)
4268c2ecf20Sopenharmony_ci			return;
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci		string_upper(dst, s);
4298c2ecf20Sopenharmony_ci		if (memcmp(dst, strings_upper[i].out, len)) {
4308c2ecf20Sopenharmony_ci			pr_warn("Test 'string_upper' failed : expected %s, got %s!\n",
4318c2ecf20Sopenharmony_ci				strings_upper[i].out, dst);
4328c2ecf20Sopenharmony_ci			kfree(dst);
4338c2ecf20Sopenharmony_ci			return;
4348c2ecf20Sopenharmony_ci		}
4358c2ecf20Sopenharmony_ci		kfree(dst);
4368c2ecf20Sopenharmony_ci	}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(strings_lower); i++) {
4398c2ecf20Sopenharmony_ci		const char *s = strings_lower[i].in;
4408c2ecf20Sopenharmony_ci		int len = strlen(strings_lower[i].in) + 1;
4418c2ecf20Sopenharmony_ci
4428c2ecf20Sopenharmony_ci		dst = kmalloc(len, GFP_KERNEL);
4438c2ecf20Sopenharmony_ci		if (!dst)
4448c2ecf20Sopenharmony_ci			return;
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		string_lower(dst, s);
4478c2ecf20Sopenharmony_ci		if (memcmp(dst, strings_lower[i].out, len)) {
4488c2ecf20Sopenharmony_ci			pr_warn("Test 'string_lower failed : : expected %s, got %s!\n",
4498c2ecf20Sopenharmony_ci				strings_lower[i].out, dst);
4508c2ecf20Sopenharmony_ci			kfree(dst);
4518c2ecf20Sopenharmony_ci			return;
4528c2ecf20Sopenharmony_ci		}
4538c2ecf20Sopenharmony_ci		kfree(dst);
4548c2ecf20Sopenharmony_ci	}
4558c2ecf20Sopenharmony_ci}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cistatic int __init test_string_helpers_init(void)
4588c2ecf20Sopenharmony_ci{
4598c2ecf20Sopenharmony_ci	unsigned int i;
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	pr_info("Running tests...\n");
4628c2ecf20Sopenharmony_ci	for (i = 0; i < UNESCAPE_ANY + 1; i++)
4638c2ecf20Sopenharmony_ci		test_string_unescape("unescape", i, false);
4648c2ecf20Sopenharmony_ci	test_string_unescape("unescape inplace",
4658c2ecf20Sopenharmony_ci			     get_random_int() % (UNESCAPE_ANY + 1), true);
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_ci	/* Without dictionary */
4688c2ecf20Sopenharmony_ci	for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++)
4698c2ecf20Sopenharmony_ci		test_string_escape("escape 0", escape0, i, TEST_STRING_2_DICT_0);
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	/* With dictionary */
4728c2ecf20Sopenharmony_ci	for (i = 0; i < (ESCAPE_ANY_NP | ESCAPE_HEX) + 1; i++)
4738c2ecf20Sopenharmony_ci		test_string_escape("escape 1", escape1, i, TEST_STRING_2_DICT_1);
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ci	/* Test string_get_size() */
4768c2ecf20Sopenharmony_ci	test_string_get_size();
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	/* Test string upper(), string_lower() */
4798c2ecf20Sopenharmony_ci	test_string_upper_lower();
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci	return -EINVAL;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_cimodule_init(test_string_helpers_init);
4848c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
485