xref: /linux/lib/tests/scanf_kunit.c (revision bbfd5594756011167b8f8de9a00e0c946afda1e6)
197c1f302STamir Duberstein // SPDX-License-Identifier: GPL-2.0-only
297c1f302STamir Duberstein /*
397c1f302STamir Duberstein  * Test cases for sscanf facility.
497c1f302STamir Duberstein  */
597c1f302STamir Duberstein 
697c1f302STamir Duberstein #include <kunit/test.h>
797c1f302STamir Duberstein #include <linux/bitops.h>
897c1f302STamir Duberstein #include <linux/kernel.h>
997c1f302STamir Duberstein #include <linux/module.h>
1097c1f302STamir Duberstein #include <linux/overflow.h>
1197c1f302STamir Duberstein #include <linux/prandom.h>
1297c1f302STamir Duberstein #include <linux/slab.h>
1397c1f302STamir Duberstein #include <linux/string.h>
1497c1f302STamir Duberstein 
1597c1f302STamir Duberstein #define BUF_SIZE 1024
1697c1f302STamir Duberstein 
1797c1f302STamir Duberstein static char *test_buffer;
1897c1f302STamir Duberstein static char *fmt_buffer;
1997c1f302STamir Duberstein static struct rnd_state rnd_state;
2097c1f302STamir Duberstein 
2197c1f302STamir Duberstein typedef void (*check_fn)(struct kunit *test, const char *file, const int line,
2297c1f302STamir Duberstein 			 const void *check_data, const char *string, const char *fmt, int n_args,
2397c1f302STamir Duberstein 			 va_list ap);
2497c1f302STamir Duberstein 
2597c1f302STamir Duberstein static void __scanf(7, 9)
2697c1f302STamir Duberstein _test(struct kunit *test, const char *file, const int line, check_fn fn, const void *check_data,
2797c1f302STamir Duberstein 	const char *string, const char *fmt, int n_args, ...)
2897c1f302STamir Duberstein {
2997c1f302STamir Duberstein 	va_list ap, ap_copy;
3097c1f302STamir Duberstein 	int ret;
3197c1f302STamir Duberstein 
3297c1f302STamir Duberstein 	va_start(ap, n_args);
3397c1f302STamir Duberstein 	va_copy(ap_copy, ap);
3497c1f302STamir Duberstein 	ret = vsscanf(string, fmt, ap_copy);
3597c1f302STamir Duberstein 	va_end(ap_copy);
3697c1f302STamir Duberstein 
3797c1f302STamir Duberstein 	if (ret != n_args) {
3897c1f302STamir Duberstein 		KUNIT_FAIL(test, "%s:%d: vsscanf(\"%s\", \"%s\", ...) returned %d expected %d",
3997c1f302STamir Duberstein 			   file, line, string, fmt, ret, n_args);
4097c1f302STamir Duberstein 	} else {
4197c1f302STamir Duberstein 		(*fn)(test, file, line, check_data, string, fmt, n_args, ap);
4297c1f302STamir Duberstein 	}
4397c1f302STamir Duberstein 
4497c1f302STamir Duberstein 	va_end(ap);
4597c1f302STamir Duberstein }
4697c1f302STamir Duberstein 
4797c1f302STamir Duberstein #define _check_numbers_template(arg_fmt, expect, str, fmt, n_args, ap)		\
4897c1f302STamir Duberstein do {										\
4997c1f302STamir Duberstein 	for (; n_args > 0; n_args--, expect++) {				\
5097c1f302STamir Duberstein 		typeof(*expect) got = *va_arg(ap, typeof(expect));		\
5197c1f302STamir Duberstein 		if (got != *expect) {						\
5297c1f302STamir Duberstein 			KUNIT_FAIL(test,					\
5397c1f302STamir Duberstein 				   "%s:%d: vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt, \
5497c1f302STamir Duberstein 				   file, line, str, fmt, *expect, got);		\
5597c1f302STamir Duberstein 			return;							\
5697c1f302STamir Duberstein 		}								\
5797c1f302STamir Duberstein 	}									\
5897c1f302STamir Duberstein } while (0)
5997c1f302STamir Duberstein 
6097c1f302STamir Duberstein static void check_ull(struct kunit *test, const char *file, const int line, const void *check_data,
6197c1f302STamir Duberstein 		      const char *string, const char *fmt, int n_args, va_list ap)
6297c1f302STamir Duberstein {
6397c1f302STamir Duberstein 	const unsigned long long *pval = check_data;
6497c1f302STamir Duberstein 
6597c1f302STamir Duberstein 	_check_numbers_template("%llu", pval, string, fmt, n_args, ap);
6697c1f302STamir Duberstein }
6797c1f302STamir Duberstein 
6897c1f302STamir Duberstein static void check_ll(struct kunit *test, const char *file, const int line, const void *check_data,
6997c1f302STamir Duberstein 		     const char *string, const char *fmt, int n_args, va_list ap)
7097c1f302STamir Duberstein {
7197c1f302STamir Duberstein 	const long long *pval = check_data;
7297c1f302STamir Duberstein 
7397c1f302STamir Duberstein 	_check_numbers_template("%lld", pval, string, fmt, n_args, ap);
7497c1f302STamir Duberstein }
7597c1f302STamir Duberstein 
7697c1f302STamir Duberstein static void check_ulong(struct kunit *test, const char *file, const int line,
7797c1f302STamir Duberstein 			const void *check_data, const char *string, const char *fmt, int n_args,
7897c1f302STamir Duberstein 			va_list ap)
7997c1f302STamir Duberstein {
8097c1f302STamir Duberstein 	const unsigned long *pval = check_data;
8197c1f302STamir Duberstein 
8297c1f302STamir Duberstein 	_check_numbers_template("%lu", pval, string, fmt, n_args, ap);
8397c1f302STamir Duberstein }
8497c1f302STamir Duberstein 
8597c1f302STamir Duberstein static void check_long(struct kunit *test, const char *file, const int line, const void *check_data,
8697c1f302STamir Duberstein 		       const char *string, const char *fmt, int n_args, va_list ap)
8797c1f302STamir Duberstein {
8897c1f302STamir Duberstein 	const long *pval = check_data;
8997c1f302STamir Duberstein 
9097c1f302STamir Duberstein 	_check_numbers_template("%ld", pval, string, fmt, n_args, ap);
9197c1f302STamir Duberstein }
9297c1f302STamir Duberstein 
9397c1f302STamir Duberstein static void check_uint(struct kunit *test, const char *file, const int line, const void *check_data,
9497c1f302STamir Duberstein 		       const char *string, const char *fmt, int n_args, va_list ap)
9597c1f302STamir Duberstein {
9697c1f302STamir Duberstein 	const unsigned int *pval = check_data;
9797c1f302STamir Duberstein 
9897c1f302STamir Duberstein 	_check_numbers_template("%u", pval, string, fmt, n_args, ap);
9997c1f302STamir Duberstein }
10097c1f302STamir Duberstein 
10197c1f302STamir Duberstein static void check_int(struct kunit *test, const char *file, const int line, const void *check_data,
10297c1f302STamir Duberstein 		      const char *string, const char *fmt, int n_args, va_list ap)
10397c1f302STamir Duberstein {
10497c1f302STamir Duberstein 	const int *pval = check_data;
10597c1f302STamir Duberstein 
10697c1f302STamir Duberstein 	_check_numbers_template("%d", pval, string, fmt, n_args, ap);
10797c1f302STamir Duberstein }
10897c1f302STamir Duberstein 
10997c1f302STamir Duberstein static void check_ushort(struct kunit *test, const char *file, const int line,
11097c1f302STamir Duberstein 			 const void *check_data, const char *string, const char *fmt, int n_args,
11197c1f302STamir Duberstein 			 va_list ap)
11297c1f302STamir Duberstein {
11397c1f302STamir Duberstein 	const unsigned short *pval = check_data;
11497c1f302STamir Duberstein 
11597c1f302STamir Duberstein 	_check_numbers_template("%hu", pval, string, fmt, n_args, ap);
11697c1f302STamir Duberstein }
11797c1f302STamir Duberstein 
11897c1f302STamir Duberstein static void check_short(struct kunit *test, const char *file, const int line,
11997c1f302STamir Duberstein 			const void *check_data, const char *string, const char *fmt, int n_args,
12097c1f302STamir Duberstein 			va_list ap)
12197c1f302STamir Duberstein {
12297c1f302STamir Duberstein 	const short *pval = check_data;
12397c1f302STamir Duberstein 
12497c1f302STamir Duberstein 	_check_numbers_template("%hd", pval, string, fmt, n_args, ap);
12597c1f302STamir Duberstein }
12697c1f302STamir Duberstein 
12797c1f302STamir Duberstein static void check_uchar(struct kunit *test, const char *file, const int line,
12897c1f302STamir Duberstein 			const void *check_data, const char *string, const char *fmt, int n_args,
12997c1f302STamir Duberstein 			va_list ap)
13097c1f302STamir Duberstein {
13197c1f302STamir Duberstein 	const unsigned char *pval = check_data;
13297c1f302STamir Duberstein 
13397c1f302STamir Duberstein 	_check_numbers_template("%hhu", pval, string, fmt, n_args, ap);
13497c1f302STamir Duberstein }
13597c1f302STamir Duberstein 
13697c1f302STamir Duberstein static void check_char(struct kunit *test, const char *file, const int line, const void *check_data,
13797c1f302STamir Duberstein 		       const char *string, const char *fmt, int n_args, va_list ap)
13897c1f302STamir Duberstein {
13997c1f302STamir Duberstein 	const signed char *pval = check_data;
14097c1f302STamir Duberstein 
14197c1f302STamir Duberstein 	_check_numbers_template("%hhd", pval, string, fmt, n_args, ap);
14297c1f302STamir Duberstein }
14397c1f302STamir Duberstein 
14497c1f302STamir Duberstein /* Selection of interesting numbers to test, copied from test-kstrtox.c */
14597c1f302STamir Duberstein static const unsigned long long numbers[] = {
14697c1f302STamir Duberstein 	0x0ULL,
14797c1f302STamir Duberstein 	0x1ULL,
14897c1f302STamir Duberstein 	0x7fULL,
14997c1f302STamir Duberstein 	0x80ULL,
15097c1f302STamir Duberstein 	0x81ULL,
15197c1f302STamir Duberstein 	0xffULL,
15297c1f302STamir Duberstein 	0x100ULL,
15397c1f302STamir Duberstein 	0x101ULL,
15497c1f302STamir Duberstein 	0x7fffULL,
15597c1f302STamir Duberstein 	0x8000ULL,
15697c1f302STamir Duberstein 	0x8001ULL,
15797c1f302STamir Duberstein 	0xffffULL,
15897c1f302STamir Duberstein 	0x10000ULL,
15997c1f302STamir Duberstein 	0x10001ULL,
16097c1f302STamir Duberstein 	0x7fffffffULL,
16197c1f302STamir Duberstein 	0x80000000ULL,
16297c1f302STamir Duberstein 	0x80000001ULL,
16397c1f302STamir Duberstein 	0xffffffffULL,
16497c1f302STamir Duberstein 	0x100000000ULL,
16597c1f302STamir Duberstein 	0x100000001ULL,
16697c1f302STamir Duberstein 	0x7fffffffffffffffULL,
16797c1f302STamir Duberstein 	0x8000000000000000ULL,
16897c1f302STamir Duberstein 	0x8000000000000001ULL,
16997c1f302STamir Duberstein 	0xfffffffffffffffeULL,
17097c1f302STamir Duberstein 	0xffffffffffffffffULL,
17197c1f302STamir Duberstein };
17297c1f302STamir Duberstein 
17397c1f302STamir Duberstein #define value_representable_in_type(T, val)					 \
17497c1f302STamir Duberstein (is_signed_type(T)								 \
17597c1f302STamir Duberstein 	? ((long long)(val) >= type_min(T)) && ((long long)(val) <= type_max(T)) \
17697c1f302STamir Duberstein 	: ((unsigned long long)(val) <= type_max(T)))
17797c1f302STamir Duberstein 
17897c1f302STamir Duberstein 
17997c1f302STamir Duberstein #define test_one_number(T, gen_fmt, scan_fmt, val, fn)			\
18097c1f302STamir Duberstein do {									\
18197c1f302STamir Duberstein 	const T expect_val = (T)(val);					\
18297c1f302STamir Duberstein 	T result = ~expect_val; /* should be overwritten */		\
18397c1f302STamir Duberstein 									\
18497c1f302STamir Duberstein 	snprintf(test_buffer, BUF_SIZE, gen_fmt, expect_val);		\
18597c1f302STamir Duberstein 	_test(test, __FILE__, __LINE__, fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result);\
18697c1f302STamir Duberstein } while (0)
18797c1f302STamir Duberstein 
18897c1f302STamir Duberstein #define simple_numbers_loop(T, gen_fmt, scan_fmt, fn)			\
18997c1f302STamir Duberstein do {									\
19097c1f302STamir Duberstein 	int i;								\
19197c1f302STamir Duberstein 									\
19297c1f302STamir Duberstein 	for (i = 0; i < ARRAY_SIZE(numbers); i++) {			\
19397c1f302STamir Duberstein 		if (value_representable_in_type(T, numbers[i]))		\
19497c1f302STamir Duberstein 			test_one_number(T, gen_fmt, scan_fmt,		\
19597c1f302STamir Duberstein 					numbers[i], fn);		\
19697c1f302STamir Duberstein 									\
19797c1f302STamir Duberstein 		if (value_representable_in_type(T, -numbers[i]))	\
19897c1f302STamir Duberstein 			test_one_number(T, gen_fmt, scan_fmt,		\
19997c1f302STamir Duberstein 					-numbers[i], fn);		\
20097c1f302STamir Duberstein 	}								\
20197c1f302STamir Duberstein } while (0)
20297c1f302STamir Duberstein 
20397c1f302STamir Duberstein static void numbers_simple(struct kunit *test)
20497c1f302STamir Duberstein {
20597c1f302STamir Duberstein 	simple_numbers_loop(unsigned long long,	"%llu",	  "llu", check_ull);
20697c1f302STamir Duberstein 	simple_numbers_loop(long long,		"%lld",	  "lld", check_ll);
20797c1f302STamir Duberstein 	simple_numbers_loop(long long,		"%lld",	  "lli", check_ll);
20897c1f302STamir Duberstein 	simple_numbers_loop(unsigned long long,	"%llx",	  "llx", check_ull);
20997c1f302STamir Duberstein 	simple_numbers_loop(long long,		"%llx",	  "llx", check_ll);
21097c1f302STamir Duberstein 	simple_numbers_loop(long long,		"0x%llx", "lli", check_ll);
21197c1f302STamir Duberstein 	simple_numbers_loop(unsigned long long, "0x%llx", "llx", check_ull);
21297c1f302STamir Duberstein 	simple_numbers_loop(long long,		"0x%llx", "llx", check_ll);
21397c1f302STamir Duberstein 
21497c1f302STamir Duberstein 	simple_numbers_loop(unsigned long,	"%lu",	  "lu", check_ulong);
21597c1f302STamir Duberstein 	simple_numbers_loop(long,		"%ld",	  "ld", check_long);
21697c1f302STamir Duberstein 	simple_numbers_loop(long,		"%ld",	  "li", check_long);
21797c1f302STamir Duberstein 	simple_numbers_loop(unsigned long,	"%lx",	  "lx", check_ulong);
21897c1f302STamir Duberstein 	simple_numbers_loop(long,		"%lx",	  "lx", check_long);
21997c1f302STamir Duberstein 	simple_numbers_loop(long,		"0x%lx",  "li", check_long);
22097c1f302STamir Duberstein 	simple_numbers_loop(unsigned long,	"0x%lx",  "lx", check_ulong);
22197c1f302STamir Duberstein 	simple_numbers_loop(long,		"0x%lx",  "lx", check_long);
22297c1f302STamir Duberstein 
22397c1f302STamir Duberstein 	simple_numbers_loop(unsigned int,	"%u",	  "u", check_uint);
22497c1f302STamir Duberstein 	simple_numbers_loop(int,		"%d",	  "d", check_int);
22597c1f302STamir Duberstein 	simple_numbers_loop(int,		"%d",	  "i", check_int);
22697c1f302STamir Duberstein 	simple_numbers_loop(unsigned int,	"%x",	  "x", check_uint);
22797c1f302STamir Duberstein 	simple_numbers_loop(int,		"%x",	  "x", check_int);
22897c1f302STamir Duberstein 	simple_numbers_loop(int,		"0x%x",   "i", check_int);
22997c1f302STamir Duberstein 	simple_numbers_loop(unsigned int,	"0x%x",   "x", check_uint);
23097c1f302STamir Duberstein 	simple_numbers_loop(int,		"0x%x",   "x", check_int);
23197c1f302STamir Duberstein 
23297c1f302STamir Duberstein 	simple_numbers_loop(unsigned short,	"%hu",	  "hu", check_ushort);
23397c1f302STamir Duberstein 	simple_numbers_loop(short,		"%hd",	  "hd", check_short);
23497c1f302STamir Duberstein 	simple_numbers_loop(short,		"%hd",	  "hi", check_short);
23597c1f302STamir Duberstein 	simple_numbers_loop(unsigned short,	"%hx",	  "hx", check_ushort);
23697c1f302STamir Duberstein 	simple_numbers_loop(short,		"%hx",	  "hx", check_short);
23797c1f302STamir Duberstein 	simple_numbers_loop(short,		"0x%hx",  "hi", check_short);
23897c1f302STamir Duberstein 	simple_numbers_loop(unsigned short,	"0x%hx",  "hx", check_ushort);
23997c1f302STamir Duberstein 	simple_numbers_loop(short,		"0x%hx",  "hx", check_short);
24097c1f302STamir Duberstein 
24197c1f302STamir Duberstein 	simple_numbers_loop(unsigned char,	"%hhu",	  "hhu", check_uchar);
24297c1f302STamir Duberstein 	simple_numbers_loop(signed char,	"%hhd",	  "hhd", check_char);
24397c1f302STamir Duberstein 	simple_numbers_loop(signed char,	"%hhd",	  "hhi", check_char);
24497c1f302STamir Duberstein 	simple_numbers_loop(unsigned char,	"%hhx",	  "hhx", check_uchar);
24597c1f302STamir Duberstein 	simple_numbers_loop(signed char,	"%hhx",	  "hhx", check_char);
24697c1f302STamir Duberstein 	simple_numbers_loop(signed char,	"0x%hhx", "hhi", check_char);
24797c1f302STamir Duberstein 	simple_numbers_loop(unsigned char,	"0x%hhx", "hhx", check_uchar);
24897c1f302STamir Duberstein 	simple_numbers_loop(signed char,	"0x%hhx", "hhx", check_char);
24997c1f302STamir Duberstein }
25097c1f302STamir Duberstein 
25197c1f302STamir Duberstein /*
25297c1f302STamir Duberstein  * This gives a better variety of number "lengths" in a small sample than
25397c1f302STamir Duberstein  * the raw prandom*() functions (Not mathematically rigorous!!).
25497c1f302STamir Duberstein  * Variabilty of length and value is more important than perfect randomness.
25597c1f302STamir Duberstein  */
25697c1f302STamir Duberstein static u32 next_test_random(u32 max_bits)
25797c1f302STamir Duberstein {
25897c1f302STamir Duberstein 	u32 n_bits = hweight32(prandom_u32_state(&rnd_state)) % (max_bits + 1);
25997c1f302STamir Duberstein 
26097c1f302STamir Duberstein 	return prandom_u32_state(&rnd_state) & GENMASK(n_bits, 0);
26197c1f302STamir Duberstein }
26297c1f302STamir Duberstein 
26397c1f302STamir Duberstein static unsigned long long next_test_random_ull(void)
26497c1f302STamir Duberstein {
26597c1f302STamir Duberstein 	u32 rand1 = prandom_u32_state(&rnd_state);
26697c1f302STamir Duberstein 	u32 n_bits = (hweight32(rand1) * 3) % 64;
26797c1f302STamir Duberstein 	u64 val = (u64)prandom_u32_state(&rnd_state) * rand1;
26897c1f302STamir Duberstein 
26997c1f302STamir Duberstein 	return val & GENMASK_ULL(n_bits, 0);
27097c1f302STamir Duberstein }
27197c1f302STamir Duberstein 
27297c1f302STamir Duberstein #define random_for_type(T)				\
27397c1f302STamir Duberstein 	((T)(sizeof(T) <= sizeof(u32)			\
27497c1f302STamir Duberstein 		? next_test_random(BITS_PER_TYPE(T))	\
27597c1f302STamir Duberstein 		: next_test_random_ull()))
27697c1f302STamir Duberstein 
27797c1f302STamir Duberstein /*
27897c1f302STamir Duberstein  * Define a pattern of negative and positive numbers to ensure we get
27997c1f302STamir Duberstein  * some of both within the small number of samples in a test string.
28097c1f302STamir Duberstein  */
28197c1f302STamir Duberstein #define NEGATIVES_PATTERN 0x3246	/* 00110010 01000110 */
28297c1f302STamir Duberstein 
28397c1f302STamir Duberstein #define fill_random_array(arr)							\
28497c1f302STamir Duberstein do {										\
28597c1f302STamir Duberstein 	unsigned int neg_pattern = NEGATIVES_PATTERN;				\
28697c1f302STamir Duberstein 	int i;									\
28797c1f302STamir Duberstein 										\
28897c1f302STamir Duberstein 	for (i = 0; i < ARRAY_SIZE(arr); i++, neg_pattern >>= 1) {		\
28997c1f302STamir Duberstein 		(arr)[i] = random_for_type(typeof((arr)[0]));			\
29097c1f302STamir Duberstein 		if (is_signed_type(typeof((arr)[0])) && (neg_pattern & 1))	\
29197c1f302STamir Duberstein 			(arr)[i] = -(arr)[i];					\
29297c1f302STamir Duberstein 	}									\
29397c1f302STamir Duberstein } while (0)
29497c1f302STamir Duberstein 
29597c1f302STamir Duberstein /*
29697c1f302STamir Duberstein  * Convenience wrapper around snprintf() to append at buf_pos in buf,
29797c1f302STamir Duberstein  * updating buf_pos and returning the number of characters appended.
29897c1f302STamir Duberstein  * On error buf_pos is not changed and return value is 0.
29997c1f302STamir Duberstein  */
30097c1f302STamir Duberstein static int __printf(4, 5)
30197c1f302STamir Duberstein append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...)
30297c1f302STamir Duberstein {
30397c1f302STamir Duberstein 	va_list ap;
30497c1f302STamir Duberstein 	int field_len;
30597c1f302STamir Duberstein 
30697c1f302STamir Duberstein 	va_start(ap, val_fmt);
30797c1f302STamir Duberstein 	field_len = vsnprintf(buf + *buf_pos, buf_len - *buf_pos, val_fmt, ap);
30897c1f302STamir Duberstein 	va_end(ap);
30997c1f302STamir Duberstein 
31097c1f302STamir Duberstein 	if (field_len < 0)
31197c1f302STamir Duberstein 		field_len = 0;
31297c1f302STamir Duberstein 
31397c1f302STamir Duberstein 	*buf_pos += field_len;
31497c1f302STamir Duberstein 
31597c1f302STamir Duberstein 	return field_len;
31697c1f302STamir Duberstein }
31797c1f302STamir Duberstein 
31897c1f302STamir Duberstein /*
31997c1f302STamir Duberstein  * Convenience function to append the field delimiter string
32097c1f302STamir Duberstein  * to both the value string and format string buffers.
32197c1f302STamir Duberstein  */
32297c1f302STamir Duberstein static void append_delim(char *str_buf, int *str_buf_pos, int str_buf_len,
32397c1f302STamir Duberstein 				char *fmt_buf, int *fmt_buf_pos, int fmt_buf_len,
32497c1f302STamir Duberstein 				const char *delim_str)
32597c1f302STamir Duberstein {
32697c1f302STamir Duberstein 	append_fmt(str_buf, str_buf_pos, str_buf_len, delim_str);
32797c1f302STamir Duberstein 	append_fmt(fmt_buf, fmt_buf_pos, fmt_buf_len, delim_str);
32897c1f302STamir Duberstein }
32997c1f302STamir Duberstein 
33097c1f302STamir Duberstein #define test_array_8(fn, check_data, string, fmt, arr)				\
33197c1f302STamir Duberstein do {										\
33297c1f302STamir Duberstein 	BUILD_BUG_ON(ARRAY_SIZE(arr) != 8);					\
33397c1f302STamir Duberstein 	_test(test, __FILE__, __LINE__, fn, check_data, string, fmt, 8,		\
33497c1f302STamir Duberstein 		&(arr)[0], &(arr)[1], &(arr)[2], &(arr)[3],			\
33597c1f302STamir Duberstein 		&(arr)[4], &(arr)[5], &(arr)[6], &(arr)[7]);			\
33697c1f302STamir Duberstein } while (0)
33797c1f302STamir Duberstein 
33897c1f302STamir Duberstein #define numbers_list_8(T, gen_fmt, field_sep, scan_fmt, fn)			\
33997c1f302STamir Duberstein do {										\
34097c1f302STamir Duberstein 	int i, pos = 0, fmt_pos = 0;						\
34197c1f302STamir Duberstein 	T expect[8], result[8];							\
34297c1f302STamir Duberstein 										\
34397c1f302STamir Duberstein 	fill_random_array(expect);						\
34497c1f302STamir Duberstein 										\
34597c1f302STamir Duberstein 	for (i = 0; i < ARRAY_SIZE(expect); i++) {				\
34697c1f302STamir Duberstein 		if (i != 0)							\
34797c1f302STamir Duberstein 			append_delim(test_buffer, &pos, BUF_SIZE,		\
34897c1f302STamir Duberstein 				     fmt_buffer, &fmt_pos, BUF_SIZE,		\
34997c1f302STamir Duberstein 				     field_sep);				\
35097c1f302STamir Duberstein 										\
35197c1f302STamir Duberstein 		append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt, expect[i]);	\
35297c1f302STamir Duberstein 		append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE, "%%%s", scan_fmt);	\
35397c1f302STamir Duberstein 	}									\
35497c1f302STamir Duberstein 										\
35597c1f302STamir Duberstein 	test_array_8(fn, expect, test_buffer, fmt_buffer, result);		\
35697c1f302STamir Duberstein } while (0)
35797c1f302STamir Duberstein 
35897c1f302STamir Duberstein #define numbers_list_fix_width(T, gen_fmt, field_sep, width, scan_fmt, fn)	\
35997c1f302STamir Duberstein do {										\
36097c1f302STamir Duberstein 	char full_fmt[16];							\
36197c1f302STamir Duberstein 										\
36297c1f302STamir Duberstein 	snprintf(full_fmt, sizeof(full_fmt), "%u%s", width, scan_fmt);		\
36397c1f302STamir Duberstein 	numbers_list_8(T, gen_fmt, field_sep, full_fmt, fn);			\
36497c1f302STamir Duberstein } while (0)
36597c1f302STamir Duberstein 
36697c1f302STamir Duberstein #define numbers_list_val_width(T, gen_fmt, field_sep, scan_fmt, fn)		\
36797c1f302STamir Duberstein do {										\
36897c1f302STamir Duberstein 	int i, val_len, pos = 0, fmt_pos = 0;					\
36997c1f302STamir Duberstein 	T expect[8], result[8];							\
37097c1f302STamir Duberstein 										\
37197c1f302STamir Duberstein 	fill_random_array(expect);						\
37297c1f302STamir Duberstein 										\
37397c1f302STamir Duberstein 	for (i = 0; i < ARRAY_SIZE(expect); i++) {				\
37497c1f302STamir Duberstein 		if (i != 0)							\
37597c1f302STamir Duberstein 			append_delim(test_buffer, &pos, BUF_SIZE,		\
37697c1f302STamir Duberstein 				     fmt_buffer, &fmt_pos, BUF_SIZE, field_sep);\
37797c1f302STamir Duberstein 										\
37897c1f302STamir Duberstein 		val_len = append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt,	\
37997c1f302STamir Duberstein 				     expect[i]);				\
38097c1f302STamir Duberstein 		append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE,			\
38197c1f302STamir Duberstein 			   "%%%u%s", val_len, scan_fmt);			\
38297c1f302STamir Duberstein 	}									\
38397c1f302STamir Duberstein 										\
38497c1f302STamir Duberstein 	test_array_8(fn, expect, test_buffer, fmt_buffer, result);		\
38597c1f302STamir Duberstein } while (0)
38697c1f302STamir Duberstein 
38797c1f302STamir Duberstein static void numbers_list_ll(struct kunit *test, const char *delim)
38897c1f302STamir Duberstein {
38997c1f302STamir Duberstein 	numbers_list_8(unsigned long long, "%llu",   delim, "llu", check_ull);
39097c1f302STamir Duberstein 	numbers_list_8(long long,	   "%lld",   delim, "lld", check_ll);
39197c1f302STamir Duberstein 	numbers_list_8(long long,	   "%lld",   delim, "lli", check_ll);
39297c1f302STamir Duberstein 	numbers_list_8(unsigned long long, "%llx",   delim, "llx", check_ull);
39397c1f302STamir Duberstein 	numbers_list_8(unsigned long long, "0x%llx", delim, "llx", check_ull);
39497c1f302STamir Duberstein 	numbers_list_8(long long,	   "0x%llx", delim, "lli", check_ll);
39597c1f302STamir Duberstein }
39697c1f302STamir Duberstein 
39797c1f302STamir Duberstein static void numbers_list_l(struct kunit *test, const char *delim)
39897c1f302STamir Duberstein {
39997c1f302STamir Duberstein 	numbers_list_8(unsigned long,	   "%lu",    delim, "lu", check_ulong);
40097c1f302STamir Duberstein 	numbers_list_8(long,		   "%ld",    delim, "ld", check_long);
40197c1f302STamir Duberstein 	numbers_list_8(long,		   "%ld",    delim, "li", check_long);
40297c1f302STamir Duberstein 	numbers_list_8(unsigned long,	   "%lx",    delim, "lx", check_ulong);
40397c1f302STamir Duberstein 	numbers_list_8(unsigned long,	   "0x%lx",  delim, "lx", check_ulong);
40497c1f302STamir Duberstein 	numbers_list_8(long,		   "0x%lx",  delim, "li", check_long);
40597c1f302STamir Duberstein }
40697c1f302STamir Duberstein 
40797c1f302STamir Duberstein static void numbers_list_d(struct kunit *test, const char *delim)
40897c1f302STamir Duberstein {
40997c1f302STamir Duberstein 	numbers_list_8(unsigned int,	   "%u",     delim, "u", check_uint);
41097c1f302STamir Duberstein 	numbers_list_8(int,		   "%d",     delim, "d", check_int);
41197c1f302STamir Duberstein 	numbers_list_8(int,		   "%d",     delim, "i", check_int);
41297c1f302STamir Duberstein 	numbers_list_8(unsigned int,	   "%x",     delim, "x", check_uint);
41397c1f302STamir Duberstein 	numbers_list_8(unsigned int,	   "0x%x",   delim, "x", check_uint);
41497c1f302STamir Duberstein 	numbers_list_8(int,		   "0x%x",   delim, "i", check_int);
41597c1f302STamir Duberstein }
41697c1f302STamir Duberstein 
41797c1f302STamir Duberstein static void numbers_list_h(struct kunit *test, const char *delim)
41897c1f302STamir Duberstein {
41997c1f302STamir Duberstein 	numbers_list_8(unsigned short,	   "%hu",    delim, "hu", check_ushort);
42097c1f302STamir Duberstein 	numbers_list_8(short,		   "%hd",    delim, "hd", check_short);
42197c1f302STamir Duberstein 	numbers_list_8(short,		   "%hd",    delim, "hi", check_short);
42297c1f302STamir Duberstein 	numbers_list_8(unsigned short,	   "%hx",    delim, "hx", check_ushort);
42397c1f302STamir Duberstein 	numbers_list_8(unsigned short,	   "0x%hx",  delim, "hx", check_ushort);
42497c1f302STamir Duberstein 	numbers_list_8(short,		   "0x%hx",  delim, "hi", check_short);
42597c1f302STamir Duberstein }
42697c1f302STamir Duberstein 
42797c1f302STamir Duberstein static void numbers_list_hh(struct kunit *test, const char *delim)
42897c1f302STamir Duberstein {
42997c1f302STamir Duberstein 	numbers_list_8(unsigned char,	   "%hhu",   delim, "hhu", check_uchar);
43097c1f302STamir Duberstein 	numbers_list_8(signed char,	   "%hhd",   delim, "hhd", check_char);
43197c1f302STamir Duberstein 	numbers_list_8(signed char,	   "%hhd",   delim, "hhi", check_char);
43297c1f302STamir Duberstein 	numbers_list_8(unsigned char,	   "%hhx",   delim, "hhx", check_uchar);
43397c1f302STamir Duberstein 	numbers_list_8(unsigned char,	   "0x%hhx", delim, "hhx", check_uchar);
43497c1f302STamir Duberstein 	numbers_list_8(signed char,	   "0x%hhx", delim, "hhi", check_char);
43597c1f302STamir Duberstein }
43697c1f302STamir Duberstein 
437*d62f8c95STamir Duberstein static void numbers_list(struct kunit *test)
43897c1f302STamir Duberstein {
439*d62f8c95STamir Duberstein 	const char * const *param = test->param_value;
440*d62f8c95STamir Duberstein 	const char *delim = *param;
441*d62f8c95STamir Duberstein 
44297c1f302STamir Duberstein 	numbers_list_ll(test, delim);
44397c1f302STamir Duberstein 	numbers_list_l(test, delim);
44497c1f302STamir Duberstein 	numbers_list_d(test, delim);
44597c1f302STamir Duberstein 	numbers_list_h(test, delim);
44697c1f302STamir Duberstein 	numbers_list_hh(test, delim);
44797c1f302STamir Duberstein }
44897c1f302STamir Duberstein 
44997c1f302STamir Duberstein static void numbers_list_field_width_ll(struct kunit *test, const char *delim)
45097c1f302STamir Duberstein {
45197c1f302STamir Duberstein 	numbers_list_fix_width(unsigned long long, "%llu",   delim, 20, "llu", check_ull);
45297c1f302STamir Duberstein 	numbers_list_fix_width(long long,	   "%lld",   delim, 20, "lld", check_ll);
45397c1f302STamir Duberstein 	numbers_list_fix_width(long long,	   "%lld",   delim, 20, "lli", check_ll);
45497c1f302STamir Duberstein 	numbers_list_fix_width(unsigned long long, "%llx",   delim, 16, "llx", check_ull);
45597c1f302STamir Duberstein 	numbers_list_fix_width(unsigned long long, "0x%llx", delim, 18, "llx", check_ull);
45697c1f302STamir Duberstein 	numbers_list_fix_width(long long,	   "0x%llx", delim, 18, "lli", check_ll);
45797c1f302STamir Duberstein }
45897c1f302STamir Duberstein 
45997c1f302STamir Duberstein static void numbers_list_field_width_l(struct kunit *test, const char *delim)
46097c1f302STamir Duberstein {
46197c1f302STamir Duberstein #if BITS_PER_LONG == 64
46297c1f302STamir Duberstein 	numbers_list_fix_width(unsigned long,	"%lu",	     delim, 20, "lu", check_ulong);
46397c1f302STamir Duberstein 	numbers_list_fix_width(long,		"%ld",	     delim, 20, "ld", check_long);
46497c1f302STamir Duberstein 	numbers_list_fix_width(long,		"%ld",	     delim, 20, "li", check_long);
46597c1f302STamir Duberstein 	numbers_list_fix_width(unsigned long,	"%lx",	     delim, 16, "lx", check_ulong);
46697c1f302STamir Duberstein 	numbers_list_fix_width(unsigned long,	"0x%lx",     delim, 18, "lx", check_ulong);
46797c1f302STamir Duberstein 	numbers_list_fix_width(long,		"0x%lx",     delim, 18, "li", check_long);
46897c1f302STamir Duberstein #else
46997c1f302STamir Duberstein 	numbers_list_fix_width(unsigned long,	"%lu",	     delim, 10, "lu", check_ulong);
47097c1f302STamir Duberstein 	numbers_list_fix_width(long,		"%ld",	     delim, 11, "ld", check_long);
47197c1f302STamir Duberstein 	numbers_list_fix_width(long,		"%ld",	     delim, 11, "li", check_long);
47297c1f302STamir Duberstein 	numbers_list_fix_width(unsigned long,	"%lx",	     delim, 8,  "lx", check_ulong);
47397c1f302STamir Duberstein 	numbers_list_fix_width(unsigned long,	"0x%lx",     delim, 10, "lx", check_ulong);
47497c1f302STamir Duberstein 	numbers_list_fix_width(long,		"0x%lx",     delim, 10, "li", check_long);
47597c1f302STamir Duberstein #endif
47697c1f302STamir Duberstein }
47797c1f302STamir Duberstein 
47897c1f302STamir Duberstein static void numbers_list_field_width_d(struct kunit *test, const char *delim)
47997c1f302STamir Duberstein {
48097c1f302STamir Duberstein 	numbers_list_fix_width(unsigned int,	"%u",	     delim, 10, "u", check_uint);
48197c1f302STamir Duberstein 	numbers_list_fix_width(int,		"%d",	     delim, 11, "d", check_int);
48297c1f302STamir Duberstein 	numbers_list_fix_width(int,		"%d",	     delim, 11, "i", check_int);
48397c1f302STamir Duberstein 	numbers_list_fix_width(unsigned int,	"%x",	     delim, 8,  "x", check_uint);
48497c1f302STamir Duberstein 	numbers_list_fix_width(unsigned int,	"0x%x",	     delim, 10, "x", check_uint);
48597c1f302STamir Duberstein 	numbers_list_fix_width(int,		"0x%x",	     delim, 10, "i", check_int);
48697c1f302STamir Duberstein }
48797c1f302STamir Duberstein 
48897c1f302STamir Duberstein static void numbers_list_field_width_h(struct kunit *test, const char *delim)
48997c1f302STamir Duberstein {
49097c1f302STamir Duberstein 	numbers_list_fix_width(unsigned short,	"%hu",	     delim, 5, "hu", check_ushort);
49197c1f302STamir Duberstein 	numbers_list_fix_width(short,		"%hd",	     delim, 6, "hd", check_short);
49297c1f302STamir Duberstein 	numbers_list_fix_width(short,		"%hd",	     delim, 6, "hi", check_short);
49397c1f302STamir Duberstein 	numbers_list_fix_width(unsigned short,	"%hx",	     delim, 4, "hx", check_ushort);
49497c1f302STamir Duberstein 	numbers_list_fix_width(unsigned short,	"0x%hx",     delim, 6, "hx", check_ushort);
49597c1f302STamir Duberstein 	numbers_list_fix_width(short,		"0x%hx",     delim, 6, "hi", check_short);
49697c1f302STamir Duberstein }
49797c1f302STamir Duberstein 
49897c1f302STamir Duberstein static void numbers_list_field_width_hh(struct kunit *test, const char *delim)
49997c1f302STamir Duberstein {
50097c1f302STamir Duberstein 	numbers_list_fix_width(unsigned char,	"%hhu",	     delim, 3, "hhu", check_uchar);
50197c1f302STamir Duberstein 	numbers_list_fix_width(signed char,	"%hhd",	     delim, 4, "hhd", check_char);
50297c1f302STamir Duberstein 	numbers_list_fix_width(signed char,	"%hhd",	     delim, 4, "hhi", check_char);
50397c1f302STamir Duberstein 	numbers_list_fix_width(unsigned char,	"%hhx",	     delim, 2, "hhx", check_uchar);
50497c1f302STamir Duberstein 	numbers_list_fix_width(unsigned char,	"0x%hhx",    delim, 4, "hhx", check_uchar);
50597c1f302STamir Duberstein 	numbers_list_fix_width(signed char,	"0x%hhx",    delim, 4, "hhi", check_char);
50697c1f302STamir Duberstein }
50797c1f302STamir Duberstein 
50897c1f302STamir Duberstein /*
50997c1f302STamir Duberstein  * List of numbers separated by delim. Each field width specifier is the
51097c1f302STamir Duberstein  * maximum possible digits for the given type and base.
51197c1f302STamir Duberstein  */
512*d62f8c95STamir Duberstein static void numbers_list_field_width_typemax(struct kunit *test)
51397c1f302STamir Duberstein {
514*d62f8c95STamir Duberstein 	const char * const *param = test->param_value;
515*d62f8c95STamir Duberstein 	const char *delim = *param;
516*d62f8c95STamir Duberstein 
51797c1f302STamir Duberstein 	numbers_list_field_width_ll(test, delim);
51897c1f302STamir Duberstein 	numbers_list_field_width_l(test, delim);
51997c1f302STamir Duberstein 	numbers_list_field_width_d(test, delim);
52097c1f302STamir Duberstein 	numbers_list_field_width_h(test, delim);
52197c1f302STamir Duberstein 	numbers_list_field_width_hh(test, delim);
52297c1f302STamir Duberstein }
52397c1f302STamir Duberstein 
52497c1f302STamir Duberstein static void numbers_list_field_width_val_ll(struct kunit *test, const char *delim)
52597c1f302STamir Duberstein {
52697c1f302STamir Duberstein 	numbers_list_val_width(unsigned long long, "%llu",   delim, "llu", check_ull);
52797c1f302STamir Duberstein 	numbers_list_val_width(long long,	   "%lld",   delim, "lld", check_ll);
52897c1f302STamir Duberstein 	numbers_list_val_width(long long,	   "%lld",   delim, "lli", check_ll);
52997c1f302STamir Duberstein 	numbers_list_val_width(unsigned long long, "%llx",   delim, "llx", check_ull);
53097c1f302STamir Duberstein 	numbers_list_val_width(unsigned long long, "0x%llx", delim, "llx", check_ull);
53197c1f302STamir Duberstein 	numbers_list_val_width(long long,	   "0x%llx", delim, "lli", check_ll);
53297c1f302STamir Duberstein }
53397c1f302STamir Duberstein 
53497c1f302STamir Duberstein static void numbers_list_field_width_val_l(struct kunit *test, const char *delim)
53597c1f302STamir Duberstein {
53697c1f302STamir Duberstein 	numbers_list_val_width(unsigned long,	"%lu",	     delim, "lu", check_ulong);
53797c1f302STamir Duberstein 	numbers_list_val_width(long,		"%ld",	     delim, "ld", check_long);
53897c1f302STamir Duberstein 	numbers_list_val_width(long,		"%ld",	     delim, "li", check_long);
53997c1f302STamir Duberstein 	numbers_list_val_width(unsigned long,	"%lx",	     delim, "lx", check_ulong);
54097c1f302STamir Duberstein 	numbers_list_val_width(unsigned long,	"0x%lx",     delim, "lx", check_ulong);
54197c1f302STamir Duberstein 	numbers_list_val_width(long,		"0x%lx",     delim, "li", check_long);
54297c1f302STamir Duberstein }
54397c1f302STamir Duberstein 
54497c1f302STamir Duberstein static void numbers_list_field_width_val_d(struct kunit *test, const char *delim)
54597c1f302STamir Duberstein {
54697c1f302STamir Duberstein 	numbers_list_val_width(unsigned int,	"%u",	     delim, "u", check_uint);
54797c1f302STamir Duberstein 	numbers_list_val_width(int,		"%d",	     delim, "d", check_int);
54897c1f302STamir Duberstein 	numbers_list_val_width(int,		"%d",	     delim, "i", check_int);
54997c1f302STamir Duberstein 	numbers_list_val_width(unsigned int,	"%x",	     delim, "x", check_uint);
55097c1f302STamir Duberstein 	numbers_list_val_width(unsigned int,	"0x%x",	     delim, "x", check_uint);
55197c1f302STamir Duberstein 	numbers_list_val_width(int,		"0x%x",	     delim, "i", check_int);
55297c1f302STamir Duberstein }
55397c1f302STamir Duberstein 
55497c1f302STamir Duberstein static void numbers_list_field_width_val_h(struct kunit *test, const char *delim)
55597c1f302STamir Duberstein {
55697c1f302STamir Duberstein 	numbers_list_val_width(unsigned short,	"%hu",	     delim, "hu", check_ushort);
55797c1f302STamir Duberstein 	numbers_list_val_width(short,		"%hd",	     delim, "hd", check_short);
55897c1f302STamir Duberstein 	numbers_list_val_width(short,		"%hd",	     delim, "hi", check_short);
55997c1f302STamir Duberstein 	numbers_list_val_width(unsigned short,	"%hx",	     delim, "hx", check_ushort);
56097c1f302STamir Duberstein 	numbers_list_val_width(unsigned short,	"0x%hx",     delim, "hx", check_ushort);
56197c1f302STamir Duberstein 	numbers_list_val_width(short,		"0x%hx",     delim, "hi", check_short);
56297c1f302STamir Duberstein }
56397c1f302STamir Duberstein 
56497c1f302STamir Duberstein static void numbers_list_field_width_val_hh(struct kunit *test, const char *delim)
56597c1f302STamir Duberstein {
56697c1f302STamir Duberstein 	numbers_list_val_width(unsigned char,	"%hhu",	     delim, "hhu", check_uchar);
56797c1f302STamir Duberstein 	numbers_list_val_width(signed char,	"%hhd",	     delim, "hhd", check_char);
56897c1f302STamir Duberstein 	numbers_list_val_width(signed char,	"%hhd",	     delim, "hhi", check_char);
56997c1f302STamir Duberstein 	numbers_list_val_width(unsigned char,	"%hhx",	     delim, "hhx", check_uchar);
57097c1f302STamir Duberstein 	numbers_list_val_width(unsigned char,	"0x%hhx",    delim, "hhx", check_uchar);
57197c1f302STamir Duberstein 	numbers_list_val_width(signed char,	"0x%hhx",    delim, "hhi", check_char);
57297c1f302STamir Duberstein }
57397c1f302STamir Duberstein 
57497c1f302STamir Duberstein /*
57597c1f302STamir Duberstein  * List of numbers separated by delim. Each field width specifier is the
57697c1f302STamir Duberstein  * exact length of the corresponding value digits in the string being scanned.
57797c1f302STamir Duberstein  */
578*d62f8c95STamir Duberstein static void numbers_list_field_width_val_width(struct kunit *test)
57997c1f302STamir Duberstein {
580*d62f8c95STamir Duberstein 	const char * const *param = test->param_value;
581*d62f8c95STamir Duberstein 	const char *delim = *param;
582*d62f8c95STamir Duberstein 
58397c1f302STamir Duberstein 	numbers_list_field_width_val_ll(test, delim);
58497c1f302STamir Duberstein 	numbers_list_field_width_val_l(test, delim);
58597c1f302STamir Duberstein 	numbers_list_field_width_val_d(test, delim);
58697c1f302STamir Duberstein 	numbers_list_field_width_val_h(test, delim);
58797c1f302STamir Duberstein 	numbers_list_field_width_val_hh(test, delim);
58897c1f302STamir Duberstein }
58997c1f302STamir Duberstein 
59097c1f302STamir Duberstein /*
59197c1f302STamir Duberstein  * Slice a continuous string of digits without field delimiters, containing
59297c1f302STamir Duberstein  * numbers of varying length, using the field width to extract each group
59397c1f302STamir Duberstein  * of digits. For example the hex values c0,3,bf01,303 would have a
59497c1f302STamir Duberstein  * string representation of "c03bf01303" and extracted with "%2x%1x%4x%3x".
59597c1f302STamir Duberstein  */
59697c1f302STamir Duberstein static void numbers_slice(struct kunit *test)
59797c1f302STamir Duberstein {
598*d62f8c95STamir Duberstein 	const char *delim = "";
599*d62f8c95STamir Duberstein 
600*d62f8c95STamir Duberstein 	KUNIT_ASSERT_PTR_EQ(test, test->param_value, NULL);
601*d62f8c95STamir Duberstein 	test->param_value = &delim;
602*d62f8c95STamir Duberstein 
603*d62f8c95STamir Duberstein 	numbers_list_field_width_val_width(test);
60497c1f302STamir Duberstein }
60597c1f302STamir Duberstein 
60697c1f302STamir Duberstein #define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn)	\
60797c1f302STamir Duberstein do {										\
60897c1f302STamir Duberstein 	const T expect[2] = { expect0, expect1 };				\
60997c1f302STamir Duberstein 	T result[2] = { (T)~expect[0], (T)~expect[1] };				\
61097c1f302STamir Duberstein 										\
61197c1f302STamir Duberstein 	_test(test, __FILE__, __LINE__, fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]);\
61297c1f302STamir Duberstein } while (0)
61397c1f302STamir Duberstein 
61497c1f302STamir Duberstein /*
61597c1f302STamir Duberstein  * Number prefix is >= field width.
61697c1f302STamir Duberstein  * Expected behaviour is derived from testing userland sscanf.
61797c1f302STamir Duberstein  */
61897c1f302STamir Duberstein static void numbers_prefix_overflow(struct kunit *test)
61997c1f302STamir Duberstein {
62097c1f302STamir Duberstein 	/*
62197c1f302STamir Duberstein 	 * Negative decimal with a field of width 1, should quit scanning
62297c1f302STamir Duberstein 	 * and return 0.
62397c1f302STamir Duberstein 	 */
62497c1f302STamir Duberstein 	test_number_prefix(long long,	"-1 1", "%1lld %lld",	0, 0, 0, check_ll);
62597c1f302STamir Duberstein 	test_number_prefix(long,	"-1 1", "%1ld %ld",	0, 0, 0, check_long);
62697c1f302STamir Duberstein 	test_number_prefix(int,		"-1 1", "%1d %d",	0, 0, 0, check_int);
62797c1f302STamir Duberstein 	test_number_prefix(short,	"-1 1", "%1hd %hd",	0, 0, 0, check_short);
62897c1f302STamir Duberstein 	test_number_prefix(signed char,	"-1 1", "%1hhd %hhd",	0, 0, 0, check_char);
62997c1f302STamir Duberstein 
63097c1f302STamir Duberstein 	test_number_prefix(long long,	"-1 1", "%1lli %lli",	0, 0, 0, check_ll);
63197c1f302STamir Duberstein 	test_number_prefix(long,	"-1 1", "%1li %li",	0, 0, 0, check_long);
63297c1f302STamir Duberstein 	test_number_prefix(int,		"-1 1", "%1i %i",	0, 0, 0, check_int);
63397c1f302STamir Duberstein 	test_number_prefix(short,	"-1 1", "%1hi %hi",	0, 0, 0, check_short);
63497c1f302STamir Duberstein 	test_number_prefix(signed char,	"-1 1", "%1hhi %hhi",	0, 0, 0, check_char);
63597c1f302STamir Duberstein 
63697c1f302STamir Duberstein 	/*
63797c1f302STamir Duberstein 	 * 0x prefix in a field of width 1: 0 is a valid digit so should
63897c1f302STamir Duberstein 	 * convert. Next field scan starts at the 'x' which isn't a digit so
63997c1f302STamir Duberstein 	 * scan quits with one field converted.
64097c1f302STamir Duberstein 	 */
64197c1f302STamir Duberstein 	test_number_prefix(unsigned long long,	"0xA7", "%1llx%llx", 0, 0, 1, check_ull);
64297c1f302STamir Duberstein 	test_number_prefix(unsigned long,	"0xA7", "%1lx%lx",   0, 0, 1, check_ulong);
64397c1f302STamir Duberstein 	test_number_prefix(unsigned int,	"0xA7", "%1x%x",     0, 0, 1, check_uint);
64497c1f302STamir Duberstein 	test_number_prefix(unsigned short,	"0xA7", "%1hx%hx",   0, 0, 1, check_ushort);
64597c1f302STamir Duberstein 	test_number_prefix(unsigned char,	"0xA7", "%1hhx%hhx", 0, 0, 1, check_uchar);
64697c1f302STamir Duberstein 	test_number_prefix(long long,		"0xA7", "%1lli%llx", 0, 0, 1, check_ll);
64797c1f302STamir Duberstein 	test_number_prefix(long,		"0xA7", "%1li%lx",   0, 0, 1, check_long);
64897c1f302STamir Duberstein 	test_number_prefix(int,			"0xA7", "%1i%x",     0, 0, 1, check_int);
64997c1f302STamir Duberstein 	test_number_prefix(short,		"0xA7", "%1hi%hx",   0, 0, 1, check_short);
65097c1f302STamir Duberstein 	test_number_prefix(char,		"0xA7", "%1hhi%hhx", 0, 0, 1, check_char);
65197c1f302STamir Duberstein 
65297c1f302STamir Duberstein 	/*
65397c1f302STamir Duberstein 	 * 0x prefix in a field of width 2 using %x conversion: first field
65497c1f302STamir Duberstein 	 * converts to 0. Next field scan starts at the character after "0x".
65597c1f302STamir Duberstein 	 * Both fields will convert.
65697c1f302STamir Duberstein 	 */
65797c1f302STamir Duberstein 	test_number_prefix(unsigned long long,	"0xA7", "%2llx%llx", 0, 0xa7, 2, check_ull);
65897c1f302STamir Duberstein 	test_number_prefix(unsigned long,	"0xA7", "%2lx%lx",   0, 0xa7, 2, check_ulong);
65997c1f302STamir Duberstein 	test_number_prefix(unsigned int,	"0xA7", "%2x%x",     0, 0xa7, 2, check_uint);
66097c1f302STamir Duberstein 	test_number_prefix(unsigned short,	"0xA7", "%2hx%hx",   0, 0xa7, 2, check_ushort);
66197c1f302STamir Duberstein 	test_number_prefix(unsigned char,	"0xA7", "%2hhx%hhx", 0, 0xa7, 2, check_uchar);
66297c1f302STamir Duberstein 
66397c1f302STamir Duberstein 	/*
66497c1f302STamir Duberstein 	 * 0x prefix in a field of width 2 using %i conversion: first field
66597c1f302STamir Duberstein 	 * converts to 0. Next field scan starts at the character after "0x",
66697c1f302STamir Duberstein 	 * which will convert if can be interpreted as decimal but will fail
66797c1f302STamir Duberstein 	 * if it contains any hex digits (since no 0x prefix).
66897c1f302STamir Duberstein 	 */
66997c1f302STamir Duberstein 	test_number_prefix(long long,	"0x67", "%2lli%lli", 0, 67, 2, check_ll);
67097c1f302STamir Duberstein 	test_number_prefix(long,	"0x67", "%2li%li",   0, 67, 2, check_long);
67197c1f302STamir Duberstein 	test_number_prefix(int,		"0x67", "%2i%i",     0, 67, 2, check_int);
67297c1f302STamir Duberstein 	test_number_prefix(short,	"0x67", "%2hi%hi",   0, 67, 2, check_short);
67397c1f302STamir Duberstein 	test_number_prefix(char,	"0x67", "%2hhi%hhi", 0, 67, 2, check_char);
67497c1f302STamir Duberstein 
67597c1f302STamir Duberstein 	test_number_prefix(long long,	"0xA7", "%2lli%lli", 0, 0,  1, check_ll);
67697c1f302STamir Duberstein 	test_number_prefix(long,	"0xA7", "%2li%li",   0, 0,  1, check_long);
67797c1f302STamir Duberstein 	test_number_prefix(int,		"0xA7", "%2i%i",     0, 0,  1, check_int);
67897c1f302STamir Duberstein 	test_number_prefix(short,	"0xA7", "%2hi%hi",   0, 0,  1, check_short);
67997c1f302STamir Duberstein 	test_number_prefix(char,	"0xA7", "%2hhi%hhi", 0, 0,  1, check_char);
68097c1f302STamir Duberstein }
68197c1f302STamir Duberstein 
68297c1f302STamir Duberstein #define _test_simple_strtoxx(T, fn, gen_fmt, expect, base)			\
68397c1f302STamir Duberstein do {										\
68497c1f302STamir Duberstein 	T got;									\
68597c1f302STamir Duberstein 	char *endp;								\
68697c1f302STamir Duberstein 	int len;								\
68797c1f302STamir Duberstein 										\
68897c1f302STamir Duberstein 	len = snprintf(test_buffer, BUF_SIZE, gen_fmt, expect);			\
68997c1f302STamir Duberstein 	got = (fn)(test_buffer, &endp, base);					\
69097c1f302STamir Duberstein 	if (got != (expect)) {							\
69197c1f302STamir Duberstein 		KUNIT_FAIL(test, #fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt, \
69297c1f302STamir Duberstein 			   test_buffer, base, got, expect);			\
69397c1f302STamir Duberstein 	} else if (endp != test_buffer + len) {					\
69497c1f302STamir Duberstein 		KUNIT_FAIL(test, #fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px", \
69597c1f302STamir Duberstein 			   test_buffer, base, test_buffer,			\
69697c1f302STamir Duberstein 			   test_buffer + len, endp);				\
69797c1f302STamir Duberstein 	}									\
69897c1f302STamir Duberstein } while (0)
69997c1f302STamir Duberstein 
70097c1f302STamir Duberstein #define test_simple_strtoxx(T, fn, gen_fmt, base)				\
70197c1f302STamir Duberstein do {										\
70297c1f302STamir Duberstein 	int i;									\
70397c1f302STamir Duberstein 										\
70497c1f302STamir Duberstein 	for (i = 0; i < ARRAY_SIZE(numbers); i++) {				\
70597c1f302STamir Duberstein 		_test_simple_strtoxx(T, fn, gen_fmt, (T)numbers[i], base);	\
70697c1f302STamir Duberstein 										\
70797c1f302STamir Duberstein 		if (is_signed_type(T))						\
70897c1f302STamir Duberstein 			_test_simple_strtoxx(T, fn, gen_fmt,			\
70997c1f302STamir Duberstein 					      -(T)numbers[i], base);		\
71097c1f302STamir Duberstein 	}									\
71197c1f302STamir Duberstein } while (0)
71297c1f302STamir Duberstein 
71397c1f302STamir Duberstein static void test_simple_strtoull(struct kunit *test)
71497c1f302STamir Duberstein {
71597c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu",   10);
71697c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu",   0);
71797c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long long, simple_strtoull, "%llx",   16);
71897c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 16);
71997c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 0);
72097c1f302STamir Duberstein }
72197c1f302STamir Duberstein 
72297c1f302STamir Duberstein static void test_simple_strtoll(struct kunit *test)
72397c1f302STamir Duberstein {
72497c1f302STamir Duberstein 	test_simple_strtoxx(long long, simple_strtoll, "%lld",	 10);
72597c1f302STamir Duberstein 	test_simple_strtoxx(long long, simple_strtoll, "%lld",	 0);
72697c1f302STamir Duberstein 	test_simple_strtoxx(long long, simple_strtoll, "%llx",	 16);
72797c1f302STamir Duberstein 	test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 16);
72897c1f302STamir Duberstein 	test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 0);
72997c1f302STamir Duberstein }
73097c1f302STamir Duberstein 
73197c1f302STamir Duberstein static void test_simple_strtoul(struct kunit *test)
73297c1f302STamir Duberstein {
73397c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long, simple_strtoul, "%lu",   10);
73497c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long, simple_strtoul, "%lu",   0);
73597c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long, simple_strtoul, "%lx",   16);
73697c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 16);
73797c1f302STamir Duberstein 	test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 0);
73897c1f302STamir Duberstein }
73997c1f302STamir Duberstein 
74097c1f302STamir Duberstein static void test_simple_strtol(struct kunit *test)
74197c1f302STamir Duberstein {
74297c1f302STamir Duberstein 	test_simple_strtoxx(long, simple_strtol, "%ld",   10);
74397c1f302STamir Duberstein 	test_simple_strtoxx(long, simple_strtol, "%ld",   0);
74497c1f302STamir Duberstein 	test_simple_strtoxx(long, simple_strtol, "%lx",   16);
74597c1f302STamir Duberstein 	test_simple_strtoxx(long, simple_strtol, "0x%lx", 16);
74697c1f302STamir Duberstein 	test_simple_strtoxx(long, simple_strtol, "0x%lx", 0);
74797c1f302STamir Duberstein }
74897c1f302STamir Duberstein 
74997c1f302STamir Duberstein /* Selection of common delimiters/separators between numbers in a string. */
75097c1f302STamir Duberstein static const char * const number_delimiters[] = {
75197c1f302STamir Duberstein 	" ", ":", ",", "-", "/",
75297c1f302STamir Duberstein };
75397c1f302STamir Duberstein 
754*d62f8c95STamir Duberstein static void number_delimiter_param_desc(const char * const *param,
755*d62f8c95STamir Duberstein 					   char *desc)
75697c1f302STamir Duberstein {
757*d62f8c95STamir Duberstein 	snprintf(desc, KUNIT_PARAM_DESC_SIZE, "\"%s\"", *param);
758*d62f8c95STamir Duberstein }
75997c1f302STamir Duberstein 
760*d62f8c95STamir Duberstein KUNIT_ARRAY_PARAM(number_delimiters, number_delimiters, number_delimiter_param_desc);
76197c1f302STamir Duberstein 
762*d62f8c95STamir Duberstein static struct kunit_case scanf_test_cases[] = {
763*d62f8c95STamir Duberstein 	KUNIT_CASE(numbers_simple),
76497c1f302STamir Duberstein 	/* String with multiple numbers separated by delimiter. */
765*d62f8c95STamir Duberstein 	KUNIT_CASE_PARAM(numbers_list, number_delimiters_gen_params),
76697c1f302STamir Duberstein 	/* Field width may be longer than actual field digits. */
767*d62f8c95STamir Duberstein 	KUNIT_CASE_PARAM(numbers_list_field_width_typemax, number_delimiters_gen_params),
76897c1f302STamir Duberstein 	/* Each field width exactly length of actual field digits. */
769*d62f8c95STamir Duberstein 	KUNIT_CASE_PARAM(numbers_list_field_width_val_width, number_delimiters_gen_params),
77097c1f302STamir Duberstein 	/* Slice continuous sequence of digits using field widths. */
771*d62f8c95STamir Duberstein 	KUNIT_CASE(numbers_slice),
772*d62f8c95STamir Duberstein 	KUNIT_CASE(numbers_prefix_overflow),
77397c1f302STamir Duberstein 
774*d62f8c95STamir Duberstein 	KUNIT_CASE(test_simple_strtoull),
775*d62f8c95STamir Duberstein 	KUNIT_CASE(test_simple_strtoll),
776*d62f8c95STamir Duberstein 	KUNIT_CASE(test_simple_strtoul),
777*d62f8c95STamir Duberstein 	KUNIT_CASE(test_simple_strtol),
778*d62f8c95STamir Duberstein 	{}
779*d62f8c95STamir Duberstein };
78097c1f302STamir Duberstein 
781*d62f8c95STamir Duberstein static int scanf_suite_init(struct kunit_suite *suite)
78297c1f302STamir Duberstein {
78397c1f302STamir Duberstein 	test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
78497c1f302STamir Duberstein 	if (!test_buffer)
785*d62f8c95STamir Duberstein 		return -ENOMEM;
78697c1f302STamir Duberstein 
78797c1f302STamir Duberstein 	fmt_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
78897c1f302STamir Duberstein 	if (!fmt_buffer) {
78997c1f302STamir Duberstein 		kfree(test_buffer);
790*d62f8c95STamir Duberstein 		return -ENOMEM;
79197c1f302STamir Duberstein 	}
79297c1f302STamir Duberstein 
79397c1f302STamir Duberstein 	prandom_seed_state(&rnd_state, 3141592653589793238ULL);
79497c1f302STamir Duberstein 
795*d62f8c95STamir Duberstein 	return 0;
796*d62f8c95STamir Duberstein }
79797c1f302STamir Duberstein 
798*d62f8c95STamir Duberstein static void scanf_suite_exit(struct kunit_suite *suite)
799*d62f8c95STamir Duberstein {
80097c1f302STamir Duberstein 	kfree(fmt_buffer);
80197c1f302STamir Duberstein 	kfree(test_buffer);
80297c1f302STamir Duberstein }
80397c1f302STamir Duberstein 
80497c1f302STamir Duberstein static struct kunit_suite scanf_test_suite = {
80597c1f302STamir Duberstein 	.name = "scanf",
806*d62f8c95STamir Duberstein 	.suite_init = scanf_suite_init,
807*d62f8c95STamir Duberstein 	.suite_exit = scanf_suite_exit,
80897c1f302STamir Duberstein 	.test_cases = scanf_test_cases,
80997c1f302STamir Duberstein };
81097c1f302STamir Duberstein 
81197c1f302STamir Duberstein kunit_test_suite(scanf_test_suite);
81297c1f302STamir Duberstein 
81397c1f302STamir Duberstein MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
81497c1f302STamir Duberstein MODULE_DESCRIPTION("Test cases for sscanf facility");
81597c1f302STamir Duberstein MODULE_LICENSE("GPL v2");
816