tests for macro running and parsing

pull/14/head
sezanzeb 4 years ago
parent 8d23593c89
commit ace421e84a

@ -42,20 +42,23 @@ import time
import re
import random
try:
from rich.traceback import install
install(show_locals=True)
except ImportError:
pass
from keymapper.logger import logger
logger.setLevel(5)
class Macro:
"""Supports chaining and preparing actions."""
def __init__(self):
def __init__(self, handler):
"""Create a macro instance that can be populated with tasks.
Parameters
----------
handler : func
A function that accepts keycodes as the first parameter and the
key-press state as the second. 1 for down and 0 for up. The
macro will write to this function once executed with `.run()`.
"""
self.tasks = []
self.handler = handler
def run(self):
"""Run the macro."""
@ -75,9 +78,9 @@ class Macro:
modifier : str
macro : Macro
"""
# TODO press modifier down
self.tasks.append(lambda: self.handler(modifier, 1))
self.tasks.append(macro.run)
# TODO release modifier
self.tasks.append(lambda: self.handler(modifier, 0))
return self
def repeat(self, repeats, macro):
@ -94,8 +97,8 @@ class Macro:
def keycode(self, character):
"""Write the character."""
# TODO write character
self.tasks.append(lambda: print(character))
self.tasks.append(lambda: self.handler(character, 1))
self.tasks.append(lambda: self.handler(character, 0))
return self
def wait(self, min, max=None):
@ -105,7 +108,7 @@ class Macro:
return self
def parse(macro):
def parse(macro, handler):
"""parse and generate a Macro that can be run as often as you want.
Parameters
@ -114,13 +117,13 @@ def parse(macro):
"r(3, k(a).w(10))"
"r(2, k(a).k(-)).k(b)"
"w(1000).m(SHIFT_L, r(2, k(a))).w(10, 20).k(b)"
handler : func
A function that accepts keycodes as the first parameter and the
key-press state as the second. 1 for down and 0 for up. The
macro will write to this function once executed with `.run()`.
"""
try:
return parse_recurse(macro)
except Exception as e:
logger.error(e)
# parsing unsuccessful
return None
# simpler function prototype and docstring than parse_recurse
return parse_recurse(macro, handler)
def extract_params(inner):
@ -154,13 +157,15 @@ def extract_params(inner):
return params
def parse_recurse(macro, macro_instance=None, depth=0):
def parse_recurse(macro, handler, macro_instance=None, depth=0):
"""Handle a subset of the macro, e.g. one parameter or function call.
Parameters
----------
macro : string
Just like parse
handler : function
passed to Macro constructors
macro_instance : Macro or None
A macro instance to add tasks to
depth : int
@ -170,8 +175,16 @@ def parse_recurse(macro, macro_instance=None, depth=0):
# please make a pull request. Because it probably is.
# not using eval for security reasons ofc. And this syntax doesn't need
# string quotes for its params.
# If this gets more complicated than that I'd rather make a macro
# editor GUI and store them as json.
assert isinstance(macro, str)
assert callable(handler)
assert isinstance(depth, int)
if macro_instance is None:
macro_instance = Macro()
macro_instance = Macro(handler)
else:
assert isinstance(macro_instance, Macro)
macro = macro.strip()
logger.spam('%sinput %s', ' ' * depth, macro)
@ -221,7 +234,7 @@ def parse_recurse(macro, macro_instance=None, depth=0):
logger.spam('%scalls %s with %s', space, call, string_params)
# evaluate the params
params = [
parse_recurse(param.strip(), None, depth + 1)
parse_recurse(param.strip(), handler, None, depth + 1)
for param in string_params
]
@ -232,7 +245,7 @@ def parse_recurse(macro, macro_instance=None, depth=0):
if len(macro) > position and macro[position] == '.':
chain = macro[position + 1:]
logger.spam('%sfollowed by %s', space, chain)
parse_recurse(chain, macro_instance, depth)
parse_recurse(chain, handler, macro_instance, depth)
return macro_instance
else:
@ -242,10 +255,3 @@ def parse_recurse(macro, macro_instance=None, depth=0):
except ValueError:
pass
return macro
parse("k(1).k(2).k(3)").run()
parse("r(1, k(2))").run()
parse("r(3, k(a).w(10))").run()
parse("r(2, k(a).k(-)).k(b)").run()
parse("w(1000).m(SHIFT_L, r(2, k(a))).w(10, 20).k(b)").run()

@ -21,24 +21,67 @@
import unittest
from keymapper.dev.macros import Macro, k, m, r, w
from keymapper.dev.macros import parse
class TestMacros(unittest.TestCase):
def test_1(self):
r(3, k('a').w(200)).run()
def setUp(self):
self.result = []
self.handler = lambda char, value: self.result.append((char, value))
def tearDown(self):
self.result = []
def test_0(self):
parse('k(1)', self.handler).run()
self.assertListEqual(self.result, [(1, 1), (1, 0)])
def test_1(self):
parse('k(1).k(a).k(3)', self.handler).run()
self.assertListEqual(self.result, [
(1, 1), (1, 0),
('a', 1), ('a', 0),
(3, 1), (3, 0),
])
def test_2(self):
r(2, k('a').k('-')).k('b').run()
parse('r(1, k(k))', self.handler).run()
self.assertListEqual(self.result, [
('k', 1), ('k', 0),
])
def test_3(self):
w(400).m('SHIFT_L', r(2, k('a'))).w(10).k('b').run()
parse('r(3, k(m).w(200))', self.handler).run()
self.assertListEqual(self.result, [
('m', 1), ('m', 0),
('m', 1), ('m', 0),
('m', 1), ('m', 0),
])
def test_4(self):
# prints nothing without .run
k('a').r(3, k('b'))
parse(' r(2,\nk(\rr ).k(-\n )).k(m) ', self.handler).run()
self.assertListEqual(self.result, [
('r', 1), ('r', 0),
('-', 1), ('-', 0),
('r', 1), ('r', 0),
('-', 1), ('-', 0),
('m', 1), ('m', 0),
])
def test_5(self):
parse('w(400).r(2,m(w,\rr(2,\tk(r))).w(10).k(k))', self.handler).run()
expected = [('w', 1)]
expected += [('r', 1), ('r', 0)] * 2
expected += [('w', 0)]
expected += [('k', 1), ('k', 0)]
expected *= 2
self.assertListEqual(self.result, expected)
def test_6(self):
# prints nothing without .run
parse('k(a).r(3, k(b))', self.handler)
self.assertListEqual(self.result, [])
if __name__ == "__main__":
if __name__ == '__main__':
unittest.main()

Loading…
Cancel
Save