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