Skip to content

Commit

Permalink
Merge branch '__rultor'
Browse files Browse the repository at this point in the history
  • Loading branch information
rultor committed Nov 12, 2019
2 parents d7e54b3 + 8e52754 commit b9a9bee
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 47 deletions.
5 changes: 5 additions & 0 deletions src/main/java/org/cactoos/collection/Immutable.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
* @todo #898:30min Replace all the Collections.unmodifiableCollection
* with the {@link org.cactoos.collection.Immutable} from the cactoos codebase.
* That should be done because Elegant Object principles are against static methods.
* @todo #1224:30min Original collection should be copied inside this
* immutable decorator. That should be done because otherwise true immutability
* cannot be achieved.
* see: https://github.com/yegor256/cactoos/issues/1224 and
* https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html
*/
@SuppressWarnings(
{
Expand Down
96 changes: 88 additions & 8 deletions src/main/java/org/cactoos/list/Immutable.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,21 @@
*/
package org.cactoos.list;

import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.cactoos.Scalar;
import org.cactoos.collection.CollectionOf;
import org.cactoos.scalar.And;
import org.cactoos.scalar.Folded;
import org.cactoos.scalar.Or;
import org.cactoos.scalar.SumOfInt;
import org.cactoos.scalar.Unchecked;
import org.cactoos.text.TextOf;
import org.cactoos.text.UncheckedText;

/**
* {@link List} envelope that doesn't allow mutations.
Expand All @@ -35,6 +46,7 @@
*
* @param <T> Element type
* @since 1.16
* @checkstyle ClassDataAbstractionCouplingCheck (500 lines)
* @todo #898:30min Replace all the Collections.unmodifiableList
* with the {@link org.cactoos.list.Immutable} from the cactoos codebase.
* That should be done because Elegant Object principles are against static methods.
Expand All @@ -55,10 +67,47 @@ public final class Immutable<T> implements List<T> {

/**
* Ctor.
* @param src Source
* @param items Source array
*/
@SafeVarargs
public Immutable(final T... items) {
this(new CollectionOf<T>(items));
}

/**
* Ctor.
* @param src Source list
*/
public Immutable(final List<T> src) {
this.list = src;
this(new CollectionOf<>(src));
}

/**
* Ctor.
* @param src Source iterable
*/
public Immutable(final Iterable<T> src) {
this(new CollectionOf<T>(src));
}

/**
* Ctor.
* @param src Source collection
*/
public Immutable(final Collection<T> src) {
this(() -> {
final List<T> copy = new ArrayList<>(src.size());
copy.addAll(src);
return copy;
});
}

/**
* Ctor.
* @param slr The scalar
*/
public Immutable(final Scalar<List<T>> slr) {
this.list = new Unchecked<>(slr).value();
}

@Override
Expand Down Expand Up @@ -198,21 +247,52 @@ public ListIterator<T> listIterator(final int index) {

@Override
public List<T> subList(final int start, final int end) {
return this.list.subList(start, end);
return new Immutable<>(
this.list.subList(start, end)
);
}

@Override
public String toString() {
return this.list.toString();
@SuppressFBWarnings("EQ_UNUSUAL")
public boolean equals(final Object other) {
return new Unchecked<>(
new Or(
() -> other == this,
new And(
() -> other != null,
() -> List.class.isAssignableFrom(other.getClass()),
() -> {
final List<?> compared = (List<?>) other;
final Iterator<?> iterator = compared.iterator();
return new Unchecked<>(
new And(
(T input) -> input.equals(iterator.next()),
this
)
).value();
}
)
)
).value();
}

// @checkstyle MagicNumberCheck (30 lines)
@Override
public int hashCode() {
return this.list.hashCode();
return new Unchecked<>(
new Folded<>(
42,
(hash, entry) -> new SumOfInt(
() -> 37 * hash,
entry::hashCode
).value(),
this
)
).value();
}

@Override
public boolean equals(final Object obj) {
return this.list.equals(obj);
public String toString() {
return new UncheckedText(new TextOf(this)).asString();
}
}
99 changes: 79 additions & 20 deletions src/test/java/org/cactoos/list/ImmutableTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@
*/
package org.cactoos.list;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.cactoos.collection.CollectionOf;
import org.hamcrest.core.IsEqual;
import org.hamcrest.core.IsNot;
import org.junit.Test;
import org.llorllale.cactoos.matchers.Assertion;
import org.llorllale.cactoos.matchers.HasValues;
Expand All @@ -38,9 +42,22 @@
* @checkstyle MagicNumberCheck (500 lines)
* @checkstyle ClassDataAbstractionCouplingCheck (500 lines)
*/
@SuppressWarnings("PMD.TooManyMethods")
@SuppressWarnings({"PMD.TooManyMethods", "PMD.AvoidDuplicateLiterals"})
public class ImmutableTest {

@Test
public void innerListMustNotBeChanged() {
final List<String> strings = new ArrayList<>(Arrays.asList("a", "b", "c"));
final List<String> immutable = new Immutable<>(strings);
final int original = immutable.size();
strings.add("d");
new Assertion<>(
"inner list must not be changed",
original,
new IsEqual<>(immutable.size())
).affirm();
}

@Test
public void size() {
new Assertion<>(
Expand Down Expand Up @@ -373,42 +390,84 @@ public void subList() {
}

@Test
public void testToString() {
public void immutableSubList() {
new Assertion<>(
"toString() must be equals to original",
new Immutable<>(
"subList() result must be immutable",
() -> new Immutable<>(
new ListOf<>("a", "b", "c")
).toString(),
new IsEqual<>(
new ListOf<>("a", "b", "c").toString()
).subList(0, 2).add("d"),
new Throws<>(
new MatcherOf<>(
(String msg) -> msg.equals("#add(T): the list is read-only")
),
UnsupportedOperationException.class
)
).affirm();
}

@Test
public void notEqualsToObjectOfAnotherType() {
new Assertion<>(
"must not equal to object of another type",
new Immutable<>(),
new IsNot<>(new IsEqual<>(new Object()))
).affirm();
}

@Test
public void notEqualsToListWithDifferentElements() {
new Assertion<>(
"must not equal to List with different elements",
new Immutable<>(1, 2),
new IsNot<>(new IsEqual<>(new ListOf<>(1, 0)))
).affirm();
}

@Test
public void isEqualToItself() {
final List<Integer> list = new Immutable<>(1, 2);
new Assertion<>(
"must be equal to itself",
list,
new IsEqual<>(list)
).affirm();
}

@Test
public void isEqualToListWithTheSameElements() {
new Assertion<>(
"must be equal to List with the same elements",
new Immutable<>(1, 2),
new IsEqual<>(new ListOf<>(1, 2))
).affirm();
}

@Test
public void equalToEmptyImmutable() {
new Assertion<>(
"empty Immutable must be equal to empty Immutable",
new Immutable<>(),
new IsEqual<>(new Immutable<>())
).affirm();
}

@Test
public void testHashCode() {
new Assertion<>(
"hashCode() must be equals to original",
new Immutable<>(
new ListOf<>(1, 2, 3)
).hashCode(),
"hashCode() must be equal to hashCode of the corresponding List",
new Immutable<>(1, 2, 3).hashCode(),
new IsEqual<>(
new ListOf<>(1, 2, 3).hashCode()
)
).affirm();
}

@Test
public void testEquals() {
final ListOf<Integer> another = new ListOf<>(4, 5, 6);
public void testToString() {
new Assertion<>(
"equals() must be equals to original",
new Immutable<>(
new ListOf<>(1, 2, 3)
).equals(another),
new IsEqual<>(
new ListOf<>(1, 2, 3).equals(another)
)
"toString() must be concatenation of nested elements",
new Immutable<>("a", "b", "c").toString(),
new IsEqual<>("a, b, c")
).affirm();
}
}
47 changes: 28 additions & 19 deletions src/test/java/org/cactoos/list/ListEnvelopeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,14 @@
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.hamcrest.core.IsEqual;
import org.junit.Test;
import org.llorllale.cactoos.matchers.Assertion;
import org.llorllale.cactoos.matchers.MatcherOf;
import org.llorllale.cactoos.matchers.Throws;

/**
* Test case for {@link ListEnvelope}.
Expand All @@ -41,6 +42,7 @@
* @checkstyle JavadocMethodCheck (500 lines)
* @checkstyle JavadocTypeCheck (500 lines)
* @checkstyle MagicNumberCheck (500 lines)
* @checkstyle ClassDataAbstractionCouplingCheck (500 lines)
* @todo #898:30min Get rid of the Immutable in StringList nested class
* That's because this test should check the original behavior of ListEnvelope
* Now this test checks behavior of the Immutable decorator
Expand Down Expand Up @@ -91,19 +93,25 @@ public void subListReturnsListIteratorWithUnsupportedRemove() {

@Test()
public void subListReturnsListIteratorWithSupportedSet() {
final ListIterator<String> iterator = new StringList("one", "two", "three")
.subList(0, 2)
.listIterator(0);
iterator.next();
iterator.set("zero");
iterator.previous();
MatcherAssert.assertThat(
"iterator is not equal to expected",
() -> iterator,
Matchers.contains(
"zero", "two"
new Assertion<>(
"subList.listIterator().set() must throw exception",
() -> {
final ListIterator<String> iterator = new StringList("one", "two", "three")
.subList(0, 2)
.listIterator(0);
iterator.next();
iterator.set("zero");
return new Object();
},
new Throws<>(
new MatcherOf<>(
(String msg) -> msg.equals(
"List Iterator is read-only and doesn't allow rewriting items"
)
),
UnsupportedOperationException.class
)
);
).affirm();
}

@Test(expected = UnsupportedOperationException.class)
Expand Down Expand Up @@ -141,13 +149,14 @@ public void returnsSubListWithUnsupportedRemove() {

@Test()
public void returnsSubListWithSupportedSet() {
final List<String> sublist = new StringList("one").subList(0, 1);
sublist.set(0, "zero");
new Assertion<>(
"subList must be equal to expected",
sublist,
new IsEqual<>(
new ListOf<>("zero")
"subList.set() must throw exception",
() -> new StringList("one").subList(0, 1).set(0, "zero"),
new Throws<>(
new MatcherOf<>(
(String msg) -> msg.equals("#set(): the list is read-only")
),
UnsupportedOperationException.class
)
).affirm();
}
Expand Down

1 comment on commit b9a9bee

@0pdd
Copy link
Collaborator

@0pdd 0pdd commented on b9a9bee Nov 12, 2019

Choose a reason for hiding this comment

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

Puzzle 1224-6c7b441d discovered in src/main/java/org/cactoos/collection/Immutable.java and submitted as #1236. Please, remember that the puzzle was not necessarily added in this particular commit. Maybe it was added earlier, but we discovered it only now.

Please sign in to comment.