blob: e719927c40b6bbec80d59a7e2c03c62bbccc8b74 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.configuration2.event;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.util.Collection;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
/**
* Test class for BaseEventSource.
*
*/
public class TestEventSource
{
/** Constant for the event property name. */
private final String TEST_PROPNAME = "test.property.name";
/** Constant for the event property value. */
private static final Object TEST_PROPVALUE = "a test property value";
/** The object under test. */
private CountingEventSource source;
@Before
public void setUp() throws Exception
{
source = new CountingEventSource();
}
/**
* Tests a newly created source object.
*/
@Test
public void testInit()
{
assertTrue("Listeners list is not empty", source
.getEventListenerRegistrations().isEmpty());
assertFalse("Removing listener", source.removeEventListener(
ConfigurationEvent.ANY, new EventListenerTestImpl(null)));
assertFalse("Detail events are enabled", source.isDetailEvents());
}
/**
* Tests registering a new listener.
*/
@Test
public void testAddEventListener()
{
final EventListenerTestImpl l = new EventListenerTestImpl(this);
source.addEventListener(ConfigurationEvent.ANY, l);
final Collection<EventListener<? super ConfigurationEvent>> listeners =
source.getEventListeners(ConfigurationEvent.ANY);
assertEquals("Wrong number of listeners", 1, listeners.size());
assertTrue("Listener not in list", listeners.contains(l));
}
/**
* Tests adding an undefined configuration listener. This should cause an
* exception.
*/
@Test(expected = IllegalArgumentException.class)
public void testAddNullEventListener()
{
source.addEventListener(ConfigurationEvent.ANY, null);
}
/**
* Tests removing a listener.
*/
@Test
public void testRemoveEventListener()
{
final EventListenerTestImpl l = new EventListenerTestImpl(this);
assertFalse("Listener can be removed?", source
.removeEventListener(ConfigurationEvent.ANY, l));
source.addEventListener(ConfigurationEvent.ADD_NODES, new EventListenerTestImpl(this));
source.addEventListener(ConfigurationEvent.ANY, l);
assertFalse("Unknown listener can be removed", source
.removeEventListener(ConfigurationEvent.ANY, new EventListenerTestImpl(null)));
assertTrue("Could not remove listener", source
.removeEventListener(ConfigurationEvent.ANY, l));
assertFalse("Listener still in list", source
.getEventListeners(ConfigurationEvent.ANY).contains(l));
}
/**
* Tests if a null listener can be removed. This should be a no-op.
*/
@Test
public void testRemoveNullEventListener()
{
source.addEventListener(ConfigurationEvent.ANY, new EventListenerTestImpl(null));
assertFalse("Null listener can be removed", source
.removeEventListener(ConfigurationEvent.ANY, null));
assertEquals("Listener list was modified", 1, source
.getEventListeners(ConfigurationEvent.ANY).size());
}
/**
* Tests whether the listeners list is read only.
*/
@Test(expected = UnsupportedOperationException.class)
public void testGetEventListenersUpdate()
{
source.addEventListener(ConfigurationEvent.ANY,
new EventListenerTestImpl(null));
final Collection<EventListener<? super ConfigurationEvent>> list =
source.getEventListeners(ConfigurationEvent.ANY);
list.clear();
}
/**
* Tests that the collection returned by getEventListeners() is
* really a snapshot. A later added listener must not be visible.
*/
@Test
public void testGetEventListenersAddNew()
{
final Collection<EventListener<? super ConfigurationEvent>> list =
source.getEventListeners(ConfigurationEvent.ANY);
source.addEventListener(ConfigurationEvent.ANY,
new EventListenerTestImpl(null));
assertTrue("Listener snapshot not empty", list.isEmpty());
}
/**
* Tests enabling and disabling the detail events flag.
*/
@Test
public void testSetDetailEvents()
{
source.setDetailEvents(true);
assertTrue("Detail events are disabled", source.isDetailEvents());
source.setDetailEvents(true);
source.setDetailEvents(false);
assertTrue("Detail events are disabled again", source.isDetailEvents());
source.setDetailEvents(false);
assertFalse("Detail events are still enabled", source.isDetailEvents());
}
/**
* Tests delivering an event to a listener.
*/
@Test
public void testFireEvent()
{
final EventListenerTestImpl l = new EventListenerTestImpl(source);
source.addEventListener(ConfigurationEvent.ANY, l);
source.fireEvent(ConfigurationEvent.ADD_PROPERTY, TEST_PROPNAME,
TEST_PROPVALUE, true);
l.checkEvent(ConfigurationEvent.ADD_PROPERTY, TEST_PROPNAME,
TEST_PROPVALUE, true);
l.done();
}
/**
* Tests firing an event if there are no listeners.
*/
@Test
public void testFireEventNoListeners()
{
source.fireEvent(ConfigurationEvent.ADD_NODES, TEST_PROPNAME,
TEST_PROPVALUE, false);
assertEquals("An event object was created", 0, source.eventCount);
}
/**
* Tests generating a detail event if detail events are not allowed.
*/
@Test
public void testFireEventNoDetails()
{
final EventListenerTestImpl l = new EventListenerTestImpl(source);
source.addEventListener(ConfigurationEvent.ANY, l);
source.setDetailEvents(false);
source.fireEvent(ConfigurationEvent.SET_PROPERTY, TEST_PROPNAME, TEST_PROPVALUE, false);
assertEquals("Event object was created", 0, source.eventCount);
l.done();
}
/**
* Tests whether an event listener can deregister itself in reaction of a
* delivered event.
*/
@Test
public void testRemoveListenerInFireEvent()
{
final EventListener<ConfigurationEvent> lstRemove = new EventListener<ConfigurationEvent>()
{
@Override
public void onEvent(final ConfigurationEvent event)
{
source.removeEventListener(ConfigurationEvent.ANY, this);
}
};
source.addEventListener(ConfigurationEvent.ANY, lstRemove);
final EventListenerTestImpl l = new EventListenerTestImpl(source);
source.addEventListener(ConfigurationEvent.ANY, l);
source.fireEvent(ConfigurationEvent.ADD_PROPERTY, TEST_PROPNAME,
TEST_PROPVALUE, false);
l.checkEvent(ConfigurationEvent.ADD_PROPERTY, TEST_PROPNAME,
TEST_PROPVALUE, false);
assertEquals("Listener was not removed", 1,
source.getEventListeners(ConfigurationEvent.ANY).size());
}
/**
* Tests delivering an error event to a listener.
*/
@Test
public void testFireError()
{
final ErrorListenerTestImpl lstRead = new ErrorListenerTestImpl(source);
final ErrorListenerTestImpl lstWrite = new ErrorListenerTestImpl(source);
final ErrorListenerTestImpl lstAll = new ErrorListenerTestImpl(source);
source.addEventListener(ConfigurationErrorEvent.READ, lstRead);
source.addEventListener(ConfigurationErrorEvent.WRITE, lstWrite);
source.addEventListener(ConfigurationErrorEvent.ANY, lstAll);
final Exception testException = new Exception("A test");
source.fireError(ConfigurationErrorEvent.WRITE,
ConfigurationEvent.ADD_PROPERTY, TEST_PROPNAME, TEST_PROPVALUE,
testException);
lstRead.done();
assertEquals("Wrong exception (1)", testException, lstWrite.checkEvent(
ConfigurationErrorEvent.WRITE, ConfigurationEvent.ADD_PROPERTY,
TEST_PROPNAME, TEST_PROPVALUE));
lstWrite.done();
assertEquals("Wrong exception (2)", testException, lstAll.checkEvent(
ConfigurationErrorEvent.WRITE, ConfigurationEvent.ADD_PROPERTY,
TEST_PROPNAME, TEST_PROPVALUE));
lstAll.done();
assertEquals("Wrong number of error events created", 1,
source.errorCount);
}
/**
* Tests firing an error event if there are no error listeners.
*/
@Test
public void testFireErrorNoListeners()
{
source.fireError(ConfigurationErrorEvent.ANY, ConfigurationEvent.ANY,
TEST_PROPNAME, TEST_PROPVALUE, new Exception());
assertEquals("An error event object was created", 0, source.errorCount);
}
/**
* Tests cloning an event source object. The registered listeners should not
* be registered at the clone.
*/
@Test
public void testClone() throws CloneNotSupportedException
{
source.addEventListener(ConfigurationEvent.ANY, new EventListenerTestImpl(source));
final BaseEventSource copy = (BaseEventSource) source.clone();
assertTrue("Configuration listeners registered for clone", copy
.getEventListenerRegistrations().isEmpty());
}
/**
* Tests whether all event listeners can be removed.
*/
@Test
public void testClearEventListeners()
{
source.addEventListener(ConfigurationEvent.ANY,
new EventListenerTestImpl(source));
source.addEventListener(ConfigurationEvent.ANY_HIERARCHICAL,
new EventListenerTestImpl(source));
source.clearEventListeners();
assertTrue("Got ANY listeners",
source.getEventListeners(ConfigurationEvent.ANY).isEmpty());
assertTrue("Got HIERARCHICAL listeners",
source.getEventListeners(ConfigurationEvent.ANY_HIERARCHICAL)
.isEmpty());
}
/**
* Tests whether event listeners can be copied to another source.
*/
@Test
public void testCopyEventListeners()
{
final EventListenerTestImpl l1 = new EventListenerTestImpl(source);
final EventListenerTestImpl l2 = new EventListenerTestImpl(source);
source.addEventListener(ConfigurationEvent.ANY, l1);
source.addEventListener(ConfigurationEvent.ANY_HIERARCHICAL, l2);
final BaseEventSource source2 = new BaseEventSource();
source.copyEventListeners(source2);
Collection<EventListener<? super ConfigurationEvent>> listeners =
source2.getEventListeners(ConfigurationEvent.ANY_HIERARCHICAL);
assertEquals("Wrong number of listeners (1)", 2, listeners.size());
assertTrue("l1 not found", listeners.contains(l1));
assertTrue("l2 not found", listeners.contains(l2));
listeners = source2.getEventListeners(ConfigurationEvent.ANY);
assertEquals("Wrong number of listeners (2)", 1, listeners.size());
assertTrue("Wrong listener", listeners.contains(l1));
}
/**
* Tries to copy event listeners to a null source.
*/
@Test(expected = IllegalArgumentException.class)
public void testCopyEventListenersNullSource()
{
source.copyEventListeners(null);
}
/**
* Tests whether all error listeners can be cleared.
*/
@Test
public void testClearErrorListeners()
{
final EventListener<ConfigurationEvent> cl = new EventListenerTestImpl(null);
final ErrorListenerTestImpl el1 = new ErrorListenerTestImpl(null);
final ErrorListenerTestImpl el2 = new ErrorListenerTestImpl(null);
final ErrorListenerTestImpl el3 = new ErrorListenerTestImpl(null);
source.addEventListener(ConfigurationErrorEvent.READ, el1);
source.addEventListener(ConfigurationErrorEvent.ANY, el2);
source.addEventListener(ConfigurationEvent.ANY, cl);
source.addEventListener(ConfigurationErrorEvent.WRITE, el3);
source.clearErrorListeners();
final List<EventListenerRegistrationData<?>> regs =
source.getEventListenerRegistrations();
assertEquals("Wrong number of event listener registrations", 1,
regs.size());
assertSame("Wrong remaining listener", cl, regs.get(0).getListener());
}
/**
* A specialized event source implementation that counts the number of
* created event objects. It is used to test whether the
* {@code fireEvent()} methods only creates event objects if
* necessary. It also allows testing the clone() operation.
*/
private static class CountingEventSource extends BaseEventSource implements Cloneable
{
int eventCount;
int errorCount;
@Override
protected <T extends ConfigurationEvent> ConfigurationEvent createEvent(
final EventType<T> eventType, final String propName, final Object propValue,
final boolean before)
{
eventCount++;
return super.createEvent(eventType, propName, propValue, before);
}
@Override
protected ConfigurationErrorEvent createErrorEvent(
final EventType<? extends ConfigurationErrorEvent> type,
final EventType<?> opType, final String propName, final Object propValue,
final Throwable ex)
{
errorCount++;
return super
.createErrorEvent(type, opType, propName, propValue, ex);
}
}
}