libinput-record-verify-yaml.py 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687
  1. #!/usr/bin/env python3
  2. # vim: set expandtab shiftwidth=4:
  3. # -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
  4. #
  5. # Copyright © 2018 Red Hat, Inc.
  6. #
  7. # Permission is hereby granted, free of charge, to any person obtaining a
  8. # copy of this software and associated documentation files (the "Software"),
  9. # to deal in the Software without restriction, including without limitation
  10. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. # and/or sell copies of the Software, and to permit persons to whom the
  12. # Software is furnished to do so, subject to the following conditions:
  13. #
  14. # The above copyright notice and this permission notice (including the next
  15. # paragraph) shall be included in all copies or substantial portions of the
  16. # Software.
  17. #
  18. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  21. # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23. # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  24. # DEALINGS IN THE SOFTWARE.
  25. import argparse
  26. import os
  27. import re
  28. import sys
  29. import unittest
  30. import yaml
  31. from pkg_resources import parse_version
  32. class TestYaml(unittest.TestCase):
  33. filename = ""
  34. @classmethod
  35. def setUpClass(cls):
  36. with open(cls.filename) as f:
  37. cls.yaml = yaml.safe_load(f)
  38. def dict_key_crosscheck(self, d, keys):
  39. """Check that each key in d is in keys, and that each key is in d"""
  40. self.assertEqual(sorted(d.keys()), sorted(keys))
  41. def libinput_events(self, filter=None):
  42. """Returns all libinput events in the recording, regardless of the
  43. device"""
  44. devices = self.yaml["devices"]
  45. for d in devices:
  46. events = d["events"]
  47. if not events:
  48. raise unittest.SkipTest()
  49. for e in events:
  50. try:
  51. libinput = e["libinput"]
  52. except KeyError:
  53. continue
  54. for ev in libinput:
  55. if (
  56. filter is None
  57. or ev["type"] == filter
  58. or isinstance(filter, list)
  59. and ev["type"] in filter
  60. ):
  61. yield ev
  62. def test_sections_exist(self):
  63. sections = ["version", "ndevices", "libinput", "system", "devices"]
  64. for section in sections:
  65. self.assertIn(section, self.yaml)
  66. def test_version(self):
  67. version = self.yaml["version"]
  68. self.assertTrue(isinstance(version, int))
  69. self.assertEqual(version, 1)
  70. def test_ndevices(self):
  71. ndevices = self.yaml["ndevices"]
  72. self.assertTrue(isinstance(ndevices, int))
  73. self.assertGreaterEqual(ndevices, 1)
  74. self.assertEqual(ndevices, len(self.yaml["devices"]))
  75. def test_libinput(self):
  76. libinput = self.yaml["libinput"]
  77. version = libinput["version"]
  78. self.assertTrue(isinstance(version, str))
  79. self.assertGreaterEqual(parse_version(version), parse_version("1.10.0"))
  80. git = libinput["git"]
  81. self.assertTrue(isinstance(git, str))
  82. self.assertNotEqual(git, "unknown")
  83. def test_system(self):
  84. system = self.yaml["system"]
  85. kernel = system["kernel"]
  86. self.assertTrue(isinstance(kernel, str))
  87. self.assertEqual(kernel, os.uname().release)
  88. dmi = system["dmi"]
  89. self.assertTrue(isinstance(dmi, str))
  90. with open("/sys/class/dmi/id/modalias") as f:
  91. sys_dmi = f.read()[:-1] # trailing newline
  92. self.assertEqual(dmi, sys_dmi)
  93. def test_devices_sections_exist(self):
  94. devices = self.yaml["devices"]
  95. for d in devices:
  96. self.assertIn("node", d)
  97. self.assertIn("evdev", d)
  98. self.assertIn("udev", d)
  99. def test_evdev_sections_exist(self):
  100. sections = ["name", "id", "codes", "properties"]
  101. devices = self.yaml["devices"]
  102. for d in devices:
  103. evdev = d["evdev"]
  104. for s in sections:
  105. self.assertIn(s, evdev)
  106. def test_evdev_name(self):
  107. devices = self.yaml["devices"]
  108. for d in devices:
  109. evdev = d["evdev"]
  110. name = evdev["name"]
  111. self.assertTrue(isinstance(name, str))
  112. self.assertGreaterEqual(len(name), 5)
  113. def test_evdev_id(self):
  114. devices = self.yaml["devices"]
  115. for d in devices:
  116. evdev = d["evdev"]
  117. id = evdev["id"]
  118. self.assertTrue(isinstance(id, list))
  119. self.assertEqual(len(id), 4)
  120. self.assertGreater(id[0], 0)
  121. self.assertGreater(id[1], 0)
  122. def test_evdev_properties(self):
  123. devices = self.yaml["devices"]
  124. for d in devices:
  125. evdev = d["evdev"]
  126. properties = evdev["properties"]
  127. self.assertTrue(isinstance(properties, list))
  128. def test_hid(self):
  129. devices = self.yaml["devices"]
  130. for d in devices:
  131. hid = d["hid"]
  132. self.assertTrue(isinstance(hid, list))
  133. for byte in hid:
  134. self.assertGreaterEqual(byte, 0)
  135. self.assertLessEqual(byte, 255)
  136. def test_udev_sections_exist(self):
  137. sections = ["properties"]
  138. devices = self.yaml["devices"]
  139. for d in devices:
  140. udev = d["udev"]
  141. for s in sections:
  142. self.assertIn(s, udev)
  143. def test_udev_properties(self):
  144. devices = self.yaml["devices"]
  145. for d in devices:
  146. udev = d["udev"]
  147. properties = udev["properties"]
  148. self.assertTrue(isinstance(properties, list))
  149. self.assertGreater(len(properties), 0)
  150. self.assertIn("ID_INPUT=1", properties)
  151. for p in properties:
  152. self.assertTrue(re.match("[A-Z0-9_]+=.+", p))
  153. def test_udev_id_inputs(self):
  154. devices = self.yaml["devices"]
  155. for d in devices:
  156. udev = d["udev"]
  157. properties = udev["properties"]
  158. id_inputs = [p for p in properties if p.startswith("ID_INPUT")]
  159. # We expect ID_INPUT and ID_INPUT_something, but might get more
  160. # than one of the latter
  161. self.assertGreaterEqual(len(id_inputs), 2)
  162. def test_events_have_section(self):
  163. devices = self.yaml["devices"]
  164. for d in devices:
  165. events = d["events"]
  166. if not events:
  167. raise unittest.SkipTest()
  168. for e in events:
  169. self.assertTrue("evdev" in e or "libinput" in e)
  170. def test_events_evdev(self):
  171. devices = self.yaml["devices"]
  172. for d in devices:
  173. events = d["events"]
  174. if not events:
  175. raise unittest.SkipTest()
  176. for e in events:
  177. try:
  178. evdev = e["evdev"]
  179. except KeyError:
  180. continue
  181. for ev in evdev:
  182. self.assertEqual(len(ev), 5)
  183. # Last event in each frame is SYN_REPORT
  184. ev_syn = evdev[-1]
  185. self.assertEqual(ev_syn[2], 0)
  186. self.assertEqual(ev_syn[3], 0)
  187. # SYN_REPORT value is 1 in case of some key repeats
  188. self.assertLessEqual(ev_syn[4], 1)
  189. def test_events_evdev_syn_report(self):
  190. devices = self.yaml["devices"]
  191. for d in devices:
  192. events = d["events"]
  193. if not events:
  194. raise unittest.SkipTest()
  195. for e in events:
  196. try:
  197. evdev = e["evdev"]
  198. except KeyError:
  199. continue
  200. for ev in evdev[:-1]:
  201. self.assertFalse(ev[2] == 0 and ev[3] == 0)
  202. def test_events_libinput(self):
  203. devices = self.yaml["devices"]
  204. for d in devices:
  205. events = d["events"]
  206. if not events:
  207. raise unittest.SkipTest()
  208. for e in events:
  209. try:
  210. libinput = e["libinput"]
  211. except KeyError:
  212. continue
  213. self.assertTrue(isinstance(libinput, list))
  214. for ev in libinput:
  215. self.assertTrue(isinstance(ev, dict))
  216. def test_events_libinput_type(self):
  217. types = [
  218. "POINTER_MOTION",
  219. "POINTER_MOTION_ABSOLUTE",
  220. "POINTER_AXIS",
  221. "POINTER_BUTTON",
  222. "DEVICE_ADDED",
  223. "KEYBOARD_KEY",
  224. "TOUCH_DOWN",
  225. "TOUCH_MOTION",
  226. "TOUCH_UP",
  227. "TOUCH_FRAME",
  228. "GESTURE_SWIPE_BEGIN",
  229. "GESTURE_SWIPE_UPDATE",
  230. "GESTURE_SWIPE_END",
  231. "GESTURE_PINCH_BEGIN",
  232. "GESTURE_PINCH_UPDATE",
  233. "GESTURE_PINCH_END",
  234. "TABLET_TOOL_AXIS",
  235. "TABLET_TOOL_PROXIMITY",
  236. "TABLET_TOOL_BUTTON",
  237. "TABLET_TOOL_TIP",
  238. "TABLET_PAD_STRIP",
  239. "TABLET_PAD_RING",
  240. "TABLET_PAD_BUTTON",
  241. "SWITCH_TOGGLE",
  242. ]
  243. for e in self.libinput_events():
  244. self.assertIn("type", e)
  245. self.assertIn(e["type"], types)
  246. def test_events_libinput_time(self):
  247. # DEVICE_ADDED has no time
  248. # first event may have 0.0 time if the first frame generates a
  249. # libinput event.
  250. try:
  251. for e in list(self.libinput_events())[2:]:
  252. self.assertIn("time", e)
  253. self.assertGreater(e["time"], 0.0)
  254. self.assertLess(e["time"], 60.0)
  255. except IndexError:
  256. pass
  257. def test_events_libinput_device_added(self):
  258. keys = ["type", "seat", "logical_seat"]
  259. for e in self.libinput_events("DEVICE_ADDED"):
  260. self.dict_key_crosscheck(e, keys)
  261. self.assertEqual(e["seat"], "seat0")
  262. self.assertEqual(e["logical_seat"], "default")
  263. def test_events_libinput_pointer_motion(self):
  264. keys = ["type", "time", "delta", "unaccel"]
  265. for e in self.libinput_events("POINTER_MOTION"):
  266. self.dict_key_crosscheck(e, keys)
  267. delta = e["delta"]
  268. self.assertTrue(isinstance(delta, list))
  269. self.assertEqual(len(delta), 2)
  270. for d in delta:
  271. self.assertTrue(isinstance(d, float))
  272. unaccel = e["unaccel"]
  273. self.assertTrue(isinstance(unaccel, list))
  274. self.assertEqual(len(unaccel), 2)
  275. for d in unaccel:
  276. self.assertTrue(isinstance(d, float))
  277. def test_events_libinput_pointer_button(self):
  278. keys = ["type", "time", "button", "state", "seat_count"]
  279. for e in self.libinput_events("POINTER_BUTTON"):
  280. self.dict_key_crosscheck(e, keys)
  281. button = e["button"]
  282. self.assertGreater(button, 0x100) # BTN_0
  283. self.assertLess(button, 0x160) # KEY_OK
  284. state = e["state"]
  285. self.assertIn(state, ["pressed", "released"])
  286. scount = e["seat_count"]
  287. self.assertGreaterEqual(scount, 0)
  288. def test_events_libinput_pointer_absolute(self):
  289. keys = ["type", "time", "point", "transformed"]
  290. for e in self.libinput_events("POINTER_MOTION_ABSOLUTE"):
  291. self.dict_key_crosscheck(e, keys)
  292. point = e["point"]
  293. self.assertTrue(isinstance(point, list))
  294. self.assertEqual(len(point), 2)
  295. for p in point:
  296. self.assertTrue(isinstance(p, float))
  297. self.assertGreater(p, 0.0)
  298. self.assertLess(p, 300.0)
  299. transformed = e["transformed"]
  300. self.assertTrue(isinstance(transformed, list))
  301. self.assertEqual(len(transformed), 2)
  302. for t in transformed:
  303. self.assertTrue(isinstance(t, float))
  304. self.assertGreater(t, 0.0)
  305. self.assertLess(t, 100.0)
  306. def test_events_libinput_touch(self):
  307. keys = ["type", "time", "slot", "seat_slot"]
  308. for e in self.libinput_events():
  309. if not e["type"].startswith("TOUCH_") or e["type"] == "TOUCH_FRAME":
  310. continue
  311. for k in keys:
  312. self.assertIn(k, e.keys())
  313. slot = e["slot"]
  314. seat_slot = e["seat_slot"]
  315. self.assertGreaterEqual(slot, 0)
  316. self.assertGreaterEqual(seat_slot, 0)
  317. def test_events_libinput_touch_down(self):
  318. keys = ["type", "time", "slot", "seat_slot", "point", "transformed"]
  319. for e in self.libinput_events("TOUCH_DOWN"):
  320. self.dict_key_crosscheck(e, keys)
  321. point = e["point"]
  322. self.assertTrue(isinstance(point, list))
  323. self.assertEqual(len(point), 2)
  324. for p in point:
  325. self.assertTrue(isinstance(p, float))
  326. self.assertGreater(p, 0.0)
  327. self.assertLess(p, 300.0)
  328. transformed = e["transformed"]
  329. self.assertTrue(isinstance(transformed, list))
  330. self.assertEqual(len(transformed), 2)
  331. for t in transformed:
  332. self.assertTrue(isinstance(t, float))
  333. self.assertGreater(t, 0.0)
  334. self.assertLess(t, 100.0)
  335. def test_events_libinput_touch_motion(self):
  336. keys = ["type", "time", "slot", "seat_slot", "point", "transformed"]
  337. for e in self.libinput_events("TOUCH_MOTION"):
  338. self.dict_key_crosscheck(e, keys)
  339. point = e["point"]
  340. self.assertTrue(isinstance(point, list))
  341. self.assertEqual(len(point), 2)
  342. for p in point:
  343. self.assertTrue(isinstance(p, float))
  344. self.assertGreater(p, 0.0)
  345. self.assertLess(p, 300.0)
  346. transformed = e["transformed"]
  347. self.assertTrue(isinstance(transformed, list))
  348. self.assertEqual(len(transformed), 2)
  349. for t in transformed:
  350. self.assertTrue(isinstance(t, float))
  351. self.assertGreater(t, 0.0)
  352. self.assertLess(t, 100.0)
  353. def test_events_libinput_touch_frame(self):
  354. devices = self.yaml["devices"]
  355. for d in devices:
  356. events = d["events"]
  357. if not events:
  358. raise unittest.SkipTest()
  359. for e in events:
  360. try:
  361. evdev = e["libinput"]
  362. except KeyError:
  363. continue
  364. need_frame = False
  365. for ev in evdev:
  366. t = ev["type"]
  367. if not t.startswith("TOUCH_"):
  368. self.assertFalse(need_frame)
  369. continue
  370. if t == "TOUCH_FRAME":
  371. self.assertTrue(need_frame)
  372. need_frame = False
  373. else:
  374. need_frame = True
  375. self.assertFalse(need_frame)
  376. def test_events_libinput_gesture_pinch(self):
  377. keys = ["type", "time", "nfingers", "delta", "unaccel", "angle_delta", "scale"]
  378. for e in self.libinput_events(
  379. ["GESTURE_PINCH_BEGIN", "GESTURE_PINCH_UPDATE", "GESTURE_PINCH_END"]
  380. ):
  381. self.dict_key_crosscheck(e, keys)
  382. delta = e["delta"]
  383. self.assertTrue(isinstance(delta, list))
  384. self.assertEqual(len(delta), 2)
  385. for d in delta:
  386. self.assertTrue(isinstance(d, float))
  387. unaccel = e["unaccel"]
  388. self.assertTrue(isinstance(unaccel, list))
  389. self.assertEqual(len(unaccel), 2)
  390. for d in unaccel:
  391. self.assertTrue(isinstance(d, float))
  392. adelta = e["angle_delta"]
  393. self.assertTrue(isinstance(adelta, list))
  394. self.assertEqual(len(adelta), 2)
  395. for d in adelta:
  396. self.assertTrue(isinstance(d, float))
  397. scale = e["scale"]
  398. self.assertTrue(isinstance(scale, list))
  399. self.assertEqual(len(scale), 2)
  400. for d in scale:
  401. self.assertTrue(isinstance(d, float))
  402. def test_events_libinput_gesture_swipe(self):
  403. keys = ["type", "time", "nfingers", "delta", "unaccel"]
  404. for e in self.libinput_events(
  405. ["GESTURE_SWIPE_BEGIN", "GESTURE_SWIPE_UPDATE", "GESTURE_SWIPE_END"]
  406. ):
  407. self.dict_key_crosscheck(e, keys)
  408. delta = e["delta"]
  409. self.assertTrue(isinstance(delta, list))
  410. self.assertEqual(len(delta), 2)
  411. for d in delta:
  412. self.assertTrue(isinstance(d, float))
  413. unaccel = e["unaccel"]
  414. self.assertTrue(isinstance(unaccel, list))
  415. self.assertEqual(len(unaccel), 2)
  416. for d in unaccel:
  417. self.assertTrue(isinstance(d, float))
  418. def test_events_libinput_tablet_pad_button(self):
  419. keys = ["type", "time", "button", "state", "mode", "is-toggle"]
  420. for e in self.libinput_events("TABLET_PAD_BUTTON"):
  421. self.dict_key_crosscheck(e, keys)
  422. b = e["button"]
  423. self.assertTrue(isinstance(b, int))
  424. self.assertGreaterEqual(b, 0)
  425. self.assertLessEqual(b, 16)
  426. state = e["state"]
  427. self.assertIn(state, ["pressed", "released"])
  428. m = e["mode"]
  429. self.assertTrue(isinstance(m, int))
  430. self.assertGreaterEqual(m, 0)
  431. self.assertLessEqual(m, 3)
  432. t = e["is-toggle"]
  433. self.assertTrue(isinstance(t, bool))
  434. def test_events_libinput_tablet_pad_ring(self):
  435. keys = ["type", "time", "number", "position", "source", "mode"]
  436. for e in self.libinput_events("TABLET_PAD_RING"):
  437. self.dict_key_crosscheck(e, keys)
  438. n = e["number"]
  439. self.assertTrue(isinstance(n, int))
  440. self.assertGreaterEqual(n, 0)
  441. self.assertLessEqual(n, 4)
  442. p = e["position"]
  443. self.assertTrue(isinstance(p, float))
  444. if p != -1.0: # special 'end' case
  445. self.assertGreaterEqual(p, 0.0)
  446. self.assertLess(p, 360.0)
  447. m = e["mode"]
  448. self.assertTrue(isinstance(m, int))
  449. self.assertGreaterEqual(m, 0)
  450. self.assertLessEqual(m, 3)
  451. s = e["source"]
  452. self.assertIn(s, ["finger", "unknown"])
  453. def test_events_libinput_tablet_pad_strip(self):
  454. keys = ["type", "time", "number", "position", "source", "mode"]
  455. for e in self.libinput_events("TABLET_PAD_STRIP"):
  456. self.dict_key_crosscheck(e, keys)
  457. n = e["number"]
  458. self.assertTrue(isinstance(n, int))
  459. self.assertGreaterEqual(n, 0)
  460. self.assertLessEqual(n, 4)
  461. p = e["position"]
  462. self.assertTrue(isinstance(p, float))
  463. if p != -1.0: # special 'end' case
  464. self.assertGreaterEqual(p, 0.0)
  465. self.assertLessEqual(p, 1.0)
  466. m = e["mode"]
  467. self.assertTrue(isinstance(m, int))
  468. self.assertGreaterEqual(m, 0)
  469. self.assertLessEqual(m, 3)
  470. s = e["source"]
  471. self.assertIn(s, ["finger", "unknown"])
  472. def test_events_libinput_tablet_tool_proximity(self):
  473. keys = ["type", "time", "proximity", "tool-type", "serial", "axes"]
  474. for e in self.libinput_events("TABLET_TOOL_PROXIMITY"):
  475. for k in keys:
  476. self.assertIn(k, e)
  477. p = e["proximity"]
  478. self.assertIn(p, ["in", "out"])
  479. p = e["tool-type"]
  480. self.assertIn(
  481. p, ["pen", "eraser", "brush", "airbrush", "mouse", "lens", "unknown"]
  482. )
  483. s = e["serial"]
  484. self.assertTrue(isinstance(s, int))
  485. self.assertGreaterEqual(s, 0)
  486. a = e["axes"]
  487. for ax in e["axes"]:
  488. self.assertIn(a, "pdtrsw")
  489. def test_events_libinput_tablet_tool(self):
  490. keys = ["type", "time", "tip"]
  491. for e in self.libinput_events(["TABLET_TOOL_AXIS", "TABLET_TOOL_TIP"]):
  492. for k in keys:
  493. self.assertIn(k, e)
  494. t = e["tip"]
  495. self.assertIn(t, ["down", "up"])
  496. def test_events_libinput_tablet_tool_button(self):
  497. keys = ["type", "time", "button", "state"]
  498. for e in self.libinput_events("TABLET_TOOL_BUTTON"):
  499. self.dict_key_crosscheck(e, keys)
  500. b = e["button"]
  501. # STYLUS, STYLUS2, STYLUS3
  502. self.assertIn(b, [0x14B, 0x14C, 0x139])
  503. s = e["state"]
  504. self.assertIn(s, ["pressed", "released"])
  505. def test_events_libinput_tablet_tool_axes(self):
  506. for e in self.libinput_events(
  507. ["TABLET_TOOL_PROXIMITY", "TABLET_TOOL_AXIS", "TABLET_TOOL_TIP"]
  508. ):
  509. point = e["point"]
  510. self.assertTrue(isinstance(point, list))
  511. self.assertEqual(len(point), 2)
  512. for p in point:
  513. self.assertTrue(isinstance(p, float))
  514. self.assertGreater(p, 0.0)
  515. try:
  516. tilt = e["tilt"]
  517. self.assertTrue(isinstance(tilt, list))
  518. self.assertEqual(len(tilt), 2)
  519. for t in tilt:
  520. self.assertTrue(isinstance(t, float))
  521. except KeyError:
  522. pass
  523. try:
  524. d = e["distance"]
  525. self.assertTrue(isinstance(d, float))
  526. self.assertGreaterEqual(d, 0.0)
  527. self.assertNotIn("pressure", e)
  528. except KeyError:
  529. pass
  530. try:
  531. p = e["pressure"]
  532. self.assertTrue(isinstance(p, float))
  533. self.assertGreaterEqual(p, 0.0)
  534. self.assertNotIn("distance", e)
  535. except KeyError:
  536. pass
  537. try:
  538. r = e["rotation"]
  539. self.assertTrue(isinstance(r, float))
  540. self.assertGreaterEqual(r, 0.0)
  541. except KeyError:
  542. pass
  543. try:
  544. s = e["slider"]
  545. self.assertTrue(isinstance(s, float))
  546. self.assertGreaterEqual(s, 0.0)
  547. except KeyError:
  548. pass
  549. try:
  550. w = e["wheel"]
  551. self.assertTrue(isinstance(w, float))
  552. self.assertGreaterEqual(w, 0.0)
  553. self.assertIn("wheel-discrete", e)
  554. wd = e["wheel-discrete"]
  555. self.assertTrue(isinstance(wd, 1))
  556. self.assertGreaterEqual(wd, 0.0)
  557. def sign(x):
  558. (1, -1)[x < 0]
  559. self.assertTrue(sign(w), sign(wd))
  560. except KeyError:
  561. pass
  562. def test_events_libinput_switch(self):
  563. keys = ["type", "time", "switch", "state"]
  564. for e in self.libinput_events("SWITCH_TOGGLE"):
  565. self.dict_key_crosscheck(e, keys)
  566. s = e["switch"]
  567. self.assertTrue(isinstance(s, int))
  568. self.assertIn(s, [0x00, 0x01])
  569. # yaml converts on/off to true/false
  570. state = e["state"]
  571. self.assertTrue(isinstance(state, bool))
  572. if __name__ == "__main__":
  573. parser = argparse.ArgumentParser(description="Verify a YAML recording")
  574. parser.add_argument(
  575. "recording",
  576. metavar="recorded-file.yaml",
  577. type=str,
  578. help="Path to device recording",
  579. )
  580. parser.add_argument("--verbose", action="store_true")
  581. args, remainder = parser.parse_known_args()
  582. TestYaml.filename = args.recording
  583. verbosity = 1
  584. if args.verbose:
  585. verbosity = 3
  586. argv = [sys.argv[0], *remainder]
  587. unittest.main(argv=argv, verbosity=verbosity)