Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#881 equals and hashCode for CollectionEnvelope #894

Merged
merged 5 commits into from
Jun 4, 2018
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 49 additions & 5 deletions src/main/java/org/cactoos/collection/CollectionEnvelope.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@
import java.util.Iterator;
import org.cactoos.Scalar;
import org.cactoos.iterator.Immutable;
import org.cactoos.scalar.And;
import org.cactoos.scalar.Folded;
import org.cactoos.scalar.InheritanceLevel;
import org.cactoos.scalar.Or;
import org.cactoos.scalar.SumOfIntScalar;
import org.cactoos.scalar.UncheckedScalar;

/**
* Base collection.
*
* <p>There is no thread-safety guarantee.</p>
*
* @param <X> Element type
* @since 0.23
* @todo #844:30min Implement methods equals and hashCode for this class.
* Implementation should rely on the items of the nested collection, but not
* on default JVM impl. Class {@link org.cactoos.map.MapEnvelope} can be used
* as an example.
* @checkstyle AbstractClassNameCheck (500 lines)
*/
@SuppressWarnings(
Expand Down Expand Up @@ -147,4 +147,48 @@ public String toString() {
return this.col.value().toString();
}

@Override
public final boolean equals(final Object other) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vatavuk this equals is missing the null-check

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@llorllale fixed in d4538f8

return new UncheckedScalar<>(
new And(
new Or(
() -> new InheritanceLevel(
other.getClass(), Collection.class
).value() > -1,
() -> new InheritanceLevel(
other.getClass(), CollectionEnvelope.class
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vatavuk I believe this isn't necessary because CollectionEnvelope is a Collection already

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@llorllale InheritanceLevel measures inheritance distance between base and derived class. It cannot determine wether a class is instance of Collection.
I'we removed first condition comparing (other.getClass(), Collection.class) because it always evaluates to false.

Copy link
Contributor Author

@Vatavuk Vatavuk May 29, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@llorllale the end result is that we will only compare classes that are related to CollectionEnvelope

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Vatavuk We should be comparing Collections here, not CollectionEnvelopes.

I think I understand the problem now: InheritanceLevel does not check if a class implements an interface (maybe it shouldn't).

We're missing tests that compare CollectionEnvelope against regular JDK Collections. I believe they will fail with the current implementation. So we either need to a) add an instanceof (against our principles) or b) build a new type that checks if a class implements/extends an interface, or c) modify InheritanceLevel to take into account (b).

Please leave a puzzle for this and we'll merge.

).value() > -1
),
() -> {
final Collection<?> compared = (Collection<?>) other;
return this.size() == compared.size();
},
() -> {
final Iterable<?> compared = (Iterable<?>) other;
final Iterator<?> iterator = compared.iterator();
return new UncheckedScalar<>(
new And(
(X input) -> input.equals(iterator.next()),
this
)
).value();
}
)
).value();
}

// @checkstyle MagicNumberCheck (30 lines)
@Override
public final int hashCode() {
return new UncheckedScalar<>(
new Folded<>(
42,
(hash, entry) -> new SumOfIntScalar(
() -> 37 * hash,
entry::hashCode
).value(),
this
)
).value();
}
}
10 changes: 0 additions & 10 deletions src/main/java/org/cactoos/list/ListEnvelope.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,6 @@ public final List<T> subList(final int start, final int end) {
return this.list.value().subList(start, end);
}

@Override
public boolean equals(final Object obj) {
return this.list.value().equals(obj);
}

@Override
public int hashCode() {
return this.list.value().hashCode();
}

@Override
public String toString() {
return this.list.value().toString();
Expand Down
100 changes: 100 additions & 0 deletions src/test/java/org/cactoos/collection/CollectionEnvelopeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.cactoos.list.ListOf;
import org.hamcrest.MatcherAssert;
import org.hamcrest.core.IsEqual;
import org.hamcrest.core.IsNot;
import org.junit.Test;

/**
Expand All @@ -37,6 +41,7 @@
* Iterator for IterableEnvelope `iterator()` method.
* @checkstyle JavadocMethodCheck (500 lines)
*/
@SuppressWarnings("PMD.AvoidDuplicateLiterals")
public final class CollectionEnvelopeTest {
@Test(expected = UnsupportedOperationException.class)
public void returnsIteratorWithUnsupportedRemove() {
Expand All @@ -51,4 +56,99 @@ public void returnsIteratorWithUnsupportedRemove() {
iterator.next();
iterator.remove();
}

@Test
public void notEqualToObjectOfAnotherType() {
MatcherAssert.assertThat(
"Collection is equal to object of different type",
new CollectionOf<>(),
new IsNot<>(new IsEqual<>("a"))
);
}

@Test
public void notEqualToCollectionOfDifferentSize() {
MatcherAssert.assertThat(
"Collection is equal to a collection of different size",
new CollectionOf<>(),
new IsNot<>(new IsEqual<>(new CollectionOf<>("b")))
);
}

@Test
public void notEqualToCollectionOfDifferentElements() {
MatcherAssert.assertThat(
"Collection is equal to a collection with different content",
new CollectionOf<>("a", "b"),
new IsNot<>(new IsEqual<>(new CollectionOf<>("a", "c")))
);
}

@Test
public void equalToCollectionWithIdenticalContent() {
MatcherAssert.assertThat(
"Collection is not equal to a collection with identical content",
new CollectionOf<>("val1", "val2"),
new IsEqual<>(new CollectionOf<>("val1", "val2"))
);
}

@Test
public void equalToListWithIdenticalContent() {
MatcherAssert.assertThat(
"Collection not equal to a list with identical content",
new CollectionOf<>("a"),
new IsEqual<>(new ListOf<>("a"))
);
}

@Test
public void equalToDerivedCollection() {
MatcherAssert.assertThat(
"Collection not equal to derived collection with identical content",
new CollectionOf<>("a"),
new IsEqual<>(new CollectionEnvelopeTest.CustomCollection("a"))
);
}

@Test
public void equalToEmptyCollection() {
MatcherAssert.assertThat(
"Empty collection not equal with empty collection",
new CollectionOf<>(),
new IsEqual<>(new CollectionOf<>())
);
}

@Test
public void hashCodeEqual() {
MatcherAssert.assertThat(
"HashCode returns different results for same entries",
new CollectionOf<>("a", "b").hashCode(),
new IsEqual<>(new CollectionOf<>("a", "b").hashCode())
);
}

@Test
public void differentHashCode() {
MatcherAssert.assertThat(
"HashCode returns identical results for different entries",
new CollectionOf<>("a", "b").hashCode(),
new IsNot<>(new IsEqual<>(new CollectionOf<>("b", "a").hashCode()))
);
}

/**
* Custom collection.
*/
private static class CustomCollection extends CollectionEnvelope<String> {

/**
* Ctor.
* @param elements String elements
*/
CustomCollection(final String... elements) {
super(() -> new CollectionOf<>(elements));
}
}
}