• 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 
565 	ARRAY_FOR_EACH(quirks_file, qf) {
566 		struct data_dir dd = make_data_dir(*qf);
567 
568 		ctx = quirks_init_subsystem(dd.dirname,
569 					    NULL,
570 					    log_handler,
571 					    NULL,
572 					    QLOG_CUSTOM_LOG_PRIORITIES);
573 		ck_assert(ctx == NULL);
574 		cleanup_data_dir(dd);
575 	}
576 }
577 END_TEST
578 
START_TEST(quirks_parse_product)579 START_TEST(quirks_parse_product)
580 {
581 	struct quirks_context *ctx;
582 	const char quirks_file[] =
583 	"[Section name]\n"
584 	"MatchProduct=0x0000\n"
585 	"ModelAppleTouchpad=1\n"
586 	"\n"
587 	"[Section name]\n"
588 	"MatchProduct=0x0001\n"
589 	"ModelAppleTouchpad=1\n"
590 	"\n"
591 	"[Section name]\n"
592 	"MatchProduct=0x2343\n"
593 	"ModelAppleTouchpad=1\n";
594 	struct data_dir dd = make_data_dir(quirks_file);
595 
596 	ctx = quirks_init_subsystem(dd.dirname,
597 				    NULL,
598 				    log_handler,
599 				    NULL,
600 				    QLOG_CUSTOM_LOG_PRIORITIES);
601 	ck_assert_notnull(ctx);
602 	quirks_context_unref(ctx);
603 	cleanup_data_dir(dd);
604 }
605 END_TEST
606 
START_TEST(quirks_parse_product_invalid)607 START_TEST(quirks_parse_product_invalid)
608 {
609 	struct quirks_context *ctx;
610 	const char *quirks_file[] = {
611 	"[Section name]\n"
612 	"MatchProduct=-1\n"
613 	"ModelAppleTouchpad=1\n",
614 	"[Section name]\n"
615 	"MatchProduct=abc\n"
616 	"ModelAppleTouchpad=1\n",
617 	"[Section name]\n"
618 	"MatchProduct=0xFFFFF\n"
619 	"ModelAppleTouchpad=1\n",
620 	"[Section name]\n"
621 	"MatchProduct=123\n"
622 	"ModelAppleTouchpad=1\n",
623 	};
624 
625 	ARRAY_FOR_EACH(quirks_file, qf) {
626 		struct data_dir dd = make_data_dir(*qf);
627 
628 		ctx = quirks_init_subsystem(dd.dirname,
629 					    NULL,
630 					    log_handler,
631 					    NULL,
632 					    QLOG_CUSTOM_LOG_PRIORITIES);
633 		ck_assert(ctx == NULL);
634 		cleanup_data_dir(dd);
635 	}
636 }
637 END_TEST
638 
START_TEST(quirks_parse_version)639 START_TEST(quirks_parse_version)
640 {
641 	struct quirks_context *ctx;
642 	const char quirks_file[] =
643 	"[Section name]\n"
644 	"MatchVersion=0x0000\n"
645 	"ModelAppleTouchpad=1\n"
646 	"\n"
647 	"[Section name]\n"
648 	"MatchVersion=0x0001\n"
649 	"ModelAppleTouchpad=1\n"
650 	"\n"
651 	"[Section name]\n"
652 	"MatchVersion=0x2343\n"
653 	"ModelAppleTouchpad=1\n";
654 	struct data_dir dd = make_data_dir(quirks_file);
655 
656 	ctx = quirks_init_subsystem(dd.dirname,
657 				    NULL,
658 				    log_handler,
659 				    NULL,
660 				    QLOG_CUSTOM_LOG_PRIORITIES);
661 	ck_assert_notnull(ctx);
662 	quirks_context_unref(ctx);
663 	cleanup_data_dir(dd);
664 }
665 END_TEST
666 
START_TEST(quirks_parse_version_invalid)667 START_TEST(quirks_parse_version_invalid)
668 {
669 	struct quirks_context *ctx;
670 	const char *quirks_file[] = {
671 	"[Section name]\n"
672 	"MatchVersion=-1\n"
673 	"ModelAppleTouchpad=1\n",
674 	"[Section name]\n"
675 	"MatchVersion=abc\n"
676 	"ModelAppleTouchpad=1\n",
677 	"[Section name]\n"
678 	"MatchVersion=0xFFFFF\n"
679 	"ModelAppleTouchpad=1\n",
680 	"[Section name]\n"
681 	"MatchVersion=123\n"
682 	"ModelAppleTouchpad=1\n",
683 	};
684 
685 	ARRAY_FOR_EACH(quirks_file, qf) {
686 		struct data_dir dd = make_data_dir(*qf);
687 
688 		ctx = quirks_init_subsystem(dd.dirname,
689 					    NULL,
690 					    log_handler,
691 					    NULL,
692 					    QLOG_CUSTOM_LOG_PRIORITIES);
693 		ck_assert(ctx == NULL);
694 		cleanup_data_dir(dd);
695 	}
696 }
697 END_TEST
698 
START_TEST(quirks_parse_name)699 START_TEST(quirks_parse_name)
700 {
701 	struct quirks_context *ctx;
702 	const char quirks_file[] =
703 	"[Section name]\n"
704 	"MatchName=1235\n"
705 	"ModelAppleTouchpad=1\n"
706 	"\n"
707 	"[Section name]\n"
708 	"MatchName=abc\n"
709 	"ModelAppleTouchpad=1\n"
710 	"\n"
711 	"[Section name]\n"
712 	"MatchName=*foo\n"
713 	"ModelAppleTouchpad=1\n"
714 	"\n"
715 	"[Section name]\n"
716 	"MatchName=foo*\n"
717 	"ModelAppleTouchpad=1\n"
718 	"\n"
719 	"[Section name]\n"
720 	"MatchName=foo[]\n"
721 	"ModelAppleTouchpad=1\n"
722 	"\n"
723 	"[Section name]\n"
724 	"MatchName=*foo*\n"
725 	"ModelAppleTouchpad=1\n";
726 	struct data_dir dd = make_data_dir(quirks_file);
727 
728 	ctx = quirks_init_subsystem(dd.dirname,
729 				    NULL,
730 				    log_handler,
731 				    NULL,
732 				    QLOG_CUSTOM_LOG_PRIORITIES);
733 	ck_assert_notnull(ctx);
734 	quirks_context_unref(ctx);
735 	cleanup_data_dir(dd);
736 }
737 END_TEST
738 
START_TEST(quirks_parse_name_invalid)739 START_TEST(quirks_parse_name_invalid)
740 {
741 	struct quirks_context *ctx;
742 	const char *quirks_file[] = {
743 	"[Section name]\n"
744 	"MatchName=\n"
745 	"ModelAppleTouchpad=1\n",
746 	};
747 
748 	ARRAY_FOR_EACH(quirks_file, qf) {
749 		struct data_dir dd = make_data_dir(*qf);
750 
751 		ctx = quirks_init_subsystem(dd.dirname,
752 					    NULL,
753 					    log_handler,
754 					    NULL,
755 					    QLOG_CUSTOM_LOG_PRIORITIES);
756 		ck_assert(ctx == NULL);
757 		cleanup_data_dir(dd);
758 	}
759 }
760 END_TEST
761 
START_TEST(quirks_parse_udev)762 START_TEST(quirks_parse_udev)
763 {
764 	struct quirks_context *ctx;
765 	const char quirks_file[] =
766 	"[Section name]\n"
767 	"MatchUdevType=touchpad\n"
768 	"ModelAppleTouchpad=1\n"
769 	"\n"
770 	"[Section name]\n"
771 	"MatchUdevType=mouse\n"
772 	"ModelAppleTouchpad=1\n"
773 	"\n"
774 	"[Section name]\n"
775 	"MatchUdevType=pointingstick\n"
776 	"ModelAppleTouchpad=1\n"
777 	"\n"
778 	"[Section name]\n"
779 	"MatchUdevType=tablet\n"
780 	"ModelAppleTouchpad=1\n"
781 	"\n"
782 	"[Section name]\n"
783 	"MatchUdevType=tablet-pad\n"
784 	"ModelAppleTouchpad=1\n"
785 	"\n"
786 	"[Section name]\n"
787 	"MatchUdevType=keyboard\n"
788 	"ModelAppleTouchpad=1\n"
789 	"\n"
790 	"[Section name]\n"
791 	"MatchUdevType=joystick\n"
792 	"ModelAppleTouchpad=1\n";
793 	struct data_dir dd = make_data_dir(quirks_file);
794 
795 	ctx = quirks_init_subsystem(dd.dirname,
796 				    NULL,
797 				    log_handler,
798 				    NULL,
799 				    QLOG_CUSTOM_LOG_PRIORITIES);
800 	ck_assert_notnull(ctx);
801 	quirks_context_unref(ctx);
802 	cleanup_data_dir(dd);
803 }
804 END_TEST
805 
START_TEST(quirks_parse_udev_invalid)806 START_TEST(quirks_parse_udev_invalid)
807 {
808 	struct quirks_context *ctx;
809 	const char *quirks_file[] = {
810 	"[Section name]\n"
811 	"MatchUdevType=blah\n"
812 	"ModelAppleTouchpad=1\n",
813 	"[Section name]\n"
814 	"MatchUdevType=\n"
815 	"ModelAppleTouchpad=1\n",
816 	"[Section name]\n"
817 	"MatchUdevType=123\n"
818 	"ModelAppleTouchpad=1\n",
819 	};
820 
821 	ARRAY_FOR_EACH(quirks_file, qf) {
822 		struct data_dir dd = make_data_dir(*qf);
823 
824 		ctx = quirks_init_subsystem(dd.dirname,
825 					    NULL,
826 					    log_handler,
827 					    NULL,
828 					    QLOG_CUSTOM_LOG_PRIORITIES);
829 		ck_assert(ctx == NULL);
830 		cleanup_data_dir(dd);
831 	}
832 }
833 END_TEST
834 
START_TEST(quirks_parse_dmi)835 START_TEST(quirks_parse_dmi)
836 {
837 	struct quirks_context *ctx;
838 	const char quirks_file[] =
839 	"[Section name]\n"
840 	"MatchDMIModalias=dmi:*\n"
841 	"ModelAppleTouchpad=1\n"
842 	"\n"
843 	"[Section name]\n"
844 	"MatchDMIModalias=dmi:*svn*pn*:\n"
845 	"ModelAppleTouchpad=1\n";
846 	struct data_dir dd = make_data_dir(quirks_file);
847 
848 	ctx = quirks_init_subsystem(dd.dirname,
849 				    NULL,
850 				    log_handler,
851 				    NULL,
852 				    QLOG_CUSTOM_LOG_PRIORITIES);
853 	ck_assert_notnull(ctx);
854 	quirks_context_unref(ctx);
855 	cleanup_data_dir(dd);
856 }
857 END_TEST
858 
START_TEST(quirks_parse_dmi_invalid)859 START_TEST(quirks_parse_dmi_invalid)
860 {
861 	struct quirks_context *ctx;
862 	const char *quirks_file[] = {
863 	"[Section name]\n"
864 	"MatchDMIModalias=\n"
865 	"ModelAppleTouchpad=1\n",
866 	"[Section name]\n"
867 	"MatchDMIModalias=*pn*\n"
868 	"ModelAppleTouchpad=1\n",
869 	"[Section name]\n"
870 	"MatchDMIModalias=dmi*pn*\n"
871 	"ModelAppleTouchpad=1\n",
872 	"[Section name]\n"
873 	"MatchDMIModalias=foo\n"
874 	"ModelAppleTouchpad=1\n",
875 	};
876 
877 	ARRAY_FOR_EACH(quirks_file, qf) {
878 		struct data_dir dd = make_data_dir(*qf);
879 
880 		ctx = quirks_init_subsystem(dd.dirname,
881 					    NULL,
882 					    log_handler,
883 					    NULL,
884 					    QLOG_CUSTOM_LOG_PRIORITIES);
885 		ck_assert(ctx == NULL);
886 		cleanup_data_dir(dd);
887 	}
888 }
889 END_TEST
890 
891 typedef bool (*qparsefunc) (struct quirks *q, enum quirk which, void* data);
892 
893 /*
894    Helper for generic testing, matches on a mouse device with the given
895    quirk set to the given string. Creates a data directory, inits the quirks
896    and calls func() to return the value in data. The func has to take the
897    right data, otherwise boom. Usage:
898    rc = test_attr_parse(dev, QUIRK_ATTR_SIZE_HINT,
899                         "10x30", quirks_get_dimensions,
900 			&some_struct_quirks_dimensions);
901    if (rc == false) // failed to parse
902    else // struct now contains the 10, 30 values
903  */
904 static bool
test_attr_parse(struct litest_device * dev,enum quirk which,const char * str,qparsefunc func,void * data)905 test_attr_parse(struct litest_device *dev,
906 		enum quirk which,
907 		const char *str,
908 		qparsefunc func,
909 		void *data)
910 {
911 	struct udev_device *ud = libinput_device_get_udev_device(dev->libinput_device);
912 	struct quirks_context *ctx;
913 	struct data_dir dd;
914 	char buf[512];
915 	bool result;
916 
917 	snprintf(buf,
918 		 sizeof(buf),
919 		 "[Section name]\n"
920 		 "MatchUdevType=mouse\n"
921 		 "%s=%s\n",
922 		 quirk_get_name(which),
923 		 str);
924 
925 	dd = make_data_dir(buf);
926 	ctx = quirks_init_subsystem(dd.dirname,
927 				    NULL,
928 				    log_handler,
929 				    NULL,
930 				    QLOG_CUSTOM_LOG_PRIORITIES);
931 	if (ctx != NULL) {
932 		struct quirks *q;
933 		q = quirks_fetch_for_device(ctx, ud);
934 		ck_assert_notnull(q);
935 		ck_assert(func(q, which, data));
936 		ck_assert(quirks_has_quirk(q, which));
937 		quirks_unref(q);
938 		quirks_context_unref(ctx);
939 		result = true;
940 	} else {
941 		result = false;
942 	}
943 
944 	cleanup_data_dir(dd);
945 	udev_device_unref(ud);
946 	return result;
947 }
948 
949 struct qtest_dim {
950 		const char *str;
951 		bool success;
952 		int w, h;
953 };
954 
START_TEST(quirks_parse_dimension_attr)955 START_TEST(quirks_parse_dimension_attr)
956 {
957 	struct litest_device *dev = litest_current_device();
958 	enum quirk attrs[] = {
959 		QUIRK_ATTR_SIZE_HINT,
960 		QUIRK_ATTR_RESOLUTION_HINT,
961 	};
962 	struct qtest_dim test_values[] = {
963 		{ "10x10", true, 10, 10 },
964 		{ "20x30", true, 20, 30 },
965 		{ "-10x30", false, 0, 0 },
966 		{ "10:30", false, 0, 0 },
967 		{ "30", false, 0, 0 },
968 		{ "0x00", false, 0, 0 },
969 		{ "0xa0", false, 0, 0 },
970 	};
971 
972 	ARRAY_FOR_EACH(attrs, a) {
973 		ARRAY_FOR_EACH(test_values, t) {
974 			struct quirk_dimensions dim;
975 			bool rc;
976 
977 			rc = test_attr_parse(dev,
978 					     *a,
979 					     t->str,
980 					     (qparsefunc)quirks_get_dimensions,
981 					     &dim);
982 			ck_assert_int_eq(rc, t->success);
983 			if (!rc)
984 				continue;
985 
986 			ck_assert_int_eq(dim.x, t->w);
987 			ck_assert_int_eq(dim.y, t->h);
988 		}
989 	}
990 }
991 END_TEST
992 
993 struct qtest_range {
994 		const char *str;
995 		bool success;
996 		int hi, lo;
997 };
998 
START_TEST(quirks_parse_range_attr)999 START_TEST(quirks_parse_range_attr)
1000 {
1001 	struct litest_device *dev = litest_current_device();
1002 	enum quirk attrs[] = {
1003 		QUIRK_ATTR_TOUCH_SIZE_RANGE,
1004 		QUIRK_ATTR_PRESSURE_RANGE,
1005 	};
1006 	struct qtest_range test_values[] = {
1007 		{ "20:10", true, 20, 10 },
1008 		{ "30:5", true, 30, 5 },
1009 		{ "30:-10", true, 30, -10 },
1010 		{ "-30:-100", true, -30, -100 },
1011 
1012 		{ "5:10", false, 0, 0 },
1013 		{ "5:5", false, 0, 0 },
1014 		{ "-10:5", false, 0, 0 },
1015 		{ "-10:-5", false, 0, 0 },
1016 		{ "10x30", false, 0, 0 },
1017 		{ "30x10", false, 0, 0 },
1018 		{ "30", false, 0, 0 },
1019 		{ "0x00", false, 0, 0 },
1020 		{ "0xa0", false, 0, 0 },
1021 		{ "0x10:0x5", false, 0, 0 },
1022 	};
1023 
1024 	ARRAY_FOR_EACH(attrs, a) {
1025 		ARRAY_FOR_EACH(test_values, t) {
1026 			struct quirk_range r;
1027 			bool rc;
1028 
1029 			rc = test_attr_parse(dev,
1030 					     *a,
1031 					     t->str,
1032 					     (qparsefunc)quirks_get_range,
1033 					     &r);
1034 			ck_assert_int_eq(rc, t->success);
1035 			if (!rc)
1036 				continue;
1037 
1038 			ck_assert_int_eq(r.lower, t->lo);
1039 			ck_assert_int_eq(r.upper, t->hi);
1040 		}
1041 	}
1042 }
1043 END_TEST
1044 
1045 struct qtest_uint {
1046 	const char *str;
1047 	bool success;
1048 	uint32_t val;
1049 };
1050 
START_TEST(quirks_parse_uint_attr)1051 START_TEST(quirks_parse_uint_attr)
1052 {
1053 	struct litest_device *dev = litest_current_device();
1054 	enum quirk attrs[] = {
1055 		QUIRK_ATTR_PALM_SIZE_THRESHOLD,
1056 		QUIRK_ATTR_PALM_PRESSURE_THRESHOLD,
1057 		QUIRK_ATTR_THUMB_PRESSURE_THRESHOLD,
1058 	};
1059 	struct qtest_uint test_values[] = {
1060 		{ "10", true, 10 },
1061 		{ "0", true, 0 },
1062 		{ "5", true, 5 },
1063 		{ "65535", true, 65535 },
1064 		{ "4294967295", true, 4294967295 },
1065 		{ "-10", false, 0 },
1066 		{ "0x10", false, 0 },
1067 		{ "0xab", false, 0 },
1068 		{ "ab", false, 0 },
1069 	};
1070 
1071 	ARRAY_FOR_EACH(attrs, a) {
1072 		ARRAY_FOR_EACH(test_values, t) {
1073 			uint32_t v;
1074 			bool rc;
1075 
1076 			rc = test_attr_parse(dev,
1077 					     *a,
1078 					     t->str,
1079 					     (qparsefunc)quirks_get_uint32,
1080 					     &v);
1081 			ck_assert_int_eq(rc, t->success);
1082 			if (!rc)
1083 				continue;
1084 
1085 			ck_assert_int_eq(v, t->val);
1086 		}
1087 	}
1088 }
1089 END_TEST
1090 
1091 struct qtest_double {
1092 	const char *str;
1093 	bool success;
1094 	double val;
1095 };
1096 
START_TEST(quirks_parse_double_attr)1097 START_TEST(quirks_parse_double_attr)
1098 {
1099 	struct litest_device *dev = litest_current_device();
1100 	enum quirk attrs[] = {
1101 		QUIRK_ATTR_TRACKPOINT_MULTIPLIER,
1102 	};
1103 	struct qtest_double test_values[] = {
1104 		{ "10", true, 10.0 },
1105 		{ "10.0", true, 10.0 },
1106 		{ "-10.0", true, -10.0 },
1107 		{ "0", true, 0.0 },
1108 		{ "0.0", true, 0.0 },
1109 		{ "5.1", true, 5.1 },
1110 		{ "-5.9", true, -5.9 },
1111 		{ "65535", true, 65535 },
1112 		{ "4294967295", true, 4294967295 },
1113 		{ "4294967295.123", true, 4294967295.123 },
1114 		/* our safe_atoi parses hex even though we don't really want
1115 		 * to */
1116 		{ "0x10", false, 0 },
1117 		{ "0xab", false, 0 },
1118 		{ "ab", false, 0 },
1119 		{ "10:5", false, 0 },
1120 		{ "10x5", false, 0 },
1121 	};
1122 
1123 	ARRAY_FOR_EACH(attrs, a) {
1124 		ARRAY_FOR_EACH(test_values, t) {
1125 			double v;
1126 			bool rc;
1127 
1128 			rc = test_attr_parse(dev,
1129 					     *a,
1130 					     t->str,
1131 					     (qparsefunc)quirks_get_double,
1132 					     &v);
1133 			ck_assert_int_eq(rc, t->success);
1134 			if (!rc)
1135 				continue;
1136 
1137 			ck_assert_int_eq(v, t->val);
1138 		}
1139 	}
1140 }
1141 END_TEST
1142 
1143 struct qtest_str {
1144 	const char *str;
1145 	enum quirk where;
1146 };
1147 
START_TEST(quirks_parse_string_attr)1148 START_TEST(quirks_parse_string_attr)
1149 {
1150 	struct litest_device *dev = litest_current_device();
1151 	enum quirk attrs[] = {
1152 		QUIRK_ATTR_TPKBCOMBO_LAYOUT,
1153 		QUIRK_ATTR_LID_SWITCH_RELIABILITY,
1154 		QUIRK_ATTR_KEYBOARD_INTEGRATION,
1155 	};
1156 	struct qtest_str test_values[] = {
1157 		{ "below", QUIRK_ATTR_TPKBCOMBO_LAYOUT },
1158 		{ "reliable", QUIRK_ATTR_LID_SWITCH_RELIABILITY },
1159 		{ "write_open", QUIRK_ATTR_LID_SWITCH_RELIABILITY },
1160 		{ "internal", QUIRK_ATTR_KEYBOARD_INTEGRATION },
1161 		{ "external", QUIRK_ATTR_KEYBOARD_INTEGRATION },
1162 
1163 		{ "10", 0 },
1164 		{ "-10", 0 },
1165 		{ "0", 0 },
1166 		{ "", 0 },
1167 		{ "banana", 0 },
1168 		{ "honk honk", 0 },
1169 		{ "0x12", 0 },
1170 		{ "0xa", 0 },
1171 		{ "0.0", 0 },
1172 	};
1173 
1174 	ARRAY_FOR_EACH(attrs, a) {
1175 		ARRAY_FOR_EACH(test_values, t) {
1176 			bool rc;
1177 			char *do_not_use; /* freed before we can use it */
1178 
1179 			rc = test_attr_parse(dev,
1180 					     *a,
1181 					     t->str,
1182 					     (qparsefunc)quirks_get_string,
1183 					     &do_not_use);
1184 			if (*a == t->where)
1185 				ck_assert_int_eq(rc, true);
1186 			else
1187 				ck_assert_int_eq(rc, false);
1188 		}
1189 	}
1190 }
1191 END_TEST
1192 
1193 struct qtest_bool {
1194 	const char *str;
1195 	bool success;
1196 	bool val;
1197 };
1198 
START_TEST(quirks_parse_bool_attr)1199 START_TEST(quirks_parse_bool_attr)
1200 {
1201 	struct litest_device *dev = litest_current_device();
1202 	enum quirk attrs[] = {
1203 	        QUIRK_ATTR_USE_VELOCITY_AVERAGING,
1204 		QUIRK_ATTR_TABLET_SMOOTHING,
1205 	};
1206 	struct qtest_bool test_values[] = {
1207 		{ "0", true, false },
1208 		{ "1", true, true },
1209 		{ "2", false, false },
1210 		{ "-1", false, false },
1211 		{ "a", false, false },
1212 	};
1213 
1214 	ARRAY_FOR_EACH(attrs, a) {
1215 		ARRAY_FOR_EACH(test_values, t) {
1216 			bool v;
1217 			bool rc;
1218 
1219 			rc = test_attr_parse(dev,
1220 					     *a,
1221 					     t->str,
1222 					     (qparsefunc)quirks_get_bool,
1223 					     &v);
1224 			ck_assert(rc == t->success);
1225 			if (!rc)
1226 				continue;
1227 
1228 			ck_assert(v == t->val);
1229 		}
1230 	}
1231 }
1232 END_TEST
1233 
START_TEST(quirks_parse_integration_attr)1234 START_TEST(quirks_parse_integration_attr)
1235 {
1236 	struct litest_device *dev = litest_current_device();
1237 	char *do_not_use; /* freed before we can use it */
1238 	bool
1239 
1240 	rc = test_attr_parse(dev,
1241 			     QUIRK_ATTR_KEYBOARD_INTEGRATION,
1242 			     "internal",
1243 			     (qparsefunc)quirks_get_string,
1244 			     &do_not_use);
1245 	ck_assert(rc);
1246 	rc = test_attr_parse(dev,
1247 			     QUIRK_ATTR_KEYBOARD_INTEGRATION,
1248 			     "external",
1249 			     (qparsefunc)quirks_get_string,
1250 			     &do_not_use);
1251 	ck_assert(rc);
1252 	rc = test_attr_parse(dev,
1253 			     QUIRK_ATTR_TRACKPOINT_INTEGRATION,
1254 			     "internal",
1255 			     (qparsefunc)quirks_get_string,
1256 			     &do_not_use);
1257 	ck_assert(rc);
1258 	rc = test_attr_parse(dev,
1259 			     QUIRK_ATTR_TRACKPOINT_INTEGRATION,
1260 			     "external",
1261 			     (qparsefunc)quirks_get_string,
1262 			     &do_not_use);
1263 	ck_assert(rc);
1264 }
1265 END_TEST
1266 
START_TEST(quirks_model_one)1267 START_TEST(quirks_model_one)
1268 {
1269 	struct litest_device *dev = litest_current_device();
1270 	struct udev_device *ud = libinput_device_get_udev_device(dev->libinput_device);
1271 	struct quirks_context *ctx;
1272 	const char quirks_file[] =
1273 	"[Section name]\n"
1274 	"MatchUdevType=mouse\n"
1275 	"ModelAppleTouchpad=1\n";
1276 	struct data_dir dd = make_data_dir(quirks_file);
1277 	struct quirks *q;
1278 	bool isset;
1279 
1280 	ctx = quirks_init_subsystem(dd.dirname,
1281 				    NULL,
1282 				    log_handler,
1283 				    NULL,
1284 				    QLOG_CUSTOM_LOG_PRIORITIES);
1285 	ck_assert_notnull(ctx);
1286 
1287 	q = quirks_fetch_for_device(ctx, ud);
1288 	ck_assert_notnull(q);
1289 
1290 	ck_assert(quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &isset));
1291 	ck_assert(isset == true);
1292 
1293 	quirks_unref(q);
1294 	quirks_context_unref(ctx);
1295 	cleanup_data_dir(dd);
1296 	udev_device_unref(ud);
1297 }
1298 END_TEST
1299 
START_TEST(quirks_model_zero)1300 START_TEST(quirks_model_zero)
1301 {
1302 	struct litest_device *dev = litest_current_device();
1303 	struct udev_device *ud = libinput_device_get_udev_device(dev->libinput_device);
1304 	struct quirks_context *ctx;
1305 	const char quirks_file[] =
1306 	"[Section name]\n"
1307 	"MatchUdevType=mouse\n"
1308 	"ModelAppleTouchpad=0\n";
1309 	struct data_dir dd = make_data_dir(quirks_file);
1310 	struct quirks *q;
1311 	bool isset;
1312 
1313 	ctx = quirks_init_subsystem(dd.dirname,
1314 				    NULL,
1315 				    log_handler,
1316 				    NULL,
1317 				    QLOG_CUSTOM_LOG_PRIORITIES);
1318 	ck_assert_notnull(ctx);
1319 
1320 	q = quirks_fetch_for_device(ctx, ud);
1321 	ck_assert_notnull(q);
1322 
1323 	ck_assert(quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &isset));
1324 	ck_assert(isset == false);
1325 
1326 	quirks_unref(q);
1327 	quirks_context_unref(ctx);
1328 	cleanup_data_dir(dd);
1329 	udev_device_unref(ud);
1330 }
1331 END_TEST
1332 
START_TEST(quirks_model_override)1333 START_TEST(quirks_model_override)
1334 {
1335 	struct litest_device *dev = litest_current_device();
1336 	struct udev_device *ud = libinput_device_get_udev_device(dev->libinput_device);
1337 	struct quirks_context *ctx;
1338 	char *quirks_file;
1339 	struct data_dir dd;
1340 	struct quirks *q;
1341 	bool isset;
1342 	bool set = _i; /* ranged test */
1343 
1344 	/* Test model quirks override by setting, then unsetting (or the
1345 	   other way round) */
1346 	int rc = xasprintf(&quirks_file,
1347 			   "[first]\n"
1348 			   "MatchUdevType=mouse\n"
1349 			   "ModelAppleTouchpad=%d\n"
1350 			   "\n"
1351 			   "[second]\n"
1352 			   "MatchUdevType=mouse\n"
1353 			   "ModelAppleTouchpad=%d\n",
1354 			   set ? 0 : 1,
1355 			   set ? 1 : 0);
1356 	ck_assert_int_ne(rc, -1);
1357 
1358 	dd = make_data_dir(quirks_file);
1359 
1360 	ctx = quirks_init_subsystem(dd.dirname,
1361 				    NULL,
1362 				    log_handler,
1363 				    NULL,
1364 				    QLOG_CUSTOM_LOG_PRIORITIES);
1365 	ck_assert_notnull(ctx);
1366 
1367 	q = quirks_fetch_for_device(ctx, ud);
1368 	ck_assert_notnull(q);
1369 
1370 	ck_assert(quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &isset));
1371 	ck_assert(isset == set);
1372 
1373 	quirks_unref(q);
1374 	quirks_context_unref(ctx);
1375 	cleanup_data_dir(dd);
1376 	udev_device_unref(ud);
1377 	free(quirks_file);
1378 }
1379 END_TEST
1380 
START_TEST(quirks_model_alps)1381 START_TEST(quirks_model_alps)
1382 {
1383 	struct litest_device *dev = litest_current_device();
1384 	struct libinput_device *device = dev->libinput_device;
1385 	struct quirks *q;
1386 	bool exists, value = false;
1387 
1388 	q = dev->quirks;
1389 	exists = quirks_get_bool(q, QUIRK_MODEL_ALPS_SERIAL_TOUCHPAD, &value);
1390 
1391 	if (strstr(libinput_device_get_name(device), "ALPS")) {
1392 		ck_assert(exists);
1393 		ck_assert(value);
1394 	} else {
1395 		ck_assert(!exists);
1396 		ck_assert(!value);
1397 	}
1398 }
1399 END_TEST
1400 
START_TEST(quirks_model_wacom)1401 START_TEST(quirks_model_wacom)
1402 {
1403 	struct litest_device *dev = litest_current_device();
1404 	struct quirks *q;
1405 	bool exists, value = false;
1406 
1407 	q = dev->quirks;
1408 	exists = quirks_get_bool(q, QUIRK_MODEL_WACOM_TOUCHPAD, &value);
1409 
1410 	if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_WACOM) {
1411 		ck_assert(exists);
1412 		ck_assert(value);
1413 	} else {
1414 		ck_assert(!exists);
1415 		ck_assert(!value);
1416 	}
1417 }
1418 END_TEST
1419 
START_TEST(quirks_model_apple)1420 START_TEST(quirks_model_apple)
1421 {
1422 	struct litest_device *dev = litest_current_device();
1423 	struct quirks *q;
1424 	bool exists, value = false;
1425 
1426 	q = dev->quirks;
1427 	exists = quirks_get_bool(q, QUIRK_MODEL_APPLE_TOUCHPAD, &value);
1428 
1429 	if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_APPLE) {
1430 		ck_assert(exists);
1431 		ck_assert(value);
1432 	} else {
1433 		ck_assert(!exists);
1434 		ck_assert(!value);
1435 	}
1436 }
1437 END_TEST
1438 
START_TEST(quirks_model_synaptics_serial)1439 START_TEST(quirks_model_synaptics_serial)
1440 {
1441 	struct litest_device *dev = litest_current_device();
1442 	struct quirks *q;
1443 	bool exists, value = false;
1444 
1445 	q = dev->quirks;
1446 	exists = quirks_get_bool(q, QUIRK_MODEL_SYNAPTICS_SERIAL_TOUCHPAD, &value);
1447 
1448 	if (libevdev_get_id_vendor(dev->evdev) == VENDOR_ID_SYNAPTICS_SERIAL &&
1449 	    libevdev_get_id_product(dev->evdev) == PRODUCT_ID_SYNAPTICS_SERIAL) {
1450 		ck_assert(exists);
1451 		ck_assert(value);
1452 	} else {
1453 		ck_assert(!exists);
1454 		ck_assert(!value);
1455 	}
1456 }
1457 END_TEST
1458 
START_TEST(quirks_call_NULL)1459 START_TEST(quirks_call_NULL)
1460 {
1461 	ck_assert(!quirks_fetch_for_device(NULL, NULL));
1462 
1463 	ck_assert(!quirks_get_uint32(NULL, 0, NULL));
1464 	ck_assert(!quirks_get_int32(NULL, 0, NULL));
1465 	ck_assert(!quirks_get_range(NULL, 0, NULL));
1466 	ck_assert(!quirks_get_dimensions(NULL, 0, NULL));
1467 	ck_assert(!quirks_get_double(NULL, 0, NULL));
1468 	ck_assert(!quirks_get_string(NULL, 0, NULL));
1469 	ck_assert(!quirks_get_bool(NULL, 0, NULL));
1470 }
1471 END_TEST
1472 
START_TEST(quirks_ctx_ref)1473 START_TEST(quirks_ctx_ref)
1474 {
1475 	struct quirks_context *ctx, *ctx2;
1476 	const char quirks_file[] =
1477 	"[Section name]\n"
1478 	"MatchUdevType=mouse\n"
1479 	"AttrSizeHint=10x10\n";
1480 	struct data_dir dd = make_data_dir(quirks_file);
1481 
1482 	ctx = quirks_init_subsystem(dd.dirname,
1483 				    NULL,
1484 				    log_handler,
1485 				    NULL,
1486 				    QLOG_CUSTOM_LOG_PRIORITIES);
1487 	ck_assert_notnull(ctx);
1488 	ctx2 = quirks_context_ref(ctx);
1489 	litest_assert_ptr_eq(ctx, ctx2);
1490 	ctx2 = quirks_context_unref(ctx);
1491 	litest_assert_ptr_eq(ctx2, NULL);
1492 	ctx2 = quirks_context_unref(ctx);
1493 	litest_assert_ptr_eq(ctx2, NULL);
1494 	cleanup_data_dir(dd);
1495 }
1496 END_TEST
1497 
TEST_COLLECTION(quirks)1498 TEST_COLLECTION(quirks)
1499 {
1500 	struct range boolean = {0, 2};
1501 
1502 	litest_add_deviceless(quirks_invalid_dir);
1503 	litest_add_deviceless(quirks_empty_dir);
1504 
1505 	litest_add_deviceless(quirks_section_empty);
1506 	litest_add_deviceless(quirks_section_double);
1507 	litest_add_deviceless(quirks_section_missing_match);
1508 	litest_add_deviceless(quirks_section_missing_attr);
1509 	litest_add_deviceless(quirks_section_match_after_attr);
1510 	litest_add_deviceless(quirks_section_duplicate_match);
1511 	litest_add_deviceless(quirks_section_duplicate_attr);
1512 
1513 	litest_add_deviceless(quirks_parse_error_section);
1514 	litest_add_deviceless(quirks_parse_error_trailing_whitespace);
1515 	litest_add_deviceless(quirks_parse_error_unknown_match);
1516 	litest_add_deviceless(quirks_parse_error_unknown_attr);
1517 	litest_add_deviceless(quirks_parse_error_unknown_model);
1518 	litest_add_deviceless(quirks_parse_error_unknown_prefix);
1519 	litest_add_deviceless(quirks_parse_error_model_not_one);
1520 	litest_add_deviceless(quirks_parse_comment_inline);
1521 	litest_add_deviceless(quirks_parse_comment_empty);
1522 	litest_add_deviceless(quirks_parse_string_quotes_single);
1523 	litest_add_deviceless(quirks_parse_string_quotes_double);
1524 
1525 	litest_add_deviceless(quirks_parse_bustype);
1526 	litest_add_deviceless(quirks_parse_bustype_invalid);
1527 	litest_add_deviceless(quirks_parse_vendor);
1528 	litest_add_deviceless(quirks_parse_vendor_invalid);
1529 	litest_add_deviceless(quirks_parse_product);
1530 	litest_add_deviceless(quirks_parse_product_invalid);
1531 	litest_add_deviceless(quirks_parse_version);
1532 	litest_add_deviceless(quirks_parse_version_invalid);
1533 	litest_add_deviceless(quirks_parse_name);
1534 	litest_add_deviceless(quirks_parse_name_invalid);
1535 	litest_add_deviceless(quirks_parse_udev);
1536 	litest_add_deviceless(quirks_parse_udev_invalid);
1537 	litest_add_deviceless(quirks_parse_dmi);
1538 	litest_add_deviceless(quirks_parse_dmi_invalid);
1539 
1540 	litest_add_for_device(quirks_parse_dimension_attr, LITEST_MOUSE);
1541 	litest_add_for_device(quirks_parse_range_attr, LITEST_MOUSE);
1542 	litest_add_for_device(quirks_parse_uint_attr, LITEST_MOUSE);
1543 	litest_add_for_device(quirks_parse_double_attr, LITEST_MOUSE);
1544 	litest_add_for_device(quirks_parse_string_attr, LITEST_MOUSE);
1545 	litest_add_for_device(quirks_parse_bool_attr, LITEST_MOUSE);
1546 	litest_add_for_device(quirks_parse_integration_attr, LITEST_MOUSE);
1547 
1548 	litest_add_for_device(quirks_model_one, LITEST_MOUSE);
1549 	litest_add_for_device(quirks_model_zero, LITEST_MOUSE);
1550 	litest_add_ranged_for_device(quirks_model_override, LITEST_MOUSE, &boolean);
1551 
1552 	litest_add(quirks_model_alps, LITEST_TOUCHPAD, LITEST_ANY);
1553 	litest_add(quirks_model_wacom, LITEST_TOUCHPAD, LITEST_ANY);
1554 	litest_add(quirks_model_apple, LITEST_TOUCHPAD, LITEST_ANY);
1555 	litest_add(quirks_model_synaptics_serial, LITEST_TOUCHPAD, LITEST_ANY);
1556 
1557 	litest_add_deviceless(quirks_call_NULL);
1558 	litest_add_deviceless(quirks_ctx_ref);
1559 }
1560