/*
* Copyright (c) 2015 EMC Corporation
* All Rights Reserved
*/
package com.emc.sa.util;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.Map;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.junit.Assert;
import com.google.common.collect.Maps;
/**
* This is a utility class for testing bean getters and setters. Any 'standard' properties can be tested automatically
* using {@link #testGettersAndSetters(Object)} using random input values. Any other properties can be tested by calling
* {@link #testGetterAndSetter(Object, String, Object)} with an appropriate value. The types supported for random value
* testing are:
* <ul>
* <li>String</li>
* <li>Integer (int)</li>
* <li>Long (long)</li>
* <li>Short (short)</li>
* <li>Byte (byte)</li>
* <li>Double (double)</li>
* <li>Float (float)</li>
* <li>Boolean (boolean)
* <li>
* <li>Date</li>
* </ul>
*
* @author jonnymiller
*/
public class BeanTestUtils {
private static final Map<Class<?>, ValueGenerator> TYPES = createTypes();
private static final Map<Class<?>, ValueGenerator> createTypes() {
Map<Class<?>, ValueGenerator> types = Maps.newHashMap();
types.put(String.class, new StringGenerator());
types.put(Integer.class, new IntegerGenerator());
types.put(int.class, new IntegerGenerator());
types.put(Long.class, new LongGenerator());
types.put(long.class, new LongGenerator());
types.put(Short.class, new ShortGenerator());
types.put(short.class, new ShortGenerator());
types.put(Byte.class, new ByteGenerator());
types.put(byte.class, new ByteGenerator());
types.put(Double.class, new DoubleGenerator());
types.put(double.class, new DoubleGenerator());
types.put(Float.class, new FloatGenerator());
types.put(float.class, new FloatGenerator());
types.put(Boolean.class, new BooleanGenerator());
types.put(boolean.class, new BooleanGenerator());
types.put(Date.class, new DateGenerator());
return types;
}
private static boolean isSupportedType(Class<?> type) {
return TYPES.containsKey(type);
}
private static Object randomValue(Class<?> type) {
return TYPES.get(type).randomValue();
}
public static void testGettersAndSetters(Object bean) {
Assert.assertNotNull(bean);
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
PropertyDescriptor[] properties = beanInfo.getPropertyDescriptors();
Assert.assertNotNull("No properties for " + bean.getClass(), properties);
for (PropertyDescriptor property : properties) {
Class<?> type = property.getPropertyType();
if (isSupportedType(type)) {
boolean canRead = property.getReadMethod() != null;
boolean canWrite = property.getWriteMethod() != null;
if (canRead && canWrite) {
testGetterAndSetter(bean, property.getName(), type);
}
}
}
} catch (IntrospectionException e) {
throw new RuntimeException(e);
}
}
public static void testGetterAndSetter(Object bean, String property, Class<?> type) {
for (int i = 0; i < 3; i++) {
Object value = randomValue(type);
testGetterAndSetter(bean, property, value);
}
}
public static void testGetterAndSetter(Object bean, String property, Object value) {
try {
PropertyUtils.setProperty(bean, property, value);
Object newValue = PropertyUtils.getProperty(bean, property);
Assert.assertEquals("get/set property " + property, value, newValue);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private static interface ValueGenerator {
public Object randomValue();
}
private static class StringGenerator implements ValueGenerator {
public Object randomValue() {
return RandomStringUtils.random(10);
}
}
private static class IntegerGenerator implements ValueGenerator {
public Object randomValue() {
int value = (int) (Math.random() * Integer.MAX_VALUE);
return (Math.random() > 0.5) ? value : -value;
}
}
private static class LongGenerator implements ValueGenerator {
public Object randomValue() {
long value = (long) (Math.random() * Long.MAX_VALUE);
return (Math.random() > 0.5) ? value : -value;
}
}
private static class ShortGenerator implements ValueGenerator {
public Object randomValue() {
short value = (short) (Math.random() * Short.MAX_VALUE);
return (Math.random() > 0.5) ? value : -value;
}
}
private static class ByteGenerator implements ValueGenerator {
public Object randomValue() {
byte value = (byte) (Math.random() * Byte.MAX_VALUE);
return (Math.random() > 0.5) ? value : -value;
}
}
private static class DoubleGenerator implements ValueGenerator {
public Object randomValue() {
double value = Math.random() * Double.MAX_VALUE;
return (Math.random() > 0.5) ? value : -value;
}
}
private static class FloatGenerator implements ValueGenerator {
public Object randomValue() {
float value = (float) (Math.random() * Float.MAX_VALUE);
return (Math.random() > 0.5) ? value : -value;
}
}
private static class BooleanGenerator implements ValueGenerator {
public Object randomValue() {
return Math.random() > 0.5 ? true : false;
}
}
private static class DateGenerator implements ValueGenerator {
public Object randomValue() {
long value = (int) (Math.random() * (Long.MAX_VALUE / 2));
return new Date(value);
}
}
}