206 lines
5.6 KiB
Python
206 lines
5.6 KiB
Python
import pytest
|
||
import inspect
|
||
from unittest.mock import MagicMock, patch
|
||
from textwrap import dedent
|
||
from slic.utils.shortcut import Shortcut, as_shortcut, shortcuts, Registry
|
||
|
||
@pytest.fixture(autouse=True)
|
||
def reset_shortcuts():
|
||
# Si c’est bien un Registry, il suffit de clear ses données
|
||
shortcuts._get().clear()
|
||
yield
|
||
shortcuts._get().clear()
|
||
|
||
# Tests for Shortcut class
|
||
class TestShortcutInitialization:
|
||
def test_init_with_custom_name(self):
|
||
# Verify initialization with custom name
|
||
func = lambda x: x * 2
|
||
sc = Shortcut(func, name="Doubler")
|
||
assert sc.func(5) == 10
|
||
assert sc.name == "Doubler"
|
||
|
||
def test_init_without_name(self):
|
||
# Test auto-naming from __name__
|
||
def addition_fct(a, b):
|
||
return a + b
|
||
sc = Shortcut(addition_fct)
|
||
assert sc.name == "addition fct"
|
||
assert sc.func(2, 3) == 5
|
||
|
||
def test_run_method(capsys):
|
||
# Test direct execution while verifying print output
|
||
execution_results = []
|
||
|
||
def sample():
|
||
execution_results.append("executed")
|
||
return "ok"
|
||
|
||
sc = Shortcut(sample, name="TestRun")
|
||
task = sc.run(hold=False) # Testing immediate execution
|
||
|
||
# Verify the print output
|
||
captured = capsys.readouterr()
|
||
assert captured.out == 'Running "TestRun"\n'
|
||
|
||
# Verify the function executed
|
||
assert execution_results == ["executed"]
|
||
|
||
# Verify Task properties
|
||
assert task.func == sample
|
||
assert task.func() == "ok"
|
||
assert task.status == "done"
|
||
|
||
def test_repr_output():
|
||
# Test exact __repr__ format
|
||
def my_func():
|
||
pass
|
||
|
||
sc = Shortcut(my_func, name="Test Repr")
|
||
assert repr(sc) == f"Shortcut \"Test Repr\""
|
||
|
||
def test_source_with_regular_function():
|
||
# Test source with normal function
|
||
def example():
|
||
a = 1
|
||
b = 2
|
||
return a + b
|
||
|
||
sc = Shortcut(example)
|
||
src = sc.source
|
||
assert "def example():" in src
|
||
assert "a = 1" in src
|
||
assert "b = 2" in src
|
||
assert "return a + b" in src
|
||
|
||
@patch('inspect.getsource')
|
||
def test_source_error_handling(mock_getsource):
|
||
# Test exception handling when inspect fails
|
||
mock_getsource.side_effect = OSError("No source")
|
||
sc = Shortcut(lambda x: x)
|
||
with pytest.raises(OSError):
|
||
_ = sc.source
|
||
|
||
# Tests for as_shortcut decorator
|
||
|
||
def test_as_shortcut_basic():
|
||
# Test basic decorator without parameters
|
||
@as_shortcut
|
||
def basic_func():
|
||
return 42
|
||
|
||
assert isinstance(basic_func, Shortcut)
|
||
assert basic_func.name == "basic func"
|
||
assert basic_func.func() == 42
|
||
|
||
def test_as_shortcut_with_name():
|
||
# Test decorator with name parameter
|
||
@as_shortcut(name="CustomName")
|
||
def decorated():
|
||
pass
|
||
|
||
assert decorated.name == "CustomName"
|
||
|
||
def test_as_shortcut_factory_pattern():
|
||
# Test factory pattern usage
|
||
decorator = as_shortcut(name="FromFactory")
|
||
|
||
@decorator
|
||
def sample():
|
||
pass
|
||
|
||
assert sample.name == "FromFactory"
|
||
|
||
# Tests for shortcuts singleton
|
||
|
||
class TestShortcutsSingleton:
|
||
def setup_method(self):
|
||
# Reset singleton before each test
|
||
shortcuts._instance = None
|
||
|
||
def test_singleton_behavior(self):
|
||
# Verify singleton pattern
|
||
inst1 = shortcuts
|
||
inst2 = shortcuts
|
||
assert inst1 is inst2
|
||
|
||
def test_registration(self):
|
||
# Test automatic registration
|
||
@as_shortcut(name="FuncA")
|
||
def func_a():
|
||
pass
|
||
|
||
@as_shortcut(name="FuncB")
|
||
def func_b():
|
||
pass
|
||
|
||
assert len(shortcuts._get()) == 2
|
||
assert "FuncA" in shortcuts._get()
|
||
assert shortcuts["FuncA"].func == func_a.func
|
||
|
||
def test_getitem_access(self):
|
||
# Test dictionary-style access
|
||
@as_shortcut(name="TestAccess")
|
||
def access_test():
|
||
return 123
|
||
|
||
assert shortcuts["TestAccess"].func() == 123
|
||
|
||
def test_missing_key(self):
|
||
# Test access with invalid key
|
||
with pytest.raises(KeyError):
|
||
_ = shortcuts["InvalidKey"]
|
||
|
||
def test_repr_output(self):
|
||
# Test registry display
|
||
@as_shortcut(name="DisplayTest")
|
||
def to_display():
|
||
pass
|
||
|
||
repr_str = repr(shortcuts)
|
||
assert "DisplayTest" in repr_str
|
||
assert "Shortcut" in repr_str
|
||
|
||
# Full integration tests
|
||
|
||
class TestFullIntegration:
|
||
def setup_method(self):
|
||
shortcuts._instance = None
|
||
|
||
def test_workflow(self, capsys):
|
||
# Test complete workflow from creation to execution
|
||
@as_shortcut(name="FullTest")
|
||
def integration_test(a, b):
|
||
print(f"Calculating {a} + {b}")
|
||
return a + b
|
||
|
||
sc = shortcuts["FullTest"]
|
||
assert sc.name == "FullTest"
|
||
|
||
task = sc.run(hold=True)
|
||
out, _ = capsys.readouterr()
|
||
assert "Running \"FullTest\"" in out
|
||
|
||
assert task.func(3, 4) == 7
|
||
|
||
source = sc.source
|
||
assert "def integration_test(a, b):" in source
|
||
assert "print(f\"Calculating {a} + {b}\")" in source
|
||
|
||
def test_multiple_shortcuts(self):
|
||
# Test multiple shortcuts coexistence
|
||
@as_shortcut(name="First")
|
||
def first():
|
||
return 1
|
||
|
||
@as_shortcut(name="Second")
|
||
def second():
|
||
return 2
|
||
|
||
assert shortcuts["First"].func() == 1
|
||
assert shortcuts["Second"].func() == 2
|
||
assert len(shortcuts._get()) == 2
|
||
|
||
def test_registry_inheritance():
|
||
# Verify Shortcut inherits from Registry
|
||
assert issubclass(Shortcut, Registry) |