Skip to content

Commit 948a6ed

Browse files
authored
Merge pull request #239 from evanofficial/fix/migration-result-equals-hashcode
Add equals/hashCode to MigrationResult
2 parents 2e864da + da9f3cc commit 948a6ed

2 files changed

Lines changed: 120 additions & 2 deletions

File tree

aether-datafixers-spring-boot-starter/src/main/java/de/splatgames/aether/datafixers/spring/service/MigrationResult.java

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.jetbrains.annotations.Nullable;
3030

3131
import java.time.Duration;
32+
import java.util.Objects;
3233
import java.util.Optional;
3334

3435
/**
@@ -120,8 +121,8 @@
120121
* shared between threads without synchronization.</p>
121122
*
122123
* <h2>Equality and Hashing</h2>
123-
* <p>This class does not override {@code equals()} and {@code hashCode()}.
124-
* Each instance is unique and identity-based comparison is used.</p>
124+
* <p>Two {@code MigrationResult} instances are considered equal if they have the same
125+
* success status, source and target versions, domain, and duration.</p>
125126
*
126127
* @author Erik Pförtner
127128
* @see MigrationService
@@ -429,6 +430,46 @@ public int getVersionSpan() {
429430
return Math.abs(this.toVersion.getVersion() - this.fromVersion.getVersion());
430431
}
431432

433+
/**
434+
* Indicates whether some other object is "equal to" this migration result.
435+
*
436+
* <p>Two {@code MigrationResult} instances are considered equal if and only if they
437+
* have the same success status, source version, target version, domain, and duration.</p>
438+
*
439+
* @param obj the reference object with which to compare; may be {@code null}
440+
* @return {@code true} if this result is equal to the specified object; {@code false} otherwise
441+
* @see #hashCode()
442+
*/
443+
@Override
444+
public boolean equals(final Object obj) {
445+
if (this == obj) {
446+
return true;
447+
}
448+
if (!(obj instanceof MigrationResult other)) {
449+
return false;
450+
}
451+
return this.success == other.success
452+
&& Objects.equals(this.fromVersion, other.fromVersion)
453+
&& Objects.equals(this.toVersion, other.toVersion)
454+
&& Objects.equals(this.domain, other.domain)
455+
&& Objects.equals(this.duration, other.duration);
456+
}
457+
458+
/**
459+
* Returns a hash code value for this migration result.
460+
*
461+
* <p>The hash code is computed based on the success status, source version, target version,
462+
* domain, and duration. This implementation satisfies the general contract of
463+
* {@link Object#hashCode()}.</p>
464+
*
465+
* @return a hash code value for this migration result
466+
* @see #equals(Object)
467+
*/
468+
@Override
469+
public int hashCode() {
470+
return Objects.hash(this.success, this.fromVersion, this.toVersion, this.domain, this.duration);
471+
}
472+
432473
/**
433474
* Returns a human-readable string representation of this result.
434475
*

aether-datafixers-spring-boot-starter/src/test/java/de/splatgames/aether/datafixers/spring/service/MigrationResultTest.java

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,83 @@ void getDurationReturnsMigrationDuration() {
237237
}
238238
}
239239

240+
@Nested
241+
@DisplayName("equals and hashCode")
242+
class EqualsAndHashCode {
243+
244+
@Test
245+
@DisplayName("equals() returns true for same values")
246+
void equalsReturnsTrueForSameValues() {
247+
TaggedDynamic data = mock(TaggedDynamic.class);
248+
249+
MigrationResult a = MigrationResult.success(
250+
data, FROM_VERSION, TO_VERSION, DOMAIN, DURATION
251+
);
252+
MigrationResult b = MigrationResult.success(
253+
data, FROM_VERSION, TO_VERSION, DOMAIN, DURATION
254+
);
255+
256+
assertThat(a).isEqualTo(b);
257+
}
258+
259+
@Test
260+
@DisplayName("equals() returns false for different success status")
261+
void equalsReturnsFalseForDifferentSuccess() {
262+
TaggedDynamic data = mock(TaggedDynamic.class);
263+
264+
MigrationResult success = MigrationResult.success(
265+
data, FROM_VERSION, TO_VERSION, DOMAIN, DURATION
266+
);
267+
MigrationResult failure = MigrationResult.failure(
268+
FROM_VERSION, TO_VERSION, DOMAIN, DURATION, new RuntimeException("error")
269+
);
270+
271+
assertThat(success).isNotEqualTo(failure);
272+
}
273+
274+
@Test
275+
@DisplayName("equals() returns false for different versions")
276+
void equalsReturnsFalseForDifferentVersions() {
277+
TaggedDynamic data = mock(TaggedDynamic.class);
278+
279+
MigrationResult a = MigrationResult.success(
280+
data, FROM_VERSION, TO_VERSION, DOMAIN, DURATION
281+
);
282+
MigrationResult b = MigrationResult.success(
283+
data, FROM_VERSION, new DataVersion(300), DOMAIN, DURATION
284+
);
285+
286+
assertThat(a).isNotEqualTo(b);
287+
}
288+
289+
@Test
290+
@DisplayName("hashCode() is consistent for equal objects")
291+
void hashCodeConsistentForEqualObjects() {
292+
TaggedDynamic data = mock(TaggedDynamic.class);
293+
294+
MigrationResult a = MigrationResult.success(
295+
data, FROM_VERSION, TO_VERSION, DOMAIN, DURATION
296+
);
297+
MigrationResult b = MigrationResult.success(
298+
data, FROM_VERSION, TO_VERSION, DOMAIN, DURATION
299+
);
300+
301+
assertThat(a.hashCode()).isEqualTo(b.hashCode());
302+
}
303+
304+
@Test
305+
@DisplayName("equals() returns false for null")
306+
void equalsReturnsFalseForNull() {
307+
TaggedDynamic data = mock(TaggedDynamic.class);
308+
309+
MigrationResult result = MigrationResult.success(
310+
data, FROM_VERSION, TO_VERSION, DOMAIN, DURATION
311+
);
312+
313+
assertThat(result).isNotEqualTo(null);
314+
}
315+
}
316+
240317
@Nested
241318
@DisplayName("toString")
242319
class ToStringMethod {

0 commit comments

Comments
 (0)