"""Tests for Tools/input_emulation.py — the pure ioctl/key-code parts. The device path itself needs /dev/uinput, so only the encoding helpers are covered here; the end-to-end injection is verified by running the tool (see Docs/release-checks.md and MEMORY.md). """ import unittest import input_emulation as ie class IocEncodingTest(unittest.TestCase): """_IOC must match the Linux ioctl bit layout.""" def test_layout_constants(self): self.assertEqual(ie._IOC_NRSHIFT, 0) self.assertEqual(ie._IOC_TYPESHIFT, 8) self.assertEqual(ie._IOC_SIZESHIFT, 16) self.assertEqual(ie._IOC_DIRSHIFT, 30) def test_known_values(self): # UI_SET_EVBIT = _IOW('U', 100, int) -> 0x40045564 on Linux. self.assertEqual(ie.UI_SET_EVBIT, 0x40045564) # UI_DEV_CREATE = _IO('U', 1) -> 0x5501. self.assertEqual(ie.UI_DEV_CREATE, 0x5501) def test_type_accepts_char_or_int(self): self.assertEqual(ie._ioc(1, 4, "U", 100), ie._ioc(1, 4, ord("U"), 100)) class KeyCodeTest(unittest.TestCase): """KEYCODES must hold the Linux input-event codes the demo uses.""" EXPECTED = { "w": 17, "s": 31, "a": 30, "d": 32, "space": 57, "r": 19, "esc": 1, } def test_demo_controls(self): for name, code in self.EXPECTED.items(): self.assertEqual(ie.KEYCODES[name], code, f"{name} code") def test_lookup_is_case_insensitive(self): dev = ie.InputDevice.__new__(ie.InputDevice) # no device opened self.assertEqual(dev._key_code("W"), 17) self.assertEqual(dev._key_code("SPACE"), 57) self.assertEqual(dev._key_code(19), 19) # a raw code passes through def test_unknown_key_raises(self): dev = ie.InputDevice.__new__(ie.InputDevice) with self.assertRaises(ie.UInputError): dev._key_code("not-a-key") if __name__ == "__main__": unittest.main()