/** * Originally from http://www.cornetdesign.com/files/BeanTestCase.java.txt */ package org.connectbot.mock; import junit.framework.TestCase; import java.lang.reflect.Field; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; public class BeanAssertions { private static final String TEST_STRING_VAL1 = "Some Value"; private static final String TEST_STRING_VAL2 = "Some Other Value"; private BeanAssertions() { } public static void assertMeetsEqualsContract(Class<?> classUnderTest, String[] fieldNames) { Object o1; Object o2; try { // Get Instances o1 = classUnderTest.newInstance(); o2 = classUnderTest.newInstance(); assertTrue( "Instances with default constructor not equal (o1.equals(o2))", o1.equals(o2)); assertTrue( "Instances with default constructor not equal (o2.equals(o1))", o2.equals(o1)); Field[] fields = getFieldsByNameOrAll(classUnderTest, fieldNames); for (int i = 0; i < fields.length; i++) { // Reset the instances o1 = classUnderTest.newInstance(); o2 = classUnderTest.newInstance(); Field field = fields[i]; field.setAccessible(true); if (field.getType() == String.class) { field.set(o1, TEST_STRING_VAL1); } else if (field.getType() == boolean.class) { field.setBoolean(o1, true); } else if (field.getType() == short.class) { field.setShort(o1, (short) 1); } else if (field.getType() == long.class) { field.setLong(o1, (long) 1); } else if (field.getType() == float.class) { field.setFloat(o1, (float) 1); } else if (field.getType() == int.class) { field.setInt(o1, 1); } else if (field.getType() == byte.class) { field.setByte(o1, (byte) 1); } else if (field.getType() == char.class) { field.setChar(o1, (char) 1); } else if (field.getType() == double.class) { field.setDouble(o1, (double) 1); } else if (field.getType().isEnum()) { field.set(o1, field.getType().getEnumConstants()[0]); } else if (Object.class.isAssignableFrom(field.getType())) { field.set(o1, field.getType().newInstance()); } else { fail("Don't know how to set a " + field.getType().getName()); } assertFalse("Instances with o1 having " + field.getName() + " set and o2 having it not set are equal", o1 .equals(o2)); field.set(o2, field.get(o1)); assertTrue( "After setting o2 with the value of the object in o1, the two objects in the field are not equal", field.get(o1).equals(field.get(o2))); assertTrue( "Instances with o1 having " + field.getName() + " set and o2 having it set to the same object of type " + field.get(o2).getClass().getName() + " are not equal", o1.equals(o2)); if (field.getType() == String.class) { field.set(o2, TEST_STRING_VAL2); } else if (field.getType() == boolean.class) { field.setBoolean(o2, false); } else if (field.getType() == short.class) { field.setShort(o2, (short) 0); } else if (field.getType() == long.class) { field.setLong(o2, (long) 0); } else if (field.getType() == float.class) { field.setFloat(o2, (float) 0); } else if (field.getType() == int.class) { field.setInt(o2, 0); } else if (field.getType() == byte.class) { field.setByte(o2, (byte) 0); } else if (field.getType() == char.class) { field.setChar(o2, (char) 0); } else if (field.getType() == double.class) { field.setDouble(o2, (double) 1); } else if (field.getType().isEnum()) { field.set(o2, field.getType().getEnumConstants()[1]); } else if (Object.class.isAssignableFrom(field.getType())) { field.set(o2, field.getType().newInstance()); } else { fail("Don't know how to set a " + field.getType().getName()); } if (field.get(o1).equals(field.get(o2))) { // Even though we have different instances, they are equal. // Let's walk one of them // to see if we can find a field to set Field[] paramFields = field.get(o1).getClass() .getDeclaredFields(); for (int j = 0; j < paramFields.length; j++) { paramFields[j].setAccessible(true); if (paramFields[j].getType() == String.class) { paramFields[j].set(field.get(o1), TEST_STRING_VAL1); } } } assertFalse( "After setting o2 with a different object than what is in o1, the two objects in the field are equal. " + "This is after an attempt to walk the fields to make them different", field.get(o1).equals(field.get(o2))); assertFalse( "Instances with o1 having " + field.getName() + " set and o2 having it set to a different object are equal", o1.equals(o2)); } } catch (InstantiationException e) { e.printStackTrace(); throw new AssertionError( "Unable to construct an instance of the class under test"); } catch (IllegalAccessException e) { e.printStackTrace(); throw new AssertionError( "Unable to construct an instance of the class under test"); } catch (SecurityException e) { e.printStackTrace(); throw new AssertionError( "Unable to read the field from the class under test"); } catch (NoSuchFieldException e) { e.printStackTrace(); throw new AssertionError( "Unable to find field in the class under test"); } } /** * @param classUnderTest * @param fieldNames * @return * @throws NoSuchFieldException */ private static Field[] getFieldsByNameOrAll(Class<?> classUnderTest, String[] fieldNames) throws NoSuchFieldException { Field fields[]; if (fieldNames == null) { fields = classUnderTest.getDeclaredFields(); } else { fields = new Field[fieldNames.length]; for (int i = 0; i < fieldNames.length; i++) fields[i] = classUnderTest.getDeclaredField(fieldNames[i]); } return fields; } public static void assertMeetsHashCodeContract(Class<?> classUnderTest, String[] fieldNames) { try { Field[] fields = getFieldsByNameOrAll(classUnderTest, fieldNames); for (int i = 0; i < fields.length; i++) { Object o1 = classUnderTest.newInstance(); int initialHashCode = o1.hashCode(); Field field = fields[i]; field.setAccessible(true); if (field.getType() == String.class) { field.set(o1, TEST_STRING_VAL1); } else if (field.getType() == boolean.class) { field.setBoolean(o1, true); } else if (field.getType() == short.class) { field.setShort(o1, (short) 1); } else if (field.getType() == long.class) { field.setLong(o1, (long) 1); } else if (field.getType() == float.class) { field.setFloat(o1, (float) 1); } else if (field.getType() == int.class) { field.setInt(o1, 1); } else if (field.getType() == byte.class) { field.setByte(o1, (byte) 1); } else if (field.getType() == char.class) { field.setChar(o1, (char) 1); } else if (field.getType() == double.class) { field.setDouble(o1, (double) 1); } else if (field.getType().isEnum()) { field.set(o1, field.getType().getEnumConstants()[0]); } else if (Object.class.isAssignableFrom(field.getType())) { field.set(o1, field.getType().newInstance()); } else { fail("Don't know how to set a " + field.getType().getName()); } int updatedHashCode = o1.hashCode(); assertFalse( "The field " + field.getName() + " was not taken into account for the hashCode contract ", initialHashCode == updatedHashCode); } } catch (InstantiationException e) { e.printStackTrace(); throw new AssertionError( "Unable to construct an instance of the class under test"); } catch (IllegalAccessException e) { e.printStackTrace(); throw new AssertionError( "Unable to construct an instance of the class under test"); } catch (NoSuchFieldException e) { e.printStackTrace(); throw new AssertionError( "Unable to find field in the class under test"); } } }