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 const struct test_string strings_upper
[] __initconst
= {
243 .in
= "abcdefgh1234567890test",
244 .out
= "ABCDEFGH1234567890TEST",
247 .in
= "abCdeFgH1234567890TesT",
248 .out
= "ABCDEFGH1234567890TEST",
252 static const struct test_string strings_lower
[] __initconst
= {
254 .in
= "ABCDEFGH1234567890TEST",
255 .out
= "abcdefgh1234567890test",
258 .in
= "abCdeFgH1234567890TesT",
259 .out
= "abcdefgh1234567890test",
263 static __init
const char *test_string_find_match(const struct test_string_2
*s2
,
266 const struct test_string_1
*s1
= s2
->s1
;
272 /* Test cases are NULL-aware */
273 flags
&= ~ESCAPE_NULL
;
275 /* ESCAPE_OCTAL has a higher priority */
276 if (flags
& ESCAPE_OCTAL
)
277 flags
&= ~ESCAPE_HEX
;
279 for (i
= 0; i
< TEST_STRING_2_MAX_S1
&& s1
->out
; i
++, s1
++)
280 if (s1
->flags
== flags
)
286 test_string_escape_overflow(const char *in
, int p
, unsigned int flags
, const char *esc
,
287 int q_test
, const char *name
)
291 q_real
= string_escape_mem(in
, p
, NULL
, 0, flags
, esc
);
292 if (q_real
!= q_test
)
293 pr_warn("Test '%s' failed: flags = %u, osz = 0, expected %d, got %d\n",
294 name
, flags
, q_test
, q_real
);
297 static __init
void test_string_escape(const char *name
,
298 const struct test_string_2
*s2
,
299 unsigned int flags
, const char *esc
)
301 size_t out_size
= 512;
302 char *out_test
= kmalloc(out_size
, GFP_KERNEL
);
303 char *out_real
= kmalloc(out_size
, GFP_KERNEL
);
304 char *in
= kmalloc(256, GFP_KERNEL
);
305 int p
= 0, q_test
= 0;
308 if (!out_test
|| !out_real
|| !in
)
311 for (; s2
->in
; s2
++) {
316 if (flags
& ESCAPE_NULL
) {
318 out_test
[q_test
++] = '\\';
319 out_test
[q_test
++] = '0';
322 /* Don't try strings that have no output */
323 out
= test_string_find_match(s2
, flags
);
327 /* Copy string to in buffer */
328 len
= strlen(s2
->in
);
329 memcpy(&in
[p
], s2
->in
, len
);
332 /* Copy expected result for given flags */
334 memcpy(&out_test
[q_test
], out
, len
);
338 q_real
= string_escape_mem(in
, p
, out_real
, out_size
, flags
, esc
);
340 test_string_check_buf(name
, flags
, in
, p
, out_real
, q_real
, out_test
,
343 test_string_escape_overflow(in
, p
, flags
, esc
, q_test
, name
);
351 #define string_get_size_maxbuf 16
352 #define test_string_get_size_one(size, blk_size, exp_result10, exp_result2) \
354 BUILD_BUG_ON(sizeof(exp_result10) >= string_get_size_maxbuf); \
355 BUILD_BUG_ON(sizeof(exp_result2) >= string_get_size_maxbuf); \
356 __test_string_get_size((size), (blk_size), (exp_result10), \
361 static __init
void test_string_get_size_check(const char *units
,
367 if (!memcmp(res
, exp
, strlen(exp
) + 1))
370 res
[string_get_size_maxbuf
- 1] = '\0';
372 pr_warn("Test 'test_string_get_size' failed!\n");
373 pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %s)\n",
374 size
, blk_size
, units
);
375 pr_warn("expected: '%s', got '%s'\n", exp
, res
);
378 static __init
void __test_string_get_size(const u64 size
, const u64 blk_size
,
379 const char *exp_result10
,
380 const char *exp_result2
)
382 char buf10
[string_get_size_maxbuf
];
383 char buf2
[string_get_size_maxbuf
];
385 string_get_size(size
, blk_size
, STRING_UNITS_10
, buf10
, sizeof(buf10
));
386 string_get_size(size
, blk_size
, STRING_UNITS_2
, buf2
, sizeof(buf2
));
388 test_string_get_size_check("STRING_UNITS_10", exp_result10
, buf10
,
391 test_string_get_size_check("STRING_UNITS_2", exp_result2
, buf2
,
395 static __init
void test_string_get_size(void)
398 test_string_get_size_one(0, 512, "0 B", "0 B");
399 test_string_get_size_one(1, 512, "512 B", "512 B");
400 test_string_get_size_one(1100, 1, "1.10 kB", "1.07 KiB");
403 test_string_get_size_one(16384, 512, "8.39 MB", "8.00 MiB");
404 test_string_get_size_one(500118192, 512, "256 GB", "238 GiB");
405 test_string_get_size_one(8192, 4096, "33.6 MB", "32.0 MiB");
407 /* weird block sizes */
408 test_string_get_size_one(3000, 1900, "5.70 MB", "5.44 MiB");
411 test_string_get_size_one(U64_MAX
, 4096, "75.6 ZB", "64.0 ZiB");
412 test_string_get_size_one(4096, U64_MAX
, "75.6 ZB", "64.0 ZiB");
415 static void __init
test_string_upper_lower(void)
420 for (i
= 0; i
< ARRAY_SIZE(strings_upper
); i
++) {
421 const char *s
= strings_upper
[i
].in
;
422 int len
= strlen(strings_upper
[i
].in
) + 1;
424 dst
= kmalloc(len
, GFP_KERNEL
);
428 string_upper(dst
, s
);
429 if (memcmp(dst
, strings_upper
[i
].out
, len
)) {
430 pr_warn("Test 'string_upper' failed : expected %s, got %s!\n",
431 strings_upper
[i
].out
, dst
);
438 for (i
= 0; i
< ARRAY_SIZE(strings_lower
); i
++) {
439 const char *s
= strings_lower
[i
].in
;
440 int len
= strlen(strings_lower
[i
].in
) + 1;
442 dst
= kmalloc(len
, GFP_KERNEL
);
446 string_lower(dst
, s
);
447 if (memcmp(dst
, strings_lower
[i
].out
, len
)) {
448 pr_warn("Test 'string_lower failed : : expected %s, got %s!\n",
449 strings_lower
[i
].out
, dst
);
457 static int __init
test_string_helpers_init(void)
461 pr_info("Running tests...\n");
462 for (i
= 0; i
< UNESCAPE_ANY
+ 1; i
++)
463 test_string_unescape("unescape", i
, false);
464 test_string_unescape("unescape inplace",
465 get_random_int() % (UNESCAPE_ANY
+ 1), true);
467 /* Without dictionary */
468 for (i
= 0; i
< (ESCAPE_ANY_NP
| ESCAPE_HEX
) + 1; i
++)
469 test_string_escape("escape 0", escape0
, i
, TEST_STRING_2_DICT_0
);
471 /* With dictionary */
472 for (i
= 0; i
< (ESCAPE_ANY_NP
| ESCAPE_HEX
) + 1; i
++)
473 test_string_escape("escape 1", escape1
, i
, TEST_STRING_2_DICT_1
);
475 /* Test string_get_size() */
476 test_string_get_size();
478 /* Test string upper(), string_lower() */
479 test_string_upper_lower();
483 module_init(test_string_helpers_init
);
484 MODULE_LICENSE("Dual BSD/GPL");