Clover coverage report - gsbase - 2.0.1
Coverage timestamp: Sat Jan 1 2005 12:30:02 EST
file stats: LOC: 280   Methods: 12
NCLOC: 114   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
EventCatcher.java 45% 62% 50% 56.1%
coverage coverage
 1    /*
 2    * Copyright (c) 1998, 2005 Gargoyle Software Inc. All rights reserved.
 3    *
 4    * Redistribution and use in source and binary forms, with or without
 5    * modification, are permitted provided that the following conditions are met:
 6    *
 7    * 1. Redistributions of source code must retain the above copyright notice,
 8    * this list of conditions and the following disclaimer.
 9    * 2. Redistributions in binary form must reproduce the above copyright notice,
 10    * this list of conditions and the following disclaimer in the documentation
 11    * and/or other materials provided with the distribution.
 12    * 3. The end-user documentation included with the redistribution, if any, must
 13    * include the following acknowledgment:
 14    *
 15    * "This product includes software developed by Gargoyle Software Inc.
 16    * (http://www.GargoyleSoftware.com/)."
 17    *
 18    * Alternately, this acknowledgment may appear in the software itself, if
 19    * and wherever such third-party acknowledgments normally appear.
 20    * 4. The name "Gargoyle Software" must not be used to endorse or promote
 21    * products derived from this software without prior written permission.
 22    * For written permission, please contact info@GargoyleSoftware.com.
 23    * 5. Products derived from this software may not be called "GSBase", nor may
 24    * "GSBase" appear in their name, without prior written permission of
 25    * Gargoyle Software Inc.
 26    *
 27    * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
 28    * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 29    * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GARGOYLE
 30    * SOFTWARE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 31    * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 32    * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 33    * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 34    * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 35    * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 36    * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 37    */
 38    package com.gargoylesoftware.base.testing;
 39   
 40    import java.lang.reflect.InvocationHandler;
 41    import java.lang.reflect.InvocationTargetException;
 42    import java.lang.reflect.Method;
 43    import java.lang.reflect.Proxy;
 44    import java.util.ArrayList;
 45    import java.util.Collections;
 46    import java.util.EventObject;
 47    import java.util.HashMap;
 48    import java.util.Iterator;
 49    import java.util.List;
 50    import java.util.Map;
 51    import junit.framework.AssertionFailedError;
 52   
 53    /**
 54    * A testing class for catching and logging events.
 55    * <pre>
 56    * // Catch all events fired by JFrame
 57    * final JFrame frame = new JFrame();
 58    * final EventCatcher eventCatcher = new EventCatcher();
 59    * eventCatcher.listenTo(frame);
 60    *
 61    * frame.show();
 62    *
 63    * for( int i=0; i&lt;eventCatcher.size(); i++ ) {
 64    * System.out.println(eventCatcher.getEventAt(i));
 65    * }
 66    * </pre>
 67    * @version $Revision: 1.4 $
 68    * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
 69    */
 70    public class EventCatcher {
 71   
 72    /**
 73    * An inner class to handle the various events.
 74    */
 75    private InvocationHandler invocationHandler_ = new InvocationHandler() {
 76  8 public Object invoke( final Object proxy,
 77    final Method method,
 78    final Object[] args) {
 79  8 final String methodName = method.getName();
 80  8 final Object result;
 81  8 if( methodName.equals("hashCode") ) {
 82  0 result = new Integer(1);
 83    }
 84  8 else if( methodName.equals("equals") && args.length == 1 ) {
 85  0 result = new Boolean(this == args[0]);
 86    }
 87    else {
 88  8 synchronized(EventCatcher.this) {
 89  8 eventRecords_.add( new EventCatcherRecord(method, (EventObject)args[0]) );
 90    }
 91  8 result = null;
 92    }
 93  8 return result;
 94    }
 95    };
 96   
 97    private final List eventRecords_ = new ArrayList();
 98   
 99    /**
 100    * Create a new EventCatcher.
 101    */
 102  4 public EventCatcher() {
 103    }
 104   
 105   
 106    /**
 107    * Return information about the event at the specified index.
 108    *
 109    * @param index The index.
 110    * @return The record.
 111    * @deprecated Use {@link #getEventCatcherRecordAt(int)} instead
 112    */
 113  0 public synchronized EventCatcherRecord get( final int index ) {
 114  0 return (EventCatcherRecord)eventRecords_.get(index);
 115    }
 116   
 117   
 118    /**
 119    * Return the number of events that have been caught.
 120    * @return the number of events that have been caught.
 121    * @deprecated Use {@link #getEventCount()} instead
 122    */
 123  0 public synchronized int size() {
 124  0 return eventRecords_.size();
 125    }
 126   
 127   
 128    /**
 129    * Return a listener object that will log all fired events. This listener
 130    * should be used when you want to only listen for one kind of events on a bean.
 131    * If you want to listen to all events then you should just call {@link #listenTo(Object)}
 132    * <pre>
 133    * // Catch all window events
 134    * final ObjectCatcher objectCatcher = new ObjectCatcher();
 135    * final JFrame frame = new JFrame();
 136    *
 137    * frame.addWindowListener( (WindowListener)objectCatcher.getListener(WindowListener.class) );
 138    * </pre>
 139    *
 140    * @param clazz The listener interface that we need to support.
 141    * @return A listener.
 142    */
 143  4 public Object getListener( final Class clazz ) {
 144  4 return Proxy.newProxyInstance( getClass().getClassLoader(),
 145    new Class[]{ clazz },
 146    invocationHandler_ );
 147    }
 148   
 149   
 150    /**
 151    * Register the event catcher as a listener for all events that this object fires.
 152    * <pre>
 153    * // Catch all events fired by JFrame
 154    * final ObjectCatcher objectCatcher = new ObjectCatcher();
 155    * final JFrame frame = new JFrame();
 156    *
 157    * eventCatcher.listenTo(frame);
 158    * </pre>
 159    *
 160    * @param object The object that we will be listening to.
 161    * @throws IllegalAccessException If we do not have authorization to call
 162    * the respective addXXXListener() method
 163    * @throws InvocationTargetException If an exception is thrown during the
 164    * call to the addXXXListener() method
 165    */
 166  4 public void listenTo( final Object object )
 167    throws
 168    IllegalAccessException,
 169    InvocationTargetException {
 170   
 171  4 final Method methods[] = object.getClass().getMethods();
 172   
 173  4 String methodName;
 174  4 Class parameterClasses[];
 175  4 final Map addMethods = new HashMap(89);
 176   
 177  4 int i;
 178  4 for( i=0; i<methods.length; i++ ) {
 179  136 methodName = methods[i].getName();
 180  136 if( methodName.startsWith("add") && methodName.endsWith("Listener") ) {
 181  4 parameterClasses = methods[i].getParameterTypes();
 182  4 if( parameterClasses.length == 1 ) {
 183  4 addMethods.put( methods[i], parameterClasses[0] );
 184    }
 185    }
 186    }
 187   
 188  4 Map.Entry entry;
 189  4 Object proxy;
 190  4 Method method;
 191   
 192  4 final Iterator iterator = addMethods.entrySet().iterator();
 193  4 while( iterator.hasNext() ) {
 194  4 entry = (Map.Entry)iterator.next();
 195  4 method = (Method)entry.getKey();
 196  4 proxy = getListener( (Class)entry.getValue() );
 197  4 method.invoke( object, new Object[]{proxy} );
 198    }
 199    }
 200   
 201   
 202    /**
 203    * Return the event at the specified index.
 204    * @param index The index
 205    * @return The event at that index.
 206    */
 207  0 public synchronized EventObject getEventAt( final int index ) {
 208  0 return getEventCatcherRecordAt(index).getEvent();
 209    }
 210   
 211   
 212    /**
 213    * Return the record at the specified index. The record will contain the event and
 214    * assorted information about the event.
 215    * @param index The index
 216    * @return The record at that index.
 217    */
 218  9 public synchronized EventCatcherRecord getEventCatcherRecordAt( final int index ) {
 219  9 return (EventCatcherRecord)eventRecords_.get(index);
 220    }
 221   
 222   
 223    /**
 224    * Return the number of events that have been collected so far.
 225    *
 226    * @return The number of events.
 227    */
 228  8 public synchronized int getEventCount() {
 229  8 return eventRecords_.size();
 230    }
 231   
 232   
 233    /**
 234    * Return an immutable list containing all the events collected so far.
 235    *
 236    * @return A list of collected events.
 237    */
 238  0 public synchronized List getEvents() {
 239  0 final List list = new ArrayList(eventRecords_.size());
 240  0 final Iterator iterator = eventRecords_.iterator();
 241  0 while( iterator.hasNext() ) {
 242  0 final EventCatcherRecord record = (EventCatcherRecord)iterator.next();
 243  0 list.add( record.getEvent() );
 244    }
 245   
 246  0 return Collections.unmodifiableList(list);
 247    }
 248   
 249   
 250    /**
 251    * Throw away all the currently collected events.
 252    */
 253  0 public synchronized void clear() {
 254  0 eventRecords_.clear();
 255    }
 256   
 257   
 258    /**
 259    * Compare the specified events against the actual collected event to see if they
 260    * appear to be the same. Refer to {@link TestUtil#appearsEqual(Object,Object)}
 261    * for an explanation of "appearing" to be the same.
 262    *
 263    * @param expectedEvents The events that we expect to have been collected.
 264    */
 265  0 public synchronized void assertEventsAppearEquals( final List expectedEvents ) {
 266  0 final List actualEvents = getEvents();
 267  0 final int eventCount = actualEvents.size();
 268  0 if( expectedEvents.size() != eventCount ) {
 269  0 throw new AssertionFailedError("Different number of events: expected="
 270    +expectedEvents+" actual="+actualEvents);
 271    }
 272   
 273  0 for( int i=0; i<eventCount; i++ ) {
 274  0 if( TestUtil.appearsEqual( expectedEvents.get(i), actualEvents.get(i) ) == false ) {
 275  0 throw new AssertionFailedError("Different events: expected="
 276    +expectedEvents+" actual="+actualEvents);
 277    }
 278    }
 279    }
 280    }