Module is under config option CONFIG_TEST_SCANF. This is just basic cases, complete coverage isn't that easy for such complicated function.
Signed-off-by: Konstantin Khlebnikov <khlebni...@yandex-team.ru> --- lib/Kconfig.debug | 3 + lib/Makefile | 1 lib/test_scanf.c | 252 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 256 insertions(+) create mode 100644 lib/test_scanf.c diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 91ed81250fb3..b50ac3c81961 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -1806,6 +1806,9 @@ config TEST_STRING_HELPERS config TEST_KSTRTOX tristate "Test kstrto*() family of functions at runtime" +config TEST_SCANF + tristate "Test scanf() family of functions at runtime" + config TEST_PRINTF tristate "Test printf() family of functions at runtime" diff --git a/lib/Makefile b/lib/Makefile index 647517940b29..b1d538d7180e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_TEST_USER_COPY) += test_user_copy.o obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o obj-$(CONFIG_TEST_PRINTF) += test_printf.o +obj-$(CONFIG_TEST_SCANF) += test_scanf.o obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o obj-$(CONFIG_TEST_BITFIELD) += test_bitfield.o obj-$(CONFIG_TEST_UUID) += test_uuid.o diff --git a/lib/test_scanf.c b/lib/test_scanf.c new file mode 100644 index 000000000000..1a4f8f145a46 --- /dev/null +++ b/lib/test_scanf.c @@ -0,0 +1,252 @@ +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> + +#ifndef KERN_EOT +#define KERN_EOT "" +#define SCANF_MORE 0 +#endif + +#define TEST_ONE(str, fmt, type, type_fmt, ret, val) \ + do { \ + type _neg = (type)~(type)(val); \ + type _val = _neg; \ + int _ret = sscanf(str, fmt, &_val); \ + WARN(_ret != (ret), "scanf(\"%s\", \"%s\", ...) returned %d, expected %d", str, fmt, _ret, ret); \ + WARN(ret && _ret && _val != (type)(val), "scanf(\"%s\", \"%s\", ...) matched value " type_fmt ", expected " type_fmt, str, fmt, _val, (type)(val)); \ + WARN(!_ret && _val != _neg, "scanf(\"%s\", \"%s\", ...) unmached value overwritten with " type_fmt, str, fmt, _val); \ + } while (0); + +#define TEST_STR(str, fmt, len, ret, val) \ + do { \ + char _val[len + 1] = {0,}; \ + int _ret = sscanf(str, fmt, _val); \ + WARN(_ret != (ret), "scanf(\"%s\", \"%s\", ...) returned %d, expected %d", str, fmt, _ret, ret); \ + WARN(ret && _ret && strncmp(_val, val, len), "scanf(\"%s\", \"%s\", ...) matched value \"%.*s\", expected \"%.*s\"", str, fmt, len + 1, _val, len + 1, val); \ + WARN(!_ret && _val[0], "scanf(\"%s\", \"%s\", ...) unmached value overwritten with \"%.*s\"", str, fmt, len + 1, _val); \ + } while (0); + +#define TEST_VA(str, fmt, ret, ...) \ + do { \ + int _ret = sscanf(str, fmt, ##__VA_ARGS__); \ + WARN(_ret != (ret), "scanf(\"%s\", \"%s\", ...) returned %d, expected %d", str, fmt, _ret, ret); \ + } while (0); + +#define TEST_SC(str, fmt, ret, val) TEST_ONE(str, fmt, signed char, "%d", ret, val) +#define TEST_UC(str, fmt, ret, val) TEST_ONE(str, fmt, unsigned char, "%u", ret, val) +#define TEST_SS(str, fmt, ret, val) TEST_ONE(str, fmt, short, "%d", ret, val) +#define TEST_US(str, fmt, ret, val) TEST_ONE(str, fmt, unsigned short, "%u", ret, val) +#define TEST_SI(str, fmt, ret, val) TEST_ONE(str, fmt, int, "%d", ret, val) +#define TEST_UI(str, fmt, ret, val) TEST_ONE(str, fmt, unsigned int, "%u", ret, val) +#define TEST_SL(str, fmt, ret, val) TEST_ONE(str, fmt, long, "%ld", ret, val) +#define TEST_UL(str, fmt, ret, val) TEST_ONE(str, fmt, unsigned long, "%lu", ret, val) +#define TEST_SQ(str, fmt, ret, val) TEST_ONE(str, fmt, long long, "%llu", ret, val) +#define TEST_UQ(str, fmt, ret, val) TEST_ONE(str, fmt, unsigned long long, "%llu", ret, val) + +static void __init test_base(void) +{ + TEST_UI("10", "%u", 1, 10); + TEST_SI("10", "%d", 1, 10); + TEST_UI("10", "%o", 1, 8); + TEST_UI("10", "%x", 1, 16); + TEST_SI("10", "%i", 1, 10); + TEST_SI("010", "%i", 1, 8); + TEST_SI("0x10", "%i", 1, 16); + + TEST_UI("9a", "%u", 1, 9); + TEST_SI("9a", "%d", 1, 9); + TEST_UI("78", "%o", 1, 7); + TEST_UI("fg", "%x", 1, 15); + TEST_SI("9a", "%i", 1, 9); + TEST_SI("078", "%i", 1, 7); + TEST_SI("0xfg", "%i", 1, 15); + + TEST_UI("a", "%u", 0, 0); + TEST_SI("a", "%d", 0, 0); + TEST_UI("8", "%o", 0, 0); + TEST_UI("g", "%x", 0, 0); + TEST_SI("a", "%i", 0, 0); +} + +static void __init test_sign(void) +{ + TEST_UI("+0", "%u", 0, 0); + TEST_UI("-0", "%u", 0, 0); + TEST_UI("+1", "%u", 0, 0); + TEST_UI("-1", "%u", 0, 0); + TEST_UI("++1", "%u", 0, 0); + TEST_UI("--1", "%u", 0, 0); + TEST_UI("+-1", "%u", 0, 0); + TEST_UI("-+1", "%u", 0, 0); + TEST_UI("+", "%u", 0, 0); + TEST_UI("-", "%u", 0, 0); + + TEST_SI("+0", "%d", 1, 0); + TEST_SI("-0", "%d", 1, 0); + TEST_SI("+1", "%d", 1, 1); + TEST_SI("-1", "%d", 1, -1); + TEST_SI("++1", "%d", 0, 0); + TEST_SI("--1", "%d", 0, 0); + TEST_SI("+-1", "%d", 0, 0); + TEST_SI("-+1", "%d", 0, 0); + TEST_SI("+", "%d", 0, 0); + TEST_SI("-", "%d", 0, 0); +} + +static void __init test_range(void) +{ + TEST_UC("255", "%hhu", 1, 255); + TEST_US("65535", "%hu", 1, 65535); + TEST_UI("4294967295", "%u", 1, 4294967295); + TEST_UL("4294967295", "%lu", 1, 4294967295); +#if BITS_PER_LONG == 32 + TEST_UL("18446744073709551615", "%lu", 0, 0); +#else + TEST_UL("18446744073709551615", "%lu", 1, 18446744073709551615ull); +#endif + TEST_UQ("18446744073709551615", "%llu", 1, 18446744073709551615ull); + + + TEST_SC("-128", "%hhd", 1, -128); + TEST_SC("127", "%hhd", 1, 127); + TEST_SS("-32768", "%hd", 1, -32768); + TEST_SS("32767", "%hd", 1, 32767); + TEST_SI("-2147483648", "%d", 1, -2147483648); + TEST_SI("2147483647", "%d", 1, 2147483647); + TEST_SL("-2147483648", "%ld", 1, -2147483648); + TEST_SL("2147483647", "%ld", 1, 2147483647); +#if BITS_PER_LONG == 32 + TEST_SL("-9223372036854775808", "%ld", 0, 0); + TEST_SL("9223372036854775807", "%ld", 0, 0); +#else + TEST_SL("-9223372036854775808", "%ld", 1, -9223372036854775808ull); + TEST_SL("9223372036854775807", "%ld", 1, 9223372036854775807ll); +#endif + TEST_SQ("-9223372036854775808", "%lld", 1, -9223372036854775808ull); + TEST_SQ("9223372036854775807", "%lld", 1, 9223372036854775807ll); + + + TEST_UC("256", "%hhu", 0, 0); + TEST_US("65536", "%hu", 0, 0); + TEST_UI("4294967296", "%u", 0, 0); +#if BITS_PER_LONG == 32 + TEST_UL("4294967296", "%lu", 0, 0); +#else + TEST_UL("4294967296", "%lu", 1, 4294967296); +#endif + TEST_UL("18446744073709551616", "%lu", 0, 0); + TEST_UQ("18446744073709551616", "%llu", 0, 0); + + TEST_SC("-129", "%hhd", 0, 0); + TEST_SC("128", "%hhd", 0, 0); + TEST_SS("-32769", "%hd", 0, 0); + TEST_SS("32768", "%hd", 0, 0); + TEST_SI("-2147483649", "%d", 0, 0); + TEST_SI("2147483648", "%d", 0, 0); +#if BITS_PER_LONG == 32 + TEST_SL("-2147483649", "%ld", 0, 0); + TEST_SL("2147483648", "%ld", 0, 0); +#else + TEST_SL("-2147483649", "%ld", 1, -2147483649); + TEST_SL("2147483648", "%ld", 1, 2147483648); +#endif + TEST_SL("-9223372036854775809", "%ld", 0, 0); + TEST_SL("9223372036854775808", "%ld", 0, 0); + TEST_SQ("-9223372036854775809", "%lld", 0, 0); + TEST_SQ("9223372036854775808", "%lld", 0, 0); +} + +static void __init test_eot(void) +{ + TEST_UI("123", "%u" KERN_EOT, 1, 123); + TEST_UI("123 ", "%u" KERN_EOT, 1 | SCANF_MORE, 123); + TEST_UI("123 ", "%u " KERN_EOT, 1, 123); + TEST_UI("123 \t\n", "%u " KERN_EOT, 1, 123); + TEST_UI("123z ", "%u " KERN_EOT, 1 | SCANF_MORE, 123); + + TEST_SI("1M", "%d", 1, 1); + TEST_SI("1M", "%d" KERN_EOT, 1 | SCANF_MORE, 1); + + TEST_SI("1\n", "%d" KERN_EOT, 1 | SCANF_MORE, 1); + TEST_SI("1\n", "%d " KERN_EOT, 1, 1); +} + +static void __init test_set(void) +{ + // TODO it would be nice to make field width mandatory here + TEST_STR("abc", "%s", 3, 1, "abc"); + + TEST_STR("abc", "%3s", 3, 1, "abc"); + TEST_STR("abc", "%2s", 3, 1, "ab"); + TEST_STR("abc", "%1s", 3, 1, "a"); + + TEST_STR(" a\n", "%3s", 3, 1, "a"); + + TEST_STR("abc", "%3c", 3, 1, "abc"); + TEST_STR(" a\n", "%3c", 3, 1, " a\n"); + + TEST_STR("abc", "%[a-z]", 3, 0, ""); // no width + + TEST_STR("abc", "%3[abc]", 3, 1, "abc"); + TEST_STR("abc", "%3[^abc]", 3, 0, ""); + + TEST_STR("abc", "%3[xyz]", 3, 0, ""); + TEST_STR("abc", "%3[^xyz]", 3, 1, "abc"); + + TEST_STR(" a", "%3[a]", 3, 0, ""); + TEST_STR(" a", "%3[ a]", 3, 1, " a"); + + TEST_STR("abcd", "%5[a-c]", 5, 1, "abc"); + TEST_STR("abc", "%3[^a-b]", 3, 0, ""); + + TEST_STR("bd", "%3[a-c]", 3, 1, "b"); + TEST_STR("db", "%3[^a-c]", 3, 1, "d"); + + TEST_STR("q1w2e3", "%8[a-z0-9]", 8, 1, "q1w2e3"); + TEST_STR("q1w2e3", "%8[^a-z0-9]", 8, 0, ""); + + TEST_STR("a-", "%3[a-b]", 3, 1, "a"); + TEST_STR("a-", "%3[a-]", 3, 1, "a-"); + TEST_STR("a-", "%3[^a-]", 3, 0, ""); + + TEST_STR("-", "%3[-]", 3, 1, "-"); + TEST_STR("-", "%3[^-]", 3, 0, ""); + + TEST_STR("]ab", "%3[]]", 3, 1, "]"); + TEST_STR("a]b", "%3[^]]", 3, 1, "a"); + + TEST_STR("]-abc", "%3[]-]", 3, 1, "]-"); + TEST_STR("abc]-", "%3[^]-]", 3, 1, "abc"); +} + +static void __init test_va(void) +{ + int x, y, z; + char a, b, c; + + TEST_VA(" 1 ", "%d%d", 1, &x, &y); + TEST_VA(" 1 2 ", "%d%d", 2, &x, &y); + TEST_VA(" 1 2 3 ", "%d%d%d", 3, &x, &y, &z); + TEST_VA(" 1 2 3 ", "%d%d", 2, &x, &y); + + TEST_VA(" 1x 2 ", "%d%d", 1, &x, &y); + + TEST_VA("1", "%d%c", 1, &x, &a); + TEST_VA("1 ", "%d%c", 2, &x, &a); + TEST_VA("1 ", "%d %c", 1, &x, &a); + + TEST_VA(" \t\n", "%c%c%c", 3, &a, &b, &c); +} + +static int __init test_scanf_init(void) +{ + test_base(); + test_sign(); + test_range(); + test_eot(); + test_set(); + test_va(); + return -EINVAL; +} +module_init(test_scanf_init); +MODULE_LICENSE("GPL");