• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2018 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 #include <config.h>
25 
26 #include <check.h>
27 #include <libinput.h>
28 
29 #include "libinput-util.h"
30 #include "litest.h"
31 #include "quirks.h"
32 
33 static void
log_handler(struct libinput * this_is_null,enum libinput_log_priority priority,const char * format,va_list args)34 log_handler(struct libinput *this_is_null,
35 	    enum libinput_log_priority priority,
36 	    const char *format,
37 	    va_list args)
38 {
39 #if 0
40 	vprintf(format, args);
41 #endif
42 }
43 
44 struct data_dir {
45 	char *dirname;
46 	char *filename;
47 };
48 
49 static struct data_dir
make_data_dir(const char * file_content)50 make_data_dir(const char *file_content)
51 {
52 	struct data_dir dir = {0};
53 	char dirname[PATH_MAX] = "/tmp/litest-quirk-test-XXXXXX";
54 	char *filename;
55 	FILE *fp;
56 	int rc;
57 
58 	litest_assert_notnull(mkdtemp(dirname));
59 	dir.dirname = safe_strdup(dirname);
60 
61 	if (file_content) {
62 		rc = xasprintf(&filename, "%s/testfile.quirks", dirname);
63 		litest_assert_int_eq(rc, (int)(strlen(dirname) + 16));
64 
65 		fp = fopen(filename, "w+");
66 		litest_assert_notnull(fp);
67 		rc = fputs(file_content, fp);
68 		fclose(fp);
69 		litest_assert_int_ge(rc, 0);
70 		dir.filename = filename;
71 	}
72 
73 	return dir;
74 }
75 
76 static void
cleanup_data_dir(struct data_dir dd)77 cleanup_data_dir(struct data_dir dd)
78 {
79 	if (dd.filename) {
80 		unlink(dd.filename);
81 		free(dd.filename);
82 	}
83 	if (dd.dirname) {
84 		rmdir(dd.dirname);
85 		free(dd.dirname);
86 	}
87 }
88 
START_TEST(quirks_invalid_dir)89 START_TEST(quirks_invalid_dir)
90 {
91 	struct quirks_context *ctx;
92 
93 	ctx = quirks_init_subsystem("/does-not-exist",
94 				    NULL,
95 				    log_handler,
96 				    NULL,
97 				    QLOG_LIBINPUT_LOGGING);
98 	ck_assert(ctx == NULL);
99 }
100 END_TEST
101 
START_TEST(quirks_empty_dir)102 START_TEST(quirks_empty_dir)
103 {
104 	struct quirks_context *ctx;
105 	struct data_dir dd = make_data_dir(NULL);
106 
107 	ctx = quirks_init_subsystem(dd.dirname,
108 				    NULL,
109 				    log_handler,
110 				    NULL,
111 				    QLOG_LIBINPUT_LOGGING);
112 	ck_assert(ctx == NULL);
113 
114 	cleanup_data_dir(dd);
115 }
116 END_TEST
117 
START_TEST(quirks_section_empty)118 START_TEST(quirks_section_empty)
119 {
120 	struct quirks_context *ctx;
121 	const char quirks_file[] = "[Empty Section]";
122 	struct data_dir dd = make_data_dir(quirks_file);
123 
124 	ctx = quirks_init_subsystem(dd.dirname,
125 				    NULL,
126 				    log_handler,
127 				    NULL,
128 				    QLOG_CUSTOM_LOG_PRIORITIES);
129 	ck_assert(ctx == NULL);
130 	cleanup_data_dir(dd);
131 }
132 END_TEST
133 
START_TEST(quirks_section_double)134 START_TEST(quirks_section_double)
135 {
136 	struct quirks_context *ctx;
137 	const char quirks_file[] = "[Section name]";
138 	struct data_dir dd = make_data_dir(quirks_file);
139 
140 	ctx = quirks_init_subsystem(dd.dirname,
141 				    NULL,
142 				    log_handler,
143 				    NULL,
144 				    QLOG_CUSTOM_LOG_PRIORITIES);
145 	ck_assert(ctx == NULL);
146 	cleanup_data_dir(dd);
147 }
148 END_TEST
149 
START_TEST(quirks_section_missing_match)150 START_TEST(quirks_section_missing_match)
151 {
152 	struct quirks_context *ctx;
153 	const char quirks_file[] =
154 	"[Section name]\n"
155 	"AttrSizeHint=10x10\n";
156 	struct data_dir dd = make_data_dir(quirks_file);
157 
158 	ctx = quirks_init_subsystem(dd.dirname,
159 				    NULL,
160 				    log_handler,
161 				    NULL,
162 				    QLOG_CUSTOM_LOG_PRIORITIES);
163 	ck_assert(ctx == NULL);
164 	cleanup_data_dir(dd);
165 }
166 END_TEST
167 
START_TEST(quirks_section_missing_attr)168 START_TEST(quirks_section_missing_attr)
169 {
170 	struct quirks_context *ctx;
171 	const char quirks_file[] =
172 	"[Section name]\n"
173 	"MatchUdevType=mouse\n";
174 	struct data_dir dd = make_data_dir(quirks_file);
175 
176 	ctx = quirks_init_subsystem(dd.dirname,
177 				    NULL,
178 				    log_handler,
179 				    NULL,
180 				    QLOG_CUSTOM_LOG_PRIORITIES);
181 	ck_assert(ctx == NULL);
182 	cleanup_data_dir(dd);
183 }
184 END_TEST
185 
START_TEST(quirks_section_match_after_attr)186 START_TEST(quirks_section_match_after_attr)
187 {
188 	struct quirks_context *ctx;
189 	const char quirks_file[] =
190 	"[Section name]\n"
191 	"MatchUdevType=mouse\n"
192 	"AttrSizeHint=10x10\n"
193 	"MatchName=mouse\n";
194 	struct data_dir dd = make_data_dir(quirks_file);
195 
196 	ctx = quirks_init_subsystem(dd.dirname,
197 				    NULL,
198 				    log_handler,
199 				    NULL,
200 				    QLOG_CUSTOM_LOG_PRIORITIES);
201 	ck_assert(ctx == NULL);
202 	cleanup_data_dir(dd);
203 }
204 END_TEST
205 
START_TEST(quirks_section_duplicate_match)206 START_TEST(quirks_section_duplicate_match)
207 {
208 	struct quirks_context *ctx;
209 	const char quirks_file[] =
210 	"[Section name]\n"
211 	"MatchUdevType=mouse\n"
212 	"MatchUdevType=mouse\n"
213 	"AttrSizeHint=10x10\n";
214 	struct data_dir dd = make_data_dir(quirks_file);
215 
216 	ctx = quirks_init_subsystem(dd.dirname,
217 				    NULL,
218 				    log_handler,
219 				    NULL,
220 				    QLOG_CUSTOM_LOG_PRIORITIES);
221 	ck_assert(ctx == NULL);
222 	cleanup_data_dir(dd);
223 }
224 END_TEST
225 
START_TEST(quirks_section_duplicate_attr)226 START_TEST(quirks_section_duplicate_attr)
227 {
228 	/* This shouldn't be allowed but the current parser
229 	   is happy with it */
230 	struct quirks_context *ctx;
231 	const char quirks_file[] =
232 	"[Section name]\n"
233 	"MatchUdevType=mouse\n"
234 	"AttrSizeHint=10x10\n"
235 	"AttrSizeHint=10x10\n";
236 	struct data_dir dd = make_data_dir(quirks_file);
237 
238 	ctx = quirks_init_subsystem(dd.dirname,
239 				    NULL,
240 				    log_handler,
241 				    NULL,
242 				    QLOG_CUSTOM_LOG_PRIORITIES);
243 	ck_assert_notnull(ctx);
244 	quirks_context_unref(ctx);
245 	cleanup_data_dir(dd);
246 }
247 END_TEST
248 
START_TEST(quirks_parse_error_section)249 START_TEST(quirks_parse_error_section)
250 {
251 	struct quirks_context *ctx;
252 	const char quirks_file[] =
253 	"[Section Missing Bracket\n"
254 	"MatchUdevType=mouse\n"
255 	"AttrSizeHint=10x10\n";
256 	struct data_dir dd = make_data_dir(quirks_file);
257 
258 	ctx = quirks_init_subsystem(dd.dirname,
259 				    NULL,
260 				    log_handler,
261 				    NULL,
262 				    QLOG_CUSTOM_LOG_PRIORITIES);
263 	ck_assert(ctx == NULL);
264 	cleanup_data_dir(dd);
265 }
266 END_TEST
267 
START_TEST(quirks_parse_error_trailing_whitespace)268 START_TEST(quirks_parse_error_trailing_whitespace)
269 {
270 	struct quirks_context *ctx;
271 	const char quirks_file[] =
272 	"[Section name]\n"
273 	"MatchUdevType=mouse    \n"
274 	"AttrSizeHint=10x10\n";
275 	struct data_dir dd = make_data_dir(quirks_file);
276 
277 	ctx = quirks_init_subsystem(dd.dirname,
278 				    NULL,
279 				    log_handler,
280 				    NULL,
281 				    QLOG_CUSTOM_LOG_PRIORITIES);
282 	ck_assert(ctx == NULL);
283 	cleanup_data_dir(dd);
284 }
285 END_TEST
286 
START_TEST(quirks_parse_error_unknown_match)287 START_TEST(quirks_parse_error_unknown_match)
288 {
289 	struct quirks_context *ctx;
290 	const char quirks_file[] =
291 	"[Section name]\n"
292 	"Matchblahblah=mouse\n"
293 	"AttrSizeHint=10x10\n";
294 	struct data_dir dd = make_data_dir(quirks_file);
295 
296 	ctx = quirks_init_subsystem(dd.dirname,
297 				    NULL,
298 				    log_handler,
299 				    NULL,
300 				    QLOG_CUSTOM_LOG_PRIORITIES);
301 	ck_assert(ctx == NULL);
302 	cleanup_data_dir(dd);
303 }
304 END_TEST
305 
START_TEST(quirks_parse_error_unknown_attr)306 START_TEST(quirks_parse_error_unknown_attr)
307 {
308 	struct quirks_context *ctx;
309 	const char quirks_file[] =
310 	"[Section name]\n"
311 	"MatchUdevType=mouse\n"
312 	"Attrblahblah=10x10\n";
313 	struct data_dir dd = make_data_dir(quirks_file);
314 
315 	ctx = quirks_init_subsystem(dd.dirname,
316 				    NULL,
317 				    log_handler,
318 				    NULL,
319 				    QLOG_CUSTOM_LOG_PRIORITIES);
320 	ck_assert(ctx == NULL);
321 	cleanup_data_dir(dd);
322 }
323 END_TEST
324 
START_TEST(quirks_parse_error_unknown_model)325 START_TEST(quirks_parse_error_unknown_model)
326 {
327 	struct quirks_context *ctx;
328 	const char quirks_file[] =
329 	"[Section name]\n"
330 	"MatchUdevType=mouse\n"
331 	"Modelblahblah=1\n";
332 	struct data_dir dd = make_data_dir(quirks_file);
333 
334 	ctx = quirks_init_subsystem(dd.dirname,
335 				    NULL,
336 				    log_handler,
337 				    NULL,
338 				    QLOG_CUSTOM_LOG_PRIORITIES);
339 	ck_assert(ctx == NULL);
340 	cleanup_data_dir(dd);
341 }
342 END_TEST
343 
START_TEST(quirks_parse_error_unknown_prefix)344 START_TEST(quirks_parse_error_unknown_prefix)
345 {
346 	struct quirks_context *ctx;
347 	const char quirks_file[] =
348 	"[Section name]\n"
349 	"MatchUdevType=mouse\n"
350 	"Fooblahblah=10x10\n";
351 	struct data_dir dd = make_data_dir(quirks_file);
352 
353 	ctx = quirks_init_subsystem(dd.dirname,
354 				    NULL,
355 				    log_handler,
356 				    NULL,
357 				    QLOG_CUSTOM_LOG_PRIORITIES);
358 	ck_assert(ctx == NULL);
359 	cleanup_data_dir(dd);
360 }
361 END_TEST
362 
START_TEST(quirks_parse_error_model_not_one)363 START_TEST(quirks_parse_error_model_not_one)
364 {
365 	struct quirks_context *ctx;
366 	const char quirks_file[] =
367 	"[Section name]\n"
368 	"MatchUdevType=mouse\n"
369 	"ModelAppleTouchpad=true\n";
370 	struct data_dir dd = make_data_dir(quirks_file);
371 
372 	ctx = quirks_init_subsystem(dd.dirname,
373 				    NULL,
374 				    log_handler,
375 				    NULL,
376 				    QLOG_CUSTOM_LOG_PRIORITIES);
377 	ck_assert(ctx == NULL);
378 	cleanup_data_dir(dd);
379 }
380 END_TEST
381 
START_TEST(quirks_parse_comment_inline)382 START_TEST(quirks_parse_comment_inline)
383 {
384 	struct quirks_context *ctx;
385 	const char quirks_file[] =
386 	"[Section name] # some inline comment\n"
387 	"MatchUdevType=mouse\t   # another inline comment\n"
388 	"ModelAppleTouchpad=1#\n";
389 	struct data_dir dd = make_data_dir(quirks_file);
390 
391 	ctx = quirks_init_subsystem(dd.dirname,
392 				    NULL,
393 				    log_handler,
394 				    NULL,
395 				    QLOG_CUSTOM_LOG_PRIORITIES);
396 	ck_assert_notnull(ctx);
397 	quirks_context_unref(ctx);
398 	cleanup_data_dir(dd);
399 }
400 END_TEST
401 
START_TEST(quirks_parse_comment_empty)402 START_TEST(quirks_parse_comment_empty)
403 {
404 	struct quirks_context *ctx;
405 	const char quirks_file[] =
406 	"[Section name]\n"
407 	"#\n"
408 	"   #\n"
409 	"MatchUdevType=mouse\n"
410 	"ModelAppleTouchpad=1\n";
411 	struct data_dir dd = make_data_dir(quirks_file);
412 
413 	ctx = quirks_init_subsystem(dd.dirname,
414 				    NULL,
415 				    log_handler,
416 				    NULL,
417 				    QLOG_CUSTOM_LOG_PRIORITIES);
418 	ck_assert_notnull(ctx);
419 	quirks_context_unref(ctx);
420 	cleanup_data_dir(dd);
421 }
422 END_TEST
423 
START_TEST(quirks_parse_string_quotes_single)424 START_TEST(quirks_parse_string_quotes_single)
425 {
426 	struct quirks_context *ctx;
427 	const char quirks_file[] =
428 	"[Section name]\n"
429 	"MatchUdevType=mouse\n"
430 	"AttrKeyboardIntegration='internal'\n";
431 	struct data_dir dd = make_data_dir(quirks_file);
432 
433 	ctx = quirks_init_subsystem(dd.dirname,
434 				    NULL,
435 				    log_handler,
436 				    NULL,
437 				    QLOG_CUSTOM_LOG_PRIORITIES);
438 	ck_assert(ctx == NULL);
439 	quirks_context_unref(ctx);
440 	cleanup_data_dir(dd);
441 }
442 END_TEST
443 
START_TEST(quirks_parse_string_quotes_double)444 START_TEST(quirks_parse_string_quotes_double)
445 {
446 	struct quirks_context *ctx;
447 	const char quirks_file[] =
448 	"[Section name]\n"
449 	"MatchUdevType=mouse\n"
450 	"AttrKeyboardIntegration=\"internal\"\n";
451 	struct data_dir dd = make_data_dir(quirks_file);
452 
453 	ctx = quirks_init_subsystem(dd.dirname,
454 				    NULL,
455 				    log_handler,
456 				    NULL,
457 				    QLOG_CUSTOM_LOG_PRIORITIES);
458 	ck_assert(ctx == NULL);
459 	quirks_context_unref(ctx);
460 	cleanup_data_dir(dd);
461 }
462 END_TEST
463 
START_TEST(quirks_parse_bustype)464 START_TEST(quirks_parse_bustype)
465 {
466 	struct quirks_context *ctx;
467 	const char quirks_file[] =
468 	"[Section name]\n"
469 	"MatchBus=usb\n"
470 	"ModelAppleTouchpad=1\n"
471 	"\n"
472 	"[Section name]\n"
473 	"MatchBus=bluetooth\n"
474 	"ModelAppleTouchpad=1\n"
475 	"\n"
476 	"[Section name]\n"
477 	"MatchBus=i2c\n"
478 	"ModelAppleTouchpad=1\n"
479 	"\n"
480 	"[Section name]\n"
481 	"MatchBus=rmi\n"
482 	"ModelAppleTouchpad=1\n"
483 	"\n"
484 	"[Section name]\n"
485 	"MatchBus=ps2\n"
486 	"ModelAppleTouchpad=1\n";
487 	struct data_dir dd = make_data_dir(quirks_file);
488 
489 	ctx = quirks_init_subsystem(dd.dirname,
490 				    NULL,
491 				    log_handler,
492 				    NULL,
493 				    QLOG_CUSTOM_LOG_PRIORITIES);
494 	ck_assert_notnull(ctx);
495 	quirks_context_unref(ctx);
496 	cleanup_data_dir(dd);
497 }
498 END_TEST
499 
START_TEST(quirks_parse_bustype_invalid)500 START_TEST(quirks_parse_bustype_invalid)
501 {
502 	struct quirks_context *ctx;
503 	const char quirks_file[] =
504 	"[Section name]\n"
505 	"MatchBus=venga\n"
506 	"ModelAppleTouchpad=1\n";
507 	struct data_dir dd = make_data_dir(quirks_file);
508 
509 	ctx = quirks_init_subsystem(dd.dirname,
510 				    NULL,
511 				    log_handler,
512 				    NULL,
513 				    QLOG_CUSTOM_LOG_PRIORITIES);
514 	ck_assert(ctx == NULL);
515 	cleanup_data_dir(dd);
516 }
517 END_TEST
518 
START_TEST(quirks_parse_vendor)519 START_TEST(quirks_parse_vendor)
520 {
521 	struct quirks_context *ctx;
522 	const char quirks_file[] =
523 	"[Section name]\n"
524 	"MatchVendor=0x0000\n"
525 	"ModelAppleTouchpad=1\n"
526 	"\n"
527 	"[Section name]\n"
528 	"MatchVendor=0x0001\n"
529 	"ModelAppleTouchpad=1\n"
530 	"\n"
531 	"[Section name]\n"
532 	"MatchVendor=0x2343\n"
533 	"ModelAppleTouchpad=1\n";
534 	struct data_dir dd = make_data_dir(quirks_file);
535 
536 	ctx = quirks_init_subsystem(dd.dirname,
537 				    NULL,
538 				    log_handler,
539 				    NULL,
540 				    QLOG_CUSTOM_LOG_PRIORITIES);
541 	ck_assert_notnull(ctx);
542 	quirks_context_unref(ctx);
543 	cleanup_data_dir(dd);
544 }
545 END_TEST
546 
START_TEST(quirks_parse_vendor_invalid)547 START_TEST(quirks_parse_vendor_invalid)
548 {
549 	struct quirks_context *ctx;
550 	const char *quirks_file[] = {
551 	"[Section name]\n"
552 	"MatchVendor=-1\n"
553 	"ModelAppleTouchpad=1\n",
554 	"[Section name]\n"
555 	"MatchVendor=abc\n"
556 	"ModelAppleTouchpad=1\n",
557 	"[Section name]\n"
558 	"MatchVendor=0xFFFFF\n"
559 	"ModelAppleTouchpad=1\n",
560 	"[Section name]\n"
561 	"MatchVendor=123\n"
562 	"ModelAppleTouchpad=1\n",
563 	};
564 	const char **qf;
565 
566 	ARRAY_FOR_EACH(quirks_file, qf) {
567 		struct data_dir dd = make_data_dir(*qf);
568 
569 		ctx = quirks_init_subsystem(dd.dirname,
570 					    NULL,
571 					    log_handler,
572 					    NULL,
573 					    QLOG_CUSTOM_LOG_PRIORITIES);
574 		ck_assert(ctx == NULL);
575 		cleanup_data_dir(dd);
576 	}
577 }
578 END_TEST
579 
START_TEST(quirks_parse_product)580 START_TEST(quirks_parse_product)
581 {
582 	struct quirks_context *ctx;
583 	const char quirks_file[] =
584 	"[Section name]\n"
585 	"MatchProduct=0x0000\n"
586 	"ModelAppleTouchpad=1\n"
587 	"\n"
588 	"[Section name]\n"
589 	"MatchProduct=0x0001\n"
590 	"ModelAppleTouchpad=1\n"
591 	"\n"
592 	"[Section name]\n"
593 	"MatchProduct=0x2343\n"
594 	"ModelAppleTouchpad=1\n";
595 	struct data_dir dd = make_data_dir(quirks_file);
596 
597 	ctx = quirks_init_subsystem(dd.dirname,
598 				    NULL,
599 				    log_handler,
600 				    NULL,
601 				    QLOG_CUSTOM_LOG_PRIORITIES);
602 	ck_assert_notnull(ctx);
603 	quirks_context_unref(ctx);
604 	cleanup_data_dir(dd);
605 }
606 END_TEST
607 
START_TEST(quirks_parse_product_invalid)608 START_TEST(quirks_parse_product_invalid)
609 {
610 	struct quirks_context *ctx;
611 	const char *quirks_file[] = {
612 	"[Section name]\n"
613 	"MatchProduct=-1\n"
614 	"ModelAppleTouchpad=1\n",
615 	"[Section name]\n"
616 	"MatchProduct=abc\n"
617 	"ModelAppleTouchpad=1\n",
618 	"[Section name]\n"
619 	"MatchProduct=0xFFFFF\n"
620 	"ModelAppleTouchpad=1\n",
621 	"[Section name]\n"
622 	"MatchProduct=123\n"
623 	"ModelAppleTouchpad=1\n",
624 	};
625 	const char **qf;
626 
627 	ARRAY_FOR_EACH(quirks_file, qf) {
628 		struct data_dir dd = make_data_dir(*qf);
629 
630 		ctx = quirks_init_subsystem(dd.dirname,
631 					    NULL,
632 					    log_handler,
633 					    NULL,
634 					    QLOG_CUSTOM_LOG_PRIORITIES);
635 		ck_assert(ctx == NULL);
636 		cleanup_data_dir(dd);
637 	}
638 }
639 END_TEST
640 
START_TEST(quirks_parse_version)641 START_TEST(quirks_parse_version)
642 {
643 	struct quirks_context *ctx;
644 	const char quirks_file[] =
645 	"[Section name]\n"
646 	"MatchVersion=0x0000\n"
647 	"ModelAppleTouchpad=1\n"
648 	"\n"
649 	"[Section name]\n"
650 	"MatchVersion=0x0001\n"
651 	"ModelAppleTouchpad=1\n"
652 	"\n"
653 	"[Section name]\n"
654 	"MatchVersion=0x2343\n"
655 	"ModelAppleTouchpad=1\n";
656 	struct data_dir dd = make_data_dir(quirks_file);
657 
658 	ctx = quirks_init_subsystem(dd.dirname,
659 				    NULL,
660 				    log_handler,
661 				    NULL,
662 				    QLOG_CUSTOM_LOG_PRIORITIES);
663 	ck_assert_notnull(ctx);
664 	quirks_context_unref(ctx);
665 	cleanup_data_dir(dd);
666 }
667 END_TEST
668 
START_TEST(quirks_parse_version_invalid)669 START_TEST(quirks_parse_version_invalid)
670 {
671 	struct quirks_context *ctx;
672 	const char *quirks_file[] = {
673 	"[Section name]\n"
674 	"MatchVersion=-1\n"
675 	"ModelAppleTouchpad=1\n",
676 	"[Section name]\n"
677 	"MatchVersion=abc\n"
678 	"ModelAppleTouchpad=1\n",
679 	"[Section name]\n"
680 	"MatchVersion=0xFFFFF\n"
681 	"ModelAppleTouchpad=1\n",
682 	"[Section name]\n"
683 	"MatchVersion=123\n"
684 	"ModelAppleTouchpad=1\n",
685 	};
686 	const char **qf;
687 
688 	ARRAY_FOR_EACH(quirks_file, qf) {
689 		struct data_dir dd = make_data_dir(*qf);
690 
691 		ctx = quirks_init_subsystem(dd.dirname,
692 					    NULL,
693 					    log_handler,
694 					    NULL,
695 					    QLOG_CUSTOM_LOG_PRIORITIES);
696 		ck_assert(ctx == NULL);
697 		cleanup_data_dir(dd);
698 	}
699 }
700 END_TEST
701 
START_TEST(quirks_parse_name)702 START_TEST(quirks_parse_name)
703 {
704 	struct quirks_context *ctx;
705 	const char quirks_file[] =
706 	"[Section name]\n"
707 	"MatchName=1235\n"
708 	"ModelAppleTouchpad=1\n"
709 	"\n"
710 	"[Section name]\n"
711 	"MatchName=abc\n"
712 	"ModelAppleTouchpad=1\n"
713 	"\n"
714 	"[Section name]\n"
715 	"MatchName=*foo\n"
716 	"ModelAppleTouchpad=1\n"
717 	"\n"
718 	"[Section name]\n"
719 	"MatchName=foo*\n"
720 	"ModelAppleTouchpad=1\n"
721 	"\n"
722 	"[Section name]\n"
723 	"MatchName=foo[]\n"
724 	"ModelAppleTouchpad=1\n"
725 	"\n"
726 	"[Section name]\n"
727 	"MatchName=*foo*\n"
728 	"ModelAppleTouchpad=1\n";
729 	struct data_dir dd = make_data_dir(quirks_file);
730 
731 	ctx = quirks_init_subsystem(dd.dirname,
732 				    NULL,
733 				    log_handler,
734 				    NULL,
735 				    QLOG_CUSTOM_LOG_PRIORITIES);
736 	ck_assert_notnull(ctx);
737 	quirks_context_unref(ctx);
738 	cleanup_data_dir(dd);
739 }
740 END_TEST
741 
START_TEST(quirks_parse_name_invalid)742 START_TEST(quirks_parse_name_invalid)
743 {
744 	struct quirks_context *ctx;
745 	const char *quirks_file[] = {
746 	"[Section name]\n"
747 	"MatchName=\n"
748 	"ModelAppleTouchpad=1\n",
749 	};
750 	const char **qf;
751 
752 	ARRAY_FOR_EACH(quirks_file, qf) {
753 		struct data_dir dd = make_data_dir(*qf);
754 
755 		ctx = quirks_init_subsystem(dd.dirname,
756 					    NULL,
757 					    log_handler,
758 					    NULL,
759 					    QLOG_CUSTOM_LOG_PRIORITIES);
760 		ck_assert(ctx == NULL);
761 		cleanup_data_dir(dd);
762 	}
763 }
764 END_TEST
765 
START_TEST(quirks_parse_udev)766 START_TEST(quirks_parse_udev)
767 {
768 	struct quirks_context *ctx;
769 	const char quirks_file[] =
770 	"[Section name]\n"
771 	"MatchUdevType=touchpad\n"
772 	"ModelAppleTouchpad=1\n"
773 	"\n"
774 	"[Section name]\n"
775 	"MatchUdevType=mouse\n"
776 	"ModelAppleTouchpad=1\n"
777 	"\n"
778 	"[Section name]\n"
779 	"MatchUdevType=pointingstick\n"
780 	"ModelAppleTouchpad=1\n"
781 	"\n"
782 	"[Section name]\n"
783 	"MatchUdevType=tablet\n"
784 	"ModelAppleTouchpad=1\n"
785 	"\n"
786 	"[Section name]\n"
787 	"MatchUdevType=tablet-pad\n"
788 	"ModelAppleTouchpad=1\n"
789 	"\n"
790 	"[Section name]\n"
791 	"MatchUdevType=keyboard\n"
792 	"ModelAppleTouchpad=1\n"
793 	"\n"
794 	"[Section name]\n"
795 	"MatchUdevType=joystick\n"
796 	"ModelAppleTouchpad=1\n";
797 	struct data_dir dd = make_data_dir(quirks_file);
798 
799 	ctx = quirks_init_subsystem(dd.dirname,
800 				    NULL,
801 				    log_handler,
802 				    NULL,
803 				    QLOG_CUSTOM_LOG_PRIORITIES);
804 	ck_assert_notnull(ctx);
805 	quirks_context_unref(ctx);
806 	cleanup_data_dir(dd);
807 }
808 END_TEST
809 
START_TEST(quirks_parse_udev_invalid)810 START_TEST(quirks_parse_udev_invalid)
811 {
812 	struct quirks_context *ctx;
813 	const char *quirks_file[] = {
814 	"[Section name]\n"
815 	"MatchUdevType=blah\n"
816 	"ModelAppleTouchpad=1\n",
817 	"[Section name]\n"
818 	"MatchUdevType=\n"
819 	"ModelAppleTouchpad=1\n",
820 	"[Section name]\n"
821 	"MatchUdevType=123\n"
822 	"ModelAppleTouchpad=1\n",
823 	};
824 	const char **qf;
825 
826 	ARRAY_FOR_EACH(quirks_file, qf) {
827 		struct data_dir dd = make_data_dir(*qf);
828 
829 		ctx = quirks_init_subsystem(dd.dirname,
830 					    NULL,
831 					    log_handler,
832 					    NULL,
833 					    QLOG_CUSTOM_LOG_PRIORITIES);
834 		ck_assert(ctx == NULL);
835 		cleanup_data_dir(dd);
836 	}
837 }
838 END_TEST
839 
START_TEST(quirks_parse_dmi)840 START_TEST(quirks_parse_dmi)
841 {
842 	struct quirks_context *ctx;
843 	const char quirks_file[] =
844 	"[Section name]\n"
845 	"MatchDMIModalias=dmi:*\n"
846 	"ModelAppleTouchpad=1\n"
847 	"\n"
848 	"[Section name]\n"
849 	"MatchDMIModalias=dmi:*svn*pn*:\n"
850 	"ModelAppleTouchpad=1\n";
851 	struct data_dir dd = make_data_dir(quirks_file);
852 
853 	ctx = quirks_init_subsystem(dd.dirname,
854 				    NULL,
855 				    log_handler,
856 				    NULL,
857 				    QLOG_CUSTOM_LOG_PRIORITIES);
858 	ck_assert_notnull(ctx);
859 	quirks_context_unref(ctx);
860 	cleanup_data_dir(dd);
861 }
862 END_TEST
863 
START_TEST(quirks_parse_dmi_invalid)864 START_TEST(quirks_parse_dmi_invalid)
865 {
866 	struct quirks_context *ctx;
867 	const char *quirks_file[] = {
868 	"[Section name]\n"
869 	"MatchDMIModalias=\n"
870 	"ModelAppleTouchpad=1\n",
871 	"[Section name]\n"
872 	"MatchDMIModalias=*pn*\n"
873 	"ModelAppleTouchpad=1\n",
874 	"[Section name]\n"
875 	"MatchDMIModalias=dmi*pn*\n"
876 	"ModelAppleTouchpad=1\n",
877 	"[Section name]\n"
878 	"MatchDMIModalias=foo\n"
879 	"ModelAppleTouchpad=1\n",
880 	};
881 	const char **qf;
882 
883 	ARRAY_FOR_EACH(quirks_file, qf) {
884 		struct data_dir dd = make_data_dir(*qf);
885 
886 		ctx = quirks_init_subsystem(dd.dirname,
887 					    NULL,
888 					    log_handler,
889 					    NULL,
890 					    QLOG_CUSTOM_LOG_PRIORITIES);
891 		ck_assert(ctx == NULL);
892 		cleanup_data_dir(dd);
893 	}
894 }
895 END_TEST
896 
897 typedef bool (*qparsefunc) (struct quirks *q, enum quirk which, void* data);
898 
899 /*
900    Helper for generic testing, matches on a mouse device with the given
901    quirk set to the given string. Creates a data directory, inits the quirks
902    and calls func() to return the value in data. The func has to take the
903    right data, otherwise boom. Usage:
904    rc = test_attr_parse(dev, QUIRK_ATTR_SIZE_HINT,
905                         "10x30", quirks_get_dimensions,
906 			&some_struct_quirks_dimensions);
907    if (rc == false) // failed to parse
908    else // struct now contains the 10, 30 values
909  */
910 static bool
test_attr_parse(struct litest_device * dev,enum quirk which,const char * str,qparsefunc func,void * data)911 test_attr_parse(struct litest_device *dev,
912 		enum quirk which,
913 		const char *str,
914 		qparsefunc func,
915 		void *data)
916 {
917 	struct udev_device *ud = libinput_device_get_udev_device(dev->libinput_device);
918 	struct quirks_context *ctx;
919 	struct data_dir dd;
920 	char buf[512];
921 	bool result;
922 
923 	snprintf(buf,
924 		 sizeof(buf),
925 		 "[Section name]\n"
926 		 "MatchUdevType=mouse\n"
927 		 "%s=%s\n",
928 		 quirk_get_name(which),
929 		 str);
930 
931 	dd = make_data_dir(buf);
932 	ctx = quirks_init_subsystem(dd.dirname,
933 				    NULL,
934 				    log_handler,
935 				    NULL,
936 				    QLOG_CUSTOM_LOG_PRIORITIES);
937 	if (ctx != NULL) {
938 		struct quirks *q;
939 		q = quirks_fetch_for_device(ctx, ud);
940 		ck_assert_notnull(q);
941 		ck_assert(func(q, which, data));
942 		ck_assert(quirks_has_quirk(q, which));
943 		quirks_unref(q);
944 		quirks_context_unref(ctx);
945 		result = true;
946 	} else {
947 		result = false;
948 	}
949 
950 	cleanup_data_dir(dd);
951 	udev_device_unref(ud);
952 	return result;
953 }
954 
955 struct qtest_dim {
956 		const char *str;
957 		bool success;
958 		int w, h;
959 };
960 
START_TEST(quirks_parse_dimension_attr)961 START_TEST(quirks_parse_dimension_attr)
962 {
963 	struct litest_device *dev = litest_current_device();
964 	enum quirk attrs[] = {
965 		QUIRK_ATTR_SIZE_HINT,
966 		QUIRK_ATTR_RESOLUTION_HINT,
967 	};
968 	enum quirk *a;
969 	struct qtest_dim test_values[] = {
970 		{ "10x10", true, 10, 10 },
971 		{ "20x30", true, 20, 30 },
972 		{ "-10x30", false, 0, 0 },
973 		{ "10:30", false, 0, 0 },
974 		{ "30", false, 0, 0 },
975 		{ "0x00", false, 0, 0 },
976 		{ "0xa0", false, 0, 0 },
977 	};
978 	struct qtest_dim *t;
979 
980 	ARRAY_FOR_EACH(attrs, a) {
981 		ARRAY_FOR_EACH(test_values, t) {
982 			struct quirk_dimensions dim;
983 			bool rc;
984 
985 			rc = test_attr_parse(dev,
986 					     *a,
987 					     t->str,
988 					     (qparsefunc)quirks_get_dimensions,
989 					     &dim);
990 			ck_assert_int_eq(rc, t->success);
991 			if (!rc)
992 				continue;
993 
994 			ck_assert_int_eq(dim.x, t->w);
995 			ck_assert_int_eq(dim.y, t->h);
996 		}
997 	}
998 }
999 END_TEST
1000 
1001 struct qtest_range {
1002 		const char *str;
1003 		bool success;
1004 		int hi, lo;
1005 };
1006 
START_TEST(quirks_parse_range_attr)1007 START_TEST(quirks_parse_range_attr)
1008 {
1009 	struct litest_device *dev = litest_current_device();
1010 	enum quirk attrs[] = {
1011 		QUIRK_ATTR_TOUCH_SIZE_RANGE,
1012 		QUIRK_ATTR_PRESSURE_RANGE,
1013 	};
1014 	enum quirk *a;
1015 	struct qtest_range test_values[] = {
1016 		{ "20:10", true, 20, 10 },
1017 		{ "30:5", true, 30, 5 },
1018 		{ "30:-10", true, 30, -10 },
1019 		{ "-30:-100", true, -30, -100 },
1020 
1021 		{ "5:10", false, 0, 0 },
1022 		{ "5:5", false, 0, 0 },
1023 		{ "-10:5", false, 0, 0 },
1024 		{ "-10:-5", false, 0, 0 },
1025 		{ "10x30", false, 0, 0 },
1026 		{ "30x10", false, 0, 0 },
1027 		{ "30", false, 0, 0 },
1028 		{ "0x00", false, 0, 0 },
1029 		{ "0xa0", false, 0, 0 },
1030 		{ "0x10:0x5", false, 0, 0 },
1031 	};
1032 	struct qtest_range *t;
1033 
1034 	ARRAY_FOR_EACH(attrs, a) {
1035 		ARRAY_FOR_EACH(test_values, t) {
1036 			struct quirk_range r;
1037 			bool rc;
1038 
1039 			rc = test_attr_parse(dev,
1040 					     *a,
1041 					     t->str,
1042 					     (qparsefunc)quirks_get_range,
1043 					     &r);
1044 			ck_assert_int_eq(rc, t->success);
1045 			if (!rc)
1046 				continue;
1047 
1048 			ck_assert_int_eq(r.lower, t->lo);
1049 			ck_assert_int_eq(r.upper, t->hi);
1050 		}
1051 	}
1052 }
1053 END_TEST
1054 
1055 struct qtest_uint {
1056 	const char *str;
1057 	bool success;
1058 	uint32_t val;
1059 };
1060 
START_TEST(quirks_parse_uint_attr)1061 START_TEST(quirks_parse_uint_attr)
1062 {
1063 	struct litest_device *dev = litest_current_device();
1064 	enum quirk attrs[] = {
1065 		QUIRK_ATTR_PALM_SIZE_THRESHOLD,
1066 		QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
1067 		QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
1068 	};
1069 	enum quirk *a;
1070 	struct qtest_uint test_values[] = {
1071 		{ "10", true, 10 },
1072 		{ "0", true, 0 },
1073 		{ "5", true, 5 },
1074 		{ "65535", true, 65535 },
1075 		{ "4294967295", true, 4294967295 },
1076 		{ "-10", false, 0 },
1077 		{ "0x10", false, 0 },
1078 		{ "0xab", false, 0 },
1079 		{ "ab", false, 0 },
1080 	};
1081 	struct qtest_uint *t;
1082 
1083 	ARRAY_FOR_EACH(attrs, a) {
1084 		ARRAY_FOR_EACH(test_values, t) {
1085 			uint32_t v;
1086 			bool rc;
1087 
1088 			rc = test_attr_parse(dev,
1089 					     *a,
1090 					     t->str,
1091 					     (qparsefunc)quirks_get_uint32,
1092 					     &v);
1093 			ck_assert_int_eq(rc, t->success);
1094 			if (!rc)
1095 				continue;
1096 
1097 			ck_assert_int_eq(v, t->val);
1098 		}
1099 	}
1100 }
1101 END_TEST
1102 
1103 struct qtest_double {
1104 	const char *str;
1105 	bool success;
1106 	double val;
1107 };
1108 
START_TEST(quirks_parse_double_attr)1109 START_TEST(quirks_parse_double_attr)
1110 {
1111 	struct litest_device *dev = litest_current_device();
1112 	enum quirk attrs[] = {
1113 		QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
1114 	};
1115 	enum quirk *a;
1116 	struct qtest_double test_values[] = {
1117 		{ "10", true, 10.0 },
1118 		{ "10.0", true, 10.0 },
1119 		{ "-10.0", true, -10.0 },
1120 		{ "0", true, 0.0 },
1121 		{ "0.0", true, 0.0 },
1122 		{ "5.1", true, 5.1 },
1123 		{ "-5.9", true, -5.9 },
1124 		{ "65535", true, 65535 },
1125 		{ "4294967295", true, 4294967295 },
1126 		{ "4294967295.123", true, 4294967295.123 },
1127 		/* our safe_atoi parses hex even though we don't really want
1128 		 * to */
1129 		{ "0x10", false, 0 },
1130 		{ "0xab", false, 0 },
1131 		{ "ab", false, 0 },
1132 		{ "10:5", false, 0 },
1133 		{ "10x5", false, 0 },
1134 	};
1135 	struct qtest_double *t;
1136 
1137 	ARRAY_FOR_EACH(attrs, a) {
1138 		ARRAY_FOR_EACH(test_values, t) {
1139 			double v;
1140 			bool rc;
1141 
1142 			rc = test_attr_parse(dev,
1143 					     *a,
1144 					     t->str,
1145 					     (qparsefunc)quirks_get_double,
1146 					     &v);
1147 			ck_assert_int_eq(rc, t->success);
1148 			if (!rc)
1149 				continue;
1150 
1151 			ck_assert_int_eq(v, t->val);
1152 		}
1153 	}
1154 }
1155 END_TEST
1156 
1157 struct qtest_str {
1158 	const char *str;
1159 	enum quirk where;
1160 };
1161 
START_TEST(quirks_parse_string_attr)1162 START_TEST(quirks_parse_string_attr)
1163 {
1164 	struct litest_device *dev = litest_current_device();
1165 	enum quirk attrs[] = {
1166 		QUIRK_ATTR_TPKBCOMBO_LAYOUT,
1167 		QUIRK_ATTR_LID_SWITCH_RELIABILITY,
1168 		QUIRK_ATTR_KEYBOARD_INTEGRATION,
1169 	};
1170 	enum quirk *a;
1171 	struct qtest_str test_values[] = {
1172 		{ "below", QUIRK_ATTR_TPKBCOMBO_LAYOUT },
1173 		{ "reliable", QUIRK_ATTR_LID_SWITCH_RELIABILITY },
1174 		{ "write_open", QUIRK_ATTR_LID_SWITCH_RELIABILITY },
1175 		{ "internal", QUIRK_ATTR_KEYBOARD_INTEGRATION },
1176 		{ "external", QUIRK_ATTR_KEYBOARD_INTEGRATION },
1177 
1178 		{ "10", 0 },
1179 		{ "-10", 0 },
1180 		{ "0", 0 },
1181 		{ "", 0 },
1182 		{ "banana", 0 },
1183 		{ "honk honk", 0 },
1184 		{ "0x12", 0 },
1185 		{ "0xa", 0 },
1186 		{ "0.0", 0 },
1187 	};
1188 	struct qtest_str *t;
1189 
1190 	ARRAY_FOR_EACH(attrs, a) {
1191 		ARRAY_FOR_EACH(test_values, t) {
1192 			bool rc;
1193 			char *do_not_use; /* freed before we can use it */
1194 
1195 			rc = test_attr_parse(dev,
1196 					     *a,
1197 					     t->str,
1198 					     (qparsefunc)quirks_get_string,
1199 					     &do_not_use);
1200 			if (*a == t->where)
1201 				ck_assert_int_eq(rc, true);
1202 			else
1203 				ck_assert_int_eq(rc, false);
1204 		}
1205 	}
1206 }
1207 END_TEST
1208 
START_TEST(quirks_parse_integration_attr)1209 START_TEST(quirks_parse_integration_attr)
1210 {
1211 	struct litest_device *dev = litest_current_device();
1212 	char *do_not_use; /* freed before we can use it */
1213 	bool
1214 
1215 	rc = test_attr_parse(dev,
1216 			     QUIRK_ATTR_KEYBOARD_INTEGRATION,
1217 			     "internal",
1218 			     (qparsefunc)quirks_get_string,
1219 			     &do_not_use);
1220 	ck_assert(rc);
1221 	rc = test_attr_parse(dev,
1222 			     QUIRK_ATTR_KEYBOARD_INTEGRATION,
1223 			     "external",
1224 			     (qparsefunc)quirks_get_string,
1225 			     &do_not_use);
1226 	ck_assert(rc);
1227 	rc = test_attr_parse(dev,
1228 			     QUIRK_ATTR_TRACKPOINT_INTEGRATION,
1229 			     "internal",
1230 			     (qparsefunc)quirks_get_string,
1231 			     &do_not_use);
1232 	ck_assert(rc);
1233 	rc = test_attr_parse(dev,
1234 			     QUIRK_ATTR_TRACKPOINT_INTEGRATION,
1235 			     "external",
1236 			     (qparsefunc)quirks_get_string,
1237 			     &do_not_use);
1238 	ck_assert(rc);
1239 }
1240 END_TEST
1241 
START_TEST(quirks_model_one)1242 START_TEST(quirks_model_one)
1243 {
1244 	struct litest_device *dev = litest_current_device();
1245 	struct udev_device *ud = libinput_device_get_udev_device(dev->libinput_device);
1246 	struct quirks_context *ctx;
1247 	const char quirks_file[] =
1248 	"[Section name]\n"
1249 	"MatchUdevType=mouse\n"
1250 	"ModelAppleTouchpad=1\n";
1251 	struct data_dir dd = make_data_dir(quirks_file);
1252 	struct quirks *q;
1253 	bool isset;
1254 
1255 	ctx = quirks_init_subsystem(dd.dirname,
1256 				    NULL,
1257 				    log_handler,
1258 				    NULL,
1259 				    QLOG_CUSTOM_LOG_PRIORITIES);
1260 	ck_assert_notnull(ctx);
1261 
1262 	q = quirks_fetch_for_device(ctx, ud);
1263 	ck_assert_notnull(q);
1264 
1265 	ck_assert(quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &isset));
1266 	ck_assert(isset == true);
1267 
1268 	quirks_unref(q);
1269 	quirks_context_unref(ctx);
1270 	cleanup_data_dir(dd);
1271 	udev_device_unref(ud);
1272 }
1273 END_TEST
1274 
START_TEST(quirks_model_zero)1275 START_TEST(quirks_model_zero)
1276 {
1277 	struct litest_device *dev = litest_current_device();
1278 	struct udev_device *ud = libinput_device_get_udev_device(dev->libinput_device);
1279 	struct quirks_context *ctx;
1280 	const char quirks_file[] =
1281 	"[Section name]\n"
1282 	"MatchUdevType=mouse\n"
1283 	"ModelAppleTouchpad=0\n";
1284 	struct data_dir dd = make_data_dir(quirks_file);
1285 	struct quirks *q;
1286 	bool isset;
1287 
1288 	ctx = quirks_init_subsystem(dd.dirname,
1289 				    NULL,
1290 				    log_handler,
1291 				    NULL,
1292 				    QLOG_CUSTOM_LOG_PRIORITIES);
1293 	ck_assert_notnull(ctx);
1294 
1295 	q = quirks_fetch_for_device(ctx, ud);
1296 	ck_assert_notnull(q);
1297 
1298 	ck_assert(quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &isset));
1299 	ck_assert(isset == false);
1300 
1301 	quirks_unref(q);
1302 	quirks_context_unref(ctx);
1303 	cleanup_data_dir(dd);
1304 	udev_device_unref(ud);
1305 }
1306 END_TEST
1307 
START_TEST(quirks_model_alps)1308 START_TEST(quirks_model_alps)
1309 {
1310 	struct litest_device *dev = litest_current_device();
1311 	struct libinput_device *device = dev->libinput_device;
1312 	struct quirks *q;
1313 	bool exists, value = false;
1314 
1315 	q = dev->quirks;
1316 	exists = quirks_get_bool(q, QUIRK_MODEL_ALPS_SERIAL_TOUCHPAD, &value);
1317 
1318 	if (strstr(libinput_device_get_name(device), "ALPS")) {
1319 		ck_assert(exists);
1320 		ck_assert(value);
1321 	} else {
1322 		ck_assert(!exists);
1323 		ck_assert(!value);
1324 	}
1325 }
1326 END_TEST
1327 
START_TEST(quirks_model_wacom)1328 START_TEST(quirks_model_wacom)
1329 {
1330 	struct litest_device *dev = litest_current_device();
1331 	struct quirks *q;
1332 	bool exists, value = false;
1333 
1334 	q = dev->quirks;
1335 	exists = quirks_get_bool(q, QUIRK_MODEL_WACOM_TOUCHPAD, &value);
1336 
1337 	if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM) {
1338 		ck_assert(exists);
1339 		ck_assert(value);
1340 	} else {
1341 		ck_assert(!exists);
1342 		ck_assert(!value);
1343 	}
1344 }
1345 END_TEST
1346 
START_TEST(quirks_model_apple)1347 START_TEST(quirks_model_apple)
1348 {
1349 	struct litest_device *dev = litest_current_device();
1350 	struct quirks *q;
1351 	bool exists, value = false;
1352 
1353 	q = dev->quirks;
1354 	exists = quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &value);
1355 
1356 	if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_APPLE) {
1357 		ck_assert(exists);
1358 		ck_assert(value);
1359 	} else {
1360 		ck_assert(!exists);
1361 		ck_assert(!value);
1362 	}
1363 }
1364 END_TEST
1365 
START_TEST(quirks_model_synaptics_serial)1366 START_TEST(quirks_model_synaptics_serial)
1367 {
1368 	struct litest_device *dev = litest_current_device();
1369 	struct quirks *q;
1370 	bool exists, value = false;
1371 
1372 	q = dev->quirks;
1373 	exists = quirks_get_bool(q, QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD, &value);
1374 
1375 	if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_SYNAPTICS_SERIAL &&
1376 	    libevdev_get_id_product(dev->evdev) == PRODUCT_ID_SYNAPTICS_SERIAL) {
1377 		ck_assert(exists);
1378 		ck_assert(value);
1379 	} else {
1380 		ck_assert(!exists);
1381 		ck_assert(!value);
1382 	}
1383 }
1384 END_TEST
1385 
START_TEST(quirks_call_NULL)1386 START_TEST(quirks_call_NULL)
1387 {
1388 	ck_assert(!quirks_fetch_for_device(NULL, NULL));
1389 
1390 	ck_assert(!quirks_get_uint32(NULL, 0, NULL));
1391 	ck_assert(!quirks_get_int32(NULL, 0, NULL));
1392 	ck_assert(!quirks_get_range(NULL, 0, NULL));
1393 	ck_assert(!quirks_get_dimensions(NULL, 0, NULL));
1394 	ck_assert(!quirks_get_double(NULL, 0, NULL));
1395 	ck_assert(!quirks_get_string(NULL, 0, NULL));
1396 	ck_assert(!quirks_get_bool(NULL, 0, NULL));
1397 }
1398 END_TEST
1399 
START_TEST(quirks_ctx_ref)1400 START_TEST(quirks_ctx_ref)
1401 {
1402 	struct quirks_context *ctx, *ctx2;
1403 	const char quirks_file[] =
1404 	"[Section name]\n"
1405 	"MatchUdevType=mouse\n"
1406 	"AttrSizeHint=10x10\n";
1407 	struct data_dir dd = make_data_dir(quirks_file);
1408 
1409 	ctx = quirks_init_subsystem(dd.dirname,
1410 				    NULL,
1411 				    log_handler,
1412 				    NULL,
1413 				    QLOG_CUSTOM_LOG_PRIORITIES);
1414 	ck_assert_notnull(ctx);
1415 	ctx2 = quirks_context_ref(ctx);
1416 	litest_assert_ptr_eq(ctx, ctx2);
1417 	ctx2 = quirks_context_unref(ctx);
1418 	litest_assert_ptr_eq(ctx2, NULL);
1419 	ctx2 = quirks_context_unref(ctx);
1420 	litest_assert_ptr_eq(ctx2, NULL);
1421 	cleanup_data_dir(dd);
1422 }
1423 END_TEST
1424 
TEST_COLLECTION(quirks)1425 TEST_COLLECTION(quirks)
1426 {
1427 	litest_add_deviceless("quirks:datadir", quirks_invalid_dir);
1428 	litest_add_deviceless("quirks:datadir", quirks_empty_dir);
1429 
1430 	litest_add_deviceless("quirks:structure", quirks_section_empty);
1431 	litest_add_deviceless("quirks:structure", quirks_section_double);
1432 	litest_add_deviceless("quirks:structure", quirks_section_missing_match);
1433 	litest_add_deviceless("quirks:structure", quirks_section_missing_attr);
1434 	litest_add_deviceless("quirks:structure", quirks_section_match_after_attr);
1435 	litest_add_deviceless("quirks:structure", quirks_section_duplicate_match);
1436 	litest_add_deviceless("quirks:structure", quirks_section_duplicate_attr);
1437 
1438 	litest_add_deviceless("quirks:parsing", quirks_parse_error_section);
1439 	litest_add_deviceless("quirks:parsing", quirks_parse_error_trailing_whitespace);
1440 	litest_add_deviceless("quirks:parsing", quirks_parse_error_unknown_match);
1441 	litest_add_deviceless("quirks:parsing", quirks_parse_error_unknown_attr);
1442 	litest_add_deviceless("quirks:parsing", quirks_parse_error_unknown_model);
1443 	litest_add_deviceless("quirks:parsing", quirks_parse_error_unknown_prefix);
1444 	litest_add_deviceless("quirks:parsing", quirks_parse_error_model_not_one);
1445 	litest_add_deviceless("quirks:parsing", quirks_parse_comment_inline);
1446 	litest_add_deviceless("quirks:parsing", quirks_parse_comment_empty);
1447 	litest_add_deviceless("quirks:parsing", quirks_parse_string_quotes_single);
1448 	litest_add_deviceless("quirks:parsing", quirks_parse_string_quotes_double);
1449 
1450 	litest_add_deviceless("quirks:parsing", quirks_parse_bustype);
1451 	litest_add_deviceless("quirks:parsing", quirks_parse_bustype_invalid);
1452 	litest_add_deviceless("quirks:parsing", quirks_parse_vendor);
1453 	litest_add_deviceless("quirks:parsing", quirks_parse_vendor_invalid);
1454 	litest_add_deviceless("quirks:parsing", quirks_parse_product);
1455 	litest_add_deviceless("quirks:parsing", quirks_parse_product_invalid);
1456 	litest_add_deviceless("quirks:parsing", quirks_parse_version);
1457 	litest_add_deviceless("quirks:parsing", quirks_parse_version_invalid);
1458 	litest_add_deviceless("quirks:parsing", quirks_parse_name);
1459 	litest_add_deviceless("quirks:parsing", quirks_parse_name_invalid);
1460 	litest_add_deviceless("quirks:parsing", quirks_parse_udev);
1461 	litest_add_deviceless("quirks:parsing", quirks_parse_udev_invalid);
1462 	litest_add_deviceless("quirks:parsing", quirks_parse_dmi);
1463 	litest_add_deviceless("quirks:parsing", quirks_parse_dmi_invalid);
1464 
1465 	litest_add_for_device("quirks:parsing", quirks_parse_dimension_attr, LITEST_MOUSE);
1466 	litest_add_for_device("quirks:parsing", quirks_parse_range_attr, LITEST_MOUSE);
1467 	litest_add_for_device("quirks:parsing", quirks_parse_uint_attr, LITEST_MOUSE);
1468 	litest_add_for_device("quirks:parsing", quirks_parse_double_attr, LITEST_MOUSE);
1469 	litest_add_for_device("quirks:parsing", quirks_parse_string_attr, LITEST_MOUSE);
1470 	litest_add_for_device("quirks:parsing", quirks_parse_integration_attr, LITEST_MOUSE);
1471 
1472 	litest_add_for_device("quirks:model", quirks_model_one, LITEST_MOUSE);
1473 	litest_add_for_device("quirks:model", quirks_model_zero, LITEST_MOUSE);
1474 
1475 	litest_add("quirks:devices", quirks_model_alps, LITEST_TOUCHPAD, LITEST_ANY);
1476 	litest_add("quirks:devices", quirks_model_wacom, LITEST_TOUCHPAD, LITEST_ANY);
1477 	litest_add("quirks:devices", quirks_model_apple, LITEST_TOUCHPAD, LITEST_ANY);
1478 	litest_add("quirks:devices", quirks_model_synaptics_serial, LITEST_TOUCHPAD, LITEST_ANY);
1479 
1480 	litest_add_deviceless("quirks:misc", quirks_call_NULL);
1481 	litest_add_deviceless("quirks:misc", quirks_ctx_ref);
1482 }
1483