Repository: jmrozanec/cron-utils
Pull request #533 (2022-08-09 11:50:33)

Equals and hashcode for FieldConstraints and FieldDefinition
Necessary to get proper behavior for equals and hashcode in `CronDefinition`.

I also corrected the test class, the original tests were misleading because they used the very same instance of `FieldDefinition`s.

See #507 and #516


Patch:
diff --git a/src/main/java/com/cronutils/model/field/constraint/FieldConstraints.java b/src/main/java/com/cronutils/model/field/constraint/FieldConstraints.java
index 1a6a7af..b2b3b37 100755
--- a/src/main/java/com/cronutils/model/field/constraint/FieldConstraints.java
+++ b/src/main/java/com/cronutils/model/field/constraint/FieldConstraints.java
@@ -19,6 +19,7 @@ import com.cronutils.utils.Preconditions;
 import java.io.Serializable;
 import java.util.Collections;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 
 /**
@@ -100,4 +101,19 @@ public class FieldConstraints implements Serializable {
     public boolean isStrictRange() {
         return strictRange;
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        FieldConstraints that = (FieldConstraints) o;
+        return strictRange == that.strictRange && stringMapping.equals(that.stringMapping)
+                && intMapping.equals(that.intMapping) && specialChars.equals(that.specialChars)
+                && startRange.equals(that.startRange) && endRange.equals(that.endRange);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(stringMapping, intMapping, specialChars, startRange, endRange, strictRange);
+    }
 }
diff --git a/src/main/java/com/cronutils/model/field/definition/FieldDefinition.java b/src/main/java/com/cronutils/model/field/definition/FieldDefinition.java
index 98ab707..d195398 100644
--- a/src/main/java/com/cronutils/model/field/definition/FieldDefinition.java
+++ b/src/main/java/com/cronutils/model/field/definition/FieldDefinition.java
@@ -19,6 +19,7 @@ import com.cronutils.utils.Preconditions;
 
 import java.io.Serializable;
 import java.util.Comparator;
+import java.util.Objects;
 
 /**
  * Represents a definition of allowed values for a cron field.
@@ -92,5 +93,18 @@ public class FieldDefinition implements Serializable {
     public static Comparator<FieldDefinition> createFieldDefinitionComparator() {
         return Comparator.comparingInt(o -> o.getFieldName().getOrder());
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        FieldDefinition that = (FieldDefinition) o;
+        return optional == that.optional && fieldName == that.fieldName && constraints.equals(that.constraints);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(fieldName, constraints, optional);
+    }
 }
 


Test patch:
diff --git a/src/test/java/com/cronutils/model/definition/CronDefinitionTest.java b/src/test/java/com/cronutils/model/definition/CronDefinitionTest.java
index 5ba1942..1bfa1dd 100755
--- a/src/test/java/com/cronutils/model/definition/CronDefinitionTest.java
+++ b/src/test/java/com/cronutils/model/definition/CronDefinitionTest.java
@@ -13,7 +13,10 @@
 
 package com.cronutils.model.definition;
 
+import com.cronutils.model.CronType;
 import com.cronutils.model.field.CronFieldName;
+import com.cronutils.model.field.constraint.FieldConstraints;
+import com.cronutils.model.field.constraint.FieldConstraintsBuilder;
 import com.cronutils.model.field.definition.FieldDefinition;
 import junitparams.JUnitParamsRunner;
 import junitparams.Parameters;
@@ -27,6 +30,8 @@ import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.UnaryOperator;
 
 import static org.junit.Assert.*;
 import static org.mockito.Mockito.when;
@@ -115,9 +120,16 @@ public class CronDefinitionTest {
         assertTrue(cronDefinition.getFieldDefinitions().contains(mockFieldDefinition1));
     }
 
+    @Test
+    public void simpleEqualityTest() {
+        assertEquals(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ), CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ));
+    }
+
     @Test
     @Parameters(method = "parametersToTestIfEqual")
     public void testIfDefinitionsAreEqual(
+        List<FieldDefinition> fieldDefinitionsOne,
+        List<FieldDefinition> fieldDefinitionsTwo,
         Set<CronConstraint> cronConstraintsOne,
         Set<CronConstraint> cronConstraintsTwo,
         Set<CronNicknames> cronNicknamesOne,
@@ -127,12 +139,12 @@ public class CronDefinitionTest {
         boolean shouldBeEqual) {
         // given
         CronDefinition definitionOne = new CronDefinition(
-            provideFieldDefinitionListWithSingleDefinition(),
+            fieldDefinitionsOne,
             cronConstraintsOne,
             cronNicknamesOne,
             shouldMatchDayOfWeekAndDayOfMonthOne);
         CronDefinition definitionTwo = new CronDefinition(
-            provideFieldDefinitionListWithSingleDefinition(),
+            fieldDefinitionsTwo,
             cronConstraintsTwo,
             cronNicknamesTwo,
             shouldMatchDayOfWeekAndDayOfMonthTwo);
@@ -152,6 +164,8 @@ public class CronDefinitionTest {
     private Object[] parametersToTestIfEqual() {
         return new Object[] {
             new Object[] {
+                provideSimpleFieldDefinitions(),
+                provideSimpleFieldDefinitions(),
                 provideCronConstraintSetWithTwoConstraints(),
                 provideCronConstraintSetWithTwoConstraints(),
                 provideCronNicknameSetWithTwoNicknames(),
@@ -161,6 +175,19 @@ public class CronDefinitionTest {
                 true
             },
             new Object[] {
+                provideFieldDefinitions(CronFieldName.SECOND, b -> b.withValidRange(0, 59)),
+                provideFieldDefinitions(CronFieldName.SECOND, b -> b.withValidRange(1, 60)),
+                provideCronConstraintSetWithTwoConstraints(),
+                provideCronConstraintSetWithTwoConstraints(),
+                provideCronNicknameSetWithTwoNicknames(),
+                provideCronNicknameSetWithTwoNicknames(),
+                true,
+                true,
+                false
+            },
+            new Object[] {
+                provideSimpleFieldDefinitions(),
+                provideSimpleFieldDefinitions(),
                 provideCronConstraintSetWithOneConstraint(),
                 provideCronConstraintSetWithTwoConstraints(),
                 provideCronNicknameSetWithTwoNicknames(),
@@ -170,6 +197,8 @@ public class CronDefinitionTest {
                 false
             },
             new Object[] {
+                provideSimpleFieldDefinitions(),
+                provideSimpleFieldDefinitions(),
                 provideCronConstraintSetWithTwoConstraints(),
                 provideCronConstraintSetWithTwoConstraints(),
                 provideCronNicknameSetWithOneNickname(),
@@ -179,6 +208,8 @@ public class CronDefinitionTest {
                 false
             },
             new Object[] {
+                provideSimpleFieldDefinitions(),
+                provideSimpleFieldDefinitions(),
                 provideCronConstraintSetWithTwoConstraints(),
                 provideCronConstraintSetWithTwoConstraints(),
                 provideCronNicknameSetWithTwoNicknames(),
@@ -188,6 +219,8 @@ public class CronDefinitionTest {
                 false
             },
             new Object[] {
+                provideSimpleFieldDefinitions(),
+                provideSimpleFieldDefinitions(),
                 provideCronConstraintSetWithTwoConstraints(),
                 provideCronConstraintSetWithOneConstraint(),
                 provideCronNicknameSetWithTwoNicknames(),
@@ -199,6 +232,18 @@ public class CronDefinitionTest {
         };
     }
 
+    private List<FieldDefinition> provideFieldDefinitions(CronFieldName cronFieldName, UnaryOperator<FieldConstraintsBuilder> configurator) {
+        List<FieldDefinition> defs = new ArrayList<>();
+        defs.add(new FieldDefinition(cronFieldName, configurator.apply(
+                FieldConstraintsBuilder.instance().forField(cronFieldName)).createConstraintsInstance()));
+
+        return defs;
+    }
+
+    private List<FieldDefinition> provideSimpleFieldDefinitions() {
+        return provideFieldDefinitions(CronFieldName.SECOND, b -> b);
+    }
+
     private Set<CronNicknames> provideCronNicknameSetWithTwoNicknames() {
         Set<CronNicknames> constraints = provideCronNicknameSetWithOneNickname();
         constraints.add(CronNicknames.DAILY);