def test_emit(self): """ Test if events are succesfully emitted. """ callback = mock.Mock() self.evt_mgr.connect(BaseEvent, callback) evt1 = BaseEvent() self.evt_mgr.emit(evt1) self.assertEqual(callback.call_count, 1) self.assertEqual(callback.call_args, ((evt1, ), {})) callback2 = mock.Mock() self.evt_mgr.connect(BaseEvent, callback2) evt2 = BaseEvent() self.evt_mgr.emit(evt2) self.assertEqual(callback.call_count, 2) self.assertEqual(callback.call_args, ((evt2, ), {})) self.assertEqual(callback2.call_count, 1) self.assertEqual(callback2.call_args, ((evt2, ), {})) # Exceptions in listeners should still propagate events. def callback3(evt): raise RuntimeError('i\'m just like this') callback3 = mock.Mock(wraps=callback3) callback4 = mock.Mock() self.evt_mgr.connect(BaseEvent, callback3) self.evt_mgr.connect(BaseEvent, callback4) evt3 = BaseEvent() self.evt_mgr.emit(evt3) self.assertEqual(callback.call_count, 3) self.assertEqual(callback2.call_count, 2) self.assertEqual(callback3.call_count, 1) self.assertEqual(callback4.call_count, 1)
def test_set_trace(self): """ Test whether setting trace method works. """ self.evt_mgr.set_trace(self.trace_func) self.evt_mgr.emit(BaseEvent()) self.assertTrue(len(self.traces), 1) self.evt_mgr.set_trace(None) self.evt_mgr.emit(BaseEvent()) self.assertTrue(len(self.traces), 1)
def test_disable(self): """ Test if temporarily disabling an event works. """ class MyEvt(BaseEvent): def __init__(self): super(MyEvt, self).__init__() callback = mock.Mock() self.evt_mgr.connect(BaseEvent, callback) callback2 = mock.Mock() self.evt_mgr.connect(MyEvt, callback2) evt1 = BaseEvent() self.evt_mgr.emit(evt1) self.assertEqual(callback.call_count, 1) self.assertEqual(callback.call_args, ((evt1, ), {})) # Disabling BaseEvent. self.evt_mgr.disable(BaseEvent) self.evt_mgr.emit(BaseEvent()) self.assertEqual(callback.call_count, 1) # Disabling BaseEvent should also disable MyEvt. self.evt_mgr.emit(MyEvt()) self.assertEqual(callback.call_count, 1) self.assertEqual(callback2.call_count, 0) # Reenabling BaseEvent should fire notifications. self.evt_mgr.enable(BaseEvent) self.evt_mgr.emit(MyEvt()) self.assertEqual(callback.call_count, 2) self.assertEqual(callback2.call_count, 1) # Disabling MyEvt should not disable BaseEvent but only MyEvt. self.evt_mgr.disable(MyEvt) self.evt_mgr.emit(BaseEvent()) self.assertEqual(callback.call_count, 3) self.evt_mgr.emit(MyEvt()) self.assertEqual(callback.call_count, 3) self.assertEqual(callback2.call_count, 1) # Reenabling MyEvent should notify callback2. self.evt_mgr.enable(MyEvt) self.evt_mgr.emit(MyEvt()) self.assertEqual(callback.call_count, 4) self.assertEqual(callback2.call_count, 2) # Test for disable before any method is registered. class MyEvt2(BaseEvent): pass self.evt_mgr.disable(MyEvt2) callback = mock.Mock() self.evt_mgr.connect(MyEvt2, callback) self.evt_mgr.emit(MyEvt2()) self.assertFalse(callback.called)
def test_disconnect(self): """ Test if disconnecting listeners works. """ callback = mock.Mock() self.evt_mgr.connect(BaseEvent, callback) evt1 = BaseEvent() self.evt_mgr.emit(evt1) self.assertEqual(callback.call_count, 1) self.assertEqual(callback.call_args, ((evt1, ), {})) self.evt_mgr.disconnect(BaseEvent, callback) self.evt_mgr.emit(BaseEvent()) self.assertEqual(callback.call_count, 1) self.assertEqual(callback.call_args, ((evt1, ), {}))
def test_no_block(self): """ Test if non-blocking emit works. """ data = [] lock = threading.Lock() lock.acquire() def callback(evt): # callback will wait until lock is released. with lock: data.append('callback') data.append(threading.current_thread().name) self.evt_mgr.connect(BaseEvent, callback) t = self.evt_mgr.emit(BaseEvent(), block=False) # The next statement will be executed before callback returns. data.append('main') # Unblock the callback to proceed. lock.release() # Wait until the event handling finishes. t.join() data.append('main2') self.assertEqual(len(data), 4) self.assertEqual(data[0], 'main') self.assertEqual(data[1], 'callback') self.assertEqual(data[3], 'main2')
def test_lambda_connect(self): """ Test if lambda functions w/o references are not garbage collected. """ data = [] self.evt_mgr.connect(BaseEvent, lambda evt: data.append(1)) self.evt_mgr.emit(BaseEvent()) self.assertEqual(data, [1])
def test_priority(self): """ Test if setting priority of handlers works. """ class Callback(object): calls = [] def __init__(self, name): self.name = name def __call__(self, evt): self.calls.append(self.name) callback = mock.Mock(wraps=Callback(name=1)) self.evt_mgr.connect(BaseEvent, callback, priority=1) callback2 = mock.Mock(wraps=Callback(name=2)) self.evt_mgr.connect(BaseEvent, callback2, priority=2) callback3 = mock.Mock(wraps=Callback(name=3)) self.evt_mgr.connect(BaseEvent, callback3, priority=0) self.evt_mgr.emit(BaseEvent()) self.assertEqual(callback.call_count, 1) self.assertEqual(callback2.call_count, 1) self.assertEqual(callback3.call_count, 1) self.assertEqual(Callback.calls, [2, 1, 3])
def test_trace_veto(self): """ Test whether vetoing of actions works. """ callback1 = mock.Mock() callback2 = mock.Mock() self.evt_mgr.set_trace(self.trace_func_veto) self.evt_mgr.connect(BaseEvent, callback1) self.evt_mgr.emit(BaseEvent()) self.assertTrue(len(self.traces), 2) self.assertEqual(len(self.tracedict['connect']), 1) self.assertEqual(len(self.tracedict['emit']), 1) self.assertEqual(len(self.tracedict.get('listen', [])), 0) self.assertFalse(callback1.called) # Disable calling of callback1 self.veto_condition = lambda name, method, args: name == 'listen' and method == callback1 self.evt_mgr.connect(BaseEvent, callback1) self.evt_mgr.emit(BaseEvent()) self.assertEqual(len(self.tracedict['connect']), 2) self.assertEqual(len(self.tracedict['emit']), 2) self.assertEqual(len(self.tracedict['listen']), 1) self.assertFalse(callback1.called) # Ensure callback2 is still called. self.evt_mgr.connect(BaseEvent, callback2) self.evt_mgr.emit(BaseEvent()) self.assertEqual(len(self.tracedict['connect']), 3) self.assertEqual(len(self.tracedict['emit']), 3) self.assertEqual(len(self.tracedict['listen']), 3) self.assertFalse(callback1.called) self.assertTrue(callback2.called) # Disable tracing. self.evt_mgr.set_trace(None) self.evt_mgr.emit(BaseEvent()) self.assertEqual(len(self.tracedict['connect']), 3) self.assertEqual(len(self.tracedict['emit']), 3) self.assertEqual(len(self.tracedict['listen']), 3) self.assertTrue(callback1.called) self.assertEqual(callback2.call_count, 2)
def test_trace_emit(self): """ Test whether trace works for all actions. """ self.evt_mgr.set_trace(self.trace_func) self.evt_mgr.emit(BaseEvent()) self.assertTrue(len(self.traces), 1) self.assertEqual(len(self.tracedict['emit']), 1) callback1 = mock.Mock() self.evt_mgr.connect(BaseEvent, callback1) self.assertTrue(len(self.traces), 2) self.assertEqual(len(self.tracedict['connect']), 1) self.evt_mgr.emit(BaseEvent()) self.assertTrue(len(self.traces), 4) self.assertEqual(len(self.tracedict['emit']), 2) self.assertEqual(len(self.tracedict['listen']), 1) self.assertEqual(callback1.call_count, 1) self.evt_mgr.disconnect(BaseEvent, callback1) self.assertTrue(len(self.traces), 5) self.assertEqual(len(self.tracedict['disconnect']), 1) self.assertEqual(callback1.call_count, 1)
def test_reconnect(self): """ Test reconnecting already connected listener. """ calls = [] def callback1(evt): calls.append(1) def callback2(evt): calls.append(2) # Test if reconnect disconnects previous. self.evt_mgr.connect(BaseEvent, callback1) self.evt_mgr.connect(BaseEvent, callback1) self.evt_mgr.emit(BaseEvent()) self.assertEqual(calls, [1]) calls[:] = [] # Test if sequence is changed. self.evt_mgr.connect(BaseEvent, callback2) self.evt_mgr.connect(BaseEvent, callback1) self.evt_mgr.emit(BaseEvent()) self.assertEqual(calls, [2, 1]) calls[:] = []
def test_method_weakref(self): """ Test if methods do not prevent garbage collection of objects. """ data = [] class MyHeavyObject(object): def callback(self, evt): data.append(1) obj = MyHeavyObject() obj_wr = weakref.ref(obj) self.evt_mgr.connect(BaseEvent, obj.callback) del obj # Now there should be no references to obj. self.assertEqual(obj_wr(), None) self.evt_mgr.emit(BaseEvent()) self.assertEqual(data, [])
def test_method_disconnect2(self): """ Test if method disconnect on unconnected method fails. """ data = [] class MyHeavyObject(object): def callback(self, evt): data.append(1) def callback2(self, evt): data.append(2) obj = MyHeavyObject() self.evt_mgr.connect(BaseEvent, obj.callback) with self.assertRaises(Exception): self.evt_mgr.disconnect(BaseEvent, obj.callback2) self.evt_mgr.emit(BaseEvent()) self.assertEqual(data, [1])
def test_method_collect(self): """ Test if object garbage collection disconnects listener method. """ data = [] class MyHeavyObject(object): def callback(self, evt): data.append(1) obj = MyHeavyObject() obj_wr = weakref.ref(obj) self.evt_mgr.connect(BaseEvent, obj.callback) del obj # Now there should be no references to obj. self.assertEqual(obj_wr(), None) self.evt_mgr.emit(BaseEvent()) self.assertEqual(data, []) self.assertEqual(len(list(self.evt_mgr.get_listeners(BaseEvent))), 0)
def test_subclass(self): """ Test if subclass event notifies superclass listeners. Cases to test: 1. subclass event should notify superclass listeners even when the subclass event is not registered/connected even when the superclass event is added before/after subclass 2. superclass event should not notify subclass listeners """ class MyEvt(BaseEvent): pass class MyEvt2(MyEvt): pass callback = mock.Mock() callback2 = mock.Mock() self.evt_mgr.connect(MyEvt, callback) self.evt_mgr.connect(MyEvt2, callback2) # No callback called on BaseEvent self.evt_mgr.emit(BaseEvent()) self.assertEqual(callback.call_count, 0) self.assertEqual(callback2.call_count, 0) # Only callback called on MyEvt self.evt_mgr.emit(MyEvt()) self.assertEqual(callback.call_count, 1) self.assertEqual(callback2.call_count, 0) # Both callbacks called on MyEvt2 self.evt_mgr.emit(MyEvt2()) self.assertEqual(callback.call_count, 2) self.assertEqual(callback2.call_count, 1) # Add a new subclass event class MyEvt3(MyEvt2): pass # Subclass event not registered # Both callbacks called on MyEvt3 self.evt_mgr.emit(MyEvt3()) self.assertEqual(callback.call_count, 3) self.assertEqual(callback2.call_count, 2)
def test_reentrant_disconnect_emit(self): """ Test listener is called even if it is disconnected before notify. """ data = [] def callback(evt): data.append(0) self.evt_mgr.disconnect(BaseEvent, callback2) self.evt_mgr.disconnect(BaseEvent, callback3) data.append(1) def callback2(evt): data.append(2) def callback3(evt): data.append(3) self.evt_mgr.connect(BaseEvent, callback) self.evt_mgr.connect(BaseEvent, callback2) self.evt_mgr.connect(BaseEvent, callback3) self.evt_mgr.emit(BaseEvent()) self.assertEqual(data, [0, 1, 2, 3])