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