1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.configuration.event;
18  
19  import java.util.Collection;
20  
21  import junit.framework.TestCase;
22  
23  /***
24   * Test class for EventSource.
25   *
26   * @version $Id: TestEventSource.java 495918 2007-01-13 16:33:02Z oheger $
27   */
28  public class TestEventSource extends TestCase
29  {
30      /*** Constant for the event type used for testing. */
31      static final int TEST_TYPE = 42;
32  
33      /*** Constant for the event property name. */
34      static final String TEST_PROPNAME = "test.property.name";
35  
36      /*** Constant for the event property value. */
37      static final Object TEST_PROPVALUE = "a test property value";
38  
39      /*** The object under test. */
40      CountingEventSource source;
41  
42      protected void setUp() throws Exception
43      {
44          super.setUp();
45          source = new CountingEventSource();
46      }
47  
48      /***
49       * Tests a newly created source object.
50       */
51      public void testInit()
52      {
53          assertTrue("Listeners list is not empty", source
54                  .getConfigurationListeners().isEmpty());
55          assertFalse("Removing listener", source
56                  .removeConfigurationListener(new TestListener()));
57          assertFalse("Detail events are enabled", source.isDetailEvents());
58          assertTrue("Error listeners list is not empty", source
59                  .getErrorListeners().isEmpty());
60      }
61  
62      /***
63       * Tests registering a new listener.
64       */
65      public void testAddConfigurationListener()
66      {
67          TestListener l = new TestListener();
68          source.addConfigurationListener(l);
69          Collection listeners = source.getConfigurationListeners();
70          assertEquals("Wrong number of listeners", 1, listeners.size());
71          assertTrue("Listener not in list", listeners.contains(l));
72      }
73  
74      /***
75       * Tests adding an undefined configuration listener. This should cause an
76       * exception.
77       */
78      public void testAddNullConfigurationListener()
79      {
80          try
81          {
82              source.addConfigurationListener(null);
83              fail("Could add null listener!");
84          }
85          catch (IllegalArgumentException iex)
86          {
87              // ok
88          }
89      }
90  
91      /***
92       * Tests removing a listener.
93       */
94      public void testRemoveConfigurationListener()
95      {
96          TestListener l = new TestListener();
97          assertFalse("Listener can be removed?", source
98                  .removeConfigurationListener(l));
99          source.addConfigurationListener(l);
100         source.addConfigurationListener(new TestListener());
101         assertFalse("Unknown listener can be removed", source
102                 .removeConfigurationListener(new TestListener()));
103         assertTrue("Could not remove listener", source
104                 .removeConfigurationListener(l));
105         assertFalse("Listener still in list", source
106                 .getConfigurationListeners().contains(l));
107     }
108 
109     /***
110      * Tests if a null listener can be removed. This should be a no-op.
111      */
112     public void testRemoveNullConfigurationListener()
113     {
114         source.addConfigurationListener(new TestListener());
115         assertFalse("Null listener can be removed", source
116                 .removeConfigurationListener(null));
117         assertEquals("Listener list was modified", 1, source
118                 .getConfigurationListeners().size());
119     }
120 
121     /***
122      * Tests whether the listeners list is read only.
123      */
124     public void testGetConfigurationListenersUpdate()
125     {
126         source.addConfigurationListener(new TestListener());
127         Collection list = source.getConfigurationListeners();
128         try
129         {
130             list.add("test");
131             fail("Could manipulate list!");
132         }
133         catch (Exception ex)
134         {
135             // ok
136         }
137     }
138 
139     /***
140      * Tests that the collection returned by getConfigurationListeners() is
141      * really a snapshot. A later added listener must not be visible.
142      */
143     public void testGetConfigurationListenersAddNew()
144     {
145         Collection list = source.getConfigurationListeners();
146         source.addConfigurationListener(new TestListener());
147         assertTrue("Listener snapshot not empty", list.isEmpty());
148     }
149 
150     /***
151      * Tests enabling and disabling the detail events flag.
152      */
153     public void testSetDetailEvents()
154     {
155         source.setDetailEvents(true);
156         assertTrue("Detail events are disabled", source.isDetailEvents());
157         source.setDetailEvents(true);
158         source.setDetailEvents(false);
159         assertTrue("Detail events are disabled again", source.isDetailEvents());
160         source.setDetailEvents(false);
161         assertFalse("Detail events are still enabled", source.isDetailEvents());
162     }
163 
164     /***
165      * Tests delivering an event to a listener.
166      */
167     public void testFireEvent()
168     {
169         TestListener l = new TestListener();
170         source.addConfigurationListener(l);
171         source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, true);
172         assertEquals("Not 1 event created", 1, source.eventCount);
173         assertEquals("Listener not called once", 1, l.numberOfCalls);
174         assertEquals("Wrong event type", TEST_TYPE, l.lastEvent.getType());
175         assertEquals("Wrong property name", TEST_PROPNAME, l.lastEvent
176                 .getPropertyName());
177         assertEquals("Wrong property value", TEST_PROPVALUE, l.lastEvent
178                 .getPropertyValue());
179         assertTrue("Wrong before event flag", l.lastEvent.isBeforeUpdate());
180     }
181 
182     /***
183      * Tests firering an event if there are no listeners.
184      */
185     public void testFireEventNoListeners()
186     {
187         source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, false);
188         assertEquals("An event object was created", 0, source.eventCount);
189     }
190 
191     /***
192      * Tests generating a detail event if detail events are not allowed.
193      */
194     public void testFireEventNoDetails()
195     {
196         TestListener l = new TestListener();
197         source.addConfigurationListener(l);
198         source.setDetailEvents(false);
199         source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, false);
200         assertEquals("Event object was created", 0, source.eventCount);
201         assertEquals("Listener was called", 0, l.numberOfCalls);
202     }
203 
204     /***
205      * Tests whether an event listener can deregister itself in reaction of a
206      * delivered event.
207      */
208     public void testRemoveListenerInFireEvent()
209     {
210         ConfigurationListener lstRemove = new ConfigurationListener()
211         {
212             public void configurationChanged(ConfigurationEvent event)
213             {
214                 source.removeConfigurationListener(this);
215             }
216         };
217 
218         source.addConfigurationListener(lstRemove);
219         TestListener l = new TestListener();
220         source.addConfigurationListener(l);
221         source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, false);
222         assertEquals("Listener was not called", 1, l.numberOfCalls);
223         assertEquals("Listener was not removed", 1, source
224                 .getConfigurationListeners().size());
225     }
226 
227     /***
228      * Tests registering a new error listener.
229      */
230     public void testAddErrorListener()
231     {
232         TestListener l = new TestListener();
233         source.addErrorListener(l);
234         Collection listeners = source.getErrorListeners();
235         assertEquals("Wrong number of listeners", 1, listeners.size());
236         assertTrue("Listener not in list", listeners.contains(l));
237     }
238 
239     /***
240      * Tests adding an undefined error listener. This should cause an exception.
241      */
242     public void testAddNullErrorListener()
243     {
244         try
245         {
246             source.addErrorListener(null);
247             fail("Could add null error listener!");
248         }
249         catch (IllegalArgumentException iex)
250         {
251             // ok
252         }
253     }
254 
255     /***
256      * Tests removing an error listener.
257      */
258     public void testRemoveErrorListener()
259     {
260         TestListener l = new TestListener();
261         assertFalse("Listener can be removed?", source.removeErrorListener(l));
262         source.addErrorListener(l);
263         source.addErrorListener(new TestListener());
264         assertFalse("Unknown listener can be removed", source
265                 .removeErrorListener(new TestListener()));
266         assertTrue("Could not remove listener", source.removeErrorListener(l));
267         assertFalse("Listener still in list", source.getErrorListeners()
268                 .contains(l));
269     }
270 
271     /***
272      * Tests if a null error listener can be removed. This should be a no-op.
273      */
274     public void testRemoveNullErrorListener()
275     {
276         source.addErrorListener(new TestListener());
277         assertFalse("Null listener can be removed", source
278                 .removeErrorListener(null));
279         assertEquals("Listener list was modified", 1, source
280                 .getErrorListeners().size());
281     }
282 
283     /***
284      * Tests whether the listeners list is read only.
285      */
286     public void testGetErrorListenersUpdate()
287     {
288         source.addErrorListener(new TestListener());
289         Collection list = source.getErrorListeners();
290         try
291         {
292             list.add("test");
293             fail("Could manipulate list!");
294         }
295         catch (Exception ex)
296         {
297             // ok
298         }
299     }
300 
301     /***
302      * Tests delivering an error event to a listener.
303      */
304     public void testFireError()
305     {
306         TestListener l = new TestListener();
307         source.addErrorListener(l);
308         Exception testException = new Exception("A test");
309         source.fireError(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE,
310                 testException);
311         assertEquals("Not 1 event created", 1, source.errorCount);
312         assertEquals("Error listener not called once", 1, l.numberOfErrors);
313         assertEquals("Normal event was generated", 0, l.numberOfCalls);
314         assertEquals("Wrong event type", TEST_TYPE, l.lastEvent.getType());
315         assertEquals("Wrong property name", TEST_PROPNAME, l.lastEvent
316                 .getPropertyName());
317         assertEquals("Wrong property value", TEST_PROPVALUE, l.lastEvent
318                 .getPropertyValue());
319         assertEquals("Wrong Throwable object", testException,
320                 ((ConfigurationErrorEvent) l.lastEvent).getCause());
321     }
322 
323     /***
324      * Tests firering an error event if there are no error listeners.
325      */
326     public void testFireErrorNoListeners()
327     {
328         source.fireError(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE,
329                 new Exception());
330         assertEquals("An error event object was created", 0, source.errorCount);
331     }
332 
333     /***
334      * Tests cloning an event source object. The registered listeners should not
335      * be registered at the clone.
336      */
337     public void testClone() throws CloneNotSupportedException
338     {
339         source.addConfigurationListener(new TestListener());
340         source.addErrorListener(new TestListener());
341         EventSource copy = (EventSource) source.clone();
342         assertTrue("Configuration listeners registered for clone", copy
343                 .getConfigurationListeners().isEmpty());
344         assertTrue("Error listeners registered for clone", copy
345                 .getErrorListeners().isEmpty());
346     }
347 
348     /***
349      * A test event listener implementation.
350      */
351     static class TestListener implements ConfigurationListener,
352             ConfigurationErrorListener
353     {
354         ConfigurationEvent lastEvent;
355 
356         int numberOfCalls;
357 
358         int numberOfErrors;
359 
360         public void configurationChanged(ConfigurationEvent event)
361         {
362             lastEvent = event;
363             numberOfCalls++;
364         }
365 
366         public void configurationError(ConfigurationErrorEvent event)
367         {
368             lastEvent = event;
369             numberOfErrors++;
370         }
371     }
372 
373     /***
374      * A specialized event source implementation that counts the number of
375      * created event objects. It is used to test whether the
376      * <code>fireEvent()</code> methods only creates event objects if
377      * necessary. It also allows testing the clone() operation.
378      */
379     static class CountingEventSource extends EventSource implements Cloneable
380     {
381         int eventCount;
382 
383         int errorCount;
384 
385         protected ConfigurationEvent createEvent(int type, String propName,
386                 Object propValue, boolean before)
387         {
388             eventCount++;
389             return super.createEvent(type, propName, propValue, before);
390         }
391 
392         protected ConfigurationErrorEvent createErrorEvent(int type,
393                 String propName, Object value, Throwable ex)
394         {
395             errorCount++;
396             return super.createErrorEvent(type, propName, value, ex);
397         }
398     }
399 }