content: 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);
              }
          }
      }
  }