160 lines
6.4 KiB
Python
160 lines
6.4 KiB
Python
import pytest
|
|
|
|
from components.jsonviewer.hooks import (
|
|
HookContext, EventType, Hook, HookManager,
|
|
WhenLongText, WhenEditable, WhenType, WhenKey, WhenPath, WhenValue,
|
|
CompositeCondition
|
|
)
|
|
|
|
|
|
# HookContext test helper
|
|
def create_mock_context(value=None, key=None, json_path=None, parent_node=None, node_type=None, children=None):
|
|
"""Helper to create a mock HookContext for testing."""
|
|
|
|
class Node:
|
|
def __init__(self, value, node_type=None, children=None):
|
|
self.value = value
|
|
self.__class__.__name__ = node_type or "MockNode"
|
|
self.children = children or []
|
|
|
|
mock_node = Node(value, node_type=node_type, children=children)
|
|
return HookContext(key=key, node=mock_node, helper=None, jsonviewer=None, json_path=json_path,
|
|
parent_node=parent_node)
|
|
|
|
|
|
# ================
|
|
# Test Conditions
|
|
# ================
|
|
|
|
@pytest.mark.parametrize("text, threshold, expected", [
|
|
("This is a very long text." * 10, 50, True), # Long text, above threshold
|
|
("Short text", 50, False), # Short text, below threshold
|
|
])
|
|
def test_i_can_detect_long_text(text, threshold, expected):
|
|
context = create_mock_context(value=text)
|
|
condition = WhenLongText(threshold=threshold)
|
|
assert condition.evaluate(context) == expected
|
|
|
|
|
|
@pytest.mark.parametrize("json_path, editable_paths, editable_types, node_value, is_leaf, expected", [
|
|
("root.editable.value", ["root.editable.value"], None, "Editable value", True, True), # Editable path matches
|
|
("root.not_editable.value", ["root.editable.value"], None, "Editable value", True, False),
|
|
# Editable path does not match
|
|
("root.editable.numeric", [], [int], 10, True, True), # Type is editable (int)
|
|
("root.editable.string", [], [int], "Non-editable value", True, False) # Type is not editable
|
|
])
|
|
def test_i_can_detect_editable(json_path, editable_paths, editable_types, node_value, is_leaf, expected):
|
|
context = create_mock_context(value=node_value, json_path=json_path)
|
|
context.is_leaf_node = lambda: is_leaf # Mock is_leaf_node behavior
|
|
condition = WhenEditable(editable_paths=editable_paths, editable_types=editable_types)
|
|
assert condition.evaluate(context) == expected
|
|
|
|
|
|
@pytest.mark.parametrize("node_value, target_type, expected", [
|
|
(123, int, True), # Matches target type
|
|
("String value", int, False) # Does not match target type
|
|
])
|
|
def test_i_can_detect_type_match(node_value, target_type, expected):
|
|
context = create_mock_context(value=node_value)
|
|
condition = WhenType(target_type=target_type)
|
|
assert condition.evaluate(context) == expected
|
|
|
|
|
|
@pytest.mark.parametrize("key, key_pattern, expected", [
|
|
("target_key", "target_key", True), # Exact match
|
|
("target_key", lambda k: k.startswith("target"), True), # Callable match
|
|
("wrong_key", "target_key", False) # Pattern does not match
|
|
])
|
|
def test_i_can_match_key(key, key_pattern, expected):
|
|
context = create_mock_context(key=key)
|
|
condition = WhenKey(key_pattern=key_pattern)
|
|
assert condition.evaluate(context) == expected
|
|
|
|
|
|
@pytest.mark.parametrize("json_path, path_pattern, expected", [
|
|
("root.items[0].name", r"root\.items\[\d+\]\.name", True), # Matches pattern
|
|
("root.invalid_path", r"root\.items\[\d+\]\.name", False) # Does not match
|
|
])
|
|
def test_i_can_match_path(json_path, path_pattern, expected):
|
|
context = create_mock_context(json_path=json_path)
|
|
condition = WhenPath(path_pattern=path_pattern)
|
|
assert condition.evaluate(context) == expected
|
|
|
|
|
|
@pytest.mark.parametrize("value, target_value, predicate, expected", [
|
|
(123, 123, None, True), # Direct match
|
|
(123, 456, None, False), # Direct mismatch
|
|
(150, None, lambda v: v > 100, True), # Satisfies predicate
|
|
(50, None, lambda v: v > 100, False), # Does not satisfy predicate
|
|
])
|
|
def test_i_can_detect_value(value, target_value, predicate, expected):
|
|
context = create_mock_context(value=value)
|
|
condition = WhenValue(target_value=target_value, predicate=predicate)
|
|
assert condition.evaluate(context) == expected
|
|
|
|
|
|
@pytest.mark.parametrize("value, conditions, operator, expected", [
|
|
(200, [WhenValue(predicate=lambda v: v > 100), WhenType(target_type=int)], "AND", True),
|
|
# Both conditions pass (AND)
|
|
(200, [WhenValue(predicate=lambda v: v > 100), WhenType(target_type=str)], "AND", False),
|
|
# One condition fails (AND)
|
|
(200, [WhenValue(predicate=lambda v: v > 100), WhenType(target_type=str)], "OR", True),
|
|
# At least one passes (OR)
|
|
(50, [], "AND", True), # No conditions (default True for AND/OR)
|
|
])
|
|
def test_i_can_combine_conditions(value, conditions, operator, expected):
|
|
context = create_mock_context(value=value)
|
|
composite = CompositeCondition(conditions=conditions, operator=operator)
|
|
assert composite.evaluate(context) == expected
|
|
|
|
|
|
# ================
|
|
# Test Hooks
|
|
# ================
|
|
|
|
@pytest.mark.parametrize("event_type, actual_event, threshold, text, expected", [
|
|
(EventType.RENDER, EventType.RENDER, 10, "Long text" * 10, True), # Event matches, meets condition
|
|
(EventType.RENDER, EventType.CLICK, 10, "Long text" * 10, False), # Event mismatch
|
|
])
|
|
def test_i_can_match_hook(event_type, actual_event, threshold, text, expected):
|
|
context = create_mock_context(value=text)
|
|
condition = WhenLongText(threshold=threshold)
|
|
hook = Hook(event_type=event_type, conditions=[condition], executor=lambda ctx: "Executed")
|
|
|
|
assert hook.matches(event_type=actual_event, context=context) == expected
|
|
|
|
|
|
# ================
|
|
# Test HookManager
|
|
# ================
|
|
|
|
def test_i_can_execute_hooks_in_manager():
|
|
hook_manager = HookManager()
|
|
|
|
# Add hooks
|
|
hook1 = Hook(EventType.RENDER, conditions=[], executor=lambda ctx: "Render Executed")
|
|
hook2 = Hook(EventType.CLICK, conditions=[], executor=lambda ctx: "Click Executed")
|
|
|
|
hook_manager.add_hook(hook1)
|
|
hook_manager.add_hook(hook2)
|
|
|
|
context = create_mock_context()
|
|
render_results = hook_manager.execute_hooks(event_type=EventType.RENDER, context=context)
|
|
click_results = hook_manager.execute_hooks(event_type=EventType.CLICK, context=context)
|
|
|
|
assert len(render_results) == 1
|
|
assert render_results[0] == "Render Executed"
|
|
|
|
assert len(click_results) == 1
|
|
assert click_results[0] == "Click Executed"
|
|
|
|
|
|
def test_i_can_clear_hooks_in_manager():
|
|
hook_manager = HookManager()
|
|
|
|
hook_manager.add_hook(Hook(EventType.RENDER, conditions=[], executor=lambda ctx: "Render"))
|
|
assert len(hook_manager.hooks) == 1
|
|
|
|
hook_manager.clear_hooks()
|
|
assert len(hook_manager.hooks) == 0
|