Package org.apache.hivemind.test

Source Code of org.apache.hivemind.test.HiveMindTestCase$InterfaceMockControlFactory

// Copyright 2004, 2005 The Apache Software Foundation
//
// Licensed 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.hivemind.test;

import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;

import junit.framework.AssertionFailedError;
import junit.framework.TestCase;

import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.hivemind.ClassResolver;
import org.apache.hivemind.Location;
import org.apache.hivemind.ModuleDescriptorProvider;
import org.apache.hivemind.Registry;
import org.apache.hivemind.Resource;
import org.apache.hivemind.impl.DefaultClassResolver;
import org.apache.hivemind.impl.LocationImpl;
import org.apache.hivemind.impl.RegistryBuilder;
import org.apache.hivemind.impl.XmlModuleDescriptorProvider;
import org.apache.hivemind.internal.ser.ServiceSerializationHelper;
import org.apache.hivemind.util.ClasspathResource;
import org.apache.hivemind.util.PropertyUtils;
import org.apache.hivemind.util.URLResource;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.spi.LoggingEvent;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
import org.easymock.MockControl;
import org.easymock.classextension.MockClassControl;

/**
* Contains some support for creating HiveMind tests; this is useful enough that has been moved into
* the main framework, to simplify creation of tests in the dependent libraries.
*
* @author Howard Lewis Ship
*/
public abstract class HiveMindTestCase extends TestCase
{
    // /CLOVER:OFF

    /**
     * An instance of {@link DefaultClassResolver} that can be used by tests.
     */

    private ClassResolver _classResolver;

    protected String _interceptedLoggerName;

    protected StoreAppender _appender;

    private static Perl5Compiler _compiler;

    private static Perl5Matcher _matcher;

    /** List of {@link org.easymock.MockControl}. */

    private List _controls = new ArrayList();

    /** @since 1.1 */
    interface MockControlFactory
    {
        public MockControl newControl(Class mockClass);
    }

    /** @since 1.1 */
    private static class InterfaceMockControlFactory implements MockControlFactory
    {
        public MockControl newControl(Class mockClass)
        {
            return MockControl.createStrictControl(mockClass);
        }
    }

    /** @since 1.1 */
    private static class ClassMockControlFactory implements MockControlFactory
    {
        public MockControl newControl(Class mockClass)
        {
            return MockClassControl.createStrictControl(mockClass);
        }
    }

    /** @since 1.1 */
    static class PlaceholderClassMockControlFactory implements MockControlFactory
    {
        public MockControl newControl(Class mockClass)
        {
            throw new RuntimeException(
                    "Unable to instantiate EasyMock control for "
                            + mockClass
                            + "; ensure that easymockclassextension-1.1.jar and cglib-full-2.0.1.jar are on the classpath.");
        }
    }

    /** @since 1.1 */
    private static final MockControlFactory _interfaceMockControlFactory = new InterfaceMockControlFactory();

    /** @since 1.1 */
    private static MockControlFactory _classMockControlFactory;

    static
    {
        try
        {
            _classMockControlFactory = new ClassMockControlFactory();
        }
        catch (NoClassDefFoundError ex)
        {
            _classMockControlFactory = new PlaceholderClassMockControlFactory();
        }
    }

    /**
     * Returns the given file as a {@link Resource} from the classpath. Typically, this is to find
     * files in the same folder as the invoking class.
     */
    protected Resource getResource(String file)
    {
        URL url = getClass().getResource(file);

        if (url == null)
            throw new NullPointerException("No resource named '" + file + "'.");

        return new URLResource(url);
    }

    /**
     * Converts the actual list to an array and invokes
     * {@link #assertListsEqual(Object[], Object[])}.
     */
    protected static void assertListsEqual(Object[] expected, List actual)
    {
        assertListsEqual(expected, actual.toArray());
    }

    /**
     * Asserts that the two arrays are equal; same length and all elements equal. Checks the
     * elements first, then the length.
     */
    protected static void assertListsEqual(Object[] expected, Object[] actual)
    {
        assertNotNull(actual);

        int min = Math.min(expected.length, actual.length);

        for (int i = 0; i < min; i++)
            assertEquals("list[" + i + "]", expected[i], actual[i]);

        assertEquals("list length", expected.length, actual.length);
    }

    /**
     * Called when code should not be reachable (because a test is expected to throw an exception);
     * throws AssertionFailedError always.
     */
    protected static void unreachable()
    {
        throw new AssertionFailedError("This code should be unreachable.");
    }

    /**
     * Sets up an appender to intercept logging for the specified logger. Captured log events can be
     * recovered via {@link #getInterceptedLogEvents()}.
     */
    protected void interceptLogging(String loggerName)
    {
        Logger logger = LogManager.getLogger(loggerName);

        logger.removeAllAppenders();

        _interceptedLoggerName = loggerName;
        _appender = new StoreAppender();
        _appender.activateOptions();

        logger.setLevel(Level.DEBUG);
        logger.setAdditivity(false);
        logger.addAppender(_appender);
    }

    /**
     * Gets the list of events most recently intercepted. This resets the appender, clearing the
     * list of stored events.
     *
     * @see #interceptLogging(String)
     */

    protected List getInterceptedLogEvents()
    {
        return _appender.getEvents();
    }

    /**
     * Removes the appender that may have been setup by {@link #interceptLogging(String)}. Also,
     * invokes {@link org.apache.hivemind.util.PropertyUtils#clearCache()}.
     */
    protected void tearDown() throws Exception
    {
        super.tearDown();

        if (_appender != null)
        {
            _appender = null;

            Logger logger = LogManager.getLogger(_interceptedLoggerName);
            logger.setLevel(null);
            logger.setAdditivity(true);
            logger.removeAllAppenders();
        }

        PropertyUtils.clearCache();

        ServiceSerializationHelper.setServiceSerializationSupport(null);
    }

    /**
     * Checks that the provided substring exists in the exceptions message.
     */
    protected void assertExceptionSubstring(Throwable ex, String substring)
    {
        String message = ex.getMessage();
        assertNotNull(message);

        int pos = message.indexOf(substring);

        if (pos < 0)
            throw new AssertionFailedError("Exception message (" + message + ") does not contain ["
                    + substring + "]");
    }

    /**
     * Checks that the message for an exception matches a regular expression.
     */

    protected void assertExceptionRegexp(Throwable ex, String pattern) throws Exception
    {
        String message = ex.getMessage();
        assertNotNull(message);

        setupMatcher();

        Pattern compiled = _compiler.compile(pattern);

        if (_matcher.contains(message, compiled))
            return;

        throw new AssertionFailedError("Exception message (" + message
                + ") does not contain regular expression [" + pattern + "].");
    }

    protected void assertRegexp(String pattern, String actual) throws Exception
    {
        setupMatcher();

        Pattern compiled = _compiler.compile(pattern);

        if (_matcher.contains(actual, compiled))
            return;

        throw new AssertionFailedError("\"" + actual + "\" does not contain regular expression["
                + pattern + "].");
    }

    /**
     * Digs down through (potentially) a stack of ApplicationRuntimeExceptions until it reaches the
     * originating exception, which is returned.
     */
    protected Throwable findNestedException(ApplicationRuntimeException ex)
    {
        Throwable cause = ex.getRootCause();

        if (cause == null || cause == ex)
            return ex;

        if (cause instanceof ApplicationRuntimeException)
            return findNestedException((ApplicationRuntimeException) cause);

        return cause;
    }

    /**
     * Checks to see if a specific event matches the name and message.
     *
     * @param message
     *            exact message to search for
     * @param events
     *            the list of events {@link #getInterceptedLogEvents()}
     * @param index
     *            the index to check at
     */
    private void assertLoggedMessage(String message, List events, int index)
    {
        LoggingEvent e = (LoggingEvent) events.get(index);

        assertEquals("Message", message, e.getMessage());
    }

    /**
     * Checks the messages for all logged events for exact match against the supplied list.
     */
    protected void assertLoggedMessages(String[] messages)
    {
        List events = getInterceptedLogEvents();

        for (int i = 0; i < messages.length; i++)
        {
            assertLoggedMessage(messages[i], events, i);
        }
    }

    /**
     * Asserts that some capture log event matches the given message exactly.
     */
    protected void assertLoggedMessage(String message)
    {
        assertLoggedMessage(message, getInterceptedLogEvents());
    }

    /**
     * Asserts that some capture log event matches the given message exactly.
     *
     * @param message
     *            to search for; success is finding a logged message contain the parameter as a
     *            substring
     * @param events
     *            from {@link #getInterceptedLogEvents()}
     */
    protected void assertLoggedMessage(String message, List events)
    {
        int count = events.size();

        for (int i = 0; i < count; i++)
        {
            LoggingEvent e = (LoggingEvent) events.get(i);

            String eventMessage = String.valueOf(e.getMessage());

            if (eventMessage.indexOf(message) >= 0)
                return;
        }

        throw new AssertionFailedError("Could not find logged message: " + message);
    }

    protected void assertLoggedMessagePattern(String pattern) throws Exception
    {
        assertLoggedMessagePattern(pattern, getInterceptedLogEvents());
    }

    protected void assertLoggedMessagePattern(String pattern, List events) throws Exception
    {
        setupMatcher();

        Pattern compiled = null;

        int count = events.size();

        for (int i = 0; i < count; i++)
        {
            LoggingEvent e = (LoggingEvent) events.get(i);

            String eventMessage = e.getMessage().toString();

            if (compiled == null)
                compiled = _compiler.compile(pattern);

            if (_matcher.contains(eventMessage, compiled))
                return;

        }

        throw new AssertionFailedError("Could not find logged message with pattern: " + pattern);
    }

    private void setupMatcher()
    {
        if (_compiler == null)
            _compiler = new Perl5Compiler();

        if (_matcher == null)
            _matcher = new Perl5Matcher();
    }

    /**
     * Convienience method for invoking {@link #buildFrameworkRegistry(String[])} with only a single
     * file.
     */
    protected Registry buildFrameworkRegistry(String file) throws Exception
    {
        return buildFrameworkRegistry(new String[]
        { file });
    }

    /**
     * Builds a minimal registry, containing only the specified files, plus the master module
     * descriptor (i.e., those visible on the classpath). Files are resolved using
     * {@link HiveMindTestCase#getResource(String)}.
     */
    protected Registry buildFrameworkRegistry(String[] files) throws Exception
    {
        ClassResolver resolver = getClassResolver();

        List descriptorResources = new ArrayList();
        for (int i = 0; i < files.length; i++)
        {
            Resource resource = getResource(files[i]);

            descriptorResources.add(resource);
        }

        ModuleDescriptorProvider provider = new XmlModuleDescriptorProvider(resolver,
                descriptorResources);

        return buildFrameworkRegistry(provider);
    }

    /**
     * Builds a registry, containing only the modules delivered by the specified
     * {@link org.apache.hivemind.ModuleDescriptorProvider}, plus the master module descriptor
     * (i.e., those visible on the classpath).
     */
    protected Registry buildFrameworkRegistry(ModuleDescriptorProvider customProvider)
    {
        ClassResolver resolver = getClassResolver();

        RegistryBuilder builder = new RegistryBuilder();

        builder.addModuleDescriptorProvider(new XmlModuleDescriptorProvider(resolver));
        builder.addModuleDescriptorProvider(customProvider);

        return builder.constructRegistry(Locale.getDefault());
    }

    /**
     * Builds a registry from exactly the provided resource; this registry will not include the
     * <code>hivemind</code> module.
     */
    protected Registry buildMinimalRegistry(Resource l) throws Exception
    {
        RegistryBuilder builder = new RegistryBuilder();

        return builder.constructRegistry(Locale.getDefault());
    }

    /**
     * Creates a <em>managed</em> control via
     * {@link MockControl#createStrictControl(java.lang.Class)}. The created control is remembered,
     * and will be invoked by {@link #replayControls()}, {@link #verifyControls()}, etc.
     * <p>
     * The class to mock may be either an interface or a class. The EasyMock class extension
     * (easymockclassextension-1.1.jar) and CGLIB (cglib-full-2.01.jar) must be present in the
     * latter case (new since 1.1).
     */
    protected MockControl newControl(Class mockClass)
    {
        MockControlFactory factory = mockClass.isInterface() ? _interfaceMockControlFactory
                : _classMockControlFactory;

        MockControl result = factory.newControl(mockClass);

        addControl(result);

        return result;
    }

    /**
     * Accesses the control for a previously created mock object. Iterates over the list of managed
     * controls until one is found whose mock object identity equals the mock object provided.
     *
     * @param Mock
     *            object whose control is needed
     * @return the corresponding MockControl if found
     * @throws IllegalArgumentException
     *             if not found
     * @since 1.1
     */

    protected MockControl getControl(Object mock)
    {
        Iterator i = _controls.iterator();
        while (i.hasNext())
        {
            MockControl control = (MockControl) i.next();

            if (control.getMock() == mock)
                return control;
        }

        throw new IllegalArgumentException(mock
                + " is not a mock object controlled by any registered MockControl instance.");
    }

    /**
     * Adds the control to the list of managed controls used by {@link #replayControls()} and
     * {@link #verifyControls()}.
     */
    protected void addControl(MockControl control)
    {
        _controls.add(control);
    }

    /**
     * Convienience for invoking {@link #newControl(Class)} and then invoking
     * {@link MockControl#getMock()} on the result.
     */
    protected Object newMock(Class mockClass)
    {
        return newControl(mockClass).getMock();
    }

    /**
     * Invokes {@link MockControl#replay()} on all controls created by {@link #newControl(Class)}.
     */
    protected void replayControls()
    {
        Iterator i = _controls.iterator();
        while (i.hasNext())
        {
            MockControl c = (MockControl) i.next();
            c.replay();
        }
    }

    /**
     * Invokes {@link org.easymock.MockControl#verify()} and {@link MockControl#reset()} on all
     * controls created by {@link #newControl(Class)}.
     */

    protected void verifyControls()
    {
        Iterator i = _controls.iterator();
        while (i.hasNext())
        {
            MockControl c = (MockControl) i.next();
            c.verify();
            c.reset();
        }
    }

    /**
     * Invokes {@link org.easymock.MockControl#reset()} on all controls.
     */

    protected void resetControls()
    {
        Iterator i = _controls.iterator();
        while (i.hasNext())
        {
            MockControl c = (MockControl) i.next();
            c.reset();
        }
    }

    /**
     * @deprecated To be removed in 1.2. Use {@link #newLocation()} instead.
     */
    protected Location fabricateLocation(int line)
    {
        String path = "/" + getClass().getName().replace('.', '/');

        Resource r = new ClasspathResource(getClassResolver(), path);

        return new LocationImpl(r, line);
    }

    private int _line = 1;

    /**
     * Returns a new {@link Location} instance. The resource is the test class, and the line number
     * increments by one from one for each invocation (thus each call will get a unique instance not
     * equal to any previously obtained instance).
     *
     * @since 1.1
     */
    protected Location newLocation()
    {
        return fabricateLocation(_line++);
    }

    /**
     * Returns a {@link DefaultClassResolver}. Repeated calls in the same test return the same
     * value.
     *
     * @since 1.1
     */

    protected ClassResolver getClassResolver()
    {
        if (_classResolver == null)
            _classResolver = new DefaultClassResolver();

        return _classResolver;
    }

    protected boolean matches(String input, String pattern) throws Exception
    {
        setupMatcher();

        Pattern compiled = _compiler.compile(pattern);

        return _matcher.matches(input, compiled);
    }

}
TOP

Related Classes of org.apache.hivemind.test.HiveMindTestCase$InterfaceMockControlFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.