2 * Test cases for lib/string_helpers.c module.
4 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
6 #include <linux/init.h>
7 #include <linux/kernel.h>
8 #include <linux/slab.h>
9 #include <linux/module.h>
10 #include <linux/random.h>
11 #include <linux/string.h>
12 #include <linux/string_helpers.h>
14 static __init
bool test_string_check_buf(const char *name
, unsigned int flags
,
16 char *out_real
, size_t q_real
,
17 char *out_test
, size_t q_test
)
19 if (q_real
== q_test
&& !memcmp(out_test
, out_real
, q_test
))
22 pr_warn("Test '%s' failed: flags = %u\n", name
, flags
);
24 print_hex_dump(KERN_WARNING
, "Input: ", DUMP_PREFIX_NONE
, 16, 1,
26 print_hex_dump(KERN_WARNING
, "Expected: ", DUMP_PREFIX_NONE
, 16, 1,
27 out_test
, q_test
, true);
28 print_hex_dump(KERN_WARNING
, "Got: ", DUMP_PREFIX_NONE
, 16, 1,
29 out_real
, q_real
, true);
40 static const struct test_string strings
[] __initconst
= {
42 .in
= "\\f\\ \\n\\r\\t\\v",
43 .out
= "\f\\ \n\r\t\v",
44 .flags
= UNESCAPE_SPACE
,
47 .in
= "\\40\\1\\387\\0064\\05\\040\\8a\\110\\777",
48 .out
= " \001\00387\0064\005 \\8aH?7",
49 .flags
= UNESCAPE_OCTAL
,
52 .in
= "\\xv\\xa\\x2c\\xD\\x6f2",
54 .flags
= UNESCAPE_HEX
,
57 .in
= "\\h\\\\\\\"\\a\\e\\",
58 .out
= "\\h\\\"\a\e\\",
59 .flags
= UNESCAPE_SPECIAL
,
63 static void __init
test_string_unescape(const char *name
, unsigned int flags
,
67 char *in
= kmalloc(q_real
, GFP_KERNEL
);
68 char *out_test
= kmalloc(q_real
, GFP_KERNEL
);
69 char *out_real
= kmalloc(q_real
, GFP_KERNEL
);
70 int i
, p
= 0, q_test
= 0;
72 if (!in
|| !out_test
|| !out_real
)
75 for (i
= 0; i
< ARRAY_SIZE(strings
); i
++) {
76 const char *s
= strings
[i
].in
;
77 int len
= strlen(strings
[i
].in
);
79 /* Copy string to in buffer */
80 memcpy(&in
[p
], s
, len
);
83 /* Copy expected result for given flags */
84 if (flags
& strings
[i
].flags
) {
86 len
= strlen(strings
[i
].out
);
88 memcpy(&out_test
[q_test
], s
, len
);
93 /* Call string_unescape and compare result */
95 memcpy(out_real
, in
, p
);
96 if (flags
== UNESCAPE_ANY
)
97 q_real
= string_unescape_any_inplace(out_real
);
99 q_real
= string_unescape_inplace(out_real
, flags
);
100 } else if (flags
== UNESCAPE_ANY
) {
101 q_real
= string_unescape_any(in
, out_real
, q_real
);
103 q_real
= string_unescape(in
, out_real
, q_real
, flags
);
106 test_string_check_buf(name
, flags
, in
, p
- 1, out_real
, q_real
,
114 struct test_string_1
{
119 #define TEST_STRING_2_MAX_S1 32
120 struct test_string_2
{
122 struct test_string_1 s1
[TEST_STRING_2_MAX_S1
];
125 #define TEST_STRING_2_DICT_0 NULL
126 static const struct test_string_2 escape0
[] __initconst
= {{
127 .in
= "\f\\ \n\r\t\v",
129 .out
= "\\f\\ \\n\\r\\t\\v",
130 .flags
= ESCAPE_SPACE
,
132 .out
= "\\f\\134\\040\\n\\r\\t\\v",
133 .flags
= ESCAPE_SPACE
| ESCAPE_OCTAL
,
135 .out
= "\\f\\x5c\\x20\\n\\r\\t\\v",
136 .flags
= ESCAPE_SPACE
| ESCAPE_HEX
,
141 .in
= "\\h\\\"\a\e\\",
143 .out
= "\\\\h\\\\\"\\a\\e\\\\",
144 .flags
= ESCAPE_SPECIAL
,
146 .out
= "\\\\\\150\\\\\\042\\a\\e\\\\",
147 .flags
= ESCAPE_SPECIAL
| ESCAPE_OCTAL
,
149 .out
= "\\\\\\x68\\\\\\x22\\a\\e\\\\",
150 .flags
= ESCAPE_SPECIAL
| ESCAPE_HEX
,
155 .in
= "\eb \\C\007\"\x90\r]",
157 .out
= "\eb \\C\007\"\x90\\r]",
158 .flags
= ESCAPE_SPACE
,
160 .out
= "\\eb \\\\C\\a\"\x90\r]",
161 .flags
= ESCAPE_SPECIAL
,
163 .out
= "\\eb \\\\C\\a\"\x90\\r]",
164 .flags
= ESCAPE_SPACE
| ESCAPE_SPECIAL
,
166 .out
= "\\033\\142\\040\\134\\103\\007\\042\\220\\015\\135",
167 .flags
= ESCAPE_OCTAL
,
169 .out
= "\\033\\142\\040\\134\\103\\007\\042\\220\\r\\135",
170 .flags
= ESCAPE_SPACE
| ESCAPE_OCTAL
,
172 .out
= "\\e\\142\\040\\\\\\103\\a\\042\\220\\015\\135",
173 .flags
= ESCAPE_SPECIAL
| ESCAPE_OCTAL
,
175 .out
= "\\e\\142\\040\\\\\\103\\a\\042\\220\\r\\135",
176 .flags
= ESCAPE_SPACE
| ESCAPE_SPECIAL
| ESCAPE_OCTAL
,
178 .out
= "\eb \\C\007\"\x90\r]",
181 .out
= "\eb \\C\007\"\x90\\r]",
182 .flags
= ESCAPE_SPACE
| ESCAPE_NP
,
184 .out
= "\\eb \\C\\a\"\x90\r]",
185 .flags
= ESCAPE_SPECIAL
| ESCAPE_NP
,
187 .out
= "\\eb \\C\\a\"\x90\\r]",
188 .flags
= ESCAPE_SPACE
| ESCAPE_SPECIAL
| ESCAPE_NP
,
190 .out
= "\\033b \\C\\007\"\\220\\015]",
191 .flags
= ESCAPE_OCTAL
| ESCAPE_NP
,
193 .out
= "\\033b \\C\\007\"\\220\\r]",
194 .flags
= ESCAPE_SPACE
| ESCAPE_OCTAL
| ESCAPE_NP
,
196 .out
= "\\eb \\C\\a\"\\220\\r]",
197 .flags
= ESCAPE_SPECIAL
| ESCAPE_SPACE
| ESCAPE_OCTAL
|
200 .out
= "\\x1bb \\C\\x07\"\\x90\\x0d]",
201 .flags
= ESCAPE_NP
| ESCAPE_HEX
,
209 #define TEST_STRING_2_DICT_1 "b\\ \t\r"
210 static const struct test_string_2 escape1
[] __initconst
= {{
211 .in
= "\f\\ \n\r\t\v",
213 .out
= "\f\\134\\040\n\\015\\011\v",
214 .flags
= ESCAPE_OCTAL
,
216 .out
= "\f\\x5c\\x20\n\\x0d\\x09\v",
222 .in
= "\\h\\\"\a\e\\",
224 .out
= "\\134h\\134\"\a\e\\134",
225 .flags
= ESCAPE_OCTAL
,
230 .in
= "\eb \\C\007\"\x90\r]",
232 .out
= "\e\\142\\040\\134C\007\"\x90\\015]",
233 .flags
= ESCAPE_OCTAL
,
241 static __init
const char *test_string_find_match(const struct test_string_2
*s2
,
244 const struct test_string_1
*s1
= s2
->s1
;
250 /* Test cases are NULL-aware */
251 flags
&= ~ESCAPE_NULL
;
253 /* ESCAPE_OCTAL has a higher priority */
254 if (flags
& ESCAPE_OCTAL
)
255 flags
&= ~ESCAPE_HEX
;
257 for (i
= 0; i
< TEST_STRING_2_MAX_S1
&& s1
->out
; i
++, s1
++)
258 if (s1
->flags
== flags
)
263 static __init
void test_string_escape(const char *name
,
264 const struct test_string_2
*s2
,
265 unsigned int flags
, const char *esc
)
268 char *out_test
= kmalloc(q_real
, GFP_KERNEL
);
269 char *out_real
= kmalloc(q_real
, GFP_KERNEL
);
270 char *in
= kmalloc(256, GFP_KERNEL
);
271 char *buf
= out_real
;
272 int p
= 0, q_test
= 0;
274 if (!out_test
|| !out_real
|| !in
)
277 for (; s2
->in
; s2
++) {
282 if (flags
& ESCAPE_NULL
) {
284 out_test
[q_test
++] = '\\';
285 out_test
[q_test
++] = '0';
288 /* Don't try strings that have no output */
289 out
= test_string_find_match(s2
, flags
);
293 /* Copy string to in buffer */
294 len
= strlen(s2
->in
);
295 memcpy(&in
[p
], s2
->in
, len
);
298 /* Copy expected result for given flags */
300 memcpy(&out_test
[q_test
], out
, len
);
304 q_real
= string_escape_mem(in
, p
, &buf
, q_real
, flags
, esc
);
306 test_string_check_buf(name
, flags
, in
, p
, out_real
, q_real
, out_test
,
314 static __init
void test_string_escape_nomem(void)
316 char *in
= "\eb \\C\007\"\x90\r]";
317 char out
[64], *buf
= out
;
318 int rc
= -ENOMEM
, ret
;
320 ret
= string_escape_str_any_np(in
, &buf
, strlen(in
), NULL
);
324 pr_err("Test 'escape nomem' failed: got %d instead of %d\n", ret
, rc
);
327 static int __init
test_string_helpers_init(void)
331 pr_info("Running tests...\n");
332 for (i
= 0; i
< UNESCAPE_ANY
+ 1; i
++)
333 test_string_unescape("unescape", i
, false);
334 test_string_unescape("unescape inplace",
335 get_random_int() % (UNESCAPE_ANY
+ 1), true);
337 /* Without dictionary */
338 for (i
= 0; i
< (ESCAPE_ANY_NP
| ESCAPE_HEX
) + 1; i
++)
339 test_string_escape("escape 0", escape0
, i
, TEST_STRING_2_DICT_0
);
341 /* With dictionary */
342 for (i
= 0; i
< (ESCAPE_ANY_NP
| ESCAPE_HEX
) + 1; i
++)
343 test_string_escape("escape 1", escape1
, i
, TEST_STRING_2_DICT_1
);
345 test_string_escape_nomem();
349 module_init(test_string_helpers_init
);
350 MODULE_LICENSE("Dual BSD/GPL");