001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.configuration.event;
018    
019    import static org.junit.Assert.assertEquals;
020    import static org.junit.Assert.assertFalse;
021    import static org.junit.Assert.assertTrue;
022    
023    import java.util.Collection;
024    
025    import org.junit.Before;
026    import org.junit.Test;
027    
028    /**
029     * Test class for EventSource.
030     *
031     * @version $Id: TestEventSource.java 1225652 2011-12-29 21:00:57Z oheger $
032     */
033    public class TestEventSource
034    {
035        /** Constant for the event type used for testing. */
036        static final int TEST_TYPE = 42;
037    
038        /** Constant for the event property name. */
039        static final String TEST_PROPNAME = "test.property.name";
040    
041        /** Constant for the event property value. */
042        static final Object TEST_PROPVALUE = "a test property value";
043    
044        /** The object under test. */
045        CountingEventSource source;
046    
047        @Before
048        public void setUp() throws Exception
049        {
050            source = new CountingEventSource();
051        }
052    
053        /**
054         * Tests a newly created source object.
055         */
056        @Test
057        public void testInit()
058        {
059            assertTrue("Listeners list is not empty", source
060                    .getConfigurationListeners().isEmpty());
061            assertFalse("Removing listener", source
062                    .removeConfigurationListener(new TestListener()));
063            assertFalse("Detail events are enabled", source.isDetailEvents());
064            assertTrue("Error listeners list is not empty", source
065                    .getErrorListeners().isEmpty());
066        }
067    
068        /**
069         * Tests registering a new listener.
070         */
071        @Test
072        public void testAddConfigurationListener()
073        {
074            TestListener l = new TestListener();
075            source.addConfigurationListener(l);
076            Collection<ConfigurationListener> listeners = source.getConfigurationListeners();
077            assertEquals("Wrong number of listeners", 1, listeners.size());
078            assertTrue("Listener not in list", listeners.contains(l));
079        }
080    
081        /**
082         * Tests adding an undefined configuration listener. This should cause an
083         * exception.
084         */
085        @Test(expected = IllegalArgumentException.class)
086        public void testAddNullConfigurationListener()
087        {
088            source.addConfigurationListener(null);
089        }
090    
091        /**
092         * Tests removing a listener.
093         */
094        @Test
095        public void testRemoveConfigurationListener()
096        {
097            TestListener l = new TestListener();
098            assertFalse("Listener can be removed?", source
099                    .removeConfigurationListener(l));
100            source.addConfigurationListener(l);
101            source.addConfigurationListener(new TestListener());
102            assertFalse("Unknown listener can be removed", source
103                    .removeConfigurationListener(new TestListener()));
104            assertTrue("Could not remove listener", source
105                    .removeConfigurationListener(l));
106            assertFalse("Listener still in list", source
107                    .getConfigurationListeners().contains(l));
108        }
109    
110        /**
111         * Tests if a null listener can be removed. This should be a no-op.
112         */
113        @Test
114        public void testRemoveNullConfigurationListener()
115        {
116            source.addConfigurationListener(new TestListener());
117            assertFalse("Null listener can be removed", source
118                    .removeConfigurationListener(null));
119            assertEquals("Listener list was modified", 1, source
120                    .getConfigurationListeners().size());
121        }
122    
123        /**
124         * Tests whether the listeners list is read only.
125         */
126        @Test(expected = UnsupportedOperationException.class)
127        public void testGetConfigurationListenersUpdate()
128        {
129            source.addConfigurationListener(new TestListener());
130            Collection<ConfigurationListener> list = source.getConfigurationListeners();
131            list.clear();
132        }
133    
134        /**
135         * Tests that the collection returned by getConfigurationListeners() is
136         * really a snapshot. A later added listener must not be visible.
137         */
138        @Test
139        public void testGetConfigurationListenersAddNew()
140        {
141            Collection<ConfigurationListener> list = source.getConfigurationListeners();
142            source.addConfigurationListener(new TestListener());
143            assertTrue("Listener snapshot not empty", list.isEmpty());
144        }
145    
146        /**
147         * Tests enabling and disabling the detail events flag.
148         */
149        @Test
150        public void testSetDetailEvents()
151        {
152            source.setDetailEvents(true);
153            assertTrue("Detail events are disabled", source.isDetailEvents());
154            source.setDetailEvents(true);
155            source.setDetailEvents(false);
156            assertTrue("Detail events are disabled again", source.isDetailEvents());
157            source.setDetailEvents(false);
158            assertFalse("Detail events are still enabled", source.isDetailEvents());
159        }
160    
161        /**
162         * Tests delivering an event to a listener.
163         */
164        @Test
165        public void testFireEvent()
166        {
167            TestListener l = new TestListener();
168            source.addConfigurationListener(l);
169            source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, true);
170            assertEquals("Not 1 event created", 1, source.eventCount);
171            assertEquals("Listener not called once", 1, l.numberOfCalls);
172            assertEquals("Wrong event type", TEST_TYPE, l.lastEvent.getType());
173            assertEquals("Wrong property name", TEST_PROPNAME, l.lastEvent
174                    .getPropertyName());
175            assertEquals("Wrong property value", TEST_PROPVALUE, l.lastEvent
176                    .getPropertyValue());
177            assertTrue("Wrong before event flag", l.lastEvent.isBeforeUpdate());
178        }
179    
180        /**
181         * Tests firing an event if there are no listeners.
182         */
183        @Test
184        public void testFireEventNoListeners()
185        {
186            source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, false);
187            assertEquals("An event object was created", 0, source.eventCount);
188        }
189    
190        /**
191         * Tests generating a detail event if detail events are not allowed.
192         */
193        @Test
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        @Test
209        public void testRemoveListenerInFireEvent()
210        {
211            ConfigurationListener lstRemove = new ConfigurationListener()
212            {
213                public void configurationChanged(ConfigurationEvent event)
214                {
215                    source.removeConfigurationListener(this);
216                }
217            };
218    
219            source.addConfigurationListener(lstRemove);
220            TestListener l = new TestListener();
221            source.addConfigurationListener(l);
222            source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, false);
223            assertEquals("Listener was not called", 1, l.numberOfCalls);
224            assertEquals("Listener was not removed", 1, source
225                    .getConfigurationListeners().size());
226        }
227    
228        /**
229         * Tests registering a new error listener.
230         */
231        @Test
232        public void testAddErrorListener()
233        {
234            TestListener l = new TestListener();
235            source.addErrorListener(l);
236            Collection<ConfigurationErrorListener> listeners = source.getErrorListeners();
237            assertEquals("Wrong number of listeners", 1, listeners.size());
238            assertTrue("Listener not in list", listeners.contains(l));
239        }
240    
241        /**
242         * Tests adding an undefined error listener. This should cause an exception.
243         */
244        @Test(expected = IllegalArgumentException.class)
245        public void testAddNullErrorListener()
246        {
247            source.addErrorListener(null);
248        }
249    
250        /**
251         * Tests removing an error listener.
252         */
253        @Test
254        public void testRemoveErrorListener()
255        {
256            TestListener l = new TestListener();
257            assertFalse("Listener can be removed?", source.removeErrorListener(l));
258            source.addErrorListener(l);
259            source.addErrorListener(new TestListener());
260            assertFalse("Unknown listener can be removed", source
261                    .removeErrorListener(new TestListener()));
262            assertTrue("Could not remove listener", source.removeErrorListener(l));
263            assertFalse("Listener still in list", source.getErrorListeners()
264                    .contains(l));
265        }
266    
267        /**
268         * Tests if a null error listener can be removed. This should be a no-op.
269         */
270        @Test
271        public void testRemoveNullErrorListener()
272        {
273            source.addErrorListener(new TestListener());
274            assertFalse("Null listener can be removed", source
275                    .removeErrorListener(null));
276            assertEquals("Listener list was modified", 1, source
277                    .getErrorListeners().size());
278        }
279    
280        /**
281         * Tests whether the listeners list is read only.
282         */
283        @Test(expected = UnsupportedOperationException.class)
284        public void testGetErrorListenersUpdate()
285        {
286            source.addErrorListener(new TestListener());
287            Collection<ConfigurationErrorListener> list = source.getErrorListeners();
288            list.clear();
289        }
290    
291        /**
292         * Tests delivering an error event to a listener.
293         */
294        @Test
295        public void testFireError()
296        {
297            TestListener l = new TestListener();
298            source.addErrorListener(l);
299            Exception testException = new Exception("A test");
300            source.fireError(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE,
301                    testException);
302            assertEquals("Not 1 event created", 1, source.errorCount);
303            assertEquals("Error listener not called once", 1, l.numberOfErrors);
304            assertEquals("Normal event was generated", 0, l.numberOfCalls);
305            assertEquals("Wrong event type", TEST_TYPE, l.lastEvent.getType());
306            assertEquals("Wrong property name", TEST_PROPNAME, l.lastEvent
307                    .getPropertyName());
308            assertEquals("Wrong property value", TEST_PROPVALUE, l.lastEvent
309                    .getPropertyValue());
310            assertEquals("Wrong Throwable object", testException,
311                    ((ConfigurationErrorEvent) l.lastEvent).getCause());
312        }
313    
314        /**
315         * Tests firing an error event if there are no error listeners.
316         */
317        @Test
318        public void testFireErrorNoListeners()
319        {
320            source.fireError(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE,
321                    new Exception());
322            assertEquals("An error event object was created", 0, source.errorCount);
323        }
324    
325        /**
326         * Tests cloning an event source object. The registered listeners should not
327         * be registered at the clone.
328         */
329        @Test
330        public void testClone() throws CloneNotSupportedException
331        {
332            source.addConfigurationListener(new TestListener());
333            source.addErrorListener(new TestListener());
334            EventSource copy = (EventSource) source.clone();
335            assertTrue("Configuration listeners registered for clone", copy
336                    .getConfigurationListeners().isEmpty());
337            assertTrue("Error listeners registered for clone", copy
338                    .getErrorListeners().isEmpty());
339        }
340    
341        /**
342         * A test event listener implementation.
343         */
344        static class TestListener implements ConfigurationListener,
345                ConfigurationErrorListener
346        {
347            ConfigurationEvent lastEvent;
348    
349            int numberOfCalls;
350    
351            int numberOfErrors;
352    
353            public void configurationChanged(ConfigurationEvent event)
354            {
355                lastEvent = event;
356                numberOfCalls++;
357            }
358    
359            public void configurationError(ConfigurationErrorEvent event)
360            {
361                lastEvent = event;
362                numberOfErrors++;
363            }
364        }
365    
366        /**
367         * A specialized event source implementation that counts the number of
368         * created event objects. It is used to test whether the
369         * {@code fireEvent()} methods only creates event objects if
370         * necessary. It also allows testing the clone() operation.
371         */
372        static class CountingEventSource extends EventSource implements Cloneable
373        {
374            int eventCount;
375    
376            int errorCount;
377    
378            @Override
379            protected ConfigurationEvent createEvent(int type, String propName,
380                    Object propValue, boolean before)
381            {
382                eventCount++;
383                return super.createEvent(type, propName, propValue, before);
384            }
385    
386            @Override
387            protected ConfigurationErrorEvent createErrorEvent(int type,
388                    String propName, Object value, Throwable ex)
389            {
390                errorCount++;
391                return super.createErrorEvent(type, propName, value, ex);
392            }
393        }
394    }