001    // Copyright 2006 Howard M. Lewis Ship
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // You may obtain a copy of the License at
006    //
007    //     http://www.apache.org/licenses/LICENSE-2.0
008    //
009    // Unless required by applicable law or agreed to in writing, software
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    
015    /**
016     * 
017     */
018    package com.javaforge.tapestry.testng;
019    
020    import org.easymock.IArgumentMatcher;
021    
022    import static org.easymock.EasyMock.reportMatcher;
023    
024    /**
025     * An EasyMock 2.0 argument matcher that captures a method argument value. This allows an object
026     * created inside a test method to be interrogated after the method completes, even when the object
027     * is not a return value, but is merely passed as a parameter to a mock object.
028     * 
029     * @author Howard M. Lewis Ship
030     * @param <T>
031     *            the type of object to capture
032     */
033    public final class Capturer<T> implements IArgumentMatcher
034    {
035        private final Class<T> _matchType;
036    
037        private T _captured;
038    
039        /**
040         * Creates a new Capturer for the given type. Because of Generics syntax, it is easier to use
041         * the static method.
042         */
043        public Capturer(Class<T> matchType)
044        {
045            _matchType = matchType;
046        }
047    
048        /**
049         * Factory method that invokes the normal constructor in a way that keeps Java Generics happy.
050         */
051        public static <T> Capturer<T> newCapturer(Class<T> matchType)
052        {
053            return new Capturer<T>(matchType);
054        }
055    
056        public void appendTo(StringBuffer buffer)
057        {
058            buffer.append(String.format("capture(%s)", _matchType.getName()));
059        }
060    
061        public boolean matches(Object parameter)
062        {
063            boolean result = _matchType.isInstance(parameter);
064    
065            if (result)
066                _captured = _matchType.cast(parameter);
067    
068            return result;
069        }
070    
071        /** Returns the method argument value previously captured. */
072        public T getCaptured()
073        {
074            return _captured;
075        }
076    
077        /**
078         * Useage (with static imports):
079         * <p>
080         * Capturer&lt;Type&gt; c = newCapturer(Type.class);
081         * <p>
082         * mock.someMethod(capture(c));
083         * <p> . . .
084         * <p>
085         * c.getCaptured().getXXX()
086         * <p>
087         * The interrogation of the captured argument should occur after the test subject has invoked
088         * the method on the mock; the best time for this is typically after invoking
089         * {@link TestBase#verify()}.
090         * <p>
091         * Remember that when you use an argument matcher for one argument of a method invocation, you
092         * must use argument matchers for <em>all</em> arguments of the method invocation.
093         */
094        public static <T> T capture(Capturer<T> capturer)
095        {
096            reportMatcher(capturer);
097    
098            return null;
099        }
100    
101    }