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