| // 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_FAIL_AND_ABORT(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; | |
| if (input_dev) | |
| 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; | |
| /* 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 = { 0 }; | |
| /* | |
| * 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 void input_test_grab(struct kunit *test) | |
| { | |
| struct input_dev *input_dev = test->priv; | |
| struct input_handle test_handle; | |
| struct input_handler handler; | |
| struct input_handle handle; | |
| struct input_device_id id; | |
| int res; | |
| handler.name = "handler"; | |
| handler.id_table = &id; | |
| handle.dev = input_get_device(input_dev); | |
| handle.name = dev_name(&input_dev->dev); | |
| handle.handler = &handler; | |
| res = input_grab_device(&handle); | |
| KUNIT_ASSERT_TRUE(test, res == 0); | |
| test_handle.dev = input_get_device(input_dev); | |
| test_handle.name = dev_name(&input_dev->dev); | |
| test_handle.handler = &handler; | |
| res = input_grab_device(&test_handle); | |
| KUNIT_ASSERT_EQ(test, res, -EBUSY); | |
| input_release_device(&handle); | |
| input_put_device(input_dev); | |
| res = input_grab_device(&test_handle); | |
| KUNIT_ASSERT_TRUE(test, res == 0); | |
| input_put_device(input_dev); | |
| } | |
| static struct kunit_case input_tests[] = { | |
| KUNIT_CASE(input_test_polling), | |
| KUNIT_CASE(input_test_timestamp), | |
| KUNIT_CASE(input_test_match_device_id), | |
| KUNIT_CASE(input_test_grab), | |
| { /* 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_DESCRIPTION("KUnit test for the input core"); | |
| MODULE_LICENSE("GPL"); |