xref: /third_party/libevdev/test/test-uinput.c (revision c0abf9e6)
1// SPDX-License-Identifier: MIT
2/*
3 * Copyright © 2013 Red Hat, Inc.
4 */
5
6#include "config.h"
7#include <linux/input.h>
8#include <errno.h>
9#include <unistd.h>
10#include <stdlib.h>
11#include <fcntl.h>
12#include <libevdev/libevdev-uinput.h>
13
14#include "test-common.h"
15#define UINPUT_NODE "/dev/uinput"
16
17START_TEST(test_uinput_create_device)
18{
19	struct libevdev *dev, *dev2;
20	struct libevdev_uinput *uidev;
21	int fd, uinput_fd;
22	unsigned int type, code;
23	int rc;
24	const char *devnode;
25
26	dev = libevdev_new();
27	ck_assert(dev != NULL);
28	libevdev_set_name(dev, TEST_DEVICE_NAME);
29	libevdev_enable_event_type(dev, EV_SYN);
30	libevdev_enable_event_type(dev, EV_REL);
31	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
32	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
33	libevdev_enable_event_code(dev, EV_REL, REL_MAX, NULL);
34
35	rc = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev);
36	ck_assert_int_eq(rc, 0);
37	ck_assert(uidev != NULL);
38
39	uinput_fd = libevdev_uinput_get_fd(uidev);
40	ck_assert_int_gt(uinput_fd, -1);
41
42	devnode = libevdev_uinput_get_devnode(uidev);
43	ck_assert(devnode != NULL);
44
45	fd = open(devnode, O_RDONLY);
46	ck_assert_int_gt(fd, -1);
47	rc = libevdev_new_from_fd(fd, &dev2);
48	ck_assert_int_eq(rc, 0);
49
50	for (type = 0; type < EV_CNT; type++) {
51		int max = libevdev_event_type_get_max(type);
52		if (max == -1)
53			continue;
54
55		for (code = 0; code < (unsigned int)max; code++) {
56			ck_assert_int_eq(libevdev_has_event_code(dev, type, code),
57					 libevdev_has_event_code(dev2, type, code));
58		}
59	}
60
61	libevdev_free(dev);
62	libevdev_free(dev2);
63	libevdev_uinput_destroy(uidev);
64	close(fd);
65
66	/* uinput fd is managed, so make sure it did get closed */
67	ck_assert_int_eq(close(uinput_fd), -1);
68	ck_assert_int_eq(errno, EBADF);
69
70}
71END_TEST
72
73START_TEST(test_uinput_create_device_invalid)
74{
75	struct libevdev *dev;
76	struct libevdev_uinput *uidev = NULL;
77	int rc;
78
79	dev = libevdev_new();
80	ck_assert(dev != NULL);
81	libevdev_set_name(dev, TEST_DEVICE_NAME);
82	libevdev_enable_event_type(dev, EV_SYN);
83	libevdev_enable_event_type(dev, EV_REL);
84	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
85	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
86
87	libevdev_set_log_function(test_logfunc_ignore_error, NULL);
88	rc = libevdev_uinput_create_from_device(dev, -1, &uidev);
89	ck_assert_int_eq(rc, -EBADF);
90	ck_assert(uidev == NULL);
91	libevdev_set_log_function(test_logfunc_abort_on_error, NULL);
92
93	libevdev_free(dev);
94}
95END_TEST
96
97START_TEST(test_uinput_create_device_from_fd)
98{
99	struct libevdev *dev, *dev2;
100	struct libevdev_uinput *uidev;
101	int fd, fd2;
102	unsigned int type, code;
103	int rc;
104	const char *devnode;
105
106	dev = libevdev_new();
107	ck_assert(dev != NULL);
108	libevdev_set_name(dev, TEST_DEVICE_NAME);
109	libevdev_enable_event_type(dev, EV_SYN);
110	libevdev_enable_event_type(dev, EV_REL);
111	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
112	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
113
114	fd = open(UINPUT_NODE, O_RDWR);
115	ck_assert_int_gt(fd, -1);
116
117	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
118	ck_assert_int_eq(rc, 0);
119	ck_assert(uidev != NULL);
120
121	ck_assert_int_eq(libevdev_uinput_get_fd(uidev), fd);
122
123	devnode = libevdev_uinput_get_devnode(uidev);
124	ck_assert(devnode != NULL);
125
126	fd2 = open(devnode, O_RDONLY);
127	ck_assert_int_gt(fd2, -1);
128	rc = libevdev_new_from_fd(fd2, &dev2);
129	ck_assert_int_eq(rc, 0);
130
131	for (type = 0; type < EV_CNT; type++) {
132		int max = libevdev_event_type_get_max(type);
133		if (max == -1)
134			continue;
135
136		for (code = 0; code < (unsigned int)max; code++) {
137			ck_assert_int_eq(libevdev_has_event_code(dev, type, code),
138					 libevdev_has_event_code(dev2, type, code));
139		}
140	}
141
142	libevdev_free(dev);
143	libevdev_free(dev2);
144	libevdev_uinput_destroy(uidev);
145	close(fd);
146	close(fd2);
147}
148END_TEST
149
150#ifdef __FreeBSD__
151START_TEST(test_uinput_check_devnode_bsd)
152{
153	struct libevdev *dev;
154	struct libevdev_uinput *uidev, *uidev2;
155	const char *devnode, *devnode2;
156	int fd, fd2;
157	int rc;
158
159	dev = libevdev_new();
160	ck_assert(dev != NULL);
161	libevdev_set_name(dev, TEST_DEVICE_NAME);
162	libevdev_enable_event_type(dev, EV_SYN);
163	libevdev_enable_event_type(dev, EV_REL);
164	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
165	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
166
167	fd = open(UINPUT_NODE, O_RDWR);
168	ck_assert_int_gt(fd, -1);
169	fd2 = open(UINPUT_NODE, O_RDWR);
170	ck_assert_int_gt(fd2, -1);
171
172	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
173	ck_assert_int_eq(rc, 0);
174
175	/* create a second one */
176	libevdev_set_name(dev, TEST_DEVICE_NAME " 2");
177	rc = libevdev_uinput_create_from_device(dev, fd2, &uidev2);
178	ck_assert_int_eq(rc, 0);
179
180	devnode = libevdev_uinput_get_devnode(uidev);
181	ck_assert(devnode != NULL);
182
183	/* get syspath twice returns same pointer */
184	devnode2 = libevdev_uinput_get_devnode(uidev);
185	ck_assert(devnode == devnode2);
186
187	/* second dev has different devnode */
188	devnode2 = libevdev_uinput_get_devnode(uidev2);
189	ck_assert(strcmp(devnode, devnode2) != 0);
190
191	libevdev_uinput_destroy(uidev2);
192	libevdev_uinput_destroy(uidev);
193
194	close(fd2);
195	close(fd);
196
197	libevdev_free(dev);
198}
199END_TEST
200
201START_TEST(test_uinput_check_syspath_bsd)
202{
203	struct libevdev *dev;
204	struct libevdev_uinput *uidev;
205	const char *syspath;
206	int fd;
207	int rc;
208
209	dev = libevdev_new();
210	ck_assert(dev != NULL);
211	libevdev_set_name(dev, TEST_DEVICE_NAME);
212	libevdev_enable_event_type(dev, EV_SYN);
213	libevdev_enable_event_type(dev, EV_REL);
214	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
215	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
216
217	fd = open(UINPUT_NODE, O_RDWR);
218	ck_assert_int_gt(fd, -1);
219
220	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
221	ck_assert_int_eq(rc, 0);
222
223	syspath = libevdev_uinput_get_syspath(uidev);
224	/* FreeBSD should always return NULL for libevdev_unput_get_syspath() */
225	ck_assert(syspath == NULL);
226
227	libevdev_uinput_destroy(uidev);
228
229	close(fd);
230
231	libevdev_free(dev);
232}
233END_TEST
234
235#else /* !__FreeBSD__ */
236
237START_TEST(test_uinput_check_syspath_time)
238{
239	struct libevdev *dev;
240	struct libevdev_uinput *uidev, *uidev2;
241	const char *syspath, *syspath2;
242	int fd, fd2;
243	int rc;
244
245	dev = libevdev_new();
246	ck_assert(dev != NULL);
247	libevdev_set_name(dev, TEST_DEVICE_NAME);
248	libevdev_enable_event_type(dev, EV_SYN);
249	libevdev_enable_event_type(dev, EV_REL);
250	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
251	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
252
253	fd = open(UINPUT_NODE, O_RDWR);
254	ck_assert_int_gt(fd, -1);
255	fd2 = open(UINPUT_NODE, O_RDWR);
256	ck_assert_int_gt(fd2, -1);
257
258	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
259	ck_assert_int_eq(rc, 0);
260
261	/* sleep for 1.5 seconds. sysfs resolution is 1 second, so
262	   creating both devices without delay means
263	   libevdev_uinput_get_syspath can't actually differ between
264	   them. By waiting, we get different ctime for uidev and uidev2,
265	   and exercise that part of the code.
266	 */
267	usleep(1500000);
268
269	/* create a second one to test the syspath time filtering code */
270	rc = libevdev_uinput_create_from_device(dev, fd2, &uidev2);
271	ck_assert_int_eq(rc, 0);
272
273	syspath = libevdev_uinput_get_syspath(uidev);
274	ck_assert(syspath != NULL);
275
276	/* get syspath twice returns same pointer */
277	syspath2 = libevdev_uinput_get_syspath(uidev);
278	ck_assert(syspath == syspath2);
279
280	/* second dev has different syspath */
281	syspath2 = libevdev_uinput_get_syspath(uidev2);
282	ck_assert(strcmp(syspath, syspath2) != 0);
283
284	libevdev_free(dev);
285	libevdev_uinput_destroy(uidev);
286	libevdev_uinput_destroy(uidev2);
287
288	close(fd);
289	close(fd2);
290}
291END_TEST
292
293START_TEST(test_uinput_check_syspath_name)
294{
295	struct libevdev *dev;
296	struct libevdev_uinput *uidev, *uidev2;
297	const char *syspath, *syspath2;
298	int fd, fd2;
299	int rc;
300
301	dev = libevdev_new();
302	ck_assert(dev != NULL);
303	libevdev_set_name(dev, TEST_DEVICE_NAME);
304	libevdev_enable_event_type(dev, EV_SYN);
305	libevdev_enable_event_type(dev, EV_REL);
306	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
307	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
308
309	fd = open(UINPUT_NODE, O_RDWR);
310	ck_assert_int_gt(fd, -1);
311	fd2 = open(UINPUT_NODE, O_RDWR);
312	ck_assert_int_gt(fd2, -1);
313
314	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
315	ck_assert_int_eq(rc, 0);
316
317	/* create a second one to stress the syspath filtering code */
318	libevdev_set_name(dev, TEST_DEVICE_NAME " 2");
319	rc = libevdev_uinput_create_from_device(dev, fd2, &uidev2);
320	ck_assert_int_eq(rc, 0);
321
322	syspath = libevdev_uinput_get_syspath(uidev);
323	ck_assert(syspath != NULL);
324
325	/* get syspath twice returns same pointer */
326	syspath2 = libevdev_uinput_get_syspath(uidev);
327	ck_assert(syspath == syspath2);
328
329	/* second dev has different syspath */
330	syspath2 = libevdev_uinput_get_syspath(uidev2);
331	ck_assert(strcmp(syspath, syspath2) != 0);
332
333	libevdev_free(dev);
334	libevdev_uinput_destroy(uidev);
335	libevdev_uinput_destroy(uidev2);
336
337	close(fd);
338	close(fd2);
339}
340END_TEST
341
342#endif /* __FreeBSD __ */
343
344START_TEST(test_uinput_events)
345{
346	struct libevdev *dev;
347	struct libevdev_uinput *uidev;
348	int fd, fd2;
349	int rc;
350	const char *devnode;
351	int i;
352	const int nevents = 5;
353	struct input_event events[] = { {{0, 0}, EV_REL, REL_X, 1},
354					{{0, 0}, EV_REL, REL_Y, -1},
355					{{0, 0}, EV_SYN, SYN_REPORT, 0},
356					{{0, 0}, EV_KEY, BTN_LEFT, 1},
357					{{0, 0}, EV_SYN, SYN_REPORT, 0}};
358	struct input_event events_read[nevents];
359
360	dev = libevdev_new();
361	ck_assert(dev != NULL);
362	libevdev_set_name(dev, TEST_DEVICE_NAME);
363	libevdev_enable_event_type(dev, EV_SYN);
364	libevdev_enable_event_type(dev, EV_REL);
365	libevdev_enable_event_type(dev, EV_KEY);
366	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
367	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
368	libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL);
369
370	fd = open(UINPUT_NODE, O_RDWR);
371	ck_assert_int_gt(fd, -1);
372
373	rc = libevdev_uinput_create_from_device(dev, fd, &uidev);
374	ck_assert_int_eq(rc, 0);
375	ck_assert(uidev != NULL);
376
377	devnode = libevdev_uinput_get_devnode(uidev);
378	ck_assert(devnode != NULL);
379
380	fd2 = open(devnode, O_RDONLY);
381
382	for (i = 0; i < nevents; i++)
383		libevdev_uinput_write_event(uidev, events[i].type, events[i].code, events[i].value);
384
385	rc = read(fd2, events_read, sizeof(events_read));
386	ck_assert_int_eq(rc, sizeof(events_read));
387
388	for (i = 0; i < nevents; i++) {
389		ck_assert_int_eq(events[i].type, events_read[i].type);
390		ck_assert_int_eq(events[i].code, events_read[i].code);
391		ck_assert_int_eq(events[i].value, events_read[i].value);
392	}
393
394	libevdev_free(dev);
395	libevdev_uinput_destroy(uidev);
396	close(fd);
397	close(fd2);
398}
399END_TEST
400
401START_TEST(test_uinput_properties)
402{
403	struct libevdev *dev, *dev2;
404	struct libevdev_uinput *uidev;
405	int fd;
406	int rc;
407	const char *devnode;
408
409	dev = libevdev_new();
410	ck_assert(dev != NULL);
411	libevdev_set_name(dev, TEST_DEVICE_NAME);
412	libevdev_enable_event_type(dev, EV_SYN);
413	libevdev_enable_event_type(dev, EV_REL);
414	libevdev_enable_event_type(dev, EV_KEY);
415	libevdev_enable_event_code(dev, EV_REL, REL_X, NULL);
416	libevdev_enable_event_code(dev, EV_REL, REL_Y, NULL);
417	libevdev_enable_event_code(dev, EV_KEY, BTN_LEFT, NULL);
418	libevdev_enable_property(dev, INPUT_PROP_BUTTONPAD);
419	libevdev_enable_property(dev, INPUT_PROP_MAX);
420
421	rc = libevdev_uinput_create_from_device(dev, LIBEVDEV_UINPUT_OPEN_MANAGED, &uidev);
422	ck_assert_int_eq(rc, 0);
423	ck_assert(uidev != NULL);
424
425	devnode = libevdev_uinput_get_devnode(uidev);
426	ck_assert(devnode != NULL);
427
428	fd = open(devnode, O_RDONLY);
429	ck_assert_int_gt(fd, -1);
430	rc = libevdev_new_from_fd(fd, &dev2);
431	ck_assert_int_eq(rc, 0);
432
433	ck_assert(libevdev_has_property(dev2, INPUT_PROP_BUTTONPAD));
434	ck_assert(libevdev_has_property(dev2, INPUT_PROP_MAX));
435
436	libevdev_free(dev);
437	libevdev_free(dev2);
438	libevdev_uinput_destroy(uidev);
439	close(fd);
440}
441END_TEST
442
443TEST_SUITE_ROOT_PRIVILEGES(uinput_suite)
444{
445	Suite *s = suite_create("libevdev uinput device tests");
446
447	add_test(s, test_uinput_create_device);
448	add_test(s, test_uinput_create_device_invalid);
449	add_test(s, test_uinput_create_device_from_fd);
450#ifdef __FreeBSD__
451	add_test(s, test_uinput_check_devnode_bsd);
452	add_test(s, test_uinput_check_syspath_bsd);
453#else
454	add_test(s, test_uinput_check_syspath_time);
455	add_test(s, test_uinput_check_syspath_name);
456#endif
457
458	add_test(s, test_uinput_events);
459
460	add_test(s, test_uinput_properties);
461
462	return s;
463}
464