xref: /third_party/libinput/test/test-quirks.c (revision a46c0ec8)
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
33static void
34log_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
44struct data_dir {
45	char *dirname;
46	char *filename;
47};
48
49static struct data_dir
50make_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
76static void
77cleanup_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
89START_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}
100END_TEST
101
102START_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}
116END_TEST
117
118START_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}
132END_TEST
133
134START_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}
148END_TEST
149
150START_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}
166END_TEST
167
168START_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}
184END_TEST
185
186START_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}
204END_TEST
205
206START_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}
224END_TEST
225
226START_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}
247END_TEST
248
249START_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}
266END_TEST
267
268START_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}
285END_TEST
286
287START_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}
304END_TEST
305
306START_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}
323END_TEST
324
325START_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}
342END_TEST
343
344START_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}
361END_TEST
362
363START_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}
380END_TEST
381
382START_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}
400END_TEST
401
402START_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}
422END_TEST
423
424START_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}
442END_TEST
443
444START_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}
462END_TEST
463
464START_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}
498END_TEST
499
500START_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}
517END_TEST
518
519START_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}
545END_TEST
546
547START_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}
577END_TEST
578
579START_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}
605END_TEST
606
607START_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}
637END_TEST
638
639START_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}
665END_TEST
666
667START_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}
697END_TEST
698
699START_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}
737END_TEST
738
739START_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}
760END_TEST
761
762START_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}
804END_TEST
805
806START_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}
833END_TEST
834
835START_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}
857END_TEST
858
859START_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}
889END_TEST
890
891typedef 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 */
904static bool
905test_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
949struct qtest_dim {
950		const char *str;
951		bool success;
952		int w, h;
953};
954
955START_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}
991END_TEST
992
993struct qtest_range {
994		const char *str;
995		bool success;
996		int hi, lo;
997};
998
999START_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}
1043END_TEST
1044
1045struct qtest_uint {
1046	const char *str;
1047	bool success;
1048	uint32_t val;
1049};
1050
1051START_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}
1089END_TEST
1090
1091struct qtest_double {
1092	const char *str;
1093	bool success;
1094	double val;
1095};
1096
1097START_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}
1141END_TEST
1142
1143struct qtest_str {
1144	const char *str;
1145	enum quirk where;
1146};
1147
1148START_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}
1191END_TEST
1192
1193struct qtest_bool {
1194	const char *str;
1195	bool success;
1196	bool val;
1197};
1198
1199START_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}
1232END_TEST
1233
1234START_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}
1265END_TEST
1266
1267START_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}
1298END_TEST
1299
1300START_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}
1331END_TEST
1332
1333START_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}
1379END_TEST
1380
1381START_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}
1399END_TEST
1400
1401START_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}
1418END_TEST
1419
1420START_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}
1437END_TEST
1438
1439START_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}
1457END_TEST
1458
1459START_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}
1471END_TEST
1472
1473START_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}
1496END_TEST
1497
1498TEST_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