test-plugins-lua.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353
  1. /*
  2. * Copyright © 2025 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. #include "config.h"
  24. #include <fcntl.h>
  25. #include <inttypes.h>
  26. #include <valgrind/valgrind.h>
  27. #include "util-files.h"
  28. #include "util-strings.h"
  29. #include "util-time.h"
  30. #include "libinput.h"
  31. #include "litest.h"
  32. static char *
  33. _litest_write_plugin(const char *tmpdir, const char *filename, const char *content)
  34. {
  35. static int counter = 0;
  36. counter += 10;
  37. char *path = strdup_printf("%s/%d-%s.lua", tmpdir, counter, filename);
  38. _autoclose_ int fd = open(path, O_WRONLY | O_CREAT, 0644);
  39. litest_assert_errno_success(fd);
  40. if (content) {
  41. write(fd, content, strlen(content));
  42. fsync(fd);
  43. }
  44. return path;
  45. }
  46. #define litest_write_plugin(tmpdir_, content_) \
  47. _litest_write_plugin(tmpdir_, __func__, content_)
  48. START_TEST(lua_load_failure)
  49. {
  50. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  51. const char *lua = "asfasdk1298'..asdfasdf'123@2;asd"; /* invalid lua */
  52. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  53. _litest_context_destroy_ struct libinput *li =
  54. litest_create_context_with_plugindir(tmpdir->path);
  55. litest_with_logcapture(li, capture) {
  56. libinput_plugin_system_load_plugins(li,
  57. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  58. litest_drain_events(li);
  59. size_t index = 0;
  60. litest_assert(
  61. strv_find_substring(capture->errors, "Failed to load", &index));
  62. litest_assert_str_in(path, capture->errors[index]);
  63. }
  64. }
  65. END_TEST
  66. enum content {
  67. EMPTY,
  68. NOTHING,
  69. BASIC,
  70. COMMENT,
  71. DUPLICATE_CALL,
  72. VERSION_NOT_A_TABLE,
  73. MISSING_REGISTER,
  74. };
  75. START_TEST(lua_load_success_but_no_register)
  76. {
  77. enum content content = litest_test_param_get_i32(test_env->params, "content");
  78. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  79. const char *lua = NULL;
  80. switch (content) {
  81. case DUPLICATE_CALL:
  82. lua = "v1 = libinput:register({1})\np2 = libinput:register({2})\n";
  83. break;
  84. case VERSION_NOT_A_TABLE:
  85. lua = "v1 = libinput:register(1)\n";
  86. break;
  87. case MISSING_REGISTER:
  88. lua = "libinput:connect(\"new-evdev-device\", function(device) assert(false) end)\n";
  89. break;
  90. case BASIC:
  91. lua = "a = 1 + 10";
  92. break;
  93. case COMMENT:
  94. lua = "-- near-empty file";
  95. break;
  96. case NOTHING:
  97. lua = "";
  98. break;
  99. case EMPTY:
  100. break;
  101. }
  102. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  103. _litest_context_destroy_ struct libinput *li =
  104. litest_create_context_with_plugindir(tmpdir->path);
  105. litest_with_logcapture(li, capture) {
  106. libinput_plugin_system_load_plugins(li,
  107. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  108. switch (content) {
  109. case VERSION_NOT_A_TABLE:
  110. litest_assert_strv_substring(capture->errors,
  111. "unloading after error");
  112. break;
  113. case DUPLICATE_CALL:
  114. litest_assert_strv_substring(capture->errors,
  115. "plugin already registered");
  116. break;
  117. default:
  118. litest_assert_strv_substring(capture->errors,
  119. "plugin never registered");
  120. break;
  121. }
  122. }
  123. }
  124. END_TEST
  125. START_TEST(lua_register_noop)
  126. {
  127. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  128. const char *lua = "libinput:register({1})";
  129. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  130. _litest_context_destroy_ struct libinput *li =
  131. litest_create_context_with_plugindir(tmpdir->path);
  132. litest_with_logcapture(li, capture) {
  133. libinput_plugin_system_load_plugins(li,
  134. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  135. litest_drain_events(li);
  136. litest_assert_logcapture_no_errors(capture);
  137. }
  138. }
  139. END_TEST
  140. START_TEST(lua_unregister_is_last)
  141. {
  142. const char *when = litest_test_param_get_string(test_env->params, "when");
  143. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  144. _autofree_ char *lua = strdup_printf(
  145. "libinput:register({1})\n"
  146. "libinput:connect(\"new-evdev-device\", function(device)\n %s\n libinput:log_error(\"abort abort\")\nend)\n"
  147. "%slibinput:log_error(\"must not happen\")",
  148. streq(when, "connect") ? "libinput:unregister()" : "",
  149. streq(when, "run") ? "libinput:unregister()\n" : "--");
  150. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  151. _litest_context_destroy_ struct libinput *li =
  152. litest_create_context_with_plugindir(tmpdir->path);
  153. litest_with_logcapture(li, capture) {
  154. libinput_plugin_system_load_plugins(li,
  155. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  156. _destroy_(litest_device) *device = litest_add_device(li, LITEST_MOUSE);
  157. litest_drain_events(li);
  158. litest_assert_logcapture_no_errors(capture);
  159. }
  160. }
  161. END_TEST
  162. START_TEST(lua_test_logging)
  163. {
  164. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  165. enum libinput_log_priority priority =
  166. litest_test_param_get_i32(test_env->params, "priority");
  167. const char *lua = NULL;
  168. switch (priority) {
  169. case LIBINPUT_LOG_PRIORITY_DEBUG:
  170. lua = "libinput:log_debug(\"deb-ug\");";
  171. break;
  172. case LIBINPUT_LOG_PRIORITY_INFO:
  173. lua = "libinput:log_info(\"inf-o\");";
  174. break;
  175. case LIBINPUT_LOG_PRIORITY_ERROR:
  176. lua = "libinput:log_error(\"err-or\");";
  177. break;
  178. default:
  179. litest_assert_not_reached();
  180. break;
  181. }
  182. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  183. _litest_context_destroy_ struct libinput *li =
  184. litest_create_context_with_plugindir(tmpdir->path);
  185. libinput_log_set_priority(li, priority);
  186. litest_with_logcapture(li, capture) {
  187. libinput_plugin_system_load_plugins(li,
  188. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  189. litest_drain_events(li);
  190. switch (priority) {
  191. case LIBINPUT_LOG_PRIORITY_DEBUG:
  192. litest_assert(
  193. strv_find_substring(capture->debugs, "deb-ug", NULL));
  194. litest_assert(
  195. !strv_find_substring(capture->infos, "inf-o", NULL));
  196. litest_assert(
  197. !strv_find_substring(capture->errors, "err-or", NULL));
  198. break;
  199. case LIBINPUT_LOG_PRIORITY_INFO:
  200. litest_assert(
  201. !strv_find_substring(capture->debugs, "deb-ug", NULL));
  202. litest_assert(
  203. strv_find_substring(capture->infos, "inf-o", NULL));
  204. litest_assert(
  205. !strv_find_substring(capture->errors, "err-or", NULL));
  206. break;
  207. case LIBINPUT_LOG_PRIORITY_ERROR:
  208. litest_assert(
  209. !strv_find_substring(capture->debugs, "deb-ug", NULL));
  210. litest_assert(
  211. !strv_find_substring(capture->infos, "inf-o", NULL));
  212. litest_assert(
  213. strv_find_substring(capture->errors, "err-or", NULL));
  214. break;
  215. }
  216. }
  217. }
  218. END_TEST
  219. START_TEST(lua_test_evdev_global)
  220. {
  221. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  222. /* This is generated, if a few of them work the
  223. * rest should work too */
  224. const char *lua =
  225. "libinput:register({1}); a = evdev.ABS_X\nb = evdev.REL_X\nc = evdev.KEY_A\nd = evdev.EV_SYN\n";
  226. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  227. _litest_context_destroy_ struct libinput *li =
  228. litest_create_context_with_plugindir(tmpdir->path);
  229. litest_with_logcapture(li, capture) {
  230. libinput_plugin_system_load_plugins(li,
  231. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  232. litest_drain_events(li);
  233. litest_assert_logcapture_no_errors(capture);
  234. }
  235. }
  236. END_TEST
  237. START_TEST(lua_test_libinput_now)
  238. {
  239. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  240. const char *lua = "libinput:log_error(\">>>\" .. libinput:now())";
  241. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  242. _litest_context_destroy_ struct libinput *li =
  243. litest_create_context_with_plugindir(tmpdir->path);
  244. litest_with_logcapture(li, capture) {
  245. libinput_plugin_system_load_plugins(li,
  246. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  247. litest_drain_events(li);
  248. usec_t test_now;
  249. int rc = now_in_us(&test_now);
  250. litest_assert_neg_errno_success(rc);
  251. size_t index = 0;
  252. litest_assert(strv_find_substring(capture->errors, ">>>", &index));
  253. size_t nelem = 0;
  254. _autostrvfree_ char **tokens =
  255. strv_from_string(capture->errors[index], ">>>", &nelem);
  256. litest_assert_int_eq(nelem, 2U);
  257. uint64_t plugin_now = strtoull(tokens[1], NULL, 10);
  258. litest_assert_int_le(plugin_now, usec_as_uint64_t(test_now));
  259. /* Even a slow test runner hopefully doesn't take >300ms to get to the
  260. * log print */
  261. litest_assert_int_gt(
  262. plugin_now,
  263. usec_as_uint64_t(usec_sub(test_now, usec_from_millis(300))));
  264. }
  265. }
  266. END_TEST
  267. START_TEST(lua_test_libinput_timer)
  268. {
  269. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  270. const char *mode = litest_test_param_get_string(test_env->params, "mode");
  271. bool reschedule = litest_test_param_get_bool(test_env->params, "reschedule");
  272. _autofree_ char *timeout =
  273. strdup_printf("%s%" PRIu64,
  274. streq(mode, "absolute") ? "libinput:now() + " : "",
  275. usec_as_uint64_t(usec_from_millis(100)));
  276. _autofree_ char *reschedule_timeout =
  277. strdup_printf("libinput:timer_set_%s(%s%" PRIu64 ")\n",
  278. mode,
  279. streq(mode, "absolute") ? "t + " : "",
  280. usec_as_uint64_t(usec_from_millis(100)));
  281. _autofree_ char *lua = strdup_printf(
  282. "libinput:register({1})\n"
  283. "libinput:connect(\"timer-expired\",\n"
  284. " function(t)\n"
  285. " libinput:log_error(\">>>\" .. t)\n"
  286. " %s\n"
  287. " end)\n"
  288. "libinput:timer_set_%s(%s)\n",
  289. reschedule ? reschedule_timeout : "",
  290. mode,
  291. timeout);
  292. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  293. _litest_context_destroy_ struct libinput *li =
  294. litest_create_context_with_plugindir(tmpdir->path);
  295. litest_with_logcapture(li, capture) {
  296. libinput_plugin_system_load_plugins(li,
  297. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  298. litest_drain_events(li);
  299. litest_assert_logcapture_no_errors(capture);
  300. size_t nloops = reschedule ? 4 : 1;
  301. for (size_t i = 0; i < nloops; i++) {
  302. libinput_dispatch(li);
  303. msleep(100);
  304. libinput_dispatch(li);
  305. usec_t test_now;
  306. int rc = now_in_us(&test_now);
  307. litest_assert_neg_errno_success(rc);
  308. _autostrvfree_ char **msg = steal(&capture->errors);
  309. litest_assert_ptr_notnull(msg);
  310. size_t index;
  311. litest_assert(strv_find_substring(msg, ">>>", &index));
  312. size_t nelem = 0;
  313. _autostrvfree_ char **tokens =
  314. strv_from_string(msg[index], ">>>", &nelem);
  315. litest_assert_int_eq(nelem, 2U);
  316. uint64_t plugin_now = strtoull(tokens[1], NULL, 10);
  317. litest_assert_int_le(plugin_now, usec_as_uint64_t(test_now));
  318. /* Even a slow test runner hopefully doesn't take >300ms between
  319. * dispatch and now_in_us */
  320. litest_assert_int_gt(
  321. plugin_now,
  322. usec_as_uint64_t(
  323. usec_sub(test_now, usec_from_millis(300))));
  324. }
  325. if (!reschedule) {
  326. libinput_dispatch(li);
  327. msleep(120);
  328. libinput_dispatch(li);
  329. }
  330. litest_assert_logcapture_no_errors(capture);
  331. }
  332. }
  333. END_TEST
  334. enum connect_error {
  335. BAD_TYPE,
  336. TOO_FEW_ARGS,
  337. TOO_MANY_ARGS,
  338. };
  339. START_TEST(lua_bad_connect)
  340. {
  341. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  342. const char *handler = litest_test_param_get_string(test_env->params, "handler");
  343. enum connect_error error = litest_test_param_get_i32(test_env->params, "error");
  344. const char *func = NULL;
  345. switch (error) {
  346. case BAD_TYPE:
  347. func = "a";
  348. break;
  349. case TOO_FEW_ARGS:
  350. func = "function(p) libinput:log_debug(\"few\"); end";
  351. break;
  352. case TOO_MANY_ARGS:
  353. func = "function(p, a, b) libinput:log_debug(\"many\"); end";
  354. break;
  355. }
  356. _autofree_ char *lua = strdup_printf(
  357. "libinput:register({1})\n"
  358. "a = 10\n"
  359. "libinput:connect(\"%s\", %s)\n",
  360. handler,
  361. func);
  362. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  363. _litest_context_destroy_ struct libinput *li =
  364. litest_create_context_with_plugindir(tmpdir->path);
  365. litest_with_logcapture(li, capture) {
  366. libinput_plugin_system_load_plugins(li,
  367. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  368. litest_drain_events(li);
  369. switch (error) {
  370. /* These don't trigger a lua erro so we just test they don't segfault us
  371. */
  372. case TOO_FEW_ARGS:
  373. case TOO_MANY_ARGS:
  374. litest_assert_logcapture_no_errors(capture);
  375. break;
  376. case BAD_TYPE:
  377. litest_assert_strv_substring(capture->errors,
  378. "bad argument #2 to 'connect'");
  379. break;
  380. }
  381. }
  382. }
  383. END_TEST
  384. START_TEST(lua_register_multiversions)
  385. {
  386. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  387. const char *lua =
  388. "v = libinput:register({1, 3, 4, 10, 15})\nlibinput:log_info(\"VERSION:\" .. v)\n";
  389. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  390. _litest_context_destroy_ struct libinput *li =
  391. litest_create_context_with_plugindir(tmpdir->path);
  392. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_INFO)
  393. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO);
  394. litest_with_logcapture(li, capture) {
  395. libinput_plugin_system_load_plugins(li,
  396. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  397. litest_drain_events(li);
  398. litest_assert_logcapture_no_errors(capture);
  399. litest_assert_strv_substring(capture->infos, "VERSION:1");
  400. }
  401. }
  402. END_TEST
  403. START_TEST(lua_allowed_functions)
  404. {
  405. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  406. /* This tests on the assumption that if some of these work,
  407. * then the others we allow will work too. */
  408. const char *lua =
  409. "\n"
  410. "libinput:register({1})\n"
  411. "a = {10, 20}\n"
  412. "for _, v in ipairs(a) do\n"
  413. " v = v + 1\n"
  414. "end\n"
  415. "b = {foo = 1}"
  416. "for k, v in pairs(a) do\n"
  417. " v = v + 1\n"
  418. "end\n"
  419. "print(math.maxinteger)\n"
  420. "table.sort({10, 2, 4})\n"
  421. "assert(true)\n"
  422. "";
  423. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  424. _litest_context_destroy_ struct libinput *li =
  425. litest_create_context_with_plugindir(tmpdir->path);
  426. litest_with_logcapture(li, capture) {
  427. libinput_plugin_system_load_plugins(li,
  428. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  429. litest_drain_events(li);
  430. litest_assert_logcapture_no_errors(capture);
  431. }
  432. }
  433. END_TEST
  434. START_TEST(lua_disallowed_functions)
  435. {
  436. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  437. /* This tests on the assumption that if some of these work,
  438. * then the others we allow will work too. */
  439. const char *lua =
  440. "\n"
  441. "libinput:register({1})\n"
  442. "assert(io == nil)\n"
  443. "assert(require == nil)\n"
  444. "assert(rawget == nil)\n"
  445. "assert(rawset == nil)\n"
  446. "assert(setfenv == nil)\n"
  447. "assert(getmetatable == nil)\n"
  448. "assert(setmetatable == nil)\n"
  449. "assert(package == nil)\n"
  450. "assert(os == nil)\n"
  451. "assert(debug == nil)\n"
  452. "";
  453. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  454. _litest_context_destroy_ struct libinput *li =
  455. litest_create_context_with_plugindir(tmpdir->path);
  456. litest_with_logcapture(li, capture) {
  457. libinput_plugin_system_load_plugins(li,
  458. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  459. litest_drain_events(li);
  460. litest_assert_logcapture_no_errors(capture);
  461. }
  462. }
  463. END_TEST
  464. START_TEST(lua_gc_not_accessible)
  465. {
  466. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  467. const char *lua =
  468. "libinput:register({1})\n"
  469. "assert(libinput.__gc == nil)\n"
  470. "function check_device_gc(device)\n"
  471. " assert(device.__gc == nil)\n"
  472. " libinput:log_info(\"gc_not_accessible: ok\")\n"
  473. "end\n"
  474. "libinput:connect(\"new-evdev-device\", check_device_gc)\n";
  475. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  476. _litest_context_destroy_ struct libinput *li =
  477. litest_create_context_with_plugindir(tmpdir->path);
  478. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_INFO)
  479. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO);
  480. litest_with_logcapture(li, capture) {
  481. libinput_plugin_system_load_plugins(li,
  482. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  483. litest_drain_events(li);
  484. _destroy_(litest_device) *device = litest_add_device(li, LITEST_MOUSE);
  485. litest_drain_events(li);
  486. litest_assert_logcapture_no_errors(capture);
  487. litest_assert_strv_substring(capture->infos, "gc_not_accessible: ok");
  488. }
  489. }
  490. END_TEST
  491. START_TEST(lua_frame_handler)
  492. {
  493. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  494. const char *lua =
  495. "libinput:register({1})\n"
  496. "function frame_handler(_, frame, timestamp)\n"
  497. " libinput:log_info(\"T:\" .. timestamp)\n"
  498. " for _, e in ipairs(frame) do\n"
  499. " libinput:log_info(\"E:\" .. e.usage .. \":\" .. e.value)\n"
  500. " end\n"
  501. "end\n"
  502. "libinput:connect(\"new-evdev-device\", function(device) device:connect(\"evdev-frame\", frame_handler) end)\n";
  503. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  504. _litest_context_destroy_ struct libinput *li =
  505. litest_create_context_with_plugindir(tmpdir->path);
  506. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_INFO)
  507. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO);
  508. litest_with_logcapture(li, capture) {
  509. libinput_plugin_system_load_plugins(li,
  510. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  511. litest_drain_events(li);
  512. _destroy_(litest_device) *device = litest_add_device(li, LITEST_MOUSE);
  513. litest_drain_events(li);
  514. usec_t before, after;
  515. now_in_us(&before);
  516. msleep(1);
  517. litest_button_click_debounced(device, li, BTN_LEFT, 1);
  518. litest_button_click_debounced(device, li, BTN_LEFT, 0);
  519. litest_assert_logcapture_no_errors(capture);
  520. msleep(1);
  521. now_in_us(&after);
  522. /* EV_KEY << 16 | BTN_LEFT -> 65808 */
  523. litest_assert_strv_substring(capture->infos, "E:65808:1");
  524. litest_assert_strv_substring(capture->infos, "E:65808:0");
  525. /* SYN_REPORT shouldn't show up in the frame */
  526. litest_assert(!strv_find_substring(capture->infos, "E:0:0", NULL));
  527. size_t idx;
  528. litest_assert(strv_find_substring(capture->infos, "T:", &idx));
  529. _autofree_ char *str = safe_strdup(capture->infos[idx]);
  530. for (size_t i = 0; str[i]; i++) {
  531. if (str[i] == '\n') {
  532. str[i] = '\0';
  533. break;
  534. }
  535. }
  536. size_t nelems;
  537. _autostrvfree_ char **split = strv_from_string(str, ":", &nelems);
  538. litest_assert_int_gt(nelems, 1U);
  539. char *strtime = split[nelems - 1];
  540. uint64_t timestamp = 0;
  541. litest_assert(safe_atou64(strtime, &timestamp));
  542. litest_assert_int_gt(timestamp, usec_as_uint64_t(before));
  543. litest_assert_int_lt(timestamp, usec_as_uint64_t(after));
  544. }
  545. }
  546. END_TEST
  547. START_TEST(lua_device_info)
  548. {
  549. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  550. const char *lua =
  551. "libinput:register({1})\n"
  552. "function info_printer(device)\n"
  553. " local info = device:info()\n"
  554. " libinput:log_info(\"BUS:\" .. info.bustype)\n"
  555. " libinput:log_info(\"VID:\" .. info.vid)\n"
  556. " libinput:log_info(\"PID:\" .. info.pid)\n"
  557. "end\n"
  558. "libinput:connect(\"new-evdev-device\", info_printer)\n";
  559. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  560. _litest_context_destroy_ struct libinput *li =
  561. litest_create_context_with_plugindir(tmpdir->path);
  562. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_INFO)
  563. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO);
  564. litest_with_logcapture(li, capture) {
  565. libinput_plugin_system_load_plugins(li,
  566. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  567. litest_drain_events(li);
  568. _destroy_(litest_device) *device = litest_add_device(li, LITEST_MOUSE);
  569. litest_drain_events(li);
  570. litest_assert_strv_substring(capture->infos, "BUS:3");
  571. litest_assert_strv_substring(capture->infos, "VID:6127");
  572. litest_assert_strv_substring(capture->infos, "PID:24601");
  573. }
  574. }
  575. END_TEST
  576. START_TEST(lua_set_absinfo)
  577. {
  578. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  579. const char *lua =
  580. "libinput:register({1})\n"
  581. "function absinfo_setter(device)\n"
  582. " local absinfos = device:absinfos()\n"
  583. " for u, a in pairs(absinfos) do\n"
  584. " libinput:log_info(\"A:\" .. u .. \":\" .. a.minimum .. \":\" .. a.maximum .. \":\" .. a.resolution .. \":\" .. a.fuzz .. \":\" .. a.flat)\n"
  585. " end\n"
  586. " device:set_absinfo(evdev.ABS_X, { minimum = 0, maximum = 1000, resolution = 100 })\n"
  587. " device:set_absinfo(evdev.ABS_Y, { minimum = 0, maximum = 200, resolution = 10 })\n"
  588. " device:set_absinfo(evdev.ABS_MT_POSITION_X, { minimum = 0, maximum = 1000, resolution = 100 })\n"
  589. " device:set_absinfo(evdev.ABS_MT_POSITION_Y, { minimum = 0, maximum = 200, resolution = 10 })\n"
  590. "end\n"
  591. "libinput:connect(\"new-evdev-device\", absinfo_setter)\n";
  592. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  593. _litest_context_destroy_ struct libinput *li =
  594. litest_create_context_with_plugindir(tmpdir->path);
  595. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_INFO)
  596. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO);
  597. litest_with_logcapture(li, capture) {
  598. libinput_plugin_system_load_plugins(li,
  599. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  600. litest_drain_events(li);
  601. _destroy_(litest_device) *device =
  602. litest_add_device(li, LITEST_GENERIC_MULTITOUCH_SCREEN);
  603. litest_drain_events(li);
  604. litest_assert_logcapture_no_errors(capture);
  605. for (int code = 0; code <= ABS_MAX; code++) {
  606. if (!libevdev_has_event_code(device->evdev, EV_ABS, code)) {
  607. _autofree_ char *prefix =
  608. strdup_printf("A:%u", (EV_ABS << 16) | code);
  609. litest_assert(!strv_find_substring(capture->infos,
  610. prefix,
  611. NULL));
  612. continue;
  613. }
  614. const struct input_absinfo *absinfo =
  615. libevdev_get_abs_info(device->evdev, code);
  616. _autofree_ char *message = strdup_printf("A:%u:%d:%d:%d:%d:%d",
  617. (EV_ABS << 16) | code,
  618. absinfo->minimum,
  619. absinfo->maximum,
  620. absinfo->resolution,
  621. absinfo->fuzz,
  622. absinfo->flat);
  623. litest_assert_strv_substring(capture->infos, message);
  624. }
  625. /* If the absinfo worked, our device is 10x20mm big */
  626. double w, h;
  627. libinput_device_get_size(device->libinput_device, &w, &h);
  628. litest_assert_double_eq(w, 10.0);
  629. litest_assert_double_eq(h, 20.0);
  630. }
  631. }
  632. END_TEST
  633. START_TEST(lua_enable_disable_evdev_usage)
  634. {
  635. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  636. /* We have two plugins here, one that enables codes and one that prints
  637. * the frame.
  638. *
  639. * The first plugin also inserts a REL_Z event into the frame since we
  640. * can't send that through the kernel.
  641. */
  642. const char *lua1 =
  643. "libinput:register({1})\n"
  644. "function frame_handler(_, frame, timestamp)\n"
  645. " table.insert(frame, { usage = evdev.REL_Z, value = 3 })\n"
  646. " return frame\n"
  647. "end\n"
  648. "function enabler(device)\n"
  649. " device:enable_evdev_usage(evdev.REL_Z)\n"
  650. " device:enable_evdev_usage(evdev.BTN_STYLUS2)\n"
  651. " device:disable_evdev_usage(evdev.REL_WHEEL)\n"
  652. " device:connect(\"evdev-frame\", frame_handler)\n"
  653. "end\n"
  654. "libinput:connect(\"new-evdev-device\", enabler)\n";
  655. const char *lua2 =
  656. "libinput:register({1})\n"
  657. "function frame_handler(_, frame, timestamp)\n"
  658. " libinput:log_info(\"frame\")\n"
  659. " for _, e in ipairs(frame) do\n"
  660. " libinput:log_info(\"E:\" .. e.usage .. \":\" .. e.value)\n"
  661. " end\n"
  662. "end\n"
  663. "function f(device)\n"
  664. " libinput:log_info(\"F: \" .. device:name())\n"
  665. " device:connect(\"evdev-frame\", frame_handler)\n"
  666. "end\n"
  667. "libinput:connect(\"new-evdev-device\", f)\n";
  668. _autofree_ char *p1 = litest_write_plugin(tmpdir->path, lua1);
  669. _autofree_ char *p2 = litest_write_plugin(tmpdir->path, lua2);
  670. _litest_context_destroy_ struct libinput *li =
  671. litest_create_context_with_plugindir(tmpdir->path);
  672. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_INFO)
  673. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO);
  674. litest_with_logcapture(li, capture) {
  675. libinput_plugin_system_load_plugins(li,
  676. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  677. litest_drain_events(li);
  678. _destroy_(litest_device) *device = litest_add_device(li, LITEST_MOUSE);
  679. litest_drain_events(li);
  680. /* We enabled that one ourselves */
  681. litest_assert(
  682. libinput_device_pointer_has_button(device->libinput_device,
  683. BTN_STYLUS2));
  684. litest_assert_logcapture_no_errors(capture);
  685. litest_event(device, EV_REL, REL_X, 1);
  686. litest_event(device, EV_REL, REL_Y, 2);
  687. litest_event(device, EV_REL, REL_WHEEL, -1);
  688. litest_event(device, EV_SYN, SYN_REPORT, 0);
  689. litest_dispatch(li);
  690. litest_assert_logcapture_no_errors(capture);
  691. litest_assert_strv_substring(capture->infos, "E:131072:1");
  692. litest_assert_strv_substring(capture->infos, "E:131073:2");
  693. litest_assert_strv_substring(capture->infos, "E:131074:3");
  694. litest_assert(!strv_find_substring(capture->infos, "E:131080", NULL));
  695. }
  696. }
  697. END_TEST
  698. START_TEST(lua_udev_properties)
  699. {
  700. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  701. const char *lua =
  702. "libinput:register({1})\n"
  703. "function prop_printer(device)\n"
  704. " local properties = device:udev_properties()\n"
  705. " for k, v in pairs(properties) do\n"
  706. " libinput:log_info(k .. \"=\" .. v)\n"
  707. " end\n"
  708. "end\n"
  709. "libinput:connect(\"new-evdev-device\", prop_printer)\n";
  710. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  711. _litest_context_destroy_ struct libinput *li =
  712. litest_create_context_with_plugindir(tmpdir->path);
  713. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_INFO)
  714. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_INFO);
  715. litest_with_logcapture(li, capture) {
  716. libinput_plugin_system_load_plugins(li,
  717. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  718. litest_drain_events(li);
  719. enum litest_device_type which =
  720. litest_test_param_get_i32(test_env->params, "which");
  721. _destroy_(litest_device) *device = litest_add_device(li, which);
  722. litest_drain_events(li);
  723. litest_assert_logcapture_no_errors(capture);
  724. switch (which) {
  725. case LITEST_TRACKPOINT:
  726. litest_assert_strv_substring(capture->infos,
  727. "ID_INPUT_POINTINGSTICK=1");
  728. _fallthrough_;
  729. case LITEST_MOUSE:
  730. litest_assert_strv_substring(capture->infos,
  731. "ID_INPUT_MOUSE=1");
  732. break;
  733. case LITEST_GENERIC_MULTITOUCH_SCREEN:
  734. litest_assert_strv_substring(capture->infos,
  735. "ID_INPUT_TOUCHSCREEN=1");
  736. break;
  737. default:
  738. litest_assert_not_reached();
  739. break;
  740. }
  741. litest_assert(!strv_find_substring(capture->infos,
  742. "ID_INPUT_WIDTH_MM",
  743. NULL));
  744. litest_assert(!strv_find_substring(capture->infos,
  745. "ID_INPUT_WIDTH_MM",
  746. NULL));
  747. }
  748. }
  749. END_TEST
  750. START_TEST(lua_append_prepend_frame)
  751. {
  752. bool append = litest_test_param_get_bool(test_env->params, "append");
  753. bool in_timer = litest_test_param_get_bool(test_env->params, "in_timer");
  754. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  755. _autofree_ char *lua = strdup_printf(
  756. "libinput:register({1})\n"
  757. "mydev = nil\n"
  758. "function frame_handler(device, frame, timestamp)\n"
  759. " device:%s_frame({{ usage = evdev.BTN_LEFT, value = 1}})\n" /* commented
  760. out
  761. if
  762. !in_timer
  763. */
  764. " return nil\n"
  765. "end\n"
  766. "libinput:connect(\"new-evdev-device\", function(device)\n"
  767. " mydev = device\n"
  768. " %sdevice:connect(\"evdev-frame\", frame_handler)\n"
  769. " %slibinput:timer_set_relative(200000)\n" /* commented out if
  770. !in_timer */
  771. "end)\n"
  772. "function timer_expired(t)\n"
  773. " mydev:%s_frame({{ usage = evdev.BTN_LEFT, value = 1 }})\n"
  774. "end\n"
  775. "libinput:connect(\"timer-expired\", timer_expired)\n",
  776. append ? "append" : "prepend",
  777. in_timer ? "-- " : "",
  778. in_timer ? "" : "-- ",
  779. append ? "append" : "prepend");
  780. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  781. _litest_context_destroy_ struct libinput *li =
  782. litest_create_context_with_plugindir(tmpdir->path);
  783. libinput_plugin_system_load_plugins(li, LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  784. litest_drain_events(li);
  785. _destroy_(litest_device) *device = litest_add_device(li, LITEST_MOUSE);
  786. litest_drain_events(li);
  787. msleep(10); /* trigger the timer, if any */
  788. litest_dispatch(li);
  789. if (in_timer) {
  790. litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
  791. }
  792. litest_event(device, EV_REL, REL_X, 1);
  793. litest_event(device, EV_REL, REL_Y, 2);
  794. litest_event(device, EV_SYN, SYN_REPORT, 0);
  795. litest_dispatch(li);
  796. litest_timeout_debounce(li);
  797. litest_dispatch(li);
  798. if (!in_timer && !append) {
  799. litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
  800. }
  801. _destroy_(libinput_event) *ev = libinput_get_event(li);
  802. litest_is_motion_event(ev);
  803. if (!in_timer && append) {
  804. litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
  805. }
  806. litest_assert_empty_queue(li);
  807. }
  808. END_TEST
  809. START_TEST(lua_ignore_unsupported_codes)
  810. {
  811. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  812. _autofree_ char *lua = strdup_printf(
  813. "libinput:register({1})\n"
  814. "function frame_handler(device, frame, timestamp)\n"
  815. " local events = {}\n"
  816. " for _, v in ipairs(frame) do\n"
  817. " table.insert(events, { usage = v.usage, value = v.value })\n"
  818. " end\n"
  819. " table.insert(events, { usage = evdev.ABS_X, value = 1000 })\n"
  820. " table.insert(events, { usage = evdev.ABS_Y, value = 100 })\n"
  821. " table.insert(events, { usage = evdev.BTN_BACK, value = 1 })\n"
  822. " table.insert(events, { usage = evdev.BTN_LEFT, value = 1 })\n" /* this
  823. one actually exists */
  824. " return events\n"
  825. "end\n"
  826. "libinput:connect(\"new-evdev-device\", function(device)\n"
  827. " device:connect(\"evdev-frame\", frame_handler)\n"
  828. "end)\n");
  829. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  830. _litest_context_destroy_ struct libinput *li =
  831. litest_create_context_with_plugindir(tmpdir->path);
  832. libinput_plugin_system_load_plugins(li, LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  833. litest_drain_events(li);
  834. _destroy_(litest_device) *device = litest_add_device(li, LITEST_MOUSE);
  835. litest_drain_events(li);
  836. litest_event(device, EV_REL, REL_X, 1);
  837. litest_event(device, EV_REL, REL_Y, 2);
  838. litest_event(device, EV_SYN, SYN_REPORT, 0);
  839. litest_dispatch(li);
  840. litest_timeout_debounce(li);
  841. litest_dispatch(li);
  842. _destroy_(libinput_event) *ev = libinput_get_event(li);
  843. litest_is_motion_event(ev);
  844. litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
  845. litest_assert_empty_queue(li);
  846. }
  847. END_TEST
  848. enum when {
  849. DEVICE_NEW,
  850. FIRST_FRAME,
  851. };
  852. START_TEST(lua_disable_button_debounce)
  853. {
  854. enum when when = litest_test_param_get_i32(test_env->params, "when");
  855. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  856. _autofree_ char *lua = strdup_printf(
  857. "libinput:register({1})\n"
  858. "function frame_handler(device, _, _)\n"
  859. " device:disable_feature(\"button-debouncing\")\n"
  860. "end\n"
  861. "function new_device(device)\n"
  862. " %s device:disable_feature(\"button-debouncing\")\n"
  863. " %s device:connect(\"evdev-frame\", frame_handler)\n"
  864. "end\n"
  865. "libinput:connect(\"new-evdev-device\", new_device)\n",
  866. when == DEVICE_NEW ? "" : "--",
  867. when == FIRST_FRAME ? "" : "--");
  868. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  869. _litest_context_destroy_ struct libinput *li =
  870. litest_create_context_with_plugindir(tmpdir->path);
  871. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_DEBUG)
  872. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_DEBUG);
  873. litest_with_logcapture(li, capture) {
  874. libinput_plugin_system_load_plugins(li,
  875. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  876. litest_drain_events(li);
  877. _destroy_(litest_device) *dev = litest_add_device(li, LITEST_MOUSE);
  878. litest_drain_events(li);
  879. litest_disable_middleemu(dev);
  880. litest_event(dev, EV_KEY, BTN_LEFT, 1);
  881. litest_event(dev, EV_SYN, SYN_REPORT, 0);
  882. litest_event(dev, EV_KEY, BTN_LEFT, 0);
  883. litest_event(dev, EV_SYN, SYN_REPORT, 0);
  884. litest_event(dev, EV_KEY, BTN_LEFT, 1);
  885. litest_event(dev, EV_SYN, SYN_REPORT, 0);
  886. litest_event(dev, EV_KEY, BTN_LEFT, 0);
  887. litest_event(dev, EV_SYN, SYN_REPORT, 0);
  888. litest_timeout_debounce(li);
  889. litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
  890. litest_assert_button_event(li,
  891. BTN_LEFT,
  892. LIBINPUT_BUTTON_STATE_RELEASED);
  893. litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
  894. litest_assert_button_event(li,
  895. BTN_LEFT,
  896. LIBINPUT_BUTTON_STATE_RELEASED);
  897. litest_assert_empty_queue(li);
  898. litest_assert_strv_substring(capture->debugs,
  899. "disabled button debouncing on request");
  900. }
  901. }
  902. END_TEST
  903. START_TEST(lua_disable_touchpad_jump_detection)
  904. {
  905. enum when when = litest_test_param_get_i32(test_env->params, "when");
  906. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  907. _autofree_ char *lua = strdup_printf(
  908. "libinput:register({1})\n"
  909. "function frame_handler(dev, f, ts)\n"
  910. " dev:disable_feature(\"touchpad-jump-detection\")\n"
  911. "end\n"
  912. "function new_device(device)\n"
  913. " %sdevice:disable_feature(\"touchpad-jump-detection\")\n"
  914. " %sdevice:connect(\"evdev-frame\", frame_handler)\n"
  915. "end\n"
  916. "libinput:connect(\"new-evdev-device\", new_device)\n",
  917. when == DEVICE_NEW ? "" : "-- ",
  918. when == FIRST_FRAME ? "" : "-- ");
  919. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  920. _litest_context_destroy_ struct libinput *li =
  921. litest_create_context_with_plugindir(tmpdir->path);
  922. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_DEBUG)
  923. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_DEBUG);
  924. litest_with_logcapture(li, capture) {
  925. libinput_plugin_system_load_plugins(li,
  926. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  927. litest_drain_events(li);
  928. _destroy_(litest_device) *dev =
  929. litest_add_device(li, LITEST_SYNAPTICS_RMI4);
  930. litest_drain_events(li);
  931. litest_touch_down(dev, 0, 40, 50);
  932. litest_touch_move(dev, 0, 80, 80);
  933. litest_touch_move(dev, 0, 90, 90);
  934. litest_touch_up(dev, 0);
  935. litest_assert_only_typed_events(li, LIBINPUT_EVENT_POINTER_MOTION);
  936. litest_assert_empty_queue(li);
  937. litest_assert(!strv_find_substring(capture->infos,
  938. "Touch jump detected and discarded",
  939. NULL));
  940. }
  941. }
  942. END_TEST
  943. START_TEST(lua_disable_wheel_debouncing)
  944. {
  945. enum when when = litest_test_param_get_i32(test_env->params, "when");
  946. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  947. _autofree_ char *lua = strdup_printf(
  948. "libinput:register({1})\n"
  949. "function frame_handler(device, _, _)\n"
  950. " device:disable_feature(\"wheel-debouncing\")\n"
  951. "end\n"
  952. "function new_device(device)\n"
  953. " %s device:disable_feature(\"wheel-debouncing\")\n"
  954. " %s device:connect(\"evdev-frame\", frame_handler)\n"
  955. "end\n"
  956. "libinput:connect(\"new-evdev-device\", new_device)\n",
  957. when == DEVICE_NEW ? "" : "--",
  958. when == FIRST_FRAME ? "" : "--");
  959. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  960. _litest_context_destroy_ struct libinput *li =
  961. litest_create_context_with_plugindir(tmpdir->path);
  962. if (libinput_log_get_priority(li) > LIBINPUT_LOG_PRIORITY_DEBUG)
  963. libinput_log_set_priority(li, LIBINPUT_LOG_PRIORITY_DEBUG);
  964. litest_with_logcapture(li, capture) {
  965. libinput_plugin_system_load_plugins(li,
  966. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  967. _destroy_(litest_device) *dev = litest_add_device(li, LITEST_MOUSE);
  968. litest_drain_events(li);
  969. for (size_t i = 0; i < 4; i++) {
  970. /* Send a small wheel events - when debouncing is disabled, they
  971. * should all be delivered immediately without delay */
  972. litest_event(dev, EV_REL, REL_WHEEL_HI_RES, 10);
  973. litest_event(dev, EV_SYN, SYN_REPORT, 0);
  974. litest_dispatch(li);
  975. _destroy_(libinput_event) *ev = libinput_get_event(li);
  976. auto ptrev = litest_is_axis_event(
  977. ev,
  978. LIBINPUT_EVENT_POINTER_SCROLL_WHEEL,
  979. LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL,
  980. 0);
  981. double v120 = libinput_event_pointer_get_scroll_value_v120(
  982. ptrev,
  983. LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
  984. litest_assert_double_eq(v120, -10);
  985. }
  986. litest_assert_empty_queue(li);
  987. litest_assert_strv_substring(capture->debugs,
  988. "disabled wheel debouncing on request");
  989. }
  990. }
  991. END_TEST
  992. START_TEST(lua_remove_plugin_on_timeout)
  993. {
  994. enum when when = litest_test_param_get_i32(test_env->params, "when");
  995. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  996. _autofree_ char *lua = strdup_printf(
  997. "libinput:register({1})\n"
  998. "function infinite_loop(device)\n"
  999. " local i = 0\n"
  1000. " while true do\n"
  1001. " i = i + 1\n"
  1002. " end\n"
  1003. "end\n"
  1004. "function new_device(device)\n"
  1005. " device:connect(\"evdev-frame\", infinite_loop)\n"
  1006. "end\n"
  1007. "%s libinput:connect(\"new-evdev-device\", infinite_loop)\n"
  1008. "%s libinput:connect(\"new-evdev-device\", new_device)\n",
  1009. when == DEVICE_NEW ? "" : "--",
  1010. when == FIRST_FRAME ? "" : "--");
  1011. _autofree_ char *path = litest_write_plugin(tmpdir->path, lua);
  1012. _litest_context_destroy_ struct libinput *li =
  1013. litest_create_context_with_plugindir(tmpdir->path);
  1014. _destroy_(litest_device) *dev = NULL;
  1015. litest_with_logcapture(li, capture) {
  1016. libinput_plugin_system_load_plugins(li,
  1017. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  1018. litest_drain_events(li);
  1019. usec_t before = usec_from_now();
  1020. dev = litest_add_device(li, LITEST_MOUSE);
  1021. litest_drain_events(li);
  1022. if (when == FIRST_FRAME) {
  1023. litest_event(dev, EV_KEY, BTN_LEFT, 1);
  1024. litest_event(dev, EV_SYN, SYN_REPORT, 0);
  1025. litest_dispatch(li);
  1026. litest_event(dev, EV_KEY, BTN_LEFT, 0);
  1027. litest_event(dev, EV_SYN, SYN_REPORT, 0);
  1028. litest_dispatch(li);
  1029. }
  1030. usec_t after = usec_from_now();
  1031. usec_t elapsed = usec_delta(after, before);
  1032. /* verify the timeout kicked in around ~1 second (but less than 2s) */
  1033. litest_assert_int_ge(usec_to_millis(elapsed), 1000U);
  1034. if (!RUNNING_ON_VALGRIND)
  1035. litest_assert_int_lt(usec_to_millis(elapsed), 2000U);
  1036. size_t index = 0;
  1037. litest_assert(strv_find_substring(capture->errors,
  1038. "Plugin execution timeout",
  1039. &index));
  1040. litest_assert_str_in("exceeded 1 second", capture->errors[index]);
  1041. litest_assert(strv_find_substring(capture->errors,
  1042. "unloading after error",
  1043. NULL));
  1044. }
  1045. /* device events should go through now */
  1046. litest_event(dev, EV_KEY, BTN_LEFT, 1);
  1047. litest_event(dev, EV_SYN, SYN_REPORT, 0);
  1048. litest_dispatch(li);
  1049. litest_assert_button_event(li, BTN_LEFT, LIBINPUT_BUTTON_STATE_PRESSED);
  1050. }
  1051. END_TEST
  1052. /* Pre-compiled Lua 5.4 bytecode for the following source:
  1053. *
  1054. * libinput:register({1})
  1055. * libinput:connect("new-evdev-device", function(device)
  1056. * libinput:log_info("loaded from binary lua file")
  1057. * end)
  1058. *
  1059. * To regenerate:
  1060. * luac5.4 -o /dev/stdout /tmp/plugin.lua | xxd -i
  1061. */
  1062. static const unsigned char binary_lua_plugin[] = {
  1063. 0x1b, 0x4c, 0x75, 0x61, 0x54, 0x00, 0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a, 0x04,
  1064. 0x08, 0x08, 0x78, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  1065. 0x00, 0x00, 0x28, 0x77, 0x40, 0x01, 0x9b, 0x40, 0x74, 0x65, 0x73, 0x74, 0x2f,
  1066. 0x31, 0x30, 0x2d, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x2d, 0x70, 0x6c, 0x75,
  1067. 0x67, 0x69, 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x80, 0x80, 0x00, 0x01, 0x04, 0x8e,
  1068. 0x51, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00, 0x01, 0x13,
  1069. 0x01, 0x00, 0x01, 0x52, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x80, 0x4e, 0x01,
  1070. 0x01, 0x00, 0x44, 0x00, 0x03, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x14, 0x80, 0x00,
  1071. 0x02, 0x03, 0x81, 0x01, 0x00, 0xcf, 0x01, 0x00, 0x00, 0x44, 0x00, 0x04, 0x01,
  1072. 0x46, 0x00, 0x01, 0x01, 0x84, 0x04, 0x89, 0x6c, 0x69, 0x62, 0x69, 0x6e, 0x70,
  1073. 0x75, 0x74, 0x04, 0x89, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x04,
  1074. 0x88, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x04, 0x91, 0x6e, 0x65, 0x77,
  1075. 0x2d, 0x65, 0x76, 0x64, 0x65, 0x76, 0x2d, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65,
  1076. 0x81, 0x01, 0x00, 0x00, 0x81, 0x80, 0x8d, 0x8f, 0x01, 0x00, 0x04, 0x85, 0x8b,
  1077. 0x00, 0x00, 0x00, 0x94, 0x80, 0x01, 0x01, 0x83, 0x01, 0x01, 0x00, 0xc4, 0x00,
  1078. 0x03, 0x01, 0xc7, 0x00, 0x01, 0x00, 0x83, 0x04, 0x89, 0x6c, 0x69, 0x62, 0x69,
  1079. 0x6e, 0x70, 0x75, 0x74, 0x04, 0x89, 0x6c, 0x6f, 0x67, 0x5f, 0x69, 0x6e, 0x66,
  1080. 0x6f, 0x04, 0x9c, 0x6c, 0x6f, 0x61, 0x64, 0x65, 0x64, 0x20, 0x66, 0x72, 0x6f,
  1081. 0x6d, 0x20, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x20, 0x6c, 0x75, 0x61, 0x20,
  1082. 0x66, 0x69, 0x6c, 0x65, 0x81, 0x00, 0x00, 0x00, 0x80, 0x85, 0x01, 0x00, 0x00,
  1083. 0x00, 0x01, 0x80, 0x81, 0x87, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x80, 0x85,
  1084. 0x81, 0x85, 0x5f, 0x45, 0x4e, 0x56, 0x8e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x00,
  1085. 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0xfe, 0x02, 0x80, 0x80, 0x81, 0x85, 0x5f,
  1086. 0x45, 0x4e, 0x56,
  1087. };
  1088. START_TEST(lua_reject_precompiled_files)
  1089. {
  1090. _destroy_(tmpdir) *tmpdir = tmpdir_create(NULL);
  1091. /* Write the binary bytecode to a .lua file in the tmpdir.
  1092. * Binary (pre-compiled) Lua files must be rejected by the
  1093. * plugin loader for security reasons. */
  1094. _autofree_ char *path = strdup_printf("%s/10-binary-plugin.lua", tmpdir->path);
  1095. _autoclose_ int fd = open(path, O_WRONLY | O_CREAT, 0644);
  1096. litest_assert_errno_success(fd);
  1097. ssize_t written = write(fd, binary_lua_plugin, sizeof(binary_lua_plugin));
  1098. litest_assert_int_eq((int)written, (int)sizeof(binary_lua_plugin));
  1099. fsync(fd);
  1100. _litest_context_destroy_ struct libinput *li =
  1101. litest_create_context_with_plugindir(tmpdir->path);
  1102. litest_with_logcapture(li, capture) {
  1103. libinput_plugin_system_load_plugins(li,
  1104. LIBINPUT_PLUGIN_SYSTEM_FLAG_NONE);
  1105. litest_drain_events(li);
  1106. size_t index = 0;
  1107. litest_assert(
  1108. strv_find_substring(capture->errors, "Failed to load", &index));
  1109. litest_assert_str_in(path, capture->errors[index]);
  1110. }
  1111. }
  1112. END_TEST
  1113. TEST_COLLECTION(lua)
  1114. {
  1115. /* clang-format off */
  1116. litest_add_no_device(lua_load_failure);
  1117. litest_add_no_device(lua_reject_precompiled_files);
  1118. litest_with_parameters(params,
  1119. "content", 'I', 6,
  1120. litest_named_i32(EMPTY),
  1121. litest_named_i32(BASIC),
  1122. litest_named_i32(COMMENT),
  1123. litest_named_i32(DUPLICATE_CALL),
  1124. litest_named_i32(MISSING_REGISTER),
  1125. litest_named_i32(VERSION_NOT_A_TABLE)) {
  1126. litest_add_parametrized_no_device(lua_load_success_but_no_register,
  1127. params);
  1128. }
  1129. litest_add_no_device(lua_register_noop);
  1130. litest_with_parameters(params, "when", 's', 2, "run", "connect") {
  1131. litest_add_parametrized_no_device(lua_unregister_is_last, params);
  1132. }
  1133. litest_add_no_device(lua_test_evdev_global);
  1134. litest_add_no_device(lua_test_libinput_now);
  1135. litest_with_parameters(params,
  1136. "mode", 's', 2, "absolute", "relative",
  1137. "reschedule", 'b') {
  1138. litest_add_parametrized_no_device(lua_test_libinput_timer, params);
  1139. }
  1140. litest_with_parameters(params,
  1141. "priority", 'I', 3,
  1142. litest_named_i32(LIBINPUT_LOG_PRIORITY_DEBUG),
  1143. litest_named_i32(LIBINPUT_LOG_PRIORITY_INFO),
  1144. litest_named_i32(LIBINPUT_LOG_PRIORITY_ERROR)) {
  1145. litest_add_parametrized_no_device(lua_test_logging, params);
  1146. }
  1147. litest_with_parameters(params,
  1148. "handler", 's', 2, "new-evdev-device", "timer-expired",
  1149. "error", 'I', 3,
  1150. litest_named_i32(BAD_TYPE),
  1151. litest_named_i32(TOO_FEW_ARGS),
  1152. litest_named_i32(TOO_MANY_ARGS)) {
  1153. litest_add_parametrized_no_device(lua_bad_connect, params);
  1154. }
  1155. litest_add_no_device(lua_register_multiversions);
  1156. litest_add_no_device(lua_allowed_functions);
  1157. litest_add_no_device(lua_disallowed_functions);
  1158. litest_add_no_device(lua_gc_not_accessible);
  1159. litest_add_no_device(lua_frame_handler);
  1160. litest_add_no_device(lua_device_info);
  1161. litest_add_no_device(lua_set_absinfo);
  1162. litest_add_no_device(lua_enable_disable_evdev_usage);
  1163. litest_add_no_device(lua_ignore_unsupported_codes);
  1164. litest_with_parameters(params,
  1165. "which", 'I', 3,
  1166. litest_named_i32(LITEST_MOUSE),
  1167. litest_named_i32(LITEST_TRACKPOINT),
  1168. litest_named_i32(LITEST_GENERIC_MULTITOUCH_SCREEN)) {
  1169. litest_add_parametrized_no_device(lua_udev_properties, params);
  1170. }
  1171. litest_with_parameters(params, "append", 'b', "in_timer", 'b') {
  1172. litest_add_parametrized_no_device(lua_append_prepend_frame, params);
  1173. }
  1174. litest_with_parameters(params, "when", 'I', 2,
  1175. litest_named_i32(DEVICE_NEW),
  1176. litest_named_i32(FIRST_FRAME)) {
  1177. litest_add_parametrized_no_device(lua_disable_button_debounce, params);
  1178. litest_add_parametrized_no_device(lua_disable_touchpad_jump_detection, params);
  1179. litest_add_parametrized_no_device(lua_disable_wheel_debouncing, params);
  1180. litest_add_parametrized_no_device(lua_remove_plugin_on_timeout, params);
  1181. }
  1182. /* clang-format on */
  1183. }