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
)
264 test_string_escape_overflow(const char *in
, int p
, unsigned int flags
, const char *esc
,
265 int q_test
, const char *name
)
269 q_real
= string_escape_mem(in
, p
, NULL
, 0, flags
, esc
);
270 if (q_real
!= q_test
)
271 pr_warn("Test '%s' failed: flags = %u, osz = 0, expected %d, got %d\n",
272 name
, flags
, q_test
, q_real
);
275 static __init
void test_string_escape(const char *name
,
276 const struct test_string_2
*s2
,
277 unsigned int flags
, const char *esc
)
279 size_t out_size
= 512;
280 char *out_test
= kmalloc(out_size
, GFP_KERNEL
);
281 char *out_real
= kmalloc(out_size
, GFP_KERNEL
);
282 char *in
= kmalloc(256, GFP_KERNEL
);
283 int p
= 0, q_test
= 0;
286 if (!out_test
|| !out_real
|| !in
)
289 for (; s2
->in
; s2
++) {
294 if (flags
& ESCAPE_NULL
) {
296 out_test
[q_test
++] = '\\';
297 out_test
[q_test
++] = '0';
300 /* Don't try strings that have no output */
301 out
= test_string_find_match(s2
, flags
);
305 /* Copy string to in buffer */
306 len
= strlen(s2
->in
);
307 memcpy(&in
[p
], s2
->in
, len
);
310 /* Copy expected result for given flags */
312 memcpy(&out_test
[q_test
], out
, len
);
316 q_real
= string_escape_mem(in
, p
, out_real
, out_size
, flags
, esc
);
318 test_string_check_buf(name
, flags
, in
, p
, out_real
, q_real
, out_test
,
321 test_string_escape_overflow(in
, p
, flags
, esc
, q_test
, name
);
329 #define string_get_size_maxbuf 16
330 #define test_string_get_size_one(size, blk_size, exp_result10, exp_result2) \
332 BUILD_BUG_ON(sizeof(exp_result10) >= string_get_size_maxbuf); \
333 BUILD_BUG_ON(sizeof(exp_result2) >= string_get_size_maxbuf); \
334 __test_string_get_size((size), (blk_size), (exp_result10), \
339 static __init
void test_string_get_size_check(const char *units
,
345 if (!memcmp(res
, exp
, strlen(exp
) + 1))
348 res
[string_get_size_maxbuf
- 1] = '\0';
350 pr_warn("Test 'test_string_get_size' failed!\n");
351 pr_warn("string_get_size(size = %llu, blk_size = %llu, units = %s)\n",
352 size
, blk_size
, units
);
353 pr_warn("expected: '%s', got '%s'\n", exp
, res
);
356 static __init
void __test_string_get_size(const u64 size
, const u64 blk_size
,
357 const char *exp_result10
,
358 const char *exp_result2
)
360 char buf10
[string_get_size_maxbuf
];
361 char buf2
[string_get_size_maxbuf
];
363 string_get_size(size
, blk_size
, STRING_UNITS_10
, buf10
, sizeof(buf10
));
364 string_get_size(size
, blk_size
, STRING_UNITS_2
, buf2
, sizeof(buf2
));
366 test_string_get_size_check("STRING_UNITS_10", exp_result10
, buf10
,
369 test_string_get_size_check("STRING_UNITS_2", exp_result2
, buf2
,
373 static __init
void test_string_get_size(void)
376 test_string_get_size_one(0, 512, "0 B", "0 B");
377 test_string_get_size_one(1, 512, "512 B", "512 B");
378 test_string_get_size_one(1100, 1, "1.10 kB", "1.07 KiB");
381 test_string_get_size_one(16384, 512, "8.39 MB", "8.00 MiB");
382 test_string_get_size_one(500118192, 512, "256 GB", "238 GiB");
383 test_string_get_size_one(8192, 4096, "33.6 MB", "32.0 MiB");
385 /* weird block sizes */
386 test_string_get_size_one(3000, 1900, "5.70 MB", "5.44 MiB");
389 test_string_get_size_one(U64_MAX
, 4096, "75.6 ZB", "64.0 ZiB");
390 test_string_get_size_one(4096, U64_MAX
, "75.6 ZB", "64.0 ZiB");
393 static int __init
test_string_helpers_init(void)
397 pr_info("Running tests...\n");
398 for (i
= 0; i
< UNESCAPE_ANY
+ 1; i
++)
399 test_string_unescape("unescape", i
, false);
400 test_string_unescape("unescape inplace",
401 get_random_int() % (UNESCAPE_ANY
+ 1), true);
403 /* Without dictionary */
404 for (i
= 0; i
< (ESCAPE_ANY_NP
| ESCAPE_HEX
) + 1; i
++)
405 test_string_escape("escape 0", escape0
, i
, TEST_STRING_2_DICT_0
);
407 /* With dictionary */
408 for (i
= 0; i
< (ESCAPE_ANY_NP
| ESCAPE_HEX
) + 1; i
++)
409 test_string_escape("escape 1", escape1
, i
, TEST_STRING_2_DICT_1
);
411 /* Test string_get_size() */
412 test_string_get_size();
416 module_init(test_string_helpers_init
);
417 MODULE_LICENSE("Dual BSD/GPL");