package net.mostlyoriginal.api.event.dispatcher; import com.artemis.utils.reflect.ClassReflection; import com.artemis.utils.reflect.Method; import net.mostlyoriginal.api.event.common.*; import org.junit.Before; import org.junit.Test; import java.util.List; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public abstract class AbstractEventDispatcherTest { public EventDispatchStrategy dispatcher; @Before public void setUp() throws Exception { dispatcher = createDispatcherInstance(); } protected abstract EventDispatchStrategy createDispatcherInstance(); public static class CancellableEvent implements Event, Cancellable { private boolean cancelled; @Override public boolean isCancelled() { return cancelled; } @Override public void setCancelled(boolean value) { cancelled = value; } } public static class BaseEvent implements Event {} public static class ExtendedEvent extends BaseEvent {} public static class MismatchedEvent implements Event {} public static class SingleListenPojo { public int calls=0; public void l(BaseEvent event) { calls++; } } /** Setup a listener pojo, registering all methods as listeners. */ protected <T> T setupListenerPojo(Class<T> pojoClass) { try { final T pojo = pojoClass.newInstance(); for (Method method : ClassReflection.getMethods(pojoClass)) { // do not register superclass methods. if ( !method.getDeclaringClass().equals(pojoClass) ) continue; dispatcher.register(new EventListener(pojo, method)); } return pojo; } catch ( Exception e ) { throw new RuntimeException("Could not setup listener pojo",e); } } @Test public void Dispatch_EventWithExactClassListener_ListenerReceivesEvent() { final SingleListenPojo pojo = setupListenerPojo(SingleListenPojo.class); // match on exact listener class. dispatch(new BaseEvent()); assertEquals(1, pojo.calls); } /** Dispatch wrapper. */ protected void dispatch(Event event) { dispatcher.dispatch(event); } @Test public void Dispatch_EventWithSuperclassListener_ListenerReceivesEvent() { final SingleListenPojo pojo = setupListenerPojo(SingleListenPojo.class); dispatch(new ExtendedEvent()); assertEquals(1, pojo.calls); } @Test public void Dispatch_LateRegisteredListener_NoRegistrationIssues() { // Make sure registering a listener late doesn't break the dispatchers. final SingleListenPojo pojo = setupListenerPojo(SingleListenPojo.class); dispatch(new ExtendedEvent()); final SingleListenPojo pojo2 = setupListenerPojo(SingleListenPojo.class); dispatch(new ExtendedEvent()); assertEquals(2, pojo.calls); assertEquals(1, pojo2.calls); } @Test public void Dispatch_RegisterListenerTwice_NotCalledTwice() { // Create doubled up event listeners. final SingleListenPojo pojo = new SingleListenPojo(); for (Method method : ClassReflection.getMethods(SingleListenPojo.class)) { // do not register superclass methods. if ( !method.getDeclaringClass().equals(SingleListenPojo.class) ) continue; // register methods twice. EventListener listener = new EventListener(pojo, method); dispatcher.register(listener); dispatcher.register(listener); } dispatch(new ExtendedEvent()); assertEquals(1, pojo.calls); } @Test public void Dispatch_MismatchingEvents_ListenerDoesNotReceiveEvent() { final SingleListenPojo pojo = setupListenerPojo(SingleListenPojo.class); // mismatched event has no listeners. dispatch(new MismatchedEvent()); assertEquals(0, pojo.calls); } public static class MultiListenPojo { public int calls1=0; public int calls2=0; public int calls3=0; public void l(BaseEvent event) { calls1++; } public void l2(BaseEvent event) { calls2++; } public void l3(ExtendedEvent event) { calls3++; } } @Test public void Dispatch_SeveralMatchingListeners_AllListenersCalled() { final MultiListenPojo pojo = setupListenerPojo(MultiListenPojo.class); dispatch(new ExtendedEvent()); // all listeners should be hit, even superclass ones. assertEquals(1, pojo.calls1); assertEquals(1, pojo.calls2); assertEquals(1, pojo.calls3); } @Test public void Dispatch_PrioritizedListeners_CalledInCorrectOrder() { class SequenceListen { public int lastCalls = 0; public int firstCalls = 0; public int middleCalls = 0; @Subscribe(priority = -5) public void last(BaseEvent event) { assertEquals( "last - first not called before us.", 1, firstCalls ); assertEquals( "last - middle not called before us.", 1, middleCalls ); lastCalls++; } @Subscribe(priority = 5) public void first(BaseEvent event) { assertEquals( "first - middle called before us.", 0, middleCalls ); assertEquals( "first - last called before us.", 0, lastCalls ); firstCalls++; } @Subscribe public void middle(BaseEvent event) { assertEquals( "middle - first method not called.", 1, firstCalls ); assertEquals( "middle - last called before us.", 0, lastCalls ); middleCalls++; } } final SequenceListen pojo = new SequenceListen(); final List<EventListener> listeners = new SubscribeAnnotationFinder().resolve(pojo); for (EventListener listener : listeners) { dispatcher.register(listener); } dispatch(new BaseEvent()); // asserts are run in the SequenceListen class. // we just have to make sure the final class has also been called. assertEquals("last method never called.", 1, pojo.firstCalls); assertEquals("middle method never called.", 1, pojo.middleCalls); assertEquals("last method never called.", 1, pojo.lastCalls); } @Test public void Dispatch_PrioritizedListenersCancelledEvent_CancelledProperly() { class CancelListener { private int calledCancelled =0; @Subscribe(priority = 3, ignoreCancelledEvents = true) public void called(CancellableEvent event) { } @Subscribe(priority = 2, ignoreCancelledEvents = true) public void cancelling(CancellableEvent event) { event.setCancelled(true); } @Subscribe(priority = 1, ignoreCancelledEvents = true) public void ignoreCancelled(CancellableEvent event) { fail("Should never be called"); } @Subscribe(priority = 0) public void dontIgnoreCancelled(CancellableEvent event) { calledCancelled++; } } final CancelListener pojo = new CancelListener(); final List<EventListener> listeners = new SubscribeAnnotationFinder().resolve(pojo); for (EventListener listener : listeners) { dispatcher.register(listener); } dispatch(new CancellableEvent()); // expect cancelled events to be properly called. assertEquals(1, pojo.calledCancelled); } public static class UnrelatedEvent1 implements Event {} public static class UnrelatedEvent2 implements Event {} public static class UnrelatedEvent3 implements Event {} @Test public void Dispatch_SeveralEventHandlers_CorrectlyCascadedEventDispatch() { class MultiEventHandler { boolean handler1Called = false; boolean handler2Called = false; boolean handler3Called = false; @Subscribe() public void handler1(UnrelatedEvent1 evt) { handler1Called = true; dispatch(new UnrelatedEvent2()); } @Subscribe() public void handler2(UnrelatedEvent2 evt) { handler2Called = true; dispatch(new UnrelatedEvent3()); } @Subscribe() public void handler3(UnrelatedEvent3 evt) { handler3Called = true; } } final MultiEventHandler handler = new MultiEventHandler(); final List<EventListener> listeners = new SubscribeAnnotationFinder().resolve(handler); for (EventListener listener : listeners) { dispatcher.register(listener); } dispatch(new UnrelatedEvent1()); // expect that all event handlers were called in cascade aftet dispatch the first one assert(handler.handler1Called); assert(handler.handler2Called); assert(handler.handler3Called); } }