diff --git a/src/main/java/org/cactoos/collection/CollectionEnvelope.java b/src/main/java/org/cactoos/collection/CollectionEnvelope.java
index f024782ad5..9da842e51d 100644
--- a/src/main/java/org/cactoos/collection/CollectionEnvelope.java
+++ b/src/main/java/org/cactoos/collection/CollectionEnvelope.java
@@ -27,19 +27,23 @@
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.
*
*
There is no thread-safety guarantee.
- *
* @param 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.
+ * 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.
+ * @since 0.23
* @checkstyle AbstractClassNameCheck (500 lines)
*/
@SuppressWarnings(
@@ -147,4 +151,48 @@ public String toString() {
return this.col.value().toString();
}
+ @Override
+ public final boolean equals(final Object other) {
+ return new UncheckedScalar<>(
+ new And(
+ new Or(
+ () -> new InheritanceLevel(
+ other.getClass(), Collection.class
+ ).value() > -1,
+ () -> new InheritanceLevel(
+ other.getClass(), CollectionEnvelope.class
+ ).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();
+ }
}
diff --git a/src/main/java/org/cactoos/list/ListEnvelope.java b/src/main/java/org/cactoos/list/ListEnvelope.java
index 848c08cbcd..3f5391a1d5 100644
--- a/src/main/java/org/cactoos/list/ListEnvelope.java
+++ b/src/main/java/org/cactoos/list/ListEnvelope.java
@@ -113,16 +113,6 @@ public final List 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();
diff --git a/src/test/java/org/cactoos/collection/CollectionEnvelopeTest.java b/src/test/java/org/cactoos/collection/CollectionEnvelopeTest.java
index 58d4f27e74..fa17779ff4 100644
--- a/src/test/java/org/cactoos/collection/CollectionEnvelopeTest.java
+++ b/src/test/java/org/cactoos/collection/CollectionEnvelopeTest.java
@@ -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;
/**
@@ -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() {
@@ -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 {
+
+ /**
+ * Ctor.
+ * @param elements String elements
+ */
+ CustomCollection(final String... elements) {
+ super(() -> new CollectionOf<>(elements));
+ }
+ }
}