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 = %#x\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\\\\\\\"\\a\\e\\\\",
147 .flags
= ESCAPE_SPECIAL
| ESCAPE_OCTAL
,
149 .out
= "\\\\\\x68\\\\\\\"\\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\\\"\\220\\015\\135",
173 .flags
= ESCAPE_SPECIAL
| ESCAPE_OCTAL
,
175 .out
= "\\e\\142\\040\\\\\\103\\a\\\"\\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
,
206 .in
= "\007 \eb\"\x90\xCF\r",
208 .out
= "\007 \eb\"\\220\\317\r",
209 .flags
= ESCAPE_OCTAL
| ESCAPE_NA
,
211 .out
= "\007 \eb\"\\x90\\xcf\r",
212 .flags
= ESCAPE_HEX
| ESCAPE_NA
,
214 .out
= "\007 \eb\"\x90\xCF\r",
223 #define TEST_STRING_2_DICT_1 "b\\ \t\r\xCF"
224 static const struct test_string_2 escape1
[] __initconst
= {{
225 .in
= "\f\\ \n\r\t\v",
227 .out
= "\f\\134\\040\n\\015\\011\v",
228 .flags
= ESCAPE_OCTAL
,
230 .out
= "\f\\x5c\\x20\n\\x0d\\x09\v",
233 .out
= "\f\\134\\040\n\\015\\011\v",
234 .flags
= ESCAPE_ANY
| ESCAPE_APPEND
,
236 .out
= "\\014\\134\\040\\012\\015\\011\\013",
237 .flags
= ESCAPE_OCTAL
| ESCAPE_APPEND
| ESCAPE_NAP
,
239 .out
= "\\x0c\\x5c\\x20\\x0a\\x0d\\x09\\x0b",
240 .flags
= ESCAPE_HEX
| ESCAPE_APPEND
| ESCAPE_NAP
,
242 .out
= "\f\\134\\040\n\\015\\011\v",
243 .flags
= ESCAPE_OCTAL
| ESCAPE_APPEND
| ESCAPE_NA
,
245 .out
= "\f\\x5c\\x20\n\\x0d\\x09\v",
246 .flags
= ESCAPE_HEX
| ESCAPE_APPEND
| ESCAPE_NA
,
251 .in
= "\\h\\\"\a\xCF\e\\",
253 .out
= "\\134h\\134\"\a\\317\e\\134",
254 .flags
= ESCAPE_OCTAL
,
256 .out
= "\\134h\\134\"\a\\317\e\\134",
257 .flags
= ESCAPE_ANY
| ESCAPE_APPEND
,
259 .out
= "\\134h\\134\"\\007\\317\\033\\134",
260 .flags
= ESCAPE_OCTAL
| ESCAPE_APPEND
| ESCAPE_NAP
,
262 .out
= "\\134h\\134\"\a\\317\e\\134",
263 .flags
= ESCAPE_OCTAL
| ESCAPE_APPEND
| ESCAPE_NA
,
268 .in
= "\eb \\C\007\"\x90\r]",
270 .out
= "\e\\142\\040\\134C\007\"\x90\\015]",
271 .flags
= ESCAPE_OCTAL
,
276 .in
= "\007 \eb\"\x90\xCF\r",
278 .out
= "\007 \eb\"\x90\xCF\r",
281 .out
= "\007 \eb\"\x90\xCF\r",
282 .flags
= ESCAPE_SPACE
| ESCAPE_NA
,
284 .out
= "\007 \eb\"\x90\xCF\r",
285 .flags
= ESCAPE_SPECIAL
| ESCAPE_NA
,
287 .out
= "\007 \eb\"\x90\xCF\r",
288 .flags
= ESCAPE_SPACE
| ESCAPE_SPECIAL
| ESCAPE_NA
,
290 .out
= "\007 \eb\"\x90\\317\r",
291 .flags
= ESCAPE_OCTAL
| ESCAPE_NA
,
293 .out
= "\007 \eb\"\x90\\317\r",
294 .flags
= ESCAPE_SPACE
| ESCAPE_OCTAL
| ESCAPE_NA
,
296 .out
= "\007 \eb\"\x90\\317\r",
297 .flags
= ESCAPE_SPECIAL
| ESCAPE_OCTAL
| ESCAPE_NA
,
299 .out
= "\007 \eb\"\x90\\317\r",
300 .flags
= ESCAPE_ANY
| ESCAPE_NA
,
302 .out
= "\007 \eb\"\x90\\xcf\r",
303 .flags
= ESCAPE_HEX
| ESCAPE_NA
,
305 .out
= "\007 \eb\"\x90\\xcf\r",
306 .flags
= ESCAPE_SPACE
| ESCAPE_HEX
| ESCAPE_NA
,
308 .out
= "\007 \eb\"\x90\\xcf\r",
309 .flags
= ESCAPE_SPECIAL
| ESCAPE_HEX
| ESCAPE_NA
,
311 .out
= "\007 \eb\"\x90\\xcf\r",
312 .flags
= ESCAPE_SPACE
| ESCAPE_SPECIAL
| ESCAPE_HEX
| ESCAPE_NA
,
317 .in
= "\007 \eb\"\x90\xCF\r",
319 .out
= "\007 \eb\"\x90\xCF\r",
322 .out
= "\007 \eb\"\x90\xCF\\r",
323 .flags
= ESCAPE_SPACE
| ESCAPE_NAP
,
325 .out
= "\007 \eb\"\x90\xCF\r",
326 .flags
= ESCAPE_SPECIAL
| ESCAPE_NAP
,
328 .out
= "\007 \eb\"\x90\xCF\\r",
329 .flags
= ESCAPE_SPACE
| ESCAPE_SPECIAL
| ESCAPE_NAP
,
331 .out
= "\007 \eb\"\x90\\317\\015",
332 .flags
= ESCAPE_OCTAL
| ESCAPE_NAP
,
334 .out
= "\007 \eb\"\x90\\317\\r",
335 .flags
= ESCAPE_SPACE
| ESCAPE_OCTAL
| ESCAPE_NAP
,
337 .out
= "\007 \eb\"\x90\\317\\015",
338 .flags
= ESCAPE_SPECIAL
| ESCAPE_OCTAL
| ESCAPE_NAP
,
340 .out
= "\007 \eb\"\x90\\317\r",
341 .flags
= ESCAPE_ANY
| ESCAPE_NAP
,
343 .out
= "\007 \eb\"\x90\\xcf\\x0d",
344 .flags
= ESCAPE_HEX
| ESCAPE_NAP
,
346 .out
= "\007 \eb\"\x90\\xcf\\r",
347 .flags
= ESCAPE_SPACE
| ESCAPE_HEX
| ESCAPE_NAP
,
349 .out
= "\007 \eb\"\x90\\xcf\\x0d",
350 .flags
= ESCAPE_SPECIAL
| ESCAPE_HEX
| ESCAPE_NAP
,
352 .out
= "\007 \eb\"\x90\\xcf\\r",
353 .flags
= ESCAPE_SPACE
| ESCAPE_SPECIAL
| ESCAPE_HEX
| ESCAPE_NAP
,
361 static const struct test_string strings_upper
[] __initconst
= {
363 .in
= "abcdefgh1234567890test",
364 .out
= "ABCDEFGH1234567890TEST",
367 .in
= "abCdeFgH1234567890TesT",
368 .out
= "ABCDEFGH1234567890TEST",
372 static const struct test_string strings_lower
[] __initconst
= {
374 .in
= "ABCDEFGH1234567890TEST",
375 .out
= "abcdefgh1234567890test",
378 .in
= "abCdeFgH1234567890TesT",
379 .out
= "abcdefgh1234567890test",
383 static __init
const char *test_string_find_match(const struct test_string_2
*s2
,
386 const struct test_string_1
*s1
= s2
->s1
;
392 /* Test cases are NULL-aware */
393 flags
&= ~ESCAPE_NULL
;
395 /* ESCAPE_OCTAL has a higher priority */
396 if (flags
& ESCAPE_OCTAL
)
397 flags
&= ~ESCAPE_HEX
;
399 for (i
= 0; i
< TEST_STRING_2_MAX_S1
&& s1
->out
; i
++, s1
++)
400 if (s1
->flags
== flags
)
406 test_string_escape_overflow(const char *in
, int p
, unsigned int flags
, const char *esc
,
407 int q_test
, const char *name
)
411 q_real
= string_escape_mem(in
, p
, NULL
, 0, flags
, esc
);
412 if (q_real
!= q_test
)
413 pr_warn("Test '%s' failed: flags = %#x, osz = 0, expected %d, got %d\n",
414 name
, flags
, q_test
, q_real
);
417 static __init
void test_string_escape(const char *name
,
418 const struct test_string_2
*s2
,
419 unsigned int flags
, const char *esc
)
421 size_t out_size
= 512;
422 char *out_test
= kmalloc(out_size
, GFP_KERNEL
);
423 char *out_real
= kmalloc(out_size
, GFP_KERNEL
);
424 char *in
= kmalloc(256, GFP_KERNEL
);
425 int p
= 0, q_test
= 0;
428 if (!out_test
|| !out_real
|| !in
)
431 for (; s2
->in
; s2
++) {
436 if (flags
& ESCAPE_NULL
) {
438 /* '\0' passes isascii() test */
439 if (flags
& ESCAPE_NA
&& !(flags
& ESCAPE_APPEND
&& esc
)) {
440 out_test
[q_test
++] = '\0';
442 out_test
[q_test
++] = '\\';
443 out_test
[q_test
++] = '0';
447 /* Don't try strings that have no output */
448 out
= test_string_find_match(s2
, flags
);
452 /* Copy string to in buffer */
453 len
= strlen(s2
->in
);
454 memcpy(&in
[p
], s2
->in
, len
);
457 /* Copy expected result for given flags */
459 memcpy(&out_test
[q_test
], out
, len
);
463 q_real
= string_escape_mem(in
, p
, out_real
, out_size
, flags
, esc
);
465 test_string_check_buf(name
, flags
, in
, p
, out_real
, q_real
, out_test
,
468 test_string_escape_overflow(in
, p
, flags
, esc
, q_test
, name
);
476 #define string_get_size_maxbuf 16
477 #define test_string_get_size_one(size, blk_size, exp_result10, exp_result2) \
479 BUILD_BUG_ON(sizeof(exp_result10) >= string_get_size_maxbuf); \
480 BUILD_BUG_ON(sizeof(exp_result2) >= string_get_size_maxbuf); \
481 __test_string_get_size((size), (blk_size), (exp_result10), \
486 static __init
void test_string_get_size_check(const char *units
,
492 if (!memcmp(res
, exp
, strlen(exp
) + 1))
495 res
[string_get_size_maxbuf
- 1] = '\0';
497 pr_warn("Test 'test_string_get_size' failed!\n");
498 pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %s)\n",
499 size
, blk_size
, units
);
500 pr_warn("expected: '%s', got '%s'\n", exp
, res
);
503 static __init
void __test_string_get_size(const u64 size
, const u64 blk_size
,
504 const char *exp_result10
,
505 const char *exp_result2
)
507 char buf10
[string_get_size_maxbuf
];
508 char buf2
[string_get_size_maxbuf
];
510 string_get_size(size
, blk_size
, STRING_UNITS_10
, buf10
, sizeof(buf10
));
511 string_get_size(size
, blk_size
, STRING_UNITS_2
, buf2
, sizeof(buf2
));
513 test_string_get_size_check("STRING_UNITS_10", exp_result10
, buf10
,
516 test_string_get_size_check("STRING_UNITS_2", exp_result2
, buf2
,
520 static __init
void test_string_get_size(void)
523 test_string_get_size_one(0, 512, "0 B", "0 B");
524 test_string_get_size_one(1, 512, "512 B", "512 B");
525 test_string_get_size_one(1100, 1, "1.10 kB", "1.07 KiB");
528 test_string_get_size_one(16384, 512, "8.39 MB", "8.00 MiB");
529 test_string_get_size_one(500118192, 512, "256 GB", "238 GiB");
530 test_string_get_size_one(8192, 4096, "33.6 MB", "32.0 MiB");
532 /* weird block sizes */
533 test_string_get_size_one(3000, 1900, "5.70 MB", "5.44 MiB");
536 test_string_get_size_one(U64_MAX
, 4096, "75.6 ZB", "64.0 ZiB");
537 test_string_get_size_one(4096, U64_MAX
, "75.6 ZB", "64.0 ZiB");
540 static void __init
test_string_upper_lower(void)
545 for (i
= 0; i
< ARRAY_SIZE(strings_upper
); i
++) {
546 const char *s
= strings_upper
[i
].in
;
547 int len
= strlen(strings_upper
[i
].in
) + 1;
549 dst
= kmalloc(len
, GFP_KERNEL
);
553 string_upper(dst
, s
);
554 if (memcmp(dst
, strings_upper
[i
].out
, len
)) {
555 pr_warn("Test 'string_upper' failed : expected %s, got %s!\n",
556 strings_upper
[i
].out
, dst
);
563 for (i
= 0; i
< ARRAY_SIZE(strings_lower
); i
++) {
564 const char *s
= strings_lower
[i
].in
;
565 int len
= strlen(strings_lower
[i
].in
) + 1;
567 dst
= kmalloc(len
, GFP_KERNEL
);
571 string_lower(dst
, s
);
572 if (memcmp(dst
, strings_lower
[i
].out
, len
)) {
573 pr_warn("Test 'string_lower failed : : expected %s, got %s!\n",
574 strings_lower
[i
].out
, dst
);
582 static int __init
test_string_helpers_init(void)
586 pr_info("Running tests...\n");
587 for (i
= 0; i
< UNESCAPE_ALL_MASK
+ 1; i
++)
588 test_string_unescape("unescape", i
, false);
589 test_string_unescape("unescape inplace",
590 get_random_u32_below(UNESCAPE_ALL_MASK
+ 1), true);
592 /* Without dictionary */
593 for (i
= 0; i
< ESCAPE_ALL_MASK
+ 1; i
++)
594 test_string_escape("escape 0", escape0
, i
, TEST_STRING_2_DICT_0
);
596 /* With dictionary */
597 for (i
= 0; i
< ESCAPE_ALL_MASK
+ 1; i
++)
598 test_string_escape("escape 1", escape1
, i
, TEST_STRING_2_DICT_1
);
600 /* Test string_get_size() */
601 test_string_get_size();
603 /* Test string upper(), string_lower() */
604 test_string_upper_lower();
608 module_init(test_string_helpers_init
);
609 MODULE_LICENSE("Dual BSD/GPL");