1 /* 2 * Copyright (C) 2007 The Guava Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.common.eventbus; 18 19 import com.google.common.collect.Lists; 20 import java.util.Collection; 21 import java.util.List; 22 import java.util.Set; 23 import junit.framework.TestCase; 24 25 /** 26 * Test case for {@link EventBus}. 27 * 28 * @author Cliff Biffle 29 */ 30 public class EventBusTest extends TestCase { 31 private static final String EVENT = "Hello"; 32 private static final String BUS_IDENTIFIER = "test-bus"; 33 34 private EventBus bus; 35 36 @Override protected void setUp() throws Exception { 37 super.setUp(); 38 bus = new EventBus(BUS_IDENTIFIER); 39 } 40 41 public void testBasicCatcherDistribution() { 42 StringCatcher catcher = new StringCatcher(); 43 bus.register(catcher); 44 45 Set<EventHandler> wrappers = bus.getHandlersForEventType(String.class); 46 assertNotNull("Should have at least one method registered.", wrappers); 47 assertEquals("One method should be registered.", 1, wrappers.size()); 48 49 bus.post(EVENT); 50 51 List<String> events = catcher.getEvents(); 52 assertEquals("Only one event should be delivered.", 1, events.size()); 53 assertEquals("Correct string should be delivered.", EVENT, events.get(0)); 54 } 55 56 /** 57 * Tests that events are distributed to any subscribers to their type or any 58 * supertype, including interfaces and superclasses. 59 * 60 * Also checks delivery ordering in such cases. 61 */ 62 public void testPolymorphicDistribution() { 63 // Three catchers for related types String, Object, and Comparable<?>. 64 // String isa Object 65 // String isa Comparable<?> 66 // Comparable<?> isa Object 67 StringCatcher stringCatcher = new StringCatcher(); 68 69 final List<Object> objectEvents = Lists.newArrayList(); 70 Object objCatcher = new Object() { 71 @SuppressWarnings("unused") 72 @Subscribe public void eat(Object food) { 73 objectEvents.add(food); 74 } 75 }; 76 77 final List<Comparable<?>> compEvents = Lists.newArrayList(); 78 Object compCatcher = new Object() { 79 @SuppressWarnings("unused") 80 @Subscribe public void eat(Comparable<?> food) { 81 compEvents.add(food); 82 } 83 }; 84 bus.register(stringCatcher); 85 bus.register(objCatcher); 86 bus.register(compCatcher); 87 88 // Two additional event types: Object and Comparable<?> (played by Integer) 89 final Object OBJ_EVENT = new Object(); 90 final Object COMP_EVENT = new Integer(6); 91 92 bus.post(EVENT); 93 bus.post(OBJ_EVENT); 94 bus.post(COMP_EVENT); 95 96 // Check the StringCatcher... 97 List<String> stringEvents = stringCatcher.getEvents(); 98 assertEquals("Only one String should be delivered.", 99 1, stringEvents.size()); 100 assertEquals("Correct string should be delivered.", 101 EVENT, stringEvents.get(0)); 102 103 // Check the Catcher<Object>... 104 assertEquals("Three Objects should be delivered.", 105 3, objectEvents.size()); 106 assertEquals("String fixture must be first object delivered.", 107 EVENT, objectEvents.get(0)); 108 assertEquals("Object fixture must be second object delivered.", 109 OBJ_EVENT, objectEvents.get(1)); 110 assertEquals("Comparable fixture must be thirdobject delivered.", 111 COMP_EVENT, objectEvents.get(2)); 112 113 // Check the Catcher<Comparable<?>>... 114 assertEquals("Two Comparable<?>s should be delivered.", 115 2, compEvents.size()); 116 assertEquals("String fixture must be first comparable delivered.", 117 EVENT, compEvents.get(0)); 118 assertEquals("Comparable fixture must be second comparable delivered.", 119 COMP_EVENT, compEvents.get(1)); 120 } 121 122 public void testDeadEventForwarding() { 123 GhostCatcher catcher = new GhostCatcher(); 124 bus.register(catcher); 125 126 // A String -- an event for which noone has registered. 127 bus.post(EVENT); 128 129 List<DeadEvent> events = catcher.getEvents(); 130 assertEquals("One dead event should be delivered.", 1, events.size()); 131 assertEquals("The dead event should wrap the original event.", 132 EVENT, events.get(0).getEvent()); 133 } 134 135 public void testDeadEventPosting() { 136 GhostCatcher catcher = new GhostCatcher(); 137 bus.register(catcher); 138 139 bus.post(new DeadEvent(this, EVENT)); 140 141 List<DeadEvent> events = catcher.getEvents(); 142 assertEquals("The explicit DeadEvent should be delivered.", 143 1, events.size()); 144 assertEquals("The dead event must not be re-wrapped.", 145 EVENT, events.get(0).getEvent()); 146 } 147 148 public void testFlattenHierarchy() { 149 HierarchyFixture fixture = new HierarchyFixture(); 150 Set<Class<?>> hierarchy = bus.flattenHierarchy(fixture.getClass()); 151 152 assertEquals(5, hierarchy.size()); 153 assertContains(Object.class, hierarchy); 154 assertContains(HierarchyFixtureInterface.class, hierarchy); 155 assertContains(HierarchyFixtureSubinterface.class, hierarchy); 156 assertContains(HierarchyFixtureParent.class, hierarchy); 157 assertContains(HierarchyFixture.class, hierarchy); 158 } 159 160 public void testMissingSubscribe() { 161 bus.register(new Object()); 162 } 163 164 public void testUnregister() { 165 StringCatcher catcher1 = new StringCatcher(); 166 StringCatcher catcher2 = new StringCatcher(); 167 try { 168 bus.unregister(catcher1); 169 fail("Attempting to unregister an unregistered object succeeded"); 170 } catch (IllegalArgumentException expected) { 171 // OK. 172 } 173 174 bus.register(catcher1); 175 bus.post(EVENT); 176 bus.register(catcher2); 177 bus.post(EVENT); 178 179 List<String> expectedEvents = Lists.newArrayList(); 180 expectedEvents.add(EVENT); 181 expectedEvents.add(EVENT); 182 183 assertEquals("Two correct events should be delivered.", 184 expectedEvents, catcher1.getEvents()); 185 186 assertEquals("One correct event should be delivered.", 187 Lists.newArrayList(EVENT), catcher2.getEvents()); 188 189 bus.unregister(catcher1); 190 bus.post(EVENT); 191 192 assertEquals("Shouldn't catch any more events when unregistered.", 193 expectedEvents, catcher1.getEvents()); 194 assertEquals("Two correct events should be delivered.", 195 expectedEvents, catcher2.getEvents()); 196 197 try { 198 bus.unregister(catcher1); 199 fail("Attempting to unregister an unregistered object succeeded"); 200 } catch (IllegalArgumentException expected) { 201 // OK. 202 } 203 204 bus.unregister(catcher2); 205 bus.post(EVENT); 206 assertEquals("Shouldn't catch any more events when unregistered.", 207 expectedEvents, catcher1.getEvents()); 208 assertEquals("Shouldn't catch any more events when unregistered.", 209 expectedEvents, catcher2.getEvents()); 210 } 211 212 private <T> void assertContains(T element, Collection<T> collection) { 213 assertTrue("Collection must contain " + element, 214 collection.contains(element)); 215 } 216 217 /** 218 * A collector for DeadEvents. 219 * 220 * @author cbiffle 221 * 222 */ 223 public static class GhostCatcher { 224 private List<DeadEvent> events = Lists.newArrayList(); 225 226 @Subscribe 227 public void ohNoesIHaveDied(DeadEvent event) { 228 events.add(event); 229 } 230 231 public List<DeadEvent> getEvents() { 232 return events; 233 } 234 } 235 236 public interface HierarchyFixtureInterface { 237 // Exists only for hierarchy mapping; no members. 238 } 239 240 public interface HierarchyFixtureSubinterface 241 extends HierarchyFixtureInterface { 242 // Exists only for hierarchy mapping; no members. 243 } 244 245 public static class HierarchyFixtureParent 246 implements HierarchyFixtureSubinterface { 247 // Exists only for hierarchy mapping; no members. 248 } 249 250 public static class HierarchyFixture extends HierarchyFixtureParent { 251 // Exists only for hierarchy mapping; no members. 252 } 253 254 } 255