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