From 959dd2a35bb7399db87f18ae54030bd4d026d458 Mon Sep 17 00:00:00 2001 From: MattHag <16444067+MattHag@users.noreply.github.com> Date: Sat, 27 Apr 2024 23:56:27 +0200 Subject: [PATCH] Refactor rule loading for testability (#2456) rules: Introduce tests for YAML rule loading functionality. --- lib/logitech_receiver/diversion.py | 38 ++++++++------- lib/solaar/ui/diversion_rules.py | 2 +- tests/logitech_receiver/test_diversion.py | 57 +++++++++++++++++++++++ 3 files changed, 80 insertions(+), 17 deletions(-) create mode 100644 tests/logitech_receiver/test_diversion.py diff --git a/lib/logitech_receiver/diversion.py b/lib/logitech_receiver/diversion.py index 7e1df102..8e0722f6 100644 --- a/lib/logitech_receiver/diversion.py +++ b/lib/logitech_receiver/diversion.py @@ -1547,23 +1547,29 @@ def _save_config_rule_file(file_name=_file_path): return True -def _load_config_rule_file(): +def load_config_rule_file(): + """Loads user configured rules.""" global rules - loaded_rules = [] + if _path.isfile(_file_path): - try: - with open(_file_path) as config_file: - loaded_rules = [] - for loaded_rule in _yaml_safe_load_all(config_file): - rule = Rule(loaded_rule, source=_file_path) - if logger.isEnabledFor(logging.DEBUG): - logger.debug("load rule: %s", rule) - loaded_rules.append(rule) - if logger.isEnabledFor(logging.INFO): - logger.info("loaded %d rules from %s", len(loaded_rules), config_file.name) - except Exception as e: - logger.error("failed to load from %s\n%s", _file_path, e) - rules = Rule([Rule(loaded_rules, source=_file_path), built_in_rules]) + rules = _load_rule_config(_file_path) -_load_config_rule_file() +def _load_rule_config(file_path: str) -> Rule: + loaded_rules = [] + try: + with open(file_path) as config_file: + loaded_rules = [] + for loaded_rule in _yaml_safe_load_all(config_file): + rule = Rule(loaded_rule, source=file_path) + if logger.isEnabledFor(logging.DEBUG): + logger.debug("load rule: %s", rule) + loaded_rules.append(rule) + if logger.isEnabledFor(logging.INFO): + logger.info("loaded %d rules from %s", len(loaded_rules), config_file.name) + except Exception as e: + logger.error("failed to load from %s\n%s", file_path, e) + return Rule([Rule(loaded_rules, source=file_path), built_in_rules]) + + +load_config_rule_file() diff --git a/lib/solaar/ui/diversion_rules.py b/lib/solaar/ui/diversion_rules.py index 8836acdc..15034acc 100644 --- a/lib/solaar/ui/diversion_rules.py +++ b/lib/solaar/ui/diversion_rules.py @@ -229,7 +229,7 @@ class DiversionDialog: self.dirty = False for c in self.selected_rule_edit_panel.get_children(): self.selected_rule_edit_panel.remove(c) - _DIV._load_config_rule_file() + _DIV.load_config_rule_file() self.model = self._create_model() self.view.set_model(self.model) self.view.expand_all() diff --git a/tests/logitech_receiver/test_diversion.py b/tests/logitech_receiver/test_diversion.py new file mode 100644 index 00000000..0dd512f5 --- /dev/null +++ b/tests/logitech_receiver/test_diversion.py @@ -0,0 +1,57 @@ +import textwrap + +from unittest import mock +from unittest.mock import mock_open + +import pytest + +from logitech_receiver import diversion + + +@pytest.fixture +def rule_config(): + rule_content = """ + %YAML 1.3 + --- + - MouseGesture: Mouse Left + - KeyPress: + - [Control_L, Alt_L, Left] + - click + ... + --- + - MouseGesture: Mouse Up + - KeyPress: + - [Super_L, Up] + - click + ... + --- + - Test: [thumb_wheel_up, 10] + - KeyPress: + - [Control_L, Page_Down] + - click + ... + --- + """ + return textwrap.dedent(rule_content) + + +def test_load_rule_config(rule_config): + expected_rules = [ + [ + diversion.MouseGesture, + diversion.KeyPress, + ], + [diversion.MouseGesture, diversion.KeyPress], + [diversion.Test, diversion.KeyPress], + ] + + with mock.patch("builtins.open", new=mock_open(read_data=rule_config)): + loaded_rules = diversion._load_rule_config(file_path=mock.Mock()) + + assert len(loaded_rules.components) == 2 # predefined and user configured rules + user_configured_rules = loaded_rules.components[0] + assert isinstance(user_configured_rules, diversion.Rule) + + for components, expected_components in zip(user_configured_rules.components, expected_rules): + for component, expected_component in zip(components.components, expected_components): + assert isinstance(component, expected_component)