# -*- coding: utf-8 -*-
"""Test CLR event support."""
import pytest
from Python.Test import EventTest, EventArgsTest
from .utils import (CallableHandler, ClassMethodHandler, GenericHandler,
MultipleHandler, StaticMethodHandler, VarCallableHandler,
VariableArgsHandler)
def test_public_instance_event():
"""Test public instance events."""
ob = EventTest()
handler = GenericHandler()
assert handler.value is None
ob.PublicEvent += handler.handler
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 10
ob.PublicEvent -= handler.handler
def test_public_static_event():
"""Test public static events."""
handler = GenericHandler()
assert handler.value is None
EventTest.PublicStaticEvent += handler.handler
EventTest.OnPublicStaticEvent(EventArgsTest(10))
assert handler.value == 10
def test_protected_instance_event():
"""Test protected instance events."""
ob = EventTest()
handler = GenericHandler()
assert handler.value is None
ob.ProtectedEvent += handler.handler
ob.OnProtectedEvent(EventArgsTest(10))
assert handler.value == 10
ob.ProtectedEvent -= handler.handler
def test_protected_static_event():
"""Test protected static events."""
handler = GenericHandler()
assert handler.value is None
EventTest.ProtectedStaticEvent += handler.handler
EventTest.OnProtectedStaticEvent(EventArgsTest(10))
assert handler.value == 10
EventTest.ProtectedStaticEvent -= handler.handler
def test_internal_events():
"""Test internal events."""
with pytest.raises(AttributeError):
_ = EventTest().InternalEvent
with pytest.raises(AttributeError):
_ = EventTest().InternalStaticEvent
with pytest.raises(AttributeError):
_ = EventTest.InternalStaticEvent
def test_private_events():
"""Test private events."""
with pytest.raises(AttributeError):
_ = EventTest().PrivateEvent
with pytest.raises(AttributeError):
_ = EventTest().PrivateStaticEvent
with pytest.raises(AttributeError):
_ = EventTest.PrivateStaticEvent
def test_multicast_event():
"""Test multicast events."""
ob = EventTest()
handler1 = GenericHandler()
handler2 = GenericHandler()
handler3 = GenericHandler()
ob.PublicEvent += handler1.handler
ob.PublicEvent += handler2.handler
ob.PublicEvent += handler3.handler
ob.OnPublicEvent(EventArgsTest(10))
assert handler1.value == 10
assert handler2.value == 10
assert handler3.value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert handler1.value == 20
assert handler2.value == 20
assert handler3.value == 20
ob.PublicEvent -= handler1.handler
ob.PublicEvent -= handler2.handler
ob.PublicEvent -= handler3.handler
def test_instance_method_handler():
"""Test instance method handlers."""
ob = EventTest()
handler = GenericHandler()
ob.PublicEvent += handler.handler
assert handler.value is None
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 10
ob.PublicEvent -= handler.handler
assert handler.value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert handler.value == 10
def test_var_args_instance_method_handler():
"""Test vararg instance method handlers."""
ob = EventTest()
handler = VariableArgsHandler()
ob.PublicEvent += handler.handler
assert handler.value is None
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 10
ob.PublicEvent -= handler.handler
assert handler.value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert handler.value == 10
def test_callableob_handler():
"""Test callable ob handlers."""
ob = EventTest()
handler = CallableHandler()
ob.PublicEvent += handler
assert handler.value is None
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 10
ob.PublicEvent -= handler
assert handler.value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert handler.value == 10
def test_var_args_callable_handler():
"""Test varargs callable handlers."""
ob = EventTest()
handler = VarCallableHandler()
ob.PublicEvent += handler
assert handler.value is None
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 10
ob.PublicEvent -= handler
assert handler.value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert handler.value == 10
def test_static_method_handler():
"""Test static method handlers."""
ob = EventTest()
handler = StaticMethodHandler()
StaticMethodHandler.value = None
ob.PublicEvent += handler.handler
assert handler.value is None
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 10
ob.PublicEvent -= handler.handler
assert handler.value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert handler.value == 10
def test_class_method_handler():
"""Test class method handlers."""
ob = EventTest()
handler = ClassMethodHandler()
ClassMethodHandler.value = None
ob.PublicEvent += handler.handler
assert handler.value is None
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 10
ob.PublicEvent -= handler.handler
assert handler.value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert handler.value == 10
def test_managed_instance_method_handler():
"""Test managed instance method handlers."""
ob = EventTest()
ob.PublicEvent += ob.GenericHandler
assert ob.value == 0
ob.OnPublicEvent(EventArgsTest(10))
assert ob.value == 10
ob.PublicEvent -= ob.GenericHandler
assert ob.value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert ob.value == 10
def test_managed_static_method_handler():
"""Test managed static method handlers."""
ob = EventTest()
EventTest.s_value = 0
ob.PublicEvent += ob.StaticHandler
assert EventTest.s_value == 0
ob.OnPublicEvent(EventArgsTest(10))
assert EventTest.s_value == 10
ob.PublicEvent -= ob.StaticHandler
assert EventTest.s_value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert EventTest.s_value == 10
def test_unbound_method_handler():
"""Test failure mode for unbound method handlers."""
ob = EventTest()
ob.PublicEvent += GenericHandler.handler
with pytest.raises(TypeError):
ob.OnPublicEvent(EventArgsTest(10))
ob.PublicEvent -= GenericHandler.handler
def test_function_handler():
"""Test function handlers."""
ob = EventTest()
dict_ = {'value': None}
def handler(sender, args, dict_=dict_):
dict_['value'] = args.value
ob.PublicEvent += handler
assert dict_['value'] is None
ob.OnPublicEvent(EventArgsTest(10))
assert dict_['value'] == 10
ob.PublicEvent -= handler
assert dict_['value'] == 10
ob.OnPublicEvent(EventArgsTest(20))
assert dict_['value'] == 10
def test_out_function_handler():
"""Test function handlers with Out arguments."""
ob = EventTest()
value = 10
def handler(ignored):
return value
ob.OutIntEvent += handler
result = ob.OnOutIntEvent(55)
assert result == value
ob.OutStringEvent += handler
value = 'This is the event data'
result = ob.OnOutStringEvent('Hello')
assert result == value
def test_ref_function_handler():
"""Test function handlers with Ref arguments."""
ob = EventTest()
value = 10
def handler(data):
return value + data
ob.RefIntEvent += ob.RefIntHandler
ob.RefIntEvent += handler
result = ob.OnRefIntEvent(5)
assert result == value + 5 + 1
ob.RefStringEvent += ob.RefStringHandler
ob.RefStringEvent += handler
value = 'This is the event data'
result = ob.OnRefStringEvent('!')
assert result == value + '!!'
def test_add_non_callable_handler():
"""Test handling of attempts to add non-callable handlers."""
with pytest.raises(TypeError):
ob = EventTest()
ob.PublicEvent += 10
with pytest.raises(TypeError):
ob = EventTest()
ob.PublicEvent += "spam"
with pytest.raises(TypeError):
class Spam(object):
pass
ob = EventTest()
ob.PublicEvent += Spam()
def test_remove_multiple_handlers():
"""Test removing multiple instances of the same handler."""
ob = EventTest()
handler = MultipleHandler()
h1 = handler.handler
ob.PublicEvent += h1
h2 = handler.handler
ob.PublicEvent += h2
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 20
ob.PublicEvent -= h1
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 30
ob.PublicEvent -= h2
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 30
# try again, removing in a different order.
ob = EventTest()
handler = MultipleHandler()
h1 = handler.handler
ob.PublicEvent += h1
h2 = handler.handler
ob.PublicEvent += h2
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 20
ob.PublicEvent -= h2
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 30
ob.PublicEvent -= h1
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 30
def test_remove_multiple_static_handlers():
"""Test removing multiple instances of a static handler."""
ob = EventTest()
handler = MultipleHandler()
h1 = handler.handler
ob.PublicStaticEvent += h1
h2 = handler.handler
ob.PublicStaticEvent += h2
ob.OnPublicStaticEvent(EventArgsTest(10))
assert handler.value == 20
ob.PublicStaticEvent -= h1
ob.OnPublicStaticEvent(EventArgsTest(10))
assert handler.value == 30
ob.PublicStaticEvent -= h2
ob.OnPublicStaticEvent(EventArgsTest(10))
assert handler.value == 30
# try again, removing in a different order.
ob = EventTest()
handler = MultipleHandler()
h1 = handler.handler
ob.PublicStaticEvent += h1
h2 = handler.handler
ob.PublicStaticEvent += h2
ob.OnPublicStaticEvent(EventArgsTest(10))
assert handler.value == 20
ob.PublicStaticEvent -= h2
ob.OnPublicStaticEvent(EventArgsTest(10))
assert handler.value == 30
ob.PublicStaticEvent -= h1
ob.OnPublicStaticEvent(EventArgsTest(10))
assert handler.value == 30
def test_random_multiple_handlers():
"""Test random subscribe / unsubscribe of the same handlers."""
import random
ob = EventTest()
handler = MultipleHandler()
handler2 = MultipleHandler()
ob.PublicEvent += handler2.handler
ob.PublicEvent += handler2.handler
handlers = []
for _ in range(30):
method = handler.handler
ob.PublicEvent += method
handlers.append(method)
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 300
assert handler2.value == 20
handler.value = 0
handler2.value = 0
for i in range(30):
item = random.choice(handlers)
handlers.remove(item)
ob.PublicEvent -= item
handler.value = 0
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == (len(handlers) * 10)
assert handler2.value == ((i + 1) * 20)
handler2.value = 0
ob.OnPublicEvent(EventArgsTest(10))
assert handler2.value == 20
ob.PublicEvent -= handler2.handler
handler2.value = 0
ob.OnPublicEvent(EventArgsTest(10))
assert handler2.value == 10
ob.PublicEvent -= handler2.handler
handler2.value = 0
ob.OnPublicEvent(EventArgsTest(10))
assert handler2.value == 0
def test_remove_internal_call_handler():
"""Test remove on an event sink implemented w/internalcall."""
ob = EventTest()
def h(sender, args):
pass
ob.PublicEvent += h
ob.PublicEvent -= h
def test_remove_unknown_handler():
"""Test removing an event handler that was never added."""
with pytest.raises(ValueError):
ob = EventTest()
handler = GenericHandler()
ob.PublicEvent -= handler.handler
def test_handler_callback_failure():
"""Test failure mode for inappropriate handlers."""
class BadHandler(object):
def handler(self, one):
return 'too many'
ob = EventTest()
handler = BadHandler()
with pytest.raises(TypeError):
ob.PublicEvent += handler.handler
ob.OnPublicEvent(EventArgsTest(10))
ob.PublicEvent -= handler.handler
class BadHandler(object):
def handler(self, one, two, three, four, five):
return 'not enough'
ob = EventTest()
handler = BadHandler()
with pytest.raises(TypeError):
ob.PublicEvent += handler.handler
ob.OnPublicEvent(EventArgsTest(10))
ob.PublicEvent -= handler.handler
def test_incorrect_invokation():
"""Test incorrect invocation of events."""
ob = EventTest()
handler = GenericHandler()
ob.PublicEvent += handler.handler
with pytest.raises(TypeError):
ob.OnPublicEvent()
with pytest.raises(TypeError):
ob.OnPublicEvent(32)
ob.PublicEvent -= handler.handler
def test_explicit_cls_event_registration():
"""Test explicit CLS event registration."""
from Python.Test import EventHandlerTest
ob = EventTest()
handler = GenericHandler()
delegate = EventHandlerTest(handler.handler)
ob.add_PublicEvent(delegate)
assert handler.value is None
ob.OnPublicEvent(EventArgsTest(10))
assert handler.value == 10
ob.remove_PublicEvent(delegate)
assert handler.value == 10
ob.OnPublicEvent(EventArgsTest(20))
assert handler.value == 10
def test_implicit_cls_event_registration():
"""Test implicit CLS event registration."""
with pytest.raises(TypeError):
ob = EventTest()
handler = GenericHandler()
ob.add_PublicEvent(handler.handler)
def test_event_descriptor_abuse():
"""Test event descriptor abuse."""
with pytest.raises(TypeError):
del EventTest.PublicEvent
with pytest.raises(TypeError):
del EventTest.__dict__['PublicEvent']
desc = EventTest.__dict__['PublicEvent']
with pytest.raises(TypeError):
desc.__get__(0, 0)
with pytest.raises(TypeError):
desc.__set__(0, 0)
with pytest.raises(TypeError):
ob = EventTest()
ob.PublicEvent = 0
with pytest.raises(TypeError):
EventTest.PublicStaticEvent = 0