/* * Copyright 2015 Goldman Sachs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.gs.collections.impl.list.immutable; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.NoSuchElementException; import com.gs.collections.api.RichIterable; import com.gs.collections.api.block.function.Function; import com.gs.collections.api.collection.ImmutableCollection; import com.gs.collections.api.collection.MutableCollection; import com.gs.collections.api.collection.primitive.ImmutableBooleanCollection; import com.gs.collections.api.list.ImmutableList; import com.gs.collections.api.list.MutableList; import com.gs.collections.api.map.MutableMap; import com.gs.collections.api.multimap.Multimap; import com.gs.collections.api.multimap.MutableMultimap; import com.gs.collections.api.multimap.list.ImmutableListMultimap; import com.gs.collections.api.partition.list.PartitionImmutableList; import com.gs.collections.api.stack.MutableStack; import com.gs.collections.api.tuple.Pair; import com.gs.collections.impl.block.factory.Functions; import com.gs.collections.impl.block.factory.HashingStrategies; import com.gs.collections.impl.block.factory.IntegerPredicates; import com.gs.collections.impl.block.factory.ObjectIntProcedures; import com.gs.collections.impl.block.factory.Predicates; import com.gs.collections.impl.block.factory.Predicates2; import com.gs.collections.impl.block.factory.PrimitiveFunctions; import com.gs.collections.impl.block.factory.Procedures; import com.gs.collections.impl.block.function.NegativeIntervalFunction; import com.gs.collections.impl.block.procedure.CollectionAddProcedure; import com.gs.collections.impl.collection.immutable.AbstractImmutableCollectionTestCase; import com.gs.collections.impl.factory.Lists; import com.gs.collections.impl.list.Interval; import com.gs.collections.impl.list.mutable.FastList; import com.gs.collections.impl.multimap.list.FastListMultimap; import com.gs.collections.impl.set.mutable.UnifiedSet; import com.gs.collections.impl.test.Verify; import com.gs.collections.impl.utility.Iterate; import com.gs.collections.impl.utility.ListIterate; import org.junit.Assert; import org.junit.Test; import static com.gs.collections.impl.factory.Iterables.iList; public abstract class AbstractImmutableListTestCase extends AbstractImmutableCollectionTestCase { @Override protected abstract ImmutableList<Integer> classUnderTest(); @Override protected <T> MutableList<T> newMutable() { return FastList.newList(); } @Test public void equalsAndHashCode() { ImmutableList<Integer> immutable = this.classUnderTest(); MutableList<Integer> mutable1 = FastList.newList(immutable); ImmutableList<Integer> immutable1 = mutable1.toImmutable(); List<Integer> mutable2 = new LinkedList<>(mutable1); List<Integer> mutable3 = new ArrayList<>(mutable1); Verify.assertEqualsAndHashCode(mutable1, immutable); Verify.assertEqualsAndHashCode(immutable1, immutable); Verify.assertEqualsAndHashCode(mutable2, immutable); Verify.assertEqualsAndHashCode(mutable3, immutable); Verify.assertPostSerializedEqualsAndHashCode(immutable); Assert.assertNotEquals(immutable, UnifiedSet.newSet(mutable1)); mutable1.add(null); mutable2.add(null); mutable3.add(null); Assert.assertNotEquals(mutable1, immutable); Assert.assertNotEquals(mutable2, immutable); Assert.assertNotEquals(mutable3, immutable); mutable1.remove(null); mutable2.remove(null); mutable3.remove(null); Verify.assertEqualsAndHashCode(mutable1, immutable); Verify.assertEqualsAndHashCode(mutable2, immutable); Verify.assertEqualsAndHashCode(mutable3, immutable); if (immutable.size() > 2) { mutable1.set(2, null); mutable2.set(2, null); mutable3.set(2, null); Assert.assertNotEquals(mutable1, immutable); Assert.assertNotEquals(mutable2, immutable); Assert.assertNotEquals(mutable3, immutable); mutable1.remove(2); mutable2.remove(2); mutable3.remove(2); Assert.assertNotEquals(mutable1, immutable); Assert.assertNotEquals(mutable2, immutable); Assert.assertNotEquals(mutable3, immutable); } } @Test public void contains() { ImmutableList<Integer> list = this.classUnderTest(); for (int i = 1; i <= list.size(); i++) { Assert.assertTrue(list.contains(i)); } Assert.assertFalse(list.contains(list.size() + 1)); } @Test public void containsAll() { Assert.assertTrue(this.classUnderTest().containsAll(this.classUnderTest().toList())); } @Test public void containsAllArray() { Assert.assertTrue(this.classUnderTest().containsAllArguments(this.classUnderTest().toArray())); } @Test public void containsAllIterable() { Assert.assertTrue(this.classUnderTest().containsAllIterable(this.classUnderTest())); } @Test public void indexOf() { Assert.assertEquals(0, this.classUnderTest().indexOf(1)); Assert.assertEquals(-1, this.classUnderTest().indexOf(null)); ImmutableList<Integer> immutableList = this.classUnderTest().newWith(null); Assert.assertEquals(immutableList.size() - 1, immutableList.indexOf(null)); Assert.assertEquals(-1, this.classUnderTest().indexOf(Integer.MAX_VALUE)); } @Test public void lastIndexOf() { Assert.assertEquals(0, this.classUnderTest().lastIndexOf(1)); Assert.assertEquals(-1, this.classUnderTest().lastIndexOf(null)); Assert.assertEquals(-1, this.classUnderTest().lastIndexOf(null)); ImmutableList<Integer> immutableList = this.classUnderTest().newWith(null); Assert.assertEquals(immutableList.size() - 1, immutableList.lastIndexOf(null)); Assert.assertEquals(-1, this.classUnderTest().lastIndexOf(Integer.MAX_VALUE)); } @Test public void get() { ImmutableList<Integer> list = this.classUnderTest(); Verify.assertThrows(IndexOutOfBoundsException.class, () -> list.get(list.size() + 1)); Verify.assertThrows(IndexOutOfBoundsException.class, () -> list.get(-1)); } @Test public void forEach() { MutableList<Integer> result = Lists.mutable.of(); ImmutableList<Integer> collection = this.classUnderTest(); collection.forEach(CollectionAddProcedure.on(result)); Assert.assertEquals(collection, result); } @Test public void each() { MutableList<Integer> result = Lists.mutable.of(); ImmutableList<Integer> collection = this.classUnderTest(); collection.each(result::add); Assert.assertEquals(collection, result); } @Test public void reverseForEach() { MutableList<Integer> result = Lists.mutable.of(); ImmutableList<Integer> list = this.classUnderTest(); list.reverseForEach(result::add); Assert.assertEquals(ListIterate.reverseThis(FastList.newList(list)), result); } @Test public void corresponds() { ImmutableList<Integer> integers1 = this.classUnderTest(); ImmutableList<Integer> integers2 = this.classUnderTest().newWith(Integer.valueOf(1)); Assert.assertFalse(integers1.corresponds(integers2, Predicates2.alwaysTrue())); ImmutableList<Integer> integers3 = integers1.collect(integer -> integer + 1); Assert.assertTrue(integers1.corresponds(integers3, Predicates2.lessThan())); Assert.assertFalse(integers1.corresponds(integers3, Predicates2.greaterThan())); } @Test public void forEachFromTo() { MutableList<Integer> result = Lists.mutable.of(); MutableList<Integer> reverseResult = Lists.mutable.of(); ImmutableList<Integer> list = this.classUnderTest(); list.forEach(0, list.size() - 1, result::add); Assert.assertEquals(list, result); list.forEach(list.size() - 1, 0, reverseResult::add); Assert.assertEquals(ListIterate.reverseThis(FastList.newList(list)), reverseResult); Verify.assertThrows(IndexOutOfBoundsException.class, () -> list.forEach(-1, 0, result::add)); Verify.assertThrows(IndexOutOfBoundsException.class, () -> list.forEach(0, -1, result::add)); } @Test public void forEachWithIndexFromTo() { MutableList<Integer> result = Lists.mutable.of(); MutableList<Integer> reverseResult = Lists.mutable.of(); ImmutableList<Integer> list = this.classUnderTest(); list.forEachWithIndex(0, list.size() - 1, ObjectIntProcedures.fromProcedure(result::add)); Assert.assertEquals(list, result); list.forEachWithIndex(list.size() - 1, 0, ObjectIntProcedures.fromProcedure(reverseResult::add)); Assert.assertEquals(ListIterate.reverseThis(FastList.newList(list)), reverseResult); Verify.assertThrows(IndexOutOfBoundsException.class, () -> list.forEachWithIndex(-1, 0, result::add)); Verify.assertThrows(IndexOutOfBoundsException.class, () -> list.forEachWithIndex(0, -1, result::add)); } @Test public void forEachWith() { MutableCollection<Integer> result = Lists.mutable.of(); this.classUnderTest().forEachWith((argument1, argument2) -> result.add(argument1 + argument2), 0); Assert.assertEquals(this.classUnderTest(), result); } @Test public void forEachWithIndex() { ImmutableList<Integer> list = this.classUnderTest(); MutableList<Integer> result = Lists.mutable.of(); list.forEachWithIndex((object, index) -> result.add(object + index)); result.forEachWithIndex((object, index) -> Assert.assertEquals(object, result.set(index, object - index))); Assert.assertEquals(list, result); } @Test public void detectIndex() { Assert.assertEquals(0, this.classUnderTest().detectIndex(integer -> integer == 1)); Assert.assertEquals(-1, this.classUnderTest().detectIndex(integer -> integer == 0)); } @Test public void detectLastIndex() { Assert.assertEquals(0, this.classUnderTest().detectLastIndex(integer -> integer == 1)); Assert.assertEquals(-1, this.classUnderTest().detectLastIndex(integer -> integer == 0)); } @Test public void select_target() { ImmutableCollection<Integer> integers = this.classUnderTest(); Assert.assertEquals(integers, integers.select(Predicates.lessThan(integers.size() + 1), FastList.<Integer>newList())); Verify.assertEmpty(integers.select(Predicates.greaterThan(integers.size()), FastList.<Integer>newList())); } @Test public void reject_target() { ImmutableCollection<Integer> integers = this.classUnderTest(); Verify.assertEmpty(integers.reject(Predicates.lessThan(integers.size() + 1), FastList.<Integer>newList())); Assert.assertEquals(integers, integers.reject(Predicates.greaterThan(integers.size()), FastList.<Integer>newList())); } @Test public void flatCollectWithTarget() { MutableCollection<String> actual = this.classUnderTest().flatCollect(integer -> Lists.fixedSize.of(String.valueOf(integer)), FastList.<String>newList()); ImmutableCollection<String> expected = this.classUnderTest().collect(String::valueOf); Assert.assertEquals(expected, actual); } @Test public void distinct() { ImmutableList<Integer> integers = this.classUnderTest(); Assert.assertEquals(integers, integers.newWith(1).distinct()); Assert.assertEquals(this.classUnderTest(), this.classUnderTest().distinct()); } @Test public void distinctWithHashingStrategy() { FastList<String> strings = FastList.newListWith("A", "b", "a", "c", "B", "D", "e", "D", "e", "E"); ImmutableList<Integer> integers = this.classUnderTest(); ImmutableList<String> letters = strings.subList(0, integers.size()).toImmutable().distinct(HashingStrategies.fromFunction(String::toLowerCase)); List<String> expectedLetters = strings.subList(0, integers.size()).distinct(HashingStrategies.fromFunction(String::toLowerCase)); Assert.assertEquals(expectedLetters, letters); } @Test public void zip() { ImmutableCollection<Integer> immutableCollection = this.classUnderTest(); List<Object> nulls = Collections.nCopies(immutableCollection.size(), null); List<Object> nullsPlusOne = Collections.nCopies(immutableCollection.size() + 1, null); List<Object> nullsMinusOne = Collections.nCopies(immutableCollection.size() - 1, null); ImmutableCollection<Pair<Integer, Object>> pairs = immutableCollection.zip(nulls); Assert.assertEquals(immutableCollection, pairs.collect((Function<Pair<Integer, ?>, Integer>) Pair::getOne)); Assert.assertEquals(nulls, pairs.collect((Function<Pair<?, Object>, Object>) Pair::getTwo)); ImmutableCollection<Pair<Integer, Object>> pairsPlusOne = immutableCollection.zip(nullsPlusOne); Assert.assertEquals(immutableCollection, pairsPlusOne.collect((Function<Pair<Integer, ?>, Integer>) Pair::getOne)); Assert.assertEquals(nulls, pairsPlusOne.collect((Function<Pair<?, Object>, Object>) Pair::getTwo)); ImmutableCollection<Pair<Integer, Object>> pairsMinusOne = immutableCollection.zip(nullsMinusOne); Assert.assertEquals(immutableCollection.size() - 1, pairsMinusOne.size()); Assert.assertTrue(immutableCollection.containsAllIterable(pairsMinusOne.collect((Function<Pair<Integer, ?>, Integer>) Pair::getOne))); Assert.assertEquals(immutableCollection.zip(nulls), immutableCollection.zip(nulls, FastList.<Pair<Integer, Object>>newList())); } @Test public void zipWithIndex() { ImmutableCollection<Integer> immutableCollection = this.classUnderTest(); ImmutableCollection<Pair<Integer, Integer>> pairs = immutableCollection.zipWithIndex(); Assert.assertEquals(immutableCollection, pairs.collect((Function<Pair<Integer, ?>, Integer>) Pair::getOne)); Assert.assertEquals(Interval.zeroTo(immutableCollection.size() - 1), pairs.collect((Function<Pair<?, Integer>, Integer>) Pair::getTwo)); Assert.assertEquals(immutableCollection.zipWithIndex(), immutableCollection.zipWithIndex(FastList.<Pair<Integer, Integer>>newList())); } @Test public void chunk_large_size() { Assert.assertEquals(this.classUnderTest(), this.classUnderTest().chunk(10).getFirst()); Verify.assertInstanceOf(ImmutableList.class, this.classUnderTest().chunk(10).getFirst()); } @Test public void collectIfWithTarget() { ImmutableCollection<Integer> integers = this.classUnderTest(); Assert.assertEquals(integers, integers.collectIf(Integer.class::isInstance, Functions.getIntegerPassThru(), FastList.<Integer>newList())); } @Test public void toList() { ImmutableCollection<Integer> integers = this.classUnderTest(); MutableList<Integer> list = integers.toList(); Verify.assertEqualsAndHashCode(integers, list); Assert.assertNotSame(integers, list); } @Test public void toSortedListBy() { MutableList<Integer> mutableList = this.classUnderTest().toList(); mutableList.shuffleThis(); ImmutableList<Integer> immutableList = mutableList.toImmutable(); MutableList<Integer> sortedList = immutableList.toSortedListBy(Functions.getIntegerPassThru()); Assert.assertEquals(this.classUnderTest(), sortedList); } @Test public void removeAtIndex() { Verify.assertThrows(UnsupportedOperationException.class, () -> this.classUnderTest().castToList().remove(1)); } @Test public void set() { Verify.assertThrows(UnsupportedOperationException.class, () -> this.classUnderTest().castToList().set(0, 1)); } @Test public void addAtIndex() { Verify.assertThrows(UnsupportedOperationException.class, () -> this.classUnderTest().castToList().add(0, 1)); } @Test public void addAllAtIndex() { Verify.assertThrows(UnsupportedOperationException.class, () -> this.classUnderTest().castToList().addAll(0, Lists.fixedSize.<Integer>of())); } @Test public void subList() { Verify.assertListsEqual(Lists.immutable.of(1).castToList(), this.classUnderTest().castToList().subList(0, 1)); } @Test(expected = IndexOutOfBoundsException.class) public void subListFromNegative() { this.classUnderTest().castToList().subList(-1, 1); } @Test(expected = IllegalArgumentException.class) public void subListFromGreaterThanTO() { this.classUnderTest().castToList().subList(1, 0); } @Test(expected = IndexOutOfBoundsException.class) public void subListToGreaterThanSize() { this.classUnderTest().castToList().subList(0, 100); } @Test public void listIterator() { ListIterator<Integer> it = this.classUnderTest().listIterator(); Assert.assertFalse(it.hasPrevious()); Verify.assertThrows(NoSuchElementException.class, (Runnable) it::previous); Assert.assertEquals(-1, it.previousIndex()); Assert.assertEquals(0, it.nextIndex()); it.next(); Assert.assertEquals(1, it.nextIndex()); Verify.assertThrows(UnsupportedOperationException.class, it::remove); Verify.assertThrows(UnsupportedOperationException.class, () -> it.add(null)); Verify.assertThrows(UnsupportedOperationException.class, () -> it.set(null)); } @Test(expected = IndexOutOfBoundsException.class) public void listIterator_throwsNegative() { this.classUnderTest().listIterator(-1); } @Test(expected = IndexOutOfBoundsException.class) public void listIterator_throwsGreaterThanSize() { this.classUnderTest().listIterator(100); } @Test public void toStack() { MutableStack<Integer> stack = this.classUnderTest().toStack(); Assert.assertEquals(stack.toSortedList().toReversed(), stack.toList()); } @Test public void take() { ImmutableList<Integer> immutableList = this.classUnderTest(); Assert.assertEquals(Lists.immutable.of(), immutableList.take(0)); Assert.assertEquals(iList(1), immutableList.take(1)); Assert.assertEquals(immutableList, immutableList.take(10)); MutableList<Integer> mutableList = Lists.mutable.ofAll(immutableList); Assert.assertEquals( mutableList.take(mutableList.size() - 1), immutableList.take(immutableList.size() - 1)); Assert.assertSame(immutableList, immutableList.take(immutableList.size())); Assert.assertSame(immutableList, immutableList.take(Integer.MAX_VALUE)); } @Test(expected = IllegalArgumentException.class) public void take_throws() { this.classUnderTest().take(-1); } @Test public void takeWhile() { Assert.assertEquals( iList(1), this.classUnderTest().takeWhile(Predicates.lessThan(2))); } @Test public void drop() { ImmutableList<Integer> immutableList = this.classUnderTest(); Assert.assertSame(immutableList, immutableList.drop(0)); MutableList<Integer> mutableList = Lists.mutable.ofAll(immutableList); Assert.assertEquals(mutableList.drop(1), immutableList.drop(1)); if (mutableList.size() > 0) { Assert.assertEquals( mutableList.drop(mutableList.size() - 1), immutableList.drop(immutableList.size() - 1)); } Assert.assertEquals(Lists.immutable.of(), immutableList.drop(10)); Assert.assertEquals(Lists.immutable.of(), immutableList.drop(immutableList.size())); Assert.assertEquals(Lists.immutable.of(), immutableList.drop(Integer.MAX_VALUE)); } @Test(expected = IllegalArgumentException.class) public void drop_throws() { this.classUnderTest().drop(-1); } @Test public void dropWhile() { Assert.assertEquals( this.classUnderTest(), this.classUnderTest().dropWhile(Predicates.lessThan(0))); Assert.assertEquals( Lists.immutable.of(), this.classUnderTest().dropWhile(Predicates.greaterThan(0))); } @Test public void partitionWhile() { PartitionImmutableList<Integer> partitionAll = this.classUnderTest().partitionWhile(Predicates.greaterThan(0)); Assert.assertEquals(this.classUnderTest(), partitionAll.getSelected()); Assert.assertEquals(Lists.immutable.of(), partitionAll.getRejected()); PartitionImmutableList<Integer> partitionNone = this.classUnderTest().partitionWhile(Predicates.lessThan(0)); Assert.assertEquals(Lists.immutable.of(), partitionNone.getSelected()); Assert.assertEquals(this.classUnderTest(), partitionNone.getRejected()); } @Override @Test public void collectBoolean() { ImmutableCollection<Integer> integers = this.classUnderTest(); ImmutableBooleanCollection immutableCollection = integers.collectBoolean(PrimitiveFunctions.integerIsPositive()); Verify.assertSize(integers.size(), immutableCollection); } @Test public void groupBy() { ImmutableList<Integer> list = this.classUnderTest(); ImmutableListMultimap<Boolean, Integer> multimap = list.groupBy(integer -> IntegerPredicates.isOdd().accept(integer)); MutableMap<Boolean, RichIterable<Integer>> actualMap = multimap.toMap(); int halfSize = this.classUnderTest().size() / 2; boolean odd = this.classUnderTest().size() % 2 != 0; Assert.assertEquals(halfSize, Iterate.sizeOf(actualMap.getIfAbsent(false, FastList::new))); Assert.assertEquals(halfSize + (odd ? 1 : 0), Iterate.sizeOf(actualMap.getIfAbsent(true, FastList::new))); } @Test public void groupByEach() { ImmutableList<Integer> list = this.classUnderTest(); MutableMultimap<Integer, Integer> expected = FastListMultimap.newMultimap(); list.forEach(Procedures.cast(value -> expected.putAll(-value, Interval.fromTo(value, list.size())))); Multimap<Integer, Integer> actual = list.groupByEach(new NegativeIntervalFunction()); Assert.assertEquals(expected, actual); Multimap<Integer, Integer> actualWithTarget = list.groupByEach(new NegativeIntervalFunction(), FastListMultimap.<Integer, Integer>newMultimap()); Assert.assertEquals(expected, actualWithTarget); } @Test public void asReversed() { Verify.assertIterablesEqual(this.classUnderTest().toList().toReversed(), this.classUnderTest().asReversed()); } @Test public void toReversed() { ImmutableList<Integer> immutableList = this.classUnderTest(); Assert.assertEquals(immutableList.toReversed().toReversed(), immutableList); if (immutableList.size() <= 1) { Assert.assertSame(immutableList.toReversed(), immutableList); } else { Assert.assertNotEquals(immutableList.toReversed(), immutableList); } } @Test public void toImmutable() { ImmutableList<Integer> integers = this.classUnderTest(); ImmutableList<Integer> actual = integers.toImmutable(); Assert.assertEquals(integers, actual); Assert.assertSame(integers, actual); } }