package alien4cloud.utils; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.junit.Assert; import org.junit.Test; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; import alien4cloud.model.common.Tag; import org.alien4cloud.tosca.model.CSARDependency; import org.alien4cloud.tosca.model.definitions.CapabilityDefinition; import org.alien4cloud.tosca.model.Csar; import org.alien4cloud.tosca.model.types.NodeType; import org.alien4cloud.tosca.model.definitions.PropertyDefinition; import org.alien4cloud.tosca.model.definitions.RequirementDefinition; import org.alien4cloud.tosca.model.definitions.constraints.EqualConstraint; import org.alien4cloud.tosca.model.definitions.constraints.GreaterOrEqualConstraint; import org.alien4cloud.tosca.model.definitions.constraints.GreaterThanConstraint; import org.alien4cloud.tosca.model.definitions.constraints.InRangeConstraint; import org.alien4cloud.tosca.model.definitions.constraints.LengthConstraint; import org.alien4cloud.tosca.model.definitions.constraints.LessOrEqualConstraint; import org.alien4cloud.tosca.model.definitions.constraints.LessThanConstraint; import org.alien4cloud.tosca.model.definitions.constraints.MaxLengthConstraint; import org.alien4cloud.tosca.model.definitions.constraints.MinLengthConstraint; import org.alien4cloud.tosca.model.definitions.constraints.PatternConstraint; import org.alien4cloud.tosca.model.definitions.constraints.ValidValuesConstraint; /** * Most of the equals and hashcode methods are generated using Lombok. * Jacoco is not able to ignore theses in coverage reports (feature request is done there). * This class performs equals and hashcode tests in order to avoid wrong results in coverage reports. */ public class EqualsAndHashCodeAutoTest { @Test public void testEqualsAndHashCode() throws IllegalAccessException, NoSuchFieldException, InstantiationException { doTest(NodeType.class, "elementId", "archiveName", "archiveVersion"); doTest(Tag.class, "name"); // TODO is it really what we want to check on CloudImageFlavor ? doTest(CSARDependency.class, "name", "version"); doTest(CapabilityDefinition.class, "id"); doTest(Csar.class, "name", "version"); doTest(PropertyDefinition.class, "type", "required", "description", "defaultValue", "constraints", "entrySchema"); doTest(RequirementDefinition.class, "id"); // doTest(ScalarPropertyValue.class, "value"); doTest(EqualConstraint.class, "equal"); doTest(GreaterOrEqualConstraint.class, "greaterOrEqual"); doTest(GreaterThanConstraint.class, "greaterThan"); doTest(InRangeConstraint.class, "inRange"); doTest(LengthConstraint.class, "length"); doTest(LessOrEqualConstraint.class, "lessOrEqual"); doTest(LessThanConstraint.class, "lessThan"); doTest(MaxLengthConstraint.class, "maxLength"); doTest(MinLengthConstraint.class, "minLength"); doTest(PatternConstraint.class, "pattern"); doTest(ValidValuesConstraint.class, "validValues"); } private void doTest(Class<?> clazz, String... fieldNames) throws IllegalAccessException, InstantiationException, NoSuchFieldException { Object instance = clazz.newInstance(); Object equalInstance = clazz.newInstance(); String wrongTypeInstance = ""; Assert.assertFalse(instance.equals(null)); Assert.assertTrue(instance.equals(equalInstance)); Assert.assertFalse(instance.equals(wrongTypeInstance)); // generate field values for each field we need two different values (to test equals and not equals). Object[][] allFieldValues = new Object[fieldNames.length][]; for (int i = 0; i < fieldNames.length; i++) { Field field = ReflectionUtil.getDeclaredField(clazz, fieldNames[i]); if (ReflectionUtil.isPrimitiveOrWrapperOrString(field.getType())) { allFieldValues[i] = new Object[] { "0", "1" }; } else if (!field.getType().isInterface() && !Modifier.isAbstract(field.getType().getModifiers())) { allFieldValues[i] = new Object[] { field.getType().newInstance(), field.getType().newInstance() }; } else { allFieldValues[i] = new Object[] { null, null }; } } Object[][] testFieldValues = new Object[allFieldValues.length][]; // try every field associations doTest(clazz, allFieldValues, testFieldValues, fieldNames, 0, allFieldValues.length, 0); } private void doTest(Class<?> clazz, Object[][] allFieldValues, Object[][] testFieldValues, String[] fieldNames, int start, int end, int index) throws IllegalAccessException, InstantiationException { if (index == fieldNames.length) { Object instance = clazz.newInstance(); Object equalInstance = clazz.newInstance(); Object otherInstance = clazz.newInstance(); BeanWrapper instanceWrapper = new BeanWrapperImpl(instance); BeanWrapper equalInstanceWrapper = new BeanWrapperImpl(equalInstance); BeanWrapper otherInstanceWrapper = new BeanWrapperImpl(otherInstance); // set field values for (int i = 0; i < fieldNames.length; i++) { String fieldName = fieldNames[i]; if (clazz.equals(PropertyDefinition.class) && fieldNames[i].equals("defaultValue")) { fieldName = "default"; } instanceWrapper.setPropertyValue(fieldName, testFieldValues[i][0]); equalInstanceWrapper.setPropertyValue(fieldName, testFieldValues[i][0]); otherInstanceWrapper.setPropertyValue(fieldName, testFieldValues[i][1]); } // Two instances that are the same must have the same hashcode (but two different instance may have the same hashcode). Assert.assertEquals(instance.hashCode(), equalInstance.hashCode()); Assert.assertTrue(instance.equals(equalInstance)); } else { // recursive prepare a set of field values to test so we test all combinations for (int i = start; i < end && end - i + 1 >= fieldNames.length - index; i++) { testFieldValues[index] = allFieldValues[i]; doTest(clazz, allFieldValues, testFieldValues, fieldNames, i + 1, end, index + 1); } } } }