org.opensaas.jaudit.test.BeanTest.java Source code

Java tutorial

Introduction

Here is the source code for org.opensaas.jaudit.test.BeanTest.java

Source

/**
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE
 * You may obtain a copy of the License at
 *
 *   http://www.gnu.org/licenses/lgpl-3.0.txt
 *
 * 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.opensaas.jaudit.test;

import java.beans.PropertyDescriptor;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.beanutils.PropertyUtils;
import org.junit.Test;
import org.opensaas.jaudit.test.DefaultFactories.StringFactory;

/**
 * A basic abstract class for testing simple bean functionality of an object.
 * 
 * @param <T>
 *            The type of object under test.
 */
public abstract class BeanTest<T> {

    /**
     * A collection of useful instances for common class types.
     * 
     * @see AccessorAssert#assertGetterAndSetter(Object, String, Class,
     *      Object...)
     * @see AccessorAssert#assertGetterAndSetter(Object,
     *      java.lang.reflect.Method, java.lang.reflect.Method, Object[])
     */
    protected static final Map<Class<?>, Object[]> CLASS_TO_VALUES = newClassToValues();

    /**
     * An {@link ObjectFactory} used for generating {@link String} objects.
     */
    protected static final StringFactory STRING_FACTORY = new DefaultFactories.StringFactory();

    private static final Object[] EMPTY_ARRAY = new Object[] {};

    /**
     * Verify that the factory we'll use for the other tests satisfies the
     * {@ObjectFactory} contract.
     */
    @Test
    public final void verifyFactory() {
        ObjectFactoryAssert.assertObjectFactoryContract(getObjectFactory());
    }

    /**
     * Verifies that all getter/setter combinations (java bean spec) work in
     * combination correctly together. Uses {@link #getTestValues(Class)} to
     * determine test values to feed into setters to test the return value of
     * getters.
     * 
     * @throws Exception
     *             when an unexpected error occurs.
     */
    @Test
    public final void verifyGetterSetters() throws Exception {

        final T bean = getObjectFactory().createEquivalent();

        final PropertyDescriptor[] properties = PropertyUtils.getPropertyDescriptors(bean);
        for (final PropertyDescriptor pd : properties) {
            if (pd.getReadMethod() == null || pd.getWriteMethod() == null) {
                continue;
            }
            final Object[] testValues = getTestValues(pd);

            AccessorAssert.assertGetterAndSetter(bean, pd.getWriteMethod(), pd.getReadMethod(), testValues);
        }

    }

    /**
     * Test method for the toString() method.
     */
    @Test
    public void testToString() {
        ObjectAssert.assertToStringContract(getObjectFactory());
    }

    /**
     * Test method for hashCode() method.
     */
    @Test
    public void testHashCode() {
        ObjectAssert.assertHashCodeContract(getObjectFactory());
    }

    /**
     * Test method for equals method.
     */
    @Test
    public void testEquals() {
        ObjectAssert.assertEqualsContract(getObjectFactory());
    }

    /**
     * Test that the object under test is properly {@link Serializable}.
     * 
     * @throws Exception
     *             if something bad happens.
     */
    @Test
    public void testSerializable() throws Exception {
        final T bean = getObjectFactory().createEquivalent();
        if (Serializable.class.isAssignableFrom(bean.getClass())) {
            @SuppressWarnings("unchecked")
            final ObjectFactory<? extends Serializable> objectFactory = (ObjectFactory<? extends Serializable>) getObjectFactory();
            SerializableAssert.testSerialization(objectFactory);
        }
    }

    /**
     * Return an {@link ObjectFactory} for the type of object currently under
     * test.
     * 
     * @return an ObjectFactory.
     */
    protected abstract ObjectFactory<T> getObjectFactory();

    /**
     * Will look up test values based on the PropertyDescriptor's read method's
     * return type. This implementation may be overridden but it currently
     * delegates to {@link #getTestValues(Class)} to determine what to return.
     * 
     * @param pd
     *            PropertyDescriptor to check the return type of the read
     *            method.
     * @return Object[] or emtpy if none.
     */
    protected Object[] getTestValues(final PropertyDescriptor pd) {
        final Class<?> returnType = pd.getReadMethod().getReturnType();

        final Object[] values = getTestValues(returnType);
        if (values == null) {
            return EMPTY_ARRAY;
        }
        return values;
    }

    /**
     * Returns test values based on the passed in value type. This method may be
     * overridden for types the base BeanTest class does not support. Currently
     * delegates to the Map returned by {@link #newClassToValues()}.
     * 
     * @param valueType
     *            Class to resolve values for.
     * 
     * @return Object[] matching values to test.
     */
    protected Object[] getTestValues(final Class<?> valueType) {

        final Object[] values = CLASS_TO_VALUES.get(valueType);
        if (values == null) {

            // check if enum
            if (valueType.isEnum()) {
                final Object[] enumConsts = valueType.getEnumConstants();
                final List<Object> consts = new ArrayList<Object>(enumConsts.length + 1);
                consts.addAll(Arrays.asList(enumConsts));
                consts.add(null);
                return consts.toArray();
            }

            return EMPTY_ARRAY;
        }
        return values;
    }

    /**
     * Returns a new Map of default test class to test values types useful in
     * testing getters/setters.
     * 
     * @return Map of supported types and associated values.
     */
    protected static Map<Class<?>, Object[]> newClassToValues() {
        final Map<Class<?>, Object[]> ctov = new HashMap<Class<?>, Object[]>();

        ctov.put(Boolean.class, new Object[] { Boolean.TRUE, Boolean.FALSE, null });
        ctov.put(Boolean.TYPE, new Object[] { Boolean.TRUE, Boolean.FALSE });
        ctov.put(Date.class, new Object[] { new Date(), new Date(0L), new Date(1000L), null });
        ctov.put(Double.class, new Object[] { 0d, Double.MAX_VALUE, Double.MIN_VALUE, null });
        ctov.put(Double.TYPE, new Object[] { 0d, Double.MAX_VALUE, Double.MIN_VALUE });
        ctov.put(Integer.class, new Object[] { 0, Integer.MAX_VALUE, Integer.MIN_VALUE, null });
        ctov.put(Integer.TYPE, new Object[] { 0, Integer.MAX_VALUE, Integer.MIN_VALUE });
        ctov.put(Long.class, new Object[] { 0L, Long.MAX_VALUE, Long.MIN_VALUE, null });
        ctov.put(Long.TYPE, new Object[] { 0L, Long.MAX_VALUE, Long.MIN_VALUE });
        ctov.put(String.class, new Object[] { "", " ", "Texas Fight!", UUID.randomUUID().toString(), null });

        return Collections.unmodifiableMap(ctov);
    }
}