Commit fdefcbdd authored by Javier Martinez Canillas's avatar Javier Martinez Canillas Committed by Dmitry Torokhov
Browse files

Input: Add KUnit tests for some of the input core helper functions



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: default avatarJavier Martinez Canillas <javierm@redhat.com>
Tested-by: default avatarEnric 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: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 57d94d15
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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

+3 −0
Original line number Diff line number Diff line
CONFIG_KUNIT=y
CONFIG_INPUT=y
CONFIG_INPUT_KUNIT_TEST=y
+3 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0

obj-$(CONFIG_INPUT_KUNIT_TEST) += input_test.o
+150 −0
Original line number Diff line number Diff line
// 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");