The input subsystem doesn't currently have any unit tests, let's add a CONFIG_INPUT_KUNIT_TEST option that builds a test suite to be executed with the KUnit test infrastructure. For now, only three tests were added for some of the input core helper functions that are trivial to test: * input_test_polling: set/get poll interval and set-up a poll handler. * input_test_timestamp: set/get input event timestamps. * input_test_match_device_id: match a device by bus, vendor, product and events that is capable of handling. But having the minimal KUnit support allows to add more tests and suites as follow-up changes. The tests can be run with the following command: $ ./tools/testing/kunit/kunit.py run \ --kunitconfig=drivers/input/tests/.kunitconfig Signed-off-by: Javier Martinez Canillas <javierm@xxxxxxxxxx> --- drivers/input/Kconfig | 12 +++ drivers/input/Makefile | 1 + drivers/input/tests/Makefile | 3 + drivers/input/tests/input_test.c | 144 +++++++++++++++++++++++++++++++ 4 files changed, 160 insertions(+) create mode 100644 drivers/input/tests/Makefile create mode 100644 drivers/input/tests/input_test.c diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index e2752f7364bc..e094e5bbaa0c 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -166,6 +166,18 @@ config INPUT_EVBUG To compile this driver as a module, choose M here: the module will be called evbug. +config INPUT_KUNIT_TEST + tristate "KUnit tests for Input" if !KUNIT_ALL_TESTS + depends on INPUT && KUNIT=y + default KUNIT_ALL_TESTS + help + Say Y here if you want to build the KUnit tests for the input + subsystem. For more information about KUnit and unit tests in + general, please refer to the KUnit documentation in + Documentation/dev-tools/kunit/. + + If in doubt, say "N". + config INPUT_APMPOWER tristate "Input Power Event -> APM Bridge" if EXPERT depends on INPUT && APM_EMULATION diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 2266c7d010ef..c78753274921 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ +obj-$(CONFIG_INPUT_KUNIT_TEST) += tests/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o diff --git a/drivers/input/tests/Makefile b/drivers/input/tests/Makefile new file mode 100644 index 000000000000..90cf954181bc --- /dev/null +++ b/drivers/input/tests/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0 + +obj-$(CONFIG_INPUT_KUNIT_TEST) += input_test.o diff --git a/drivers/input/tests/input_test.c b/drivers/input/tests/input_test.c new file mode 100644 index 000000000000..25bbf51b5c87 --- /dev/null +++ b/drivers/input/tests/input_test.c @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * KUnit test for the input core. + * + * Copyright (c) 2023 Red Hat Inc + */ + +#include <linux/delay.h> +#include <linux/input.h> + +#include <kunit/test.h> + +#define POLL_INTERVAL 100 + +static int input_test_init(struct kunit *test) +{ + struct input_dev *input_dev; + int ret; + + input_dev = input_allocate_device(); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, input_dev); + + input_dev->name = "Test input device"; + input_dev->id.bustype = BUS_VIRTUAL; + input_dev->id.vendor = 1; + input_dev->id.product = 1; + input_dev->id.version = 1; + input_set_capability(input_dev, EV_KEY, BTN_LEFT); + input_set_capability(input_dev, EV_KEY, BTN_RIGHT); + + ret = input_register_device(input_dev); + KUNIT_ASSERT_EQ(test, ret, 0); + + test->priv = input_dev; + + return 0; +} + +static void input_test_exit(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + + input_unregister_device(input_dev); +} + +static void input_test_poll(struct input_dev *input) { } + +static void input_test_polling(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + int ret; + + ret = input_get_poll_interval(input_dev); + KUNIT_ASSERT_EQ(test, ret, -EINVAL); + + ret = input_setup_polling(input_dev, input_test_poll); + KUNIT_ASSERT_EQ(test, ret, 0); + + input_set_poll_interval(input_dev, POLL_INTERVAL); + + ret = input_get_poll_interval(input_dev); + KUNIT_ASSERT_EQ(test, ret, POLL_INTERVAL); +} + +static void input_test_timestamp(struct kunit *test) +{ + const ktime_t invalid_timestamp = ktime_set(0, 0); + struct input_dev *input_dev = test->priv; + ktime_t *timestamp, time; + int ret; + + timestamp = input_get_timestamp(input_dev); + time = timestamp[INPUT_CLK_MONO]; + + ret = ktime_compare(time, invalid_timestamp); + KUNIT_ASSERT_EQ(test, ret, 1); + + time = ktime_get(); + input_set_timestamp(input_dev, time); + + timestamp = input_get_timestamp(input_dev); + KUNIT_ASSERT_EQ(test, ktime_compare(timestamp[INPUT_CLK_MONO], + time), 0); +} + +static void input_test_match_device_id(struct kunit *test) +{ + struct input_dev *input_dev = test->priv; + struct input_device_id id; + + id.flags = INPUT_DEVICE_ID_MATCH_BUS; + id.bustype = BUS_VIRTUAL; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.bustype = BUS_I2C; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_VENDOR; + id.vendor = 1; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.vendor = 2; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_PRODUCT; + id.product = 1; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.product = 2; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_VERSION; + id.version = 1; + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + id.version = 2; + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); + + id.flags = INPUT_DEVICE_ID_MATCH_EVBIT; + __set_bit(EV_KEY, id.evbit); + KUNIT_ASSERT_TRUE(test, input_match_device_id(input_dev, &id)); + + __set_bit(EV_ABS, id.evbit); + KUNIT_ASSERT_FALSE(test, input_match_device_id(input_dev, &id)); +} + +static struct kunit_case input_tests[] = { + KUNIT_CASE(input_test_polling), + KUNIT_CASE(input_test_timestamp), + KUNIT_CASE(input_test_match_device_id), + { /* sentinel */ } +}; + +static struct kunit_suite input_test_suite = { + .name = "input_core", + .init = input_test_init, + .exit = input_test_exit, + .test_cases = input_tests, +}; + +kunit_test_suite(input_test_suite); + +MODULE_AUTHOR("Javier Martinez Canillas <javierm@xxxxxxxxxx>"); +MODULE_LICENSE("GPL"); base-commit: 3a93e40326c8f470e71d20b4c42d36767450f38f -- 2.40.0