From 7505a3dcb1f03dc73e88bbbc288b4375a3170de8 Mon Sep 17 00:00:00 2001 From: Sebastian Reddig Date: Fri, 30 Aug 2024 19:46:36 +0200 Subject: [PATCH] Fix: Correct contract of equals and hashCode of HODateTime --- src/main/java/core/util/HODateTime.java | 20 +++++- src/test/java/core/util/HODateTimeTest.java | 75 ++++++++++++++++++++- 2 files changed, 93 insertions(+), 2 deletions(-) diff --git a/src/main/java/core/util/HODateTime.java b/src/main/java/core/util/HODateTime.java index 8364e51ab..a4950ce8e 100644 --- a/src/main/java/core/util/HODateTime.java +++ b/src/main/java/core/util/HODateTime.java @@ -218,7 +218,25 @@ public int compareTo(@NotNull HODateTime o) { return instant.compareTo(o.instant); } - public boolean equals(HODateTime t){ return this.instant.equals(t.instant);} + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o instanceof HODateTime that) { + return that.canEqual(this) && instant.equals(that.instant); + } + return false; + } + + @Override + public int hashCode() { + return instant.hashCode(); + } + + protected boolean canEqual(Object o) { + return o instanceof HODateTime; + } public HODateTime minus(int i, ChronoUnit unit) { return new HODateTime(instant.minus(i, unit)); diff --git a/src/test/java/core/util/HODateTimeTest.java b/src/test/java/core/util/HODateTimeTest.java index 575cb4a0f..07bb15622 100644 --- a/src/test/java/core/util/HODateTimeTest.java +++ b/src/test/java/core/util/HODateTimeTest.java @@ -13,15 +13,22 @@ import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.temporal.ChronoUnit; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; import static java.math.BigDecimal.ONE; import static java.math.BigDecimal.ZERO; -import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.assertj.core.data.Offset.offset; import static org.junit.jupiter.params.provider.Arguments.of; class HODateTimeTest { + private static final HODateTime HO_DATE_TIME = HODateTime.fromHT("2024-01-01 00:00:00"); + @Test void test() { var nextTraining = HODateTime.fromHT("2022-03-31 08:30:00"); @@ -74,6 +81,72 @@ void test() { } + static Stream equals() { + return Stream.of( + Arguments.of(HODateTime.fromHT("2024-10-30 20:00:00"), HODateTime.fromHT("2025-10-30 20:00:00"), false), + Arguments.of(HODateTime.fromHT("2024-10-30 20:00:00"), HODateTime.fromHT("2024-11-30 20:00:00"), false), + Arguments.of(HODateTime.fromHT("2024-10-30 20:00:00"), HODateTime.fromHT("2024-10-31 20:00:00"), false), + Arguments.of(HODateTime.fromHT("2024-10-30 20:00:00"), HODateTime.fromHT("2024-10-30 21:00:00"), false), + Arguments.of(HODateTime.fromHT("2024-10-30 20:00:00"), HODateTime.fromHT("2024-10-30 20:01:00"), false), + Arguments.of(HODateTime.fromHT("2024-10-30 20:00:00"), HODateTime.fromHT("2024-10-30 20:00:01"), false), + Arguments.of(HO_DATE_TIME, HO_DATE_TIME, true), + Arguments.of(HODateTime.fromHT("2024-10-30 20:00:00"), HODateTime.fromHT("2024-10-30 20:00:00"), true), + Arguments.of(HO_DATE_TIME, null, false) + ); + } + + @ParameterizedTest + @MethodSource + void equals(HODateTime lhs, HODateTime rhs, boolean result) { + assertThat(lhs.equals(rhs)).isEqualTo(result); + } + + + @Test + void testHashCode_consistencyOnTwoCalls() { + // given + final var now = HODateTime.now(); + + // when + final var hashCode1 = now.hashCode(); + final var hashCode2 = now.hashCode(); + + // then + assertThat(hashCode1).isEqualTo(hashCode2); + } + + @Test + void testHashCode_twoEqualObjectsResultsEqualHashCodes() { + // given + final var htTimeString = "2024-12-31 23:59:59"; + final var hoDateTime1 = HODateTime.fromHT(htTimeString); + final var hoDateTime2 = HODateTime.fromHT(htTimeString); + + // when + final var hashCode1 = hoDateTime1.hashCode(); + final var hashCode2 = hoDateTime2.hashCode(); + + // then + assertThat(hashCode1).isEqualTo(hashCode2); + } + + @Test + void testHashCode_givenMultipleObjects_whenTestingHashCodeDistribution_thenEvenDistributionOfHashCodes() { + // given + final var localDateTime = LocalDateTime.now(); + final var objects = IntStream.range(0, 1000).mapToObj(i -> generate(i, localDateTime)).toList(); + + // when + final Set hashCodes = objects.stream().map(Objects::hashCode).collect(Collectors.toSet()); + + // then + assertThat(hashCodes.size()).isCloseTo( objects.size(), offset(10)); + } + + private static HODateTime generate(int i, LocalDateTime localDateTime) { + return fromLocalDateTime(localDateTime.plusDays(i)); + } + @Test void daysFromNow_future() { // given