Re: [PATCH] Input: Add KUnit tests for some of the input core helper functions

From: Enric Balletbo i Serra
Date: Wed Mar 29 2023 - 17:02:52 EST


Hi Javier,

Many thanks for the patch and to work on this.


On Wed, Mar 29, 2023 at 11:23 AM Javier Martinez Canillas
<javierm@xxxxxxxxxx> wrote:
>
> 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>

I'll let other more experienced people comment on the kunit tests. In
my opinion it's a starting point and after applying your patch and
giving a try I can confirm that it works as expected, so just wanted
to give my.

Tested-by: Enric Balletbo i Serra <eballetbo@xxxxxxxxxx>

Thanks,
Enric

> ---
>
> 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
>