1 /* 2 * Copyright (C) 2010 Google Inc. 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 libcore.java.util.beans; 18 19 import java.beans.IndexedPropertyChangeEvent; 20 import java.beans.PropertyChangeEvent; 21 import java.beans.PropertyChangeListener; 22 import java.beans.PropertyChangeListenerProxy; 23 import java.beans.PropertyChangeSupport; 24 import java.io.Serializable; 25 import java.util.ArrayList; 26 import java.util.Arrays; 27 import java.util.Collections; 28 import java.util.EventListener; 29 import java.util.List; 30 import junit.framework.TestCase; 31 import libcore.libcore.util.SerializationTester; 32 33 public final class PropertyChangeSupportTest extends TestCase { 34 testOldAndNewAreBothNull()35 public void testOldAndNewAreBothNull() { 36 Object bean = new Object(); 37 PropertyChangeSupport support = new PropertyChangeSupport(bean); 38 EventLog listener = new EventLog(); 39 support.addPropertyChangeListener(listener); 40 41 PropertyChangeEvent nullToNull = new PropertyChangeEvent(bean, "a", null, null); 42 support.firePropertyChange(nullToNull); 43 assertEquals(Arrays.<PropertyChangeEvent>asList(nullToNull), listener.log); 44 } 45 testOldAndNewAreTheSame()46 public void testOldAndNewAreTheSame() { 47 Object bean = new Object(); 48 PropertyChangeSupport support = new PropertyChangeSupport(bean); 49 EventLog listener = new EventLog(); 50 support.addPropertyChangeListener(listener); 51 52 PropertyChangeEvent xToX = new PropertyChangeEvent(bean, "a", "x", new String("x")); 53 support.firePropertyChange(xToX); 54 assertEquals(Arrays.<PropertyChangeEvent>asList(), listener.log); 55 } 56 testEventsFilteredByProxies()57 public void testEventsFilteredByProxies() { 58 Object bean = new Object(); 59 PropertyChangeEvent eventA = new PropertyChangeEvent(bean, "a", false, true); 60 PropertyChangeEvent eventB = new PropertyChangeEvent(bean, "b", false, true); 61 PropertyChangeEvent eventC = new PropertyChangeEvent(bean, "c", false, true); 62 63 PropertyChangeSupport support = new PropertyChangeSupport(bean); 64 65 EventLog all = new EventLog(); 66 support.addPropertyChangeListener(all); 67 68 EventLog proxiedA = new EventLog(); 69 support.addPropertyChangeListener(new PropertyChangeListenerProxy("a", proxiedA)); 70 71 EventLog addA = new EventLog(); 72 support.addPropertyChangeListener("a", addA); 73 74 EventLog addAProxiedB = new EventLog(); 75 support.addPropertyChangeListener("a", new PropertyChangeListenerProxy("b", addAProxiedB)); 76 77 EventLog proxiedAB = new EventLog(); 78 support.addPropertyChangeListener(new PropertyChangeListenerProxy( 79 "a", new PropertyChangeListenerProxy("b", proxiedAB))); 80 81 EventLog proxiedAA = new EventLog(); 82 support.addPropertyChangeListener(new PropertyChangeListenerProxy("a", 83 new PropertyChangeListenerProxy("a", proxiedAA))); 84 85 EventLog proxiedAAC = new EventLog(); 86 support.addPropertyChangeListener(new PropertyChangeListenerProxy("a", 87 new PropertyChangeListenerProxy("a", 88 new PropertyChangeListenerProxy("c", proxiedAAC)))); 89 90 support.firePropertyChange(eventA); 91 support.firePropertyChange(eventB); 92 support.firePropertyChange(eventC); 93 94 assertEquals(Arrays.asList(eventA, eventB, eventC), all.log); 95 assertEquals(Arrays.asList(eventA), proxiedA.log); 96 assertEquals(Arrays.asList(eventA), addA.log); 97 assertEquals(Arrays.asList(eventA), addAProxiedB.log); 98 assertEquals(Arrays.asList(eventA), proxiedAB.log); 99 assertEquals(Arrays.asList(eventA), proxiedAA.log); 100 assertEquals(Arrays.asList(eventA), proxiedAAC.log); 101 } 102 103 /** 104 * Test that we need to do our own equals() work to manually unwrap an 105 * arbitrary number of proxies. 106 */ testRemoveWithProxies()107 public void testRemoveWithProxies() { 108 Object bean = new Object(); 109 PropertyChangeSupport support = new PropertyChangeSupport(bean); 110 111 EventLog all = new EventLog(); 112 support.addPropertyChangeListener(all); 113 assertEquals(1, support.getPropertyChangeListeners().length); 114 115 EventLog proxiedA = new EventLog(); 116 support.addPropertyChangeListener(new PropertyChangeListenerProxy("a", proxiedA)); 117 assertEquals(2, support.getPropertyChangeListeners().length); 118 119 EventLog addA = new EventLog(); 120 support.addPropertyChangeListener("a", addA); 121 assertEquals(3, support.getPropertyChangeListeners().length); 122 123 EventLog addAProxiedB = new EventLog(); 124 support.addPropertyChangeListener("a", new PropertyChangeListenerProxy("b", addAProxiedB)); 125 assertEquals(4, support.getPropertyChangeListeners().length); 126 127 EventLog proxiedAB = new EventLog(); 128 PropertyChangeListenerProxy proxyAB = new PropertyChangeListenerProxy( 129 "a", new PropertyChangeListenerProxy("b", proxiedAB)); 130 support.addPropertyChangeListener(proxyAB); 131 assertEquals(5, support.getPropertyChangeListeners().length); 132 133 EventLog proxiedAAC = new EventLog(); 134 support.addPropertyChangeListener(new PropertyChangeListenerProxy("a", 135 new PropertyChangeListenerProxy("a", 136 new PropertyChangeListenerProxy("c", proxiedAAC)))); 137 assertEquals(6, support.getPropertyChangeListeners().length); 138 139 support.removePropertyChangeListener(all); 140 assertEquals(5, support.getPropertyChangeListeners().length); 141 support.removePropertyChangeListener("a", proxiedA); 142 assertEquals(4, support.getPropertyChangeListeners().length); 143 support.removePropertyChangeListener(new PropertyChangeListenerProxy("a", addA)); 144 assertEquals(3, support.getPropertyChangeListeners().length); 145 support.removePropertyChangeListener( 146 "a", new PropertyChangeListenerProxy("b", addAProxiedB)); 147 assertEquals(2, support.getPropertyChangeListeners().length); 148 support.removePropertyChangeListener(proxyAB); 149 assertEquals(1, support.getPropertyChangeListeners().length); 150 151 support.removePropertyChangeListener(proxiedAAC); 152 assertEquals(1, support.getPropertyChangeListeners().length); 153 support.removePropertyChangeListener(new PropertyChangeListenerProxy("a", proxiedAAC)); 154 assertEquals(0, support.getPropertyChangeListeners().length); 155 } 156 testAddingOneListenerTwice()157 public void testAddingOneListenerTwice() { 158 Object bean = new Object(); 159 PropertyChangeSupport support = new PropertyChangeSupport(bean); 160 EventLog log = new EventLog(); 161 support.addPropertyChangeListener("a", log); 162 support.addPropertyChangeListener(log); 163 support.addPropertyChangeListener(log); 164 support.addPropertyChangeListener("a", log); 165 166 PropertyChangeEvent eventA = new PropertyChangeEvent(bean, "a", false, true); 167 PropertyChangeEvent eventB = new PropertyChangeEvent(bean, "b", false, true); 168 169 support.firePropertyChange(eventA); 170 support.firePropertyChange(eventB); 171 172 assertEquals(Arrays.asList(eventA, eventA, eventA, eventA, eventB, eventB), log.log); 173 } 174 testAddingAListenerActuallyAddsAProxy()175 public void testAddingAListenerActuallyAddsAProxy() { 176 Object bean = new Object(); 177 PropertyChangeSupport support = new PropertyChangeSupport(bean); 178 PropertyChangeListener listener = new PropertyChangeListener() { 179 public void propertyChange(PropertyChangeEvent event) {} 180 }; 181 support.addPropertyChangeListener("a", listener); 182 183 PropertyChangeListenerProxy p1 184 = (PropertyChangeListenerProxy) support.getPropertyChangeListeners()[0]; 185 assertEquals(PropertyChangeListenerProxy.class, p1.getClass()); 186 assertTrue(p1 != listener); // weird but consistent with the RI 187 assertEquals("a", p1.getPropertyName()); 188 assertEquals(listener, p1.getListener()); 189 } 190 testAddingAProxy()191 public void testAddingAProxy() { 192 Object bean = new Object(); 193 PropertyChangeSupport support = new PropertyChangeSupport(bean); 194 PropertyChangeListener listener = new PropertyChangeListener() { 195 public void propertyChange(PropertyChangeEvent event) {} 196 }; 197 PropertyChangeListenerProxy proxy = new PropertyChangeListenerProxy("a", listener); 198 support.addPropertyChangeListener("b", proxy); 199 200 // this proxy sets us up to receive 'b' events 201 PropertyChangeListenerProxy p1 202 = (PropertyChangeListenerProxy) support.getPropertyChangeListeners()[0]; 203 assertEquals(PropertyChangeListenerProxy.class, p1.getClass()); 204 assertEquals("b", p1.getPropertyName()); 205 206 // there's no more proxy on 'a'. 207 assertEquals(listener, p1.getListener()); 208 } 209 testSerialize()210 public void testSerialize() { 211 String s = "aced0005737200206a6176612e6265616e732e50726f70657274794368616e67" 212 + "65537570706f727458d5d264574860bb03000349002a70726f706572747943686" 213 + "16e6765537570706f727453657269616c697a65644461746156657273696f6e4c" 214 + "00086368696c6472656e7400154c6a6176612f7574696c2f486173687461626c6" 215 + "53b4c0006736f757263657400124c6a6176612f6c616e672f4f626a6563743b78" 216 + "7000000002737200136a6176612e7574696c2e486173687461626c6513bb0f252" 217 + "14ae4b803000246000a6c6f6164466163746f724900097468726573686f6c6478" 218 + "703f4000000000000877080000000b00000001740001617371007e00000000000" 219 + "2707400046265616e7372003a6c6962636f72652e6a6176612e7574696c2e6265" 220 + "616e732e50726f70657274794368616e6765537570706f7274546573742445766" 221 + "56e744c6f67b92667637d0b6f450200024c00036c6f677400104c6a6176612f75" 222 + "74696c2f4c6973743b4c00046e616d657400124c6a6176612f6c616e672f53747" 223 + "2696e673b7870737200136a6176612e7574696c2e41727261794c6973747881d2" 224 + "1d99c7619d03000149000473697a6578700000000077040000000a7874000b6c6" 225 + "97374656e6572546f4171007e000c70787871007e00087371007e00097371007e" 226 + "000d0000000077040000000a7874000d6c697374656e6572546f416c6c7078"; 227 228 Object bean = "bean"; 229 PropertyChangeSupport support = new PropertyChangeSupport(bean); 230 EventLog listenerToAll = new EventLog(); 231 listenerToAll.name = "listenerToAll"; 232 EventLog listenerToA = new EventLog(); 233 listenerToA.name = "listenerToA"; 234 support.addPropertyChangeListener(listenerToAll); 235 support.addPropertyChangeListener("a", listenerToA); 236 support.addPropertyChangeListener("a", listenerToA); 237 238 new SerializationTester<PropertyChangeSupport>(support, s) { 239 @Override protected boolean equals(PropertyChangeSupport a, PropertyChangeSupport b) { 240 return describe(a.getPropertyChangeListeners()) 241 .equals(describe(b.getPropertyChangeListeners())); 242 } 243 @Override protected void verify(PropertyChangeSupport deserialized) { 244 assertEquals("[a to listenerToA, a to listenerToA, listenerToAll]", 245 describe(deserialized.getPropertyChangeListeners())); 246 } 247 }.test(); 248 } 249 testFireIndexedPropertyChange_intUpdate()250 public void testFireIndexedPropertyChange_intUpdate() { 251 Object bean = "bean"; 252 PropertyChangeSupport support = new PropertyChangeSupport(bean); 253 254 EventLog listenerToIntProperty = new EventLog(); 255 support.addPropertyChangeListener("intProperty", listenerToIntProperty); 256 257 support.fireIndexedPropertyChange("intProperty", 10, 1, 2); 258 259 List<PropertyChangeEvent> events = listenerToIntProperty.log; 260 assertEquals(1, events.size()); 261 assertEquals(1, events.get(0).getOldValue()); 262 assertEquals(2, events.get(0).getNewValue()); 263 assertEquals("intProperty", events.get(0).getPropertyName()); 264 assertTrue(events.get(0) instanceof IndexedPropertyChangeEvent); 265 assertEquals(10, ((IndexedPropertyChangeEvent) events.get(0)).getIndex()); 266 } 267 testFireIndexedPropertyChange_intUpdate_noEventWhenOldIsEqualToNew()268 public void testFireIndexedPropertyChange_intUpdate_noEventWhenOldIsEqualToNew() { 269 Object bean = "bean"; 270 PropertyChangeSupport support = new PropertyChangeSupport(bean); 271 272 EventLog listenerToIntProperty = new EventLog(); 273 support.addPropertyChangeListener("intProperty", listenerToIntProperty); 274 275 support.fireIndexedPropertyChange("intProperty", 0, 1, 1); 276 277 List<PropertyChangeEvent> events = listenerToIntProperty.log; 278 assertTrue(events.isEmpty()); 279 } 280 testFireIndexedPropertyChange_booleanUpdate()281 public void testFireIndexedPropertyChange_booleanUpdate() { 282 Object bean = "bean"; 283 PropertyChangeSupport support = new PropertyChangeSupport(bean); 284 285 EventLog listenerToBooleanProperty = new EventLog(); 286 support.addPropertyChangeListener("booleanProperty", listenerToBooleanProperty); 287 288 support.fireIndexedPropertyChange("booleanProperty", 11, true, false); 289 290 List<PropertyChangeEvent> events = listenerToBooleanProperty.log; 291 assertEquals(1, events.size()); 292 assertEquals(true, events.get(0).getOldValue()); 293 assertEquals(false, events.get(0).getNewValue()); 294 assertEquals("booleanProperty", events.get(0).getPropertyName()); 295 assertTrue(events.get(0) instanceof IndexedPropertyChangeEvent); 296 assertEquals(11, ((IndexedPropertyChangeEvent) events.get(0)).getIndex()); 297 } 298 testFireIndexedPropertyChange_booleanUpdate_noEventWhenOldIsEqualToNew()299 public void testFireIndexedPropertyChange_booleanUpdate_noEventWhenOldIsEqualToNew() { 300 Object bean = "bean"; 301 PropertyChangeSupport support = new PropertyChangeSupport(bean); 302 303 EventLog listenerToBooleanProperty = new EventLog(); 304 support.addPropertyChangeListener("booleanProperty", listenerToBooleanProperty); 305 306 support.fireIndexedPropertyChange("booleanProperty", 0, true, true); 307 308 List<PropertyChangeEvent> events = listenerToBooleanProperty.log; 309 assertTrue(events.isEmpty()); 310 } 311 describe(PropertyChangeListener[] listeners)312 private String describe(PropertyChangeListener[] listeners) { 313 List<String> result = new ArrayList<String>(); 314 for (PropertyChangeListener listener : listeners) { 315 result.add(describe(listener)); 316 } 317 Collections.sort(result); 318 return result.toString(); 319 } 320 describe(EventListener listener)321 private String describe(EventListener listener) { 322 if (listener instanceof PropertyChangeListenerProxy) { 323 PropertyChangeListenerProxy proxy = (PropertyChangeListenerProxy) listener; 324 return proxy.getPropertyName() + " to " + describe(proxy.getListener()); 325 } else { 326 return listener.toString(); 327 } 328 } 329 330 static class EventLog implements PropertyChangeListener, Serializable { 331 String name = "EventLog"; 332 List<PropertyChangeEvent> log = new ArrayList<PropertyChangeEvent>(); propertyChange(PropertyChangeEvent event)333 public void propertyChange(PropertyChangeEvent event) { 334 log.add(event); 335 } toString()336 @Override public String toString() { 337 return name; 338 } 339 } 340 } 341