Input: Add KUnit tests for some of the input core helper functions
authorJavier Martinez Canillas <javierm@redhat.com>
Sun, 2 Apr 2023 05:45:09 +0000 (22:45 -0700)
committerDmitry Torokhov <dmitry.torokhov@gmail.com>
Sun, 2 Apr 2023 05:47:04 +0000 (22:47 -0700)
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,
                                version and events 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/

Signed-off-by: Javier Martinez Canillas <javierm@redhat.com>
Tested-by: Enric Balletbo i Serra <eballetbo@redhat.com>
config: powerpc-allnoconfig (https://download.01.org/0day-ci/archive/20230330/202303301815.kRKFM3NH-lkp@intel.com/config)
Link: https://lore.kernel.org/r/20230330081831.2291351-1-javierm@redhat.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
drivers/input/Kconfig
drivers/input/Makefile
drivers/input/tests/.kunitconfig [new file with mode: 0644]
drivers/input/tests/Makefile [new file with mode: 0644]
drivers/input/tests/input_test.c [new file with mode: 0644]

index e2752f7364bcfe8e687710926846fe175d86e4da..735f90b74ee5ad44b34e85ad9c7888ec2b6c3261 100644 (file)
@@ -166,6 +166,16 @@ 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.
+
+         If in doubt, say "N".
+
 config INPUT_APMPOWER
        tristate "Input Power Event -> APM Bridge" if EXPERT
        depends on INPUT && APM_EMULATION
index 2266c7d010efca94d348881dcb40233422508e51..c787532749214cc1fee3b4f9a6ddb713143e71cf 100644 (file)
@@ -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/.kunitconfig b/drivers/input/tests/.kunitconfig
new file mode 100644 (file)
index 0000000..2f5bedf
--- /dev/null
@@ -0,0 +1,3 @@
+CONFIG_KUNIT=y
+CONFIG_INPUT=y
+CONFIG_INPUT_KUNIT_TEST=y
diff --git a/drivers/input/tests/Makefile b/drivers/input/tests/Makefile
new file mode 100644 (file)
index 0000000..90cf954
--- /dev/null
@@ -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 (file)
index 0000000..e5a6c1a
--- /dev/null
@@ -0,0 +1,150 @@
+// 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);
+       if (ret) {
+               input_free_device(input_dev);
+               KUNIT_ASSERT_FAILURE(test, "Register device failed: %d", ret);
+       }
+
+       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);
+       input_free_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;
+
+       /* Must fail because a poll handler has not been set-up yet */
+       KUNIT_ASSERT_EQ(test, input_get_poll_interval(input_dev), -EINVAL);
+
+       KUNIT_ASSERT_EQ(test, input_setup_polling(input_dev, input_test_poll), 0);
+
+       input_set_poll_interval(input_dev, POLL_INTERVAL);
+
+       /* Must succeed because poll handler was set-up and poll interval set */
+       KUNIT_ASSERT_EQ(test, input_get_poll_interval(input_dev), 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;
+
+       timestamp = input_get_timestamp(input_dev);
+       time = timestamp[INPUT_CLK_MONO];
+
+       /* The returned timestamp must always be valid */
+       KUNIT_ASSERT_EQ(test, ktime_compare(time, invalid_timestamp), 1);
+
+       time = ktime_get();
+       input_set_timestamp(input_dev, time);
+
+       timestamp = input_get_timestamp(input_dev);
+       /* The timestamp must be the same than set before */
+       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;
+
+       /*
+        * Must match when the input device bus, vendor, product, version
+        * and events capable of handling are the same and fail to match
+        * otherwise.
+        */
+       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@redhat.com>");
+MODULE_LICENSE("GPL");