/* * 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.stack; import java.util.Collections; import java.util.EmptyStackException; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import com.gs.collections.api.RichIterable; import com.gs.collections.api.bag.sorted.SortedBag; import com.gs.collections.api.block.function.Function; import com.gs.collections.api.block.function.Function0; import com.gs.collections.api.block.function.Function2; import com.gs.collections.api.block.predicate.Predicate; import com.gs.collections.api.block.predicate.Predicate2; import com.gs.collections.api.block.procedure.Procedure; import com.gs.collections.api.list.MutableList; import com.gs.collections.api.map.MapIterable; import com.gs.collections.api.map.MutableMap; import com.gs.collections.api.map.primitive.ObjectDoubleMap; import com.gs.collections.api.map.primitive.ObjectLongMap; import com.gs.collections.api.multimap.Multimap; import com.gs.collections.api.multimap.MutableMultimap; import com.gs.collections.api.multimap.list.ListMultimap; import com.gs.collections.api.partition.stack.PartitionStack; import com.gs.collections.api.set.SetIterable; import com.gs.collections.api.set.sorted.MutableSortedSet; import com.gs.collections.api.stack.StackIterable; import com.gs.collections.api.tuple.Pair; import com.gs.collections.impl.bag.sorted.mutable.TreeBag; import com.gs.collections.impl.block.factory.Comparators; import com.gs.collections.impl.block.factory.Functions; import com.gs.collections.impl.block.factory.IntegerPredicates; 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.AddFunction; import com.gs.collections.impl.block.function.NegativeIntervalFunction; import com.gs.collections.impl.block.function.PassThruFunction0; import com.gs.collections.impl.factory.Bags; import com.gs.collections.impl.factory.Lists; import com.gs.collections.impl.factory.Stacks; import com.gs.collections.impl.list.Interval; import com.gs.collections.impl.list.mutable.FastList; import com.gs.collections.impl.map.mutable.UnifiedMap; import com.gs.collections.impl.map.sorted.mutable.TreeSortedMap; import com.gs.collections.impl.multimap.list.FastListMultimap; import com.gs.collections.impl.set.mutable.UnifiedSet; import com.gs.collections.impl.set.mutable.primitive.BooleanHashSet; import com.gs.collections.impl.set.mutable.primitive.ByteHashSet; import com.gs.collections.impl.set.mutable.primitive.CharHashSet; import com.gs.collections.impl.set.mutable.primitive.DoubleHashSet; import com.gs.collections.impl.set.mutable.primitive.FloatHashSet; import com.gs.collections.impl.set.mutable.primitive.IntHashSet; import com.gs.collections.impl.set.mutable.primitive.LongHashSet; import com.gs.collections.impl.set.mutable.primitive.ShortHashSet; import com.gs.collections.impl.set.sorted.mutable.TreeSortedSet; import com.gs.collections.impl.stack.mutable.ArrayStack; import com.gs.collections.impl.stack.mutable.primitive.BooleanArrayStack; import com.gs.collections.impl.stack.mutable.primitive.ByteArrayStack; import com.gs.collections.impl.stack.mutable.primitive.CharArrayStack; import com.gs.collections.impl.stack.mutable.primitive.DoubleArrayStack; import com.gs.collections.impl.stack.mutable.primitive.FloatArrayStack; import com.gs.collections.impl.stack.mutable.primitive.IntArrayStack; import com.gs.collections.impl.stack.mutable.primitive.LongArrayStack; import com.gs.collections.impl.stack.mutable.primitive.ShortArrayStack; import com.gs.collections.impl.test.Verify; import com.gs.collections.impl.tuple.Tuples; import org.junit.Assert; import org.junit.Test; public abstract class StackIterableTestCase { protected abstract <T> StackIterable<T> newStackWith(T... elements); protected abstract <T> StackIterable<T> newStackFromTopToBottom(T... elements); protected abstract <T> StackIterable<T> newStackFromTopToBottom(Iterable<T> elements); protected abstract <T> StackIterable<T> newStack(Iterable<T> elements); @Test public void testNewStackFromTopToBottom() { Assert.assertEquals( this.newStackWith(3, 2, 1), this.newStackFromTopToBottom(1, 2, 3)); } @Test(expected = EmptyStackException.class) public void peek_empty_throws() { this.newStackWith().peek(); } @Test(expected = EmptyStackException.class) public void peek_int_empty_throws() { this.newStackWith().peek(1); } @Test(expected = IllegalArgumentException.class) public void peek_int_count_throws() { this.newStackWith(1, 2, 3).peek(4); } @Test(expected = IllegalArgumentException.class) public void peek_int_neg_throws() { this.newStackWith(1, 2, 3).peek(-1); } @Test public void peek_illegal_arguments() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); Verify.assertThrows(IllegalArgumentException.class, () -> stack.peek(-1)); Verify.assertThrows(IllegalArgumentException.class, () -> stack.peek(4)); Assert.assertEquals(FastList.newListWith(1, 2, 3), stack.peek(3)); } @Test public void peek() { Assert.assertEquals("3", this.newStackWith("1", "2", "3").peek()); Assert.assertEquals(FastList.newListWith(), this.newStackWith("1", "2", "3").peek(0)); Assert.assertEquals(FastList.newListWith("3", "2"), this.newStackWith("1", "2", "3").peek(2)); } @Test public void peekAt() { Assert.assertEquals("3", this.newStackWith("1", "2", "3").peekAt(0)); Assert.assertEquals("2", this.newStackWith("1", "2", "3").peekAt(1)); Assert.assertEquals("1", this.newStackWith("1", "2", "3").peekAt(2)); } @Test public void peekAt_illegal_arguments() { StackIterable<String> stack = this.newStackWith("1", "2", "3"); Verify.assertThrows(IllegalArgumentException.class, () -> stack.peekAt(stack.size())); } @Test public void size() { StackIterable<Integer> stack1 = this.newStackWith(); Assert.assertEquals(0, stack1.size()); StackIterable<Integer> stack2 = this.newStackWith(1, 2); Assert.assertEquals(2, stack2.size()); } @Test public void isEmpty() { StackIterable<Integer> stack = this.newStackWith(); Assert.assertTrue(stack.isEmpty()); Assert.assertFalse(stack.notEmpty()); } @Test public void notEmpty() { StackIterable<Integer> stack = this.newStackWith(1); Assert.assertTrue(stack.notEmpty()); Assert.assertFalse(stack.isEmpty()); } @Test public void getFirst() { StackIterable<Integer> stack = this.newStackWith(1, 2, 3); Assert.assertEquals(Integer.valueOf(3), stack.getFirst()); Assert.assertEquals(stack.peek(), stack.getFirst()); Verify.assertThrows(EmptyStackException.class, () -> this.newStackWith().getFirst()); StackIterable<Integer> stack2 = this.newStackFromTopToBottom(1, 2, 3); Assert.assertEquals(Integer.valueOf(1), stack2.getFirst()); } @Test(expected = UnsupportedOperationException.class) public void getLast() { StackIterable<Integer> stack = this.newStackWith(1, 2, 3); Assert.assertEquals(Integer.valueOf(1), stack.getLast()); } @Test public void contains() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); Assert.assertTrue(stack.contains(2)); Assert.assertTrue(stack.contains(3)); Assert.assertFalse(stack.contains(4)); } @Test public void containsAllIterable() { StackIterable<Integer> stack = this.newStackWith(1, 2, 3); Assert.assertTrue(stack.containsAllIterable(Interval.fromTo(2, 3))); Assert.assertFalse(stack.containsAllIterable(Interval.fromTo(2, 4))); } @Test public void containsAll() { StackIterable<Integer> stack = this.newStackWith(1, 2, 3, 4); Assert.assertTrue(stack.containsAll(Interval.oneTo(2))); Assert.assertFalse(stack.containsAll(FastList.newListWith(1, 2, 5))); } @Test public void containsAllArguments() { StackIterable<Integer> stack = this.newStackWith(1, 2, 3, 4); Assert.assertTrue(stack.containsAllArguments(2, 1, 3)); Assert.assertFalse(stack.containsAllArguments(2, 1, 3, 5)); } @Test public void collect() { StackIterable<Boolean> stack = this.newStackFromTopToBottom(Boolean.TRUE, Boolean.FALSE, null); CountingFunction<Object, String> function = CountingFunction.of(String::valueOf); Assert.assertEquals( this.newStackFromTopToBottom("true", "false", "null"), stack.collect(function)); Assert.assertEquals(3, function.count); Assert.assertEquals(FastList.newListWith("true", "false", "null"), stack.collect(String::valueOf, FastList.<String>newList())); } @Test public void collectBoolean() { StackIterable<String> stack = this.newStackFromTopToBottom("true", "nah", "TrUe", "false"); Assert.assertEquals( BooleanArrayStack.newStackFromTopToBottom(true, false, true, false), stack.collectBoolean(Boolean::parseBoolean)); } @Test public void collectBooleanWithTarget() { BooleanHashSet target = new BooleanHashSet(); StackIterable<String> stack = this.newStackFromTopToBottom("true", "nah", "TrUe", "false"); BooleanHashSet result = stack.collectBoolean(Boolean::parseBoolean, target); Assert.assertEquals(BooleanHashSet.newSetWith(true, false, true, false), result); Assert.assertSame("Target sent as parameter not returned", target, result); } @Test public void collectByte() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); Assert.assertEquals(ByteArrayStack.newStackFromTopToBottom((byte) 1, (byte) 2, (byte) 3), stack.collectByte(PrimitiveFunctions.unboxIntegerToByte())); } @Test public void collectByteWithTarget() { ByteHashSet target = new ByteHashSet(); StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); ByteHashSet result = stack.collectByte(PrimitiveFunctions.unboxIntegerToByte(), target); Assert.assertEquals(ByteHashSet.newSetWith((byte) 1, (byte) 2, (byte) 3), result); Assert.assertSame("Target sent as parameter not returned", target, result); } @Test public void collectChar() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); Assert.assertEquals(CharArrayStack.newStackFromTopToBottom((char) 1, (char) 2, (char) 3), stack.collectChar(PrimitiveFunctions.unboxIntegerToChar())); } @Test public void collectCharWithTarget() { CharHashSet target = new CharHashSet(); StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); CharHashSet result = stack.collectChar(PrimitiveFunctions.unboxIntegerToChar(), target); Assert.assertEquals(CharHashSet.newSetWith((char) 1, (char) 2, (char) 3), result); Assert.assertSame("Target sent as parameter not returned", target, result); } @Test public void collectDouble() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); Assert.assertEquals(DoubleArrayStack.newStackFromTopToBottom(1, 2, 3), stack.collectDouble(PrimitiveFunctions.unboxIntegerToDouble())); } @Test public void collectDoubleWithTarget() { DoubleHashSet target = new DoubleHashSet(); StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); DoubleHashSet result = stack.collectDouble(PrimitiveFunctions.unboxIntegerToDouble(), target); Assert.assertEquals(DoubleHashSet.newSetWith(1, 2, 3), result); Assert.assertSame("Target sent as parameter not returned", target, result); } @Test public void collectFloat() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); Assert.assertEquals(FloatArrayStack.newStackFromTopToBottom(1, 2, 3), stack.collectFloat(PrimitiveFunctions.unboxIntegerToFloat())); } @Test public void collectFloatWithTarget() { FloatHashSet target = new FloatHashSet(); StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); FloatHashSet result = stack.collectFloat(PrimitiveFunctions.unboxIntegerToFloat(), target); Assert.assertEquals(FloatHashSet.newSetWith(1, 2, 3), result); Assert.assertSame("Target sent as parameter not returned", target, result); } @Test public void collectInt() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); Assert.assertEquals(IntArrayStack.newStackFromTopToBottom(1, 2, 3), stack.collectInt(PrimitiveFunctions.unboxIntegerToInt())); } @Test public void collectIntWithTarget() { IntHashSet target = new IntHashSet(); StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); IntHashSet result = stack.collectInt(PrimitiveFunctions.unboxIntegerToInt(), target); Assert.assertEquals(IntHashSet.newSetWith(1, 2, 3), result); Assert.assertSame("Target sent as parameter not returned", target, result); } @Test public void collectLong() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); Assert.assertEquals(LongArrayStack.newStackFromTopToBottom(1, 2, 3), stack.collectLong(PrimitiveFunctions.unboxIntegerToLong())); } @Test public void collectLongWithTarget() { LongHashSet target = new LongHashSet(); StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); LongHashSet result = stack.collectLong(PrimitiveFunctions.unboxIntegerToLong(), target); Assert.assertEquals(LongHashSet.newSetWith(1, 2, 3), result); Assert.assertSame("Target sent as parameter not returned", target, result); } @Test public void collectShort() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); Assert.assertEquals(ShortArrayStack.newStackFromTopToBottom((short) 1, (short) 2, (short) 3), stack.collectShort(PrimitiveFunctions.unboxIntegerToShort())); } @Test public void collectShortWithTarget() { ShortHashSet target = new ShortHashSet(); StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); ShortHashSet result = stack.collectShort(PrimitiveFunctions.unboxIntegerToShort(), target); Assert.assertEquals(ShortHashSet.newSetWith((short) 1, (short) 2, (short) 3), result); Assert.assertSame("Target sent as parameter not returned", target, result); } @Test public void collectIf() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3, 4, 5); CountingPredicate<Integer> predicate1 = CountingPredicate.of(Predicates.lessThan(3)); CountingFunction<Object, String> function1 = CountingFunction.of(String::valueOf); Assert.assertEquals( this.newStackFromTopToBottom("1", "2"), stack.collectIf(predicate1, function1)); Assert.assertEquals(5, predicate1.count); Assert.assertEquals(2, function1.count); CountingPredicate<Integer> predicate2 = CountingPredicate.of(Predicates.lessThan(3)); CountingFunction<Object, String> function2 = CountingFunction.of(String::valueOf); Assert.assertEquals( FastList.newListWith("1", "2"), stack.collectIf(predicate2, function2, FastList.<String>newList())); Assert.assertEquals(5, predicate2.count); Assert.assertEquals(2, function2.count); } @Test public void collectWith() { StackIterable<Integer> stack = this.newStackFromTopToBottom(3, 2, 1); Assert.assertEquals( ArrayStack.newStackFromTopToBottom(4, 3, 2), stack.collectWith(AddFunction.INTEGER, 1)); } @Test public void collectWithTarget() { StackIterable<Integer> stack = this.newStackFromTopToBottom(3, 2, 1); Assert.assertEquals( FastList.newListWith(4, 3, 2), stack.collectWith(AddFunction.INTEGER, 1, FastList.<Integer>newList())); } @Test public void flatCollect() { StackIterable<String> stack = this.newStackFromTopToBottom("1", "One", "2", "Two"); CountingFunction<String, Iterable<Character>> function = CountingFunction.of(object -> { MutableList<Character> result = Lists.mutable.of(); char[] chars = object.toCharArray(); for (char aChar : chars) { result.add(Character.valueOf(aChar)); } return result; }); Assert.assertEquals( this.newStackFromTopToBottom('1', 'O', 'n', 'e', '2', 'T', 'w', 'o'), stack.flatCollect(function)); Assert.assertEquals(4, function.count); Assert.assertEquals( FastList.newListWith('1', 'O', 'n', 'e', '2', 'T', 'w', 'o'), stack.flatCollect(function, FastList.<Character>newList())); } @Test public void select() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); CountingPredicate<Object> predicate = new CountingPredicate<>(Integer.valueOf(1)::equals); StackIterable<Integer> actual = stack.select(predicate); Assert.assertEquals(this.newStackFromTopToBottom(1), actual); Assert.assertEquals(3, predicate.count); Assert.assertEquals( this.newStackFromTopToBottom(2, 3), stack.select(Predicates.greaterThan(1))); Assert.assertEquals( FastList.newListWith(2, 3), stack.select(Predicates.greaterThan(1), FastList.<Integer>newList())); } @Test public void selectInstancesOf() { StackIterable<Number> numbers = this.<Number>newStackFromTopToBottom(1, 2.0, 3, 4.0, 5); Assert.assertEquals(this.newStackFromTopToBottom(1, 3, 5), numbers.selectInstancesOf(Integer.class)); Assert.assertEquals(this.<Number>newStackFromTopToBottom(1, 2.0, 3, 4.0, 5), numbers.selectInstancesOf(Number.class)); } @Test public void selectWith() { Assert.assertEquals( ArrayStack.newStackFromTopToBottom(2, 1), this.newStackFromTopToBottom(5, 4, 3, 2, 1).selectWith(Predicates2.<Integer>lessThan(), 3)); } @Test public void selectWithTarget() { Assert.assertEquals( UnifiedSet.newSetWith(2, 1), this.newStackFromTopToBottom(5, 4, 3, 2, 1).selectWith(Predicates2.<Integer>lessThan(), 3, UnifiedSet.<Integer>newSet())); } @Test public void reject() { StackIterable<Integer> stack = this.newStackFromTopToBottom(3, 2, 1); CountingPredicate<Integer> predicate = new CountingPredicate<>(Predicates.greaterThan(2)); Assert.assertEquals( this.newStackFromTopToBottom(2, 1), stack.reject(predicate)); Assert.assertEquals(3, predicate.count); Assert.assertEquals( FastList.newListWith(2, 1), stack.reject(Predicates.greaterThan(2), FastList.<Integer>newList())); } @Test public void rejectWith() { StackIterable<Integer> stack = this.newStackFromTopToBottom(3, 2, 1); Assert.assertEquals( this.newStackFromTopToBottom(2, 1), stack.rejectWith(Predicates2.<Integer>greaterThan(), 2)); } @Test public void rejectWithTarget() { Assert.assertEquals( UnifiedSet.newSetWith(5, 4, 3), this.newStackFromTopToBottom(5, 4, 3, 2, 1).rejectWith(Predicates2.<Integer>lessThan(), 3, UnifiedSet.<Integer>newSet())); } @Test public void detect() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); CountingPredicate<Integer> predicate = new CountingPredicate<>(Predicates.lessThan(3)); Assert.assertEquals(Integer.valueOf(1), stack.detect(predicate)); Assert.assertEquals(1, predicate.count); Assert.assertNull(stack.detect(Integer.valueOf(4)::equals)); } @Test public void detectWith() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); CountingPredicate2<Integer, Integer> predicate = new CountingPredicate2<>(Predicates2.<Integer>lessThan()); Assert.assertEquals(Integer.valueOf(1), stack.detectWith(predicate, 3)); Assert.assertEquals(1, predicate.count); Assert.assertNull(stack.detectWith(Object::equals, Integer.valueOf(4))); } @Test public void detectIfNone() { Function0<Integer> defaultResultFunction = new PassThruFunction0<>(-1); CountingPredicate<Integer> predicate = new CountingPredicate<>(Predicates.lessThan(3)); Assert.assertEquals( Integer.valueOf(1), this.newStackFromTopToBottom(1, 2, 3, 4, 5).detectIfNone(predicate, defaultResultFunction)); Assert.assertEquals(1, predicate.count); Assert.assertEquals( Integer.valueOf(-1), this.newStackWith(1, 2, 3, 4, 5).detectIfNone(Predicates.lessThan(-1), defaultResultFunction)); } @Test public void detectWithIfNone() { Function0<Integer> defaultResultFunction = new PassThruFunction0<>(-1); CountingPredicate2<Integer, Integer> predicate = new CountingPredicate2<>(Predicates2.<Integer>lessThan()); Assert.assertEquals( Integer.valueOf(1), this.newStackFromTopToBottom(1, 2, 3, 4, 5).detectWithIfNone(predicate, Integer.valueOf(3), defaultResultFunction)); Assert.assertEquals(1, predicate.count); Assert.assertEquals( Integer.valueOf(-1), this.newStackWith(1, 2, 3, 4, 5).detectIfNone(Predicates.lessThan(-1), defaultResultFunction)); } @Test public void partition() { CountingPredicate<Integer> predicate = new CountingPredicate<>(Predicates.lessThan(3)); PartitionStack<Integer> partition = this.newStackFromTopToBottom(1, 2, 3, 4, 5).partition(predicate); Assert.assertEquals(5, predicate.count); Assert.assertEquals(this.newStackFromTopToBottom(1, 2), partition.getSelected()); Assert.assertEquals(this.newStackFromTopToBottom(3, 4, 5), partition.getRejected()); } @Test public void partitionWith() { PartitionStack<Integer> partition = this.newStackFromTopToBottom(1, 2, 3, 4, 5).partitionWith(Predicates2.<Integer>lessThan(), 3); Assert.assertEquals(this.newStackFromTopToBottom(1, 2), partition.getSelected()); Assert.assertEquals(this.newStackFromTopToBottom(3, 4, 5), partition.getRejected()); } @Test public void zip() { StackIterable<String> stack = this.newStackFromTopToBottom("7", "6", "5", "4", "3", "2", "1"); List<Integer> interval = Interval.oneTo(7); StackIterable<Pair<String, Integer>> expected = this.newStackFromTopToBottom( Tuples.pair("7", 1), Tuples.pair("6", 2), Tuples.pair("5", 3), Tuples.pair("4", 4), Tuples.pair("3", 5), Tuples.pair("2", 6), Tuples.pair("1", 7)); Assert.assertEquals(expected, stack.zip(interval)); Assert.assertEquals( expected.toSet(), stack.zip(interval, UnifiedSet.<Pair<String, Integer>>newSet())); } @Test public void zipWithIndex() { StackIterable<String> stack = this.newStackFromTopToBottom("4", "3", "2", "1"); StackIterable<Pair<String, Integer>> expected = this.newStackFromTopToBottom( Tuples.pair("4", 0), Tuples.pair("3", 1), Tuples.pair("2", 2), Tuples.pair("1", 3)); Assert.assertEquals(expected, stack.zipWithIndex()); Assert.assertEquals(expected.toSet(), stack.zipWithIndex(UnifiedSet.<Pair<String, Integer>>newSet())); } @Test public void count() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3, 4, 5); CountingPredicate<Integer> predicate = new CountingPredicate<>(Predicates.greaterThan(2)); Assert.assertEquals(3, stack.count(predicate)); Assert.assertEquals(5, predicate.count); Assert.assertEquals(0, stack.count(Predicates.greaterThan(6))); } @Test public void countWith() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3, 4, 5); CountingPredicate2<Object, Object> predicate = new CountingPredicate2<>(Object::equals); Assert.assertEquals(1, stack.countWith(predicate, 1)); Assert.assertEquals(5, predicate.count); Assert.assertNotEquals(2, stack.countWith(predicate, 4)); } @Test public void anySatisfy() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); CountingPredicate<Object> predicate = new CountingPredicate<>(Integer.valueOf(1)::equals); Assert.assertTrue(stack.anySatisfy(predicate)); Assert.assertEquals(1, predicate.count); Assert.assertFalse(stack.anySatisfy(Integer.valueOf(4)::equals)); } @Test public void allSatisfy() { StackIterable<Integer> stack = this.newStackWith(3, 3, 3); CountingPredicate<Object> predicate = new CountingPredicate<>(Integer.valueOf(3)::equals); Assert.assertTrue(stack.allSatisfy(predicate)); Assert.assertEquals(3, predicate.count); Assert.assertFalse(stack.allSatisfy(Integer.valueOf(2)::equals)); } @Test public void noneSatisfy() { StackIterable<Integer> stack = this.newStackWith(3, 3, 3); CountingPredicate<Object> predicate = new CountingPredicate<>(Integer.valueOf(4)::equals); Assert.assertTrue(stack.noneSatisfy(predicate)); Assert.assertEquals(3, predicate.count); Assert.assertTrue(stack.noneSatisfy(Integer.valueOf(2)::equals)); } @Test public void anySatisfyWith() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); CountingPredicate2<Object, Object> predicate = new CountingPredicate2<>(Object::equals); Assert.assertTrue(stack.anySatisfyWith(predicate, 1)); Assert.assertEquals(1, predicate.count); Assert.assertFalse(stack.anySatisfyWith(Object::equals, 4)); } @Test public void allSatisfyWith() { StackIterable<Integer> stack = this.newStackWith(3, 3, 3); CountingPredicate2<Object, Object> predicate = new CountingPredicate2<>(Object::equals); Assert.assertTrue(stack.allSatisfyWith(predicate, 3)); Assert.assertEquals(3, predicate.count); Assert.assertFalse(stack.allSatisfyWith(Object::equals, 2)); } @Test public void noneSatisfyWith() { StackIterable<Integer> stack = this.newStackWith(3, 3, 3); CountingPredicate2<Object, Object> predicate = new CountingPredicate2<>(Object::equals); Assert.assertTrue(stack.noneSatisfyWith(predicate, 4)); Assert.assertEquals(3, predicate.count); Assert.assertTrue(stack.noneSatisfyWith(Object::equals, 2)); } @Test public void injectInto() { Assert.assertEquals( Integer.valueOf(10), this.newStackWith(1, 2, 3, 4).injectInto(Integer.valueOf(0), AddFunction.INTEGER)); Assert.assertEquals( 10, this.newStackWith(1, 2, 3, 4).injectInto(0, AddFunction.INTEGER_TO_INT)); Assert.assertEquals( 7.0, this.newStackWith(1.0, 2.0, 3.0).injectInto(1.0d, AddFunction.DOUBLE_TO_DOUBLE), 0.001); Assert.assertEquals( 7, this.newStackWith(1, 2, 3).injectInto(1L, AddFunction.INTEGER_TO_LONG)); Assert.assertEquals( 7.0, this.newStackWith(1, 2, 3).injectInto(1.0f, AddFunction.INTEGER_TO_FLOAT), 0.001); } @Test public void sumOf() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3, 4); Assert.assertEquals(10, stack.sumOfInt(integer -> integer)); Assert.assertEquals(10, stack.sumOfLong(Integer::longValue)); Assert.assertEquals(10.0d, stack.sumOfDouble(Integer::doubleValue), 0.001); Assert.assertEquals(10.0f, stack.sumOfFloat(Integer::floatValue), 0.001); } @Test public void sumOfFloatConsistentRounding() { MutableList<Integer> list = Interval.oneTo(100_000).toList().shuffleThis(); StackIterable<Integer> stack = this.newStackWith(list.toArray(new Integer[]{})); // The test only ensures the consistency/stability of rounding. This is not meant to test the "correctness" of the float calculation result. // Indeed the lower bits of this calculation result are always incorrect due to the information loss of original float values. Assert.assertEquals( 1.082323233761663, stack.sumOfFloat(i -> 1.0f / (i.floatValue() * i.floatValue() * i.floatValue() * i.floatValue())), 1.0e-15); } @Test public void sumOfDoubleConsistentRounding() { MutableList<Integer> list = Interval.oneTo(100_000).toList().shuffleThis(); StackIterable<Integer> stack = this.newStackWith(list.toArray(new Integer[]{})); Assert.assertEquals( 1.082323233711138, stack.sumOfDouble(i -> 1.0d / (i.doubleValue() * i.doubleValue() * i.doubleValue() * i.doubleValue())), 1.0e-15); } @Test public void sumByInt() { RichIterable<Integer> values = this.newStackFromTopToBottom(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); ObjectLongMap<Integer> result = values.sumByInt(i -> i % 2, e -> e); Assert.assertEquals(25, result.get(1)); Assert.assertEquals(30, result.get(0)); } @Test public void sumByFloat() { RichIterable<Integer> values = this.newStackFromTopToBottom(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); ObjectDoubleMap<Integer> result = values.sumByFloat(f -> f % 2, e -> e); Assert.assertEquals(25.0f, result.get(1), 0.0); Assert.assertEquals(30.0f, result.get(0), 0.0); } @Test public void sumByFloatConsistentRounding() { MutableList<Integer> group1 = Interval.oneTo(100_000).toList().shuffleThis(); MutableList<Integer> group2 = Interval.fromTo(100_001, 200_000).toList().shuffleThis(); MutableList<Integer> integers = Lists.mutable.withAll(group1); integers.addAll(group2); StackIterable<Integer> values = this.newStackWith(integers.toArray(new Integer[]{})); ObjectDoubleMap<Integer> result = values.sumByFloat( integer -> integer > 100_000 ? 2 : 1, integer -> { Integer i = integer > 100_000 ? integer - 100_000 : integer; return 1.0f / (i.floatValue() * i.floatValue() * i.floatValue() * i.floatValue()); }); // The test only ensures the consistency/stability of rounding. This is not meant to test the "correctness" of the float calculation result. // Indeed the lower bits of this calculation result are always incorrect due to the information loss of original float values. Assert.assertEquals( 1.082323233761663, result.get(1), 1.0e-15); Assert.assertEquals( 1.082323233761663, result.get(2), 1.0e-15); } @Test public void sumByLong() { RichIterable<Integer> values = this.newStackFromTopToBottom(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); ObjectLongMap<Integer> result = values.sumByLong(l -> l % 2, e -> e); Assert.assertEquals(25, result.get(1)); Assert.assertEquals(30, result.get(0)); } @Test public void sumByDouble() { RichIterable<Integer> values = this.newStackFromTopToBottom(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); ObjectDoubleMap<Integer> result = values.sumByDouble(d -> d % 2, e -> e); Assert.assertEquals(25.0d, result.get(1), 0.0); Assert.assertEquals(30.0d, result.get(0), 0.0); } @Test public void sumByDoubleConsistentRounding() { MutableList<Integer> group1 = Interval.oneTo(100_000).toList().shuffleThis(); MutableList<Integer> group2 = Interval.fromTo(100_001, 200_000).toList().shuffleThis(); MutableList<Integer> integers = Lists.mutable.withAll(group1); integers.addAll(group2); StackIterable<Integer> values = this.newStackWith(integers.toArray(new Integer[]{})); ObjectDoubleMap<Integer> result = values.sumByDouble( integer -> integer > 100_000 ? 2 : 1, integer -> { Integer i = integer > 100_000 ? integer - 100_000 : integer; return 1.0d / (i.doubleValue() * i.doubleValue() * i.doubleValue() * i.doubleValue()); }); Assert.assertEquals( 1.082323233711138, result.get(1), 1.0e-15); Assert.assertEquals( 1.082323233711138, result.get(2), 1.0e-15); } @Test public void max() { Assert.assertEquals( Integer.valueOf(4), this.newStackFromTopToBottom(4, 3, 2, 1).max()); Assert.assertEquals( Integer.valueOf(1), this.newStackFromTopToBottom(4, 3, 2, 1).max(Comparators.<Integer>reverseNaturalOrder())); } @Test public void maxBy() { Assert.assertEquals( Integer.valueOf(3), this.newStackWith(1, 2, 3).maxBy(String::valueOf)); } @Test public void min() { Assert.assertEquals( Integer.valueOf(1), this.newStackWith(1, 2, 3, 4).min()); Assert.assertEquals( Integer.valueOf(4), this.newStackWith(1, 2, 3, 4).min(Comparators.<Integer>reverseNaturalOrder())); } @Test public void minBy() { CountingFunction<Object, String> function = CountingFunction.of(String::valueOf); Assert.assertEquals( Integer.valueOf(1), this.newStackWith(1, 2, 3).minBy(function)); Assert.assertEquals(3, function.count); } @Test public void testToString() { StackIterable<Integer> stack = this.newStackFromTopToBottom(4, 3, 2, 1); Assert.assertEquals("[4, 3, 2, 1]", stack.toString()); } @Test public void makeString() { Assert.assertEquals("3, 2, 1", this.newStackFromTopToBottom(3, 2, 1).makeString()); Assert.assertEquals("3~2~1", this.newStackFromTopToBottom(3, 2, 1).makeString("~")); Assert.assertEquals("[3/2/1]", this.newStackFromTopToBottom(3, 2, 1).makeString("[", "/", "]")); } @Test public void appendString() { StackIterable<String> stack = this.newStackFromTopToBottom("3", "2", "1"); Appendable appendable = new StringBuilder(); stack.appendString(appendable); Assert.assertEquals("3, 2, 1", appendable.toString()); Appendable appendable2 = new StringBuilder(); stack.appendString(appendable2, "/"); Assert.assertEquals("3/2/1", appendable2.toString()); Appendable appendable3 = new StringBuilder(); stack.appendString(appendable3, "[", "/", "]"); Assert.assertEquals("[3/2/1]", appendable3.toString()); } @Test public void groupBy() { StackIterable<String> stack = this.newStackWith("1", "2", "3"); ListMultimap<Boolean, String> expected = FastListMultimap.newMultimap( Tuples.pair(Boolean.TRUE, "3"), Tuples.pair(Boolean.FALSE, "2"), Tuples.pair(Boolean.TRUE, "1")); Assert.assertEquals(expected, stack.groupBy(object -> IntegerPredicates.isOdd().accept(Integer.parseInt(object)))); Assert.assertEquals(expected, stack.groupBy(object -> IntegerPredicates.isOdd().accept(Integer.parseInt(object)), FastListMultimap.<Boolean, String>newMultimap())); } @Test public void groupByEach() { StackIterable<Integer> stack = this.newStackFromTopToBottom(1, 2, 3); MutableMultimap<Integer, Integer> expected = FastListMultimap.newMultimap(); stack.forEach(Procedures.cast(value -> expected.putAll(-value, Interval.fromTo(value, stack.size())))); Multimap<Integer, Integer> actual = stack.groupByEach(new NegativeIntervalFunction()); Assert.assertEquals(expected, actual); Multimap<Integer, Integer> actualWithTarget = stack.groupByEach(new NegativeIntervalFunction(), FastListMultimap.<Integer, Integer>newMultimap()); Assert.assertEquals(expected, actualWithTarget); } @Test public void groupByUniqueKey() { Assert.assertEquals(UnifiedMap.newWithKeysValues(1, 1, 2, 2, 3, 3), this.newStackWith(1, 2, 3).groupByUniqueKey(id -> id)); } @Test(expected = IllegalStateException.class) public void groupByUniqueKey_throws() { this.newStackWith(1, 2, 3).groupByUniqueKey(Functions.getFixedValue(1)); } @Test public void groupByUniqueKey_target() { MutableMap<Integer, Integer> integers = this.newStackWith(1, 2, 3).groupByUniqueKey(id -> id, UnifiedMap.newWithKeysValues(0, 0)); Assert.assertEquals(UnifiedMap.newWithKeysValues(0, 0, 1, 1, 2, 2, 3, 3), integers); } @Test(expected = IllegalStateException.class) public void groupByUniqueKey_target_throws() { this.newStackWith(1, 2, 3).groupByUniqueKey(id -> id, UnifiedMap.newWithKeysValues(2, 2)); } @Test public void chunk() { Verify.assertIterablesEqual( FastList.<RichIterable<String>>newListWith( FastList.newListWith("7", "6"), FastList.newListWith("5", "4"), FastList.newListWith("3", "2"), FastList.newListWith("1")), this.newStackFromTopToBottom("7", "6", "5", "4", "3", "2", "1").chunk(2)); } @Test public void tap() { MutableList<String> tapResult = Lists.mutable.of(); StackIterable<String> stack = this.newStackWith("1", "2", "3", "4", "5"); Assert.assertSame(stack, stack.tap(tapResult::add)); Assert.assertEquals(stack.toList(), tapResult); } @Test public void forEach() { StackIterable<String> stack = this.newStackWith("1", "2", "3", "4", "5"); Appendable builder = new StringBuilder(); Procedure<String> appendProcedure = Procedures.append(builder); stack.forEach(appendProcedure); Assert.assertEquals("54321", builder.toString()); } @Test public void forEachWith() { StackIterable<String> stack = this.newStackWith("1", "2", "3", "4"); StringBuilder builder = new StringBuilder(); stack.forEachWith((argument1, argument2) -> builder.append(argument1).append(argument2), 0); Assert.assertEquals("40302010", builder.toString()); } @Test public void forEachWithIndex() { StackIterable<String> stack = this.newStackFromTopToBottom("5", "4", "3", "2", "1"); StringBuilder builder = new StringBuilder(); stack.forEachWithIndex((each, index) -> builder.append(each).append(index)); Assert.assertEquals("5041322314", builder.toString()); } @Test public void toList() { Assert.assertEquals( FastList.newListWith(4, 3, 2, 1), this.newStackFromTopToBottom(4, 3, 2, 1).toList()); } @Test public void toStack() { Assert.assertEquals(this.newStackFromTopToBottom(3, 2, 1), this.newStackFromTopToBottom(3, 2, 1).toStack()); } @Test public void toSortedList() { Assert.assertEquals( Interval.oneTo(4), this.newStackFromTopToBottom(4, 3, 1, 2).toSortedList()); Assert.assertEquals( Interval.fromTo(4, 1), this.newStackFromTopToBottom(4, 3, 1, 2).toSortedList(Collections.<Integer>reverseOrder())); } @Test public void toSortedListBy() { MutableList<Integer> list = FastList.newList(Interval.oneTo(10)).shuffleThis(); Assert.assertEquals( Interval.oneTo(10), this.newStack(list).toSortedListBy(Functions.getIntegerPassThru())); } @Test public void toSet() { Assert.assertEquals(UnifiedSet.newSetWith(4, 3, 2, 1), this.newStackWith(1, 2, 3, 4).toSet()); } @Test public void toSortedSet() { MutableSortedSet<Integer> expected = TreeSortedSet.newSetWith(1, 2, 4, 5); StackIterable<Integer> stack = this.newStackWith(2, 1, 5, 4); Assert.assertEquals(expected, stack.toSortedSet()); Assert.assertEquals(FastList.newListWith(1, 2, 4, 5), stack.toSortedSet().toList()); MutableSortedSet<Integer> reversed = stack.toSortedSet(Comparators.reverseNaturalOrder()); Verify.assertSortedSetsEqual(reversed, stack.toSortedSet(Comparators.reverseNaturalOrder())); Assert.assertEquals( FastList.newListWith(5, 4, 2, 1), stack.toSortedSet(Comparators.reverseNaturalOrder()).toList()); } @Test public void toSortedSetBy() { SetIterable<Integer> expected = UnifiedSet.newSetWith(10, 9, 8, 7, 6, 5, 4, 3, 2, 1); StackIterable<Integer> stack = this.newStackWith(5, 2, 4, 3, 1, 6, 7, 8, 9, 10); Assert.assertEquals( expected, stack.toSortedSetBy(String::valueOf)); Assert.assertEquals( FastList.newListWith(1, 10, 2, 3, 4, 5, 6, 7, 8, 9), stack.toSortedSetBy(String::valueOf).toList()); } @Test public void toBag() { Assert.assertEquals(Bags.mutable.of("C", "B", "A"), this.newStackFromTopToBottom("C", "B", "A").toBag()); } @Test public void toSortedBag() { SortedBag<Integer> expected = TreeBag.newBagWith(1, 2, 2, 4, 5); StackIterable<Integer> stack = this.newStackWith(2, 2, 1, 5, 4); Verify.assertSortedBagsEqual(expected, stack.toSortedBag()); Assert.assertEquals(FastList.newListWith(1, 2, 2, 4, 5), stack.toSortedBag().toList()); SortedBag<Integer> expected2 = TreeBag.newBagWith(Comparators.reverseNaturalOrder(), 1, 2, 2, 4, 5); Verify.assertSortedBagsEqual(expected2, stack.toSortedBag(Comparators.reverseNaturalOrder())); Assert.assertEquals( FastList.newListWith(5, 4, 2, 2, 1), stack.toSortedBag(Comparators.reverseNaturalOrder()).toList()); } @Test public void toSortedBagBy() { SortedBag<Integer> expected = TreeBag.newBagWith(1, 2, 3, 3, 4, 5); StackIterable<Integer> stack = this.newStackWith(1, 2, 3, 3, 4, 5); Verify.assertSortedBagsEqual( expected, stack.toSortedBagBy(String::valueOf)); } @Test public void toMap() { Assert.assertEquals(UnifiedMap.newWithKeysValues("4", "4", "3", "3", "2", "2", "1", "1"), this.newStackFromTopToBottom(4, 3, 2, 1).toMap(String::valueOf, String::valueOf)); } @Test public void toSortedMap() { Assert.assertEquals(UnifiedMap.newWithKeysValues(3, "3", 2, "2", 1, "1"), this.newStackFromTopToBottom(3, 2, 1).toSortedMap(Functions.getIntegerPassThru(), String::valueOf)); Assert.assertEquals(TreeSortedMap.newMapWith(Comparators.<Integer>reverseNaturalOrder(), 3, "3", 2, "2", 1, "1"), this.newStackFromTopToBottom(3, 2, 1).toSortedMap(Comparators.<Integer>reverseNaturalOrder(), Functions.getIntegerPassThru(), String::valueOf)); } @Test public void asLazy() { Assert.assertEquals(FastList.newListWith("3", "2", "1"), this.newStackFromTopToBottom("3", "2", "1").asLazy().toList()); } @Test public void toArray() { Assert.assertArrayEquals(new Object[]{4, 3, 2, 1}, this.newStackFromTopToBottom(4, 3, 2, 1).toArray()); Assert.assertArrayEquals(new Integer[]{4, 3, 2, 1}, this.newStackFromTopToBottom(4, 3, 2, 1).toArray(new Integer[0])); } @Test public void iterator() { StringBuilder builder = new StringBuilder(); StackIterable<String> stack = this.newStackFromTopToBottom("5", "4", "3", "2", "1"); for (String string : stack) { builder.append(string); } Assert.assertEquals("54321", builder.toString()); } @Test public void testEquals() { StackIterable<Integer> stack1 = this.newStackFromTopToBottom(1, 2, 3, 4); StackIterable<Integer> stack2 = this.newStackFromTopToBottom(1, 2, 3, 4); StackIterable<Integer> stack3 = this.newStackFromTopToBottom(5, 2, 1, 4); StackIterable<Integer> stack4 = this.newStackFromTopToBottom(1, 2, 3); StackIterable<Integer> stack5 = this.newStackFromTopToBottom(1, 2, 3, 4, 5); StackIterable<Integer> stack6 = this.newStackFromTopToBottom(1, 2, 3, null); Verify.assertEqualsAndHashCode(stack1, stack2); Verify.assertPostSerializedEqualsAndHashCode(this.newStackWith(1, 2, 3, 4)); Assert.assertNotEquals(stack1, stack3); Assert.assertNotEquals(stack1, stack4); Assert.assertNotEquals(stack1, stack5); Assert.assertNotEquals(stack1, stack6); Verify.assertPostSerializedEqualsAndHashCode(this.newStackWith(null, null, null)); Assert.assertEquals(Stacks.mutable.of(), this.newStackWith()); } @Test public void testHashCode() { StackIterable<Integer> stack1 = this.newStackWith(1, 2, 3, 5); StackIterable<Integer> stack2 = this.newStackWith(1, 2, 3, 4); Assert.assertNotEquals(stack1.hashCode(), stack2.hashCode()); Assert.assertEquals( 31 * 31 * 31 * 31 + 1 * 31 * 31 * 31 + 2 * 31 * 31 + 3 * 31 + 4, this.newStackFromTopToBottom(1, 2, 3, 4).hashCode()); Assert.assertEquals(31 * 31 * 31, this.newStackFromTopToBottom(null, null, null).hashCode()); Assert.assertNotEquals(this.newStackFromTopToBottom(1, 2, 3, 4).hashCode(), this.newStackFromTopToBottom(4, 3, 2, 1).hashCode()); } @Test public void aggregateByMutating() { Function0<AtomicInteger> valueCreator = AtomicInteger::new; StackIterable<Integer> collection = this.newStackWith(1, 1, 1, 2, 2, 3); MapIterable<String, AtomicInteger> aggregation = collection.aggregateInPlaceBy(String::valueOf, valueCreator, AtomicInteger::addAndGet); Assert.assertEquals(3, aggregation.get("1").intValue()); Assert.assertEquals(4, aggregation.get("2").intValue()); Assert.assertEquals(3, aggregation.get("3").intValue()); } @Test public void aggregateByNonMutating() { Function0<Integer> valueCreator = () -> 0; Function2<Integer, Integer, Integer> sumAggregator = (integer1, integer2) -> integer1 + integer2; StackIterable<Integer> collection = this.newStackWith(1, 1, 1, 2, 2, 3); MapIterable<String, Integer> aggregation = collection.aggregateBy(String::valueOf, valueCreator, sumAggregator); Assert.assertEquals(3, aggregation.get("1").intValue()); Assert.assertEquals(4, aggregation.get("2").intValue()); Assert.assertEquals(3, aggregation.get("3").intValue()); } private static final class CountingPredicate<T> implements Predicate<T> { private static final long serialVersionUID = 1L; private final Predicate<T> predicate; private int count; private CountingPredicate(Predicate<T> predicate) { this.predicate = predicate; } private static <T> CountingPredicate<T> of(Predicate<T> predicate) { return new CountingPredicate<>(predicate); } @Override public boolean accept(T anObject) { this.count++; return this.predicate.accept(anObject); } } private static final class CountingPredicate2<T1, T2> implements Predicate2<T1, T2> { private static final long serialVersionUID = 1L; private final Predicate2<T1, T2> predicate; private int count; private CountingPredicate2(Predicate2<T1, T2> predicate) { this.predicate = predicate; } private static <T1, T2> CountingPredicate2<T1, T2> of(Predicate2<T1, T2> predicate) { return new CountingPredicate2<>(predicate); } @Override public boolean accept(T1 each, T2 parameter) { this.count++; return this.predicate.accept(each, parameter); } } private static final class CountingFunction<T, V> implements Function<T, V> { private static final long serialVersionUID = 1L; private int count; private final Function<T, V> function; private CountingFunction(Function<T, V> function) { this.function = function; } private static <T, V> CountingFunction<T, V> of(Function<T, V> function) { return new CountingFunction<>(function); } @Override public V valueOf(T object) { this.count++; return this.function.valueOf(object); } } }