|
|
|
@ -3,60 +3,44 @@
|
|
|
|
|
* Test cases for sscanf facility.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
|
|
|
|
|
|
|
|
|
#include <kunit/test.h>
|
|
|
|
|
#include <linux/bitops.h>
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
|
#include <linux/module.h>
|
|
|
|
|
#include <linux/overflow.h>
|
|
|
|
|
#include <linux/printk.h>
|
|
|
|
|
#include <linux/prandom.h>
|
|
|
|
|
#include <linux/slab.h>
|
|
|
|
|
#include <linux/string.h>
|
|
|
|
|
|
|
|
|
|
#include "../tools/testing/selftests/kselftest_module.h"
|
|
|
|
|
|
|
|
|
|
#define BUF_SIZE 1024
|
|
|
|
|
|
|
|
|
|
KSTM_MODULE_GLOBALS();
|
|
|
|
|
static char *test_buffer __initdata;
|
|
|
|
|
static char *fmt_buffer __initdata;
|
|
|
|
|
static struct rnd_state rnd_state __initdata;
|
|
|
|
|
static char *test_buffer;
|
|
|
|
|
static char *fmt_buffer;
|
|
|
|
|
static struct rnd_state rnd_state;
|
|
|
|
|
|
|
|
|
|
typedef int (*check_fn)(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap);
|
|
|
|
|
typedef void (*check_fn)(struct kunit *test, const char *file, const int line,
|
|
|
|
|
const void *check_data, const char *string, const char *fmt, int n_args,
|
|
|
|
|
va_list ap);
|
|
|
|
|
|
|
|
|
|
static void __scanf(6, 8) __init
|
|
|
|
|
_test(const char *file, const int line, check_fn fn, const void *check_data, const char *string,
|
|
|
|
|
const char *fmt, int n_args, ...)
|
|
|
|
|
static void __scanf(7, 9)
|
|
|
|
|
_test(struct kunit *test, const char *file, const int line, check_fn fn, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap, ap_copy;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
total_tests++;
|
|
|
|
|
|
|
|
|
|
va_start(ap, n_args);
|
|
|
|
|
va_copy(ap_copy, ap);
|
|
|
|
|
ret = vsscanf(string, fmt, ap_copy);
|
|
|
|
|
va_end(ap_copy);
|
|
|
|
|
|
|
|
|
|
if (ret != n_args) {
|
|
|
|
|
pr_warn("%s:%d: vsscanf(\"%s\", \"%s\", ...) returned %d expected %d\n",
|
|
|
|
|
file, line, string, fmt, ret, n_args);
|
|
|
|
|
goto fail;
|
|
|
|
|
KUNIT_FAIL(test, "%s:%d: vsscanf(\"%s\", \"%s\", ...) returned %d expected %d",
|
|
|
|
|
file, line, string, fmt, ret, n_args);
|
|
|
|
|
} else {
|
|
|
|
|
(*fn)(test, file, line, check_data, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = (*fn)(file, line, check_data, string, fmt, n_args, ap);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
fail:
|
|
|
|
|
failed_tests++;
|
|
|
|
|
va_end(ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -65,88 +49,92 @@ do { \
|
|
|
|
|
for (; n_args > 0; n_args--, expect++) { \
|
|
|
|
|
typeof(*expect) got = *va_arg(ap, typeof(expect)); \
|
|
|
|
|
if (got != *expect) { \
|
|
|
|
|
pr_warn("%s:%d, vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt "\n", \
|
|
|
|
|
file, line, str, fmt, *expect, got); \
|
|
|
|
|
return 1; \
|
|
|
|
|
KUNIT_FAIL(test, \
|
|
|
|
|
"%s:%d: vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt, \
|
|
|
|
|
file, line, str, fmt, *expect, got); \
|
|
|
|
|
return; \
|
|
|
|
|
} \
|
|
|
|
|
} \
|
|
|
|
|
return 0; \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
static int __init check_ull(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_ull(struct kunit *test, const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const unsigned long long *pval = check_data;
|
|
|
|
|
|
|
|
|
|
_check_numbers_template("%llu", pval, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __init check_ll(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_ll(struct kunit *test, const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const long long *pval = check_data;
|
|
|
|
|
|
|
|
|
|
_check_numbers_template("%lld", pval, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __init check_ulong(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_ulong(struct kunit *test, const char *file, const int line,
|
|
|
|
|
const void *check_data, const char *string, const char *fmt, int n_args,
|
|
|
|
|
va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const unsigned long *pval = check_data;
|
|
|
|
|
|
|
|
|
|
_check_numbers_template("%lu", pval, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __init check_long(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_long(struct kunit *test, const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const long *pval = check_data;
|
|
|
|
|
|
|
|
|
|
_check_numbers_template("%ld", pval, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __init check_uint(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_uint(struct kunit *test, const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const unsigned int *pval = check_data;
|
|
|
|
|
|
|
|
|
|
_check_numbers_template("%u", pval, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __init check_int(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_int(struct kunit *test, const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const int *pval = check_data;
|
|
|
|
|
|
|
|
|
|
_check_numbers_template("%d", pval, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __init check_ushort(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_ushort(struct kunit *test, const char *file, const int line,
|
|
|
|
|
const void *check_data, const char *string, const char *fmt, int n_args,
|
|
|
|
|
va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const unsigned short *pval = check_data;
|
|
|
|
|
|
|
|
|
|
_check_numbers_template("%hu", pval, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __init check_short(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_short(struct kunit *test, const char *file, const int line,
|
|
|
|
|
const void *check_data, const char *string, const char *fmt, int n_args,
|
|
|
|
|
va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const short *pval = check_data;
|
|
|
|
|
|
|
|
|
|
_check_numbers_template("%hd", pval, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __init check_uchar(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_uchar(struct kunit *test, const char *file, const int line,
|
|
|
|
|
const void *check_data, const char *string, const char *fmt, int n_args,
|
|
|
|
|
va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *pval = check_data;
|
|
|
|
|
|
|
|
|
|
_check_numbers_template("%hhu", pval, string, fmt, n_args, ap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int __init check_char(const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
static void check_char(struct kunit *test, const char *file, const int line, const void *check_data,
|
|
|
|
|
const char *string, const char *fmt, int n_args, va_list ap)
|
|
|
|
|
{
|
|
|
|
|
const signed char *pval = check_data;
|
|
|
|
|
|
|
|
|
@ -154,7 +142,7 @@ static int __init check_char(const char *file, const int line, const void *check
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Selection of interesting numbers to test, copied from test-kstrtox.c */
|
|
|
|
|
static const unsigned long long numbers[] __initconst = {
|
|
|
|
|
static const unsigned long long numbers[] = {
|
|
|
|
|
0x0ULL,
|
|
|
|
|
0x1ULL,
|
|
|
|
|
0x7fULL,
|
|
|
|
@ -194,7 +182,7 @@ do { \
|
|
|
|
|
T result = ~expect_val; /* should be overwritten */ \
|
|
|
|
|
\
|
|
|
|
|
snprintf(test_buffer, BUF_SIZE, gen_fmt, expect_val); \
|
|
|
|
|
_test(__FILE__, __LINE__, fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result); \
|
|
|
|
|
_test(test, __FILE__, __LINE__, fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result);\
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
#define simple_numbers_loop(T, gen_fmt, scan_fmt, fn) \
|
|
|
|
@ -212,7 +200,7 @@ do { \
|
|
|
|
|
} \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
static void __init numbers_simple(void)
|
|
|
|
|
static void numbers_simple(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
simple_numbers_loop(unsigned long long, "%llu", "llu", check_ull);
|
|
|
|
|
simple_numbers_loop(long long, "%lld", "lld", check_ll);
|
|
|
|
@ -265,14 +253,14 @@ static void __init numbers_simple(void)
|
|
|
|
|
* the raw prandom*() functions (Not mathematically rigorous!!).
|
|
|
|
|
* Variabilty of length and value is more important than perfect randomness.
|
|
|
|
|
*/
|
|
|
|
|
static u32 __init next_test_random(u32 max_bits)
|
|
|
|
|
static u32 next_test_random(u32 max_bits)
|
|
|
|
|
{
|
|
|
|
|
u32 n_bits = hweight32(prandom_u32_state(&rnd_state)) % (max_bits + 1);
|
|
|
|
|
|
|
|
|
|
return prandom_u32_state(&rnd_state) & GENMASK(n_bits, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned long long __init next_test_random_ull(void)
|
|
|
|
|
static unsigned long long next_test_random_ull(void)
|
|
|
|
|
{
|
|
|
|
|
u32 rand1 = prandom_u32_state(&rnd_state);
|
|
|
|
|
u32 n_bits = (hweight32(rand1) * 3) % 64;
|
|
|
|
@ -309,7 +297,7 @@ do { \
|
|
|
|
|
* updating buf_pos and returning the number of characters appended.
|
|
|
|
|
* On error buf_pos is not changed and return value is 0.
|
|
|
|
|
*/
|
|
|
|
|
static int __init __printf(4, 5)
|
|
|
|
|
static int __printf(4, 5)
|
|
|
|
|
append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
@ -331,7 +319,7 @@ append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...)
|
|
|
|
|
* Convenience function to append the field delimiter string
|
|
|
|
|
* to both the value string and format string buffers.
|
|
|
|
|
*/
|
|
|
|
|
static void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len,
|
|
|
|
|
static void append_delim(char *str_buf, int *str_buf_pos, int str_buf_len,
|
|
|
|
|
char *fmt_buf, int *fmt_buf_pos, int fmt_buf_len,
|
|
|
|
|
const char *delim_str)
|
|
|
|
|
{
|
|
|
|
@ -342,7 +330,7 @@ static void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len
|
|
|
|
|
#define test_array_8(fn, check_data, string, fmt, arr) \
|
|
|
|
|
do { \
|
|
|
|
|
BUILD_BUG_ON(ARRAY_SIZE(arr) != 8); \
|
|
|
|
|
_test(__FILE__, __LINE__, fn, check_data, string, fmt, 8, \
|
|
|
|
|
_test(test, __FILE__, __LINE__, fn, check_data, string, fmt, 8, \
|
|
|
|
|
&(arr)[0], &(arr)[1], &(arr)[2], &(arr)[3], \
|
|
|
|
|
&(arr)[4], &(arr)[5], &(arr)[6], &(arr)[7]); \
|
|
|
|
|
} while (0)
|
|
|
|
@ -396,7 +384,7 @@ do { \
|
|
|
|
|
test_array_8(fn, expect, test_buffer, fmt_buffer, result); \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_ll(const char *delim)
|
|
|
|
|
static void numbers_list_ll(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_8(unsigned long long, "%llu", delim, "llu", check_ull);
|
|
|
|
|
numbers_list_8(long long, "%lld", delim, "lld", check_ll);
|
|
|
|
@ -406,7 +394,7 @@ static void __init numbers_list_ll(const char *delim)
|
|
|
|
|
numbers_list_8(long long, "0x%llx", delim, "lli", check_ll);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_l(const char *delim)
|
|
|
|
|
static void numbers_list_l(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_8(unsigned long, "%lu", delim, "lu", check_ulong);
|
|
|
|
|
numbers_list_8(long, "%ld", delim, "ld", check_long);
|
|
|
|
@ -416,7 +404,7 @@ static void __init numbers_list_l(const char *delim)
|
|
|
|
|
numbers_list_8(long, "0x%lx", delim, "li", check_long);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_d(const char *delim)
|
|
|
|
|
static void numbers_list_d(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_8(unsigned int, "%u", delim, "u", check_uint);
|
|
|
|
|
numbers_list_8(int, "%d", delim, "d", check_int);
|
|
|
|
@ -426,7 +414,7 @@ static void __init numbers_list_d(const char *delim)
|
|
|
|
|
numbers_list_8(int, "0x%x", delim, "i", check_int);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_h(const char *delim)
|
|
|
|
|
static void numbers_list_h(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_8(unsigned short, "%hu", delim, "hu", check_ushort);
|
|
|
|
|
numbers_list_8(short, "%hd", delim, "hd", check_short);
|
|
|
|
@ -436,7 +424,7 @@ static void __init numbers_list_h(const char *delim)
|
|
|
|
|
numbers_list_8(short, "0x%hx", delim, "hi", check_short);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_hh(const char *delim)
|
|
|
|
|
static void numbers_list_hh(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_8(unsigned char, "%hhu", delim, "hhu", check_uchar);
|
|
|
|
|
numbers_list_8(signed char, "%hhd", delim, "hhd", check_char);
|
|
|
|
@ -446,16 +434,16 @@ static void __init numbers_list_hh(const char *delim)
|
|
|
|
|
numbers_list_8(signed char, "0x%hhx", delim, "hhi", check_char);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list(const char *delim)
|
|
|
|
|
static void numbers_list(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_ll(delim);
|
|
|
|
|
numbers_list_l(delim);
|
|
|
|
|
numbers_list_d(delim);
|
|
|
|
|
numbers_list_h(delim);
|
|
|
|
|
numbers_list_hh(delim);
|
|
|
|
|
numbers_list_ll(test, delim);
|
|
|
|
|
numbers_list_l(test, delim);
|
|
|
|
|
numbers_list_d(test, delim);
|
|
|
|
|
numbers_list_h(test, delim);
|
|
|
|
|
numbers_list_hh(test, delim);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_ll(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_ll(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_fix_width(unsigned long long, "%llu", delim, 20, "llu", check_ull);
|
|
|
|
|
numbers_list_fix_width(long long, "%lld", delim, 20, "lld", check_ll);
|
|
|
|
@ -465,7 +453,7 @@ static void __init numbers_list_field_width_ll(const char *delim)
|
|
|
|
|
numbers_list_fix_width(long long, "0x%llx", delim, 18, "lli", check_ll);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_l(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_l(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
#if BITS_PER_LONG == 64
|
|
|
|
|
numbers_list_fix_width(unsigned long, "%lu", delim, 20, "lu", check_ulong);
|
|
|
|
@ -484,7 +472,7 @@ static void __init numbers_list_field_width_l(const char *delim)
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_d(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_d(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_fix_width(unsigned int, "%u", delim, 10, "u", check_uint);
|
|
|
|
|
numbers_list_fix_width(int, "%d", delim, 11, "d", check_int);
|
|
|
|
@ -494,7 +482,7 @@ static void __init numbers_list_field_width_d(const char *delim)
|
|
|
|
|
numbers_list_fix_width(int, "0x%x", delim, 10, "i", check_int);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_h(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_h(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_fix_width(unsigned short, "%hu", delim, 5, "hu", check_ushort);
|
|
|
|
|
numbers_list_fix_width(short, "%hd", delim, 6, "hd", check_short);
|
|
|
|
@ -504,7 +492,7 @@ static void __init numbers_list_field_width_h(const char *delim)
|
|
|
|
|
numbers_list_fix_width(short, "0x%hx", delim, 6, "hi", check_short);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_hh(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_hh(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_fix_width(unsigned char, "%hhu", delim, 3, "hhu", check_uchar);
|
|
|
|
|
numbers_list_fix_width(signed char, "%hhd", delim, 4, "hhd", check_char);
|
|
|
|
@ -518,16 +506,16 @@ static void __init numbers_list_field_width_hh(const char *delim)
|
|
|
|
|
* List of numbers separated by delim. Each field width specifier is the
|
|
|
|
|
* maximum possible digits for the given type and base.
|
|
|
|
|
*/
|
|
|
|
|
static void __init numbers_list_field_width_typemax(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_typemax(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_field_width_ll(delim);
|
|
|
|
|
numbers_list_field_width_l(delim);
|
|
|
|
|
numbers_list_field_width_d(delim);
|
|
|
|
|
numbers_list_field_width_h(delim);
|
|
|
|
|
numbers_list_field_width_hh(delim);
|
|
|
|
|
numbers_list_field_width_ll(test, delim);
|
|
|
|
|
numbers_list_field_width_l(test, delim);
|
|
|
|
|
numbers_list_field_width_d(test, delim);
|
|
|
|
|
numbers_list_field_width_h(test, delim);
|
|
|
|
|
numbers_list_field_width_hh(test, delim);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_val_ll(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_val_ll(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_val_width(unsigned long long, "%llu", delim, "llu", check_ull);
|
|
|
|
|
numbers_list_val_width(long long, "%lld", delim, "lld", check_ll);
|
|
|
|
@ -537,7 +525,7 @@ static void __init numbers_list_field_width_val_ll(const char *delim)
|
|
|
|
|
numbers_list_val_width(long long, "0x%llx", delim, "lli", check_ll);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_val_l(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_val_l(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_val_width(unsigned long, "%lu", delim, "lu", check_ulong);
|
|
|
|
|
numbers_list_val_width(long, "%ld", delim, "ld", check_long);
|
|
|
|
@ -547,7 +535,7 @@ static void __init numbers_list_field_width_val_l(const char *delim)
|
|
|
|
|
numbers_list_val_width(long, "0x%lx", delim, "li", check_long);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_val_d(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_val_d(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_val_width(unsigned int, "%u", delim, "u", check_uint);
|
|
|
|
|
numbers_list_val_width(int, "%d", delim, "d", check_int);
|
|
|
|
@ -557,7 +545,7 @@ static void __init numbers_list_field_width_val_d(const char *delim)
|
|
|
|
|
numbers_list_val_width(int, "0x%x", delim, "i", check_int);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_val_h(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_val_h(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_val_width(unsigned short, "%hu", delim, "hu", check_ushort);
|
|
|
|
|
numbers_list_val_width(short, "%hd", delim, "hd", check_short);
|
|
|
|
@ -567,7 +555,7 @@ static void __init numbers_list_field_width_val_h(const char *delim)
|
|
|
|
|
numbers_list_val_width(short, "0x%hx", delim, "hi", check_short);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init numbers_list_field_width_val_hh(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_val_hh(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_val_width(unsigned char, "%hhu", delim, "hhu", check_uchar);
|
|
|
|
|
numbers_list_val_width(signed char, "%hhd", delim, "hhd", check_char);
|
|
|
|
@ -581,13 +569,13 @@ static void __init numbers_list_field_width_val_hh(const char *delim)
|
|
|
|
|
* List of numbers separated by delim. Each field width specifier is the
|
|
|
|
|
* exact length of the corresponding value digits in the string being scanned.
|
|
|
|
|
*/
|
|
|
|
|
static void __init numbers_list_field_width_val_width(const char *delim)
|
|
|
|
|
static void numbers_list_field_width_val_width(struct kunit *test, const char *delim)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_field_width_val_ll(delim);
|
|
|
|
|
numbers_list_field_width_val_l(delim);
|
|
|
|
|
numbers_list_field_width_val_d(delim);
|
|
|
|
|
numbers_list_field_width_val_h(delim);
|
|
|
|
|
numbers_list_field_width_val_hh(delim);
|
|
|
|
|
numbers_list_field_width_val_ll(test, delim);
|
|
|
|
|
numbers_list_field_width_val_l(test, delim);
|
|
|
|
|
numbers_list_field_width_val_d(test, delim);
|
|
|
|
|
numbers_list_field_width_val_h(test, delim);
|
|
|
|
|
numbers_list_field_width_val_hh(test, delim);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -596,9 +584,9 @@ static void __init numbers_list_field_width_val_width(const char *delim)
|
|
|
|
|
* of digits. For example the hex values c0,3,bf01,303 would have a
|
|
|
|
|
* string representation of "c03bf01303" and extracted with "%2x%1x%4x%3x".
|
|
|
|
|
*/
|
|
|
|
|
static void __init numbers_slice(void)
|
|
|
|
|
static void numbers_slice(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
numbers_list_field_width_val_width("");
|
|
|
|
|
numbers_list_field_width_val_width(test, "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn) \
|
|
|
|
@ -606,14 +594,14 @@ do { \
|
|
|
|
|
const T expect[2] = { expect0, expect1 }; \
|
|
|
|
|
T result[2] = { (T)~expect[0], (T)~expect[1] }; \
|
|
|
|
|
\
|
|
|
|
|
_test(__FILE__, __LINE__, fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]); \
|
|
|
|
|
_test(test, __FILE__, __LINE__, fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]);\
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Number prefix is >= field width.
|
|
|
|
|
* Expected behaviour is derived from testing userland sscanf.
|
|
|
|
|
*/
|
|
|
|
|
static void __init numbers_prefix_overflow(void)
|
|
|
|
|
static void numbers_prefix_overflow(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Negative decimal with a field of width 1, should quit scanning
|
|
|
|
@ -682,24 +670,17 @@ do { \
|
|
|
|
|
T got; \
|
|
|
|
|
char *endp; \
|
|
|
|
|
int len; \
|
|
|
|
|
bool fail = false; \
|
|
|
|
|
\
|
|
|
|
|
total_tests++; \
|
|
|
|
|
len = snprintf(test_buffer, BUF_SIZE, gen_fmt, expect); \
|
|
|
|
|
got = (fn)(test_buffer, &endp, base); \
|
|
|
|
|
if (got != (expect)) { \
|
|
|
|
|
fail = true; \
|
|
|
|
|
pr_warn(#fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt "\n", \
|
|
|
|
|
test_buffer, base, got, expect); \
|
|
|
|
|
KUNIT_FAIL(test, #fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt, \
|
|
|
|
|
test_buffer, base, got, expect); \
|
|
|
|
|
} else if (endp != test_buffer + len) { \
|
|
|
|
|
fail = true; \
|
|
|
|
|
pr_warn(#fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px\n", \
|
|
|
|
|
test_buffer, base, test_buffer, \
|
|
|
|
|
test_buffer + len, endp); \
|
|
|
|
|
KUNIT_FAIL(test, #fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px", \
|
|
|
|
|
test_buffer, base, test_buffer, \
|
|
|
|
|
test_buffer + len, endp); \
|
|
|
|
|
} \
|
|
|
|
|
\
|
|
|
|
|
if (fail) \
|
|
|
|
|
failed_tests++; \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
#define test_simple_strtoxx(T, fn, gen_fmt, base) \
|
|
|
|
@ -715,7 +696,7 @@ do { \
|
|
|
|
|
} \
|
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
|
static void __init test_simple_strtoull(void)
|
|
|
|
|
static void test_simple_strtoull(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 10);
|
|
|
|
|
test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 0);
|
|
|
|
@ -724,7 +705,7 @@ static void __init test_simple_strtoull(void)
|
|
|
|
|
test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init test_simple_strtoll(void)
|
|
|
|
|
static void test_simple_strtoll(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
test_simple_strtoxx(long long, simple_strtoll, "%lld", 10);
|
|
|
|
|
test_simple_strtoxx(long long, simple_strtoll, "%lld", 0);
|
|
|
|
@ -733,7 +714,7 @@ static void __init test_simple_strtoll(void)
|
|
|
|
|
test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init test_simple_strtoul(void)
|
|
|
|
|
static void test_simple_strtoul(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 10);
|
|
|
|
|
test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 0);
|
|
|
|
@ -742,7 +723,7 @@ static void __init test_simple_strtoul(void)
|
|
|
|
|
test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init test_simple_strtol(void)
|
|
|
|
|
static void test_simple_strtol(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
test_simple_strtoxx(long, simple_strtol, "%ld", 10);
|
|
|
|
|
test_simple_strtoxx(long, simple_strtol, "%ld", 0);
|
|
|
|
@ -752,35 +733,35 @@ static void __init test_simple_strtol(void)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Selection of common delimiters/separators between numbers in a string. */
|
|
|
|
|
static const char * const number_delimiters[] __initconst = {
|
|
|
|
|
static const char * const number_delimiters[] = {
|
|
|
|
|
" ", ":", ",", "-", "/",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void __init test_numbers(void)
|
|
|
|
|
static void test_numbers(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* String containing only one number. */
|
|
|
|
|
numbers_simple();
|
|
|
|
|
numbers_simple(test);
|
|
|
|
|
|
|
|
|
|
/* String with multiple numbers separated by delimiter. */
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(number_delimiters); i++) {
|
|
|
|
|
numbers_list(number_delimiters[i]);
|
|
|
|
|
numbers_list(test, number_delimiters[i]);
|
|
|
|
|
|
|
|
|
|
/* Field width may be longer than actual field digits. */
|
|
|
|
|
numbers_list_field_width_typemax(number_delimiters[i]);
|
|
|
|
|
numbers_list_field_width_typemax(test, number_delimiters[i]);
|
|
|
|
|
|
|
|
|
|
/* Each field width exactly length of actual field digits. */
|
|
|
|
|
numbers_list_field_width_val_width(number_delimiters[i]);
|
|
|
|
|
numbers_list_field_width_val_width(test, number_delimiters[i]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Slice continuous sequence of digits using field widths. */
|
|
|
|
|
numbers_slice();
|
|
|
|
|
numbers_slice(test);
|
|
|
|
|
|
|
|
|
|
numbers_prefix_overflow();
|
|
|
|
|
numbers_prefix_overflow(test);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __init selftest(void)
|
|
|
|
|
static void scanf_test(struct kunit *test)
|
|
|
|
|
{
|
|
|
|
|
test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
|
|
|
|
|
if (!test_buffer)
|
|
|
|
@ -794,18 +775,29 @@ static void __init selftest(void)
|
|
|
|
|
|
|
|
|
|
prandom_seed_state(&rnd_state, 3141592653589793238ULL);
|
|
|
|
|
|
|
|
|
|
test_numbers();
|
|
|
|
|
test_numbers(test);
|
|
|
|
|
|
|
|
|
|
test_simple_strtoull();
|
|
|
|
|
test_simple_strtoll();
|
|
|
|
|
test_simple_strtoul();
|
|
|
|
|
test_simple_strtol();
|
|
|
|
|
test_simple_strtoull(test);
|
|
|
|
|
test_simple_strtoll(test);
|
|
|
|
|
test_simple_strtoul(test);
|
|
|
|
|
test_simple_strtol(test);
|
|
|
|
|
|
|
|
|
|
kfree(fmt_buffer);
|
|
|
|
|
kfree(test_buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
KSTM_MODULE_LOADERS(test_scanf);
|
|
|
|
|
static struct kunit_case scanf_test_cases[] = {
|
|
|
|
|
KUNIT_CASE(scanf_test),
|
|
|
|
|
{}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct kunit_suite scanf_test_suite = {
|
|
|
|
|
.name = "scanf",
|
|
|
|
|
.test_cases = scanf_test_cases,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
kunit_test_suite(scanf_test_suite);
|
|
|
|
|
|
|
|
|
|
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
|
|
|
|
|
MODULE_DESCRIPTION("Test cases for sscanf facility");
|
|
|
|
|
MODULE_LICENSE("GPL v2");
|