Skip to content

Commit

Permalink
Input: Add KUnit tests for some of the input core helper functions
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
martinezjavier authored and intel-lab-lkp committed Mar 30, 2023
1 parent 3a93e40 commit c0455fa
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 0 deletions.
10 changes: 10 additions & 0 deletions drivers/input/Kconfig
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions drivers/input/Makefile
Expand Up @@ -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

Expand Down
3 changes: 3 additions & 0 deletions drivers/input/tests/.kunitconfig
@@ -0,0 +1,3 @@
CONFIG_KUNIT=y
CONFIG_INPUT=y
CONFIG_INPUT_KUNIT_TEST=y
3 changes: 3 additions & 0 deletions drivers/input/tests/Makefile
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0

obj-$(CONFIG_INPUT_KUNIT_TEST) += input_test.o
150 changes: 150 additions & 0 deletions drivers/input/tests/input_test.c
@@ -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");

0 comments on commit c0455fa

Please sign in to comment.